SERIES

<< Click to Display Table of Contents >>

Navigation:  Gekko User Manual > Gekko statements >

SERIES

Previous pageReturn to chapter overviewNext page

The SERIES (or SER) statement alters timeseries variables (often just called 'series'). Series variables have no starting symbol like % (scalars) or # (collections), but they may include a frequency indicator !, for instance x!q for x in a quarterly version. When Gekko starts up, the default frequency is annual, so x will be understood as x!a. A Gekko series can have annual (a), quarterly (q), monthly (m), weekly (w), daily (d) or undated (u) frequency.

 

Guide: timeseries

For an easier introductory guide on Gekko timeseries, see this page. For an introductory guide on array-timeseries, see this page.

 

Data tracing

Gekko timeseries statements support data tracing, making it possible to trace a series values backwards in time to its origins, see this page.

 

Compatibility note regarding lags:

Since series statements are calculated in a vector-like fashion in Gekko 3.0/3.1.x (in contrast to the Gekko 2.x versions), lags no longer automatically accumulate period-for-period, if the left-hand side variable is present with lags on the right-hand side (lagged dependent/endogenous variable). See more on the help page on dynamic statements. In Gekko versions >= 3.1.7, a statement like for instance = x[-1] + 1 will need to be decorated with an indication regarding whether it should accumulate (<dyn>) or not (<dyn = no>), cf. examples on the linked help page. Note that for absolute accumulations like <dyn> = x[-1] + 1, you may use <d>= 1, ^= 1 or dif(x) = 1 instead (and there are also variants regarding relative accumulations, see below). Note that setting <dyn> (or block series dyn = yes) unnecessarily entails a speed penalty and should therefore not be used unless needed.

 

Gekko has to kinds of timeseries: normal series and array-series. Array-series allow the use of multidimensional indexes, for instance x['a', 'b'], picking out a sub-series with 'a' in the first dimension and 'b' in the second dimension. This could be for instance input-output cells, indicating the providing ('a') and receiving ('b') sector of intermediate goods. Array-series are quite similar to the map collection, but with special capabilities convenient for series data. The sub-series x['a', 'b'], or the shorter notation x[a, b], is internally a normal series. Therefore, an array-series can be thought of as a container that contains a collection of normal series that can be accessed via the indexes.

 

Normal series (including array-subseries) will use the global time setting regarding the time period they are calculated over (cf. TIME), unless a local time period is indicated in the <>-option field.

 

If []-brackets are used to the right of a series variable, for a normal series it may either indicate a date (x[2025] or x[2020q3]) or a lag/lead (x[-2] or x[+1]). For an array-series, the []-index is used to pick out elements, for instance x[a, b]. These may be combined, like x[a, b][2025]. Beware that lags and leads must start with the symbol - or +, respectively, otherwise they are not interpreted as leads (so if %= 1, you must use x[+%i], not just x[%i]). For integer lags like x[-1] or x[-2], you may use the shorter form x.1 and x.2, too.

 

To put values into a series, you can use a list of values on the right-hand side, for instance = 1, -2, 3; (the list of values could also be put inside a parenthesis). If you need to use blank-separated numbers, you can use the data() function, for instance = data('1 -2  3');.

 

If you need to use alias names for series, you can use an #alias list to assign one name to another. Cf. the last part of this help page.

 

Note that a bank-less variable like for instance x on the right-hand side of a SERIES expression may be searched for in other databanks than the first-position databank, cf. the databank search page. Beware that the keys [Tab] or [Ctrl+Space] offer autocompletion on timeseries names (cf. here).

 

 


 

Syntax

 
variable <period operator KEEP=... LABEL=... SOURCE=... UNITS=... STAMP=... DYN  MISSING=...> = expression;
variable[date] = expression;     //updating for one period
variable[indexes] = expression; //array-series

f(variable) = expression;         //left-side function: dif(), pch(), dlog(), log()

series ?;                         //show an overview series count from all open databanks

 

Note: The series keyword known from versions prior to Gekko 3.0/3.1.x is now superfluous. If you prefer to use it, you can still use series <2010 2020> x = ... ; instead of <2010 2020> = ... ;.

 

 

period

(Optional). Local period, for instance 2010 2020, 2010q1 2020q4 or %per1 %per2+1.

operator

The operator can be d, p, m, q, mp, l or dl. See the 'Operators' section below.

KEEP=

If <keep=p> is used, Gekko will keep the growth rate of the left-hand series intact after the period over which the series is updated. For instance, <2020 2025 m keep=p> = 100; will add 100 to x over the period 2020-25. The keep=p setting makes sure that the growth rate of x regarding 2026 and later already existing observations in x is the same as before the update.

 

You may alternatively use <keep=d> in the same manner, to keep absolute changes rather than relative changes. Other keep operators than d or p are not implemented  yet.

LABEL=

(Optional). Label (string) for the series, cf. DOC.

SOURCE=

(Optional). Source (string) for the series, cf. DOC.

UNITS=

(Optional). Units (string) for the series, cf. DOC.

STAMP=

(Optional). Stamp (string) for the series, cf. DOC.

DYN

(Optional). With this option, lagged dependent/endogenous variables like x[-1] in the expression = x[-1] + 1; accumulate over time. Using <dyn> entails a speed penalty, so please do not use if not needed (in this particular case, ^= 1;, <d>= 1; or dif(x) = 1; could be used instead). Using the <dyn> local option, or equivalently putting the expression inside a block series dyn = yes; ... ; end; basically means that the expression is run n times successively, for each observation in the time period. Therefore, the following two are equivalent:

 

Using <dyn>

<2021 2023 dyn> = x[-1] + 1;  //the <dyn> option implicitly runs the expression three times

 

Explicit

<2021 2021> = x[-1] + 1;  //these three lines are equivalent to the use of <dyn> above
<2022 2022> = x[-1] + 1;
<2023 2023> = x[-1] + 1;

 

Starting from Gekko 3.1.7, statements like = x[-1] + 1; must have an indication of whether they are to be run dynamically or not, cf. the page on dynamic statements for much more information on such 'dynamics errors' and how to handle them.

 

If the endogenous variable does not appear lagged on the right-hand side (like x[-1] or some other lag or lag function), running the expression in one go over 2021-23 yields the same result as running it in three tempi. Therefore, <dyn> is a waste of effort in such cases. It is not disallowed to combine <dyn> with time-operators like for instance ^ or <d>, or left-hand side functions like dif(), but such combinations can be rather hard to understand.

MISSING=

(Optional). With <missing = ignore>, SERIES will deal with missing array sub-series and missing data values like GAMS, treating them as zero for sums and mathematical expressions. The following options are set locally and reverted afterwards: option series array calc missing = zero; option series data missing = zero. See also the appendix page on missings.

variable

Left-side name

expression

Any expression

In addition to = (assignment), the following variants can also be used (see the 'Operators' section below):

 

+=  add to existing

-=  subtract from existing

*=  multiply to existing

/=  divide from existing

^=  set absolute time change

%=  set percent time change

#=  add to percent time change

 

 

If no period is given inside the <...> angle brackets, the global period is used (cf. TIME).

If a variable on the right-hand side of = is stated without databank, Gekko may look for it in the list of open databanks (if databank search is active, cf. MODE).

Looping: with a list like for instance #= a, b;, you may use y{#m} = 1/(x{#m}); to calculate ya from xa, and yb from xb.


 

Types of series

 

Normal series

 

Normal series look like the following example:

 

= 100;

 

In that case, 100 is assigned to each observation in the global time period (cf. TIME). Different values for each observation can be assigned like this:

 

time 2021 2023;
= 100, 110, 90;
= (10*10, 113-3, 88+2);  //list with expressions must use parentheses 

 

The right-hand side of the x series in this example is a comma-separated sequence of simple numbers. Beware that if you want to use a sequence of expressions, you must use a list definition (and lists are enclosed in parentheses, cf. the y series above).

 

You may indicate a local time period in the <>-option field:

 

time 2020 2030;
<2021 2023 label='Gekko-variable'> = 100, 110, 90;
series <2021 2023 label='Gekko-variable'> x = 100, 110, 90; //the same: old syntax

 

The local time period overrules the global period. If the three values corresponded to quarters for a quarterly series x, the statement x!= 100, 110, 90; could be used. Alternatively, one could change the global frequency first like this: option freq q; x = 100, 110, 90;. In that case, you do not need to use the frequency indicator x!q explicitly, since !q is added implicitly to x in all places where the frequency is not stated. Note that the example above sets the label of x to 'Gekko-variable' (cf. also DOC).

 

The right-hand side of a series variable can be any legal Gekko expression that evaluates to a series, or anything that evaluates to a list of values of a suitable length. For list values, you may repeat them using rep, for instance = 1, 2 rep 2, 3; is equal to = 1, 2, 2, 3;. The last value in a list may be indicated with rep * which will repeat the item a suitable number of times, if the left-hand side is a series. For instance: <2021 2025> = 1, 2, 3 rep *;, where the series will get values 1, 2, 3, 3, 3 over the period 2021-25.

 

Series names may be composed with {}-curlies, representing characters. For instance:

 

time 2010 2012;
= 100; b = 200; xa = 1; xb = 2;
%= 'b';
#= ('a', 'b'); //or: #i = a, b;
prt <n> {%i}, {#i}, x{%i}, x{#i}; //the elements of #i have 'x' prepended

 

Result (the four PRT arguments are shown in different colors):

 

                    b              a              b             xb             xa             xb 

  2010       200.0000       100.0000       200.0000         2.0000         1.0000         2.0000 

  2011       200.0000       100.0000       200.0000         2.0000         1.0000         2.0000 

  2012       200.0000       100.0000       200.0000         2.0000         1.0000         2.0000 

 

 

Array-series

 

For an easier introductory guide on array-timeseries, see this page. The dimensions of an array-series need to be stated when it is constructed. Afterwards, indexes are used to refer to its elements:

 

= series(2);         //two dimensions
x[a, b] = 100;         //or: x['a', 'b'] = 100;
x[a, o] = 200;         //or: x['a', 'o'] = 200;

 

As seen, you may use the shorter x[a, b] instead of the more strict x['a', 'b'], when the elements are simple names, for instance not containing blanks or special symbols.

 

When dealing with timeseries given in some logical structure apart from time (for instance input-output cells), name composition is often used, for instance using the name convention xab and xao instead of x[a, b] and x[a, o]. Using array-series, there are convenient summing functions like sum(#j, x[a, #j]), summing up the second dimension of the array-series x (for instance, with #j = ('b', 'o'), the index x[a, #j] will correspond to x[a, b], x[a, o]). The same kind of logic can also be implemented with name-conventions, for instance sum(#i, xa{#j}), where xa{#j} will correspond to xab, xao. Still, array-series can be very practical in order to organize timeseries in some non-time structure/dimensions, and an array-subseries like for instance x[a, b] can be used in the same way as a normal timeseries xab. Also, with array-series there is no risk of name-collisions. For instance, x[ab, c] is clearly different from x[a, bc], whereas a simple naming convention will produce the same name, xabc. This can be remedied with, for instance, underscores (x_ab_c vs. x_a_bc), but in that case why not just use array-series?

 

Elements that are simple numbers represented as strings may have values added or subtracted, for instance x[#a+1], where #a could be a list of strings representing ages, like ('18', '19', ..., '80').

 

You may perform simple mathematical operations on array-series without indexes, for instance * x in the above example, being equivalent to p[#i, #j] * x[#i, #j]. Such possibilities (array-series algebra) will be augmented.

 

 


 

Operators and left-side functions

 

The following tables presents the different operators:

 

Type

Operator

Example

Result

Note

Absolute

^=

^= 1200;

= x[-1] + 1200

Same as <d> or dif(x) = 1200;. See also the <dyn> option.

Relative

%=

%= 3.5;

= x[-1]*(1+3.5/100)

Same as <p> or pch(x) = 3.5;. See also the <dyn> option.

Absolute

+=

+= 1200;

= x + 1200

Same as <m>. You can also use -= to subtract values.

Relative

*=

*= 1.03;

= x*1.03

Similar to <q>. You can also use /= to divide with values.

Change in

relative

#=

#= 2.1;

= x[-1]*(x0/x0[-1] + 2.1/100)

Same as <mp>. See also the <dyn> option.

 

In the formula regarding the # operator, x0 is the original timeseries, and x is the new one. Alternatively, the so-called 'short' operators may be used:

 

Type

Option

Example

Result

Note

Absolute

<d>

<d>= 1200;

<dyn> = x[-1] + 1200

Same as ^=. or dif(x) = 1200;. See also the <dyn> option.

Relative

<p>

<p>= 3.5;

<dyn> = x[-1]*(1+3.5/100)

Same as %= or pch(x) = 3.5;. See also the <dyn> option.

Absolute

<m>

<m>= 1200;

= x + 1200

Same as +=. You can also use -= to subtract values.

Relative

<q>

<q>= 3;

= x*(1+3/100)

Similar to *=. You can also use /= to divide with values.

 

Change in

relative

<mp>

<mp>= 2.1;

<dyn> = x[-1]*(x0/x0[-1] + 2.1/100)

Same as #=. See also the <dyn> option.

Log

<l>

<l>= 5;

= exp(5)

Same as log(x) = 5;.

Relative

<dl>

<dl>= 0.035;

<dyn> = x[-1]*exp(0.035)

Same as dlog(x) = 0.035;.

 

 

Left-side functions:

 

Type

Option

Example

Result

Note

Absolute

dif()
diff()

dif(x) = 1200;

<dyn> = x[-1] + 1200

Same as ^= or <d>=. See also the <dyn> option. You may use diff() as synonym.

Relative

pch()

pch(x) = 3.5;

<dyn> = x[-1]*(1+3.5/100)

Same as %= or <p>=. See also the <dyn> option.

Log

log()

log(x) = 5;

= exp(5)

Same as <l>=.

Relative

dlog()

dlog(x) = 0.035;

<dyn> = x[-1]*exp(0.035)

Same as <dl>=.

 

 

 

 


 

Examples, normal series

 

Create a deflated price index (not an existing variable):

 

time 2010 2013;
create p1, p, rp1; //only necessary in sim-mode
p1 = 1.00, 1.12, 1.15, 1.14;
= 1.00, 1.02, 1.04, 1.06;
rp1 = p1/p;
prt rp1;

 

Create a series with a given growth rate:

 

create x;             //only necessary in sim-mode
time 2011 2013;
<2010 2010> = 1;    //uses a local time period
%= 2.5;             //uses x is set to grow with 2.5 percent annually
<p>= 2.5;           //same as above, alternative syntax
pch(x) = 2.5;         //same as above, alternative syntax
prt x;                //grows with 2.5% p.a.

 

Change compared to the reference bank:

 

create x;                           //only necessary in sim-mode
time 2011 2013;
= 1, 2, 3;
clone;                              //Ref bank made as copy of Work bank
<q> = 10;                         //or: x *= 1.10;
prt <n r m q> x;                    //level, ref-value, difference, %difference
prt <n> x, @x, x-@x, 100*(x-@x)/@x; //same info, done manually

 

In the last PRT, @x is short for ref:x, that is, x from the Ref databank.

 

To set for instance a growth rate equal to another growth rate, you can use the <p> operator:

 

<p> = pch(x);  //or: y %= pch(x), or: pch(y) = pch(x), or: y = y[-1] * x/x[-1]

 

To change only one period, you may use:

 

tg[2020] = %v;  //%v is a scalar value

 

This will only set the 2020-value, and will work regardless of what the global sample might be. Used like this, at the same time stating a local period inside the <>-option field is not legal (or meaningful). Note that when using SERIES with []-brackets like this, a scalar value (or expression) is expected on the right-hand side of the equation. The above statement is functionally equivalent to the following:

 

tg <2020 2020> = %v

 

The $-operator can be used to "control" expressions, like an implicit IF-statement. For instance:

 

reset;
#= a, b; %= 10;
y1 = 3 $ ('b' in #m and %== 10);
y2 $ ('b' in #m and %== 10) = 3;

 

In the y1-statement, y will be 3 if the condition is true (if 'b' is a member of #m and %v has the value 10), and else y will obtain the value 0. In the y2-statement, the whole statement is skipped if the condition is false, and in that case y will not exist at all. Note this conceptual difference regarding $-condition to the left of or to the right of =.

 

The $-operator can be used to switch between values inside a period, for instance:

 

reset;
time 2001 2005;
= 10, 10, 11, 12, 10;
y1 = 110 $ (== 10) + 111 $ (<> 10);
y2 = iif(x, '==', 10, 110, 111);

 

The y1-statement illustrates the use of the $-operator for switching, and y1 will contain the numbers 110, 110, 111, 111, 110 (the 10's are replaced with 110, and all other values are replaced with 111). The last y2-statement illustrates how to perform the same operation using the iif() function. The operation could alternatively be performed with FOR and IF statements, looping explicitly over each period, but using the $-operator or the iif() function is much more convenient here.

 

Adding 1000 to a series jx can be done with the + operator, or the <m> option:

 

jx <2010 2010> += 1000;
jx <2010 2010 m> = 1000;  //same result

 

Instead of updating with raw numbers, you may use scalar variables instead (in this case, you have to use parentheses to indicate the list, because the elements are not simple numbers):

 

%f1 = 0.02;
tg <2010 2012> += (%f1, 2*%f1, 0.01);

 

Using a list #m:

 

time 2010 2012;
#= x1, x2;               //or: ('x1', 'x2')
{#m} = 100, 80, 110;
{#m} <2010 2012> *= 1.02;  //x1 and x2 become 2% larger, could also use <q> option
prt {#m};

 

Note that 1.02 is implicitly used for all three periods (you do not need to write (1.02, 1.02, 1.02)). Note also the {}-curlies in {#m} = (100, 80, 110);. Without the curlies, #m would become a list of the three values 100, 80, 110, which is not the intention. In <2010 2012> {#m} *= 1.02;, without the curlies, the expression would fail, since a list does not implement the *= operator. Finally, in prt {#m};, without the curlies, Gekko would print the strings 'x1' and 'x2', not the series x1 and x2.

 

If you use <keep=p>, Gekko will keep the same growth rate in the data, after the time period where the variable is changed.

 

<2007 2007 m keep=p> = 0.01;

 

This way, y has 0.01 added in 2007 (because of the <m> operator), and in all the subsequent years of data, the old growth rate in y is preserved (which is what the keep option does). Note that keep=p updates the series outside of the indicated period.

 

In sim-mode, you must first create a non-existing variable, but if the variable name starts with 'xx', it is automatically created:

 

xxvar = 27;  //works in sim-mode without prior create

 

If convenient, you may also use wildcard lists:

 

{'j*'} <2010 2010> = 0;

 

This sets all variables in the Work databank beginning with j to 0, for the given period.

 

You may set timeseries in other databanks than Work, for instance:

 

bank1:= 100;

 

This will set the variable x to 100 in the bank bank1 (cf. the OPEN statement), provided that the bank is unlocked. If you need to change timeseries in the reference databank, you may use the @-indicator for convenience:

 

@fy *= 1.03;
<q> @fy = 3;  //same

 

This will increase the variable fy in the Ref databank with 3% over the global sample period.

         

 


 

Examples, array-series

 

Array-timeseries comply rather tightly with GAMS syntax, to interface more naturally with GAMS files (gdx). But array-timeseries have many other uses, for instance when downloading multi-dimensional data, or reading data from px-files (PC-Axis), cf. the IMPORT statement.

 

An array-series can be thought of as a super-series, containing sub-series in one or more dimensions, where these sub-series are accessed with (lists of) simple names. For instance, x may be a one-dimensional array-series, containing the sub-series x[a] and x[b]. These sub-series are like any other normal timeseries, just stored inside the array-series. In this sense, x can be thought of as a kind of special map, allowing multiple dimensions, and designed for series access. In older versions of Gekko (prior to 2.3.1), such dimensions would typically be handled by means of naming conventions, for instance using normal series x_a, and x_b instead of x[a] and x[b].

 

You may use single quotes for element access, so x[a] = x['a'], x[b] = x['b'], etc. Using quotes is the strict form, and using quotes, the element names may include any characters, for instance x['ab ? x22'].

 

The following is an example of the use of array-series. In the example, #i and #j are lists of strings containing the sets of names spanning the dimensions, in this case a 3 x 3 structure [#i, #j] like this:

 

[a, a]  [a, b]  [a, o]

[b, a]  [b, b]  [b, o]

[o, a]  [o, b]  [o, o]

 

The last part of the example below illustrates how to use default sets (via the map #default). In order for default sets to work, the array-series must contain domain information.

 

#= a, b, o;                             //or: ('a', 'b', 'o')
#= a, b, o;
#j0 = a, o;
= series(2);                            //two dimension
= series(2);                            //two dimensions
x[#i, #j] = 100;                          //all elements = 100
p[#i, #j] = 2;                            //all elements = 2
prt <n> x;                                //prints all elements of the array-series x, the <n> avoids printing percentage growth
prt <n> p * x;                            //same as p[#i, #j] * x[#i, #j], simple array-series algebra is possible
prt <n> x[a, #j];                         //or: x['a', #j], prints the elements with 'a' in the first dimension
prt <n> x[#i, #j];                        //prints all elements, similar to prt x;
= sum((#i, #j), x[#i, #j]);             //the sum of all elements, y = 900
= sum(#j, x[a, #j] $ (#j in #j0));      //the sum of those #j that are in #j0 (that is, middle column 'b' is skipped), z = 200
x.setdomains(('#i', '#j'));               //domains set, necessary for #default logic
p.setdomains(('#i', '#j'));               //domains set, necessary for #default logic
#default = map();                         //#default is a map type
#default.#= #j0;                        //chose elements of #j to print
prt x;                                    //will omit printing middle column 'b' in set #j
prt <split> x;                            //splits the output
prt x.getelements();                      //elements belonging to each of the 2 dimensions
prt x.subseries('elements');              //element combinations for each of the 9 sub-series

 

The summing up with sum() is sometimes called a 'roll-up operation', aggregating rows/columns, whereas for instance x[a, #j] would be a so-called 'slice operation'. The in-built functions getelements() and subseries() can be practical if you need to know more about the elements of the sub-series of a given array-series x (for instance, the sub-series x[a, b] has element a in the first dimension, and element b in the second dimension).

 

You may $-condition on a variable that reflects sparsity in two or more dimensions, too (you may for instance have 193 countries, where only a subset of all combinations trade with each other). The following example illustrates two-dimensional sparsity:

 

= series(2);
x[a, 10] = 100; x[a, 11] = 101; x[b, 10] = 102; x[b, 11] = 103;
= series(2);
e[a, 10] = 0; e[a, 11] = 1; e[b, 10] = 1; e[b, 11] = 0; //sparsity
#= (('a', '11'), ('b', '10')); //sparsity
#= ('a', 'b');
#= ('10', '11');
y1 = sum((#i, #j) $ (e[#i, #j]), x[#i, #j]); //203
y2 = sum((#i, #j) $ (#e[#i, #j]), x[#i, #j]); //203

 

In y1, the condition is on the array-series e, whereas in y2 it is on the nested list #e (in GAMS, a nested list would correspond to a multidimensional set). You may alternatively move the dollar condition to the right, for instance y1 = sum((#i, #j), x[#i, #j] $ (e[#i, #j]));. Note that array-series are a bit more lenient regarding the user of integers, which are automatically interpreted as their corresponding strings. Also beware regarding the array-series example that there are settings that makes it possible to omit stating the 0 combinations for e, if these are numerous (option series array calc missing = zero), cf. this page.

 

Regarding domains, it is easy to remove a single element from a list of strings with for instance #i.remove(%s), where %s is a string. To remove several elements from a list of strings, you may use #- #j. Hence these $-conditionals can be used for easy removal/skipping of elements:

 

= sum(#j, x['a', #j] $ (#j in #j.remove('b')));
= sum(#j, x['a', #j] $ (#j in #- ('b', 'o')));

 

To print an array-series x1, use either:

 

disp x1;                                         //shows info regarding dimensions, elements, etc.
disp x1[a, b];                                   //shows info for the the sub-series
prt x1;                                          //will print out all elements
prt x1[#i, #j];                                  //prints out the elements in lists #i and #j (combined)

 

If you need non-existing array-timeseries elements to be implicitly understood as having value 0, you can use option series array calc missing = zero;. In that case, you may use for instance sum(#j, x1[#i, #j]), even if some of the combinations (sub-series) of #i and #j do not exist in x1.

 

In general, you may print or plot an array-series without indicating the dimensions. You can assign lists to array-series dimensions and afterwards control which elements are printed/plotted via a special map with the name #default. This can be practical if you typically only want to see some of the elements of an array-series, but not all.

 

#= ('e1', 'e2');
= series(1);                   //array-series with 1 dimension
a[#s] = 100;                     //sets a[e1] = a[e2] = 100
a.setdomains(('#s',));           //assigns #s to dimension 1 of the array-series
<n> a;                         //prints a[e1] and a[e2]
#default = map();                //defines map #default and puts it in the global databank
#default.#= ('e1',);           //or in one line: #default = (#s = ('e1',))
<n> a;                         //now, because of #default, only a[e1] is printed

 

It can often be practical to put the #default map into the Global databank (that is: global:#default = ...), so that it is generally available irrespective of potential OPEN or READ statements. The #default map shown above will restrict all printing/plotting of array-series that have #s assigned to a dimension as its domain.

 

If you need to put "normal" timeseries into an array-series or vice versa (or if you are interfacing with multidimensional GAMS/gdx data), you can use the following example:

 

reset;                   
x1 = 1; x2 = 2;          //create some data here
index * to #m;           //put all series names into the list #m
= series(1);           //define an array-series with 1 dimension
x[#m] = {#m};            //put the normal series into the array-series
prt x;                   //print the 2 elements of x, try also "disp x;"
delete x1, x2, #m;       //delete everything except x
#= x.getelements()[1]; //get the elements of dimension #1 of x
{#m} = x[#m];            //recreate the normal series from the array-series
prt x1, x2;              //print the normal series

 

 


 

Alias names

 

It is possible to assign one variable name to another via a special list with the name #alias. This can be practical if, for instance, the users are used to one kind of variable names, but are for instance using a model with another kind of variable names.

 

option interface alias = yes;            //this option must be set
global:#alias = #(listfile alias);       //reads alias.lst from file
= series(1); c[a] = 100; c[b] = 200;
= 300; 
prt x1, x2,  x3;

 

The #alias list could look like the following file:

 

--------------- alias.lst --------------------
x1; c[a]
x2; c[b]
x3; y
----------------------------------------------

 

This file is read as a list of lists, equivalent to #alias = (('x1', 'c[s]'), ('x2', 'c[b]'), ('x3', 'y'));. The print prints out x1, x2, and x3 as 100, 200, and 300, respectively, even though the 'real' values are stored inside c[a], c[b], and y.

 

 


 

Details, x = x[-1] + ... type, and <dyn> option

 

In Gekko 3.0, series operations are handled more vector-like than in Gekko 2.x. This affects the use of lags in expressions with lagged dependent/endogenous variable:

 

time 2021 2024;
= 100;
time 2022 2024;
= x[-1] + 1;  //ERROR: will fail with a dynamics error
<dyn = no> = x[-1] + 1;  //result: 101, 101, 101
<dyn> = x[-1] + 1;  //result: 101, 102, 103

 

The last statement is  probably easy enough to understand, but the second-last may seem strange. See much more on this, including illustrations, on the dynamic statements page. There are three easy ways of getting accumulations to work without using the <dyn> tag:

 

time 2021 2024;
= 100;
time 2022 2024;
^= 1;     //result: 101, 102, 103
<d>= 1;   //result: 101, 102, 103
dif(x) = 1; //result: 101, 102, 103

 

Still, in some cases it my be practical to be able to use the formulation = x[-1] + 1 and have it accumulate, for instance if the equation originates from a model equation. For such cases, either use the local option <dyn>, or alternatively use a BLOCK like block series dyn = yes; ... ; end;. Example:

 

time 2021 2024;
= 100;
time 2022 2024;
<dyn> = x[-1] + 1;     //result: 101, 102, 103
block series dyn = yes;
  x = x[-1] + 1;         //result: 101, 102, 103
end;

 

To guard against errors of this type where the user forgets to use <dyn> or a block series dyn on an expression like = x[-1] + 1, from version 3.1.7 and onwards, Gekko will check this for the presence of lagged dependent/endogenous variables on the right-hand side and issue a 'dynamics error' if an expression like = x[-1] + 1 or similar is used without considering the dynamics question. As stated above, there is much more info on this on the dynamic statements page.

 

 

 


 

Note

 

See the page with syntax diagrams if the basics of names, expressions, etc. is confusing.

 

In addition to operators += and *=, you can also use their inverse counterparts: -= and /=. So -= 2; is the same as = x - 2;, and /= 2; is the same as = x / 2;. This is standard in most computer languages. But please note that ^= 2; is not the same as = x ^ 2;, that is, x in the second power.

 

If any of the right-hand side variables are not found (searching depends upon mode), the statement will exit with an error, unless you set option series array calc missing = ...; or option series normal calc missing = ...;. If some of the variables have missing values (shown as 'M' when printing), the left-hand side will become missing as well (for the periods affected).

 

You may use m() to indicate a missing value, for instance = m();.

 

Regarding $-conditions to the right of =, these always evaluate to 0 if the condition is false. On the other hand, regarding a $-condition to the left of =, the whole statement is skipped if the condition is false. Note however that such skipping does not apply intra-series regarding $ to the left of =. So in a statement like y $ (> 100) = 2 * x; the y series will attain the value 0 in the periods where <= 100, and the value * x otherwise. If you need y to remain untouched when <= 100, you may instead use = iif(x, '>', 100, 2 * x, y);, cf. the iif() function.

 

Regarding variable types and the Gekko type system, see the VAR section. In this appendix, variable assignment rules, including variable types, is explained in more detail.

 

A Gekko array-series can be though of as a nested dictionary/map, cf. this:

 

Gekko: = series(2); m[a, x] = 1; m[a, y] = 2; m[b, x] = 3; m[b, y] = 4; prt m[a, x];

R: nested named list, <- list(= list(= 1, y = 2), b = list(= 3, y = 4)); print(m$a$x); print(m[['a']][['x']]);The elements here are numbers and not sub-series, but the idea is similar.

Python: nested dict.

 

 


 

Related options

 

OPTION freq = a; [a|q|m|d|u]

OPTION databank create auto = no; [yes|no]

OPTION series array calc missing = error; [error|m|zero]

BLOCK series dyn = no; [yes|no]. This option can only be set using a block

OPTION series dyn check = yes; [yes|no]

OPTION series normal calc missing = error; [error|m|zero]

 


 

Related functions

 

For array-series: getdomains(), subseries().

 


 

Related statements

 

CREATE, DOC, PRT, VAL, EXPORT<gcm>, EXPORT<flat>