Skip to content

Commit

Permalink
Minor fixes (#598)
Browse files Browse the repository at this point in the history
* black formatting

* minor fixes
  • Loading branch information
pchtsp authored Nov 3, 2022
1 parent 9f479c9 commit c0c391a
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 29 deletions.
2 changes: 1 addition & 1 deletion pulp/apis/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import configparser
from typing import Union

Parser = configparser.ConfigParser

from .. import sparse
Expand Down Expand Up @@ -477,7 +478,6 @@ def executable(command):
return shutil.which(command)



def ctypesArrayFill(myList, type=ctypes.c_double):
"""
Creates a c array with ctypes from a python list
Expand Down
37 changes: 28 additions & 9 deletions pulp/apis/scip_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ def actualSolve(self, lp):
if "maxNodes" in self.optionsDict:
file_options.append(f"limits/nodes={self.optionsDict['maxNodes']}")
if "threads" in self.optionsDict and int(self.optionsDict["threads"]) > 1:
warnings.warn("SCIP can only run with a single thread - use FSCIP_CMD for a parallel version of SCIP")
warnings.warn(
"SCIP can only run with a single thread - use FSCIP_CMD for a parallel version of SCIP"
)
if not self.mip:
warnings.warn(f"{self.name} does not allow a problem to be relaxed")

Expand Down Expand Up @@ -194,7 +196,9 @@ def readsol(filename):
except Exception:
raise PulpSolverError(f"Can't get SCIP solver status: {line!r}")

status = SCIP_CMD.SCIP_STATUSES.get(comps[1].strip(), constants.LpStatusUndefined)
status = SCIP_CMD.SCIP_STATUSES.get(
comps[1].strip(), constants.LpStatusUndefined
)
values = {}

if status in SCIP_CMD.NO_SOLUTION_STATUSES:
Expand Down Expand Up @@ -293,7 +297,9 @@ def actualSolve(self, lp):
if not self.executable(self.path):
raise PulpSolverError("PuLP: cannot execute " + self.path)

tmpLp, tmpSol, tmpOptions, tmpParams = self.create_tmp_files(lp.name, "lp", "sol", "set", "prm")
tmpLp, tmpSol, tmpOptions, tmpParams = self.create_tmp_files(
lp.name, "lp", "sol", "set", "prm"
)
lp.writeLP(tmpLp)

file_options: List[str] = []
Expand Down Expand Up @@ -428,14 +434,18 @@ def readsol(filename):
objective_line = file.readline()
objective = FSCIP_CMD.parse_objective(objective_line)
if objective is None:
raise PulpSolverError(f"Can't get FSCIP solver objective: {objective_line!r}")
raise PulpSolverError(
f"Can't get FSCIP solver objective: {objective_line!r}"
)

# Parse the variable values.
variables: Dict[str, float] = {}
for variable_line in file:
variable = FSCIP_CMD.parse_variable(variable_line)
if variable is None:
raise PulpSolverError(f"Can't read FSCIP solver output: {variable_line!r}")
raise PulpSolverError(
f"Can't read FSCIP solver output: {variable_line!r}"
)

name, value = variable
variables[name] = value
Expand Down Expand Up @@ -539,7 +549,9 @@ def findSolutionValues(self, lp):
for variable in lp._variables:
variable.varValue = solution[variable.solverVar]
for constraint in lp.constraints.values():
constraint.slack = lp.solverModel.getSlack(constraint.solverConstraint, solution)
constraint.slack = lp.solverModel.getSlack(
constraint.solverConstraint, solution
)

# TODO: check if problem is an LP i.e. does not have integer variables
# if :
Expand Down Expand Up @@ -588,7 +600,9 @@ def buildSolverModel(self, lp):
if "logPath" in self.optionsDict:
lp.solverModel.setLogfile(self.optionsDict["logPath"])
if "threads" in self.optionsDict and int(self.optionsDict["threads"]) > 1:
warnings.warn(f"The solver {self.name} can only run with a single thread")
warnings.warn(
f"The solver {self.name} can only run with a single thread"
)
if not self.mip:
warnings.warn(f"{self.name} does not allow a problem to be relaxed")

Expand Down Expand Up @@ -629,7 +643,10 @@ def buildSolverModel(self, lp):
for name, constraint in lp.constraints.items():
constraint.solverConstraint = lp.solverModel.addCons(
cons=sense_to_operator[constraint.sense](
scip.quicksum(coefficient * variable.solverVar for variable, coefficient in constraint.items()),
scip.quicksum(
coefficient * variable.solverVar
for variable, coefficient in constraint.items()
),
-constraint.constant,
),
name=name,
Expand Down Expand Up @@ -660,4 +677,6 @@ def actualResolve(self, lp):
# TODO: add ability to resolve pysciptopt models
# - http://listserv.zib.de/pipermail/scip/2020-May/003977.html
# - https://scipopt.org/doc-8.0.0/html/REOPT.php
raise PulpSolverError(f"The {self.name} solver does not implement resolving")
raise PulpSolverError(
f"The {self.name} solver does not implement resolving"
)
4 changes: 3 additions & 1 deletion pulp/mps_lp.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ def readMPSSetRhs(line, constraintsDict):
return


def writeMPS(LpProblem, filename, mpsSense=0, rename=0, mip=1, with_objsense: bool = False):
def writeMPS(
LpProblem, filename, mpsSense=0, rename=0, mip=1, with_objsense: bool = False
):
wasNone, dummyVar = LpProblem.fixObjective()
if mpsSense == 0:
mpsSense = LpProblem.sense
Expand Down
13 changes: 11 additions & 2 deletions pulp/pulp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,9 @@ def coefficients(self, translation=None):
coefs.extend([(translation[v.name], ctr, cst[v]) for v in cst])
return coefs

def writeMPS(self, filename, mpsSense=0, rename=0, mip=1, with_objsense: bool = False):
def writeMPS(
self, filename, mpsSense=0, rename=0, mip=1, with_objsense: bool = False
):
"""
Writes an mps files from the problem information
Expand All @@ -1780,7 +1782,14 @@ def writeMPS(self, filename, mpsSense=0, rename=0, mip=1, with_objsense: bool =
Side Effects:
- The file is created
"""
return mpslp.writeMPS(self, filename, mpsSense=mpsSense, rename=rename, mip=mip, with_objsense=with_objsense)
return mpslp.writeMPS(
self,
filename,
mpsSense=mpsSense,
rename=rename,
mip=mip,
with_objsense=with_objsense,
)

def writeLP(self, filename, writeSOS=1, mip=1, max_length=100):
"""
Expand Down
24 changes: 8 additions & 16 deletions pulp/tests/test_pulp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@ def test_measuring_solving_time(self):
prob = create_bin_packing_problem(bins=bins, seed=99)
self.solver.timeLimit = time_limit
prob.solve(self.solver)
delta = 4
delta = 20
reported_time = prob.solutionTime
if self.solver.name in ["PULP_CBC_CMD", "COIN_CMD"]:
# CBC is less exact with the timeLimit
Expand Down Expand Up @@ -1340,21 +1340,17 @@ def test_LpVariable_indexs_deprecation_logic(self):
name="test",
)

# Not supported in 2.7. Introduced to unittest in 3.2
# with self.assertWarns(DeprecationWarning):
# assign_vars_matrix = LpVariable.dicts(
# name="test",
# indexs=(customers, agents),
# )
with self.assertWarns(DeprecationWarning):
assign_vars_matrix = LpVariable.dicts(
name="test",
indexs=(customers, agents),
)

def test_parse_cplex_mipopt_solution(self):
"""
Ensures `readsol` can parse CPLEX mipopt solutions (see issue #508).
"""
try:
from io import StringIO
except ImportError: # python 2
from StringIO import StringIO
from io import StringIO

print("\t Testing that `readsol` can parse CPLEX mipopt solution")
# Example solution generated by CPLEX mipopt solver
Expand Down Expand Up @@ -1395,11 +1391,7 @@ def test_parse_cplex_mipopt_solution(self):
</objectiveValues>
</CPLEXSolution>
"""

try:
solution_file = StringIO(file_content)
except TypeError: # python 2
solution_file = StringIO(unicode(file_content))
solution_file = StringIO(file_content)

# This call to `readsol` would crash for this solution format #508
_, _, reducedCosts, shadowPrices, _, _ = CPLEX_CMD().readsol(solution_file)
Expand Down

0 comments on commit c0c391a

Please sign in to comment.