#include <config.h>
#include <distributions/DMNorm.h>
#include <matrix/lapack.h>
#include <matrix/matrix.h>
#include <sarray/SArray.h>
#include <cmath>
#include <vector>
#include <stdexcept>
#include <Rmath.h>
using std::vector;
using std::logic_error;
DMNorm::DMNorm()
: Distribution("dmnorm", 2, false, false)
{}
DMNorm::~DMNorm()
{}
double DMNorm::logLikelihood(SArray const &x,
vector<SArray const *> const ¶meters) const
{
double const *y = x.value();
int m = parameters[0]->length();
double const * mu = parameters[0]->value();
double const * T = parameters[1]->value();
double loglik = logdet(T, m)/2;
double * delta = new double[m];
for (int i = 0; i < m; ++i) {
delta[i] = y[i] - mu[i];
loglik -= (delta[i] * T[i + i * m] * delta[i])/2;
for (int j = 0; j < i; ++j) {
loglik -= (delta[i] * T[i + j * m] * delta[j]);
}
}
delete [] delta;
return loglik;
}
void DMNorm::randomSample(SArray &x,
vector<SArray const *> const ¶meters) const
{
double const * mu = parameters[0]->value();
double const * T = parameters[1]->value();
int nrow = parameters[0]->length();
double *y = new double[nrow];
randomsample(y, mu, T, nrow);
x.setValue(y, nrow);
delete [] y;
}
void DMNorm::randomsample(double *x, double const *mu, double const *T,
int nrow)
{
int N = nrow*nrow;
double * Tcopy = new double[N];
for (int i = 0; i < N; ++i) {
Tcopy[i] = T[i];
}
double * w = new double[nrow];
int info = 0;
double worktest;
int lwork = -1;
// Workspace query
F77_DSYEV ("V", "L", &nrow, Tcopy, &nrow, w, &worktest, &lwork, &info);
// Now get eigenvalues/vectors with optimal work space
lwork = static_cast<int>(worktest + DBL_EPSILON);
double * work = new double[lwork];
F77_DSYEV ("V", "L", &nrow, Tcopy, &nrow, w, work, &lwork, &info);
delete [] work;
/* Generate independent random normal variates, scaled by
the eigen values. We reuse the array w. */
for (int i = 0; i < nrow; ++i) {
w[i] = rnorm(0, 1/sqrt(w[i]));
}
/* Now transform them to dependant variates
(On exit from DSYEV, Tcopy contains the eigenvectors)
*/
for (int i = 0; i < nrow; ++i) {
x[i] = mu[i];
for (int j = 0; j < nrow; ++j) {
x[i] += Tcopy[i + j * nrow] * w[j];
}
}
delete [] w;
delete [] Tcopy;
}
bool DMNorm::checkParameterDim(vector<SArray const *> const ¶meters) const
{
Index const &dim0 = parameters[0]->dim(true);
Index const &dim1 = parameters[1]->dim(true);
if (dim0.size() != 1)
return false;
if (dim1.size() != 2)
return false;
if (dim1[0] != dim1[1] || dim0[0] != dim1[0]) {
return false;
}
return true;
}
Index const &DMNorm::dim(vector<SArray const *> const ¶meters) const
{
return parameters[0]->dim(true);
}
bool DMNorm::checkParameterValue(vector<SArray const *> const ¶meters) const
{
long n = parameters[0]->length();
double const *T = parameters[1]->value();
// Check symmetry
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (fabs(T[i + j*n] - T[j + i*n]) > DBL_EPSILON)
return false;
}
}
// Don't bother checking positive definiteness
return true;
}
unsigned long DMNorm::df(std::vector<SArray const *> const ¶meters) const
{
return parameters[0]->length();
}
double
DMNorm::lowerSupport(unsigned long i,
std::vector<SArray const *> const ¶meters) const
{
unsigned long m = parameters[0]->length();
if (i >= m)
throw logic_error("Invalid index in DMNorm::lowerSupport");
return -DBL_MAX;
}
double
DMNorm::upperSupport(unsigned long i,
std::vector<SArray const *> const ¶meters) const
{
unsigned long m = parameters[0]->length();
if (i >= m)
throw logic_error("Invalid index in DMNorm::upperSupport");
return DBL_MAX;
}
syntax highlighted by Code2HTML, v. 0.9.1