Stan  1.3
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
log_determinant_spd.hpp
Go to the documentation of this file.
1 #ifndef __STAN__AGRAD__REV__MATRIX__LOG_DETERMINANT_SPD_HPP__
2 #define __STAN__AGRAD__REV__MATRIX__LOG_DETERMINANT_SPD_HPP__
3 
4 #include <vector>
9 #include <stan/agrad/rev/var.hpp>
11 
12 // FIXME: use explicit files
13 #include <stan/agrad/agrad.hpp>
14 
15 namespace stan {
16  namespace agrad {
17 
18  namespace {
19  template <int R,int C>
20  class log_determinant_spd_alloc : public chainable_alloc {
21  public:
22  virtual ~log_determinant_spd_alloc() {}
23 
24  Eigen::Matrix<double,R,C> _invA;
25  };
26 
27 
28  template<int R,int C>
29  class log_determinant_spd_vari : public vari {
30  log_determinant_spd_alloc<R,C> *_alloc;
31  int _rows;
32  int _cols;
33  vari** _adjARef;
34  public:
35  log_determinant_spd_vari(const Eigen::Matrix<var,R,C> &A)
36  : vari(log_determinant_spd_vari_calc(A,&_alloc)),
37  _rows(A.rows()),
38  _cols(A.cols()),
39  _adjARef((vari**)stan::agrad::memalloc_.alloc(sizeof(vari*)
40  * A.rows() * A.cols()))
41  {
42  size_t pos = 0;
43  for (size_type j = 0; j < _cols; j++) {
44  for (size_type i = 0; i < _rows; i++) {
45  _adjARef[pos++] = A(i,j).vi_;
46  }
47  }
48  }
49 
50  static
51  double log_determinant_spd_vari_calc(const Eigen::Matrix<var,R,C> &A,
52  log_determinant_spd_alloc<R,C> **alloc)
53  {
54  // allocate space for information needed in chain
55  *alloc = new log_determinant_spd_alloc<R,C>();
56 
57  // compute cholesky decomposition of A
58  (*alloc)->_invA.resize(A.rows(),A.cols());
59  for (size_type j = 0; j < A.cols(); j++)
60  for (size_type i = 0; i < A.rows(); i++)
61  (*alloc)->_invA(i,j) = A(i,j).val();
62  Eigen::LDLT< Eigen::Matrix<double,R,C> > ldlt((*alloc)->_invA);
63  if (ldlt.info() != Eigen::Success) {
64  // Handle this better.
65  std::cerr << "Failed LDLT factorization" << std::endl;
66  (*alloc)->_invA.setZero(A.rows(),A.cols());
67  return -std::numeric_limits<double>::infinity();
68  }
69 
70  // compute the inverse of A (needed for the derivative)
71  (*alloc)->_invA.setIdentity(A.rows(),A.cols());
72  ldlt.solveInPlace((*alloc)->_invA);
73 
74  if (ldlt.isNegative() || (ldlt.vectorD().array() <= 1e-16).any()) {
75  std::cerr << "Matrix is negative definite" << std::endl;
76  return -std::numeric_limits<double>::infinity();
77  }
78 
79  double ret = ldlt.vectorD().array().log().sum();
80  if (!boost::math::isfinite(ret)) {
81  std::cerr << ldlt.vectorD() << std::endl;
82  }
83  return ret;
84  }
85 
86  virtual void chain() {
87  size_t pos = 0;
88  for (size_type j = 0; j < _cols; j++) {
89  for (size_type i = 0; i < _rows; i++) {
90  _adjARef[pos++]->adj_ += adj_*_alloc->_invA(i,j);
91  }
92  }
93  }
94  };
95  }
96 
97  template <int R, int C>
98  inline var log_determinant_spd(const Eigen::Matrix<var,R,C>& m) {
99  stan::math::validate_square(m,"log_determinant_spd");
100  return var(new log_determinant_spd_vari<R,C>(m));
101  }
102 
103  }
104 }
105 #endif

     [ Stan Home Page ] © 2011–2013, Stan Development Team.