Given, parameters, variables, objective and constraints#
A spec declares its data under parameters: and its decisions under
variables:, and states its goal under objective: and its rules under
constraints:. It lists under given: what another file declares. This page
lists the keys of those five sections, in the order of the
top-level keys. Every entry in these sections
also takes description:, free text that the
typeset legend lists beside the entry.
given#
given: lists what this file uses and another file declares. It takes five keys: data under parameters:, named conditions under
conditions:, variables under variables:, named expressions under
expressions:, and families of rows under constraints:. A file with a
given: section loads and prints on its own, and
python -m mathspec check prints one line of
advice for each given entry.
merge replaces each
given entry with the entry that another file
of the composed spec (a fragment) declares under the
same name.
mathspec refuses a name that a file declares both in a section and under the
same key of given:. For a parameter cost, the message is:
For a variable, an expression or a condition, mathspec prints the same
message with the kind of entry changed. For a constraint c, mathspec prints a
different message, with one rewrite:
The typeset legend lists every given entry under Given.
given: parameters#
A given parameter is data that this file uses and another file declares.
given:
parameters:
gen_cost: { dims: [generator], description: what one unit of output costs }
gen_on: { dims: [generator], dtype: bool }
variables:
gen_p: { dims: [snapshot, generator] }
dimensions:
snapshot: { dtype: int }
generator: { dtype: str }
constraints:
off_units_idle:
dims: [snapshot, generator]
where: not gen_on
expression: gen_p <= 0
objective:
sense: minimize
expression: sum(gen_p * gen_cost)
python -m mathspec check loads the file and prints one line of advice for
each of the three given entries:
parameter 'gen_cost' is read here and declared elsewhere: the model this one is layered onto provides it. A tool refuses the spec where that model does not, over the same dims. merge() replaces this entry with the one another file declares.
parameter 'gen_on' is read here and declared elsewhere: the model this one is layered onto provides it. A tool refuses the spec where that model does not, over the same dims. merge() replaces this entry with the one another file declares.
variable 'gen_p' is read here and declared elsewhere: the model this one is layered onto provides it. A tool refuses the spec where that model does not, over the same dims. merge() replaces this entry with the one another file declares.
Each line states that the entry must come from another file, over the same dimensions.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions the parameter is indexed over | |
dtype |
float, int, bool or str |
float |
A given parameter may appear wherever a parameter may: in an expression, a
where: and a bound.
given: conditions#
A given condition is a named condition that this file uses and another file defines.
given:
variables:
p: { dims: [period, generator] }
conditions:
stands:
dims: [period, generator]
description: the generator stands in this period
dimensions:
period: { dtype: int, ordered: true }
generator: { dtype: str }
parameters:
ramp: { dims: [generator] }
constraints:
ramp_up:
dims: [period, generator]
where: stands AND shift(stands, along=period, offset=1)
expression: p - shift(p, along=period, offset=1) <= ramp
ramp_up has a row only where the generator stands in this period and in the
period before.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions that the condition of the defining file uses |
A given condition has no body, because the file that defines it sets the
body. A condition in this file uses the name as data over its dims, true or
false at each coordinate. As for a named condition,
mathspec refuses the name in arithmetic. merge
refuses a given condition whose dims
differ from the dimensions of the defining condition.
given: variables#
A given variable is a variable that this file uses and another file declares.
given:
variables:
flow:
dims: [snapshot, port]
description: what a port puts into its bus
dimensions:
snapshot: { dtype: int }
port: { dtype: str }
generator: { dtype: str }
maps:
generator: { port: port }
variables:
gen_p: { dims: [snapshot, generator], bounds: { lower: 0 } }
constraints:
gen_injects:
dims: [snapshot, generator]
expression: at(flow, by=generator[port]) == gen_p
gen_injects states that the flow at the port of each generator equals the
output of that generator.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions the variable is indexed over | |
domain |
continuous, integer or binary |
continuous |
A given variable takes no bounds and no where, because the file that
declares the variable sets both. mathspec prints no domain line for it.
merge keeps the entry of the file that
declares the variable. Where no file of the composed spec declares the
variable, the given entry stays in the compiled form of the spec (its
program). With data attached,
the model that the spec is layered onto
provides the variable.
given: expressions#
A given expression is a named expression that this file uses and another file defines.
given:
expressions:
injection:
dims: [snapshot, bus]
description: what the components put into a bus
dimensions:
snapshot: { dtype: int }
bus: { dtype: str }
constraints:
balance:
dims: [snapshot, bus]
expression: injection == 0
balance states that what the components put into each bus adds up to zero.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions the expression is indexed over |
A given expression has no body, but a named expression of this file may
add a term to it. mathspec reads the name as it
reads a given variable: a quantity over its dims, of degree one.
mathspec refuses a comparison on a given expression in a condition, because a
condition is read before any variable exists. For where: "injection > 0" on
a variable x, the message is:
Variable 'x': where references the given expression 'injection'. A given expression may hold a variable, and a condition is read before variables exist — it may test parameters and dimension coordinates only.
The bare name, where: injection, loads. check prints only the advice for
the given entry, and mathspec ends the typeset domain of x with the
condition "injection exists".
merge replaces a given expression with the definition of another fragment,
and checks that body against the dims of
this file. merge accepts a body
over fewer dimensions. It refuses a row that would repeat the body across a
missing dimension where no other term is over that dimension. merge also holds the body to the rules of every place where this file uses it. So mathspec refuses a square of a given expression once the body is quadratic.
given: constraints#
A given constraint is a family of rows that another file declares, and whose marginal value per row (dual) this file uses.
given:
constraints:
balance:
dims: [snapshot, bus]
description: another file clears each bus
dimensions:
snapshot: { dtype: int }
bus: { dtype: str }
expressions:
price:
expression: dual(balance)
price is the dual of each balance row: the marginal price at each bus and
snapshot.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions the family of rows is indexed over |
A given constraint takes no expression, because a file may use it only
inside dual(name). price, a named expression computed
after the solver runs (a reported expression),
takes its dimensions from the dims of the given entry.
parameters#
A parameter is a column of data that the spec uses, such as the load at each snapshot or the cost of each generator. The entry declares the dimensions of the column, and the numbers arrive with the data, which a tool matches to the parameter by name.
dimensions:
snapshot: { dtype: int }
parameters:
load:
dims: [snapshot]
discount_rate:
dims: [] # a scalar
variables:
p: { dims: [snapshot] }
constraints:
meet:
dims: [snapshot]
expression: p * (1 + discount_rate) >= load
load has one value per snapshot, and discount_rate has one value only,
because dims: [] declares a scalar.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions it is indexed over. [] means a scalar |
|
dtype |
float, int, bool or str |
float |
missing |
what a missing row of the data means (missing) |
refused |
in |
the relations of its index set (in) |
[] |
where |
the condition that limits its coordinates (where) |
null |
With data attached, a tool requires the column to match the dtype:
dtype |
The column | Note |
|---|---|---|
float |
a float column, or an integer one | |
int |
an integer column | |
bool |
a boolean column | a column of 1 and 0 is not a boolean column |
str |
a string column |
When the data is attached, a tool refuses a null value or a not-a-number
value (NaN), so a coordinate with no value has no row. inf and -inf are
values.
Only a float or an int parameter is a number. A str parameter is a label
and a bool parameter is a condition, and each one selects rows in a
where:. mathspec refuses either one at load as a
coefficient, a term or a divisor. For a bool parameter flag in
p * flag >= 0, the message is:
Constraint 'c': 'flag' is declared dtype: bool, and an expression reads only float and int. Name it in a condition ("flag", "NOT flag"), or declare it dtype: int to multiply by 0 and 1.
mathspec suggests both rewrites.
A str parameter takes any label. A dimension with
one_of has a fixed list of labels.
missing#
missing: sets the meaning of a coordinate of the dims at which the data has
no row. It takes refused (the default), absent, a value of the dtype
of the parameter, or a reading per label. On a
parameter with a where:, missing: applies only where the
condition is true. On a parameter with an in:, it
applies only where each relation has a row.
dimensions:
generator: { dtype: str }
parameters:
cost: { dims: [generator] } # refused: every generator has a cost
start_up_cost: { dims: [generator], missing: 0 } # no row means no cost
p_set: { dims: [generator], missing: absent } # no row, no fixing row
efficiency: { dims: [generator], missing: 1 }
p_nom_max: { dims: [generator], missing: .inf }
active: { dims: [generator], dtype: bool, missing: true }
variables:
p: { dims: [generator], where: active, bounds: { lower: 0, upper: p_nom_max } }
start: { dims: [generator], domain: binary }
constraints:
fix:
dims: [generator]
expression: p == p_set
eff:
dims: [generator]
where: efficiency <= 1
expression: p * efficiency >= 0
objective:
expression: sum(p * cost) + sum(start * start_up_cost)
cost takes the default, refused. p_set takes absent, and
start_up_cost, efficiency, p_nom_max and active each take a value.
missing on a parameter lists what a
missing row means in each position of an expression. An
assumption can require a row of
an absent parameter wherever its where: is true.
A condition treats a missing row in one of three ways:
- Whatever the
missing:, a bare numeric name is true where the data has a row. A barefloatname is true only where its value is also finite. Sowhere: p_nom_maxselects the rows that the data contains. Unless the parameter has awhere:, mathspec refuses a bareintorstrname underrefusedat load, because the condition would be true everywhere. - A comparison uses the value. So
where: efficiency <= 1is true at a missing row ofefficiencyabove, which is1there. Underabsent, a comparison at a missing row is false. - A bare
boolname is its value. Sowhere: activeis true at a missing row ofactiveabove.
A value has the dtype of the parameter:
dtype |
A value |
|---|---|
float |
a number. .inf, inf, -.inf and -inf are numbers |
int |
an integer. An integer column has no inf |
bool |
true or false |
str |
none. A label has no value to fill |
A reading per label#
missing: also takes a mapping that reads a missing row by the label that a
map gives its coordinate:
dimensions:
component:
dtype: str
one_of: [Generator, Link, Load, ShuntImpedance, StorageUnit]
entity:
dtype: str
maps:
entity:
component: component
parameters:
sign:
dims: [entity]
missing:
by: entity[component]
fill:
Load: -1
ShuntImpedance: -1
otherwise: 1
A missing row of sign reads -1 at a load or a shunt impedance, and 1 at
every other entity.
| Key | Value | Default |
|---|---|---|
by |
subject[map]: one map of a subject over dimensions of the parameter |
required |
fill |
a reading for each of one or more labels of that map | required |
otherwise |
the reading at every other label, and where the map gives the coordinate no label | refused |
Each reading is one that a plain missing: takes. As in
at(x, by=), by: names the map, so the subject may
have other maps. In a flow mapping, quote it:
missing: { by: "entity[component]", fill: { Load: -1 } }.
mathspec refuses at load a by: that names a subject and no map, a key
column, more than one map, or a map the subject does not have. It also
refuses a fill: label that the one_of of the
dimension the map refers to does not list. For by: entity, it prints:
Parameter 'sign': missing: by: entity names the subject and none of its maps. Write by: entity[<map>], with a map of 'entity': ['component'].
The subject may be a relation that the parameter names under in:.
Every coordinate then has a row in it, so otherwise reads only at a label
that fill: does not name, or where the map gives no label.
mathspec refuses a NaN, a quoted number and missing: null at load, and in
each message mathspec suggests what to write. For missing: null it prints:
parameters.v.missing: missing: null on a parameter names no reading. Write absent for a row that is not there, or leave the key out for refused.
mathspec suggests two rewrites, absent and refused.
A given: parameter has no missing: and no where:, because the file that
declares the parameter sets both.
A values parameter of a curve with a where: over its breakpoints must declare a
missing: other than refused.
The typeset legend lists what a missing row means beside the parameter, such
as `0` where the data has no row. It lists nothing for refused. For a
reading per label, it lists each reading with its labels, then otherwise.
where#
where: limits a parameter to the coordinates where a
condition is true. The dimensions keep every
label, and only the parameter loses coordinates. In this example, efficiency
has a value only at the pairs of an entity and a bus that are wired as an
output:
dimensions:
entity: { dtype: str }
bus: { dtype: str }
role: { dtype: str }
snapshot: { dtype: int }
relations:
connection: { dims: [entity, bus], missing: absent }
maps:
connection: { role: role }
parameters:
efficiency:
dims: [entity, bus, snapshot]
where: "connection[role] == 'output'"
missing: 1
variables:
p: { dims: [entity, snapshot] }
constraints:
balance:
dims: [bus, snapshot]
expression: sum(efficiency * p, over=entity) == 0
With the data in the figure, efficiency has rows only at the pairs that
connection lists as an output. connection does not list boiler at el,
so that pair has no role, and a tool drops its data row. missing: 1 gives
chp at heat the value 1. In balance,
efficiency * p is absent at an entity that is not wired to the bus, so the
sum adds only the wired entities.
With data attached, a tool decides the coordinates of a parameter in two steps:
- Where the condition is false, the parameter is absent in every expression that uses it, and the tool drops any row of the data there.
- Where the condition is true, the tool uses each row of the data as it is.
A missing row there is refused, absent or a value, as
missing:sets.
Under missing: refused, a tool requires a row at each output pair and
snapshot of the example, and drops every other row.
A tool drops a row of the data outside the condition without refusing the
data. An assumption on the parameter does not test that row
either, because the parameter has no row there. To have a tool refuse a row at
a pair that is not wired, write in: [connection]. A relation name
alone in the where: would state the same rows a second time, so mathspec
refuses it. For where: connection on efficiency, the message is:
Parameter 'efficiency': `where: connection` tests the rows of 'connection', which `in:` states. Write `in: [connection]` in place of the `where:`.
A tool evaluates the condition from the data alone, before it reads the
parameter. So the condition may contain dimensions,
relations and parameters with neither a where: nor an
in:.
mathspec refuses four conditions at load:
- a condition that contains a variable
- a condition that contains the parameter itself
- a condition that contains a parameter with a
where:or anin:of its own - a condition over a dimension that the parameter does not have
For a where: on efficiency that contains the variable p, the message
is:
Parameter 'efficiency': its `where:` contains variable 'p', and a tool evaluates the `where:` of a parameter from the data alone, before any variable has a value. Test a parameter or a map instead.
mathspec suggests a parameter or a map as the rewrite.
The typeset legend lists the condition beside the dimensions, after
only where. For efficiency, the legend entry ends in
only where \(\mathrm{role}(b,\ e) = \text{'}\mathrm{output}\text{'}\).
in#
in: lists the relations that make up the index set of the parameter. The
parameter has coordinates only where each relation has a row, and a tool
refuses a row of the data anywhere else. A where: drops that row
instead. In this example, efficiency and p_nom_max have values only at the
pairs that connection lists:
dimensions:
entity: { dtype: str }
bus: { dtype: str }
snapshot: { dtype: int }
relations:
connection: { dims: [entity, bus], missing: absent }
parameters:
efficiency: { dims: [entity, bus, snapshot], in: [connection], missing: 1 }
p_nom_max: { dims: [entity, bus], in: [connection], missing: .inf }
distance: { dims: [entity, bus] }
variables:
p: { dims: [entity, snapshot] }
constraints:
balance:
dims: [bus, snapshot]
expression: sum(efficiency * p, over=entity) == 0
Each parameter names its own relations. distance is also over entity and
bus, names none, and needs a row at every pair.
With data attached, a tool decides the coordinates of efficiency in three
steps:
- Where
connectionhas no row,efficiencyis absent, and the tool refuses any row of the data ofefficiencythere. - Where the
where:ofefficiencyis false, the tool drops the row.efficiencyhas nowhere:, so the tool drops nothing. - At each remaining coordinate with no row,
missing: 1sets the value.
So missing: 1 fills only the wired pairs, and a data row for an entity at a
bus it is not wired to is refused.
A parameter in several relations has coordinates only where each of them has a row.
A relation in in: gives its rows, and its maps play no
part in the index set. They stay readable as connection[bus] in a where:
and in a call. In this example, connection has a row per port of a unit, and
its maps bus and role give each port a bus and a role:
dimensions:
unit: { dtype: str }
port: { dtype: int }
bus: { dtype: str }
role: { dtype: str }
snapshot: { dtype: int }
relations:
connection: { dims: [unit, port], missing: absent }
maps:
connection: { bus: bus, role: role }
parameters:
efficiency:
dims: [unit, port, snapshot]
in: [connection]
where: "connection[role] == 'output'"
missing: 1
variables:
flow: { dims: [unit, snapshot], bounds: { lower: 0 } }
constraints:
delivered:
dims: [bus, snapshot]
expression: sum(efficiency * flow, over=[unit, port], by=connection[bus]) >= 0
efficiency has coordinates at each port that connection lists, and a tool
refuses a data row for a port that connection does not list. The where:
then drops the input ports. efficiency is not over bus or role, the
dimensions that the maps refer to. An entry over one of them has a coordinate
at every label of that dimension, not only at the label that the map gives the
port.
mathspec refuses seven index sets at load:
- a name that is not a relation, such as a dimension
- a relation named twice
- a map, written as
subject[map], in place of a relation - a relation under
missing: refused, which has a row at every combination and so leaves nothing out - a relation with two columns over one dimension
- a relation over a dimension that the parameter does not have
- a
where:that reads the bare name of a relation of thein:
For p_nom_max: { dims: [entity], in: [connection] }, the message is:
Parameter 'p_nom_max': in: names 'connection', over ['bus', 'entity'], and 'p_nom_max' is not over ['bus']. Add ['bus'] to its dims:, or delete 'connection' from in:.
mathspec suggests both rewrites. For in: ["connection[bus]"] on
efficiency in the second example, the message is:
Parameter 'efficiency': in: names 'connection[bus]', a map of 'connection', and an index set is a relation. To keep the rows the map gives a label, write where: connection[bus].
A where: on a parameter with an in: narrows the coordinates inside the
index set, and the tool drops the rows outside it, as in step 2. Inside the
index set, the bare name of each relation of the in: is true. So mathspec
refuses a where: that reads one, and names what the where: is left with.
where: connection on efficiency in the first example is always true:
Parameter 'efficiency': in: gives 'efficiency' coordinates only where 'connection' has a row, so `where: connection` narrows nothing. Delete the `where:`, or the relation from it.
A where: that is always false, such as where: NOT connection, leaves the
parameter no coordinate, and mathspec suggests a where: that holds somewhere
inside the relation. For where: "connection AND active", where active is a
bool parameter, the message ends in
`where: connection AND active` repeats the relation. Delete the relation from it.
A test of a map, such as connection[role] == 'output', is not the bare name
of the relation, so it loads.
The typeset legend prints the index set as the domain of the parameter, after
over. For efficiency in the first example, the legend entry starts with
efficiency over \((b, e) \in \mathrm{connection},\ t \in \mathcal{T}\). In
the second example, it starts with efficiency over
\((p, u) \in \mathrm{connection},\ t \in \mathcal{T}\), without the maps.
variables#
A variable is a quantity that the solver decides, with one value per
coordinate of its dims.
dimensions:
generator: { dtype: str }
parameters:
capacity: { dims: [generator] }
variables:
dispatch:
dims: [generator]
where: "capacity > 0"
bounds:
lower: 0
upper: capacity
A where: leaves dispatch only at the generators whose
capacity is above zero. The solver keeps each value between 0 and the
capacity of its generator.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions it is indexed over | |
in |
the relations of its index set (in) |
[] |
where |
which coordinates exist (absence) | null |
bounds.lower / bounds.upper |
a finite number, or the name of a float or int parameter. null leaves that side open |
null |
domain |
continuous, integer or binary. binary has fixed bounds of 0 and 1 |
continuous |
missing |
absent or a finite number: what a coordinate outside the where: means (absence) |
absent |
A bound is never infinite, so an open side is null. mathspec refuses .inf
and -.inf at load, and gives null as the rewrite:
A bound is a name or a number, and not an expression. So upper: capacity is
accepted, and lower: -rating is refused:
Variable 'p' bounds.lower: bounds take a parameter name or a number, not an expression (got '-rating'). Precompute it as a parameter.
mathspec suggests the rewrite: a parameter whose value is -rating.
Equal bounds pin a variable to one value (fix a quantity), and a pinned variable is still a variable.
in on a variable#
A variable takes in: as a parameter does: it exists only where each
relation has a row. In this example, flow exists at the pairs that
connection lists, at every snapshot:
dimensions:
generator: { dtype: str }
bus: { dtype: str }
snapshot: { dtype: int }
relations:
connection: { dims: [generator, bus], missing: absent }
parameters:
load: { dims: [bus, snapshot] }
variables:
flow:
dims: [generator, bus, snapshot]
in: [connection]
bounds: { lower: 0 }
constraints:
balance:
dims: [bus, snapshot]
expression: sum(flow, over=generator) == load
A variable has no data, so nothing is refused, and in: [connection] gives
flow the coordinates that where: connection gives it. mathspec refuses
the same index sets at load as on a parameter, and a where: on the variable
narrows inside the index set. A missing: number stands for the variable
outside its in:, as outside a where:.
mathspec refuses a where: that tests the rows of a relation, as on a
parameter, because in: states them. For where: connection on flow, the
message is:
Variable 'flow': `where: connection` tests the rows of 'connection', which `in:` states. Write `in: [connection]` in place of the `where:`.
For where: "connection AND active", the rewrite is in: [connection], with
active kept in the where:. Under OR or NOT, in: cannot state the
rows, and mathspec suggests a bool parameter in their place. A
map tested alone, such as connection[bus], asks for a
label rather than a row, so it loads.
objective#
The objective is the one number that the solver minimises or maximises. It is a single entry with no name.
dimensions:
generator: { dtype: str }
parameters:
cost: { dims: [generator] }
variables:
dispatch: { dims: [generator] }
objective:
sense: minimize
expression: sum(dispatch * cost)
The solver minimises the total cost of dispatch over every generator.
| Key | What it sets | Default |
|---|---|---|
expression |
required. Arithmetic, with no comparison | |
sense |
minimize or maximize |
minimize |
The expression must be scalar, and mathspec adds no sum for you. Without
the sum, the expression above is over generator:
The objective: the expression carries dims ['generator'], and an objective is one number. Wrap each additive term in its own sum(): `sum(p * cost) + sum(p_nom * capex)`.
mathspec suggests the rewrite, with one sum per term.
sum(x * a) + sum(y * b) and sum(x * a + y * b) are both accepted, and they
state different objectives where x or y is
absent.
A spec has one objective entry, and that entry has one expression, so several
goals are weighted into that expression. A spec composed from several files
also has one objective, which one file sets, and
merge refuses a second one. With
adds_to:, each other file adds its part to a sum that the
objective uses.
A file with no objective states a feasibility problem. The solver then
looks for any decisions that meet every constraint, and minimises nothing.
constraints#
A constraint is a rule that the decisions obey, with one row per
coordinate of its dims. Each key under constraints: declares one
constraint, named by the key.
dimensions:
snapshot: { dtype: int }
generator: { dtype: str }
parameters:
load: { dims: [snapshot] }
variables:
dispatch: { dims: [snapshot, generator] }
constraints:
power_balance:
dims: [snapshot]
expression: sum(dispatch, over=generator) == load
power_balance has one row per snapshot, and each row states that the
generators together meet the load.
| Key | What it sets | Default |
|---|---|---|
dims |
required. The dimensions of its rows | |
expression |
required. A comparison with exactly one of <=, >= or == |
|
where |
which rows exist (absence) | null |
The dimensions of the expression
(how dimensions combine) must
equal the dims of the constraint. With
dispatch == load as the expression above, dispatch is over generator,
which the dims do not list:
Constraint 'power_balance': the expression carries dims ['generator'] that are not in its dims: ['snapshot']. Add them to dims:, or sum them out.
mathspec lists the extra dimension and the dims, and suggests two
rewrites.
At least one side of the comparison must have a variable, so at load mathspec refuses a comparison between numbers and parameters alone:
Constraint 'enough': neither side of the comparison carries a variable, so the row decides nothing.
Got: 'load <= cap'
Name the variable it bounds, or state the fact under `assumptions:`.
mathspec repeats the refused comparison and suggests two rewrites.
dims: [] declares one scalar row, for a rule such as a budget for the whole
system.
A rule that differs by case is two entries, each under
its own where:.
See also
- named expressions, conditions and macros for
expressions:,conditions:andadds_to: - absence and
wherefor the rows that awhere:or a missing row removes - composing specs for what
mergebuilds from given entries missingon a parameter for the result of each value ofmissing: