diff --git a/doc/dynare.texi b/doc/dynare.texi index 75cec054cd7ef4b86971c8b4b716f919ac6a3cce..703295a5de3cce19dbb04458fe7bfabb63ee4599 100644 --- a/doc/dynare.texi +++ b/doc/dynare.texi @@ -1244,6 +1244,14 @@ Base 10 logarithm. Square root. @end defun +@defun abs (@var{x}) +Absolute value. +@end defun + +@defun sign (@var{x}) +Signum function. +@end defun + @defun sin (@var{x}) @defunx cos (@var{x}) @defunx tan (@var{x}) diff --git a/preprocessor/CodeInterpreter.hh b/preprocessor/CodeInterpreter.hh index 8d6e600ed0b34ef05750aae19a9a5e83a5fa8870..f730cbbc94ea013df5953d1b0a694de32ca17229 100644 --- a/preprocessor/CodeInterpreter.hh +++ b/preprocessor/CodeInterpreter.hh @@ -188,6 +188,8 @@ enum UnaryOpcode oAsinh, oAtanh, oSqrt, + oAbs, + oSign, oSteadyState, oSteadyStateParamDeriv, // for the derivative of the STEADY_STATE operator w.r.t. to a parameter oSteadyStateParam2ndDeriv, // for the 2nd derivative of the STEADY_STATE operator w.r.t. to a parameter diff --git a/preprocessor/DataTree.cc b/preprocessor/DataTree.cc index 267a97e60bf4ac266510ac120319cf1d49d49d12..24f97f981b5d2e691cac396d718e538a1a4356bb 100644 --- a/preprocessor/DataTree.cc +++ b/preprocessor/DataTree.cc @@ -401,6 +401,28 @@ DataTree::AddSqrt(expr_t iArg1) return Zero; } +expr_t +DataTree::AddAbs(expr_t iArg1) +{ + if (iArg1 == Zero) + return Zero; + if (iArg1 == One) + return One; + else + return AddUnaryOp(oAbs, iArg1); +} + +expr_t +DataTree::AddSign(expr_t iArg1) +{ + if (iArg1 == Zero) + return Zero; + if (iArg1 == One) + return One; + else + return AddUnaryOp(oSign, iArg1); +} + expr_t DataTree::AddErf(expr_t iArg1) { diff --git a/preprocessor/DataTree.hh b/preprocessor/DataTree.hh index 1456e9c86f617ae97b88ec0dde4794a3fee06944..0cb2ab7cd2c14347ca5aa728d2cd3a8dd7a093b7 100644 --- a/preprocessor/DataTree.hh +++ b/preprocessor/DataTree.hh @@ -176,6 +176,10 @@ public: expr_t AddAtanh(expr_t iArg1); //! Adds "sqrt(arg)" to model tree expr_t AddSqrt(expr_t iArg1); + //! Adds "abs(arg)" to model tree + expr_t AddAbs(expr_t iArg1); + //! Adds "sign(arg)" to model tree + expr_t AddSign(expr_t iArg1); //! Adds "erf(arg)" to model tree expr_t AddErf(expr_t iArg1); //! Adds "max(arg1,arg2)" to model tree diff --git a/preprocessor/DynareBison.yy b/preprocessor/DynareBison.yy index 09c45b7c35d2b6ae4fc29dd4dd5bafb5072362cf..bdd3f2de3b6153623b04eee47c8541497c3348e1 100644 --- a/preprocessor/DynareBison.yy +++ b/preprocessor/DynareBison.yy @@ -108,7 +108,7 @@ class ParsingDriver; %token LABELS LAPLACE LIK_ALGO LIK_INIT LINEAR LOAD_IDENT_FILES LOAD_MH_FILE LOAD_PARAMS_AND_STEADY_STATE LOGLINEAR %token MARKOWITZ MARGINAL_DENSITY MAX %token MFS MH_DROP MH_INIT_SCALE MH_JSCALE MH_MODE MH_NBLOCKS MH_REPLIC MH_RECOVER MIN MINIMAL_SOLVING_PERIODS -%token MODE_CHECK MODE_COMPUTE MODE_FILE MODEL MODEL_COMPARISON MODEL_INFO MSHOCKS +%token MODE_CHECK MODE_COMPUTE MODE_FILE MODEL MODEL_COMPARISON MODEL_INFO MSHOCKS ABS SIGN %token MODIFIEDHARMONICMEAN MOMENTS_VARENDO DIFFUSE_FILTER %token <string_val> NAME %token NAN_CONSTANT NO_STATIC NOBS NOCONSTANT NOCORR NODIAGNOSTIC NOFUNCTIONS @@ -459,6 +459,10 @@ expression : '(' expression ')' { $$ = driver.add_atan($3); } | SQRT '(' expression ')' { $$ = driver.add_sqrt($3); } + | ABS '(' expression ')' + { $$ = driver.add_abs($3); } + | SIGN '(' expression ')' + { $$ = driver.add_sign($3); } | MAX '(' expression COMMA expression ')' { $$ = driver.add_max($3, $5); } | MIN '(' expression COMMA expression ')' @@ -613,6 +617,10 @@ hand_side : '(' hand_side ')' { $$ = driver.add_atan($3); } | SQRT '(' hand_side ')' { $$ = driver.add_sqrt($3); } + | ABS '(' hand_side ')' + { $$ = driver.add_abs($3); } + | SIGN '(' hand_side ')' + { $$ = driver.add_sign($3); } | MAX '(' hand_side COMMA hand_side ')' { $$ = driver.add_max($3, $5); } | MIN '(' hand_side COMMA hand_side ')' diff --git a/preprocessor/DynareFlex.ll b/preprocessor/DynareFlex.ll index eec5336436c5b56e6193052eeb99f36f344dd4ca..6d8b51e4d5050639e1e9edac3e26774d10948623 100644 --- a/preprocessor/DynareFlex.ll +++ b/preprocessor/DynareFlex.ll @@ -511,6 +511,8 @@ string eofbuff; <DYNARE_STATEMENT,DYNARE_BLOCK>sqrt {return token::SQRT;} <DYNARE_STATEMENT,DYNARE_BLOCK>max {return token::MAX;} <DYNARE_STATEMENT,DYNARE_BLOCK>min {return token::MIN;} +<DYNARE_STATEMENT,DYNARE_BLOCK>abs {return token::ABS;} +<DYNARE_STATEMENT,DYNARE_BLOCK>sign {return token::SIGN;} <DYNARE_STATEMENT,DYNARE_BLOCK>normcdf {return token::NORMCDF;} <DYNARE_STATEMENT,DYNARE_BLOCK>normpdf {return token::NORMPDF;} <DYNARE_STATEMENT,DYNARE_BLOCK>erf {return token::ERF;} diff --git a/preprocessor/ExprNode.cc b/preprocessor/ExprNode.cc index 3974cbbfcb2486397f8314eca8a4dc45d5e8c088..386f28702632e09f7b7be4241ac8e89791305dd1 100644 --- a/preprocessor/ExprNode.cc +++ b/preprocessor/ExprNode.cc @@ -1323,6 +1323,11 @@ UnaryOpNode::composeDerivatives(expr_t darg, int deriv_id) case oSqrt: t11 = datatree.AddPlus(this, this); return datatree.AddDivide(darg, t11); + case oAbs: + t11 = datatree.AddSign(arg); + return datatree.AddTimes(t11, darg); + case oSign: + return datatree.Zero; case oSteadyState: if (datatree.isDynamic()) { @@ -1406,6 +1411,7 @@ UnaryOpNode::cost(const temporary_terms_t &temporary_terms, bool is_matlab) cons switch (op_code) { case oUminus: + case oSign: return cost + 70; case oExp: return cost + 160; @@ -1437,6 +1443,7 @@ UnaryOpNode::cost(const temporary_terms_t &temporary_terms, bool is_matlab) cons case oAtanh: return cost + 350; case oSqrt: + case oAbs: return cost + 570; case oSteadyState: case oSteadyStateParamDeriv: @@ -1449,6 +1456,7 @@ UnaryOpNode::cost(const temporary_terms_t &temporary_terms, bool is_matlab) cons switch (op_code) { case oUminus: + case oSign: return cost + 3; case oExp: case oAcosh: @@ -1477,6 +1485,7 @@ UnaryOpNode::cost(const temporary_terms_t &temporary_terms, bool is_matlab) cons case oAtanh: return cost + 150; case oSqrt: + case oAbs: return cost + 90; case oSteadyState: case oSteadyStateParamDeriv: @@ -1622,6 +1631,15 @@ UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, case oSqrt: output << "sqrt"; break; + case oAbs: + output << "abs"; + break; + case oSign: + if (output_type == oCDynamicModel) + output << "copysign"; + else + output << "sign"; + break; case oSteadyState: ExprNodeOutputType new_output_type; switch (output_type) @@ -1692,6 +1710,8 @@ UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms))) { output << LEFT_PAR(output_type); + if (op_code == oSign && output_type == oCDynamicModel) + output << "1.0,"; close_parenthesis = true; } @@ -1763,6 +1783,10 @@ UnaryOpNode::eval_opcode(UnaryOpcode op_code, double v) throw (EvalException, Ev return (atanh(v)); case oSqrt: return (sqrt(v)); + case oAbs: + return (abs(v)); + case oSign: + return (v > 0) ? 1 : ((v < 0) ? -1 : 0); case oSteadyState: return (v); case oSteadyStateParamDeriv: @@ -1901,6 +1925,10 @@ UnaryOpNode::normalizeEquation(int var_endo, vector<pair<int, pair<expr_t, expr_ return (make_pair(0, datatree.AddAtanh(New_expr_t))); case oSqrt: return (make_pair(0, datatree.AddSqrt(New_expr_t))); + case oAbs: + return (make_pair(0, datatree.AddAbs(New_expr_t))); + case oSign: + return (make_pair(0, datatree.AddSign(New_expr_t))); case oSteadyState: return (make_pair(0, datatree.AddSteadyState(New_expr_t))); case oErf: @@ -1960,6 +1988,10 @@ UnaryOpNode::buildSimilarUnaryOpNode(expr_t alt_arg, DataTree &alt_datatree) con return alt_datatree.AddAtanh(alt_arg); case oSqrt: return alt_datatree.AddSqrt(alt_arg); + case oAbs: + return alt_datatree.AddAbs(alt_arg); + case oSign: + return alt_datatree.AddSign(alt_arg); case oSteadyState: return alt_datatree.AddSteadyState(alt_arg); case oSteadyStateParamDeriv: diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc index 0e2d324a9a48853cfde0cb7e4a772f6abb34509d..0c138ca32b6866cc305e2dc3f65d92781c45a2af 100644 --- a/preprocessor/ParsingDriver.cc +++ b/preprocessor/ParsingDriver.cc @@ -1746,6 +1746,18 @@ ParsingDriver::add_sqrt(expr_t arg1) return data_tree->AddSqrt(arg1); } +expr_t +ParsingDriver::add_abs(expr_t arg1) +{ + return data_tree->AddAbs(arg1); +} + +expr_t +ParsingDriver::add_sign(expr_t arg1) +{ + return data_tree->AddSign(arg1); +} + expr_t ParsingDriver::add_max(expr_t arg1, expr_t arg2) { diff --git a/preprocessor/ParsingDriver.hh b/preprocessor/ParsingDriver.hh index c60a18c1fa529014de220f5da0ee50bd6087fc4e..74ddc41d046509f0abe9c87083780d5d413d8598 100644 --- a/preprocessor/ParsingDriver.hh +++ b/preprocessor/ParsingDriver.hh @@ -485,6 +485,10 @@ public: expr_t add_atanh(expr_t arg1); //! Writes token "sqrt(arg1)" to model tree expr_t add_sqrt(expr_t arg1); + //! Writes token "abs(arg1)" to model tree + expr_t add_abs(expr_t arg1); + //! Writes token "sign(arg1)" to model tree + expr_t add_sign(expr_t arg1); //! Writes token "max(arg1,arg2)" to model tree expr_t add_max(expr_t arg1, expr_t arg2); //! Writes token "min(arg1,arg2)" to model tree diff --git a/tests/Makefile.am b/tests/Makefile.am index 3656805c0677b4faf8448175d405d32b23c98aab..6974b2998628556af0076551fc02ca2a13324d8e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,7 @@ MODFILES = \ example1_use_dll.mod \ example1_with_tags.mod \ example1_irf_shocks.mod \ + example1_abs_sign_dynamic.mod \ t_sgu_ex1.mod \ osr_example.mod \ optimal_policy/ramsey.mod \ diff --git a/tests/example1_abs_sign.mod b/tests/example1_abs_sign.mod new file mode 100644 index 0000000000000000000000000000000000000000..6fea109aa355a4849ab2a26b85585e709897c984 --- /dev/null +++ b/tests/example1_abs_sign.mod @@ -0,0 +1,44 @@ +// Example 1 from Collard's guide to Dynare +var y, c, k, a, h, b; +varexo e, u; + +parameters beta, rho, alpha, delta, theta, psi, tau; + +alpha = 0.36; +rho = 0.95; +tau = 0.025; +beta = 0.99; +delta = 0.025; +psi = 0; +theta = 2.95; + +phi = 0.1; + +model(use_dll); +c*theta*h^(1+psi)=abs((1-alpha)*y); +k = beta*(((exp(b)*c)/(exp(b(+1))*c(+1))) + *(exp(b(+1))*alpha*y(+1)+(1-delta)*k)); +y = exp(a)*(k(-1)^alpha)*(h^(1-alpha)); +k = exp(b)*(y-c)+(1-delta)*k(-1)*sign(k*k); +a = rho*a(-1)+tau*b(-1) + e; +b = tau*a(-1)+rho*b(-1) + u; +end; + +initval; +y = 1.08068253095672; +c = 0.80359242014163; +h = 0.29175631001732; +k = 11.08360443260358; +a = 0; +b = 0; +e = 0; +u = 0; +end; + +shocks; +var e; stderr 0.009; +var u; stderr 0.009; +var e, u = phi*0.009*0.009; +end; + +stoch_simul;