// Copyright 2004, Ondra Kamenik #include "kord_exception.hh" #include "first_order.hh" #include double qz_criterium = 1.000001; /* This is a function which selects the eigenvalues pair used by |dgges|. See documentation to DGGES for details. Here we want to select (return true) the pairs for which $\alpha<\beta$. */ lapack_int order_eigs(const double *alphar, const double *alphai, const double *beta) { return (*alphar **alphar + *alphai **alphai < *beta **beta * qz_criterium * qz_criterium); } /* Here we solve the linear approximation. The result are the matrices $g_{y^*}$ and $g_u$. The method solves the first derivatives of $g$ so that the following equation would be true: $$E_t[F(y^*_{t-1},u_t,u_{t+1},\sigma)] = E_t[f(g^{**}(g^*(y_{t-1}^*,u_t,\sigma), u_{t+1}, \sigma), g(y_{t-1}^*,u_t,\sigma), y^*_{t-1},u_t)]=0$$ where $f$ is a given system of equations. It is known that $g_{y^*}$ is given by $F_{y^*}=0$, $g_u$ is given by $F_u=0$, and $g_\sigma$ is zero. The only input to the method are the derivatives |fd| of the system $f$, and partitioning of the vector $y$ (from object). */ void FirstOrder::solve(const TwoDMatrix &fd) { JournalRecordPair pa(journal); pa << "Recovering first order derivatives " << endrec; ::qz_criterium = FirstOrder::qz_criterium; // ********************** // solve derivatives |gy| // ********************** /* The derivatives $g_{y^*}$ are retrieved from the equation $F_{y^*}=0$. The calculation proceeds as follows: \orderedlist \li For each variable appearing at both $t-1$ and $t-1$ we add a dummy variable, so that the predetermined variables and forward looking would be disjoint. This is, the matrix of the first derivatives of the system written as: $$\left[\matrix{f_{y^{**}_+}&f_{ys}&f_{yp}&f_{yb}&f_{yf}&f_{y^*_-}}\right],$$ where $f_{ys}$, $f_{yp}$, $f_{yb}$, and $f_{yf}$ are derivatives wrt static, predetermined, both, forward looking at time $t$, is rewritten to the matrix: $$\left[ \matrix{f_{y^{**}_+}&f_{ys}&f_{yp}&f_{yb}&0&f_{yf}&f_{y^*_-}\cr 0 &0 &0 &I &-I&0 &0} \right],$$ where the second line has number of rows equal to the number of both variables. \li Next, provided that forward looking and predetermined are disjoint, the equation $F_{y^*}=0$ is written as: $$\left[f_+{y^{**}_+}\right]\left[g_{y^*}^{**}\right]\left[g_{y^*}^*\right] +\left[f_{ys}\right]\left[g^s_{y^*}\right] +\left[f_{y^*}\right]\left[g^*_{y^*}\right] +\left[f_{y^{**}}\right]\left[g^{**}_{y^*}\right]+\left[f_{y^*_-}\right]=0$$ This is rewritten as $$\left[\matrix{f_{y^*}&0&f_{y^{**}_+}}\right] \left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]\left[g_{y^*}^*\right]+ \left[\matrix{f_{y^*_-}&f_{ys}&f_{y^{**}}}\right] \left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]=0 $$ Now, in the above equation, there are the auxiliary variables standing for copies of both variables at time $t+1$. This equation is then rewritten as: $$ \left[\matrix{f_{yp}&f_{yb}&0&f_{y^{**}_+}\cr 0&I&0&0}\right] \left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]\left[g_{y^*}^*\right]+ \left[\matrix{f_{y^*_-}&f_{ys}&0&f_{yf}\cr 0&0&-I&0}\right] \left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]=0 $$ The two matrices are denoted as $D$ and $-E$, so the equation takes the form: $$D\left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]\left[g_{y^*}^*\right]= E\left[\matrix{I\cr g^s_{y^*}\cr g^{**}_{y^*}}\right]$$ \li Next we solve the equation by Generalized Schur decomposition: $$ \left[\matrix{T_{11}&T_{12}\cr 0&T_{22}}\right] \left[\matrix{Z_{11}^T&Z_{21}^T\cr Z_{12}^T&Z_{22}^T}\right] \left[\matrix{I\cr X}\right]\left[g_{y^*}^*\right]= \left[\matrix{S_{11}&S_{12}\cr 0&S_{22}}\right] \left[\matrix{Z_{11}^T&Z_{21}^T\cr Z_{12}^T&Z_{22}^T}\right] \left[\matrix{I\cr X}\right] $$ We reorder the eigenvalue pair so that $S_{ii}/T_{ii}$ with modulus less than one would be in the left-upper part. \li The Blanchard--Kahn stability argument implies that the pairs with modulus less that one will be in and only in $S_{11}/T_{11}$. The exploding paths will be then eliminated when $$ \left[\matrix{Z_{11}^T&Z_{21}^T\cr Z_{12}^T&Z_{22}^T}\right] \left[\matrix{I\cr X}\right]= \left[\matrix{Y\cr 0}\right] $$ From this we have, $Y=Z_{11}^{-1}$, and $X=Z_{21}Y$, or equivalently $X=-Z_{22}^{-T}Z_{12}^T$. From the equation, we get $\left[g_{y^*}^*\right]=Y^{-1}T_{11}^{-1}S_{11}Y$, which is $Z_{11}T_{11}^{-1}S_{11}Z_{11}^{-1}$. \li We then copy the derivatives to storage |gy|. Note that the derivatives of both variables are in $X$ and in $\left[g_{y^*}^*\right]$, so we check whether the two submatrices are the same. The difference is only numerical error. \endorderedlist */ // setup submatrices of |f| /* Here we setup submatrices of the derivatives |fd|. */ int off = 0; ConstTwoDMatrix fyplus(fd, off, ypart.nyss()); off += ypart.nyss(); ConstTwoDMatrix fyszero(fd, off, ypart.nstat); off += ypart.nstat; ConstTwoDMatrix fypzero(fd, off, ypart.npred); off += ypart.npred; ConstTwoDMatrix fybzero(fd, off, ypart.nboth); off += ypart.nboth; ConstTwoDMatrix fyfzero(fd, off, ypart.nforw); off += ypart.nforw; ConstTwoDMatrix fymins(fd, off, ypart.nys()); off += ypart.nys(); ConstTwoDMatrix fuzero(fd, off, nu); off += nu; // form matrix $D$ lapack_int n = ypart.ny()+ypart.nboth; TwoDMatrix matD(n, n); matD.zeros(); matD.place(fypzero, 0, 0); matD.place(fybzero, 0, ypart.npred); matD.place(fyplus, 0, ypart.nys()+ypart.nstat); for (int i = 0; i < ypart.nboth; i++) matD.get(ypart.ny()+i, ypart.npred+i) = 1.0; lapack_int ldb = matD.getLD(); // form matrix $E$ TwoDMatrix matE(n, n); matE.zeros(); matE.place(fymins, 0, 0); matE.place(fyszero, 0, ypart.nys()); matE.place(fyfzero, 0, ypart.nys()+ypart.nstat+ypart.nboth); for (int i = 0; i < ypart.nboth; i++) matE.get(ypart.ny()+i, ypart.nys()+ypart.nstat+i) = -1.0; matE.mult(-1.0); lapack_int lda = matE.getLD(); // solve generalized Schur TwoDMatrix vsl(n, n); TwoDMatrix vsr(n, n); lapack_int ldvsl = vsl.getLD(), ldvsr = vsr.getLD(); lapack_int lwork = 100*n+16; Vector work(lwork); auto *bwork = new lapack_int[n]; lapack_int info; lapack_int sdim2 = sdim; dgges("N", "V", "S", order_eigs, &n, matE.getData().base(), &lda, matD.getData().base(), &ldb, &sdim2, alphar.base(), alphai.base(), beta.base(), vsl.getData().base(), &ldvsl, vsr.getData().base(), &ldvsr, work.base(), &lwork, bwork, &info); if (info) { throw KordException(__FILE__, __LINE__, "DGGES returns an error in FirstOrder::solve"); } sdim = sdim2; bk_cond = (sdim == ypart.nys()); delete[] bwork; // make submatrices of right space /* Here we setup submatrices of the matrix $Z$. */ ConstGeneralMatrix z11(vsr, 0, 0, ypart.nys(), ypart.nys()); ConstGeneralMatrix z12(vsr, 0, ypart.nys(), ypart.nys(), n-ypart.nys()); ConstGeneralMatrix z21(vsr, ypart.nys(), 0, n-ypart.nys(), ypart.nys()); ConstGeneralMatrix z22(vsr, ypart.nys(), ypart.nys(), n-ypart.nys(), n-ypart.nys()); // calculate derivatives of static and forward /* Here we calculate $X=-Z_{22}^{-T}Z_{12}^T$, where $X$ is |sfder| in the code. */ GeneralMatrix sfder(transpose(z12)); z22.multInvLeftTrans(sfder); sfder.mult(-1); // calculate derivatives of predetermined /* Here we calculate $g_{y^*}^*=Z_{11}T^{-1}_{11}S_{11}Z_{11}^{-1} =Z_{11}T^{-1}_{11}(Z_{11}^{-T}S^T_{11})^T$. */ ConstGeneralMatrix s11(matE, 0, 0, ypart.nys(), ypart.nys()); ConstGeneralMatrix t11(matD, 0, 0, ypart.nys(), ypart.nys()); GeneralMatrix dumm(transpose(s11)); z11.multInvLeftTrans(dumm); GeneralMatrix preder(transpose(dumm)); t11.multInvLeft(preder); preder.multLeft(z11); // copy derivatives to |gy| gy.place(preder, ypart.nstat, 0); GeneralMatrix sder(sfder, 0, 0, ypart.nstat, ypart.nys()); gy.place(sder, 0, 0); GeneralMatrix fder(sfder, ypart.nstat+ypart.nboth, 0, ypart.nforw, ypart.nys()); gy.place(fder, ypart.nstat+ypart.nys(), 0); // check difference for derivatives of both GeneralMatrix bder((const GeneralMatrix &)sfder, ypart.nstat, 0, ypart.nboth, ypart.nys()); GeneralMatrix bder2(preder, ypart.npred, 0, ypart.nboth, ypart.nys()); bder.add(-1, bder2); b_error = bder.getData().getMax(); // ********************** // solve derivatives |gu| // ********************** /* The equation $F_u=0$ can be written as $$ \left[f_{y^{**}_+}\right]\left[g^{**}_{y^*}\right]\left[g_u^*\right]+ \left[f_y\right]\left[g_u\right]+\left[f_u\right]=0 $$ and rewritten as $$ \left[f_y + \left[\matrix{0&f_{y^{**}_+}g^{**}_{y^*}&0}\right]\right]g_u=f_u $$ This is exactly done here. The matrix $\left[f_y +\left[\matrix{0&f_{y^{**}_+}g^{**}_{y^*}&0}\right]\right]$ is |matA| in the code. */ GeneralMatrix matA(ypart.ny(), ypart.ny()); matA.zeros(); ConstGeneralMatrix gss(gy, ypart.nstat+ypart.npred, 0, ypart.nyss(), ypart.nys()); matA.place(fyplus * gss, 0, ypart.nstat); ConstGeneralMatrix fyzero(fd, 0, ypart.nyss(), ypart.ny(), ypart.ny()); matA.add(1.0, fyzero); gu.zeros(); gu.add(-1.0, fuzero); ConstGeneralMatrix(matA).multInvLeft(gu); journalEigs(); if (!gy.isFinite() || !gu.isFinite()) { throw KordException(__FILE__, __LINE__, "NaN or Inf asserted in first order derivatives in FirstOrder::solve"); } } void FirstOrder::journalEigs() { if (bk_cond) { JournalRecord jr(journal); jr << "Blanchard-Kahn conditition satisfied, model stable" << endrec; } else { JournalRecord jr(journal); jr << "Blanchard-Kahn condition not satisfied, model not stable: sdim=" << sdim << " " << "npred=" << ypart.nys() << endrec; } if (!bk_cond) { for (int i = 0; i < alphar.length(); i++) { if (i == sdim || i == ypart.nys()) { JournalRecord jr(journal); jr << "---------------------------------------------------- "; if (i == sdim) jr << "sdim"; else jr << "npred"; jr << endrec; } JournalRecord jr(journal); double mod = sqrt(alphar[i]*alphar[i]+alphai[i]*alphai[i]); mod = mod/round(100000*std::abs(beta[i]))*100000; jr << i << "\t(" << alphar[i] << "," << alphai[i] << ") / " << beta[i] << " \t" << mod << endrec; } } }