This is made possible by the getLagEquivalenceClass() method introduced in the
previous commit.
Previously, the static version of the LHS expressions was used.
As a consequence, drop ModFile::diff_static_model, now useless.
Previously, for testing whether two diff() expressions or two unary ops were
the lead/lag of each other, the preprocessor would test whether they have the
same static representation. This is ok for simple expressions (e.g.
diff(x(-1))), but not for more complex ones (e.g. diff(x-y) and diff(x(-1)-y)
should not be given the same auxiliary variable).
This commit fixes this by properly constructing the equivalence relationship
and choosing a representative within each equivalence class. See the comments
above lag_equivalence_table_t in ExprNode.hh for more details.
Closes#27
Those methods can return a negative value in some cases. For example,
maxLead(x₋₁) = −1.
But constants were always returning a value of zero, which means that we had
inconsistent behaviour like maxLead(x₋₁ + 2) = 0.
This commits fixes the behaviour by making these methods return the smallest
possible integer when called on constants.
- ExprNode::maxLag() and ExprNode::maxLead() now take into account exogenous
deterministic variables, for consistency with M_.maximum_{lead,lag}
- ExprNode::maxLag() no longer behaves as if diff() operators were
expanded (i.e. it now returns 1 on diff(x(-1))), for consistency with
maxEndoLag() and maxExoLag()
- New ExprNode::maxLagWithDiffsExpanded() method, that behaves as maxLag() used
to behave (except that it also takes exogenous deterministic into account)
Previously, this function was counting the total number of diff() operators in
an expression. But this is not very useful, and is potentially misleading,
because in practice we use this function to compute the maximum lag on
variables in levels.
This function now returns the maximum number of nested diffs.
For example, on diff(x)+diff(diff(y)), this function was returning 3, and it
now returns 2.
The engine is now more robust and should reject any expression that does not
conform to the expected form. It is also able to deal with more cases, such as
terms appearing with a minus sign, or variables in the middle of a
three-factors product.
BTW, use a std::tuple for storing the result of the matching inside
PacExpectationNode, and change the order of components within the
structure (variable first, scalar last).
This facilitates switching variable types on the fly. In particular, this
allows removing the hack in DynamicModel::updateAfterVariableChange() that way
basically recreating all the nodes after the type change.