Skip to content

State a rule that differs by regime#

Write one model in which a rule takes a different form for some members of a dimension. Committable and non-committable generators are the usual case, and the recipe needs no second model file.

  1. Put the regime in the data. A bool parameter says which members are in it; a str parameter names one of several:
parameters:
  committable: { dims: [generator], dtype: bool }
  1. Write one block per regime, each under its own where:. The block builds rows only where its mask holds, so a regime that needs no row gets none:
dimensions:
  snapshot: { dtype: int }
  generator: { dtype: str }

parameters:
  capacity: { dims: [generator] }
  min_output: { dims: [generator] }
  committable: { dims: [generator], dtype: bool }

variables:
  dispatch: { dims: [snapshot, generator], bounds: { lower: 0, upper: capacity } }
  on: { dims: [snapshot, generator], where: committable, domain: binary }

constraints:
  floor_committed:
    dims: [snapshot, generator]
    where: committable
    expression: dispatch >= min_output * on
  ceiling_committed:
    dims: [snapshot, generator]
    where: committable
    expression: dispatch <= capacity * on

Here a non-committable generator is bounded by capacity alone, through the variable's bounds:. Where the other regime has a rule of its own, write it as a third block under where: "NOT committable".

  1. Where the regime changes a quantity rather than a rule, name the quantity with cases: and write the rule once against it:
dimensions:
  snapshot: { dtype: int }
  generator: { dtype: str }

parameters:
  capacity: { dims: [generator] }
  committable: { dims: [generator], dtype: bool }

variables:
  dispatch: { dims: [snapshot, generator], bounds: { lower: 0 } }
  on: { dims: [snapshot, generator], where: committable, domain: binary }

expressions:
  available:
    dims: [snapshot, generator]
    cases:
      committed:
        when: committable
        expression: capacity * on
    otherwise: capacity

constraints:
  ceiling:
    dims: [snapshot, generator]
    expression: dispatch <= available

The loader proves at load that no two cases can hold at one coordinate, and otherwise: takes every coordinate they leave.

  1. Check it with python -m math_spec check model.yaml. A pair of masks that can both hold, or a case with no otherwise:, is refused there with the rewrite named.

What a where: means is under absence; what a cases: block accepts is under named expressions.