1 /*
2  * Copyright © 2006 Ondra Kamenik
3  * Copyright © 2019 Dynare Team
4  *
5  * This file is part of Dynare.
6  *
7  * Dynare is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dynare is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef OGP_ATOM_ASSIGNINGS_H
22 #define OGP_ATOM_ASSIGNINGS_H
23 
24 #include "static_atoms.hh"
25 #include "formula_parser.hh"
26 #include "atom_substitutions.hh"
27 
28 #include <vector>
29 #include <map>
30 
31 namespace ogp
32 {
33   class AtomAsgnEvaluator;
34 
35   /** This class represents atom assignments used in parameters
36    * settings and initval initialization. It maintains atoms of the
37    * all expressions on the right hand side, the parsed formulas of
38    * the right hand sides, and the information about the left hand
39    * sides. See documentation to the order member below. */
40   class AtomAssignings
41   {
42     friend class AtomAsgnEvaluator;
43   protected:
44     using Tvarintmap = std::map<string, int>;
45     /** All atoms which should be sufficient for formulas at the
46      * right hand sides. The atoms should be filled with names
47      * (preregistered). This is a responsibility of the caller. */
48     StaticAtoms &atoms;
49     /** The formulas of right hand sides. */
50     FormulaParser expr;
51     /** Name storage of the names from left hand sides. */
52     NameStorage left_names;
53     /** Information on left hand sides. This maps a name to the
54      * index of its assigned expression in expr. More than one
55      * name may reference to the same expression. */
56     Tvarintmap lname2expr;
57     /** Information on left hand sides. If order[i] >= 0, then it
58      * says that i-th expression in expr is assigned to atom with
59      * order[i] tree index. */
60     std::vector<int> order;
61   public:
62     /** Construct the object using the provided static atoms. */
AtomAssignings(StaticAtoms & a)63     AtomAssignings(StaticAtoms &a) : atoms(a), expr(atoms)
64     {
65     }
66     /** Make a copy with provided reference to (posibly different)
67      * static atoms. */
68     AtomAssignings(const AtomAssignings &aa, StaticAtoms &a);
69     virtual ~AtomAssignings() = default;
70     /** Parse the assignments from the given string. */
71     void parse(const string &stream);
72     /** Process a syntax error from bison. */
73     void error(string mes);
74     /** Add an assignment of the given name to the given
75      * double. Can be called by a user, anytime. */
76     void add_assignment_to_double(string name, double val);
77     /** Add an assignment. Called from assign.y. */
78     void add_assignment(int asgn_off, const string &str, int name_len,
79                         int right_off, int right_len);
80     /** This applies old2new map (possibly from atom
81      * substitutions) to this object. It registers new variables
82      * in the atoms, and adds the expressions to expr, and left
83      * names to lname2expr. The information about dynamical part
84      * of substitutions is ignored, since we are now in the static
85      * world. */
86     void apply_subst(const AtomSubstitutions::Toldnamemap &mm);
87     /** Debug print. */
88     void print() const;
89   };
90 
91   /** This class basically evaluates the atom assignments
92    * AtomAssignings, so it inherits from ogp::FormulaEvaluator. It
93    * is also a storage for the results of the evaluation stored as a
94    * vector, so the class inherits from std::vector<double> and
95    * ogp::FormulaEvalLoader. As the expressions for atoms are
96    * evaluated, the results are values for atoms which will be
97    * used in subsequent evaluations. For this reason, the class
98    * inherits also from AtomValues. */
99   class AtomAsgnEvaluator : public FormulaEvalLoader,
100                             public AtomValues,
101                             protected FormulaEvaluator,
102                             public std::vector<double>
103   {
104   protected:
105     using Tusrvalmap = std::map<int, double>;
106     Tusrvalmap user_values;
107     const AtomAssignings &aa;
108   public:
AtomAsgnEvaluator(const AtomAssignings & a)109     AtomAsgnEvaluator(const AtomAssignings &a)
110       : FormulaEvaluator(a.expr),
111         std::vector<double>(a.expr.nformulas()), aa(a)
112     {
113     }
114     ~AtomAsgnEvaluator() override = default;
115     /** This sets all initial values to NaNs, all constants and
116      * all values set by user by call set_value. This is called by
117      * FormulaEvaluator::eval() method, which is called by eval()
118      * method passing this argument as AtomValues. So the
119      * ogp::EvalTree will be always this->etree. */
120     void setValues(EvalTree &et) const override;
121     /** User setting of the values. For example in initval,
122      * parameters are known and should be set to their values. In
123      * constrast endogenous variables are set initially to NaNs by
124      * AtomValues::setValues. */
125     void set_user_value(const string &name, double val);
126     /** This sets the result of i-th expression in aa to res, and
127      * also checks whether the i-th expression is an atom. If so,
128      * it sets the value of the atom in ogp::EvalTree
129      * this->etree. */
130     void load(int i, double res) override;
131     /** After the user values have been set, the assignments can
132      * be evaluated. For this purpose we have eval() method. The
133      * result is that this object as std::vector<double> will
134      * contain the values. It is ordered given by formulas in
135      * expr. */
136     void
eval()137     eval()
138     {
139       FormulaEvaluator::eval(*this, *this);
140     }
141     /** This returns a value for a given name. If the name is not
142      * found among atoms, or there is no assignment for the atom,
143      * NaN is returned. */
144     double get_value(const string &name) const;
145   };
146 };
147 
148 #endif
149