Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
119 lines (107 sloc) 3.51 KB
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 2012-2016 The R Core Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.R-project.org/Licenses/
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <string.h> // memset, memcpy
#include <R.h>
#include <Rinternals.h>
#include <Rmath.h>
#include <R_ext/Lapack.h> /* for Lapack (dpotrf, etc.) and BLAS */
#include "stats.h" // for _()
#include "statsR.h"
/**
* Simulate the Cholesky factor of a standardized Wishart variate with
* dimension p and nu degrees of freedom.
*
* @param nu degrees of freedom
* @param p dimension of the Wishart distribution
* @param upper if 0 the result is lower triangular, otherwise upper
triangular
* @param ans array of size p * p to hold the result
*
* @return ans
*/
static double
*std_rWishart_factor(double nu, int p, int upper, double ans[])
{
int pp1 = p + 1;
if (nu < (double) p || p <= 0)
error(_("inconsistent degrees of freedom and dimension"));
memset(ans, 0, p * p * sizeof(double));
for (int j = 0; j < p; j++) { /* jth column */
ans[j * pp1] = sqrt(rchisq(nu - (double) j));
for (int i = 0; i < j; i++) {
int uind = i + j * p, /* upper triangle index */
lind = j + i * p; /* lower triangle index */
ans[(upper ? uind : lind)] = norm_rand();
ans[(upper ? lind : uind)] = 0;
}
}
return ans;
}
/**
* Simulate a sample of random matrices from a Wishart distribution
*
* @param ns Number of samples to generate
* @param nuP Degrees of freedom
* @param scal Positive-definite scale matrix
*
* @return
*/
SEXP
rWishart(SEXP ns, SEXP nuP, SEXP scal)
{
SEXP ans;
int *dims = INTEGER(getAttrib(scal, R_DimSymbol)), info,
n = asInteger(ns), psqr;
double *scCp, *ansp, *tmp, nu = asReal(nuP), one = 1, zero = 0;
if (!isMatrix(scal) || !isReal(scal) || dims[0] != dims[1])
error(_("'scal' must be a square, real matrix"));
if (n <= 0) n = 1;
// allocate early to avoid memory leaks in Callocs below.
PROTECT(ans = alloc3DArray(REALSXP, dims[0], dims[0], n));
psqr = dims[0] * dims[0];
tmp = Calloc(psqr, double);
scCp = Calloc(psqr, double);
Memcpy(scCp, REAL(scal), psqr);
memset(tmp, 0, psqr * sizeof(double));
F77_CALL(dpotrf)("U", &(dims[0]), scCp, &(dims[0]), &info);
if (info)
error(_("'scal' matrix is not positive-definite"));
ansp = REAL(ans);
GetRNGstate();
for (int j = 0; j < n; j++) {
double *ansj = ansp + j * psqr;
std_rWishart_factor(nu, dims[0], 1, tmp);
F77_CALL(dtrmm)("R", "U", "N", "N", dims, dims,
&one, scCp, dims, tmp, dims);
F77_CALL(dsyrk)("U", "T", &(dims[1]), &(dims[1]),
&one, tmp, &(dims[1]),
&zero, ansj, &(dims[1]));
for (int i = 1; i < dims[0]; i++)
for (int k = 0; k < i; k++)
ansj[i + k * dims[0]] = ansj[k + i * dims[0]];
}
PutRNGstate();
Free(scCp); Free(tmp);
UNPROTECT(1);
return ans;
}
You can’t perform that action at this time.