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

Transformation of explicit constraints to variable bounds #190

Merged
merged 12 commits into from
Jan 9, 2018

Conversation

qtothec
Copy link
Contributor

@qtothec qtothec commented Jul 21, 2017

Adding a new transformation.

@codecov-io
Copy link

codecov-io commented Aug 1, 2017

Codecov Report

Merging #190 into master will increase coverage by 0.02%.
The diff coverage is 88.63%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #190      +/-   ##
=========================================
+ Coverage   66.17%   66.2%   +0.02%     
=========================================
  Files         442     443       +1     
  Lines       56759   56803      +44     
=========================================
+ Hits        37561   37605      +44     
  Misses      19198   19198
Impacted Files Coverage Δ
pyomo/core/plugins/transform/bounds_to_vars.py 88.63% <88.63%> (ø)
pyomo/pysp/scenariotree/tree_structure.py 84.78% <0%> (+0.23%) ⬆️
pyomo/solvers/plugins/smanager/phpyro.py 88.94% <0%> (+1.05%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d6d5716...99c51ab. Read the comment docs.

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.

This is in pretty good shape. Just a couple edge cases to look at.

# Check if the constraint is k * x + c1 <= c2 or c2 <= k * x + c1
if constr.body.polynomial_degree() == 1:
repn = generate_canonical_repn(constr.body)
if repn.variables is not None and len(repn.variables) == 1:
Copy link
Member

Choose a reason for hiding this comment

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

Again, you should filter out the variables with a 0 coefficient first before you decide if you can update the 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.

I assume that using the > and < operators implicitly do this filtering. Is that not sufficient?

Copy link
Member

Choose a reason for hiding this comment

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

No: edge cases like in your other transformation (e.g., m.x + m.y - m.x <= 0 will end up with a zero coefficient in the canonical repn - and two variables in the repn.variables. That said, the correct answer may be to have generate_canonical_repn filter those out as part of it's final postprocessing step...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it might be compelling to do that post-processing, since I tend to assume at least for linear systems that the variable terms are aggregated. I don't think that the edge case is relevant to this transformation, though, because of the len(repn.variables) == 1 requirement. It will just fail to transform that constraint.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, it appears that for your simple example, this kind of processing already takes place, both for coopr3 and pyomo4 expression systems.

if repn.variables is not None and len(repn.variables) == 1:
var = repn.variables[0]
const = repn.constant if repn.constant is not None else 0
coef = repn.linear[0]
Copy link
Member

Choose a reason for hiding this comment

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

For safety (and Python2 compatibility), you should cast the coef to a float to avoid integer division: coef = float(repn.linear[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.

Even with the from __future__ import division up top?

Copy link
Member

Choose a reason for hiding this comment

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

DOH. I missed that. Yes - the __future__ will cover it. [So you are seeing a style difference ... instead of remembering to start every script with the division import, I just trained myself to explicitly convert something to float]

@qtothec
Copy link
Contributor Author

qtothec commented Aug 21, 2017

Close and reopen to trigger rebuild due to a network-connectivity-related issue.

@qtothec qtothec closed this Aug 21, 2017
@qtothec qtothec reopened this Aug 21, 2017
@qtothec
Copy link
Contributor Author

qtothec commented Aug 22, 2017

Close and reopen to work around test_farmer_quadratic_ipopt_with_phpyro intermittency

@qtothec qtothec closed this Aug 22, 2017
@qtothec qtothec reopened this Aug 22, 2017
@qtothec qtothec mentioned this pull request Sep 1, 2017
Copy link
Member

@carldlaird carldlaird left a comment

Choose a reason for hiding this comment

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

Some minor comments - see review. These should be easy to address, and then I am for merging.

# variable from all active constraints, so that it won't be
# updated during the optimization. Therefore, we need to
# shift the value of var as necessary in order to keep it
# within the constraints.
Copy link
Member

Choose a reason for hiding this comment

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

Several comments:

  1. Unclear exactly what this comment is saying. Are you indicating that it is possible that the variable is only in constr, therefore, when we deactivate it, the variable does not appear in any constraints at all?

  2. Also, why is it necessary to shift the value? It is possible to have variable values that are outside the bounds. Is this just "cleanup"?

  3. If I understand correctly, then "keep it within the constraints" should read "keep it within the 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.

  1. Yep.
  2. Yes, this is a form of cleanup.
  3. Yeah, I can change that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On further thought, with 2: It makes sense to shift the value because we are removing a constraint from the system and shifting its "effect" directly onto the variable. In order for post-solve variable values to remain as they would be had we not performed the transformation, we need to move the variable value if it falls outside of the new bound.

@jsiirola jsiirola merged commit de272bc into Pyomo:master Jan 9, 2018
@qtothec qtothec deleted the bounds_to_vars_xfrm branch January 14, 2018 15:49
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.

4 participants