Skip to content

Commit 3d81d04

Browse files
authored
[FileFormats.LP] add a documentation page and refactor some names (#2848)
1 parent 6e9c83c commit 3d81d04

File tree

7 files changed

+361
-137
lines changed

7 files changed

+361
-137
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const _PAGES = [
6767
"FileFormats" => [
6868
"Overview" => "submodules/FileFormats/overview.md",
6969
"API Reference" => "submodules/FileFormats/reference.md",
70+
"The LP file format" => "submodules/FileFormats/LP.md",
7071
],
7172
"Nonlinear" => [
7273
"Overview" => "submodules/Nonlinear/overview.md",
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# The LP file format
2+
3+
The purpose of this page is to document the LP file format, and the various
4+
differences that occur between solvers.
5+
6+
## Resources
7+
8+
There are a bunch of different descriptions of the LP file format on the
9+
internet.
10+
11+
* [CPLEX](https://www.ibm.com/docs/en/icos/22.1.0?topic=cplex-lp-file-format-algebraic-representation)
12+
* [FICO](https://www.fico.com/fico-xpress-optimization/docs/dms2021-01/solver/optimizer/HTML/chapter10_sec_section102.html)
13+
* [Gurobi](https://docs.gurobi.com/projects/optimizer/en/current/reference/fileformats/modelformats.html#lp-format)
14+
* [lpsolve](https://lpsolve.sourceforge.net/5.5/CPLEX-format.htm)
15+
* [Mosek](https://docs.mosek.com/11.0/capi/lp-format.html)
16+
* [QSopt](https://www.math.uwaterloo.ca/~bico/qsopt/hlp/ff_lp_format.htm)
17+
18+
## Grammar
19+
20+
This section gives the grammar of an LP file as we implement it. This grammar
21+
may be different to that of particular solvers.
22+
23+
The syntax rules for the grammar are:
24+
25+
* `<name>`: the name of a symbol in the grammar
26+
* `A :== B`: A is equivalent to B
27+
* `A | B`: either A or B
28+
* `i""`: case insensitive string
29+
* `[A]`: A is optional
30+
* `(A)*`: there are 0 or more repeats of A
31+
* `(A)+`: there is at least one or more repeats of A
32+
33+
In addition to the grammar, there are the following rules:
34+
35+
* Comments begin with `\`, and run until the next `\n` character
36+
* Whitespace is ignored
37+
* Newlines are ignored, except where explicitly described
38+
39+
```
40+
<lp-file> :==
41+
<keyword-objective>\n
42+
[<section-objective>\n]
43+
<keyword-constraints>\n
44+
(<constraint>)*
45+
[<keyword-bounds>\n (<bound-expression>)+]
46+
[<keyword-general>\n (<identifier>)+]
47+
[<keyword-binary>\n (<identifier>)+]
48+
[<keyword-sos>\n (<constraint-sos>)+]
49+
[<keyword-end>]
50+
51+
<keyword-objective> :==
52+
i"min" | i"minimum" | i"minimize" | i"minimise"
53+
| i"max" | i"maximum" | i"maximize" | i"maximise"
54+
55+
<keyword-constraints> :==
56+
(i"subject to" | i"st" | i"st." | i"s.t." | i"such that")[":"]
57+
58+
<keyword-bounds> :== i"bound" | i"bounds"
59+
60+
<keyword-general> :== i"gen" | i"general" | i"generals"
61+
62+
<keyword-binary> :== i"bin" | i"binary" | i"binaries"
63+
64+
<keyword-sos> :== i"sos"
65+
66+
<keyword-end> :== i"end"
67+
68+
<digit> :== "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
69+
70+
<char> :== a-z | A-Z | !"#$%&()/,;?@_'`|~
71+
72+
<identifier> :== <char> (<char> | <digit> | ".")*
73+
74+
<number> :==
75+
"+" <number>
76+
| "-" <number>
77+
| <digit>+[.(<digit>)*][("e" | "E")("+" | "-")(<digit>)+]
78+
| i"inf"
79+
| i"infinity"
80+
81+
<quadratic-term> :==
82+
"+" <quadratic-term>
83+
| "-" <quadratic-term>
84+
| [<number> ["*"]] <identifier> "^" "2"
85+
| [<number> ["*"]] <identifier> "*" <identifier>
86+
87+
<quadratic-expression> :==
88+
"[" <quadratic-term> (("+" | "-") <quadratic-term>)* "]" ["/" "2"]
89+
90+
<term> :==
91+
"+" <term>
92+
| "-" <term>
93+
| <identifier>
94+
| <number>
95+
| <number> <identifier>
96+
| <number> "*" <identifier>
97+
| <quadratic-expression>
98+
99+
<expression> :== <term> (("+" | "-") <term>)*
100+
101+
<name> :== [<identifier>":"]
102+
103+
<objective> :== <name> [<expression>]
104+
105+
<inequality> :== "<" | "<=" | "=<" | ">" | ">=" | "=>" | "=" | "=="
106+
107+
<set-suffix> := <inequality> <number>
108+
109+
<set-prefix> := <number> <inequality>
110+
111+
<constraint-indicator> :== <identifier> "=" (0 | 1) "->" <expression> <set-suffix>
112+
113+
<constraint-sos> :==
114+
"S1::" (<identifier>":"<number>)+\n
115+
| "S2::" (<identifier>":"<number>)+\n
116+
117+
<constraint> :==
118+
<name> <expression> <set-suffix>
119+
| <name> <constraint-indicator>
120+
| <name> <sos-constraint>
121+
122+
<bound-expression> :==
123+
<identifier> i"free"
124+
| <identifier> <set-suffix>
125+
| <set-prefix> <identifier>
126+
| <set-prefix> <identifier> <set-suffix>
127+
```
128+
129+
## Differences
130+
131+
There are many differences in how solvers parse an LP file.
132+
133+
### The "integer" section
134+
135+
Consider the section:
136+
```
137+
integers
138+
x
139+
```
140+
Gurobi will interpret this as `x in MOI.Integer()`. FICO Xpress will interpret
141+
this as `x in MOI.ZeroOne()`.
142+
143+
FICO document this behavior, but they're an outlier.
144+
145+
**We choose to interpret `integers` as `MOI.Integer()`.**
146+
147+
### Whether variables can have the same name as a keyword
148+
149+
Consider the file
150+
```
151+
min
152+
st
153+
st
154+
st >= 0
155+
end
156+
```
157+
or even the horrific
158+
```
159+
min st st st >= 0 end
160+
```
161+
Gurobi will complain up front that the keyword `st` appears twice, whereas
162+
Xpress will read the file as equivalent to :
163+
```
164+
minimize
165+
x
166+
subject to
167+
x >= 0
168+
end
169+
```
170+
171+
**We choose to allow variables to be named as keywords, and we use context to
172+
disambiguate.**
173+
174+
### Whitespace
175+
176+
Consider the file
177+
```
178+
minimize
179+
2x
180+
end
181+
```
182+
183+
Gurobi will interpret this as a single variable with the name `2x`, where as
184+
Xpress will interpret this as the expression `2 * x`.
185+
186+
Gurobi document this behavior, saying that they require whitespace around all
187+
tokens, but they're an outlier.
188+
189+
**We choose to allow juxtaposted tokens without whitespace.**
190+
191+
### Identifiers
192+
193+
In general, an identifier may contain the letters a-z, A-Z, the digits 0-9, and
194+
the characters ```!"#\$%&()/,.;?@_'`|~```.
195+
196+
Additional solvers put additional restrictions:
197+
198+
* In (all?) solvers except Gurobi, the identifier must not start with a digit
199+
or a `.` (in Gurobi, identifiers must be separated by whitespace)
200+
* Identifiers in Mosek and lpsolve may not start with the letter e or E
201+
* Keywords must not be used as names in Gurobi or Mosek, but they may in Xpress
202+
* Many solvers _actually_ support reading any UTF-8 string as the identifier,
203+
but they will normalize to the legal letters on write
204+
205+
**We choose to allow any valid UTF-8 names.**

docs/styles/config/vocabularies/JuMP/accept.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ errored
1515
flamegraph
1616
getters
1717
[Jj]ulia
18+
juxtaposted
1819
linkcheck
1920
nonlinearly
2021
nonzeros
@@ -52,7 +53,10 @@ Hijazi
5253
Holy
5354
JSONSchema
5455
MOI
56+
Mosek
5557
PATHSolver
58+
QSopt
5659
preprint
5760
Lubin
5861
Nemirovski
62+
Xpress

0 commit comments

Comments
 (0)