You are here

Working with equations : Arrays and lists

Arrays and lists

Arrays are data structures that consist of more than one element. Each element of the array may be:

  • a scalar: a single real, integer or Boolean value; or
  • an array or list: thus arrays and lists can be nested (to any depth).

Arrays can be created either automatically (when required) or by the user.

Lists are data structures that consist of zero or more elements, and can only be created automatically. Lists are created when values from a population submodel, conditional submodel or other variable-membership submodel are used outside the submodel itself.

Referring to arrays and lists

An array variable is denoted by enclosing the variable's name in square brackets. Thus, [weight] represents an array of one or more weights. This is a one-dimensional array (a vector), because the variable name is enclosed in a single pair of square brackets. By contrast, [[weight]] is a two-dimensional (rectangular) array of weights. This could be used to represent, for example, the weight of each of 10 varieties of fruit (orange, apple, banana, etc) in each of 20 samples.

Note that the size of the array (also known as its dimensions) is not referred to when the array is used in equations. The dimensions are shown in dimensions field of the equation dialogue box.

An list variable is denoted by enclosing the variable's name in curly brackets. Thus, {weight} represents a list of zero or more weights.

How arrays are made

There are three ways in which an array can appear in a model.

  1. An influence arrow might be drawn from a variable inside a fixed-membership, multiple-instance submodel to a variable outside the submodel. As soon as the influence crosses the submodel boundary, what was referred to as a scalar variable inside the submodel becomes an array outside it, since there is now a fixed set of values (one for each submodel instance).
  1. The user might build an array inside the equation dialogue for a variable by explicitly listing all the elements of the array. Thus, if you enter [2,4,6,7] in the equation dialogue for a variable, then its value becomes the array consisting of these four values. Note that the square bracket notation has two quite different interpretations. When the square brackets enclose the name of a single variable, then it is understood that this variable is an array. When the square brackets enclose more than one values, then it is understood that the whole structure is an array. This difference is illustrated by the following examples: (a) [weight] and (b) [weight, height]. The first is referring to an array called weight (which could have any number of values). The second is defining an array with two elements, the scalar variable weight and the scalar variable height. The latter has just two elements.
  1. The user might use the makearray(…) function. This is called explicit replication.

Processing arrays

Arrays can be processed in a number of ways.

  1. You can use a function that is expecting an array as an argument. For example, the function sum(…) will sum the elements of an array.
  1. You can use arrays in mathematical expressions. Simile has powerful built-in methods for calculating with array variables which totally avoid the need for looping structures for calculating with arrays. For example, the expression: [k]*[weight] where both arrays have the same number of elements, returns an array with each element equal to the corresponding value of [k] multiplied by the corresponding value of [weight].
  2. You can also combine scalar values with arrays in expressions. In this case, the result has the same dimensionality as the array, with the scalar value being used the same way for each element. For instance, 2 + [3,4,6,7] = [5,6,8,9]. This is called implicit replication.
  3. Similarly you can combine arrays of different dimensionalities (but not different dimensions), e.g., a 3-element array with a 3x2-element array. What happens is that the function is applied separately to each corresponding set of elements in the argument arrays, and the results combined to give the result array.
  4. You can extract particular values from an array. The function element(array,i) returns the i'th element from the array. Thus: element([2,4,6,3],2) returns the value 4 (being the second element of the array).

Array-valued components

If a component's equation evaluates to an array, the component will be displayed with a repeated border as shown above, to indicate a stack of different values. An influence from that component to another will allow the array to be used in the destination component's equation in any of the ways described above. The number of layers in the stack indicates the outermost dimension of the array, up to a maximum of four. Only compartments, variables and flows can have array values.

How lists are made

There is only one way in which a list can appear in a model: by having an influence arrow coming out of a submodel with a variable number of instances. This means:

  • a population submodel;
  • a relation (association) submodel; or
  • a conditional submodel.

As of Simile v6.1 an influence arrow within a special-purpose submodel can be set to deliver values from 'neighbour' components, which form a list as some instances have more neighbours than others.

Processing lists

Lists can be used in functions and operators along with scalar values or other lists with the same member ids (e.g., from another variable in the same submodel). The rules for combining scalars and lists are similar to those for combining arrays as described above. Lists must be processed as soon as they appear in the variable outside the submodel which receives an influence arrow from a variable inside it. You cannot have a variable whose value is a list or array of lists. Rather, you must perform some legitimate list-processing operation, such as using the function sum(…) to sum the values of the list, so the variable's value is a scalar or fixed array.

As of Simile v6.1 the 'element()' function can be used to extract a sublist from a list, but the result is still a list, so some aggregating function must be applied to it when creating a component value from it.

More about Replication

In many cases, it is obvious how implicit replication will be applied when combining values with functions or operators. If one is scalar, then whatever the dimensions of the other, the result will have those dimensions. But what if the values are arrays with different nestings? If we add a 1-D array to a 2-D array, the result will be a 2-D array -- but how will the values of the 1-D array be shared out?

What happens is, the elements of the lesser-dimensional array are assigned to the elements of the higher-dimensional array with the same outer indices. For instance, [[1,2],[3,4]] + [10,20] is [[11,12], [23,24]] and not [[11,22], [13,24]]. Effectively the second argument is replicated from [10,20] to [[10,10], [20,20]]. Another way of looking at the same process is to imagine that the arguments are separated into groups, then the function applied to each group and the results combined back into arrays. So, [[1,2],[3,4]] + [10,20] becomes [ [1,2] + 10, [3,4] + 20 ].

The easiest way to remember how it is done is to learn the reason for it being that way, which is as follows: a modeller might wish to get either of the two possible results above, depending on the needs of their model. If they want the second case, they can be sure of getting it by using the makearray() function on the second argument, so they are actually adding [[1,2],[3,4]] and [[10,20], [10,20]] which have the same dimensions. However, if they want the first case, it would be more complicated to arrange it using such explicit replication, so to make things simpler, that is how implicit replication works.

In: Contents >> Working with equations