Closed schlichtanders closed 2 months ago
This would be a something like the all_equal
constraint from constraint programming. This would be something that could be added to the package so that we can use something like: @constraint(m, Y in AllEqual())
. We would need to discuss how this would be reformulated.
You can also use @constraint(m, [i in 1:n-1], Y[i] == Y[i+1] := true)
to avoid writing all Y variables. This is an alternate formulation for what you have referenced above.
You can just use splatting with the logical_and
function:
@constraint(m, logical_and(Y...) := true)
Other useful functions you can use include logical_or
, logical_not
, implies
, and iff
.
I don't think any feature additions are needed, but we should better document these functions.
Thank you both for your solutions and your help! Really cool that this already exists.
(I tried @constraint(m, reduce(==, Y) :=)
which didn't seem to work)
reopened for tracking the documentation request
You can just use splatting with the
logical_and
function:@constraint(m, logical_and(Y...) := true)
@pulsipher , thank you for pointing out the splatting. The correct splatting based on @schlichtanders request would be:
@constraint(m, iff(Y...) := true)
However, I will point out that neither of these are correct if you want to "constraint them all to be equal". Here is why:
1) Y[1] == Y[2] == Y[3]
:= true can be accomplished with and odd number of true
values: e.g., Y[1] = true
, Y[2] = false
, and Y[3] = false
.
2) Y[1] and Y[2] and Y[3]
:= true forces all of them to be true, but ignores the possibility of all of them being equal to false.
Therefore, only @constraint(m, [i in 1:n-1], Y[i] == Y[i+1] := true)
will accomplish the "all equal" requirement by linking the variables sequentially. In the 3 variable example, this would be equivalent to Y[1] == Y[2] := true
and Y[2] == Y[3] := true
. These two constraints can only be satisfied if all of the variables are true
or if all of them are false
, meaning they are "all equal".
@hdavid16 To make them all equal (either true or false) with one constraint, couldn't you do the following:
@constraint(m, logical_and(Y...) || ¬logical_and(Y...) := true)
Which forces the variables to all be true
or all be false
. I suppose this doubles the number of terms in the constraint, but it should work.
What's cool is that the framework is flexible enough to do all these different ways of formulating the constraint.
@pulsipher yes that is another valid approach. However, you would need to have the negation inside the second logical_and
so that you have that all are false
:
@constraint(m, logical_and(Y...) || logical_and(logical_not.(Y)...) := true)
I suspect my sequential 2 term constraint set is more efficient, but I agree that it's great that the flexibility is there to test alternate representations.
I know that one can do
@constraint(m, Y[1] == Y[2] == ... == Y[n] := true)
, but I am wondering whether this is also possible without explicitly naming all single Y.