Skip to content

Choose between a dimension, a relation, a map and a parameter#

This guide shows how to choose the declaration for a column of your data, in the specification of an optimisation model (a spec). The choice depends on what you do with the column in the spec, not on how you store the column. You need a spec file and the columns of the data you plan to attach to the spec.

Look up what you do with the column#

Use the first row that fits what you do with the column in the spec:

In the spec you… For example So declare it as
index parameters, variables or constraints over the rows the column lists generator, snapshot a dimension
look up a label of another dimension, one per row the bus of each generator a map of generator into bus, a dimension
list which pairs of two dimensions exist, with no value connection, the buses a generator may connect to a relation with missing: absent
use its numbers in an expression or a bound cost per generator, availability per generator and snapshot a parameter over the dimensions that index it
test its values in a condition fuel, is_committable a str or bool parameter

Declare each kind of column#

The spec below declares at least one column for each row of the table. Save it as spec.yaml:

spec.yaml
dimensions:
  generator: { dtype: str }
  snapshot: { dtype: int }
  bus: { dtype: str }

relations:
  connection: { dims: [generator, bus], missing: absent }

maps:
  generator: { bus: bus }

parameters:
  cost: { dims: [generator] }
  availability: { dims: [generator, snapshot] }
  load: { dims: [snapshot, bus] }
  fuel: { dims: [generator], dtype: str }
  is_committable: { dims: [generator], dtype: bool }

variables:
  dispatch: { dims: [snapshot, generator], bounds: { lower: 0, upper: availability } }
  reserve:
    dims: [snapshot, generator, bus]
    in: [connection]
    bounds: { lower: 0, upper: availability }

constraints:
  balance:
    dims: [snapshot, bus]
    expression: sum(dispatch, over=generator, by=generator[bus]) == load
  reserve_need:
    dims: [snapshot, bus]
    expression: sum(reserve, over=generator) >= 0.1 * load
  gas_limit:
    dims: [snapshot, generator]
    where: "fuel == 'gas'"
    expression: dispatch <= 0.5 * availability
  min_committed:
    dims: [snapshot, generator]
    where: is_committable
    expression: dispatch >= 0.2 * availability

objective:
  sense: minimize
  expression: sum(cost * dispatch)

With data attached, reserve exists only for the pairs that connection lists. gas_limit and min_committed exist only where the tests on fuel and is_committable hold.

Check the declaration#

Run check on spec.yaml:

python -m mathspec check spec.yaml
import mathspec as ms

for note in ms.advice('spec.yaml'):
    print(note)

The command and the Python loop print nothing, because mathspec accepts the spec and has no remark that is not a refusal (advice).

See also