Skip to content

Commit 00041ff

Browse files
authored
Merge branch 'main' into skip-draft-prs
2 parents b082419 + f15a1da commit 00041ff

File tree

19 files changed

+451
-317
lines changed

19 files changed

+451
-317
lines changed

pyomo/contrib/gdpopt/tests/test_LBB.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def test_infeasible_GDP(self):
5959
self.assertIsNone(m.d.disjuncts[0].indicator_var.value)
6060
self.assertIsNone(m.d.disjuncts[1].indicator_var.value)
6161

62+
@unittest.skipUnless(z3_available, "Z3 SAT solver is not available")
6263
def test_infeasible_GDP_check_sat(self):
6364
"""Test for infeasible GDP with check_sat option True."""
6465
m = ConcreteModel()

pyomo/contrib/gdpopt/tests/test_gdpopt.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from pyomo.common.collections import Bunch
2323
from pyomo.common.config import ConfigDict, ConfigValue
2424
from pyomo.common.fileutils import import_file, PYOMO_ROOT_DIR
25-
from pyomo.contrib.appsi.solvers.gurobi import Gurobi
2625
from pyomo.contrib.gdpopt.create_oa_subproblems import (
2726
add_util_block,
2827
add_disjunct_list,
@@ -767,6 +766,9 @@ def test_time_limit(self):
767766
results.solver.termination_condition, TerminationCondition.maxTimeLimit
768767
)
769768

769+
@unittest.skipUnless(
770+
license_available, "No BARON license--8PP logical problem exceeds demo size"
771+
)
770772
def test_LOA_8PP_logical_default_init(self):
771773
"""Test logic-based outer approximation with 8PP."""
772774
exfile = import_file(join(exdir, 'eight_process', 'eight_proc_logical.py'))
@@ -870,6 +872,9 @@ def test_LOA_8PP_maxBinary(self):
870872
)
871873
ct.check_8PP_solution(self, eight_process, results)
872874

875+
@unittest.skipUnless(
876+
license_available, "No BARON license--8PP logical problem exceeds demo size"
877+
)
873878
def test_LOA_8PP_logical_maxBinary(self):
874879
"""Test logic-based OA with max_binary initialization."""
875880
exfile = import_file(join(exdir, 'eight_process', 'eight_proc_logical.py'))
@@ -1050,7 +1055,11 @@ def assert_correct_disjuncts_active(
10501055

10511056
self.assertTrue(fabs(value(eight_process.profit.expr) - 68) <= 1e-2)
10521057

1053-
@unittest.skipUnless(Gurobi().available(), "APPSI Gurobi solver is not available")
1058+
@unittest.skipUnless(
1059+
SolverFactory('appsi_gurobi').available(exception_flag=False)
1060+
and SolverFactory('appsi_gurobi').license_is_valid(),
1061+
"Legacy APPSI Gurobi solver is not available",
1062+
)
10541063
def test_auto_persistent_solver(self):
10551064
exfile = import_file(join(exdir, 'eight_process', 'eight_proc_model.py'))
10561065
m = exfile.build_eight_process_flowsheet()
@@ -1126,6 +1135,9 @@ def test_RIC_8PP_default_init(self):
11261135
)
11271136
ct.check_8PP_solution(self, eight_process, results)
11281137

1138+
@unittest.skipUnless(
1139+
license_available, "No BARON license--8PP logical problem exceeds demo size"
1140+
)
11291141
def test_RIC_8PP_logical_default_init(self):
11301142
"""Test logic-based outer approximation with 8PP."""
11311143
exfile = import_file(join(exdir, 'eight_process', 'eight_proc_logical.py'))

pyomo/contrib/gdpopt/util.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,13 @@ def _add_bigm_constraint_to_transformed_model(m, constraint, block):
553553
# making a Reference to the ComponentData so that it will look like an
554554
# indexed component for now. If I redesign bigm at some point, then this
555555
# could be prettier.
556-
bigm._transform_constraint(Reference(constraint), parent_disjunct, None, [], [])
556+
bigm._transform_constraint(
557+
Reference(constraint),
558+
parent_disjunct,
559+
None,
560+
[],
561+
[],
562+
1 - parent_disjunct.binary_indicator_var,
563+
)
557564
# Now get rid of it because this is a class attribute!
558565
del bigm._config

pyomo/core/expr/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def size(self):
360360
"""
361361
return visitor.sizeof_expression(self)
362362

363-
def _apply_operation(self, result): # pragma: no cover
363+
def _apply_operation(self, result):
364364
"""
365365
Compute the values of this node given the values of its children.
366366

pyomo/core/expr/numeric_expr.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,8 +2288,11 @@ def _iadd_mutablenpvsum_mutable(a, b):
22882288
def _iadd_mutablenpvsum_native(a, b):
22892289
if not b:
22902290
return a
2291-
a._args_.append(b)
2292-
a._nargs += 1
2291+
if a._args_ and a._args_[-1].__class__ in native_numeric_types:
2292+
a._args_[-1] += b
2293+
else:
2294+
a._args_.append(b)
2295+
a._nargs += 1
22932296
return a
22942297

22952298

@@ -2301,9 +2304,7 @@ def _iadd_mutablenpvsum_npv(a, b):
23012304

23022305
def _iadd_mutablenpvsum_param(a, b):
23032306
if b.is_constant():
2304-
b = b.value
2305-
if not b:
2306-
return a
2307+
return _iadd_mutablesum_native(a, b.value)
23072308
a._args_.append(b)
23082309
a._nargs += 1
23092310
return a
@@ -2384,8 +2385,11 @@ def _iadd_mutablelinear_mutable(a, b):
23842385
def _iadd_mutablelinear_native(a, b):
23852386
if not b:
23862387
return a
2387-
a._args_.append(b)
2388-
a._nargs += 1
2388+
if a._args_ and a._args_[-1].__class__ in native_numeric_types:
2389+
a._args_[-1] += b
2390+
else:
2391+
a._args_.append(b)
2392+
a._nargs += 1
23892393
return a
23902394

23912395

@@ -2397,9 +2401,7 @@ def _iadd_mutablelinear_npv(a, b):
23972401

23982402
def _iadd_mutablelinear_param(a, b):
23992403
if b.is_constant():
2400-
b = b.value
2401-
if not b:
2402-
return a
2404+
return _iadd_mutablesum_native(a, b.value)
24032405
a._args_.append(b)
24042406
a._nargs += 1
24052407
return a
@@ -2483,8 +2485,11 @@ def _iadd_mutablesum_mutable(a, b):
24832485
def _iadd_mutablesum_native(a, b):
24842486
if not b:
24852487
return a
2486-
a._args_.append(b)
2487-
a._nargs += 1
2488+
if a._args_ and a._args_[-1].__class__ in native_numeric_types:
2489+
a._args_[-1] += b
2490+
else:
2491+
a._args_.append(b)
2492+
a._nargs += 1
24882493
return a
24892494

24902495

@@ -2496,9 +2501,7 @@ def _iadd_mutablesum_npv(a, b):
24962501

24972502
def _iadd_mutablesum_param(a, b):
24982503
if b.is_constant():
2499-
b = b.value
2500-
if not b:
2501-
return a
2504+
return _iadd_mutablesum_native(a, b.value)
25022505
a._args_.append(b)
25032506
a._nargs += 1
25042507
return a

pyomo/core/expr/template_expr.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
from pyomo.core.expr.base import ExpressionBase, ExpressionArgs_Mixin, NPV_Mixin
2020
from pyomo.core.expr.logical_expr import BooleanExpression
2121
from pyomo.core.expr.numeric_expr import (
22+
ARG_TYPE,
2223
NumericExpression,
23-
SumExpression,
2424
Numeric_NPV_Mixin,
25+
SumExpression,
26+
mutable_expression,
2527
register_arg_type,
26-
ARG_TYPE,
2728
_balanced_parens,
2829
)
2930
from pyomo.core.expr.numvalue import (
@@ -116,18 +117,10 @@ def _to_string(self, values, verbose, smap):
116117
return "%s[%s]" % (values[0], ','.join(values[1:]))
117118

118119
def _resolve_template(self, args):
119-
return args[0].__getitem__(tuple(args[1:]))
120+
return args[0].__getitem__(args[1:])
120121

121122
def _apply_operation(self, result):
122-
args = tuple(
123-
(
124-
arg
125-
if arg.__class__ in native_types or not arg.is_numeric_type()
126-
else value(arg)
127-
)
128-
for arg in result[1:]
129-
)
130-
return result[0].__getitem__(tuple(result[1:]))
123+
return result[0].__getitem__(result[1:])
131124

132125

133126
class Numeric_GetItemExpression(GetItemExpression, NumericExpression):
@@ -258,8 +251,8 @@ def nargs(self):
258251
return 2
259252

260253
def _apply_operation(self, result):
261-
assert len(result) == 2
262-
return getattr(result[0], result[1])
254+
obj, attr = result
255+
return getattr(obj, attr)
263256

264257
def _to_string(self, values, verbose, smap):
265258
assert len(values) == 2
@@ -273,7 +266,7 @@ def _to_string(self, values, verbose, smap):
273266
return "%s.%s" % (values[0], attr)
274267

275268
def _resolve_template(self, args):
276-
return getattr(*tuple(args))
269+
return getattr(*args)
277270

278271

279272
class Numeric_GetAttrExpression(GetAttrExpression, NumericExpression):
@@ -521,7 +514,15 @@ def _to_string(self, values, verbose, smap):
521514
return 'SUM(%s %s)' % (val, iterStr)
522515

523516
def _resolve_template(self, args):
524-
return SumExpression(args)
517+
with mutable_expression() as e:
518+
for arg in args:
519+
e += arg
520+
if e.nargs() > 1:
521+
return e
522+
elif not e.nargs():
523+
return 0
524+
else:
525+
return e.arg(0)
525526

526527

527528
class IndexTemplate(NumericValue):

pyomo/core/tests/unit/test_numeric_expr_dispatcher.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6490,11 +6490,11 @@ def test_mutable_nvp_iadd(self):
64906490
(mutable_npv, self.invalid, NotImplemented),
64916491
(mutable_npv, self.asbinary, _MutableLinearExpression([10, self.bin])),
64926492
(mutable_npv, self.zero, _MutableNPVSumExpression([10])),
6493-
(mutable_npv, self.one, _MutableNPVSumExpression([10, 1])),
6493+
(mutable_npv, self.one, _MutableNPVSumExpression([11])),
64946494
# 4:
6495-
(mutable_npv, self.native, _MutableNPVSumExpression([10, 5])),
6495+
(mutable_npv, self.native, _MutableNPVSumExpression([15])),
64966496
(mutable_npv, self.npv, _MutableNPVSumExpression([10, self.npv])),
6497-
(mutable_npv, self.param, _MutableNPVSumExpression([10, 6])),
6497+
(mutable_npv, self.param, _MutableNPVSumExpression([16])),
64986498
(
64996499
mutable_npv,
65006500
self.param_mut,
@@ -6534,7 +6534,7 @@ def test_mutable_nvp_iadd(self):
65346534
_MutableSumExpression([10] + self.mutable_l2.args),
65356535
),
65366536
(mutable_npv, self.param0, _MutableNPVSumExpression([10])),
6537-
(mutable_npv, self.param1, _MutableNPVSumExpression([10, 1])),
6537+
(mutable_npv, self.param1, _MutableNPVSumExpression([11])),
65386538
# 20:
65396539
(mutable_npv, self.mutable_l3, _MutableNPVSumExpression([10, self.npv])),
65406540
]

pyomo/core/tests/unit/test_numeric_expr_zerofilter.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6020,11 +6020,11 @@ def test_mutable_nvp_iadd(self):
60206020
(mutable_npv, self.invalid, NotImplemented),
60216021
(mutable_npv, self.asbinary, _MutableLinearExpression([10, self.bin])),
60226022
(mutable_npv, self.zero, _MutableNPVSumExpression([10])),
6023-
(mutable_npv, self.one, _MutableNPVSumExpression([10, 1])),
6023+
(mutable_npv, self.one, _MutableNPVSumExpression([11])),
60246024
# 4:
6025-
(mutable_npv, self.native, _MutableNPVSumExpression([10, 5])),
6025+
(mutable_npv, self.native, _MutableNPVSumExpression([15])),
60266026
(mutable_npv, self.npv, _MutableNPVSumExpression([10, self.npv])),
6027-
(mutable_npv, self.param, _MutableNPVSumExpression([10, 6])),
6027+
(mutable_npv, self.param, _MutableNPVSumExpression([16])),
60286028
(
60296029
mutable_npv,
60306030
self.param_mut,
@@ -6064,7 +6064,7 @@ def test_mutable_nvp_iadd(self):
60646064
_MutableSumExpression([10] + self.mutable_l2.args),
60656065
),
60666066
(mutable_npv, self.param0, _MutableNPVSumExpression([10])),
6067-
(mutable_npv, self.param1, _MutableNPVSumExpression([10, 1])),
6067+
(mutable_npv, self.param1, _MutableNPVSumExpression([11])),
60686068
# 20:
60696069
(mutable_npv, self.mutable_l3, _MutableNPVSumExpression([10, self.npv])),
60706070
]

pyomo/core/tests/unit/test_template_expr.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -490,14 +490,14 @@ def c(m):
490490
self.assertEqual(
491491
str(resolve_template(template)),
492492
'x[1,1,10] + '
493-
'(x[2,1,10] + x[2,1,20]) + '
494-
'(x[3,1,10] + x[3,1,20] + x[3,1,30]) + '
495-
'(x[1,2,10]) + '
496-
'(x[2,2,10] + x[2,2,20]) + '
497-
'(x[3,2,10] + x[3,2,20] + x[3,2,30]) + '
498-
'(x[1,3,10]) + '
499-
'(x[2,3,10] + x[2,3,20]) + '
500-
'(x[3,3,10] + x[3,3,20] + x[3,3,30]) <= 0',
493+
'x[2,1,10] + x[2,1,20] + '
494+
'x[3,1,10] + x[3,1,20] + x[3,1,30] + '
495+
'x[1,2,10] + '
496+
'x[2,2,10] + x[2,2,20] + '
497+
'x[3,2,10] + x[3,2,20] + x[3,2,30] + '
498+
'x[1,3,10] + '
499+
'x[2,3,10] + x[2,3,20] + '
500+
'x[3,3,10] + x[3,3,20] + x[3,3,30] <= 0',
501501
)
502502

503503
def test_multidim_nested_sum_rule(self):
@@ -566,14 +566,14 @@ def c(m):
566566
self.assertEqual(
567567
str(resolve_template(template)),
568568
'x[1,1,10] + '
569-
'(x[2,1,10] + x[2,1,20]) + '
570-
'(x[3,1,10] + x[3,1,20] + x[3,1,30]) + '
571-
'(x[1,2,10]) + '
572-
'(x[2,2,10] + x[2,2,20]) + '
573-
'(x[3,2,10] + x[3,2,20] + x[3,2,30]) + '
574-
'(x[1,3,10]) + '
575-
'(x[2,3,10] + x[2,3,20]) + '
576-
'(x[3,3,10] + x[3,3,20] + x[3,3,30]) <= 0',
569+
'x[2,1,10] + x[2,1,20] + '
570+
'x[3,1,10] + x[3,1,20] + x[3,1,30] + '
571+
'x[1,2,10] + '
572+
'x[2,2,10] + x[2,2,20] + '
573+
'x[3,2,10] + x[3,2,20] + x[3,2,30] + '
574+
'x[1,3,10] + '
575+
'x[2,3,10] + x[2,3,20] + '
576+
'x[3,3,10] + x[3,3,20] + x[3,3,30] <= 0',
577577
)
578578

579579
def test_multidim_nested_getattr_sum_rule(self):
@@ -609,14 +609,14 @@ def c(m):
609609
self.assertEqual(
610610
str(resolve_template(template)),
611611
'x[1,1,10] + '
612-
'(x[2,1,10] + x[2,1,20]) + '
613-
'(x[3,1,10] + x[3,1,20] + x[3,1,30]) + '
614-
'(x[1,2,10]) + '
615-
'(x[2,2,10] + x[2,2,20]) + '
616-
'(x[3,2,10] + x[3,2,20] + x[3,2,30]) + '
617-
'(x[1,3,10]) + '
618-
'(x[2,3,10] + x[2,3,20]) + '
619-
'(x[3,3,10] + x[3,3,20] + x[3,3,30]) <= 0',
612+
'x[2,1,10] + x[2,1,20] + '
613+
'x[3,1,10] + x[3,1,20] + x[3,1,30] + '
614+
'x[1,2,10] + '
615+
'x[2,2,10] + x[2,2,20] + '
616+
'x[3,2,10] + x[3,2,20] + x[3,2,30] + '
617+
'x[1,3,10] + '
618+
'x[2,3,10] + x[2,3,20] + '
619+
'x[3,3,10] + x[3,3,20] + x[3,3,30] <= 0',
620620
)
621621

622622
def test_eval_getattr(self):

0 commit comments

Comments
 (0)