Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warm Starts for HiGHS_CMD #713

Merged
merged 9 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/KPyCon2009/code/wedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def happiness(table):

seating_model.solve()

print(f"The choosen tables are out of a total of {len(possible_tables)}:")
print(f"The chosen tables are out of a total of {len(possible_tables)}:")
for table in possible_tables:
if x[table].value() == 1.0:
print(table)
2 changes: 1 addition & 1 deletion examples/wedding.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def happiness(table):

seating_model.solve()

print(f"The choosen tables are out of a total of {len(possible_tables)}:")
print(f"The chosen tables are out of a total of {len(possible_tables)}:")
for table in possible_tables:
if x[table].value() == 1.0:
print(table)
2 changes: 1 addition & 1 deletion examples/wedding_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def happiness(table):
seating_model.solve(solver)


print(f"The choosen tables are out of a total of {len(possible_tables)}:")
print(f"The chosen tables are out of a total of {len(possible_tables)}:")
for table in possible_tables:
if x[table].value() == 1.0:
print(table)
6 changes: 3 additions & 3 deletions pulp/apis/coin_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,21 @@ def __init__(
"""

if fracGap is not None:
warnings.warn("Parameter fracGap is being depreciated for gapRel")
warnings.warn("Parameter fracGap is being deprecated for gapRel")
if gapRel is not None:
warnings.warn("Parameter gapRel and fracGap passed, using gapRel")
else:
gapRel = fracGap
if maxSeconds is not None:
warnings.warn("Parameter maxSeconds is being depreciated for timeLimit")
warnings.warn("Parameter maxSeconds is being deprecated for timeLimit")
if timeLimit is not None:
warnings.warn(
"Parameter timeLimit and maxSeconds passed, using timeLimit"
)
else:
timeLimit = maxSeconds
if mip_start:
warnings.warn("Parameter mip_start is being depreciated for warmStart")
warnings.warn("Parameter mip_start is being deprecated for warmStart")
if warmStart:
warnings.warn(
"Parameter mipStart and mip_start passed, using warmStart"
Expand Down
6 changes: 3 additions & 3 deletions pulp/apis/copt_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __init__(
Initialize command-line solver
"""
if mip_start:
warnings.warn("Parameter mip_start is being depreciated for warmStart")
warnings.warn("Parameter mip_start is being deprecated for warmStart")
if warmStart:
warnings.warn(
"Parameter warmStart and mip_start passed, using warmStart"
Expand Down Expand Up @@ -334,7 +334,7 @@ def __init__(
Initialize COPT solver
"""
if mip_start:
warnings.warn("Parameter mip_start is being depreciated for warmStart")
warnings.warn("Parameter mip_start is being deprecated for warmStart")
if warmStart:
warnings.warn(
"Parameter warmStart and mip_start passed, using warmStart"
Expand Down Expand Up @@ -904,7 +904,7 @@ def __init__(
:param float epgap: deprecated for gapRel
"""
if epgap is not None:
warnings.warn("Parameter epgap is being depreciated for gapRel")
warnings.warn("Parameter epgap is being deprecated for gapRel")
if gapRel is not None:
warnings.warn("Parameter gapRel and epgap passed, using gapRel")
else:
Expand Down
8 changes: 4 additions & 4 deletions pulp/apis/cplex_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ def __init__(
:param float timelimit: deprecated for timeLimit
"""
if timelimit is not None:
warnings.warn("Parameter timelimit is being depreciated for timeLimit")
warnings.warn("Parameter timelimit is being deprecated for timeLimit")
if timeLimit is not None:
warnings.warn(
"Parameter timeLimit and timelimit passed, using timeLimit "
)
else:
timeLimit = timelimit
if mip_start:
warnings.warn("Parameter mip_start is being depreciated for warmStart")
warnings.warn("Parameter mip_start is being deprecated for warmStart")
if warmStart:
warnings.warn(
"Parameter mipStart and mip_start passed, using warmStart"
Expand Down Expand Up @@ -309,13 +309,13 @@ def __init__(
:param int threads: number of threads to be used by CPLEX to solve a problem (default None uses all available)
"""
if epgap is not None:
warnings.warn("Parameter epgap is being depreciated for gapRel")
warnings.warn("Parameter epgap is being deprecated for gapRel")
if gapRel is not None:
warnings.warn("Parameter gapRel and epgap passed, using gapRel")
else:
gapRel = epgap
if logfilename is not None:
warnings.warn("Parameter logfilename is being depreciated for logPath")
warnings.warn("Parameter logfilename is being deprecated for logPath")
if logPath is not None:
warnings.warn(
"Parameter logPath and logfilename passed, using logPath"
Expand Down
4 changes: 2 additions & 2 deletions pulp/apis/gurobi_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def __init__(
self.init_gurobi = False # whether env and model have been initialised

if epgap is not None:
warnings.warn("Parameter epgap is being depreciated for gapRel")
warnings.warn("Parameter epgap is being deprecated for gapRel")
if gapRel is not None:
warnings.warn("Parameter gapRel and epgap passed, using gapRel")
else:
Expand Down Expand Up @@ -419,7 +419,7 @@ def __init__(
:param bool mip_start: deprecated for warmStart
"""
if mip_start:
warnings.warn("Parameter mip_start is being depreciated for warmStart")
warnings.warn("Parameter mip_start is being deprecated for warmStart")
if warmStart:
warnings.warn(
"Parameter warmStart and mip_start passed, using warmStart"
Expand Down
39 changes: 33 additions & 6 deletions pulp/apis/highs_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __init__(
gapAbs=None,
threads=None,
logPath=None,
warmStart=False,
):
"""
:param bool mip: if False, assume LP even if integer variables
Expand All @@ -66,6 +67,7 @@ def __init__(
:param str path: path to the solver binary (you can get binaries for your platform from https://github.com/JuliaBinaryWrappers/HiGHS_jll.jl/releases, or else compile from source - https://highs.dev)
:param int threads: sets the maximum number of threads
:param str logPath: path to the log file
:param bool warmStart: if True, the solver will use the current value of variables as a start
"""
LpSolver_CMD.__init__(
self,
Expand All @@ -79,6 +81,7 @@ def __init__(
keepFiles=keepFiles,
threads=threads,
logPath=logPath,
warmStart=warmStart,
)

def defaultPath(self):
Expand All @@ -94,8 +97,8 @@ def actualSolve(self, lp):
raise PulpSolverError("PuLP: cannot execute " + self.path)
lp.checkDuplicateVars()

tmpMps, tmpSol, tmpOptions, tmpLog = self.create_tmp_files(
lp.name, "mps", "sol", "HiGHS", "HiGHS_log"
tmpMps, tmpSol, tmpOptions, tmpLog, tmpMst = self.create_tmp_files(
lp.name, "mps", "sol", "HiGHS", "HiGHS_log", "mst"
)
lp.writeMPS(tmpMps, with_objsense=True)

Expand Down Expand Up @@ -127,6 +130,9 @@ def actualSolve(self, lp):
command.append("--solver=simplex")
if "threads" in self.optionsDict:
command.append("--parallel=on")
if self.optionsDict.get("warmStart", False):
self.writesol(tmpMst, lp)
command.append(f"--read_solution_file={tmpMst}")

options = iter(self.options)
for option in options:
Expand Down Expand Up @@ -199,18 +205,39 @@ def actualSolve(self, lp):
elif status_sol == constants.LpSolutionNoSolutionFound:
values = None
else:
values = self.readsol(lp.variables(), tmpSol)
values = self.readsol(tmpSol)

self.delete_tmp_files(tmpMps, tmpSol, tmpOptions, tmpLog)
self.delete_tmp_files(tmpMps, tmpSol, tmpOptions, tmpLog, tmpMst)
lp.assignStatus(status, status_sol)

if status == constants.LpStatusOptimal:
lp.assignVarsVals(values)

return status

@staticmethod
def readsol(variables, filename):
def writesol(self, filename, lp):
"""Writes a HiGHS solution file"""

variable_rows = []
for var in lp.variables(): # zero variables must be included
variable_rows.append(f"{var.name} {var.varValue or 0}")

# Required preamble for HiGHS to accept a solution
all_rows = [
"Model status",
"None",
"",
"# Primal solution values",
"Feasible",
"",
f"# Columns {len(variable_rows)}",
]
all_rows.extend(variable_rows)

with open(filename, "w") as file:
file.write("\n".join(all_rows))

def readsol(self, filename):
"""Read a HiGHS solution file"""
with open(filename) as file:
lines = file.readlines()
Expand Down
4 changes: 2 additions & 2 deletions pulp/apis/xpress_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ def __init__(
:param bool warmStart: if True, then use current variable values as start
"""
if maxSeconds:
warnings.warn("Parameter maxSeconds is being depreciated for timeLimit")
warnings.warn("Parameter maxSeconds is being deprecated for timeLimit")
if timeLimit is not None:
warnings.warn(
"Parameter timeLimit and maxSeconds passed, using timeLimit"
)
else:
timeLimit = maxSeconds
if targetGap is not None:
warnings.warn("Parameter targetGap is being depreciated for gapRel")
warnings.warn("Parameter targetGap is being deprecated for gapRel")
if gapRel is not None:
warnings.warn("Parameter gapRel and epgap passed, using gapRel")
else:
Expand Down
1 change: 1 addition & 0 deletions pulp/tests/test_pulp.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ def test_pulp_022(self):
"CPLEX_CMD",
"CPLEX_PY",
"COPT",
"HiGHS_CMD",
]:
self.solver.optionsDict["warmStart"] = True
print("\t Testing Initial value in MIP solution")
Expand Down