...
 
Commits (9)
......@@ -683,6 +683,58 @@ ForecastStatement::writeJsonOutput(ostream &output) const
output << "}";
}
DetCondForecast::DetCondForecast(const SymbolList &symbol_list_arg,
const OptionsList &options_list_arg,
const bool linear_decomposition_arg) :
options_list(options_list_arg),
symbol_list(symbol_list_arg),
linear_decomposition(linear_decomposition_arg)
{
}
void
DetCondForecast::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
{
options_list.writeOutput(output);
if (linear_decomposition)
{
output << "first_order_solution_to_compute = 1;" << endl;
output << "if exist('oo_')" << endl;
output << " if isfield(oo_, 'dr')" << endl;
output << " if isfield(oo_.dr, 'ghx') && isfield(oo_.dr, 'ghu') && isfield(oo_.dr, 'state_var') && isfield(oo_.dr, 'order_var')" << endl;
output << " first_order_solution_to_compute = 0;" << endl;
output << " end;" << endl;
output << " end;" << endl;
output << "end;" << endl;
output << "if first_order_solution_to_compute" << endl;
output << " fprintf('%s','Computing the first order solution ...');" << endl;
output << " options_.nograph = 1;" << endl;
output << " options_.order = 1;" << endl;
output << " options_.noprint = 1;" << endl;
output << " options_.nocorr = 1;" << endl;
output << " options_.nomoments = 1;" << endl;
output << " options_.nodecomposition = 1;" << endl;
output << " options_.nofunctions = 1;" << endl;
output << " options_.irf = 0;" << endl;
output << " tmp_periods = options_.periods;" << endl;
output << " options_.periods = 0;" << endl;
output << " var_list_ = char();" << endl;
output << " info = stoch_simul(var_list_);" << endl;
output << " fprintf('%s\\n','done');" << endl;
output << " options_.periods = tmp_periods;" << endl;
output << "end;" << endl;
}
vector<string> symbols = symbol_list.get_symbols();
if (symbols.size() > 0)
output << symbols[1] << " = det_cond_forecast(" ;
for (unsigned int i = 0; i < symbols.size() - 1; i++)
output << symbols[i] << ", ";
if (symbols.size() > 0)
output << symbols[symbols.size() - 1];
output << ");" << endl;
}
RamseyModelStatement::RamseyModelStatement(OptionsList options_list_arg) :
options_list(move(options_list_arg))
{
......
......@@ -95,6 +95,21 @@ public:
void writeJsonOutput(ostream &output) const override;
};
class DetCondForecast : public Statement
{
private:
const OptionsList options_list;
const SymbolList symbol_list;
const bool linear_decomposition;
public:
DetCondForecast(const SymbolList &symbol_list_arg,
const OptionsList &options_list_arg,
const bool linear_decompositiontion_arg);
//virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
virtual void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const;
};
class ModelInfoStatement : public Statement
{
private:
......
This diff is collapsed.
......@@ -118,7 +118,7 @@ private:
//! Writes the Block reordred structure of the model in M output
void writeModelEquationsOrdered_M(const string &basename) const;
//! Writes the code of the Block reordred structure of the model in virtual machine bytecode
void writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx) const;
void writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx, const bool linear_decomposition) const;
//! Writes the code of the model in virtual machine bytecode
void writeModelEquationsCode(const string &basename, const map_idx_t &map_idx) const;
......@@ -280,9 +280,9 @@ public:
\param no_tmp_terms if true, no temporary terms will be computed in the dynamic files
*/
void computingPass(bool jacobianExo, bool hessian, bool thirdDerivatives, int paramsDerivsOrder,
const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode, const bool nopreprocessoroutput);
const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode, const bool nopreprocessoroutput, bool linear_decomposition);
//! Writes model initialization and lead/lag incidence matrix to output
void writeOutput(ostream &output, const string &basename, bool block, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const;
void writeOutput(ostream &output, const string &basename, bool block, bool linear_decomposition, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const;
//! Write JSON AST
void writeJsonAST(ostream &output) const;
......@@ -351,9 +351,9 @@ public:
//! Adds informations for simulation in a binary file
void Write_Inf_To_Bin_File_Block(const string &basename,
const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries) const;
const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries, const bool linear_decomposition) const;
//! Writes dynamic model file
void writeDynamicFile(const string &basename, bool block, bool bytecode, bool use_dll, int order, bool julia) const;
void writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, int order, bool julia) const;
//! Writes file containing parameters derivatives
void writeParamsDerivativesFile(const string &basename, bool julia) const;
......@@ -361,6 +361,11 @@ public:
/*! It assumes that the static model given in argument has just been allocated */
void toStatic(StaticModel &static_model) const;
//! Converts to nonlinear model (only the equations)
/*! It assumes that the nonlinear model given in argument has just been allocated */
void toNonlinearPart(DynamicModel &non_linear_equations_dynamic_model) const;
//! Find endogenous variables not used in model
set<int> findUnusedEndogenous();
//! Find exogenous variables not used in model
......
......@@ -81,7 +81,7 @@ class ParsingDriver;
%token BVAR_REPLIC BYTECODE ALL_VALUES_REQUIRED PROPOSAL_DISTRIBUTION REALTIME VINTAGE
%token CALIB_SMOOTHER CHANGE_TYPE CHECK CONDITIONAL_FORECAST CONDITIONAL_FORECAST_PATHS CONF_SIG CONSTANT CONTROLLED_VAREXO CORR CUTOFF CYCLE_REDUCTION LOGARITHMIC_REDUCTION
%token COMMA CONSIDER_ALL_ENDOGENOUS CONSIDER_ONLY_OBSERVED INITIAL_CONDITION_DECOMPOSITION
%token DATAFILE FILE SERIES DOUBLING DR_CYCLE_REDUCTION_TOL DR_LOGARITHMIC_REDUCTION_TOL DR_LOGARITHMIC_REDUCTION_MAXITER DR_ALGO DROP DSAMPLE DYNASAVE DYNATYPE CALIBRATION DIFFERENTIATE_FORWARD_VARS
%token DATAFILE FILE SERIES DET_COND_FORECAST DOUBLING DR_CYCLE_REDUCTION_TOL DR_LOGARITHMIC_REDUCTION_TOL DR_LOGARITHMIC_REDUCTION_MAXITER DR_ALGO DROP DSAMPLE DYNASAVE DYNATYPE CALIBRATION DIFFERENTIATE_FORWARD_VARS
%token END ENDVAL EQUAL ESTIMATION ESTIMATED_PARAMS ESTIMATED_PARAMS_BOUNDS ESTIMATED_PARAMS_INIT EXTENDED_PATH ENDOGENOUS_PRIOR
%token FILENAME DIRNAME FILTER_STEP_AHEAD FILTERED_VARS FIRST_OBS LAST_OBS SET_TIME OSR_PARAMS_BOUNDS KEEP_KALMAN_ALGO_IF_SINGULARITY_IS_DETECTED
%token <string> FLOAT_NUMBER DATES
......@@ -93,7 +93,7 @@ class ParsingDriver;
%token <string> INT_NUMBER
%token INV_GAMMA_PDF INV_GAMMA1_PDF INV_GAMMA2_PDF IRF IRF_SHOCKS IRF_PLOT_THRESHOLD IRF_CALIBRATION
%token FAST_KALMAN_FILTER KALMAN_ALGO KALMAN_TOL DIFFUSE_KALMAN_TOL SUBSAMPLES OPTIONS TOLF TOLX PLOT_INIT_DATE PLOT_END_DATE
%token LAPLACE LIK_ALGO LIK_INIT LINEAR LOAD_IDENT_FILES LOAD_MH_FILE LOAD_RESULTS_AFTER_LOAD_MH LOAD_PARAMS_AND_STEADY_STATE LOGLINEAR LOGDATA LYAPUNOV LINEAR_APPROXIMATION
%token LAPLACE LIK_ALGO LIK_INIT LINEAR LINEAR_DECOMPOSITION LOAD_IDENT_FILES LOAD_MH_FILE LOAD_RESULTS_AFTER_LOAD_MH LOAD_PARAMS_AND_STEADY_STATE LOGLINEAR LOGDATA LYAPUNOV LINEAR_APPROXIMATION
%token LYAPUNOV_FIXED_POINT_TOL LYAPUNOV_DOUBLING_TOL LOG_DEFLATOR LOG_TREND_VAR LOG_GROWTH_FACTOR MARKOWITZ MARGINAL_DENSITY MAX MAXIT
%token MFS MH_CONF_SIG MH_DROP MH_INIT_SCALE MH_JSCALE MH_TUNE_JSCALE MH_MODE MH_NBLOCKS MH_REPLIC MH_RECOVER POSTERIOR_MAX_SUBSAMPLE_DRAWS MIN MINIMAL_SOLVING_PERIODS
%token MODE_CHECK MODE_CHECK_NEIGHBOURHOOD_SIZE MODE_CHECK_SYMMETRIC_PLOTS MODE_CHECK_NUMBER_OF_POINTS MODE_COMPUTE MODE_FILE MODEL MODEL_COMPARISON MODEL_INFO MSHOCKS ABS SIGN
......@@ -301,6 +301,7 @@ statement : parameters
| gmm_estimation
| smm_estimation
| shock_groups
| det_cond_forecast
| var_expectation_model
;
......@@ -970,6 +971,7 @@ model_options : BLOCK { driver.block(); }
| DIFFERENTIATE_FORWARD_VARS EQUAL '(' symbol_list ')' { driver.differentiate_forward_vars_some(); }
| o_linear
| PARALLEL_LOCAL_FILES EQUAL '(' parallel_local_filename_list ')'
| LINEAR_DECOMPOSITION { driver.linear_decomposition(); }
;
model_options_list : model_options_list COMMA model_options
......@@ -1194,7 +1196,7 @@ restriction_elem_expression : COEFF '(' symbol COMMA INT_NUMBER ')'
svar_global_identification_check: SVAR_GLOBAL_IDENTIFICATION_CHECK ';'
{ driver.add_svar_global_identification_check(); }
;
markov_switching : MARKOV_SWITCHING '(' ms_options_list ')' ';'
{ driver.markov_switching(); }
;
......@@ -1477,6 +1479,16 @@ prior_posterior_function_options : o_function
| o_sampling_draws
;
det_cond_forecast : DET_COND_FORECAST '(' symbol ')' ';'
{ driver.det_cond_forecast_linear_decomposition($3); }
| DET_COND_FORECAST '(' symbol COMMA symbol ')' ';'
{ driver.det_cond_forecast_linear_decomposition($3,$5); }
| DET_COND_FORECAST '(' symbol COMMA simul_options_list ')' ';'
{ driver.det_cond_forecast_linear_decomposition($3); }
| DET_COND_FORECAST '(' symbol COMMA symbol COMMA simul_options_list ')' ';'
{ driver.det_cond_forecast_linear_decomposition($3,$5); }
;
simul : SIMUL ';'
{ driver.simul(); }
| SIMUL '(' simul_options_list ')' ';'
......@@ -2357,7 +2369,7 @@ ramsey_constraints : RAMSEY_CONSTRAINTS ';' ramsey_constraints_list END ';'
{ driver.add_ramsey_constraints_statement(); }
;
ramsey_constraints_list : ramsey_constraints_list ramsey_constraint
ramsey_constraints_list : ramsey_constraints_list ramsey_constraint
| ramsey_constraint
;
......@@ -2365,7 +2377,7 @@ ramsey_constraint : NAME LESS expression ';'
{ driver.ramsey_constraint_add_less($1,$3); }
| NAME GREATER expression ';'
{ driver.ramsey_constraint_add_greater($1,$3); }
| NAME LESS_EQUAL expression ';'
| NAME LESS_EQUAL expression ';'
{ driver.ramsey_constraint_add_less_equal($1,$3); }
| NAME GREATER_EQUAL expression ';'
{ driver.ramsey_constraint_add_greater_equal($1,$3); }
......@@ -2385,7 +2397,7 @@ discretionary_policy_options_list : discretionary_policy_options_list COMMA disc
| discretionary_policy_options
;
discretionary_policy_options : ramsey_policy_options
discretionary_policy_options : ramsey_policy_options
| o_discretionary_tol;
| o_dp_maxit;
;
......@@ -3029,7 +3041,7 @@ generate_irfs_exog_element_list : generate_irfs_exog_element_list COMMA symbol E
extended_path : EXTENDED_PATH ';'
{ driver.extended_path(); }
| EXTENDED_PATH '(' extended_path_options_list ')' ';'
| EXTENDED_PATH '(' extended_path_options_list ')' ';'
{ driver.extended_path(); }
;
......@@ -3321,7 +3333,7 @@ o_mh_nblocks : MH_NBLOCKS EQUAL INT_NUMBER { driver.option_num("mh_nblck", $3);
o_load_mh_file : LOAD_MH_FILE { driver.option_num("load_mh_file", "1"); };
o_load_results_after_load_mh : LOAD_RESULTS_AFTER_LOAD_MH { driver.option_num("load_results_after_load_mh", "1"); };
o_loglinear : LOGLINEAR { driver.option_num("loglinear", "1"); };
o_linear_approximation : LINEAR_APPROXIMATION { driver.option_num("linear_approximation", "1"); };
o_linear_approximation : LINEAR_APPROXIMATION { driver.option_num("linear_approximation", "1"); };
o_logdata : LOGDATA { driver.option_num("logdata", "1"); };
o_nodiagnostic : NODIAGNOSTIC { driver.option_num("nodiagnostic", "1"); };
o_bayesian_irf : BAYESIAN_IRF { driver.option_num("bayesian_irf", "1"); };
......@@ -3616,7 +3628,7 @@ o_second_deriv_provided : SECOND_DERIV_PROVIDED EQUAL filename
| SECOND_DERIV_PROVIDED
{ driver.external_function_option("second_deriv_provided", ""); }
;
o_filter_covariance : FILTER_COVARIANCE
o_filter_covariance : FILTER_COVARIANCE
{ driver.option_num("filter_covariance","1");}
;
o_filter_decomposition : FILTER_DECOMPOSITION
......@@ -3728,12 +3740,12 @@ o_gmm_order : ORDER EQUAL INT_NUMBER { driver.option_num("gmm.order", $3); };
o_smm_order : ORDER EQUAL INT_NUMBER { driver.option_num("smm.order", $3); };
o_gmm_centered_moments : CENTERED_MOMENTS { driver.option_num("gmm.centered_moments", "1"); };
o_smm_centered_moments : CENTERED_MOMENTS { driver.option_num("smm.centered_moments", "1"); };
o_gmm_autolag : AUTOLAG EQUAL vec_int
o_gmm_autolag : AUTOLAG EQUAL vec_int
{ driver.option_vec_int("gmm.autolag", $3); }
| AUTOLAG EQUAL vec_int_number
{ driver.option_vec_int("gmm.autolag", $3); }
;
o_smm_autolag : AUTOLAG EQUAL vec_int
o_smm_autolag : AUTOLAG EQUAL vec_int
{ driver.option_vec_int("smm.autolag", $3); }
| AUTOLAG EQUAL vec_int_number
{ driver.option_vec_int("smm.autolag", $3); }
......@@ -3743,7 +3755,7 @@ o_smm_recursive_order_estimation : RECURSIVE_ORDER_ESTIMATION { driver.option_nu
o_gmm_bartlett_kernel_lag : BARTLETT_KERNEL_LAG EQUAL INT_NUMBER { driver.option_num("gmm.qLag", $3); };
o_smm_bartlett_kernel_lag : BARTLETT_KERNEL_LAG EQUAL INT_NUMBER { driver.option_num("smm.qLag", $3); };
o_gmm_weighting_matrix : WEIGHTING_MATRIX EQUAL OPTIMAL
{ driver.option_str("gmm.weighting_matrix", $3); }
{ driver.option_str("gmm.weighting_matrix", $3); }
| WEIGHTING_MATRIX EQUAL IDENTITY_MATRIX
{ driver.option_str("gmm.weighting_matrix", $3); }
| WEIGHTING_MATRIX EQUAL DIAGONAL
......@@ -3752,7 +3764,7 @@ o_gmm_weighting_matrix : WEIGHTING_MATRIX EQUAL OPTIMAL
{ driver.option_str("gmm.weighting_matrix", $3); }
;
o_smm_weighting_matrix : WEIGHTING_MATRIX EQUAL OPTIMAL
{ driver.option_str("smm.weighting_matrix", $3); }
{ driver.option_str("smm.weighting_matrix", $3); }
| WEIGHTING_MATRIX EQUAL IDENTITY_MATRIX
{ driver.option_str("smm.weighting_matrix", $3); }
| WEIGHTING_MATRIX EQUAL DIAGONAL
......
......@@ -186,6 +186,7 @@ DATE -?[0-9]+([YyAa]|[Mm]([1-9]|1[0-2])|[Qq][1-4]|[Ww]([1-9]{1}|[1-4][0-9]|5[0-2
<INITIAL>smoother2histval {BEGIN DYNARE_STATEMENT; return token::SMOOTHER2HISTVAL;}
<INITIAL>perfect_foresight_setup {BEGIN DYNARE_STATEMENT; return token::PERFECT_FORESIGHT_SETUP;}
<INITIAL>perfect_foresight_solver {BEGIN DYNARE_STATEMENT; return token::PERFECT_FORESIGHT_SOLVER;}
<INITIAL>det_cond_forecast {BEGIN DYNARE_STATEMENT; return token::DET_COND_FORECAST;}
<DYNARE_STATEMENT>; {
if (!sigma_e)
......@@ -776,6 +777,7 @@ DATE -?[0-9]+([YyAa]|[Mm]([1-9]|1[0-2])|[Qq][1-4]|[Ww]([1-9]{1}|[1-4][0-9]|5[0-2
<DYNARE_BLOCK>use_dll {return token::USE_DLL;}
<DYNARE_BLOCK>block {return token::BLOCK;}
<DYNARE_BLOCK>bytecode {return token::BYTECODE;}
<DYNARE_BLOCK>linear_decomposition {return token::LINEAR_DECOMPOSITION;}
<DYNARE_BLOCK>all_values_required {return token::ALL_VALUES_REQUIRED;}
<DYNARE_BLOCK>no_static {return token::NO_STATIC;}
<DYNARE_BLOCK>differentiate_forward_vars {return token::DIFFERENTIATE_FORWARD_VARS;}
......
This diff is collapsed.
......@@ -67,13 +67,15 @@ public:
DynamicModel ramsey_FOC_equations_dynamic_model;
//! A copy of the original model, used to test model linearity under ramsey problem
DynamicModel orig_ramsey_dynamic_model;
//! A copy of the Dynamic model, containing only the non-linear equations w.r. to endogenous variables
DynamicModel non_linear_equations_dynamic_model;
//! Epilogue model, as declared in the "epilogue" block
Epilogue epilogue;
//! Static model, as derived from the "model" block when leads and lags have been removed
StaticModel static_model;
//! Static model, as declared in the "steady_state_model" block if present
SteadyStateModel steady_state_model;
//! Static model used for mapping arguments of diff operator
//! Static model used for mapping arguments of diff operator
StaticModel diff_static_model;
//! Option linear
......@@ -100,6 +102,9 @@ public:
with a lead */
vector<string> differentiate_forward_vars_subset;
//! Is the model is block-decomposed according the linear and the non-linear equations
bool linear_decomposition;
//! Are nonstationary variables present ?
bool nonstationary_variables;
......
......@@ -316,6 +316,105 @@ ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_m
}
}
vector<pair<int, int> >
ModelTree::select_non_linear_equations_and_variables(vector<bool> is_equation_linear, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered,
vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered,
lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead,
vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed)
{
vector<int> eq2endo(equations.size(), 0);
/*equation_reordered.resize(equations.size());
variable_reordered.resize(equations.size());*/
unsigned int num = 0;
for (vector<int>::const_iterator it = endo2eq.begin(); it != endo2eq.end(); it++)
if (!is_equation_linear[*it])
num++;
vector<int> endo2block = vector<int>(endo2eq.size(), 1);
vector<pair<set<int>, pair<set<int>, vector<int> > > > components_set(num);
int i = 0, j = 0;
for (vector<int>::const_iterator it = endo2eq.begin(); it != endo2eq.end(); it++, j++)
{
if (!is_equation_linear[*it])
{
equation_reordered[i] = *it;
variable_reordered[i] = j;
endo2block[j] = 0;
components_set[endo2block[j]].first.insert(i);
/*cout << " -----------------------------------------" << endl;
cout.flush();
cout << "equation_reordered[" << *it << "] = " << i << endl;
cout.flush();
cout << "variable_reordered[" << j << "] = " << i << endl;
cout.flush();
cout << "components_set[" << endo2block[j] << "].first[" << i << "] = " << i << endl;
cout << "endo2block[" << j << "] = " << 0 << endl;
cout.flush();
*/
i++;
}
}
/* for (unsigned int j = 0; j < is_equation_linear.size() ; j++)
cout << "endo2block[" << j << "] = " << endo2block[j] << endl;*/
/*cout << "before getVariableLeadLAgByBlock\n";
cout.flush();*/
getVariableLeadLagByBlock(dynamic_jacobian, endo2block, endo2block.size(), equation_lag_lead, variable_lag_lead, equation_reordered, variable_reordered);
n_static = vector<unsigned int>(endo2eq.size(), 0);
n_forward = vector<unsigned int>(endo2eq.size(), 0);
n_backward = vector<unsigned int>(endo2eq.size(), 0);
n_mixed = vector<unsigned int>(endo2eq.size(), 0);
for (unsigned int i = 0; i < endo2eq.size(); i++)
{
if (variable_lag_lead[variable_reordered[i]].first != 0 && variable_lag_lead[variable_reordered[i]].second != 0)
n_mixed[i]++;
else if (variable_lag_lead[variable_reordered[i]].first == 0 && variable_lag_lead[variable_reordered[i]].second != 0)
n_forward[i]++;
else if (variable_lag_lead[variable_reordered[i]].first != 0 && variable_lag_lead[variable_reordered[i]].second == 0)
n_backward[i]++;
else if (variable_lag_lead[variable_reordered[i]].first == 0 && variable_lag_lead[variable_reordered[i]].second == 0)
n_static[i]++;
}
cout.flush();
int nb_endo = is_equation_linear.size();
vector<pair<int, int> > blocks = vector<pair<int, int> >(1, make_pair(i, i));
inv_equation_reordered = vector<int>(nb_endo);
inv_variable_reordered = vector<int>(nb_endo);
for (int i = 0; i < nb_endo; i++)
{
inv_variable_reordered[variable_reordered[i]] = i;
inv_equation_reordered[equation_reordered[i]] = i;
}
return blocks;
}
bool
ModelTree::computeNaturalNormalization()
{
bool bool_result = true;
set<pair<int, int> > result;
endo2eq.resize(equations.size());
for (int eq = 0; eq < (int) equations.size(); eq++)
if (!is_equation_linear[eq])
{
BinaryOpNode *eq_node = equations[eq];
expr_t lhs = eq_node->get_arg1();
result.clear();
lhs->collectDynamicVariables(SymbolType::endogenous, result);
if (result.size() == 1 && result.begin()->second == 0)
{
//check if the endogenous variable has not been already used in an other match !
vector<int>::iterator it = find(endo2eq.begin(), endo2eq.end(), result.begin()->first);
if (it == endo2eq.end())
endo2eq[result.begin()->first] = eq;
else
{
bool_result = false;
break;
}
}
}
return bool_result;
}
void
ModelTree::computePrologueAndEpilogue(const jacob_map_t &static_jacobian_arg, vector<int> &equation_reordered, vector<int> &variable_reordered)
{
......@@ -792,7 +891,7 @@ ModelTree::printBlockDecomposition(const vector<pair<int, int>> &blocks) const
}
block_type_firstequation_size_mfs_t
ModelTree::reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<pair< pair<int, int>, pair<int, int>>> &block_col_type)
ModelTree::reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<pair< pair<int, int>, pair<int, int>>> &block_col_type, bool linear_decomposition)
{
int i = 0;
int count_equ = 0, blck_count_simult = 0;
......@@ -836,14 +935,27 @@ ModelTree::reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_j
int curr_variable = it.first;
int curr_lag = it.second;
auto it1 = find(variable_reordered.begin()+first_count_equ, variable_reordered.begin()+(first_count_equ+Blck_Size), curr_variable);
if (it1 != variable_reordered.begin()+(first_count_equ+Blck_Size))
if (dynamic_jacobian.find({ curr_lag, { equation_reordered[count_equ], curr_variable } }) != dynamic_jacobian.end())
{
if (curr_lag > Lead)
Lead = curr_lag;
else if (-curr_lag > Lag)
Lag = -curr_lag;
if (linear_decomposition)
{
if (dynamic_jacobian.find(make_pair(curr_lag, make_pair(equation_reordered[count_equ], curr_variable))) != dynamic_jacobian.end())
{
if (curr_lag > Lead)
Lead = curr_lag;
else if (-curr_lag > Lag)
Lag = -curr_lag;
}
}
else
{
if (it1 != variable_reordered.begin()+(first_count_equ+Blck_Size))
if (dynamic_jacobian.find({ curr_lag, { equation_reordered[count_equ], curr_variable } }) != dynamic_jacobian.end())
{
if (curr_lag > Lead)
Lead = curr_lag;
else if (-curr_lag > Lag)
Lag = -curr_lag;
}
}
}
}
if ((Lag > 0) && (Lead > 0))
......@@ -939,6 +1051,24 @@ ModelTree::reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_j
return (block_type_size_mfs);
}
vector<bool>
ModelTree::equationLinear(map<pair<int, pair<int, int> >, expr_t> first_order_endo_derivatives) const
{
vector<bool> is_linear(symbol_table.endo_nbr(), true);
for (map<pair<int, pair<int, int> >, expr_t>::const_iterator it = first_order_endo_derivatives.begin(); it != first_order_endo_derivatives.end(); it++)
{
expr_t Id = it->second;
set<pair<int, int> > endogenous;
Id->collectEndogenous(endogenous);
if (endogenous.size() > 0)
{
int eq = it->first.first;
is_linear[eq] = false;
}
}
return is_linear;
}
vector<bool>
ModelTree::BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const
{
......@@ -1106,7 +1236,7 @@ ModelTree::computeThirdDerivatives(const set<int> &vars)
}
void
ModelTree::computeTemporaryTerms(bool is_matlab)
ModelTree::computeTemporaryTerms(bool is_matlab, bool no_tmp_terms)
{
map<expr_t, pair<int, NodeTreeReference>> reference_count;
temporary_terms.clear();
......@@ -1129,6 +1259,11 @@ ModelTree::computeTemporaryTerms(bool is_matlab)
reference_count[v] = { ExprNode::min_cost(is_matlab)+1, NodeTreeReference::residuals };
}
/* When option notmpterms is set, we only need to process model local
variables (and turn them into temporary terms); no need to go further */
if (no_tmp_terms)
return;
map<NodeTreeReference, temporary_terms_t> temp_terms_map;
temp_terms_map[NodeTreeReference::residuals] = temporary_terms_res;
temp_terms_map[NodeTreeReference::firstDeriv] = temporary_terms_g1;
......
......@@ -171,6 +171,9 @@ protected:
//! the file containing the model and the derivatives code
ofstream code_file;
//! Vector indicating if the equation is linear in endogenous variable (true) or not (false)
vector<bool> is_equation_linear;
//! Computes 1st derivatives
/*! \param vars the derivation IDs w.r. to which compute the derivatives */
......@@ -186,7 +189,7 @@ protected:
//! Write derivative of an equation w.r. to a variable
void writeDerivative(ostream &output, int eq, int symb_id, int lag, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
//! Computes temporary terms (for all equations and derivatives)
void computeTemporaryTerms(bool is_matlab);
void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
//! Computes temporary terms for the file containing parameters derivatives
void computeParamsDerivativesTemporaryTerms();
//! Writes temporary terms
......@@ -250,11 +253,17 @@ protected:
If no matching is found with a zero cutoff close to zero an error message is printout.
*/
void computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian, double cutoff, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian);
//! Try to find a natural normalization if all equations are matched to an endogenous variable on the LHS
bool computeNaturalNormalization();
//! Try to normalized each unnormalized equation (matched endogenous variable only on the LHS)
void computeNormalizedEquations(multimap<int, int> &endo2eqs) const;
//! Evaluate the jacobian and suppress all the elements below the cutoff
void evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_map_t &contemporaneous_jacobian, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian, double cutoff, bool verbose);
//! Select and reorder the non linear equations of the model
vector<pair<int, int> > select_non_linear_equations_and_variables(vector<bool> is_equation_linear, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered,
vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered,
lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead,
vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed);
//! Search the equations and variables belonging to the prologue and the epilogue of the model
void computePrologueAndEpilogue(const jacob_map_t &static_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered);
//! Determine the type of each equation of model and try to normalized the unnormalized equation using computeNormalizedEquations
......@@ -262,9 +271,11 @@ protected:
//! Compute the block decomposition and for a non-recusive block find the minimum feedback set
void computeBlockDecompositionAndFeedbackVariablesForEachBlock(const jacob_map_t &static_jacobian, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, bool verbose_, bool select_feedback_variable, int mfs, vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered, lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead_t, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed) const;
//! Reduce the number of block merging the same type equation in the prologue and the epilogue and determine the type of each block
block_type_firstequation_size_mfs_t reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<pair< pair<int, int>, pair<int, int>>> &block_col_type);
block_type_firstequation_size_mfs_t reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<pair< pair<int, int>, pair<int, int>>> &block_col_type, bool linear_decomposition);
//! Determine the maximum number of lead and lag for the endogenous variable in a bloc
void getVariableLeadLagByBlock(const dynamic_jacob_map_t &dynamic_jacobian, const vector<int> &components_set, int nb_blck_sim, lag_lead_vector_t &equation_lead_lag, lag_lead_vector_t &variable_lead_lag, const vector<int> &equation_reordered, const vector<int> &variable_reordered) const;
//! For each equation determine if it is linear or not
vector<bool> equationLinear(map<pair<int, pair<int, int> >, expr_t> first_order_endo_derivatives) const;
//! Print an abstract of the block structure of the model
void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
//! Determine for each block if it is linear or not
......
......@@ -501,13 +501,13 @@ void
ParsingDriver::end_VAR_restrictions(const string &var_model_name)
{
mod_file->addStatement(make_unique<VarRestrictionsStatement>(var_model_name,
var_map,
exclusion_restrictions,
equation_restrictions,
crossequation_restrictions,
covariance_number_restriction,
covariance_pair_restriction,
mod_file->symbol_table));
var_map,
exclusion_restrictions,
equation_restrictions,
crossequation_restrictions,
covariance_number_restriction,
covariance_pair_restriction,
mod_file->symbol_table));
clear_VAR_storage();
}
......@@ -771,6 +771,12 @@ ParsingDriver::block()
mod_file->block = true;
}
void
ParsingDriver::linear_decomposition()
{
mod_file->linear_decomposition = true;
}
void
ParsingDriver::no_static()
{
......@@ -913,7 +919,7 @@ void
ParsingDriver::end_shocks(bool overwrite)
{
mod_file->addStatement(make_unique<ShocksStatement>(overwrite, det_shocks, var_shocks, std_shocks,
covar_shocks, corr_shocks, mod_file->symbol_table));
covar_shocks, corr_shocks, mod_file->symbol_table));
det_shocks.clear();
var_shocks.clear();
std_shocks.clear();
......@@ -1103,10 +1109,10 @@ void
ParsingDriver::end_svar_identification()
{
mod_file->addStatement(make_unique<SvarIdentificationStatement>(svar_ident_restrictions,
svar_upper_cholesky,
svar_lower_cholesky,
svar_constants_exclusion,
mod_file->symbol_table));
svar_upper_cholesky,
svar_lower_cholesky,
svar_constants_exclusion,
mod_file->symbol_table));
svar_restriction_symbols.clear();
svar_equation_restrictions.clear();
svar_ident_restrictions.clear();
......@@ -1511,7 +1517,7 @@ ParsingDriver::var_model()
if (itn != options_list.num_options.end())
order = stoi(itn->second);
else
if (!symbol_list.empty())
if (!symbol_list.empty())
error("You must pass the order option when passing a symbol list to the var_model statement");
vector<string> eqtags;
......@@ -1520,9 +1526,9 @@ ParsingDriver::var_model()
{
eqtags = itvs->second;
if (!symbol_list.empty())
error("You cannot pass a symbol list when passing equation tags to the var_model statement");
error("You cannot pass a symbol list when passing equation tags to the var_model statement");
else if (itn != options_list.num_options.end())
error("You cannot pass the order option when passing equation tags to the var_model statement");
error("You cannot pass the order option when passing equation tags to the var_model statement");
}
mod_file->var_model_table.addVarModel(name, eqtags, make_pair(symbol_list, order));
......@@ -1650,7 +1656,7 @@ ParsingDriver::set_subsamples(string name1, string name2)
check_symbol_existence(name2);
mod_file->addStatement(make_unique<SubsamplesStatement>(name1, name2, subsample_declaration_map,
mod_file->symbol_table));
mod_file->symbol_table));
subsample_declarations[{ move(name1), move(name2) }] = subsample_declaration_map;
subsample_declaration_map.clear();
}
......@@ -1674,7 +1680,7 @@ ParsingDriver::copy_subsamples(string to_name1, string to_name2, string from_nam
}
mod_file->addStatement(make_unique<SubsamplesEqualStatement>(to_name1, to_name2, from_name1, from_name2,
mod_file->symbol_table));
mod_file->symbol_table));
subsample_declarations[{ move(to_name1), move(to_name2) }]
= subsample_declarations[{ move(from_name1), move(from_name2) }];
......@@ -1794,10 +1800,10 @@ ParsingDriver::copy_prior(const string &to_declaration_type, const string &to_na
}
mod_file->addStatement(make_unique<PriorEqualStatement>(to_declaration_type, to_name1,
to_name2, to_subsample_name,
from_declaration_type, from_name1,
from_name2, from_subsample_name,
mod_file->symbol_table));
to_name2, to_subsample_name,
from_declaration_type, from_name1,
from_name2, from_subsample_name,
mod_file->symbol_table));
}
......@@ -1835,10 +1841,10 @@ ParsingDriver::copy_options(const string &to_declaration_type, const string &to_
}
mod_file->addStatement(make_unique<OptionsEqualStatement>(to_declaration_type, to_name1,
to_name2, to_subsample_name,
from_declaration_type, from_name1,
from_name2, from_subsample_name,
mod_file->symbol_table));
to_name2, to_subsample_name,
from_declaration_type, from_name1,
from_name2, from_subsample_name,
mod_file->symbol_table));
}
void
......@@ -1884,7 +1890,7 @@ ParsingDriver::set_std_prior(const string &name, const string &subsample_name)
check_symbol_is_endogenous_or_exogenous(name);
check_subsample_declaration_exists(name, subsample_name);
mod_file->addStatement(make_unique<StdPriorStatement>(name, subsample_name, prior_shape, prior_variance,
options_list, mod_file->symbol_table));
options_list, mod_file->symbol_table));
options_list.clear();
set_prior_variance();
prior_shape = PriorDistributions::noShape;
......@@ -1906,7 +1912,7 @@ ParsingDriver::set_corr_prior(const string &name1, const string &name2, const st
check_symbol_is_endogenous_or_exogenous(name2);
check_subsample_declaration_exists(name1, name2, subsample_name);
mod_file->addStatement(make_unique<CorrPriorStatement>(name1, name2, subsample_name, prior_shape, prior_variance,
options_list, mod_file->symbol_table));
options_list, mod_file->symbol_table));
options_list.clear();
set_prior_variance();
prior_shape = PriorDistributions::noShape;
......@@ -2405,6 +2411,23 @@ ParsingDriver::conditional_forecast_paths()
det_shocks.clear();
}
void
ParsingDriver::det_cond_forecast_linear_decomposition(std::__cxx11::basic_string<char>& plan)
{
symbol_list.clear();
symbol_list.addSymbol(plan);
mod_file->addStatement(make_unique<DetCondForecast>(symbol_list, options_list, mod_file->linear_decomposition));
}
void
ParsingDriver::det_cond_forecast_linear_decomposition(std::__cxx11::basic_string<char>&plan, std::__cxx11::basic_string<char> &dset)
{
symbol_list.clear();
symbol_list.addSymbol(plan);
symbol_list.addSymbol(dset);
mod_file->addStatement(make_unique<DetCondForecast>(symbol_list, options_list, mod_file->linear_decomposition));
}
void
ParsingDriver::calib_smoother()
{
......@@ -3156,7 +3179,7 @@ void
ParsingDriver::end_moment_calibration()
{
mod_file->addStatement(make_unique<MomentCalibration>(moment_calibration_constraints,
mod_file->symbol_table));
mod_file->symbol_table));
moment_calibration_constraints.clear();
}
......@@ -3185,8 +3208,8 @@ void
ParsingDriver::end_irf_calibration()
{
mod_file->addStatement(make_unique<IrfCalibration>(irf_calibration_constraints,
mod_file->symbol_table,
options_list));
mod_file->symbol_table,
options_list));
irf_calibration_constraints.clear();
}
......@@ -3351,7 +3374,7 @@ ParsingDriver::var_expectation_model()
var_expectation_model_discount = data_tree->One;
mod_file->addStatement(make_unique<VarExpectationModelStatement>(model_name, variable, var_model_name, horizon,
var_expectation_model_discount, mod_file->symbol_table));
var_expectation_model_discount, mod_file->symbol_table));
options_list.clear();
var_expectation_model_discount = nullptr;
......
......@@ -323,6 +323,9 @@ public:
void use_dll();
//! the modelis block decomposed
void block();
//! the model is decomposed according to the linearity of its equations
void linear_decomposition();
//! the model is stored in a binary file
void byte_code();
//! the static model is not computed
......@@ -428,6 +431,7 @@ public:
void end_mshocks(bool overwrite);
//! Adds a deterministic shock or a path element inside a conditional_forecast_paths block
void add_det_shock(const string &var, bool conditional_forecast);
//! Adds a std error chock
void add_stderr_shock(const string &var, expr_t value);
//! Adds a variance chock
......@@ -673,6 +677,9 @@ public:
void conditional_forecast_paths();
//! Plot conditional forecast statement
void plot_conditional_forecast(const string &periods = "");
//! Deterministic conditional forecast statement
void det_cond_forecast_linear_decomposition(std::__cxx11::basic_string<char>&plan);
void det_cond_forecast_linear_decomposition(std::__cxx11::basic_string<char>&plan, std::__cxx11::basic_string<char>&dset);
//! Smoother on calibrated models
void calib_smoother();
//! Extended path
......
......@@ -450,13 +450,12 @@ ConditionalForecastPathsStatement::checkPass(ModFileStructure &mod_file_struct,
for (auto elem : elems)
// Period1 < Period2, as enforced in ParsingDriver::add_period()
this_path_length = max(this_path_length, elem.period2);
if (path_length == -1)
path_length = this_path_length;
else if (path_length != this_path_length)
{
cerr << "conditional_forecast_paths: all constrained paths must have the same length!" << endl;
exit(EXIT_FAILURE);
}
path_length = max(this_path_length, path_length);
// else if (path_length != this_path_length)
// {
// cerr << "conditional_forecast_paths: all constrained paths must have the same length!" << endl;
// exit(EXIT_FAILURE);
// }
}
}
......@@ -465,7 +464,7 @@ ConditionalForecastPathsStatement::writeOutput(ostream &output, const string &ba
{
assert(path_length > 0);
output << "constrained_vars_ = [];" << endl
<< "constrained_paths_ = zeros(" << paths.size() << ", " << path_length << ");" << endl;
<< "constrained_paths_ = NaN(" << paths.size() << ", " << path_length << ");" << endl;
int k = 1;
for (auto it = paths.begin();
......@@ -475,7 +474,6 @@ ConditionalForecastPathsStatement::writeOutput(ostream &output, const string &ba
output << "constrained_vars_ = " << symbol_table.getTypeSpecificID(it->first) + 1 << ";" << endl;
else
output << "constrained_vars_ = [constrained_vars_; " << symbol_table.getTypeSpecificID(it->first) + 1 << "];" << endl;
const vector<AbstractShocksStatement::DetShockElement> &elems = it->second;
for (auto elem : elems)
for (int j = elem.period1; j <= elem.period2; j++)
......
......@@ -399,7 +399,7 @@ StaticModel::writeModelEquationsCode(const string &basename, map_idx_t map_idx)
unsigned int instruction_number = 0;
bool file_open = false;
boost::filesystem::create_directories(basename + "/model/bytecode");
boost::filesystem::create_directories(basename + "/model/bytecode");
string main_name = basename + "/model/bytecode/static.cod";
code_file.open(main_name, ios::out | ios::binary | ios::ate);
......@@ -581,7 +581,7 @@ StaticModel::writeModelEquationsCode_Block(const string &basename, map_idx_t map
deriv_node_temp_terms_t tef_terms;
bool file_open = false;
boost::filesystem::create_directories(basename + "/model/bytecode");
boost::filesystem::create_directories(basename + "/model/bytecode");
string main_name = basename + "/model/bytecode/static.cod";
code_file.open(main_name, ios::out | ios::binary | ios::ate);
......@@ -1123,7 +1123,7 @@ StaticModel::computingPass(const eval_context_t &eval_context, bool no_tmp_terms
computeBlockDecompositionAndFeedbackVariablesForEachBlock(static_jacobian, dynamic_jacobian, equation_reordered, variable_reordered, blocks, equation_type_and_normalized_equation, false, false, mfs, inv_equation_reordered, inv_variable_reordered, equation_lag_lead, variable_lag_lead, n_static, n_forward, n_backward, n_mixed);
block_type_firstequation_size_mfs = reduceBlocksAndTypeDetermination(dynamic_jacobian, blocks, equation_type_and_normalized_equation, variable_reordered, equation_reordered, n_static, n_forward, n_backward, n_mixed, block_col_type);
block_type_firstequation_size_mfs = reduceBlocksAndTypeDetermination(dynamic_jacobian, blocks, equation_type_and_normalized_equation, variable_reordered, equation_reordered, n_static, n_forward, n_backward, n_mixed, block_col_type, false);
printBlockDecomposition(blocks);
......@@ -1139,12 +1139,9 @@ StaticModel::computingPass(const eval_context_t &eval_context, bool no_tmp_terms
}
else
{
if (!no_tmp_terms)
{
computeTemporaryTerms(true);
if (bytecode)
computeTemporaryTermsMapping(temporary_terms, map_idx);
}
computeTemporaryTerms(true, no_tmp_terms);
if (bytecode && !no_tmp_terms)
computeTemporaryTermsMapping(temporary_terms, map_idx);
}
}
......@@ -1705,7 +1702,7 @@ StaticModel::writeStaticModel(const string &basename,
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl << endl
<< "## Remarks ##" << endl
<< " [1] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the static model called. The number of temporary variables" << endl
<< " [1] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the static model called. The number of temporary variables" << endl
<< " used for the different returned objects (residuals, jacobian, hessian or third order derivatives) is given by the elements in `tmp_nbr`" << endl
<< " exported vector. The first element is the number of temporaries used for the computation of the residuals, the second element is the" << endl
<< " number of temporaries used for the evaluation of the jacobian matrix, etc. If one calls the version of the static model computing the" << endl
......
......@@ -262,6 +262,9 @@ TrendComponentModelTable::getOrigDiffVar(const string &name_arg) const
void
TrendComponentModelTable::writeOutput(const string &basename, ostream &output) const
{
if (names.empty())
return;
string filename = "+" + basename + "/trend_component_ar_ec.m";
ofstream ar_ec_output;
ar_ec_output.open(filename, ios::out | ios::binary);
......@@ -426,6 +429,9 @@ VarModelTable::getSymbolListAndOrder() const
void
VarModelTable::writeOutput(const string &basename, ostream &output) const
{
if (names.empty())
return;
string filename = "+" + basename + "/var_ar.m";
ofstream ar_output;
ar_output.open(filename, ios::out | ios::binary);
......@@ -498,8 +504,7 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
int eqn, lag, lhs_symb_id;
tie (eqn, lag, lhs_symb_id) = it.first;
int colidx = (int) distance(lhs.begin(), find(lhs.begin(), lhs.end(), lhs_symb_id));
ar_output << " ar(" << eqn + 1 << ", " << colidx + 1 << ", " << lag
<< ") = ";
ar_output << " ar(" << eqn + 1 << ", " << colidx + 1 << ", " << lag << ") = ";
it.second->writeOutput(ar_output, ExprNodeOutputType::matlabDynamicModel);
ar_output << ";" << endl;
}
......
......@@ -68,6 +68,7 @@ class MacroDriver;
%token COMMA DEFINE LINE FOR IN IF ECHO_DIR ERROR IFDEF IFNDEF POWER
%token LPAREN RPAREN LBRACKET RBRACKET EQUAL EOL LENGTH ECHOMACROVARS SAVE
%token SEMICOLON ATSIGN
%token <int> INTEGER
%token <string> NAME STRING
......@@ -88,7 +89,7 @@ class MacroDriver;
%type <vector<string>> comma_name
%type <MacroValuePtr> expr
%type <vector<MacroValuePtr>> comma_expr tuple_comma_expr
%type <vector<MacroValuePtr>> comma_expr tuple_comma_expr comprehension_clause
%%
%start statement_list_or_nothing;
......@@ -217,6 +218,24 @@ expr : INTEGER
{ TYPERR_CATCH($$ = $1->set_intersection($3), @$); }
| expr POWER expr
{ TYPERR_CATCH($$ = $1->power($3), @$); }
| LBRACKET NAME IN expr SEMICOLON
{
driver.init_comprehension(vector<string>{$2}, $4);
driver.iter_comprehension();
}
comprehension_clause RBRACKET
{
$$ = make_shared<ArrayMV>($7);
}
| LBRACKET LPAREN comma_name RPAREN IN expr SEMICOLON
{
driver.init_comprehension($3, $6);
driver.iter_comprehension();
}
comprehension_clause RBRACKET
{
$$ = make_shared<ArrayMV>($9);
}
;
comma_expr : %empty
......@@ -237,6 +256,23 @@ tuple_comma_expr : %empty
{ $1.push_back($3); $$ = $1; }
;
/* The lexer will repeat the comprehension clause as many times as there are
elements in the set to be filtered. It also adds a dummy at-sign (@) at the
end of every repetition (for making parsing of repetitions unambiguous). */
comprehension_clause : expr ATSIGN
{
$$ = vector<MacroValuePtr>{};
driver.possibly_add_comprehension_element($$, $1);
driver.iter_comprehension();
}
| comprehension_clause expr ATSIGN
{
$$ = $1;
driver.possibly_add_comprehension_element($$, $2);
driver.iter_comprehension();
}
;
%%
void
......
......@@ -260,6 +260,79 @@ MacroDriver::iter_loop() noexcept(false)
}
}
void
MacroDriver::init_comprehension(const vector<string> &names, MacroValuePtr value)
{
auto mv = dynamic_pointer_cast<ArrayMV>(value);
if (!mv)
throw MacroValue::TypeError("In a comprehension, the expression after the 'in' keyword must be an array");
comprehension_stack.emplace(names, move(mv), 0);
}
int
MacroDriver::get_comprehension_iter_nb() const
{
assert(!comprehension_stack.empty());
auto &mv = get<1>(comprehension_stack.top());
return mv->values.size();
}
void
MacroDriver::iter_comprehension()
{
assert(!comprehension_stack.empty());
int &i = get<2>(comprehension_stack.top());
auto &mv = get<1>(comprehension_stack.top());
vector<string> &names = get<0>(comprehension_stack.top());
assert(i <= static_cast<int>(mv->values.size()));
if (i == static_cast<int>(mv->values.size()))
comprehension_stack.pop();
else
{
if (names.size() == 1)
env[names.at(0)] = mv->values[i++];
else
{
auto tmv = dynamic_pointer_cast<TupleMV>(mv->values[i++]);
if (!tmv)
throw MacroValue::TypeError("The expression after the 'in' keyword must be an array expression of tuples");
if (tmv->values.size() != names.size())
{
cerr << "Error in comprehension loop: tuple in array contains " << tmv->length()
<< " elements while you are assigning to " << names.size() << " variables."
<< endl;
exit(EXIT_FAILURE);
}
for (auto &name: names)
{
auto idx = &name - &names[0];
env[name] = tmv->values.at(idx);
}
}
}
}
void
MacroDriver::possibly_add_comprehension_element(vector<MacroValuePtr> &v, MacroValuePtr test_expr) const
{
auto ival = dynamic_pointer_cast<IntMV>(test_expr);
if (!ival)
throw MacroValue::TypeError("In a comprehension, the expression after the semicolon must evaluate to an integer");
if (ival->value)
{
assert(!comprehension_stack.empty());
const int &i = get<2>(comprehension_stack.top());
auto &mv = get<1>(comprehension_stack.top());
v.push_back(mv->values.at(i-1));
}
}
void
MacroDriver::begin_if(const MacroValuePtr &value) noexcept(false)
{
......
......@@ -60,12 +60,27 @@ private:
const bool is_for_context;
const string for_body;
const Macro::parser::location_type for_body_loc;
const bool is_comprehension_context;
const string comprehension_clause;
const Macro::parser::location_type comprehension_clause_loc;
const int comprehension_start_condition;
const int comprehension_iter_nb;
ScanContext(istream *input_arg, struct yy_buffer_state *buffer_arg,
Macro::parser::location_type &yylloc_arg, bool is_for_context_arg,
string for_body_arg,
Macro::parser::location_type &for_body_loc_arg) :
Macro::parser::location_type &for_body_loc_arg,
bool is_comprehension_context_arg,
string comprehension_clause_arg,
Macro::parser::location_type &comprehension_clause_loc_arg,
int comprehension_start_condition_arg,
int comprehension_iter_nb_arg) :
input(input_arg), buffer(buffer_arg), yylloc(yylloc_arg), is_for_context(is_for_context_arg),
for_body(move(for_body_arg)), for_body_loc(for_body_loc_arg)
for_body(move(for_body_arg)), for_body_loc(for_body_loc_arg),
is_comprehension_context{is_comprehension_context_arg},
comprehension_clause{comprehension_clause_arg},
comprehension_clause_loc{comprehension_clause_loc_arg},
comprehension_start_condition{comprehension_start_condition_arg},
comprehension_iter_nb{comprehension_iter_nb_arg}
{
}
};
......@@ -114,6 +129,19 @@ private:
//! Set to true while parsing an IF statement (only the statement, not the body)
bool reading_if_statement;
//! Set to true while parsing the comprehension in a new buffer
bool is_comprehension_context{false};
//! Counter for the current comprehension
int comprehension_iter_nb{0};
//! The lexer start condition (EXPR or STMT) before entering the comprehension
int comprehension_start_condition;
//! Number of nested comprehensions, used during the construction of the new lexer buffer
int nested_comprehension_nb{0};
//! Temporary stores for the new lexer buffer
string comprehension_clause, comprehension_clause_tmp;
//! Stores for the location of the comprehension clause
Macro::parser::location_type comprehension_clause_loc, comprehension_clause_loc_tmp;
//! Output the @#line declaration
void output_line(Macro::parser::location_type *yylloc) const;
......@@ -141,6 +169,9 @@ private:
//! Initialise a new flex buffer with the loop body
void new_loop_body_buffer(Macro::parser::location_type *yylloc);
//! Initialize a new flex buffer with the comprehension conditional clause
void new_comprehension_clause_buffer(Macro::parser::location_type *yylloc);
public:
MacroFlex(istream *in, ostream *out, bool no_line_macro_arg, vector<string> path_arg);
......@@ -169,6 +200,8 @@ private:
//! Second is the array over which iteration is done
//! Third is subscript to be used by next call of iter_loop() (beginning with 0) */
stack<tuple<vector<string>, shared_ptr<ArrayMV>, int>> loop_stack;
stack<tuple<vector<string>, shared_ptr<ArrayMV>, int>> comprehension_stack;
public:
//! Exception thrown when value of an unknown variable is requested
class UnknownVariable
......@@ -239,6 +272,15 @@ public:
in that case it destroys the pointer given to init_loop() */
bool iter_loop() noexcept(false);
//! Initializes the evaluation of a comprehension
void init_comprehension(const vector<string> &names, MacroValuePtr value);
//! Iterates during the evaluation of the comprehension
void iter_comprehension();
//! Helper to construct the value corresponding to the comprehension
void possibly_add_comprehension_element(vector<MacroValuePtr> &v, MacroValuePtr test_expr) const;
//! Returns the size of the set over which the current comprehension iterates
int get_comprehension_iter_nb() const;
//! Begins an @#if statement
void begin_if(const MacroValuePtr &value) noexcept(false);
......
......@@ -55,6 +55,7 @@ using token = Macro::parser::token;
%x FOR_BODY
%x THEN_BODY
%x ELSE_BODY
%x COMPREHENSION_CLAUSE
%{
// Increments location counter for every token read
......@@ -238,6 +239,17 @@ CONT \\\\
yylval->build<string>(yytext + 1).pop_back();
return token::STRING;
}
<STMT,EXPR>; {
comprehension_clause_tmp.erase();
nested_comprehension_nb = 0;
// Save start condition (either STMT or EXPR)
comprehension_start_condition = YY_START;
// Save location
comprehension_clause_loc_tmp = *yylloc;
BEGIN(COMPREHENSION_CLAUSE);
return token::SEMICOLON;
}
<EXPR>@ { return token::ATSIGN; } // Used for separation of repeated comprehension clauses
<STMT>line { return token::LINE; }
<STMT>define { return token::DEFINE; }
......@@ -263,7 +275,22 @@ CONT \\\\
return token::NAME;
}
<EXPR><<EOF>> { driver.error(*yylloc, "Unexpected end of file while parsing a macro expression"); }
<EXPR><<EOF>> {
if (!is_comprehension_context)
driver.error(*yylloc, "Unexpected end of file while parsing a macro expression");
else
{
if (--comprehension_iter_nb > 0)
new_comprehension_clause_buffer(yylloc);
else
{
restore_context(yylloc);
BEGIN(comprehension_start_condition);
return token::RBRACKET;
}
}
}
<STMT><<EOF>> { driver.error(*yylloc, "Unexpected end of file while parsing a macro statement"); }
<FOR_BODY>{EOL} { yylloc->lines(1); yylloc->step(); for_body_tmp.append(yytext); }
......@@ -385,6 +412,39 @@ CONT \\\\
}
}
<COMPREHENSION_CLAUSE>{EOL} { driver.error(*yylloc, "Unexpected line break in comprehension"); }
<COMPREHENSION_CLAUSE><<EOF>> { driver.error(*yylloc, "Unexpected end of file in comprehension"); }
<COMPREHENSION_CLAUSE>[^\[\]] { comprehension_clause_tmp.append(yytext); yylloc->step(); }
<COMPREHENSION_CLAUSE>\[ { nested_comprehension_nb++; comprehension_clause_tmp.append(yytext); yylloc->step(); }
<COMPREHENSION_CLAUSE>\] {
yylloc->step();
if (nested_comprehension_nb)
{
nested_comprehension_nb--;
comprehension_clause_tmp.append(yytext);
}
else
{
int comprehension_iter_nb_tmp = driver.get_comprehension_iter_nb();
comprehension_clause_tmp.append(" @ ");
if (comprehension_iter_nb_tmp > 0)
{
// Save old buffer state and location
save_context(yylloc);
is_comprehension_context = true;
comprehension_iter_nb = comprehension_iter_nb_tmp;
comprehension_clause = comprehension_clause_tmp;
comprehension_clause_loc = comprehension_clause_loc_tmp;
new_comprehension_clause_buffer(yylloc);
}
BEGIN(EXPR);
}
}
<INITIAL><<EOF>> {
// Quit lexer if end of main file
if (context_stack.empty())
......@@ -444,7 +504,9 @@ void
MacroFlex::save_context(Macro::parser::location_type *yylloc)
{
context_stack.push(ScanContext(input, YY_CURRENT_BUFFER, *yylloc, is_for_context,
for_body, for_body_loc));
for_body, for_body_loc, is_comprehension_context,
comprehension_clause, comprehension_clause_loc,
comprehension_start_condition, comprehension_iter_nb));
}
void
......@@ -456,10 +518,15 @@ MacroFlex::restore_context(Macro::parser::location_type *yylloc)
is_for_context = context_stack.top().is_for_context;
for_body = context_stack.top().for_body;
for_body_loc = context_stack.top().for_body_loc;
if (!is_comprehension_context)
output_line(yylloc); // Dump @#line instruction
is_comprehension_context = context_stack.top().is_comprehension_context;
comprehension_clause = context_stack.top().comprehension_clause;
comprehension_clause_loc = context_stack.top().comprehension_clause_loc;
comprehension_start_condition = context_stack.top().comprehension_start_condition;
comprehension_iter_nb = context_stack.top().comprehension_iter_nb;
// Remove top of stack
context_stack.pop();
// Dump @#line instruction
output_line(yylloc);
}
void
......@@ -556,6 +623,17 @@ MacroFlex::new_loop_body_buffer(Macro::parser::location_type *yylloc)
yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
}
void
MacroFlex::new_comprehension_clause_buffer(Macro::parser::location_type *yylloc)
{
input = new stringstream(comprehension_clause);
*yylloc = comprehension_clause_loc;
yylloc->begin.filename = yylloc->end.filename = new string(*comprehension_clause_loc.begin.filename);
is_for_context = false;
for_body.clear();
yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
}
/* This implementation of MacroFlexLexer::yylex() is required to fill the
* vtable of the class MacroFlexLexer. We define the scanner's main yylex
* function via YY_DECL to reside in the MacroFlex class instead. */
......