Skip to content
This repository has been archived by the owner on Apr 21, 2022. It is now read-only.

Commit

Permalink
[MOF] Begin formal JSON schema (#47)
Browse files Browse the repository at this point in the history
* [MOF] Begin formal JSON schema

* More updates to the schema

* Finish Base MOI schema

* A few minor fixes

* Add nonlinear schema

* Update schema

* Add JSONSchema to validate models

* Remove Manifest file

* Add manifest to .gitignore

* Add minimum values to some integer fields

* Split functions into scalar and vector types

* Re-order top-level properties of schema

* Update field names after #49

* Add top-level `name` field and minor comment fixes

* Tidy schema

* Add (validated) example files

* Add more examples

* Fix coefficients

* Add descriptions to schema

* Add VariablePrimalStart attribute
  • Loading branch information
odow authored Mar 16, 2019
1 parent 670c90e commit 21824c6
Show file tree
Hide file tree
Showing 11 changed files with 803 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.jl.cov
*.jl.*.cov
*.jl.mem
Manifest.toml
15 changes: 15 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name = "MathOptFormat"
uuid = "f4570300-c277-12e8-125c-4912f86ce65d"
authors = ["Oscar Dowson <[email protected]"]
version = "0.0.0"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
GZip = "92fee26a-97fe-5a0c-ad85-20a5f3185b63"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
julia = "1.0"
23 changes: 23 additions & 0 deletions src/MOF/MOF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ using DataStructures, JSON

import ..MathOptFormat

import ..MathOptFormat
import JSONSchema
const SCHEMA_PATH = joinpath(@__DIR__, "schema", "mof.schema.json")

# we use an ordered dict to make the JSON printing nicer
const Object = OrderedDict{String, Any}

Expand Down Expand Up @@ -52,6 +56,25 @@ function Base.show(io::IO, ::Model)
return
end

"""
validate(filename::String)
Validate that the MOF file `filename` conforms to the MOF JSON schema. Returns
`nothing` if the file is valid, otherwise throws an error describing why the
file is not valid.
"""
function validate(filename::String)
MathOptFormat.gzip_open(filename, "r") do io
object = JSON.parse(io)
mof_schema = JSONSchema.Schema(JSON.parsefile(SCHEMA_PATH))
if !JSONSchema.isvalid(object, mof_schema)
error("Unable to read file because it does not conform to the MOF " *
"schema: ", JSONSchema.diagnose(object, mof_schema))
end
end
return
end

include("nonlinear.jl")

include("read.jl")
Expand Down
32 changes: 32 additions & 0 deletions src/MOF/schema/examples/biobjective.mof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"description": "The problem: [min{2x - y + 1}, max{y}]",
"version": 0,
"variables": [{
"name": "x"
}, {
"name": "y"
}],
"objectives": [{
"sense": "min",
"function": {
"head": "ScalarAffineFunction",
"terms": [{
"coefficient": 2,
"variable": "x"
},
{
"coefficient": -1,
"variable": "y"
}
],
"constant": 1
}
}, {
"sense": "max",
"function": {
"head": "SingleVariable",
"variable": "y"
}
}],
"constraints": []
}
58 changes: 58 additions & 0 deletions src/MOF/schema/examples/milp.mof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"description": "The problem: min{x | x + y >= 1, x ∈ [0, 1], y ∈ {0, 1}}",
"version": 0,
"variables": [{
"name": "x",
"primal_start": 0.0
}, {
"name": "y",
"primal_start": 1.0
}],
"objectives": [{
"sense": "min",
"function": {
"head": "SingleVariable",
"variable": "x"
}
}],
"constraints": [{
"name": "x + y >= 1",
"function": {
"head": "ScalarAffineFunction",
"terms": [{
"coefficient": 1,
"variable": "x"
},
{
"coefficient": 1,
"variable": "y"
}
],
"constant": 0
},
"set": {
"head": "GreaterThan",
"lower": 1
}
}, {
"name": "x ∈ [0, 1]",
"function": {
"head": "SingleVariable",
"variable": "x"
},
"set": {
"head": "Interval",
"lower": 0,
"upper": 1
}
}, {
"name": "y ∈ {0, 1}",
"function": {
"head": "SingleVariable",
"variable": "y"
},
"set": {
"head": "ZeroOne"
}
}]
}
57 changes: 57 additions & 0 deletions src/MOF/schema/examples/nlp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"description": "The problem: min{2x + sin(x)^2 + y}.",
"version": 0,
"variables": [{
"name": "x"
}, {
"name": "y"
}],
"objectives": [{
"sense": "min",
"function": {
"head": "Nonlinear",
"root": {
"head": "node",
"index": 4
},
"node_list": [{
"head": "*",
"args": [{
"head": "real",
"value": 2
}, {
"head": "variable",
"name": "x"
}]
}, {
"head": "sin",
"args": [{
"head": "variable",
"name": "x"
}]
}, {
"head": "^",
"args": [{
"head": "node",
"index": 2
}, {
"head": "real",
"value": 2
}]
}, {
"head": "+",
"args": [{
"head": "node",
"index": 1
}, {
"head": "node",
"index": 3
}, {
"head": "variable",
"name": "y"
}]
}]
}
}],
"constraints": []
}
35 changes: 35 additions & 0 deletions src/MOF/schema/examples/quadratic.mof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"description": "The problem: min{x^2 + x * y + y^2}",
"version": 0,
"variables": [{
"name": "x"
}, {
"name": "y"
}],
"objectives": [{
"sense": "min",
"function": {
"description": "Note that the format is `a'x + 0.5 x' Q x + c`.",
"head": "ScalarQuadraticFunction",
"affine_terms": [],
"quadratic_terms": [{
"coefficient": 2,
"variable_1": "x",
"variable_2": "x"
},
{
"coefficient": 1,
"variable_1": "x",
"variable_2": "y"
},
{
"coefficient": 2,
"variable_1": "y",
"variable_2": "y"
}
],
"constant": 0
}
}],
"constraints": []
}
45 changes: 45 additions & 0 deletions src/MOF/schema/examples/vector.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"description": "The problem: min{0 | [1 2; 3 4][x, y] + [5, 6] ∈ R+.",
"version": 0,
"variables": [{
"name": "x"
}, {
"name": "y"
}],
"objectives": [],
"constraints": [{
"function": {
"head": "VectorAffineFunction",
"terms": [{
"output_index": 1,
"scalar_term": {
"coefficient": 1,
"variable": "x"
}
}, {
"output_index": 1,
"scalar_term": {
"coefficient": 2,
"variable": "y"
}
}, {
"output_index": 2,
"scalar_term": {
"coefficient": 3,
"variable": "x"
}
}, {
"output_index": 2,
"scalar_term": {
"coefficient": 4,
"variable": "y"
}
}],
"constants": [5, 6]
},
"set": {
"head": "Nonnegatives",
"dimension": 2
}
}]
}
Loading

0 comments on commit 21824c6

Please sign in to comment.