Skip to main content

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​

MemberReturns
dimsthe sets it is indexed over
nnzthe 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]