Param
Param
Coefficients over a set product. A parameter is data, not a model object: it has no columns and produces no rows. It supplies a term's coefficient and a constraint's right-hand side.
The array of a parameter declares absence="empty". A coordinate it does
not have contributes no coefficient. Absence is the additive identity a sum
requires.
Param.from_dense(name, sets, values)
Every cell of values as a coefficient. values.shape must equal the
sizes of sets, in order; a mismatch raises ValueError with both shapes.
import numpy as np
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
cost = Param.from_dense("cost", (P, W), np.array([[2.0, 4.0, 5.0], [3.0, 1.0, 6.0]]))
print(cost.dims, cost.nnz)
Output
('P', 'W') 6
Param.from_long(name, sets, columns, values)
Coefficients from one label column per set and one value column. columns
is a mapping keyed by set name. Each column and values are read in
parallel and have the same length.
import numpy as np
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
cost = Param.from_long(
"cost",
(P, W),
{"P": np.array(["lisbon", "porto"]), "W": np.array(["berlin", "paris"])},
np.array([2.0, 1.0]),
)
print(cost.nnz)
Output
2
A label column of a different length raises ValueError; the message
gives the parameter, the column, its length and the value column's.
import numpy as np
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
Param.from_long(
"cost",
(P, W),
{"P": np.array(["lisbon"]), "W": np.array(["berlin", "paris"])},
np.array([2.0, 1.0]),
)
Raises ValueError
ValueError: parameter 'cost': label columns have lengths {'P': 1, 'W': 2} and the value column has length 2; pass columns of equal length
Param.from_positions(name, sets, index, values)
Coefficients from an index matrix and one value column. index has one row
per set, and each column identifies one member by its position in each set.
A caller that already has positions resolves no labels. The columns are in
any order, and each member appears once.
import numpy as np
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
cost = Param.from_positions("cost", (P, W), [[1, 0], [1, 0]], [1.0, 2.0])
print(cost.array.to_dense())
Output
[[2. 0. 0.]
[0. 1. 0.]]
A position outside its set raises ValueError, as does a member given twice.
Param.from_array(name, sets, array)
Coefficients from a nimblend array over the sets' names, in any order. The
labels are members of the sets, in any order and extent. The parameter has
an entry where the array has one, under absence 'empty' and 'unknown'
alike. A label outside its set, other dimension names and a set with no
members raise ValueError; an object that is not a nimblend array raises
TypeError.
import numpy as np
import nimblend as nb
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
cost = Param.from_array(
"cost",
(P, W),
nb.from_dense(
np.array([[1.0]]), {"P": np.array(["porto"]), "W": np.array(["paris"])}
),
)
print(cost.array.to_dense())
Output
[[0. 0. 0.]
[0. 1. 0.]]
Members
| Member | Returns |
|---|---|
dims | the sets it is indexed over |
nnz | the number of coefficients |
materialise() | the coefficients as a nimblend array |
param[sets] | a reference, with the sets given checked against dims |
A label in place of a set fixes that dimension at one member: the coefficients at that member are read and the dimension leaves the reference.
import numpy as np
from nimopt import Param, Set
P = Set("P", np.array(["lisbon", "porto"]))
W = Set("W", np.array(["berlin", "paris", "rome"]))
cost = Param.from_dense("cost", (P, W), np.array([[2.0, 4.0, 5.0], [3.0, 1.0, 6.0]]))
print(cost[P, W].dims)
print(cost[P, "berlin"].dims)
Output
('P', 'W')
('P',)
Coefficient
What a term reads as its coefficient: a name to report, the dims it is
indexed over, the array it materialise()s to, and a reading at its sets. A
parameter read at its sets is a coefficient, and so is an arithmetic
combination of coefficients. One interface therefore covers both.
+, -, *, / and a power by a number combine coefficients. The
combination is symbolic: it contains references, derives its dimensions from
its operands, and is evaluated once, when the term it multiplies is
materialised. It can therefore be written in a definition before any data
exists.
import numpy as np
from nimopt import Param, Set
G = Set("G", np.array(["base", "peak"]))
T = Set("T", np.arange(3))
price = Param.from_dense("fuel_price", (G, T), np.full((2, 3), 30.0))
eta = Param.from_dense("efficiency", (G, T), np.array([[0.5] * 3, [0.4] * 3]))
unit_cost = price[G, T] / eta[G, T]
print(unit_cost.name, unit_cost.dims)
print(unit_cost[G, T].materialise().to_dense()[:, 0])
Output
(fuel_price / efficiency) ('G', 'T')
[60. 75.]
A parameter has no arithmetic of its own. It is read at its sets, and the references combine.
import numpy as np
from nimopt import Param, Set
G = Set("G", np.array(["a", "b"]))
price = Param.from_dense("price", (G,), np.array([1.0, 2.0]))
eta = Param.from_dense("eta", (G,), np.array([0.5, 0.4]))
price / eta
Raises TypeError
TypeError: parameter 'price' is over ('G',) and expresses no coefficient until it is read; read it at its sets as price[G]