Skip to content

Commit

Permalink
added timeMode argument for counting cbc wall-time. (#487)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
pchtsp authored Sep 28, 2021
1 parent 449e4b2 commit a560dc8
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 40 deletions.
4 changes: 4 additions & 0 deletions HISTORY
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
fixed bugs
added HiGHS solver
added pysmps dependency for mps parsing
2.5.1 2021-09-28
updated docs
fixed minor issues
cbc now uses wall-time for timeLimit
2.5.0 2021-08-11
measuring wall time and cpu time
unittests of timeLimit
Expand Down
53 changes: 39 additions & 14 deletions doc/source/develop/contribute.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
How to contribute to PuLP
======================================

This is a minimalistic guid to setup pulp and help you modify the code and send a PR.
This is a minimalistic guide to setup pulp and help you modify the code and send a PR.

The quick summary is:

#. Fork the repo.
#. Clone your forked repo.
#. Install dependencies.
#. Make your changes.
#. Create a test for your changes if needed.
#. Make sure all the tests pass.
#. Lint your code with black.
#. Ensure the docs are accurate.
#. Submit a Pull Request.


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.
We will use plain git through the command line but feel free to use the git client of your choice.

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

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.

Building the documentation
----------------------------

The documentation is based in `Sphinx and reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_.

To build the documentation::

cd pulp/doc
make html

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.
You only need to execute ``make html`` to rebuild the docs each time.

Running tests
----------------

Expand All @@ -63,6 +64,30 @@ Creating a test

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.

Applying the black linter / formatter
-----------------------------------------------------

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.
The quickest way to do this is to run:

python -m black pulp

And it will do the changes directly on the files.

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>`_.

Building the documentation
----------------------------

The documentation is based in `Sphinx and reStructuredText <https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html>`_.

To build the documentation::

cd pulp/doc
make html

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.
You only need to execute ``make html`` to rebuild the docs each time.

Making a Pull Request
----------------------------
Expand Down
8 changes: 6 additions & 2 deletions pulp/apis/coin_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def __init__(
path=None,
threads=None,
logPath=None,
timeMode="elapsed",
mip_start=False,
):
"""
Expand All @@ -80,6 +81,7 @@ def __init__(
:param bool strong: if True, adds strong
:param float fracGap: deprecated for gapRel
:param float maxSeconds: deprecated for timeLimit
:param str timeMode: "elapsed": count wall-time to timeLimit; "cpu": count cpu-time
:param bool mip_start: deprecated for warmStart
"""

Expand Down Expand Up @@ -121,6 +123,7 @@ def __init__(
threads=threads,
gapAbs=gapAbs,
logPath=logPath,
timeMode=timeMode,
)

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

return [
Expand Down Expand Up @@ -377,6 +379,7 @@ def __init__(
threads=None,
logPath=None,
mip_start=False,
timeMode="elapsed",
):
if path is not None:
raise PulpSolverError("Use COIN_CMD if you want to set a path")
Expand All @@ -400,6 +403,7 @@ def __init__(
threads=threads,
logPath=logPath,
mip_start=mip_start,
timeMode=timeMode,
)


Expand Down
2 changes: 1 addition & 1 deletion pulp/apis/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def __init__(
self.solution_time = 0

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

def available(self):
Expand Down
2 changes: 1 addition & 1 deletion pulp/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
This file contains the constant definitions for PuLP
Note that hopefully these will be changed into something more pythonic
"""
VERSION = "2.5.0"
VERSION = "2.5.1"
EPS = 1e-7

# variable categories
Expand Down
43 changes: 21 additions & 22 deletions pulp/tests/test_pulp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1148,24 +1148,23 @@ def add_const(prob):
def test_measuring_solving_time(self):
print("\t Testing measuring optimization time")

time_limit = 5
time_limit = 10
solver_settings = dict(
PULP_CBC_CMD=30, COIN_CMD=30, SCIP_CMD=30, GUROBI_CMD=50, CPLEX_CMD=50
)
bins = solver_settings.get(self.solver.name)
if bins is None:
# not all solvers have timeLimit support
return
prob = create_bin_packing_problem(bins=bins)
prob = create_bin_packing_problem(bins=bins, seed=99)
self.solver.timeLimit = time_limit
prob.solve(self.solver)
delta = 2
delta = 4
reported_time = prob.solutionTime
if self.solver.name in ["PULP_CBC_CMD", "COIN_CMD"]:
# CBC uses cpu-time for timeLimit
# also: CBC is less exact with the timeLimit
# CBC is less exact with the timeLimit
reported_time = prob.solutionCpuTime
delta = 4
delta = 5

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

def test_invalid_var_names(self):
prob = LpProblem(self._testMethodName, const.LpMinimize)
x = LpVariable("a")
w = LpVariable("b")
y = LpVariable("g", -1, 1)
z = LpVariable("End")
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing invalid var names")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)


class PULP_CBC_CMDTest(BaseSolverTest.PuLPTest):
solveInst = PULP_CBC_CMD
Expand Down Expand Up @@ -1238,22 +1253,6 @@ class MOSEKTest(BaseSolverTest.PuLPTest):
class SCIP_CMDTest(BaseSolverTest.PuLPTest):
solveInst = SCIP_CMD

def test_invalid_var_names(self):
prob = LpProblem(self._testMethodName, const.LpMinimize)
x = LpVariable("a")
w = LpVariable("b")
y = LpVariable("g", -1, 1)
z = LpVariable("End")
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing invalid var names")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)


def pulpTestCheck(
prob,
Expand Down

0 comments on commit a560dc8

Please sign in to comment.