3.10. Interpretation of map_variables
elements¶
For the purposes of this specification, the conceptual “variable equivalence network” SHALL be an undirected graph with one node for every
variable
element in the CellML model.The arcs of this graph SHALL be equivalences defined in the CellML model.
See more
Understanding the terminology
The idea of component modularity and separateness is helpful in organising models and reusing parts of them, but only if it’s also possible to share information between the distinct components.
This is the goal of “variable equivalence”, and requires the combined mechanisms of connection
elements (to connect components) and map_variables
elements (to connect their variables).
Several different words have been used to describe what is essentially this one process: equivalent variables, the connected variable set, mapped variables, etc.
All of these mean the same thing: that the variables in the set act as a single agent throughout the model.
They may have different local names within a component, but they will have the same value everywhere they exist.
Thus there are two ways in which variables are related to one another.
The first is through the mathematical equations as specified in intra-component math
elements; the second is through variable equivalences as specified in inter-component connection
and map_variables
elements.
Both the connection
and map_variables
elements are undirected.
There is no update direction or hierarchy; they all represent, instantaneously, the same thing.
For each
map_variables
element present in the CellML model, we define variables A and B for use in the rules in this section as follows:Variable A SHALL be the variable referenced by the encompassing
connection
element’scomponent_1
and thismap_variables
element’svariable_1
attribute; andVariable B SHALL be the variable referenced by the encompassing
connection
element’scomponent_2
and thismap_variables
element’svariable_2
attribute.
For every
map_variables
element present in the CellML model, there SHALL be an arc in the variable equivalence network.One endpoint of the arc in the variable equivalence network SHALL be the node corresponding to variable A; and
One endpoint of the arc in the variable equivalence network SHALL be the node corresponding to variable B.
See more
Understanding the players
You can think of the previous two points as defining an address using a street name and number.
Since streets (components) have lots of houses (variables) they all need different numbers (variable names) in that street.
And since lots of streets (components) have houses (variables) with the same number (name), we need both the street name and the house number in order to locate a house properly.
This is the purpose of the component_1
and component_2
attributes of connection
elements (to define the respective street (component) names), and the variable_1
and variable_2
attributes of each connection
element’s map_variables
element (to define the respective house number (variable name)).
Thus the “equivalent variable network” is a collection of unique variables (each specified a component and a variable name), which will be treated as the same variable throughout the model.
Note that we use the term “network” here as it best describes the process by which variable equivalence is constructed, even if its final interpretation is not a network, but rather a set.
CellML models MUST NOT contain any pair of
map_variables
elements which duplicates an existing arc in the variable equivalence network.The variable equivalence network MUST NOT contain any cycles.
See more
Understanding the rules
As well as the syntax definitions above, there are rules regarding which variables are able to be connected to one another too.
Both points 3.10.4 and 3.10.5 address a similar issue: that the “network” of variable equivalence must not contain any cycles (a connection such that A-B-A is just a mini cycle after all).
In the model below there are three sets of variables which have equivalent values, and it is the modeller’s desire that they be able to use them interchangably in each language whilst maintaining their value throughout. There are two situations which would render the model invalid if these variables were mapped incorrectly, as shown below.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een
│ ├─ variable: twee
│ ├─ variable: drie
│ └─ variable: vier
├─ component: Maori
│ ├─ variable: tahi
│ ├─ variable: rua
│ ├─ variable: toru
│ └─ variable: wha
└─ component: French
├─ variable: un
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<model name="LearningToCount">
<component name="Dutch">
<variable name="een" />
<variable name="twee" />
<variable name="drie" />
<variable name="vier" />
</component>
<component name="Maori">
<variable name="tahi" />
<variable name="rua" />
<variable name="toru" />
<variable name="wha" />
</component>
<component name="French">
<variable name="un" />
<variable name="deux" />
<variable name="trois" />
<variable name="quatre" />
</component>
</model>
Firstly, duplicated connections are not permitted because they create a mini-cycle of two variables. If an Anglophone is given a definition of een to mean tahi, and tahi to mean een, they are none the wiser.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een <╴╴╴┬╴╴╴┐
│ ├─ variable: twee ╷ ╷
│ ├─ variable: drie duplicate mapping
│ └─ variable: vier causes a mini-cycle
├─ component: Maori ╵ ╵
│ ├─ variable: tahi <╴╴┴╴╴╴┘
│ ├─ variable: rua
│ ├─ variable: toru
│ └─ variable: wha
└─ component: French
├─ variable: un
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<!-- Valid: First define the two components using a connection ... -->
<connection component_1="Dutch" component_2="Maori">
<!-- ... and then define the mapping between two variables within
those two components. -->
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<!-- Invalid: Duplicated mappings are not allowed. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<!-- Invalid: Duplicated connections are not allowed. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<connection component_1="Maori" component_2="Dutch">
<map_variables variable_1="tahi" variable_2="een" />
...
</connection>
Secondly, any form of cyclical definition is invalid, as it leaves the mathematical model underdefined. So our Anglophone could be also told that drie means trois, trois means toru, and toru means drie, but unless one of them is nailed down to an actual value somewhere, the model remains under-defined.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een <╴╴╴╴┐<╴╴╴╴╴╴╴╴┐
│ ├─ variable: twee ╷ ╷
│ ├─ variable: drie cycle created
│ └─ variable: vier ╷ ╷
├─ component: Maori ╷ ╷
│ ├─ variable: tahi <╴╴╴┘<╴╴╴┐ ╷
│ ├─ variable: rua ╷ ╷
│ ├─ variable: toru ╷ ╷
│ └─ variable: wha ╷ ╷
└─ component: French ╷ ╷
├─ variable: un <╴╴╴╴╴╴╴╴╴╴┘<╴╴╴┘
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<!-- Invalid: a cycle is created. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<connection component_1="Maori" component_2="French">
<map_variables variable_1="tahi" variable_2="un" />
...
</connection>
<connection component_1="French" component_2="Dutch">
<map_variables variable_1="un" variable_2="een" />
...
</connection>
For a given variable, the “available interfaces” SHALL be determined by the value of the
interface
attribute on the correspondingvariable
element as follows:A value of
public
specifies that the variable has a public interface;A value of
private
specifies that the variable has a private interface;A value of
public_and_private
specifies that the variable has both a public and a private interface;A value of
none
specifies that the variable has no interface; orIf the
interface
attribute is absent, then the variable has no interface.
The “applicable interfaces” for variables A and B in components AA and BB respectively SHALL be defined as follows:
When component AA is in the sibling set of component BB (and vice versa), the applicable interface for both variables A and B SHALL be the public interface.
When component AA is in the encapsulated set of component BB, the applicable interface for variable A SHALL be the public interface, and the applicable interface for variable B SHALL be the private interface.
When component BB is in the encapsulated set of component AA, the applicable interface for variable B SHALL be the public interface, and the applicable interface for variable A SHALL be the private interface.
Note
For the avoidance of doubt, if components AA and BB are in each other’s hidden set, then there are no applicable interfaces for the variables A and B.
CellML models MUST only contain
map_variables
elements where the applicable interfaces for both variables are available.
See more
Understanding mappings and units
The only place in which valid units
items can cause a model to be invalid is between mapped variables.
Point 3.10.6 means that each variable within a map_variables
element must have an equivalent unit reduction.
Please see that section for more details.
For each
map_variables
element present in the CellML model, the variable unit reduction (see 3.7 Effect of units on a variable) of variable A MUST have an identical set of tuples to the variable unit reduction of variable B.Two sets of tuples SHALL be considered identical if all of the tuples from each set are present in the other, or if both sets are empty.
Two tuples are considered identical if and only if both the unit name and exponent of each tuple are identical.
Tuples differing by a multiplying factor in their unit reduction MUST be taken into account when interpreting the numerical values of the variables (see 3.3 Interpretation of units elements).
See more
Understanding interfaces
There are two hurdles to get past before variables can be mapped to one another.
The first is the relative position within the encapsulation hierarchy of the variable
elements’ parent component
elements (as discussed in 3.9 Interpretation of encapsulation elements, and the second is the value of the interface_type
attribute given to each variable
itself.
This means that even if two components are sufficiently close relatives that they can be connected, the modeller still has control at the individual variable level as to which of those relatives can have access.
The interface_type
attribute value choices are:
- public
(used by child components to reference their parent, or between siblings),
- private
(used by parent components to reference their children),
- public_and_private
(used when both the public
and private
interfaces are required), or
- none
, which is the default.
Which one(s) of these are deemed applicable for any variable
mapping is determined by the relationship between the their parent component
elements.
In the example below, Christopher Robin must assemble an average score of the mood of all of his friends in the Hundred Acre Wood.
He does not have access to all of their mood
scores directly, so must use mapped variables in order to create the average.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood
│ ├─ variable: average_mood_of_everyone
│ ├─ variable: roos_mood
│ ├─ variable: kangas_mood <╴╴╴╴╴┐
│ ├─ variable: eeyores_mood <╴╴╴┐╷
│ └─ variable: poohs_mood <╴╴╴╴┐╷╷
│ ╷╷╷
│ connections between these
│ components are possible, depending
│ on the variables' interfaces
│ ╵╵╵
├─ component: WinnieThePooh ╵╵╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴┘╵╵
├─ component: Eeyore ╵╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴╴┘╵
└─ component: Kanga ╵
│ ├─ variable: mood ╴╴╴╴╴╴╴╴╴╴┘
└─ component: Roo
└─ variable: mood ╴╴╴╴╴╴╴╴╴╴> This variable cannot be connected to
anything within the ChristopherRobin
component as its component is too distant.
At present, the connections above in dashed lines are possible, as long as the variables have interface types which support them.
One connection is not possible (yet): Christopher Robin doesn’t know Roo’s mood, because their components are too distant (grandparent/grandchild) to be directly connected.
We can add a utility variable roos_mood
to the Kanga
component in order to pass along its value to the ChristopherRobin
component.
We’ll also add interface types to the variables, and discuss their effects below.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood
│ ├─ variable: average_mood_of_everyone
│ ├─ variable: roos_mood (interface: public) <╴╴╴╴╴ D ╴╴╴╴╴╴╴╴╴╴╴╴┐
│ ├─ variable: kangas_mood (interface: none) <╴╴╴╴╴ C ╴╴╴╴┐ ╷
│ ├─ variable: eeyores_mood (interface: public) <╴╴ B ╴╴╴┐╷ ╷
│ └─ variable: poohs_mood (interface: public) <╴╴╴╴ A ╴╴┐╷╷ ╷
│ ╷╷╷ utility variable added so
├─ component: WinnieThePooh ╷╷╷ that Roo's mood can be passed
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷ down to Christopher Robin
├─ component: Eeyore ╷╷ ╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷ ╵
└─ component: Kanga ╷ ╵
│ ├─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵
│ └─ variable: roos_mood (interface: private) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┤
└─ component: Roo ╷
└─ variable: mood (interface: public) ╴╴╴╴╴╴ E ╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="TheHouseAtPoohCorner">
<!-- Defining the components and local variables. -->
<component name="ChristopherRobin">
<variable name="my_mood" interface_type="none" units="mood_score" />
<variable name="average_mood_of_everyone" interface_type="none" units="mood_score" />
<variable name="roos_mood" interface_type="public" units="mood_score" />
<variable name="kangas_mood" interface_type="none" units="mood_score" />
<variable name="eeyores_mood" interface_type="public" units="mood_score" />
<variable name="poohs_mood" interface_type="public" units="mood_score" />
</component>
<component name="WinnieThePooh">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Eeyore">
<variable name="mood" units="mood_score" />
</component>
<component name="Kanga">
<variable name="mood" interface_type="public" units="mood_score" />
<!-- The utility variable roos_mood is included here so that it can pass
the value of mood in component Roo to roos_mood in component ChristopherRobin. -->
<variable name="roos_mood" interface_type="private" units="mood_score" />
</component>
<component name="Roo">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<!-- Defining connections and mapped variables. -->
<connection component_1="ChristopherRobin" component_2="WinnieThePooh">
<!-- Mapping A -->
<map_variables variable_1="poohs_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Eeyore">
<!-- Mapping B -->
<map_variables variable_1="eeyores_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Kanga">
<!-- Mapping C -->
<map_variables variable_1="kangas_mood" variable_2="mood" />
<!-- Mapping D -->
<map_variables variable_1="roos_mood" variable_2="roos_mood" />
</connection>
<connection component_1="Kanga" component_2="Roo">
<!-- Mapping E -->
<map_variables variable_1="roos_mood" variable_2="mood" />
</connection>
</model>
Mapping A is valid. The sibling components
WinnieThePooh
andChristopherRobin
havepublic
interfaces between theirmood
andpoohs_mood
variables respectively. This follows point 3.10.9.1 and is valid.Mapping B is not valid. By default an interface type is
none
, and since themood
variable in componentEeyore
does not specify one, no mappings are permitted. For that connection to exist, themood
variable must have an interface typepublic
.Mapping C is not valid. The variable
kangas_mood
has explicitly specified that no mappings are possible by using thenone
interface type. For this mapping to be valid, the type needs to bepublic
.Mapping D is not valid. Because they are sibling components, the variables in
ChristopherRobin
andKanga
must both have the interface type ofpublic
in order to be valid … but there’s a twist.Mapping E is currently valid, because variables in component
Kanga
can only access variables in its child componentRoo
with aprivate
interface. But if Mapping D is to be made valid, that same variable must maintain apublic
interface in order to access variables in its sibling componentChristopherRobin
. It is for this reason that thepublic_and_private
interface type exists. For Mappings D and E to be valid, the variableroos_mood
in componentKanga
must have an interface type ofpublic_and_private
.
The corrected model is shown below.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood (interface: none)
│ ├─ variable: average_mood_of_everyone (interface: none)
│ ├─ variable: roos_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
│ ├─ variable: kangas_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷
│ ├─ variable: eeyores_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷╷
│ └─ variable: poohs_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷╷╷
│ ╷╷╷╷
├─ component: WinnieThePooh ╷╷╷╷
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷╷
├─ component: Eeyore ╷╷╷
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷
└─ component: Kanga ╷╷
│ ├─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴ ╴╴╴╴┘╷
│ └─ variable: roos_mood (interface: public_and_private) <╴╴╴┤
└─ component: Roo ╷
└─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="TheHouseAtPoohCorner">
<!-- Defining the components and local variables. -->
<component name="ChristopherRobin">
<variable name="my_mood" interface_type="none" units="mood_score" />
<variable name="average_mood_of_everyone" interface_type="none" units="mood_score" />
<variable name="roos_mood" interface_type="public" units="mood_score" />
<variable name="kangas_mood" interface_type="public" units="mood_score" />
<variable name="eeyores_mood" interface_type="public" units="mood_score" />
<variable name="poohs_mood" interface_type="public" units="mood_score" />
</component>
<component name="WinnieThePooh">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Eeyore">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Kanga">
<variable name="mood" interface_type="public" units="mood_score" />
<!-- The utility variable roos_mood is included here so that it can pass
the value of mood in component Roo to roos_mood in component ChristopherRobin. -->
<variable name="roos_mood" interface_type="public_and_private" units="mood_score" />
</component>
<component name="Roo">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<!-- Defining connections and mapped variables. -->
<connection component_1="ChristopherRobin" component_2="WinnieThePooh">
<map_variables variable_1="poohs_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Kanga">
<map_variables variable_1="kangas_mood" variable_2="mood" />
<map_variables variable_1="roos_mood" variable_2="roos_mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Eeyore">
<map_variables variable_1="eeyores_mood" variable_2="mood" />
</connection>
<connection component_1="Kanga" component_2="Roo">
<map_variables variable_1="roos_mood" variable_2="mood" />
</connection>
</model>
The
variable
elements in a CellML model SHALL be treated as belonging to a single “equivalent variable set”.Each set of equivalent variables is the set of all
variable
elements for which the corresponding nodes in the variable equivalence network form a connected subgraph.Each set of equivalent variables represents one variable in the underlying mathematical model.
See more
Understanding mathematics
In an episode of Bill Watterson’s comic, Calvin and Hobbes, Calvin builds a duplicator machine and clones himself several times so that the clones can do his chores in different rooms of the house.
This is essentially the purpose of creating map_variables
elements: to enable the “clones” (the mapped variables) to be used in separate “rooms” (components) whilst really representing the same thing.
The first sentence in 3.10.11 explains this: Each variable
element in a CellML model SHALL be treated as belonging to a single “connected variable set”; or, while there are many “connected variable sets” in a model, any one variable
may belong to only one of them.
In a CellML model there are two mechanisms by which variables can relate to one another: through the mathematics in the math
elements, and through the mapping in the map_variables
elements.
In a mathematical model, there is only one mechanism: the maths itself.
There are no clones, no duplicates, no mappings.
Thus, the purely mathematical model is found by collapsing each set of mapped variables (cloned characters) onto a single unique variable (character), until the relationships between these unique variables no longer involve mapping (cloning) but only mathematics. In the end, Calvin does the same, and the world returns to (roughly) normal.