ModelEquationBlock.cc 13.5 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,
                                   const StaticModel &static_model_arg) :
29 30
  DataTree{symbol_table_arg, num_constants_arg, external_functions_table_arg},
  static_model{static_model_arg}
31 32 33
{
}

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
SteadyStateModel::SteadyStateModel(const SteadyStateModel &m) :
  DataTree {m},
  static_model {m.static_model}
{
  for (const auto &it : m.def_table)
    def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
}

SteadyStateModel &
SteadyStateModel::operator=(const SteadyStateModel &m)
{
  DataTree::operator=(m);

  assert(&static_model == &m.static_model);

  def_table.clear();
  for (const auto &it : m.def_table)
    def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));

  return *this;
}

56
void
57
SteadyStateModel::addDefinition(int symb_id, expr_t expr)
58
{
59 60
  AddVariable(symb_id); // Create the variable node to be used in write method

61 62 63
  assert(symbol_table.getType(symb_id) == SymbolType::endogenous
         || symbol_table.getType(symb_id) == SymbolType::modFileLocalVariable
         || symbol_table.getType(symb_id) == SymbolType::parameter);
64 65

  // Add the variable
66 67
  vector<int> v;
  v.push_back(symb_id);
68
  def_table.emplace_back(v, expr);
69 70 71 72 73
}

void
SteadyStateModel::addMultipleDefinitions(const vector<int> &symb_ids, expr_t expr)
{
74
  for (int symb_id : symb_ids)
75
    {
76
      AddVariable(symb_id); // Create the variable nodes to be used in write method
77 78 79
      assert(symbol_table.getType(symb_id) == SymbolType::endogenous
             || symbol_table.getType(symb_id) == SymbolType::modFileLocalVariable
             || symbol_table.getType(symb_id) == SymbolType::parameter);
80
    }
81
  def_table.emplace_back(symb_ids, expr);
82 83 84
}

void
85
SteadyStateModel::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) const
86
{
87
  if (def_table.size() == 0)
88 89
    return;

90
  mod_file_struct.steady_state_model_present = true;
91 92
  vector<int> so_far_defined;

93
  for (const auto & i : def_table)
94
    {
95
      const vector<int> &symb_ids = i.first;
96 97

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

103
      // Check that expression has no undefined symbol
104
      if (!mod_file_struct.ramsey_model_present)
105
        {
106
          set<int> used_symbols;
107
          const expr_t &expr = i.second;
108 109
          expr->collectVariables(SymbolType::endogenous, used_symbols);
          expr->collectVariables(SymbolType::modFileLocalVariable, used_symbols);
110 111
          for (int used_symbol : used_symbols)
            if (find(so_far_defined.begin(), so_far_defined.end(), used_symbol)
112
                == so_far_defined.end())
113
              {
114
                cerr << "ERROR: in the 'steady_state_model' block, variable '" << symbol_table.getName(used_symbol)
115
                     << "' is undefined in the declaration of variable '" << symbol_table.getName(symb_ids[0]) << "'" << endl;
116 117 118
                exit(EXIT_FAILURE);
              }
        }
119 120

      copy(symb_ids.begin(), symb_ids.end(), back_inserter(so_far_defined));
121
    }
122 123

  set<int> orig_endogs = symbol_table.getOrigEndogenous();
124
  for (int orig_endog : orig_endogs)
125
    {
126
      if (find(so_far_defined.begin(), so_far_defined.end(), orig_endog)
127
          == so_far_defined.end())
128
        warnings << "WARNING: in the 'steady_state_model' block, variable '" << symbol_table.getName(orig_endog) << "' is not assigned a value" << endl;
129
    }
130 131
}

132 133 134 135 136 137 138 139
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";

140
  output.open(filename, ios::out | ios::binary);
141 142 143 144 145 146
  if (!output.is_open())
    {
      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

147
  content_output.open(content_filename, ios::out | ios::binary);
148 149 150 151 152 153 154 155 156 157 158 159 160 161
  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;

162
  for (const auto & it : def_table)
163
    for (auto it1 = it.first.begin(); it1 != it.first.end(); it1++)
164 165
      {
        int id = *it1;
166
        expr_t value = it.second;
167 168
        content_output << "\\begin{dmath}" << endl
                       << symbol_table.getTeXName(id) << " = ";
169
        value->writeOutput(content_output, ExprNodeOutputType::latexStaticModel);
170 171 172 173 174 175 176 177 178 179 180 181
        content_output << endl << "\\end{dmath}" << endl;
      }

  static_model.writeLatexAuxVarRecursiveDefinitions(content_output);

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

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

182
void
Houtan Bastani's avatar
Houtan Bastani committed
183
SteadyStateModel::writeSteadyStateFile(const string &basename, bool ramsey_model, bool julia) const
184
{
185
  if (def_table.size() == 0)
186 187
    return;

188
  string filename = julia ? basename + "SteadyState2.jl" : packageDir(basename) + "/steadystate.m";
189
  ofstream output;
190
  output.open(filename, ios::out | ios::binary);
191 192 193 194 195 196
  if (!output.is_open())
    {
      cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
      exit(EXIT_FAILURE);
    }

197
  ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaSteadyStateFile : ExprNodeOutputType::steadyStateFile);
Houtan Bastani's avatar
Houtan Bastani committed
198 199

  if (!julia)
200
    output << "function [ys_, params, info] = steadystate("
Houtan Bastani's avatar
Houtan Bastani committed
201 202 203 204
           << "ys_, exo_, params)" << endl
           << "% Steady state generated by Dynare preprocessor" << endl
           << "    info = 0;" << endl;
  else
205 206 207 208 209
    output << "module " << basename << "SteadyState2" << endl
           << "#" << endl
           << "# NB: this file was automatically generated by Dynare" << endl
           << "#     from " << basename << ".mod" << endl
           << "#" << endl
210
           << "export steady_state!" << endl << endl
211 212
           << "function steady_state!(ys_::Vector{Float64}, exo_::Vector{Float64}, "
           << "params::Vector{Float64})" << endl;
213

214
  for (const auto & i : def_table)
215
    {
216
      const vector<int> &symb_ids = i.first;
217
      output << "    ";
218 219 220 221
      if (symb_ids.size() > 1)
        output << "[";
      for (size_t j = 0; j < symb_ids.size(); j++)
        {
222
          getVariable(symb_ids[j])->ExprNode::writeOutput(output, output_type);
223 224 225 226 227 228 229
          if (j < symb_ids.size()-1)
            output << ",";
        }
      if (symb_ids.size() > 1)
        output << "]";

      output << "=";
230
      i.second->writeOutput(output, output_type);
231 232
      output << ";" << endl;
    }
Houtan Bastani's avatar
Houtan Bastani committed
233 234 235 236
  if (!julia)
    output << "    % Auxiliary equations" << endl;
  else
    output << "    # Auxiliary equations" << endl;
237
  static_model.writeAuxVarRecursiveDefinitions(output, output_type);
Houtan Bastani's avatar
Houtan Bastani committed
238

239 240 241
  if (!julia)
    output << "    check_=0;" << endl;

Houtan Bastani's avatar
Houtan Bastani committed
242 243 244
  output << "end" << endl;
  if (julia)
    output << "end" << endl;
245
  output.close();
246 247
}

248 249 250 251 252 253
void
SteadyStateModel::writeJsonSteadyStateFile(ostream &output, bool transformComputingPass) const
{
  if (def_table.size() == 0)
    return;

254
  vector<pair<string, string>> eqtags;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

  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 << ",";
          output << "\"";
271
          getVariable(symb_ids[j])->writeJsonOutput(output, {}, {}, false);
272 273 274 275 276
          output << "\"";
        }
      if (symb_ids.size() > 1)
        output << "]";
      output << ", \"rhs\":\"";
277
      def_table[i].second->writeJsonOutput(output, {}, {}, false);
278 279 280 281 282 283 284 285
      output << "\"}" << endl;
    }

  if (transformComputingPass)
    static_model.writeJsonAuxVarRecursiveDefinitions(output);

  output << "]}";
}
Houtan Bastani's avatar
Houtan Bastani committed
286 287 288 289 290 291

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) :
292 293
  DynamicModel{symbol_table_arg, num_constants_arg, external_functions_table_arg,
               trend_component_model_table_arg, var_model_table_arg}
Houtan Bastani's avatar
Houtan Bastani committed
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
Epilogue::Epilogue(const Epilogue &m) :
  DynamicModel {m},
  endogs {m.endogs},
  exogs {m.exogs}
{
  for (const auto &it : m.def_table)
    def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
}

Epilogue &
Epilogue::operator=(const Epilogue &m)
{
  DynamicModel::operator=(m);

  endogs = m.endogs;
  exogs = m.exogs;

  def_table.clear();
  for (const auto &it : m.def_table)
    def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));

  return *this;
}

Houtan Bastani's avatar
Houtan Bastani committed
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
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);
    }

369
  ExprNodeOutputType output_type = ExprNodeOutputType::epilogueFile;
Houtan Bastani's avatar
Houtan Bastani committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  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)
    {
      output << "    ";
400
      getVariable(it.first)->ExprNode::writeOutput(output, output_type);
Houtan Bastani's avatar
Houtan Bastani committed
401 402 403 404 405 406 407 408 409 410 411 412
      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();
}