Skip to content
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

Fix appsi auto-update when unfixing a variable and changing its bound #2996

Merged
merged 4 commits into from
Sep 19, 2023

Conversation

michaelbynum
Copy link
Contributor

Summary/Motivation:

This PR fixes a bug in appsi. The bug occurs when both unfixing a variable and changing its bound. Because of the ordering of some if statements, we were not hitting some code that we should. As a result, objectives/constraints that used the fixed variable were not getting updated correctly.

Changes proposed in this PR:

  • fix the bug
  • add a test

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:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

Copy link
Member

@jsiirola jsiirola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some questions (although nothing that necessarily should block this PR)

elif ub is not v._ub:
vars_to_update.append(v)
elif (fixed is not v.fixed) or (fixed and (value != v.value)):
if (fixed is not v.fixed) or (fixed and (value != v.value)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linters would probably prefer this to be != and not is not (because you are comparing bool). The issue is that it is possible to get POD values that compare equal, but are not the same object (so is not returns True). In this case, a false positive it fine (it just means APPSI does a little extra unnecessary work), but it might be better to make a distinction for when we care if an object changes or when the value changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great point. I'll update this.

Comment on lines +1416 to +1419
elif lb is not v._lb:
vars_to_update.append(v)
elif ub is not v._ub:
vars_to_update.append(v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This catches if the user re-assigns the lower / upper bound, but what about bounds that include mutable Params? Does changing the Param value get propagated to updated bounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that should get caught on the next two lines.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's the case: that only catches if the domain changes, and not if the value of the bounds change:

>>> from pyomo.environ import *
>>> m = ConcreteModel()
>>> m.x = Var()
>>> m.p = Param(mutable=True, initialize=1)
>>> m.x.bounds = -m.p, m.p
>>> m.x.bounds
(-1.0, 1.0)
>>> m.x.domain.get_interval()
(None, None, 0)
>>> m.p = 5
>>> m.x.bounds
(-5.0, 5.0)
>>> m.x.domain.get_interval()
(None, None, 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, my mistake. You are right. The case of bounds with mutable parameters is actually caught with the update_params method and is handled differently for each solver. Here is how it is handled with Gurobi.

Comment on lines 1420 to 1421
elif domain_interval != v.domain.get_interval():
vars_to_update.append(v)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right here, @jsiirola

@codecov
Copy link

codecov bot commented Sep 18, 2023

Codecov Report

Patch coverage: 100.00% and project coverage change: +0.23% 🎉

Comparison is base (c471729) 87.85% compared to head (5a9b6e0) 88.09%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2996      +/-   ##
==========================================
+ Coverage   87.85%   88.09%   +0.23%     
==========================================
  Files         769      769              
  Lines       89497    89497              
==========================================
+ Hits        78632    78838     +206     
+ Misses      10865    10659     -206     
Flag Coverage Δ
linux 85.17% <100.00%> (+1.44%) ⬆️
osx 74.98% <100.00%> (ø)
other 85.35% <100.00%> (+1.45%) ⬆️
win 82.43% <100.00%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Changed Coverage Δ
pyomo/contrib/appsi/base.py 85.69% <100.00%> (ø)

... and 10 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@michaelbynum michaelbynum merged commit 6cc5630 into Pyomo:main Sep 19, 2023
33 checks passed
@michaelbynum michaelbynum deleted the gurobi_fix branch February 25, 2024 04:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants