Block decomposition: add specialized normalization algorithm for purely backward models
If the model is purely backward, determine whether all original equations have a single contemporaneous endogenous on the LHS. If this is the case, then first try a normalization by enforcing that each original equation is matched with the endogenous on the LHS. This helps with the simulation of purely backward models, where equations are renormalized with mfs=3, since it produces a simpler system to be recursively evaluated/solved.master
parent
d246f9f99a
commit
2d3e3eff6f
|
@ -283,6 +283,25 @@ ModelTree::computeNonSingularNormalization(const eval_context_t &eval_context)
|
|||
|
||||
cout << "Normalizing the " << modelClassName() << "..." << endl;
|
||||
|
||||
/* If the model is purely backward, determine whether all original equations
|
||||
have a single contemporaneous endogenous on the LHS. If this is the case,
|
||||
then first try a normalization by enforcing that each original equation is
|
||||
matched with the endogenous on the LHS. */
|
||||
if (time_recursive_block_decomposition)
|
||||
{
|
||||
auto [normalize_by_lhs, lhs_symbolic_jacobian] { computeLeftHandSideSymbolicJacobian() };
|
||||
if (normalize_by_lhs)
|
||||
try
|
||||
{
|
||||
computeNormalization(lhs_symbolic_jacobian);
|
||||
return true;
|
||||
}
|
||||
catch (ModelNormalizationFailed &e)
|
||||
{
|
||||
cerr << "WARNING: All equations are written so that a single contemporaneous endogenous variable appears on the left-hand side. This suggests a natural normalization of the model. However, variable " << e.unmatched_endo << " could not be matched with an equation. Check whether this is desired." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
auto contemporaneous_jacobian {evaluateAndReduceJacobian(eval_context)};
|
||||
|
||||
// Compute the maximum value of each row of the contemporaneous Jacobian matrix
|
||||
|
@ -1826,6 +1845,35 @@ ModelTree::computeSymbolicJacobian(bool contemporaneous_only) const
|
|||
return symbolic_jacobian;
|
||||
}
|
||||
|
||||
pair<bool, ModelTree::jacob_map_t>
|
||||
ModelTree::computeLeftHandSideSymbolicJacobian() const
|
||||
{
|
||||
jacob_map_t lhs_symbolic_jacobian;
|
||||
auto not_contemporaneous = [](const pair<int, int> &p) { return p.second != 0; };
|
||||
|
||||
for (int eq {0}; eq < static_cast<int>(equations.size()); eq++)
|
||||
if (equations_lineno[eq]) // Hand-written equation: test whether LHS has single contemporaneous endo
|
||||
{
|
||||
set<pair<int, int>> endos_and_lags;
|
||||
equations[eq]->arg1->collectEndogenous(endos_and_lags);
|
||||
erase_if(endos_and_lags, not_contemporaneous);
|
||||
if (endos_and_lags.size() == 1)
|
||||
lhs_symbolic_jacobian.try_emplace({ eq, endos_and_lags.begin()->first }, 1);
|
||||
else
|
||||
return { false, {} };
|
||||
}
|
||||
else // Generated equation: keep all endos on both LHS and RHS
|
||||
{
|
||||
set<pair<int, int>> endos_and_lags;
|
||||
equations[eq]->collectEndogenous(endos_and_lags);
|
||||
erase_if(endos_and_lags, not_contemporaneous);
|
||||
for (const auto &[endo, lag] : endos_and_lags)
|
||||
lhs_symbolic_jacobian.try_emplace({ eq, endo }, 1);
|
||||
}
|
||||
|
||||
return { true, lhs_symbolic_jacobian };
|
||||
}
|
||||
|
||||
void
|
||||
ModelTree::updateReverseVariableEquationOrderings()
|
||||
{
|
||||
|
|
|
@ -433,6 +433,17 @@ private:
|
|||
variables; otherwise also considers leads and lags. */
|
||||
jacob_map_t computeSymbolicJacobian(bool contemporaneous_only) const;
|
||||
|
||||
/* Compute a pseudo-Jacobian whose all elements are either zero or one.
|
||||
For the equations that were originally written by the user (identified as
|
||||
those having an associated line number), checks whether there is a single
|
||||
contemporaneous endogenous on the left-hand side; if yes, only this
|
||||
endogenous is associated with a one on the line of the corresponding
|
||||
equation; otherwise, returns false as the first output argument and
|
||||
aborts the computation.
|
||||
For the other equations, fills the corresponding lines as is done
|
||||
by computeSymbolicJacobian(true). */
|
||||
pair<bool, jacob_map_t> computeLeftHandSideSymbolicJacobian() const;
|
||||
|
||||
// Compute {var,eq}_idx_orig2block from {var,eq}_idx_block2orig
|
||||
void updateReverseVariableEquationOrderings();
|
||||
|
||||
|
|
Loading…
Reference in New Issue