Skip to content
Snippets Groups Projects
Select Git revision
  • be67116bf957f88dc6bb2a0c746212bca843c2da
  • master default protected
  • julia protected
  • 6.x protected
  • python-codegen
  • llvm-15
  • 5.x protected
  • 4.6 protected
  • uop
  • rework_pac
  • aux_vars_fix
  • julia-7.0.0
  • julia-6.4.0
  • julia-6.3.0
  • julia-6.2.0
15 results

SigmaeInitialization.hh

Blame
  • atom_assignings.cc 6.72 KiB
    /*
     * 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 <https://www.gnu.org/licenses/>.
     */
    
    #include "atom_assignings.hh"
    #include "location.hh"
    #include "parser_exception.hh"
    
    #include "utils/cc/exception.hh"
    
    #include <limits>
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    
    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<double>::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 << " through a second assignment (e.g. in initval) 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<double>::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<double>::quiet_NaN();
      else
        return operator[](it->second);
    }