-
Notifications
You must be signed in to change notification settings - Fork 64
feat: Add sos constraints #495
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
base: master
Are you sure you want to change the base?
Conversation
Note that with the implementation here, it is currently unclear how to remove an SOS constraint again or where to access dual values. Is that a thing for SOS constraints? |
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.
Impressive and wonderful! the IO currently only support the polars lp file writing, not the "standard" pandas based, right? for non-breaking compat we would then need to focus on the IO
Great, I will test out now!
No need to worry about duals since it's MILP class. Option to remove SOS constraints would be useful.
Would be cool if the standard pandas lp file writing were supported. But probably @coroa just sketched it with polars first. |
Indeed, i was only sketching out how it works (it's still a draft). Currently supported:
I don't think it's difficult to do the others. |
For removing, it would be easy to add:
|
Open question: Context: The weight of an SOS constraint is only relevant for ordering the variables in an SOS2 constraint (where 2 adjacent variables can be non-zero). If we use the coordinate values:
The current implementation uses coordinate values, but the more i think about it, i think this is more confusing than helpful (i like string coordinates, sometimes) and using the coordinate order directly seems to be intuitive. if you want a different order, it would be fine to reindex the dimension. Any other thoughts? Am I misunderstanding SOS weights? |
2nd open question: should we add a check/raise when the solver does not support sos constraints in the lp file somewhere? |
It would certainly be more general. If I understand correctly, it's only relevant for SOS2 since SOS1 does not care about order. Mostly, SOS2 would be used for interpolation, in which case the coordinate would very likely be a numerical value. But I think it's better to be explicit. In Gurobi reference you can find:
https://docs.gurobi.com/projects/optimizer/en/current/concepts/modeling/constraints.html
Yes, definitely an error should be thrown when an attempt is made to solve a model with SOS constraints when either the solver or the IO API (or the combination) does not support it. Other Feedback
Here are the cases I played with (could be unit tests): import linopy
import pandas as pd
import numpy as np
m = linopy.Model()
locations = pd.Index([0, 1, 2], name="locations")
build = m.add_variables(coords=[locations], name="build", binary=True)
m.add_sos_constraints(build, sos_type=1, sos_dim="locations")
m.add_objective(build * [1, 2, 3], sense="max")
m.solve(solver_name='gurobi', io_api='lp-polars')
assert np.isclose(build.solution.values, [0, 0, 1]).all()
assert np.isclose(m.objective.value, 3)
m = linopy.Model()
locations = pd.Index([0, 1, 2], name="locations")
build = m.add_variables(coords=[locations], name="build", binary=True)
m.add_sos_constraints(build, sos_type=2, sos_dim="locations")
m.add_objective(build * [1, 2, 3], sense="max")
m.solve(solver_name='gurobi', io_api='direct')
assert np.isclose(build.solution, [0, 1, 1]).all()
assert np.isclose(m.objective.value, 5)
m = linopy.Model()
locations = pd.Index([0, 1, 2], name="locations")
build = m.add_variables(coords=[locations], name="build", binary=True)
m.add_sos_constraints(build, sos_type=2, sos_dim="locations")
m.add_objective(build * [2, 1, 3], sense="max")
m.solve(solver_name='gurobi', io_api='direct')
assert np.isclose(build.solution, [0, 1, 1]).all()
assert np.isclose(m.objective.value, 4) |
i guess we could improve this representation to:
|
I guess this is fine as long as it is possible to distinguish between SOS1 and SOS2 sets. |
3bd223e
to
f82876f
Compare
Rebased on latest master (ie. where only lp-polars remains) I added the representation that we talked about above. I added the Solver support seems to be:
We unfortunately do not have a good representation of solver features! Do we? Anyone has any prior ideas on how this should look like? |
Closes #437 (if applicable).
Changes proposed in this Pull Request
Add Special Ordered Sets (SOS) Constraints Support
I added SOS1/2 constraints as an extension of variables. ie. in the example
The
add_sos_constraints
only addssos_type
andsos_dim
as attributes to thebuild
variable's dataset.These attributes have then to be interpreted by the lp file writer or the direct apis. In this draft version this is implemented for the gurobipy direct api as well as for the lp-polars writer.
The coordinates of the chosen dimension are also always used as weights for the SOS. It felt natural, but i am open to other suggestions. Weights are only used by SOS2 constraints to order them, and then only two adjacent variables can be non-zero at the same time. In principle always taking the coordinate order directly (ie use something like
np.arange(var.sizes[sos_dim])
as weights) would be the another option.The documentation that i added was claude written and might still contain mistakes. The code is tested, but the claude tests are to extensive to be helpful. I need to clean them up first.
Core SOS Constraints API
Model.add_sos_constraints()
: New method to add SOS1 and SOS2 constraints to variablessos_type
,sos_dim
)SOS Constraint Types
Solver Support
gurobipy
📁 Files Added/Modified
Core Implementation
linopy/model.py
: Addedadd_sos_constraints()
method with validationlinopy/variables.py
: Enhanced Variable class with SOS attribute support andVariables.sos
propertylinopy/io.py
: SOS constraint export for file-based solvers and Gurobi direct APIDocumentation & Examples
doc/sos-constraints.rst
: Comprehensive documentation with theory and examplesdoc/index.rst
: Updated to include SOS constraints documentationTesting
to be done
Checklist
doc
.doc/release_notes.rst
of the upcoming release is included.