ConstraintSolver.jl
ConstraintSolver.jl copied to clipboard
Support of nonlinear constraints?
Are there plan to support general nonlinear constraints (in the future)?
Coming from constraint programming systems such as MiniZinc, Picat, Gecode, OR-tools, etc, I'm quite used to - and spoiled with - nonlinear constraints. But what I can see, there is no support at all in ConstraintSolver.jl for nonlinear constraints which is - I assume - because JuMP don't handle general nonlinear constraint what I know. And it seems that ConstraintSolver.jl don' support quadratic constraints either.
Here's a simple (and contrived) example which yield the following error:
MOI.ScalarQuadraticFunction{Float64}-in-'MOI.GreaterThan{Float64}' constraints are not supported and cannot be bridged into supported constrained variables and constraints. See details below: ....
# ....
@variable(model, 1 <= x[1:n] <= n, Int)
@variable(model, b1[1:n], Bin)
for i in 1:n
@constraint(model, b1[i] := {x[i] <= i})
@constraint(model, b1[i]*x[i] >= 1)
end
# ...
And the following constraint yield Cannot multiply a quadratic expression by a variable
# ...
@constraint(model, b1[i]*x[i]*x[i] >= 1)
# ...
I know that many/most nonlinear constraint can be reformulated using a lot of binary variables instead, but I would really prefer to use "traditional" nonlinear constraints, especially when trying to translate (decompose) global constraints.
Here's a more realistic example: modelling the cumulative
global constraint (adapted from MiniZinc's cumulative function)
function cumulative(model, start, duration, resource, b)
tasks = [i for i in 1:length(start) if resource[i] > 0 && duration[i] > 0]
num_tasks = length(tasks)
# upper and lower limits of start times
times_min_a = round.(Int,[JuMP.lower_bound(start[i]) for i in tasks])
times_min = minimum(times_min_a)
times_max_a = round.(Int,[JuMP.upper_bound(start[i]) for i in tasks])
times_max = minimum(times_max_a)
for t in times_min:times_max + 1
bs = @variable(model, [1:num_tasks], Bin)
bt = @variable(model, [1:num_tasks], Bin)
for i in tasks
# This don't work: Throws: `no method matching isless(::VariableRef, ::Int64)`
# Hence the use of indicators.
# @constraint(model,sum([(start[i] <= t) * (t <= start[i] + duration[i])*resource[i] for i in tasks]) <= b)
# Using indicators instead:
@constraint(model, bs[i] := {start[i] <= t})
@constraint(model, bt[i] := {t <= start[i]})
# This throws MOI.ScalarQuadraticFunction ... error
@constraint(model,sum([bs[i] * (bt[i] + duration[i])*resource[i] for i in tasks]) <= b)
end
end
end
It's currently not planned to do this even though JuMP supports non linear constraints. The problem for the constraint solver is that I don't know how to prune such constraints.
OK. Is it the same with quadratic constraints?
Yes whereas there it might be easier to do something I think. I was think I can support them if I have something like: monotonically increasing in all variables but that is quite restrictive. I'll have a look in the literature if I can find something on how to prune constraints like this.
That's great. That would help for at least some of these non-linear constraints.