Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/FileFormats/MOF/MOF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import JSONSchema
import MathOptInterface

const MOI = MathOptInterface
const SCHEMA_PATH = joinpath(@__DIR__, "v0.4.0.json")
const SCHEMA_PATH = joinpath(@__DIR__, "mof.0.5.schema.json")
const VERSION = let data = JSON.parsefile(SCHEMA_PATH, use_mmap=false)
VersionNumber(
data["properties"]["version"]["properties"]["major"]["const"],
Expand Down

Large diffs are not rendered by default.

45 changes: 23 additions & 22 deletions src/FileFormats/MOF/nonlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function moi_to_object(
node_list = OrderedObject[]
foo_object = convert_expr_to_mof(foo.expr, node_list, name_map)
return OrderedObject(
"head" => "ScalarNonlinearFunction",
"type" => "ScalarNonlinearFunction",
"root" => foo_object,
"node_list" => node_list,
)
Expand Down Expand Up @@ -111,34 +111,34 @@ Tree form:
MOF format:

{
"head": "nonlinear",
"root": {"head": "node", "index": 4},
"type": "nonlinear",
"root": {"type": "node", "index": 4},
"node_list": [
{
"head": "*", "args": [
{"head": "real", "value": 2},
{"head": "variable", "name": "x"}
"type": "*", "args": [
{"type": "real", "value": 2},
{"type": "variable", "name": "x"}
]
},
{
"head": "sin",
"type": "sin",
"args": [
{"head": "variable", "name", "x"}
{"type": "variable", "name", "x"}
]
}
{
"head": "^",
"type": "^",
"args": [
{"head": "node", "index": 2},
{"head": "real", "value": 2}
{"type": "node", "index": 2},
{"type": "real", "value": 2}
]
},
{
"head": "+",
"type": "+",
"args": [
{"head": "node", "index": 1},
{"head": "node", "index": 3},
{"head": "variable", "name": "y"}
{"type": "node", "index": 1},
{"type": "node", "index": 3},
{"type": "variable", "name": "y"}
]
}
]
Expand Down Expand Up @@ -172,7 +172,7 @@ end
SUPPORTED_FUNCTIONS

A vector of string-symbol pairs that map the MathOptFormat string representation
(i.e, the value of the `"head"` field) to the name of a Julia function (in
(i.e, the value of the `"type"` field) to the name of a Julia function (in
Symbol form).
"""
const SUPPORTED_FUNCTIONS = Pair{String, Tuple{Symbol, ARITY}}[
Expand Down Expand Up @@ -276,7 +276,8 @@ to their variable index.
function convert_mof_to_expr(
node::T, node_list::Vector{T}, name_map::Dict{String, MOI.VariableIndex}
) where {T <: Object}
head = node["head"]
# TODO(odow): remove when v0.4 no longer supported.
head = haskey(node, "type") ? node["type"] : node["head"]
if head == "real"
return node["value"]
elseif head == "complex"
Expand Down Expand Up @@ -324,12 +325,12 @@ function convert_expr_to_mof(
end
(mathoptformat_string, arity) = FUNCTION_TO_STRING[function_name]
validate_arguments(function_name, arity, length(expr.args) - 1)
node = T("head" => mathoptformat_string, "args" => T[])
node = T("type" => mathoptformat_string, "args" => T[])
for arg in @view(expr.args[2:end])
push!(node["args"], convert_expr_to_mof(arg, node_list, name_map))
end
push!(node_list, node)
return T("head" => "node", "index" => length(node_list))
return T("type" => "node", "index" => length(node_list))
end

# Recursion end for variables.
Expand All @@ -338,21 +339,21 @@ function convert_expr_to_mof(
::Vector{T},
name_map::Dict{MOI.VariableIndex, String},
) where {T <: Object}
return T("head" => "variable", "name" => name_map[variable])
return T("type" => "variable", "name" => name_map[variable])
end

# Recursion end for real constants.
function convert_expr_to_mof(
value::Real, ::Vector{T}, name_map::Dict{MOI.VariableIndex, String}
) where {T <: Object}
return T("head" => "real", "value" => value)
return T("type" => "real", "value" => value)
end

# Recursion end for complex numbers.
function convert_expr_to_mof(
value::Complex, ::Vector{T}, ::Dict{MOI.VariableIndex, String}
) where {T <: Object}
return T("head" => "complex", "real" => real(value), "imag" => imag(value))
return T("type" => "complex", "real" => real(value), "imag" => imag(value))
end

# Recursion fallback.
Expand Down
20 changes: 16 additions & 4 deletions src/FileFormats/MOF/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function Base.read!(io::IO, model::Model)
end
object = JSON.parse(io; dicttype = UnorderedObject)
file_version = _parse_mof_version(object["version"]::UnorderedObject)
if file_version > VERSION
if file_version.major != VERSION.major || file_version.minor > VERSION.minor
error(
"Sorry, the file can't be read because this library supports " *
"v$(VERSION) of MathOptFormat, but the file you are trying to " *
Expand Down Expand Up @@ -141,7 +141,12 @@ Convert `x` from an MOF representation into a MOI representation.
function function_to_moi(
x::Object, name_map::Dict{String, MOI.VariableIndex}
)
val = head_to_function(x["head"]::String)
val = if haskey(x, "type")
head_to_function(x["type"]::String)
else
# TODO(odow): remove when v0.4 no longer supported.
head_to_function(x["head"]::String)
end
return function_to_moi(val, x, name_map)
end

Expand Down Expand Up @@ -169,7 +174,7 @@ end
# ========== Typed scalar functions ==========

# Here, we deal with a special case: ScalarAffineTerm, ScalarQuadraticTerm,
# VectorAffineTerm, and VectorQuadraticTerm do not contain a "head" field
# VectorAffineTerm, and VectorQuadraticTerm do not contain a "type" field
# (because it is unnecessary at the JSON level).

function parse_scalar_affine_term(
Expand Down Expand Up @@ -312,7 +317,14 @@ end

Convert `x` from an OrderedDict representation into a MOI representation.
"""
set_to_moi(x::Object) = set_to_moi(head_to_set(x["head"]::String), x)
function set_to_moi(x::Object)
if haskey(x, "type")
return set_to_moi(head_to_set(x["type"]::String), x)
else
# TODO(odow): remove when v0.4 no longer supported.
return set_to_moi(head_to_set(x["head"]::String), x)
end
end

# ========== Non-typed scalar sets ==========

Expand Down
18 changes: 9 additions & 9 deletions src/FileFormats/MOF/write.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function moi_to_object(
foo::MOI.SingleVariable, name_map::Dict{MOI.VariableIndex, String}
)
return OrderedObject(
"head" => "SingleVariable",
"type" => "SingleVariable",
"variable" => name_map[foo.variable]
)
end
Expand All @@ -134,7 +134,7 @@ function moi_to_object(
name_map::Dict{MOI.VariableIndex, String},
)
return OrderedObject(
"head" => "ScalarAffineFunction",
"type" => "ScalarAffineFunction",
"terms" => moi_to_object.(foo.terms, Ref(name_map)),
"constant" => foo.constant,
)
Expand All @@ -156,7 +156,7 @@ function moi_to_object(
name_map::Dict{MOI.VariableIndex, String},
)
return OrderedObject(
"head" => "ScalarQuadraticFunction",
"type" => "ScalarQuadraticFunction",
"affine_terms" => moi_to_object.(foo.affine_terms, Ref(name_map)),
"quadratic_terms" => moi_to_object.(foo.quadratic_terms, Ref(name_map)),
"constant" => foo.constant,
Expand All @@ -169,7 +169,7 @@ function moi_to_object(
foo::MOI.VectorOfVariables, name_map::Dict{MOI.VariableIndex, String}
)
return OrderedObject(
"head" => "VectorOfVariables",
"type" => "VectorOfVariables",
"variables" => [name_map[variable] for variable in foo.variables],
)
end
Expand All @@ -189,7 +189,7 @@ function moi_to_object(
foo::MOI.VectorAffineFunction, name_map::Dict{MOI.VariableIndex, String}
)
return OrderedObject(
"head" => "VectorAffineFunction",
"type" => "VectorAffineFunction",
"terms" => moi_to_object.(foo.terms, Ref(name_map)),
"constants" => foo.constants,
)
Expand All @@ -208,7 +208,7 @@ function moi_to_object(
foo::MOI.VectorQuadraticFunction, name_map::Dict{MOI.VariableIndex, String}
)
return OrderedObject(
"head" => "VectorQuadraticFunction",
"type" => "VectorQuadraticFunction",
"affine_terms" => moi_to_object.(foo.affine_terms, Ref(name_map)),
"quadratic_terms" => moi_to_object.(foo.quadratic_terms, Ref(name_map)),
"constants" => foo.constants,
Expand All @@ -219,7 +219,7 @@ end
"""
head_name(::Type{SetType}) where SetType <: MOI.AbstractSet

Return the string that is stored in the `"head"` field of the MOF object for a
Return the string that is stored in the `"type"` field of the MOF object for a
set of type `SetType`.
"""
function head_name end
Expand All @@ -230,7 +230,7 @@ function head_name end
function moi_to_object(
set::SetType, ::Dict{MOI.VariableIndex, String}
) where {SetType}
object = OrderedObject("head" => head_name(SetType))
object = OrderedObject("type" => head_name(SetType))
for key in fieldnames(SetType)
object[string(key)] = getfield(set, key)
end
Expand Down Expand Up @@ -286,7 +286,7 @@ function moi_to_object(
) where {I, S}
@assert I == MOI.ACTIVATE_ON_ONE || I == MOI.ACTIVATE_ON_ZERO
return OrderedObject(
"head" => "IndicatorSet",
"type" => "IndicatorSet",
"set" => moi_to_object(set.set, name_map),
"activate_on" => (I == MOI.ACTIVATE_ON_ONE) ? "one" : "zero"
)
Expand Down
8 changes: 8 additions & 0 deletions test/FileFormats/MOF/MOF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ end
@test MOF.moi_to_object(c1, model, name_map)["name"] == "c_1"
@test MOF.moi_to_object(c2, model, name_map)["name"] == "c"
end
@testset "v0.4" begin
filename = joinpath(@__DIR__, "v0.4.mof.json")
model = MOF.Model(validate = true)
@test_throws ErrorException MOI.read_from_file(model, filename)
model = MOF.Model(validate = false)
MOI.read_from_file(model, filename)
@test MOI.get(model, MOI.NumberOfVariables()) == 2
end
end
@testset "round trips" begin
@testset "Empty model" begin
Expand Down
2 changes: 1 addition & 1 deletion test/FileFormats/MOF/empty_model.mof.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [],
"objective": {"sense": "feasibility"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{"name": ""}],
"objective": {
"sense": "min",
"function": {"head": "SingleVariable", "variable": ""}
"function": {"type": "SingleVariable", "variable": ""}
},
"constraints": []
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{}],
"objective": {
"sense": "min",
"function": {"head": "SingleVariable", "variable": "x"}
"function": {"type": "SingleVariable", "variable": "x"}
},
"constraints": []
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{"name": "x"}],
"objective": {
"sense": "min",
"function": {"head": "SingleVariable", "variable": "x"}
"function": {"type": "SingleVariable", "variable": "x"}
},
"constraints": [{
"function": {"head": "UnsupportedConstraintFunction"},
"set": {"head": "ZeroOne"}
"function": {"type": "UnsupportedConstraintFunction"},
"set": {"type": "ZeroOne"}
}]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{"name": "x"}],
"objective": {
"sense": "min",
"function": {"head": "SingleVariable", "variable": "x"}
"function": {"type": "SingleVariable", "variable": "x"}
},
"constraints": [{
"function": {"head": "SingleVariable", "variable": "x"},
"set": {"head": "UnsupportedConstraintSet"}
"function": {"type": "SingleVariable", "variable": "x"},
"set": {"type": "UnsupportedConstraintSet"}
}]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{"name": "x"}],
"objective": {
"sense": "min",
"function": {
"head": "UnsupportedObjectiveFunction"
"type": "UnsupportedObjectiveFunction"
}
},
"constraints": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "MathOptFormat Model",
"version": {
"major": 0,
"minor": 4
"minor": 5
},
"variables": [{"name": "x"}],
"objective": {
Expand Down
Loading