|
<< Click to Display Table of Contents >> More about syntax |
![]() ![]()
|
Below, some of the main concepts of the Gekko 3.x syntax are explained in more detail. The descriptions in this section are quite advanced. So as mentioned before, for new users it is perhaps better to read the easier to understand Gekko guides, for instance starting out with reading the elevator pitch, and then moving on to the Data Management User Guide, perhaps followed by the Modeling User Guide.
See the page with syntax diagrams if the basics of names, expressions, etc. is confusing.
Banks, symbols, names, frequencies, indexes
A variable may be referred to in the following way:
bank + : + symbol + variable + ! + freq
First a databank name (optional), followed by a colon (:). Next an optional prefix symbol (% for scalars, # for collections, and no symbol for timeseries). The the variable name followed by an optional ! and a frequency (only for timeseries). For instance, b1:x!q refers to the quarterly (!q) series x in the b1 databank.
Array-series allow indexing, for instance b1:x!q[a,b] would refer to the sub-series [a,b] (that is, with two-dimensional indices a, b) of x!q. But other variable types allow indexing too, for instance b1:#m[2, 3], picking out row 2, column 3 from the matrix #m residing in the databank b1.
In some cases, omitting the databank name is silently interpreted as adding first: to the name, independent of mode settings. For instance copy x to y; is interpreted as copy first:x to first:y;, where first: refers to the first-position databank (often Work). In other commands, like for instance prt x;, Gekko will per default search for x in open databanks (excluding the Ref databank).
If the frequency is omitted for variables of series type, the current frequency will be silently added. So if the frequency is set to quarterly (option freq q;), you may use x1 as short-hand for x1!q.
For array-series, the array indexes may sometimes be omitted, so that you may write prt x; instead of prt x[#i, #j];, printing out all the elements inside the array-series x.
Names and quotes
In general, a string is enclosed in single quotes, for instance: 'x', whereas a name is not, for instance: x. Because of the use of prefix symbols in Gekko (% and # to start scalar and collection names), the single quotes may omitted in those cases where a series would not make sense. For instance, for array-series, using the shorter x[a] instead of the more strict x['a'] is legal, because in the former variant it would not make sense to use an index with a series argument. Using x[%a] is another story, because %a could be a string, so the rule only applies to simple names without prefix symbols (that is, sequences of characters that are either alphanumeric or _).
In the same manner, a lot of options accept string arguments, for instance compare <sort=rel>;, where rel is the argument (relative sorting). It would not make sense for rel to be a timeseries. Omitting single quotes is possible regarding list definitions and loops too, as seen in the following section.
Names, lists and loops
In general, lists are defined as comma-separated variables, enclosed in parentheses. For instance, #m may be a list of strings:
#m = ('a', 'b', 'c'); //strict |
As seen, a naked list variant is allowed, in the special case where all of the list elements are simple strings or simple values. Note that the syntax for a naked list of strings is always without parentheses in the list definition. The list #m = a, b, c; is interpreted as three strings 'a', 'b', 'c', whereas the list #m = (a, b, c); is different, containing three series variables (objects): a, b, c. The list #m = 1, 2, 3; becomes the three values 1, 2, and 3.
The same goes for FOR, so the two following are equivalent.
for string %i = ('a', 'b', 'c'); prt {%i}; end; //strict |
A one-element list (singleton) is special:
#m = a,; //or: ('a',) or list('a') |
The empty list is special too:
#m = list(); //note: using () may become legal later on |
For a one-element list with string element 'a', you cannot use #m = a; or #m = ('a');. In the first case, the right-hand side is interpreted as a series (a), and assigning a series directly to a list will fail. In the second case the expression evaluates to #m = 'a';, assigning a string directly to a list (which will fail, too). Using a trailing comma like #m = a,; makes it a list.
You can read more on lists, in particular naked lists, here.
Indexes [...]
Regarding indexes of array-series or other variables, single quotes on a string can in general be omitted (both the following are valid):
prt x['a','b']; //strict |
Indexes are often used on lists to pick out items (so-called slicing), like #m[3] to pick out the third element of the list #m. For maps, you can also omit the single quotes like the following (all three are equivalent):
prt #m['a']; //strict |
Maps can be thought of as a kind of mini-databank. Note the similarity between for instance b1:%x1 picking out the scalar %x1 from the databank b1, and #m1.%x1, picking out the scalar %x1 from the map #m1.
Name-substitution {...}
The {}-curlies are used for name-composition, and in general you may think of {...} as representing simply a sequence of (unquoted) characters, like x22 or y_15_sum. When used, the inside of {...} must evaluate to a string or list of strings, for instance {%s} or {#m}, for instance:
%s = 'x'; |
This is equivalent to prt ax, ay, az;. As mentioned several times before, in a sense, {...} curlies eat/remove single quotes, so that {'x'} = x, transforming the string 'x' into the variable/series x. As seen, the {}-curlies can also be used together with other characters (or other curly braces), for instance x{%i}a. If %i = 'e', this amounts to xea.
Often, instead of using array-series, normal series may be used to the same effect, using name-composition. So instead of the array-series x[i1, j1], the user may simply use a series called xi1j1. If the list #i contains the string 'i1' and the list #j contains the string 'j1', you may print the array-series x[i1, i2] like this: prt x[#i, #j];. Or with normal series and name-composition you can print the series xi1j1 like this: prt x{#i}{#j}. There is a similarity between x[#i, #j] and x{#i}{#j}, and most of the time you can use both variants. Array-series, however, have more capabilities than name-composition.
Using x%i|a as another way of writing x{%i}a is no longer endorsed in Gekko, but it still works.
See also the syntax diagrams.
More on indexes
Indexes can be used for:
•Array-series (mentioned above), for instance x[a, b] or x['a', 'b']. Integers may be used, if the dimension is compatible with an integer, for instance age dimension. When using integers, trailing zeroes are allowed, so for an array-series, x[007] is understood as x['007'], not x['7'].
•Lags/leads, for instance x[-1] or x[+1]. Note that a lag or lead must contain a + or - as the first character after the bracket. So if you define %i = 2, you may use x[-%i] or x[+%i], but x[%i] will not work as a lag or lead (even if %i is negative). Instead, if x is a normal series, x[%i] will be understood as x[2], which again is understood as the year 2 (two years after the birth of Christ). If x is instead an array-series, x[%i] will be understood as x['2'] which could, for instance, represent 2-year olds (if x contains population data).
•Period reference: x[2020q1], first quarter of 2020.
•Positions in lists: #m[2] picks out the second element of the list #m.
•Names in maps: #m[a] or #m['a'] picks out the variable named a in the map #m. For simple names, #m.a can also be used (the variable a is a series).
•Matrix references (row/column), for instance #m[2, 1] picks out the numeric value in row 2, column 1.
•Searching: #m['a*'] finds all elements matching the pattern 'a*'.
•To get the number of elements of the list #m, use length(#m) or #m.length().
•Ranges can be used for picking out elements, for instance #m[2..4] picks out elements 2 to 4 (inclusive), or %s[2..4] takes characters 2 to 4 from the string %s.