Created
June 14, 2021 19:47
-
-
Save matbesancon/667a1089f5114e29bc804fe8614a96eb to your computer and use it in GitHub Desktop.
Bilevel AUX Reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Takes the model loaded from the MPS file and the line of the `.aux` file. | |
""" | |
function build_from_mibp(m::JuMP.Model, aux_file::Vector{String}; complete=false) | |
l1 = split(aux_file[1]) | |
@assert length(l1) == 2 | |
nl = parse(Int, l1[2]) | |
nu = num_variables(m) - nl | |
l2 = split(aux_file[2]) | |
@assert length(l2) == 2 | |
ml = parse(Int, l2[2]) | |
mu = num_constraints(m, AffExpr, MOI.GreaterThan{Float64}) - ml | |
curr_line_idx = 3 | |
lower_var = Int[] | |
while true | |
curr_line = split(aux_file[curr_line_idx]) | |
if curr_line[1] != "LC" | |
break | |
end | |
vname = "C" * pad_string(parse(Int, curr_line[2])) | |
vidx = variable_by_name(m, vname).index.value | |
push!(lower_var, vidx) | |
curr_line_idx += 1 | |
end | |
@info "Finished LC phase: $curr_line_idx $curr_line" | |
upper_var = filter(1:nl+nu) do v | |
v ∉ lower_var | |
end | |
@assert length(upper_var) == nu | |
@assert length(lower_var) == nl | |
lower_cons = BitSet() | |
b = Float64[] | |
A = spzeros(ml, nu) | |
B = spzeros(ml, nl) | |
curr_row = 1 | |
while true | |
curr_line = split(aux_file[curr_line_idx]) | |
if curr_line[1] != "LR" | |
break | |
end | |
cname = "R" * pad_string(parse(Int, curr_line[2])) | |
cons = constraint_by_name(m, cname, AffExpr, MOI.GreaterThan{Float64}) | |
cons.index isa MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64},MOI.GreaterThan{Float64}} || error("unexpected type $cidx.index") | |
cfunc = MOI.get(m, MOI.ConstraintFunction(), cons) | |
cset = MOI.get(m, MOI.ConstraintSet(), cons) | |
@assert cfunc.constant ≈ 0 | |
push!(lower_cons, cons.index.value) | |
push!(b, -cset.lower) | |
for term in cfunc.terms | |
vidx = findfirst(lower_var) do idx | |
idx == term.variable_index.value | |
end | |
if vidx !== nothing # found in lower variable | |
B[curr_row, vidx] = -term.coefficient | |
else # find in upper variable | |
vidx = findfirst(upper_var) do idx | |
idx == term.variable_index.value | |
end | |
vidx === nothing && error("index not found for term $term") | |
A[curr_row, vidx] = -term.coefficient | |
end | |
end | |
curr_line_idx += 1 | |
curr_row += 1 | |
end | |
@assert length(lower_cons) == ml | |
@info "Finished LR phase: $curr_line_idx" | |
# build upper-level constraints | |
q = Float64[] | |
G = spzeros(mu, nu) | |
H = spzeros(mu, nl) | |
curr_row = 1 | |
for cons in all_constraints(m, AffExpr, MOI.GreaterThan{Float64}) | |
if cons.index.value ∉ lower_cons | |
@info "upper found" | |
cfunc = MOI.get(m, MOI.ConstraintFunction(), cons) | |
cset = MOI.get(m, MOI.ConstraintSet(), cons) | |
push!(q, -cset.lower) | |
for term in cfunc.terms | |
vidx = findfirst(lower_var) do idx | |
idx == term.variable_index.value | |
end | |
if vidx !== nothing # found in lower variable | |
H[curr_row, vidx] = -term.coefficient | |
else # find in upper variable | |
vidx = findfirst(upper_var) do idx | |
idx == term.variable_index.value | |
end | |
vidx === nothing && error("index not found for term $term") | |
G[curr_row, vidx] = -term.coefficient | |
end | |
end | |
curr_row += 1 | |
end | |
end | |
# fetching objective | |
nobj = 0 | |
d = Float64[] | |
while true | |
curr_line = split(aux_file[curr_line_idx]) | |
if curr_line[1] != "LO" | |
break | |
end | |
push!(d, | |
parse(Float64, curr_line[2]) | |
) | |
curr_line_idx += 1 | |
nobj += 1 | |
end | |
@info "Finished LO phase: $curr_line_idx" | |
curr_line = split(aux_file[curr_line_idx]) | |
@assert nobj == nl | |
curr_line[1] == "OS" || error("$curr_line_idx: $curr_line") | |
if curr_line[2] == "-1" | |
d .*= -1 | |
end | |
# upper-level objective | |
cx = Float64[] | |
for vidx in upper_var | |
for (varref, coeff) in objective_function(m).terms | |
if varref.index.value == vidx | |
push!(cx, coeff) | |
end | |
end | |
end | |
cy = Float64[] | |
for vidx in lower_var | |
for (varref, coeff) in objective_function(m).terms | |
if varref.index.value == vidx | |
push!(cy, coeff) | |
end | |
end | |
end | |
if objective_sense(m) == MOI.MAX_SENSE | |
cx .*= -1 | |
cy .*= -1 | |
end | |
if mu > 0 | |
return [(G, H, A, B, cx, cy, d, q, b)] | |
end | |
# else, split constraints | |
dv = ml ÷ 3 | |
Ga = A[1:dv,:] | |
Aa = A[dv+1:end,:] | |
Ha = B[1:dv,:] | |
Ba = B[dv+1:end,:] | |
qa = b[1:dv] | |
ba = b[dv+1:end] | |
Gb = A[end-dv+1:end,:] | |
Ab = A[1:end-dv,:] | |
Hb = B[end-dv+1:end,:] | |
Bb = B[1:end-dv,:] | |
qb = b[end-dv+1:end] | |
bb = b[1:end-dv] | |
if !complete | |
return [(Ga, Ha, Aa, Ba, cx, cy, d, qa, ba), (Gb, Hb, Ab, Bb, cx, cy, d, qb, bb)] | |
end | |
Gc = Aa | |
Ac = Ga | |
Hc = Ba | |
Bc = Ha | |
qc = ba | |
bc = qa | |
Gd = Ab | |
Ad = Gb | |
Hd = Bb | |
Bd = Hb | |
qd = bb | |
bd = qb | |
return [(Ga, Ha, Aa, Ba, cx, cy, d, qa, ba), (Gb, Hb, Ab, Bb, cx, cy, d, qb, bb), (Gc, Hc, Ac, Bc, cx, cy, d, qc, bc), (Gd, Hd, Ad, Bd, cx, cy, d, qd, bd)] | |
end | |
# example | |
const data_path = joinpath(@__DIR__, "../data/notInterdiction/MIPS/RAND_BILEVEL") | |
const all_files = Filesystem.readdir(data_path) | |
for file in all_files | |
global results | |
global result_times | |
if !endswith(file, "mps") | |
continue | |
end | |
file_base = split(file, '.')[1] | |
m = JuMP.read_from_file(joinpath(data_path, file)) | |
list_cons_types = [ | |
(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}), | |
(MOI.SingleVariable, MOI.Interval{Float64}), | |
(MOI.SingleVariable, MOI.Integer), | |
] | |
all(zip(list_cons_types, MOI.get(m, MOI.ListOfConstraints()))) do (c1, c2) | |
c1 == c2 | |
end || error("hello") | |
aux_file = open(joinpath(data_path, file_base * ".aux")) do f | |
readlines(f) | |
end | |
prob_instance = build_from_mibp(m, aux_file, complete=true) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment