Complementarity.jl with Path

Some good news is that you can stop using Complementarity.jl. We’ve recently added first-class support for mixed-complementarity problems to JuMP. See:

Here’s what the translation would look like:

using JuMP
import PATHSolver
A = [300, 350, 400, 450, 500]
theta = [0.2, 0.2, 0.2, 0.2, 0.2]
B = 1
I = 90
C = 60
Tau = 8760
technologies = [1, 2, 3, 4, 5]
m = Model(PATHSolver.Optimizer)
@variables(m, begin
    x[technologies] >= 0
    Q[technologies] >= 0
    alpha[technologies] >= 0
end)
for i in 2:length(technologies)
    @constraint(m, x[1] == x[i])
end
@constraints(m, begin
    max_capacity[i in technologies], x[i] - Q[i] ⟂ alpha[i]
    kkt_Q[i in technologies], Tau * sum(theta[j] * (C - A[j] + B * Q[j]) for j in technologies) + alpha[i] ⟂ Q[i]
    kkt_x[i in technologies], 1000 * I - alpha[i] ⟂ x[i]
end)
optimize!(m)
println("x = ", value.(x))
println("Q = ", value.(Q))

But if you run the code, you’ll get the error:

julia> for i in 2:length(technologies)
           @constraint(m, x[1] == x[i])
       end
ERROR: Constraints of type MathOptInterface.ScalarAffineFunction{Float64}-in-MathOptInterface.EqualTo{Float64} are not supported by the solver.

If you expected the solver to support your problem, you may have an error in your formulation. Otherwise, consider using a different solver.

The list of available solvers, along with the problem types they support, is available at https://jump.dev/JuMP.jl/stable/installation/#Supported-solvers.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] _moi_add_constraint(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.GenericOptimizer{Float64, MathOptInterface.Utilities.ObjectiveContainer{Float64}, MathOptInterface.Utilities.VariablesContainer{Float64}, PATHSolver.OptimizerFunctionConstraints{Float64}}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, f::MathOptInterface.ScalarAffineFunction{Float64}, s::MathOptInterface.EqualTo{Float64})
   @ JuMP ~/.julia/packages/JuMP/ToPd2/src/constraints.jl:679
 [3] add_constraint(model::Model, con::ScalarConstraint{AffExpr, MathOptInterface.EqualTo{Float64}}, name::String)
   @ JuMP ~/.julia/packages/JuMP/ToPd2/src/constraints.jl:706
 [4] macro expansion
   @ ~/.julia/packages/JuMP/ToPd2/src/macros.jl:1345 [inlined]
 [5] top-level scope
   @ ./REPL[14]:2

That’s because you cannot add equality constraints to a mixed-complementarity problem.

You need to do instead:

using JuMP
import PATHSolver
A = [300, 350, 400, 450, 500]
theta = [0.2, 0.2, 0.2, 0.2, 0.2]
B = 1
I = 90
C = 60
Tau = 8760
technologies = [1, 2, 3, 4, 5]
m = Model(PATHSolver.Optimizer)
@variables(m, begin
    x[technologies] >= 0
    Q[technologies] >= 0
    alpha[technologies] >= 0
    μ[technologies[2:end]]   # !!! NEW !!!
end)
@constraints(m, begin
    [i=technologies[2:end]], x[1] - x[i] ⟂ μ[i]   # !!! NEW !!!
    max_capacity[i in technologies], x[i] - Q[i] ⟂ alpha[i]
    kkt_Q[i in technologies], Tau * sum(theta[j] * (C - A[j] + B * Q[j]) for j in technologies) + alpha[i] ⟂ Q[i]
    kkt_x[i in technologies], 1000 * I - alpha[i] ⟂ x[i]
end)
optimize!(m)
println("x = ", value.(x))
println("Q = ", value.(Q))

and now I get the same solution as Complementarity.jl.

If this solution isn’t what you expect, then you have a mistake somewhere in your equations.

1 Like