m4opt 2.2.0__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {m4opt-2.2.0 → m4opt-2.3.0}/.github/workflows/ci_cron_weekly.yml +1 -1
- {m4opt-2.2.0 → m4opt-2.3.0}/.github/workflows/ci_tests.yml +1 -1
- {m4opt-2.2.0 → m4opt-2.3.0}/.pre-commit-config.yaml +1 -1
- {m4opt-2.2.0 → m4opt-2.3.0}/CHANGES.rst +16 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/PKG-INFO +1 -1
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/changes.rst +16 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/schedule.py +2 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_version.py +3 -3
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/milp.py +19 -4
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/tests/test_milp.py +11 -3
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/PKG-INFO +1 -1
- {m4opt-2.2.0 → m4opt-2.3.0}/.github/dependabot.yml +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/.github/workflows/publish.yml +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/.gitignore +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/.readthedocs.yml +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/CITATION.cff +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/MANIFEST.in +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/Makefile +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/_static/css/risk_table.css +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/_static/example.ecsv +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/_static/example.gif +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/conf.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/design/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/design/milp.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/contributing.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/npr7150.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/related.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/dev/testing.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/cli.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/constraints.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/dynamics.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/fov.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/milp.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/missions.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/observer.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/skygrid.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/synphot.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/guide/utils.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/install/cplex.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/install/deploy.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/install/gurobi.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/install/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/make.bat +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/refs.bib +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/scenarios/dorado.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/scenarios/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/scenarios/sedmachine.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/docs/scenarios/ztf.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/licenses/DORADO_LICENSE.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/licenses/LICENSE.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/licenses/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/licenses/TEMPLATE_LICENCE.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/animate.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/prime.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/tests/conftest.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/tests/data/800.fits +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/tests/test_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/_cli/tests/test_end_to_end.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/conftest.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_airmass.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_atnight.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_body_separation.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_earth_limb.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_galactic.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_logical.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_positional.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/_radiation.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/tests/test_body_separation.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/tests/test_earth_limb.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/tests/test_galactic.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/constraints/tests/test_positional.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/dynamics/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/dynamics/_roll.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/dynamics/_slew.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/dynamics/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/dynamics/tests/test_roll.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/extern/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/fov/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/fov/_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_rubin/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_rubin/data/LICENSE.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_rubin/data/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_rubin/data/lsstCamSim.yaml +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ultrasat/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ultrasat/data/AllSS_grid_361.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ultrasat/data/LCS_nonoverlapping_grid.csv +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ultrasat/data/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_uvex.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ztf/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ztf/data/LICENSE.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ztf/data/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/missions/_ztf/data/ZTF_Fields.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/observer/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/observer/_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/observer/_earth_fixed.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/observer/_spice.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/observer/_tle.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/py.typed +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/_geodesic.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/_healpix.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/_sinusoidal.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/_spiral.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/skygrid/tests/test_skygrid.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/_bandpass.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/_detector.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/_extrinsic.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/_math.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_core.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_galactic.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10FebZen.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10JunZen.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10Nog.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10Nwh.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10Phx.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10Tuc.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/10Zen.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/README.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_skybright/data/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_zodiacal/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_zodiacal/data/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_zodiacal/data/leinert_zodi.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/background/_zodiacal/data/stis_zodi_high.ecsv +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/extinction/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/extinction/_dust.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/extinction/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/extinction/tests/test_dust.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/synphot/tests/test_detector.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/tests/hypothesis.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/tests/plugins/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/tests/plugins/problem_size_limits.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/console.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/functional.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/numpy.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/optimization.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/pybtex/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/pybtex/styles/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/pybtex/styles/short_alpha.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/resource.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/sympy.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/__init__.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/conftest.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/sphinx_roots/test-pybtex/conf.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/sphinx_roots/test-pybtex/index.rst +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/sphinx_roots/test-pybtex/refs.bib +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/test_console.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/test_optimization.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/tests/test_pybtex.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt/utils/typing_extensions.py +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/SOURCES.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/dependency_links.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/entry_points.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/requires.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/m4opt.egg-info/top_level.txt +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/pyproject.toml +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/setup.cfg +0 -0
- {m4opt-2.2.0 → m4opt-2.3.0}/tox.ini +0 -0
|
@@ -29,7 +29,7 @@ jobs:
|
|
|
29
29
|
steps:
|
|
30
30
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
31
31
|
- name: Cache Astropy data
|
|
32
|
-
uses: actions/cache@
|
|
32
|
+
uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
|
|
33
33
|
with:
|
|
34
34
|
key: ${{ matrix.toxenv }}
|
|
35
35
|
path: ~/.astropy/cache
|
|
@@ -75,7 +75,7 @@ jobs:
|
|
|
75
75
|
with:
|
|
76
76
|
fetch-depth: 0
|
|
77
77
|
- name: Cache Astropy data
|
|
78
|
-
uses: actions/cache@
|
|
78
|
+
uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
|
|
79
79
|
with:
|
|
80
80
|
key: ${{ matrix.toxenv }}
|
|
81
81
|
path: ~/.astropy/cache
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
Changes
|
|
3
3
|
*******
|
|
4
4
|
|
|
5
|
+
2.3.0 (2026-01-22)
|
|
6
|
+
==================
|
|
7
|
+
|
|
8
|
+
- When available memory is limited by the ``--memory`` option, spool CPLEX's
|
|
9
|
+
node file to disk.
|
|
10
|
+
|
|
11
|
+
- If the solution is aborted because the best bound falls below the objective
|
|
12
|
+
lower cutoff, then record the solution status as
|
|
13
|
+
`aborted, lower cutoff reached`.
|
|
14
|
+
|
|
15
|
+
2.2.1 (2026-01-16)
|
|
16
|
+
==================
|
|
17
|
+
|
|
18
|
+
- Fix crash for sky maps with invalid pixels when using a fixed absolute
|
|
19
|
+
magnitude.
|
|
20
|
+
|
|
5
21
|
2.2.0 (2026-01-15)
|
|
6
22
|
==================
|
|
7
23
|
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
Changes
|
|
3
3
|
*******
|
|
4
4
|
|
|
5
|
+
2.3.0 (2026-01-22)
|
|
6
|
+
==================
|
|
7
|
+
|
|
8
|
+
- When available memory is limited by the ``--memory`` option, spool CPLEX's
|
|
9
|
+
node file to disk.
|
|
10
|
+
|
|
11
|
+
- If the solution is aborted because the best bound falls below the objective
|
|
12
|
+
lower cutoff, then record the solution status as
|
|
13
|
+
`aborted, lower cutoff reached`.
|
|
14
|
+
|
|
15
|
+
2.2.1 (2026-01-16)
|
|
16
|
+
==================
|
|
17
|
+
|
|
18
|
+
- Fix crash for sky maps with invalid pixels when using a fixed absolute
|
|
19
|
+
magnitude.
|
|
20
|
+
|
|
5
21
|
2.2.0 (2026-01-15)
|
|
6
22
|
==================
|
|
7
23
|
|
|
@@ -355,6 +355,8 @@ def schedule(
|
|
|
355
355
|
appmag_quantiles = stats.norm(
|
|
356
356
|
loc=appmag_mu[:, np.newaxis], scale=appmag_sigma[:, np.newaxis]
|
|
357
357
|
).ppf(quantiles)
|
|
358
|
+
# FIXME: prune pixels with infinite distance
|
|
359
|
+
appmag_quantiles[np.isposinf(appmag_mu)] = np.inf
|
|
358
360
|
|
|
359
361
|
with observing(
|
|
360
362
|
observer_location=observer_locations[0],
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.
|
|
32
|
-
__version_tuple__ = version_tuple = (2,
|
|
31
|
+
__version__ = version = '2.3.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 3, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'gbb83227d0'
|
|
@@ -6,7 +6,7 @@ from gzip import GzipFile
|
|
|
6
6
|
from io import BufferedWriter
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from shutil import copyfileobj
|
|
9
|
-
from tempfile import NamedTemporaryFile
|
|
9
|
+
from tempfile import NamedTemporaryFile, gettempdir
|
|
10
10
|
from unittest.mock import patch
|
|
11
11
|
|
|
12
12
|
import cplex
|
|
@@ -25,6 +25,7 @@ __all__ = ("Model", "SolveSolution")
|
|
|
25
25
|
class LowerCutoffCallback:
|
|
26
26
|
def __init__(self, cutoff: float):
|
|
27
27
|
self._cutoff = cutoff
|
|
28
|
+
self._reached = False
|
|
28
29
|
|
|
29
30
|
def invoke(self, context: cplex.callbacks.Context):
|
|
30
31
|
best_bound = context.get_double_info(cplex.callbacks.CallbackInfo.best_bound)
|
|
@@ -32,6 +33,7 @@ class LowerCutoffCallback:
|
|
|
32
33
|
print(
|
|
33
34
|
f"giving up because best bound ({best_bound}) <= cutoff ({self._cutoff})"
|
|
34
35
|
)
|
|
36
|
+
self._reached = True
|
|
35
37
|
context.abort()
|
|
36
38
|
|
|
37
39
|
|
|
@@ -89,6 +91,7 @@ class Model(_Model):
|
|
|
89
91
|
|
|
90
92
|
self.context.solver.log_output = verbose
|
|
91
93
|
self.context.cplex_parameters.threads = jobs
|
|
94
|
+
self.context.cplex_parameters.workdir = gettempdir()
|
|
92
95
|
|
|
93
96
|
# Disable deterministic parallelism. We're OK with results being
|
|
94
97
|
# slightly dependent upon timing.
|
|
@@ -110,7 +113,8 @@ class Model(_Model):
|
|
|
110
113
|
)
|
|
111
114
|
|
|
112
115
|
if np.isfinite(memory):
|
|
113
|
-
self.context.cplex_parameters.mip.
|
|
116
|
+
self.context.cplex_parameters.mip.strategy.file = 3
|
|
117
|
+
self.context.cplex_parameters.workmem = memory.to_value(u.MiB)
|
|
114
118
|
|
|
115
119
|
if lowercutoff is not None:
|
|
116
120
|
# FIXME: Setting lowercutoff drastically hurts solution quality.
|
|
@@ -118,8 +122,9 @@ class Model(_Model):
|
|
|
118
122
|
# See https://github.com/IBMDecisionOptimization/docplex/issues/20
|
|
119
123
|
#
|
|
120
124
|
# model.context.cplex_parameters.mip.tolerances.lowercutoff = cutoff
|
|
125
|
+
self._lower_cutoff = LowerCutoffCallback(lowercutoff)
|
|
121
126
|
self.get_cplex().set_callback(
|
|
122
|
-
|
|
127
|
+
self._lower_cutoff,
|
|
123
128
|
cplex.callbacks.Context.id.global_progress,
|
|
124
129
|
)
|
|
125
130
|
|
|
@@ -186,7 +191,17 @@ class Model(_Model):
|
|
|
186
191
|
|
|
187
192
|
def solve(self, **kwargs):
|
|
188
193
|
with patch("docplex.mp.solution.SolveSolution", SolveSolution):
|
|
189
|
-
|
|
194
|
+
result = super().solve(**kwargs)
|
|
195
|
+
if (
|
|
196
|
+
(cutoff := getattr(self, "_lower_cutoff", None))
|
|
197
|
+
and cutoff._reached
|
|
198
|
+
and self.solve_details.status == "aborted"
|
|
199
|
+
):
|
|
200
|
+
message = "aborted, lower cutoff reached"
|
|
201
|
+
self._solve_details._solve_status = message
|
|
202
|
+
if result is not None:
|
|
203
|
+
result.solve_details._solve_status = message
|
|
204
|
+
return result
|
|
190
205
|
|
|
191
206
|
def min(self, *args):
|
|
192
207
|
return np.asarray(super().min(*args)).view(VariableArray)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Test production problem size limits for MILP solvers."""
|
|
2
2
|
|
|
3
|
+
from tempfile import gettempdir
|
|
4
|
+
|
|
3
5
|
import docplex.mp.model
|
|
4
6
|
import numpy as np
|
|
5
7
|
import pytest
|
|
@@ -24,26 +26,32 @@ def test_cplex_parameters():
|
|
|
24
26
|
"""Test configuration of CPLEX solver parameters."""
|
|
25
27
|
m = Model()
|
|
26
28
|
assert m.context.cplex_parameters.mip.pool.capacity.value == 0
|
|
29
|
+
assert m.context.cplex_parameters.mip.strategy.file.value == 1
|
|
27
30
|
assert m.context.cplex_parameters.parallel.value == -1
|
|
28
31
|
assert m.context.cplex_parameters.threads.value == 0
|
|
29
32
|
assert m.context.cplex_parameters.timelimit.value == 1e75
|
|
30
|
-
assert m.context.cplex_parameters.
|
|
33
|
+
assert m.context.cplex_parameters.workmem.value == 2048
|
|
34
|
+
assert m.context.cplex_parameters.workdir.value == gettempdir()
|
|
31
35
|
assert m.context.solver.log_output
|
|
32
36
|
|
|
33
37
|
m = Model(timelimit=1 * u.minute, jobs=3)
|
|
34
38
|
assert m.context.cplex_parameters.mip.pool.capacity.value == 0
|
|
39
|
+
assert m.context.cplex_parameters.mip.strategy.file.value == 1
|
|
35
40
|
assert m.context.cplex_parameters.parallel.value == -1
|
|
36
41
|
assert m.context.cplex_parameters.threads.value == 3
|
|
37
42
|
assert m.context.cplex_parameters.timelimit.value == 60
|
|
38
|
-
assert m.context.cplex_parameters.
|
|
43
|
+
assert m.context.cplex_parameters.workmem.value == 2048
|
|
44
|
+
assert m.context.cplex_parameters.workdir.value == gettempdir()
|
|
39
45
|
assert m.context.solver.log_output
|
|
40
46
|
|
|
41
47
|
m = Model(timelimit=1 * u.minute, jobs=3, memory=5 * u.GiB)
|
|
42
48
|
assert m.context.cplex_parameters.mip.pool.capacity.value == 0
|
|
49
|
+
assert m.context.cplex_parameters.mip.strategy.file.value == 3
|
|
43
50
|
assert m.context.cplex_parameters.parallel.value == -1
|
|
44
51
|
assert m.context.cplex_parameters.threads.value == 3
|
|
45
52
|
assert m.context.cplex_parameters.timelimit.value == 60
|
|
46
|
-
assert m.context.cplex_parameters.
|
|
53
|
+
assert m.context.cplex_parameters.workmem.value == 5120
|
|
54
|
+
assert m.context.cplex_parameters.workdir.value == gettempdir()
|
|
47
55
|
assert m.context.solver.log_output
|
|
48
56
|
|
|
49
57
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|