Skip to content

Conversation

emma58
Copy link
Contributor

@emma58 emma58 commented Oct 6, 2025

Fixes #3522 (except for the request to have a persistent MINLP interface to Gurobi)

Summary/Motivation:

This adds a new solver interface gurobi_direct_minlp that supports sending MINLP problems to Gurobi via the Python API. currently this is implemented as a separate Gurobi direct interface in contrib.solver so that we don't have negative performance implications for gurobi_direct_v2 (and to punt for the moment on integrating the matrix-vector inferface with the general MINLP one).

Changes proposed in this PR:

  • Adds a walker that makes the (required, in Gurobi 12) conversion from general nonlinear constraints to a mixture of aux_var == general_nonlinear_expr equalities and linear/quadratic constraints involving the auxiliary and other variables.
  • Implements a pretty minimalistic writer that uses the above walker: The special thing here is that some Pyomo constraints will create more than one constraint in the gurobi model because of the transformation mentioned in the bullet point above.
  • Implements a new solver interface that inherits from GurobiDirect in contrib.solver: The only thing special here is the solve function which is again just unique because of the custom walker/writer explained above.
  • Gets the test coverage to 89%, which rounds to 90%... The only thing interesting here is that I added a method for converting general nonlinear Gurobi expression trees back to Pyomo expressions so that we can test them that way.

Outstanding TODOs, none of which should prevent merging unless we want them to:

  • Move all the tests that manually test Gurobi's expression tree onto the gurobi_nl_to_pyo_expr function, which will make them a lot more readable, and easier to maintain if every there is a change to the public API in gurobipy.
  • Add some tests for the sake of coverage--we're missing some cases

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.

emma58 and others added 30 commits January 7, 2025 13:48
… from Gurobi's perspective. Starting to write the gurobi walker modeled after the sympy one
…on visitor, no real tests to speak of yet though
…ngs like AbsExpression, we can't rely completely on the expression evaluation visitor, and I need to know the types of expressions. Starting to build out tests of the walker.
Copy link

codecov bot commented Oct 6, 2025

Codecov Report

❌ Patch coverage is 89.85507% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.35%. Comparing base (918824e) to head (bbb1da8).
⚠️ Report is 30 commits behind head on main.

Files with missing lines Patch % Lines
...yomo/contrib/solver/solvers/gurobi_direct_minlp.py 89.47% 28 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3745      +/-   ##
==========================================
+ Coverage   89.31%   89.35%   +0.04%     
==========================================
  Files         896      897       +1     
  Lines      103687   104487     +800     
==========================================
+ Hits        92609    93369     +760     
- Misses      11078    11118      +40     
Flag Coverage Δ
builders 29.11% <32.97%> (+0.02%) ⬆️
default 85.94% <89.85%> (?)
expensive 35.86% <33.69%> (?)
linux 86.97% <89.81%> (-2.08%) ⬇️
linux_other 86.97% <89.81%> (+<0.01%) ⬆️
osx 83.12% <89.81%> (+0.01%) ⬆️
win 85.22% <89.45%> (+<0.01%) ⬆️
win_other 85.22% <89.45%> (+<0.01%) ⬆️

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

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +417 to +419
# ESJ TODO: THIS IS COPIED FROM THE LINEAR WALKER--CAN WE PUT IT IN UTIL OR
# SOMETHING?
def check_constant(self, ans, obj):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsiirola I copied this over from the linear walker, but can we somehow centralize it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Answer: Promote to pyomo.core.expr. And does it really need the visitor?

Comment on lines +24 to +25
# ESJ TODO: Could we move this to util or somewhere less bizarre?
from pyomo.contrib.cp.repn.docplex_writer import collect_valid_components
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsiirola this is my other oddity: I kind of like this function, and we hid it in the docplex writer. Where should we put it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ans: repn.util, if it or something similar isn't already there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Support Gurobi nonlinear expressions in the direct/persistent solvers

2 participants