Skip to content

Commit 413f8f6

Browse files
authored
Merge pull request #2406 from emma58/gdpopt-rewrite
GDPopt rewrite!
2 parents c9811bf + bd67602 commit 413f8f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+4859
-3622
lines changed

doc/OnlineDocs/contributed_packages/gdpopt.rst

+62-14
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,35 @@ Credit for prototyping and development can be found in the ``GDPopt`` class docu
2929
.. _Lee & Grossmann, 2000: https://doi.org/10.1016/S0098-1354(00)00581-0
3030
.. _Chen et al., 2018: https://doi.org/10.1016/B978-0-444-64241-7.50143-9
3131

32-
Usage of GDPopt to solve a Pyomo.GDP concrete model involves:
32+
GDPopt can be used to solve a Pyomo.GDP concrete model in two ways.
33+
The simplest is to instantiate the generic GDPopt solver and specify the desired algorithm as an argument to the ``solve`` method:
3334

3435
.. code::
3536
36-
>>> SolverFactory('gdpopt').solve(model)
37+
>>> SolverFactory('gdpopt').solve(model, algorithm='LOA')
38+
39+
The alternative is to instantiate an algorithm-specific GDPopt solver:
40+
41+
.. code::
42+
43+
>>> SolverFactory('gdpopt.loa').solve(model)
44+
45+
In the above examples, GDPopt uses the GDPopt-LOA algorithm.
46+
Other algorithms may be used by specifying them in the ``algorithm`` argument when using the generic solver or by instantiating the algorithm-specific GDPopt solvers. All GDPopt options are listed below.
3747

3848
.. note::
3949

40-
By default, GDPopt uses the GDPopt-LOA strategy.
41-
Other strategies may be used by specifying the ``strategy`` argument during ``solve()``.
42-
All GDPopt options are listed below.
50+
The generic GDPopt solver allows minimal configuration outside of the arguments to the ``solve`` method. To avoid repeatedly specifying the same configuration options to the ``solve`` method, use the algorithm-specific solvers.
4351

44-
Logic-based Outer Approximation
45-
-------------------------------
52+
Logic-based Outer Approximation (LOA)
53+
-------------------------------------
4654

4755
`Chen et al., 2018`_ contains the following flowchart, taken from the preprint version:
4856

4957
.. image:: gdpopt_flowchart.png
5058
:scale: 70%
5159

52-
An example which includes the modeling approach may be found below.
60+
An example that includes the modeling approach may be found below.
5361

5462
.. doctest::
5563
:skipif: not glpk_available
@@ -75,8 +83,8 @@ An example which includes the modeling approach may be found below.
7583
>>> model.objective = Objective(expr=model.x + 0.1*model.y, sense=minimize)
7684

7785
Solve the model using GDPopt
78-
>>> results = SolverFactory('gdpopt').solve(
79-
... model, strategy='LOA', mip_solver='glpk') # doctest: +IGNORE_RESULT
86+
>>> results = SolverFactory('gdpopt.loa').solve(
87+
... model, mip_solver='glpk') # doctest: +IGNORE_RESULT
8088

8189
Display the final solution
8290
>>> model.display()
@@ -107,10 +115,38 @@ An example which includes the modeling approach may be found below.
107115

108116
.. code::
109117
110-
>>> SolverFactory('gdpopt').solve(model, tee=True)
118+
>>> SolverFactory('gdpopt.loa').solve(model, tee=True)
119+
120+
Global Logic-based Outer Approximation (GLOA)
121+
---------------------------------------------
111122

112-
Logic-based Branch-and-Bound
113-
----------------------------
123+
The same algorithm can be used to solve GDPs involving nonconvex nonlinear constraints by solving the subproblems globally:
124+
125+
.. code::
126+
127+
>>> SolverFactory('gdpopt.gloa').solve(model)
128+
129+
.. warning::
130+
131+
The ``nlp_solver`` option must be set to a global solver for the solution returned by GDPopt to also be globally optimal.
132+
133+
Relaxation with Integer Cuts (RIC)
134+
----------------------------------
135+
136+
Instead of outer approximation, GDPs can be solved using the same MILP relaxation as in the previous two algorithms, but instead of using the subproblems to generate outer-approximation cuts, the algorithm adds only no-good cuts for every discrete solution encountered:
137+
138+
.. code::
139+
140+
>>> SolverFactory('gdpopt.ric').solve(model)
141+
142+
Again, this is a global algorithm if the subproblems are solved globally, and is not otherwise.
143+
144+
.. note::
145+
146+
The RIC algorithm will not necessarily enumerate all discrete solutions as it is possible for the bounds to converge first. However, full enumeration is not uncommon.
147+
148+
Logic-based Branch-and-Bound (LBB)
149+
----------------------------------
114150

115151
The GDPopt-LBB solver branches through relaxed subproblems with inactive disjunctions.
116152
It explores the possibilities based on best lower bound,
@@ -139,7 +175,7 @@ To use the GDPopt-LBB solver, define your Pyomo GDP model as usual:
139175
>>> m.djn = Disjunction(expr=[m.y1, m.y2])
140176

141177
Invoke the GDPopt-LBB solver
142-
>>> results = SolverFactory('gdpopt').solve(m, strategy='LBB')
178+
>>> results = SolverFactory('gdpopt.lbb').solve(m)
143179

144180
>>> print(results) # doctest: +SKIP
145181
>>> print(results.solver.status)
@@ -160,3 +196,15 @@ GDPopt implementation and optional arguments
160196

161197
.. autoclass:: pyomo.contrib.gdpopt.GDPopt.GDPoptSolver
162198
:members:
199+
200+
.. autoclass:: pyomo.contrib.gdpopt.loa.GDP_LOA_Solver
201+
:members:
202+
203+
.. autoclass:: pyomo.contrib.gdpopt.gloa.GDP_GLOA_Solver
204+
:members:
205+
206+
.. autoclass:: pyomo.contrib.gdpopt.ric.GDP_RIC_Solver
207+
:members:
208+
209+
.. autoclass:: pyomo.contrib.gdpopt.branch_and_bound.GDP_LBB_Solver
210+
:members:

examples/gdp/eight_process/eight_proc_logical.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def use_unit_or_not(m, unit):
162162
m = build_eight_process_flowsheet()
163163
from pyomo.environ import TransformationFactory
164164
TransformationFactory('core.logical_to_linear').apply_to(m)
165-
SolverFactory('gdpopt').solve(m, tee=True, strategy='LOA')
165+
SolverFactory('gdpopt.loa').solve(m, tee=True)
166166
update_boolean_vars_from_binary(m)
167167
m.Y.display()
168168
m.flow.display()

examples/gdp/nine_process/small_process.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ def build_nonexclusive_model():
198198
if __name__ == '__main__':
199199
from pyomo.environ import SolverFactory
200200
m = build_model()
201-
result = SolverFactory('gdpopt').solve(
202-
m, tee=True, strategy='GLOA',
201+
result = SolverFactory('gdpopt.gloa').solve(
202+
m, tee=True,
203203
mip_solver='gams',
204204
nlp_solver='gams',
205205
nlp_solver_args=dict(add_options=['option optcr=0.01;']),
@@ -211,8 +211,8 @@ def build_nonexclusive_model():
211211
m.x.display()
212212

213213
m = build_nonexclusive_model()
214-
result = SolverFactory('gdpopt').solve(
215-
m, tee=True, strategy='GLOA',
214+
result = SolverFactory('gdpopt.gloa').solve(
215+
m, tee=True,
216216
mip_solver='gams',
217217
nlp_solver='gams',
218218
nlp_solver_args=dict(add_options=['option optcr=0.01;']),

examples/gdp/small_lit/ex1_Lee.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ def build_model():
3434

3535
if __name__ == "__main__":
3636
model = build_model()
37-
results = SolverFactory('gdpopt').solve(model, tee=True, strategy='LOA')
37+
results = SolverFactory('gdpopt.loa').solve(model, tee=True)
3838
print(results)
3939

examples/gdp/small_lit/ex_633_trespalacios.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def build_simple_nonconvex_gdp():
5252
if __name__ == "__main__":
5353
model = build_simple_nonconvex_gdp()
5454
model.pprint()
55-
res = SolverFactory('gdpopt').solve(model, tee=True, strategy='GLOA')
55+
res = SolverFactory('gdpopt.gloa').solve(model, tee=True)
5656

5757
model.display()
5858
print(res)

examples/gdp/small_lit/nonconvex_HEN.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def exchanger_disjunction(m, disjctn):
8989
res = SolverFactory('gams').solve(model, tee=True, solver='baron', add_options=['option optcr = 0;'], keepfiles=True)
9090
else:
9191
# Note: MC++ needs to be properly installed to use strategy GLOA
92-
res = SolverFactory('gdpopt').solve(model, tee=True, strategy='GLOA')
92+
res = SolverFactory('gdpopt.gloa').solve(model, tee=True)
9393

9494
# model.display()
9595
print(res)

0 commit comments

Comments
 (0)