Skip to content

Commit 4ace470

Browse files
authored
Merge branch 'main' into add-greybox
2 parents d634267 + 8dfd55b commit 4ace470

21 files changed

Lines changed: 1968 additions & 747 deletions

File tree

.github/workflows/test_branches.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ jobs:
4444
python-version: '3.10'
4545
- name: Black Formatting Check
4646
run: |
47-
# Note v24.4.1 fails due to a bug in the parser
47+
# Note v24.4.1 fails due to a bug in the parser. Project-level
48+
# configuration is inherited from pyproject.toml.
4849
pip install 'black!=24.4.1'
49-
black . -S -C --check --diff --exclude examples/pyomobook/python-ch/BadIndent.py
50+
black . --check --diff
5051
- name: Spell Check
5152
uses: crate-ci/typos@master
5253
with:

.github/workflows/test_pr_and_main.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ jobs:
5555
python-version: '3.10'
5656
- name: Black Formatting Check
5757
run: |
58-
# Note v24.4.1 fails due to a bug in the parser
58+
# Note v24.4.1 fails due to a bug in the parser. Project-level
59+
# configuration is inherited from pyproject.toml.
5960
pip install 'black!=24.4.1'
60-
black . -S -C --check --diff --exclude examples/pyomobook/python-ch/BadIndent.py
61+
black . --check --diff
6162
- name: Spell Check
6263
uses: crate-ci/typos@master
6364
with:

doc/OnlineDocs/contribution_guide.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,17 @@ run:
3737

3838
# Auto-apply correct formatting
3939
pip install black
40-
black -S -C <path> --exclude examples/pyomobook/python-ch/BadIndent.py
40+
black <path>
4141
# Find typos in files
4242
conda install typos
4343
typos --config .github/workflows/typos.toml <path>
4444
45-
If the spell-checker returns a failure for a word that is spelled correctly,
46-
please add the word to the ``.github/workflows/typos.toml`` file.
45+
If the spell-checker returns a failure for a word that is spelled
46+
correctly, please add the word to the ``.github/workflows/typos.toml``
47+
file. Note also that ``black`` reads from ``pyproject.toml`` to
48+
determine correct configuration, so if you are running ``black``
49+
indirectly (for example, using an IDE integration), please ensure you
50+
are not overriding the project-level configuration set in that file.
4751

4852
Online Pyomo documentation is generated using `Sphinx <https://www.sphinx-doc.org/en/master/>`_
4953
with the ``napoleon`` extension enabled. For API documentation we use of one of these

doc/OnlineDocs/explanation/modeling/math_programming/sets.rst

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,30 @@ and postpones creation of its members:
2929

3030
The :class:`Set` class takes optional arguments such as:
3131

32-
- ``dimen`` = Dimension of the members of the set
33-
- ``doc`` = String describing the set
34-
- ``filter`` = A Boolean function used during construction to indicate if a
35-
potential new member should be assigned to the set
36-
- ``initialize`` = An iterable containing the initial members of the Set, or
37-
function that returns an iterable of the initial members the set.
38-
- ``ordered`` = A Boolean indicator that the set is ordered; the default is ``True``
39-
- ``validate`` = A Boolean function that validates new member data
40-
- ``within`` = Set used for validation; it is a super-set of the set being declared.
32+
``dimen``
33+
Dimension of the members of the set; ``None`` for "jagged" sets
34+
(where members do not have a uniform length).
35+
36+
``doc``
37+
String describing the set
38+
39+
``filter``
40+
A Boolean function used during construction to indicate if a
41+
potential new member should be assigned to the set
42+
43+
``initialize``
44+
An iterable containing the initial members of the Set, or
45+
function that returns an iterable of the initial members the set.
46+
47+
``ordered``
48+
A Boolean indicator that the set is ordered; the default is ``True``
49+
(Set is ordered by insertion order)
50+
51+
``validate``
52+
A Boolean function that validates new member data
53+
54+
``within``
55+
Set used for validation; it is a super-set of the set being declared.
4156

4257
In general, Pyomo attempts to infer the "dimensionality" of Set
4358
components (that is, the number of apparent indices) when they are
@@ -451,8 +466,40 @@ for this model, a toy data file (in AMPL "``.dat``" format) would be:
451466

452467
>>> inst = model.create_instance('src/scripting/Isinglecomm.dat')
453468

454-
This can also be done somewhat more efficiently, and perhaps more clearly,
455-
using a :class:`BuildAction` (for more information, see :ref:`BuildAction`):
469+
A similar result can be accomplished more efficiently (because we only
470+
iterate over the Arcs twice) using initialization functions that accept
471+
only a model block and return a ``dict`` with all the information needed
472+
for the indexed set:
473+
474+
.. doctest::
475+
:hide:
476+
477+
>>> model = inst
478+
>>> del model.NodesIn
479+
>>> del model.NodesOut
480+
481+
.. testcode::
482+
483+
def NodesIn_init(m):
484+
# Create a dict to show NodesIn list for every node
485+
d = {i: [] for i in m.Nodes}
486+
# loop over the arcs and record the end points
487+
for i, j in model.Arcs:
488+
d[j].append(i)
489+
return d
490+
model.NodesIn = pyo.Set(model.Nodes, initialize=NodesIn_init)
491+
492+
def NodesOut_init(m):
493+
d = {i: [] for i in m.Nodes}
494+
for i, j in model.Arcs:
495+
d[i].append(j)
496+
return d
497+
model.NodesOut = pyo.Set(model.Nodes, initialize=NodesOut_init)
498+
499+
Alternatively, this can also be done even more efficiently, and perhaps
500+
more clearly, outside the context of Set initialization. For concrete
501+
models, scripts can explicitly add elements to the Sets after
502+
declaration:
456503

457504
.. doctest::
458505
:hide:
@@ -463,8 +510,29 @@ using a :class:`BuildAction` (for more information, see :ref:`BuildAction`):
463510

464511
.. testcode::
465512

513+
model.NodesIn = pyo.Set(model.Nodes, within=model.Nodes)
466514
model.NodesOut = pyo.Set(model.Nodes, within=model.Nodes)
515+
516+
# loop over the arcs and record the end points
517+
for i, j in model.Arcs:
518+
model.NodesIn[j].add(i)
519+
model.NodesOut[i].add(j)
520+
521+
For abstract models, that action must be deferred to instance
522+
construction time using a :class:`BuildAction` (for more information,
523+
see :ref:`BuildAction`):
524+
525+
.. doctest::
526+
:hide:
527+
528+
>>> model = inst
529+
>>> del model.NodesIn
530+
>>> del model.NodesOut
531+
532+
.. testcode::
533+
467534
model.NodesIn = pyo.Set(model.Nodes, within=model.Nodes)
535+
model.NodesOut = pyo.Set(model.Nodes, within=model.Nodes)
468536

469537
def Populate_In_and_Out(model):
470538
# loop over the arcs and record the end points

doc/OnlineDocs/explanation/solvers/pyros.rst

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -906,13 +906,13 @@ Observe that the log contains the following information:
906906
information, (UTC) time at which the solver was invoked,
907907
and, if available, information on the local Git branch and
908908
commit hash.
909-
* **Summary of solver options** (lines 19--38).
910-
* **Preprocessing information** (lines 39--41).
909+
* **Summary of solver options** (lines 19--40).
910+
* **Preprocessing information** (lines 41--43).
911911
Wall time required for preprocessing
912912
the deterministic model and associated components,
913913
i.e., standardizing model components and adding the decision rule
914914
variables and equations.
915-
* **Model component statistics** (lines 42--58).
915+
* **Model component statistics** (lines 44--61).
916916
Breakdown of model component statistics.
917917
Includes components added by PyROS, such as the decision rule variables
918918
and equations.
@@ -927,7 +927,7 @@ Observe that the log contains the following information:
927927
The number of truly uncertain parameters detected during preprocessing
928928
is also noted in parentheses
929929
(in which "eff." is an abbreviation for "effective").
930-
* **Iteration log table** (lines 59--69).
930+
* **Iteration log table** (lines 62--69).
931931
Summary information on the problem iterates and subproblem outcomes.
932932
The constituent columns are defined in detail in
933933
:ref:`the table following the snippet <table-iteration-log-columns>`.
@@ -953,7 +953,7 @@ Observe that the log contains the following information:
953953

954954
* **Termination statistics** (lines 89--94). Summary of statistics related to the
955955
iterate at which PyROS terminates.
956-
* **Exit message** (lines 95--96).
956+
* **Exit message** (lines 95--97).
957957

958958

959959
.. _solver-log-snippet:
@@ -963,10 +963,10 @@ Observe that the log contains the following information:
963963
:linenos:
964964
965965
==============================================================================
966-
PyROS: The Pyomo Robust Optimization Solver, v1.3.8.
966+
PyROS: The Pyomo Robust Optimization Solver, v1.3.9.
967967
Pyomo version: 6.9.3dev0
968968
Commit hash: unknown
969-
Invoked at UTC 2025-05-05T00:00:00.000000+00:00
969+
Invoked at UTC 2025-07-21T00:00:00.000000+00:00
970970
971971
Developed by: Natalie M. Isenberg (1), Jason A. F. Sherman (1),
972972
John D. Siirola (2), Chrysanthos E. Gounaris (1)
@@ -977,7 +977,7 @@ Observe that the log contains the following information:
977977
of Energy's Institute for the Design of Advanced Energy Systems (IDAES).
978978
==============================================================================
979979
================================= DISCLAIMER =================================
980-
PyROS is still under development.
980+
PyROS is still under development.
981981
Please provide feedback and/or report any issues by creating a ticket at
982982
https://github.com/Pyomo/pyomo/issues/new/choose
983983
==============================================================================
@@ -998,6 +998,7 @@ Observe that the log contains the following information:
998998
backup_local_solvers=[]
999999
backup_global_solvers=[]
10001000
subproblem_file_directory=None
1001+
subproblem_format_options={'bar': {'symbolic_solver_labels': True}}
10011002
bypass_local_separation=False
10021003
bypass_global_separation=False
10031004
p_robustness={}
@@ -1025,33 +1026,34 @@ Observe that the log contains the following information:
10251026
------------------------------------------------------------------------------
10261027
Itn Objective 1-Stg Shift 2-Stg Shift #CViol Max Viol Wall Time (s)
10271028
------------------------------------------------------------------------------
1028-
0 3.5838e+07 - - 5 1.8832e+04 0.759
1029-
1 3.5838e+07 2.9329e-09 5.0030e-10 5 2.1295e+04 1.573
1030-
2 3.6285e+07 7.6526e-01 2.0398e-01 2 2.2457e+02 2.272
1031-
3 3.6285e+07 7.7212e-13 1.2525e-10 0 7.2940e-08g 5.280
1029+
0 3.5838e+07 - - 5 1.8832e+04 0.611
1030+
1 3.5838e+07 1.2289e-09 1.5886e-12 5 2.8919e+02 1.702
1031+
2 3.6269e+07 3.1647e-01 1.0432e-01 4 2.9020e+02 3.407
1032+
3 3.6285e+07 7.6526e-01 1.4596e-04 7 7.5966e+03 5.919
1033+
4 3.6285e+07 1.1608e-11 2.2270e-01 0 1.5084e-12g 8.823
10321034
------------------------------------------------------------------------------
10331035
Robust optimal solution identified.
10341036
------------------------------------------------------------------------------
10351037
Timing breakdown:
1036-
1038+
10371039
Identifier ncalls cumtime percall %
10381040
-----------------------------------------------------------
1039-
main 1 5.281 5.281 100.0
1041+
main 1 8.824 8.824 100.0
10401042
------------------------------------------------------
1041-
dr_polishing 3 0.155 0.052 2.9
1042-
global_separation 27 1.280 0.047 24.2
1043-
local_separation 108 2.200 0.020 41.7
1044-
master 4 0.727 0.182 13.8
1045-
master_feasibility 3 0.103 0.034 1.9
1046-
preprocessing 1 0.021 0.021 0.4
1047-
other n/a 0.794 n/a 15.0
1043+
dr_polishing 4 0.547 0.137 6.2
1044+
global_separation 27 0.978 0.036 11.1
1045+
local_separation 135 4.645 0.034 52.6
1046+
master 5 1.720 0.344 19.5
1047+
master_feasibility 4 0.239 0.060 2.7
1048+
preprocessing 1 0.013 0.013 0.2
1049+
other n/a 0.681 n/a 7.7
10481050
======================================================
10491051
===========================================================
1050-
1052+
10511053
------------------------------------------------------------------------------
10521054
Termination stats:
1053-
Iterations : 4
1054-
Solve time (wall s) : 5.281
1055+
Iterations : 5
1056+
Solve time (wall s) : 8.824
10551057
Final objective value : 3.6285e+07
10561058
Termination condition : pyrosTerminationCondition.robust_optimal
10571059
------------------------------------------------------------------------------

examples/doc/samples/case_studies/diet/DietProblem.tex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ \subsection*{Build the model}
6262

6363
At this point we must start defining the rules associated with our parameters and variables. We begin with the most important rule, the cost rule, which will tell the model to try and minimize the overall cost. Logically, the total cost is going to be the sum of how much is spent on each food, and that value in turn is going to be determined by the cost of the food and how much of it is purchased. For example, if three \$5 hamburgers and two \$1 apples are purchased, than the total cost would be $3 \cdot 5 + 2 \cdot 1 = 17$. Note that this process is the same as taking the dot product of the amounts vector and the costs vector.
6464

65-
To input this, we must define the cost rule, which we creatively call costRule as
65+
To input this, we must define the cost rule, which we creatively call costRule as
6666

6767
\begin{verbatim}def costRule(model):
6868
return sum(model.costs[n]*model.amount[n] for n in model.foods)
@@ -75,10 +75,10 @@ \subsection*{Build the model}
7575

7676
This line defines the objective of the model as the costRule, which Pyomo interprets as the value it needs to minimize; in this case it will minimize our costs. Also, as a note, we defined the objective as ``model.cost'' which is not to be confused with the parameter we defined earlier as ``model.costs,'' despite their similar names. These are two different values and accidentally giving them the same name will cause problems when trying to solve the problem.
7777

78-
We must also create a rule for the volume consumed. The construction of this rule is similar to the cost rule as once again we take the dot product, this time between the volume and amount vectors.
78+
We must also create a rule for the volume consumed. The construction of this rule is similar to the cost rule as once again we take the dot product, this time between the volume and amount vectors.
7979

8080
\begin{verbatim}def volumeRule(model):
81-
return sum(model.volumes[n]*model.amount[n] for n in
81+
return sum(model.volumes[n]*model.amount[n] for n in
8282
model.foods) <= model.max_volume
8383
8484
model.volume = pyo.Constraint(rule=volumeRule)
@@ -90,7 +90,7 @@ \subsection*{Build the model}
9090

9191
\begin{verbatim}
9292
def nutrientRule(n, model):
93-
value = sum(model.nutrient_value[n,f]*model.amount[f]
93+
value = sum(model.nutrient_value[n,f]*model.amount[f]
9494
for f in model.foods)
9595
return (model.min_nutrient[n], value, model.max_nutrient[n])
9696
@@ -160,7 +160,7 @@ \subsection*{Data entry}
160160

161161
The amount of spaces between each element is irrelevant (as long as there is at least one) so the matrix should be formatted for ease of reading.
162162

163-
Now that we have finished both the model and the data file save them both. It's convention to give the model file a .py extension and the data file a .dat extension.
163+
Now that we have finished both the model and the data file save them both. It's convention to give the model file a .py extension and the data file a .dat extension.
164164

165165
\subsection*{Solution}
166166

0 commit comments

Comments
 (0)