From 23f15c644a8dc763791223f87d7ee0b4326b0c37 Mon Sep 17 00:00:00 2001 From: Stuart Mitchell Date: Thu, 23 Jan 2014 18:05:08 +0800 Subject: [PATCH] Initial conversion to py 2.6, 2.7, 3.2 version --- bootstrap.py | 23 ++- doc/KPyCon2009/code/wedding.py | 4 +- doc/KPyCon2009/code/whiskas.py | 14 +- doc/source/conf.py | 8 +- examples/AmericanSteelProblem.py | 6 +- examples/BeerDistributionProblem.py | 6 +- examples/BeerDistributionProblem_resolve.py | 6 +- examples/CG.py | 58 +++---- examples/ComputerPlantProblem.py | 6 +- examples/SpongeRollProblem1.py | 6 +- examples/SpongeRollProblem2.py | 6 +- examples/SpongeRollProblem3.py | 10 +- examples/SpongeRollProblem4.py | 56 +++---- examples/SpongeRollProblem5.py | 6 +- examples/SpongeRollProblem6.py | 6 +- examples/Sudoku1.py | 4 +- examples/Sudoku2.py | 4 +- examples/WhiskasModel1.py | 6 +- examples/WhiskasModel2.py | 6 +- examples/furniture.py | 4 +- examples/test1.py | 6 +- examples/test2.py | 8 +- examples/test3.py | 28 ++-- examples/test4.py | 6 +- examples/test5.py | 12 +- examples/test6.py | 6 +- examples/test7.py | 12 +- examples/wedding.py | 4 +- ez_setup.py | 30 ++-- setup.py | 9 +- src/pulp/__init__.py | 8 +- src/pulp/amply.py | 18 +-- src/pulp/pulp.py | 147 +++++++++-------- src/pulp/solvers.py | 169 ++++++++++---------- src/pulp/sparse.py | 20 +-- src/pulp/tests.py | 90 +++++------ tests/amply_tests.py | 12 +- 37 files changed, 434 insertions(+), 396 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index a545477..354a661 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -20,7 +20,11 @@ use the -c option to specify an alternate configuration file. $Id$ """ -import os, shutil, sys, tempfile, urllib2 +import os, shutil, sys, tempfile +try: + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen from optparse import OptionParser tmpeggs = tempfile.mkdtemp() @@ -54,16 +58,23 @@ try: except ImportError: ez = {} if USE_DISTRIBUTE: - exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py' - ).read() in ez + exec(urlopen('http://python-distribute.org/distribute_setup.py' + ).read(), ez) ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True) else: - exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' - ).read() in ez + try: + exec(urlopen('http://peak.telecommunity.com/dist/ez_setup.py') + .read(), ez) + except SyntaxError: + exec(urlopen('http://python-distribute.org/distribute_setup.py') + .read(), ez) ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) if to_reload: - reload(pkg_resources) + try: + reload(pkg_resources) + except NameError: # distribute is deprecated by now + pass else: import pkg_resources diff --git a/doc/KPyCon2009/code/wedding.py b/doc/KPyCon2009/code/wedding.py index 7417b60..1327c33 100644 --- a/doc/KPyCon2009/code/wedding.py +++ b/doc/KPyCon2009/code/wedding.py @@ -42,9 +42,9 @@ for guest in guests: seating_model.solve() -print "The choosen tables are out of a total of %s:"%len(possible_tables) +print("The choosen tables are out of a total of %s:"%len(possible_tables)) for table in possible_tables: if x[table].value() == 1.0: - print table + print(table) diff --git a/doc/KPyCon2009/code/whiskas.py b/doc/KPyCon2009/code/whiskas.py index 70349e9..7fda9bc 100644 --- a/doc/KPyCon2009/code/whiskas.py +++ b/doc/KPyCon2009/code/whiskas.py @@ -5,11 +5,11 @@ import pulp #initialise the model whiskas_model = pulp.LpProblem('The Whiskas Problem', pulp.LpMinimize) -# make a list of ingredients +# make a list of ingredients ingredients = ['chicken', 'beef', 'mutton', 'rice', 'wheat', 'gel'] # create a dictionary of pulp variables with keys from ingredients # the default lower bound is -inf -x = pulp.LpVariable.dict('x_%s', ingredients, lowBound =0) +x = pulp.LpVariable.dict('x_%s', ingredients, lowBound =0) # cost data cost = dict(zip(ingredients, [0.013, 0.008, 0.010, 0.002, 0.005, 0.001])) @@ -17,9 +17,9 @@ cost = dict(zip(ingredients, [0.013, 0.008, 0.010, 0.002, 0.005, 0.001])) whiskas_model += sum( [cost[i] * x[i] for i in ingredients]) # ingredient parameters -protein = dict(zip(ingredients, [0.100, 0.200, 0.150, 0.000, 0.040, 0.000])) -fat = dict(zip(ingredients, [0.080, 0.100, 0.110, 0.010, 0.010, 0.000])) -fibre = dict(zip(ingredients, [0.001, 0.005, 0.003, 0.100, 0.150, 0.000])) +protein = dict(zip(ingredients, [0.100, 0.200, 0.150, 0.000, 0.040, 0.000])) +fat = dict(zip(ingredients, [0.080, 0.100, 0.110, 0.010, 0.010, 0.000])) +fibre = dict(zip(ingredients, [0.001, 0.005, 0.003, 0.100, 0.150, 0.000])) salt = dict(zip(ingredients, [0.002, 0.005, 0.007, 0.002, 0.008, 0.000])) #note these are constraints and not an objective as there is a equality/inequality @@ -33,6 +33,6 @@ whiskas_model.solve() #print the result for ingredient in ingredients: - print 'The mass of %s is %s grams per can'%(ingredient, - x[ingredient].value()) + print('The mass of %s is %s grams per can'%(ingredient, + x[ingredient].value())) diff --git a/doc/source/conf.py b/doc/source/conf.py index dd356ad..d0b15d2 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -41,8 +41,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'PuLP' -copyright = u'2009-, pulp documentation team.' +project = 'PuLP' +copyright = '2009-, pulp documentation team.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -176,8 +176,8 @@ htmlhelp_basename = 'pulpdoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'pulp.tex', u'pulp Documentation', - u'pulp documentation team', 'manual'), + ('index', 'pulp.tex', 'pulp Documentation', + 'pulp documentation team', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/examples/AmericanSteelProblem.py b/examples/AmericanSteelProblem.py index caea200..91537b9 100644 --- a/examples/AmericanSteelProblem.py +++ b/examples/AmericanSteelProblem.py @@ -90,11 +90,11 @@ prob.writeLP("AmericanSteelProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Cost of Transportation = ", value(prob.objective) +print("Total Cost of Transportation = ", value(prob.objective)) diff --git a/examples/BeerDistributionProblem.py b/examples/BeerDistributionProblem.py index 50c0e90..fa706d8 100644 --- a/examples/BeerDistributionProblem.py +++ b/examples/BeerDistributionProblem.py @@ -61,11 +61,11 @@ prob.writeLP("BeerDistributionProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Cost of Transportation = ", value(prob.objective) +print("Total Cost of Transportation = ", value(prob.objective)) diff --git a/examples/BeerDistributionProblem_resolve.py b/examples/BeerDistributionProblem_resolve.py index 7561133..7787446 100644 --- a/examples/BeerDistributionProblem_resolve.py +++ b/examples/BeerDistributionProblem_resolve.py @@ -72,11 +72,11 @@ for demand in range(500, 601, 10): prob.solve() # The status of the solution is printed to the screen - print "Status:", LpStatus[prob.status] + print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen - print "Total Cost of Transportation = ", value(prob.objective) + print("Total Cost of Transportation = ", value(prob.objective)) diff --git a/examples/CG.py b/examples/CG.py index 0cc71d5..43daadb 100644 --- a/examples/CG.py +++ b/examples/CG.py @@ -1,7 +1,7 @@ """ Column Generation Functions -Authors: Antony Phillips, Dr Stuart Mitchell 2008 +Authors: Antony Phillips, Dr Stuart Mitchell 2008 """ # Import PuLP modeler functions @@ -15,92 +15,92 @@ class Pattern: trimValue = 0.04 totalRollLength = 20 lenOpts = ["5", "7", "9"] - + def __init__(self, name, lengths = None): self.name = name self.lengthsdict = dict(zip(self.lenOpts,lengths)) - + def __str__(self): return self.name - + def trim(self): return Pattern.totalRollLength - sum([int(i)*int(self.lengthsdict[i]) for i in self.lengthsdict]) def masterSolve(Patterns, rollData, relax = True): - + # The rollData is made into separate dictionaries (rollDemand,surplusPrice) = splitDict(rollData) - + # The variable 'prob' is created prob = LpProblem("Cutting Stock Problem",LpMinimize) - + # vartype represents whether or not the variables are relaxed if relax: vartype = LpContinuous else: vartype = LpInteger - - # The problem variables are created + + # The problem variables are created pattVars = LpVariable.dicts("Pattern", Patterns, 0, None, vartype) surplusVars = LpVariable.dicts("Surplus", Pattern.lenOpts, 0, None, vartype) - + # The objective function is entered: (the total number of large rolls used * the cost of each) - # (the value of the surplus stock) - (the value of the trim) prob += lpSum([pattVars[i]*Pattern.cost for i in Patterns]) - lpSum([surplusVars[i]*surplusPrice[i]\ for i in Pattern.lenOpts]) - lpSum([pattVars[i]*i.trim()*Pattern.trimValue for i in Patterns]) - + # The demand minimum constraint is entered for j in Pattern.lenOpts: prob += lpSum([pattVars[i]*i.lengthsdict[j] for i in Patterns]) - surplusVars[j]>=rollDemand[j],"Min%s"%j - + # The problem is solved prob.solve() - + # The variable values are rounded prob.roundSolution() - + if relax: # Creates a dual variables list duals = {} for name,i in zip(['Min5','Min7','Min9'],Pattern.lenOpts): duals[i] = prob.constraints[name].pi - + return duals - + else: # Creates a dictionary of the variables and their values varsdict = {} for v in prob.variables(): varsdict[v.name] = v.varValue - + # The number of rolls of each length in each pattern is printed for i in Patterns: - print i, " = %s"%[i.lengthsdict[j] for j in Pattern.lenOpts] - + print(i, " = %s"%[i.lengthsdict[j] for j in Pattern.lenOpts]) + return value(prob.objective), varsdict - + def subSolve(Patterns, duals): - + # The variable 'prob' is created prob = LpProblem("SubProb",LpMinimize) - + # The problem variables are created vars = LpVariable.dicts("Roll Length", Pattern.lenOpts, 0, None, LpInteger) - + trim = LpVariable("Trim", 0 ,None,LpInteger) - + # The objective function is entered: the reduced cost of a new pattern prob += (Pattern.cost - Pattern.trimValue*trim) - lpSum([vars[i]*duals[i] for i in Pattern.lenOpts]), "Objective" - + # The conservation of length constraint is entered prob += lpSum([vars[i]*int(i) for i in Pattern.lenOpts]) + trim == Pattern.totalRollLength, "lengthEquate" - - # The problem is solved + + # The problem is solved prob.solve() - + # The variable values are rounded prob.roundSolution() - + # The new pattern is written to a dictionary varsdict = {} newPattern = {} diff --git a/examples/ComputerPlantProblem.py b/examples/ComputerPlantProblem.py index 6835208..6640434 100644 --- a/examples/ComputerPlantProblem.py +++ b/examples/ComputerPlantProblem.py @@ -81,11 +81,11 @@ prob.writeLP("ComputerPlantProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Costs = ", value(prob.objective) \ No newline at end of file +print("Total Costs = ", value(prob.objective)) \ No newline at end of file diff --git a/examples/SpongeRollProblem1.py b/examples/SpongeRollProblem1.py index b7bc1c7..acfa872 100644 --- a/examples/SpongeRollProblem1.py +++ b/examples/SpongeRollProblem1.py @@ -51,11 +51,11 @@ prob.writeLP("SpongeRollProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Production Costs = ", value(prob.objective) +print("Production Costs = ", value(prob.objective)) diff --git a/examples/SpongeRollProblem2.py b/examples/SpongeRollProblem2.py index f9ad2ab..5c68b7e 100644 --- a/examples/SpongeRollProblem2.py +++ b/examples/SpongeRollProblem2.py @@ -68,11 +68,11 @@ prob.writeLP("SpongeRollProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Production Costs = ", value(prob.objective) +print("Production Costs = ", value(prob.objective)) diff --git a/examples/SpongeRollProblem3.py b/examples/SpongeRollProblem3.py index e45d2fc..624320c 100644 --- a/examples/SpongeRollProblem3.py +++ b/examples/SpongeRollProblem3.py @@ -63,9 +63,9 @@ def makePatterns(totalRollLength,lenOpts): trim[name] = totalRollLength - ssum # The different cutting lengths are printed, and the number of each roll of that length in each # pattern is printed below. This is so the user can see what each pattern contains. - print "Lens: %s" %lenOpts + print("Lens: %s" %lenOpts) for name,pattern in zip(PatternNames,patterns): - print name + " = %s"%pattern + print(name + " = %s"%pattern) return (PatternNames,patterns,trim) @@ -125,11 +125,11 @@ prob.writeLP("SpongeRollProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Production Costs = ", value(prob.objective) +print("Production Costs = ", value(prob.objective)) diff --git a/examples/SpongeRollProblem4.py b/examples/SpongeRollProblem4.py index 7ab7d4c..e6eccc0 100644 --- a/examples/SpongeRollProblem4.py +++ b/examples/SpongeRollProblem4.py @@ -4,18 +4,18 @@ The Full Sponge Roll Problem using Classes for the PuLP Modeller Authors: Antony Phillips, Dr Stuart Mitchell 2007 """ -def calculatePatterns(totalRollLength,lenOpts,head): +def calculatePatterns(totalRollLength,lenOpts,head): """ Recursively calculates the list of options lists for a cutting stock problem. The input 'tlist' is a pointer, and will be the output of the function call. - + The inputs are: totalRollLength - the length of the roll lenOpts - a list of the sizes of remaining cutting options head - the current list that has been passed down though the recusion - + Returns the list of patterns - + Authors: Bojan Blazevic, Dr Stuart Mitchell 2007 """ if lenOpts: @@ -24,10 +24,10 @@ def calculatePatterns(totalRollLength,lenOpts,head): opt = lenOpts[0] for rep in range(int(totalRollLength/opt)+1): #reduce the length - l = totalRollLength - rep*opt + l = totalRollLength - rep*opt h = head[:] h.append(rep) - + patterns.extend(calculatePatterns(l, lenOpts[1:], h)) else: #end of the recursion @@ -37,33 +37,33 @@ def calculatePatterns(totalRollLength,lenOpts,head): def makePatterns(totalRollLength,lenOpts): """ Makes the different cutting patterns for a cutting stock problem. - + The inputs are: totalRollLength : the length of the roll lenOpts: a list of the sizes of cutting options as strings - + Authors: Antony Phillips, Dr Stuart Mitchell 2007 """ - + # calculatePatterns is called to create a list of the feasible cutting options in 'tlist' patternslist = calculatePatterns(totalRollLength,lenOpts,[]) - - # The list 'PatternNames' is created + + # The list 'PatternNames' is created PatternNames = [] for i in range(len(patternslist)): PatternNames += ["P"+str(i)] - + #Patterns = [0 for i in range(len(PatternNames))] - Patterns = [] - + Patterns = [] + for i,j in enumerate(PatternNames): Patterns += [Pattern(j, patternslist[i])] - + # The different cutting lengths are printed, and the number of each roll of that length in each # pattern is printed below. This is so the user can see what each pattern contains. - print "Lens: %s" %lenOpts + print("Lens: %s" %lenOpts) for i in Patterns: - print i, " = %s"%[i.lengthsdict[j] for j in lenOpts] + print(i, " = %s"%[i.lengthsdict[j] for j in lenOpts]) return Patterns @@ -76,18 +76,18 @@ class Pattern: trimValue = 0.04 totalRollLength = 20 lenOpts = [5, 7, 9] - + def __init__(self,name,lengths = None): - self.name = name + self.name = name self.lengthsdict = dict(zip(self.lenOpts,lengths)) - + def __str__(self): return self.name - + def trim(self): return Pattern.totalRollLength - sum([int(i)*self.lengthsdict[i] for i in self.lengthsdict]) - - + + # Import PuLP modeler functions from pulp import * @@ -97,7 +97,7 @@ rollData = {#Length Demand SalePrice 9: [300, 0.40]} # The pattern names and the patterns are created as lists, and the associated trim with each pattern -# is created as a dictionary. The inputs are the total roll length and the list (as integers) of +# is created as a dictionary. The inputs are the total roll length and the list (as integers) of # cutting options. Patterns = makePatterns(Pattern.totalRollLength,Pattern.lenOpts) @@ -119,7 +119,7 @@ prob += lpSum([pattVars[i]*Pattern.cost for i in Patterns]) - lpSum([surplusVars # The demand minimum constraint is entered for j in Pattern.lenOpts: prob += lpSum([pattVars[i]*i.lengthsdict[j] for i in Patterns]) - surplusVars[j] >= rollDemand[j],"Ensuring enough %s cm rolls"%j - + # The problem data is written to an .lp file prob.writeLP("SpongeRollProblem.lp") @@ -127,11 +127,11 @@ prob.writeLP("SpongeRollProblem.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Production Costs = ", value(prob.objective) +print("Production Costs = ", value(prob.objective)) diff --git a/examples/SpongeRollProblem5.py b/examples/SpongeRollProblem5.py index c4776f6..b64ec5d 100644 --- a/examples/SpongeRollProblem5.py +++ b/examples/SpongeRollProblem5.py @@ -37,7 +37,7 @@ while morePatterns == True: solution, varsdict = masterSolve(Patterns, rollData, relax = False) # Display Solution -for i,j in varsdict.items(): - print i, "=", j +for i,j in list(varsdict.items()): + print(i, "=", j) -print "objective = ", solution \ No newline at end of file +print("objective = ", solution) \ No newline at end of file diff --git a/examples/SpongeRollProblem6.py b/examples/SpongeRollProblem6.py index 21ed22f..1a39ec0 100644 --- a/examples/SpongeRollProblem6.py +++ b/examples/SpongeRollProblem6.py @@ -27,7 +27,7 @@ while newPatterns: solution, varsdict = masterSolve(prob,relax = False) # Display Solution -for i,j in varsdict.items(): - print i, "=", j +for i,j in list(varsdict.items()): + print(i, "=", j) -print "objective = ", solution \ No newline at end of file +print("objective = ", solution) \ No newline at end of file diff --git a/examples/Sudoku1.py b/examples/Sudoku1.py index 980debf..b28e7b6 100644 --- a/examples/Sudoku1.py +++ b/examples/Sudoku1.py @@ -84,7 +84,7 @@ prob.writeLP("Sudoku.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # A file called sudokuout.txt is created/overwritten for writing to sudokuout = open('sudokuout.txt','w') @@ -108,4 +108,4 @@ sudokuout.write("+-------+-------+-------+") sudokuout.close() # The location of the solution is give to the user -print "Solution Written to sudokuout.txt" +print("Solution Written to sudokuout.txt") diff --git a/examples/Sudoku2.py b/examples/Sudoku2.py index a9ef06e..202de02 100644 --- a/examples/Sudoku2.py +++ b/examples/Sudoku2.py @@ -85,7 +85,7 @@ sudokuout = open('sudokuout.txt','w') while True: prob.solve() # The status of the solution is printed to the screen - print "Status:", LpStatus[prob.status] + print("Status:", LpStatus[prob.status]) # The solution is printed if it was deemed "optimal" i.e met the constraints if LpStatus[prob.status] == "Optimal": # The solution is written to the sudokuout.txt file @@ -112,4 +112,4 @@ while True: sudokuout.close() # The location of the solutions is give to the user -print "Solutions Written to sudokuout.txt" +print("Solutions Written to sudokuout.txt") diff --git a/examples/WhiskasModel1.py b/examples/WhiskasModel1.py index 6911ca6..98ef582 100644 --- a/examples/WhiskasModel1.py +++ b/examples/WhiskasModel1.py @@ -31,11 +31,11 @@ prob.writeLP("WhiskasModel.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Cost of Ingredients per can = ", value(prob.objective) +print("Total Cost of Ingredients per can = ", value(prob.objective)) diff --git a/examples/WhiskasModel2.py b/examples/WhiskasModel2.py index 5517a5e..ab4641c 100644 --- a/examples/WhiskasModel2.py +++ b/examples/WhiskasModel2.py @@ -73,11 +73,11 @@ prob.writeLP("WhiskasModel2.lp") prob.solve() # The status of the solution is printed to the screen -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Each of the variables is printed with it's resolved optimum value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Cost of Ingredients per can = ", value(prob.objective) +print("Total Cost of Ingredients per can = ", value(prob.objective)) diff --git a/examples/furniture.py b/examples/furniture.py index 9e30255..0a3bfe5 100644 --- a/examples/furniture.py +++ b/examples/furniture.py @@ -26,6 +26,6 @@ prob.writeLP("furniture.lp") prob.solve() # Each of the variables is printed with it's value for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # The optimised objective function value is printed to the screen -print "Total Revenue from Production = ", value(prob.objective) \ No newline at end of file +print("Total Revenue from Production = ", value(prob.objective)) \ No newline at end of file diff --git a/examples/test1.py b/examples/test1.py index 6c57b88..3294997 100644 --- a/examples/test1.py +++ b/examples/test1.py @@ -42,11 +42,11 @@ prob.solve() # two paths may be provided (one to clp, one to cbc). # Print the status of the solved LP -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Print the value of the variables at the optimum for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # Print the value of the objective -print "objective=", value(prob.objective) +print("objective=", value(prob.objective)) diff --git a/examples/test2.py b/examples/test2.py index 66d3fa3..8c35fc1 100644 --- a/examples/test2.py +++ b/examples/test2.py @@ -19,7 +19,7 @@ n = 15 k = floor(log(n)/log(2)); # A vector of n binary variables -x = LpVariable.matrix("x", range(n), 0, 1, LpInteger) +x = LpVariable.matrix("x", list(range(n)), 0, 1, LpInteger) # A vector of weights a = [pow(2,k + n + 1) + pow(2,k + n + 1 - j) + 1 for j in range(1,n+1)] @@ -38,11 +38,11 @@ prob += weight <= b prob.solve() # Print the status of the solved LP -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Print the value of the variables at the optimum for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # Print the value of the objective -print "objective=", value(prob.objective) +print("objective=", value(prob.objective)) diff --git a/examples/test3.py b/examples/test3.py index 666871b..fc43cf8 100644 --- a/examples/test3.py +++ b/examples/test3.py @@ -29,11 +29,11 @@ hpmax = 100.0 sini = 50.0 # Time range -time = range(tmax) +time = list(range(tmax)) # Time range (and one more step for the last state of plants) -xtime = range(tmax+1) +xtime = list(range(tmax+1)) # Units range -unit = range(units) +unit = list(range(units)) # The demand demand = [dmin+(dmax-dmin)*0.5 + 0.5*(dmax-dmin)*sin(4*t*2*3.1415/tmax) for t in time] # Maximum output for the thermal units @@ -100,23 +100,23 @@ prob += ctp + cts # Solve the problem prob.solve() -print "Minimum total cost:", prob.objective.value() +print("Minimum total cost:", prob.objective.value()) # Print the results -print " D S U ", -for i in unit: print " T%d " %i, -print +print(" D S U ", end=' ') +for i in unit: print(" T%d " %i, end=' ') +print() for t in time: # Demand, hydro storage, hydro production - print "%5.1f" % demand[t], "%5.1f" % value(s[t]), "%5.1f" % value(ph[t]), + print("%5.1f" % demand[t], "%5.1f" % value(s[t]), "%5.1f" % value(ph[t]), end=' ') for i in unit: # Thermal production - print "%4.1f" % value(p[t][i]), + print("%4.1f" % value(p[t][i]), end=' ') # The state of the unit - if value(d[t][i]): print "+", - else: print "-", + if value(d[t][i]): print("+", end=' ') + else: print("-", end=' ') # Wether the unit will be started - if value(u[t][i]): print "*", - else: print " ", - print + if value(u[t][i]): print("*", end=' ') + else: print(" ", end=' ') + print() diff --git a/examples/test4.py b/examples/test4.py index b8a85c4..4885add 100644 --- a/examples/test4.py +++ b/examples/test4.py @@ -16,8 +16,8 @@ B = 500 # Resources available for the two years s = 20 # Number of scenarios n = 10 # Number of projects -N = range(n) -S = range(s) +N = list(range(n)) +S = list(range(s)) # First year costs c = [randint(0,C) for i in N] @@ -56,4 +56,4 @@ lp.solve() # Solution printing for i in N: - print x[i], "=", x[i].value() + print(x[i], "=", x[i].value()) diff --git a/examples/test5.py b/examples/test5.py index 51a2f46..cb9465d 100644 --- a/examples/test5.py +++ b/examples/test5.py @@ -25,11 +25,11 @@ D = 100 n = 10*(m-1) # A vector of n binary variables -x = LpVariable.matrix("x", range(n), 0, 1, LpInteger) +x = LpVariable.matrix("x", list(range(n)), 0, 1, LpInteger) # Slacks -s = LpVariable.matrix("s", range(m), 0) -w = LpVariable.matrix("w", range(m), 0) +s = LpVariable.matrix("s", list(range(m)), 0) +w = LpVariable.matrix("w", list(range(m)), 0) # Objective prob += lpSum(s) + lpSum(w) @@ -43,11 +43,11 @@ for j in range(m): prob.solve() # Print the status of the solved LP -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Print the value of the variables at the optimum for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # Print the value of the objective -print "objective=", value(prob.objective) +print("objective=", value(prob.objective)) diff --git a/examples/test6.py b/examples/test6.py index 467008f..c53a81c 100644 --- a/examples/test6.py +++ b/examples/test6.py @@ -51,11 +51,11 @@ prob.solve() # two paths may be provided (one to clp, one to cbc). # Print the status of the solved LP -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) # Print the value of the variables at the optimum for v in prob.variables(): - print v.name, "=", v.varValue + print(v.name, "=", v.varValue) # Print the value of the objective -print "objective=", value(prob.objective) \ No newline at end of file +print("objective=", value(prob.objective)) \ No newline at end of file diff --git a/examples/test7.py b/examples/test7.py index e03d4b7..7182ed2 100644 --- a/examples/test7.py +++ b/examples/test7.py @@ -23,13 +23,13 @@ prob.writeLP("test7.lp") prob.solve() -print "Status:", LpStatus[prob.status] +print("Status:", LpStatus[prob.status]) for v in prob.variables(): - print v.name, "=", v.varValue, "\tReduced Cost =", v.dj + print(v.name, "=", v.varValue, "\tReduced Cost =", v.dj) -print "objective=", value(prob.objective) +print("objective=", value(prob.objective)) -print "\nSensitivity Analysis\nConstraint\t\tShadow Price\tSlack" -for name, c in prob.constraints.items(): - print name, ":", c, "\t", c.pi, "\t\t", c.slack +print("\nSensitivity Analysis\nConstraint\t\tShadow Price\tSlack") +for name, c in list(prob.constraints.items()): + print(name, ":", c, "\t", c.pi, "\t\t", c.slack) diff --git a/examples/wedding.py b/examples/wedding.py index 7417b60..1327c33 100644 --- a/examples/wedding.py +++ b/examples/wedding.py @@ -42,9 +42,9 @@ for guest in guests: seating_model.solve() -print "The choosen tables are out of a total of %s:"%len(possible_tables) +print("The choosen tables are out of a total of %s:"%len(possible_tables)) for table in possible_tables: if x[table].value() == 1.0: - print table + print(table) diff --git a/ez_setup.py b/ez_setup.py index e14ac7e..0a8029d 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -13,6 +13,7 @@ the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ +from os import linesep import sys DEFAULT_VERSION = "0.6c11" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] @@ -70,10 +71,10 @@ def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: - print >>sys.stderr, ( + sys.stderr.write( "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) + % egg_name + linesep) + sys.stderr.write() sys.exit(2) return data @@ -103,14 +104,13 @@ def use_setuptools( return do_download() try: pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: + except pkg_resources.VersionConflict as e: if was_imported: - print >>sys.stderr, ( + sys.stderr.write( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." - "\n\n(Currently using %r)" - ) % (version, e.args[0]) + "\n\n(Currently using %r)" % (version, e.args[0]) + linesep) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok @@ -129,7 +129,7 @@ def download_setuptools( with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ - import urllib2, shutil + import urllib.request, urllib.error, urllib.parse, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) @@ -155,7 +155,7 @@ and place it in this directory before rerunning this script.) version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) - src = urllib2.urlopen(url) + src = urllib.request.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) @@ -216,10 +216,10 @@ def main(argv, version=DEFAULT_VERSION): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( + sys.stderr.write( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." - ) + + linesep) sys.exit(2) req = "setuptools>="+version @@ -238,8 +238,8 @@ def main(argv, version=DEFAULT_VERSION): from setuptools.command.easy_install import main main(argv) else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + print("Setuptools version",version,"or greater has been installed.") + print('(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)') def update_md5(filenames): """Update our built-in md5 registry""" @@ -252,7 +252,7 @@ def update_md5(filenames): md5_data[base] = md5(f.read()).hexdigest() f.close() - data = [" %r: %r,\n" % it for it in md5_data.items()] + data = [" %r: %r,\n" % it for it in list(md5_data.items())] data.sort() repl = "".join(data) @@ -262,7 +262,7 @@ def update_md5(filenames): match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: - print >>sys.stderr, "Internal error!" + sys.stderr.write("Internal error!" + linesep) sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] diff --git a/setup.py b/setup.py index 98af2e7..3ee2f2b 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ Setup script for PuLP added by Stuart Mitchell 2007 Copyright 2007 Stuart Mitchell """ +import sys from ez_setup import use_setuptools use_setuptools() from setuptools import setup @@ -13,6 +14,12 @@ License = open('LICENSE').read() Version = open('VERSION').read().strip() +#hack because pyparsing made version 2 python 3 specific +if sys.version_info[0] <= 2: + pyparsing_ver = 'pyparsing<=1.9.9' +else: + pyparsing_ver = 'pyparsing>=2.0.0' + setup(name="PuLP", version=Version, description=""" @@ -46,7 +53,7 @@ problems. "README.CoinMP.txt", ], 'pulp.solverdir' : ['*','*.*']}, - install_requires = ['pyparsing<=1.9.9'], + install_requires = [pyparsing_ver], entry_points = (""" [console_scripts] pulptest = pulp:pulpTestAll diff --git a/src/pulp/__init__.py b/src/pulp/__init__.py index a92374b..030f603 100644 --- a/src/pulp/__init__.py +++ b/src/pulp/__init__.py @@ -30,8 +30,10 @@ Module file that imports all of the pulp functions Copyright 2007- Stuart Mitchell (s.mitchell@auckland.ac.nz) """ -from pulp import * -from amply import * +VERSION = '1.5.5' + +from .pulp import * +from .amply import * __doc__ = pulp.__doc__ -import tests +from . import tests diff --git a/src/pulp/amply.py b/src/pulp/amply.py index b159419..85034d4 100644 --- a/src/pulp/amply.py +++ b/src/pulp/amply.py @@ -38,10 +38,10 @@ Usage: Symbols that are defined can be accessed as attributes or items. - >>> print a.T - 3 - >>> print a['T'] - 3 + >>> print(a.T) + 3.0 + >>> print(a['T']) + 3.0 The load_string and load_file methods can be used to parse additional data @@ -152,10 +152,10 @@ else: Transpose a matrix represented as a dict of dicts """ - rows = data.keys() + rows = list(data.keys()) cols = set() - for d in data.values(): - cols.update(d.keys()) + for d in list(data.values()): + cols.update(list(d.keys())) d = {} @@ -337,7 +337,7 @@ else: old = self.next try: - self.next = self.it.next() + self.next = next(self.it) except StopIteration: self.empty = True return old @@ -445,7 +445,7 @@ else: elif isinstance(record, TabularRecord): record_data = record.data() for row_symbol in record_data: - for col_symbol, value in record_data[row_symbol].items(): + for col_symbol, value in list(record_data[row_symbol].items()): self.setValue((row_symbol, col_symbol), _v(value)) def _setSlice(self, slice): diff --git a/src/pulp/pulp.py b/src/pulp/pulp.py index 0664bc2..0acc157 100755 --- a/src/pulp/pulp.py +++ b/src/pulp/pulp.py @@ -97,10 +97,15 @@ import types import string import itertools -from constants import * -from solvers import * +from .constants import * +from .solvers import * from types import GeneratorType +try: # allow Python 2/3 compatibility + maketrans = str.maketrans +except AttributeError: + from string import maketrans + _DICT_TYPE = dict if sys.platform not in ['cli']: @@ -151,7 +156,7 @@ class LpElement(object): """Base class for LpVariable and LpConstraintVar """ #to remove illegal characters from the names - trans = string.maketrans("-+[] ->/","________") + trans = maketrans("-+[] ->/","________") def setName(self,name): if name: self.__name = str(name).translate(self.trans) @@ -182,7 +187,7 @@ class LpElement(object): def __pos__(self): return self - def __nonzero__(self): + def __bool__(self): return 1 def __add__(self, other): @@ -207,7 +212,7 @@ class LpElement(object): return LpAffineExpression(self)/other def __rdiv__(self, other): - raise TypeError, "Expressions cannot be divided by a variable" + raise TypeError("Expressions cannot be divided by a variable") def __le__(self, other): return LpAffineExpression(self) <= other @@ -421,7 +426,7 @@ class LpVariable(LpElement): return True def infeasibilityGap(self, mip = 1): - if self.varValue == None: raise ValueError, "variable value is None" + if self.varValue == None: raise ValueError("variable value is None") if self.upBound != None and self.varValue > self.upBound: return self.varValue - self.upBound if self.lowBound != None and self.varValue < self.lowBound: @@ -512,7 +517,7 @@ class LpAffineExpression(_DICT_TYPE): 1*x_0 + -3*x_1 + 4*x_2 + 0 """ #to remove illegal characters from the names - trans = string.maketrans("-+[] ","_____") + trans = maketrans("-+[] ","_____") def setName(self,name): if name: self.__name = str(name).translate(self.trans) @@ -532,10 +537,10 @@ class LpAffineExpression(_DICT_TYPE): if isinstance(e, LpAffineExpression): # Will not copy the name self.constant = e.constant - super(LpAffineExpression, self).__init__(e.items()) + super(LpAffineExpression, self).__init__(list(e.items())) elif isinstance(e, dict): self.constant = constant - super(LpAffineExpression, self).__init__(e.items()) + super(LpAffineExpression, self).__init__(list(e.items())) elif isinstance(e, list) or isinstance(e, GeneratorType): self.constant = constant super(LpAffineExpression, self).__init__(e) @@ -549,22 +554,22 @@ class LpAffineExpression(_DICT_TYPE): # Proxy functions for variables def isAtomic(self): - return len(self) == 1 and self.constant == 0 and self.values()[0] == 1 + return len(self) == 1 and self.constant == 0 and list(self.values())[0] == 1 def isNumericalConstant(self): return len(self) == 0 def atom(self): - return self.keys()[0] + return list(self.keys())[0] # Functions on expressions - def __nonzero__(self): - return float(self.constant) != 0 or len(self) + def __bool__(self): + return (float(self.constant) != 0.0) or (len(self) > 0) def value(self): s = self.constant - for v,x in self.iteritems(): + for v,x in self.items(): if v.varValue is None: return None s += v.varValue * x @@ -572,7 +577,7 @@ class LpAffineExpression(_DICT_TYPE): def valueOrDefault(self): s = self.constant - for v,x in self.iteritems(): + for v,x in self.items(): s += v.valueOrDefault() * x return s @@ -699,10 +704,10 @@ class LpAffineExpression(_DICT_TYPE): self.addInPlace(e) elif isinstance(other,LpAffineExpression): self.constant += other.constant - for v,x in other.iteritems(): + for v,x in other.items(): self.addterm(v, x) elif isinstance(other,dict): - for e in other.itervalues(): + for e in other.values(): self.addInPlace(e) else: self.constant += other @@ -719,10 +724,10 @@ class LpAffineExpression(_DICT_TYPE): self.subInPlace(e) elif isinstance(other,LpAffineExpression): self.constant -= other.constant - for v,x in other.iteritems(): + for v,x in other.items(): self.addterm(v, -x) elif isinstance(other,dict): - for e in other.itervalues(): + for e in other.values(): self.subInPlace(e) else: self.constant -= other @@ -731,7 +736,7 @@ class LpAffineExpression(_DICT_TYPE): def __neg__(self): e = self.emptyCopy() e.constant = - self.constant - for v,x in self.iteritems(): + for v,x in self.items(): e[v] = - x return e @@ -756,23 +761,23 @@ class LpAffineExpression(_DICT_TYPE): e.constant = self.constant * other.constant if len(other): if len(self): - raise TypeError, "Non-constant expressions cannot be multiplied" + raise TypeError("Non-constant expressions cannot be multiplied") else: c = self.constant if c != 0: - for v,x in other.iteritems(): + for v,x in other.items(): e[v] = c * x else: c = other.constant if c != 0: - for v,x in self.iteritems(): + for v,x in self.items(): e[v] = c * x elif isinstance(other,LpVariable): return self * LpAffineExpression(other) else: if other != 0: e.constant = self.constant * other - for v,x in self.iteritems(): + for v,x in self.items(): e[v] = other * x return e @@ -782,22 +787,22 @@ class LpAffineExpression(_DICT_TYPE): def __div__(self, other): if isinstance(other,LpAffineExpression) or isinstance(other,LpVariable): if len(other): - raise TypeError, "Expressions cannot be divided by a non-constant expression" + raise TypeError("Expressions cannot be divided by a non-constant expression") other = other.constant e = self.emptyCopy() e.constant = self.constant / other - for v,x in self.iteritems(): + for v,x in self.items(): e[v] = x / other return e def __rdiv__(self, other): e = self.emptyCopy() if len(self): - raise TypeError, "Expressions cannot be divided by a non-constant expression" + raise TypeError("Expressions cannot be divided by a non-constant expression") c = self.constant if isinstance(other,LpAffineExpression): e.constant = other.constant / c - for v,x in other.iteritems(): + for v,x in other.items(): e[v] = x / c else: e.constant = other / c @@ -855,7 +860,7 @@ class LpConstraint(LpAffineExpression): Returns a constraint as a string """ result, line = self.asCplexVariablesOnly(name) - if not self.keys(): + if not list(self.keys()): line += ["0"] c = -self.constant if c == 0: @@ -1109,7 +1114,7 @@ class LpProblem(object): if self.constraints: string += "SUBJECT TO\n" - for n, c in self.constraints.iteritems(): + for n, c in self.constraints.items(): string += c.asCplexLpConstraint(n) +"\n" string += "VARIABLES\n" for v in self.variables(): @@ -1131,7 +1136,7 @@ class LpProblem(object): if lpcopy.objective is not None: lpcopy.objective = self.objective.copy() lpcopy.constraints = {} - for k,v in self.constraints.iteritems(): + for k,v in self.constraints.items(): lpcopy.constraints[k] = v.copy() lpcopy.sos1 = self.sos1.copy() lpcopy.sos2 = self.sos2.copy() @@ -1179,7 +1184,7 @@ class LpProblem(object): def valid(self, eps = 0): for v in self.variables(): if not v.valid(eps): return False - for c in self.constraints.itervalues(): + for c in self.constraints.values(): if not c.valid(eps): return False else: return True @@ -1188,7 +1193,7 @@ class LpProblem(object): gap = 0 for v in self.variables(): gap = max(abs(v.infeasibilityGap(mip)), gap) - for c in self.constraints.itervalues(): + for c in self.constraints.values(): if not c.valid(0): gap = max(abs(c.value()), gap) return gap @@ -1223,9 +1228,9 @@ class LpProblem(object): - A list of the problem variables """ if self.objective: - self.addVariables(self.objective.keys()) - for c in self.constraints.itervalues(): - self.addVariables(c.keys()) + self.addVariables(list(self.objective.keys())) + for c in self.constraints.values(): + self.addVariables(list(c.keys())) variables = self._variables #sort the varibles DSU variables = [[v.name, v] for v in variables] @@ -1238,7 +1243,7 @@ class LpProblem(object): if self.objective: for v in self.objective: variables[v.name] = v - for c in self.constraints.values(): + for c in list(self.constraints.values()): for v in c: variables[v.name] = v return variables @@ -1248,7 +1253,7 @@ class LpProblem(object): def addConstraint(self, constraint, name = None): if not isinstance(constraint, LpConstraint): - raise TypeError, "Can only add LpConstraint objects" + raise TypeError("Can only add LpConstraint objects") if name: constraint.name = name try: @@ -1257,19 +1262,19 @@ class LpProblem(object): else: name = self.unusedConstraintName() except AttributeError: - raise TypeError, "Can only add LpConstraint objects" + raise TypeError("Can only add LpConstraint objects") #removed as this test fails for empty constraints # if len(constraint) == 0: # if not constraint.valid(): # raise ValueError, "Cannot add false constraints" if name in self.constraints: if self.noOverlap: - raise PulpError, "overlapping constraint names: " + name + raise PulpError("overlapping constraint names: " + name) else: - print "Warning: overlapping constraint names:", name + print("Warning: overlapping constraint names:", name) self.constraints[name] = constraint self.modifiedConstraints.append(constraint) - self.addVariables(constraint.keys()) + self.addVariables(list(constraint.keys())) def setObjective(self,obj): """ @@ -1310,7 +1315,7 @@ class LpProblem(object): self.objective = LpAffineExpression(other) self.objective.name = name else: - raise TypeError, "Can only add LpConstraintVar, LpConstraint, LpAffineExpression or True objects" + raise TypeError("Can only add LpConstraintVar, LpConstraint, LpAffineExpression or True objects") return self def extend(self, other, use_objective = True): @@ -1332,7 +1337,7 @@ class LpProblem(object): elif isinstance(other, LpProblem): for v in set(other.variables()).difference(self.variables()): v.name = other.name + v.name - for name,c in other.constraints.iteritems(): + for name,c in other.constraints.items(): c.name = other.name + name self.addConstraint(c) if use_objective: @@ -1363,7 +1368,7 @@ class LpProblem(object): def writeMPS(self, filename, mpsSense = 0, rename = 0, mip = 1): wasNone, dummyVar = self.fixObjective() - f = file(filename, "w") + f = open(filename, "w") if mpsSense == 0: mpsSense = self.sense cobj = self.objective if mpsSense != self.sense: @@ -1383,7 +1388,7 @@ class LpProblem(object): if not objName: objName = "OBJ" f.write(" N %s\n" % objName) mpsConstraintType = {LpConstraintLE:"L", LpConstraintEQ:"E", LpConstraintGE:"G"} - for k,c in self.constraints.iteritems(): + for k,c in self.constraints.items(): if rename: k = constraintsNames[k] f.write(" "+mpsConstraintType[c.sense]+" "+k+"\n") # matrix @@ -1391,7 +1396,7 @@ class LpProblem(object): # Creation of a dict of dict: # coefs[nomVariable][nomContrainte] = coefficient coefs = {} - for k,c in self.constraints.iteritems(): + for k,c in self.constraints.items(): if rename: k = constraintsNames[k] for v in c: n = v.name @@ -1417,7 +1422,7 @@ class LpProblem(object): f.write(" MARK 'MARKER' 'INTEND'\n") # right hand side f.write("RHS\n") - for k,c in self.constraints.iteritems(): + for k,c in self.constraints.items(): c = -c.constant if rename: k = constraintsNames[k] if c == 0: c = 0 @@ -1466,7 +1471,7 @@ class LpProblem(object): Side Effects: - The file is created. """ - f = file(filename, "w") + f = open(filename, "w") f.write("\\* "+self.name+" *\\\n") if self.sense == 1: f.write("Minimize\n") @@ -1477,11 +1482,11 @@ class LpProblem(object): if not objName: objName = "OBJ" f.write(self.objective.asCplexLpAffineExpression(objName, constant = 0)) f.write("Subject To\n") - ks = self.constraints.keys() + ks = list(self.constraints.keys()) ks.sort() for k in ks: constraint = self.constraints[k] - if not constraint.keys(): + if not list(constraint.keys()): #empty constraint add the dummyVar constraint += self.get_dummyVar() f.write(constraint.asCplexLpConstraint(k)) @@ -1495,7 +1500,7 @@ class LpProblem(object): repeated_names = {} for v in vs: repeated_names[v.name] = repeated_names.get(v.name, 0) + 1 - repeated_names = [(key, value) for key, value in repeated_names.items() + repeated_names = [(key, value) for key, value in list(repeated_names.items()) if value >= 2] if repeated_names: raise PulpError('Repeated variable names in Lp format\n' @@ -1527,14 +1532,14 @@ class LpProblem(object): if writeSOS and (self.sos1 or self.sos2): f.write("SOS\n") if self.sos1: - for sos in self.sos1.itervalues(): + for sos in self.sos1.values(): f.write("S1:: \n") - for v,val in sos.iteritems(): + for v,val in sos.items(): f.write(" %s: %.12g\n" % (v.name, val)) if self.sos2: - for sos in self.sos2.itervalues(): + for sos in self.sos2.values(): f.write("S2:: \n") - for v,val in sos.iteritems(): + for v,val in sos.items(): f.write(" %s: %.12g\n" % (v.name, val)) f.write("End\n") f.close() @@ -1830,7 +1835,7 @@ class FractionElasticSubProblem(FixedElasticSubProblem): self.denominator = denominator self.complement = denominator - numerator else: - raise PulpError, 'only one of denominator and complement must be specified' + raise PulpError('only one of denominator and complement must be specified') self.RHS = RHS self.lowTarget = self.upTarget = None LpProblem.__init__(self, subProblemName, LpMinimize) @@ -1972,7 +1977,7 @@ def combination(orgset, k = None): >>> c = combination([1,2,3,4],2) >>> for s in c: - ... print s + ... print(s) (1, 2) (1, 3) (1, 4) @@ -2014,7 +2019,7 @@ def permutation(orgset, k = None): >>> c = permutation([1,2,3,4],2) >>> for s in c: - ... print s + ... print(s) (1, 2) (1, 3) (1, 4) @@ -2061,7 +2066,7 @@ def allpermutations(orgset,k): >>> c = allpermutations([1,2,3,4],2) >>> for s in c: - ... print s + ... print(s) (1,) (2,) (3,) @@ -2094,7 +2099,7 @@ def allcombinations(orgset,k): >>> c = allcombinations([1,2,3,4],2) >>> for s in c: - ... print s + ... print(s) (1,) (2,) (3,) @@ -2203,18 +2208,18 @@ def configSolvers(): """ configlist = [(cplex_dll_path,"cplexpath","CPLEX: "), (coinMP_path, "coinmppath","CoinMP dll (windows only): ")] - print ("Please type the full path including filename and extension \n" + + print("Please type the full path including filename and extension \n" + "for each solver available") configdict = {} for (default, key, msg) in configlist: - value = raw_input(msg + "[" + str(default) +"]") + value = input(msg + "[" + str(default) +"]") if value: configdict[key] = value setConfigInformation(**configdict) def pulpTestAll(): - from tests import pulpTestSolver + from .tests import pulpTestSolver solvers = [PULP_CBC_CMD, CPLEX_DLL, CPLEX_CMD, @@ -2231,14 +2236,14 @@ def pulpTestAll(): for s in solvers: if s().available(): - #~ try: + try: pulpTestSolver(s) - print "* Solver", s, "passed." - #~ except Exception, e: - #~ print e - #~ print "* Solver", s, "failed." + print("* Solver %s passed." % s) + except Exception as e: + print(e) + print("* Solver", s, "failed.") else: - print "Solver", s, "unavailable." + print("Solver %s unavailable" % s) def pulpDoctest(): """ @@ -2246,7 +2251,7 @@ def pulpDoctest(): """ import doctest if __name__ != '__main__': - import pulp + from . import pulp doctest.testmod(pulp) else: doctest.testmod() diff --git a/src/pulp/solvers.py b/src/pulp/solvers.py index 724ba08..7d2cbbd 100644 --- a/src/pulp/solvers.py +++ b/src/pulp/solvers.py @@ -34,12 +34,15 @@ import os import subprocess import sys from time import clock -import ConfigParser -import sparse +try: + import configparser +except ImportError: + import ConfigParser as configparser +from . import sparse import collections import warnings from tempfile import mktemp -from constants import * +from .constants import * import logging log = logging.getLogger(__name__) @@ -54,42 +57,46 @@ class PulpSolverError(PulpError): def initialize(filename): """ reads the configuration file to initialise the module""" here = os.path.dirname(filename) - config = ConfigParser.SafeConfigParser({'here':here}) + config = configparser.SafeConfigParser({'here':here}) config.read(filename) try: cplex_dll_path = config.get("locations", "CplexPath") - except ConfigParser.Error: + except configparser.Error: cplex_dll_path = 'libcplex110.so' try: - ilm_cplex_license = config.get("licenses", + try: + ilm_cplex_license = config.get("licenses", "ilm_cplex_license").decode("string-escape").replace('"','') - except ConfigParser.Error: + except AttributeError: + ilm_cplex_license = config.get("licenses", + "ilm_cplex_license").replace('"','') + except configparser.Error: ilm_cplex_license = '' try: ilm_cplex_license_signature = config.getint("licenses", "ilm_cplex_license_signature") - except ConfigParser.Error: + except configparser.Error: ilm_cplex_license_signature = 0 try: coinMP_path = config.get("locations", "CoinMPPath").split(', ') - except ConfigParser.Error: + except configparser.Error: coinMP_path = ['libCoinMP.so'] try: gurobi_path = config.get("locations", "GurobiPath") - except ConfigParser.Error: + except configparser.Error: gurobi_path = '/opt/gurobi201/linux32/lib/python2.5' try: cbc_path = config.get("locations", "CbcPath") - except ConfigParser.Error: + except configparser.Error: cbc_path = 'cbc' try: glpk_path = config.get("locations", "GlpkPath") - except ConfigParser.Error: + except configparser.Error: glpk_path = 'glpsol' try: pulp_cbc_path = config.get("locations", "PulpCbcPath") - except ConfigParser.Error: + except configparser.Error: pulp_cbc_path = 'cbc' for i,path in enumerate(coinMP_path): if not os.path.dirname(path): @@ -112,7 +119,7 @@ if __name__ != '__main__': config_filename = os.path.join(DIRNAME, PULPCFGFILE) else: #run as a script - from pulp import __file__ as fname + from .pulp import __file__ as fname DIRNAME = os.path.dirname(fname) config_filename = os.path.join(DIRNAME, PULPCFGFILE) @@ -185,7 +192,7 @@ class LpSolver: NumVarDoubleArray = ctypes.c_double * numVars objectCoeffs=NumVarDoubleArray() #print "Get objective Values" - for v,val in lp.objective.iteritems(): + for v,val in lp.objective.items(): objectCoeffs[self.v2n[v]]=val #values for variables objectConst = ctypes.c_double(0.0) @@ -228,7 +235,7 @@ class LpSolver: i = i+1 #return the coefficient matrix as a series of vectors coeffs = lp.coefficients() - sparseMatrix = sparse.Matrix(range(numRows), range(numVars)) + sparseMatrix = sparse.Matrix(list(range(numRows)), list(range(numVars))) for var,row,coeff in coeffs: sparseMatrix.add(self.c2n[row], self.vname2n[var], coeff) (numels, mystartsBase, mylenBase, myindBase, @@ -325,7 +332,7 @@ class GLPK_CMD(LpSolver_CMD): def actualSolve(self, lp): """Solve a well formulated lp problem""" if not self.executable(self.path): - raise PulpSolverError, "PuLP: cannot execute "+self.path + raise PulpSolverError("PuLP: cannot execute "+self.path) if not self.keepFiles: pid = os.getpid() tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid) @@ -345,18 +352,18 @@ class GLPK_CMD(LpSolver_CMD): rc = subprocess.call(proc, stdout = pipe, stderr = pipe) if rc: - raise PulpSolverError, "PuLP: Error while trying to execute "+self.path + raise PulpSolverError("PuLP: Error while trying to execute "+self.path) else: if os.name != 'nt': rc = os.spawnvp(os.P_WAIT, self.path, proc) else: rc = os.spawnv(os.P_WAIT, self.executable(self.path), proc) if rc == 127: - raise PulpSolverError, "PuLP: Error while trying to execute "+self.path + raise PulpSolverError("PuLP: Error while trying to execute "+self.path) self.solution_time += clock() if not os.path.exists(tmpSol): - raise PulpSolverError, "PuLP: Error while executing "+self.path + raise PulpSolverError("PuLP: Error while executing "+self.path) lp.status, values = self.readsol(tmpSol) lp.assignVarsVals(values) if not self.keepFiles: @@ -368,7 +375,7 @@ class GLPK_CMD(LpSolver_CMD): def readsol(self,filename): """Read a GLPK solution file""" - f = file(filename) + f = open(filename) f.readline() rows = int(f.readline().split()[1]) cols = int(f.readline().split()[1]) @@ -386,7 +393,7 @@ class GLPK_CMD(LpSolver_CMD): } #print "statusString ",statusString if statusString not in glpkStatus: - raise PulpSolverError, "Unknown status returned by GLPK" + raise PulpSolverError("Unknown status returned by GLPK") status = glpkStatus[statusString] isInteger = statusString in ["INTEGER NON-OPTIMAL","INTEGER OPTIMAL","INTEGER UNDEFINED"] values = {} @@ -421,7 +428,7 @@ class CPLEX_CMD(LpSolver_CMD): def actualSolve(self, lp): """Solve a well formulated lp problem""" if not self.executable(self.path): - raise PulpSolverError, "PuLP: cannot execute "+self.path + raise PulpSolverError("PuLP: cannot execute "+self.path) if not self.keepFiles: pid = os.getpid() tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid) @@ -452,7 +459,7 @@ class CPLEX_CMD(LpSolver_CMD): cplex_cmds += "quit\n" cplex.communicate(cplex_cmds) if cplex.returncode != 0: - raise PulpSolverError, "PuLP: Error while trying to execute "+self.path + raise PulpSolverError("PuLP: Error while trying to execute "+self.path) if not self.keepFiles: try: os.remove(tmpLp) except: pass @@ -486,7 +493,7 @@ class CPLEX_CMD(LpSolver_CMD): "optimal":LpStatusOptimal, } if statusString not in cplexStatus: - raise PulpSolverError, "Unknown status returned by CPLEX: "+statusString + raise PulpSolverError("Unknown status returned by CPLEX: "+statusString) status = cplexStatus[statusString] shadowPrices = {} @@ -638,13 +645,13 @@ try: status = CPLEX_DLL.lib.CPXgetobjval(self.env, self.hprob, byref(objectiveValue)) if status != 0 and status != 1217: #no solution exists - raise PulpSolverError, ("Error in CPXgetobjval status=" + raise PulpSolverError("Error in CPXgetobjval status=" + str(status)) status = CPLEX_DLL.lib.CPXgetx(self.env, self.hprob, byref(x), 0, numcols - 1) if status != 0 and status != 1217: - raise PulpSolverError, "Error in CPXgetx status=" + str(status) + raise PulpSolverError("Error in CPXgetx status=" + str(status)) else: status = CPLEX_DLL.lib.CPXsolution(self.env, self.hprob, byref(solutionStatus), @@ -676,7 +683,7 @@ try: lp.assignConsSlack(constraintslackvalues) #TODO: clear up the name of self.n2c if self.msg: - print "Cplex status=", solutionStatus.value + print("Cplex status=", solutionStatus.value) lp.resolveOK = True for var in lp.variables(): var.isModified = False @@ -710,14 +717,14 @@ try: # has another license. Let us forgive bad user # configuration: if not (runtime_status == 0) and self.msg: - print ( + print( "CPLEX library failed to load the runtime license" + "the call returned status=%s" % str(runtime_status) + "Please check the pulp config file.") self.env = CPLEX_DLL.lib.CPXopenCPLEX(ctypes.byref(status)) self.hprob = None if not(status.value == 0): - raise PulpSolverError, ("CPLEX library failed on " + + raise PulpSolverError("CPLEX library failed on " + "CPXopenCPLEX status=" + str(status)) @@ -727,7 +734,7 @@ try: status=CPLEX_DLL.lib.CPXcloseCPLEX(self.env) self.env = self.hprob = None else: - raise PulpSolverError, "No CPLEX enviroment to close" + raise PulpSolverError("No CPLEX enviroment to close") def callSolver(self, isMIP): """Solves the problem with cplex @@ -737,12 +744,12 @@ try: if isMIP and self.mip: status= CPLEX_DLL.lib.CPXmipopt(self.env, self.hprob) if status != 0: - raise PulpSolverError, ("Error in CPXmipopt status=" + raise PulpSolverError("Error in CPXmipopt status=" + str(status)) else: status = CPLEX_DLL.lib.CPXlpopt(self.env, self.hprob) if status != 0: - raise PulpSolverError, ("Error in CPXlpopt status=" + raise PulpSolverError("Error in CPXlpopt status=" + str(status)) self.cplexTime += clock() @@ -756,7 +763,7 @@ try: self.hprob = CPLEX_DLL.lib.CPXcreateprob(self.env, byref(status), lp.name) if status.value != 0: - raise PulpSolverError, ("Error in CPXcreateprob status=" + raise PulpSolverError("Error in CPXcreateprob status=" + str(status)) (numcols, numrows, numels, rangeCount, objSense, obj, objconst, @@ -768,14 +775,14 @@ try: objSense, obj, rhs, rowSense, matbeg, matcnt, matind, matval, lb, ub, None, colname, rowname) if status.value != 0: - raise PulpSolverError, ("Error in CPXcopylpwnames status=" + + raise PulpSolverError("Error in CPXcopylpwnames status=" + str(status)) if lp.isMIP() and self.mip: status.value = CPLEX_DLL.lib.CPXcopyctype(self.env, self.hprob, xctype) if status.value != 0: - raise PulpSolverError, ("Error in CPXcopyctype status=" + + raise PulpSolverError("Error in CPXcopyctype status=" + str(status)) #set the initial solution self.callSolver(lp.isMIP()) @@ -867,9 +874,9 @@ try: #return the coefficient matrix as a series of vectors myobjectCoeffs = {} numRows = len(lp.constraints) - sparseMatrix = sparse.Matrix(range(numRows), range(numVars)) + sparseMatrix = sparse.Matrix(list(range(numRows)), list(range(numVars))) for var in vars: - for row,coeff in var.expression.iteritems(): + for row,coeff in var.expression.items(): if row.name == lp.objective.name: myobjectCoeffs[var] = coeff else: @@ -911,8 +918,8 @@ try: v2n = self.v2n else: v2n = dict((v, self.v2n[v]) for v in vars) - ifirst = min(v2n.itervalues()) - ilast = max(v2n.itervalues()) + ifirst = min(v2n.values()) + ilast = max(v2n.values()) row_t = ctypes.c_double * (ilast - ifirst + 1) lo = row_t() @@ -921,10 +928,10 @@ try: status.value = CPLEX_DLL.lib.CPXobjsa(self.env, self.hprob, ifirst, ilast, lo, hi) if status.value != 0: - raise PulpSolverError, ("Error in CPXobjsa, status=" + raise PulpSolverError("Error in CPXobjsa, status=" + str(status)) return dict((v, (lo[i - ifirst], hi[i - ifirst])) - for v, i in v2n.iteritems()) + for v, i in v2n.items()) @@ -937,7 +944,7 @@ except (ImportError,OSError): return False def actualSolve(self, lp): """Solve a well formulated lp problem""" - raise PulpSolverError, "CPLEX_DLL: Not Available" + raise PulpSolverError("CPLEX_DLL: Not Available") CPLEX = CPLEX_CMD try: @@ -950,7 +957,7 @@ except (ImportError): return False def actualSolve(self, lp): """Solve a well formulated lp problem""" - raise PulpSolverError, "CPLEX_PY: Not Available" + raise PulpSolverError("CPLEX_PY: Not Available") else: class CPLEX_PY(LpSolver): """ @@ -1071,7 +1078,7 @@ else: #if the constraint is empty rows.append(([],[])) else: - rows.append(zip(*expr)) + rows.append(list(zip(*expr))) if constraint.sense == LpConstraintLE: senses.append('L') elif constraint.sense == LpConstraintGE: @@ -1079,7 +1086,7 @@ else: elif constraint.sense == LpConstraintEQ: senses.append('E') else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') rownames.append(name) rhs.append(float(-constraint.constant)) lp.solverModel.linear_constraints.add(lin_expr=rows, senses=senses, @@ -1148,7 +1155,7 @@ else: #put pi and slack variables against the constraints #TODO: clear up the name of self.n2c if self.msg: - print "Cplex status=", lp.cplex_status + print("Cplex status=", lp.cplex_status) lp.resolveOK = True for var in lp.variables(): var.isModified = False @@ -1175,7 +1182,7 @@ class XPRESS(LpSolver_CMD): def actualSolve(self, lp): """Solve a well formulated lp problem""" if not self.executable(self.path): - raise PulpSolverError, "PuLP: cannot execute "+self.path + raise PulpSolverError("PuLP: cannot execute "+self.path) if not self.keepFiles: pid = os.getpid() tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid) @@ -1198,7 +1205,7 @@ class XPRESS(LpSolver_CMD): xpress.write("WRITEPRTSOL "+tmpSol+"\n") xpress.write("QUIT\n") if xpress.close() != None: - raise PulpSolverError, "PuLP: Error while executing "+self.path + raise PulpSolverError("PuLP: Error while executing "+self.path) status, values = self.readsol(tmpSol) if not self.keepFiles: try: os.remove(tmpLp) @@ -1213,7 +1220,7 @@ class XPRESS(LpSolver_CMD): def readsol(self,filename): """Read an XPRESS solution file""" - f = file(filename) + f = open(filename) for i in range(6): f.readline() l = f.readline().split() @@ -1225,7 +1232,7 @@ class XPRESS(LpSolver_CMD): "Optimal":LpStatusOptimal, } if statusString not in xpressStatus: - raise PulpSolverError, "Unknow status returned by XPRESS: "+statusString + raise PulpSolverError("Unknow status returned by XPRESS: "+statusString) status = xpressStatus[statusString] values = {} while 1: @@ -1282,8 +1289,8 @@ class COIN_CMD(LpSolver_CMD): def solve_CBC(self, lp, use_mps=True): """Solve a MIP problem using CBC""" if not self.executable(self.path): - raise PulpSolverError, "Pulp: cannot execute %s cwd: %s"%(self.path, - os.getcwd()) + raise PulpSolverError("Pulp: cannot execute %s cwd: %s"%(self.path, + os.getcwd())) if not self.keepFiles: pid = os.getpid() tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid) @@ -1333,10 +1340,10 @@ class COIN_CMD(LpSolver_CMD): cbc = subprocess.Popen((self.path + cmds).split(), stdout = pipe, stderr = pipe) if cbc.wait() != 0: - raise PulpSolverError, "Pulp: Error while trying to execute " + \ - self.path + raise PulpSolverError("Pulp: Error while trying to execute " + \ + self.path) if not os.path.exists(tmpSol): - raise PulpSolverError, "Pulp: Error while executing "+self.path + raise PulpSolverError("Pulp: Error while executing "+self.path) if use_mps: lp.status, values, reducedCosts, shadowPrices, slacks = self.readsol_MPS( tmpSol, lp, lp.variables(), @@ -1367,10 +1374,10 @@ class COIN_CMD(LpSolver_CMD): values = {} reverseVn = {} - for k, n in variablesNames.iteritems(): + for k, n in variablesNames.items(): reverseVn[n] = k reverseCn = {} - for k, n in constraintsNames.iteritems(): + for k, n in constraintsNames.items(): reverseCn[n] = k @@ -1384,7 +1391,7 @@ class COIN_CMD(LpSolver_CMD): 'Infeasible': LpStatusInfeasible, 'Unbounded': LpStatusUnbounded, 'Stopped': LpStatusNotSolved} - f = file(filename) + f = open(filename) statusstr = f.readline().split()[0] status = cbcStatus.get(statusstr, LpStatusUndefined) for l in f: @@ -1416,7 +1423,7 @@ class COIN_CMD(LpSolver_CMD): 'Infeasible': LpStatusInfeasible, 'Unbounded': LpStatusUnbounded, 'Stopped': LpStatusNotSolved} - f = file(filename) + f = open(filename) statusstr = f.readline().split()[0] status = cbcStatus.get(statusstr, LpStatusUndefined) for l in f: @@ -1458,7 +1465,7 @@ class PULP_CBC_CMD(COIN_CMD): return False def actualSolve(self, lp, callback = None): """Solve a well formulated lp problem""" - raise PulpSolverError, "PULP_CBC_CMD: Not Available (check permissions on %s)" % self.arch_pulp_cbc_path + raise PulpSolverError("PULP_CBC_CMD: Not Available (check permissions on %s)" % self.arch_pulp_cbc_path) else: def __init__(self, path=None, *args, **kwargs): """ @@ -1501,7 +1508,7 @@ class COINMP_DLL(LpSolver): return False def actualSolve(self, lp): """Solve a well formulated lp problem""" - raise PulpSolverError, "COINMP_DLL: Not Available" + raise PulpSolverError("COINMP_DLL: Not Available") else: COIN_INT_LOGLEVEL = 7 COIN_REAL_MAXSECONDS = 16 @@ -1584,7 +1591,7 @@ class COINMP_DLL(LpSolver): ctypes.c_double(self.fracGap)) #CoinGetInfinity is needed for varibles with no bounds coinDblMax = self.lib.CoinGetInfinity() - if self.debug: print "Before getCoinMPArrays" + if self.debug: print("Before getCoinMPArrays") (numVars, numRows, numels, rangeCount, objectSense, objectCoeffs, objectConst, rhsValues, rangeValues, rowType, startsBase, @@ -1606,7 +1613,7 @@ class COINMP_DLL(LpSolver): savestdout = os.dup(1) os.close(1) if os.dup(tempfile.fileno()) != 1: - raise PulpSolverError, "couldn't redirect stdout - dup() error" + raise PulpSolverError("couldn't redirect stdout - dup() error") self.coinTime = -clock() self.lib.CoinOptimizeProblem(hProb, 0); self.coinTime += clock() @@ -1689,7 +1696,7 @@ class GUROBI(LpSolver): return False def actualSolve(self, lp, callback = None): """Solve a well formulated lp problem""" - raise PulpSolverError, "GUROBI: Not Available" + raise PulpSolverError("GUROBI: Not Available") else: def __init__(self, mip = True, @@ -1751,7 +1758,7 @@ class GUROBI(LpSolver): except gurobipy.GurobiError: pass if self.msg: - print "Gurobi status=", solutionStatus + print("Gurobi status=", solutionStatus) lp.resolveOK = True for var in lp.variables(): var.isModified = False @@ -1802,7 +1809,7 @@ class GUROBI(LpSolver): log.debug("add the Constraints to the problem") for name,constraint in lp.constraints.items(): #build the expression - expr = gurobipy.LinExpr(constraint.values(), + expr = gurobipy.LinExpr(list(constraint.values()), [v.solverVar for v in constraint.keys()]) if constraint.sense == LpConstraintLE: relation = gurobipy.GRB.LESS_EQUAL @@ -1811,7 +1818,7 @@ class GUROBI(LpSolver): elif constraint.sense == LpConstraintEQ: relation = gurobipy.GRB.EQUAL else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') constraint.solverConstraint = lp.solverModel.addConstr(expr, relation, -constraint.constant, name) lp.solverModel.update() @@ -1868,7 +1875,7 @@ class GUROBI_CMD(LpSolver_CMD): def actualSolve(self, lp): """Solve a well formulated lp problem""" if not self.executable(self.path): - raise PulpSolverError, "PuLP: cannot execute "+self.path + raise PulpSolverError("PuLP: cannot execute "+self.path) if not self.keepFiles: pid = os.getpid() tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid) @@ -1895,7 +1902,7 @@ class GUROBI_CMD(LpSolver_CMD): return_code = subprocess.call(cmd.split(), stdout = pipe, stderr = pipe) if return_code != 0: - raise PulpSolverError, "PuLP: Error while trying to execute "+self.path + raise PulpSolverError("PuLP: Error while trying to execute "+self.path) if not self.keepFiles: try: os.remove(tmpLp) except: pass @@ -1921,7 +1928,7 @@ class GUROBI_CMD(LpSolver_CMD): """Read a Gurobi solution file""" my_file = open(filename) try: - my_file.next() # skip the objective value + next(my_file) # skip the objective value except StopIteration: # Empty file not solved warnings.warn('GUROBI_CMD does provide good solution status of non optimal solutions') @@ -1964,7 +1971,7 @@ class PYGLPK(LpSolver): return False def actualSolve(self, lp, callback = None): """Solve a well formulated lp problem""" - raise PulpSolverError, "GLPK: Not Available" + raise PulpSolverError("GLPK: Not Available") else: def __init__(self, mip = True, @@ -2051,7 +2058,7 @@ class PYGLPK(LpSolver): if lp.sense == LpMaximize: glpk.glp_set_obj_dir(prob, glpk.GLP_MAX) log.debug("add the constraints to the problem") - glpk.glp_add_rows(prob, len(lp.constraints.keys())) + glpk.glp_add_rows(prob, len(list(lp.constraints.keys()))) for i, v in enumerate(lp.constraints.items(), start=1): name, constraint = v glpk.glp_set_row_name(prob, i, name) @@ -2065,7 +2072,7 @@ class PYGLPK(LpSolver): glpk.glp_set_row_bnds(prob, i, glpk.GLP_FX, -constraint.constant, -constraint.constant) else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') constraint.glpk_index = i log.debug("add the variables to the problem") glpk.glp_add_cols(prob, len(lp.variables())) @@ -2097,7 +2104,7 @@ class PYGLPK(LpSolver): glpk.glp_set_obj_coef(prob, var.glpk_index, value) log.debug("set the problem matrix") for constraint in lp.constraints.values(): - l = len(constraint.items()) + l = len(list(constraint.items())) ind = glpk.intArray(l + 1) val = glpk.doubleArray(l + 1) for j, v in enumerate(constraint.items(), start=1): @@ -2149,7 +2156,7 @@ class PYGLPK(LpSolver): glpk.glp_set_row_bnds(prob, i, glpk.GLP_FX, -constraint.constant, -constraint.constant) else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') self.callSolver(lp, callback = callback) #get the solution information solutionStatus = self.findSolutionValues(lp) @@ -2180,7 +2187,7 @@ class YAPOSIB(LpSolver): return False def actualSolve(self, lp, callback = None): """Solve a well formulated lp problem""" - raise PulpSolverError, "YAPOSIB: Not Available" + raise PulpSolverError("YAPOSIB: Not Available") else: def __init__(self, mip = True, @@ -2224,7 +2231,7 @@ class YAPOSIB(LpSolver): constr.pi = constr.solverConstraint.dual constr.slack = -constr.constant - constr.solverConstraint.activity if self.msg: - print "yaposib status=", solutionStatus + print("yaposib status=", solutionStatus) lp.resolveOK = True for var in lp.variables(): var.isModified = False @@ -2245,7 +2252,7 @@ class YAPOSIB(LpSolver): savestdout = os.dup(1) os.close(1) if os.dup(tempfile.fileno()) != 1: - raise PulpSolverError, "couldn't redirect stdout - dup() error" + raise PulpSolverError("couldn't redirect stdout - dup() error") self.solveTime = -clock() lp.solverModel.solve(self.mip) self.solveTime += clock() @@ -2290,7 +2297,7 @@ class YAPOSIB(LpSolver): row.upperbound = -constraint.constant row.lowerbound = -constraint.constant else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') row.name = name constraint.solverConstraint = row @@ -2332,7 +2339,7 @@ class YAPOSIB(LpSolver): row.upperbound = -constraint.constant row.lowerbound = -constraint.constant else: - raise PulpSolverError, 'Detected an invalid constraint type' + raise PulpSolverError('Detected an invalid constraint type') self.callSolver(lp, callback = callback) #get the solution information solutionStatus = self.findSolutionValues(lp) diff --git a/src/pulp/sparse.py b/src/pulp/sparse.py index b214cb0..62b6ca3 100644 --- a/src/pulp/sparse.py +++ b/src/pulp/sparse.py @@ -46,19 +46,19 @@ class Matrix(dict): self.rowdict[row][col] = item self.coldict[col][row] = item else: - print self.cols - raise RuntimeError, "col %s is not in the matrix columns"%col + print(self.cols) + raise RuntimeError("col %s is not in the matrix columns"%col) else: - raise RuntimeError, "row %s is not in the matrix rows"%row + raise RuntimeError("row %s is not in the matrix rows"%row) def addcol(self,col,rowitems): """adds a column """ if col in self.cols: - for row,item in rowitems.iteritems(): + for row,item in rowitems.items(): self.add(row, col, item, colcheck = False) else: - raise RuntimeError, "col is not in the matrix columns" + raise RuntimeError("col is not in the matrix columns") @@ -73,8 +73,8 @@ class Matrix(dict): lenBase = [] for i,col in enumerate(self.cols): startsBase.append(len(elemBase)) - elemBase.extend(self.coldict[col].values()) - indBase.extend(self.coldict[col].keys()) + elemBase.extend(list(self.coldict[col].values())) + indBase.extend(list(self.coldict[col].keys())) lenBase.append(len(elemBase) - startsBase[-1]) startsBase.append(len(elemBase)) return numEls, startsBase, lenBase, indBase, elemBase @@ -82,11 +82,11 @@ class Matrix(dict): if __name__ == "__main__": """ unit test """ - rows = range(10) - cols = range(50,60) + rows = list(range(10)) + cols = list(range(50,60)) mat = Matrix(rows,cols) mat.add(1,52,"item") mat.add(2,54,"stuff") - print mat.col_based_arrays() + print(mat.col_based_arrays()) diff --git a/src/pulp/tests.py b/src/pulp/tests.py index a8b6b71..14ec552 100644 --- a/src/pulp/tests.py +++ b/src/pulp/tests.py @@ -1,7 +1,7 @@ """ Tests for pulp """ -from pulp import * +from .pulp import * def pulpTestCheck(prob, solver, okstatus, sol = {}, reducedcosts = None, @@ -16,41 +16,41 @@ def pulpTestCheck(prob, solver, okstatus, sol = {}, if status not in okstatus: prob.writeLP("debug.lp") prob.writeMPS("debug.mps") - print "Failure: status ==", status, "not in", okstatus - print "Failure: status ==", LpStatus[status], "not in", \ - [LpStatus[s] for s in okstatus] - raise PulpError, "Tests failed for solver %s"%solver + print("Failure: status ==", status, "not in", okstatus) + print("Failure: status ==", LpStatus[status], "not in", \ + [LpStatus[s] for s in okstatus]) + raise PulpError("Tests failed for solver %s"%solver) if sol: - for v,x in sol.iteritems(): + for v,x in sol.items(): if abs(v.varValue - x) > eps: prob.writeLP("debug.lp") prob.writeMPS("debug.mps") - print "Test failed: var", v, "==", v.varValue, "!=", x - raise PulpError, "Tests failed for solver %s"%solver + print("Test failed: var", v, "==", v.varValue, "!=", x) + raise PulpError("Tests failed for solver %s"%solver) if reducedcosts: - for v,dj in reducedcosts.iteritems(): + for v,dj in reducedcosts.items(): if abs(v.dj - dj) > eps: prob.writeLP("debug.lp") prob.writeMPS("debug.mps") - print "Test failed: var.dj", v, "==", v.dj, "!=", dj - raise PulpError, "Tests failed for solver %s"%solver + print("Test failed: var.dj", v, "==", v.dj, "!=", dj) + raise PulpError("Tests failed for solver %s"%solver) if duals: - for cname,p in duals.iteritems(): + for cname,p in duals.items(): c = prob.constraints[cname] if abs(c.pi - p) > eps: prob.writeLP("debug.lp") prob.writeMPS("debug.mps") - print "Test failed: constraint.pi", cname , "==", c.pi, "!=", p - raise PulpError, "Tests failed for solver %s"%solver + print("Test failed: constraint.pi", cname , "==", c.pi, "!=", p) + raise PulpError("Tests failed for solver %s"%solver) if slacks: - for cname,slack in slacks.iteritems(): + for cname,slack in slacks.items(): c = prob.constraints[cname] if abs(c.slack - slack) > eps: prob.writeLP("debug.lp") prob.writeMPS("debug.mps") - print ("Test failed: constraint.slack", cname , "==", - c.slack, "!=", slack) - raise PulpError, "Tests failed for solver %s"%solver + print(("Test failed: constraint.slack", cname , "==", + c.slack, "!=", slack)) + raise PulpError("Tests failed for solver %s"%solver) def pulpTest001(solver): """ @@ -61,7 +61,7 @@ def pulpTest001(solver): z = LpVariable("z", 0) c1 = x+y <= 5 c2 = c1 + z -z - print "\t Testing zero subtraction" + print("\t Testing zero subtraction") assert str(c2) #will raise an exception def pulpTest010(solver): @@ -76,7 +76,7 @@ def pulpTest010(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob += w >= 0, "c4" - print "\t Testing continuous LP solution" + print("\t Testing continuous LP solution") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:0}) def pulpTest011(solver): @@ -91,7 +91,7 @@ def pulpTest011(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob += w >= 0, "c4" - print "\t Testing maximize continuous LP solution" + print("\t Testing maximize continuous LP solution") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:1, z:8, w:0}) def pulpTest012(solver): @@ -106,13 +106,13 @@ def pulpTest012(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob += w >= 0, "c4" - print "\t Testing unbounded continuous LP solution" + print("\t Testing unbounded continuous LP solution") if solver.__class__ in [GUROBI, CPLEX_CMD, YAPOSIB, CPLEX_PY]: # These solvers report infeasible or unbounded pulpTestCheck(prob, solver, [LpStatusInfeasible]) elif solver.__class__ in [COINMP_DLL,]: # COINMP_DLL is just plain wrong - print '\t\t Error in CoinMP it reports Optimal' + print('\t\t Error in CoinMP it reports Optimal') pulpTestCheck(prob, solver, [LpStatusOptimal]) elif solver.__class__ is GLPK_CMD: # GLPK_CMD Does not report unbounded problems, correctly @@ -136,7 +136,7 @@ def pulpTest013(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob += w >= 0, "c4" - print "\t Testing Long Names" + print("\t Testing Long Names") if solver.__class__ in [CPLEX_CMD, GLPK_CMD, GUROBI_CMD]: try: pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:0}) @@ -158,7 +158,7 @@ def pulpTest014(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob += w >= 0, "c4" - print "\t Testing repeated Names" + print("\t Testing repeated Names") if solver.__class__ in [COIN_CMD, PULP_CBC_CMD, CPLEX_CMD, CPLEX_PY, GLPK_CMD, GUROBI_CMD]: try: @@ -182,7 +182,7 @@ def pulpTest015(solver): prob += -y+z == 7, "c3" prob += w >= 0, "c4" prob += lpSum([0, 0]) <= 0, "c5" - print "\t Testing zero constraint" + print("\t Testing zero constraint") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:0}) def pulpTest016(solver): @@ -197,7 +197,7 @@ def pulpTest016(solver): prob += -y+z == 7, "c3" prob += w >= 0, "c4" prob += lpSum([0, 0]) <= 0, "c5" - print "\t Testing zero objective" + print("\t Testing zero objective") pulpTestCheck(prob, solver, [LpStatusOptimal]) def pulpTest017(solver): @@ -213,7 +213,7 @@ def pulpTest017(solver): prob += -y+z == 7, "c3" prob += w >= 0, "c4" prob += lpSum([0, 0]) <= 0, "c5" - print "\t Testing LpVariable (not LpAffineExpression) objective" + print("\t Testing LpVariable (not LpAffineExpression) objective") pulpTestCheck(prob, solver, [LpStatusOptimal]) def pulpTest018(solver): @@ -229,7 +229,7 @@ def pulpTest018(solver): prob += -y+z == 7, "c3" prob += w >= 0, "c4" if solver.__class__ in [COIN_CMD]: - print "\t Testing Long lines in LP" + print("\t Testing Long lines in LP") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:0}, use_mps=False) @@ -243,7 +243,7 @@ def pulpTest020(solver): prob += x+y <= 5, "c1" prob += x+z >= 10, "c2" prob += -y+z == 7.5, "c3" - print "\t Testing MIP solution" + print("\t Testing MIP solution") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:3, y:-0.5, z:7}) def pulpTest030(solver): @@ -257,7 +257,7 @@ def pulpTest030(solver): prob += x+z >= 10, "c2" prob += -y+z == 7.5, "c3" solver.mip = 0 - print "\t Testing MIP relaxation" + print("\t Testing MIP relaxation") if solver.__class__ in [GUROBI_CMD]: #gurobi command does not let the problem be relaxed pulpTestCheck(prob, solver, [LpStatusOptimal], {x:3.0, y:-0.5, z:7}) @@ -274,7 +274,7 @@ def pulpTest040(solver): prob += x+y <= 5, "c1" prob += x+z >= 10, "c2" prob += -y+z == 7.5, "c3" - print "\t Testing feasibility problem (no objective)" + print("\t Testing feasibility problem (no objective)") pulpTestCheck(prob, solver, [LpStatusOptimal]) @@ -287,7 +287,7 @@ def pulpTest050(solver): prob += x+y <= 5.2, "c1" prob += x+z >= 10.3, "c2" prob += -y+z == 17.5, "c3" - print "\t Testing an infeasible problem" + print("\t Testing an infeasible problem") if solver.__class__ is GLPK_CMD: # GLPK_CMD return codes are not informative enough pulpTestCheck(prob, solver, [LpStatusUndefined]) @@ -306,14 +306,14 @@ def pulpTest060(solver): prob += x+y <= 5.2, "c1" prob += x+z >= 10.3, "c2" prob += -y+z == 7.4, "c3" - print "\t Testing an integer infeasible problem" + print("\t Testing an integer infeasible problem") if solver.__class__ in [GLPK_CMD, COIN_CMD, PULP_CBC_CMD]: # GLPK_CMD returns InfeasibleOrUnbounded pulpTestCheck(prob, solver, [LpStatusInfeasible, LpStatusUndefined]) elif solver.__class__ in [COINMP_DLL]: #Currently there is an error in COINMP for problems where #presolve eliminates too many variables - print "\t\t Error in CoinMP to be fixed, reports Optimal" + print("\t\t Error in CoinMP to be fixed, reports Optimal") pulpTestCheck(prob, solver, [LpStatusOptimal]) elif solver.__class__ in [GUROBI_CMD]: pulpTestCheck(prob, solver, [LpStatusNotSolved]) @@ -337,7 +337,7 @@ def pulpTest070(solver): x = LpVariable("x", 0, 4, LpContinuous, obj + a + b) y = LpVariable("y", -1, 1, LpContinuous, 4*obj + a - c) z = LpVariable("z", 0, None, LpContinuous, 9*obj + b + c) - print "\t Testing column based modelling" + print("\t Testing column based modelling") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6}) def pulpTest075(solver): @@ -359,7 +359,7 @@ def pulpTest075(solver): z = LpVariable("z", 0, None, LpContinuous, 9*obj + b + c) if solver.__class__ in [CPLEX_DLL, CPLEX_CMD, COINMP_DLL, YAPOSIB, PYGLPK]: - print "\t Testing column based modelling with empty constraints" + print("\t Testing column based modelling with empty constraints") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6}) def pulpTest080(solver): @@ -381,7 +381,7 @@ def pulpTest080(solver): if solver.__class__ in [CPLEX_DLL, CPLEX_CMD, COINMP_DLL, PULP_CBC_CMD, YAPOSIB, PYGLPK]: - print "\t Testing dual variables and slacks reporting" + print("\t Testing dual variables and slacks reporting") pulpTestCheck(prob, solver, [LpStatusOptimal], sol = {x:4, y:-1, z:6}, reducedcosts = {x:0, y:12, z:0}, @@ -408,7 +408,7 @@ def pulpTest090(solver): prob.resolve() z = LpVariable("z", 0, None, LpContinuous, 9*obj + b + c) if solver.__class__ in [CPLEX_DLL, COINMP_DLL]: - print "\t Testing resolve of problem" + print("\t Testing resolve of problem") prob.resolve() #difficult to check this is doing what we want as the resolve is #over ridden if it is not implemented @@ -429,7 +429,7 @@ def pulpTest100(solver): prob += x <= 1, "c1" if solver.__class__ in [CPLEX_DLL, COINMP_DLL, GUROBI]: - print "\t Testing Sequential Solves" + print("\t Testing Sequential Solves") status = prob.sequentialSolve([obj1,obj2], solver = solver) pulpTestCheck(prob, solver, [[LpStatusOptimal,LpStatusOptimal]], sol = {x:0, y:1}, @@ -450,7 +450,7 @@ def pulpTest110(solver): prob += -y+z == 7, "c3" prob += w >= 0, "c4" prob += LpFractionConstraint(x, z, LpConstraintEQ, 0.5, name = 'c5') - print "\t Testing fractional constraints" + print("\t Testing fractional constraints") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:10/3.0, y:-1/3.0, z:20/3.0, w:0}) @@ -468,7 +468,7 @@ def pulpTest120(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob.extend((w >= -1).makeElasticSubProblem()) - print "\t Testing elastic constraints (no change)" + print("\t Testing elastic constraints (no change)") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:-1}) @@ -486,7 +486,7 @@ def pulpTest121(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob.extend((w >= -1).makeElasticSubProblem(proportionFreeBound = 0.1)) - print "\t Testing elastic constraints (freebound)" + print("\t Testing elastic constraints (freebound)") pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:-1.1}) @@ -504,7 +504,7 @@ def pulpTest122(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob.extend((w >= -1).makeElasticSubProblem(penalty = 1.1)) - print "\t Testing elastic constraints (penalty unchanged)" + print("\t Testing elastic constraints (penalty unchanged)") prob.writeLP('debug.lp') pulpTestCheck(prob, solver, [LpStatusOptimal], {x:4, y:-1, z:6, w:-1.0}) @@ -523,7 +523,7 @@ def pulpTest123(solver): prob += x+z >= 10, "c2" prob += -y+z == 7, "c3" prob.extend((w >= -1).makeElasticSubProblem(penalty = 0.9)) - print "\t Testing elastic constraints (penalty unbounded)" + print("\t Testing elastic constraints (penalty unbounded)") prob.writeLP('debug.lp') if solver.__class__ in [COINMP_DLL, GUROBI, CPLEX_CMD, CPLEX_PY, YAPOSIB]: # COINMP_DLL Does not report unbounded problems, correctly diff --git a/tests/amply_tests.py b/tests/amply_tests.py index a443c72..c6a4aa9 100644 --- a/tests/amply_tests.py +++ b/tests/amply_tests.py @@ -1,5 +1,5 @@ from pulp.amply import Amply, AmplyError -from StringIO import StringIO +from io import StringIO from nose.tools import assert_raises @@ -38,7 +38,10 @@ def test_attr_access(): assert result == 4 def test_from_file(): - s = StringIO("param T:= 4;") + try: + s = StringIO("param T:= 4;") + except TypeError: + s = StringIO(u"param T:= 4;") assert Amply.from_file(s).T == 4 def test_load_string(): @@ -50,7 +53,10 @@ def test_load_string(): def test_load_file(): a = Amply("param T:= 4; param X{foo};") - s = StringIO("param S := 6; param X := 1 2;") + try: + s = StringIO("param S := 6; param X := 1 2;") + except TypeError: + s = StringIO(u"param S := 6; param X := 1 2;") a.load_file(s) assert a.T == 4 assert a.S == 6