2009-04-14 16:39:53 +02:00
/*
2022-01-06 14:54:57 +01:00
* Copyright © 2003 - 2022 Dynare Team
2009-04-14 16:39:53 +02:00
*
* 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
2021-06-09 16:52:20 +02:00
* along with Dynare . If not , see < https : //www.gnu.org/licenses/>.
2009-04-14 16:39:53 +02:00
*/
2009-12-16 14:21:31 +01:00
# ifndef _STATIC_MODEL_HH
# define _STATIC_MODEL_HH
# include <fstream>
2019-04-04 17:01:37 +02:00
# include <filesystem>
2018-10-26 11:44:26 +02:00
2009-04-14 16:39:53 +02:00
# include "ModelTree.hh"
2022-06-23 14:28:13 +02:00
# include "Bytecode.hh"
2009-04-14 16:39:53 +02:00
2022-01-06 14:54:57 +01:00
using namespace std ;
2018-10-10 17:08:54 +02:00
class DynamicModel ;
2010-04-23 18:39:07 +02:00
//! Stores a static model, as derived from the "model" block when leads and lags have been removed
2009-04-14 16:39:53 +02:00
class StaticModel : public ModelTree
{
private :
2009-07-07 17:58:17 +02:00
//! Writes static model file (standard Matlab version)
2018-06-27 15:01:31 +02:00
void writeStaticMFile ( const string & basename ) const ;
2009-12-16 14:21:31 +01:00
2011-08-18 12:44:11 +02:00
//! Writes static model file (C version)
2022-09-30 12:06:31 +02:00
// Returns the path to the generated C source file
filesystem : : path writeStaticCFile ( const string & basename ) const ;
2011-08-18 12:44:11 +02:00
2015-07-27 15:33:38 +02:00
//! Writes static model file (Julia version)
2015-07-27 15:59:13 +02:00
void writeStaticJuliaFile ( const string & basename ) const ;
2015-07-27 15:33:38 +02:00
2020-05-19 16:56:53 +02:00
//! Writes the main static function of block decomposed model (MATLAB version)
void writeStaticBlockMFile ( const string & basename ) const ;
2009-04-14 16:39:53 +02:00
2020-06-23 15:13:04 +02:00
//! Writes the main static function of block decomposed model (C version)
2022-09-30 12:06:31 +02:00
// Returns the path to the generated C source file
filesystem : : path writeStaticBlockCFile ( const string & basename ) const ;
2020-06-23 15:13:04 +02:00
2020-06-22 12:46:33 +02:00
//! Helper for writing a per-block static file of block decomposed model
2022-07-12 14:13:27 +02:00
template < ExprNodeOutputType output_type >
void writeStaticPerBlockHelper ( int blk , ostream & output , temporary_terms_t & temporary_terms ) const ;
2020-06-22 12:46:33 +02:00
2020-05-19 16:56:53 +02:00
//! Writes the per-block static files of block decomposed model (MATLAB version)
void writeStaticPerBlockMFiles ( const string & basename ) const ;
2009-06-30 17:07:09 +02:00
2022-09-30 12:06:31 +02:00
/* Writes the per-block static files of block decomposed model (C version).
Returns the list of paths to the generated C source files ( not the headers ) */
vector < filesystem : : path > writeStaticPerBlockCFiles ( const string & basename ) const ;
2020-06-23 15:13:04 +02:00
2020-05-19 17:43:35 +02:00
//! Writes the code of the block-decomposed model in virtual machine bytecode
void writeStaticBlockBytecode ( const string & basename ) const ;
2010-01-22 11:03:29 +01:00
//! Writes the code of the model in virtual machine bytecode
2020-05-19 17:43:35 +02:00
void writeStaticBytecode ( const string & basename ) const ;
2009-12-16 14:21:31 +01:00
//! Computes jacobian and prepares for equation normalization
/*! Using values from initval/endval blocks and parameter initializations:
- computes the jacobian for the model w . r . to contemporaneous variables
- removes edges of the incidence matrix when derivative w . r . to the corresponding variable is too close to zero ( below the cutoff )
*/
2010-09-16 19:00:48 +02:00
void evaluateJacobian ( const eval_context_t & eval_context , jacob_map_t * j_m , bool dynamic ) ;
2009-07-10 16:22:40 +02:00
2018-06-04 12:53:26 +02:00
SymbolType getTypeByDerivID ( int deriv_id ) const noexcept ( false ) override ;
int getLagByDerivID ( int deriv_id ) const noexcept ( false ) override ;
int getSymbIDByDerivID ( int deriv_id ) const noexcept ( false ) override ;
2022-07-12 15:28:52 +02:00
int getTypeSpecificIDByDerivID ( int deriv_id ) const override ;
2022-07-11 17:33:09 +02:00
int
getJacobianCol ( int deriv_id ) const override
{
2022-07-12 15:28:52 +02:00
return getTypeSpecificIDByDerivID ( deriv_id ) ;
2022-07-11 17:33:09 +02:00
}
int
getJacobianColsNbr ( ) const override
{
return symbol_table . endo_nbr ( ) ;
}
2009-12-16 14:21:31 +01:00
//! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables
2020-03-19 17:46:10 +01:00
void computeChainRuleJacobian ( ) ;
2009-12-16 14:21:31 +01:00
2022-07-12 17:04:41 +02:00
// Helper for writing MATLAB/Octave functions for residuals/derivatives and their temporary terms
void writeStaticMFileHelper ( const string & basename ,
2018-06-27 15:01:31 +02:00
const string & name , const string & retvalname ,
2018-03-27 17:14:30 +02:00
const string & name_tt , size_t ttlen ,
const string & previous_tt_name ,
const ostringstream & init_s , const ostringstream & end_s ,
const ostringstream & s , const ostringstream & s_tt ) const ;
2022-07-12 17:04:41 +02:00
// Writes MATLAB/Octave wrapper function for computing residuals and derivatives at the same time
void writeStaticMWrapperFunction ( const string & basename , const string & ending ) const ;
2018-05-23 16:10:26 +02:00
2022-07-12 17:04:41 +02:00
//! Create a legacy *_static.m file for MATLAB/Octave not yet using the temporary terms array interface
void writeStaticMCompatFile ( const string & name ) const ;
2018-05-23 16:10:26 +02:00
2022-07-19 18:24:36 +02:00
int
getBlockJacobianEndoCol ( [[maybe_unused]] int blk, int var, [[maybe_unused]] int lag ) const override
{
return var ;
}
2022-09-13 15:43:13 +02:00
/* Compute block decomposition, its derivatives and temporary terms.
Meant to be overriden in derived classes which don ’ t support block
decomposition ( currently PlannerObjective ) . Returns a boolean indicating success
( failure can happen in normalization ) . */
virtual bool computingPassBlock ( const eval_context_t & eval_context , bool no_tmp_terms ) ;
2022-09-21 18:47:14 +02:00
// Write the block structure of the model in the driver file
void writeBlockDriverOutput ( ostream & output ) const ;
2022-09-14 17:48:33 +02:00
protected :
string
modelClassName ( ) const override
{
return " static model " ;
}
2009-04-14 16:39:53 +02:00
public :
2018-08-14 14:23:21 +02:00
StaticModel ( SymbolTable & symbol_table_arg ,
NumericalConstants & num_constants ,
2018-09-14 17:04:06 +02:00
ExternalFunctionsTable & external_functions_table_arg ) ;
2009-07-07 16:20:48 +02:00
2018-10-09 18:27:19 +02:00
StaticModel ( const StaticModel & m ) ;
2019-12-20 16:59:30 +01:00
StaticModel & operator = ( const StaticModel & m ) ;
2018-10-10 17:08:54 +02:00
//! Creates the static version of a dynamic model
explicit StaticModel ( const DynamicModel & m ) ;
2018-10-09 18:27:19 +02:00
2020-05-20 11:44:40 +02:00
//! Writes information about the static model to the driver file
void writeDriverOutput ( ostream & output , bool block ) const ;
2009-07-07 16:20:48 +02:00
2022-09-13 15:43:13 +02:00
//! Execute computations (variable sorting + derivation + block decomposition)
2009-12-16 14:21:31 +01:00
/*!
\ param eval_context evaluation context for normalization
\ param no_tmp_terms if true , no temporary terms will be computed in the static files
2018-11-22 14:32:40 +01:00
\ param derivsOrder order of derivation with respect to endogenous
\ param paramsDerivsOrder order of derivatives w . r . to a pair ( endogenous , parameter ) to be computed
2009-12-16 14:21:31 +01:00
*/
2022-05-19 14:10:22 +02:00
void computingPass ( int derivsOrder , int paramsDerivsOrder , const eval_context_t & eval_context , bool no_tmp_terms , bool block ) ;
2009-12-16 14:21:31 +01:00
2022-05-19 14:15:43 +02:00
//! Writes static model file (+ bytecode)
void writeStaticFile ( const string & basename , bool block , bool use_dll , const string & mexext , const filesystem : : path & matlabroot , const filesystem : : path & dynareroot , bool julia ) const ;
2009-04-17 18:26:23 +02:00
2017-02-27 15:40:34 +01:00
//! Write JSON Output (used by PlannerObjectiveStatement)
void writeJsonOutput ( ostream & output ) const ;
2017-02-20 12:18:11 +01:00
//! Write JSON representation of static model
2017-03-02 18:34:18 +01:00
void writeJsonComputingPassOutput ( ostream & output , bool writeDetails ) const ;
2017-02-20 12:18:11 +01:00
2022-07-12 17:47:02 +02:00
//! Write JSON params derivatives
void writeJsonParamsDerivatives ( ostream & output , bool writeDetails ) const ;
2017-02-20 12:18:11 +01:00
2012-11-29 18:07:48 +01:00
//! Writes file containing static parameters derivatives
2022-07-12 12:27:22 +02:00
template < bool julia >
void writeParamsDerivativesFile ( const string & basename ) const ;
2012-11-29 18:07:48 +01:00
2009-04-30 15:14:33 +02:00
//! Writes LaTeX file with the equations of the static model
2019-12-16 19:42:59 +01:00
void writeLatexFile ( const string & basename , bool write_equation_tags ) const ;
2009-04-30 15:14:33 +02:00
2010-04-27 17:04:52 +02:00
//! Writes initializations in oo_.steady_state or steady state file for the auxiliary variables
void writeAuxVarInitval ( ostream & output , ExprNodeOutputType output_type ) const ;
2009-09-30 17:10:31 +02:00
2015-08-17 15:36:18 +02:00
//! Writes definition of the auxiliary variables in a .m or .jl file
2019-12-16 19:42:59 +01:00
void writeSetAuxiliaryVariables ( const string & basename , bool julia ) const ;
2016-04-04 17:11:03 +02:00
void writeAuxVarRecursiveDefinitions ( ostream & output , ExprNodeOutputType output_type ) const ;
2017-08-30 11:32:01 +02:00
void writeLatexAuxVarRecursiveDefinitions ( ostream & output ) const ;
2017-10-16 17:24:55 +02:00
void writeJsonAuxVarRecursiveDefinitions ( ostream & output ) const ;
2011-07-24 20:52:03 +02:00
2016-08-12 11:50:57 +02:00
//! To ensure that no exogenous is present in the planner objective
//! See #1264
bool exoPresentInEqs ( ) const ;
2018-06-04 12:53:26 +02:00
int getDerivID ( int symb_id , int lag ) const noexcept ( false ) override ;
void addAllParamDerivId ( set < int > & deriv_id_set ) override ;
2009-04-14 16:39:53 +02:00
} ;
2022-07-12 14:13:27 +02:00
template < ExprNodeOutputType output_type >
void
StaticModel : : writeStaticPerBlockHelper ( int blk , ostream & output , temporary_terms_t & temporary_terms ) const
{
BlockSimulationType simulation_type { blocks [ blk ] . simulation_type } ;
int block_recursive_size { blocks [ blk ] . getRecursiveSize ( ) } ;
2022-07-21 18:20:35 +02:00
// Write residuals and temporary terms (incl. for derivatives)
writePerBlockHelper < output_type > ( blk , output , temporary_terms ) ;
2022-07-21 17:30:03 +02:00
2022-07-12 14:13:27 +02:00
// The Jacobian if we have to solve the block
if ( simulation_type ! = BlockSimulationType : : evaluateBackward
& & simulation_type ! = BlockSimulationType : : evaluateForward )
{
ostringstream i_output , j_output , v_output ;
for ( int line_counter { ARRAY_SUBSCRIPT_OFFSET ( output_type ) } ;
const auto & [ indices , d ] : blocks_derivatives [ blk ] )
{
const auto & [ eq , var , ignore ] { indices } ;
i_output < < " g1_i " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < eq + 1 - block_recursive_size
< < ' ; ' < < endl ;
j_output < < " g1_j " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' < < var + 1 - block_recursive_size
< < ' ; ' < < endl ;
v_output < < " g1_v " < < LEFT_ARRAY_SUBSCRIPT ( output_type ) < < line_counter
< < RIGHT_ARRAY_SUBSCRIPT ( output_type ) < < ' = ' ;
d - > writeOutput ( v_output , output_type , temporary_terms , blocks_temporary_terms_idxs ) ;
v_output < < ' ; ' < < endl ;
line_counter + + ;
}
output < < i_output . str ( ) < < j_output . str ( ) < < v_output . str ( ) ;
}
}
2022-07-12 12:27:22 +02:00
template < bool julia >
void
StaticModel : : writeParamsDerivativesFile ( const string & basename ) const
{
if ( ! params_derivatives . size ( ) )
return ;
constexpr ExprNodeOutputType output_type { julia ? ExprNodeOutputType : : juliaStaticModel : ExprNodeOutputType : : matlabStaticModel } ;
auto [ tt_output , rp_output , gp_output , rpp_output , gpp_output , hp_output , g3p_output ]
{ writeParamsDerivativesFileHelper < output_type > ( ) } ;
// g3p_output is ignored
string filename { julia ? basename + " StaticParamsDerivs.jl " : packageDir ( basename ) + " /static_params_derivs.m " } ;
ofstream paramsDerivsFile { filename , ios : : out | ios : : binary } ;
if ( ! paramsDerivsFile . is_open ( ) )
{
cerr < < " ERROR: Can't open file " < < filename < < " for writing " < < endl ;
exit ( EXIT_FAILURE ) ;
}
if constexpr ( ! julia )
{
paramsDerivsFile < < " function [rp, gp, rpp, gpp, hp] = static_params_derivs(y, x, params) " < < endl
< < " % " < < endl
< < " % Status : Computes derivatives of the static model with respect to the parameters " < < endl
< < " % " < < endl
< < " % Inputs : " < < endl
< < " % y [M_.endo_nbr by 1] double vector of endogenous variables in declaration order " < < endl
< < " % x [M_.exo_nbr by 1] double vector of exogenous variables in declaration order " < < endl
< < " % params [M_.param_nbr by 1] double vector of parameter values in declaration order " < < endl
< < " % " < < endl
< < " % Outputs: " < < endl
< < " % rp [M_.eq_nbr by #params] double Jacobian matrix of static model equations with respect to parameters " < < endl
< < " % Dynare may prepend or append auxiliary equations, see M_.aux_vars " < < endl
< < " % gp [M_.endo_nbr by M_.endo_nbr by #params] double Derivative of the Jacobian matrix of the static model equations with respect to the parameters " < < endl
< < " % rows: variables in declaration order " < < endl
< < " % rows: equations in order of declaration " < < endl
< < " % rpp [#second_order_residual_terms by 4] double Hessian matrix of second derivatives of residuals with respect to parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: number of the first parameter in derivative " < < endl
< < " % 3rd column: number of the second parameter in derivative " < < endl
< < " % 4th column: value of the Hessian term " < < endl
< < " % gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second derivatives of the Jacobian with respect to the parameters; " < < endl
< < " % rows: respective derivative term " < < endl
< < " % 1st column: equation number of the term appearing " < < endl
< < " % 2nd column: column number of variable in Jacobian of the static model " < < endl
< < " % 3rd column: number of the first parameter in derivative " < < endl
< < " % 4th column: number of the second parameter in derivative " < < endl
< < " % 5th column: value of the Hessian term " < < endl
< < " % " < < endl
< < " % " < < endl
< < " % Warning : this file is generated automatically by Dynare " < < endl
< < " % from model file (.mod) " < < endl < < endl
< < " T = NaN( " < < params_derivs_temporary_terms_idxs . size ( ) < < " ,1); " < < endl
< < tt_output . str ( )
< < " rp = zeros( " < < equations . size ( ) < < " , "
< < symbol_table . param_nbr ( ) < < " ); " < < endl
< < rp_output . str ( )
< < " gp = zeros( " < < equations . size ( ) < < " , " < < symbol_table . endo_nbr ( ) < < " , "
< < symbol_table . param_nbr ( ) < < " ); " < < endl
< < gp_output . str ( )
< < " if nargout >= 3 " < < endl
2022-09-27 12:51:22 +02:00
< < " rpp = zeros( " < < params_derivatives . at ( { 0 , 2 } ) . size ( ) < < " ,4); " < < endl
2022-07-12 12:27:22 +02:00
< < rpp_output . str ( )
2022-09-27 12:51:22 +02:00
< < " gpp = zeros( " < < params_derivatives . at ( { 1 , 2 } ) . size ( ) < < " ,5); " < < endl
2022-07-12 12:27:22 +02:00
< < gpp_output . str ( )
< < " end " < < endl
< < " if nargout >= 5 " < < endl
2022-09-27 12:51:22 +02:00
< < " hp = zeros( " < < params_derivatives . at ( { 2 , 1 } ) . size ( ) < < " ,5); " < < endl
2022-07-12 12:27:22 +02:00
< < hp_output . str ( )
< < " end " < < endl
< < " end " < < endl ;
}
else
paramsDerivsFile < < " module " < < basename < < " StaticParamsDerivs " < < endl
< < " # " < < endl
< < " # NB: this file was automatically generated by Dynare " < < endl
< < " # from " < < basename < < " .mod " < < endl
< < " # " < < endl
< < " export params_derivs " < < endl < < endl
< < " function params_derivs(y, x, params) " < < endl
< < " @inbounds begin " < < endl
< < tt_output . str ( )
< < " end " < < endl
< < " rp = zeros( " < < equations . size ( ) < < " , "
< < symbol_table . param_nbr ( ) < < " ); " < < endl
< < " @inbounds begin " < < endl
< < rp_output . str ( )
< < " end " < < endl
< < " gp = zeros( " < < equations . size ( ) < < " , " < < symbol_table . endo_nbr ( ) < < " , "
< < symbol_table . param_nbr ( ) < < " ); " < < endl
< < " @inbounds begin " < < endl
< < gp_output . str ( )
< < " end " < < endl
2022-09-27 12:51:22 +02:00
< < " rpp = zeros( " < < params_derivatives . at ( { 0 , 2 } ) . size ( ) < < " ,4); " < < endl
2022-07-12 12:27:22 +02:00
< < " @inbounds begin " < < endl
< < rpp_output . str ( )
< < " end " < < endl
2022-09-27 12:51:22 +02:00
< < " gpp = zeros( " < < params_derivatives . at ( { 1 , 2 } ) . size ( ) < < " ,5); " < < endl
2022-07-12 12:27:22 +02:00
< < " @inbounds begin " < < endl
< < gpp_output . str ( )
< < " end " < < endl
2022-09-27 12:51:22 +02:00
< < " hp = zeros( " < < params_derivatives . at ( { 2 , 1 } ) . size ( ) < < " ,5); " < < endl
2022-07-12 12:27:22 +02:00
< < " @inbounds begin " < < endl
< < hp_output . str ( )
< < " end " < < endl
< < " (rp, gp, rpp, gpp, hp) " < < endl
< < " end " < < endl
< < " end " < < endl ;
paramsDerivsFile . close ( ) ;
}
2009-04-14 16:39:53 +02:00
# endif