Subranges

A subrange is a dimension that is defined using elements that are all part of another dimension. For example, if there is a dimension Store, with elements Downton, Glendale, Landsdown, Whyte then a subrange would be the dimension StoreWithBakery with elements Downtown, Landsdown. Nothing is required to specify that StoreWithBakery is a subrange of Store - the software can determine that from the names of the elements. However, because StoreWithBakery is subrange, you easily combine equations using Store and StoreWithBakery without having to create detailed equations relating the two.

Subranges do not need to be contiguous elements in the full range, nor do they need to be in the same order. For example, defining BackStore as Whyte, Landsdown, Glendale, Downtown could be used to reverse element order. In this case BackStore is a subrange of Store, and Store is a Subrange or BackStore (and StoreWithBakery is a subrange of both).

Note The purpose of subranges is to simplify equations. Sticking to a naming convention will also help make them clear.

Using arrays defined by the parent dimension

If you have variables that are applicable only to a subset of the elements in a dimension, you can define a subrange of that dimension and use that subrange as the dimension for the variables. For example, anything related to baking might use the dimension StoreWithBakery instead of Store.

If you created the dimensions and equations this way, and want to use a variable arrayed by the full dimension in an equation arrayed by the subrange, you can do it by using the variable name and then the subrange name in brackets.

For example, suppose sales is arrayed by [Product, Store] you might have

planned_production[BakedProduct,StoreWithBakery] = sales[BakedProduct,StoreWithBakery]

Here BakedProduct is a subrange of Product, and StoreWithBakery is a subrange of Store. The above equation will appropriately select the correct elements of Product and Store to defined planned_production. This is done by matching the names of the different elements, and is the same as creating a non-apply-to-all set of equations with:

planned_production[Bread,Downtown] = sales[Bread,Downtown]

planned_production[Bread,Landsdown] = sales[Bread,Landsdown]

planned_production[Roll,Downtown] = sales[Roll,Downtown]

planned_production[Roll,Landsdown] = sales[Roll,Landsdown]

planned_production[Croissant,Downtown] = sales[Croissant,Downtown]

planned_production[Croissant,Landsdown] = sales[Croissant,Landsdown]

Using the subrange, in this case, both simplifies the writing of the equations, and allows you to keep the equation even when you make changes to the definitions of the dimensions involved.

To use a subrange in an equation, that subrange must be a dimension of the variable being defined (just as with any range). The ability to use that subrange in a variable that has the full range (or a bigger subrange) of the dimension is what is distinct.

To use variables with different dimensions, you must explicitly use the subrange. The equation

sales

for example would be invalid because sales is not arrayed by [BakedProduct,StoreWithBakery].

Using arrays defined by the subrange dimension

Continuing with the above example suppose that we are trying to determine utility costs at the stores, but that baking_utilties has been computed only for StoreWithBakery. We can still use it in the equation for utility_cost as in

lighting_cost[Store]+heating_cost[Store]+refrigeration[Store]+baking_utilities[Store]

For Downtown baking_utilities would be added to utility_cost sine Downtown is an element of StoreWithBakery. For Whyte, however, there is no match - so the software treats this as an invalid element index which by convention returns 0. Thus the aboe equation works for all stores without needing to write separate equations for each dimension of complex IF THEN ELSE logic.

You can apply this same logic inside of array expressions. For example total_sales across stores might be

SUM(produce_sales[*,Product]) + SUM(cheese_sales[*,Product]) + SUM(bakery_sales[*,Product])

where each of produce_sales, cheese_sales and bakery_sales is defined only for a subrange of Product. In this case those subranges would not overlap, but they could if it made sense.

Using Subranges in Array Builtins

When you use an array builtin such as SUM, you can specify the elements in the array to sum over by using *, a:b, or *:subrange as detailed in Specialized Array Manipulation. For example

sales_in_stores_with_bakery[Product] = SUM(sales[Product,*:StoreWithBakery])

would give the sales for all products (not just baked goods) in the stores that have bakeries. Because elements in the subranges do not need to be contiguous, this is much more flexible than using the a:b notation.

Writing Multiple Equations and Shifting Elements in Arrays

There are two potential uses of subranges that are not currently supported in Stella.

The first is the ability to write multiple equations and divide those equations up by subranges. Currently in Stella, there is either a single equation for all array elements, or one equation for each array element. In order break up definitions it is most effective to use IF THEN ELSE logic. For example

IF Store = Downtown OR Store = Landsdown THEN standard_va[Store]*bakery_adjustment ELSE standard_val[Store]

As long as there are not too many cases, this equation format is generally more readable than defining every element independently. It does, however, require that the equation be changed if the dimension definitions change (as would a non-apply-to-all set of equations).

The second potential use of a subrange is the mapping of elements in the same array. This will probably not ever be suported in Stella as it adds complexity and in most situations simply using an equation for the element value is all that is required. For example,

aging_in[Country,Sex,Age] = IF Age = A0 THEN 0 ELSE aging_out[Country,Sex,Age-1]

The IF THEN ELSE Logic is not actually needed in the above equation, since by convention the reference to an invalid array element returns 0, but it can be helpful for clarity. Using this type of array adjustment will work for most cases were a subrange mapping might have been used.