Stan Math Library: stan/math/rev/mat/fun/cholesky_decompose.hpp Source File

| Stan Math Library 2.10.0 reverse mode automatic differentiation

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

cholesky_decompose.hpp
Go to the documentation of this file.
1 #ifndef STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
2 #define STAN_MATH_REV_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
3
4 #include <stan/math/prim/mat/fun/Eigen.hpp>
5 #include <stan/math/prim/mat/fun/typedefs.hpp>
6 #include <stan/math/prim/mat/fun/cholesky_decompose.hpp>
7 #include <stan/math/rev/scal/fun/value_of_rec.hpp>
8 #include <stan/math/rev/scal/fun/value_of.hpp>
9 #include <stan/math/rev/core.hpp>
10 #include <stan/math/prim/mat/fun/value_of_rec.hpp>
11 #include <stan/math/prim/mat/err/check_pos_definite.hpp>
12 #include <stan/math/prim/mat/err/check_square.hpp>
13 #include <stan/math/prim/mat/err/check_symmetric.hpp>
14
15 namespace stan {
16 namespace math {
17
18 class cholesky_decompose_v_vari : public vari {
19 public:
20 int M_; // A.rows() = A.cols()
21 vari** variRefA_;
22 vari** variRefL_;
23
24 /* ctor for cholesky function
25 *
26 * Stores varis for A
27 * Instantiates and stores varis for L
28 * Instantiates and stores dummy vari for
29 * upper triangular part of var result returned
30 * in cholesky_decompose function call
31 *
32 * variRefL aren't on the chainable
33 * autodiff stack, only used for storage
34 * and computation. Note that varis for
35 * L are constructed externally in
36 * cholesky_decompose.
37 *
38 * @param matrix A
39 * @param matrix L, cholesky factor of A
40 * */
41 cholesky_decompose_v_vari(const Eigen::Matrix<var, -1, -1>& A,
42 const Eigen::Matrix<double, -1, -1>& L_A)
43 : vari(0.0),
44 M_(A.rows()),
45 variRefA_(ChainableStack::memalloc_.alloc_array<vari*>
46 (A.rows() * (A.rows() + 1) / 2)),
47 variRefL_(ChainableStack::memalloc_.alloc_array<vari*>
48 (A.rows() * (A.rows() + 1) / 2)) {
49 size_t accum = 0;
50 size_t accum_i = accum;
51 for (size_type j = 0; j < M_; ++j) {
52 for (size_type i = j; i < M_; ++i) {
53 accum_i += i;
54 size_t pos = j + accum_i;
55 variRefA_[pos] = A.coeffRef(i, j).vi_;
56 variRefL_[pos] = new vari(L_A.coeffRef(i, j), false);
57 }
58 accum += j;
59 accum_i = accum;
60 }
61 }
62
63 /* Reverse mode differentiation
64 * algorithm refernce:
65 *
66 * Mike Giles. An extended collection of matrix
67 * derivative results for forward and reverse mode AD.
68 * Jan. 2008.
69 *
70 * Note algorithm as laid out in Giles is
71 * row-major, so Eigen::Matrices are explicitly storage
72 * order RowMajor, whereas Eigen defaults to
73 * ColumnMajor. Also note algorithm
74 * starts by calculating the adjoint for
75 * A(M_ - 1, M_ - 1), hence pos on line 94 is decremented
76 * to start at pos = M_ * (M_ + 1) / 2.
77 * */
78 virtual void chain() {
79 using Eigen::Matrix;
80 using Eigen::RowMajor;
81 Matrix<double, -1, -1, RowMajor> adjL(M_, M_);
82 Matrix<double, -1, -1, RowMajor> LA(M_, M_);
83 Matrix<double, -1, -1, RowMajor> adjA(M_, M_);
84 size_t pos = 0;
85 for (size_type i = 0; i < M_; ++i) {
86 for (size_type j = 0; j <= i; ++j) {
87 adjL.coeffRef(i, j) = variRefL_[pos]->adj_;
88 LA.coeffRef(i, j) = variRefL_[pos]->val_;
89 ++pos;
90 }
91 }
92
93 --pos;
94 for (int i = M_ - 1; i >= 0; --i) {
95 for (int j = i; j >= 0; --j) {
96 if (i == j) {
97 adjA.coeffRef(i, j) = 0.5 * adjL.coeff(i, j)
98 / LA.coeff(i, j);
99 } else {
100 adjA.coeffRef(i, j) = adjL.coeff(i, j)
101 / LA.coeff(j, j);
102 adjL.coeffRef(j, j) -= adjL.coeff(i, j)
103 * LA.coeff(i, j) / LA.coeff(j, j);
104 }
105 for (int k = j - 1; k >=0; --k) {
106 adjL.coeffRef(i, k) -= adjA.coeff(i, j)
107 * LA.coeff(j, k);
108 adjL.coeffRef(j, k) -= adjA.coeff(i, j)
109 * LA.coeff(i, k);
110 }
111 variRefA_[pos--]->adj_ += adjA.coeffRef(i, j);
112 }
113 }
114 }
115 };
116
117 /* Reverse mode specialization of
118 * cholesky decomposition
119 *
120 * Internally calls llt rather than using
121 * stan::math::cholesky_decompose in order
122 * to use selfadjointView<Lower> optimization.
123 *
124 * Note chainable stack varis are created
125 * below in Matrix<var, -1, -1>
126 *
127 * @param Matrix A
128 * @return L cholesky factor of A
129 */
130 Eigen::Matrix<var, -1, -1>
131 cholesky_decompose(const Eigen::Matrix<var, -1, -1> &A) {
132 stan::math::check_square("cholesky_decompose", "A", A);
133 stan::math::check_symmetric("cholesky_decompose", "A", A);
134
135 Eigen::Matrix<double, -1, -1> L_A(value_of_rec(A));
136 Eigen::LLT<Eigen::MatrixXd> L_factor
137 = L_A.selfadjointView<Eigen::Lower>().llt();
138 check_pos_definite("cholesky_decompose", "m", L_factor);
139 L_A = L_factor.matrixL();
140
141 // NOTE: this is not a memory leak, this vari is used in the
142 // expression graph to evaluate the adjoint, but is not needed
143 // for the returned matrix. Memory will be cleaned up with the
144 // arena allocator.
145 cholesky_decompose_v_vari *baseVari
146 = new cholesky_decompose_v_vari(A, L_A);
147 stan::math::vari dummy(0.0, false);
148 Eigen::Matrix<var, -1, -1> L(A.rows(), A.cols());
149 size_t accum = 0;
150 size_t accum_i = accum;
151 for (size_type j = 0; j < L.cols(); ++j) {
152 for (size_type i = j; i < L.cols(); ++i) {
153 accum_i += i;
154 size_t pos = j + accum_i;
155 L.coeffRef(i, j).vi_ = baseVari->variRefL_[pos];
156 }
157 for (size_type k = 0; k < j; ++k)
158 L.coeffRef(k, j).vi_ = &dummy;
159 accum += j;
160 accum_i = accum;
161 }
162 return L;
163 }
164 }
165 }
166 #endif
stan::math::vari::vari
vari(const double x)
Construct a variable implementation from a value.
Definition: vari.hpp:58
stan::math::cholesky_decompose_v_vari::M_
int M_
Definition: cholesky_decompose.hpp:20
stan::math::rows
int rows(const Eigen::Matrix< T, R, C > &m)
Return the number of rows in the specified matrix, vector, or row vector.
Definition: rows.hpp:20
value_of_rec.hpp
core.hpp
stan::math::cholesky_decompose_v_vari::chain
virtual void chain()
Apply the chain rule to this variable based on the variables on which it depends. ...
Definition: cholesky_decompose.hpp:78
stan::math::cholesky_decompose_v_vari::cholesky_decompose_v_vari
cholesky_decompose_v_vari(const Eigen::Matrix< var,-1,-1 > &A, const Eigen::Matrix< double,-1,-1 > &L_A)
Definition: cholesky_decompose.hpp:41
value_of_rec.hpp
stan
Definition: log_sum_exp.hpp:8
stan::math::value_of_rec
double value_of_rec(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of_rec.hpp:21
stan::math::vari
The variable implementation base class.
Definition: vari.hpp:30
check_symmetric.hpp
stan::math::vari::val_
const double val_
The value of this variable.
Definition: vari.hpp:38
stan::math::dummy
Empty struct for use in boost::condtional::value, T1, dummy>::type as false co...
Definition: container_view.hpp:53
stan::math::size_type
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic >::Index size_type
Type for sizes and indexes in an Eigen matrix with double e.
Definition: typedefs.hpp:13
stan::math::cholesky_decompose_v_vari::variRefL_
vari ** variRefL_
Definition: cholesky_decompose.hpp:22
Eigen.hpp
stan::math::cholesky_decompose
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > cholesky_decompose(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &m)
Return the lower-triangular Cholesky factor (i.e., matrix square root) of the specified square...
Definition: cholesky_decompose.hpp:25
stan::math::check_pos_definite
bool check_pos_definite(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Return true if the specified square, symmetric matrix is positive definite.
Definition: check_pos_definite.hpp:37
stan::math::AutodiffStackStorage
Definition: autodiffstackstorage.hpp:12
stan::math::cholesky_decompose_v_vari
Definition: cholesky_decompose.hpp:18
stan::math::cholesky_decompose_v_vari::variRefA_
vari ** variRefA_
Definition: cholesky_decompose.hpp:21
stan::math::check_symmetric
bool check_symmetric(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Return true if the specified matrix is symmetric.
Definition: check_symmetric.hpp:37
stan::math::vari::adj_
double adj_
The adjoint of this variable, which is the partial derivative of this variable with respect to the ro...
Definition: vari.hpp:44
cholesky_decompose.hpp
stan::math::check_square
bool check_square(const char *function, const char *name, const Eigen::Matrix< T_y, Eigen::Dynamic, Eigen::Dynamic > &y)
Return true if the specified matrix is square.
Definition: check_square.hpp:28
value_of.hpp
check_pos_definite.hpp
typedefs.hpp
check_square.hpp

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