#include <config.h>
#include <distributions/DMulti.h>
#include <sarray/SArray.h>
#include <stdexcept>
#include <cmath>
#include <Rmath.h>
using std::vector;
using std::length_error;
using std::logic_error;
static inline double const *PROB(vector<SArray const *> const ¶meters)
{
return parameters[0]->value();
}
static inline unsigned long LENGTH(vector<SArray const *> const ¶meters)
{
return parameters[0]->length();
}
static inline double SIZE(vector<SArray const *> const ¶meters)
{
return *parameters[1]->value();
}
DMulti::DMulti()
: Distribution("dmulti", 2, false, true)
{}
DMulti::~DMulti()
{}
bool DMulti::checkParameterDim(vector<SArray const *> const ¶meters) const
{
//Check that PROB is a vector
if (parameters[0]->ndim(true) != 1 || parameters[0]->length() <= 1)
return false;
//Check that SIZE is a discrete-valued scalar
if (parameters[1]->length() != 1 || !parameters[1]->isDiscreteValued())
return false;
return true;
}
bool DMulti::checkParameterValue(vector<SArray const *> const &par) const
{
double const *prob = PROB(par);
unsigned long length = LENGTH(par);
if (SIZE(par) < 1)
return false;
double sump = 0.0;
for (unsigned long i = 0; i < length; i++) {
if (prob[i] < 0 || prob[i] > 1)
return false;
sump += prob[i];
}
if (fabs(sump - 1.0) > 1.0E-6)
return false;
return true;
}
double DMulti::logLikelihood(SArray const &x,
vector<SArray const *> const &par) const
{
double const *y = x.value();
double const *prob = PROB(par);
unsigned long length = LENGTH(par);
double loglik = 0.0;
double ysum = 0.0;
for (unsigned long i = 0; i < length; i++) {
if (prob[i] == 0) {
if (y[i] != 0)
return -DBL_MAX;
}
else if (y[i] != 0) {
loglik += y[i] * log(prob[i]) - lgamma(y[i] + 1);
ysum += y[i];
}
}
loglik += lgamma(ysum + 1);
return loglik;
}
void DMulti::randomSample(SArray &x,
vector<SArray const *> const &par) const
{
unsigned long length = LENGTH(par);
/* Sample multinomial as a series of binomial distributions */
double *y = new double[length];
double N = SIZE(par);
double sump = 1.0;
double const *prob = PROB(par);
for (unsigned long i = 0; i < length - 1; i++) {
if (N == 0) {
y[i] = 0;
}
else {
y[i] = rbinom(N, prob[i]/sump);
N -= y[i];
sump -= prob[i];
}
}
y[length - 1] = N;
x.setValue(y, length);
delete [] y;
}
unsigned long DMulti::df(std::vector<SArray const *> const &par) const
{
unsigned long length = LENGTH(par);
double const *prob = PROB(par);
//FIXME: Should we allow structural zeros only for fixed p, as in DDirch?
unsigned long df = length - 1;
for (unsigned long i = 0; i < length; ++i) {
if (df == 0) {
throw logic_error("Bad degrees of freedom in DMulti");
}
else {
df -= (prob[i] == 0);
}
}
return df;
}
double
DMulti::lowerSupport(unsigned long i,
std::vector<SArray const *> const &par) const
{
if (i >= LENGTH(par))
throw logic_error("Invalid index in DMulti::lowerSupport");
return 0.0;
}
double
DMulti::upperSupport(unsigned long i,
std::vector<SArray const *> const &par) const
{
if (i >= LENGTH(par))
throw logic_error("Invalid index in DMulti::upperSupport");
return DBL_MAX;
}
Index const &
DMulti::dim(std::vector<SArray const *> const &par) const
{
return par[0]->dim(true);
}
syntax highlighted by Code2HTML, v. 0.9.1