trunk preprocessor: added new option "block_mfs" to "steady"

* normalizes the static model
* computes its block decomposition, using topological order
* for each block, computes minimum feedback set of variables
* at this stage, only produces text output (no change in the computation of steady state)


git-svn-id: https://www.dynare.org/svn/dynare/trunk@2798 ac1d8469-bf42-47a9-8791-bf33cf982152
time-shift
sebastien 2009-06-30 15:07:09 +00:00
parent 1f22698295
commit 62f6368a19
9 changed files with 235 additions and 38 deletions

View File

@ -32,6 +32,13 @@ SteadyStatement::SteadyStatement(const OptionsList &options_list_arg) :
{ {
} }
void
SteadyStatement::checkPass(ModFileStructure &mod_file_struct)
{
if (options_list.num_options.find("block_mfs") != options_list.num_options.end())
mod_file_struct.steady_block_mfs_option = true;
}
void void
SteadyStatement::writeOutput(ostream &output, const string &basename) const SteadyStatement::writeOutput(ostream &output, const string &basename) const
{ {
@ -904,7 +911,7 @@ PlannerObjectiveStatement::checkPass(ModFileStructure &mod_file_struct)
void void
PlannerObjectiveStatement::computingPass() PlannerObjectiveStatement::computingPass()
{ {
model_tree->computingPass(true, false); model_tree->computingPass(false, true, false);
} }
void void

View File

@ -34,6 +34,7 @@ private:
const OptionsList options_list; const OptionsList options_list;
public: public:
SteadyStatement(const OptionsList &options_list_arg); SteadyStatement(const OptionsList &options_list_arg);
virtual void checkPass(ModFileStructure &mod_file_struct);
virtual void writeOutput(ostream &output, const string &basename) const; virtual void writeOutput(ostream &output, const string &basename) const;
}; };

View File

@ -87,7 +87,7 @@ class ParsingDriver;
%} %}
%token AR AUTOCORR %token AR AUTOCORR
%token BAYESIAN_IRF BETA_PDF BICGSTAB %token BAYESIAN_IRF BETA_PDF BICGSTAB BLOCK_MFS
%token BVAR_DENSITY BVAR_FORECAST %token BVAR_DENSITY BVAR_FORECAST
%token BVAR_PRIOR_DECAY BVAR_PRIOR_FLAT BVAR_PRIOR_LAMBDA %token BVAR_PRIOR_DECAY BVAR_PRIOR_FLAT BVAR_PRIOR_LAMBDA
%token BVAR_PRIOR_MU BVAR_PRIOR_OMEGA BVAR_PRIOR_TAU BVAR_PRIOR_TRAIN %token BVAR_PRIOR_MU BVAR_PRIOR_OMEGA BVAR_PRIOR_TAU BVAR_PRIOR_TRAIN
@ -631,6 +631,7 @@ steady_options_list : steady_options_list COMMA steady_options
steady_options : o_solve_algo steady_options : o_solve_algo
| o_homotopy_mode | o_homotopy_mode
| o_homotopy_steps | o_homotopy_steps
| o_block_mfs
; ;
check : CHECK ';' check : CHECK ';'
@ -1434,6 +1435,7 @@ o_gsa_trans_ident : TRANS_IDENT EQUAL INT_NUMBER { driver.option_num("trans_iden
o_homotopy_mode : HOMOTOPY_MODE EQUAL INT_NUMBER {driver.option_num("homotopy_mode",$3); }; o_homotopy_mode : HOMOTOPY_MODE EQUAL INT_NUMBER {driver.option_num("homotopy_mode",$3); };
o_homotopy_steps : HOMOTOPY_STEPS EQUAL INT_NUMBER {driver.option_num("homotopy_steps",$3); }; o_homotopy_steps : HOMOTOPY_STEPS EQUAL INT_NUMBER {driver.option_num("homotopy_steps",$3); };
o_block_mfs : BLOCK_MFS { driver.option_num("block_mfs", "1"); }
range : NAME ':' NAME range : NAME ':' NAME
{ {

View File

@ -216,6 +216,7 @@ int sigma_e = 0;
<DYNARE_STATEMENT>filename {return token::FILENAME;} <DYNARE_STATEMENT>filename {return token::FILENAME;}
<DYNARE_STATEMENT>diffuse_filter {return token::DIFFUSE_FILTER;} <DYNARE_STATEMENT>diffuse_filter {return token::DIFFUSE_FILTER;}
<DYNARE_STATEMENT>plot_priors {return token::PLOT_PRIORS;} <DYNARE_STATEMENT>plot_priors {return token::PLOT_PRIORS;}
<DYNARE_STATEMENT>block_mfs {return token::BLOCK_MFS;}
/* These four (var, varexo, varexo_det, parameters) are for change_type */ /* These four (var, varexo, varexo_det, parameters) are for change_type */
<DYNARE_STATEMENT>var { return token::VAR; } <DYNARE_STATEMENT>var { return token::VAR; }

View File

@ -144,7 +144,7 @@ ModFile::computingPass(bool no_tmp_terms)
{ {
// Compute static model and its derivatives // Compute static model and its derivatives
dynamic_model.toStatic(static_model); dynamic_model.toStatic(static_model);
static_model.computingPass(false, no_tmp_terms); static_model.computingPass(mod_file_struct.steady_block_mfs_option, false, no_tmp_terms);
// Set things to compute for dynamic model // Set things to compute for dynamic model

View File

@ -30,7 +30,8 @@ ModFileStructure::ModFileStructure() :
order_option(0), order_option(0),
bvar_density_present(false), bvar_density_present(false),
bvar_forecast_present(false), bvar_forecast_present(false),
identification_present(false) identification_present(false),
steady_block_mfs_option(false)
{ {
} }

View File

@ -56,6 +56,8 @@ public:
bool bvar_forecast_present; bool bvar_forecast_present;
//! Whether an identification statement is present //! Whether an identification statement is present
bool identification_present; bool identification_present;
//! Whether the option "block_mfs" is used on steady statement
bool steady_block_mfs_option;
}; };
class Statement class Statement

View File

@ -20,18 +20,22 @@
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <cassert>
#include <deque>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
/* #ifdef DEBUG
#include <ext/functional> # include <ext/functional>
using namespace __gnu_cxx; using namespace __gnu_cxx;
*/ #endif
#include <boost/graph/adjacency_list.hpp> #include <boost/graph/adjacency_list.hpp>
#include <boost/graph/max_cardinality_matching.hpp> #include <boost/graph/max_cardinality_matching.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/topological_sort.hpp>
#include "StaticModel.hh" #include "StaticModel.hh"
#include "MinimumFeedbackSet.hh"
using namespace boost; using namespace boost;
@ -298,7 +302,7 @@ StaticModel::writeStaticFile(const string &basename) const
} }
void void
StaticModel::computingPass(bool hessian, bool no_tmp_terms) StaticModel::computingPass(bool block_mfs, bool hessian, bool no_tmp_terms)
{ {
// Compute derivatives w.r. to all endogenous // Compute derivatives w.r. to all endogenous
set<int> vars; set<int> vars;
@ -319,24 +323,17 @@ StaticModel::computingPass(bool hessian, bool no_tmp_terms)
if (!no_tmp_terms) if (!no_tmp_terms)
computeTemporaryTerms(); computeTemporaryTerms();
/* if (block_mfs)
vector<int> endo2eq(equation_number());
computeNormalization(endo2eq);
multimap<int, int> natural_endo2eqs;
computeNormalizedEquations(natural_endo2eqs);
for(int i = 0; i < symbol_table.endo_nbr(); i++)
{ {
if (natural_endo2eqs.count(i) == 0) vector<int> endo2eq(equation_number());
continue; computeNormalization(endo2eq);
pair<multimap<int, int>::const_iterator, multimap<int, int>::const_iterator> x = natural_endo2eqs.equal_range(i); vector<set<int> > blocks;
if (find_if(x.first, x.second, compose1(bind2nd(equal_to<int>(), endo2eq[i]), select2nd<multimap<int, int>::value_type>())) == x.second) computeSortedBlockDecomposition(blocks, endo2eq);
cout << "Natural normalization of variable " << symbol_table.getName(symbol_table.getID(eEndogenous, i))
<< " not used." << endl; vector<set<int> > blocksMFS;
computeMFS(blocksMFS, blocks, endo2eq);
} }
*/
} }
int int
@ -358,9 +355,9 @@ StaticModel::getDerivID(int symb_id, int lag) const throw (UnknownDerivIDExcepti
} }
void void
StaticModel::computeNormalization(vector<int> &endo_to_eq) const StaticModel::computeNormalization(vector<int> &endo2eq) const
{ {
int n = equation_number(); const int n = equation_number();
assert(n == symbol_table.endo_nbr()); assert(n == symbol_table.endo_nbr());
@ -384,15 +381,42 @@ StaticModel::computeNormalization(vector<int> &endo_to_eq) const
} }
// Compute maximum cardinality matching // Compute maximum cardinality matching
typedef vector<graph_traits<BipartiteGraph>::vertex_descriptor> mate_map_t; vector<int> mate_map(2*n);
mate_map_t mate_map(2*n);
#if 1
bool check = checked_edmonds_maximum_cardinality_matching(g, &mate_map[0]); bool check = checked_edmonds_maximum_cardinality_matching(g, &mate_map[0]);
#else // Alternative way to compute normalization, by giving an initial matching using natural normalizations
fill(mate_map.begin(), mate_map.end(), graph_traits<BipartiteGraph>::null_vertex());
multimap<int, int> natural_endo2eqs;
computeNormalizedEquations(natural_endo2eqs);
for(int i = 0; i < symbol_table.endo_nbr(); i++)
{
if (natural_endo2eqs.count(i) == 0)
continue;
int j = natural_endo2eqs.find(i)->second;
put(&mate_map[0], i, n+j);
put(&mate_map[0], n+j, i);
}
edmonds_augmenting_path_finder<BipartiteGraph, size_t *, property_map<BipartiteGraph, vertex_index_t>::type> augmentor(g, &mate_map[0], get(vertex_index, g));
bool not_maximum_yet = true;
while(not_maximum_yet)
{
not_maximum_yet = augmentor.augment_matching();
}
augmentor.get_current_matching(&mate_map[0]);
bool check = maximum_cardinality_matching_verifier<BipartiteGraph, size_t *, property_map<BipartiteGraph, vertex_index_t>::type>::verify_matching(g, &mate_map[0], get(vertex_index, g));
#endif
assert(check); assert(check);
// Check if all variables are normalized // Check if all variables are normalized
mate_map_t::const_iterator it = find(mate_map.begin(), mate_map.begin() + n, graph_traits<BipartiteGraph>::null_vertex()); vector<int>::const_iterator it = find(mate_map.begin(), mate_map.begin() + n, graph_traits<BipartiteGraph>::null_vertex());
if (it != mate_map.begin() + n) if (it != mate_map.begin() + n)
{ {
cerr << "ERROR: Could not normalize static model. Variable " cerr << "ERROR: Could not normalize static model. Variable "
@ -401,18 +425,44 @@ StaticModel::computeNormalization(vector<int> &endo_to_eq) const
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifdef DEBUG
for(int i = 0; i < n; i++) for(int i = 0; i < n; i++)
cout << "Endogenous " << symbol_table.getName(symbol_table.getID(eEndogenous, i)) cout << "Endogenous " << symbol_table.getName(symbol_table.getID(eEndogenous, i))
<< " matched with equation " << (mate_map[i]-n+1) << endl; << " matched with equation " << (mate_map[i]-n+1) << endl;
#endif
assert((int) endo_to_eq.size() == n); assert((int) endo2eq.size() == n);
// Create the resulting map, by copying the n first elements of mate_map, and substracting n to them // Create the resulting map, by copying the n first elements of mate_map, and substracting n to them
transform(mate_map.begin(), mate_map.begin() + n, endo_to_eq.begin(), bind2nd(minus<int>(), n)); transform(mate_map.begin(), mate_map.begin() + n, endo2eq.begin(), bind2nd(minus<int>(), n));
#ifdef DEBUG
multimap<int, int> natural_endo2eqs;
computeNormalizedEquations(natural_endo2eqs);
int n1 = 0, n2 = 0;
for(int i = 0; i < symbol_table.endo_nbr(); i++)
{
if (natural_endo2eqs.count(i) == 0)
continue;
n1++;
pair<multimap<int, int>::const_iterator, multimap<int, int>::const_iterator> x = natural_endo2eqs.equal_range(i);
if (find_if(x.first, x.second, compose1(bind2nd(equal_to<int>(), endo2eq[i]), select2nd<multimap<int, int>::value_type>())) == x.second)
cout << "Natural normalization of variable " << symbol_table.getName(symbol_table.getID(eEndogenous, i))
<< " not used." << endl;
else
n2++;
}
cout << "Used " << n2 << " natural normalizations out of " << n1 << ", for a total of " << n << " equations." << endl;
#endif
} }
void void
StaticModel::computeNormalizedEquations(multimap<int, int> &endo_to_eqs) const StaticModel::computeNormalizedEquations(multimap<int, int> &endo2eqs) const
{ {
for(int i = 0; i < equation_number(); i++) for(int i = 0; i < equation_number(); i++)
{ {
@ -429,7 +479,7 @@ StaticModel::computeNormalizedEquations(multimap<int, int> &endo_to_eqs) const
if (endo.find(make_pair(symb_id, 0)) != endo.end()) if (endo.find(make_pair(symb_id, 0)) != endo.end())
continue; continue;
endo_to_eqs.insert(make_pair(symbol_table.getTypeSpecificID(symb_id), i)); endo2eqs.insert(make_pair(symbol_table.getTypeSpecificID(symb_id), i));
cout << "Endogenous " << symbol_table.getName(symb_id) << " normalized in equation " << (i+1) << endl; cout << "Endogenous " << symbol_table.getName(symb_id) << " normalized in equation " << (i+1) << endl;
} }
} }
@ -439,3 +489,120 @@ StaticModel::writeLatexFile(const string &basename) const
{ {
writeLatexModelFile(basename + "_static.tex", oLatexStaticModel); writeLatexModelFile(basename + "_static.tex", oLatexStaticModel);
} }
void
StaticModel::computeSortedBlockDecomposition(vector<set<int> > &blocks, const vector<int> &endo2eq) const
{
const int n = equation_number();
assert((int) endo2eq.size() == n);
// Compute graph representation of static model
typedef adjacency_list<vecS, vecS, directedS> DirectedGraph;
DirectedGraph g(n);
set<pair<int, int> > endo;
for(int i = 0; i < n; i++)
{
endo.clear();
equations[endo2eq[i]]->collectEndogenous(endo);
for(set<pair<int, int> >::const_iterator it = endo.begin();
it != endo.end(); it++)
add_edge(symbol_table.getTypeSpecificID(it->first), i, g);
}
// Compute strongly connected components
vector<int> endo2block(n);
int m = strong_components(g, &endo2block[0]);
// Create directed acyclic graph associated to the strongly connected components
DirectedGraph dag(m);
graph_traits<DirectedGraph>::edge_iterator ei, ei_end;
for(tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
{
int s = endo2block[source(*ei, g)];
int t = endo2block[target(*ei, g)];
if (s != t)
add_edge(s, t, dag);
}
// Compute topological sort of DAG (ordered list of unordered SCC)
deque<int> ordered2unordered;
topological_sort(dag, front_inserter(ordered2unordered)); // We use a front inserter because topological_sort returns the inverse order
// Construct mapping from unordered SCC to ordered SCC
vector<int> unordered2ordered(m);
for(int i = 0; i < m; i++)
unordered2ordered[ordered2unordered[i]] = i;
// Fill in data structure representing blocks
blocks.clear();
blocks.resize(m);
for(int i = 0; i < n; i++)
blocks[unordered2ordered[endo2block[i]]].insert(i);
#ifdef DEBUG
cout << "Found " << m << " blocks" << endl;
for(int i = 0; i < m; i++)
cout << " Block " << i << " of size " << blocks[i].size() << endl;
#endif
}
void
StaticModel::computeMFS(vector<set<int> > &blocksMFS, const vector<set<int> > &blocks, const vector<int> &endo2eq) const
{
const int n = equation_number();
assert((int) endo2eq.size() == n);
const int nblocks = blocks.size();
blocksMFS.clear();
blocksMFS.resize(nblocks);
// Iterate over blocks
for(int b = 0; b < nblocks; b++)
{
// Construct subgraph for MFS computation, where vertex number is position in the block
int p = blocks[b].size();
MFS::AdjacencyList_type g(p);
// Construct v_index and v_index1 properties, and a mapping between type specific IDs and vertex descriptors
property_map<MFS::AdjacencyList_type, vertex_index_t>::type v_index = get(vertex_index, g);
property_map<MFS::AdjacencyList_type, vertex_index1_t>::type v_index1 = get(vertex_index1, g);
map<int, graph_traits<MFS::AdjacencyList_type>::vertex_descriptor> tsid2vertex;
int j = 0;
for(set<int>::const_iterator it = blocks[b].begin(); it != blocks[b].end(); ++it)
{
tsid2vertex[*it] = vertex(j, g);
put(v_index, vertex(j, g), *it);
put(v_index1, vertex(j, g), *it);
j++;
}
// Add edges, loop over endogenous in the block
set<pair<int, int> > endo;
for(set<int>::const_iterator it = blocks[b].begin(); it != blocks[b].end(); ++it)
{
endo.clear();
// Test if associated equation is in normalized form, and compute set of endogenous appearing in it
ExprNode *lhs = equations[endo2eq[*it]]->get_arg1();
VariableNode *lhs_var = dynamic_cast<VariableNode *>(lhs);
if (lhs_var == NULL || lhs_var->get_symb_id() != symbol_table.getID(eEndogenous, *it))
lhs->collectEndogenous(endo); // Only collect endogenous of LHS if not normalized form
ExprNode *rhs = equations[endo2eq[*it]]->get_arg2();
rhs->collectEndogenous(endo);
for(set<pair<int, int> >::const_iterator it2 = endo.begin();
it2 != endo.end(); ++it2)
{
const int tsid = symbol_table.getTypeSpecificID(it2->first);
if (blocks[b].find(tsid) != blocks[b].end()) // Add edge only if vertex member of this block
add_edge(tsid2vertex[tsid], tsid2vertex[*it], g);
}
}
// Compute minimum feedback set
MFS::Minimal_set_of_feedback_vertex(blocksMFS[b], g);
cout << "Block " << b << ": " << blocksMFS[b].size() << "/" << blocks[b].size() << " in MFS" << endl;
}
}

View File

@ -38,20 +38,36 @@ private:
virtual int computeDerivID(int symb_id, int lag); virtual int computeDerivID(int symb_id, int lag);
//! Computes normalization of the static model //! Computes normalization of the static model
/*! Maps each endogenous type specific ID to the equation which defines it */ /*! Maps each endogenous type specific ID to the equation to which it is associated */
void computeNormalization(vector<int> &endo_to_eq) const; void computeNormalization(vector<int> &endo2eq) const;
//! Computes blocks of the static model, sorted in topological order
/*!
\param blocks ordered list of blocks, each one containing a list of type specific IDs of endogenous variables
\param endo2eq chosen normalization (mapping from type specific IDs of endogenous to equations)
*/
void computeSortedBlockDecomposition(vector<set<int> > &blocks, const vector<int> &endo2eq) const;
//! For each block of the static model, computes minimum feedback set (MFS)
/*!
\param blocksMFS for each block, contains the subset of type specific IDs which are in the MFS
\param blocks ordered list of blocks, each one containing a list of type specific IDs of endogenous variables
\param endo2eq chosen normalization (mapping from type specific IDs of endogenous to equations)
*/
void computeMFS(vector<set<int> > &blocksMFS, const vector<set<int> > &blocks, const vector<int> &endo2eq) const;
//! Computes the list of equations which are already in normalized form //! Computes the list of equations which are already in normalized form
/*! Returns a multimap mapping endogenous which are normalized (represented by their type specific ID) to the equation(s) which define it */ /*! Returns a multimap mapping endogenous which are normalized (represented by their type specific ID) to the equation(s) which define it */
void computeNormalizedEquations(multimap<int, int> &endo_to_eqs) const; void computeNormalizedEquations(multimap<int, int> &endo2eqs) const;
public: public:
StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants);
//! Execute computations (derivation) //! Execute computations (derivation)
/*! You must set computeStaticHessian before calling this function /*!
\param block_mfs whether block decomposition and minimum feedback set should be computed
\param hessian whether Hessian (w.r. to endogenous only) should be computed \param hessian whether Hessian (w.r. to endogenous only) should be computed
\param no_tmp_terms if true, no temporary terms will be computed in the static and dynamic files */ \param no_tmp_terms if true, no temporary terms will be computed in the static and dynamic files */
void computingPass(bool hessian, bool no_tmp_terms); void computingPass(bool block_mfs, bool hessian, bool no_tmp_terms);
//! Writes static model file //! Writes static model file
void writeStaticFile(const string &basename) const; void writeStaticFile(const string &basename) const;