/* * Copyright © 2006 Ondra Kamenik * Copyright © 2019 Dynare Team * * This file is part of Dynare. * * Dynare is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Dynare is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Dynare. If not, see . */ #ifndef OGP_ATOM_SUBSTITUTIONS_H #define OGP_ATOM_SUBSTITUTIONS_H #include "fine_atoms.hh" #include namespace ogp { using std::string; using std::map; using std::pair; /** This class tracts an information about the performed * substitutions. In fact, there is only one number to keep track * about, this is a number of substitutions. */ struct SubstInfo { int num_substs{0}; SubstInfo() = default; }; /** This class tracks all atom substitutions during the job and * then builds structures when all substitutions are finished. */ class AtomSubstitutions { public: using Tshiftname = pair; using Tshiftmap = map; using Tshiftnameset = set; using Toldnamemap = map; protected: /** This maps a new name to a shifted old name. This is, one * entry looks as "a_m3 ==> a(-3)", saying that a variable * "a_m3" corresponds to a variable "a" lagged by 3. */ Tshiftmap new2old; /** This is inverse to new2old, which is not unique. For old * name, say "a", it says what new names are derived with what * shifts from the "a". For example, it can map "a" to a two * element set {["a_m3", +3], ["a_p2", -2]}. This says that * leading "a_m3" by 3 one gets old "a" and lagging "a_p2" by * 2 one gets also old "a". */ Toldnamemap old2new; /** This is a reference to old atoms with multiple leads and * lags. They are supposed to be used with parsing finished * being had called, so that the external ordering is * available. */ const FineAtoms &old_atoms; /** This is a reference to new atoms. All name pointers point * to storage of these atoms. */ FineAtoms &new_atoms; /** Substitutions information. */ SubstInfo info; public: /** Create the object with reference to the old and new * atoms. In the beginning, old atoms are supposed to be with * parsing_finished() called, and new atoms a simple copy of * old atoms. The new atoms will be an instance of SAtoms. All * substitution job is done by a substitution method of the * new atoms. */ AtomSubstitutions(const FineAtoms &oa, FineAtoms &na) : old_atoms(oa), new_atoms(na) { } /** Construct a copy of the object using a different instances * of old atoms and new atoms, which are supposed to be * semantically same as the atoms from as. */ AtomSubstitutions(const AtomSubstitutions &as, const FineAtoms &oa, FineAtoms &na); virtual ~AtomSubstitutions() = default; /** This is called during the substitution job from the * substitution method of the new atoms. This says that the * new name, say "a_m3" is a substitution of old name "a" * shifted by -3. */ void add_substitution(string newname, string oldname, int tshift); /** This is called when all substitutions are finished. This * forms the new external ordering of the new atoms and calls * parsing_finished() for the new atoms with the given ordering type. */ void substitutions_finished(VarOrdering::ord_type ot); /** Returns a new name for old name and given tshift. For "a" * and tshift=-3, it returns "a_m3". If there is no such * substitution, it returns an empty string. */ string get_new4old(const string &oldname, int tshift) const; /** Return new2old. */ const Tshiftmap & get_new2old() const { return new2old; } /** Return old2new. */ const Toldnamemap & get_old2new() const { return old2new; } /** Return substitution info. */ const SubstInfo & get_info() const { return info; } /** Return old atoms. */ const FineAtoms & get_old_atoms() const { return old_atoms; } /** Return new atoms. */ const FineAtoms & get_new_atoms() const { return new_atoms; } /** Debug print. */ void print() const; }; class SAtoms : public FineAtoms { public: SAtoms() : FineAtoms() { } SAtoms(const SAtoms &sa) = default; /** This substitutes all lags and leads for all exogenous and * all lags and leads greater than 1 for all endogenous * variables. This is useful for perfect foresight problems * where we can do that. */ void substituteAllLagsAndLeads(FormulaParser &fp, AtomSubstitutions &as); /** This substitutes all lags of all endo and exo and one step * leads of all exo variables. This is useful for stochastic * models where we cannot solve leads more than 1. */ void substituteAllLagsAndExo1Leads(FormulaParser &fp, AtomSubstitutions &as); protected: /** This finds an endogenous variable name which occurs between * ll1 and ll2 included. */ string findEndoWithLeadInInterval(int ll1, int ll2) const { return findNameWithLeadInInterval(get_endovars(), ll1, ll2); } /** This finds an exogenous variable name which occurs between * ll1 and ll2 included. */ string findExoWithLeadInInterval(int ll1, int ll2) const { return findNameWithLeadInInterval(get_exovars(), ll1, ll2); } /** This attempts to find a non registered name of the form * _m or _p. A letter 'p' is * chosen if ll is positive, 'm' if negative. If a name of * such form is already registered, one more character (either * 'p' or 'm') is added and the test is performed again. The * resulting name is returned in a string out. */ void attemptAuxName(const string &str, int ll, string &out) const; /** This makes auxiliary variables to eliminate all leads/lags * greater/less than or equal to start up to the limit_lead * for a variable with the given name. If the limit_lead is * greater/less than the maxlead/minlag of the variable, than * maxlead/minlag is used. This process is recorded in * AtomSubstitutions. The new auxiliary variables and their * atoms are created in this object. The auxiliary equations * are created in the given FormulaParser. The value of step * is allowed to be either -1 (lags) or +1 (leads). */ void makeAuxVariables(const string &name, int step, int start, int limit_lead, FormulaParser &fp, AtomSubstitutions &as); private: /** This is a worker routine for findEndoWithLeadInInterval * and findExoWithLeadInInterval. */ string findNameWithLeadInInterval(const vector &names, int ll1, int ll2) const; }; }; #endif