More flexible LinearStandardFormCompiler#3949
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3949 +/- ##
==========================================
+ Coverage 90.11% 90.13% +0.01%
==========================================
Files 905 905
Lines 107502 107579 +77
==========================================
+ Hits 96878 96964 +86
+ Misses 10624 10615 -9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
jsiirola
left a comment
There was a problem hiding this comment.
I like this approach. I am still digging through the review, but in the interests of getting things moving one big initial question: have you quantified how this change impacts the standard_form performance?
| ), | ||
| ) | ||
| CONFIG.declare( | ||
| 'extra_valid_ctypes', |
There was a problem hiding this comment.
Potentially rename this ignore_ctypes? Should this be promoted to an ADVANCED_OPTION?
michaelbynum
left a comment
There was a problem hiding this comment.
This is a clever way to enable using the standard form compiler with solvers that support nonlinear expressions. Nice work.
Question - are you actually using kernel, or were you just trying to get tests to pass?
| offset, linear_index, linear_data, lb, ub = ( | ||
| template_visitor.expand_expression(obj, obj.template_expr()) | ||
| ) | ||
| except InvalidExpressionError: |
There was a problem hiding this comment.
Is it possible to get an InvalidExpressionError for some reason other than a nonlinear expression?
| offset, linear_index, linear_data, lb, ub = ( | ||
| template_visitor.expand_expression(con, con.template_expr()) | ||
| ) | ||
| except InvalidExpressionError: |
There was a problem hiding this comment.
Same question here: Is there a way to get an InvalidExpressionError for a reason other than a nonlinear expression?
| linear_index = map(var_recorder.var_order.__getitem__, repn.linear) | ||
| linear_data = repn.linear.values() | ||
|
|
||
| # Normalize ±inf to None: both kernel constraints and AML |
There was a problem hiding this comment.
I don't normally see symbols like the +/- symbol here (which show up in several places). Will this cause problems? In other words, do we have any reason to limit ourselves to ASCII (I believe these characters are UTF-8)?
| constraint is not misclassified as a range constraint, and a fully | ||
| unbounded constraint is skipped rather than emitted as a range row. | ||
| """ | ||
| import pyomo.kernel as pmo |
There was a problem hiding this comment.
Do we want new tests for kernel?
| mk = pmo.block() | ||
| mk.x = pmo.variable() | ||
| # lb=-inf (unbounded below) → should become a pure ≤ row, not a range row | ||
| mk.c_ub = pmo.constraint(ub=2.0, body=mk.x) | ||
| # ub=+inf (unbounded above) → should become a pure ≥ row, not a range row | ||
| mk.c_lb = pmo.constraint(lb=-3.0, body=mk.x) | ||
| # Explicit finite range → should still be a range row | ||
| mk.c_rng = pmo.constraint((-1.0, mk.x, 4.0)) |
There was a problem hiding this comment.
I was surprised that I didn't see any inf bounds here given the name of the test and the docstring for the function. This is not necessarily a bad test, but I don't see how it tests inf bounds.
| when ``allow_nonlinear=False`` (the default). When | ||
| ``allow_nonlinear=True``, holds the list of objectives with nonlinear | ||
| terms that were omitted from the compiled matrices (may be empty). | ||
|
|
There was a problem hiding this comment.
Should this class also contain a list of the active ctypes that it found but ignored (when extra_valid_ctypes is used)?
| except AttributeError: | ||
| # Note that this only works for the AML, as kernel does not | ||
| # provide a parent_component() | ||
| _iter = (None, var) |
There was a problem hiding this comment.
I don't understand how this worked previously. Wouldn't an error get raised below because there was no tuple to unpack?
|
I don't see anything that could impact performance unless |
Fixes # N/A
Summary/Motivation:
LinearStandardFormCompileris a great tool for rapidly expanding a Pyomo model into the form need for (mixed-integer) linear programming solvers. Many of these solvers also handle ranged (linear) constraints, quadratic constraints, SOS constraints, quadratic objectives, and even sometimes general nonlinear constraints and objectives. This PR would augment theLinearStandardFormCompilertwo significant ways:allow_nonlinearandextra_valid_ctypes).LinearStandardFormInfowhen the new optionkeep_range_constraints=True.See the usage proof of concept on #3879, which includes these changes.
Changes proposed in this PR:
keep_range_constraintstoLinearStandardFormCompilerand compile range constraints appropriately (84afd9a, e330102, efc1c74)LinearStandardFormCompilerto return non-linear constraints / objectives it encounters instead of raising an error (optionallow_nonlinearaa9ce77)ctypes, to be handled by the caller. Useful for SOS constraints (36953d1).TemplateVarRecorderto correctly handlepyomo.kernelvariables (6a2c69a)This PR was created with the help of GitHub Copilot CLI.
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: