65. Stability in Linear Rational Expectations Models#

In addition to what’s in Anaconda, this lecture deploys the following libraries:

!pip install quantecon
Hide code cell output
Requirement already satisfied: quantecon in /opt/conda/envs/quantecon/lib/python3.12/site-packages (0.8.0)
Requirement already satisfied: numba>=0.49.0 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from quantecon) (0.60.0)
Requirement already satisfied: numpy>=1.17.0 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from quantecon) (1.26.4)
Requirement already satisfied: requests in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from quantecon) (2.32.3)
Requirement already satisfied: scipy>=1.5.0 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from quantecon) (1.13.1)
Requirement already satisfied: sympy in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from quantecon) (1.13.1)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from numba>=0.49.0->quantecon) (0.43.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from requests->quantecon) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from requests->quantecon) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from requests->quantecon) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from requests->quantecon) (2024.8.30)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /opt/conda/envs/quantecon/lib/python3.12/site-packages (from sympy->quantecon) (1.3.0)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable.It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.

import matplotlib.pyplot as plt
import numpy as np
import quantecon as qe
from sympy import init_printing, symbols, Matrix
init_printing()

65.1. Overview#

This lecture studies stability in the context of an elementary rational expectations model.

We study a rational expectations version of Philip Cagan’s model [Cagan, 1956] linking the price level to the money supply.

Cagan did not use a rational expectations version of his model, but Sargent [Sargent, 1977] did.

We study a rational expectations version of this model because it is intrinsically interesting and because it has a mathematical structure that appears in virtually all linear rational expectations model, namely, that a key endogenous variable equals a mathematical expectation of a geometric sum of future values of another variable.

The model determines the price level or rate of inflation as a function of the money supply or the rate of change in the money supply.

In this lecture, we’ll encounter:

  • a convenient formula for the expectation of geometric sum of future values of a variable

  • a way of solving an expectational difference equation by mapping it into a vector first-order difference equation and appropriately manipulating an eigen decomposition of the transition matrix in order to impose stability

  • a way to use a Big K, little k argument to allow apparent feedback from endogenous to exogenous variables within a rational expectations equilibrium

  • a use of eigenvector decompositions of matrices that allowed Blanchard and Khan (1981) [Blanchard and Kahn, 1980] and Whiteman (1983) [Whiteman, 1983] to solve a class of linear rational expectations models

  • how to use SymPy to get analytical formulas for some key objects comprising a rational expectations equilibrium

Matrix decompositions employed here are described in more depth in this lecture Lagrangian formulations.

We formulate a version of Cagan’s model under rational expectations as an expectational difference equation whose solution is a rational expectations equilibrium.

We’ll start this lecture with a quick review of deterministic (i.e., non-random) first-order and second-order linear difference equations.

65.2. Linear Difference Equations#

We’ll use the backward shift or lag operator L.

The lag operator L maps a sequence {xt}t=0 into the sequence {xt1}t=0

We’ll deploy L by using the equality Lxtxt1 in algebraic expressions.

Further, the inverse L1 of the lag operator is the forward shift operator.

We’ll often use the equality L1xtxt+1 below.

The algebra of lag and forward shift operators can simplify representing and solving linear difference equations.

65.2.1. First Order#

We want to solve a linear first-order scalar difference equation.

Let |λ|<1 and let {ut}t= be a bounded sequence of scalar real numbers.

Let L be the lag operator defined by Lxtxt1 and let L1 be the forward shift operator defined by L1xtxt+1.

Then

(65.1)#(1λL)yt=ut,t

has solutions

(65.2)#yt=(1λL)1ut+kλt

or

yt=j=0λjutj+kλt

for any real number k.

You can verify this fact by applying (1λL) to both sides of equation (65.2) and noting that (1λL)λt=0.

To pin down k we need one condition imposed from outside (e.g., an initial or terminal condition) on the path of y.

Now let |λ|>1.

Rewrite equation (65.1) as

(65.3)#yt1=λ1ytλ1ut,t

or

(65.4)#(1λ1L1)yt=λ1ut+1.

A solution is

(65.5)#yt=λ1(11λ1L1)ut+1+kλt

for any k.

To verify that this is a solution, check the consequences of operating on both sides of equation (65.5) by (1λL) and compare to equation (65.1).

For any bounded {ut} sequence, solution (65.2) exists for |λ|<1 because the distributed lag in u converges.

Solution (65.5) exists when |λ|>1 because the distributed lead in u converges.

When |λ|>1, the distributed lag in u in (65.2) may diverge, in which case a solution of this form does not exist.

The distributed lead in u in (65.5) need not converge when |λ|<1.

65.2.2. Second Order#

Now consider the second order difference equation

(65.6)#(1λ1L)(1λ2L)yt+1=ut

where {ut} is a bounded sequence, y0 is an initial condition, |λ1|<1 and |λ2|>1.

We seek a bounded sequence {yt}t=0 that satisfies (65.6). Using insights from our analysis of the first-order equation, operate on both sides of (65.6) by the forward inverse of (1λ2L) to rewrite equation (65.6) as

(1λ1L)yt+1=λ211λ21L1ut+1

or

(65.7)#yt+1=λ1ytλ21j=0λ2jut+j+1.

Thus, we obtained equation (65.7) by solving a stable root (in this case λ1) backward, and an unstable root (in this case λ2) forward.

Equation (65.7) has a form that we shall encounter often.

  • λ1yt is called the feedback part

  • λ211λ21L1ut+1 is called the feedforward part

65.3. Illustration: Cagan’s Model#

Now let’s use linear difference equations to represent and solve Sargent’s [Sargent, 1977] rational expectations version of Cagan’s model [Cagan, 1956] that connects the price level to the public’s anticipations of future money supplies.

Cagan did not use a rational expectations version of his model, but Sargent [Sargent, 1977]

Let

  • mtd be the log of the demand for money

  • mt be the log of the supply of money

  • pt be the log of the price level

It follows that pt+1pt is the rate of inflation.

The logarithm of the demand for real money balances mtdpt is an inverse function of the expected rate of inflation pt+1pt for t0:

mtdpt=β(pt+1pt),β>0

Equate the demand for log money mtd to the supply of log money mt in the above equation and rearrange to deduce that the logarithm of the price level pt is related to the logarithm of the money supply mt by

(65.8)#pt=(1λ)mt+λpt+1

where λβ1+β(0,1).

(We note that the characteristic polynomial if 1λ1z1=0 so that the zero of the characteristic polynomial in this case is λ(0,1) which here is inside the unit circle.)

Solving the first order difference equation (65.8) forward gives

(65.9)#pt=(1λ)j=0λjmt+j,

which is the unique stable solution of difference equation (65.8) among a class of more general solutions

(65.10)#pt=(1λ)j=0λjmt+j+cλt

that is indexed by the real number cR.

Because we want to focus on stable solutions, we set c=0.

Equation (65.10) attributes perfect foresight about the money supply sequence to the holders of real balances.

We begin by assuming that the log of the money supply is exogenous in the sense that it is an autonomous process that does not feed back on the log of the price level.

In particular, we assume that the log of the money supply is described by the linear state space system

(65.11)#mt=Gxtxt+1=Axt

where xt is an n×1 vector that does not include pt or lags of pt, A is an n×n matrix with eigenvalues that are less than λ1 in absolute values, and G is a 1×n selector matrix.

Variables appearing in the vector xt contain information that might help predict future values of the money supply.

We’ll start with an example in which xt includes only mt, possibly lagged values of m, and a constant.

An example of such an {mt} process that fits info state space system (65.11) is one that satisfies the second order linear difference equation

mt+1=α+ρ1mt+ρ2mt1

where the zeros of the characteristic polynomial (1ρ1zρ2z2) are strictly greater than 1 in modulus.

(Please see this QuantEcon lecture for more about characteristic polynomials and their role in solving linear difference equations.)

We seek a stable or non-explosive solution of the difference equation (65.8) that obeys the system comprised of (65.8)-(65.11).

By stable or non-explosive, we mean that neither mt nor pt diverges as t+.

This requires that we shut down the term cλt in equation (65.10) above by setting c=0

The solution we are after is

(65.12)#pt=Fxt

where

(65.13)#F=(1λ)G(IλA)1

Note

As mentioned above, an explosive solution of difference equation (65.8) can be constructed by adding to the right hand of (65.12) a sequence cλt where c is an arbitrary positive constant.

65.4. Some Python Code#

We’ll construct examples that illustrate (65.11).

Our first example takes as the law of motion for the log money supply the second order difference equation

(65.14)#mt+1=α+ρ1mt+ρ2mt1

that is parameterized by ρ1,ρ2,α

To capture this parameterization with system (65.9) we set

xt=[1mtmt1],A=[100αρ1ρ2010],G=[010]

Here is Python code

λ = .9

α = 0
ρ1 = .9
ρ2 = .05

A = np.array([[1,  0,  0],
              [α, ρ1, ρ2],
              [0,  1,  0]])
G = np.array([[0, 1, 0]])

The matrix A has one eigenvalue equal to unity.

It is associated with the A11 component that captures a constant component of the state xt.

We can verify that the two eigenvalues of A not associated with the constant in the state xt are strictly less than unity in modulus.

eigvals = np.linalg.eigvals(A)
print(eigvals)
[-0.05249378  0.95249378  1.        ]
(abs(eigvals) <= 1).all()
True

Now let’s compute F in formulas (65.12) and (65.13).

# compute the solution, i.e. forumula (3)
F = (1 - λ) * G @ np.linalg.inv(np.eye(A.shape[0]) - λ * A)
print("F= ",F)
F=  [[0.         0.66889632 0.03010033]]

Now let’s simulate paths of mt and pt starting from an initial value x0.

# set the initial state
x0 = np.array([1, 1, 0])

T = 100 # length of simulation

m_seq = np.empty(T+1)
p_seq = np.empty(T+1)

[m_seq[0]] = G @ x0
[p_seq[0]] = F @ x0

# simulate for T periods
x_old = x0
for t in range(T):

    x = A @ x_old

    [m_seq[t+1]] = G @ x
    [p_seq[t+1]] = F @ x

    x_old = x
plt.figure()
plt.plot(range(T+1), m_seq, label=r'$m_t$')
plt.plot(range(T+1), p_seq, label=r'$p_t$')
plt.xlabel('t')
plt.title(rf'λ={λ}, α={α}, $ρ_1$={ρ1}, $ρ_2$={ρ2}')
plt.legend()
plt.show()
_images/b749e8e83da961410063f5ce616b2b4883d2798a771cc9cc4f394be404265dc0.png

In the above graph, why is the log of the price level always less than the log of the money supply?

Because

  • according to equation (65.9), pt is a geometric weighted average of current and future values of mt, and

  • it happens that in this example future m’s are always less than the current m

65.5. Alternative Code#

We could also have run the simulation using the quantecon LinearStateSpace code.

The following code block performs the calculation with that code.

# construct a LinearStateSpace instance

# stack G and F
G_ext = np.vstack([G, F])

C = np.zeros((A.shape[0], 1))

ss = qe.LinearStateSpace(A, C, G_ext, mu_0=x0)
T = 100

# simulate using LinearStateSpace
x, y = ss.simulate(ts_length=T)

# plot
plt.figure()
plt.plot(range(T), y[0,:], label='$m_t$')
plt.plot(range(T), y[1,:], label='$p_t$')
plt.xlabel('t')
plt.title(f'λ={λ}, α={α}, $ρ_1$={ρ1}, $ρ_2$={ρ2}')
plt.legend()
plt.show()
_images/7482e29f04891e6ee288ae2ce3cf2da13e5aefc082680c0678a96adcabec693d.png

65.5.1. Special Case#

To simplify our presentation in ways that will let focus on an important idea, in the above second-order difference equation (65.14) that governs mt, we now set α=0, ρ1=ρ(1,1), and ρ2=0 so that the law of motion for mt becomes

(65.15)#mt+1=ρmt

and the state xt becomes

xt=mt.

Consequently, we can set G=1,A=ρ making our formula (65.13) for F become

F=(1λ)(1λρ)1.

so that the log the log price level satisfies

pt=Fmt.

Please keep these formulas in mind as we investigate an alternative route to and interpretation of our formula for F.

65.6. Another Perspective#

Above, we imposed stability or non-explosiveness on the solution of the key difference equation (65.8) in Cagan’s model by solving the unstable root of the characteristic polynomial forward.

To shed light on the mechanics involved in imposing stability on a solution of a potentially unstable system of linear difference equations and to prepare the way for generalizations of our model in which the money supply is allowed to feed back on the price level itself, we stack equations (65.8) and (65.15) to form the system

(65.16)#[mt+1pt+1]=[ρ0(1λ)/λλ1][mtpt]

or

(65.17)#yt+1=Hyt,t0

where

(65.18)#H=[ρ0(1λ)/λλ1].

Transition matrix H has eigenvalues ρ(0,1) and λ1>1.

Because an eigenvalue of H exceeds unity, if we iterate on equation (65.17) starting from an arbitrary initial vector y0=[m0p0] with m0>0,p0>0, we discover that in general absolute values of both components of yt diverge toward + as t+.

To substantiate this claim, we can use the eigenvector matrix decomposition of H that is available to us because the eigenvalues of H are distinct

H=QΛQ1.

Here Λ is a diagonal matrix of eigenvalues of H and Q is a matrix whose columns are eigenvectors associated with the corresponding eigenvalues.

Note that

Ht=QΛtQ1

so that

yt=QΛtQ1y0

For almost all initial vectors y0, the presence of the eigenvalue λ1>1 causes both components of yt to diverge in absolute value to +.

To explore this outcome in more detail, we can use the following transformation

yt=Q1yt

that allows us to represent the dynamics in a way that isolates the source of the propensity of paths to diverge:

yt+1=Λtyt

Staring at this equation indicates that unless

(65.19)#y0=[y1,00]

the path of yt and therefore the paths of both components of yt=Qyt will diverge in absolute value as t+. (We say that the paths explode)

Equation (65.19) also leads us to conclude that there is a unique setting for the initial vector y0 for which both components of yt do not diverge.

The required setting of y0 must evidently have the property that

Qy0=y0=[y1,00].

But note that since y0=[m0p0] and m0 is given to us an initial condition, p0 has to do all the adjusting to satisfy this equation.

Sometimes this situation is described by saying that while m0 is truly a state variable, p0 is a jump variable that must adjust at t=0 in order to satisfy the equation.

Thus, in a nutshell the unique value of the vector y0 for which the paths of yt do not diverge must have second component p0 that verifies equality (65.19) by setting the second component of y0 equal to zero.

The component p0 of the initial vector y0=[m0p0] must evidently satisfy

Q{2}y0=0

where Q{2} denotes the second row of Q1, a restriction that is equivalent to

(65.20)#Q21m0+Q22p0=0

where Qij denotes the (i,j) component of Q1.

Solving this equation for p0, we find

(65.21)#p0=(Q22)1Q21m0.

This is the unique stabilizing value of p0 expressed as a function of m0.

65.6.1. Refining the Formula#

We can get an even more convenient formula for p0 that is cast in terms of components of Q instead of components of Q1.

To get this formula, first note that because (Q21 Q22) is the second row of the inverse of Q and because Q1Q=I, it follows that

[Q21Q22][Q11Q21]=0

which implies that

Q21Q11+Q22Q21=0.

Therefore,

(Q22)1Q21=Q21Q111.

So we can write

(65.22)#p0=Q21Q111m0.

It can be verified that this formula replicates itself over time in the sense that

(65.23)#pt=Q21Q111mt.

To implement formula (65.23), we want to compute Q1 the eigenvector of Q associated with the stable eigenvalue ρ of Q.

By hand it can be verified that the eigenvector associated with the stable eigenvalue ρ is proportional to

Q1=[1λρ1λ].

Notice that if we set A=ρ and G=1 in our earlier formula for pt we get

pt=G(IλA)1mt=(1λ)(1λρ)1mt,

a formula that is equivalent with

pt=Q21Q111mt,

where

Q1=[Q11Q21].

65.6.2. Remarks about Feedback#

We have expressed (65.16) in what superficially appears to be a form in which yt+1 feeds back on yt, even though what we actually want to represent is that the component pt feeds forward on pt+1, and through it, on future mt+j, j=0,1,2,.

A tell-tale sign that we should look beyond its superficial “feedback” form is that λ1>1 so that the matrix H in (65.16) is unstable

  • it has one eigenvalue ρ that is less than one in modulus that does not imperil stability, but

  • it has a second eigenvalue λ1 that exceeds one in modulus and that makes H an unstable matrix

We’ll keep these observations in mind as we turn now to a case in which the log money supply actually does feed back on the log of the price level.

65.7. Log money Supply Feeds Back on Log Price Level#

An arrangement of eigenvalues that split around unity, with one being below unity and another being greater than unity, sometimes prevails when there is feedback from the log price level to the log money supply.

Let the feedback rule be

(65.24)#mt+1=ρmt+δpt

where ρ(0,1) and where we shall now allow δ0.

Warning: If things are to fit together as we wish to deliver a stable system for some initial value p0 that we want to determine uniquely, δ cannot be too large.

The forward-looking equation (65.8) continues to describe equality between the demand and supply of money.

We assume that equations (65.8) and (65.24) govern yt[mtpt] for t0.

The transition matrix H in the law of motion

yt+1=Hyt

now becomes

H=[ρδ(1λ)/λλ1].

We take m0 as a given initial condition and as before seek an initial value p0 that stabilizes the system in the sense that yt converges as t+.

Our approach is identical with the one followed above and is based on an eigenvalue decomposition in which, cross our fingers, one eigenvalue exceeds unity and the other is less than unity in absolute value.

When δ0 as we now assume, the eigenvalues of H will no longer be ρ(0,1) and λ1>1

We’ll just calculate them and apply the same algorithm that we used above.

That algorithm remains valid so long as the eigenvalues split around unity as before.

Again we assume that m0 is an initial condition, but that p0 is not given but to be solved for.

Let’s write and execute some Python code that will let us explore how outcomes depend on δ.

def construct_H(ρ, λ, δ):
    "contruct matrix H given parameters."

    H = np.empty((2, 2))
    H[0, :] = ρ,δ
    H[1, :] = - (1 - λ) / λ, 1 / λ

    return H

def H_eigvals(ρ=.9, λ=.5, δ=0):
    "compute the eigenvalues of matrix H given parameters."

    # construct H matrix
    H = construct_H(ρ, λ, δ)

    # compute eigenvalues
    eigvals = np.linalg.eigvals(H)

    return eigvals
H_eigvals()
array([2. , 0.9])

Notice that a negative δ will not imperil the stability of the matrix H, even if it has a big absolute value.

# small negative δ
H_eigvals(δ=-0.05)
array([0.8562829, 2.0437171])
# large negative δ
H_eigvals(δ=-1.5)
array([0.10742784, 2.79257216])

A sufficiently small positive δ also causes no problem.

# sufficiently small positive δ
H_eigvals(δ=0.05)
array([0.94750622, 1.95249378])

But a large enough positive δ makes both eigenvalues of H strictly greater than unity in modulus.

For example,

H_eigvals(δ=0.2)
array([1.12984379, 1.77015621])

We want to study systems in which one eigenvalue exceeds unity in modulus while the other is less than unity in modulus, so we avoid values of δ that are too.

That is, we want to avoid too much positive feedback from pt to mt+1.

def magic_p0(m0, ρ=.9, λ=.5, δ=0):
    """
    Use the magic formula (8) to compute the level of p0
    that makes the system stable.
    """

    H = construct_H(ρ, λ, δ)
    eigvals, Q = np.linalg.eig(H)

    # find the index of the smaller eigenvalue
    ind = 0 if eigvals[0] < eigvals[1] else 1

    # verify that the eigenvalue is less than unity
    if eigvals[ind] > 1:

        print("both eigenvalues exceed unity in modulus")

        return None

    p0 = Q[1, ind] / Q[0, ind] * m0

    return p0

Let’s plot how the solution p0 changes as m0 changes for different settings of δ.

m_range = np.arange(0.1, 2., 0.1)

for δ in [-0.05, 0, 0.05]:
    plt.plot(m_range, [magic_p0(m0, δ=δ) for m0 in m_range], label=f"δ={δ}")
plt.legend()

plt.xlabel(r"$m_0$")
plt.ylabel(r"$p_0$")
plt.show()
_images/98bbe168aefa657d9cc08b27a8b330dae86e54aea478ada9a128414da2d2d326.png

To look at things from a different angle, we can fix the initial value m0 and see how p0 changes as δ changes.

m0 = 1

δ_range = np.linspace(-0.05, 0.05, 100)
plt.plot(δ_range, [magic_p0(m0, δ=δ) for δ in δ_range])
plt.xlabel(r'$\delta$')
plt.ylabel(r'$p_0$')
plt.title(rf'$m_0$={m0}')
plt.show()
_images/2c9f7110e3f817c87b6747d4feceb2026759b7c671740cc0b584f36135ffae45.png

Notice that when δ is large enough, both eigenvalues exceed unity in modulus, causing a stabilizing value of p0 not to exist.

magic_p0(1, δ=0.2)
both eigenvalues exceed unity in modulus

65.8. Big P, Little p Interpretation#

It is helpful to view our solutions of difference equations having feedback from the price level or inflation to money or the rate of money creation in terms of the Big K, little k idea discussed in Rational Expectations Models.

This will help us sort out what is taken as given by the decision makers who use the difference equation (65.9) to determine pt as a function of their forecasts of future values of mt.

Let’s write the stabilizing solution that we have computed using the eigenvector decomposition of H as Pt=Fmt, where

F=Q21Q111.

Then from Pt+1=Fmt+1 and mt+1=ρmt+δPt we can deduce the recursion Pt+1=Fρmt+FδPt and create the stacked system

[mt+1Pt+1]=[ρδFρFδ][mtPt]

or

xt+1=Axt

where xt=[mtPt].

Apply formula (65.13) for F to deduce that

pt=F[mtPt]=F[mtFmt]

which implies that

pt=[F1F2][mtFmt]=F1mt+F2Fmt

so that we can anticipate that

F=F1+F2F

We shall verify this equality in the next block of Python code that implements the following computations.

  1. For the system with δ0 so that there is feedback, we compute the stabilizing solution for pt in the form pt=Fmt where F=Q21Q111 as above.

  2. Recalling the system (65.11), (65.12), and (65.13) above, we define xt=[mtPt] and notice that it is Big Pt and not little pt here. Then we form A and G as A=[ρδFρFδ] and G=[10] and we compute [F1F2]F from equation (65.13) above.

  3. We compute F1+F2F and compare it with F and check for the anticipated equality.

# set parameters
ρ = .9
λ = .5
δ = .05
# solve for F_star
H = construct_H(ρ, λ, δ)
eigvals, Q = np.linalg.eig(H)

ind = 0 if eigvals[0] < eigvals[1] else 1
F_star = Q[1, ind] / Q[0, ind]
F_star
0.950124378879109
# solve for F_check
A = np.empty((2, 2))
A[0, :] = ρ, δ
A[1, :] = F_star * A[0, :]

G = np.array([1, 0])

F_check= (1 - λ) * G @ np.linalg.inv(np.eye(2) - λ * A)
F_check
array([0.92755597, 0.02375311])

Compare F with F1+F2F

F_check[0] + F_check[1] * F_star, F_star
(0.95012437887911, 0.950124378879109)

65.9. Fun with SymPy#

This section is a gift for readers who have made it this far.

It puts SymPy to work on our model.

Thus, we use Sympy to compute some key objects comprising the eigenvector decomposition of H.

We start by generating an H with nonzero δ.

λ, δ, ρ = symbols('λ, δ, ρ')
H1 = Matrix([[ρ,δ], [- (1 - λ) / λ, λ ** -1]])
H1
[ρδλ1λ1λ]
H1.eigenvals()
{λρ+12λ4δλ24δλ+λ2ρ22λρ+12λ:1, λρ+12λ+4δλ24δλ+λ2ρ22λρ+12λ:1}
H1.eigenvects()
[(λρ+12λ4δλ24δλ+λ2ρ22λρ+12λ, 1, [[λ(λρ+12λ4δλ24δλ+λ2ρ22λρ+12λ)λ11λ11]]), (λρ+12λ+4δλ24δλ+λ2ρ22λρ+12λ, 1, [[λ(λρ+12λ+4δλ24δλ+λ2ρ22λρ+12λ)λ11λ11]])]

Now let’s compute H when δ is zero.

H2 = Matrix([[ρ,0], [- (1 - λ) / λ, λ ** -1]])
H2
[ρ0λ1λ1λ]
H2.eigenvals()
{1λ:1, ρ:1}
H2.eigenvects()
[(1λ, 1, [[01]]), (ρ, 1, [[λρ1λ11]])]

Below we do induce SymPy to do the following fun things for us analytically:

  1. We compute the matrix Q whose first column is the eigenvector associated with ρ. and whose second column is the eigenvector associated with λ1.

  2. We use SymPy to compute the inverse Q1 of Q (both in symbols).

  3. We use SymPy to compute Q21Q111 (in symbols).

  4. Where Qij denotes the (i,j) component of Q1, we use SymPy to compute (Q22)1Q21 (again in symbols)

# construct Q
vec = []
for i, (eigval, _, eigvec) in enumerate(H2.eigenvects()):

    vec.append(eigvec[0])

    if eigval == ρ:
        ind = i

Q = vec[ind].col_insert(1, vec[1-ind])
Q
[λρ1λ1011]

Q1

Q_inv = Q ** (-1)
Q_inv
[λ1λρ101λλρ11]

Q21Q111

Q[1, 0] / Q[0, 0]
λ1λρ1

(Q22)1Q21

- Q_inv[1, 0] / Q_inv[1, 1]
1λλρ1