-
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
Add support for NotEqualTo != #2405
Comments
Let me comment on each case separately. But 1), 2), and 3) are likely a "no." 4) is a possible. I don't understand why 5) would be useful.
For this, we'd need to introduce a new
This would rewrite a
if you did the
Okay. This has merit. Instead of adding a But that's easy. Reified is a good example to follow, replacing
Which solver is this transformation needed for? |
@odow thank you for taking a look!
My main motivation is what we've just discussed in jump-dev/JuMP.jl#3651,
Aha! Okay.
My main problem is that said bridge ( MathOptInterface.jl/src/Bridges/Constraint/bridges/count_distinct.jl Lines 29 to 30 in 873d219
so if in x != 0 , x is known to be in [-100, 100] , we introduce at least ~201 variables,and it doesn't work at all if the range is unknown? ... while 2. would just work and only require a single new variable. So while i do agree that this general bridge Perhaps 4. can be an intermediate solution,
Err, i, of course, meant |
(IOW it looks to me almost as if those |
There's certainly room to have improved formulations for the One design consideration that I think we agree on is that we want to, as far as possible, limit the number of functions and sets in MOI and JuMP. We don't want to turn into constraint programming where there are Normally, a good rule of thumb is that we only introduce a set if a solver has native support for it. Perhaps as a compromise, there's room for a package of JuMP reformulations. This would make the models easier to write: julia> module JuMPReformulations
using JuMP
function monotonic(x::Vector{VariableRef})
@constraint(owner_model(first(x)), x[1:end-1] .<= x[2:end])
return
end
function not_equal(x::VariableRef, y::VariableRef)
@assert is_integer(x) && is_integer(y)
@assert owner_model(x) === owner_model(y)
model = owner_model(x)
z = @variable(model, z)
@constraint(model, z --> {x >= y + 1})
@constraint(model, !z --> {x <= y - 1})
return
end
end
WARNING: replacing module JuMPReformulations.
Main.JuMPReformulations
julia> using JuMP
julia> model = Model();
julia> @variable(model, x[1:2], Int);
julia> JuMPReformulations.monotonic(x)
julia> JuMPReformulations.not_equal(x[1], x[2])
julia> print(model)
Feasibility
Subject to
x[1] - x[2] ≤ 0
!z --> {x[1] - x[2] ≤ -1}
x[1] integer
x[2] integer
z --> {x[1] - x[2] ≥ 1} |
Yes, i very much understand being vary of adding ever more stuff to support. Again, everyone's mileage may vary, not everything will be useful for everyone, To summarize, let me look into the seemingly least controversial one,
|
True, except that the reformulations often perform poorly. I'm hesitant to add something like In some ways, forcing people to write an expansion for |
Ack, i've actually thought/wondered about that, but in the more general sense: As for performance, sure, but i can't imagine |
No
The other issue is that it's very sensitive to the formulation being able to detect that model = Model()
@variable(model, x, Int)
@variable(model, y)
@constraint(model, x == y)
@constraint(model, x != 0) # Works
@constraint(model, 2x != 2) # Fails
@constraint(model, y != 0) # Fails |
…erent(2)` ``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
So we'd make it picky in so that it's operands must be [Binary] variables. |
…erent(2)` ``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
…erent(2)` ``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
Whether or not we add a new set in MOI should be based on the fact that several solver supports these set natively. If only a single solver supports this set, then the solver can define it in the MOI wrapper (see for instance SCS and ECOS). If two solver share a same set then it makes sense to consider adding it in MOI. Are the sets you suggest supported by any solver ? If not, you can still make a case that it's very helpful for modeling and fits well within the existing sets and bridges in MOI (then, once it's added, maybe it will enable solvers to start supporting it) |
I'm not aware of any supported solver supporting strict inequalities (
That's my reasoning, yes. This I haven't checked, can a To me, this seems like an obvious improvement, even if a bit controversial one. To be most precise, i don't think strict inequalities make sense for non-MILP, only for MILP. |
``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
``` (@v1.10) pkg> activate /repositories/JuMP.jl Activating project at `/repositories/JuMP.jl` julia> using JuMP Precompiling JuMP 1 dependency successfully precompiled in 10 seconds. 37 already precompiled. julia> model = Model(); julia> @variable(model, x[1:3]) 3-element Vector{VariableRef}: x[1] x[2] x[3] julia> @variable(model, y[1:3]) 3-element Vector{VariableRef}: y[1] y[2] y[3] julia> @constraint(model, x[1] != y[1]) x[1] != y[1] julia> @constraint(model, x .!= y) 3-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.AllDifferent}, VectorShape}}: x[1] != y[1] x[2] != y[2] x[3] != y[3] julia> @constraint(model, x != y) ERROR: At REPL[8]:1: `@constraint(model, x != y)`: Ineqality operator with vector operands must be explicitly vectorized, use `.!=` instead of `!=`. Stacktrace: [1] error(::String, ::String) @ Base ./error.jl:44 [2] (::JuMP.Containers.var"#error_fn#98"{String})(str::String) @ JuMP.Containers ~/.julia/compiled/v1.10/JuMP/DmXqY_F8XkK.so:-1 [3] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [4] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [5] top-level scope @ REPL[8]:1 ``` I'm not yet sure how to support the not-explicitly vectorized case. We'd need to somehow deduce (in `parse_constraint_call()`) that our arguments are vectors, and extend `parse_constraint_call()` to return `vectorized` itself. I'm not convinced this is even possible. Otherwise, we get ``` julia> @constraint(model, x != y) vectorized = false ERROR: MethodError: no method matching _build_inequality_constraint(::Bool, ::JuMP.Containers.var"#error_fn#98"{String}, ::Vector{VariableRef}, ::Vector{VariableRef}) Closest candidates are: _build_inequality_constraint(::Function, ::Bool, ::Vector{VariableRef}, ::Vector{VariableRef}) @ JuMP /repositories/JuMP.jl/src/inequality.jl:14 Stacktrace: [1] macro expansion @ /repositories/JuMP.jl/src/macros/@constraint.jl:132 [inlined] [2] macro expansion @ /repositories/JuMP.jl/src/macros.jl:393 [inlined] [3] top-level scope @ REPL[8]:1 ``` (because we should have called `@constraint.jl:123`) Missing tests, docs. As discussed in jump-dev/MathOptInterface.jl#2405
I'm not really in favor of adding MOI sets only for the benefit of better model printing and ease of writing the model. MIP modeling is hard, and if we present an interface to users that pretends that it's easy (just pick the right set and let JuMP do the work) then we'll invite users into the bad habit of not understanding what the solver is seeing. This is super important for MIP modeling in particular, maybe less so far nonlinear. A lot of these indicator constraint formulations are technically correct but probably not most efficient as the size of the problem scales up. I'm worried that we'll get a ton of support questions along the lines of "why is my model with 1000 Oscar's example of a library of extra helper functions makes a lot of sense IMO. Then it's very clear what's going on. |
The performance concern is valid, sure, here's some 5c from me: This seems a bit unaligned with the current handling of sets: MathOptInterface.jl/src/Bridges/Constraint/bridges/count_distinct.jl Lines 29 to 30 in 873d219
If that is a problem, does it not seem like it already exists? Should MOI error out on not-natively-supported sets? I don't quite get why it matters where the code that is "slow" Also, efficiency of something that does not allow to solve some problem Again, just my 5c. |
As mentioned above, the general principle is for MOI to be an abstraction over solvers. We add sets to support constraints that are supported natively by a solver (or even better, a family of solvers). We added sets like |
See also the implementation at jump-dev/JuMP.jl#3656
@LebedevRI I get that
It's worth viewing the constraint programming sets in the context of |
Okay, and if we go with "don't add Set's to MOI unless supported by supported solver",
|
With these things, we often ask that people start experimenting with ideas in a personal repository, e.g.,
The most useful part of it being in your own repository is that you get to decide. Do what ever you think is best. Being able to demonstrate something that works is a good way of overcoming our objections 😄. It may also turn out that you learn "these three things were good ideas, these two were bad," and then we can incorporate those lessons back into MOI. We tend to be conservative adding things to MOI/JuMP because we get locked into supporting them and ensuring backwards compatibility. You don't have these limitations in your own repo. We've documented how and when we would consider moving this to (A good example is https://github.com/trulsf/UnitJuMP.jl, which may one day become official jump-dev/JuMP.jl#1350) |
This is a related post to jump-dev/JuMP.jl#3656 (comment) We discussed this issue at length on the monthly developer call. Thoughts:
Conclusions:
I think the best path forward is a JuMP extension repository that contains a bunch of reformulations (at the JuMP level) for people interested in constraint programming. |
Thank you for taking a look
FWIW, it is not at all obvious to me why the whole expansion should not be expanded to the two-element case first,
|
That expansion results in N(N-1)/2 constraints, and we'd then have to reformulate. If we did your indicator constraint approach, that's N(N-1) indicator constraints which is pretty expensive. The current one lowers to It isn't obvious which is more efficient in practice. |
I've opened a PR to improve the bridge reformulation: #2416, and I've marked that merging it will close this issue. |
To complement, the idea of understanding Constraint Programming predicates at parsing time in JuMP macros was attempted in jump-dev/JuMP.jl#2241 and it wasn't merged. What we do in JuMP macros need to work for any field of optimization and should be quite simple and transparent. On the other hand, with the new nonlinear interface, it's getting easier to create arbitrary expression graphs in JuMP and then the solver is free to parse it as it likes. This allows meta-solvers like Convex.jl to do DCP or for a CP meta-solver to understand CP primitives. So, thanks to jump-dev/JuMP.jl#3530, you can now write |
These are perhaps not very high on anyone's priority list,
and models can avoid needing them, but they come up,
so i wonder if these would be welcomed? (if someone contributes them)?
@constraint(model, [i=2:length(x)], x[i] <= x[x-i])
(configurable predicate)Int
)x != 0
->c ? (x >= 1) : (x <= -1)
Int
)x != y
->z = x - y; z != 0
x != y
->(x, y) in MOI.AllDifferent
x >= y
->x > y and x != y
(configurable predicate)The text was updated successfully, but these errors were encountered: