libcmaes
A C++11 library for stochastic optimization with CMA-ES
 All Classes Namespaces Functions Variables Typedefs
eigenmvn.h
1 
33 #ifndef __EIGENMULTIVARIATENORMAL_HPP
34 #define __EIGENMULTIVARIATENORMAL_HPP
35 
36 #include <Eigen/Dense>
37 #include <random>
38 #include <stdexcept>
39 
40 /*
41  We need a functor that can pretend it's const,
42  but to be a good random number generator
43  it needs mutable state. The standard Eigen function
44  Random() just calls rand(), which changes a global
45  variable.
46 */
47 namespace Eigen {
48  namespace internal {
49  template<typename Scalar>
51  {
52  static std::mt19937 rng; // The uniform pseudo-random algorithm
53  mutable std::normal_distribution<Scalar> norm; // gaussian combinator
54 
55  EIGEN_EMPTY_STRUCT_CTOR(scalar_normal_dist_op)
56 
57  template<typename Index>
58  inline const Scalar operator() (Index, Index = 0) const { return norm(rng); }
59  inline void seed(const uint64_t &s) { rng.seed(s); }
60  };
61 
62  template<typename Scalar>
64 
65  template<typename Scalar>
66  struct functor_traits<scalar_normal_dist_op<Scalar> >
67  { enum { Cost = 50 * NumTraits<Scalar>::MulCost, PacketAccess = false, IsRepeatable = false }; };
68 
69  } // end namespace internal
70 
75  template<typename Scalar>
77  {
78  Matrix< Scalar, Dynamic, 1> _mean;
79  internal::scalar_normal_dist_op<Scalar> randN; // Gaussian functor
80  bool _use_cholesky;
81 
82  public:
83  void set_covar(const Matrix<Scalar,Dynamic,Dynamic> &covar) { _covar = covar; }
84  void set_transform(const Matrix<Scalar,Dynamic,Dynamic> &transform) { _transform = transform; }
85 
86  private:
87  Matrix<Scalar,Dynamic,Dynamic> _covar;
88  Matrix<Scalar,Dynamic,Dynamic> _transform;
89 
90  public:
91  SelfAdjointEigenSolver<Matrix<Scalar,Dynamic,Dynamic> > _eigenSolver; // drawback: this creates a useless eigenSolver when using Cholesky decomposition, but it yields access to eigenvalues and vectors
92 
93  public:
94  EigenMultivariateNormal(const bool &use_cholesky=false,
95  const uint64_t &seed=std::mt19937::default_seed)
96  :_use_cholesky(use_cholesky)
97  {
98  randN.seed(seed);
99  }
100  EigenMultivariateNormal(const Matrix<Scalar,Dynamic,1>& mean,const Matrix<Scalar,Dynamic,Dynamic>& covar,
101  const bool &use_cholesky=false,const uint64_t &seed=std::mt19937::default_seed)
102  :_use_cholesky(use_cholesky)
103  {
104  randN.seed(seed);
105  setMean(mean);
106  setCovar(covar);
107  }
108 
109  void setMean(const Matrix<Scalar,Dynamic,1>& mean) { _mean = mean; }
110  void setCovar(const Matrix<Scalar,Dynamic,Dynamic>& covar)
111  {
112  _covar = covar;
113 
114  // Assuming that we'll be using this repeatedly,
115  // compute the transformation matrix that will
116  // be applied to unit-variance independent normals
117 
118  if (_use_cholesky)
119  {
120  Eigen::LLT<Eigen::Matrix<Scalar,Dynamic,Dynamic> > cholSolver(_covar);
121  // We can only use the cholesky decomposition if
122  // the covariance matrix is symmetric, pos-definite.
123  // But a covariance matrix might be pos-semi-definite.
124  // In that case, we'll go to an EigenSolver
125  if (cholSolver.info()==Eigen::Success)
126  {
127  // Use cholesky solver
128  _transform = cholSolver.matrixL();
129  }
130  else
131  {
132  throw std::runtime_error("Failed computing the Cholesky decomposition. Use solver instead");
133  }
134  }
135  else
136  {
137  _eigenSolver = SelfAdjointEigenSolver<Matrix<Scalar,Dynamic,Dynamic> >(_covar);
138  _transform = _eigenSolver.eigenvectors()*_eigenSolver.eigenvalues().cwiseMax(0).cwiseSqrt().asDiagonal();
139  }
140  }
141 
144  Matrix<Scalar,Dynamic,-1> samples(int nn, double factor)
145  {
146  return ((_transform * Matrix<Scalar,Dynamic,-1>::NullaryExpr(_covar.rows(),nn,randN))*factor).colwise() + _mean;
147  }
148 
149  Matrix<Scalar,Dynamic,-1> samples_ind(int nn, double factor)
150  {
151  dMat pop = (Matrix<Scalar,Dynamic,-1>::NullaryExpr(_covar.rows(),nn,randN))*factor;
152  for (int i=0;i<pop.cols();i++)
153  {
154  pop.col(i) = pop.col(i).cwiseProduct(_transform) + _mean;
155  }
156  return pop;
157  }
158 
159  Matrix<Scalar,Dynamic,-1> samples_ind(int nn)
160  {
161  return (Matrix<Scalar,Dynamic,-1>::NullaryExpr(_covar.rows(),nn,randN));
162  }
163 
164  }; // end class EigenMultivariateNormal
165 } // end namespace Eigen
166 #endif
Definition: eigenmvn.h:76
Matrix< Scalar, Dynamic,-1 > samples(int nn, double factor)
Definition: eigenmvn.h:144
Definition: eigenmvn.h:47