-
Notifications
You must be signed in to change notification settings - Fork 87
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
Indicator constraint support #709
Conversation
Codecov Report
@@ Coverage Diff @@
## master #709 +/- ##
==========================================
+ Coverage 93.73% 93.83% +0.09%
==========================================
Files 54 54
Lines 5572 5677 +105
==========================================
+ Hits 5223 5327 +104
- Misses 349 350 +1
Continue to review full report at Codecov.
|
src/sets.jl
Outdated
@@ -449,7 +466,7 @@ function Base.copy(set::Union{Reals, Zeros, Nonnegatives, Nonpositives, | |||
PositiveSemidefiniteConeSquare, | |||
LogDetConeTriangle, LogDetConeSquare, | |||
RootDetConeTriangle, RootDetConeSquare, | |||
Integer, ZeroOne, Semicontinuous, Semiinteger}) | |||
Integer, ZeroOne, Semicontinuous, Semiinteger, IndicatorSet}) |
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.
It is not an isbits type since it contains a vector. The copy should probably copy this vector too
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.
You're right, I'll re-implement copy. Should we make the vector type generic?
What about having a set parameter for whether Then the disjunction
reusing the |
Should we make the indicator set generic on vector type? |
What are the implications of having non One way to avoid storing the
Then use VAF to write down the constraints, e.g., (1.0 * y, 2*x + 3*z) in IndicatorSet(LessThan(b)) It's an error if the first component of the VAF isn't 1.0 times some variable. |
The SOS sets already have weight vectors, so this isn't breaking new ground. No problem on the MOF front |
see last version for generic vector |
Oh, wait. I misread miles' concern. Not sure how abstractvector would play with MOF. I'd prefer the vectoraffinefunction in set approach. |
This reverts commit 6e57763.
problem with |
What do you mean by this? |
Either |
The weird special term is fine with me. That's what we do for cones. We have machinery already to translate JuMP AffExprs into VAF, so today you could write: @constraint(model, [y, 2x + 3z] in IndicatorSet(LessThan(b))) OTOH, @constraint(model, [y, x, z] in IndicatorSet([2.0, 3.0], LessThan(b))) seems like a regression in modeling because you have to manually create a list of coefficients. |
Ok I see. |
Yes, those are all parsed differently. |
one thing is that the set cannot determine the dimension of the expected function |
The dimension of the set I'm proposing (under the MOI definition) would always be 2. |
ok I hadn't thought of counting like this, so the whole affine term |
What about @constraint(model, 2x1 + x2 in MOI.IndicatorSet(y=>1, MOI.GreaterThan(1.0))) So struct IndicatorSet{S}
variable::Pair{MOI.VariableIndex, Bool}
set::S
end Then if |
Ok, one design consideration I tried to keep is to represent the constraint as closely as possible to what solvers take as input |
Fixed most of the comments. @blegat I didn't find anything for testing new sets with MockOptimizer. |
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.
Almost there. Missing a (tested) copy implementation that copies the internal set
Thanks, added in last commit |
s1_copy = copy(s1) | ||
s2_copy = copy(s2) | ||
@test s1_copy isa MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE} | ||
@test s1 == s1_copy |
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.
Check that modifying the set in s1
does not modify the set in s1_copy
. You will need a scalar set which is mutable
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.
do we even have one? I understand the importance of testing it does not happen, but we are calling copy on the subtest, so if error there is, it's because copy
is not properly implemented on it
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.
@matbesancon LessThan{BigInt}
is mutable because BigInt
is mutable. You call also create a dummy mutable coefficient type or a dummy mutable set just for the test.
we are calling copy on the subtest
That's what we want to test. If you remove this copy on the subset, the tests still pass while they shouldn't
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.
@blegat I played a bit with this idea. Fundamentally, this is breaking an assumption about numbers that will be everywhere in MOI, this PR doesn't change that. BigInt
being mutable is just a constraint for their construction as far as I know, not supposed to be used.
The implementation from src/sets
:
# isbits types, nothing to copy
function Base.copy(set::Union{Reals, Zeros, Nonnegatives, Nonpositives,
GreaterThan, LessThan, EqualTo, Interval,
SecondOrderCone, RotatedSecondOrderCone,
GeometricMeanCone, ExponentialCone,
DualExponentialCone, PowerCone, DualPowerCone,
PositiveSemidefiniteConeTriangle,
PositiveSemidefiniteConeSquare,
LogDetConeTriangle, LogDetConeSquare,
RootDetConeTriangle, RootDetConeSquare,
Integer, ZeroOne, Semicontinuous, Semiinteger})
return set
end
Is then false because it should check isbits
on the set
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.
Good point. We could defer the question of whether we should copy the field of EqualTo... to a separate issue.
Still you might be able to create a mutable abstract set with Float64 to test the fact we ce copy the set for IndicatorSet
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.
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.
Looking good. Just a few minor comments.
First draft for the addition of indicator constraints to MOI. There is evidence for multiple solvers handling them:
Gurobi
CPLEX
SCIP
One thing we would want to add (suggestion from @leethargo) is a bridge for solvers supporting SOS1 but not indicator constraints natively. From SCIP documentation: