-
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
Complementarity constraint #771
Comments
The idea is to load directly complementarity constraints to the solver if it supports them. As far as I understand, Complementarity.jl reformulates complementarity constraints as NLP constraints. Once NLP would become first class in MOI, we may want to write bridges to reformulate complementarity constraints as NLP ones. |
SGTM. "How do I add complementarity constraints to JuMP?" was one of the original motivators for MOI. |
This will be great. In fact, I'm not so happy with the reformulations strategy currently in place with Complementarity.jl. A solver-native approach would be awesome. By the way, I have used something like the following in Complementarity.jl @complements(m, 0 <= F(x), x >= 0) A special symbol @constraint(m, 0 <= F(x) complements x >= 0) |
it may be reformulated differently in MILP-based solvers, or solvers with better support for integrality than non-linear constraints, using SOS1 or indicator constraints |
Sorry for giving my input so late, was too busy with ICCOPT 2019, and then I first got myself more familiar with MOI by porting my solver ReSHOP to MOI. TLDR I would like to push for supporting more than just "complementarity constraint" (CC) like 0 <= F(x) ⟂ x >= 0, but LCP, MCP, VI (variational Inequalities), QVI (quasi-variational inequalities), MPCC and MPEC. I started to type a design document 2 years ago for MBP, but right at the time the transition to MOI was started, so I will update it. I get the feeling that more problem classes can be handle through MOI. I have a lightly different take on the kind of relations to support and the UI, which I will try to motivate by some perceived shortcomings of the proposed syntax. There is quite a few occurrences of the VI lingo, I hope it is not too off-putting. Discussion on the "natural interface"
|
Thanks for the input @xhub! I believe Michaels' preference is exactly your option B): So we would define struct Complements <: MOI.AbstractVectorSet end Solvers (e.g., PATH.jl) would support function MOI.add_constraint(model, ::MOI.VectorAffineFunction, ::MOI.Complements) and throw an error is Then, bridges would map people writing @constraint(model, [y, x] in Complements()) into @constraint(model, [1.0 y, x] in Complements()) JuMP can't (currently) handle @constraint(model, [sin(y), x] in Complements()) because it doesn't have an @variable(model, z)
@NLconstraint(model, z == sin(y)
@constraint(model, [y, x] in Complements()) Handling quasi-variational inequalities seems harder, and a stretch goal. You could define @constraint(model, [F(x), x, y] in QuasiVariationalInequality()) But the number of solvers supporting this seems minimal. It might be a good function/set combo for Path-VI to support until we work out the details, rather than add to MOI from the outset. |
Would the following also work (inspired by SOS(1|2)) ? struct Complements <: AbstractVectorSet
variable::Union{MOI.VariableIndex,MOI.VectorOfVariables}
end This would also allow for the use of vectors in the definition of CC. The canonical signature would then be function MOI.add_constraint(model, S, ::MOI.Complements) where S <: Union{MOI.VariableIndex, VOV, SF, VAF, VQF} On the JuMP side, we would have @constraint(model, y in Complements(x))
@constraint(model, x*x - 1 in Complements(x)) For the NLP workaround, it's a bit sad, I have read #846 . In EMP.jl I used some macro @NLvipair. Maybe we could have a nicer but hackisch @variable(m, z)
@NLconstraint(m, func == z)
@constraint(m, z in ComplementsNL(x)) where Furthermore, the variable For MPCC, the situation may be different, since for instance KNITRO requires the CC constraints to be between 2 variables. It seems that they would not need to differentiate. Finally for QVI, how about a struct QuasiVariationalInequalitySet <: AbstractVectorSet
x::Union{MOI.VariableIndex,MOI.VectorOfVariables}
y::Union{MOI.VariableIndex,MOI.VectorOfVariables}
end That would allow for @constraint(model, F(x) in QuasiVariationalInequality(x, y)) |
I started an interface to PATH here: https://github.com/odow/PATH.jl. (It's intended to replace https://github.com/chkwon/PATHSolver.jl, which uses an additional C wrapper instead of going directly into the My next step is to write the MOI interface. Talking with Michael, we will support @constraint(model, [i=1:2], [i * x[1] + x[2], x[i]] in Complements()) You could also make This is a little ungainly, so I might try to implement @constraint(model, [i = 1:2], i * x[1] + x[2] ⟂ x[i]) Alternatively, we might take advantage of jump-dev/JuMP.jl#2051, and write @constraint(model, [i=1:2], complements(i * x[1] + x[2], x[i])) In any case, the JuMP syntax is purely cosmetic. The MOI syntax is the one required by the solvers.
No. One limitation with the current MOI implementation is that we really don't want the sets to contain variables because this violates a lot of the assumptions made by bridges etc.
I agree. In regard to nonlinear: I retract my previous work-around because you're right, it might destroy convexity/monotonicity. We won't be targeting nonlinear equilibrium problems until MOI has a
Does KNITRO allow @constraint(model, z == x + y)
@constraint(model, [z, x] in Complements()) If so, it can just support |
@odow A direct Julia interface to PATH is great! When PATHSolver.jl was written, installing PATH libraries was a bit of headache. Hope it will work out smoothly this time. By the way, they will not allow the name PATH.jl to be registered in METADATA.jl. |
Yes, hopefully this will just require installing
Ah. Good to know. I guess |
@odow I confirm that Knitro would allow your formulation. |
@frapac Based on the comments in https://github.com/JuliaOpt/KNITRO.jl/blob/master/examples/mpec1.jl I infered that it even requires that formulation. Am I missing something? |
Ok that's unfortunate. Is it something that is planned on being worked on? Sorry if I sound pushy, it would be great to be able to write @constraint(model, A*x + b ⟂ x) Could we have a struct ComplementsPairing{F,V} <: AbstractFunction
func::F
variable::V
end Then we can allow for scalar and vector use of Complements. The MOI signature would then be
|
Not pushy at all. But, we should distinguish between the JuMP syntax, and the MOI syntax. The immediate question is what the MOI syntax should be, and I favor The JuMP syntax you wrote looks great, and is what we should aim for. JuMP would lower that syntax into the vector of the complements constraints. |
Progress: julia> using JuMP, PATH
julia> model = Model(with_optimizer(PATH.Optimizer))
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: SolverName() attribute not implemented by the optimizer.
julia> @variable(model, x >= 0)
x
julia> @constraint(model, [x + 2, x] in PATH.Complements())
[x + 2, x] ∈ PATH.Complements()
julia> optimize!(model)
Path 5.0.00 (Mon Aug 19 10:57:18 2019)
Written by Todd Munson, Steven Dirkse, Youngdae Kim, and Michael Ferris
Crash Log
major func diff size residual step prox (label)
0 0 1.5279e+00 0.0e+00 (f[ 1])
1 1 1 1 0.0000e+00 1.0e+00 0.0e+00 (f[ 1])
Major Iteration Log
major minor func grad residual step type prox inorm (label)
0 0 2 2 0.0000e+00 I 0.0e+00 0.0e+00 (f[ 1])
Major Iterations. . . . 0
Minor Iterations. . . . 0
Restarts. . . . . . . . 0
Crash Iterations. . . . 1
Gradient Steps. . . . . 0
Function Evaluations. . 2
Gradient Evaluations. . 2
Basis Time. . . . . . . 0.000015
Total Time. . . . . . . 0.132081
Residual. . . . . . . . 0.000000e+00
julia> value(x)
0.0
julia> termination_status(model)
LOCALLY_SOLVED::TerminationStatusCode = 4 |
This function would not only be useful for complementarity constraints but also for indicator constraints. In fact, it was already proposed in #709 (comment). |
I would favour a tailored data structure where the functional part and the variable part are clearly separated. Just by looking at the definition of Furthermore, it would require the type I understand a drawback is to have to support another type, with the risk of having to depreciate it.
What would be cost of having to lower it vs just building a data structure? I'm just wondering :) |
@blegat Thanks for your input, I guessed right about the resistance of adding new types, which totally makes sense. I will try to further rest my case for a data type of a tuple (variable, function). One may wish to write some utilities to extract from a VAF a tuple (variable, function). Convention are usually based on the semantics of the applications, which can be inconsistent. It's true that such a data structure is not necessary in "classical" mathematical programming. It would also be useful in disjunctive programming, where it is also necessary to associate constraints with a variable. It would also work to encode those relationship by convention. I will try to think about this data strcture allowing something more. I doubt I will come up with anything, since a vector function are always capture a tuple (var, func). |
@xhub To be a bit more concrete, defining a new MOI function is about 50x more effort than defining a new set given how the infrastructure has been designed.
Relatively speaking, this is a really tiny amount of code. |
This is exactly what I do in PATH. A rough implementation without errors that need improving is here: https://github.com/odow/PATH.jl/blob/f15f931c64bfd4a81cfb3aeaac51214ca8885a2d/src/MOI_wrapper.jl#L82-L138
Not sure. But probably << than the cost of a PATH solve. I'd be surprised if it was the bottleneck. |
So I think we should define: struct Complements <: MOI.AbstractVectorFunction
dimension::Int
end Then we require that the vector valued function in Then you could go: model = Model()
@variable(model, x[1:2] >= 0)
@variable(model, y[1:2])
@constraint(model, [M * x .+ q; x] in Complements(2))
@constraint(model, [y; x] in Complements(2)) Edit: this syntax is now implemented in PATH.jl: https://github.com/odow/PATH.jl#example-usage |
And here's the transmcp example from GAMS in JuMP: https://github.com/odow/PATH.jl/blob/master/examples/transmcp.jl Current syntax forces us to write: @constraints(model, begin
vec([profit x]) in PATH.Complements(length(x))
vec([supply w]) in PATH.Complements(length(w))
vec([fxdemand p]) in PATH.Complements(length(p))
end) If we added the |
Sounds good, you guys all know better how much work it is to introduce new functions, and how MOI was intended to work. struct Complements <: MOI.AbstractVectorFunction
dimension::Unsigned
end sounds like a very good idea. From a modeler standpoint, we should support Or we would only expose |
This will be at parse time in |
We discussed with @frapac how to create a complementarity constraint type.
One idea would be to add a type
And the constraint
[x, y]
-in-Complementarity
would constraintx, y
to be nonnegative andx * y
to be zero.The text was updated successfully, but these errors were encountered: