Title: | The Matrix-Normal Inverse-Wishart Distribution |
---|---|
Description: | Density evaluation and random number generation for the Matrix-Normal Inverse-Wishart (MNIW) distribution, as well as the the Matrix-Normal, Matrix-T, Wishart, and Inverse-Wishart distributions. Core calculations are implemented in a portable (header-only) C++ library, with matrix manipulations using the 'Eigen' library for linear algebra. Also provided is a Gibbs sampler for Bayesian inference on a random-effects model with multivariate normal observations. |
Authors: | Martin Lysy [aut, cre], Bryan Yates [aut] |
Maintainer: | Martin Lysy <[email protected]> |
License: | GPL-3 |
Version: | 1.0.2 |
Built: | 2024-10-31 22:12:20 UTC |
Source: | https://github.com/mlysy/mniw |
Density evaluation and random number generation for the Matrix-Normal Inverse-Wishart (MNIW) distribution, as well as its constituent distributions, i.e., the Matrix-Normal, Matrix-T, Wishart, and Inverse-Wishart distributions.
The Matrix-Normal Inverse-Wishart (MNIW) distribution on random matrices
and symmetric positive-definite
is defined as
where the Matrix-Normal distribution is defined as the multivariate normal
where is a vector stacking the columns of
, and
denotes the Kronecker product.
Maintainer: Martin Lysy [email protected]
Authors:
Bryan Yates
Useful links:
Report bugs at https://github.com/mlysy/mniw/issues
Vectorized matrix cross-products t(X) V Y
or t(X) V^{-1} Y
.
crossprodV(X, Y = NULL, V, inverse = FALSE)
crossprodV(X, Y = NULL, V, inverse = FALSE)
X |
A matrix of size |
Y |
A matrix of size |
V |
A matrix of size |
inverse |
Logical; whether or not the inner product should be calculated with |
An array of size q x r x n
.
# problem dimensions p <- 4 q <- 2 r <- 3 n <- 5 X <- array(rnorm(p*q*n), dim = c(p, q, n)) # vectorized Y <- array(rnorm(p*r*n), dim = c(p, r, n)) # vectorized V <- crossprod(matrix(rnorm(p*p), p, p)) # not vectorized (but positive definite) crossprodV(X = X, V = V) # self cross-product # cross-product with inverse matrix weight crossprodV(X = X, V = V, Y = Y, inverse = TRUE)
# problem dimensions p <- 4 q <- 2 r <- 3 n <- 5 X <- array(rnorm(p*q*n), dim = c(p, q, n)) # vectorized Y <- array(rnorm(p*r*n), dim = c(p, r, n)) # vectorized V <- crossprod(matrix(rnorm(p*p), p, p)) # not vectorized (but positive definite) crossprodV(X = X, V = V) # self cross-product # cross-product with inverse matrix weight crossprodV(X = X, V = V, Y = Y, inverse = TRUE)
Information on patient-reported problem rates for 27 teaching hospitals and private academic health centers in the United States.
Hospitals
Hospitals
A data frame with 27 rows (one for each hospital) and 4 variables:
NSrg
Non-surgery related problem rate (percent).
Srg
Surgery related problem rate (percent).
Severity
Average health index for surveyed patients.
Size
Number of patients surveyed.
Everson, P.J. and Morris, C.N. "Inference for multivariate normal hierarchical models." Journal of the Royal Statistical Society, Series B 62:2 (2000): 399-412.
Density and random sampling for the Matrix-Normal distribution.
dMNorm(X, Lambda, SigmaR, SigmaC, log = FALSE) rMNorm(n, Lambda, SigmaR, SigmaC)
dMNorm(X, Lambda, SigmaR, SigmaC, log = FALSE) rMNorm(n, Lambda, SigmaR, SigmaC)
X |
Argument to the density function. Either a |
Lambda |
Mean parameter. Either a |
SigmaR |
Between-row covariance matrix. Either a |
SigmaC |
Between-column covariance matrix Either a |
log |
Logical; whether or not to compute the log-density. |
n |
Integer number of random samples to generate. |
The Matrix-Normal distribution on the random matrix
is defined as
where is a vector stacking the columns of
, and
denotes the Kronecker product.
A vector length n
for density evaluation, or an array of size p x q x n
for random sampling.
# problem dimensions p <- 4 q <- 2 n <- 10 # number of observations # parameter values Lambda <- matrix(rnorm(p*q),p,q) # mean matrix # row-wise variance matrix (positive definite) SigmaR <- crossprod(matrix(rnorm(p*p), p, p)) SigmaC <- rwish(n, Psi = diag(q), nu = q + 1) # column-wise variance (vectorized) # random sample X <- rMNorm(n, Lambda = Lambda, SigmaR = SigmaR, SigmaC = SigmaC) # log-density at each sampled value dMNorm(X, Lambda = Lambda, SigmaR = SigmaR, SigmaC = SigmaC, log = TRUE)
# problem dimensions p <- 4 q <- 2 n <- 10 # number of observations # parameter values Lambda <- matrix(rnorm(p*q),p,q) # mean matrix # row-wise variance matrix (positive definite) SigmaR <- crossprod(matrix(rnorm(p*p), p, p)) SigmaC <- rwish(n, Psi = diag(q), nu = q + 1) # column-wise variance (vectorized) # random sample X <- rMNorm(n, Lambda = Lambda, SigmaR = SigmaR, SigmaC = SigmaC) # log-density at each sampled value dMNorm(X, Lambda = Lambda, SigmaR = SigmaR, SigmaC = SigmaC, log = TRUE)
Density and sampling for the Matrix-t distribution.
dMT(X, Lambda, SigmaR, SigmaC, nu, log = FALSE) rMT(n, Lambda, SigmaR, SigmaC, nu)
dMT(X, Lambda, SigmaR, SigmaC, nu, log = FALSE) rMT(n, Lambda, SigmaR, SigmaC, nu)
X |
Argument to the density function. Either a |
Lambda |
Mean parameter. Either a |
SigmaR |
Between-row covariance matrix. Either a |
SigmaC |
Between-column covariance matrix Either a |
nu |
Degrees-of-freedom parameter. A scalar or vector of length |
log |
Logical; whether or not to compute the log-density. |
n |
Integer number of random samples to generate. |
The Matrix-T distribution on a random matrix
is the marginal distribution of
in
, where the Matrix-Normal Inverse-Wishart (MNIW) distribution is defined in MNIW-dist.
A vector length n
for density evaluation, or an array of size p x q x n
for random sampling.
Generate samples from the Matrix-Normal Inverse-Wishart distribution.
rMNIW(n, Lambda, Sigma, Psi, nu, prec = FALSE) rmniw(n, Lambda, Omega, Psi, nu)
rMNIW(n, Lambda, Sigma, Psi, nu, prec = FALSE) rmniw(n, Lambda, Omega, Psi, nu)
n |
number of samples. |
Lambda |
A mean matrix of size |
Sigma |
A row-wise variance or precision matrix of size |
Psi |
A scale matrix of size |
nu |
Scalar degrees-of-freedom parameter. |
prec |
Logical; whether or not |
Omega |
A between-row precision matrix of size |
The Matrix-Normal Inverse-Wishart (MNIW) distribution on random matrices
and symmetric positive-definite
is defined as
where the Matrix-Normal distribution is defined as the multivariate normal
where is a vector stacking the columns of
, and
denotes the Kronecker product.
rmniw()
is a convenience wrapper to rMNIW(Sigma = Omega, prec = TRUE)
, for the common situation in Bayesian inference with conjugate priors when between-row variances are naturally parametrized on the precision scale.
A list with elements:
X
Array of size p x q x n
random samples from the Matrix-Normal component (see Details).
V
Array of size q x q x n
of random samples from the Inverse-Wishart component.
# problem dimensions p <- 2 q <- 3 n <- 10 # number of samples # parameter specification Lambda <- matrix(rnorm(p*q),p,q) # single argument Sigma <- rwish(n, Psi = diag(p), nu = p + rexp(1)) # vectorized argument Psi <- rwish(n = 1, Psi = diag(q), nu = q + rexp(1)) # single argument nu <- q + rexp(1) # simulate n draws rMNIW(n, Lambda = Lambda, Sigma = Sigma, Psi = Psi, nu = nu)
# problem dimensions p <- 2 q <- 3 n <- 10 # number of samples # parameter specification Lambda <- matrix(rnorm(p*q),p,q) # single argument Sigma <- rwish(n, Psi = diag(p), nu = p + rexp(1)) # vectorized argument Psi <- rwish(n = 1, Psi = diag(q), nu = q + rexp(1)) # single argument nu <- q + rexp(1) # simulate n draws rMNIW(n, Lambda = Lambda, Sigma = Sigma, Psi = Psi, nu = nu)
Density and random sampling for the Multivariate Normal distribution.
dmNorm(x, mu, Sigma, log = FALSE) rmNorm(n, mu, Sigma)
dmNorm(x, mu, Sigma, log = FALSE) rmNorm(n, mu, Sigma)
x |
Argument to the density function. A vector of length |
mu |
Mean vector(s). Either a vector of length |
Sigma |
Covariance matrix or matrices. Either a |
log |
Logical; whether or not to compute the log-density. |
n |
Integer number of random samples to generate. |
A vector for densities, or a n x q
matrix for random sampling.
# Parameter specification q <- 4 # number of dimensions mu <- 1:q # mean vector V <- toeplitz(exp(-seq(1:q))) # variance matrix # Random sample n <- 100 X <- rmNorm(n, mu, V) # Calculate log density for each sampled vector dmNorm(X, mu, V, log = TRUE)
# Parameter specification q <- 4 # number of dimensions mu <- 1:q # mean vector V <- toeplitz(exp(-seq(1:q))) # variance matrix # Random sample n <- 100 X <- rmNorm(n, mu, V) # Calculate log density for each sampled vector dmNorm(X, mu, V, log = TRUE)
Sample from the conditional parameter distribution given the data and hyperparameters of the Multivariate-Normal Random-Effects (mNormRE) model (see Details).
rRxNorm(n, x, V, lambda, Sigma)
rRxNorm(n, x, V, lambda, Sigma)
n |
Integer number of random samples to generate. |
x |
Data observations. Either a vector of length |
V |
Observation variances. Either a matrix of size |
lambda |
Prior means. Either a vector of length |
Sigma |
Prior variances. Either a matrix of size |
Consider the hierarchical multivariate normal model
The Multivariate-Normal Random-Effects model on the random vector
is defined as the posterior distribution
. This distribution is multivariate normal; for the mathematical specification of its parameters please see
vignette("mniw-distributions", package = "mniw")
.
# data specification q <- 5 y <- rnorm(q) V <- rwish(1, diag(q), q+1) # prior specification lambda <- rep(0,q) A <- diag(q) n <- 10 # random sampling rRxNorm(n, y, V, lambda, A)
# data specification q <- 5 y <- rnorm(q) V <- rwish(1, diag(q), q+1) # prior specification lambda <- rep(0,q) A <- diag(q) n <- 10 # random sampling rRxNorm(n, y, V, lambda, A)
Gibbs sampler for posterior distribution of parameters and hyperparameters of a multivariate normal random-effects linear regression model called RxNormLM (see Details).
RxNormLM( nsamples, Y, V, X, prior = NULL, init, burn, updateHyp = TRUE, storeHyp = TRUE, updateRX = TRUE, storeRX = FALSE )
RxNormLM( nsamples, Y, V, X, prior = NULL, init, burn, updateHyp = TRUE, storeHyp = TRUE, updateRX = TRUE, storeRX = FALSE )
nsamples |
number of posterior samples to draw. |
Y |
|
V |
Either a |
X |
|
prior |
parameters of the prior MNIW distribution on the hyperparameters (see Details). |
init |
(optional) list with elements |
burn |
integer number of burn-in samples, or fraction of |
updateHyp , storeHyp
|
logical. Whether or not to update/store the hyperparameter draws. |
updateRX , storeRX
|
logical. Whether or not to update/store the random-effects draws. |
The RxNormLM model is given by
where and
are response and random-effects vectors of length
,
are covariate vectors of length
, and
are hyperparameter matrices of size
and
.
The MNIW prior distribution is given by a list with elements Lambda
, Omega
, Psi
, and nu
. If any of these is NULL
or missing, the default value is 0. Note that Omega == 0
gives a Lebesgue prior to .
A list with (potential) elements:
Beta
An p x q x nsamples
array of regression coefficient iterations (if storeHyp == TRUE
)
Sigma
An q x q x nsamples
array of regression variance matrices (if storeHyp == TRUE
)
Mu
An n x q x nsamples
array of random effects (if storeRX == TRUE
)
# problem dimensions n <- sample(10:20,1) # number of observations p <- sample(1:4,1) # number of covariates q <- sample(1:4,1) # number of responses # hyperparameters Lambda <- rMNorm(1, Lambda = matrix(0, p, q)) Omega <- crossprod(rMNorm(1, Lambda = matrix(0, p, p))) Psi <- crossprod(rMNorm(1, Lambda = matrix(0, q, q))) nu <- rexp(1) + (q+1) prior <- list(Lambda = Lambda, Omega = Omega, Psi = Psi, nu = nu) # random-effects parameters BSig <- rmniw(1, Lambda = Lambda, Omega = Omega, Psi = Psi, nu = nu) Beta <- BSig$X Sigma <- BSig$V # design matrix X <- rMNorm(1, matrix(0, n, p)) # random-effects themselves Mu <- rmNorm(n, X %*% Beta, Sigma) # generate response data V <- rwish(n, Psi = diag(q), nu = q+1) # error variances Y <- rmNorm(n, mu = Mu, Sigma = V) # responses # visual checks for each component of Gibbs sampler # sample from p(Mu | Beta, Sigma, Y) nsamples <- 1e5 out <- RxNormLM(nsamples, Y = Y, V = V, X = X, prior = prior, init = list(Beta = Beta, Sigma = Sigma, Mu = Mu), burn = floor(nsamples/10), updateHyp = FALSE, storeHyp = FALSE, updateRX = TRUE, storeRX = TRUE) # conditional distribution is RxNorm: iObs <- sample(n, 1) # pick an observation at random # calculate the RxNorm parameters G <- Sigma %*% solve(V[,,iObs] + Sigma) xB <- c(X[iObs,,drop=FALSE] %*% Beta) muRx <- G %*% (Y[iObs,] - xB) + xB SigmaRx <- G %*% V[,,iObs] # a' * mu_i is univariate normal with known mean and variance: a <- rnorm(q) # arbitrary vector amui <- crossprod(a, out$Mu[iObs,,]) # a' * mu_i hist(amui, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*mu[i])) curve(dnorm(x, mean = sum(a * muRx), sd = sqrt(crossprod(a, SigmaRx %*% a)[1])), add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA)) # sample from p(Beta, Sigma | Mu, Y) nsamples <- 1e5 out <- RxNormLM(nsamples, Y = Y, V = V, X = X, prior = prior, init = list(Beta = Beta, Sigma = Sigma, Mu = Mu), burn = floor(nsamples/10), updateHyp = TRUE, storeHyp = TRUE, updateRX = FALSE, storeRX = FALSE) # conditional distribution is MNIW: # calculate the MNIW parameters OmegaHat <- crossprod(X) + Omega LambdaHat <- solve(OmegaHat, crossprod(X, Mu) + Omega %*% Lambda) PsiHat <- Psi + crossprod(Mu) + crossprod(Lambda, Omega %*% Lambda) PsiHat <- PsiHat - crossprod(LambdaHat, OmegaHat %*% LambdaHat) nuHat <- nu + n # a' Sigma^{-1} a is chi^2 with known parameters: a <- rnorm(q) aSiga <- drop(crossprodV(a, V = out$Sigma, inverse = TRUE)) sigX <- crossprod(a, solve(PsiHat, a))[1] hist(aSiga, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*Sigma^{-1}*a)) curve(dchisq(x/sigX, df = nuHat)/sigX, add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA)) # a' Beta b is student-t with known parameters: a <- rnorm(p) b <- rnorm(q) # vectorized calculations aBetab <- crossprodV(X = aperm(out$Beta, c(2,1,3)), Y = b, V = diag(q)) # Beta b aBetab <- drop(crossprodV(X = a, Y = aBetab, V = diag(p))) # a' Beta b # student-t parameters muT <- crossprod(a, LambdaHat %*% b)[1] nuT <- nuHat-q+1 sigmaT <- crossprodV(a, V = OmegaHat, inverse = TRUE)[1] sigmaT <- sigmaT * crossprodV(b, V = PsiHat)[1] sigmaT <- sqrt(sigmaT / nuT) hist(aBetab, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*Beta*a)) curve(dt((x-muT)/sigmaT, df = nuT)/sigmaT, add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA))
# problem dimensions n <- sample(10:20,1) # number of observations p <- sample(1:4,1) # number of covariates q <- sample(1:4,1) # number of responses # hyperparameters Lambda <- rMNorm(1, Lambda = matrix(0, p, q)) Omega <- crossprod(rMNorm(1, Lambda = matrix(0, p, p))) Psi <- crossprod(rMNorm(1, Lambda = matrix(0, q, q))) nu <- rexp(1) + (q+1) prior <- list(Lambda = Lambda, Omega = Omega, Psi = Psi, nu = nu) # random-effects parameters BSig <- rmniw(1, Lambda = Lambda, Omega = Omega, Psi = Psi, nu = nu) Beta <- BSig$X Sigma <- BSig$V # design matrix X <- rMNorm(1, matrix(0, n, p)) # random-effects themselves Mu <- rmNorm(n, X %*% Beta, Sigma) # generate response data V <- rwish(n, Psi = diag(q), nu = q+1) # error variances Y <- rmNorm(n, mu = Mu, Sigma = V) # responses # visual checks for each component of Gibbs sampler # sample from p(Mu | Beta, Sigma, Y) nsamples <- 1e5 out <- RxNormLM(nsamples, Y = Y, V = V, X = X, prior = prior, init = list(Beta = Beta, Sigma = Sigma, Mu = Mu), burn = floor(nsamples/10), updateHyp = FALSE, storeHyp = FALSE, updateRX = TRUE, storeRX = TRUE) # conditional distribution is RxNorm: iObs <- sample(n, 1) # pick an observation at random # calculate the RxNorm parameters G <- Sigma %*% solve(V[,,iObs] + Sigma) xB <- c(X[iObs,,drop=FALSE] %*% Beta) muRx <- G %*% (Y[iObs,] - xB) + xB SigmaRx <- G %*% V[,,iObs] # a' * mu_i is univariate normal with known mean and variance: a <- rnorm(q) # arbitrary vector amui <- crossprod(a, out$Mu[iObs,,]) # a' * mu_i hist(amui, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*mu[i])) curve(dnorm(x, mean = sum(a * muRx), sd = sqrt(crossprod(a, SigmaRx %*% a)[1])), add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA)) # sample from p(Beta, Sigma | Mu, Y) nsamples <- 1e5 out <- RxNormLM(nsamples, Y = Y, V = V, X = X, prior = prior, init = list(Beta = Beta, Sigma = Sigma, Mu = Mu), burn = floor(nsamples/10), updateHyp = TRUE, storeHyp = TRUE, updateRX = FALSE, storeRX = FALSE) # conditional distribution is MNIW: # calculate the MNIW parameters OmegaHat <- crossprod(X) + Omega LambdaHat <- solve(OmegaHat, crossprod(X, Mu) + Omega %*% Lambda) PsiHat <- Psi + crossprod(Mu) + crossprod(Lambda, Omega %*% Lambda) PsiHat <- PsiHat - crossprod(LambdaHat, OmegaHat %*% LambdaHat) nuHat <- nu + n # a' Sigma^{-1} a is chi^2 with known parameters: a <- rnorm(q) aSiga <- drop(crossprodV(a, V = out$Sigma, inverse = TRUE)) sigX <- crossprod(a, solve(PsiHat, a))[1] hist(aSiga, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*Sigma^{-1}*a)) curve(dchisq(x/sigX, df = nuHat)/sigX, add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA)) # a' Beta b is student-t with known parameters: a <- rnorm(p) b <- rnorm(q) # vectorized calculations aBetab <- crossprodV(X = aperm(out$Beta, c(2,1,3)), Y = b, V = diag(q)) # Beta b aBetab <- drop(crossprodV(X = a, Y = aBetab, V = diag(p))) # a' Beta b # student-t parameters muT <- crossprod(a, LambdaHat %*% b)[1] nuT <- nuHat-q+1 sigmaT <- crossprodV(a, V = OmegaHat, inverse = TRUE)[1] sigmaT <- sigmaT * crossprodV(b, V = PsiHat)[1] sigmaT <- sqrt(sigmaT / nuT) hist(aBetab, breaks = 100, freq = FALSE, xlab = "", main = expression("Histogram of "*a^T*Beta*a)) curve(dt((x-muT)/sigmaT, df = nuT)/sigmaT, add = TRUE, col = "red") legend("topright", legend = c("Observed", "Expected"), lwd = c(NA, 2), pch = c(22, NA), seg.len = 1.5, col = c("black", "red"), bg = c("white", NA))
Densities and random sampling for the Wishart and Inverse-Wishart distributions.
dwish(X, Psi, nu, log = FALSE) rwish(n, Psi, nu) diwish(X, Psi, nu, log = FALSE) riwish(n, Psi, nu) dwishart(X, Psi, nu, inverse = FALSE, log = FALSE) rwishart(n, Psi, nu, inverse = FALSE)
dwish(X, Psi, nu, log = FALSE) rwish(n, Psi, nu) diwish(X, Psi, nu, log = FALSE) riwish(n, Psi, nu) dwishart(X, Psi, nu, inverse = FALSE, log = FALSE) rwishart(n, Psi, nu, inverse = FALSE)
X |
Argument to the density function. Either a |
Psi |
Scale parameter. Either a |
nu |
Degrees-of-freedom parameter. A scalar or vector of length |
log |
Logical; whether or not to compute the log-density. |
n |
Integer number of random samples to generate. |
inverse |
Logical; whether or not to use the Inverse-Wishart distribution. |
The Wishart distribution on a symmetric positive-definite random matrix
of size
has PDF
where is the multivariate gamma function,
The Inverse-Wishart distribution is defined as
.
dwish()
and diwish()
are convenience wrappers for dwishart()
, and similarly rwish()
and riwish()
are wrappers for rwishart()
.
A vector length n
for density evaluation, or an array of size q x q x n
for random sampling.
# Random sampling n <- 1e5 q <- 3 Psi1 <- crossprod(matrix(rnorm(q^2),q,q)) nu <- q + runif(1, 0, 5) X1 <- rwish(n,Psi1,nu) # Wishart # plot it plot_fun <- function(X) { q <- dim(X)[1] par(mfrow = c(q,q)) for(ii in 1:q) { for(jj in 1:q) { hist(X[ii,jj,], breaks = 100, freq = FALSE, xlab = "", main = parse(text = paste0("X[", ii, jj, "]"))) } } } plot_fun(X1) # "vectorized" scale parameeter Psi2 <- 5 * Psi1 vPsi <- array(c(Psi1, Psi2), dim = c(q, q, n)) X2 <- rwish(n, Psi = vPsi, nu = nu) plot_fun(X2) # Inverse-Wishart X3 <- riwish(n, Psi2, nu) plot_fun(X3) # log-density calculation for sampled values par(mfrow = c(1,1)) hist(dwish(X2, vPsi, nu, log = TRUE), breaks = 100, freq = FALSE, xlab = "", main = expression("log-p"*(X[2]*" | "*list(Psi,nu))))
# Random sampling n <- 1e5 q <- 3 Psi1 <- crossprod(matrix(rnorm(q^2),q,q)) nu <- q + runif(1, 0, 5) X1 <- rwish(n,Psi1,nu) # Wishart # plot it plot_fun <- function(X) { q <- dim(X)[1] par(mfrow = c(q,q)) for(ii in 1:q) { for(jj in 1:q) { hist(X[ii,jj,], breaks = 100, freq = FALSE, xlab = "", main = parse(text = paste0("X[", ii, jj, "]"))) } } } plot_fun(X1) # "vectorized" scale parameeter Psi2 <- 5 * Psi1 vPsi <- array(c(Psi1, Psi2), dim = c(q, q, n)) X2 <- rwish(n, Psi = vPsi, nu = nu) plot_fun(X2) # Inverse-Wishart X3 <- riwish(n, Psi2, nu) plot_fun(X3) # log-density calculation for sampled values par(mfrow = c(1,1)) hist(dwish(X2, vPsi, nu, log = TRUE), breaks = 100, freq = FALSE, xlab = "", main = expression("log-p"*(X[2]*" | "*list(Psi,nu))))