2010-09-24 12:52:58 +02:00
/*
2022-02-09 14:32:25 +01:00
* Copyright © 2007 - 2022 Dynare Team
2010-09-24 12:52:58 +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 17:33:48 +02:00
* along with Dynare . If not , see < https : //www.gnu.org/licenses/>.
2010-09-24 12:52:58 +02:00
*/
2022-07-29 12:40:33 +02:00
# ifndef _ERROR_HANDLING_HH
# define _ERROR_HANDLING_HH
2010-09-24 12:52:58 +02:00
2021-02-09 15:55:36 +01:00
# include <vector>
# include <utility>
# include <string>
2013-03-22 15:44:34 +01:00
# include <map>
2021-02-09 15:55:36 +01:00
# include <tuple>
# include <cstddef>
# include <sstream>
# include <iostream>
2017-03-24 23:15:25 +01:00
# include <stack>
2022-07-26 15:52:12 +02:00
# include <optional>
2017-03-24 23:15:25 +01:00
# define _USE_MATH_DEFINES
2021-02-01 12:28:50 +01:00
# include <cmath>
2021-02-09 15:55:36 +01:00
# include "dynmex.h"
2022-06-16 18:05:00 +02:00
# define BYTECODE_MEX
# include "Bytecode.hh"
2017-03-24 23:15:25 +01:00
2022-07-28 16:56:40 +02:00
# include "BasicSymbolTable.hh"
2010-09-24 12:52:58 +02:00
using namespace std ;
2021-02-03 18:10:01 +01:00
constexpr int NO_ERROR_ON_EXIT = 0 , ERROR_ON_EXIT = 1 ;
2010-11-20 15:45:15 +01:00
2022-07-26 18:27:23 +02:00
using it_code_type = instructions_list_t : : const_iterator ;
2010-11-20 15:45:15 +01:00
2010-09-24 12:52:58 +02:00
class GeneralExceptionHandling
{
string ErrorMsg ;
public :
2021-02-01 12:34:34 +01:00
GeneralExceptionHandling ( string ErrorMsg_arg ) : ErrorMsg { move ( ErrorMsg_arg ) }
2011-02-04 16:53:12 +01:00
{
} ;
2010-09-24 12:52:58 +02:00
inline string
GetErrorMsg ( )
2011-02-04 16:53:12 +01:00
{
return ErrorMsg ;
}
2010-09-24 12:52:58 +02:00
inline void
2021-02-03 18:10:01 +01:00
completeErrorMsg ( const string & ErrorMsg_arg )
2011-02-04 16:53:12 +01:00
{
ErrorMsg + = ErrorMsg_arg ;
}
2010-09-24 12:52:58 +02:00
} ;
class FloatingPointExceptionHandling : public GeneralExceptionHandling
{
public :
2021-02-03 18:10:01 +01:00
FloatingPointExceptionHandling ( const string & value ) : GeneralExceptionHandling ( " Floating point error in bytecode: " + value )
2011-02-04 16:53:12 +01:00
{
2021-02-03 18:10:01 +01:00
}
2010-09-24 12:52:58 +02:00
} ;
class LogExceptionHandling : public FloatingPointExceptionHandling
{
double value ;
public :
LogExceptionHandling ( double value_arg ) : FloatingPointExceptionHandling ( " log(X) " ) ,
value ( value_arg )
2011-02-04 16:53:12 +01:00
{
2022-07-28 17:10:12 +02:00
// We don’ t use std::to_string(), because it uses fixed formatting
ostringstream s ;
s < < " with X= " < < defaultfloat < < value < < " \n " ;
completeErrorMsg ( s . str ( ) ) ;
2021-02-03 18:10:01 +01:00
}
2010-09-24 12:52:58 +02:00
} ;
class Log10ExceptionHandling : public FloatingPointExceptionHandling
{
double value ;
public :
Log10ExceptionHandling ( double value_arg ) : FloatingPointExceptionHandling ( " log10(X) " ) ,
2011-02-04 16:53:12 +01:00
value ( value_arg )
{
2022-07-28 17:10:12 +02:00
// We don’ t use std::to_string(), because it uses fixed formatting
ostringstream s ;
s < < " with X= " < < defaultfloat < < value < < " \n " ;
completeErrorMsg ( s . str ( ) ) ;
2021-02-03 18:10:01 +01:00
}
2010-09-24 12:52:58 +02:00
} ;
class DivideExceptionHandling : public FloatingPointExceptionHandling
{
double value1 , value2 ;
2010-10-11 17:56:23 +02:00
public :
2010-09-24 12:52:58 +02:00
DivideExceptionHandling ( double value1_arg , double value2_arg ) : FloatingPointExceptionHandling ( " a/X " ) ,
2011-02-04 16:53:12 +01:00
value1 ( value1_arg ) ,
value2 ( value2_arg )
{
2022-07-28 17:10:12 +02:00
// We don’ t use std::to_string(), because it uses fixed formatting
ostringstream s ;
s < < " with X= " < < defaultfloat < < value2 < < " \n " ;
completeErrorMsg ( s . str ( ) ) ;
2021-02-03 18:10:01 +01:00
}
2010-09-24 12:52:58 +02:00
} ;
class PowExceptionHandling : public FloatingPointExceptionHandling
{
double value1 , value2 ;
public :
PowExceptionHandling ( double value1_arg , double value2_arg ) : FloatingPointExceptionHandling ( " X^a " ) ,
2011-02-04 16:53:12 +01:00
value1 ( value1_arg ) ,
value2 ( value2_arg )
{
2022-07-28 17:10:12 +02:00
// We don’ t use std::to_string(), because it uses fixed formatting
ostringstream s ;
s < < " with X= " < < defaultfloat < < value1 ;
if ( fabs ( value1 ) < = 1e-10 )
s < < " and a= " < < value2 ;
s < < " \n " ;
completeErrorMsg ( s . str ( ) ) ;
2011-02-04 16:53:12 +01:00
} ;
2010-09-24 12:52:58 +02:00
} ;
2013-03-22 15:44:34 +01:00
class UserExceptionHandling : public GeneralExceptionHandling
{
double value ;
public :
UserExceptionHandling ( ) : GeneralExceptionHandling ( " Fatal error in bytecode: " )
{
completeErrorMsg ( " User break \n " ) ;
} ;
} ;
2010-09-24 12:52:58 +02:00
class FatalExceptionHandling : public GeneralExceptionHandling
{
public :
2021-02-03 18:10:01 +01:00
FatalExceptionHandling ( const string & ErrorMsg_arg )
: GeneralExceptionHandling ( " Fatal error in bytecode: " )
2011-02-04 16:53:12 +01:00
{
completeErrorMsg ( ErrorMsg_arg ) ;
} ;
2010-09-24 12:52:58 +02:00
FatalExceptionHandling ( ) : GeneralExceptionHandling ( " " )
2011-02-04 16:53:12 +01:00
{
} ;
2010-09-24 12:52:58 +02:00
} ;
2010-11-20 15:45:15 +01:00
2013-03-22 15:44:34 +01:00
struct s_plan
{
string var , exo ;
int var_num , exo_num ;
2019-12-20 14:50:19 +01:00
vector < pair < int , double > > per_value ;
2015-09-22 12:45:27 +02:00
vector < double > value ;
2013-03-22 15:44:34 +01:00
} ;
2015-09-22 12:45:27 +02:00
struct table_conditional_local_type
2017-05-16 16:30:27 +02:00
{
bool is_cond ;
int var_exo , var_endo ;
double constrained_value ;
} ;
2021-02-01 13:54:38 +01:00
using vector_table_conditional_local_type = vector < table_conditional_local_type > ;
using table_conditional_global_type = map < int , vector_table_conditional_local_type > ;
2013-03-22 15:44:34 +01:00
# ifdef MATLAB_MEX_FILE
extern " C " bool utIsInterruptPending ( ) ;
# endif
2010-11-20 15:45:15 +01:00
class ErrorMsg
{
2022-07-25 16:20:19 +02:00
protected :
2022-07-28 16:56:40 +02:00
ErrorMsg ( BasicSymbolTable & symbol_table_arg ) : symbol_table { symbol_table_arg }
2011-02-04 16:53:12 +01:00
{
}
2022-07-28 16:56:40 +02:00
BasicSymbolTable & symbol_table ;
ExpressionType EQN_type ;
int EQN_equation , EQN_block , EQN_block_number , EQN_dvar1 ;
2010-11-20 15:45:15 +01:00
2022-07-25 16:20:19 +02:00
private :
2022-05-05 15:52:16 +02:00
/* Given a string which possibly contains a floating-point exception
( materialized by an operator between braces ) , returns a string spanning two
2022-07-25 16:20:19 +02:00
lines , the first line containing the original string without the braces ,
the second line containing tildes ( ~ ) under the faulty operator . */
2022-07-28 15:48:21 +02:00
static string
2011-02-04 16:53:12 +01:00
add_underscore_to_fpe ( const string & str )
{
2022-07-28 15:48:21 +02:00
string line1 ;
optional < size_t > pos1 , pos2 ;
string line2 ( str . length ( ) , ' ' ) ;
for ( char i : str )
2011-02-04 16:53:12 +01:00
{
2022-05-05 15:52:16 +02:00
if ( i ! = ' { ' & & i ! = ' } ' )
2022-07-28 15:48:21 +02:00
line1 + = i ;
2011-02-04 16:53:12 +01:00
else
{
2022-05-05 15:52:16 +02:00
if ( i = = ' { ' )
2022-07-28 15:48:21 +02:00
pos1 = line1 . length ( ) ;
2011-02-04 16:53:12 +01:00
else
2022-07-28 15:48:21 +02:00
pos2 = line1 . length ( ) ;
if ( pos1 & & pos2 )
2011-02-04 16:53:12 +01:00
{
2022-07-28 15:48:21 +02:00
line2 . replace ( * pos1 , * pos2 - * pos1 , * pos2 - * pos1 , ' ~ ' ) ;
pos1 . reset ( ) ;
pos2 . reset ( ) ;
2011-02-04 16:53:12 +01:00
}
}
}
2022-07-28 15:48:21 +02:00
return line1 + " \n " + line2 ;
2011-02-04 16:53:12 +01:00
}
2010-11-20 15:45:15 +01:00
2022-07-25 16:20:19 +02:00
protected :
string
error_location ( it_code_type expr_begin , it_code_type faulty_op , bool steady_state , int it_ )
2011-02-04 16:53:12 +01:00
{
2021-02-09 15:55:36 +01:00
ostringstream Error_loc ;
2022-07-27 18:04:39 +02:00
switch ( EQN_type )
{
case ExpressionType : : TemporaryTerm :
Error_loc < < " temporary term " ;
break ;
case ExpressionType : : ModelEquation :
Error_loc < < " equation " ;
break ;
case ExpressionType : : FirstEndoDerivative :
case ExpressionType : : FirstOtherEndoDerivative :
case ExpressionType : : FirstExoDerivative :
case ExpressionType : : FirstExodetDerivative :
Error_loc < < " first order derivative of equation " ;
break ;
}
Error_loc < < " " < < EQN_equation + 1 ;
if ( EQN_block_number > 1 )
Error_loc < < " in block " < < EQN_block + 1 ;
switch ( EQN_type )
{
case ExpressionType : : TemporaryTerm :
case ExpressionType : : ModelEquation :
break ;
case ExpressionType : : FirstEndoDerivative :
2022-07-28 16:56:40 +02:00
Error_loc < < " with respect to endogenous variable " < < symbol_table . getName ( SymbolType : : endogenous , EQN_dvar1 ) ;
2022-07-27 18:04:39 +02:00
break ;
case ExpressionType : : FirstOtherEndoDerivative :
2022-07-28 16:56:40 +02:00
Error_loc < < " with respect to other endogenous variable " < < symbol_table . getName ( SymbolType : : endogenous , EQN_dvar1 ) ;
2022-07-27 18:04:39 +02:00
break ;
case ExpressionType : : FirstExoDerivative :
2022-07-28 16:56:40 +02:00
Error_loc < < " with respect to exogenous variable " < < symbol_table . getName ( SymbolType : : exogenous , EQN_dvar1 ) ;
2022-07-27 18:04:39 +02:00
break ;
case ExpressionType : : FirstExodetDerivative :
2022-07-28 16:56:40 +02:00
Error_loc < < " with respect to deterministic exogenous variable " < < symbol_table . getName ( SymbolType : : exogenousDet , EQN_dvar1 ) ;
2022-07-27 18:04:39 +02:00
break ;
}
2011-02-04 16:53:12 +01:00
if ( ! steady_state )
2022-07-27 18:04:39 +02:00
Error_loc < < " at time " < < it_ ;
2022-07-25 16:20:19 +02:00
auto [ expr_str , it_code_ret ] = print_expression ( expr_begin , faulty_op ) ;
Error_loc < < endl < < add_underscore_to_fpe ( " " + expr_str ) ;
2021-02-03 18:10:01 +01:00
return Error_loc . str ( ) ;
2011-02-04 16:53:12 +01:00
}
2010-11-20 15:45:15 +01:00
2022-07-25 16:20:19 +02:00
/* Prints a bytecode expression in human readable form.
If faulty_op is not default constructed , it should point to a tag withing
the expression that created a floating point exception , in which case the
corresponding mathematical operator will be printed within braces .
The second output argument points to the tag past the expression . */
pair < string , it_code_type >
2022-07-26 15:52:12 +02:00
print_expression ( const it_code_type & expr_begin , const optional < it_code_type > & faulty_op = nullopt ) const
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
/* First element is output string, 2nd element is precedence of last
operator , 3 rd element is opcode if the last operator was a binary
operator .
Use same precedence values as in the preprocessor for MATLAB or JSON output :
– 0 : = ( assignment )
– 1 : = = ! =
– 2 : < > < = > =
– 3 : + -
– 4 : * /
– 5 : ^ powerDeriv
– 100 : everything else */
stack < tuple < string , int , optional < BinaryOpcode > > > Stack ;
bool go_on { true } ;
ExpressionType equation_type { ExpressionType : : ModelEquation } ;
ExternalFunctionCallType call_type { ExternalFunctionCallType : : levelWithoutDerivative } ;
auto lag_to_string = [ ] ( int l ) - > string
{
if ( l > 0 )
return " (+ " + to_string ( l ) + " ) " ;
else if ( l < 0 )
return " ( " + to_string ( l ) + " ) " ;
else
return { } ;
} ;
// Helper for FST* tags
auto assign_lhs = [ & ] ( const string & lhs )
{
auto & [ str , prec , opcode ] { Stack . top ( ) } ;
str . insert ( 0 , lhs + " = " ) ;
prec = 0 ;
opcode = BinaryOpcode : : equal ;
go_on = false ;
} ;
2010-12-31 16:41:50 +01:00
2022-07-25 16:20:19 +02:00
it_code_type it_code { expr_begin } ;
2010-11-20 15:45:15 +01:00
2011-02-04 16:53:12 +01:00
while ( go_on )
{
2014-01-02 16:17:37 +01:00
# ifdef MATLAB_MEX_FILE
2017-05-16 16:30:27 +02:00
if ( utIsInterruptPending ( ) )
throw UserExceptionHandling ( ) ;
2013-03-22 15:44:34 +01:00
# endif
2022-07-26 18:27:23 +02:00
switch ( ( * it_code ) - > op_code )
2011-02-04 16:53:12 +01:00
{
2021-02-01 12:10:47 +01:00
case Tags : : FNUMEXPR :
2022-07-26 18:27:23 +02:00
switch ( static_cast < FNUMEXPR_ * > ( * it_code ) - > get_expression_type ( ) )
2011-02-04 16:53:12 +01:00
{
2021-02-01 12:10:47 +01:00
case ExpressionType : : TemporaryTerm :
equation_type = ExpressionType : : TemporaryTerm ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case ExpressionType : : ModelEquation :
equation_type = ExpressionType : : ModelEquation ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case ExpressionType : : FirstEndoDerivative :
equation_type = ExpressionType : : FirstEndoDerivative ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case ExpressionType : : FirstOtherEndoDerivative :
equation_type = ExpressionType : : FirstOtherEndoDerivative ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case ExpressionType : : FirstExoDerivative :
equation_type = ExpressionType : : FirstExoDerivative ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case ExpressionType : : FirstExodetDerivative :
equation_type = ExpressionType : : FirstExodetDerivative ;
2011-02-04 16:53:12 +01:00
break ;
default :
2022-07-27 18:04:39 +02:00
throw FatalExceptionHandling { " in print_expression, expression type "
+ to_string ( static_cast < int > ( static_cast < FNUMEXPR_ * > ( * it_code ) - > get_expression_type ( ) ) )
+ " not implemented yet \n " } ;
2011-02-04 16:53:12 +01:00
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDV :
2022-07-27 18:04:39 +02:00
{
int var { static_cast < FLDV_ * > ( * it_code ) - > get_pos ( ) } ;
int lag { static_cast < FLDV_ * > ( * it_code ) - > get_lead_lag ( ) } ;
switch ( SymbolType type { static_cast < FLDV_ * > ( * it_code ) - > get_type ( ) } ;
type )
{
case SymbolType : : parameter :
case SymbolType : : endogenous :
case SymbolType : : exogenous :
case SymbolType : : exogenousDet :
2022-07-28 16:56:40 +02:00
Stack . emplace ( symbol_table . getName ( type , var ) + lag_to_string ( lag ) , 100 , nullopt ) ;
2022-07-27 18:04:39 +02:00
break ;
default :
throw FatalExceptionHandling { " FLDV: Unknown variable type \n " } ;
2011-02-04 16:53:12 +01:00
}
2022-07-27 18:04:39 +02:00
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDSV :
2022-07-27 18:04:39 +02:00
{
int var { static_cast < FLDSV_ * > ( * it_code ) - > get_pos ( ) } ;
switch ( SymbolType type { static_cast < FLDSV_ * > ( * it_code ) - > get_type ( ) } ;
type )
{
case SymbolType : : parameter :
case SymbolType : : endogenous :
case SymbolType : : exogenous :
case SymbolType : : exogenousDet :
2022-07-28 16:56:40 +02:00
Stack . emplace ( symbol_table . getName ( type , var ) , 100 , nullopt ) ;
2022-07-27 18:04:39 +02:00
break ;
default :
throw FatalExceptionHandling { " FLDSV: Unknown variable type \n " } ;
}
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDVS :
2022-07-27 18:04:39 +02:00
{
int var { static_cast < FLDVS_ * > ( * it_code ) - > get_pos ( ) } ;
switch ( SymbolType type { static_cast < FLDVS_ * > ( * it_code ) - > get_type ( ) } ;
type )
{
case SymbolType : : parameter :
case SymbolType : : endogenous :
case SymbolType : : exogenous :
case SymbolType : : exogenousDet :
2022-07-28 16:56:40 +02:00
Stack . emplace ( symbol_table . getName ( type , var ) , 100 , nullopt ) ;
2022-07-27 18:04:39 +02:00
break ;
default :
throw FatalExceptionHandling { " FLDVS: Unknown variable type \n " } ;
}
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDT :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " T " + to_string ( static_cast < FLDT_ * > ( * it_code ) - > get_pos ( ) + 1 ) , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDST :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " T " + to_string ( static_cast < FLDST_ * > ( * it_code ) - > get_pos ( ) + 1 ) , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDU :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " u( " + to_string ( static_cast < FLDU_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " + it_) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDSU :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " u( " + to_string ( static_cast < FLDSU_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " ) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDR :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " residual( " + to_string ( static_cast < FLDR_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " ) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDZ :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " 0 " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDC :
2022-07-28 17:10:12 +02:00
{
// We don’ t use std::to_string(), because it uses fixed formatting
ostringstream s ;
s < < defaultfloat < < static_cast < FLDC_ * > ( * it_code ) - > get_value ( ) ;
Stack . emplace ( s . str ( ) , 100 , nullopt ) ;
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPV :
2022-07-27 18:04:39 +02:00
{
int var { static_cast < FSTPV_ * > ( * it_code ) - > get_pos ( ) } ;
int lag { static_cast < FSTPV_ * > ( * it_code ) - > get_lead_lag ( ) } ;
switch ( SymbolType type { static_cast < FSTPV_ * > ( * it_code ) - > get_type ( ) } ;
type )
{
case SymbolType : : parameter :
case SymbolType : : endogenous :
case SymbolType : : exogenous :
case SymbolType : : exogenousDet :
2022-07-28 16:56:40 +02:00
assign_lhs ( symbol_table . getName ( type , var ) + lag_to_string ( lag ) ) ;
2022-07-27 18:04:39 +02:00
break ;
default :
throw FatalExceptionHandling { " FSTPV: Unknown variable type \n " } ;
}
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPSV :
2022-07-27 18:04:39 +02:00
{
int var { static_cast < FSTPSV_ * > ( * it_code ) - > get_pos ( ) } ;
switch ( SymbolType type { static_cast < FSTPSV_ * > ( * it_code ) - > get_type ( ) } ;
type )
{
case SymbolType : : parameter :
case SymbolType : : endogenous :
case SymbolType : : exogenous :
case SymbolType : : exogenousDet :
2022-07-28 16:56:40 +02:00
assign_lhs ( symbol_table . getName ( type , var ) ) ;
2022-07-27 18:04:39 +02:00
break ;
default :
throw FatalExceptionHandling { " FSTPSV: Unknown variable type \n " } ;
}
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPT :
2022-07-27 18:04:39 +02:00
assign_lhs ( " T " + to_string ( static_cast < FSTPT_ * > ( * it_code ) - > get_pos ( ) + 1 ) ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPST :
2022-07-27 18:04:39 +02:00
assign_lhs ( " T " + to_string ( static_cast < FSTPST_ * > ( * it_code ) - > get_pos ( ) + 1 ) ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPU :
2022-07-27 18:04:39 +02:00
assign_lhs ( " u( " + to_string ( static_cast < FSTPU_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " + it_) " ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPSU :
2022-07-27 18:04:39 +02:00
assign_lhs ( " u( " + to_string ( static_cast < FSTPSU_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPR :
2022-07-27 18:04:39 +02:00
assign_lhs ( " residual( " + to_string ( static_cast < FSTPR_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPG :
2022-07-27 18:04:39 +02:00
assign_lhs ( " g1( " + to_string ( static_cast < FSTPG_ * > ( * it_code ) - > get_pos ( ) + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPG2 :
2022-07-27 18:04:39 +02:00
{
int eq { static_cast < FSTPG2_ * > ( * it_code ) - > get_row ( ) } ;
int var { static_cast < FSTPG2_ * > ( * it_code ) - > get_col ( ) } ;
assign_lhs ( " jacob( " + to_string ( eq + 1 ) + " , " + to_string ( var + 1 ) + " ) " ) ;
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPG3 :
2022-07-27 18:04:39 +02:00
{
int eq { static_cast < FSTPG3_ * > ( * it_code ) - > get_row ( ) } ;
int var { static_cast < FSTPG3_ * > ( * it_code ) - > get_col ( ) } ;
int lag { static_cast < FSTPG3_ * > ( * it_code ) - > get_lag ( ) } ;
int col_pos { static_cast < FSTPG3_ * > ( * it_code ) - > get_col_pos ( ) } ;
string matrix_name { [ & ]
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
switch ( equation_type )
{
case ExpressionType : : FirstEndoDerivative :
return " jacob " ;
case ExpressionType : : FirstOtherEndoDerivative :
return " jacob_other_endo " ;
case ExpressionType : : FirstExoDerivative :
return " jacob_exo " ;
case ExpressionType : : FirstExodetDerivative :
return " jacob_exo_det " ;
default :
throw FatalExceptionHandling { " unknown equation type " + to_string ( static_cast < int > ( equation_type ) ) + " \n " } ;
}
} ( ) } ;
assign_lhs ( matrix_name + " ( " + to_string ( eq + 1 ) + " , " + to_string ( col_pos + 1 )
+ " [var= " + to_string ( var + 1 ) + " , lag= " + to_string ( lag ) + " ]) " ) ;
}
2011-02-04 16:53:12 +01:00
break ;
2022-07-27 18:04:39 +02:00
case Tags : : FUNARY :
{
UnaryOpcode op { static_cast < FUNARY_ * > ( * it_code ) - > get_op_type ( ) } ;
auto [ arg , prec_arg , op_arg ] { Stack . top ( ) } ;
Stack . pop ( ) ;
ostringstream s ;
// Always put parenthesis around uminus nodes
if ( op = = UnaryOpcode : : uminus )
s < < " ( " ;
s < < [ & ]
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
switch ( op )
{
case UnaryOpcode : : uminus :
return " - " ;
case UnaryOpcode : : exp :
return " exp " ;
case UnaryOpcode : : log :
return it_code = = faulty_op ? " {log} " : " log " ;
case UnaryOpcode : : log10 :
return it_code = = faulty_op ? " {log10} " : " log10 " ;
case UnaryOpcode : : cos :
return " cos " ;
case UnaryOpcode : : sin :
return " sin " ;
case UnaryOpcode : : tan :
return " tan " ;
case UnaryOpcode : : acos :
return " acos " ;
case UnaryOpcode : : asin :
return " asin " ;
case UnaryOpcode : : atan :
return " atan " ;
case UnaryOpcode : : cosh :
return " cosh " ;
case UnaryOpcode : : sinh :
return " sinh " ;
case UnaryOpcode : : tanh :
return " tanh " ;
case UnaryOpcode : : acosh :
return " acosh " ;
case UnaryOpcode : : asinh :
return " asinh " ;
case UnaryOpcode : : atanh :
return " atanh " ;
case UnaryOpcode : : sqrt :
return " sqrt " ;
case UnaryOpcode : : cbrt :
return " cbrt " ;
case UnaryOpcode : : erf :
return " erf " ;
case UnaryOpcode : : erfc :
return " erfc " ;
case UnaryOpcode : : abs :
return " abs " ;
case UnaryOpcode : : sign :
return " sign " ;
case UnaryOpcode : : steadyState :
return " steady_state " ;
case UnaryOpcode : : steadyStateParamDeriv :
case UnaryOpcode : : steadyStateParam2ndDeriv :
throw FatalExceptionHandling { " Unexpected derivative of steady_state operator " } ;
case UnaryOpcode : : expectation :
throw FatalExceptionHandling { " Unexpected expectation operator " } ;
case UnaryOpcode : : diff :
return " diff " ;
case UnaryOpcode : : adl :
return " adl " ;
}
throw FatalExceptionHandling { " Unknown opcode " } ;
} ( ) ;
/* Print argument. Enclose it with parentheses if:
- current opcode is not uminus , or
- current opcode is uminus and argument has lowest precedence */
bool close_parenthesis { false } ;
if ( op ! = UnaryOpcode : : uminus
| | ( op = = UnaryOpcode : : uminus & & prec_arg < 100 ) )
2010-12-31 16:41:50 +01:00
{
2022-07-27 18:04:39 +02:00
s < < " ( " ;
close_parenthesis = true ;
2010-12-31 16:41:50 +01:00
}
2022-07-27 18:04:39 +02:00
s < < arg ;
if ( close_parenthesis )
s < < " ) " ;
// Close parenthesis for uminus
if ( op = = UnaryOpcode : : uminus )
s < < " ) " ;
Stack . emplace ( s . str ( ) , 100 , nullopt ) ;
}
2011-02-04 16:53:12 +01:00
break ;
2022-07-27 18:04:39 +02:00
case Tags : : FBINARY :
{
BinaryOpcode op { static_cast < FBINARY_ * > ( * it_code ) - > get_op_type ( ) } ;
auto [ arg2 , prec_arg2 , op_arg2 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
auto [ arg1 , prec_arg1 , op_arg1 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
if ( op = = BinaryOpcode : : max )
Stack . emplace ( " max( " + arg1 + " , " + arg2 + " ) " , 100 , nullopt ) ;
else if ( op = = BinaryOpcode : : min )
Stack . emplace ( " min( " + arg1 + " , " + arg2 + " ) " , 100 , nullopt ) ;
else if ( op = = BinaryOpcode : : powerDeriv )
{
auto [ arg3 , prec_arg3 , op_arg3 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
Stack . emplace ( ( it_code = = faulty_op ? " {PowerDeriv}( " : " PowerDeriv( " ) + arg1
2022-07-28 17:13:23 +02:00
+ " , " + arg2 + " , " + arg3 + " ) " , 100 , nullopt ) ;
2022-07-27 18:04:39 +02:00
}
else
{
ostringstream s ;
int prec { [ & ]
{
switch ( op )
{
case BinaryOpcode : : equal :
return 0 ;
case BinaryOpcode : : equalEqual :
case BinaryOpcode : : different :
return 1 ;
case BinaryOpcode : : lessEqual :
case BinaryOpcode : : greaterEqual :
case BinaryOpcode : : less :
case BinaryOpcode : : greater :
return 2 ;
case BinaryOpcode : : plus :
case BinaryOpcode : : minus :
return 3 ;
case BinaryOpcode : : times :
case BinaryOpcode : : divide :
return 4 ;
case BinaryOpcode : : power :
case BinaryOpcode : : powerDeriv :
return 5 ;
case BinaryOpcode : : min :
case BinaryOpcode : : max :
return 100 ;
}
throw FatalExceptionHandling { " Unknown opcode " } ;
} ( ) } ;
/* Print left argument. If left argument has a lower
precedence , or if current and left argument are both power
operators , add parenthesis around left argument . */
bool close_parenthesis { false } ;
if ( prec_arg1 < prec
| | ( op = = BinaryOpcode : : power & & op_arg1 = = BinaryOpcode : : power ) )
{
s < < " ( " ;
close_parenthesis = true ;
}
s < < arg1 ;
if ( close_parenthesis )
s < < " ) " ;
s < < [ & ]
{
switch ( op )
{
case BinaryOpcode : : plus :
return " + " ;
case BinaryOpcode : : minus :
return " - " ;
case BinaryOpcode : : times :
return " * " ;
case BinaryOpcode : : divide :
return it_code = = faulty_op ? " { / } " : " / " ;
case BinaryOpcode : : less :
return " < " ;
case BinaryOpcode : : greater :
return " > " ;
case BinaryOpcode : : lessEqual :
return " <= " ;
case BinaryOpcode : : greaterEqual :
return " >= " ;
case BinaryOpcode : : equalEqual :
return " == " ;
case BinaryOpcode : : different :
return " != " ;
case BinaryOpcode : : power :
return it_code = = faulty_op ? " { ^ } " : " ^ " ;
case BinaryOpcode : : powerDeriv :
case BinaryOpcode : : max :
case BinaryOpcode : : min :
throw FatalExceptionHandling { " Should not arrive here " } ;
case BinaryOpcode : : equal :
return " = " ;
}
throw FatalExceptionHandling { " Unknown opcode " } ;
} ( ) ;
/* Print right argument. Add parenthesis around right argument if:
- its precedence is lower than that of the current node
- it is a power operator and current operator is also a power operator
- it has same precedence as current operator and current operator is
either a minus or a divide */
close_parenthesis = false ;
if ( prec_arg2 < prec
| | ( op = = BinaryOpcode : : power & & op_arg2 = = BinaryOpcode : : power )
| | ( prec_arg2 = = prec & & ( op = = BinaryOpcode : : minus | | op = = BinaryOpcode : : divide ) ) )
{
s < < " ( " ;
close_parenthesis = true ;
}
s < < arg2 ;
if ( close_parenthesis )
s < < " ) " ;
Stack . emplace ( s . str ( ) , prec , op ) ;
}
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FTRINARY :
2022-07-27 18:04:39 +02:00
{
TrinaryOpcode op { static_cast < FTRINARY_ * > ( * it_code ) - > get_op_type ( ) } ;
auto [ arg3 , prec_arg3 , op_arg3 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
auto [ arg2 , prec_arg2 , op_arg2 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
auto [ arg1 , prec_arg1 , op_arg1 ] { Stack . top ( ) } ;
Stack . pop ( ) ;
string opname { [ & ]
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
switch ( op )
{
case TrinaryOpcode : : normcdf :
return " normcdf " ;
case TrinaryOpcode : : normpdf :
return " normpdf " ;
}
throw FatalExceptionHandling { " Unknown opcode " } ;
} ( ) } ;
Stack . emplace ( opname + " ( " + arg1 + " , " + arg2 + " , " + arg3 + " ) " , 100 , nullopt ) ;
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FCALL :
2011-02-04 16:53:12 +01:00
{
2022-07-26 18:27:23 +02:00
auto * fc = static_cast < FCALL_ * > ( * it_code ) ;
2022-07-27 18:04:39 +02:00
string function_name { fc - > get_function_name ( ) } ;
2022-06-20 17:50:51 +02:00
int nb_input_arguments { fc - > get_nb_input_arguments ( ) } ;
int nb_add_input_arguments { fc - > get_nb_add_input_arguments ( ) } ;
2022-07-27 18:04:39 +02:00
string arg_func_name { fc - > get_arg_func_name ( ) } ;
ostringstream s ;
auto print_args = [ & ] ( int nargs )
{
vector < string > ss ( nargs ) ;
for ( int i { 0 } ; i < nargs ; i + + )
{
ss [ nargs - i - 1 ] = get < 0 > ( Stack . top ( ) ) ;
Stack . pop ( ) ;
}
for ( int i { 0 } ; i < nargs ; i + + )
{
if ( i > 0 )
s < < " , " ;
s < < ss [ i ] ;
}
} ;
2022-07-08 16:05:33 +02:00
call_type = fc - > get_call_type ( ) ;
switch ( call_type )
2011-02-04 16:53:12 +01:00
{
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : levelWithoutDerivative :
case ExternalFunctionCallType : : levelWithFirstDerivative :
case ExternalFunctionCallType : : levelWithFirstAndSecondDerivative :
2022-07-27 18:04:39 +02:00
case ExternalFunctionCallType : : separatelyProvidedFirstDerivative :
case ExternalFunctionCallType : : separatelyProvidedSecondDerivative :
s < < function_name < < " ( " ;
print_args ( nb_input_arguments ) ;
s < < " ) " ;
2011-02-04 16:53:12 +01:00
break ;
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : numericalFirstDerivative :
2022-07-27 18:04:39 +02:00
s < < function_name < < " ( " < < arg_func_name < < " , " < < fc - > get_row ( ) + 1 < < " , { " ;
print_args ( nb_add_input_arguments ) ;
s < < " }) " ;
2011-02-04 16:53:12 +01:00
break ;
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : numericalSecondDerivative :
2022-07-27 18:04:39 +02:00
s < < function_name < < " ( " < < arg_func_name < < " , " < < fc - > get_row ( ) + 1 < < " , " < < fc - > get_col ( ) + 1 < < " , { " ;
print_args ( nb_add_input_arguments ) ;
s < < " }) " ;
2011-02-04 16:53:12 +01:00
break ;
}
2022-07-27 18:04:39 +02:00
Stack . emplace ( s . str ( ) , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
}
2022-07-27 18:04:39 +02:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPTEF :
2022-07-27 18:04:39 +02:00
{
int indx { static_cast < FSTPTEF_ * > ( * it_code ) - > get_number ( ) } ;
switch ( call_type )
2011-02-04 16:53:12 +01:00
{
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : levelWithoutDerivative :
2022-07-27 18:04:39 +02:00
assign_lhs ( " TEF( " + to_string ( indx + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
break ;
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : levelWithFirstDerivative :
2022-07-27 18:04:39 +02:00
assign_lhs ( " [TEF( " + to_string ( indx + 1 ) + " ), TEFD( " + to_string ( indx + 1 ) + " ) ] " ) ;
2011-02-04 16:53:12 +01:00
break ;
2022-07-08 16:05:33 +02:00
case ExternalFunctionCallType : : levelWithFirstAndSecondDerivative :
2022-07-27 18:04:39 +02:00
assign_lhs ( " [TEF( " + to_string ( indx + 1 ) + " ), TEFD( " + to_string ( indx + 1 ) + " ), TEFDD( " + to_string ( indx + 1 ) + " ) ] " ) ;
2011-02-04 16:53:12 +01:00
break ;
default :
2022-07-27 18:04:39 +02:00
throw FatalExceptionHandling { " Unexpected external function call type " } ;
2011-02-04 16:53:12 +01:00
}
2022-07-27 18:04:39 +02:00
}
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDTEF :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " TEF( " + to_string ( static_cast < FLDTEF_ * > ( * it_code ) - > get_number ( ) + 1 ) + " ) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPTEFD :
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
int indx { static_cast < FSTPTEFD_ * > ( * it_code ) - > get_indx ( ) } ;
int row { static_cast < FSTPTEFD_ * > ( * it_code ) - > get_row ( ) } ;
2022-07-08 16:05:33 +02:00
if ( call_type = = ExternalFunctionCallType : : numericalFirstDerivative )
2022-07-27 18:04:39 +02:00
assign_lhs ( " TEFD( " + to_string ( indx + 1 ) + " , " + to_string ( row + 1 ) + " ) " ) ;
2022-07-08 16:05:33 +02:00
else if ( call_type = = ExternalFunctionCallType : : separatelyProvidedFirstDerivative )
2022-07-27 18:04:39 +02:00
assign_lhs ( " TEFD( " + to_string ( indx + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDTEFD :
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
int indx { static_cast < FLDTEFD_ * > ( * it_code ) - > get_indx ( ) } ;
int row { static_cast < FLDTEFD_ * > ( * it_code ) - > get_row ( ) } ;
Stack . emplace ( " TEFD( " + to_string ( indx + 1 ) + " , " + to_string ( row + 1 ) + " ) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FSTPTEFDD :
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
int indx { static_cast < FSTPTEFDD_ * > ( * it_code ) - > get_indx ( ) } ;
int row { static_cast < FSTPTEFDD_ * > ( * it_code ) - > get_row ( ) } ;
int col { static_cast < FSTPTEFDD_ * > ( * it_code ) - > get_col ( ) } ;
2022-07-08 16:05:33 +02:00
if ( call_type = = ExternalFunctionCallType : : numericalSecondDerivative )
2022-07-27 18:04:39 +02:00
assign_lhs ( " TEFDD( " + to_string ( indx + 1 ) + " , " + to_string ( row + 1 ) + " , " + to_string ( col + 1 ) + " ) " ) ;
2022-07-08 16:05:33 +02:00
else if ( call_type = = ExternalFunctionCallType : : separatelyProvidedSecondDerivative )
2022-07-27 18:04:39 +02:00
assign_lhs ( " TEFDD( " + to_string ( indx + 1 ) + " ) " ) ;
2011-02-04 16:53:12 +01:00
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FLDTEFDD :
2011-02-04 16:53:12 +01:00
{
2022-07-27 18:04:39 +02:00
int indx { static_cast < FLDTEFDD_ * > ( * it_code ) - > get_indx ( ) } ;
int row { static_cast < FLDTEFDD_ * > ( * it_code ) - > get_row ( ) } ;
int col { static_cast < FSTPTEFDD_ * > ( * it_code ) - > get_col ( ) } ;
Stack . emplace ( " TEFDD( " + to_string ( indx + 1 ) + " , " + to_string ( row + 1 ) + " , " + to_string ( col + 1 ) + " ) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
}
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FJMPIFEVAL :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " if (~evaluate) " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
go_on = false ;
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FJMP :
2022-07-27 18:04:39 +02:00
Stack . emplace ( " else " , 100 , nullopt ) ;
2011-02-04 16:53:12 +01:00
go_on = false ;
break ;
2021-02-01 12:10:47 +01:00
case Tags : : FENDBLOCK :
case Tags : : FENDEQU :
2011-02-04 16:53:12 +01:00
go_on = false ;
break ;
default :
2021-02-03 18:10:01 +01:00
throw FatalExceptionHandling ( " in print_expression, unknown opcode "
2022-07-27 18:04:39 +02:00
+ to_string ( static_cast < int > ( ( * it_code ) - > op_code ) ) + " \n " ) ;
2010-12-31 16:41:50 +01:00
}
2011-02-04 16:53:12 +01:00
it_code + + ;
}
2022-07-27 18:04:39 +02:00
return { get < 0 > ( Stack . top ( ) ) , it_code } ;
2011-02-04 16:53:12 +01:00
}
2022-07-25 16:20:19 +02:00
public :
static void
2021-02-03 18:10:01 +01:00
test_mxMalloc ( void * z , int line , const string & file , const string & func , int amount )
2017-05-16 16:30:27 +02:00
{
2021-02-03 18:10:01 +01:00
if ( ! z & & amount > 0 )
throw FatalExceptionHandling ( " mxMalloc: out of memory " + to_string ( amount ) + " bytes required at line " + to_string ( line ) + " in function " + func + " (file " + file ) ;
2017-05-16 16:30:27 +02:00
}
2010-11-20 15:45:15 +01:00
} ;
2022-07-29 12:40:33 +02:00
# endif // _ERROR_HANDLING_HH