Skip to content

Commit 81b29c8

Browse files
authored
Merge branch 'main' into parmest-doc-update
2 parents 4daa215 + e0fcc81 commit 81b29c8

32 files changed

+636
-315
lines changed

doc/OnlineDocs/src/kernel/examples.txt

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -76,29 +76,22 @@
7676
3 : -5.0 : vl[3] - v : 5.0 : True
7777

7878
3 SOSConstraint Declarations
79-
sd : Size=2 Index= OrderedScalarSet
80-
1
81-
Type=1
82-
Weight : Variable
83-
1 : vd[1]
84-
2 : vd[2]
85-
2
86-
Type=1
87-
Weight : Variable
88-
1 : vl[1]
89-
2 : vl[2]
90-
3 : vl[3]
91-
sos1 : Size=1
92-
Type=1
93-
Weight : Variable
94-
1 : vl[1]
95-
2 : vl[2]
96-
3 : vl[3]
97-
sos2 : Size=1
98-
Type=2
99-
Weight : Variable
100-
1 : vd[1]
101-
2 : vd[2]
79+
sd : Size=2, Index={1, 2}
80+
Key : Type : Weight : Variable
81+
1 : 1 : 1 : vd[1]
82+
: : 2 : vd[2]
83+
2 : 1 : 1 : vl[1]
84+
: : 2 : vl[2]
85+
: : 3 : vl[3]
86+
sos1 : Size=1, Index=None
87+
Key : Type : Weight : Variable
88+
None : 1 : 1 : vl[1]
89+
: : 2 : vl[2]
90+
: : 3 : vl[3]
91+
sos2 : Size=1, Index=None
92+
Key : Type : Weight : Variable
93+
None : 2 : 1 : vd[1]
94+
: : 2 : vd[2]
10295

10396
2 Block Declarations
10497
b : Size=1, Index=None, Active=True
@@ -120,13 +113,12 @@
120113
3 : 1.0 : pw.SOS2_y[0] + pw.SOS2_y[1] + pw.SOS2_y[2] + pw.SOS2_y[3] : 1.0 : True
121114

122115
1 SOSConstraint Declarations
123-
SOS2_sosconstraint : Size=1
124-
Type=2
125-
Weight : Variable
126-
1 : pw.SOS2_y[0]
127-
2 : pw.SOS2_y[1]
128-
3 : pw.SOS2_y[2]
129-
4 : pw.SOS2_y[3]
116+
SOS2_sosconstraint : Size=1, Index=None
117+
Key : Type : Weight : Variable
118+
None : 2 : 1 : pw.SOS2_y[0]
119+
: : 2 : pw.SOS2_y[1]
120+
: : 3 : pw.SOS2_y[2]
121+
: : 4 : pw.SOS2_y[3]
130122

131123
3 Declarations: SOS2_y SOS2_constraint SOS2_sosconstraint
132124

pyomo/common/formatting.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,11 @@ def tabular_writer(ostream, prefix, data, header, row_generator):
154154
_rows[_key] = None
155155
continue
156156

157+
# Include the key for only the first line in a rowset, and only
158+
# if we printed out a header (if there is no header, then the
159+
# key is not included)
157160
_rows[_key] = [
158-
((tostr("" if i else _key),) if header else ())
161+
(("" if i else tostr(_key),) if header else ())
159162
+ tuple(tostr(x) for x in _r)
160163
for i, _r in enumerate(_rowSet)
161164
]
@@ -190,7 +193,7 @@ def tabular_writer(ostream, prefix, data, header, row_generator):
190193

191194
if any(' ' in r[-1] for x in _rows.values() if x is not None for r in x):
192195
_width[-1] = '%s'
193-
for _key in sorted_robust(_rows):
196+
for _key in _rows:
194197
_rowSet = _rows[_key]
195198
if not _rowSet:
196199
_rowSet = [[_key] + [None] * (len(_width) - 1)]

pyomo/common/pyomo_typing.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# This software is distributed under the 3-clause BSD License.
1010
# ___________________________________________________________________________
1111

12+
import sys
1213
import typing
1314

1415
_overloads = {}
@@ -18,17 +19,22 @@ def _get_fullqual_name(func: typing.Callable) -> str:
1819
return f"{func.__module__}.{func.__qualname__}"
1920

2021

21-
def overload(func: typing.Callable):
22-
"""Wrap typing.overload that remembers the overloaded signatures
22+
if sys.version_info[:2] <= (3, 10) and not typing.TYPE_CHECKING:
2323

24-
This provides a custom implementation of typing.overload that
25-
remembers the overloaded signatures so that they are available for
26-
runtime inspection.
24+
def overload(func: typing.Callable):
25+
"""Wrap typing.overload that remembers the overloaded signatures
2726
28-
"""
29-
_overloads.setdefault(_get_fullqual_name(func), []).append(func)
30-
return typing.overload(func)
27+
This provides a custom implementation of typing.overload that
28+
remembers the overloaded signatures so that they are available for
29+
runtime inspection.
3130
31+
"""
32+
_overloads.setdefault(_get_fullqual_name(func), []).append(func)
33+
return typing.overload(func)
3234

33-
def get_overloads_for(func: typing.Callable):
34-
return _overloads.get(_get_fullqual_name(func), [])
35+
def get_overloads_for(func: typing.Callable):
36+
return _overloads.get(_get_fullqual_name(func), [])
37+
38+
else:
39+
from typing import get_overloads as get_overloads_for
40+
from typing import overload as overload

pyomo/common/tests/test_formatting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ def test_no_header(self):
9696
data = {(2,): (["a", 1], 1), (1, 3): ({1: 'a', 2: '2'}, '2')}
9797
tabular_writer(os, "", data.items(), [], lambda k, v: v)
9898
ref = u"""
99-
{1: 'a', 2: '2'} : 2
10099
['a', 1] : 1
100+
{1: 'a', 2: '2'} : 2
101101
"""
102102
self.assertEqual(ref.strip(), os.getvalue().strip())
103103

pyomo/contrib/appsi/base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import weakref
1717

1818
from typing import (
19+
TYPE_CHECKING,
1920
Sequence,
2021
Dict,
2122
Optional,
@@ -1714,5 +1715,9 @@ class LegacySolver(LegacySolverInterface, cls):
17141715

17151716
return decorator
17161717

1718+
if TYPE_CHECKING:
1719+
# NOTE: `Factory.__call__` can return None, but for the common case
1720+
def __call__(self, name, **kwds) -> Solver: ...
1721+
17171722

17181723
SolverFactory = SolverFactoryClass()

pyomo/contrib/cp/sequence_var.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def _pprint(self):
134134
]
135135
return (
136136
headers,
137-
self._data.items(),
137+
self.items,
138138
("IntervalVars",),
139139
lambda k, v: ['[' + ', '.join(iv.name for iv in v.interval_vars) + ']'],
140140
)

pyomo/contrib/solver/common/factory.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
# ___________________________________________________________________________
1111

1212

13-
from pyomo.opt.base.solvers import LegacySolverFactory
13+
from typing import TYPE_CHECKING
14+
1415
from pyomo.common.factory import Factory
1516
from pyomo.contrib.solver.common.base import LegacySolverWrapper
17+
from pyomo.opt.base.solvers import LegacySolverFactory
1618

1719

1820
class SolverFactoryClass(Factory):
@@ -107,6 +109,12 @@ class LegacySolver(LegacySolverWrapper, cls):
107109

108110
return decorator
109111

112+
if TYPE_CHECKING:
113+
from pyomo.contrib.solver.common.base import SolverBase
114+
115+
# NOTE: `Factory.__call__` can return None, but for the common case
116+
def __call__(self, name, **kwds) -> SolverBase: ...
117+
110118

111119
#: Global registry/factory for "v2" solver interfaces.
112120
SolverFactory: SolverFactoryClass = SolverFactoryClass()

pyomo/contrib/solver/tests/solvers/test_gurobi_minlp_walker.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,8 @@ def test_handle_complex_number_sqrt(self):
565565
with self.assertRaisesRegex(
566566
InvalidValueError,
567567
r"Invalid number encountered evaluating constant unary expression "
568-
r"sqrt\(- p\): math domain error",
568+
r"sqrt\(\s*-\s*p\s*\): "
569+
r"(?:math domain error|expected a nonnegative input, got -?\d+(?:\.\d+)?)",
569570
):
570571
_, expr = visitor.walk_expression(m.c.body)
571572

@@ -578,6 +579,7 @@ def test_handle_invalid_log(self):
578579
with self.assertRaisesRegex(
579580
InvalidValueError,
580581
r"Invalid number encountered evaluating constant unary expression "
581-
r"log\(p\): math domain error",
582+
r"log\(\s*p\s*\): "
583+
r"(?:math domain error|expected a positive input)",
582584
):
583585
_, expr = visitor.walk_expression(m.c.body)

pyomo/core/base/PyomoModel.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from weakref import ref as weakref_ref
1515
import gc
1616
import math
17+
from typing import TypeVar
1718

1819
from pyomo.common import timing
1920
from pyomo.common.collections import Bunch
@@ -572,6 +573,10 @@ def select(
572573
StaleFlagManager.mark_all_as_stale(delayed=True)
573574

574575

576+
# NOTE: Python 3.11+ use `typing.Self`
577+
ModelType = TypeVar("ModelType", bound="Model")
578+
579+
575580
@ModelComponentFactory.register(
576581
'Model objects can be used as a component of other models.'
577582
)
@@ -583,9 +588,9 @@ class Model(ScalarBlock):
583588

584589
_Block_reserved_words = set()
585590

586-
def __new__(cls, *args, **kwds):
591+
def __new__(cls: type[ModelType], *args, **kwds) -> ModelType:
587592
if cls != Model:
588-
return super(Model, cls).__new__(cls)
593+
return super(Model, cls).__new__(cls) # type: ignore
589594

590595
raise TypeError(
591596
"Directly creating the 'Model' class is not allowed. Please use the "

pyomo/core/base/block.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,7 @@ def is_constructed(self):
18361836
return False
18371837
return True
18381838

1839-
def _pprint_blockdata_components(self, ostream):
1839+
def _pprint_blockdata_components(self, ostream, sort):
18401840
#
18411841
# We hard-code the order of the core Pyomo modeling
18421842
# components, to ensure that the output follows the logical order
@@ -1862,15 +1862,18 @@ def _pprint_blockdata_components(self, ostream):
18621862

18631863
indented_ostream = StreamIndenter(ostream, self._PPRINT_INDENT)
18641864
for item in items:
1865-
keys = sorted(self.component_map(item))
1865+
if SortComponents.ALPHABETICAL in sort:
1866+
keys = sorted(self.component_map(item))
1867+
else:
1868+
keys = list(self.component_map(item))
18661869
if not keys:
18671870
continue
18681871
#
18691872
# NOTE: these conditional checks should not be hard-coded.
18701873
#
18711874
ostream.write("%d %s Declarations\n" % (len(keys), item.__name__))
18721875
for key in keys:
1873-
self.component(key).pprint(ostream=indented_ostream)
1876+
self.component(key).pprint(ostream=indented_ostream, sort=sort)
18741877
ostream.write("\n")
18751878
#
18761879
# Model Order
@@ -2070,17 +2073,17 @@ class Block(ActiveIndexedComponent):
20702073
_ComponentDataClass = BlockData
20712074
_private_data_initializers = defaultdict(lambda: dict)
20722075

2073-
@overload
2074-
def __new__(
2075-
cls: Type[Block], *args, **kwds
2076-
) -> Union[ScalarBlock, IndexedBlock]: ...
2077-
20782076
@overload
20792077
def __new__(cls: Type[ScalarBlock], *args, **kwds) -> ScalarBlock: ...
20802078

20812079
@overload
20822080
def __new__(cls: Type[IndexedBlock], *args, **kwds) -> IndexedBlock: ...
20832081

2082+
@overload
2083+
def __new__(
2084+
cls: Type[Block], *args, **kwds
2085+
) -> Union[ScalarBlock, IndexedBlock]: ...
2086+
20842087
def __new__(cls, *args, **kwds):
20852088
if cls != Block:
20862089
return super(Block, cls).__new__(cls)
@@ -2237,25 +2240,26 @@ def construct(self, data=None):
22372240
_BlockConstruction.data.pop(id(self), None)
22382241
timer.report()
22392242

2240-
def _pprint_callback(self, ostream, idx, data):
2243+
def _pprint_callback(self, ostream, sort, idx, data):
22412244
if not self.is_indexed():
2242-
data._pprint_blockdata_components(ostream)
2245+
data._pprint_blockdata_components(ostream, sort)
22432246
else:
22442247
ostream.write("%s : Active=%s\n" % (data.name, data.active))
22452248
ostream = StreamIndenter(ostream, self._PPRINT_INDENT)
2246-
data._pprint_blockdata_components(ostream)
2249+
data._pprint_blockdata_components(ostream, sort)
22472250

22482251
def _pprint(self):
2249-
_attrs = [
2250-
("Size", len(self)),
2251-
("Index", self._index_set if self.is_indexed() else None),
2252-
('Active', self.active),
2253-
]
22542252
# HACK: suppress the top-level block header (for historical reasons)
22552253
if self.parent_block() is None and not self.is_indexed():
2256-
return None, self._data.items(), None, self._pprint_callback
2254+
_attrs = None
22572255
else:
2258-
return _attrs, self._data.items(), None, self._pprint_callback
2256+
_attrs = [
2257+
("Size", len(self)),
2258+
("Index", self._index_set if self.is_indexed() else None),
2259+
('Active', self.active),
2260+
]
2261+
2262+
return _attrs, self.items, None, self._pprint_callback
22592263

22602264
def display(self, filename=None, ostream=None, prefix=""):
22612265
"""

0 commit comments

Comments
 (0)