3
$\begingroup$

I'm working on a project that involves developing a financial forecasting model. The equations used in the model will largely be linear difference equations (estimated via some form of regression analysis). Along with the difference equations will be additional equations that are simple identities, e.g., a[t] == b[t] + c[t], with no sort of time lag.

I've been experimenting with RecurrenceTable, using some simple hypothetical examples. For instance, this set of equations evaluates correctly:

 In[763]:= 
    model1 = RecurrenceTable[
      {
       x[t + 2] ==  
        0.25 + x[t + 1]  - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2]  ,
       y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2] ,
       z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2] ,
       x[0] == 1, x[1] == 1,
       y[0] == 0, y[1] == 2,
       z[0] == 0, z[1] == 1},
      {x, y, z}, {t, 1, 10}
      ]

Out[763]= {{1., 2., 1.}, {0.428571, -0.321429, -0.3625}, {0.0612245, 
  1.04337, 0.574821}, {-0.200437, -0.390488, 0.150742}, {0.0103603, 
  0.247878, 0.52746}, {0.270717, -0.414239, -0.0462812}, {0.478779, 
  0.180722, -0.245145}, {0.398813, -0.0142515, -0.689967}, {0.214079, 
  0.29056, -0.776897}, {0.0436432, 0.0325037, -0.918937}}

If I modify this to include an additional equation, q[t+2] that simply sums the results of the other equations:

In[761]:= fcstB = RecurrenceTable[
  {
   x[t + 2] ==  
    0.25 + x[t + 1]  - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2]  ,
   y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2] ,
   z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2] ,
   q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2],
   x[0] == 1, x[1] == 1,
   y[0] == 0, y[1] == 2,
   z[0] == 0, z[1] == 1,
   q[0] == 1, q[1] == 4},
  {x, y, z, q}, {t, 1, 10}
  ]

Out[761]= RecurrenceTable[{x[2 + t] == 
   0.25 - 1.5 x[t] + x[1 + t] + 0.5 y[1 + t] + y[2 + t], 
  y[2 + t] == x[1 + t] - 0.75 x[2 + t] + 0.25 y[t] - 0.5 y[1 + t], 
  z[2 + t] == -1.5 x[2 + t] - 0.25 y[2 + t] + z[t] + 0.2 z[1 + t], 
  q[2 + t] == x[2 + t] + y[2 + t] + z[2 + t], x[0] == 1, x[1] == 1, 
  y[0] == 0, y[1] == 2, z[0] == 0, z[1] == 1, q[0] == 1, 
  q[1] == 4}, {x, y, z, q}, {t, 1, 10}]

The result does not evaluate. In looking through the documentation, it appears that RecurrenceTable will not handle trivial recurrence equations. I'm hoping someone can verify this for me, or perhaps suggest an alternative. The actual model I'm developing will consist of thousands of equations, and so it seems I will need to organize blocks of equations in such a way to isolate identities in order to evaluate the entire system

Thanks!

$\endgroup$
2
$\begingroup$

Another option is to put it into a state-space form and then use OutputResponse.

I used AffineStateSpaceModel and not StateSpaceModel because the equations have residue terms.

AffineStateSpaceModel[{x[t + 2] == 
    0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
   y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
   z[t + 2] == 
    0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2]}, {x[t], y[t],
    z[t]}, {u[t]}, {x[t], y[t], z[t]}, t];
OutputResponse[{%, {1, 1, 0, 2, 0, 1}}, Table[0, 11]] // Transpose

(*{{1, 0, 0}, {1., 2., 1.}, {0.428571, -0.321429, -0.3625}, {0.0612245, 
  1.04337, 0.574821}, {-0.200437, -0.390488, 0.150742}, {0.0103603, 
  0.247878, 0.52746}, {0.270717, -0.414239, -0.0462812}, {0.478779, 
  0.180722, -0.245145}, {0.398813, -0.0142515, -0.689967}, {0.214079, 
  0.29056, -0.776897}, {0.0436432, 0.0325037, -0.918937}}*)

With the additional equation:

AffineStateSpaceModel[{x[t + 2] == 
    0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
   y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
   z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
   q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2]}, {x[t], y[t], z[t], 
   q[t]}, {u[t]}, {x[t], y[t], z[t], q[t]}, t];
OutputResponse[{%, {1, 1, 0, 2, 0, 1, 1, 4}}, Table[0, 11], 
  Method -> "RecurrenceTable"] // Transpose

(*{{1, 0, 0, 1}, {1., 2., 1., 
  4.}, {0.428571, -0.321429, -0.3625, -0.255357}, {0.0612245, 1.04337,
   0.574821, 1.67941}, {-0.200437, -0.390488, 
  0.150742, -0.440183}, {0.0103603, 0.247878, 0.52746, 
  0.785699}, {0.270717, -0.414239, -0.0462812, -0.189803}, {0.478779, 
  0.180722, -0.245145, 
  0.414356}, {0.398813, -0.0142515, -0.689967, -0.305405}, {0.214079, 
  0.29056, -0.776897, -0.272258}, {0.0436432, 
  0.0325037, -0.918937, -0.84279}}*)

If you want you can explicitly ask OutputResponse to use RecurrenceTable as I showed above. But it's not necessary.

Also applying Normal to the state-space model will give you equations in a form that can be solved by RecurrenceTable.

$\endgroup$
2
  • $\begingroup$ Thank you for a very elegant solution! $\endgroup$
    – MSC02476
    Feb 14 '20 at 16:04
  • $\begingroup$ Glad you liked it! $\endgroup$ Feb 14 '20 at 23:23
2
$\begingroup$

q can be generated and combined with the corresponding values of {x, y, z}by

fcstB = Join[#, {Total@#}] & /@ model1
(* {{1., 2., 1., 4.}, 
    {0.428571, -0.321429, -0.3625, -0.255357}, 
    {0.0612245, 1.04337, 0.574821, 1.67941}, 
    {-0.200437, -0.390488, 0.150742, -0.440183}, 
    {0.0103603, 0.247878, 0.52746, 0.785699}, 
    {0.270717, -0.414239, -0.0462812, -0.189803}, 
    {0.478779, 0.180722, -0.245145, 0.414356}, 
    {0.398813, -0.0142515, -0.689967, -0.305405}, 
    {0.214079, 0.29056, -0.776897, -0.272258}, 
    {0.0436432, 0.0325037, -0.918937, -0.84279}} *)

Another approach is to solve these linear equations for {x, y, z, q} at t + 2 and then apply RecurrenceTable:

rs = Solve[{x[t + 2] == 0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
            y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2],
            z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
            q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2]}, 
           {x[t + 2], y[t + 2], z[t + 2], q[t + 2]}] /. Rule -> Equal;
fcstB = RecurrenceTable[{rs, x[0] == 1, x[1] == 1, y[0] == 0, y[1] == 2, 
     z[0] == 0, z[1] == 1, q[0] == 1, q[1] == 4}, {x, y, z, q}, {t, 1, 10}]

which gives the same values as above. It appears that RecurrenceTable was unhappy, because the original expression for q[t +2] did not depend explicitly on variables at earlier times. But, who can say for sure without knowing the inner workings of the function.

Addendum

To test the hypothesis posed in the last paragraph above, let us add an infinitesimal amount of q[t] to the last equation in the original system.

fcstB = RecurrenceTable[{x[t + 2] == 0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
    y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
    z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
    q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2] + 10^-30 q[t], 
    x[0] == 1, x[1] == 1, y[0] == 0, y[1] == 2, z[0] == 0, z[1] == 1, q[0] == 1, q[1] == 4}, 
    {x, y, z, q}, {t, 1, 10}]

which again evaluates to the desired answer. I do not, of course, recommend this last approach for evaluating the RecurrenceTable.

$\endgroup$
1
$\begingroup$

Why not find an other equation for q[t+2] with Eliminate.

eli = Eliminate[{x[t + 2] == 
0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2]}, 
{x[t + 2], y[t + 2], z[t + 2]}]

(*   0.166667\[VeryThinSpace]+ 1.09804 q[2 + t] + 0.509804 x[1 + t] - 
 0.0392157 y[t] + 0.411765 y[1 + t] - 1.09804 z[t] - 
 0.219608 z[1 + t] == x[t]   *)

Insert equation eli instead of q[t+2] == ...

fcstB = RecurrenceTable[{x[t + 2] == 
0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
eli, x[0] == 1, x[1] == 1, y[0] == 0, y[1] == 2, z[0] == 0, 
z[1] == 1, q[0] == 1, q[1] == 4}, {x, y, z, q}, {t, 0, 10}]

(*   {{1., 0., 0., 1.}, {1., 2., 1., 4.}, {0.428571, -0.321429, -0.3625, -0.255357}, {0.0612245, 1.04337,
0.574821, 1.67941}, {-0.200437, -0.390488, 
0.150742, -0.440183}, {0.0103603, 0.247878,  0.52746, 
0.785699}, {0.270717, -0.414239, -0.0462812, -0.189803}, {0.478779, 
0.180722, -0.245145, 
0.414356}, {0.398813, -0.0142515, -0.689967,  -0.305405}, {0.214079, 
0.29056, -0.776897, -0.272258}, {0.0436432, 
0.0325037, -0.918937, -0.84279}}   *)
$\endgroup$
0
$\begingroup$

I ran into a similar problem here. The same workaround -- add Unevaluated[0 q[t]] -- works here:

fcstB = RecurrenceTable[{
   x[t + 2] == 0.25 + x[t + 1] - 1.5*x[t] + 0.5*y[t + 1] + y[t + 2], 
   y[t + 2] == -0.50*y[t + 1] + 0.25*y[t] + x[t + 1] - 0.75*x[t + 2], 
   z[t + 2] == 0.20*z[t + 1] + z[t] - 0.25*y[t + 2] - 1.5*x[t + 2], 
   q[t + 2] == x[t + 2] + y[t + 2] + z[t + 2] + Unevaluated[0 q[t]], 
   x[0] == 1, x[1] == 1, y[0] == 0, y[1] == 2, z[0] == 0, z[1] == 1, 
   q[0] == 1, q[1] == 4}, {x, y, z, q}, {t, 1, 10}]

(* {{1., 2., 1., 4.}, {0.428571, -0.321429, -0.3625, -0.255357},
{0.0612245, 1.04337, 0.574821, 1.67941}, {-0.200437, -0.390488, 0.150742, -0.440183},
{0.0103603, 0.247878, 0.52746, 0.785699}, {0.270717, -0.414239, -0.0462812, -0.189803},
{0.478779, 0.180722, -0.245145, 0.414356}, {0.398813, -0.0142515, -0.689967, -0.305405},
{0.214079, 0.29056, -0.776897, -0.272258}, {0.0436432, 0.0325037, -0.918937, -0.84279}} *)
$\endgroup$
2
  • $\begingroup$ Thanks. That is an interesting work-around. Any insight into why this approach works? $\endgroup$
    – MSC02476
    Feb 12 '20 at 15:22
  • $\begingroup$ @MSC02476 I got the idea from this answer by Mr. Wizard. I suppose it tricks RecurrenceTable into thinking that q[t+2] is a function of q[t]. The Unevaluated is needed because otherwise 0 q[t] would be simplified to 0 first. $\endgroup$
    – Chris K
    Feb 12 '20 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.