TMB Documentation  v1.9.11
graph_transform.hpp
1 #ifndef HAVE_GRAPH_TRANSFORM_HPP
2 #define HAVE_GRAPH_TRANSFORM_HPP
3 // Autogenerated - do not edit by hand !
4 #include <cstring>
5 #include <list>
6 #include <map>
7 #include "checkpoint.hpp"
8 #include "global.hpp"
9 #include "integrate.hpp"
10 #include "radix.hpp"
11 
12 namespace TMBad {
13 
18 template <class T>
19 std::vector<bool> lmatch(const std::vector<T> &x, const std::vector<T> &y) {
20  std::vector<bool> ans(x.size(), false);
21  for (size_t i = 0; i < x.size(); i++)
22  for (size_t j = 0; j < y.size(); j++) ans[i] = ans[i] || (x[i] == y[j]);
23  return ans;
24 }
25 
27 template <class I>
28 std::vector<I> which(const std::vector<bool> &x) {
29  std::vector<I> y;
30  for (size_t i = 0; i < x.size(); i++)
31  if (x[i]) y.push_back(i);
32  return y;
33 }
34 
36 std::vector<size_t> which(const std::vector<bool> &x);
37 
39 template <class T>
40 std::vector<T> subset(const std::vector<T> &x, const std::vector<bool> &y) {
41  TMBAD_ASSERT(x.size() == y.size());
42  std::vector<T> ans;
43  for (size_t i = 0; i < x.size(); i++)
44  if (y[i]) ans.push_back(x[i]);
45  return ans;
46 }
47 
49 template <class T, class I>
50 std::vector<T> subset(const std::vector<T> &x, const std::vector<I> &ind) {
51  std::vector<T> ans(ind.size());
52  for (size_t i = 0; i < ind.size(); i++) ans[i] = x[ind[i]];
53  return ans;
54 }
55 
67 template <class T, class I>
68 void make_space_inplace(std::vector<T> &x, std::vector<I> &i, T space = T(0)) {
69  std::vector<bool> mark(x.size(), false);
70  for (size_t k = 0; k < i.size(); k++) {
71  TMBAD_ASSERT(!mark[i[k]]);
72  mark[i[k]] = true;
73  }
74  std::vector<T> x_new;
75  std::vector<I> i_new;
76  for (size_t k = 0; k < x.size(); k++) {
77  if (mark[k]) {
78  x_new.push_back(space);
79  i_new.push_back(x_new.size());
80  }
81  x_new.push_back(x[k]);
82  }
83  std::swap(x, x_new);
84  std::swap(i, i_new);
85 }
86 
88 template <class T>
89 std::vector<T> invperm(const std::vector<T> &perm) {
90  std::vector<T> iperm(perm.size());
91  for (size_t i = 0; i < perm.size(); i++) iperm[perm[i]] = i;
92  return iperm;
93 }
94 
96 template <class T>
97 std::vector<size_t> match(const std::vector<T> &x, const std::vector<T> &y) {
98  return which(lmatch(x, y));
99 }
100 
102 size_t prod_int(const std::vector<size_t> &x);
103 
116 template <class T>
117 std::vector<size_t> order(std::vector<T> x) {
118  std::vector<std::pair<T, size_t> > y(x.size());
119  for (size_t i = 0; i < x.size(); i++) {
120  y[i].first = x[i];
121  y[i].second = i;
122  }
123  sort_inplace(y);
124  std::vector<size_t> z(x.size());
125  for (size_t i = 0; i < x.size(); i++) {
126  z[i] = y[i].second;
127  }
128  return z;
129 }
130 
132 std::vector<bool> reverse_boundary(global &glob, const std::vector<bool> &vars);
133 
141 std::vector<Index> get_accumulation_tree(global &glob, bool boundary = false);
142 
144 std::vector<Index> find_op_by_name(global &glob, const char *name);
145 
149 std::vector<Index> substitute(global &glob, const std::vector<Index> &seq,
150  bool inv_tags = true, bool dep_tags = true);
151 
153 std::vector<Index> substitute(global &glob, const char *name,
154  bool inv_tags = true, bool dep_tags = true);
155 
163 global accumulation_tree_split(global glob, bool sum_ = false);
164 
171 void aggregate(global &glob, int sign = 1);
172 
177 struct old_state {
178  std::vector<Index> dep_index;
179  size_t opstack_size;
180  global &glob;
181  old_state(global &glob);
182  void restore();
183 };
184 
185 std::vector<Index> remap_identical_sub_expressions(
186  global &glob, std::vector<Index> inv_remap);
187 struct term_info {
188  global &glob;
189  std::vector<Index> id;
190  std::vector<size_t> count;
191  term_info(global &glob, bool do_init = true);
192  void initialize(std::vector<Index> inv_remap = std::vector<Index>(0));
193 };
194 
195 struct gk_config {
196  bool debug;
197  bool adaptive;
198  bool nan2zero;
203  double ytol;
204  double dx;
205  gk_config();
206 };
207 
208 template <class Float = ad_adapt>
209 struct logIntegrate_t {
210  typedef Float Scalar;
211  global glob;
212  double mu, sigma, f_mu;
213  gk_config cfg;
214  double f(double x) {
215  Index k = glob.inv_index.size();
216  glob.value_inv(k - 1) = x;
217  glob.forward();
218  return glob.value_dep(0);
219  }
220  double g(double x) {
221  return (f(x + .5 * cfg.dx) - f(x - .5 * cfg.dx)) / cfg.dx;
222  }
223  double h(double x) {
224  return (g(x + .5 * cfg.dx) - g(x - .5 * cfg.dx)) / cfg.dx;
225  }
232  void rescale_integrand(const std::vector<ad_aug> &x) {
233  TMBAD_ASSERT(x.size() + 1 == glob.inv_index.size());
234  if (cfg.debug) Rcout << "rescale integrand:\n";
235  for (size_t i = 0; i < x.size(); i++) glob.value_inv(i) = x[i].Value();
236  mu = glob.value_inv(x.size());
237  f_mu = f(mu);
238  int i = 0;
239  for (; i < 100; i++) {
240  double g_mu = g(mu);
241  double h_mu = h(mu);
242  if (std::isfinite(f_mu) && !std::isfinite(h_mu)) {
243  cfg.dx = cfg.dx * .5;
244  continue;
245  }
246  double mu_new;
247  if (h_mu < 0)
248  mu_new = mu - g_mu / h_mu;
249  else
250  mu_new = mu + (g_mu > 0 ? cfg.dx : -cfg.dx);
251  double f_mu_new = f(mu_new);
252  if (cfg.debug) {
253  Rcout << "mu=" << mu << " mu_new=" << mu_new << " g_mu=" << g_mu
254  << " h_mu=" << h_mu << " f_mu=" << f_mu
255  << " f_mu_new=" << f_mu_new << "\n";
256  }
257  if (f_mu_new > f_mu + cfg.ytol) {
258  mu = mu_new;
259  f_mu = f_mu_new;
260  } else {
261  break;
262  }
263  }
264  sigma = 1. / sqrt(-h(mu));
265  if (!std::isfinite(sigma)) sigma = 10000;
266  if (cfg.debug)
267  Rcout << "==> i=" << i << " mu=" << mu << " f_mu=" << f_mu
268  << " sigma=" << sigma << "\n";
269  }
270 
271  logIntegrate_t(global &glob, gk_config cfg)
272  : glob(glob), mu(0), sigma(1), f_mu(0), cfg(cfg) {
273  TMBAD_ASSERT(glob.inv_index.size() >= 1);
274  TMBAD_ASSERT(glob.dep_index.size() == 1);
275  }
276  logIntegrate_t() {}
277  global::replay *p_replay;
278 
279  Float operator()(Float u) {
280  Index k = glob.inv_index.size();
281  p_replay->value_inv(k - 1) = sigma * u + mu;
282  p_replay->forward(false, false);
283  Float ans = exp(p_replay->value_dep(0) - f_mu);
284  if (cfg.nan2zero && ans != ans) ans = 0;
285  return ans;
286  }
287 
288  std::vector<ad_aug> operator()(const std::vector<ad_aug> &x) {
289  rescale_integrand(x);
290  global::replay replay(this->glob, *get_glob());
291  p_replay = &replay;
292  replay.start();
293  Index k = glob.inv_index.size();
294  for (Index i = 0; i < k - 1; i++) replay.value_inv(i) = x[i];
295  Float I = integrate(*this);
296  Float ans = log(I) + log(sigma) + f_mu;
297  replay.stop();
298  return std::vector<ad_aug>(1, ans);
299  }
300 };
301 
302 template <class ADFun>
303 struct integrate_subgraph {
304  global &glob;
305  std::vector<Index> random;
306  graph forward_graph;
307  graph reverse_graph;
308  std::vector<Index> var_remap;
309  std::vector<bool> mark;
310  gk_config cfg;
314  integrate_subgraph(global &glob, std::vector<Index> random,
315  gk_config cfg = gk_config())
316  : glob(glob),
317  random(random),
318  forward_graph(glob.forward_graph()),
319  reverse_graph(glob.reverse_graph()),
320  cfg(cfg) {
321  glob.subgraph_cache_ptr();
322  mark.resize(glob.opstack.size(), false);
323  }
327  global &try_integrate_variable(Index i) {
328  const std::vector<Index> &inv2op = forward_graph.inv2op;
329 
330  Index start_node = inv2op[i];
331  glob.subgraph_seq.resize(0);
332  glob.subgraph_seq.push_back(start_node);
333  forward_graph.search(glob.subgraph_seq);
334 
335  if (glob.subgraph_seq.size() == 1) return glob;
336 
337  bool any_marked = false;
338  for (Index i = 0; i < glob.subgraph_seq.size(); i++) {
339  any_marked |= mark[glob.subgraph_seq[i]];
340  if (any_marked) {
341  return glob;
342  }
343  }
344 
345  for (Index i = 0; i < glob.subgraph_seq.size(); i++) {
346  mark[glob.subgraph_seq[i]] = true;
347  }
348 
349  std::vector<Index> boundary = reverse_graph.boundary(glob.subgraph_seq);
350 
351  global new_glob;
352  var_remap.resize(glob.values.size());
353  new_glob.ad_start();
354  Index total_boundary_vars = 0;
355  std::vector<ad_plain> boundary_vars;
356  OperatorPure *constant = glob.getOperator<global::ConstOp>();
357  for (Index i = 0; i < boundary.size(); i++) {
358  Index m = glob.opstack[boundary[i]]->output_size();
359  for (Index j = 0; j < m; j++) {
360  Index boundary_var = glob.subgraph_ptr[boundary[i]].second + j;
361  var_remap[boundary_var] = total_boundary_vars;
362  total_boundary_vars++;
363  if (glob.opstack[boundary[i]] != constant) {
364  ad_plain().Independent();
365  ad_plain tmp;
366  tmp.index = boundary_var;
367  boundary_vars.push_back(tmp);
368  } else {
369  ad_plain(glob.values[boundary_var]);
370  }
371  }
372  }
373  new_glob.ad_stop();
374 
375  new_glob = glob.extract_sub(var_remap, new_glob);
376 
377  aggregate(new_glob);
378 
379  logIntegrate_t<> taped_integral(new_glob, cfg);
380 
381  glob.ad_start();
382  std::vector<ad_aug> boundary_vars2(boundary_vars.begin(),
383  boundary_vars.end());
384  if (cfg.adaptive) {
386  global::Complete<AtomOp<DTab> > taped_integral_operator(taped_integral,
387  boundary_vars2);
388  taped_integral_operator(boundary_vars)[0].Dependent();
389  } else {
390  taped_integral(boundary_vars2)[0].Dependent();
391  }
392  glob.ad_stop();
393  return glob;
394  }
395  global &gk() {
396  for (Index i = 0; i < random.size(); i++) {
397  try_integrate_variable(random[i]);
398  }
399 
400  std::vector<bool> keep_node = mark;
401  keep_node.flip();
402 
403  keep_node.resize(glob.opstack.size(), true);
404 
405  std::vector<Index> v2o = glob.var2op();
406  for (Index i = 0; i < glob.inv_index.size(); i++) {
407  keep_node[v2o[glob.inv_index[i]]] = true;
408  }
409 
410  glob.subgraph_seq.resize(0);
411  for (Index i = 0; i < keep_node.size(); i++) {
412  if (keep_node[i]) glob.subgraph_seq.push_back(i);
413  }
414 
415  glob = glob.extract_sub();
416  return glob;
417  }
418 };
419 
436  private:
437  std::vector<size_t> x;
438  std::vector<bool> mask_;
439  size_t pointer;
440  std::vector<size_t> bound;
441 
442  public:
447  size_t count();
453  multivariate_index(size_t bound_, size_t dim, bool flag = true);
458  multivariate_index(std::vector<size_t> bound, bool flag = true);
460  void flip();
462  multivariate_index &operator++();
464  operator size_t();
466  size_t index(size_t i);
468  std::vector<size_t> index();
470  std::vector<bool>::reference mask(size_t i);
472  void set_mask(const std::vector<bool> &mask);
473 };
474 
480 struct clique {
482  std::vector<Index> indices;
484  std::vector<ad_aug> logsum;
486  std::vector<size_t> dim;
487  size_t clique_size();
488  clique();
489  void subset_inplace(const std::vector<bool> &mask);
490  void logsum_init();
491  bool empty() const;
492  bool contains(Index i);
510  void get_stride(const clique &super, Index ind, std::vector<ad_plain> &offset,
511  Index &stride);
512 };
513 
520 struct sr_grid {
521  std::vector<Scalar> x;
522  std::vector<Scalar> w;
523  sr_grid();
524 
525  sr_grid(Scalar a, Scalar b, size_t n);
526 
527  sr_grid(size_t n);
528  size_t size();
529 
530  std::vector<ad_plain> logw;
531  ad_plain logw_offset();
532 };
533 
582  std::list<clique> cliques;
583  std::vector<sr_grid> grid;
584  std::vector<Index> inv2grid;
585  global &glob;
586  global new_glob;
587  std::vector<Index> random;
588  global::replay replay;
589  std::vector<bool> mark;
590  graph forward_graph;
591  graph reverse_graph;
592  std::vector<Index> var_remap;
593  const static Index NA = -1;
594  std::vector<Index> op2inv_idx;
595  std::vector<Index> op2dep_idx;
596  std::vector<bool> terms_done;
597  term_info tinfo;
598  std::map<size_t, std::vector<ad_aug> > cache;
615  sequential_reduction(global &glob, std::vector<Index> random,
616  std::vector<sr_grid> grid =
617  std::vector<sr_grid>(1, sr_grid(-20, 20, 200)),
618  std::vector<Index> random2grid = std::vector<Index>(0),
619  bool perm = true);
626  void reorder_random();
627 
628  std::vector<size_t> get_grid_bounds(std::vector<Index> inv_index);
629 
630  std::vector<sr_grid *> get_grid(std::vector<Index> inv_index);
642  std::vector<ad_aug> tabulate(std::vector<Index> inv_index, Index dep_index);
643 
665  void merge(Index i);
666 
678  void update(Index i);
679  void show_cliques();
680  void update_all();
681  ad_aug get_result();
682  global marginal();
683 };
684 
718 struct autopar {
719  global &glob;
720  graph reverse_graph;
721  size_t num_threads;
727  std::vector<std::vector<Index> > node_split;
729  std::vector<std::vector<Index> > inv_idx;
731  std::vector<std::vector<Index> > dep_idx;
733  std::vector<global> vglob;
734  autopar(global &glob, size_t num_threads);
737  std::vector<size_t> max_tree_depth();
738 
739  template <class T>
740  size_t which_min(const std::vector<T> &x) {
741  return std::min_element(x.begin(), x.end()) - x.begin();
742  }
743 
744  void run();
746  void extract();
748  size_t input_size() const;
750  size_t output_size() const;
751 };
752 
757  static const bool have_input_size_output_size = true;
759  std::vector<global> vglob;
761  std::vector<std::vector<Index> > inv_idx;
764  std::vector<std::vector<Index> > dep_idx;
765 
766  Index n, m;
767  Index input_size() const;
768  Index output_size() const;
769  ParalOp(const autopar &ap);
770 
771  template <class T>
772  void reverse(ReverseArgs<T> &args) {
773  bool parallel_operator_used_with_valid_type = false;
774  TMBAD_ASSERT(parallel_operator_used_with_valid_type);
775  }
776  static const bool add_forward_replay_copy = true;
777  template <class T>
778  void forward(ForwardArgs<T> &args) {
779  bool parallel_operator_used_with_valid_type = false;
780  TMBAD_ASSERT(parallel_operator_used_with_valid_type);
781  }
782 
783  void forward(ForwardArgs<Scalar> &args);
784  void reverse(ReverseArgs<Scalar> &args);
785  const char *op_name();
786  void print(global::print_config cfg);
787 };
788 
789 std::vector<Index> get_likely_expression_duplicates(
790  const global &glob, std::vector<Index> inv_remap);
791 
796 bool all_allow_remap(const global &glob);
797 
799 template <class T>
800 struct forbid_remap {
801  T &remap;
802  forbid_remap(T &remap) : remap(remap) {}
803  void operator()(Index a, Index b) {
804  bool ok = true;
805  for (Index i = a + 1; i <= b; i++) {
806  ok &= (remap[i] - remap[i - 1] == 1);
807  }
808  if (ok) {
809  return;
810  } else {
811  for (Index i = a; i <= b; i++) {
812  remap[i] = i;
813  }
814  }
815  }
816 };
817 
874 std::vector<Index> remap_identical_sub_expressions(
875  global &glob, std::vector<Index> inv_remap);
876 
878 
879 std::vector<Position> inv_positions(global &glob);
880 
886 void reorder_graph(global &glob, std::vector<Index> inv_idx);
887 
888 } // namespace TMBad
889 #endif // HAVE_GRAPH_TRANSFORM_HPP
Automatic differentiation library designed for TMB.
Definition: TMB.hpp:157
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
size_t prod_int(const std::vector< size_t > &x)
Integer product function.
Definition: TMBad.cpp:3534
global accumulation_tree_split(global glob, bool sum_=false)
Split a computational graph by it&#39;s accumulation tree.
Definition: TMBad.cpp:3613
std::vector< size_t > dim
Dimension of logsum array.
void forward(Position start=Position(0, 0, 0))
Full or partial forward sweep through the operation stack. Updates global::values.
Definition: TMBad.cpp:1005
graph forward_graph(std::vector< bool > keep_var=std::vector< bool >(0))
Construct operator graph with forward connections.
Definition: TMBad.cpp:1576
std::vector< T > invperm(const std::vector< T > &perm)
Inverse permutation.
void reorder_graph(global &glob, std::vector< Index > inv_idx)
Reorder computational graph such that selected independent variables come last.
Definition: TMBad.cpp:4456
operation_stack opstack
Operation stack.
Definition: global.hpp:937
void make_space_inplace(std::vector< T > &x, std::vector< I > &i, T space=T(0))
Make space for new elements in an existing vector.
void sort_inplace(std::vector< T > &x)
Utility: sort inplace.
Definition: global.hpp:604
bool keep_all_inv
Keep all independent variables for each thread?
void subgraph_cache_ptr() const
Cache array pointers required by all subgraph routines.
Definition: TMBad.cpp:1230
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
Definition: TMBad.cpp:690
std::vector< Index > boundary(const std::vector< Index > &subgraph)
Find boundary of subgraph.
Definition: TMBad.cpp:863
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
Definition: global.hpp:311
std::vector< Scalar > values
Contiguous workspace for taped variables (same length as global::derivs)
Definition: global.hpp:940
std::vector< std::vector< Index > > node_split
Complete subgraphs by thread.
std::vector< global > vglob
Computational graphs by thread.
Access input/output values during a forward pass. Write access granted for the output value only...
Definition: global.hpp:279
Sequential reduction algorithm.
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
Enable weak comparison operators of an ad type.
Definition: global.hpp:2969
std::vector< Index > indices
Variable indices of this clique.
Configuration of print method.
Definition: global.hpp:1479
std::vector< Index > inv2op
Used to lookup operator (node) of an independent variable.
Definition: global.hpp:630
The abstract operator for the operation stack global::opstack
Definition: global.hpp:811
Augmented AD type.
Definition: global.hpp:2831
global extract_sub(std::vector< Index > &var_remap, global new_glob=global())
Extract a subgraph as a new global object. Fast when called many times.
Definition: TMBad.cpp:1271
std::vector< std::vector< Index > > dep_idx
Indices to identify dependent variable subset calculated by thread.
std::vector< Index > inv_index
Pointers into global::values determining independent variables.
Definition: global.hpp:948
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 > get_accumulation_tree(global &glob, bool boundary=false)
Get node indices of the accumulation tree or its boundary.
Definition: TMBad.cpp:3550
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
std::vector< I > which(const std::vector< bool > &x)
Convert logical vector to index vector.
Integrand::Scalar integrate(Integrand f, typename Integrand::Scalar a=-INFINITY, typename Integrand::Scalar b=INFINITY, control c=control())
Integrate function over finite or infinite interval.
std::vector< size_t > match(const std::vector< T > &x, const std::vector< T > &y)
Match x vector in y vector.
std::vector< ad_aug > logsum
Log-probabilites of this clique.
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
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
Read the current tape&#39;s state and restore it on request.
Utilility class for sequential_reduction.
std::vector< std::vector< Index > > inv_idx
Indices to identify independent variable subset used by thread.
std::vector< std::vector< Index > > dep_idx
Result: Pointers into original dependent variables.
Forbid remappings if not consecutive.
std::vector< size_t > order(std::vector< T > x)
Get permutation that sorts a vector.
Operator auto-completion.
Definition: global.hpp:2129
Operator that requires dynamic allocation. Compile time known input/output size.
Definition: global.hpp:1590
bool all_allow_remap(const global &glob)
Test if all operators in the stack allow input remapping.
Definition: TMBad.cpp:4291
Scalar & value_inv(Index i)
Reference to i&#39;th input value (parameter)
Definition: TMBad.cpp:989
std::vector< global > vglob
Result: Vector of computational graphs.
Utilility class for sequential_reduction.
std::vector< Index > find_op_by_name(global &glob, const char *name)
Find nodes by name.
Definition: TMBad.cpp:3573
Parallel operator.
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?
Operator graph in compressed row storage.
Definition: global.hpp:617
Adaptive derivative table used by AtomOp
Definition: checkpoint.hpp:40
std::vector< std::vector< Index > > inv_idx
Result: Pointers into original independent variables.
void ad_start()
Enable ad calulations to be piped to this glob.
Definition: TMBad.cpp:2065
std::vector< bool > lmatch(const std::vector< T > &x, const std::vector< T > &y)
Match x vector in y vector.
std::vector< Index > dep_index
Pointers into global::values determining dependent variables.
Definition: global.hpp:951
Utilility class for sequential_reduction.
License: GPL v2