Skip to content

Commit d7db8d3

Browse files
authored
Merge branch 'main' into Example-seed-issue
2 parents 466e3b4 + 828560c commit d7db8d3

File tree

23 files changed

+243
-87
lines changed

23 files changed

+243
-87
lines changed

.github/workflows/test_branches.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,8 @@ jobs:
534534
echo "DYLD_LIBRARY_PATH=${env:DYLD_LIBRARY_PATH}:$GAMS_DIR" `
535535
Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
536536
$INSTALLER = "${env:DOWNLOAD_DIR}/gams_install.exe"
537-
# We are pinning to 29.1.0 because a license is required for
538-
# versions after this in order to run in demo mode.
539-
$URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/29.1.0"
537+
# Demo licenses are included for 5mo from the newest release
538+
$URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/50.1.0"
540539
if ( "${{matrix.TARGET}}" -eq "win" ) {
541540
$URL = "$URL/windows/windows_x64_64.exe"
542541
} elseif ( "${{matrix.TARGET}}" -eq "osx" ) {

.github/workflows/test_pr_and_main.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,8 @@ jobs:
586586
echo "DYLD_LIBRARY_PATH=${env:DYLD_LIBRARY_PATH}:$GAMS_DIR" `
587587
Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
588588
$INSTALLER = "${env:DOWNLOAD_DIR}/gams_install.exe"
589-
# We are pinning to 29.1.0 because a license is required for
590-
# versions after this in order to run in demo mode.
591-
$URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/29.1.0"
589+
# Demo licenses are included for 5mo from the newest release
590+
$URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/50.1.0"
592591
if ( "${{matrix.TARGET}}" -eq "win" ) {
593592
$URL = "$URL/windows/windows_x64_64.exe"
594593
} elseif ( "${{matrix.TARGET}}" -eq "osx" ) {

pyomo/common/dependencies.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -443,25 +443,9 @@ def check_min_version(module, min_version):
443443
module = indicator._module
444444
else:
445445
return False
446-
if check_min_version._parser is None:
447-
try:
448-
from packaging import version as _version
449-
450-
_parser = _version.parse
451-
except ImportError:
452-
# pkg_resources is an order of magnitude slower to import than
453-
# packaging. Only use it if the preferred (but optional)
454-
# packaging library is not present
455-
from pkg_resources import parse_version as _parser
456-
check_min_version._parser = _parser
457-
else:
458-
_parser = check_min_version._parser
459446

460447
version = getattr(module, '__version__', '0.0.0')
461-
return _parser(min_version) <= _parser(version)
462-
463-
464-
check_min_version._parser = None
448+
return packaging.version.parse(min_version) <= packaging.version.parse(version)
465449

466450

467451
#
@@ -993,6 +977,12 @@ def _finalize_pympler(module, available):
993977
import pympler.muppy
994978

995979

980+
def _finalize_packaging(module, available):
981+
if available:
982+
# Import key subpackages that we will want to assume are present
983+
import packaging.version
984+
985+
996986
def _finalize_matplotlib(module, available):
997987
if not available:
998988
return
@@ -1094,6 +1084,10 @@ def _pyutilib_importer():
10941084
)
10951085
random, _ = attempt_import('random')
10961086

1087+
# Necessary for minimum version checking for other optional dependencies
1088+
packaging, packaging_available = attempt_import(
1089+
'packaging', deferred_submodules=['version'], callback=_finalize_packaging
1090+
)
10971091
# Commonly-used optional dependencies
10981092
dill, dill_available = attempt_import('dill')
10991093
mpi4py, mpi4py_available = attempt_import(

pyomo/common/tests/test_dependencies.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
dill,
3232
dill_available,
3333
mpi4py_available,
34+
packaging_available,
3435
)
3536

3637
import pyomo.common.tests.dep_mod as dep_mod
@@ -125,6 +126,9 @@ def test_imported_deferred_import(self):
125126
self.assertIs(dep_mod.bogus_nonexisting_module_available, False)
126127
self.assertIs(type(dep_mod.bogus_nonexisting_module), ModuleUnavailable)
127128

129+
@unittest.skipUnless(
130+
packaging_available, "min_version tests require packaging module"
131+
)
128132
def test_min_version(self):
129133
mod, avail = attempt_import(
130134
'pyomo.common.tests.dep_mod', minimum_version='1.0', defer_import=False
@@ -177,6 +181,9 @@ def test_min_version(self):
177181
mod, avail = attempt_import('pyomo.common.tests.bogus', minimum_version='1.0')
178182
self.assertFalse(check_min_version(mod, '1.0'))
179183

184+
@unittest.skipUnless(
185+
packaging_available, "min_version tests require packaging module"
186+
)
180187
def test_and_or(self):
181188
mod0, avail0 = attempt_import('ply', defer_import=True)
182189
mod1, avail1 = attempt_import('pyomo.common.tests.dep_mod', defer_import=True)
@@ -231,6 +238,9 @@ def test_and_or(self):
231238
self.assertIsInstance(_ror, _DeferredOr)
232239
self.assertTrue(_ror)
233240

241+
@unittest.skipUnless(
242+
packaging_available, "min_version tests require packaging module"
243+
)
234244
def test_callbacks(self):
235245
ans = []
236246

pyomo/contrib/appsi/solvers/highs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from pyomo.common.collections import ComponentMap
1515
from pyomo.common.dependencies import attempt_import
1616
from pyomo.common.errors import PyomoException
17+
from pyomo.common.flags import NOTSET
1718
from pyomo.common.timing import HierarchicalTimer
1819
from pyomo.common.config import ConfigValue, NonNegativeInt
1920
from pyomo.common.tee import TeeStream, capture_output
@@ -684,9 +685,13 @@ def _postsolve(self, timer: HierarchicalTimer):
684685
results.termination_condition = TerminationCondition.maxTimeLimit
685686
elif status == highspy.HighsModelStatus.kIterationLimit:
686687
results.termination_condition = TerminationCondition.maxIterations
688+
elif status == getattr(highspy.HighsModelStatus, "kSolutionLimit", NOTSET):
689+
# kSolutionLimit was introduced in HiGHS v1.5.3 for MIP-related limits
690+
results.termination_condition = TerminationCondition.maxIterations
687691
elif status == highspy.HighsModelStatus.kUnknown:
688692
results.termination_condition = TerminationCondition.unknown
689693
else:
694+
logger.warning(f'Received unhandled {status=} from solver HiGHS.')
690695
results.termination_condition = TerminationCondition.unknown
691696

692697
timer.start('load solution')

pyomo/contrib/appsi/solvers/maingo.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,18 @@ def available(self):
173173
return self._available
174174

175175
def version(self):
176-
import pkg_resources
176+
import importlib.metadata
177177

178-
version = pkg_resources.get_distribution('maingopy').version
179-
180-
return tuple(int(k) for k in version.split('.'))
178+
try:
179+
version = importlib.metadata.version('maingopy').split('.')
180+
except ImportError:
181+
return None
182+
for i, n in enumerate(version):
183+
try:
184+
version[i] = int(version[i])
185+
except:
186+
pass
187+
return tuple(version)
181188

182189
@property
183190
def config(self) -> MAiNGOConfig:

pyomo/contrib/appsi/solvers/tests/test_highs_persistent.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from pyomo.contrib.appsi.solvers.highs import Highs
2121
from pyomo.contrib.appsi.base import TerminationCondition
2222

23+
from pyomo.contrib.solver.tests.solvers import instances
24+
2325

2426
opt = Highs()
2527
if not opt.available():
@@ -183,3 +185,10 @@ def test_warm_start(self):
183185
pyo.SolverFactory("appsi_highs").solve(m, tee=True, warmstart=True)
184186
log = output.getvalue()
185187
self.assertIn("MIP start solution is feasible, objective value is 25", log)
188+
189+
def test_node_limit_term_cond(self):
190+
opt = Highs()
191+
opt.highs_options.update({"mip_max_nodes": 1})
192+
mod = instances.multi_knapsack()
193+
res = opt.solve(mod)
194+
assert res.termination_condition == TerminationCondition.maxIterations

pyomo/contrib/fme/fourier_motzkin_elimination.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -730,12 +730,9 @@ def post_process_fme_constraints(
730730
continue
731731
# deactivate the constraint
732732
projected_constraints[i].deactivate()
733-
m.del_component(obj)
734-
# make objective to maximize its infeasibility
735-
obj = Objective(
736-
expr=projected_constraints[i].body - projected_constraints[i].lower
737-
)
738-
m.add_component(obj_name, obj)
733+
# Our constraint looks like: 0 <= a^Tx - b, so make objective to
734+
# maximize its infeasibility
735+
obj.expr = projected_constraints[i].body - projected_constraints[i].lower
739736
results = solver_factory.solve(m)
740737
if results.solver.termination_condition == TerminationCondition.unbounded:
741738
obj_val = -float('inf')
@@ -753,7 +750,6 @@ def post_process_fme_constraints(
753750
obj_val = value(obj)
754751
# if we couldn't make it infeasible, it's useless
755752
if obj_val >= tolerance:
756-
m.del_component(projected_constraints[i])
757753
del projected_constraints[i]
758754
else:
759755
projected_constraints[i].activate()

pyomo/contrib/parmest/utils/model_utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ def convert_params_to_vars(model, param_names=None, fix_vars=False):
134134
v.name in param_names for v in identify_mutable_parameters(expr)
135135
):
136136
new_expr = replace_expressions(expr=expr, substitution_map=substitution_map)
137-
model.del_component(expr)
138-
model.add_component(expr.name, pyo.Expression(rule=new_expr))
137+
expr.expr = new_expr
139138

140139
# Convert Params to Vars in Constraint expressions
141140
num_constraints = len(list(model.component_objects(pyo.Constraint, active=True)))

pyomo/contrib/pynumero/src/AmplInterface.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class PYNUMERO_ASL_EXPORT AmplInterface {
6666
// get the initial values for x
6767
void get_init_x(double *invec, int n);
6868

69-
// get the initia values for the multipliers lambda
69+
// get the initial values for the multipliers lambda
7070
void get_init_multipliers(double *invec, int n);
7171

7272
// evaluate the objective function

0 commit comments

Comments
 (0)