A variable is a dimension
A model has one column space. m.var does not create an object with its
own numbering; it takes the next range of that space, and each subsequent
variable continues from where the previous one ended.
import numpy as np
from nimopt import Model, Set
P = Set("P", np.array(["p0", "p1"]))
W = Set("W", np.array(["w0", "w1", "w2"]))
m = Model("transport")
x = m.var("x", (P, W))
y = m.var("y", (P,))
print(x.n_columns, y.n_columns)
print(m.n_columns)
Output
6 2
8
The shared column space is what makes the column a dimension. A variable's
coefficients form an array over (*dims, COLUMN), where COLUMN is the
model's column space. A variable does not own columns; it occupies a block
of one dimension that all variables share.
A column is computed, not stored
A member's column is a virtual coordinate, obtained by arithmetic rather than by lookup.
For a full product, the column is the member's multi-index ravelled against
the set sizes, offset by the start of the variable's block. ProductCoord
performs that computation.
import numpy as np
import nimblend as nb
columns = nb.ProductCoord((2, 3))
print(columns.to_position(np.array([[0, 1], [2, 0]])))
Output
[2 3]
Member (0, 2) is column 2 and (1, 0) is column 3: stride arithmetic and
nothing else.
For a variable over a subset, the column is the member's rank among the
subset's codes. SubsetCoord stores the codes in order, and a block already
in canonical order needs no lookup.
import numpy as np
import nimblend as nb
columns = nb.SubsetCoord(np.array([0, 4]), (2, 3))
print(columns.to_position(np.array([[0, 1], [0, 1]])))
Output
[0 1]
Codes 0 and 4 are members (0, 0) and (1, 1), with ranks 0 and 1.
Consequences
Nothing stores a column index. A variable over a million members stores its set sizes, the start of its block and, for a subset, the codes of its members. It stores no integer per member: the column is computed from the member itself.
The cost of declaring a variable is therefore the cost of its members, not of its columns. A variable over a full product costs nothing per column: two set sizes and a start.
A subset variable is not a special case. Both kinds report the position a member occupies. They differ in whether that position is computed by arithmetic or by a rank.