Stan Math Library  2.12.0
reverse mode automatic differentiation
mdivide_left_ldlt.hpp
Go to the documentation of this file.
1 #ifndef STAN_MATH_REV_MAT_FUN_MDIVIDE_LEFT_LDLT_HPP
2 #define STAN_MATH_REV_MAT_FUN_MDIVIDE_LEFT_LDLT_HPP
3 
4 #include <stan/math/rev/core.hpp>
9 
10 namespace stan {
11  namespace math {
12  namespace {
13  template <int R1, int C1, int R2, int C2>
14  class mdivide_left_ldlt_alloc : public chainable_alloc {
15  public:
16  virtual ~mdivide_left_ldlt_alloc() {}
17 
23  boost::shared_ptr<Eigen::LDLT<Eigen::Matrix<double, R1, C1> > > ldltP_;
24  Eigen::Matrix<double, R2, C2> C_;
25  };
26 
37  template <int R1, int C1, int R2, int C2>
38  class mdivide_left_ldlt_vv_vari : public vari {
39  public:
40  int M_; // A.rows() = A.cols() = B.rows()
41  int N_; // B.cols()
42  vari** variRefB_;
43  vari** variRefC_;
44  mdivide_left_ldlt_alloc<R1, C1, R2, C2> *alloc_;
45  const LDLT_alloc<R1, C1> *alloc_ldlt_;
46 
47  mdivide_left_ldlt_vv_vari(const LDLT_factor<var, R1, C1> &A,
48  const Eigen::Matrix<var, R2, C2> &B)
49  : vari(0.0),
50  M_(A.rows()),
51  N_(B.cols()),
52  variRefB_(reinterpret_cast<vari**>
53  (ChainableStack::memalloc_
54  .alloc(sizeof(vari*) * B.rows() * B.cols()))),
55  variRefC_(reinterpret_cast<vari**>
56  (ChainableStack::memalloc_
57  .alloc(sizeof(vari*) * B.rows() * B.cols()))),
58  alloc_(new mdivide_left_ldlt_alloc<R1, C1, R2, C2>()),
59  alloc_ldlt_(A.alloc_) {
60  int pos = 0;
61  alloc_->C_.resize(M_, N_);
62  for (int j = 0; j < N_; j++) {
63  for (int i = 0; i < M_; i++) {
64  variRefB_[pos] = B(i, j).vi_;
65  alloc_->C_(i, j) = B(i, j).val();
66  pos++;
67  }
68  }
69 
70  alloc_ldlt_->ldlt_.solveInPlace(alloc_->C_);
71 
72  pos = 0;
73  for (int j = 0; j < N_; j++) {
74  for (int i = 0; i < M_; i++) {
75  variRefC_[pos] = new vari(alloc_->C_(i, j), false);
76  pos++;
77  }
78  }
79  }
80 
81  virtual void chain() {
82  Eigen::Matrix<double, R1, C1> adjA(M_, M_);
83  Eigen::Matrix<double, R2, C2> adjB(M_, N_);
84 
85  int pos = 0;
86  for (int j = 0; j < N_; j++)
87  for (int i = 0; i < M_; i++)
88  adjB(i, j) = variRefC_[pos++]->adj_;
89 
90  alloc_ldlt_->ldlt_.solveInPlace(adjB);
91  adjA.noalias() = -adjB * alloc_->C_.transpose();
92 
93  for (int j = 0; j < M_; j++)
94  for (int i = 0; i < M_; i++)
95  alloc_ldlt_->variA_(i, j)->adj_ += adjA(i, j);
96 
97  pos = 0;
98  for (int j = 0; j < N_; j++)
99  for (int i = 0; i < M_; i++)
100  variRefB_[pos++]->adj_ += adjB(i, j);
101  }
102  };
103 
114  template <int R1, int C1, int R2, int C2>
115  class mdivide_left_ldlt_dv_vari : public vari {
116  public:
117  int M_; // A.rows() = A.cols() = B.rows()
118  int N_; // B.cols()
119  vari** variRefB_;
120  vari** variRefC_;
121  mdivide_left_ldlt_alloc<R1, C1, R2, C2> *alloc_;
122 
123  mdivide_left_ldlt_dv_vari(const LDLT_factor<double, R1, C1>
124  &A,
125  const Eigen::Matrix<var, R2, C2> &B)
126  : vari(0.0),
127  M_(A.rows()),
128  N_(B.cols()),
129  variRefB_(reinterpret_cast<vari**>
130  (ChainableStack::memalloc_
131  .alloc(sizeof(vari*) * B.rows() * B.cols()))),
132  variRefC_(reinterpret_cast<vari**>
133  (ChainableStack::memalloc_
134  .alloc(sizeof(vari*) * B.rows() * B.cols()))),
135  alloc_(new mdivide_left_ldlt_alloc<R1, C1, R2, C2>()) {
136  using Eigen::Matrix;
137  using Eigen::Map;
138 
139  int pos = 0;
140  alloc_->C_.resize(M_, N_);
141  for (int j = 0; j < N_; j++) {
142  for (int i = 0; i < M_; i++) {
143  variRefB_[pos] = B(i, j).vi_;
144  alloc_->C_(i, j) = B(i, j).val();
145  pos++;
146  }
147  }
148 
149  alloc_->ldltP_ = A.ldltP_;
150  alloc_->ldltP_->solveInPlace(alloc_->C_);
151 
152  pos = 0;
153  for (int j = 0; j < N_; j++) {
154  for (int i = 0; i < M_; i++) {
155  variRefC_[pos] = new vari(alloc_->C_(i, j), false);
156  pos++;
157  }
158  }
159  }
160 
161  virtual void chain() {
162  Eigen::Matrix<double, R2, C2> adjB(M_, N_);
163 
164  int pos = 0;
165  for (int j = 0; j < adjB.cols(); j++)
166  for (int i = 0; i < adjB.rows(); i++)
167  adjB(i, j) = variRefC_[pos++]->adj_;
168 
169  alloc_->ldltP_->solveInPlace(adjB);
170 
171  pos = 0;
172  for (int j = 0; j < adjB.cols(); j++)
173  for (int i = 0; i < adjB.rows(); i++)
174  variRefB_[pos++]->adj_ += adjB(i, j);
175  }
176  };
177 
188  template <int R1, int C1, int R2, int C2>
189  class mdivide_left_ldlt_vd_vari : public vari {
190  public:
191  int M_; // A.rows() = A.cols() = B.rows()
192  int N_; // B.cols()
193  vari** variRefC_;
194  mdivide_left_ldlt_alloc<R1, C1, R2, C2> *alloc_;
195  const LDLT_alloc<R1, C1> *alloc_ldlt_;
196 
197  mdivide_left_ldlt_vd_vari(const LDLT_factor<var, R1, C1> &A,
198  const Eigen::Matrix<double, R2, C2> &B)
199  : vari(0.0),
200  M_(A.rows()),
201  N_(B.cols()),
202  variRefC_(reinterpret_cast<vari**>
203  (ChainableStack::memalloc_
204  .alloc(sizeof(vari*) * B.rows() * B.cols()))),
205  alloc_(new mdivide_left_ldlt_alloc<R1, C1, R2, C2>()),
206  alloc_ldlt_(A.alloc_) {
207  alloc_->C_ = B;
208  alloc_ldlt_->ldlt_.solveInPlace(alloc_->C_);
209 
210  int pos = 0;
211  for (int j = 0; j < N_; j++) {
212  for (int i = 0; i < M_; i++) {
213  variRefC_[pos] = new vari(alloc_->C_(i, j), false);
214  pos++;
215  }
216  }
217  }
218 
219  virtual void chain() {
220  Eigen::Matrix<double, R1, C1> adjA(M_, M_);
221  Eigen::Matrix<double, R1, C2> adjC(M_, N_);
222 
223  int pos = 0;
224  for (int j = 0; j < adjC.cols(); j++)
225  for (int i = 0; i < adjC.rows(); i++)
226  adjC(i, j) = variRefC_[pos++]->adj_;
227 
228  adjA = -alloc_ldlt_->ldlt_.solve(adjC*alloc_->C_.transpose());
229 
230  for (int j = 0; j < adjA.cols(); j++)
231  for (int i = 0; i < adjA.rows(); i++)
232  alloc_ldlt_->variA_(i, j)->adj_ += adjA(i, j);
233  }
234  };
235  }
236 
244  template <int R1, int C1, int R2, int C2>
245  inline Eigen::Matrix<var, R1, C2>
247  const Eigen::Matrix<var, R2, C2> &b) {
248  Eigen::Matrix<var, R1, C2> res(b.rows(), b.cols());
249 
250  check_multiplicable("mdivide_left_ldlt",
251  "A", A,
252  "b", b);
253 
254  mdivide_left_ldlt_vv_vari<R1, C1, R2, C2> *baseVari
255  = new mdivide_left_ldlt_vv_vari<R1, C1, R2, C2>(A, b);
256 
257  int pos = 0;
258  for (int j = 0; j < res.cols(); j++)
259  for (int i = 0; i < res.rows(); i++)
260  res(i, j).vi_ = baseVari->variRefC_[pos++];
261 
262  return res;
263  }
264 
272  template <int R1, int C1, int R2, int C2>
273  inline Eigen::Matrix<var, R1, C2>
275  const Eigen::Matrix<double, R2, C2> &b) {
276  Eigen::Matrix<var, R1, C2> res(b.rows(), b.cols());
277 
278  check_multiplicable("mdivide_left_ldlt",
279  "A", A,
280  "b", b);
281 
282  mdivide_left_ldlt_vd_vari<R1, C1, R2, C2> *baseVari
283  = new mdivide_left_ldlt_vd_vari<R1, C1, R2, C2>(A, b);
284 
285  int pos = 0;
286  for (int j = 0; j < res.cols(); j++)
287  for (int i = 0; i < res.rows(); i++)
288  res(i, j).vi_ = baseVari->variRefC_[pos++];
289 
290  return res;
291  }
292 
300  template <int R1, int C1, int R2, int C2>
301  inline Eigen::Matrix<var, R1, C2>
303  const Eigen::Matrix<var, R2, C2> &b) {
304  Eigen::Matrix<var, R1, C2> res(b.rows(), b.cols());
305 
306  check_multiplicable("mdivide_left_ldlt",
307  "A", A,
308  "b", b);
309 
310  mdivide_left_ldlt_dv_vari<R1, C1, R2, C2> *baseVari
311  = new mdivide_left_ldlt_dv_vari<R1, C1, R2, C2>(A, b);
312 
313  int pos = 0;
314  for (int j = 0; j < res.cols(); j++)
315  for (int i = 0; i < res.rows(); i++)
316  res(i, j).vi_ = baseVari->variRefC_[pos++];
317 
318  return res;
319  }
320 
321  }
322 }
323 #endif
boost::shared_ptr< Eigen::LDLT< Eigen::Matrix< double, R1, C1 > > > ldltP_
This share_ptr is used to prevent copying the LDLT factorizations for mdivide_left_ldlt(ldltA, b) when ldltA is a LDLT_factor.
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
int N_
Eigen::Matrix< fvar< T2 >, R1, C2 > mdivide_left_ldlt(const LDLT_factor< double, R1, C1 > &A, const Eigen::Matrix< fvar< T2 >, R2, C2 > &b)
Returns the solution of the system Ax=b given an LDLT_factor of A.
int M_
mdivide_left_ldlt_alloc< R1, C1, R2, C2 > * alloc_
vari ** variRefB_
bool check_multiplicable(const char *function, const char *name1, const T1 &y1, const char *name2, const T2 &y2)
Return true if the matrices can be multiplied.
vari ** variRefC_
const LDLT_alloc< R1, C1 > * alloc_ldlt_
int cols(const Eigen::Matrix< T, R, C > &m)
Return the number of columns in the specified matrix, vector, or row vector.
Definition: cols.hpp:20
Eigen::Matrix< double, R2, C2 > C_
AutodiffStackStorage< vari, chainable_alloc > ChainableStack

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