ModelEquationBlock.cc 12.8 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
{
}

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

39 40 41
  assert(symbol_table.getType(symb_id) == SymbolType::endogenous
         || symbol_table.getType(symb_id) == SymbolType::modFileLocalVariable
         || symbol_table.getType(symb_id) == SymbolType::parameter);
42 43

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

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

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

68
  mod_file_struct.steady_state_model_present = true;
69 70
  vector<int> so_far_defined;

71
  for (const auto & i : def_table)
72
    {
73
      const vector<int> &symb_ids = i.first;
74 75

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

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

      copy(symb_ids.begin(), symb_ids.end(), back_inserter(so_far_defined));
99
    }
100 101

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

110 111 112 113 114 115 116 117
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";

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

125
  content_output.open(content_filename, ios::out | ios::binary);
126 127 128 129 130 131 132 133 134 135 136 137 138 139
  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;

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

  static_model.writeLatexAuxVarRecursiveDefinitions(content_output);

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

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

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

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

175
  ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaSteadyStateFile : ExprNodeOutputType::steadyStateFile);
Houtan Bastani's avatar
Houtan Bastani committed
176 177

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

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

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

219 220 221
  if (!julia)
    output << "    check_=0;" << endl;

Houtan Bastani's avatar
Houtan Bastani committed
222 223 224
  output << "end" << endl;
  if (julia)
    output << "end" << endl;
225
  output.close();
226 227
}

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

234
  vector<pair<string, string>> eqtags;
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

  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 << ",";
250
          auto it =
251
            variable_node_map.find({ symb_ids[j], 0 });
252 253
          assert(it != variable_node_map.end());
          output << "\"";
254
          dynamic_cast<ExprNode *>(it->second)->writeJsonOutput(output, {}, {}, false);
255 256 257 258 259
          output << "\"";
        }
      if (symb_ids.size() > 1)
        output << "]";
      output << ", \"rhs\":\"";
260
      def_table[i].second->writeJsonOutput(output, {}, {}, false);
261 262 263 264 265 266 267 268
      output << "\"}" << endl;
    }

  if (transformComputingPass)
    static_model.writeJsonAuxVarRecursiveDefinitions(output);

  output << "]}";
}
Houtan Bastani's avatar
Houtan Bastani committed
269 270 271 272 273 274

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) :
275 276
  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
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
{
}

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);
    }

328
  ExprNodeOutputType output_type = ExprNodeOutputType::epilogueFile;
Houtan Bastani's avatar
Houtan Bastani committed
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
  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();
}