JuliaConstraints / CPLEXCP.jl

Julia interface for CPLEX CP Optimizer
MIT License
3 stars 1 forks source link

Equality constraint for interval variables #12

Open matheusdiogenesandrade opened 1 year ago

matheusdiogenesandrade commented 1 year ago

Hello.

While working on the issue #11, I found other "bug". Conside the below code.

using CPLEXCP
using MathOptInterface

const MOI = MathOptInterface

model = CPLEXCP.Optimizer()

x = first(MOI.add_constrained_variable(model, MOI.Interval{Int32}(0, 10)))

MOI.add_constraint(model, x, MOI.EqualTo(10))

MOI.optimize!(model)

@show MOI.get(model, MOI.VariablePrimal(), x)

Which returns the below message.

ERROR: LoadError: 
MathOptInterface.LowerBoundAlreadySet{MathOptInterface.EqualTo{Float64}, MathOptInterface.EqualTo{Int64}(10)}: 
Cannot add `VariableIndex`-in-`MathOptInterface.EqualTo{Int64}(10)` constraint for variable 
MathOptInterface.VariableIndex(1) as a `VariableIndex`-in-`MathOptInterface.EqualTo{Float64}` constraint was already set for
this variable and both constraints set a lower bound.
Stacktrace:
 [1] _assert_no_lb
   @ ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints_singlevar.jl:38 [inlined]
 [2] add_constraint(model::CPLEXCP.Optimizer, f::MathOptInterface.VariableIndex, s::MathOptInterface.EqualTo{Int64})
   @ CPLEXCP ~/.julia/packages/CPLEXCP/jbgSe/src/MOI/wrapper_constraints_singlevar.jl:190
 [3] top-level scope
   @ ~/test/test.jl:10
 [4] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [5] top-level scope
   @ REPL[1]:1
in expression starting at ~/test/test.jl:10

I tried to comment the lines _assert_no_lb(model, f, s) and _assert_no_ub(model, f, s) of the function add_constraint, and no bug appeared.

function MOI.add_constraint(
    model::Optimizer,
    f::MOI.VariableIndex,
    s::MOI.EqualTo{T},
) where {T <: Real}
    @assert _info(model, f).type == _type_to_variabletype(T)
    _assert_no_lb(model, f, s)
    _assert_no_ub(model, f, s)
    _set_lb(model, f, s.value)
    _set_ub(model, f, s.value)
    return MOI.ConstraintIndex{MOI.VariableIndex, typeof(s)}(f.value)
end

I understand the meaning of line @assert _info(model, f).type == _type_to_variabletype(T), but I do not see the reason for the asserts on the bounds. Is there any special concern on this?

Thanks and regards.

dourouc05 commented 1 year ago

The problem when you remove these checks is when you remove constraints to update the bounds. It's the same reason why CPLEX.jl forbids having several bounds per variable (see the calls to _throw_if_existing_lower in https://github.com/jump-dev/CPLEX.jl/blob/master/src/MOI/MOI_wrapper.jl, for instance).

Do you have the same problem when going through JuMP instead of attacking directly CPLEXCP.jl?

matheusdiogenesandrade commented 11 months ago

Sorry for the late response. Yes, I did, at least I think so:

using JuMP

using CPLEX

model = direct_model(CPLEX.Optimizer())

@variable(model, x, lower_bound = 0, upper_bound = 15, integer = true)
@variable(model, 0 <= y <= 3)

@objective(model, Min, 12x + 20y)

@constraint(model, c1, 6x + 8y >= 100)
@constraint(model, c2, 7x + 12y >= 120)
@constraint(model, c3, x >= 15)

print(model)

optimize!(model)

@show termination_status(model)
@show primal_status(model)
@show objective_value(model)
@show value(x)
@show value(y)

Let me know if this is the setup you are looking for?

dourouc05 commented 11 months ago

I had in mind the most usual way to use JuMP, i.e. model = Model(CPLEXCP.Optimizer), so that it can play its magic of rewriting constraints (and not giving all the constraints to the solver as soon as they are added with @constraint, if my memory is right).

matheusdiogenesandrade commented 11 months ago

model = Model(CPLEXCP.Optimizer)

Sorry, I think I got the wrong understanding, are we talking about running CPLEXCP or CPLEX via JuMP ?