From 1c7f19cb96f20436ac82d34ad3cf9b51525cd66b Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 15:14:59 +1000 Subject: [PATCH 01/17] Update docs CI Test in CI that the docs can be built with the oldest supported python version --- .github/workflows/doc-build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 02e83dd8..146dca65 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -1,4 +1,6 @@ -# The docs should build without warnings from sphinx +# The docs should build without warnings from sphinx. +# It should be possible to build the docs with python3.8 so contributors +# can work with the oldest supported python version. name: Docs build @@ -14,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ["3.11"] + python: ["3.8", "3.11"] steps: - uses: actions/checkout@v4 From b8149f8e5ad3c5a15a6ddefbb84999cda5394c87 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 15:54:43 +1000 Subject: [PATCH 02/17] Revert "Update docs CI" This reverts commit 1c7f19cb96f20436ac82d34ad3cf9b51525cd66b. --- .github/workflows/doc-build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 146dca65..02e83dd8 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -1,6 +1,4 @@ -# The docs should build without warnings from sphinx. -# It should be possible to build the docs with python3.8 so contributors -# can work with the oldest supported python version. +# The docs should build without warnings from sphinx name: Docs build @@ -16,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ["3.8", "3.11"] + python: ["3.11"] steps: - uses: actions/checkout@v4 From 9bcf249d0f2a1a8483464f3878b8602554c1fe19 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 15:55:15 +1000 Subject: [PATCH 03/17] Relax version constraints in `make develop` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9e3f7eeb..32db098e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ develop: python -m pip install pip setuptools wheel --upgrade python -m pip install -e .[examples] - python -m pip install -r docs/requirements.txt + python -m pip install -r docs/requirements-base.txt python -m pip install sphinx-autobuild pre-commit pre-commit install From c8c92adc652baaed46d579b067740a327ab3a3a5 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 16:03:10 +1000 Subject: [PATCH 04/17] Tweak contributing guide wording --- docs/source/contributing.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 8b0b3b68..acc172f5 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -44,9 +44,10 @@ Development Environment To set up your development environment: -1. Create and activate a Python 3.8 virtual environment using your preferred - tool. We maintain compatibility with Python 3.8 and above, so developing - using 3.8 locally will ensure your contributions are compatible. +1. Create and activate a Python virtual environment using your preferred tool. + We maintain compatibility with Python 3.8 and above, so developing using + version 3.8 locally should ensure that your contributions are compatible + with all supported Python versions. 2. Run ``make develop`` from the top level of the repository. This command will install (using ``pip``) all packages required to run the unit tests, run the doc tests, and build the sphinx documentation. It will also install From 8168ffd35467ad6baeee8fea7917b7378a3bab0b Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 16:05:07 +1000 Subject: [PATCH 05/17] Update link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6aa06748..009d1b00 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ pip install gurobi-optimods ## Documentation -Full documentation for `gurobi-optimods` is hosted on [readthedocs](https://gurobi-optimization-gurobi-optimods.readthedocs-hosted.com/en/stable). +Full documentation for `gurobi-optimods` is hosted on [readthedocs](https://gurobi-optimods.readthedocs.io/en/stable). ## License From aa1950129bbe88edb81714ff77547c4cef24b1e4 Mon Sep 17 00:00:00 2001 From: nodet Date: Fri, 14 Jun 2024 08:44:13 +0200 Subject: [PATCH 06/17] Wording suggestions for line optimization (#141) --- docs/source/mods/line-optimization.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/source/mods/line-optimization.rst b/docs/source/mods/line-optimization.rst index 7a1bc3cd..fc4155aa 100644 --- a/docs/source/mods/line-optimization.rst +++ b/docs/source/mods/line-optimization.rst @@ -8,14 +8,14 @@ This problem is an example of a classical network design problem. There are different approaches and models to solve the line optimization problem. A general overview on models and methods is given by Schoebel :footcite:p:`schoebel2012`. -For this optimod we assume we are given a public transportation network, being +For this optimod we assume we are given a public transportation network: a set of stations and the direct links between them. We are given the -origin-destination (OD) demand, i.e., it is known how many passengers want to -travel from one station to another in the network within a considered time horizon. -We are also given a set of possible *lines*. A line is a path a public -transportation network. We call a subset of these lines where each line is -associated with a frequency a line plan. The optimod computes a line plan with -minimum cost such that the capacity of the chosen lines sufficient to transport +origin-destination (OD) *demand*, i.e., it is known how many passengers want to +travel from one station to another in the network within the considered time horizon. +We are also given a set of possible *lines*. A line is a path in a public +transportation network. We call *line plan* a subset of these lines where each line is +associated with a frequency. The optimod computes a line plan with +minimum cost such that the capacity of the chosen lines is sufficient to transport all passengers. We provide two different strategies to find a line plan with minimum cost: @@ -39,9 +39,9 @@ vertices :math:`V` represent the stations and the set of edges :math:`E` represent all possibilities to travel from one station to another without an intermediate station. A directed edge :math:`(u,v)\in E` has the attribute time :math:`\tau_{uv}\geq 0` that -represents the amount of time needed traveling from :math:`u` to :math:`v`. -For each pair of nodes :math:`u,v\in V` a demand :math:`d_{uv}\geq 0` can be defined. -The demand represents the number of passengers that want to travel from :math:`u` +represents the amount of time needed to travel from :math:`u` to :math:`v`. +For each pair of nodes :math:`u,v\in V` a demand :math:`d_{uv}\geq 0` is given. +The demand represents the number of passengers who want to travel from :math:`u` to :math:`v` in the considered time horizon. Let :math:`D` be the set of all node pairs with positive demand. This set is also called OD pairs. Further given is a set of lines :math:`L`. A line :math:`l\in L` contains the stations it traverses @@ -53,7 +53,7 @@ A line has the following additional attributes: - operating cost: :math:`c_{l}\geq 0` for operating the line once in the given time horizon - capacity: :math:`\kappa_{l}\geq 0` when operating the line :math:`l` once in the given time horizon -Additionally, we have a given list of frequencies. The frequencies define the possible +Additionally, we are given a list of frequencies. The frequencies define the possible number of operations for the lines in the given time horizon. If a line :math:`l` is operated with frequency :math:`f` the overall cost for the line is :math:`C_{lf}=C_l + c_{lf}\cdot f` and the total capacity provided by the line is From f7e0f926e005e53e017ca48bd1fda3e1ef7e736f Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 14 Jun 2024 17:12:38 +1000 Subject: [PATCH 07/17] Update contributing.rst --- docs/source/contributing.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index acc172f5..b3d583a4 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -45,9 +45,8 @@ Development Environment To set up your development environment: 1. Create and activate a Python virtual environment using your preferred tool. - We maintain compatibility with Python 3.8 and above, so developing using - version 3.8 locally should ensure that your contributions are compatible - with all supported Python versions. + You can use any currently supported Python version for development (versions + 3.8 through 3.12). 2. Run ``make develop`` from the top level of the repository. This command will install (using ``pip``) all packages required to run the unit tests, run the doc tests, and build the sphinx documentation. It will also install From c7f983e612718f0aa6392e746f6629534b95bcad Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 20:52:42 +1000 Subject: [PATCH 08/17] Restrict numpy version to 1.x (#144) Closes #143 For now, we cannot use numpy 2.0 due to an incompatibility with the current gurobipy releases. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e56712ef..71b4ef8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ dependencies = [ "gurobipy[matrixapi]>=10.0.3", "gurobipy-pandas>=1.0.0", - "numpy", + "numpy<2", "pandas", "scipy>=1.8.0", ] From bc2f754a80680169497e9f364d5b5e89d43171fb Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 20:54:02 +1000 Subject: [PATCH 09/17] Update version to 2.0.1 --- src/gurobi_optimods/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gurobi_optimods/__init__.py b/src/gurobi_optimods/__init__.py index af16e9ad..c4f16c00 100644 --- a/src/gurobi_optimods/__init__.py +++ b/src/gurobi_optimods/__init__.py @@ -1,3 +1,3 @@ __doc__ = "Gurobi OptiMods" -__version__ = "2.0.1dev0" +__version__ = "2.0.1" From 525b0776ca7403fcf33335a755c80397dd58d880 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 20:59:51 +1000 Subject: [PATCH 10/17] Bump version to 2.0.2.dev0 --- src/gurobi_optimods/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gurobi_optimods/__init__.py b/src/gurobi_optimods/__init__.py index c4f16c00..01a79b82 100644 --- a/src/gurobi_optimods/__init__.py +++ b/src/gurobi_optimods/__init__.py @@ -1,3 +1,3 @@ __doc__ = "Gurobi OptiMods" -__version__ = "2.0.1" +__version__ = "2.0.2.dev0" From c6ed1e7dba58fad5994f942447eb5f190799462f Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 21:02:09 +1000 Subject: [PATCH 11/17] Revert "Bump version to 2.0.2.dev0" This reverts commit 525b0776ca7403fcf33335a755c80397dd58d880. --- src/gurobi_optimods/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gurobi_optimods/__init__.py b/src/gurobi_optimods/__init__.py index 01a79b82..c4f16c00 100644 --- a/src/gurobi_optimods/__init__.py +++ b/src/gurobi_optimods/__init__.py @@ -1,3 +1,3 @@ __doc__ = "Gurobi OptiMods" -__version__ = "2.0.2.dev0" +__version__ = "2.0.1" From f9d35e2dd35bd33988b83f08c0df322f92809508 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 21:05:10 +1000 Subject: [PATCH 12/17] CI fix: fetch multiple numpy wheels --- .github/workflows/wheel-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheel-tests.yml b/.github/workflows/wheel-tests.yml index da054a35..6c2536df 100644 --- a/.github/workflows/wheel-tests.yml +++ b/.github/workflows/wheel-tests.yml @@ -37,7 +37,8 @@ jobs: python -m build - name: Fetch dependencies for offline install run: | - pip wheel --wheel-dir=dist gurobipy pandas numpy scipy gurobipy-pandas + pip wheel --wheel-dir=dist gurobipy pandas "numpy<2" scipy gurobipy-pandas + pip wheel --wheel-dir=dist "numpy>=2" - name: Install from built wheel run: | python -m pip install --find-links dist --no-index --only-binary=:all: gurobi-optimods From af07036d9c7c965fd59d6c3d0a3747c4bd667e1b Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Mon, 17 Jun 2024 21:08:05 +1000 Subject: [PATCH 13/17] CI fix: ensure a numpy <2 wheel is available --- .github/workflows/wheel-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheel-tests.yml b/.github/workflows/wheel-tests.yml index 6c2536df..97b9ea85 100644 --- a/.github/workflows/wheel-tests.yml +++ b/.github/workflows/wheel-tests.yml @@ -37,8 +37,8 @@ jobs: python -m build - name: Fetch dependencies for offline install run: | - pip wheel --wheel-dir=dist gurobipy pandas "numpy<2" scipy gurobipy-pandas - pip wheel --wheel-dir=dist "numpy>=2" + pip wheel --wheel-dir=dist gurobipy pandas numpy scipy gurobipy-pandas + pip wheel --wheel-dir=dist "numpy<2" - name: Install from built wheel run: | python -m pip install --find-links dist --no-index --only-binary=:all: gurobi-optimods From 4b6bd7e5535752b42270a5d9654fc3125ef75595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 09:26:06 +1000 Subject: [PATCH 14/17] Bump urllib3 from 2.2.1 to 2.2.2 in /docs (#145) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.2.1...2.2.2) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 902b1462..7c658301 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -54,5 +54,5 @@ sphinxcontrib-qthelp==1.0.7 sphinxcontrib-serializinghtml==1.1.10 tabulate==0.9.0 typing_extensions==4.11.0 -urllib3==2.2.1 +urllib3==2.2.2 webencodings==0.5.1 From a427d585a1efdf96ea2611bb132880783852ce82 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 21 Jun 2024 10:30:54 +1000 Subject: [PATCH 15/17] Detect size limited license in doctests (#146) Defines a flag in global doctest setup which can be used to skip doctests that require a full license. --- docs/source/conf.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index f4fcb393..0cdd12a1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -92,6 +92,31 @@ numpydoc_xref_ignore = {"optional", "or", "of"} +# -- doctest configuration + +doctest_global_setup = """ +def size_limited_license(): + + result = False + + try: + import gurobipy as gp + from gurobipy import GRB + + with gp.Env(params={"OutputFlag": 0}) as env, gp.Model(env=env) as model: + x = model.addVars(2001) + model.optimize() + except gp.GurobiError as e: + if e.errno == GRB.Error.SIZE_LIMIT_EXCEEDED: + result = True + + return result + + +size_limited_license = size_limited_license() +""" + + # -- Docstring preprocessing for autodoc autodoc_typehints = "none" From b590e7684d59c6939234ff018931db59327466f1 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 21 Jun 2024 10:53:43 +1000 Subject: [PATCH 16/17] Unify approach to size limited skips (#147) - Provide a utility function in unit tests - Use the same check in doctests and unittests --- docs/source/conf.py | 3 --- tests/opf/test_graphics.py | 14 ++------------ tests/opf/test_solver.py | 12 +----------- tests/utils.py | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0cdd12a1..0d8e5176 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -111,9 +111,6 @@ def size_limited_license(): result = True return result - - -size_limited_license = size_limited_license() """ diff --git a/tests/opf/test_graphics.py b/tests/opf/test_graphics.py index e6ba177d..6531bb28 100644 --- a/tests/opf/test_graphics.py +++ b/tests/opf/test_graphics.py @@ -6,8 +6,6 @@ import pathlib import unittest -import gurobipy as gp - from gurobi_optimods.datasets import load_opf_example, load_opf_extra from gurobi_optimods.opf import ( compute_violations, @@ -16,6 +14,8 @@ violation_plot, ) +from ..utils import size_limited_license + # If plotly is not installed, tests will be skipped try: import plotly @@ -23,16 +23,6 @@ plotly = None -def size_limited_license(): - with gp.Env(params={"OutputFlag": 0}) as env, gp.Model(env=env) as model: - model.addVars(2001) - try: - model.optimize() - return False - except gp.GurobiError: - return True - - @unittest.skipIf(plotly is None, "plotly is not installed") class TestGraphicsCase9(unittest.TestCase): def setUp(self): diff --git a/tests/opf/test_solver.py b/tests/opf/test_solver.py index 55495bdd..e2868c41 100644 --- a/tests/opf/test_solver.py +++ b/tests/opf/test_solver.py @@ -4,20 +4,10 @@ import random import unittest -import gurobipy as gp - from gurobi_optimods.datasets import load_opf_example from gurobi_optimods.opf import solve_opf - -def size_limited_license(): - with gp.Env(params={"OutputFlag": 0}) as env, gp.Model(env=env) as model: - model.addVars(2001) - try: - model.optimize() - return False - except gp.GurobiError: - return True +from ..utils import size_limited_license class TestInvalidData(unittest.TestCase): diff --git a/tests/utils.py b/tests/utils.py index ee5a5c8a..bd76da69 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -27,3 +27,20 @@ def skip_wrapper(*args, **kwargs): raise return skip_wrapper + + +def size_limited_license(): + result = False + + try: + import gurobipy as gp + from gurobipy import GRB + + with gp.Env(params={"OutputFlag": 0}) as env, gp.Model(env=env) as model: + x = model.addVars(2001) + model.optimize() + except gp.GurobiError as e: + if e.errno == GRB.Error.SIZE_LIMIT_EXCEEDED: + result = True + + return result From 0c189c6aaae2ac8b23a38cb069c6d00ed265b788 Mon Sep 17 00:00:00 2001 From: Simon Bowly Date: Fri, 21 Jun 2024 10:57:20 +1000 Subject: [PATCH 17/17] Conditionally skip doctests requiring a full license --- docs/source/mods/metromap.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/mods/metromap.rst b/docs/source/mods/metromap.rst index 69fe027d..7a0f3c05 100644 --- a/docs/source/mods/metromap.rst +++ b/docs/source/mods/metromap.rst @@ -383,6 +383,7 @@ The OptiMod can be run as follows: .. doctest:: solve :options: +NORMALIZE_WHITESPACE + :skipif: size_limited_license() >>> from gurobi_optimods import datasets >>> from gurobi_optimods.metromap import metromap @@ -500,6 +501,7 @@ this OptiMod. Here is an example of how this could be done .. testcode:: combine + :skipif: size_limited_license() # import all requirements import networkx as nx