Skip to content

Commit

Permalink
Add support for MOI.VariableName and MOI.ConstraintName (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Feb 25, 2024
1 parent 0d9e1d0 commit e6d4cb6
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
31 changes: 26 additions & 5 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ function _F_linear_operator(model::Optimizer)
M = SparseArrays.sparse(Int32[], Int32[], Float64[], n, n)
q = zeros(n)
has_term = fill(false, n)
names = String[]
for index in MOI.get(
model,
MOI.ListOfConstraintIndices{
Expand Down Expand Up @@ -232,8 +233,16 @@ function _F_linear_operator(model::Optimizer)
end
M[row_i, s_term.variable.value] += s_term.coefficient
end
c_name = MOI.get(model, MOI.ConstraintName(), index)
if Si.dimension == 2
push!(names, c_name)
else
for i in 1:div(Si.dimension, 2)
push!(names, "$(c_name)[$i]")
end
end
end
return M, q, SparseArrays.nnz(M)
return M, q, SparseArrays.nnz(M), names
end

_to_f(f) = convert(MOI.ScalarNonlinearFunction, f)
Expand All @@ -255,6 +264,7 @@ end
function _F_nonlinear_operator(model::Optimizer)
x = MOI.get(model, MOI.ListOfVariableIndices())
f_map = Vector{MOI.ScalarNonlinearFunction}(undef, length(x))
names = String[]
for (FType, SType) in MOI.get(model, MOI.ListOfConstraintTypesPresent())
if SType != MOI.Complements
continue
Expand All @@ -274,6 +284,14 @@ function _F_nonlinear_operator(model::Optimizer)
end
f_map[xi.value] = fi
end
c_name = MOI.get(model, MOI.ConstraintName(), ci)
if N == 1
push!(names, c_name)
else
for i in 1:N
push!(names, "$(c_name)[$i]")
end
end
end
end
for i in 1:length(x)
Expand Down Expand Up @@ -331,7 +349,7 @@ function _F_nonlinear_operator(model::Optimizer)
MOI.eval_constraint_jacobian(evaluator, view(data, inverse_perm), x)
return Cint(0)
end
return F, J, length(J_structure)
return F, J, length(J_structure), names
end

_finite(x, y) = isfinite(x) ? x : y
Expand All @@ -348,7 +366,8 @@ function _bounds_and_starting(model::Optimizer)
upper[i] = u
initial[i] = something(z, _finite(l, _finite(u, 0.0)))
end
return lower, upper, initial
names = MOI.get.(model, MOI.VariableName(), x)
return lower, upper, initial, names
end

# MOI.optimize!
Expand All @@ -368,13 +387,13 @@ function MOI.optimize!(model::Optimizer)
is_nlp =
(MOI.VectorNonlinearFunction, MOI.Complements) in con_types ||
(MOI.VectorQuadraticFunction{Float64}, MOI.Complements) in con_types
F, J, nnz = if is_nlp
F, J, nnz, c_names = if is_nlp
_F_nonlinear_operator(model)
else
_F_linear_operator(model)
end
model.ext[:solution] = nothing
lower, upper, initial = _bounds_and_starting(model)
lower, upper, initial, names = _bounds_and_starting(model)
status, x, info = solve_mcp(
F,
J,
Expand All @@ -385,6 +404,8 @@ function MOI.optimize!(model::Optimizer)
silent = model.ext[:silent],
jacobian_structure_constant = true,
jacobian_data_contiguous = true,
variable_names = names,
constraint_names = c_names,
[k => v for (k, v) in model.ext[:kwargs]]...,
)
if x === nothing
Expand Down
54 changes: 54 additions & 0 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,60 @@ function test_empty_model()
return
end

function test_solve_with_names()
model = PATHSolver.Optimizer()
MOI.set(model, MOI.RawOptimizerAttribute("output_linear_model"), "yes")
MOI.Utilities.loadfromstring!(
model,
"""
variables: v, w, x, y, z
c2: [0.0, -1.0 * y * y + -1.0 * z + 2, v, w] in Complements(4)
c3: VectorNonlinearFunction([ScalarNonlinearFunction(y^3 - 2z^2 + 2), ScalarNonlinearFunction(w^5 - x + 2y - 2z - 2), x, y]) in Complements(4)
c4: VectorNonlinearFunction([ScalarNonlinearFunction(w + 2x^3 - 2y + 4z - 6), z]) in Complements(2)
v in EqualTo(1.0)
w in Interval(0.0, 10.0)
x in GreaterThan(0.0)
z in Interval(1.0, 2.0)
""",
)
x = MOI.get(model, MOI.ListOfVariableIndices())
MOI.set.(model, MOI.VariablePrimalStart(), x, 1.0)
MOI.optimize!(model)
@test (
MOI.get.(model, MOI.VariablePrimal(), x),
[1.0, 1.2847523, 0.9729164, 0.9093761, 1.1730350];
atol = 1e-6,
)
return
end

function test_solve_with_names_nonlinear()
model = PATHSolver.Optimizer()
MOI.set(model, MOI.RawOptimizerAttribute("output_linear_model"), "yes")
MOI.Utilities.loadfromstring!(
model,
"""
variables: v, w, x, y, z
cnl2: VectorNonlinearFunction([0.0, -1.0 * y * y + -1.0 * z + 2, v, w]) in Complements(4)
c3: VectorNonlinearFunction([ScalarNonlinearFunction(y^3 - 2z^2 + 2), ScalarNonlinearFunction(w^5 - x + 2y - 2z - 2), x, y]) in Complements(4)
c4: VectorNonlinearFunction([ScalarNonlinearFunction(w + 2x^3 - 2y + 4z - 6), z]) in Complements(2)
v in EqualTo(1.0)
w in Interval(0.0, 10.0)
x in GreaterThan(0.0)
z in Interval(1.0, 2.0)
""",
)
x = MOI.get(model, MOI.ListOfVariableIndices())
MOI.set.(model, MOI.VariablePrimalStart(), x, 1.0)
MOI.optimize!(model)
@test (
MOI.get.(model, MOI.VariablePrimal(), x),
[1.0, 1.2847523, 0.9729164, 0.9093761, 1.1730350];
atol = 1e-6,
)
return
end

end

TestMOIWrapper.runtests()

0 comments on commit e6d4cb6

Please sign in to comment.