Back to Random symmetric positive-definite matrices
pastel/math/matrix/random_matrix/
// Description: Random symmetric positive-definite matrix
#ifndef PASTELMATH_RANDOM_SPD_MATRIX_H
#define PASTELMATH_RANDOM_SPD_MATRIX_H
#include "pastel/math/matrix/random_matrix/random_orthogonal_matrix.h"
#include "pastel/sys/random/random_uniform.h"
#include <armadillo>
#include <algorithm>
#include <vector>
namespace Pastel
{
//! Generates a random spd (n x n)-matrix S with given det(S).
/*!
Preconditions:
n >= 0
determinant > 0
*/
template <typename Real>
Matrix<Real> randomSymmetricPositiveDefinite(
integer n,
const NoDeduction<Real>& determinant)
{
ENSURE_OP(n, >=, 0);
// Generate a random partition of the
// interval [0, -ln(d)] to n subintervals
// represented by (n + 1) partition points.
Real xDelta = -std::log(determinant);
std::vector<Real> partitionSet;
partitionSet.reserve(n + 1);
partitionSet.push_back(0);
partitionSet.push_back(xDelta);
for (integer i = 0;i < n - 1;++i)
{
partitionSet.push_back(random<Real>() * xDelta);
}
std::sort(partitionSet.begin(), partitionSet.end());
// Generate a random rotation matrix.
arma::Mat<Real> result = randomOrthogonal<Real>(n);
// Multiply the columns of the rotation matrix
// with square root of the diagonal element of D.
for (integer j = 0;j < n;++j)
{
Real b = partitionSet[j + 1] - partitionSet[j];
for (integer i = 0;i < n;++i)
{
result(i, j) *= std::exp(-b / 2);
}
}
result *= transpose(result);
return result;
}
//! Generates a random spd (n x n)-matrix S with given det(S) and cond(S).
/*!
Preconditions:
n >= 0
determinant > 0
condition >= 1
*/
template <typename Real>
arma::Mat<Real> randomSymmetricPositiveDefinite(
integer n,
const NoDeduction<Real>& determinant,
const NoDeduction<Real>& condition)
{
ENSURE_OP(n, >=, 0);
ENSURE_OP(condition, >=, 1);
ENSURE_OP(determinant, >, 0);
Real a =
((n - 1) * std::log(condition) -
std::log(determinant)) / n;
Real b =
a - std::log(condition);
// Generate a random rotation matrix.
arma::Mat<Real> result = randomRotation<Real>(n);
// Multiply the columns of the rotation matrix
// with square roots of the diagonal elements of D.
for (integer i = 0;i < n;++i)
{
result(i, 0) *= std::exp(-a / 2);
}
for (integer j = 1;j < n;++j)
{
for (integer i = 0;i < n;++i)
{
result(i, j) *= std::exp(-b / 2);
}
}
result *= transpose(result);
return result;
}
}
#endif