Skip to content

Given declarations#

given: names the variables and constraints a file reads and does not introduce. Use it to write a layer: a file of math meant to be added to a model that already exists, such as an emissions cap over a dispatch model somebody else built.

A file with a given: block says all of its own math. What it does not say is where those declarations come from. That is bound by whoever builds the model, the same way the numbers behind a parameter are.

dimensions:
  snapshot: { dtype: int }
  generator: { dtype: str }
parameters:
  emission_rate: { dims: [generator] }
  cap: { dims: [] }
given:
  variables:
    p:
      foreach: [snapshot, generator]
      description: dispatch, built by the model this file is added to
  constraints:
    balance:
      foreach: [snapshot]
      sense: "=="
constraints:
  co2_cap:
    foreach: []
    expression: sum(sum(p * emission_rate, over=generator), over=snapshot) <= cap
expressions:
  price: dual(balance)

The file loads on its own, prints on its own, and is refused on its own terms. Nothing about it waits for the model it is laid over.

given.variables#

A given variable is a column the file reads. It carries every field a load-time rule asks a variable for:

Field
foreach the dimensions the column is indexed by required
where a mask, in the where grammar optional
domain continuous, integer or binary continuous
absence what a masked coordinate means (absence) undefined
description plain prose optional

There is no bounds: key. Whoever owns the column owns its bounds, and a second spelling of them here would be a second home for one fact. Writing one is refused:

given.variables.p: unknown key 'bounds' in a given variable declaration.
Valid keys: absence, description, domain, foreach, where.

Everything else treats a given variable as a variable. It resolves in an expression, it carries dimensions into a constraint, it prints in the legend, and its where is checked against its foreach. The one thing that differs is who builds the column.

given.constraints#

A given constraint is a row family the file reads the dual of:

Field
foreach the dimensions the rows are indexed by required
sense <=, == or >= required
description plain prose optional

There is no expression: key. The body belongs to whoever builds the row. Nothing here builds one, so a given constraint never reaches the constraints a build reads.

given.constraints.balance: unknown key 'expression' in a given constraint
declaration. Valid keys: description, foreach, sense.

sense is required because it fixes the sign of the dual. Under minimize, a <= row and a >= row carry shadow prices of opposite sign. A dual read against the wrong sense is a wrong number rather than an error. So the file states the sense, and a consumer checks it against what it binds.

dual() is the only thing that may name a given constraint. It is a reported expression, so the same rule holds as for any dual: the math cannot read one. Writing dual(balance) in a constraint or the objective is refused:

Constraint 'co2_cap': a dual exists only after a solve; the math cannot read
one — keep the entry that carries it out of constraints, the objective, bounds
and where.

What is refused#

The file says Because
bounds: on a given variable the owner of the column holds them
expression: on a given constraint the owner of the row holds it
a given constraint with no sense: its dual would have no sign convention
a name under both variables: and given.variables one flat namespace, so it is a collision naming both
a name under both constraints: and given.constraints a row family is built here or given, never both
a foreach naming a dimension the file does not declare every frame is a product of declared dimensions
absence: with no where: an unmasked column exists at every coordinate, so nothing is absent

What is advised#

A given entry nothing reads asks whoever binds the file to find a column or a row family it has no use for. That is advice rather than a refusal, since a half-written file looks the same:

given variable 'spare' is never read: this file declares it and then no
expression names it. Remove it, or name it in the math — a given block states
what a consumer must bind, so an unread entry asks for one it has no use for.

Read it through advice, under the kind given-never-read.

What a consumer binds#

A loaded model reports a given variable in variables, with given true and both bounds open, and a given constraint in given_constraints, apart from the constraints a build reads.

The language stops there. Whether the bound column has the declared dimensions, coordinates and domain is a question about the model, not about the file. So is whether the bound row family has the declared sense. Both are answered where the file and the model meet.