Modeling constraints with CPLEXCP.jl

Hello everyone.

I am trying to model some constraints through constraint programming, by using CPLEXCP.jl. But I am having some issues with regards to translating the constraints into functions available by the library. So, the constraint I am trying to model is this:

if x = 10 then p + 5 = q

However, I am struggling to find a way to express this by using the functions given by library. One straightforward solution, would be to create a variable r.

r = q - p
if x = 10 then r = 5

The above logic could be implemented as below:

# r - (q - p) = r - q + p
r_eq = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, -1, 1], [r, q, p]), 0)
# r - q + p = 0
MOI.add_constraint(model, r_eq, MOI.EqualsTo(0))

# if x = 10 then r = 5 
MOI.add_constraint(model, 
    MOI.VectorOfVariables([x, r]), 
    CP.Implication(MOI.EqualTo(10), MOI.EqualTo(5))
# github.com/JuliaConstraints/ConstraintProgrammingExtensions.jl/blob/master/src/Test/test_implication.jl#L16
)

However, by doing so, for each p and q we want to impose such constraint, we would have to create another variable r. I would like to know other ways of doing this without imposing a new variable to the model.

Case there is any confusing point, please, let me know. Thanks and regards.

I don’t have CPLEXCP so I can’t test, but perhaps:

# x == 10 => p - q == -5
MOI.add_constraint(
    model,
    MOI.Utilities.operate(vcat, Int, x, 1 * p + -1 * q),
    CP.Implication(MOI.EqualTo(10), MOI.EqualTo(-5)),
)

Thank you very much.

Actually, it seems to be a little bit more complex, although I do not have the answer, at least not yet. I created an environment for running the above code here. Basically, in order to make the command MOI.Utilities.operate(vcat, Int, x, 1 * p + -1 * q), to work, we have to take so concerns:

affine::MOI.ScalarAffineFunction{Float64} = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([1, -1], [p, q]), 0.0)

MOI.add_constraint(
                   model,
                   MOI.Utilities.operate(vcat, MOI.ScalarAffineFunction{Float64}, MOI.SingleVariable(x), affine), 
                   CP.Implication(MOI.EqualTo(10), MOI.EqualTo(-5)),
                  )

However tha avobe code still presents errors:

ERROR: LoadError: MethodError: no method matching _build_constraint(::CPLEXCP.Optimizer, ::MathOptInterface.VectorAffineFunction{MathOptInterface.ScalarAffineFunction{Float64}}, ::ConstraintProgrammingExtensions.Implication{MathOptInterface.EqualTo{Int64}, MathOptInterface.EqualTo{Int64}})
Closest candidates are:
  _build_constraint(::CPLEXCP.Optimizer, ::Union{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.VectorOfVariables}, ::ConstraintProgrammingExtensions.AllDifferent) where T at ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints_cp.jl:14
  _build_constraint(::CPLEXCP.Optimizer, ::Union{MathOptInterface.VectorAffineFunction{T}, MathOptInterface.VectorOfVariables}, ::ConstraintProgrammingExtensions.Implication{S1, S2}) where {T<:Int64, S1<:MathOptInterface.AbstractSet, S2<:MathOptInterface.AbstractSet} at ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints_cp_reification.jl:234
  _build_constraint(::CPLEXCP.Optimizer, ::Union{MathOptInterface.VariableIndex, MathOptInterface.ScalarAffineFunction{T}}, ::ConstraintProgrammingExtensions.AntiDomain{T}) where T<:Int64 at ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints_cp.jl:60
  ...
Stacktrace:
 [1] add_constraint(model::CPLEXCP.Optimizer, f::MathOptInterface.VectorAffineFunction{MathOptInterface.ScalarAffineFunction{Float64}}, s::ConstraintProgrammingExtensions.Implication{MathOptInterface.EqualTo{Int64}, MathOptInterface.EqualTo{Int64}})
   @ CPLEXCP ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints.jl:29
 [2] top-level scope
   @ test_conditional.jl:30
 [3] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [4] top-level scope
   @ REPL[1]:1
in expression starting at test_conditional.jl:30

The README of the project gives the step-by-step for setting up CPLEXCP locally.

Thanks for the support. Regards.

Your use of operate is incorrect. It should be something like:

affine = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], [p, q]), 0.0)
MOI.add_constraint(
    model,
    MOI.Utilities.operate(vcat, Float64, MOI.SingleVariable(x), affine), 
    CP.Implication(MOI.EqualTo(10.0), MOI.EqualTo(-5.0)),
)

I don’t have a license.