-
Notifications
You must be signed in to change notification settings - Fork 533
Fix a bug in gdp.bigm transformation for nested GDPs #3213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…aren't enforced if any parent indicator_var is False
…n this morning caught
…--the transformation of the logical stuff has nested structures and so grew to beyond demo size
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixes the error, and certainly the code has improved (thank you for the solver checks in other methods).
I wonder if the other solution you proposed is more flexible as it would allow to have recursive nested disjunctions, or just have different relaxations at different levels.
In any case, this could be a longer conversation!
@bernalde, this allows for arbitrarily deep nesting as well (assuming that's what you mean by recursive nested?). The different relaxations at different levels point is a good one though. The changes in this PR don't preclude it, but if you did want your bigm-ed inner constraints to then be hull-ed by the outer disjunction, for example, you would have to do that through careful use of the |
m.left = Disjunct() | ||
m.left.left = Disjunct() | ||
m.left.left.c = Constraint(expr=m.x >= 10) | ||
m.left.right = Disjunct() | ||
m.left.right.c = Constraint(expr=m.x >= 9) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a deep hatred of this. Not asking for it to change - it's just like directions from my nightmares.
@@ -22,6 +22,7 @@ | |||
from pyomo.common.collections import Bunch | |||
from pyomo.common.config import ConfigDict, ConfigValue | |||
from pyomo.common.fileutils import import_file, PYOMO_ROOT_DIR | |||
from pyomo.contrib.appsi.base import Solver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this import added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good catch. Because of a long and stupid adventure trying to get the appsi test to skip properly when Gurobi is installed but has no license. But we actually don't need this import or the one below.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3213 +/- ##
==========================================
+ Coverage 88.39% 88.44% +0.05%
==========================================
Files 846 847 +1
Lines 95153 96518 +1365
==========================================
+ Hits 84106 85369 +1263
- Misses 11047 11149 +102
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Fixes .
Summary/Motivation:
The
gdp.bigm
transformation was only relaxing constraints on nested Disjuncts when the constraint's Disjunct was not selected. This is wrong--the constraint also needs to be relaxed when any parent Disjunct is not selected (when the nested indicator vars are not local to their parent Disjunct). For example, consider:The optimal solution should be$x=8$ , with $Y_2$ , $Z_4$ , and $Z_2$ True and the other Booleans False. But if the $x \geq 9$ constraint is not relaxed when $Y_1$ is False, then we wrongly conclude that $x = 9$ is optimal. This PR adds parent Disjunct indicator variables to the big-M term so that this happens properly. So in the example, we write the transformed constraint as:
(Note that another way to fix this would be to put transformed constraints onto their parent Disjunct and simply let them get transformed again when the parent is transformed, but I opted against that because we don't need to recalculate the M value--we know what it is, we just need the BigM term to be ''activated'' when anything in the GDP tree above is False.)
Changes proposed in this PR:
_transform_constraint
which changes some (suboptimal) code in GDPopt.Legal Acknowledgement
By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution: