ModelEquationBlock.cc 13 KB
Newer Older
1
/*
Houtan Bastani's avatar
Houtan Bastani committed
2
 * Copyright (C) 2010-2018 Dynare Team
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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/>.
 */

#include <cassert>
#include <algorithm>

Houtan Bastani's avatar
Houtan Bastani committed
23
#include "ModelEquationBlock.hh"
24

25 26 27 28
SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg,
                                   NumericalConstants &num_constants_arg,
                                   ExternalFunctionsTable &external_functions_table_arg,
                                   TrendComponentModelTable &trend_component_model_table_arg,
Houtan Bastani's avatar
Houtan Bastani committed
29
                                   VarModelTable &var_model_table_arg,
30
                                   const StaticModel &static_model_arg) :
Houtan Bastani's avatar
Houtan Bastani committed
31 32
  DataTree(symbol_table_arg, num_constants_arg, external_functions_table_arg,
           trend_component_model_table_arg, var_model_table_arg),
33
  static_model(static_model_arg)
34 35 36 37
{
}

void
38
SteadyStateModel::addDefinition(int symb_id, expr_t expr)
39
{
40 41
  AddVariable(symb_id); // Create the variable node to be used in write method

42 43 44
  assert(symbol_table.getType(symb_id) == SymbolType::endogenous
         || symbol_table.getType(symb_id) == SymbolType::modFileLocalVariable
         || symbol_table.getType(symb_id) == SymbolType::parameter);
45 46

  // Add the variable
47 48
  vector<int> v;
  v.push_back(symb_id);
49
  def_table.emplace_back(v, expr);
50 51 52 53 54
}

void
SteadyStateModel::addMultipleDefinitions(const vector<int> &symb_ids, expr_t expr)
{
55
  for (int symb_id : symb_ids)
56
    {
57
      AddVariable(symb_id); // Create the variable nodes to be used in write method
58 59 60
      assert(symbol_table.getType(symb_id) == SymbolType::endogenous
             || symbol_table.getType(symb_id) == SymbolType::modFileLocalVariable
             || symbol_table.getType(symb_id) == SymbolType::parameter);
61
    }
62
  def_table.emplace_back(symb_ids, expr);
63 64 65
}

void
66
SteadyStateModel::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) const
67
{
68
  if (def_table.size() == 0)
69 70
    return;

71
  mod_file_struct.steady_state_model_present = true;
72 73
  vector<int> so_far_defined;

74
  for (const auto & i : def_table)
75
    {
76
      const vector<int> &symb_ids = i.first;
77 78

      // Check that symbols are not already defined
79 80
      for (int symb_id : symb_ids)
        if (find(so_far_defined.begin(), so_far_defined.end(), symb_id)
81
            != so_far_defined.end())
82
          warnings << "WARNING: in the 'steady_state_model' block, variable '" << symbol_table.getName(symb_id) << "' is declared twice" << endl;
83

84
      // Check that expression has no undefined symbol
85
      if (!mod_file_struct.ramsey_model_present)
86
        {
87
          set<int> used_symbols;
88
          const expr_t &expr = i.second;
89 90
          expr->collectVariables(SymbolType::endogenous, used_symbols);
          expr->collectVariables(SymbolType::modFileLocalVariable, used_symbols);
91 92
          for (int used_symbol : used_symbols)
            if (find(so_far_defined.begin(), so_far_defined.end(), used_symbol)
93
                == so_far_defined.end())
94
              {
95
                cerr << "ERROR: in the 'steady_state_model' block, variable '" << symbol_table.getName(used_symbol)
96
                     << "' is undefined in the declaration of variable '" << symbol_table.getName(symb_ids[0]) << "'" << endl;
97 98 99
                exit(EXIT_FAILURE);
              }
        }
100 101

      copy(symb_ids.begin(), symb_ids.end(), back_inserter(so_far_defined));
102
    }
103 104

  set<int> orig_endogs = symbol_table.getOrigEndogenous();
105
  for (int orig_endog : orig_endogs)
106
    {
107
      if (find(so_far_defined.begin(), so_far_defined.end(), orig_endog)
108
          == so_far_defined.end())
109
        warnings << "WARNING: in the 'steady_state_model' block, variable '" << symbol_table.getName(orig_endog) << "' is not assigned a value" << endl;
110
    }
111 112
}

113 114 115 116 117 118 119 120
void
SteadyStateModel::writeLatexSteadyStateFile(const string &basename) const
{
  ofstream output, content_output;
  string filename = basename + "_steady_state.tex";
  string content_basename = basename + "_steady_state_content";
  string content_filename = content_basename + ".tex";

121
  output.open(filename, ios::out | ios::binary);
122 123 124 125 126 127
  if (!output.is_open())
    {
      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

128
  content_output.open(content_filename, ios::out | ios::binary);
129 130 131 132 133 134 135 136 137 138 139 140 141 142
  if (!content_output.is_open())
    {
      cerr << "ERROR: Can't open file " << content_filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

  output << "\\documentclass[10pt,a4paper]{article}" << endl
         << "\\usepackage[landscape]{geometry}" << endl
         << "\\usepackage{fullpage}" << endl
         << "\\usepackage{amsfonts}" << endl
         << "\\usepackage{breqn}" << endl
         << "\\begin{document}" << endl
         << "\\footnotesize" << endl;

143
  for (const auto & it : def_table)
144
    for (auto it1 = it.first.begin(); it1 != it.first.end(); it1++)
145 146
      {
        int id = *it1;
147
        expr_t value = it.second;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
        content_output << "\\begin{dmath}" << endl
                       << symbol_table.getTeXName(id) << " = ";
        value->writeOutput(content_output, oLatexStaticModel);
        content_output << endl << "\\end{dmath}" << endl;
      }

  static_model.writeLatexAuxVarRecursiveDefinitions(content_output);

  output << "\\include{" << content_basename << "}" << endl
         << "\\end{document}" << endl;

  output.close();
  content_output.close();
}

163
void
Houtan Bastani's avatar
Houtan Bastani committed
164
SteadyStateModel::writeSteadyStateFile(const string &basename, bool ramsey_model, bool julia) const
165
{
166
  if (def_table.size() == 0)
167 168
    return;

169
  string filename = julia ? basename + "SteadyState2.jl" : packageDir(basename) + "/steadystate.m";
170
  ofstream output;
171
  output.open(filename, ios::out | ios::binary);
172 173 174 175 176 177
  if (!output.is_open())
    {
      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

Houtan Bastani's avatar
Houtan Bastani committed
178 179 180
  ExprNodeOutputType output_type = (julia ? oJuliaSteadyStateFile : oSteadyStateFile);

  if (!julia)
181
    output << "function [ys_, params, info] = steadystate("
Houtan Bastani's avatar
Houtan Bastani committed
182 183 184 185
           << "ys_, exo_, params)" << endl
           << "% Steady state generated by Dynare preprocessor" << endl
           << "    info = 0;" << endl;
  else
186 187 188 189 190
    output << "module " << basename << "SteadyState2" << endl
           << "#" << endl
           << "# NB: this file was automatically generated by Dynare" << endl
           << "#     from " << basename << ".mod" << endl
           << "#" << endl
191
           << "export steady_state!" << endl << endl
192 193
           << "function steady_state!(ys_::Vector{Float64}, exo_::Vector{Float64}, "
           << "params::Vector{Float64})" << endl;
194

195
  for (const auto & i : def_table)
196
    {
197
      const vector<int> &symb_ids = i.first;
198
      output << "    ";
199 200 201 202
      if (symb_ids.size() > 1)
        output << "[";
      for (size_t j = 0; j < symb_ids.size(); j++)
        {
203
          auto it = variable_node_map.find({ symb_ids[j], 0 });
204
          assert(it != variable_node_map.end());
Houtan Bastani's avatar
Houtan Bastani committed
205
          dynamic_cast<ExprNode *>(it->second)->writeOutput(output, output_type);
206 207 208 209 210 211 212
          if (j < symb_ids.size()-1)
            output << ",";
        }
      if (symb_ids.size() > 1)
        output << "]";

      output << "=";
213
      i.second->writeOutput(output, output_type);
214 215
      output << ";" << endl;
    }
Houtan Bastani's avatar
Houtan Bastani committed
216 217 218 219
  if (!julia)
    output << "    % Auxiliary equations" << endl;
  else
    output << "    # Auxiliary equations" << endl;
220
  static_model.writeAuxVarRecursiveDefinitions(output, output_type);
Houtan Bastani's avatar
Houtan Bastani committed
221

222 223 224
  if (!julia)
    output << "    check_=0;" << endl;

Houtan Bastani's avatar
Houtan Bastani committed
225 226 227
  output << "end" << endl;
  if (julia)
    output << "end" << endl;
228
  output.close();
229 230
}

231 232 233 234 235 236
void
SteadyStateModel::writeJsonSteadyStateFile(ostream &output, bool transformComputingPass) const
{
  if (def_table.size() == 0)
    return;

237
  vector<pair<string, string>> eqtags;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

  output << "{\"steady_state_model\": [";

  for (size_t i = 0; i < def_table.size(); i++)
    {
      const vector<int> &symb_ids = def_table[i].first;
      if (i != 0)
        output << ",";
      output << "{\"lhs\": ";
      if (symb_ids.size() > 1)
        output << "[";
      for (size_t j = 0; j < symb_ids.size(); j++)
        {
          if (j != 0)
            output << ",";
253
          auto it =
254
            variable_node_map.find({ symb_ids[j], 0 });
255 256
          assert(it != variable_node_map.end());
          output << "\"";
257
          dynamic_cast<ExprNode *>(it->second)->writeJsonOutput(output, {}, {}, false);
258 259 260 261 262
          output << "\"";
        }
      if (symb_ids.size() > 1)
        output << "]";
      output << ", \"rhs\":\"";
263
      def_table[i].second->writeJsonOutput(output, {}, {}, false);
264 265 266 267 268 269 270 271
      output << "\"}" << endl;
    }

  if (transformComputingPass)
    static_model.writeJsonAuxVarRecursiveDefinitions(output);

  output << "]}";
}
Houtan Bastani's avatar
Houtan Bastani committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

Epilogue::Epilogue(SymbolTable &symbol_table_arg,
                   NumericalConstants &num_constants_arg,
                   ExternalFunctionsTable &external_functions_table_arg,
                   TrendComponentModelTable &trend_component_model_table_arg,
                   VarModelTable &var_model_table_arg) :
  DynamicModel(symbol_table_arg, num_constants_arg, external_functions_table_arg,
               trend_component_model_table_arg, var_model_table_arg)
{
}

void
Epilogue::addDefinition(int symb_id, expr_t expr)
{
  AddVariable(symb_id); // Create the variable node to be used in write method
  def_table.emplace_back(symb_id, expr);
  endogs.emplace(symb_id);
  expr->collectVariables(SymbolType::endogenous, exogs);
  expr->collectVariables(SymbolType::exogenous, exogs);
  expr->collectVariables(SymbolType::endogenousEpilogue, exogs);
  expr->collectVariables(SymbolType::exogenousEpilogue, exogs);
  for (auto it : endogs)
    exogs.erase(it);
}

void
Epilogue::checkPass(WarningConsolidation &warnings) const
{
  if (def_table.size() == 0)
    return;

  vector<int> so_far_defined;
  for (const auto & it : def_table)
    {
      if (find(so_far_defined.begin(), so_far_defined.end(), it.first) != so_far_defined.end())
        {
          cerr << "WARNING: in the 'epilogue' block, variable '" << symbol_table.getName(it.first)
               << "' is declared twice" << endl;
          exit(EXIT_FAILURE);
        }
      so_far_defined.push_back(it.first);
    }
}

void
Epilogue::writeEpilogueFile(const string &basename) const
{
  if (def_table.size() == 0)
    return;

  string filename = packageDir(basename) + "/epilogue.m";
  ofstream output;
  output.open(filename, ios::out | ios::binary);
  if (!output.is_open())
    {
      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

  ExprNodeOutputType output_type = oEpilogueFile;
  output << "function ds = epilogue(params, ds)" << endl
         << "% function ds = epilogue(params, ds)" << endl
         << "% Epilogue file generated by Dynare preprocessor" << endl << endl
         << "epilogue_ds_first_date__ = ds.firstdate;" << endl
         << "epilogue_loop_begin_idx__ = lastdate(ds) - ds.lastobservedperiod;" << endl
         << "epilogue_loop_end_idx__ = lastdate(ds) - firstdate(ds) + 1;" << endl << endl;

  output << "% endogenous" << endl;
  for (auto symb_id : endogs)
    output << symbol_table.getName(symb_id) << " = ds." << symbol_table.getName(symb_id) << ".data;" << endl;
  output << endl
         << "% exogenous" << endl;
  for (auto symb_id : exogs)
    output << symbol_table.getName(symb_id) << " = ds." << symbol_table.getName(symb_id) << ".data;" << endl;
  output << endl
         << "for epilogue_it__ = epilogue_loop_begin_idx__::epilogue_loop_end_idx__" << endl;

  deriv_node_temp_terms_t tef_terms;
  temporary_terms_t temporary_terms;
  temporary_terms_idxs_t temporary_terms_idxs;
  for (const auto & it : def_table)
    if (it.second->containsExternalFunction())
      {
        output << "    ";
        it.second->writeExternalFunctionOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
      }
  output << endl;
  for (const auto & it : def_table)
    {
      auto node = variable_node_map.find({ it.first, 0 });
      assert(node != variable_node_map.end());

      output << "    ";
      dynamic_cast<ExprNode *>(node->second)->writeOutput(output, output_type);
      output << " = ";
      it.second->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
      output << ";" << endl;
    }
  output << "end" << endl << endl;
  for (auto symb_id : endogs)
    output << "ds." << symbol_table.getName(symb_id) << " = dseries(" << symbol_table.getName(symb_id)
           << ", epilogue_ds_first_date__);" << endl;
  output << endl
         << "end" << endl;
  output.close();
}