#include <config.h>
#include <model/Model.h>
#include <model/TraceMonitor.h>
#include <sampler/Sampler.h>
#include <sampler/SamplerFactory.h>
#include <graph/GraphMarks.h>
#include <graph/StochasticNode.h>
#include <graph/NodeError.h>
#include <graph/Node.h>
#include <fstream>
#include <sstream>
#include <set>
#include <stdexcept>
#include <string>
#include <algorithm>
#include <functional>
#include <map>
#include <Rmath.h>
using std::map;
using std::pair;
using std::binary_function;
using std::sort;
using std::vector;
using std::list;
using std::set;
using std::ofstream;
using std::logic_error;
using std::runtime_error;
using std::string;
using std::ostringstream;
Model::Model()
{
_iteration = 0;
_initialized = false;
_cansample = false;
}
Model::~Model()
{
while(!_samplers.empty()) {
Sampler *sampler = _samplers.back();
delete sampler;
_samplers.pop_back();
}
while(!_monitors.empty()) {
TraceMonitor *monitor = _monitors.back();
delete monitor;
_monitors.pop_back();
}
}
Graph &Model::graph()
{
return _graph;
}
bool Model::isInitialized()
{
return _initialized;
}
void Model::initialize()
{
if (_initialized)
throw logic_error("Model already initialized");
if (!_cansample)
throw logic_error("Graph not checked yet");
/* Count the uninitialized nodes */
unsigned int n = _nodes.size();
for (vector<Node*>::iterator i = _nodes.begin(); i != _nodes.end(); i++)
{
if ((*i)->isInitialized())
n--;
}
for (vector<Node*>::iterator i = _nodes.begin(); i != _nodes.end(); i++)
{
Node *node = *i;
if (!node->isInitialized()) {
node->initialize();
if (!node->isInitialized()) {
throw NodeError(node, "Initialization failure");
}
n--;
}
}
if (n != 0) {
throw logic_error("Model::initialize failed");
}
_initialized = true;
}
void Model::checkGraph()
{
if (_cansample) {
throw logic_error("Already checked ability to sample");
}
if (!_graph.isClosed())
throw runtime_error("Graph not closed");
if (_graph.hasCycle())
throw runtime_error("Directed cycle in graph");
if (_nodes.empty()) {
_graph.getSortedNodes(_nodes);
}
_cansample = true;
}
struct less_sampler {
/*
Comparison operator for Samplers which sorts them according to
the partial ordering defined by the DAG, using the first node
in the vector of nodes sampled by the sampler
*/
map<Node const*, int> const &_node_map;
less_sampler(map<Node const*, int> const &node_map) : _node_map(node_map) {};
bool operator()(Sampler *x, Sampler *y) const {
int indx = _node_map.find(x->nodes()[0])->second;
int indy = _node_map.find(y->nodes()[0])->second;
//return indx < indy; //Forward sampling order
return indx > indy; //Backward sampling order
};
};
void Model::chooseSamplers(vector<SamplerFactory const *> const &samplers)
{
if (!_samplers.empty())
throw logic_error("Samplers already chosen");
if (!_cansample)
throw logic_error("Graph not checked");
// Mark observed nodes
GraphMarks marks(_graph);
vector<Node*>::reverse_iterator i = _nodes.rbegin();
for (; i != _nodes.rend(); ++i) {
if (isObserved(*i)) {
marks.mark(*i,2);
}
}
// Now mark ancestors of observed nodes
for (i = _nodes.rbegin(); i != _nodes.rend(); ++i) {
if (marks.mark(*i) != 2) {
for (set<Node*>::const_iterator ch = (*i)->children().begin();
ch != (*i)->children().end(); ++ch)
{
if (marks.mark(*ch) != 0) {
marks.mark(*i,1);
break;
}
}
}
}
// Create set of unobserved stochastic nodes, for which we need
// to find a sampler, a graph within which sampling will take
// place (excluding uninformative nodes), and a set of "extra"
// uninformative nodes that will be updated by the model at the
// end of every iteration.
set<StochasticNode*> stochastic_nodes;
Graph graph;
for (vector<Node*>::iterator i = _nodes.begin(); i != _nodes.end(); i++) {
switch(marks.mark(*i)) {
case 0:
_extra_nodes.insert(*i);
break;
case 1:
graph.add(*i);
if ((*i)->isStochastic()) {
stochastic_nodes.insert(dynamic_cast<StochasticNode*>(*i));
}
break;
case 2:
graph.add(*i);
break;
}
}
// Traverse the list of samplers, selecting nodes that can be sampled
for (vector<SamplerFactory const *>::const_iterator p = samplers.begin();
p != samplers.end(); ++p)
{
(*p)->makeSampler(stochastic_nodes, graph, _samplers);
}
// Make sure we found a sampler for all the nodes
if (!stochastic_nodes.empty()) {
throw NodeError(*stochastic_nodes.begin(),
"Unable to find appropriate sampler");
}
/**
* Now sort the samplers in order
*
* The map node_map associates each node in the graph with its index
* in the vector of sorted nodes. This is used by the comparison
* operator less_sampler.
*/
static map <Node const *, int> node_map;
int index = 0;
for (vector<Node*>::iterator i = _nodes.begin(); i != _nodes.end(); i++)
{
node_map.insert(pair<Node const*, int>(*i, index));
index++;
}
sort(_samplers.begin(), _samplers.end(), less_sampler(node_map));
}
void Model::update(long niter)
{
if (!_initialized) {
throw logic_error("Attempt to update uninitialized model");
}
for (int iter = 0; iter < niter; ++iter) {
for (vector<Sampler*>::iterator i = _samplers.begin();
i != _samplers.end(); ++i)
{
(*i)->update();
}
for (vector<Node*>::const_iterator k = _sampled_extra.begin();
k != _sampled_extra.end(); ++k)
{
(*k)->forwardSample();
}
_iteration++;
for (list<TraceMonitor*>::iterator k = _monitors.begin();
k != _monitors.end(); k++)
{
(*k)->update(_iteration);
}
}
}
long Model::iteration() const
{
return _iteration;
}
static void addAncestors(Node *node, Graph &to, set<Node*> const &from)
{
// Take ancestors of "node" belonging to set "from" and add them to
// graph "to", along with "node" itself.
if (from.count(node) == 0 || to.contains(node)) {
return;
}
to.add(node);
for (set<Node*>::iterator p = node->parents().begin();
p != node->parents().end(); ++p)
{
addAncestors(*p, to, from);
}
}
TraceMonitor const * Model::setMonitor(Node *node, int thin)
{
if (_monitored_nodes.count(node))
throw NodeError(node, "Node already being monitored");
if (_monitors.empty()) {
// The first monitor: turn off burnin mode.
for (vector<Sampler*>::iterator p = _samplers.begin();
p != _samplers.end(); ++p)
{
(*p)->burninOff();
}
}
TraceMonitor *monitor = new TraceMonitor(node, _iteration + 1, thin);
_monitors.push_back(monitor);
_monitored_nodes.insert(node);
// Recalculate the vector of uninformative nodes that need sampling
Graph egraph;
for (set<Node*>::const_iterator j = _monitored_nodes.begin();
j != _monitored_nodes.end(); ++j)
{
addAncestors(*j, egraph, _extra_nodes);
}
_sampled_extra.clear();
egraph.getSortedNodes(_sampled_extra);
return monitor;
}
void Model::clearMonitor(Node const *node)
{
for (list<TraceMonitor*>::iterator j = _monitors.begin();
j != _monitors.end(); j++)
{
if ((*j)->node() == node) {
_monitors.erase(j);
return;
}
}
}
static string printIndex (string const &name, Index const &index)
{
ostringstream ostr;
ostr << name << "[";
for (unsigned int i = 0; i < index.size(); ++i) {
if (i > 0)
ostr << ",";
ostr << index[i];
}
ostr << "]";
return ostr.str();
}
list<TraceMonitor*> const &Model::monitors() const
{
return _monitors;
}
void Model::addExtraNode(Node *node)
{
if (!_initialized)
throw logic_error("Attempt to add extra node to uninitialized model");
if (isObserved(node)) {
throw logic_error("Cannot add observed node to initialized model");
}
if (!node->children().empty()) {
throw logic_error("Cannot add extra node with children");
}
if (_graph.contains(node)) {
throw logic_error("Extra node already in model");
}
for (set<Node*>::const_iterator p = node->parents().begin();
p != node->parents().end(); ++p)
{
if (!_graph.contains(*p)) {
throw logic_error("Extra node has parents not in model");
}
}
_extra_nodes.insert(node);
_graph.add(node);
}
syntax highlighted by Code2HTML, v. 0.9.1