Skip to content

Commit 242cae9

Browse files
committed
Add schema and examples
1 parent e44dc67 commit 242cae9

File tree

7 files changed

+899
-1
lines changed

7 files changed

+899
-1
lines changed

README.md

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,146 @@
11
# MathOptFormat
2-
Specification and description of the MathOptFormat file format
2+
3+
This repository describes a file-format for mathematical optimization problems
4+
called _MathOptFormat_ with the file extension `.mof.json`.
5+
6+
It is heavily inspired by [MathOptInterface](https://github.com/JuliaOpt/MathOptInterface.jl).
7+
8+
## Standard form
9+
10+
MathOptFormat is a generic file format for mathematical optimization problems
11+
encoded in the form
12+
13+
min/max: fᵢ(x) i=1,2,…,I
14+
subject to: gⱼ(x) ∈ Sⱼ j=1,2,…,J
15+
16+
where `x ∈ ℝᴺ`, `fᵢ: ℝᴺ → ℝ`, and `gⱼ: ℝᴺ → ℝᴹʲ`, and `Sⱼ ⊆ ℝᴹʲ`.
17+
18+
The functions `fᵢ` and `gⱼ`, and sets `Sⱼ` supported by MathOptFormat are
19+
detailed below. This list is not exhaustive. It is intended that MathOptFormat
20+
will be extended in future versions to support additional functions and sets.
21+
22+
## An example
23+
24+
The standard form described above is very general. To give a concrete example,
25+
consider the following linear program:
26+
27+
min: 2x + 1
28+
subject to: x ≥ 1
29+
30+
Encoded in our standard form, we have
31+
32+
f₁(x) = 2x + 1
33+
g₁(x) = x
34+
S₁ = [1, ∞)
35+
36+
Encoded into the MathOptFormat file format, this example becomes:
37+
```json
38+
{
39+
"version": 1,
40+
"variables": [{"name": "x"}],
41+
"objectives": [{
42+
"sense": "min",
43+
"function": {
44+
"head": "ScalarAffineFunction",
45+
"terms": [
46+
{"coefficient": 2, "variable": "x"}
47+
],
48+
"constant": 1
49+
}
50+
}],
51+
"constraints": [{
52+
"name": "x >= 1",
53+
"function": {"head": "SingleVariable", "variable": "x"},
54+
"set": {"head": "GreaterThan", "lower": 1}
55+
}]
56+
}
57+
```
58+
59+
Let us now describe each part of the file format in turn. First, notice that the
60+
file format is a valid JSON (JavaScript Object Notation) file. This enables the
61+
MathOptFormat to be both _human-readable_, and _machine-readable_. Some readers
62+
may argue that JSON is tricky to edit as a human due to the quantity of brackets
63+
and "boiler-plate" such as `"function"` and `"head"`. We do not disagree.
64+
However, we believe that JSON strikes a fine balance between human and machine
65+
readability.
66+
67+
Inside the document, the model is stored as a single JSON object. JSON objects
68+
are key-value mappings enclosed by curly braces (`{` and `}`). There are four
69+
required keys at the top level:
70+
71+
- `"version"`
72+
73+
An integer describing the minimum version of MathOptFormat needed to parse
74+
the file. This is included to safeguard against later revisions.
75+
76+
- `"variables"`
77+
78+
A list of JSON objects, with one object for each variable in the model. Each
79+
object has a required key `"name"` which maps to a unique string for that
80+
variable. It is illegal to have two variables with the same name. These names
81+
will be used later in the file to refer to each variable.
82+
83+
- `"objectives"`
84+
85+
A list of JSON objects, with one element for each objective in the model.
86+
Each object has two required keys:
87+
88+
- `"sense"`
89+
90+
A string which must be `"min"` or `"max"`.
91+
92+
- `"function"`
93+
94+
A JSON object that describes the function. There are many different types
95+
of functions that MathOptFormat recognizes, each of which has a different
96+
structure. However, each function has a required key called `"head"` which
97+
is used to describe the type of the function. In this case, the function
98+
is `"ScalarAffineFunction"`.
99+
100+
A `"ScalarAffineFunction"` is the function `f(x) = aᵀx + b`, where `a` is
101+
a constant `N×1` vector, and `b` is a scalar constant. In addition to
102+
`"head"`, it has two required keys:
103+
104+
- `"terms"`
105+
106+
A list of JSON objects, containing one object for each non-zero element
107+
in `a`. Each object has two required keys: `"coefficient"`, and
108+
`"variable"`. `"coefficient"` maps to a real number that is the
109+
coefficient in `a` corresponding to the variable (identified by its
110+
string name) in `"variable"`.
111+
112+
- `"constant"`
113+
114+
The value of `b`.
115+
116+
- `"constraints"`
117+
118+
A list of JSON objects, with one element for each constraint in the model.
119+
Each object has three required fields:
120+
121+
- `"name"`
122+
123+
A unique string name for the constraint.
124+
125+
- `"function"`
126+
127+
A JSON object that describes the function `gⱼ` associated with constraint
128+
`j`. The function field is similar to the function field in
129+
`"objectives"`; however, in this example, our function is a single
130+
variable function of the variable `"x"`.
131+
132+
- `"set"`
133+
134+
A JSON object that describes the set `Sⱼ` associated with constraint `j`.
135+
In this example, the set `[1, ∞)` is the MathOptFormat set `GreaterThan`
136+
with a lower bound of `1`.
137+
138+
## The schema
139+
140+
A [JSON schema](http://json-schema.org/) for the `mof.json` file-format is
141+
provided in the file `mof.schema.json`.
142+
143+
## Examples
144+
145+
A number of examples of optimization problems encoded using MathOptFormat are
146+
provided in the `/examples` directory.

examples/biobjective.mof.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"description": "The problem: [min{2x - y + 1}, max{y}]",
3+
"version": 0,
4+
"variables": [{
5+
"name": "x"
6+
}, {
7+
"name": "y"
8+
}],
9+
"objectives": [{
10+
"sense": "min",
11+
"function": {
12+
"head": "ScalarAffineFunction",
13+
"terms": [{
14+
"coefficient": 2,
15+
"variable": "x"
16+
},
17+
{
18+
"coefficient": -1,
19+
"variable": "y"
20+
}
21+
],
22+
"constant": 1
23+
}
24+
}, {
25+
"sense": "max",
26+
"function": {
27+
"head": "SingleVariable",
28+
"variable": "y"
29+
}
30+
}],
31+
"constraints": []
32+
}

examples/milp.mof.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"description": "The problem: min{x | x + y >= 1, x ∈ [0, 1], y ∈ {0, 1}}",
3+
"version": 0,
4+
"variables": [{
5+
"name": "x",
6+
"primal_start": 0.0
7+
}, {
8+
"name": "y",
9+
"primal_start": 1.0
10+
}],
11+
"objectives": [{
12+
"sense": "min",
13+
"function": {
14+
"head": "SingleVariable",
15+
"variable": "x"
16+
}
17+
}],
18+
"constraints": [{
19+
"name": "x + y >= 1",
20+
"function": {
21+
"head": "ScalarAffineFunction",
22+
"terms": [{
23+
"coefficient": 1,
24+
"variable": "x"
25+
},
26+
{
27+
"coefficient": 1,
28+
"variable": "y"
29+
}
30+
],
31+
"constant": 0
32+
},
33+
"set": {
34+
"head": "GreaterThan",
35+
"lower": 1
36+
}
37+
}, {
38+
"name": "x ∈ [0, 1]",
39+
"function": {
40+
"head": "SingleVariable",
41+
"variable": "x"
42+
},
43+
"set": {
44+
"head": "Interval",
45+
"lower": 0,
46+
"upper": 1
47+
}
48+
}, {
49+
"name": "y ∈ {0, 1}",
50+
"function": {
51+
"head": "SingleVariable",
52+
"variable": "y"
53+
},
54+
"set": {
55+
"head": "ZeroOne"
56+
}
57+
}]
58+
}

examples/nlp.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"description": "The problem: min{2x + sin(x)^2 + y}.",
3+
"version": 0,
4+
"variables": [{
5+
"name": "x"
6+
}, {
7+
"name": "y"
8+
}],
9+
"objectives": [{
10+
"sense": "min",
11+
"function": {
12+
"head": "Nonlinear",
13+
"root": {
14+
"head": "node",
15+
"index": 4
16+
},
17+
"node_list": [{
18+
"head": "*",
19+
"args": [{
20+
"head": "real",
21+
"value": 2
22+
}, {
23+
"head": "variable",
24+
"name": "x"
25+
}]
26+
}, {
27+
"head": "sin",
28+
"args": [{
29+
"head": "variable",
30+
"name": "x"
31+
}]
32+
}, {
33+
"head": "^",
34+
"args": [{
35+
"head": "node",
36+
"index": 2
37+
}, {
38+
"head": "real",
39+
"value": 2
40+
}]
41+
}, {
42+
"head": "+",
43+
"args": [{
44+
"head": "node",
45+
"index": 1
46+
}, {
47+
"head": "node",
48+
"index": 3
49+
}, {
50+
"head": "variable",
51+
"name": "y"
52+
}]
53+
}]
54+
}
55+
}],
56+
"constraints": []
57+
}

examples/quadratic.mof.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"description": "The problem: min{x^2 + x * y + y^2}",
3+
"version": 0,
4+
"variables": [{
5+
"name": "x"
6+
}, {
7+
"name": "y"
8+
}],
9+
"objectives": [{
10+
"sense": "min",
11+
"function": {
12+
"description": "Note that the format is `a'x + 0.5 x' Q x + c`.",
13+
"head": "ScalarQuadraticFunction",
14+
"affine_terms": [],
15+
"quadratic_terms": [{
16+
"coefficient": 2,
17+
"variable_1": "x",
18+
"variable_2": "x"
19+
},
20+
{
21+
"coefficient": 1,
22+
"variable_1": "x",
23+
"variable_2": "y"
24+
},
25+
{
26+
"coefficient": 2,
27+
"variable_1": "y",
28+
"variable_2": "y"
29+
}
30+
],
31+
"constant": 0
32+
}
33+
}],
34+
"constraints": []
35+
}

examples/vector.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"description": "The problem: min{0 | [1 2; 3 4][x, y] + [5, 6] ∈ R+.",
3+
"version": 0,
4+
"variables": [{
5+
"name": "x"
6+
}, {
7+
"name": "y"
8+
}],
9+
"objectives": [],
10+
"constraints": [{
11+
"function": {
12+
"head": "VectorAffineFunction",
13+
"terms": [{
14+
"output_index": 1,
15+
"scalar_term": {
16+
"coefficient": 1,
17+
"variable": "x"
18+
}
19+
}, {
20+
"output_index": 1,
21+
"scalar_term": {
22+
"coefficient": 2,
23+
"variable": "y"
24+
}
25+
}, {
26+
"output_index": 2,
27+
"scalar_term": {
28+
"coefficient": 3,
29+
"variable": "x"
30+
}
31+
}, {
32+
"output_index": 2,
33+
"scalar_term": {
34+
"coefficient": 4,
35+
"variable": "y"
36+
}
37+
}],
38+
"constants": [5, 6]
39+
},
40+
"set": {
41+
"head": "Nonnegatives",
42+
"dimension": 2
43+
}
44+
}]
45+
}

0 commit comments

Comments
 (0)