Fix a quantity that is data in one model and a decision in another#
Write one spec in which a quantity, such as a plant's size, is chosen by the solver in one study and given by the data in another. There are two ways:
- Pin it in the data where the solver may keep the quantity as a variable. The file and the call stay the same, and equal bounds hold the variable at one value.
- Fix it with
spec.fixwhere the model must not have the variable: a Benders subproblem, a myopic step or a rolling window. The quantity becomes a parameter, sosize * onis linear andsizemay stand in a bound.
Equal bounds in the data#
- Declare the quantity as a variable, with named bounds.
dimensions:
plant: { dtype: str }
parameters:
size_min: { dims: [plant] }
size_max: { dims: [plant] }
variables:
size:
dims: [plant]
bounds: { lower: size_min, upper: size_max }
-
Write every rule against the variable.
rate - relmax * size <= 0is one equation whethersizeis chosen or given. -
Pin it in the data where it is given. Attach
size_minandsize_maxas the same value for a plant whose size is fixed. Equal bounds pin a variable (variables).
A pinned variable is still a variable: size * on is variable * variable,
and size cannot stand in another variable's bounds:. Where a bound has to
come from it, fix it with spec.fix.
spec.fix#
- Write the spec with the quantity as a variable. Here
sizeexists only for a candidate plant:
version: 0
dimensions:
plant: { dtype: str }
snapshot: { dtype: int }
parameters:
size_min: { dims: [plant] }
size_max: { dims: [plant] }
relmax: { dims: [snapshot, plant] }
demand: { dims: [snapshot] }
invest: { dims: [plant] }
fuel: { dims: [plant] }
candidate: { dims: [plant], dtype: bool }
variables:
size:
dims: [plant]
where: candidate
bounds: { lower: size_min, upper: size_max }
rate:
dims: [snapshot, plant]
bounds: { lower: 0 }
constraints:
capacity:
dims: [snapshot, plant]
expression: rate - relmax * size <= 0
supply:
dims: [snapshot]
expression: sum(rate, over=plant) >= demand
objective:
sense: minimize
expression: sum(invest * size) + sum(fuel * rate)
- Call
spec.fixwith every name to fix, in one call.
The spec it returns differs from the file in two places:
parameters:
size: { dims: [plant], dtype: float, missing: absent }
assumptions:
size_within_bounds:
holds: size >= size_min AND size <= size_max
where: candidate
sizeis a parameter under the same name, so every expression goes on reading it. Abinaryorintegervariable becomes anintparameter.sizekeeps what it meant outside its mask. The variable did not exist outsidecandidate, socapacitywas not built there. The parameter ismissing: absent, so a plant with no row is still not built, and every row stays as written. A variable with nowhere:becomes a parameter that needs every row.- The bounds become an assumption on the numbers you attach.
- A constraint that named only fixed variables becomes an assumption under its own name, because it now compares numbers.
- Attach
sizeas data, one value for each candidate plant, as for any parameter.