TMB Documentation  v1.9.11
newton.hpp
1 #ifdef TMBAD_FRAMEWORK
2 
3 /* =================== TODO ===================
4  - Move entire code to TMBad ?
5  - Option for saddlepoint solver ?
6  - Generalize HessianSolveVector to handle non-symmetric jacobian
7  - log_determinant of sparse matrix avoid branching issue
8  ============================================
9 */
10 
15 template<class NewType, class OldType>
16 Eigen::SparseMatrix<NewType> pattern(const Eigen::SparseMatrix<OldType> &S,
17  std::vector<NewType> x = std::vector<NewType>(0) ) {
18  if (S.nonZeros() > 0 && x.size() == 0) {
19  x.resize(S.nonZeros());
20  }
21  return Eigen::Map<const Eigen::SparseMatrix<NewType> > (S.rows(),
22  S.cols(),
23  S.nonZeros(),
24  S.outerIndexPtr(),
25  S.innerIndexPtr(),
26  x.data(),
27  S.innerNonZeroPtr());
28 }
29 
30 #ifdef TMBAD_SUPERNODAL
31 #include "supernodal_inverse_subset.hpp"
32 #define INVERSE_SUBSET_TEMPLATE Eigen::SupernodalInverseSubset
33 typedef Eigen::Accessible_CholmodSupernodalLLT DEFAULT_SPARSE_FACTORIZATION;
34 inline double logDeterminant(const DEFAULT_SPARSE_FACTORIZATION &llt) {
35  return llt.logDeterminant();
36 }
37 #else
38 #include "simplicial_inverse_subset.hpp"
39 #define INVERSE_SUBSET_TEMPLATE Eigen::SimplicialInverseSubset
40 typedef Eigen::SimplicialLLT<Eigen::SparseMatrix<double> > DEFAULT_SPARSE_FACTORIZATION;
41 inline double logDeterminant(const DEFAULT_SPARSE_FACTORIZATION &llt) {
42  return 2. * llt.matrixL().nestedExpression().diagonal().array().log().sum();
43 }
44 #endif
45 
46 #include <memory>
59 namespace newton {
60 // FIXME: R macro
61 #ifdef eval
62 #undef eval
63 #endif
64 
65 template <class Type>
66 struct vector : Eigen::Array<Type, Eigen::Dynamic, 1>
67 {
68  typedef Type value_type;
69  typedef Eigen::Array<Type, Eigen::Dynamic, 1> Base;
70 
71  vector(void) : Base() {}
72 
73  template<class Derived>
74  vector(const Eigen::ArrayBase<Derived> &x) : Base(x) {}
75  template<class Derived>
76  vector(const Eigen::MatrixBase<Derived> &x) : Base(x) {}
77  vector(size_t n) : Base(n) {}
78  // std::vector
79  operator std::vector<Type>() const {
80  return std::vector<Type> (Base::data(),
81  Base::data() + Base::size());
82  }
83  vector(const std::vector<Type> &x) :
84  Base(Eigen::Map<const Base> (x.data(), x.size())) { }
85 };
86 
87 template <class Type>
88 struct matrix : Eigen::Matrix<Type, Eigen::Dynamic, Eigen::Dynamic>
89 {
90  typedef Eigen::Matrix<Type, Eigen::Dynamic, Eigen::Dynamic> Base;
91  matrix(void) : Base() {}
92  template<class Derived>
93  matrix(const Eigen::ArrayBase<Derived> &x) : Base(x) {}
94  template<class Derived>
95  matrix(const Eigen::MatrixBase<Derived> &x) : Base(x) {}
96  vector<Type> vec() const {
97  Base a(*this);
98  a.resize(a.size(), 1);
99  return a;
100  }
101 };
102 
108 template <class Hessian_Type>
110  static const bool have_input_size_output_size = true;
111  static const bool add_forward_replay_copy = true;
112  std::shared_ptr<Hessian_Type> hessian;
113  size_t nnz, x_rows, x_cols; // Dim(x)
114  HessianSolveVector(std::shared_ptr<Hessian_Type> hessian, size_t x_cols = 1) :
115  hessian ( hessian ),
116  nnz ( hessian->Range() ),
117  x_rows ( hessian->n ),
118  x_cols ( x_cols ) {}
119  TMBad::Index input_size() const {
120  return nnz + x_rows * x_cols;
121  }
122  TMBad::Index output_size() const {
123  return x_rows * x_cols;
124  }
125  vector<TMBad::Scalar> solve(const vector<TMBad::Scalar> &h,
126  const vector<TMBad::Scalar> &x) {
127  typename Hessian_Type::template MatrixResult<TMBad::Scalar>::type
128  H = hessian -> as_matrix(h);
129  hessian -> llt_factorize(H); // Assuming analyzePattern(H) has been called once
130  matrix<TMBad::Scalar> xm = x.matrix();
131  xm.resize(x_rows, x_cols);
132  vector<TMBad::Scalar> y = hessian -> llt_solve(H, xm).vec();
133  return y;
134  }
135  vector<TMBad::Replay> solve(const vector<TMBad::Replay> &h,
136  const vector<TMBad::Replay> &x) {
137  std::vector<TMBad::ad_plain> hx;
138  hx.insert(hx.end(), h.data(), h.data() + h.size());
139  hx.insert(hx.end(), x.data(), x.data() + x.size());
141  std::vector<TMBad::ad_plain> ans = Op(hx);
142  std::vector<TMBad::ad_aug> ans2(ans.begin(), ans.end());
143  return ans2;
144  }
145  void forward(TMBad::ForwardArgs<TMBad::Scalar> &args) {
146  size_t n = output_size();
147  vector<TMBad::Scalar>
148  h = args.x_segment(0, nnz),
149  x = args.x_segment(nnz, n);
150  args.y_segment(0, n) = solve(h, x);
151  }
152  template <class T>
153  void reverse(TMBad::ReverseArgs<T> &args) {
154  size_t n = output_size();
155  vector<T>
156  h = args. x_segment(0, nnz),
157  y = args. y_segment(0, n),
158  dy = args.dy_segment(0, n);
159  vector<T> y2 = solve(h, dy);
160  for (size_t j=0; j < x_cols; j++) {
161  vector<T> y_j = y .segment(j * x_rows, x_rows);
162  vector<T> y2_j = y2.segment(j * x_rows, x_rows);
163  vector<T> y2y_j = hessian -> crossprod(y2_j, y_j);
164  args.dx_segment(0, nnz) -= y2y_j;
165  args.dx_segment(nnz + j * x_rows, x_rows) += y2_j;
166  }
167  }
168  template<class T>
169  void forward(TMBad::ForwardArgs<T> &args) { TMBAD_ASSERT(false); }
170  void reverse(TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); }
171  const char* op_name() { return "JSolve"; }
172 };
173 
174 /* ======================================================================== */
175 /* === Matrix types that can be used by the Newton solver ================= */
176 /* ======================================================================== */
177 
178 /* --- Dense Hessian ------------------------------------------------------ */
179 
181 template<class Factorization=Eigen::LLT<Eigen::Matrix<double, -1, -1> > >
183  typedef TMBad::ADFun<> Base;
184  template<class T>
185  struct MatrixResult {
186  typedef matrix<T> type;
187  };
188  size_t n;
189  std::shared_ptr<Factorization> llt;
190  jacobian_dense_t() {}
191  // FIXME: Want const &F, &G, &H
192  // --> JacFun, var2op, get_keep_var --> const
193  jacobian_dense_t(TMBad::ADFun<> &H, size_t n) :
194  n(n), llt(std::make_shared<Factorization>()) {
195  Base::operator= ( H );
196  }
198  n(n), llt(std::make_shared<Factorization>()) {
199  std::vector<bool> keep_x(n, true); // inner
200  keep_x.resize(G.Domain(), false); // outer
201  std::vector<bool> keep_y(n, true); // inner
202  Base::operator= ( G.JacFun(keep_x, keep_y) );
203  }
204  template<class V>
205  matrix<typename V::value_type> as_matrix(const V &Hx) {
206  typedef typename V::value_type T;
207  return Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > (Hx.data(), n, n);
208  }
209  template<class T>
210  std::vector<T> eval(const std::vector<T> &x) {
211  return Base::operator()(x);
212  }
213  template<class T>
214  matrix<T> operator()(const std::vector<T> &x) {
215  return as_matrix(Base::operator()(x));
216  }
220  template<class T>
221  vector<T> crossprod(const vector<T> &y2, const vector<T> &y) {
222  matrix<T> ans = ( y2.matrix() * y.matrix().transpose() ).array();
223  return ans.vec();
224  }
225  // Sparse.factorize() == Dense.compute()
226  void llt_factorize(const matrix<TMBad::Scalar> &h) {
227  llt->compute(h);
228  }
229  Eigen::ComputationInfo llt_info() {
230  return llt->info();
231  }
234  matrix<TMBad::Scalar> llt_solve(const matrix<TMBad::Scalar> &H,
235  const matrix<TMBad::Scalar> &x) {
236  return llt->solve(x);
237  }
238  template<class T>
239  vector<T> solve(std::shared_ptr<jacobian_dense_t> ptr,
240  const vector<T> &h,
241  const vector<T> &x) {
242  return HessianSolveVector<jacobian_dense_t>(ptr).solve(h, x);
243  }
244 };
245 
246 /* --- Sparse Hessian ----------------------------------------------------- */
247 
249 template<class Factorization=DEFAULT_SPARSE_FACTORIZATION >
250 struct jacobian_sparse_t : TMBad::Sparse<TMBad::ADFun<> > {
251  typedef TMBad::Sparse<TMBad::ADFun<> > Base;
252  template<class T>
253  struct MatrixResult {
254  typedef Eigen::SparseMatrix<T> type;
255  };
256  size_t n;
257  std::shared_ptr<Factorization> llt;
258  jacobian_sparse_t& operator=(const jacobian_sparse_t &other) {
259  Base::operator=(other);
260  n = other.n;
261  init_llt(); // llt.analyzePattern(H)
262  return *this;
263  }
264  jacobian_sparse_t (const jacobian_sparse_t &other) : Base(other), n(other.n) {
265  init_llt(); // llt.analyzePattern(H)
266  }
267  jacobian_sparse_t() {}
268  void init_llt() {
269  llt = std::make_shared<Factorization>();
270  // Analyze pattern
271  std::vector<TMBad::Scalar> dummy(this->Range(), 0);
272  Eigen::SparseMatrix<TMBad::Scalar> H_dummy = as_matrix(dummy);
273  llt->analyzePattern(H_dummy);
274  }
275  // FIXME: &F, &G, &H const !!!
276  jacobian_sparse_t(TMBad::Sparse<TMBad::ADFun<> > &H, size_t n) :
277  n(n) {
278  Base::operator= ( H );
279  init_llt(); // llt.analyzePattern(H)
280  }
282  n(n) {
283  std::vector<bool> keep_x(n, true); // inner
284  keep_x.resize(G.Domain(), false); // outer
285  std::vector<bool> keep_y(n, true); // inner
286  Base::operator= (G.SpJacFun(keep_x, keep_y));
287  init_llt();
288  }
289  // FIXME: Optimize sparsematrix CTOR by only doing 'setFromTriplets' once?
290  template<class V>
291  Eigen::SparseMatrix<typename V::value_type> as_matrix(const V &Hx) {
292  typedef typename V::value_type T;
293  typedef Eigen::Triplet<T> T3;
294  std::vector<T3> tripletList(n);
295  // Diagonal must always be part of pattern
296  for(size_t i=0; i<n; i++) {
297  tripletList[i] = T3(i, i, 0);
298  }
299  size_t K = Hx.size();
300  for(size_t k=0; k<K; k++) {
301  tripletList.push_back( T3( Base::i[k],
302  Base::j[k],
303  Hx[k] ) );
304  }
305  Eigen::SparseMatrix<T> mat(n, n);
306  mat.setFromTriplets(tripletList.begin(), tripletList.end());
307  return mat;
308  }
309  template<class T>
310  std::vector<T> eval(const std::vector<T> &x) {
311  return Base::operator()(x);
312  }
313  template<class T>
314  Eigen::SparseMatrix<T> operator()(const std::vector<T> &x) {
315  std::vector<T> Hx = Base::operator()(x);
316  return as_matrix(Hx);
317  }
318  /* Sparsity restricted cross product */
319  template<class T>
320  vector<T> crossprod(const vector<T> &y2, const vector<T> &y) {
321  size_t nnz = Base::Range();
322  vector<T> ans(nnz);
323  for (size_t k=0; k<nnz; k++) {
324  ans[k] = y2[ Base::i [k] ] * y[ Base::j [k] ];
325  }
326  return ans;
327  }
328  // Sparse.factorize() == Dense.compute()
329  void llt_factorize(const Eigen::SparseMatrix<TMBad::Scalar> &h) {
330  llt->factorize(h);
331  }
332  Eigen::ComputationInfo llt_info() {
333  return llt->info();
334  }
337  matrix<TMBad::Scalar> llt_solve(const Eigen::SparseMatrix<TMBad::Scalar> &H,
338  const matrix<TMBad::Scalar> &x) {
339  return llt->solve(x);
340  }
341  template<class T>
342  vector<T> solve(std::shared_ptr<jacobian_sparse_t> ptr,
343  const vector<T> &h,
344  const vector<T> &x) {
345  return HessianSolveVector<jacobian_sparse_t>(ptr).solve(h, x);
346  }
347 };
348 
349 /* --- Sparse Plus Low Rank Hessian --------------------------------------- */
350 
352 template<class dummy = void>
354  static const bool have_eval = true;
355  static const bool add_forward_replay_copy = true;
356  template<class Type> Type eval(Type x0) {
357  return x0 ;
358  }
359  template<class Type> void reverse(TMBad::ReverseArgs<Type> &args) {
360  args.dx(0) += args.dy(0);
361  }
362  const char* op_name() { return "TagOp"; }
363 };
394 TMBad::ad_plain Tag(const TMBad::ad_plain &x) CSKIP( {
395  return TMBad::get_glob()->add_to_stack<TagOp<> >(x);
396 } )
398 TMBad::Scalar Tag(const TMBad::Scalar &x) CSKIP( {
399  return x;
400 } )
401 
456 template<class dummy=void>
458  // The three tapes
459  std::shared_ptr<jacobian_sparse_t<> > H;
460  std::shared_ptr<TMBad::ADFun<> > G;
461  std::shared_ptr<jacobian_dense_t<> > H0;
462  // ADFun methods that should apply to each of the three tapes
463  void optimize() {
464  H -> optimize();
465  G -> optimize();
466  H0 -> optimize();
467  }
468  void DomainVecSet(const std::vector<TMBad::Scalar> &x) {
469  H -> DomainVecSet(x);
470  G -> DomainVecSet(x);
471  H0 -> DomainVecSet(x);
472  }
473  void SwapInner() {
474  H -> SwapInner();
475  G -> SwapInner();
476  H0 -> SwapInner();
477  }
478  void SwapOuter() {
479  H -> SwapOuter();
480  G -> SwapOuter();
481  H0 -> SwapOuter();
482  }
483  void print(TMBad::print_config cfg) {
484  H -> print(cfg);
485  G -> print(cfg);
486  H0 -> print(cfg);
487  }
488  // Return type to represent the matrix
489  template<class T>
490  struct sparse_plus_lowrank {
491  Eigen::SparseMatrix<T> H;
492  matrix<T> G;
493  matrix<T> H0;
494  // Optional: Store serialized representation of H
495  vector<T> Hvec;
496  Eigen::Diagonal<Eigen::SparseMatrix<T> > diagonal() {
497  return H.diagonal();
498  }
499  };
500  template<class T>
501  struct MatrixResult {
502  typedef sparse_plus_lowrank<T> type;
503  };
504  size_t n;
507  TMBad::ADFun<> &G_,
508  size_t n) : n(n) {
510  F2 = F.decompose("TagOp");
511  size_t k = F2.first.Range();
512  std::vector<bool> keep_rc(n, true); // inner
513  keep_rc.resize(F.Domain(), false); // outer
515  F3 = F2.HesFun(keep_rc, true, false, false);
516  H = std::make_shared<jacobian_sparse_t<> >(F3.first, n);
517  G = std::make_shared<TMBad::ADFun<> >(F3.second);
518  H0 = std::make_shared<jacobian_dense_t<> >(F3.third, k);
519  }
520  // unserialize
521  template<class V>
522  sparse_plus_lowrank<typename V::value_type> as_matrix(const V &Hx) {
523  typedef typename V::value_type T;
524  const T* start = Hx.data();
525  std::vector<T> v1(start, start + H -> Range());
526  start += H -> Range();
527  std::vector<T> v2(start, start + G -> Range());
528  start += G -> Range();
529  std::vector<T> v3(start, start + H0 -> Range());
530  sparse_plus_lowrank<T> ans;
531  ans.H = H -> as_matrix(v1);
532  ans.Hvec = v1;
533  ans.G = vector<T>(v2);
534  ans.G.resize(n, v2.size() / n);
535  ans.H0 = H0 -> as_matrix(v3);
536  return ans;
537  }
538  template<class T>
539  std::vector<T> eval(const std::vector<T> &x) {
540  std::vector<T> ans = H -> eval(x);
541  std::vector<T> ans2 = (*G)(x);
542  std::vector<T> ans3 = H0 -> eval(x);
543  ans.insert(ans.end(), ans2.begin(), ans2.end());
544  ans.insert(ans.end(), ans3.begin(), ans3.end());
545  return ans;
546  }
547  template<class T>
548  sparse_plus_lowrank<T> operator()(const std::vector<T> &x) {
549  return as_matrix(eval(x));
550  }
551  void llt_factorize(const sparse_plus_lowrank<TMBad::Scalar> &h) {
552  H -> llt_factorize(h.H);
553  }
554  // FIXME: Diagonal increments should perhaps be applied to both H and H0.
555  Eigen::ComputationInfo llt_info() {
556  // Note: As long as diagonal increments are only applied to H this
557  // is the relevant info:
558  return H -> llt_info();
559  }
562  matrix<TMBad::Scalar> llt_solve(const sparse_plus_lowrank<TMBad::Scalar> &h,
563  const matrix<TMBad::Scalar> &x) {
564  matrix<TMBad::Scalar> W = H -> llt_solve(h.H, h.G); // n x k
565  matrix<TMBad::Scalar> H0M = h.H0 * h.G.transpose() * W;
566  H0M.diagonal().array() += TMBad::Scalar(1.);
567  matrix<TMBad::Scalar> y1 = H -> llt_solve(h.H, x);
568  matrix<TMBad::Scalar> y2 = W * H0M.ldlt().solve(h.H0 * W.transpose() * x);
569  return y1 - y2;
570  }
571  template<class T>
572  vector<T> solve(std::shared_ptr<jacobian_sparse_plus_lowrank_t<> > ptr,
573  const vector<T> &hvec,
574  const vector<T> &xvec) {
575  using atomic::matmul;
576  using atomic::matinv;
577  sparse_plus_lowrank<T> h = as_matrix(hvec);
578  vector<T> s =
580  h.G.cols()).
581  solve(h.Hvec, h.G.vec());
582  tmbutils::matrix<T> W = s.matrix();
583  W.resize(n, W.size() / n);
584  tmbutils::matrix<T> H0 = h.H0.array();
585  tmbutils::matrix<T> Gt = h.G.transpose();
586  tmbutils::matrix<T> H0M =
587  matmul(H0,
588  matmul(Gt,
589  W));
590  H0M.diagonal().array() += T(1.);
591  vector<T> y1 =
593  solve(h.Hvec, xvec);
594  tmbutils::matrix<T> iH0M = matinv(H0M);
595  tmbutils::matrix<T> Wt = W.transpose();
596  tmbutils::matrix<T> xmat = xvec.matrix();
597  vector<T> y2 =
598  matmul(W,
599  matmul(iH0M,
600  matmul(H0,
601  matmul(Wt,
602  xmat)))).array();
603  return y1 - y2;
604  }
605  // Scalar case: A bit faster than the above template
606  vector<TMBad::Scalar> solve(const vector<TMBad::Scalar> &h,
607  const vector<TMBad::Scalar> &x) {
608  sparse_plus_lowrank<TMBad::Scalar> H = as_matrix(h);
609  llt_factorize(H);
610  return llt_solve(H, x.matrix()).array();
611  }
612  // Helper to get determinant: det(H)*det(H0)*det(M)
613  template<class T>
614  tmbutils::matrix<T> getH0M(std::shared_ptr<jacobian_sparse_plus_lowrank_t<> > ptr,
615  const sparse_plus_lowrank<T> &h) {
616  vector<T> s =
618  h.G.cols()).
619  solve(h.Hvec, h.G.vec());
620  tmbutils::matrix<T> W = s.matrix();
621  W.resize(n, W.size() / n);
622  tmbutils::matrix<T> H0 = h.H0.array();
623  tmbutils::matrix<T> Gt = h.G.transpose();
625  H0M.diagonal().array() += T(1.);
626  return H0M;
627  }
628 };
629 
630 /* ======================================================================== */
631 /* === Newton solver ====================================================== */
632 /* ======================================================================== */
633 
634 /* --- Configuration ------------------------------------------------------ */
635 
639  int maxit;
645  int trace;
647  double grad_tol;
649  double step_tol;
651  double tol10;
653  double mgcmax;
655  double ustep;
657  double power;
659  double u0;
669  bool sparse;
671  bool lowrank;
672  bool decompose;
674  bool simplify;
687  bool SPA;
688  void set_defaults(SEXP x = R_NilValue) {
689 #define SET_DEFAULT(name, value) set_from_real(x, name, #name, value)
690  SET_DEFAULT(maxit, 1000);
691  SET_DEFAULT(max_reject, 10);
692  SET_DEFAULT(ok_exit_if_pdhess, 1);
693  SET_DEFAULT(trace, 0);
694  SET_DEFAULT(grad_tol, 1e-8);
695  SET_DEFAULT(step_tol, 1e-8);
696  SET_DEFAULT(tol10, 0.001);
697  SET_DEFAULT(mgcmax, 1e+60);
698  SET_DEFAULT(ustep, 1);
699  SET_DEFAULT(power, 0.5);
700  SET_DEFAULT(u0, 1e-04);
701  SET_DEFAULT(sparse, false);
702  SET_DEFAULT(lowrank, false);
703  SET_DEFAULT(decompose, true);
704  SET_DEFAULT(simplify, true);
705  SET_DEFAULT(on_failure_return_nan, true);
706  SET_DEFAULT(on_failure_give_warning, true);
707  SET_DEFAULT(signif_abs_reduction, 1e-6);
708  SET_DEFAULT(signif_rel_reduction, .5);
709  SET_DEFAULT(SPA, false);
710 #undef SET_DEFAULT
711  }
712  newton_config() {
713  set_defaults();
714  }
715  newton_config(SEXP x) {
716  set_defaults(x);
717  }
718  template<class T>
719  void set_from_real(SEXP x, T &target, const char* name, double value) {
720  SEXP y = getListElement(x, name);
721  target = (T) ( y != R_NilValue ? REAL(y)[0] : value );
722  }
723 };
724 template <class Type>
725 struct newton_config_t : newton_config {
726  newton_config_t() : newton_config() {}
727  newton_config_t(SEXP x) : newton_config(x) {}
728 };
729 
730 /* --- Newton Operator ---------------------------------------------------- */
731 
765 template<class Functor, class Hessian_Type=jacobian_dense_t<> >
767  static const bool have_input_size_output_size = true;
768  static const bool add_forward_replay_copy = true;
769  typedef TMBad::Scalar Scalar;
771  TMBad::ADFun<> function, gradient;
772  std::shared_ptr<Hessian_Type> hessian;
773  // Control convergence
774  newton_config cfg;
775  // Outer parameters
776  std::vector<TMBad::ad_aug> par_outer;
782  NewtonOperator(Functor &F, vector<TMBad::ad_aug> start, newton_config cfg)
783  : cfg(cfg)
784  {
785  // Create tape of the user functor and optimize the tape
786  function = TMBad::ADFun<> ( FunctorExtend(F), start);
787  function.optimize();
788  // The tape may contain expressions that do not depend on the
789  // inner parameters (RefOp and expressions that only depend on
790  // these). Move such expressions to the parent context?
791  if (cfg.decompose) {
792  function.decompose_refs();
793  }
794  // The previous operation does not change the domain vector size.
795  size_t n_inner = function.Domain();
796  TMBAD_ASSERT(n_inner == (size_t) start.size());
797  // Turn remaining references to parent contexts into outer
798  // parameters. This operation increases function.Domain()
799  par_outer = function.resolve_refs();
800  // Mark inner parameter subset in full parameter vector
801  std::vector<bool> keep_inner(n_inner, true);
802  keep_inner.resize(function.Domain(), false);
803  // Gradient function
804  gradient = function.JacFun(keep_inner);
805  if (cfg.simplify) {
806  // Masks
807  std::vector<bool> active = gradient.activeDomain();
808  for (size_t i=0; i<n_inner; i++) active[i] = true; // just in case ...
809  size_t num_inactive = std::count(active.begin(), active.end(), false);
810  if (cfg.trace) {
811  std::cout << "Dead gradient args to 'simplify': ";
812  std::cout << num_inactive << "\n";
813  }
814  if (num_inactive > 0) {
815  function.DomainReduce(active);
816  gradient.DomainReduce(active);
817  std::vector<bool> active_outer(active.begin() + n_inner, active.end());
818  par_outer = TMBad::subset(par_outer, active_outer);
819  TMBAD_ASSERT(n_inner == (size_t) function.inner_inv_index.size());
820  function.optimize();
821  }
822  }
823  gradient.optimize();
824  // Hessian
825  hessian = std::make_shared<Hessian_Type>(function, gradient, n_inner);
826  hessian -> optimize();
827  }
828  // Helper to swap inner/outer
829  void SwapInner() {
830  function.SwapInner();
831  gradient.SwapInner();
832  hessian -> SwapInner();
833  }
834  void SwapOuter() {
835  function.SwapOuter();
836  gradient.SwapOuter();
837  hessian -> SwapOuter();
838  }
839  // Put it self on tape
840  vector<TMBad::ad_aug> add_to_tape() {
842  std::vector<TMBad::ad_aug> sol = solver(par_outer);
843  // Append outer paramaters to solution
844  sol.insert(sol.end(), par_outer.begin(), par_outer.end());
845  return sol;
846  }
847  /* From TMB::newton */
848  double phi(double u) {
849  return 1. / u - 1.;
850  }
851  double invphi(double x) {
852  return 1. / (x + 1.);
853  }
854  double increase(double u) {
855  return cfg.u0 + (1. - cfg.u0) * std::pow(u, cfg.power);
856  }
857  double decrease(double u) {
858  return (u > 1e-10 ?
859  1. - increase(1. - u) :
860  (1. - cfg.u0) * cfg.power * u);
861  }
862  vector<Scalar> x_start; // Cached initial guess
863  const char* convergence_fail(const char* msg,
864  vector<Scalar> &x) {
865  if (cfg.on_failure_give_warning) {
866  if (cfg.trace) {
867  Rcout << "Newton convergence failure: " << msg << "\n";
868  }
869  Rf_warning("Newton convergence failure: %s",
870  msg);
871  }
872  if (cfg.on_failure_return_nan) {
873  x.fill(NAN);
874  }
875  return msg;
876  }
877  const char* newton_iterate(vector<Scalar> &x) {
878  int reject_counter = 0;
879  const char* msg = NULL;
880  Scalar f_x = function(x)[0];
881  if (x_start.size() == x.size()) {
882  Scalar f_x_start = function(x_start)[0];
883  if ( ! std::isfinite(f_x_start) &&
884  ! std::isfinite(f_x) ) {
885  return
886  convergence_fail("Invalid initial guess", x);
887  }
888  if (f_x_start < f_x || ! std::isfinite(f_x)) {
889  x = x_start;
890  f_x = f_x_start;
891  }
892  }
893  Scalar f_previous = f_x;
894  if (cfg.trace) std::cout << "f_start=" << f_x << "\n";
895  for (int i=0; i < cfg.maxit; i++) {
896  vector<Scalar> g = gradient(x);
897  Scalar mgc = g.abs().maxCoeff();
898  if ( ! std::isfinite(mgc) ||
899  mgc > cfg.mgcmax) {
900  return
901  convergence_fail("Inner gradient had non-finite components", x);
902  }
903  /* FIXME:
904  if (any(!is.finite(g)))
905  stop("Newton dropout because inner gradient had non-finite components.")
906  if (is.finite(mgcmax) && max(abs(g)) > mgcmax)
907  stop("Newton dropout because inner gradient too steep.")
908  if (max(abs(g)) < grad.tol)
909  return(par)
910  */
911  if (cfg.trace) std::cout << "mgc=" << mgc << " ";
912  if (mgc < cfg.grad_tol) {
913  x_start = x;
914  if (cfg.trace) std::cout << "\n";
915  return msg;
916  }
917  typename Hessian_Type::template MatrixResult<TMBad::Scalar>::type
918  H = (*hessian)(std::vector<Scalar>(x));
919  vector<Scalar> diag_cpy = H.diagonal().array();
920  // Quick ustep reduction based on Hessian diagonal
921  Scalar m = diag_cpy.minCoeff();
922  if (std::isfinite(m) && m < 0) {
923  Scalar ustep_max = invphi(-m);
924  cfg.ustep = std::min(cfg.ustep, ustep_max);
925  }
926  if (cfg.trace) std::cout << "ustep=" << cfg.ustep << " ";
927  while (true) { // FIXME: Infinite loop
928  // H := H + phi * I
929  H.diagonal().array() = diag_cpy;
930  H.diagonal().array() += phi( cfg.ustep );
931  // Try to factorize
932  hessian -> llt_factorize(H);
933  if (hessian -> llt_info() == 0) break;
934  // H not PD ==> Decrease phi
935  cfg.ustep = decrease(cfg.ustep);
936  }
937  // We now have a PD hessian
938  // Let's take a newton step and see if it improves...
939  vector<Scalar> x_new =
940  x - hessian -> llt_solve(H, g).array();
941  Scalar f = function(x_new)[0];
942  // Accept/Reject rules
943  bool accept = std::isfinite(f);
944  if ( ! accept ) {
945  reject_counter++;
946  } else {
947  // Accept if there's a value improvement:
948  accept =
949  (f < f_previous);
950  // OR...
951  if (! accept) {
952  // Accept if relative mgc reduction is substantial without increasing value 'too much'
953  accept =
954  (f - f_previous <= cfg.signif_abs_reduction ) &&
955  vector<Scalar>(gradient(x_new)).abs().maxCoeff() / mgc < 1. - cfg.signif_rel_reduction;
956  }
957  // Assess the quality of the update
958  if ( accept && (f_previous - f > cfg.signif_abs_reduction) ) {
959  reject_counter = 0;
960  } else {
961  reject_counter++;
962  }
963  }
964  // Take action depending on accept/reject
965  if ( accept ) { // Improvement
966  // Accept
967  cfg.ustep = increase(cfg.ustep);
968  f_previous = f;
969  x = x_new;
970  } else { // No improvement
971  // Reject
972  cfg.ustep = decrease(cfg.ustep);
973  }
974  // Handle long runs without improvement
975  if (reject_counter > cfg.max_reject) {
976  if (cfg.ok_exit_if_pdhess) {
977  H = (*hessian)(std::vector<Scalar>(x));
978  // Try to factorize
979  hessian -> llt_factorize(H);
980  bool PD = (hessian -> llt_info() == 0);
981  if (cfg.trace) std::cout << "Trying early exit - PD Hess? " << PD << "\n";
982  if (PD) return msg;
983  }
984  return
985  convergence_fail("Max number of rejections exceeded", x);
986  }
987  // Tracing info
988  if (cfg.trace) std::cout << "f=" << f << " ";
989  if (cfg.trace) std::cout << "reject=" << reject_counter << " ";
990  if (cfg.trace) std::cout << "\n";
991  }
992  return
993  convergence_fail("Iteration limit exceeded", x);
994  }
995  TMBad::Index input_size() const {
996  return function.DomainOuter();
997  }
998  TMBad::Index output_size() const {
999  return function.DomainInner(); // Inner dimension
1000  }
1001  void forward(TMBad::ForwardArgs<Scalar> &args) {
1002  size_t n = function.DomainOuter();
1003  std::vector<Scalar>
1004  x = args.x_segment(0, n);
1005  // Set *outer* parameters
1006  SwapOuter(); // swap
1007  function.DomainVecSet(x);
1008  gradient.DomainVecSet(x);
1009  hessian -> DomainVecSet(x);
1010  SwapOuter(); // swap back
1011  // Run *inner* iterations
1012  SwapInner(); // swap
1013  vector<Scalar> sol = function.DomainVec();
1014  newton_iterate(sol);
1015  SwapInner(); // swap back
1016  args.y_segment(0, sol.size()) = sol;
1017  }
1018  template<class T>
1019  void reverse(TMBad::ReverseArgs<T> &args) {
1020  vector<T>
1021  w = args.dy_segment(0, output_size());
1022  std::vector<T>
1023  sol = args. y_segment(0, output_size());
1024  // NOTE: 'hessian' must have full (inner, outer) vector as input
1025  size_t n = function.DomainOuter();
1026  std::vector<T>
1027  x = args.x_segment(0, n);
1028  std::vector<T> sol_x = sol; sol_x.insert(sol_x.end(), x.begin(), x.end());
1029  vector<T> hv = hessian -> eval(sol_x);
1030  vector<T> w2 = - hessian -> solve(hessian, hv, w);
1031  vector<T> g = gradient.Jacobian(sol_x, w2);
1032  args.dx_segment(0, n) += g.tail(n);
1033  }
1034  template<class T>
1035  void forward(TMBad::ForwardArgs<T> &args) { TMBAD_ASSERT(false); }
1036  void reverse(TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); }
1037  const char* op_name() { return "Newton"; }
1038  void print(TMBad::global::print_config cfg) {
1039  Rcout << cfg.prefix << "======== function:\n";
1040  function.print(cfg);
1041  Rcout << cfg.prefix << "======== gradient:\n";
1042  gradient.print(cfg);
1043  Rcout << cfg.prefix << "======== hessian:\n";
1044  hessian -> print(cfg);
1045  }
1046 };
1047 
1049 
1050 template<class Factorization=DEFAULT_SPARSE_FACTORIZATION >
1051 struct InvSubOperator : TMBad::global::DynamicOperator< -1, -1> {
1052  static const bool have_input_size_output_size = true;
1053  static const bool add_forward_replay_copy = true;
1054  typedef TMBad::Scalar Scalar;
1055  Eigen::SparseMatrix<Scalar> hessian; // Pattern
1056  std::shared_ptr< Factorization > llt; // Factorization
1057  INVERSE_SUBSET_TEMPLATE<double> ihessian;
1058  //typedef Eigen::AutoDiffScalar<Eigen::Array<double, 1, 1> > ad1;
1059  typedef atomic::tiny_ad::variable<1,1> ad1;
1060  INVERSE_SUBSET_TEMPLATE<ad1> D_ihessian;
1061  InvSubOperator(const Eigen::SparseMatrix<Scalar> &hessian,
1062  std::shared_ptr< Factorization > llt) :
1063  hessian(hessian), llt(llt), ihessian(llt), D_ihessian(llt) { }
1064  TMBad::Index input_size() const {
1065  return hessian.nonZeros();
1066  }
1067  TMBad::Index output_size() const {
1068  return hessian.nonZeros();
1069  }
1070  void forward(TMBad::ForwardArgs<Scalar> &args) {
1071  size_t n = input_size();
1072  std::vector<Scalar>
1073  x = args.x_segment(0, n);
1074  Eigen::SparseMatrix<Scalar> h = pattern(hessian, x);
1075  llt->factorize(h); // Update shared factorization
1076  h = ihessian(h);
1077  args.y_segment(0, n) = h.valuePtr();
1078  }
1079  void reverse(TMBad::ReverseArgs<Scalar> &args) {
1080  size_t n = input_size();
1081  std::vector<Scalar> x = args. x_segment(0, n);
1082  std::vector<Scalar> dy = args.dy_segment(0, n);
1083  Eigen::SparseMatrix<Scalar> dy_mat = pattern(hessian, dy);
1084  // Symmetry correction (range direction)
1085  dy_mat.diagonal() *= 2.; dy_mat *= .5;
1086  std::vector<ad1> x_ (n);
1087  for (size_t i=0; i<n; i++) {
1088  x_[i].value = x[i];
1089  x_[i].deriv[0] = dy_mat.valuePtr()[i];
1090  }
1091  Eigen::SparseMatrix<ad1> h_ = pattern(hessian, x_);
1092  // Inverse subset
1093  h_ = D_ihessian(h_);
1094  // Symmetry correction
1095  h_.diagonal() *= .5; h_ *= 2.;
1096  // Gather result
1097  std::vector<Scalar> dx(n);
1098  for (size_t i=0; i<n; i++) {
1099  dx[i] = h_.valuePtr()[i].deriv[0];
1100  }
1101  args.dx_segment(0, n) += dx;
1102  }
1103  template<class T>
1104  void reverse(TMBad::ReverseArgs<T> &args) {
1105  Rf_error("Inverse subset: order 2 not yet implemented (try changing config())");
1106  }
1107  template<class T>
1108  void forward(TMBad::ForwardArgs<T> &args) { TMBAD_ASSERT(false); }
1109  void reverse(TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); }
1110  const char* op_name() { return "InvSub"; }
1111 };
1112 template<class Factorization=DEFAULT_SPARSE_FACTORIZATION >
1113 struct LogDetOperator : TMBad::global::DynamicOperator< -1, -1> {
1114  static const bool have_input_size_output_size = true;
1115  static const bool add_forward_replay_copy = true;
1116  typedef TMBad::Scalar Scalar;
1117  Eigen::SparseMatrix<Scalar> hessian; // Pattern
1118  std::shared_ptr< Factorization > llt; // Factorization
1119  INVERSE_SUBSET_TEMPLATE<double> ihessian;
1120  LogDetOperator(const Eigen::SparseMatrix<Scalar> &hessian,
1121  std::shared_ptr< Factorization > llt) :
1122  hessian(hessian), llt(llt), ihessian(llt) { }
1123  TMBad::Index input_size() const {
1124  return hessian.nonZeros();
1125  }
1126  TMBad::Index output_size() const {
1127  return 1;
1128  }
1129  void forward(TMBad::ForwardArgs<Scalar> &args) {
1130  size_t n = input_size();
1131  std::vector<Scalar>
1132  x = args.x_segment(0, n);
1133  Eigen::SparseMatrix<Scalar> h = pattern(hessian, x);
1134  llt->factorize(h);
1135  // Get out if factorization went wrong
1136  if (llt->info() != 0) {
1137  args.y(0) = R_NaN;
1138  return;
1139  }
1140  args.y(0) = logDeterminant(*llt);
1141  }
1142  void reverse(TMBad::ReverseArgs<Scalar> &args) {
1143  size_t n = input_size();
1144  // Get out if factorization went wrong
1145  if (llt->info() != 0) {
1146  for (size_t i=0; i<n; i++) args.dx(i) = R_NaN;
1147  return;
1148  }
1149  std::vector<Scalar> x = args.x_segment(0, n);
1150  Eigen::SparseMatrix<Scalar> ih = pattern(hessian, x);
1151  // Inverse subset
1152  ih = ihessian(ih);
1153  // Symmetry correction
1154  ih.diagonal() *= .5; ih *= 2.;
1155  ih *= args.dy(0);
1156  args.dx_segment(0, n) += ih.valuePtr();
1157  }
1158  void reverse(TMBad::ReverseArgs<TMBad::ad_aug> &args) {
1159  size_t n = input_size();
1161  std::vector<TMBad::ad_aug> x = args.x_segment(0, n);
1162  std::vector<TMBad::ad_aug> y = IS(x);
1163  Eigen::SparseMatrix<TMBad::ad_aug> ih = pattern(hessian, y);
1164  // Symmetry correction
1165  ih.diagonal() *= .5; ih *= 2.;
1166  ih *= args.dy(0);
1167  args.dx_segment(0, n) += ih.valuePtr();
1168  }
1169  template<class T>
1170  void forward(TMBad::ForwardArgs<T> &args) { TMBAD_ASSERT(false); }
1171  void reverse(TMBad::ReverseArgs<TMBad::Writer> &args) { TMBAD_ASSERT(false); }
1172  const char* op_name() { return "logDet"; }
1173 };
1174 template<class Type>
1175 Type log_determinant_simple(const Eigen::SparseMatrix<Type> &H) {
1176  // FIXME: Tape once for 'reasonable' numeric values - then replay
1177  // (to avoid unpredictable brancing issues)
1178  Eigen::SimplicialLDLT< Eigen::SparseMatrix<Type> > ldl(H);
1179  //return ldl.vectorD().log().sum();
1180  vector<Type> D = ldl.vectorD();
1181  return D.log().sum();
1182 }
1183 template<class Type>
1184 Type log_determinant(const Eigen::SparseMatrix<Type> &H,
1185  std::shared_ptr< jacobian_sparse_default_t > ptr) {
1186  if (!config.tmbad.atomic_sparse_log_determinant)
1187  return log_determinant_simple(H);
1188  const Type* vptr = H.valuePtr();
1189  size_t n = H.nonZeros();
1190  std::vector<Type> x(vptr, vptr + n);
1191  TMBad::global::Complete<LogDetOperator<> > LD(pattern<double>(H), ptr->llt);
1192  std::vector<Type> y = LD(x);
1193  return y[0];
1194 }
1195 template<class Type>
1196 Type log_determinant(const Eigen::SparseMatrix<Type> &H) {
1197  const Type* vptr = H.valuePtr();
1198  size_t n = H.nonZeros();
1199  std::vector<Type> x(vptr, vptr + n);
1200  Eigen::SparseMatrix<double> H_pattern = pattern<double>(H);
1201  std::shared_ptr< DEFAULT_SPARSE_FACTORIZATION > llt =
1202  std::make_shared< DEFAULT_SPARSE_FACTORIZATION > (H_pattern);
1203  TMBad::global::Complete<LogDetOperator<> > LD(H_pattern, llt);
1204  std::vector<Type> y = LD(x);
1205  return y[0];
1206 }
1207 inline double log_determinant(const Eigen::SparseMatrix<double> &H) {
1208  DEFAULT_SPARSE_FACTORIZATION llt(H);
1209  return logDeterminant(llt);
1210 }
1211 inline double log_determinant(const Eigen::SparseMatrix<double> &H,
1212  std::shared_ptr<jacobian_sparse_default_t> ptr) {
1213  // FIXME: Use ptr llt
1214  DEFAULT_SPARSE_FACTORIZATION llt(H);
1215  return logDeterminant(llt);
1216 }
1217 
1218 template<class Type, class PTR>
1219 Type log_determinant(const matrix<Type> &H, PTR ptr) {
1220  // FIXME: Depending on TMB atomic
1222 }
1223 template<class Type>
1225  std::shared_ptr<jacobian_sparse_plus_lowrank_t<> > ptr) {
1226  matrix<Type> H0M = (ptr -> getH0M(ptr, H)).array();
1227  return
1228  log_determinant(H.H, ptr->H) +
1229  log_determinant(H0M, NULL);
1230 }
1231 
1232 
1233 // Interface
1234 template<class Newton>
1235 void Newton_CTOR_Hook(Newton &F, const vector<double> &start) {
1236  F.sol = start;
1237  F.newton_iterate(F.sol);
1238 }
1239 template<class Newton>
1240 void Newton_CTOR_Hook(Newton &F, const vector<TMBad::ad_aug> &start) {
1241  F.sol = F.add_to_tape();
1242 }
1243 
1252 template<class Functor, class Type>
1253 struct safe_eval {
1254  Type operator()(Functor &F, vector<Type> x) {
1255  return F(x);
1256  }
1257 };
1258 template<class Functor>
1259 struct safe_eval<Functor, double> {
1260  double operator()(Functor &F, vector<double> x) {
1261  /* double case: Wrap evaluation inside an AD context, just in case
1262  some operations in F adds to tape. */
1263  TMBad::global dummy;
1264  dummy.ad_start();
1265  double ans = asDouble(F(x));
1266  dummy.ad_stop();
1267  return ans;
1268  }
1269 };
1270 
1271 template<class Functor, class Type, class Hessian_Type=jacobian_dense_t<> >
1272 struct NewtonSolver : NewtonOperator<Functor, Hessian_Type > {
1274  typedef typename Hessian_Type::template MatrixResult<Type>::type hessian_t;
1275  vector<Type> sol; // c(sol, par_outer)
1276  size_t n; // Number of inner parameters
1277  Functor& F;
1278  NewtonSolver(Functor &F, vector<Type> start, newton_config cfg) :
1279  Base(F, start, cfg), n(start.size()), F(F) {
1280  Newton_CTOR_Hook(*this, start);
1281  }
1282  // Get solution
1283  operator vector<Type>() const {
1284  return sol.head(n);
1285  }
1286  tmbutils::vector<Type> solution() {
1287  return sol.head(n);
1288  }
1289  Type value() {
1290  if (Base::cfg.simplify) {
1291  return safe_eval<Functor, Type>()(F, solution());
1292  } else {
1293  return Base::function(std::vector<Type>(sol))[0];
1294  }
1295  }
1296  hessian_t hessian() {
1297  return (*(Base::hessian))(std::vector<Type>(sol));
1298  }
1299  Type Laplace() {
1300  double sign = (Base::cfg.SPA ? -1 : 1);
1301  return
1302  sign * value() +
1303  .5 * log_determinant( hessian(),
1304  Base::hessian) -
1305  sign * .5 * log(2. * M_PI) * n;
1306  }
1307 };
1308 
1309 template<class Functor, class Type>
1310 NewtonSolver<Functor,
1311  Type,
1312  jacobian_sparse_t<> > NewtonSparse(
1313  Functor &F,
1314  Eigen::Array<Type, Eigen::Dynamic, 1> start,
1315  newton_config cfg = newton_config() ) {
1316  NewtonSolver<Functor, Type, jacobian_sparse_t<> > ans(F, start, cfg);
1317  return ans;
1318 }
1319 
1320 template<class Functor, class Type>
1321 NewtonSolver<Functor,
1322  Type,
1323  jacobian_dense_t<> > NewtonDense(
1324  Functor &F,
1325  Eigen::Array<Type, Eigen::Dynamic, 1> start,
1326  newton_config cfg = newton_config() ) {
1327  NewtonSolver<Functor, Type, jacobian_dense_t<> > ans(F, start, cfg);
1328  return ans;
1329 }
1330 
1331 template<class Functor, class Type>
1332 NewtonSolver<Functor,
1333  Type,
1334  jacobian_sparse_plus_lowrank_t<> > NewtonSparsePlusLowrank(
1335  Functor &F,
1336  Eigen::Array<Type, Eigen::Dynamic, 1> start,
1337  newton_config cfg = newton_config() ) {
1338  NewtonSolver<Functor, Type, jacobian_sparse_plus_lowrank_t<> > ans(F, start, cfg);
1339  return ans;
1340 }
1341 
1353 template<class Functor, class Type>
1354 vector<Type> Newton(Functor &F,
1355  Eigen::Array<Type, Eigen::Dynamic, 1> start,
1356  newton_config cfg = newton_config() ) {
1357  if (cfg.sparse) {
1358  if (! cfg.lowrank)
1359  return NewtonSparse(F, start, cfg);
1360  else
1361  return NewtonSparsePlusLowrank(F, start, cfg);
1362  }
1363  else
1364  return NewtonDense(F, start, cfg);
1365 }
1366 
1381 template<class Functor, class Type>
1382 Type Laplace(Functor &F,
1383  Eigen::Array<Type, Eigen::Dynamic, 1> &start,
1384  newton_config cfg = newton_config() ) {
1385  if (cfg.sparse) {
1386  if (!cfg.lowrank) {
1387  auto opt = NewtonSparse(F, start, cfg);
1388  start = opt.solution();
1389  return opt.Laplace();
1390  } else {
1391  auto opt = NewtonSparsePlusLowrank(F, start, cfg);
1392  start = opt.solution();
1393  return opt.Laplace();
1394  }
1395  } else {
1396  auto opt = NewtonDense(F, start, cfg);
1397  start = opt.solution();
1398  return opt.Laplace();
1399  }
1400 }
1401 
1402 // Usage: slice<>(F, random).Laplace(cfg);
1403 template <class ADFun = TMBad::ADFun<> >
1404 struct slice {
1405  ADFun &F;
1406  std::vector<TMBad::Index> random;
1407  slice(ADFun &F,
1408  //std::vector<TMBad::ad_aug> x,
1409  std::vector<TMBad::Index> random) :
1410  F(F), random(random) {
1411  TMBAD_ASSERT2(F.Range() == 1,
1412  "Laplace approximation is for scalar valued functions");
1413  }
1414  typedef TMBad::ad_aug T;
1415  std::vector<TMBad::ad_aug> x;
1416  T operator()(const std::vector<T> &x_random) {
1417  for (size_t i=0; i<random.size(); i++)
1418  x[random[i]] = x_random[i];
1419  return F(x)[0];
1420  }
1421  ADFun Laplace_(newton_config cfg = newton_config()) {
1422  ADFun ans;
1423  std::vector<double> xd = F.DomainVec();
1424  x = std::vector<T> (xd.begin(), xd.end());
1425  ans.glob.ad_start();
1426  TMBad::Independent(x);
1427  vector<T> start = TMBad::subset(x, random);
1428  T y = Laplace(*this, start, cfg);
1429  y.Dependent();
1430  ans.glob.ad_stop();
1431  return ans;
1432  }
1433 };
1434 TMBad::ADFun<> Laplace_(TMBad::ADFun<> &F,
1435  const std::vector<TMBad::Index> &random,
1436  newton_config cfg = newton_config() ) CSKIP( {
1437  slice<> S(F, random);
1438  return S.Laplace_(cfg);
1439 } )
1440 
1441 } // End namespace newton
1442 #endif // TMBAD_FRAMEWORK
segment_ref< ReverseArgs, dx_write > dx_segment(Index from, Index size)
segment version
Definition: global.hpp:344
std::vector< T > subset(const std::vector< T > &x, const std::vector< bool > &y)
Vector subset by boolean mask.
Sparse< ADFun > SpJacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0), SpJacFun_config config=SpJacFun_config())
Sparse Jacobian function generator.
Definition: TMBad.hpp:776
bool on_failure_return_nan
Behaviour on convergence failure: Report nan-solution ?
Definition: newton.hpp:676
segment_ref< ReverseArgs, x_read > x_segment(Index from, Index size)
segment version
Definition: global.hpp:336
segment_ref< ForwardArgs, x_read > x_segment(Index from, Index size)
segment version
Definition: global.hpp:293
bool simplify
Detect and apply &#39;dead gradients&#39; simplification.
Definition: newton.hpp:674
Operator with input/output dimension known at compile time.
Definition: global.hpp:1491
Operator to mark intermediate variables on the tape.
Definition: newton.hpp:353
Operator (H, x) -> solve(H, x)
Definition: newton.hpp:109
double signif_rel_reduction
Consider this relative reduction &#39;significant&#39;.
Definition: newton.hpp:682
bool lowrank
Detect an additional low rank contribution in sparse case?
Definition: newton.hpp:671
double mgcmax
Consider initial guess as invalid if the max gradient component is larger than this number...
Definition: newton.hpp:653
segment_ref< ForwardArgs, y_write > y_segment(Index from, Index size)
segment version
Definition: global.hpp:297
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
Definition: TMBad.cpp:690
Type Laplace(Functor &F, Eigen::Array< Type, Eigen::Dynamic, 1 > &start, newton_config cfg=newton_config())
Tape a functor and return Laplace Approximation.
Definition: newton.hpp:1382
Decomposition of computational graph.
Definition: TMBad.hpp:15
ad_plain add_to_stack(Scalar result=0)
Add nullary operator to the stack based on its result
Definition: global.hpp:2448
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
Definition: global.hpp:311
double signif_abs_reduction
Consider this absolute reduction &#39;significant&#39;.
Definition: newton.hpp:680
ADFun JacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0))
Get Jacobian function object.
Definition: TMBad.hpp:680
double step_tol
Convergence tolerance of consequtive function evaluations (not yet used)
Definition: newton.hpp:649
Generalized newton solver similar to TMB R function &#39;newton&#39;.
Definition: newton.hpp:766
Access input/output values during a forward pass. Write access granted for the output value only...
Definition: global.hpp:279
bool SPA
Modify Laplace approximation to return saddlepoint approximation?
Definition: newton.hpp:687
Newton configuration parameters.
Definition: newton.hpp:637
void ad_stop()
Stop ad calculations from being piped to this glob.
Definition: TMBad.cpp:2073
Automatic differentiation function object.
Definition: TMBad.hpp:117
int ok_exit_if_pdhess
max_reject exceeded is convergence success provided that Hessian is PD?
Definition: newton.hpp:643
double tol10
Convergence tolerance of consequtive function evaluations (not yet used)
Definition: newton.hpp:651
vector< T > crossprod(const vector< T > &y2, const vector< T > &y)
Sparsity restricted cross product In dense case this is the usual cross product.
Definition: newton.hpp:221
Configuration of print method.
Definition: global.hpp:1479
TMBad::ad_plain Tag(const TMBad::ad_plain &x)
Mark a variable during taping.
segment_ref< ReverseArgs, dy_read > dy_segment(Index from, Index size)
segment version
Definition: global.hpp:348
std::vector< Scalar > DomainVec()
Get most recent input parameter vector from the tape.
Definition: TMBad.hpp:270
Type min(const vector< Type > &x)
Augmented AD type.
Definition: global.hpp:2831
Highly flexible atomic Newton() solver and Laplace() approximation.
Definition: newton.hpp:59
Methods specific for a sparse hessian.
Definition: newton.hpp:250
CppAD::vector< Type > matinv(CppAD::vector< Type > x)
Atomic version of matrix inversion. Inverts n-by-n matrix by LU-decomposition.
NewtonOperator(Functor &F, vector< TMBad::ad_aug > start, newton_config cfg)
Constructor.
Definition: newton.hpp:782
double u0
Internal parameter controlling ustep updates.
Definition: newton.hpp:659
Type & y(Index j)
j&#39;th output variable of this operator
Definition: global.hpp:287
Position DomainVecSet(const InplaceVector &x)
Set the input parameter vector on the tape.
Definition: TMBad.hpp:355
bool sparse
Use sparse as opposed to dense hessian ?
Definition: newton.hpp:669
Supernodal Cholesky factor with access to protected members.
matrix< Type > hessian(Functor f, vector< Type > x)
Calculate hessian of vector function with scalar values.
Definition: autodiff.hpp:134
std::vector< bool > activeDomain()
Which inputs are affecting some outputs.
Definition: TMBad.hpp:254
void print(print_config cfg=print_config())
Print AD workspace.
Definition: TMBad.hpp:178
Array class used by TMB.
Definition: array.hpp:22
Struct defining the main AD context.
Definition: global.hpp:797
Decomp2< ADFun > decompose(std::vector< Index > nodes)
Decompose this computational graph.
Definition: TMBad.hpp:958
int max_reject
Max number of allowed rejections.
Definition: newton.hpp:641
matrix< Type > matinv(matrix< Type > x)
Matrix inverse.
Interoperability with other vector classes.
Definition: TMBad.hpp:57
matrix< TMBad::Scalar > llt_solve(const Eigen::SparseMatrix< TMBad::Scalar > &H, const matrix< TMBad::Scalar > &x)
Definition: newton.hpp:337
matrix< Type > matmul(matrix< Type > x, matrix< Type > y)
Matrix multiply.
double grad_tol
Convergence tolerance of max gradient component.
Definition: newton.hpp:647
bool atomic_sparse_log_determinant
Use atomic sparse log determinant (faster but limited order) ?
Definition: config.hpp:47
matrix< TMBad::Scalar > llt_solve(const sparse_plus_lowrank< TMBad::Scalar > &h, const matrix< TMBad::Scalar > &x)
Definition: newton.hpp:562
void SwapInner()
Temporarily regard this object as function of inner parameters.
Definition: TMBad.hpp:1088
Type dy(Index j) const
Partial derivative of end result wrt. j&#39;th output variable of this operator.
Definition: global.hpp:326
Operator auto-completion.
Definition: global.hpp:2129
vector< Type > gradient(Functor F, vector< Type > x)
Calculate gradient of vector function with scalar values.
Definition: autodiff.hpp:67
Operator that requires dynamic allocation. Compile time known input/output size.
Definition: global.hpp:1590
CppAD::vector< Type > matmul(CppAD::vector< Type > x)
Atomic version of matrix multiply. Multiplies n1-by-n2 matrix with n2-by-n3 matrix.
double ustep
Initial step size between 0 and 1.
Definition: newton.hpp:655
Methods specific for a sparse plus low rank hessian.
Definition: newton.hpp:457
Methods specific for a dense hessian.
Definition: newton.hpp:182
Matrix class used by TMB.
Definition: tmbutils.hpp:102
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x)
Evaluate the Jacobian matrix.
Definition: TMBad.hpp:484
matrix< TMBad::Scalar > llt_solve(const matrix< TMBad::Scalar > &H, const matrix< TMBad::Scalar > &x)
Definition: newton.hpp:234
Vector class used by TMB.
Definition: tmbutils.hpp:18
Type & dx(Index j)
Partial derivative of end result wrt. j&#39;th input variable of this operator.
Definition: global.hpp:323
void SwapOuter()
Temporarily regard this object as function of outer parameters.
Definition: TMBad.hpp:1095
bool on_failure_give_warning
Behaviour on convergence failure: Throw warning ?
Definition: newton.hpp:678
int maxit
Max number of iterations.
Definition: newton.hpp:639
void optimize()
Tape optimizer.
Definition: TMBad.hpp:195
void ad_start()
Enable ad calulations to be piped to this glob.
Definition: TMBad.cpp:2065
int trace
Print trace info?
Definition: newton.hpp:645
Decomp3< ADFun > HesFun(std::vector< bool > keep_rc=std::vector< bool >(0), bool sparse_1=true, bool sparse_2=true, bool sparse_3=true)
Calculate a sparse plus low rank representation of the Hessian.
Definition: TMBad.hpp:1285
CppAD::vector< Type > logdet(CppAD::vector< Type > x)
Atomic version of log determinant of positive definite n-by-n matrix.
double power
Internal parameter controlling ustep updates.
Definition: newton.hpp:657
vector< Type > Newton(Functor &F, Eigen::Array< Type, Eigen::Dynamic, 1 > start, newton_config cfg=newton_config())
Tape a functor and return solution.
Definition: newton.hpp:1354
Decomposition of computational graph.
Definition: TMBad.hpp:13
License: GPL v2