Skip to content

Commit a560dc8

Browse files
authored
added timeMode argument for counting cbc wall-time. (#487)
* added `timeMode` argument for counting cbc wall-time. * bump pypi version and history * increased the timeLimit and added seed to be sure to pass the test.
1 parent 449e4b2 commit a560dc8

File tree

6 files changed

+72
-40
lines changed

6 files changed

+72
-40
lines changed

HISTORY

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
fixed bugs
88
added HiGHS solver
99
added pysmps dependency for mps parsing
10+
2.5.1 2021-09-28
11+
updated docs
12+
fixed minor issues
13+
cbc now uses wall-time for timeLimit
1014
2.5.0 2021-08-11
1115
measuring wall time and cpu time
1216
unittests of timeLimit

doc/source/develop/contribute.rst

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
How to contribute to PuLP
22
======================================
33

4-
This is a minimalistic guid to setup pulp and help you modify the code and send a PR.
4+
This is a minimalistic guide to setup pulp and help you modify the code and send a PR.
5+
6+
The quick summary is:
7+
8+
#. Fork the repo.
9+
#. Clone your forked repo.
10+
#. Install dependencies.
11+
#. Make your changes.
12+
#. Create a test for your changes if needed.
13+
#. Make sure all the tests pass.
14+
#. Lint your code with black.
15+
#. Ensure the docs are accurate.
16+
#. Submit a Pull Request.
17+
18+
519
On top of having python installed, we will be using git and the command line. Also, we assume you have a github account and know how to fork a project.
620
We will use plain git through the command line but feel free to use the git client of your choice.
721

@@ -35,19 +49,6 @@ To build pulp from source we wil get inside the pulp directory, then we will cre
3549

3650
This will link the pulp version on your virtual environment with the source files in the pulp directory. You can now use pulp from that virtual environment and you will be using the files in the pulp directory. We assume you have run this successfully for all further steps.
3751

38-
Building the documentation
39-
----------------------------
40-
41-
The documentation is based in `Sphinx and reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_.
42-
43-
To build the documentation::
44-
45-
cd pulp/doc
46-
make html
47-
48-
A folder named html will be created inside the ``build/`` directory. The home page for the documentation is ``doc/build/html/index.html`` which can be opened in a browser.
49-
You only need to execute ``make html`` to rebuild the docs each time.
50-
5152
Running tests
5253
----------------
5354

@@ -63,6 +64,30 @@ Creating a test
6364

6465
When you fix an issue in pulp or add a functionality, you should add a test to the repository. For this you should go to the file `tests/test_pulp.py` and add a new method that tests your change.
6566

67+
Applying the black linter / formatter
68+
-----------------------------------------------------
69+
70+
We use `the black formatter <https://black.readthedocs.io/en/stable/>`_. Before sending your changes, be sure to execute the black package to style the resulting files.
71+
The quickest way to do this is to run:
72+
73+
python -m black pulp
74+
75+
And it will do the changes directly on the files.
76+
77+
The easiest way is to integrate it inside your IDE so it runs every time you save a file. Learn how to do that `in the black integration docs <https://black.readthedocs.io/en/stable/integrations/editors.html>`_.
78+
79+
Building the documentation
80+
----------------------------
81+
82+
The documentation is based in `Sphinx and reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_.
83+
84+
To build the documentation::
85+
86+
cd pulp/doc
87+
make html
88+
89+
A folder named html will be created inside the ``build/`` directory. The home page for the documentation is ``doc/build/html/index.html`` which can be opened in a browser.
90+
You only need to execute ``make html`` to rebuild the docs each time.
6691

6792
Making a Pull Request
6893
----------------------------

pulp/apis/coin_api.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def __init__(
6161
path=None,
6262
threads=None,
6363
logPath=None,
64+
timeMode="elapsed",
6465
mip_start=False,
6566
):
6667
"""
@@ -80,6 +81,7 @@ def __init__(
8081
:param bool strong: if True, adds strong
8182
:param float fracGap: deprecated for gapRel
8283
:param float maxSeconds: deprecated for timeLimit
84+
:param str timeMode: "elapsed": count wall-time to timeLimit; "cpu": count cpu-time
8385
:param bool mip_start: deprecated for warmStart
8486
"""
8587

@@ -121,6 +123,7 @@ def __init__(
121123
threads=threads,
122124
gapAbs=gapAbs,
123125
logPath=logPath,
126+
timeMode=timeMode,
124127
)
125128

126129
def copy(self):
@@ -163,8 +166,6 @@ def solve_CBC(self, lp, use_mps=True):
163166
self.writesol(tmpMst, lp, vs, variablesNames, constraintsNames)
164167
cmds += "mips {} ".format(tmpMst)
165168
if self.timeLimit is not None:
166-
if self.optionsDict.get("threads", 1) > 1:
167-
warnings.warn("Beware: CBC uses timeLimit as cpu_time, not wall_time")
168169
cmds += "sec %s " % self.timeLimit
169170
options = self.options + self.getOptions()
170171
for option in options:
@@ -226,6 +227,7 @@ def getOptions(self):
226227
presolve="presolve on",
227228
strong="strong {}",
228229
cuts="gomory on knapsack on probing on",
230+
timeMode="timeMode {}",
229231
)
230232

231233
return [
@@ -377,6 +379,7 @@ def __init__(
377379
threads=None,
378380
logPath=None,
379381
mip_start=False,
382+
timeMode="elapsed",
380383
):
381384
if path is not None:
382385
raise PulpSolverError("Use COIN_CMD if you want to set a path")
@@ -400,6 +403,7 @@ def __init__(
400403
threads=threads,
401404
logPath=logPath,
402405
mip_start=mip_start,
406+
timeMode=timeMode,
403407
)
404408

405409

pulp/apis/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def __init__(
231231
self.solution_time = 0
232232

233233
# here we will store all other relevant information including:
234-
# gapRel, gapAbs, maxMemory, maxNodes, threads, logPath
234+
# gapRel, gapAbs, maxMemory, maxNodes, threads, logPath, timeMode
235235
self.optionsDict = {k: v for k, v in kwargs.items() if v is not None}
236236

237237
def available(self):

pulp/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
This file contains the constant definitions for PuLP
2828
Note that hopefully these will be changed into something more pythonic
2929
"""
30-
VERSION = "2.5.0"
30+
VERSION = "2.5.1"
3131
EPS = 1e-7
3232

3333
# variable categories

pulp/tests/test_pulp.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,24 +1148,23 @@ def add_const(prob):
11481148
def test_measuring_solving_time(self):
11491149
print("\t Testing measuring optimization time")
11501150

1151-
time_limit = 5
1151+
time_limit = 10
11521152
solver_settings = dict(
11531153
PULP_CBC_CMD=30, COIN_CMD=30, SCIP_CMD=30, GUROBI_CMD=50, CPLEX_CMD=50
11541154
)
11551155
bins = solver_settings.get(self.solver.name)
11561156
if bins is None:
11571157
# not all solvers have timeLimit support
11581158
return
1159-
prob = create_bin_packing_problem(bins=bins)
1159+
prob = create_bin_packing_problem(bins=bins, seed=99)
11601160
self.solver.timeLimit = time_limit
11611161
prob.solve(self.solver)
1162-
delta = 2
1162+
delta = 4
11631163
reported_time = prob.solutionTime
11641164
if self.solver.name in ["PULP_CBC_CMD", "COIN_CMD"]:
1165-
# CBC uses cpu-time for timeLimit
1166-
# also: CBC is less exact with the timeLimit
1165+
# CBC is less exact with the timeLimit
11671166
reported_time = prob.solutionCpuTime
1168-
delta = 4
1167+
delta = 5
11691168

11701169
self.assertAlmostEqual(
11711170
reported_time,
@@ -1174,6 +1173,22 @@ def test_measuring_solving_time(self):
11741173
msg="optimization time for solver {}".format(self.solver.name),
11751174
)
11761175

1176+
def test_invalid_var_names(self):
1177+
prob = LpProblem(self._testMethodName, const.LpMinimize)
1178+
x = LpVariable("a")
1179+
w = LpVariable("b")
1180+
y = LpVariable("g", -1, 1)
1181+
z = LpVariable("End")
1182+
prob += x + 4 * y + 9 * z, "obj"
1183+
prob += x + y <= 5, "c1"
1184+
prob += x + z >= 10, "c2"
1185+
prob += -y + z == 7, "c3"
1186+
prob += w >= 0, "c4"
1187+
print("\t Testing invalid var names")
1188+
pulpTestCheck(
1189+
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
1190+
)
1191+
11771192

11781193
class PULP_CBC_CMDTest(BaseSolverTest.PuLPTest):
11791194
solveInst = PULP_CBC_CMD
@@ -1238,22 +1253,6 @@ class MOSEKTest(BaseSolverTest.PuLPTest):
12381253
class SCIP_CMDTest(BaseSolverTest.PuLPTest):
12391254
solveInst = SCIP_CMD
12401255

1241-
def test_invalid_var_names(self):
1242-
prob = LpProblem(self._testMethodName, const.LpMinimize)
1243-
x = LpVariable("a")
1244-
w = LpVariable("b")
1245-
y = LpVariable("g", -1, 1)
1246-
z = LpVariable("End")
1247-
prob += x + 4 * y + 9 * z, "obj"
1248-
prob += x + y <= 5, "c1"
1249-
prob += x + z >= 10, "c2"
1250-
prob += -y + z == 7, "c3"
1251-
prob += w >= 0, "c4"
1252-
print("\t Testing invalid var names")
1253-
pulpTestCheck(
1254-
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
1255-
)
1256-
12571256

12581257
def pulpTestCheck(
12591258
prob,

0 commit comments

Comments
 (0)