Files
dumps, load, loads, save
| Function | Does |
|---|---|
dumps(what, inline=False, instructions=False, version=4) | returns the text of a definition's file, or of a model's file; a model's data is included with inline=True alone; a definition with inline=True raises ValueError |
load(path, data=None) | reads a file; returns a Definition, or a Model where the file contains data or data= gives it |
loads(text, data=None) | the same over text; a sidecar name in text raises ValueError. Text has no directory |
save(what, path, inline=False, instructions=False, version=4) | writes a definition's file, or a model's with an .npz beside it, or one file with an inline block when inline=True; instructions=True writes the comment block that describes the format at the top of the file; version is 4 or 3 |
data= is the mapping build takes or the path of an .npz. A file that
contains data and a data= together raises ValueError.
dumps returns the text save writes, without a sidecar line. Only save
writes a sidecar and the line that identifies it.
version=4 writes each piecewise declaration under piecewise, and omits
the sets, parameters, variables and constraints it generated. version=3
writes a model's generated declarations as ordinary declarations, and omits
the piecewise declarations and any parameter only they read. A model loaded
from that file contains the same rows and no piecewise declaration. A
definition with a piecewise declaration raises ValueError at version 3. Any
other version raises ValueError.
With instructions=True, every writer puts a fixed comment block at the top
of the text. The block describes the format: the keys and their order, the
defaults, the rules that determine which rows a constraint has, and the
expression syntax. The text is the same in every file and describes the
format, not the model. A reader with one file interprets it without this
package. The block is a YAML comment: a file with it and a file without it
load to the same model.
The file
| Key | Contains |
|---|---|
version | 4, or 3 where the caller asks for it; files of version 2 and 3 also load; any other value raises ValueError and reports the versions this reader accepts |
name, sense | the model's |
sets | a list of names |
aliases | each alias to its base set; absent where the model declares none |
parameters | each name to its dimensions |
variables | each name to sets, and to subset, lower, upper, integer where they differ from no subset, 0, infinity and false |
constraints | each name to relation, and to where or over where given |
piecewise | each name to x, x_points, y, y_points, sign, method, and to active, relaxed and where where given; version 4 only; absent where the model declares none |
objective | the objective expression; absent where the model declares none |
data | an inline mapping, or the name of an .npz beside the file |
subset, where and over take a parameter's name, meaning the coordinates
it contains, or a list of set names, meaning their full product. A symbol's
name is a Python identifier other than Sum. A dimension listed in
parameters, in a variable's sets, or in a list of set names is a set or an
alias. An alias is declared after its base set.
The expressions are written as they are typed in Python and are read back through the same operators. The file is a fixed point: reading it and writing it again gives the same text.
from nimopt import Definition, Sum, dumps, loads
d = Definition("d")
S = d.set("S")
c = d.param("c", (S,))
x = d.var("x", (S,), integer=True)
d.constraint("cap", 2 * c[S] * x[S] - 1 <= 5)
text = dumps(d)
print(text)
print(dumps(loads(text)) == text)
Output
version: 4
name: d
sense: min
sets: [S]
parameters:
c: [S]
variables:
x:
sets: [S]
integer: true
constraints:
cap:
relation: (c[S] * 2) * x[S] - 1 <= 5
True
A key the format does not define raises ValueError, at the top level and
inside an entry.
from nimopt import loads
loads(
"version: 3\nname: d\nsense: min\nsets: [S]\n"
"variables:\n x: {sets: [S], bound: 1}\n"
)
Raises ValueError
ValueError: variable 'x' contains the unknown key 'bound'; write only 'sets', 'subset', 'lower', 'upper', 'integer'
Data
The data in a file is the mapping build takes, in three shapes.
| Shape | Inline | In the .npz |
|---|---|---|
| a set's members | a list | a one-dimensional label array |
a set of datetime64 or timedelta64 members | dtype and members | a one-dimensional label array |
| a dense parameter | nested lists in row-major order | its grid |
| a long parameter | columns, the dimensions then value, and rows | a structured array with one field per dimension and value |
A parameter is written dense where its array covers its full product and
long otherwise. The .npz is read with allow_pickle=False. An array of
object dtype raises ValueError at save and reports the symbol: the
container would pickle it, and the reader rejects a pickled array.
from nimopt import loads
loads(
"version: 3\nname: d\nsense: min\nsets: [S]\nparameters:\n c: [S]\n"
"data:\n S: [a]\n c:\n columns: [value, S]\n rows:\n - [1.0, a]\n"
)
Raises ValueError
ValueError: parameter 'c' is given columns ['value', 'S']; a table lists the dimensions then value: ['S', 'value']
Datetime members
A set whose members are datetime64 or timedelta64 is written inline as a
mapping of dtype and members, instead of a list.
data:
T:
dtype: datetime64[s]
members: ['2030-01-01T00:00:00', '2030-01-01T01:00:00']
A datetime64 member is written as its ISO 8601 string. A timedelta64
member is written as its integer count of the unit in the dtype. A label
column of a long table is written in the same text and takes no marker: the
column belongs to a set, and the reader converts it to that set's dtype. The
.npz stores the dtype of every array and uses no separate form.
A member fixed in a relation is written as text. A datetime64 member is its
quoted ISO 8601 string, such as x['2030-01-01T00:00:00']. A timedelta64
member is a quoted count and numpy unit code, such as x['3 h'].
Every member is converted to the dtype of its set. A string is parsed as ISO
8601. A datetime.datetime, a datetime.date and a datetime64 of another
unit are converted. An integer against a timedelta64 set is a count of that
set's own unit. A conversion that is not exact raises ValueError:
'2030-01-01T00:30' against a set in hours raises instead of truncating to
the hour.
A member specifies no time zone. datetime64 represents no offset, and a
conversion to UTC would move the member. A string with an offset or a trailing
Z raises ValueError, and a datetime.datetime with a tzinfo raises the
same error. Write the naive form, '2030-01-01T00:00:00'.
A member outside the range its dtype represents raises ValueError and
reports the first and the last member of that range. A NaT member raises
ValueError.
What raises before anything is written
| Written | Reason |
|---|---|
a model whose subset, where or over is a domain with no name | declare the members as a parameter |
| two parameter objects or two set objects sharing a name in one model | the file keys a symbol by name |
a symbol whose name is not an identifier, or is Sum | the expression syntax cannot address it |
| an array of object dtype | the container would pickle it |
import numpy as np
from nimopt import Model, Set, dumps, subset
P = Set("P", np.array(["a", "b"]))
m = Model("m")
x = m.var("x", (P,))
m.constraint("cap", x[P] <= 1.0, where=subset((P,), {"P": np.array(["a"])}))
dumps(m)
Raises ValueError
ValueError: constraint 'cap' gives where= a domain with no name; declare its members as a parameter and refer to that parameter