I am attempting to resolve a segfault error, which seems to be stemming from a line of code that tries to add to an empty dictionary new constraints iteratively in a while loop. I am wondering what the best way would be to add new constraints to an existing JuMP model, so that the updated model can be resolved at each iteration while considering both new constraints and old constraints previously used in a past solve.
My attempt consists of defining an empty dictionary, and then passing that dictionary into a function which solves a feasibility problem, which returns the updated dictionary of constraints for that feasibility problem. This updated dictionary should then be passed back into the function at another iteration, however, does not get past the first iteration and is returning the following error:
MethodError: no method matching setindex!(::Nothing, ::ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}, ScalarShape}, ::Int64)
There are two functions in question (a primary one and another where the error is located it looks like) which are constructed as follows:
function SLBLR(λ0, s0, γ, ν, ζ, q0, ϵ_gap, ϵ, max_iter, time_limit, qmax, A, b, c) # ζ = 1/1.5, ν = 2, s0 = 0.02, γ = 1/I
m = size(A,1)
n = size(A,2)
ck = Dict()
iter_counter = 1
i = 1
k = 1
j = 1
λk = λ0
sk = s0
qj = q0
x̃k = solve_relaxed_problem(A,b,c,λk,true)
timer = time()
while true
if k != 1
x̃k_new = solve_subproblem(A,b,c, λk, x̃k, i)
x̃k = x̃k_new
end
gx̃ = []
for i in 1:m
push!(gx̃, sum(A[i,j] * x̃k[i,j] for j in 1:n) - b[i])
end
Lx̃λ̃ = sum(sum( c[i,j] * x̃k[i,j] for j in 1:n) for i in 1:m) + sum(λk[i] * gx̃[i] for i in 1:m)
sk = ζ * γ * (qj - Lx̃λ̃) / norm(gx̃)^2
λk_new = λk + sk * gx̃
if qmax < sk * norm(gx̃)^2 / γ + Lx̃λ̃
qmax = sk * norm(gx̃)^2 / γ + Lx̃λ̃
end
# update indices
if i == m
i = 1
else
i += 1
end
k += 1
if constraint_satisfiability_problem(λk, λk_new, m, k, ck, ν, sk, gx̃) == "INFEASIBLE"
qj = qmax
qmax = -1e9
j += 1
ck = Dict() ## reset the constraint set for the feasibility problem
else
constraints_λ = constraint_satisfiability_problem(λk, λk_new, m, k, ck, ν, sk, gx̃)
ck = constraints_λ
end
λk = λk_new
qλk = solve_relaxed_problem(A,b,c,λk, false)
if (qj - qλk)/qj < ϵ
x̂ = feasibility_milp(A,b, x̃k, 3)
fx̂ = sum( sum(c[i,j]*x̂[i,j] for i in 1:m ) for j in 1:n)
if (fx̂ - qλk)/fx̂ <= ϵ_gap
println("feasible objective value: ", fx̂)
return args["elapsed_time"], iter_counter
break
end
end
args["elapsed_time"] = timer - time() ## update the timer
iter_counter += 1 ## update the iteration count
end
end
function constraint_satisfiability_problem(λk, λk_new, m, k, ck, ν, sk, gx̃)
model = Model(CPLEX.Optimizer)
@variable(model, λ[1:m] >= 0)
ck[k] = @constraint(model, 2*(λ - λk)' * gx̃ >= sk
optimize!(model)
ck_new = ck
if termination_status(model) == "INFEASIBLE"
return termination_status(model)
elseif termination_status(model) == "OPTIMAL"
λ_out = value.(λ)
return λ_out, ck_new
end
end
The line that is returning the error is this one:
ck[k] = @constraint(model, 2*(λ - λk)' * gx̃ >= sk * norm(gx̃)^2)
and the debugger is showing that the dictionary in question, ck, has value nothing, which I am thinking may be related to the error mentioned previously.
There are several other “helper” functions which I can include as well, if they are helpful. Though, I am mainly wondering if there is an efficient way to add constraints to the subproblem outlined in constraint_satisfiability_problem
at each new iteration and subsequently resolve the segfault error.