2
$\begingroup$

I'm trying to code up some plots for Autocorrelation Functions in Time Series Analysis, which can often be defined recursively. The goal is then to have Manipulate sliders that allow you to dynamically change the controlling parameters. Here's an example of the sort of plots I'm trying to emulate: ACF for several AR(2) models

(here, $\phi_1$ and $\phi_2$ are the parameters I want to manipulate.)

For this $AR(2)$ model, the ACF, denoted $\rho_k$, can be defined recursively as follows:

$\rho_0 = 1$

$\rho_1 = \frac{\phi_1}{1-\phi_2}$

$\rho_k = \phi_1 \rho_{k-1} + \phi_2 \rho_{k-2}$


How do I implement this recursion and ListPlot in Mathematica?

I've tried doing:

ρ[0,φ1_,φ2_]:= 1
ρ[1,φ1_,φ2_]:= φ1/(1-φ2)
ρ[k,φ1_,φ2_]:= φ1 * ρ[k-1,φ1,φ2] + φ2 * ρ[k-2,φ1,φ2]

But then the ListPlot, even when plotted for e.g. {k, 0, 10}, only shows $ρ[0]$ and $ρ[1]$. I'm still a bit new to coding larger projects in Mathematica (only basic ODE StreamPlots in the past), so I think I'm misunderstanding the proper way to handle defining functions.

$\endgroup$
  • $\begingroup$ You can use \[Rho][k_, phi1_, phi2_] := If[k == 0, 1, If[k == 1, phi1/(1 - phi2), phi1*\[Rho][k - 1, phi1, phi2] + phi2*\[Rho][k - 2, phi1, phi2]]] $\endgroup$ – ulvi Mar 5 at 6:05
  • $\begingroup$ You are missing an _ after your k in your third definition. Thus φ1=1/2; φ2=1/4; ρ[0,φ1_,φ2_]:= 1; ρ[1,φ1_,φ2_]:= φ1/(1-φ2); ρ[k_,φ1_,φ2_]:= φ1 * ρ[k-1,φ1,φ2] + φ2 * ρ[k-2,φ1,φ2]; ListPlot[Table[ρ[k,φ1,φ2],{k, 0, 10}]] plots just fine $\endgroup$ – Bill Mar 5 at 6:16
2
$\begingroup$

The underlying difference equation for $\text{AR}(2)$ is a three-term recurrence with constant coefficients. RSolve[] can directly solve this, after which you can use the solution along with DiscretePlot[] for visualization.

I will let someone else implement that approach. Instead, let me show how to use LinearRecurrence[] along with ListPlot[]:

Manipulate[ListPlot[Rest[LinearRecurrence[{φ1, φ2}, {1, φ1/(1 - φ2)}, n + 1]],
                    Filling -> Axis, Frame -> True, 
                    FrameLabel -> {"Lag", "\!\(\*SubscriptBox[\(ρ\), \(k\)]\)"}, 
                    PlotRange -> All, PlotStyle -> Black],
           {{φ1, 1}, 0, 3}, {{φ2, -1/2}, -1, 1}, {{n, 12}, 2, 20, 1}]

Manipulate for AR(2) process

$\endgroup$
  • 1
    $\begingroup$ ρ[k_, φ1_, φ2_] = ρ[k] /. FullSimplify[First[RSolve[{ρ[0] == 1, ρ[1] == φ1/(1 - φ2), ρ[k] == φ1*ρ[k - 1] + φ2*ρ[k - 2]}, ρ[k], k]]] and then Manipulate[DiscretePlot[ρ[k, φ1, φ2], {k, 10}], {φ1, .5, 1.5}, {φ2, -.75, .25}] $\endgroup$ – Roman Mar 5 at 10:26
  • $\begingroup$ @Roman, very nice. Why not edit your answer to include it? $\endgroup$ – J. M. will be back soon Mar 5 at 12:07
  • $\begingroup$ Superb. I'm certainly not wedded to implementing it using the approach I was initially using, so LinearRecurrence[] is a great solution I didn't know about. $\endgroup$ – Jack Gallagher Mar 5 at 17:06
1
$\begingroup$

With recursions I'd recommend to always use memoizing functions; have a look at the tutorial on the distinction between immediate = and delayed := assignments.

You're doing a recursion where k is the recursion index and φ1,φ2 are variables, so there is a big distinction between these two kinds of parameters of ρ. In this case, I would do the recursion in terms of functions of φ1,φ2, not in terms of concrete numerical values φ1,φ2:

ρ[0] = Function[{φ1, φ2}, 1];
ρ[1] = Function[{φ1, φ2}, φ1/(1 - φ2)];
ρ[k_Integer /; k >= 2] := ρ[k] = Function[{φ1, φ2},
       Evaluate[φ1*ρ[k-1][φ1, φ2] + φ2*ρ[k-2][φ1, φ2] // FullSimplify]]

This way of defining the recursion has the advantage that the formula for each ρ[k] is only evaluated once, and the recursion is not re-traversed for every numerical value of φ1 and φ2 anew. FullSimplifying at each step in the recursion makes sure that the resulting formulas for the ρ[k] stay reasonably small, and they can be evaluated quickly in a Manipulated plot.

plot:

Manipulate[DiscretePlot[ρ[k][φ1, φ2], {k, 10}], {φ1, .5, 1.5}, {φ2, -.75, .25}]

As @JM points out, this specific recursion has a closed-form solution:

ρ[k_, φ1_, φ2_] = ρ[k] /. FullSimplify[First[
  RSolve[{ρ[0] == 1, ρ[1] == φ1/(1-φ2), ρ[k] == φ1*ρ[k-1] + φ2*ρ[k-2]}, ρ[k], k]]]

$2^{-k-1} \left(\left(\varphi_1-\sqrt{\varphi_1^2+4 \varphi_2}\right)^k+\left(\sqrt{\varphi_1^2+4 \varphi_2}+\varphi_1\right)^k+\frac{\varphi_1 (\varphi_2+1)\left(\left(\varphi_1-\sqrt{\varphi_1^2+4 \varphi_2}\right)^k-\left(\sqrt{\varphi_1^2+4 \varphi_2}+\varphi_1\right)^k\right)}{(\varphi_2-1) \sqrt{\varphi_1^2+4\varphi_2}}\right)$

Manipulate[DiscretePlot[ρ[k, φ1, φ2], {k, 10}], {φ1, .5, 1.5}, {φ2, -.75, .25}]
$\endgroup$
  • 2
    $\begingroup$ For \[CurlyPhi]2 == (-\[CurlyPhi]1)/4 the closed-form solution needs to be defined in the Limit $\endgroup$ – Bob Hanlon Mar 5 at 14:40
  • $\begingroup$ Great! Nice to learn what memoizing functions are! That's what I like about this forum. If I were to need to solve this problem myself, I'd come up with my solution and that would be that. There is a lot to learn by seeing different approaches (such as your approach, and J. M.'s, for example)! $\endgroup$ – mjw Mar 5 at 17:03
  • $\begingroup$ Also, I like the notation where you split the arguments based on function k an index and phi1 and phi2 parameters defining the recurrence. I noticed m_goldberg took a similar approach in another post. I'll have to try to remember to use this going forward! $\endgroup$ – mjw Mar 5 at 17:32
0
$\begingroup$
ρ[k_, φ1_, φ2_] := 
Which[k == 0, 1, k == 1, φ1/(1 - φ2), 
  k > 1, φ1*ρ[k - 1, φ1, φ2] + φ2*ρ[k - 2, φ1, φ2]]
Manipulate[
 ListPlot[Table[{k, ρ[k, φ1, φ2]}, {k, 10}],
 PlotRange -> {-.5, 1}, Filling -> Axis ],
   {φ1, .5, 1.5}, {φ2, -.75, .25}]

enter image description here

$\endgroup$

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.