Dynamic statements and dynamics checking/errors

<< Click to Display Table of Contents >>

Navigation:  Gekko User Manual > User manual introduction >

Dynamic statements and dynamics checking/errors

Previous pageReturn to chapter overviewNext page

Timeseries statements may contain accumulating lags like the following:

 

= x[-1] + 1;

 

This basically says: take the value of x in the previous period, add 1, and assign the result back into x. If this is only done regarding one period, there is no ambiguity. But with several periods, how should such accumulation work?

 

 

The problem

 

In Gekko 3.x, such an assignment statement (containing the lagged dependent/endogenous variable on the right-hand side) will operate on blocks of data in a vector-like fashion. This is shown in the following diagram, running a series statement = x[-1] + 1 over the time period 2001-2003.

 

Figure 1: vector-like

 

clip0036

 

Imagine the series x containing the values 17, 14, 11, and 13 over the period 2000-2003 (shown as red vector of values on the left). Now, when the statement = x[-1] + 1 is executed over the period 2001-2003, first an intermediate vector x[-1] is calculated, shifting the values of x one position downwards. This is shown as the yellow values 17, 14, and 11, and when 1 is added to these, we obtain the expression x[-1] + 1 as the fourth vector of values (18, 15 and 12). These values are assigned back into the original series x, and the end result is shown as the red vector of values on the right. Except for the first period 2001, this does not accumulate as the user might expect; the expectation being that x augments by 1 for each of the years 2001, 2002, and 2003.

 

If instead we run the statement = x[-1] + 1 period by period, we get the following three tempi, corresponding to 2001, 2002, and 2003:

 

Figure 2: time looping

 

clip0035

 

In the first period (2001), x[-1] is fetched as the value 17, x[-1]+1 is therefore 18, and 18 is immediately fed back into the x vector. Therefore, when the second period (2002) is about to be calculated, the lagged value x[-1] is not 14 as in Figure 1, but instead the just calculated value 18. This goes on for 2003 too, and the end result (the red vector at the bottom right) is that x augments by 1 each year over the period 2001-2003. Prior to this calculation, only x[2000] has relevance regarding the result, since this period acts as a starting point.

 

As it should hopefully be clear, the way lags are handled in Figure 1 and 2 are different, and hence the results are also different in this particular case. But note that these differences only occur if there are more than one period calculated, and if the left-hand side variable x appears with lags on the right-hand side. Therefore, lags in an expression like = x[-1] + 1 or similar would yield the same result in Figures 1 and 2. Some timeseries-oriented software packages like for instance AREMOS or Gekko 2.x will always accumulate as in Figure 2, where timeseries expressions are basically run period by period in an outer time loop, instead of operating on blocks/vectors of data.

 

There are many advantages regarding the calculation of timeseries expressions in a vector-like fashion, because it makes it clear exactly what the input and the output of a particular function or expression is, and there are no ambiguities as to whether some particular expression ought to be run only once (for instance a string or value expression), or should be calculated several times successively over a time period because timeseries are involved. Handling timeseries calculations in a vector-like fashion makes the flow of timeseries in and out of functions and procedures work in a much more transparent and encapsulated fashion. In addition to this, vector-like calculations run much faster than implicit time-looping, and the underlying Gekko source code becomes more simple, too.

 

 
Dynamizing with <dyn>, and the speed penalty

 

In Gekko 3.x, Gekko handles series expressions in a vector-like fashion unless stated otherwise. So out of the box, dynamic statements with lagged dependent/endogenous variables will work as shown in Figure 1. However, it is possible to run a series expression with implicit time looping, corresponding to Figure 2. There are two equivalent ways to do this:

 

<dyn> = x[-1] + 1;

 

Here, the <dyn> local option activates time looping. Run this way, you would get 18, 19 and 20 in the example in the beginning of this page, where x is augmented by 1 year period. Alternatively the following yields the same:

 

block series dyn = yes;
  x = x[-1] + 1;
end;

 

The effect of using block series dyn = yes is exactly the same as using the <dyn> option. There does not exist a any option series dyn = yes to set time looping globally, because it is deemed important to make sure that this functionality is only used where it is really necessary, so block series dyn = no is intended  for a block of series statements that all should be run dynamically, and where it would be tedious to put <dyn> tags on each of these statements. Unnecessary dynamic tags (<dyn> or block series dyn = yes) waste a lot of time, and therefore slows down the execution Gekko programs. This is important enough to warrant a bullet point:

 

When running a series statement over n observations, unnecessarily using <dyn> or block series dyn = yes on this statement typically makes the statement take n times longer to evaluate than without dynamization. Therefore, if you are evaluating series statements over, say, a period like 1970-2020, you should expect these to run around 50 times slower, if these expressions are unnecessarily dynamized (like in <dyn> = x[-1] + 1;, where <dyn> is completely unnecessary).

 

Such inefficiency would make Gekko seem sluggish, and therefore it is not possible to dynamize via a general option. In general, dynamization should only be used when necessary, and be omitted when not. Often dynamization is not necessary at all, cf. the next paragraph.

 

 

Alternative syntax

 

Before moving on, it is worth mentioning that quite a lot of accumulating behavior can be implemented using operators or left-hand side functions (cf. descriptions on the SERIES page). For instance, the following are all equivalent:

 

<dyn> = x[-1] + 1;
<d>= 1;
^= 1;
dif(x) = 1;

 

For simple accumulations (relative accumulation is possible, too, cf. SERIES), it is often easier to use operators or left-hand side functions (note that the three last expressions do not need <dyn> keyword). Also note that accumulations like dif(x) = dif(x) + 1; (adding 1 to the absolute growth) or pch(x) = pch(x) + 1; (adding 1%-point to the percentage growth) work fine out of the box, and should be used without <dyn> tags.

 

But for more complicated accumulations, or when the equations are taken from model equations, using <dyn> may be the best way to go.

 

 
Dynamics checking and dynamics errors

 

As a convenience for the users, Gekko versions 3.1.7 and later implement automatic checking for the presence of lagged dependent/endogenous variables in a series statement. Therefore, in Gekko >= 3.1.7, the following statement:

 

= x[-1] + 1;

 

will fail with a 'dynamics error', explaining that the user must decorate the statement with one of the following:

 

<dyn>

<dyn = no>

block series dyn = yes

block series dyn = no

 

In other words, when a lag like x[-1] is present in a series statement, the user must take a stand on whether the statement is to be calculated in a vector-like fashion (like Figure 1 above), or as an implicit time loop (like Figure 2 above). The following conditions will trigger the dynamics error on an assignment statement (that is, a statement of the form something = something;).

 

The right-hand side must evaluate to a series, and the time period must have > 1 observations.

The left-hand side must be a series variable.

The left-hand side series must be used with a lag on the right-hand side. Lags may be in the form x[-1], x[-2], etc., or alternatively formulated as x.1, or lag(x, 1).

Right-hand side functions that can be interpreted as containing implicit lags like dif(), pch(), movavg(), etc. will not trigger the dynamics error.

Left-hand side functions like dif() or pch() do not trigger the dynamics error either (these functions are built to deal with dynamics in an accumulating way).

 

In conclusion, the dynamics error is triggered if the user forgets to deal with the existence of a 'normal' endogenous lagged variable on the right-hand side, and this is the most common error regarding dynamic statements.

 

If you prefer to switch off automatic dynamics checking, you may use option series dyn check = no;, and in this case a statement like = x[-1] + 1 will proceed without error (as in Gekko versions prior to 3.1.7), and will be evaluated like in Figure 1 above (vector-like).

 

 

Backwards incompatibility, or how to ignore

 

In Gekko 3.1.7 and above, automatic checking for the existence of lagged dependent/endogenous variables is implemented and switched on, since option series dyn check = yes is set as default value. This may break existing programs in the sense that programs written for Gekko versions lower than 3.1.7 may allow a 'naked' statement like = x[-1] + 1 (omitting <dyn> or block series dyn), whereas in Gekko 3.1.7 and above, a 'naked' dynamic statement like that will fail with a dynamics error.

 

Because dynamics checking is not backwards compatible, it is entirely possible that a system of Gekko program files runs without error in a Gekko version < 3.1.7, whereas running the same system on Gekko >= 3.1.7 results in dynamics errors. If this is the case, there are different possibilities:

 

Ignore 1: The most radical fix for such problems is to put an option series dyn check = no in the beginning of the program file or system of program files. This way, the behavior of Gekko < 3.1.7 is emulated completely, and the errors should dissolve.

Ignore 2: Less dramatic is to decorate the problematic statements one by one with <dyn = no>, which would emulate pre 3.1.7 behavior, too. When in a hurry, this could be a short term fix, but the statements ought to be marked for later investigation.

Fix: Better than ignoring the problems, the user could try to fix them. This means taking a look at the statements and judging whether the lagged dependent/endogenous variable really should not accumulate (that is, work as in Figure 1), or -- more likely -- whether it is indeed an accumulating expression. In the former case, the user can just insert a <dyn = no>, after which the error would dissolve, and Gekko would replicate former results. In the latter case, the user should insert a <dyn>, which will dissolve the error, but not necessarily replicate former results. Not replicating is of course annoying, but most likely it will stem from dynamics being erroneously omitted from some series statements, and therefore the check might identify errors that otherwise might have gone unnoticed.

 

Dynamics checking in Gekko versions 3.1.7 and above is convenient in the sense that the user needs to worry less about forgetting to put <dyn> option on normal accumulating statements like = x[-1] +1. This eliminates a rather large source of potential bugs.

 

On the other hand, dynamics checking may also be inconvenient, when upgrading from a Gekko version < 3.1.7 to a Gekko version >= 3.1.7. In that case, dynamics errors may be reported, and these errors may be real errors that have gone unnoticed hitherto. Fixing errors is always a good thing, so even if upgrading to a Gekko version >= 3.1.7 may be inconvenient because of sudden dynamics errors, getting the potential errors sorted out is still good.

 

 

Technical note

 

When issuing a <dyn> or block series dyn = yes, over some time period %t1 to %t2, Gekko basically runs the expression first for the period %t1 to %t1, then for %t1+1 to %t1+1, and so on, ending up with %t2 to %t2. As noted above, there is a speed penalty regarding this, but the change of time periods may also affect the way the expression is interpreted in some (probably rare) cases. For instance:

 

time 2000 2003;
= 17, 14, 11, 13;
time 2001 2003;
#= 1, 2, 3;
<dyn = no> = x[-1] + #m;  //18, 16, 14 = 17+1, 14+2, 11+3

 

Note that omitting the <dyn = no> tag in Gekko versions >= 3.1.7 would fail with a dynamics error, because of the lag x[-1]. If the user instead wants this to accumulate, the following could be tried as an alternative to the last line:

 

<dyn> = x[-1] + #m;  //error

 

Now, this line fails with an error stating that Gekko expects that the list has 1 element only, because Gekko runs the expression via implicit time looping in three tempi: 2001-2001, 2002-2002, and 2003-2003. Therefore, in cases like this, decorating with <dyn> or block series dyn = yes may fail because of the implicit time looping. Such cases are probably quite rare, and in this particular case, the remedy could be to use a series to store the three numbers 1, 2, and 3 instead:

 

time 2000 2003;
= 17, 14, 11, 13;
time 2001 2003;
= 1, 2, 3;
<dyn> = x[-1] + m;  //18, 20, 23

 

For instance, for the period 2001-2001 in the implicit time loop, Gekko knows which value to fetch out of m, since m is a timeseries, not a list. The result is as expected, where x first augments with 1, then with 2, and finally with 3.