#include <config.h>
#include <graph/Graph.h>
#include <graph/StochasticNode.h>
#include <graph/NodeError.h>
#include <distributions/Distribution.h>
#include <sarray/Index.h>
#include <vector>
#include <stdexcept>
#include <string>
//#include <stdexcept>
using std::vector;
using std::string;
//using std::logic_error;
StochasticNode::StochasticNode(Distribution const *dist, Index const &dim)
: Node(dim), _dist(dist), _parameters()
{
if (dist->isDiscreteValued()) {
data.setDiscreteValued(true);
}
}
StochasticNode::~StochasticNode()
{
}
bool StochasticNode::isBounded() const
{
if (_parameters.empty()) {
return false;
}
else {
return _dist->lowerBound(_parameters) || _dist->upperBound(_parameters);
}
}
SArray const *StochasticNode::lowerBound()
{
return _dist->lowerBound(_parameters);
}
SArray const *StochasticNode::upperBound()
{
return _dist->upperBound(_parameters);
}
void StochasticNode::setBounds(Node *lBound, Node *uBound)
{
Index const &dim = data.dim(true);
if (!_dist->canBound()) {
throw NodeError(this, string("Distribution ") + _dist->name()
+ " cannot be bounded");
}
if (_parameters.empty()) {
throw NodeError(this, "Cannot set bounds before parameters");
}
if ((lBound && lBound->data.dim(true) != dim) ||
(uBound && uBound->data.dim(true) != dim))
{
throw NodeError(this,"Dimension mismatch when setting bounds");
}
if (lBound) {
SArray const *lb = _parameters[_parameters.size() - 2];
if (lb != 0) {
throw NodeError(this, "Attempt to reset lower bound");
}
_parameters[_parameters.size() - 2] = &lBound->data;
addParent(lBound);
}
if (uBound) {
SArray const *ub = _parameters[_parameters.size() - 1];
if (ub != 0) {
throw NodeError(this, "Attempt to reset upper bound");
}
_parameters[_parameters.size() - 1] = &uBound->data;
addParent(uBound);
}
}
Distribution const *StochasticNode::distribution() const
{
return _dist;
}
void StochasticNode::setParameters(vector<Node *> const ¶meters)
{
if (_parameters.size() != 0) {
throw NodeError(this, "Attempt to reset parameters");
}
for (unsigned int i = 0; i < parameters.size(); ++i) {
_parameters.push_back(&(parameters[i]->data));
this->addParent(parameters[i]);
}
// Push back zeros for the upper and lower bounds
if (_dist->canBound()) {
_parameters.push_back(0);
_parameters.push_back(0);
}
if (_parameters.size() != _dist->npar()) {
throw NodeError(this, "Incorrect number of parameters for distribution");
}
if (!_dist->checkParameterDim(_parameters)) {
throw NodeError(this,"Invalid parameter dimensions for distribution");
}
if (_dist->dim(_parameters) != data.dim(true)) {
throw NodeError(this, "Dimension mismatch between parameters and Node");
}
}
double StochasticNode::logDensity() const
{
return _dist->logLikelihood(data, _parameters);
}
vector<SArray const *> const &StochasticNode::parameters() const
{
return _parameters;
}
void StochasticNode::forwardSample()
{
_dist->randomSample(data, _parameters);
}
StochasticNode const *asStochastic(Node const *node)
{
return dynamic_cast<StochasticNode const*>(node);
}
bool StochasticNode::isStochastic() const
{
return true;
/*
if (_parameters.empty())
throw logic_error("Cannot determine if node with no parameters is stochastic");
if (_dist->df(_parameters) == 0) {
//Deterministic distributions are considered stochastic only
//if they are observed, in which case they generate a likelihood.
return isObserved(this);
}
else {
return true;
}
*/
}
syntax highlighted by Code2HTML, v. 0.9.1