Add support for external functions

time-shift
Houtan Bastani 2010-02-22 17:33:38 +01:00
parent 38b8ccf52d
commit 12c4a52ebc
23 changed files with 954 additions and 156 deletions

75
matlab/hess_element.m Normal file
View File

@ -0,0 +1,75 @@
function d=hess_element(func,element1,element2,args)
% function d=hess_element(func,element1,element2,args)
% returns an entry of the finite differences approximation to the hessian of func
%
% INPUTS
% func [function handle] associated with the function
% element1 [int] the indices showing the element within the hessian that should be returned
% element2 [int]
% args [cell array] arguments provided to func
%
% OUTPUTS
% d [double] the (element1,element2) entry of the hessian
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2010 Dynare Team
%
% 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/>.
h=10e-6;
p10 = args;
p01 = args;
m10 = args;
m01 = args;
p11 = args;
m11 = args;
for i=1:size(args,2)
if i==element1
p10{i} = p10{i} + h;
m10{i} = m10{i} - h;
p11{i} = p11{i} + h;
m11{i} = m11{i} - h;
end
if i==element2
p01{i} = p01{i} + h;
m01{i} = m01{i} - h;
p11{i} = p11{i} + h;
m11{i} = m11{i} - h;
end
end
% From Abramowitz and Stegun. Handbook of Mathematical Functions (1965)
% formulas 25.3.24 and 25.3.27 p. 884
if element1==element2
d = (16*func(p10{:})...
+16*func(m10{:})...
-30*func(args{:})...
-func(p11{:})...
-func(m11{:}))/(12*h^2);
else
d = (func(p10{:})...
+func(m10{:})...
+func(p01{:})...
+func(m01{:})...
-2*func(args{:})...
-func(p11{:})...
-func(m11{:}))/(-2*h^2);
end

43
matlab/jacob_element.m Normal file
View File

@ -0,0 +1,43 @@
function d=jacob_element(func,element,args)
% function d=jacob_element(func,element,args)
% returns an entry of the finite differences approximation to the jacobian of func
%
% INPUTS
% func [function handle] associated with the function
% element [int] the index showing the element within the jacobian that should be returned
% args [cell array] arguments provided to func
%
% OUTPUTS
% d [double] jacobian[element]
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2010 Dynare Team
%
% 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/>.
h=10e-6;
pargs=args;
margs=args;
for i=1:size(args,2)
if i==element
pargs{i} = pargs{i} + h;
margs{i} = margs{i} - h;
end
end
d=(func(pargs{:})...
-func(margs{:}))/(2*h);

61
matlab/subscript_get.m Normal file
View File

@ -0,0 +1,61 @@
function deriv = subscript_get(nargsout, func, args, varargin)
% function deriv = subscript_get(nargsout, func, args, varargin)
% returns the appropriate entry of the return argument from a user-defined function
% which returns either the jacobian or hessian (or both)
%
% INPUTS
% nargsout [int] integer indicating the number of the return argument containing the jac/hess
% func [function handle] associated with the function
% args [cell array] arguments provided to func
% varargin [cell array] arguments showing the index (or indices) of the element to be returned
%
% OUTPUTS
% deriv [double] the (element1,element2) entry of the hessian
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2010 Dynare Team
%
% 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/>.
switch size(varargin,2)
case 1 %first deriv
switch nargsout
case 1
[outargs{1}] = func(args{:});
deriv = outargs{1}(varargin{1});
case 2
[outargs{1} outargs{2}] = func(args{:});
deriv = outargs{2}(varargin{1});
otherwise
error('Wrong number of output arguments (%d) passed to subscript_get().',nargsout);
end
case 2 %second deriv
switch nargsout
case 1
[outargs{1}] = func(args{:});
deriv = outargs{1}(varargin{1},varargin{2});
case 3
[outargs{1} outargs{2} outargs{3}] = func(args{:});
deriv = outargs{3}(varargin{1},varargin{2});
otherwise
error('Wrong number of output arguments (%d) passed to subscript_get().',nargsout);
end
otherwise
error('Wrong number of indices (%d) was passed to subscript_get().',size(varargin,2));
end
end

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007-2009 Dynare Team * Copyright (C) 2007-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -139,7 +139,7 @@ enum SymbolType
eParameter = 4, //!< Parameter eParameter = 4, //!< Parameter
eModelLocalVariable = 10, //!< Local variable whose scope is model (pound expression) eModelLocalVariable = 10, //!< Local variable whose scope is model (pound expression)
eModFileLocalVariable = 11, //!< Local variable whose scope is mod file (model excluded) eModFileLocalVariable = 11, //!< Local variable whose scope is mod file (model excluded)
eUnknownFunction = 12 //!< Function unknown to the preprocessor eExternalFunction = 12 //!< External (user-defined) function
}; };
enum ExpressionType enum ExpressionType

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -23,9 +23,12 @@
#include "DataTree.hh" #include "DataTree.hh"
DataTree::DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg) : DataTree::DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg) :
symbol_table(symbol_table_arg), symbol_table(symbol_table_arg),
num_constants(num_constants_arg), num_constants(num_constants_arg),
external_functions_table(external_functions_table_arg),
node_counter(0) node_counter(0)
{ {
Zero = AddNumConstant("0"); Zero = AddNumConstant("0");
@ -454,13 +457,30 @@ DataTree::AddLocalVariable(const string &name, NodeID value) throw (LocalVariabl
} }
NodeID NodeID
DataTree::AddUnknownFunction(const string &function_name, const vector<NodeID> &arguments) DataTree::AddExternalFunction(const string &function_name, const vector<NodeID> &arguments)
{ {
int id = symbol_table.getID(function_name); return AddExternalFunction(symbol_table.getID(function_name), arguments);
}
assert(symbol_table.getType(id) == eUnknownFunction); NodeID
DataTree::AddExternalFunction(int symb_id, const vector<NodeID> &arguments)
{
assert(symbol_table.getType(symb_id) == eExternalFunction);
return new ExternalFunctionNode(*this, symb_id, arguments);
}
return new UnknownFunctionNode(*this, id, arguments); NodeID
DataTree::AddFirstDerivExternalFunctionNode(int top_level_symb_id, const vector<NodeID> &arguments, int input_index)
{
assert(symbol_table.getType(top_level_symb_id) == eExternalFunction);
return new FirstDerivExternalFunctionNode(*this, top_level_symb_id, arguments, input_index);
}
NodeID
DataTree::AddSecondDerivExternalFunctionNode(int top_level_symb_id, const vector<NodeID> &arguments, int input_index1, int input_index2)
{
assert(symbol_table.getType(top_level_symb_id) == eExternalFunction);
return new SecondDerivExternalFunctionNode(*this, top_level_symb_id, arguments, input_index1, input_index2);
} }
bool bool

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -30,6 +30,7 @@ using namespace std;
#include "SymbolTable.hh" #include "SymbolTable.hh"
#include "NumericalConstants.hh" #include "NumericalConstants.hh"
#include "ExternalFunctionsTable.hh"
#include "ExprNode.hh" #include "ExprNode.hh"
#define CONSTANTS_PRECISION 16 #define CONSTANTS_PRECISION 16
@ -42,12 +43,16 @@ class DataTree
friend class UnaryOpNode; friend class UnaryOpNode;
friend class BinaryOpNode; friend class BinaryOpNode;
friend class TrinaryOpNode; friend class TrinaryOpNode;
friend class UnknownFunctionNode; friend class ExternalFunctionNode;
friend class FirstDerivExternalFunctionNode;
friend class SecondDerivExternalFunctionNode;
protected: protected:
//! A reference to the symbol table //! A reference to the symbol table
SymbolTable &symbol_table; SymbolTable &symbol_table;
//! Reference to numerical constants table //! Reference to numerical constants table
NumericalConstants &num_constants; NumericalConstants &num_constants;
//! A reference to the external functions table
ExternalFunctionsTable &external_functions_table;
typedef map<int, NumConstNode *> num_const_node_map_type; typedef map<int, NumConstNode *> num_const_node_map_type;
num_const_node_map_type num_const_node_map; num_const_node_map_type num_const_node_map;
@ -80,7 +85,7 @@ private:
inline NodeID AddTrinaryOp(NodeID arg1, TrinaryOpcode op_code, NodeID arg2, NodeID arg3); inline NodeID AddTrinaryOp(NodeID arg1, TrinaryOpcode op_code, NodeID arg2, NodeID arg3);
public: public:
DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg); DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg);
virtual ~DataTree(); virtual ~DataTree();
//! Some predefined constants //! Some predefined constants
@ -175,9 +180,14 @@ public:
NodeID AddEqual(NodeID iArg1, NodeID iArg2); NodeID AddEqual(NodeID iArg1, NodeID iArg2);
//! Adds a model local variable with its value //! Adds a model local variable with its value
void AddLocalVariable(const string &name, NodeID value) throw (LocalVariableException); void AddLocalVariable(const string &name, NodeID value) throw (LocalVariableException);
//! Adds an unknown function node //! Adds an external function node
/*! \todo Use a map to share identical nodes */ /*! \todo Use a map to share identical nodes */
NodeID AddUnknownFunction(const string &function_name, const vector<NodeID> &arguments); NodeID AddExternalFunction(const string &function_name, const vector<NodeID> &arguments);
NodeID AddExternalFunction(int symb_id, const vector<NodeID> &arguments);
//! Adds an external function node for the first derivative of an external function
NodeID AddFirstDerivExternalFunctionNode(int top_level_symb_id, const vector<NodeID> &arguments, int input_index);
//! Adds an external function node for the second derivative of an external function
NodeID AddSecondDerivExternalFunctionNode(int top_level_symb_id, const vector<NodeID> &arguments, int input_index1, int input_index2);
//! Checks if a given symbol is used somewhere in the data tree //! Checks if a given symbol is used somewhere in the data tree
bool isSymbolUsed(int symb_id) const; bool isSymbolUsed(int symb_id) const;
//! Checks if a given unary op is used somewhere in the data tree //! Checks if a given unary op is used somewhere in the data tree

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -36,8 +36,9 @@
#endif #endif
DynamicModel::DynamicModel(SymbolTable &symbol_table_arg, DynamicModel::DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg) : NumericalConstants &num_constants_arg,
ModelTree(symbol_table_arg, num_constants_arg), ExternalFunctionsTable &external_functions_table_arg) :
ModelTree(symbol_table_arg, num_constants_arg, external_functions_table_arg),
max_lag(0), max_lead(0), max_lag(0), max_lead(0),
max_endo_lag(0), max_endo_lead(0), max_endo_lag(0), max_endo_lead(0),
max_exo_lag(0), max_exo_lead(0), max_exo_lag(0), max_exo_lead(0),

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -199,7 +199,7 @@ private:
vector<pair<int, int> > endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block; vector<pair<int, int> > endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block;
public: public:
DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_argx);
//! Adds a variable node //! Adds a variable node
/*! This implementation allows for non-zero lag */ /*! This implementation allows for non-zero lag */
virtual VariableNode *AddVariable(int symb_id, int lag = 0); virtual VariableNode *AddVariable(int symb_id, int lag = 0);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -158,9 +158,10 @@ class ParsingDriver;
%token SVAR_IDENTIFICATION EQUATION EXCLUSION LAG UPPER_CHOLESKY LOWER_CHOLESKY %token SVAR_IDENTIFICATION EQUATION EXCLUSION LAG UPPER_CHOLESKY LOWER_CHOLESKY
%token MARKOV_SWITCHING CHAIN STATE DURATION NUMBER_OF_STATES %token MARKOV_SWITCHING CHAIN STATE DURATION NUMBER_OF_STATES
%token SVAR COEFFICIENTS VARIANCES CONSTANTS EQUATIONS %token SVAR COEFFICIENTS VARIANCES CONSTANTS EQUATIONS
%token EXTERNAL_FUNCTION EXT_FUNC_NAME EXT_FUNC_NARGS FIRST_DERIV_PROVIDED SECOND_DERIV_PROVIDED
%type <node_val> expression expression_or_empty %type <node_val> expression expression_or_empty
%type <node_val> equation hand_side model_var %type <node_val> equation hand_side
%type <string_val> signed_float signed_integer prior %type <string_val> signed_float signed_integer prior
%type <string_val> filename symbol expectation_input %type <string_val> filename symbol expectation_input
%type <string_val> value value1 %type <string_val> value value1
@ -239,6 +240,7 @@ statement : parameters
| svar_identification | svar_identification
| markov_switching | markov_switching
| svar | svar
| external_function
; ;
dsample : DSAMPLE INT_NUMBER ';' dsample : DSAMPLE INT_NUMBER ';'
@ -413,8 +415,8 @@ expression : '(' expression ')'
{ $$ = driver.add_max($3, $5); } { $$ = driver.add_max($3, $5); }
| MIN '(' expression COMMA expression ')' | MIN '(' expression COMMA expression ')'
{ $$ = driver.add_min($3, $5); } { $$ = driver.add_min($3, $5); }
| symbol '(' comma_expression ')' | symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_expression ')'
{ $$ = driver.add_unknown_function($1); } { $$ = driver.add_model_var_or_external_function($1); }
| NORMCDF '(' expression COMMA expression COMMA expression ')' | NORMCDF '(' expression COMMA expression COMMA expression ')'
{ $$ = driver.add_normcdf($3, $5, $7); } { $$ = driver.add_normcdf($3, $5, $7); }
| NORMCDF '(' expression ')' | NORMCDF '(' expression ')'
@ -426,14 +428,14 @@ expression : '(' expression ')'
; ;
comma_expression : expression comma_expression : expression
{ driver.add_unknown_function_arg($1); } { driver.add_external_function_arg($1); }
| comma_expression COMMA expression | comma_expression COMMA expression
{ driver.add_unknown_function_arg($3); } { driver.add_external_function_arg($3); }
; ;
expression_or_empty : {$$ = driver.add_nan_constant();} expression_or_empty : {$$ = driver.add_nan_constant();}
| expression | expression
; ;
initval : INITVAL ';' initval_list END initval : INITVAL ';' initval_list END
{ driver.end_initval(); } { driver.end_initval(); }
@ -503,7 +505,8 @@ tag_pair : NAME EQUAL QUOTED_STRING
hand_side : '(' hand_side ')' hand_side : '(' hand_side ')'
{ $$ = $2;} { $$ = $2;}
| model_var | symbol
{ $$ = driver.add_model_variable($1); }
| FLOAT_NUMBER | FLOAT_NUMBER
{ $$ = driver.add_constant($1); } { $$ = driver.add_constant($1); }
| INT_NUMBER | INT_NUMBER
@ -562,6 +565,8 @@ hand_side : '(' hand_side ')'
{ $$ = driver.add_max($3, $5); } { $$ = driver.add_max($3, $5); }
| MIN '(' hand_side COMMA hand_side ')' | MIN '(' hand_side COMMA hand_side ')'
{ $$ = driver.add_min($3, $5); } { $$ = driver.add_min($3, $5); }
| symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_hand_side ')'
{ $$ = driver.add_model_var_or_external_function($1); }
| NORMCDF '(' hand_side COMMA hand_side COMMA hand_side ')' | NORMCDF '(' hand_side COMMA hand_side COMMA hand_side ')'
{ $$ = driver.add_normcdf($3, $5, $7); } { $$ = driver.add_normcdf($3, $5, $7); }
| NORMCDF '(' hand_side ')' | NORMCDF '(' hand_side ')'
@ -570,6 +575,11 @@ hand_side : '(' hand_side ')'
{ $$ = driver.add_steady_state($3); } { $$ = driver.add_steady_state($3); }
; ;
comma_hand_side : hand_side
{ driver.add_external_function_arg($1); }
| comma_hand_side COMMA hand_side
{ driver.add_external_function_arg($3); }
expectation_input : signed_integer expectation_input : signed_integer
| VAROBS { string *varobs = new string("varobs"); $$ = varobs; } | VAROBS { string *varobs = new string("varobs"); $$ = varobs; }
| FULL { string *full = new string("full"); $$ = full; } | FULL { string *full = new string("full"); $$ = full; }
@ -578,12 +588,6 @@ expectation_input : signed_integer
pound_expression: '#' symbol EQUAL hand_side ';' pound_expression: '#' symbol EQUAL hand_side ';'
{ driver.declare_and_init_model_local_variable($2, $4); }; { driver.declare_and_init_model_local_variable($2, $4); };
model_var : symbol
{ $$ = driver.add_model_variable($1); }
| symbol '(' signed_integer ')'
{ $$ = driver.add_model_variable($1, $3); }
;
shocks : SHOCKS ';' shock_list END { driver.end_shocks(); }; shocks : SHOCKS ';' shock_list END { driver.end_shocks(); };
shock_list : shock_list shock_elem shock_list : shock_list shock_elem
@ -772,6 +776,20 @@ simul_options : o_periods
| o_minimal_solving_periods | o_minimal_solving_periods
; ;
external_function : EXTERNAL_FUNCTION '(' external_function_options_list ')' ';'
{ driver.external_function(); }
;
external_function_options_list : external_function_options_list COMMA external_function_options
| external_function_options
;
external_function_options : o_ext_func_name
| o_ext_func_nargs
| o_first_deriv_provided
| o_second_deriv_provided
;
stoch_simul : STOCH_SIMUL ';' stoch_simul : STOCH_SIMUL ';'
{ driver.stoch_simul(); } { driver.stoch_simul(); }
| STOCH_SIMUL '(' stoch_simul_options_list ')' ';' | STOCH_SIMUL '(' stoch_simul_options_list ')' ';'
@ -1888,6 +1906,19 @@ o_equations : EQUATIONS EQUAL vec_int
o_instruments : INSTRUMENTS EQUAL '(' symbol_list ')' {driver.option_symbol_list("instruments"); }; o_instruments : INSTRUMENTS EQUAL '(' symbol_list ')' {driver.option_symbol_list("instruments"); };
o_ext_func_name : EXT_FUNC_NAME EQUAL filename { driver.external_function_option("name", $3); };
o_ext_func_nargs : EXT_FUNC_NARGS EQUAL INT_NUMBER { driver.external_function_option("nargs",$3); };
o_first_deriv_provided : FIRST_DERIV_PROVIDED EQUAL filename
{ driver.external_function_option("first_deriv_provided", $3); }
| FIRST_DERIV_PROVIDED
{ driver.external_function_option("first_deriv_provided", ""); }
;
o_second_deriv_provided : SECOND_DERIV_PROVIDED EQUAL filename
{ driver.external_function_option("second_deriv_provided", $3); }
| SECOND_DERIV_PROVIDED
{ driver.external_function_option("second_deriv_provided", ""); }
;
range : symbol ':' symbol range : symbol ':' symbol
{ {
$1->append(":"); $1->append(":");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -144,6 +144,7 @@ int sigma_e = 0;
<INITIAL>markov_switching {BEGIN DYNARE_STATEMENT; return token::MARKOV_SWITCHING;} <INITIAL>markov_switching {BEGIN DYNARE_STATEMENT; return token::MARKOV_SWITCHING;}
<INITIAL>svar {BEGIN DYNARE_STATEMENT; return token::SVAR;} <INITIAL>svar {BEGIN DYNARE_STATEMENT; return token::SVAR;}
<INITIAL>external_function {BEGIN DYNARE_STATEMENT; return token::EXTERNAL_FUNCTION;}
/* End of a Dynare statement */ /* End of a Dynare statement */
<DYNARE_STATEMENT>; { <DYNARE_STATEMENT>; {
@ -229,6 +230,10 @@ int sigma_e = 0;
<DYNARE_STATEMENT>aim_solver {return token::AIM_SOLVER;} <DYNARE_STATEMENT>aim_solver {return token::AIM_SOLVER;}
<DYNARE_STATEMENT>partial_information {return token::PARTIAL_INFORMATION;} <DYNARE_STATEMENT>partial_information {return token::PARTIAL_INFORMATION;}
<DYNARE_STATEMENT>conditional_variance_decomposition {return token::CONDITIONAL_VARIANCE_DECOMPOSITION;} <DYNARE_STATEMENT>conditional_variance_decomposition {return token::CONDITIONAL_VARIANCE_DECOMPOSITION;}
<DYNARE_STATEMENT>name {return token::EXT_FUNC_NAME;}
<DYNARE_STATEMENT>nargs {return token::EXT_FUNC_NARGS;}
<DYNARE_STATEMENT>first_deriv_provided {return token::FIRST_DERIV_PROVIDED;}
<DYNARE_STATEMENT>second_deriv_provided {return token::SECOND_DERIV_PROVIDED;}
<DYNARE_STATEMENT>freq {return token::FREQ;} <DYNARE_STATEMENT>freq {return token::FREQ;}
<DYNARE_STATEMENT>initial_year {return token::INITIAL_YEAR;} <DYNARE_STATEMENT>initial_year {return token::INITIAL_YEAR;}
@ -531,16 +536,16 @@ int sigma_e = 0;
} }
/* An instruction starting with a recognized symbol (which is not a modfile local /* An instruction starting with a recognized symbol (which is not a modfile local
or an unknown function) is passed as NAME, otherwise it is a native statement or an external function) is passed as NAME, otherwise it is a native statement
until the end of the line. until the end of the line.
We exclude modfile local vars because the user may want to modify their value We exclude modfile local vars because the user may want to modify their value
using a Matlab assignment statement. using a Matlab assignment statement.
We also exclude unknown functions because the user may have used a Matlab matrix We also exclude external functions because the user may have used a Matlab matrix
element in initval (in which case Dynare recognizes the matrix name as an unknown element in initval (in which case Dynare recognizes the matrix name as an external
function symbol), and may want to modify the matrix later with Matlab statements. function symbol), and may want to modify the matrix later with Matlab statements.
*/ */
<INITIAL>[A-Za-z_][A-Za-z0-9_]* { <INITIAL>[A-Za-z_][A-Za-z0-9_]* {
if (driver.symbol_exists_and_is_not_modfile_local_or_unknown_function(yytext)) if (driver.symbol_exists_and_is_not_modfile_local_or_external_function(yytext))
{ {
BEGIN DYNARE_STATEMENT; BEGIN DYNARE_STATEMENT;
yylval->string_val = new string(yytext); yylval->string_val = new string(yytext);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007-2009 Dynare Team * Copyright (C) 2007-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -359,7 +359,7 @@ VariableNode::VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg)
datatree.variable_node_map[make_pair(symb_id, lag)] = this; datatree.variable_node_map[make_pair(symb_id, lag)] = this;
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
assert(type != eUnknownFunction assert(type != eExternalFunction
&& (lag == 0 || (type != eModelLocalVariable && type != eModFileLocalVariable))); && (lag == 0 || (type != eModelLocalVariable && type != eModFileLocalVariable)));
} }
@ -389,7 +389,7 @@ VariableNode::prepareForDerivation()
case eModFileLocalVariable: case eModFileLocalVariable:
// Such a variable is never derived // Such a variable is never derived
break; break;
case eUnknownFunction: case eExternalFunction:
cerr << "VariableNode::prepareForDerivation: impossible case" << endl; cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -413,7 +413,7 @@ VariableNode::computeDerivative(int deriv_id)
case eModFileLocalVariable: case eModFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl; cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
case eUnknownFunction: case eExternalFunction:
cerr << "Impossible case!" << endl; cerr << "Impossible case!" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -601,7 +601,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
} }
break; break;
case eUnknownFunction: case eExternalFunction:
cerr << "Impossible case" << endl; cerr << "Impossible case" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -767,7 +767,7 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recur
case eModFileLocalVariable: case eModFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl; cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
case eUnknownFunction: case eExternalFunction:
cerr << "Impossible case!" << endl; cerr << "Impossible case!" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -3174,7 +3174,7 @@ TrinaryOpNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOp
return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
} }
UnknownFunctionNode::UnknownFunctionNode(DataTree &datatree_arg, ExternalFunctionNode::ExternalFunctionNode(DataTree &datatree_arg,
int symb_id_arg, int symb_id_arg,
const vector<NodeID> &arguments_arg) : const vector<NodeID> &arguments_arg) :
ExprNode(datatree_arg), ExprNode(datatree_arg),
@ -3184,37 +3184,65 @@ UnknownFunctionNode::UnknownFunctionNode(DataTree &datatree_arg,
} }
void void
UnknownFunctionNode::prepareForDerivation() ExternalFunctionNode::prepareForDerivation()
{ {
cerr << "UnknownFunctionNode::prepareForDerivation: operation impossible!" << endl; if (preparedForDerivation)
exit(EXIT_FAILURE); return;
for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
(*it)->prepareForDerivation();
non_null_derivatives = arguments.at(0)->non_null_derivatives;
for (int i = 1; i < (int)arguments.size(); i++)
set_union(non_null_derivatives.begin(),
non_null_derivatives.end(),
arguments.at(i)->non_null_derivatives.begin(),
arguments.at(i)->non_null_derivatives.end(),
inserter(non_null_derivatives, non_null_derivatives.begin()));
preparedForDerivation = true;
} }
NodeID NodeID
UnknownFunctionNode::computeDerivative(int deriv_id) ExternalFunctionNode::computeDerivative(int deriv_id)
{ {
cerr << "UnknownFunctionNode::computeDerivative: operation impossible!" << endl; vector<NodeID> dargs;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
dargs.push_back((*it)->getDerivative(deriv_id));
return composeDerivatives(dargs);
} }
NodeID NodeID
UnknownFunctionNode::getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables) ExternalFunctionNode::composeDerivatives(const vector<NodeID> &dargs)
{ {
cerr << "UnknownFunctionNode::getChainRuleDerivative: operation impossible!" << endl; vector<NodeID> dNodes;
for (int i = 0; i < (int)dargs.size(); i++)
if (dargs.at(i) != 0)
dNodes.push_back(datatree.AddTimes(dargs.at(i),
datatree.AddFirstDerivExternalFunctionNode(symb_id, arguments, i+1)));
NodeID theDeriv = datatree.Zero;
for (vector<NodeID>::const_iterator it = dNodes.begin(); it != dNodes.end(); it++)
theDeriv = datatree.AddPlus(theDeriv, *it);
return theDeriv;
}
NodeID
ExternalFunctionNode::getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables)
{
cerr << "ExternalFunctionNode::getChainRuleDerivative: operation impossible!" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void void
UnknownFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count, ExternalFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
temporary_terms_type &temporary_terms, temporary_terms_type &temporary_terms,
bool is_matlab) const bool is_matlab) const
{ {
cerr << "UnknownFunctionNode::computeTemporaryTerms: operation impossible!" << endl;
exit(EXIT_FAILURE);
} }
void void
UnknownFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type, ExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_type &temporary_terms) const const temporary_terms_type &temporary_terms) const
{ {
output << datatree.symbol_table.getName(symb_id) << "("; output << datatree.symbol_table.getName(symb_id) << "(";
@ -3230,19 +3258,19 @@ UnknownFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type
} }
void void
UnknownFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count, ExternalFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
temporary_terms_type &temporary_terms, temporary_terms_type &temporary_terms,
map<NodeID, pair<int, int> > &first_occurence, map<NodeID, pair<int, int> > &first_occurence,
int Curr_block, int Curr_block,
vector< vector<temporary_terms_type> > &v_temporary_terms, vector< vector<temporary_terms_type> > &v_temporary_terms,
int equation) const int equation) const
{ {
cerr << "UnknownFunctionNode::computeTemporaryTerms: not implemented" << endl; cerr << "ExternalFunctionNode::computeTemporaryTerms: not implemented" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void void
UnknownFunctionNode::collectVariables(SymbolType type_arg, set<pair<int, int> > &result) const ExternalFunctionNode::collectVariables(SymbolType type_arg, set<pair<int, int> > &result) const
{ {
for (vector<NodeID>::const_iterator it = arguments.begin(); for (vector<NodeID>::const_iterator it = arguments.begin();
it != arguments.end(); it++) it != arguments.end(); it++)
@ -3250,9 +3278,9 @@ UnknownFunctionNode::collectVariables(SymbolType type_arg, set<pair<int, int> >
} }
void void
UnknownFunctionNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, temporary_terms_inuse_type &temporary_terms_inuse, int Curr_Block) const ExternalFunctionNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, temporary_terms_inuse_type &temporary_terms_inuse, int Curr_Block) const
{ {
temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnknownFunctionNode *>(this)); temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<ExternalFunctionNode *>(this));
if (it != temporary_terms.end()) if (it != temporary_terms.end())
temporary_terms_inuse.insert(idx); temporary_terms_inuse.insert(idx);
else else
@ -3262,20 +3290,20 @@ UnknownFunctionNode::collectTemporary_terms(const temporary_terms_type &temporar
} }
double double
UnknownFunctionNode::eval(const eval_context_type &eval_context) const throw (EvalException) ExternalFunctionNode::eval(const eval_context_type &eval_context) const throw (EvalException)
{ {
throw EvalException(); throw EvalException();
} }
void void
UnknownFunctionNode::compile(ostream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, const map_idx_type &map_idx, bool dynamic, bool steady_dynamic) const ExternalFunctionNode::compile(ostream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, const map_idx_type &map_idx, bool dynamic, bool steady_dynamic) const
{ {
cerr << "UnknownFunctionNode::compile: operation impossible!" << endl; cerr << "ExternalFunctionNode::compile: operation impossible!" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
pair<int, NodeID> pair<int, NodeID>
UnknownFunctionNode::normalizeEquation(int var_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const ExternalFunctionNode::normalizeEquation(int var_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const
{ {
vector<pair<bool, NodeID> > V_arguments; vector<pair<bool, NodeID> > V_arguments;
vector<NodeID> V_NodeID; vector<NodeID> V_NodeID;
@ -3288,23 +3316,23 @@ UnknownFunctionNode::normalizeEquation(int var_endo, vector<pair<int, pair<NodeI
V_NodeID.push_back(V_arguments[V_arguments.size()-1].second); V_NodeID.push_back(V_arguments[V_arguments.size()-1].second);
} }
if (!present) if (!present)
return (make_pair(0, datatree.AddUnknownFunction(datatree.symbol_table.getName(symb_id), V_NodeID))); return (make_pair(0, datatree.AddExternalFunction(datatree.symbol_table.getName(symb_id), V_NodeID)));
else else
return (make_pair(1, (NodeID) NULL)); return (make_pair(1, (NodeID) NULL));
} }
NodeID NodeID
UnknownFunctionNode::toStatic(DataTree &static_datatree) const ExternalFunctionNode::toStatic(DataTree &static_datatree) const
{ {
vector<NodeID> static_arguments; vector<NodeID> static_arguments;
for (vector<NodeID>::const_iterator it = arguments.begin(); for (vector<NodeID>::const_iterator it = arguments.begin();
it != arguments.end(); it++) it != arguments.end(); it++)
static_arguments.push_back((*it)->toStatic(static_datatree)); static_arguments.push_back((*it)->toStatic(static_datatree));
return static_datatree.AddUnknownFunction(datatree.symbol_table.getName(symb_id), static_arguments); return static_datatree.AddExternalFunction(datatree.symbol_table.getName(symb_id), static_arguments);
} }
int int
UnknownFunctionNode::maxEndoLead() const ExternalFunctionNode::maxEndoLead() const
{ {
int val = 0; int val = 0;
for (vector<NodeID>::const_iterator it = arguments.begin(); for (vector<NodeID>::const_iterator it = arguments.begin();
@ -3314,7 +3342,7 @@ UnknownFunctionNode::maxEndoLead() const
} }
int int
UnknownFunctionNode::maxExoLead() const ExternalFunctionNode::maxExoLead() const
{ {
int val = 0; int val = 0;
for (vector<NodeID>::const_iterator it = arguments.begin(); for (vector<NodeID>::const_iterator it = arguments.begin();
@ -3324,50 +3352,187 @@ UnknownFunctionNode::maxExoLead() const
} }
NodeID NodeID
UnknownFunctionNode::decreaseLeadsLags(int n) const ExternalFunctionNode::decreaseLeadsLags(int n) const
{ {
cerr << "UnknownFunctionNode::decreaseLeadsLags: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->decreaseLeadsLags(n));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::decreaseLeadsLagsPredeterminedVariables() const ExternalFunctionNode::decreaseLeadsLagsPredeterminedVariables() const
{ {
cerr << "UnknownFunctionNode::decreaseLeadsLagsPredeterminedVariables: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->decreaseLeadsLagsPredeterminedVariables());
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const ExternalFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{ {
cerr << "UnknownFunctionNode::substituteEndoLeadGreaterThanTwo: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->substituteEndoLeadGreaterThanTwo(subst_table, neweqs));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const ExternalFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{ {
cerr << "UnknownFunctionNode::substituteEndoLagGreaterThanTwo: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->substituteEndoLagGreaterThanTwo(subst_table, neweqs));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const ExternalFunctionNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{ {
cerr << "UnknownFunctionNode::substituteExoLead: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->substituteExoLead(subst_table, neweqs));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const ExternalFunctionNode::substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{ {
cerr << "UnknownFunctionNode::substituteExoLag: not implemented!" << endl; vector<NodeID> arguments_subst;
exit(EXIT_FAILURE); for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->substituteExoLag(subst_table, neweqs));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
} }
NodeID NodeID
UnknownFunctionNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const ExternalFunctionNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const
{ {
cerr << "UnknownFunctionNode::substituteExpectation: not implemented!" << endl; vector<NodeID> arguments_subst;
for (vector<NodeID>::const_iterator it = arguments.begin(); it != arguments.end(); it++)
arguments_subst.push_back((*it)->substituteExpectation(subst_table, neweqs, partial_information_model));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
}
NodeID
ExternalFunctionNode::buildSimilarExternalFunctionNode(vector<NodeID> &alt_args, DataTree &alt_datatree) const
{
return alt_datatree.AddExternalFunction(symb_id, alt_args);
}
FirstDerivExternalFunctionNode::FirstDerivExternalFunctionNode(DataTree &datatree_arg,
int top_level_symb_id_arg,
const vector<NodeID> &arguments_arg,
int inputIndex_arg) :
ExternalFunctionNode(datatree_arg, top_level_symb_id_arg, arguments_arg),
inputIndex(inputIndex_arg)
{
}
NodeID
FirstDerivExternalFunctionNode::composeDerivatives(const vector<NodeID> &dargs)
{
vector<NodeID> dNodes;
for (int i = 0; i < (int)dargs.size(); i++)
if (dargs.at(i) != 0)
dNodes.push_back(datatree.AddTimes(dargs.at(i),
datatree.AddSecondDerivExternalFunctionNode(symb_id, arguments, inputIndex, i+1)));
NodeID theDeriv = datatree.Zero;
for (vector<NodeID>::const_iterator it = dNodes.begin(); it != dNodes.end(); it++)
theDeriv = datatree.AddPlus(theDeriv, *it);
return theDeriv;
}
void
FirstDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_type &temporary_terms) const
{
int first_deriv_symb_id = datatree.external_functions_table.getFirstDerivSymbID(symb_id);
switch (first_deriv_symb_id)
{
case eExtFunSetButNoNameProvided:
cerr << "ERROR in: FirstDerivExternalFunctionNode::writeOutput(). Please inform Dynare Team." << endl;
exit(EXIT_FAILURE);
case eExtFunNotSet:
output << "jacob_element(@" << datatree.symbol_table.getName(symb_id) << ","
<< inputIndex << ",{";
break;
default:
int numOutArgs;
if (first_deriv_symb_id==symb_id)
numOutArgs = 2; // means that the external function also returns at least the first derivative
else
numOutArgs = 1; // means that there is a function that returns only the second derivative
output << "subscript_get(" << numOutArgs << ",@" << datatree.symbol_table.getName(first_deriv_symb_id) << ",{";
}
for (vector<NodeID>::const_iterator it = arguments.begin();
it != arguments.end(); it++)
{
if (it != arguments.begin())
output << ",";
(*it)->writeOutput(output, output_type, temporary_terms);
}
output << "}";
if (first_deriv_symb_id!=eExtFunNotSet)
output << "," << inputIndex;
output << ")";
}
SecondDerivExternalFunctionNode::SecondDerivExternalFunctionNode(DataTree &datatree_arg,
int top_level_symb_id_arg,
const vector<NodeID> &arguments_arg,
int inputIndex1_arg,
int inputIndex2_arg) :
ExternalFunctionNode(datatree_arg, top_level_symb_id_arg, arguments_arg),
inputIndex1(inputIndex1_arg),
inputIndex2(inputIndex2_arg)
{
}
NodeID
SecondDerivExternalFunctionNode::computeDerivative(int deriv_id)
{
cerr << "ERROR: SecondDerivExternalFunctionNode::computeDerivative(). Not implemented" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void
SecondDerivExternalFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_type &temporary_terms) const
{
int second_deriv_symb_id = datatree.external_functions_table.getSecondDerivSymbID(symb_id);
switch (second_deriv_symb_id)
{
case eExtFunSetButNoNameProvided:
cerr << "ERROR in: FirstDerivExternalFunctionNode::writeOutput(). Please inform Dynare Team." << endl;
exit(EXIT_FAILURE);
case eExtFunNotSet:
output << "hess_element(@" << datatree.symbol_table.getName(symb_id) << ","
<< inputIndex1 << "," << inputIndex2 << ",{";
break;
default:
int numOutArgs;
if (second_deriv_symb_id==symb_id)
numOutArgs = 3; // means that the external function also returns the first and second derivatives
else
numOutArgs = 1; // means that there is a function that returns only the second derivative
output << "subscript_get(" << numOutArgs << ",@" << datatree.symbol_table.getName(second_deriv_symb_id) << ",{";
}
for (vector<NodeID>::const_iterator it = arguments.begin();
it != arguments.end(); it++)
{
if (it != arguments.begin())
output << ",";
(*it)->writeOutput(output, output_type, temporary_terms);
}
output << "}";
if (second_deriv_symb_id!=eExtFunNotSet)
output << "," << inputIndex1 << "," << inputIndex2;
output << ")";
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007-2009 Dynare Team * Copyright (C) 2007-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -29,6 +29,7 @@ using namespace std;
#include "SymbolTable.hh" #include "SymbolTable.hh"
#include "CodeInterpreter.hh" #include "CodeInterpreter.hh"
#include "ExternalFunctionsTable.hh"
class DataTree; class DataTree;
class VariableNode; class VariableNode;
@ -115,7 +116,7 @@ class ExprNode
friend class UnaryOpNode; friend class UnaryOpNode;
friend class BinaryOpNode; friend class BinaryOpNode;
friend class TrinaryOpNode; friend class TrinaryOpNode;
friend class ExternalFunctionNode;
private: private:
//! Computes derivative w.r. to a derivation ID (but doesn't store it in derivatives map) //! Computes derivative w.r. to a derivation ID (but doesn't store it in derivatives map)
/*! You shoud use getDerivative() to get the benefit of symbolic a priori and of caching */ /*! You shoud use getDerivative() to get the benefit of symbolic a priori and of caching */
@ -568,15 +569,17 @@ public:
virtual NodeID decreaseLeadsLagsPredeterminedVariables() const; virtual NodeID decreaseLeadsLagsPredeterminedVariables() const;
}; };
//! Unknown function node //! External function node
class UnknownFunctionNode : public ExprNode class ExternalFunctionNode : public ExprNode
{ {
private: private:
virtual NodeID computeDerivative(int deriv_id);
virtual NodeID composeDerivatives(const vector<NodeID> &dargs);
protected:
const int symb_id; const int symb_id;
const vector<NodeID> arguments; const vector<NodeID> arguments;
virtual NodeID computeDerivative(int deriv_id);
public: public:
UnknownFunctionNode(DataTree &datatree_arg, int symb_id_arg, ExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg,
const vector<NodeID> &arguments_arg); const vector<NodeID> &arguments_arg);
virtual void prepareForDerivation(); virtual void prepareForDerivation();
virtual void computeTemporaryTerms(map<NodeID, int> &reference_count, temporary_terms_type &temporary_terms, bool is_matlab) const; virtual void computeTemporaryTerms(map<NodeID, int> &reference_count, temporary_terms_type &temporary_terms, bool is_matlab) const;
@ -602,7 +605,36 @@ public:
virtual NodeID substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual NodeID substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
virtual NodeID substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const; virtual NodeID substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
virtual NodeID substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const; virtual NodeID substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const;
virtual NodeID buildSimilarExternalFunctionNode(vector<NodeID> &alt_args, DataTree &alt_datatree) const;
virtual NodeID decreaseLeadsLagsPredeterminedVariables() const; virtual NodeID decreaseLeadsLagsPredeterminedVariables() const;
}; };
class FirstDerivExternalFunctionNode : public ExternalFunctionNode
{
private:
const int inputIndex;
virtual NodeID composeDerivatives(const vector<NodeID> &dargs);
public:
FirstDerivExternalFunctionNode(DataTree &datatree_arg,
int top_level_symb_id_arg,
const vector<NodeID> &arguments_arg,
int inputIndex_arg);
virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
};
class SecondDerivExternalFunctionNode : public ExternalFunctionNode
{
private:
const int inputIndex1;
const int inputIndex2;
virtual NodeID computeDerivative(int deriv_id);
public:
SecondDerivExternalFunctionNode(DataTree &datatree_arg,
int top_level_symb_id_arg,
const vector<NodeID> &arguments_arg,
int inputIndex1_arg,
int inputIndex2_arg);
virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
};
#endif #endif

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2010 Dynare Team
*
* 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 <cstdlib>
#include <cassert>
#include <cerrno>
#include <cmath>
#include <iostream>
#include "ExternalFunctionsTable.hh"
#include "SymbolTable.hh"
ExternalFunctionsTable::ExternalFunctionsTable()
{
};
void
ExternalFunctionsTable::addExternalFunction(const int symb_id, const external_function_options external_function_options_arg)
{
assert(symb_id >= 0);
if (external_function_options_arg.secondDerivSymbID > eExtFunNotSet &&
external_function_options_arg.firstDerivSymbID == eExtFunNotSet)
{
cerr << "If the second derivative is provided to the external_function() command,"
<< "the first derivative must also be provided." << endl;
exit(EXIT_FAILURE);
}
if (external_function_options_arg.nargs <= 0)
{
cerr << "The number of arguments passed to an external function must be > 0." << endl;
exit(EXIT_FAILURE);
}
external_function_options external_function_options_chng = external_function_options_arg;
if (external_function_options_arg.firstDerivSymbID == eExtFunSetButNoNameProvided)
external_function_options_chng.firstDerivSymbID = symb_id;
if (external_function_options_arg.secondDerivSymbID == eExtFunSetButNoNameProvided)
external_function_options_chng.secondDerivSymbID = symb_id;
externalFunctionTable[symb_id] = external_function_options_chng;
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2010 Dynare Team
*
* 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/>.
*/
#ifndef _EXTERNALFUNCTIONSTABLE_HH
#define _EXTERNALFUNCTIONSTABLE_HH
using namespace std;
#include <iostream>
#include <string>
#include <vector>
#include <map>
enum ExternalFunctionSetOrNot
{
eExtFunSetButNoNameProvided = -2, //! Signifies that the derivative is obtained from the top-level function
eExtFunNotSet = -1, //! Signifies that no external function exists that calculates the derivative
eExtFunSetDefaultNargs = 1 //! This is the default number of arguments when nargs is not specified
};
//! Handles external functions
class ExternalFunctionsTable
{
public:
//! Thrown when trying to access an unknown symbol (by id)
class UnknownExternalFunctionSymbolIDException
{
public:
//! Symbol ID
int id;
UnknownExternalFunctionSymbolIDException(int id_arg) : id(id_arg)
{
}
};
/* For all arguments, -2 means not set
* For firstDerivSymbID and secondDerivSymbID, -1 means that the derivatives are
* provided in the main function given in the by the "name" option to the
* external_function() statement.
*/
struct external_function_options
{
int nargs, firstDerivSymbID, secondDerivSymbID;
};
typedef map<int, external_function_options> external_function_table_type;
private:
//! Map containing options provided to external_functions()
external_function_table_type externalFunctionTable;
public:
ExternalFunctionsTable();
//! Adds an external function to the table as well as its derivative functions
void addExternalFunction(const int symb_id, const external_function_options external_function_options_arg);
//! See if the function exists in the External Functions Table
inline bool exists(const int symb_id) const;
//! Get the number of arguments for a given external function
inline int getNargs(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException);
//! Get the symbol_id of the first derivative function
inline int getFirstDerivSymbID(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException);
//! Get the symbol_id of the second derivative function
inline int getSecondDerivSymbID(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException);
//! Returns the total number of unique external functions declared or used in the .mod file
inline int get_total_number_of_unique_external_functions();
};
inline bool
ExternalFunctionsTable::exists(const int symb_id) const
{
external_function_table_type::const_iterator iter = externalFunctionTable.find(symb_id);
return (iter != externalFunctionTable.end());
}
inline int
ExternalFunctionsTable::getNargs(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException)
{
if (exists(symb_id))
return externalFunctionTable.find(symb_id)->second.nargs;
else
{
cout << "In get_nargs(): id: " << symb_id << endl;
throw UnknownExternalFunctionSymbolIDException(symb_id);
}
}
inline int
ExternalFunctionsTable::getFirstDerivSymbID(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException)
{
if (exists(symb_id))
return externalFunctionTable.find(symb_id)->second.firstDerivSymbID;
else
{
cout << "In getFirstDerivSymbID(): id: " << symb_id << endl;
throw UnknownExternalFunctionSymbolIDException(symb_id);
}
}
inline int
ExternalFunctionsTable::getSecondDerivSymbID(const int symb_id) const throw (UnknownExternalFunctionSymbolIDException)
{
if (exists(symb_id))
return externalFunctionTable.find(symb_id)->second.secondDerivSymbID;
else
{
cout << "In getSecondDerivSymbID(): id: " << symb_id << endl;
throw UnknownExternalFunctionSymbolIDException(symb_id);
}
}
inline int
ExternalFunctionsTable::get_total_number_of_unique_external_functions()
{
return externalFunctionTable.size();
}
#endif

View File

@ -45,7 +45,9 @@ dynare_m_SOURCES = \
DynareMain.cc \ DynareMain.cc \
DynareMain2.cc \ DynareMain2.cc \
CodeInterpreter.hh \ CodeInterpreter.hh \
FlexLexer.h FlexLexer.h \
ExternalFunctionsTable.cc \
ExternalFunctionsTable.hh
# The -I. is for <FlexLexer.h> # The -I. is for <FlexLexer.h>
dynare_m_CPPFLAGS = $(BOOST_CPPFLAGS) -I. dynare_m_CPPFLAGS = $(BOOST_CPPFLAGS) -I.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2006-2009 Dynare Team * Copyright (C) 2006-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -23,9 +23,9 @@
#include <typeinfo> #include <typeinfo>
#include "ModFile.hh" #include "ModFile.hh"
ModFile::ModFile() : expressions_tree(symbol_table, num_constants), ModFile::ModFile() : expressions_tree(symbol_table, num_constants, external_functions_table),
static_model(symbol_table, num_constants), static_model(symbol_table, num_constants, external_functions_table),
dynamic_model(symbol_table, num_constants), dynamic_model(symbol_table, num_constants, external_functions_table),
linear(false), block(false), byte_code(false), linear(false), block(false), byte_code(false),
use_dll(false), no_static(false) use_dll(false), no_static(false)
{ {
@ -134,6 +134,12 @@ ModFile::checkPass()
cerr << "no_static option is incompatible with stochastic simulation, estimation, optimal policy, steady or check command" << endl; cerr << "no_static option is incompatible with stochastic simulation, estimation, optimal policy, steady or check command" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if ((use_dll || byte_code) && external_functions_table.get_total_number_of_unique_external_functions())
{
cerr << "ERROR: In 'model' block, use of external functions is not compatible with 'use_dll' or 'bytecode'" << endl;
exit(EXIT_FAILURE);
}
} }
void void

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2006-2009 Dynare Team * Copyright (C) 2006-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -31,6 +31,7 @@ using namespace std;
#include "StaticModel.hh" #include "StaticModel.hh"
#include "DynamicModel.hh" #include "DynamicModel.hh"
#include "Statement.hh" #include "Statement.hh"
#include "ExternalFunctionsTable.hh"
//! The abstract representation of a "mod" file //! The abstract representation of a "mod" file
class ModFile class ModFile
@ -40,6 +41,8 @@ public:
~ModFile(); ~ModFile();
//! Symbol table //! Symbol table
SymbolTable symbol_table; SymbolTable symbol_table;
//! External Functions table
ExternalFunctionsTable external_functions_table;
//! Numerical constants table //! Numerical constants table
NumericalConstants num_constants; NumericalConstants num_constants;
//! Expressions outside model block //! Expressions outside model block

View File

@ -855,8 +855,9 @@ ModelTree::BlockLinear(t_blocks_derivatives &blocks_derivatives, vector<int> &va
} }
ModelTree::ModelTree(SymbolTable &symbol_table_arg, ModelTree::ModelTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg) : NumericalConstants &num_constants_arg,
DataTree(symbol_table_arg, num_constants_arg) ExternalFunctionsTable &external_functions_table_arg) :
DataTree(symbol_table_arg, num_constants_arg, external_functions_table_arg)
{ {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
NNZDerivatives[i] = 0; NNZDerivatives[i] = 0;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -213,7 +213,7 @@ protected:
virtual int getBlockInitialVariableID(int block_number, int variable_number) const = 0; virtual int getBlockInitialVariableID(int block_number, int variable_number) const = 0;
public: public:
ModelTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); ModelTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg);
//! Declare a node as an equation of the model //! Declare a node as an equation of the model
void addEquation(NodeID eq); void addEquation(NodeID eq);
//! Adds tags to equation number i //! Adds tags to equation number i

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -20,19 +20,21 @@
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <cassert>
#include "ParsingDriver.hh" #include "ParsingDriver.hh"
#include "Statement.hh" #include "Statement.hh"
#include <ExprNode.hh>
bool bool
ParsingDriver::symbol_exists_and_is_not_modfile_local_or_unknown_function(const char *s) ParsingDriver::symbol_exists_and_is_not_modfile_local_or_external_function(const char *s)
{ {
if (!mod_file->symbol_table.exists(s)) if (!mod_file->symbol_table.exists(s))
return false; return false;
SymbolType type = mod_file->symbol_table.getType(s); SymbolType type = mod_file->symbol_table.getType(s);
return (type != eModFileLocalVariable && type != eUnknownFunction); return (type != eModFileLocalVariable && type != eExternalFunction);
} }
void void
@ -56,6 +58,15 @@ ParsingDriver::reset_data_tree()
set_current_data_tree(&mod_file->expressions_tree); set_current_data_tree(&mod_file->expressions_tree);
} }
void
ParsingDriver::reset_current_external_function_options()
{
current_external_function_options.nargs = eExtFunSetDefaultNargs;
current_external_function_options.firstDerivSymbID = eExtFunNotSet;
current_external_function_options.secondDerivSymbID = eExtFunNotSet;
current_external_function_name.clear();
}
ModFile * ModFile *
ParsingDriver::parse(istream &in, bool debug) ParsingDriver::parse(istream &in, bool debug)
{ {
@ -65,6 +76,7 @@ ParsingDriver::parse(istream &in, bool debug)
reset_data_tree(); reset_data_tree();
estim_params.init(*data_tree); estim_params.init(*data_tree);
reset_current_external_function_options();
lexer = new DynareFlex(&in); lexer = new DynareFlex(&in);
lexer->set_debug(debug); lexer->set_debug(debug);
@ -98,7 +110,7 @@ ParsingDriver::warning(const string &m)
} }
void void
ParsingDriver::declare_symbol(string *name, SymbolType type, string *tex_name) ParsingDriver::declare_symbol(const string *name, const SymbolType type, const string *tex_name)
{ {
try try
{ {
@ -114,34 +126,42 @@ ParsingDriver::declare_symbol(string *name, SymbolType type, string *tex_name)
else else
error("Symbol " + *name + " declared twice with different types!"); error("Symbol " + *name + " declared twice with different types!");
} }
delete name;
if (tex_name != NULL)
delete tex_name;
} }
void void
ParsingDriver::declare_endogenous(string *name, string *tex_name) ParsingDriver::declare_endogenous(string *name, string *tex_name)
{ {
declare_symbol(name, eEndogenous, tex_name); declare_symbol(name, eEndogenous, tex_name);
delete name;
if (tex_name != NULL)
delete tex_name;
} }
void void
ParsingDriver::declare_exogenous(string *name, string *tex_name) ParsingDriver::declare_exogenous(string *name, string *tex_name)
{ {
declare_symbol(name, eExogenous, tex_name); declare_symbol(name, eExogenous, tex_name);
delete name;
if (tex_name != NULL)
delete tex_name;
} }
void void
ParsingDriver::declare_exogenous_det(string *name, string *tex_name) ParsingDriver::declare_exogenous_det(string *name, string *tex_name)
{ {
declare_symbol(name, eExogenousDet, tex_name); declare_symbol(name, eExogenousDet, tex_name);
delete name;
if (tex_name != NULL)
delete tex_name;
} }
void void
ParsingDriver::declare_parameter(string *name, string *tex_name) ParsingDriver::declare_parameter(string *name, string *tex_name)
{ {
declare_symbol(name, eParameter, tex_name); declare_symbol(name, eParameter, tex_name);
delete name;
if (tex_name != NULL)
delete tex_name;
} }
void void
@ -194,32 +214,29 @@ ParsingDriver::add_inf_constant()
NodeID NodeID
ParsingDriver::add_model_variable(string *name) ParsingDriver::add_model_variable(string *name)
{ {
return add_model_variable(name, new string("0")); check_symbol_existence(*name);
int symb_id = mod_file->symbol_table.getID(*name);
delete name;
return add_model_variable(symb_id, 0);
} }
NodeID NodeID
ParsingDriver::add_model_variable(string *name, string *olag) ParsingDriver::add_model_variable(int symb_id, int lag)
{ {
check_symbol_existence(*name); assert(symb_id >= 0);
SymbolType type = mod_file->symbol_table.getType(*name); SymbolType type = mod_file->symbol_table.getType(symb_id);
int lag = atoi(olag->c_str());
if (type == eModFileLocalVariable) if (type == eModFileLocalVariable)
error("Variable " + *name + " not allowed inside model declaration. Its scope is only outside model."); error("Variable " + mod_file->symbol_table.getName(symb_id) + " not allowed inside model declaration. Its scope is only outside model.");
if (type == eUnknownFunction) if (type == eExternalFunction)
error("Symbol " + *name + " is a function name unknown to Dynare. It cannot be used inside model."); error("Symbol " + mod_file->symbol_table.getName(symb_id) + " is a function name external to Dynare. It cannot be used inside model.");
if (type == eModelLocalVariable && lag != 0) if (type == eModelLocalVariable && lag != 0)
error("Model local variable " + *name + " cannot be given a lead or a lag."); error("Model local variable " + mod_file->symbol_table.getName(symb_id) + " cannot be given a lead or a lag.");
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
return model_tree->AddVariable(symb_id, lag);
NodeID id = model_tree->AddVariable(*name, lag);
delete name;
delete olag;
return id;
} }
NodeID NodeID
@ -1151,7 +1168,7 @@ ParsingDriver::run_model_comparison()
void void
ParsingDriver::begin_planner_objective() ParsingDriver::begin_planner_objective()
{ {
set_current_data_tree(new StaticModel(mod_file->symbol_table, mod_file->num_constants)); set_current_data_tree(new StaticModel(mod_file->symbol_table, mod_file->num_constants, mod_file->external_functions_table));
} }
void void
@ -1608,24 +1625,145 @@ ParsingDriver::add_steady_state(NodeID arg1)
} }
void void
ParsingDriver::add_unknown_function_arg(NodeID arg) ParsingDriver::external_function_option(const string &name_option, string *opt)
{ {
unknown_function_args.push_back(arg); external_function_option(name_option, *opt);
}
void
ParsingDriver::external_function_option(const string &name_option, const string &opt)
{
if (name_option == "name")
{
if (opt.empty())
error("An argument must be passed to the 'name' option of the external_function() statement.");
declare_symbol(&opt, eExternalFunction, NULL);
current_external_function_name = opt;
}
else if (name_option == "first_deriv_provided")
{
if (opt.empty())
current_external_function_options.firstDerivSymbID = eExtFunSetButNoNameProvided;
else
{
declare_symbol(&opt, eExternalFunction, NULL);
current_external_function_options.firstDerivSymbID = mod_file->symbol_table.getID(opt);
}
}
else if (name_option == "second_deriv_provided")
{
if (opt.empty())
current_external_function_options.secondDerivSymbID = eExtFunSetButNoNameProvided;
else
{
declare_symbol(&opt, eExternalFunction, NULL);
current_external_function_options.secondDerivSymbID = mod_file->symbol_table.getID(opt);
}
}
else if (name_option == "nargs")
current_external_function_options.nargs = atoi(opt.c_str());
else
error("Unexpected error in ParsingDriver::external_function_option(): Please inform Dynare Team.");
}
void
ParsingDriver::external_function()
{
if (current_external_function_name.empty())
error("The 'name' option must be passed to external_function().");
int function_symb_id = mod_file->symbol_table.getID(current_external_function_name);
if (current_external_function_options.secondDerivSymbID > eExtFunNotSet &&
current_external_function_options.firstDerivSymbID == eExtFunNotSet)
error("If the second derivative is provided to the external_function command, the first derivative must also be provided.");
mod_file->external_functions_table.addExternalFunction(function_symb_id, current_external_function_options);
reset_current_external_function_options();
}
void
ParsingDriver::push_external_function_arg_vector_onto_stack()
{
vector<NodeID> emptyvec;
stack_external_function_args.push(emptyvec);
}
void
ParsingDriver::add_external_function_arg(NodeID arg)
{
stack_external_function_args.top().push_back(arg);
} }
NodeID NodeID
ParsingDriver::add_unknown_function(string *function_name) ParsingDriver::add_model_var_or_external_function(string *function_name)
{ {
if (mod_file->symbol_table.exists(*function_name)) if (mod_file->symbol_table.exists(*function_name))
{ {
if (mod_file->symbol_table.getType(*function_name) != eUnknownFunction) if (mod_file->symbol_table.getType(*function_name) != eExternalFunction)
error("Symbol " + *function_name + " is not a function name."); { // e.g. model_var(lag) => ADD MODEL VARIABLE WITH LEAD (NumConstNode)/LAG (UnaryOpNode)
if ((int)stack_external_function_args.top().size() == 1)
{
NumConstNode *numNode = dynamic_cast<NumConstNode *>(stack_external_function_args.top().front());
UnaryOpNode *unaryNode = dynamic_cast<UnaryOpNode *>(stack_external_function_args.top().front());
if (numNode == NULL && unaryNode == NULL)
error("A model variable is being treated as if it were a function (i.e., takes an argument that is not an integer).");
eval_context_type ectmp;
int model_var_arg;
double model_var_arg_dbl;
if (unaryNode == NULL)
{
model_var_arg = (int)numNode->eval(ectmp);
model_var_arg_dbl = numNode->eval(ectmp);
}
else
{
if (unaryNode->get_op_code() != oUminus)
error("A model variable is being treated as if it were a function (i.e., takes an argument that is not an integer).");
else
{
model_var_arg = (int)unaryNode->eval(ectmp);
model_var_arg_dbl = unaryNode->eval(ectmp);
}
}
if ((double) model_var_arg != model_var_arg_dbl) //make 100% sure int cast didn't lose info
error("A model variable is being treated as if it were a function (i.e., takes an argument that is not an integer).");
NodeID nid = add_model_variable(mod_file->symbol_table.getID(*function_name), model_var_arg);
stack_external_function_args.pop();
delete function_name;
return nid;
}
else
error("A model variable is being treated as if it were a function (i.e., has received more than one argument).");
}
else
{ // e.g. this function has already been referenced (either ad hoc or through the external_function() statement
// => check that the information matches previously declared info
int symb_id = mod_file->symbol_table.getID(*function_name);
if (!mod_file->external_functions_table.exists(symb_id))
error("In ParsingDriver::add_external_function()(1) Please report to Dynare Team.");
if ((int)(stack_external_function_args.top().size()) != mod_file->external_functions_table.getNargs(symb_id))
error("The number of arguments passed to " + *function_name +
" does not match those of a previous call or declaration of this function.");
}
} }
else else
mod_file->symbol_table.addSymbol(*function_name, eUnknownFunction); { //First time encountering this external function i.e., not previously declared or encountered
declare_symbol(function_name, eExternalFunction, NULL);
current_external_function_options.nargs = stack_external_function_args.top().size();
mod_file->external_functions_table.addExternalFunction(mod_file->symbol_table.getID(*function_name),
current_external_function_options);
reset_current_external_function_options();
}
NodeID id = data_tree->AddUnknownFunction(*function_name, unknown_function_args); //By this point, we're sure that this function exists in the External Functions Table and is not a mod var
unknown_function_args.clear(); NodeID id = data_tree->AddExternalFunction(*function_name, stack_external_function_args.top());
stack_external_function_args.pop();
delete function_name;
return id; return id;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -27,6 +27,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <istream> #include <istream>
#include <stack>
#include "ModFile.hh" #include "ModFile.hh"
#include "SymbolList.hh" #include "SymbolList.hh"
@ -78,7 +79,7 @@ private:
void check_symbol_existence(const string &name); void check_symbol_existence(const string &name);
//! Helper to add a symbol declaration //! Helper to add a symbol declaration
void declare_symbol(string *name, SymbolType type, string *tex_name); void declare_symbol(const string *name, const SymbolType type, const string *tex_name);
//! Creates option "optim_opt" in OptionsList if it doesn't exist, else add a comma, and adds the option name //! Creates option "optim_opt" in OptionsList if it doesn't exist, else add a comma, and adds the option name
void optim_options_helper(const string &name); void optim_options_helper(const string &name);
@ -153,12 +154,17 @@ private:
//! Temporary storage for lower cholesky within an svar_identification bock //! Temporary storage for lower cholesky within an svar_identification bock
bool svar_lower_cholesky; bool svar_lower_cholesky;
//! Temporary storage for argument list of unknown function //! Temporary storage for argument list of external function
vector<NodeID> unknown_function_args; stack<vector<NodeID> > stack_external_function_args;
//! Temporary storage for the symb_id associated with the "name" symbol of the current external_function statement
string current_external_function_name;
//! Temporary storage for option list provided to external_function()
ExternalFunctionsTable::external_function_options current_external_function_options;
//! reset the values for temporary storage
void reset_current_external_function_options();
//! The mod file representation constructed by this ParsingDriver //! The mod file representation constructed by this ParsingDriver
ModFile *mod_file; ModFile *mod_file;
public: public:
//! Starts parsing, and constructs the MOD file representation //! Starts parsing, and constructs the MOD file representation
/*! The returned pointer should be deleted after use */ /*! The returned pointer should be deleted after use */
@ -181,7 +187,7 @@ public:
void warning(const string &m); void warning(const string &m);
//! Check if a given symbol exists in the parsing context, and is not a mod file local variable //! Check if a given symbol exists in the parsing context, and is not a mod file local variable
bool symbol_exists_and_is_not_modfile_local_or_unknown_function(const char *s); bool symbol_exists_and_is_not_modfile_local_or_external_function(const char *s);
//! Sets mode of ModelTree class to use C output //! Sets mode of ModelTree class to use C output
void use_dll(); void use_dll();
//! the modelis block decomposed //! the modelis block decomposed
@ -221,7 +227,7 @@ public:
//! Adds a model variable to ModelTree and VariableTable //! Adds a model variable to ModelTree and VariableTable
NodeID add_model_variable(string *name); NodeID add_model_variable(string *name);
//! Adds a model lagged variable to ModelTree and VariableTable //! Adds a model lagged variable to ModelTree and VariableTable
NodeID add_model_variable(string *name, string *olag); NodeID add_model_variable(int symb_id, int lag);
//! Adds an Expression's variable //! Adds an Expression's variable
NodeID add_expression_variable(string *name); NodeID add_expression_variable(string *name);
//! Adds a "periods" statement //! Adds a "periods" statement
@ -315,6 +321,12 @@ public:
void estimated_params_init(); void estimated_params_init();
//! Writes estimated params bound command //! Writes estimated params bound command
void estimated_params_bounds(); void estimated_params_bounds();
//! Adds a declaration for a user-defined external function
void external_function();
//! Sets an external_function option to a string value
void external_function_option(const string &name_option, string *opt);
//! Sets an external_function option to a string value
void external_function_option(const string &name_option, const string &opt);
//! Add a line in an estimated params block //! Add a line in an estimated params block
void add_estimated_params_element(); void add_estimated_params_element();
//! Runs estimation process //! Runs estimation process
@ -467,10 +479,12 @@ public:
NodeID add_normcdf(NodeID arg); NodeID add_normcdf(NodeID arg);
//! Writes token "steadyState(arg1)" to model tree //! Writes token "steadyState(arg1)" to model tree
NodeID add_steady_state(NodeID arg1); NodeID add_steady_state(NodeID arg1);
//! Adds an unknwon function argument //! Pushes empty vector onto stack when a symbol is encountered (mod_var or ext_fun)
void add_unknown_function_arg(NodeID arg); void push_external_function_arg_vector_onto_stack();
//! Adds an unknown function call node //! Adds an external function argument
NodeID add_unknown_function(string *function_name); void add_external_function_arg(NodeID arg);
//! Adds an external function call node
NodeID add_model_var_or_external_function(string *function_name);
//! Adds a native statement //! Adds a native statement
void add_native(const char *s); void add_native(const char *s);
//! Resets data_tree and model_tree pointers to default (i.e. mod_file->expressions_tree) //! Resets data_tree and model_tree pointers to default (i.e. mod_file->expressions_tree)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -36,8 +36,9 @@
#endif #endif
StaticModel::StaticModel(SymbolTable &symbol_table_arg, StaticModel::StaticModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg) : NumericalConstants &num_constants_arg,
ModelTree(symbol_table_arg, num_constants_arg), ExternalFunctionsTable &external_functions_table_arg) :
ModelTree(symbol_table_arg, num_constants_arg, external_functions_table_arg),
global_temporary_terms(true), global_temporary_terms(true),
cutoff(1e-15), cutoff(1e-15),
mfs(0) mfs(0)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2003-2009 Dynare Team * Copyright (C) 2003-2010 Dynare Team
* *
* This file is part of Dynare. * This file is part of Dynare.
* *
@ -151,7 +151,7 @@ protected:
vector<pair<int, int> > endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block; vector<pair<int, int> > endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block;
public: public:
StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table_arg);
//! Writes information on block decomposition when relevant //! Writes information on block decomposition when relevant
void writeOutput(ostream &output, bool block) const; void writeOutput(ostream &output, bool block) const;