TMB Documentation  v1.9.11
TMBad.hpp
1 #ifndef HAVE_TMBAD_HPP
2 #define HAVE_TMBAD_HPP
3 // Autogenerated - do not edit by hand !
4 #include "checkpoint.hpp"
5 #include "global.hpp"
6 #include "graph_transform.hpp"
7 
8 namespace TMBad {
9 
10 template <class ADFun>
11 struct Sparse;
12 template <class ADFun>
13 struct Decomp2;
14 template <class ADFun>
15 struct Decomp3;
16 
17 namespace {
18 
19 template <class I>
20 std::vector<I> cumsum0(const std::vector<bool> &x) {
21  std::vector<I> y(x.size(), 0);
22  for (size_t i = 1; i < x.size(); i++) {
23  y[i] = y[i - 1] + x[i - 1];
24  }
25  return y;
26 }
27 } // namespace
28 
56 template <class Functor, class InterfaceVector>
57 struct StdWrap {
58  Functor &F;
59  typedef typename InterfaceVector::value_type Scalar;
60  InterfaceVector tovec(const InterfaceVector &x) { return x; }
61  InterfaceVector tovec(const Scalar &x) {
62  InterfaceVector y(1);
63  y[0] = x;
64  return y;
65  }
66  StdWrap(Functor &F) : F(F) {}
67  template <class T>
68  std::vector<T> operator()(const std::vector<T> &x) {
69  InterfaceVector xi(x);
70  InterfaceVector yi = tovec(F(xi));
71  std::vector<T> y(yi);
72  return y;
73  }
74 };
75 
79  bool compress;
80  bool index_remap;
81 };
82 
116 template <class ad = ad_aug>
117 struct ADFun {
118  global glob;
119 
121  template <class Functor, class ScalarVector>
122  ADFun(Functor F, const ScalarVector &x_) : force_update_flag(false) {
123  std::vector<ad> x(x_.size());
124  for (size_t i = 0; i < x.size(); i++) x[i] = Value(x_[i]);
125  global *glob_begin = get_glob();
126  this->glob.ad_start();
127  Independent(x);
128  std::vector<ad> y = F(x);
129  Dependent(y);
130  this->glob.ad_stop();
131  global *glob_end = get_glob();
132  TMBAD_ASSERT(glob_begin == glob_end);
133  }
134 
138  template <class Functor>
139  ADFun(Functor F, Scalar x0_) : force_update_flag(false) {
140  global *glob_begin = get_glob();
141  this->glob.ad_start();
142  ad x0(x0_);
143  x0.Independent();
144  ad y0 = F(x0);
145  y0.Dependent();
146  this->glob.ad_stop();
147  global *glob_end = get_glob();
148  TMBAD_ASSERT(glob_begin == glob_end);
149  }
150 
154  template <class Functor>
155  ADFun(Functor F, Scalar x0_, Scalar x1_) : force_update_flag(false) {
156  global *glob_begin = get_glob();
157  this->glob.ad_start();
158  ad x0(x0_);
159  x0.Independent();
160  ad x1(x1_);
161  x1.Independent();
162  ad y0 = F(x0, x1);
163  y0.Dependent();
164  this->glob.ad_stop();
165  global *glob_end = get_glob();
166  TMBAD_ASSERT(glob_begin == glob_end);
167  }
168 
169  ADFun() : force_update_flag(false) {}
170 
171  void forward() { glob.forward(); }
172  void reverse() { glob.reverse(); }
173  void clear_deriv() { glob.clear_deriv(); }
174  Scalar &deriv_inv(Index i) { return glob.deriv_inv(i); }
175  Scalar &deriv_dep(Index i) { return glob.deriv_dep(i); }
176 
178  void print(print_config cfg = print_config()) { glob.print(cfg); }
179 
181  void eliminate() { glob.eliminate(); }
182 
195  void optimize() {
196  TMBAD_ASSERT2(inv_pos.size() == 0,
197  "Tape has 'cached independent variable positions' which "
198  "would be invalidated by the optimizer");
199 
200  std::vector<bool> outer_mask;
201  if (inner_outer_in_use()) {
202  outer_mask = DomainOuterMask();
203  }
204 
206 
207  glob.eliminate();
208 
209  if (inner_outer_in_use()) {
210  TMBAD_ASSERT(outer_mask.size() == Domain());
211  set_inner_outer(*this, outer_mask);
212  }
213  }
223  std::vector<Position> pos = inv_positions(glob);
224  inv_pos = subset(pos, invperm(order(glob.inv_index)));
225  }
237  void reorder(std::vector<Index> last) {
238  std::vector<bool> outer_mask;
239  if (inner_outer_in_use()) {
240  outer_mask = DomainOuterMask();
241  }
242  reorder_graph(glob, last);
243 
244  if (inner_outer_in_use()) {
245  TMBAD_ASSERT(outer_mask.size() == Domain());
246  set_inner_outer(*this, outer_mask);
247  }
248  set_inv_positions();
249  }
250 
251  size_t Domain() const { return glob.inv_index.size(); }
252  size_t Range() const { return glob.dep_index.size(); }
254  std::vector<bool> activeDomain() {
255  std::vector<bool> mark(glob.values.size(), false);
256  for (size_t i = 0; i < glob.dep_index.size(); i++)
257  mark[glob.dep_index[i]] = true;
258  glob.reverse(mark);
259  return subset(mark, glob.inv_index);
260  }
262  std::vector<bool> activeRange() {
263  std::vector<bool> mark(glob.values.size(), false);
264  for (size_t i = 0; i < glob.inv_index.size(); i++)
265  mark[glob.inv_index[i]] = true;
266  glob.forward(mark);
267  return subset(mark, glob.dep_index);
268  }
270  std::vector<Scalar> DomainVec() {
271  std::vector<Scalar> xd(Domain());
272  for (size_t i = 0; i < xd.size(); i++) xd[i] = glob.value_inv(i);
273  return xd;
274  }
277  return IndirectAccessor<Scalar>(glob.values, glob.dep_index);
278  }
280  std::vector<bool> get_keep_var(std::vector<bool> keep_x,
281  std::vector<bool> keep_y) {
282  std::vector<bool> keep_var(glob.values.size(), true);
283  if (keep_x.size() > 0 || keep_y.size() > 0) {
284  if (keep_x.size() == 0) keep_x.resize(glob.inv_index.size(), true);
285  if (keep_y.size() == 0) keep_y.resize(glob.dep_index.size(), true);
286  TMBAD_ASSERT(keep_x.size() == glob.inv_index.size());
287  TMBAD_ASSERT(keep_y.size() == glob.dep_index.size());
288 
289  std::vector<bool> keep_var_init(keep_var.size(), false);
290  for (size_t i = 0; i < glob.inv_index.size(); i++)
291  if (keep_x[i]) keep_var_init[glob.inv_index[i]] = true;
292  for (size_t i = 0; i < glob.dep_index.size(); i++)
293  if (keep_y[i]) keep_var_init[glob.dep_index[i]] = true;
294 
295  std::vector<bool> keep_var_x = keep_var_init;
296  glob.forward(keep_var_x);
297 
298  std::vector<bool> keep_var_y = keep_var_init;
299  glob.reverse(keep_var_y);
300 
301  for (size_t i = 0; i < keep_var.size(); i++)
302  keep_var[i] = keep_var_x[i] && keep_var_y[i];
303  }
304  return keep_var;
305  }
313  std::vector<Position> inv_pos;
315  Position find_pos(Index inv) {
316  for (size_t i = 0; i < inv_pos.size(); i++) {
317  if (inv_pos[i].ptr.second == inv) return inv_pos[i];
318  }
319  return Position(0, 0, 0);
320  }
325  Position tail_start;
331  if (glob.inv_index.size() == 0) return true;
332 
333  bool is_sorted = (inv_pos.size() == 0 && !inner_outer_in_use());
334  return is_sorted && (glob.inv_index.size() ==
335  1 + glob.inv_index.back() - glob.inv_index.front());
336  }
339  void set_tail(const std::vector<Index> &random) {
340  if (inv_pos.size() > 0) {
341  std::vector<Position> pos = subset(inv_pos, random);
342  tail_start = *std::min_element(pos.begin(), pos.end());
343  } else {
344  tail_start = Position(0, 0, 0);
345  }
346  }
349  void unset_tail() { tail_start = Position(0, 0, 0); }
351  void force_update() { force_update_flag = true; }
352  bool force_update_flag;
354  template <class InplaceVector>
355  Position DomainVecSet(const InplaceVector &x) {
356  TMBAD_ASSERT(x.size() == Domain());
357  if (force_update_flag) {
358  for (size_t i = 0; i < x.size(); i++) glob.value_inv(i) = x[i];
359  force_update_flag = false;
360  return Position(0, 0, 0);
361  }
362  if (inv_pos.size() > 0) {
363  if (inner_outer_in_use()) {
364  for (size_t i = 0; i < x.size(); i++) glob.value_inv(i) = x[i];
365  Index min_inv =
366  *std::min_element(glob.inv_index.begin(), glob.inv_index.end());
367  return find_pos(min_inv);
368  }
369  TMBAD_ASSERT(inv_pos.size() == Domain());
370  size_t min_var_changed = -1;
371  size_t i_min = -1;
372  for (size_t i = 0; i < x.size(); i++) {
373  if (glob.value_inv(i) != x[i] && glob.inv_index[i] < min_var_changed) {
374  min_var_changed = glob.inv_index[i];
375  i_min = i;
376  }
377  glob.value_inv(i) = x[i];
378  }
379  if (min_var_changed == (size_t)-1)
380  return glob.end();
381  else
382  return inv_pos[i_min];
383  }
384  if (x.size() > 0) {
385  bool no_change = true;
386  for (size_t i = 0; i < x.size(); i++) {
387  if (glob.value_inv(i) != x[i]) {
388  no_change = false;
389  break;
390  }
391  }
392  if (no_change) return glob.end();
393 
394  for (size_t i = 0; i < x.size(); i++) glob.value_inv(i) = x[i];
395  }
396  return Position(0, 0, 0);
397  }
399  template <class Vector>
400  Vector forward(const Vector &x) {
401  TMBAD_ASSERT((size_t)x.size() == Domain());
402  for (size_t i = 0; i < (size_t)x.size(); i++) glob.value_inv(i) = x[i];
403  glob.forward();
404  Vector y(Range());
405  for (size_t i = 0; i < (size_t)y.size(); i++) y[i] = glob.value_dep(i);
406  return y;
407  }
409  template <class Vector>
410  Vector reverse(const Vector &w) {
411  TMBAD_ASSERT((size_t)w.size() == Range());
412  glob.clear_deriv();
413  for (size_t i = 0; i < (size_t)w.size(); i++) glob.deriv_dep(i) = w[i];
414  glob.reverse();
415  Vector d(Domain());
416  for (size_t i = 0; i < (size_t)d.size(); i++) d[i] = glob.deriv_inv(i);
417  return d;
418  }
420  std::vector<Scalar> operator()(const std::vector<Scalar> &x) {
421  Position start = DomainVecSet(x);
422  glob.forward(start);
423  return RangeVec();
424  }
425 
426  IndirectAccessor<Scalar> operator()(
427  const segment_ref<ForwardArgs<Scalar>, x_read> &x) {
428  Position start = DomainVecSet(x);
429  glob.forward(start);
430  return RangeVec();
431  }
437  std::vector<ad> operator()(const std::vector<ad> &x_) const {
438  std::vector<ad> x(x_.begin(), x_.end());
439  TMBAD_ASSERT(x.size() == Domain());
440  for (size_t i = 0; i < x.size(); i++) {
441  x[i].addToTape();
442  }
443  global *cur_glob = get_glob();
444  for (size_t i = 0; i < x.size(); i++) {
445  TMBAD_ASSERT(x[i].on_some_tape());
446  TMBAD_ASSERT(x[i].glob() == cur_glob);
447  }
448  global::replay replay(this->glob, *get_glob());
449  replay.start();
450  for (size_t i = 0; i < this->Domain(); i++) {
451  replay.value_inv(i) = x[i];
452  }
453  replay.forward(false, false);
454  std::vector<ad> y(this->Range());
455  for (size_t i = 0; i < this->Range(); i++) {
456  y[i] = replay.value_dep(i);
457  }
458  replay.stop();
459  return y;
460  }
463  ad operator()(ad x0) {
464  TMBAD_ASSERT(Domain() == 1);
465  TMBAD_ASSERT(Range() == 1);
466  std::vector<ad> x(1);
467  x[0] = x0;
468  return (*this)(x)[0];
469  }
472  ad operator()(ad x0, ad x1) {
473  TMBAD_ASSERT(Domain() == 2);
474  TMBAD_ASSERT(Range() == 1);
475  std::vector<ad> x(2);
476  x[0] = x0;
477  x[1] = x1;
478  return (*this)(x)[0];
479  }
484  std::vector<Scalar> Jacobian(const std::vector<Scalar> &x) {
485  Position start = DomainVecSet(x);
486  glob.forward(start);
487  std::vector<Scalar> ans(Domain() * Range());
488  for (size_t j = 0; j < Range(); j++) {
489  glob.clear_deriv(tail_start);
490  glob.deriv_dep(j) = 1;
491  glob.reverse(tail_start);
492  for (size_t k = 0; k < Domain(); k++)
493  ans[j * Domain() + k] = glob.deriv_inv(k);
494  }
495  return ans;
496  }
503  std::vector<Scalar> Jacobian(const std::vector<Scalar> &x,
504  std::vector<bool> keep_x,
505  std::vector<bool> keep_y) {
506  std::vector<Scalar> ans;
507 
508  std::vector<bool> keep_var = get_keep_var(keep_x, keep_y);
509 
510  graph G = this->glob.reverse_graph(keep_var);
511 
512  std::vector<size_t> which_keep_x = which(keep_x);
513  std::vector<size_t> which_keep_y = which(keep_y);
514 
515  Position start = DomainVecSet(x);
516  glob.forward(start);
517 
518  for (size_t w = 0; w < which_keep_y.size(); w++) {
519  size_t k = which_keep_y[w];
520 
521  glob.subgraph_seq.resize(0);
522  glob.subgraph_seq.push_back(G.dep2op[k]);
523  G.search(glob.subgraph_seq);
524 
525  glob.clear_deriv_sub();
526  for (size_t l = 0; l < which_keep_x.size(); l++)
527  glob.deriv_inv(which_keep_x[l]) = Scalar(0);
528  glob.deriv_dep(k) = 1.;
529  glob.reverse_sub();
530 
531  for (size_t l = 0; l < which_keep_x.size(); l++) {
532  ans.push_back(glob.deriv_inv(which_keep_x[l]));
533  }
534  }
535  return ans;
536  }
542  std::vector<Scalar> Jacobian(const std::vector<Scalar> &x,
543  const std::vector<Scalar> &w) {
544  TMBAD_ASSERT(x.size() == Domain());
545  TMBAD_ASSERT(w.size() == Range());
546  Position start = DomainVecSet(x);
547  glob.forward(start);
548  glob.clear_deriv();
549  for (size_t j = 0; j < Range(); j++) glob.deriv_dep(j) = w[j];
550  glob.reverse();
551  return IndirectAccessor<Scalar>(glob.derivs, glob.inv_index);
552  }
553 
554  IndirectAccessor<Scalar> Jacobian(
555  const segment_ref<ReverseArgs<Scalar>, x_read> &x,
556  const segment_ref<ReverseArgs<Scalar>, dy_read> &w) {
557  TMBAD_ASSERT(x.size() == Domain());
558  TMBAD_ASSERT(w.size() == Range());
559  Position start = DomainVecSet(x);
560  glob.forward(start);
561  glob.clear_deriv();
562  for (size_t j = 0; j < Range(); j++) glob.deriv_dep(j) = w[j];
563  glob.reverse();
564  return IndirectAccessor<Scalar>(glob.derivs, glob.inv_index);
565  }
566  std::vector<ad> Jacobian(const std::vector<ad> &x_,
567  const std::vector<ad> &w_) {
568  std::vector<ad> x(x_.begin(), x_.end());
569  std::vector<ad> w(w_.begin(), w_.end());
570  global *cur_glob = get_glob();
571 
572  TMBAD_ASSERT(x.size() == Domain());
573  for (size_t i = 0; i < x.size(); i++) {
574  x[i].addToTape();
575  }
576  for (size_t i = 0; i < x.size(); i++) {
577  TMBAD_ASSERT(x[i].on_some_tape());
578  TMBAD_ASSERT(x[i].glob() == cur_glob);
579  }
580 
581  TMBAD_ASSERT(w.size() == Range());
582  for (size_t i = 0; i < w.size(); i++) {
583  w[i].addToTape();
584  }
585  for (size_t i = 0; i < w.size(); i++) {
586  TMBAD_ASSERT(w[i].on_some_tape());
587  TMBAD_ASSERT(w[i].glob() == cur_glob);
588  }
589 
590  global::replay replay(this->glob, *get_glob());
591  replay.start();
592  for (size_t i = 0; i < this->Domain(); i++) {
593  replay.value_inv(i) = x[i];
594  }
595  replay.forward(false, false);
596  replay.clear_deriv();
597  for (size_t i = 0; i < this->Range(); i++) {
598  replay.deriv_dep(i) = w[i];
599  }
600  replay.reverse(false, false);
601  std::vector<ad> dx(this->Domain());
602  for (size_t i = 0; i < dx.size(); i++) {
603  dx[i] = replay.deriv_inv(i);
604  }
605  replay.stop();
606  return dx;
607  }
608  template <bool range_weight>
609  ADFun JacFun_(std::vector<bool> keep_x, std::vector<bool> keep_y) {
610  ADFun ans;
611  if (keep_x.size() == 0) keep_x.resize(Domain(), true);
612  if (keep_y.size() == 0) keep_y.resize(Range(), true);
613  std::vector<bool> keep = get_keep_var(keep_x, keep_y);
614  graph G;
615  if (!range_weight && Range() > 1) {
616  G = this->glob.reverse_graph(keep);
617  }
618  keep = glob.var2op(keep);
619  global::replay replay(this->glob, ans.glob);
620  replay.start();
621  replay.forward(true, false);
622  if (!range_weight) {
623  if (G.empty()) {
624  for (size_t i = 0; i < this->Range(); i++) {
625  if (!keep_y[i]) continue;
626  replay.clear_deriv();
627  replay.deriv_dep(i) = 1.;
628  replay.reverse(false, false, tail_start, keep);
629  for (size_t j = 0; j < this->Domain(); j++) {
630  if (keep_x[j]) replay.deriv_inv(j).Dependent();
631  }
632  }
633  } else {
634  replay.clear_deriv();
635  for (size_t i = 0; i < this->Range(); i++) {
636  if (!keep_y[i]) continue;
637  glob.subgraph_seq.resize(0);
638  glob.subgraph_seq.push_back(G.dep2op[i]);
639  G.search(glob.subgraph_seq);
640  replay.deriv_dep(i) = 1.;
641  replay.reverse_sub();
642  for (size_t j = 0; j < this->Domain(); j++) {
643  if (keep_x[j]) replay.deriv_inv(j).Dependent();
644  }
645  replay.clear_deriv_sub();
646  }
647  }
648  } else {
649  replay.clear_deriv();
650  replay.reverse(false, true, tail_start, keep);
651  for (size_t j = 0; j < this->Domain(); j++) {
652  if (keep_x[j]) replay.deriv_inv(j).Dependent();
653  }
654  }
655  replay.stop();
656  set_inner_outer(ans);
657  return ans;
658  }
680  ADFun JacFun(std::vector<bool> keep_x = std::vector<bool>(0),
681  std::vector<bool> keep_y = std::vector<bool>(0)) {
682  return JacFun_<false>(keep_x, keep_y);
683  }
702  ADFun WgtJacFun(std::vector<bool> keep_x = std::vector<bool>(0),
703  std::vector<bool> keep_y = std::vector<bool>(0)) {
704  return JacFun_<true>(keep_x, keep_y);
705  }
709  std::vector<Scalar> x = DomainVec();
710  return ADFun(F, x);
711  }
717  std::vector<ADFun> parallel_accumulate(size_t num_threads) {
718  TMBAD_ASSERT(Range() == 1);
719  global glob_split = accumulation_tree_split(glob);
720  autopar ap(glob_split, num_threads);
721  ap.do_aggregate = true;
722  ap.keep_all_inv = true;
723  ap.run();
724  ap.extract();
725  std::vector<ADFun> ans(num_threads);
726  for (size_t i = 0; i < num_threads; i++) ans[i].glob = ap.vglob[i];
727  return ans;
728  }
732  ADFun parallelize(size_t num_threads) {
733  TMBAD_ASSERT(Range() == 1);
734  global glob_split = accumulation_tree_split(glob);
735  autopar ap(glob_split, num_threads);
736  ap.do_aggregate = true;
737  ap.keep_all_inv = false;
738  ap.run();
739  ap.extract();
740  global::Complete<ParalOp> f_parallel(ap);
741  ADFun F(f_parallel, DomainVec());
742  aggregate(F.glob);
743  return F;
744  }
750  void replay() { glob.forward_replay(true, true); }
776  Sparse<ADFun> SpJacFun(std::vector<bool> keep_x = std::vector<bool>(0),
777  std::vector<bool> keep_y = std::vector<bool>(0),
778  SpJacFun_config config = SpJacFun_config()) {
779  ADFun atomic_jac_row;
780  std::vector<Index> rowcounts;
781 
782  Sparse<ADFun> ans;
783 
784  ans.m = Range();
785  ans.n = Domain();
786 
787  if (keep_x.size() == 0) keep_x.resize(Domain(), true);
788  if (keep_y.size() == 0) keep_y.resize(Range(), true);
789  std::vector<bool> keep_var = get_keep_var(keep_x, keep_y);
790 
791  size_t keep_x_count = std::count(keep_x.begin(), keep_x.end(), true);
792  size_t keep_y_count = std::count(keep_y.begin(), keep_y.end(), true);
793 
794  graph G = this->glob.reverse_graph(keep_var);
795 
796  global::replay replay(this->glob, ans.glob);
797  replay.start();
798  replay.forward(true, false);
799 
800  Index NA = -1;
801  std::vector<Index> op2inv_idx = glob.op2idx(glob.inv_index, NA);
802 
803  std::fill(keep_var.begin(), keep_var.end(), true);
804 
805  std::vector<Index> col_idx;
806  for (size_t k = 0; k < glob.dep_index.size(); k++) {
807  size_t i = glob.dep_index[k];
808 
809  glob.subgraph_seq.resize(0);
810  glob.subgraph_seq.push_back(G.dep2op[k]);
811  G.search(glob.subgraph_seq);
812 
813  bool do_compress = false;
814  if (config.compress) {
815  if (rowcounts.size() == 0) rowcounts = G.rowcounts();
816 
817  size_t cost1 = 0;
818  for (size_t i = 0; i < glob.subgraph_seq.size(); i++) {
819  cost1 += rowcounts[glob.subgraph_seq[i]];
820  }
821 
822  size_t cost2 = Domain() + Range() + Domain();
823 
824  if (cost2 < cost1) do_compress = true;
825  }
826 
827  if (true) {
828  glob.clear_array_subgraph(keep_var);
829  keep_var[i] = true;
830  glob.reverse_sub(keep_var);
831  }
832 
833  col_idx.resize(0);
834  for (size_t l = 0; l < glob.subgraph_seq.size(); l++) {
835  Index idx = op2inv_idx[glob.subgraph_seq[l]];
836  if (idx != NA) {
837  Index nrep = glob.opstack[glob.subgraph_seq[l]]->output_size();
838  for (Index r = 0; r < nrep; r++) {
839  if (keep_var[glob.inv_index[idx]]) col_idx.push_back(idx);
840  idx++;
841  }
842  }
843  }
844 
845  ans.i.resize(ans.i.size() + col_idx.size(), k);
846  ans.j.insert(ans.j.end(), col_idx.begin(), col_idx.end());
847  if (!do_compress) {
848  replay.clear_deriv_sub();
849 
850  replay.deriv_dep(k) = 1.;
851 
852  replay.reverse_sub();
853 
854  } else {
855  if (atomic_jac_row.Domain() == 0) {
856  Rcout << "Warning: This is an experimental compression method\n";
857  Rcout << "Disable: 'config(tmbad.sparse_hessian_compress=0)'\n";
858  atomic_jac_row = this->WgtJacFun(keep_x, keep_y);
859  atomic_jac_row.optimize();
860 
861  atomic_jac_row.set_inv_positions();
862 
863  atomic_jac_row = atomic_jac_row.atomic();
864 
865  replay.clear_deriv_sub();
866  Rcout << "done\n";
867 
868  TMBAD_ASSERT(atomic_jac_row.Domain() ==
869  this->Domain() + this->Range());
870  TMBAD_ASSERT(atomic_jac_row.Range() == keep_x_count);
871  }
872  std::vector<Replay> vec(atomic_jac_row.Domain(), Replay(0));
873  for (size_t i = 0; i < this->Domain(); i++) {
874  vec[i] = replay.value_inv(i);
875  }
876  vec[this->Domain() + k] = 1.;
877  std::vector<Replay> r = atomic_jac_row(vec);
878  size_t r_idx = 0;
879  for (size_t i = 0; i < this->Domain(); i++) {
880  if (keep_x[i]) replay.deriv_inv(i) = r[r_idx++];
881  }
882  }
883  for (size_t l = 0; l < col_idx.size(); l++) {
884  replay.deriv_inv(col_idx[l]).Dependent();
885  }
886  }
887  replay.stop();
888  if (config.index_remap) {
889  if (keep_x.size() > 0) {
890  std::vector<Index> remap_j = cumsum0<Index>(keep_x);
891  ans.j = TMBad::subset(remap_j, ans.j);
892  ans.n = keep_x_count;
893  }
894  if (keep_y.size() > 0) {
895  std::vector<Index> remap_i = cumsum0<Index>(keep_y);
896  ans.i = TMBad::subset(remap_i, ans.i);
897  ans.m = keep_y_count;
898  }
899  }
900  set_inner_outer(ans);
901  return ans;
902  }
907  ADFun marginal_gk(const std::vector<Index> &random,
908  gk_config cfg = gk_config()) {
909  ADFun ans;
910  old_state os(this->glob);
911  aggregate(this->glob, -1);
912  global glob_split = accumulation_tree_split(this->glob);
913  os.restore();
914  integrate_subgraph<ADFun> i_s(glob_split, random, cfg);
915  ans.glob = i_s.gk();
916  aggregate(ans.glob, -1);
917  return ans;
918  }
920  ADFun marginal_sr(const std::vector<Index> &random, std::vector<sr_grid> grid,
921  const std::vector<Index> &random2grid, bool perm = true) {
922  ADFun ans;
923  old_state os(this->glob);
924  aggregate(this->glob, -1);
925  global glob_split = accumulation_tree_split(this->glob);
926  os.restore();
927  sequential_reduction SR(glob_split, random, grid, random2grid, perm);
928  ans.glob = SR.marginal();
929  aggregate(ans.glob, -1);
930  return ans;
931  }
933  ADFun marginal_sr(const std::vector<Index> &random,
934  sr_grid grid = sr_grid()) {
935  return marginal_sr(random, std::vector<sr_grid>(1, grid),
936  std::vector<Index>(0));
937  }
942  ADFun compose(ADFun other) {
943  TMBAD_ASSERT2(other.Range() == this->Domain(),
944  "Compostion of incompatible functions");
945  struct composition {
946  const ADFun &f;
947  const ADFun &g;
948  composition(const ADFun &f, const ADFun &g) : f(f), g(g) {}
949  std::vector<ad> operator()(std::vector<ad> x) { return f(g(x)); }
950  };
951  composition fg(*this, other);
952  return ADFun(fg, other.DomainVec());
953  }
958  Decomp2<ADFun> decompose(std::vector<Index> nodes) {
959  Decomp2<ADFun> ans;
960  global &glob1 = ans.first.glob;
961  global &glob2 = ans.second.glob;
962 
963  OperatorPure *invop = glob.getOperator<global::InvOp>();
964  std::vector<bool> keep(nodes.size(), true);
965  for (size_t i = 0; i < nodes.size(); i++)
966  if (glob.opstack[nodes[i]] == invop) keep[i] = false;
967  nodes = subset(nodes, keep);
968 
969  glob1 = this->glob;
970  glob1.dep_index.resize(0);
971  std::vector<Index> dep1 = glob1.op2var(nodes);
972  glob1.ad_start();
973  for (size_t i = 0; i < dep1.size(); i++) {
974  ad_plain tmp;
975  tmp.index = dep1[i];
976  tmp.Dependent();
977  }
978  glob1.ad_stop();
979  glob1.eliminate();
980 
981  glob2 = this->glob;
982  substitute(glob2, nodes);
983  glob2.eliminate();
984 
985  set_inner_outer(ans.first);
986  set_inner_outer(ans.second);
987 
988  return ans;
989  }
994  Decomp2<ADFun> decompose(const char *name) {
995  std::vector<Index> nodes = find_op_by_name(this->glob, name);
996  return decompose(nodes);
997  }
1003  if (find_op_by_name(glob, "RefOp").size() == 0) return;
1004 
1005  std::vector<bool> keep_x(Domain(), true);
1006  std::vector<bool> keep_y(Range(), true);
1007  std::vector<bool> vars = get_keep_var(keep_x, keep_y);
1008 
1009  vars = reverse_boundary(glob, vars);
1010 
1011  std::vector<Index> nodes = which<Index>(glob.var2op(vars));
1012 
1013  Decomp2<ADFun> decomp = decompose(nodes);
1014 
1015  size_t n_inner = decomp.first.Domain();
1016  size_t n_outer = decomp.first.Range();
1017 
1018  decomp.first.glob.inv_index.resize(0);
1019 
1020  std::vector<ad_aug> empty;
1021  std::vector<ad_aug> gx = decomp.first(empty);
1022 
1023  ADFun &f = decomp.second;
1024 
1025  f.replay();
1026 
1027  TMBAD_ASSERT(n_inner + n_outer == f.Domain());
1028  TMBAD_ASSERT(find_op_by_name(f.glob, "RefOp").size() == 0);
1029  TMBAD_ASSERT(find_op_by_name(f.glob, "InvOp").size() == f.Domain());
1030  TMBAD_ASSERT(gx.size() == n_outer);
1031 
1032  for (size_t i = 0; i < n_outer; i++) {
1033  Index j = f.glob.inv_index[n_inner + i];
1034 
1035  if (gx[i].constant()) {
1036  f.glob.opstack[j] = glob.getOperator<global::ConstOp>();
1037  } else {
1038  f.glob.opstack[j] = glob.getOperator<global::RefOp>(
1039  gx[i].data.glob, gx[i].taped_value.index);
1040  }
1041  }
1042  f.glob.inv_index.resize(n_inner);
1043 
1044  *this = f;
1045  }
1055  std::vector<ad_aug> resolve_refs() {
1056  TMBAD_ASSERT2(
1057  inner_inv_index.size() == 0 && outer_inv_index.size() == 0,
1058  "'resolve_refs' can only be run once for a given function object")
1059 
1060  ;
1061  std::vector<Index> seq = find_op_by_name(glob, "RefOp");
1062  std::vector<Replay> values(seq.size());
1063  std::vector<Index> dummy_inputs;
1064  ForwardArgs<Replay> args(dummy_inputs, values);
1065  for (size_t i = 0; i < seq.size(); i++) {
1066  TMBAD_ASSERT(glob.opstack[seq[i]]->input_size() == 0);
1067  TMBAD_ASSERT(glob.opstack[seq[i]]->output_size() == 1);
1068  glob.opstack[seq[i]]->forward_incr(args);
1069  glob.opstack[seq[i]]->deallocate();
1070  glob.opstack[seq[i]] = get_glob()->getOperator<global::InvOp>();
1071  }
1072  inner_inv_index = glob.inv_index;
1073  outer_inv_index = glob.op2var(seq);
1074 
1075  glob.inv_index.insert(glob.inv_index.end(), outer_inv_index.begin(),
1076  outer_inv_index.end());
1077  return values;
1078  }
1079  std::vector<Index> inner_inv_index;
1080  std::vector<Index> outer_inv_index;
1082  size_t DomainInner() const { return inner_inv_index.size(); }
1084  size_t DomainOuter() const { return outer_inv_index.size(); }
1088  void SwapInner() {
1089  std::swap(glob.inv_index, inner_inv_index);
1090  force_update();
1091  }
1095  void SwapOuter() {
1096  std::swap(glob.inv_index, outer_inv_index);
1097  force_update();
1098  }
1101  return (DomainInner() > 0) || (DomainOuter() > 0);
1102  }
1104  std::vector<bool> DomainOuterMask() {
1105  std::vector<bool> mark_outer =
1106  glob.mark_space(glob.values.size(), outer_inv_index);
1107  return subset(mark_outer, glob.inv_index);
1108  }
1116  void set_inner_outer(ADFun &ans, const std::vector<bool> &outer_mask) {
1117  if (inner_outer_in_use()) {
1118  std::vector<bool> mark(outer_mask);
1119  mark.resize(ans.Domain(), false);
1120 
1121  ans.outer_inv_index = subset(ans.glob.inv_index, mark);
1122 
1123  mark.flip();
1124 
1125  ans.inner_inv_index = subset(ans.glob.inv_index, mark);
1126  }
1127  }
1128  void set_inner_outer(ADFun &ans) {
1129  if (inner_outer_in_use()) {
1130  set_inner_outer(ans, DomainOuterMask());
1131  }
1132  }
1133  void DomainReduce(const std::vector<bool> &inv_keep) {
1134  std::vector<bool> outer_mask = DomainOuterMask();
1135  outer_mask = subset(outer_mask, inv_keep);
1136  glob.inv_index = subset(glob.inv_index, inv_keep);
1137  set_inner_outer(*this, outer_mask);
1138  }
1144  void inactivate(std::vector<Index> nodes) {
1145  for (size_t i = 0; i < nodes.size(); i++) {
1146  OperatorPure *op = glob.opstack[nodes[i]];
1147  glob.opstack[nodes[i]] = glob.getOperator<global::NullOp2>(
1148  op->input_size(), op->output_size());
1149  op->deallocate();
1150  }
1151  }
1152 };
1164 template <class Functor, class Test = ParametersChanged>
1165 ADFun<> ADFun_retaping(Functor &F, const std::vector<ad_aug> &x,
1166  Test test = Test()) {
1167  typedef retaping_derivative_table<Functor, ADFun<>, Test> DTab;
1168  global::Complete<AtomOp<DTab> > Op(F, x, test);
1169  return ADFun<>(Op, x);
1170 }
1171 
1173 template <class dummy = void>
1175  ADFun<> Fp;
1176  ADFun_packed(const ADFun<> &Fp) : Fp(Fp) {}
1177  ADFun_packed() {}
1178  ad_segment operator()(const std::vector<ad_segment> &x) {
1179  std::vector<ad_segment> xp(x.size());
1180  for (size_t i = 0; i < xp.size(); i++) xp[i] = pack(x[i]);
1181  std::vector<ad_aug> yp = Fp(concat(xp));
1182  return unpack(yp, 0);
1183  }
1184  bool initialized() { return Fp.Domain() != 0; }
1185 };
1193 template <class Functor, class Test>
1194 ADFun_packed<> ADFun_retaping(Functor &F, const std::vector<ad_segment> &x,
1195  Test test) {
1196  static const bool packed = true;
1198  packed>
1199  DTab;
1200  PackWrap<Functor> Fp(F);
1201  std::vector<ad_segment> xp(x.size());
1202  for (size_t i = 0; i < xp.size(); i++) xp[i] = pack(x[i]);
1203  std::vector<ad_aug> xp_ = concat(xp);
1204  PackWrap<Test> testp(test);
1205  global::Complete<AtomOp<DTab> > Op(Fp, xp_, testp);
1206  ADFun<> TapeFp(Op, xp_);
1207  return ADFun_packed<>(TapeFp);
1208 }
1209 
1210 template <class ADFun>
1211 struct Sparse : ADFun {
1212  std::vector<Index> i;
1213  std::vector<Index> j;
1214  Index m;
1215  Index n;
1216  Sparse() {}
1217  Sparse(const ADFun &f) : ADFun(f) {}
1218  std::vector<Index> a2v(const std::valarray<Index> &x) const {
1219  return std::vector<Index>(&x[0], &x[0] + x.size());
1220  }
1221  std::valarray<Index> v2a(const std::vector<Index> &x) const {
1222  return std::valarray<Index>(x.data(), x.size());
1223  }
1224  std::valarray<Index> row() const { return v2a(i); }
1225  std::valarray<Index> col() const { return v2a(j); }
1226  void subset_inplace(const std::valarray<bool> &x) {
1227  i = a2v(row()[x]);
1228  j = a2v(col()[x]);
1229  this->glob.dep_index = a2v(v2a(this->glob.dep_index)[x]);
1230  }
1231  void transpose_inplace() {
1232  std::swap(i, j);
1233  std::swap(m, n);
1234  }
1235 };
1236 
1243 template <class ADFun>
1244 struct Decomp2 : std::pair<ADFun, ADFun> {
1245  struct composition {
1246  typedef ad_aug ad;
1247  const ADFun &f;
1248  const ADFun &g;
1249  composition(const ADFun &f, const ADFun &g) : f(f), g(g) {}
1250  std::vector<ad> operator()(std::vector<ad> x) {
1251  std::vector<ad> y = g(x);
1252  x.insert(x.end(), y.begin(), y.end());
1253  return f(x);
1254  }
1255  };
1256  operator ADFun() {
1257  ADFun &g = this->first;
1258  ADFun &f = this->second;
1259  composition fg(f, g);
1260  return ADFun(fg, g.DomainVec());
1261  }
1285  Decomp3<ADFun> HesFun(std::vector<bool> keep_rc = std::vector<bool>(0),
1286  bool sparse_1 = true, bool sparse_2 = true,
1287  bool sparse_3 = true) {
1288  ADFun &g = this->first;
1289  ADFun &f = this->second;
1290  Decomp3<ADFun> ans;
1291  TMBAD_ASSERT(f.Range() == 1);
1292 
1293  std::vector<bool> keep_f = std::vector<bool>(f.Range(), true);
1294  std::vector<bool> keep_g = std::vector<bool>(g.Range(), true);
1295 
1296  typedef ad_aug ad;
1297  global &glob = ans.first.glob;
1298  glob.ad_start();
1299  std::vector<Scalar> x_ = f.DomainVec();
1300  size_t k = g.Range();
1301  size_t n = f.Domain() - k;
1302 
1303  std::vector<bool> mask_x(f.Domain(), false);
1304  for (size_t i = 0; i < n; i++) mask_x[i] = true;
1305  std::vector<bool> mask_s(mask_x);
1306  mask_s.flip();
1307 
1308  std::vector<ad> x(x_.begin(), x_.end() - k);
1309  Independent(x);
1310  std::vector<ad> s = g(x);
1311  std::vector<ad> s0(s.size());
1312 
1313  for (size_t i = 0; i < s.size(); i++) s0[i] = s[i].copy0();
1314  std::vector<ad> xs(x);
1315  xs.insert(xs.end(), s.begin(), s.end());
1316  std::vector<ad> xs0(x);
1317  xs0.insert(xs0.end(), s0.begin(), s0.end());
1318  if (false) {
1319  TMBAD_ASSERT(keep_rc.size() == n || keep_rc.size() == 0);
1320  std::vector<bool> keep_xy(keep_rc);
1321  keep_xy.resize(f.Domain(), true);
1322  ADFun f_grad = f.JacFun(keep_xy, keep_f);
1323  }
1324  ADFun f_grad = f.JacFun();
1325  std::vector<ad> z = subset(f_grad(xs), mask_x);
1326  std::vector<ad> z0 = subset(f_grad(xs0), mask_s);
1327  std::vector<ad> xw(x);
1328  xw.insert(xw.end(), z0.begin(), z0.end());
1329  std::vector<ad> z1 = g.WgtJacFun()(xw);
1330  for (size_t i = 0; i < n; i++) z[i] += z1[i];
1331  Dependent(z);
1332  glob.ad_stop();
1333  glob.eliminate();
1334  ans.first.glob = glob;
1335 
1336  if (sparse_1) {
1337  ans.first = ans.first.SpJacFun(keep_rc, keep_rc);
1338  } else {
1339  ans.first = ans.first.JacFun(keep_rc, keep_rc);
1340  }
1341  ans.first.glob.eliminate();
1342  f.set_inner_outer(ans.first);
1343 
1344  if (sparse_2) {
1345  ans.second = g.SpJacFun(keep_rc);
1346  } else {
1347  ans.second = g.JacFun(keep_rc);
1348  }
1349  ans.second.glob.eliminate();
1350 
1351  Sparse<ADFun> B;
1352  if (sparse_3) {
1353  B = f_grad.SpJacFun(mask_s, mask_s);
1354  } else {
1355  B = f_grad.JacFun(mask_s, mask_s);
1356  }
1357  ans.third.glob.ad_start();
1358  std::vector<ad> xx(x_.begin(), x_.end() - k);
1359  Independent(xx);
1360  s = g(xx);
1361  xs = xx;
1362  xs.insert(xs.end(), s.begin(), s.end());
1363  z = B(xs);
1364  Dependent(z);
1365  ans.third.glob.ad_stop();
1366  ans.third.glob.eliminate();
1367  ans.third.i = B.i;
1368  ans.third.j = B.j;
1369  f.set_inner_outer(ans.third);
1370 
1371  return ans;
1372  }
1373 };
1374 
1384 template <class ADFun>
1385 struct Decomp3 : Decomp2<Sparse<ADFun> > {
1386  Sparse<ADFun> third;
1387 };
1388 
1389 } // namespace TMBad
1390 #endif // HAVE_TMBAD_HPP
Automatic differentiation library designed for TMB.
Definition: TMB.hpp:157
std::vector< bool > get_keep_var(std::vector< bool > keep_x, std::vector< bool > keep_y)
Get necessary variables to keep for given input/output selection.
Definition: TMBad.hpp:280
std::vector< Index > op2var(const std::vector< Index > &seq)
Get variables produces by a node seqence.
Definition: TMBad.cpp:1435
std::vector< T > subset(const std::vector< T > &x, const std::vector< bool > &y)
Vector subset by boolean mask.
graph reverse_graph(std::vector< bool > keep_var=std::vector< bool >(0))
Construct operator graph with reverse connections.
Definition: TMBad.cpp:1584
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
global accumulation_tree_split(global glob, bool sum_=false)
Split a computational graph by it&#39;s accumulation tree.
Definition: TMBad.cpp:3613
virtual Index output_size()=0
Number of outputs from this OperatorPure.
Decomp2< ADFun > decompose(const char *name)
Decompose this computational graph by operator name.
Definition: TMBad.hpp:994
std::vector< bool > DomainOuterMask()
Helper: Boolean mask of outer parameters.
Definition: TMBad.hpp:1104
ADFun WgtJacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0))
Get weighted Jacobian function object.
Definition: TMBad.hpp:702
std::vector< ad_aug > resolve_refs()
Resolve references of this ADFun object.
Definition: TMBad.hpp:1055
void forward_replay(bool inv_tags=true, bool dep_tags=true)
Replay this operation sequence to itself.
Definition: TMBad.cpp:1221
ADFun(Functor F, Scalar x0_, Scalar x1_)
Constructor of 2 scalar input / 1 scalar output function.
Definition: TMBad.hpp:155
void reverse(Position start=Position(0, 0, 0))
Full or partial reverse sweep through the operation stack. Updates global::derivs.
Definition: TMBad.cpp:1015
void forward(Position start=Position(0, 0, 0))
Full or partial forward sweep through the operation stack. Updates global::values.
Definition: TMBad.cpp:1005
std::vector< T > invperm(const std::vector< T > &perm)
Inverse permutation.
IndirectAccessor< Scalar > RangeVec()
Get most recent result vector from the tape.
Definition: TMBad.hpp:276
void reorder_graph(global &glob, std::vector< Index > inv_idx)
Reorder computational graph such that selected independent variables come last.
Definition: TMBad.cpp:4456
ADFun parallelize(size_t num_threads)
Parallelize this operation sequence.
Definition: TMBad.hpp:732
operation_stack opstack
Operation stack.
Definition: global.hpp:937
bool keep_all_inv
Keep all independent variables for each thread?
ADFun atomic()
Turn this operation sequence into an atomic operator.
Definition: TMBad.hpp:707
Position end()
The three pointers defining the end of the tape.
Definition: TMBad.cpp:999
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
Definition: TMBad.cpp:690
Decomposition of computational graph.
Definition: TMBad.hpp:15
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
Definition: global.hpp:311
void unset_tail()
Inactivate tail sweep to get derivatives wrt all independent variables.
Definition: TMBad.hpp:349
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
std::vector< Scalar > values
Contiguous workspace for taped variables (same length as global::derivs)
Definition: global.hpp:940
Vector forward(const Vector &x)
Forward sweep any vector class.
Definition: TMBad.hpp:400
void set_inv_positions()
Cache tape positions of independent variables.
Definition: TMBad.hpp:222
Contiguous set of variables on the current tape.
Definition: global.hpp:2780
ADFun marginal_sr(const std::vector< Index > &random, std::vector< sr_grid > grid, const std::vector< Index > &random2grid, bool perm=true)
Integrate using sequential reduction.
Definition: TMBad.hpp:920
Provide inplace read access to value or derivative arrays.
Definition: global.hpp:184
ad operator()(ad x0)
Evaluate function scalar version.
Definition: TMBad.hpp:463
void set_tail(const std::vector< Index > &random)
Set start position needed to get selected independent variable derivatives.
Definition: TMBad.hpp:339
Sequential reduction algorithm.
Transform a functor to have packed input/output.
Definition: checkpoint.hpp:253
void ad_stop()
Stop ad calculations from being piped to this glob.
Definition: TMBad.cpp:2073
Automatic differentiation function object.
Definition: TMBad.hpp:117
Scalar & value_dep(Index i)
Reference to i&#39;th component of the function value.
Definition: TMBad.cpp:993
void eliminate()
Dead operator elimination.
Definition: TMBad.hpp:181
std::vector< bool > activeRange()
Which outputs are affected by some inputs.
Definition: TMBad.hpp:262
ADFun compose(ADFun other)
Construct function composition.
Definition: TMBad.hpp:942
Configuration of print method.
Definition: global.hpp:1479
std::vector< Scalar > DomainVec()
Get most recent input parameter vector from the tape.
Definition: TMBad.hpp:270
The abstract operator for the operation stack global::opstack
Definition: global.hpp:811
std::vector< Index > op2idx(const std::vector< Index > &var_subset, Index NA=(Index) -1)
General operator -> variable table generator.
Definition: TMBad.cpp:1462
Augmented AD type.
Definition: global.hpp:2831
std::vector< bool > mark_space(size_t n, const std::vector< Index > ind)
General boolean table generator.
Definition: TMBad.cpp:1473
std::vector< ad > operator()(const std::vector< ad > &x_) const
Evaluate function for ad vector input.
Definition: TMBad.hpp:437
Position tail_start
Mark the tail of the operation sequence A &#39;tail sweep&#39; is on the subsequence tail_start:end. Only used by teh reverse sweep.
Definition: TMBad.hpp:325
std::vector< Index > inv_index
Pointers into global::values determining independent variables.
Definition: global.hpp:948
void reorder(std::vector< Index > last)
Reorder computational graph to allow quick updates of selected inputs.
Definition: TMBad.hpp:237
std::vector< bool > reverse_boundary(global &glob, const std::vector< bool > &vars)
Find boundary without using the graph.
Definition: TMBad.cpp:3540
std::vector< Index > substitute(global &glob, const std::vector< Index > &seq, bool inv_tags=true, bool dep_tags=true)
substitute node index sequence by independent variables
Definition: TMBad.cpp:3584
Position DomainVecSet(const InplaceVector &x)
Set the input parameter vector on the tape.
Definition: TMBad.hpp:355
std::vector< I > which(const std::vector< bool > &x)
Convert logical vector to index vector.
std::vector< bool > activeDomain()
Which inputs are affecting some outputs.
Definition: TMBad.hpp:254
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x, const std::vector< Scalar > &w)
Evaluate the Jacobian matrix multiplied by a vector.
Definition: TMBad.hpp:542
Empty operator with inputs and outputs.
Definition: global.hpp:2380
void print(print_config cfg)
Print workspace.
Definition: TMBad.cpp:1769
void print(print_config cfg=print_config())
Print AD workspace.
Definition: TMBad.hpp:178
std::vector< Index > remap_identical_sub_expressions(global &glob, std::vector< Index > inv_remap)
Remap identical sub-expressions.
Definition: TMBad.cpp:4303
void search(std::vector< Index > &start, bool sort_input=true, bool sort_output=true)
Find sub graph.
Definition: TMBad.cpp:843
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
Scalar & deriv_inv(Index i)
Reference to i&#39;th component of the gradient.
Definition: TMBad.cpp:991
Scalar & deriv_dep(Index i)
Reference to i&#39;th &#39;range direction&#39; used to seed the derivative.
Definition: TMBad.cpp:995
Provide read/write access to an array segment.
Definition: global.hpp:206
Split a computational graph using a simple heuristic.
void aggregate(global &glob, int sign=1)
Reduce a multivariate output function by summing its range components.
Definition: TMBad.cpp:3653
ADFun marginal_gk(const std::vector< Index > &random, gk_config cfg=gk_config())
Integrate as many univariate variables as possible.
Definition: TMBad.hpp:907
Interoperability with other vector classes.
Definition: TMBad.hpp:57
ad operator()(ad x0, ad x1)
Evaluate function scalar version.
Definition: TMBad.hpp:472
Read the current tape&#39;s state and restore it on request.
ad_segment unpack(const ad_segment &x)
Unpack consecutive values on the tape.
Definition: TMBad.cpp:4653
ad_segment pack(const ad_segment &x)
Pack consecutive values on the tape.
Definition: TMBad.cpp:4648
void push_back(OperatorPure *x)
Add new operator to this stack and update bitwise operator information.
Definition: TMBad.cpp:923
Vector reverse(const Vector &w)
Reverse sweep any vector class.
Definition: TMBad.hpp:410
virtual void deallocate()=0
Deallocate this OperatorPure.
void SwapInner()
Temporarily regard this object as function of inner parameters.
Definition: TMBad.hpp:1088
std::vector< Index > dep2op
Used to lookup operator (node) of a dependent variable.
Definition: global.hpp:632
Position find_pos(Index inv)
Helper to find the tape position of an independent variable.
Definition: TMBad.hpp:315
Configuration parameters for SpJacFun()
Definition: TMBad.hpp:77
virtual Index input_size()=0
Number of inputs to this OperatorPure.
std::vector< size_t > order(std::vector< T > x)
Get permutation that sorts a vector.
Operator auto-completion.
Definition: global.hpp:2129
Reference a variable on another tape.
Definition: global.hpp:2408
size_t DomainInner() const
Number of inner parameters.
Definition: TMBad.hpp:1082
Scalar & value_inv(Index i)
Reference to i&#39;th input value (parameter)
Definition: TMBad.cpp:989
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x)
Evaluate the Jacobian matrix.
Definition: TMBad.hpp:484
std::vector< global > vglob
Result: Vector of computational graphs.
void replay()
Replay this operation sequence to a new sequence.
Definition: TMBad.hpp:750
ADFun marginal_sr(const std::vector< Index > &random, sr_grid grid=sr_grid())
Integrate using sequential reduction.
Definition: TMBad.hpp:933
bool inner_outer_in_use()
Helper: Does tape have inner/outer information ?
Definition: TMBad.hpp:1100
void force_update()
Next forward pass must traverse the full graph.
Definition: TMBad.hpp:351
std::vector< Scalar > derivs
Contiguous workspace for derivatives (same length as global::values)
Definition: global.hpp:943
Utilility class for sequential_reduction.
void clear_array_subgraph(Vector &array, typename Vector::value_type value=typename Vector::value_type(0)) const
Generic clear array along global::subgraph.
Definition: global.hpp:1076
std::vector< Scalar > operator()(const std::vector< Scalar > &x)
Evaluate function for scalar vector input.
Definition: TMBad.hpp:420
void clear_deriv(Position start=Position(0, 0, 0))
Set derivatives to zero.
Definition: TMBad.cpp:984
std::vector< Index > find_op_by_name(global &glob, const char *name)
Find nodes by name.
Definition: TMBad.cpp:3573
std::vector< ADFun > parallel_accumulate(size_t num_threads)
Parallel split this operation sequence Split function f:R^n->R by its accumulation tree...
Definition: TMBad.hpp:717
void reverse_sub()
Reverse sweep along a subgraph.
Definition: TMBad.cpp:1029
std::vector< Index > var2op()
Build variable -> operator node lookup table using a single forward pass. The resulting sequence is m...
Definition: TMBad.cpp:1409
bool do_aggregate
Sum up result for each thread?
ADFun ADFun_retaping(Functor &F, const std::vector< ad_aug > &x, Test test=Test())
Construct ADFun that automatically retapes.
Definition: TMBad.hpp:1165
void SwapOuter()
Temporarily regard this object as function of outer parameters.
Definition: TMBad.hpp:1095
void set_inner_outer(ADFun &ans, const std::vector< bool > &outer_mask)
Helper: Pass on inner/outer information to a new tape. Some parameters are marked as &#39;outer parameter...
Definition: TMBad.hpp:1116
Operator graph in compressed row storage.
Definition: global.hpp:617
void clear_deriv_sub()
Clear derivative array along a subgraph.
Definition: TMBad.cpp:1269
ADFun(Functor F, const ScalarVector &x_)
Constructor of vector input / vector output function.
Definition: TMBad.hpp:122
Adaptive derivative table used by AtomOp
Definition: checkpoint.hpp:40
void extract()
Complete the parallel split.
Definition: TMBad.cpp:4177
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x, std::vector< bool > keep_x, std::vector< bool > keep_y)
Evaluate the Jacobian matrix subset
Definition: TMBad.hpp:503
void optimize()
Tape optimizer.
Definition: TMBad.hpp:195
void ad_start()
Enable ad calulations to be piped to this glob.
Definition: TMBad.cpp:2065
bool inv_index_is_consecutive()
Are the independent variable indices consecutive?
Definition: TMBad.hpp:330
void decompose_refs()
Optional optimization step before resolving references.
Definition: TMBad.hpp:1002
size_t DomainOuter() const
Number of outer parameters.
Definition: TMBad.hpp:1084
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
std::vector< Index > dep_index
Pointers into global::values determining dependent variables.
Definition: global.hpp:951
std::vector< Position > inv_pos
Vector of positions by independent variables.
Definition: TMBad.hpp:313
void eliminate()
Very simple tape optimizer.
Definition: TMBad.cpp:1747
Decomposition of computational graph.
Definition: TMBad.hpp:13
ADFun(Functor F, Scalar x0_)
Constructor of 1 scalar input / 1 scalar output function.
Definition: TMBad.hpp:139
Container of ADFun object with packed input and output.
Definition: TMBad.hpp:1174
void inactivate(std::vector< Index > nodes)
Substitute selected operators by void operators.
Definition: TMBad.hpp:1144
License: GPL v2