/* * 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 . */ #include "atom_assignings.hh" #include "location.hh" #include "parser_exception.hh" #include "utils/cc/exception.hh" #include #include #include #include using namespace ogp; AtomAssignings::AtomAssignings(const AtomAssignings &aa, ogp::StaticAtoms &a) : atoms(a), expr(aa.expr, atoms), left_names(aa.left_names), lname2expr(aa.lname2expr), order(aa.order) { } /** A global symbol for passing info to the AtomAssignings from * asgn_parse(). */ AtomAssignings *aparser; /** The declaration of functions defined in asgn_ll.cc and asgn_tab.cc * generated from assign.lex assign.y */ void *asgn__scan_string(const char *); void asgn__destroy_buffer(void *); void asgn_parse(); extern location_type asgn_lloc; void AtomAssignings::parse(const string &stream) { asgn_lloc.off = 0; asgn_lloc.ll = 0; void *p = asgn__scan_string(stream.c_str()); aparser = this; asgn_parse(); asgn__destroy_buffer(p); } void AtomAssignings::error(string mes) { throw ParserException(std::move(mes), asgn_lloc.off); } void AtomAssignings::add_assignment_to_double(string name, double val) { // if left hand side is a registered atom, insert it to tree int t; try { if (atoms.check(name)) t = expr.add_nulary(name); else t = -1; } catch (const ParserException &e) { t = -1; } // register left hand side in order order.push_back(t); // add the double to the tree std::ostringstream buf; buf << std::setprecision(std::numeric_limits::max_digits10) << val; try { expr.parse(buf.str()); } catch (const ParserException &e) { // should never happen throw ParserException(string("Error parsing double ")+buf.str()+": "+e.message(), 0); } // register name of the left hand side and put to lname2expr left_names.insert(name); lname2expr.emplace(std::move(name), order.size()-1); } void AtomAssignings::add_assignment(int asgn_off, const string &str, int name_len, int right_off, int right_len) { // the order of doing things here is important: since the // FormulaParser requires that all references from the i-th tree // refere to trees with index lass than i, so to capture also a // nulary term for the left hand side, it must be inserted to the // expression tree before the expression is parsed. // find the name in the atoms string name = str.substr(0, name_len); // if left hand side is a registered atom, insert it to tree int t; try { t = atoms.check(name); if (t == -1) t = expr.add_nulary(name); } catch (const ParserException &e) { atoms.register_name(name); t = expr.add_nulary(name); } // register left hand side in order order.push_back(t); // parse expression on the right try { expr.parse(str.substr(right_off, right_len)); } catch (const ParserException &e) { throw ParserException(e, asgn_off+right_off); } // register name of the left hand side and put to lname2expr left_names.insert(name); if (lname2expr.find(name) != lname2expr.end()) { // Prevent the occurrence of #415 std::cerr << "Changing the value of " << name << " is not supported. Aborting." << std::endl; exit(EXIT_FAILURE); } lname2expr[name] = order.size()-1; } void AtomAssignings::apply_subst(const AtomSubstitutions::Toldnamemap &mm) { // go through all old variables and see what are their derived new // variables for (const auto &it : mm) { const string &oldname = it.first; const AtomSubstitutions::Tshiftnameset &sset = it.second; if (!sset.empty()) { int told = atoms.index(oldname); if (told < 0 && !atoms.get_name_storage().query(oldname)) atoms.register_name(oldname); if (told == -1) told = expr.add_nulary(oldname); // at least one substitution here, so make an expression expr.add_formula(told); // say that this expression is not assigned to any atom order.push_back(-1); // now go through all new names derived from the old name and // reference to the newly added formula for (const auto &itt : sset) { const string &newname = itt.first; left_names.insert(newname); lname2expr.emplace(newname, expr.nformulas()-1); } } } } void AtomAssignings::print() const { std::cout << "Atom Assignings\nExpressions:\n"; expr.print(); std::cout << "Left names:\n"; for (auto it : lname2expr) std::cout << it.first << u8" ⇒ " << expr.formula(it.second) << " (t=" << order[it.second] << ")\n"; } void AtomAsgnEvaluator::setValues(EvalTree &et) const { // set values of constants aa.atoms.setValues(et); // set values of variables to NaN or to user set values double nan = std::numeric_limits::quiet_NaN(); for (int i = 0; i < aa.atoms.nvar(); i++) { const string &ss = aa.atoms.name(i); int t = aa.atoms.index(ss); if (t >= 0) { auto it = user_values.find(t); if (it == user_values.end()) et.set_nulary(t, nan); else et.set_nulary(t, it->second); } } } void AtomAsgnEvaluator::set_user_value(const string &name, double val) { int t = aa.atoms.index(name); if (t >= 0) { auto it = user_values.find(t); if (it == user_values.end()) user_values.emplace(t, val); else it->second = val; } } void AtomAsgnEvaluator::load(int i, double res) { // set the value operator[](i) = res; // if i-th expression is atom, set its value to this EvalTree int t = aa.order[i]; if (t >= 0) etree.set_nulary(t, res); } double AtomAsgnEvaluator::get_value(const string &name) const { auto it = aa.lname2expr.find(name); if (it == aa.lname2expr.end()) return std::numeric_limits::quiet_NaN(); else return operator[](it->second); }