201 lines
7.2 KiB
C++
201 lines
7.2 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef OGP_ATOM_SUBSTITUTIONS_H
|
|
#define OGP_ATOM_SUBSTITUTIONS_H
|
|
|
|
#include "fine_atoms.hh"
|
|
|
|
#include <string>
|
|
|
|
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<string, int>;
|
|
using Tshiftmap = map<string, Tshiftname>;
|
|
using Tshiftnameset = set<Tshiftname>;
|
|
using Toldnamemap = map<string, Tshiftnameset>;
|
|
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
|
|
* <str>_m<abs(ll)> or <str>_p<abs(ll)>. 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<string> &names,
|
|
int ll1, int ll2) const;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
#endif
|