<< Click to Display Table of Contents >> Indexing: list, matrix, map |
![]() ![]() ![]() |
Gekko lists, matrices and maps are all containers of data, where the data is organized in some structure.
•A Gekko list is one-dimensional, but can be nested (lists inside lists), and may contain any Gekko variable type.
•A Gekko matrix is two-dimensional and can only contain values.
•A Gekko map is like a list where the elements are not ordered and hence not accessed by number index (for instance #m[1], #m[2], etc.), but instead by name (#m['gdp'], #m['vat'], etc.). In a map, the elements are not ordered sequentially, but instead strings are used to look up the elements. A Gekko map can be thought of as a mini-databank.
The strict syntax for defining a list uses soft parentheses (), for instance (1, 2) to define a two-element list. Note that a singleton list (with only one element) must use a trailing comma, for instance (1,). The matrix equivalent would be [1, 2], which is a 1 x 2 matrix (row vector), or alternatively [1; 2], which would be a 2 x 1 matrix (column vector). A nested list could be stated like ((1, 2), (3, 4)), which for a matrix would be [1, 2; 3, 4], because ; is used for matrices to separate rows. A list like (1, 2) has no awareness of being a row or a column or anything else; it is just a sequence of numbers that can be indexed by position.
#m1 = ((1, 2), (3, 4)); |
Regarding the list #m1, it contains two sub-lists. Each of these sub-lists contains two values. So the list is nested, whereas the matrix #m2 is organized in a two-dimensional structure of rows and columns.
In general, a nested list is indexed like for instance #m1[2][1], picking out the value 3, and a matrix is indexed like #m2[2, 1], also picking out the value 3. However, for nested lists of lists like #m1, Gekko allows the alternatively syntax #m1[2, 1], too. So when selecting an individual element %i, %j in a nested list, there is no difference between #m1[%i][%j] and #m1[%i, %j].
Things get more complicated when ranges are used:
// 1 2 3 |
Here, #m is a four-element list, where each element is itself a three-element list. It can be represented visually as the 2d matrix shown in the comments, but beware that the nested list has no inherent notion of rows or columns. Both #m1 and #m2 amount to (5, 6). In both cases, the second row is singled out, and elements 2-3 (inclusive) are selected from this. But #m3 and #m4 are different: the former selects rows 2-4 in column 2, which is (5, 8, 11), whereas #m4 evaluates to (7, 8, 9). To understand #m4, we will split it up into #x = #m[2..4]; #m4 = #x[2];. Here, #x evaluates to ((4, 5, 6), (7, 8, 9), (10, 11, 12)) since it picks out elements 2-4 (inclusive) of the #m list. Next, from #x, the second element of this is selected, which is (7, 8, 9). Perhaps not surprising, #m5 and #m6 are different, too. The former selects rows 2-4 and columns 2-3, resulting in the nested list ((5, 6), (8, 9), (11, 12)), cutting out a part of the 2d matrix shown in the comments. In contrast, #m6 evaluates to ((7, 8, 9), (10, 11, 12)) . We can reuse the #x temporary list again: #x = #m[2..4]; #m6 = #x[2..3];. So this time, #x[2..3] picks out elements 2-3 from #x, that is, ((7, 8, 9), (10, 11, 12)).
To sum up, for nested lists of lists, Gekko allows the indexing syntax [... , ... ] in addition to the standard [...][...] indexing. When the first part of the former kind of indexing is a single value, there is no confusion. However, when the first part of such indexing is a range, the [... , ...] syntax selects elements in the same manner as matrix selection, whereas the [...][...] variant selects something altogether different.
The reason why nested lists allow [... , ... ] indexing syntax in Gekko is to make it possible to select elements in a similar manner to matrices, making it easier to use nested lists to represent for instance spreadsheet cells, tables or other 2d structures with mixed contents (for instance text, dates, and values). Another reason is to comply tightly with Python arrays (NumPy library), where such indexing is possible. Python also has a matrix library, but this is being deprecated in favor of using NumPy arrays instead (also for linear algebra calculations), among other things because arrays generalize naturally to n dimensions ("tensors"), in contrast to 2-dimensional matrices.
Arrays in Python
Since lists in Gekko follow most of the conventions of Python, the Python NumPy library also inspires some of the intricacies of multidimensional objects. First, we will have a look at the ndarray (n-dimensional array) variable type in Python.
import numpy as np |
In the following Python code, m is a standard nested list, whereas a is an array. Here, m[0] will pick out the list [1, 2, 3], and a[0] will pick out the array [1, 2, 3], note that indexes are 0-based in Python. Both m[0][0], a[0][0] and a[0, 0] will pick out 1, but m[0, 0] will fail with an error Selecting one of the row elements and a range of column elements (Python uses : instead of .. for ranges) produces this:
m1 = m[1, 1:3] #type error |
Again, the list does not allow [... , ...] notation, but apart from this, everything is as expected (the Python range 1:3 means elements 2 and 3) . Now we try to select a range of rows and a fixed column:
m3 = m[1:4, 1] #type error |
In this case, m4 and a4 still only obtain the second row, whereas a3 obtains the second column (and m3 fails with an error). Selecting several rows and columns at the same time:
m5 = m[1:4, 1:3] #type error |
In this case, there is no difference, apart from the expected type error regarding m5.
As it is seen above, the logic of ranges and nested lists in Gekko resembles the Python/NumPy/ndarray logic.