I am attempting to incorporate perspective cuts into a non-linear model for linearization using the JuMP package. My aim is to utilize the SCIP solver and introduce a cut every 5 seconds, utilizing a feasible point to add a cut. However, I have discovered that I am unable to employ the callback functions. Is there an alternative approach to achieve this?

I have discovered that I am unable to employ the callback functions

Correct. SCIP does not support adding lazy constraints via JuMP.

Is there an alternative approach to achieve this?

Use an iterative process

``````julia> using JuMP, Ipopt

julia> model = Model(Ipopt.Optimizer)
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Ipopt

julia> set_silent(model)

julia> @variable(model, 1 <= x <= 10)
x

julia> @variable(model, t >= 0)
t

julia> @objective(model, Min, t)
t

julia> # @NLconstraint(model, t >= exp(x))
while true
optimize!(model)
v_t, v_x = value(t), value(x)
if v_t >= exp(v_x) - 1e-6
break
end
@constraint(model, t >= exp(v_x) + exp(v_x)  * (x - v_x))
end

julia> value(t), value(x)
(2.718281796283739, 0.9999999909231221)

julia> print(model)
Min t
Subject to
-4.553023229112991 x + t ≥ -2.3484104909053922
-2.718281802771446 x + t ≥ 2.5687599158885632e-8
x ≥ 1.0
t ≥ 0.0
x ≤ 10.0
``````
2 Likes

For example I want to solve this very simple problem:

``````using JuMP, GAMS

# Define the model
model = Model(GAMS.Optimizer)
I = [1, 2]
J = [1, 2, 3]
a = [2 3 4; 3 2 1]
b = [10 12 20]
c = 35
l = [2, 1]
u = [4, 5]
x_1 = [3 1]

@variable(model, x[i in I] >= 0)
@variable(model, y[i in I], binary = true)

@objective(model, Min, sum(x[i] for i in I))
@constraint(model, [j in J], b[j] <= sum(a[i,j] * x[i] for i in I))
@constraint(model, [i in I], l[i] * y[i] <= x[i])
@constraint(model, [i in I], x[i] <= u[i] * y[i])

# Solve the model to get the initial objective value
best_primal_bound = Inf
cut_counter = 0

while true
# Solve the model
set_optimizer_attribute(model, GAMS.MIP(), "SCIP")
set_optimizer_attribute(model, GAMS.ResLim(), 0.003)
optimize!(model)
best_primal_bound = objective_value(model)

# Update the best dual bound
best_dual_bound = dual_objective_value(model)

# Calculate the optimality gap
optimality_gap =  (best_primal_bound - best_dual_bound) / best_primal_bound

# Check the termination condition
if optimality_gap <= 0.01
break
end

# Extract the solution
x_bar = value.(x)

# Generate new linear cuts based on the solution

# Add the new linear cuts to the model
@constraint(model,  2 * sum(x_bar[i] * x[i] for i in I) - (sum(x_bar[i]^2 for i in I) + 35) * y <= 0)
@constraint(model,  2 * sum(x_bar[i] * x[i] for i in I) - (sum(x_bar[i]^2 for i in I) + 35) * y <= 0)

# Increment the cut counter
cut_counter += 1
println("x_bar:", value.(x_bar))
end
``````

but the following error appeared:

``````ERROR: LoadError: MethodError: no method matching
constant(::MathOptInterface.ZeroOne)
caused by: MathOptInterface.GetAttributeNotAllowed{MathOptInterface.DualObjectiveValue}: Getting attribute MathOptInterface.DualObjectiveValue(1) cannot be performed: GAMS.Optimizer does not support getting the attribute MathOptInterface.DualObjectiveValue(1). You may want to use a `CachingOptimizer` in `AUTOMATIC` mode or you may need to call `reset_optimizer` before doing this operation if the `CachingOptimizer` is in `MANUAL` mode.
``````

You’re asking for `dual_objective_value`, but the problem has binary variables so it doesn’t have a dual objective.

What is the gap that you’re trying to compute?

1 Like

like the option that we have in GAMS Optcr, or primal bound - dual bound / primal bound. My aim is to adding cuts during the solving process until we reach to 1 percent optimality gap. And find out how many cuts we need.

Try `objective_bound(model)`.

But note that you’re not adding cuts during one solve. You’re repeatedly resolving the model with new constraints

How can I add cuts during the solving process? I need to use new feasible point that finds during the solving process and add the related cut and so on until the model reaches to 1 percent optimality gap.

You must use a solver-specific callback or a `MOI.LazyConstraintCallback`: Solver-independent Callbacks · JuMP

But only a few packages support such callbacks: Solver-independent Callbacks · JuMP

GAMS.jl and SCIP.jl do not support LazyConstraintCallback.

You could try Gurobi.jl instead: jump-dev/Gurobi.jl · JuMP

1 Like