Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions src/FileFormats/MOF/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,48 @@ function Base.read!(io::IO, model::Model)
name_map = read_variables(model, object)
read_objective(model, object, name_map)
read_constraints(model, object, name_map)
_convert_to_nlpblock(model)
return
end

function _convert_to_nlpblock(model::Model)
has_constraints = false
nlp_model = MOI.Nonlinear.Model()
for S in (
MOI.LessThan{Float64},
MOI.GreaterThan{Float64},
MOI.EqualTo{Float64},
MOI.Interval{Float64},
)
for ci in MOI.get(model, MOI.ListOfConstraintIndices{Nonlinear,S}())
f = MOI.get(model, MOI.ConstraintFunction(), ci)
set = MOI.get(model, MOI.ConstraintSet(), ci)
MOI.Nonlinear.add_constraint(nlp_model, f.expr, set)
# We don't need this in `model` any more.
MOI.delete(model, ci)
has_constraints = true
end
end
if MOI.get(model, MOI.ObjectiveFunctionType()) == Nonlinear
obj = MOI.get(model, MOI.ObjectiveFunction{Nonlinear}())
MOI.Nonlinear.set_objective(nlp_model, obj.expr)
MOI.set(
model,
MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(),
MOI.ScalarAffineFunction{Float64}(
MOI.ScalarAffineTerm{Float64}[],
0.0,
),
)
end
if has_constraints
evaluator = MOI.Nonlinear.Evaluator(
nlp_model,
MOI.Nonlinear.SparseReverseMode(),
MOI.get(model, MOI.ListOfVariableIndices()),
)
MOI.set(model, MOI.NLPBlock(), MOI.NLPBlockData(evaluator))
end
return
end

Expand Down Expand Up @@ -357,27 +399,27 @@ end
# ========== Typed scalar sets ==========

function set_to_moi(::Val{:LessThan}, object::Object)
return MOI.LessThan(object["upper"])
return MOI.LessThan{Float64}(object["upper"])
end

function set_to_moi(::Val{:GreaterThan}, object::Object)
return MOI.GreaterThan(object["lower"])
return MOI.GreaterThan{Float64}(object["lower"])
end

function set_to_moi(::Val{:EqualTo}, object::Object)
return MOI.EqualTo(object["value"])
return MOI.EqualTo{Float64}(object["value"])
end

function set_to_moi(::Val{:Interval}, object::Object)
return MOI.Interval(object["lower"], object["upper"])
return MOI.Interval{Float64}(object["lower"], object["upper"])
end

function set_to_moi(::Val{:Semiinteger}, object::Object)
return MOI.Semiinteger(object["lower"], object["upper"])
return MOI.Semiinteger{Float64}(object["lower"], object["upper"])
end

function set_to_moi(::Val{:Semicontinuous}, object::Object)
return MOI.Semicontinuous(object["lower"], object["upper"])
return MOI.Semicontinuous{Float64}(object["lower"], object["upper"])
end

# ========== Non-typed vector sets ==========
Expand Down Expand Up @@ -469,19 +511,19 @@ end
# ========== Typed vector sets ==========

function set_to_moi(::Val{:PowerCone}, object::Object)
return MOI.PowerCone(object["exponent"]::Float64)
return MOI.PowerCone{Float64}(object["exponent"])
end

function set_to_moi(::Val{:DualPowerCone}, object::Object)
return MOI.DualPowerCone(object["exponent"]::Float64)
return MOI.DualPowerCone{Float64}(object["exponent"])
end

function set_to_moi(::Val{:SOS1}, object::Object)
return MOI.SOS1(Float64.(object["weights"]))
return MOI.SOS1(convert(Vector{Float64}, object["weights"]))
end

function set_to_moi(::Val{:SOS2}, object::Object)
return MOI.SOS2(Float64.(object["weights"]))
return MOI.SOS2(convert(Vector{Float64}, object["weights"]))
end

# :IndicatorSet is required for v0.6
Expand Down
37 changes: 28 additions & 9 deletions test/FileFormats/MOF/MOF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,28 @@ function test_HS071()
MOI.write_to_file(model, TEST_MOF_FILE)
@test replace(read(TEST_MOF_FILE, String), '\r' => "") ==
replace(read(joinpath(@__DIR__, "nlp.mof.json"), String), '\r' => "")
return _validate(TEST_MOF_FILE)
_validate(TEST_MOF_FILE)
return
end

function test_read_HS071()
model = MOF.Model()
MOI.read_from_file(model, joinpath(@__DIR__, "nlp.mof.json"))
@test MOI.get(model, MOI.ListOfConstraintTypesPresent()) ==
Tuple{Type,Type}[(MOI.VariableIndex, MOI.Interval{Float64})]
x = MOI.get(model, MOI.ListOfVariableIndices())
@test length(x) == 4
@test MOI.get(model, MOI.VariableName(), x) == ["var_$i" for i in 1:4]
block = MOI.get(model, MOI.NLPBlock())
evaluator = block.evaluator
MOI.initialize(evaluator, [:ExprGraph])
hs071_block = HS071(x)
hs071 = hs071_block.evaluator
@test MOI.objective_expr(evaluator) == MOI.objective_expr(hs071)
for i in 1:2
@test MOI.constraint_expr(evaluator, i) == MOI.constraint_expr(hs071, i)
end
return
end

function test_nonlinear_error_handling()
Expand Down Expand Up @@ -206,7 +227,6 @@ function test_Roundtrip_nonlinear_expressions()
end

function test_nonlinear_readingwriting()
# Write to file.
model = MOF.Model()
(x, y) = MOI.add_variables(model, 2)
MOI.set(model, MOI.VariableName(), x, "var_x")
Expand All @@ -221,13 +241,12 @@ function test_nonlinear_readingwriting()
# Read the model back in.
model2 = MOF.Model()
MOI.read_from_file(model2, TEST_MOF_FILE)
con2 = MOI.get(model2, MOI.ConstraintIndex, "con")
foo2 = MOI.get(model2, MOI.ConstraintFunction(), con2)
# Test that we recover the constraint.
@test foo2.expr == :(2 * $x + sin($x)^2 - $y)
@test MOI.get(model, MOI.ConstraintSet(), con) ==
MOI.get(model2, MOI.ConstraintSet(), con2)
return _validate(TEST_MOF_FILE)
block = MOI.get(model2, MOI.NLPBlock())
MOI.initialize(block.evaluator, [:ExprGraph])
@test MOI.constraint_expr(block.evaluator, 1) ==
:(2 * x[$x] + sin(x[$x])^2 - x[$y] == 1.0)
_validate(TEST_MOF_FILE)
return
end

function test_show()
Expand Down