TMB Documentation  v1.9.11
TMBad.cpp
1 // Autogenerated - do not edit by hand !
2 #include "TMBad.hpp"
3 namespace TMBad {
4 
5 SpJacFun_config::SpJacFun_config() : compress(false), index_remap(true) {}
6 } // namespace TMBad
7 // Autogenerated - do not edit by hand !
8 #include "ad_blas.hpp"
9 namespace TMBad {
10 
11 vmatrix matmul(const vmatrix &x, const vmatrix &y) {
12  vmatrix z(x.rows(), y.cols());
13  Map<vmatrix> zm(&z(0), z.rows(), z.cols());
14  matmul<false, false, false, false>(x, y, zm);
15  return z;
16 }
17 
18 dmatrix matmul(const dmatrix &x, const dmatrix &y) { return x * y; }
19 } // namespace TMBad
20 // Autogenerated - do not edit by hand !
21 #include "checkpoint.hpp"
22 namespace TMBad {
23 
24 bool ParametersChanged::operator()(const std::vector<Scalar> &x) {
25  bool change = (x != x_prev);
26  if (change) {
27  x_prev = x;
28  }
29  return change;
30 }
31 } // namespace TMBad
32 // Autogenerated - do not edit by hand !
33 #include "code_generator.hpp"
34 namespace TMBad {
35 
36 void searchReplace(std::string &str, const std::string &oldStr,
37  const std::string &newStr) {
38  std::string::size_type pos = 0u;
39  while ((pos = str.find(oldStr, pos)) != std::string::npos) {
40  str.replace(pos, oldStr.length(), newStr);
41  pos += newStr.length();
42  }
43 }
44 
45 std::string code_config::float_ptr() { return float_str + (gpu ? "**" : "*"); }
46 
47 std::string code_config::void_str() {
48  return (gpu ? "__device__ void" : "extern \"C\" void");
49 }
50 
51 void code_config::init_code() {
52  if (gpu) {
53  *cout << indent << "int idx = threadIdx.x;" << std::endl;
54  }
55 }
56 
57 void code_config::write_header_comment() {
58  if (header_comment.length() > 0) *cout << header_comment << std::endl;
59 }
60 
61 code_config::code_config()
62  : asm_comments(true),
63  gpu(true),
64  indent(" "),
65  header_comment("// Autogenerated - do not edit by hand !"),
66  float_str(xstringify(TMBAD_SCALAR_TYPE)),
67  cout(&Rcout) {}
68 
69 void write_common(std::ostringstream &buffer, code_config cfg, size_t node) {
70  std::ostream &cout = *cfg.cout;
71  using std::endl;
72  using std::left;
73  using std::setw;
74  std::string indent = cfg.indent;
75  if (cfg.asm_comments)
76  cout << indent << "asm(\"// Node: " << node << "\");" << endl;
77  bool empty_buffer = (buffer.tellp() == 0);
78  if (!empty_buffer) {
79  std::string str = buffer.str();
80  if (cfg.gpu) {
81  std::string pattern = "]";
82  std::string replace = "][idx]";
83  searchReplace(str, pattern, replace);
84  }
85  searchReplace(str, ";v", "; v");
86  searchReplace(str, ";d", "; d");
87  cout << indent << str << endl;
88  }
89 }
90 
91 void write_forward(global &glob, code_config cfg) {
92  using std::endl;
93  using std::left;
94  using std::setw;
95  std::ostream &cout = *cfg.cout;
96  cfg.write_header_comment();
97  cout << cfg.void_str() << " forward(" << cfg.float_ptr() << " v) {" << endl;
98  cfg.init_code();
99  ForwardArgs<Writer> args(glob.inputs, glob.values);
100  for (size_t i = 0; i < glob.opstack.size(); i++) {
101  std::ostringstream buffer;
102  Writer::cout = &buffer;
103  glob.opstack[i]->forward(args);
104  write_common(buffer, cfg, i);
105  glob.opstack[i]->increment(args.ptr);
106  }
107  cout << "}" << endl;
108 }
109 
110 void write_reverse(global &glob, code_config cfg) {
111  using std::endl;
112  using std::left;
113  using std::setw;
114  std::ostream &cout = *cfg.cout;
115  cfg.write_header_comment();
116  cout << cfg.void_str() << " reverse(" << cfg.float_ptr() << " v, "
117  << cfg.float_ptr() << " d) {" << endl;
118  cfg.init_code();
119  ReverseArgs<Writer> args(glob.inputs, glob.values);
120  for (size_t i = glob.opstack.size(); i > 0;) {
121  i--;
122  glob.opstack[i]->decrement(args.ptr);
123  std::ostringstream buffer;
124  Writer::cout = &buffer;
125  glob.opstack[i]->reverse(args);
126  write_common(buffer, cfg, i);
127  }
128  cout << "}" << endl;
129 }
130 
131 void write_all(global glob, code_config cfg) {
132  using std::endl;
133  using std::left;
134  using std::setw;
135  std::ostream &cout = *cfg.cout;
136  cout << "#include \"global.hpp\"" << endl;
137  cout << "#include \"ad_blas.hpp\"" << endl;
138  write_forward(glob, cfg);
139  write_reverse(glob, cfg);
140  cout << "int main() {}" << endl;
141 }
142 } // namespace TMBad
143 #ifndef _WIN32
144 // Autogenerated - do not edit by hand !
145 #include "compile.hpp"
146 namespace TMBad {
147 
148 void compile(global &glob, code_config cfg) {
149  cfg.gpu = false;
150  cfg.asm_comments = false;
151  std::ofstream file;
152  file.open("tmp.cpp");
153  cfg.cout = &file;
154 
155  *cfg.cout << "#include <cmath>" << std::endl;
156  *cfg.cout
157  << "template<class T>T sign(const T &x) { return (x > 0) - (x < 0); }"
158  << std::endl;
159 
160  write_forward(glob, cfg);
161 
162  write_reverse(glob, cfg);
163 
164  int out = system("g++ -O3 -g tmp.cpp -o tmp.so -shared -fPIC");
165  if (out != 0) {
166  }
167 
168  void *handle = dlopen("./tmp.so", RTLD_NOW);
169  if (handle != NULL) {
170  Rcout << "Loading compiled code!" << std::endl;
171  glob.forward_compiled =
172  reinterpret_cast<void (*)(Scalar *)>(dlsym(handle, "forward"));
173  glob.reverse_compiled = reinterpret_cast<void (*)(Scalar *, Scalar *)>(
174  dlsym(handle, "reverse"));
175  }
176 }
177 } // namespace TMBad
178 #endif
179 // Autogenerated - do not edit by hand !
180 #include "compression.hpp"
181 namespace TMBad {
182 
183 std::ostream &operator<<(std::ostream &os, const period &x) {
184  os << "begin: " << x.begin;
185  os << " size: " << x.size;
186  os << " rep: " << x.rep;
187  return os;
188 }
189 
190 std::vector<period> split_period(global *glob, period p,
191  size_t max_period_size) {
192  typedef std::ptrdiff_t ptrdiff_t;
193  glob->subgraph_cache_ptr();
194 
195  size_t offset = glob->subgraph_ptr[p.begin].first;
196 
197  size_t nrow = 0;
198  for (size_t i = 0; i < p.size; i++) {
199  nrow += glob->opstack[p.begin + i]->input_size();
200  }
201 
202  size_t ncol = p.rep;
203 
204  matrix_view<Index> x(&(glob->inputs[offset]), nrow, ncol);
205 
206  std::vector<bool> marks(ncol - 1, false);
207 
208  for (size_t i = 0; i < nrow; i++) {
209  std::vector<period> pd =
210  periodic<ptrdiff_t>(x.row_diff<ptrdiff_t>(i), max_period_size)
211  .find_all();
212 
213  for (size_t j = 0; j < pd.size(); j++) {
214  if (pd[j].begin > 0) {
215  marks[pd[j].begin - 1] = true;
216  }
217  size_t end = pd[j].begin + pd[j].size * pd[j].rep;
218  if (end < marks.size()) marks[end] = true;
219  }
220  }
221 
222  std::vector<period> ans;
223  p.rep = 1;
224  ans.push_back(p);
225  for (size_t j = 0; j < marks.size(); j++) {
226  if (marks[j]) {
227  period pnew = p;
228  pnew.begin = p.begin + (j + 1) * p.size;
229  pnew.rep = 1;
230  ans.push_back(pnew);
231  } else {
232  ans.back().rep++;
233  }
234  }
235 
236  return ans;
237 }
238 
239 size_t compressed_input::input_size() const { return n; }
240 
241 void compressed_input::update_increment_pattern() const {
242  for (size_t i = 0; i < (size_t)np; i++)
243  increment_pattern[which_periodic[i]] =
244  period_data[period_offsets[i] + counter % period_sizes[i]];
245 }
246 
247 void compressed_input::increment(Args<> &args) const {
248  if (np) {
249  update_increment_pattern();
250  counter++;
251  }
252  for (size_t i = 0; i < n; i++) inputs[i] += increment_pattern[i];
253  args.ptr.first = 0;
254 }
255 
256 void compressed_input::decrement(Args<> &args) const {
257  args.ptr.first = input_size();
258  for (size_t i = 0; i < n; i++) inputs[i] -= increment_pattern[i];
259  if (np) {
260  counter--;
261  update_increment_pattern();
262  }
263 }
264 
265 void compressed_input::forward_init(Args<> &args) const {
266  counter = 0;
267  inputs.resize(input_size());
268  for (size_t i = 0; i < inputs.size(); i++) inputs[i] = args.input(i);
269  args.inputs = inputs.data();
270  args.ptr.first = 0;
271 }
272 
273 void compressed_input::reverse_init(Args<> &args) {
274  inputs.resize(input_size());
275  for (size_t i = 0; i < inputs.size(); i++)
276  inputs[i] = args.input(i) + input_diff[i];
277 
278  args.inputs = inputs.data();
279  args.ptr.first = 0;
280  args.ptr.second += m * nrep;
281  counter = nrep - 1;
282  update_increment_pattern();
283  args.ptr.first = input_size();
284 }
285 
286 void compressed_input::dependencies_intervals(Args<> &args,
287  std::vector<Index> &lower,
288  std::vector<Index> &upper) const {
289  forward_init(args);
290  lower = inputs;
291  upper = inputs;
292  for (size_t i = 0; i < nrep; i++) {
293  for (size_t j = 0; j < inputs.size(); j++) {
294  if (inputs[j] < lower[j]) lower[j] = inputs[j];
295  if (inputs[j] > upper[j]) upper[j] = inputs[j];
296  }
297  increment(args);
298  }
299 }
300 
301 bool compressed_input::test_period(std::vector<ptrdiff_t> &x, size_t p) {
302  for (size_t j = 0; j < x.size(); j++) {
303  if (x[j] != x[j % p]) return false;
304  }
305  return true;
306 }
307 
308 size_t compressed_input::find_shortest(std::vector<ptrdiff_t> &x) {
309  for (size_t p = 1; p < max_period_size; p++) {
310  if (test_period(x, p)) return p;
311  }
312  return x.size();
313 }
314 
315 compressed_input::compressed_input() {}
316 
317 compressed_input::compressed_input(std::vector<Index> &x, size_t offset,
318  size_t nrow, size_t m, size_t ncol,
319  size_t max_period_size)
320  : n(nrow), m(m), nrep(ncol), counter(0), max_period_size(max_period_size) {
321  matrix_view<Index> xm(&x[offset], nrow, ncol);
322 
323  for (size_t i = 0; i < nrow; i++) {
324  std::vector<ptrdiff_t> rd = xm.row_diff<ptrdiff_t>(i);
325 
326  size_t p = find_shortest(rd);
327 
328  increment_pattern.push_back(rd[0]);
329  if (p != 1) {
330  which_periodic.push_back(i);
331  period_sizes.push_back(p);
332 
333  size_t pos = std::search(period_data.begin(), period_data.end(),
334  rd.begin(), rd.begin() + p) -
335  period_data.begin();
336  if (pos < period_data.size()) {
337  period_offsets.push_back(pos);
338  } else {
339  period_offsets.push_back(period_data.size());
340  period_data.insert(period_data.end(), rd.begin(), rd.begin() + p);
341  }
342  }
343  }
344 
345  np = which_periodic.size();
346 
347  input_diff.resize(n, 0);
348  Args<> args(input_diff);
349  forward_init(args);
350  for (size_t i = 0; i < nrep; i++) {
351  increment(args);
352  }
353  input_diff = inputs;
354 }
355 
356 StackOp::StackOp(global *glob, period p, IndexPair ptr,
357  size_t max_period_size) {
358  opstack.resize(p.size);
359  size_t n = 0, m = 0;
360  for (size_t i = 0; i < p.size; i++) {
361  opstack[i] = glob->opstack[p.begin + i]->copy();
362  n += opstack[i]->input_size();
363  m += opstack[i]->output_size();
364  }
365  ci = compressed_input(glob->inputs, ptr.first, n, m, p.rep, max_period_size);
366 }
367 
368 StackOp::StackOp(const StackOp &x) : opstack(x.opstack), ci(x.ci) {}
369 
370 void StackOp::print(global::print_config cfg) {
371  std::vector<const char *> tmp(opstack.size());
372  for (size_t i = 0; i < opstack.size(); i++) tmp[i] = opstack[i]->op_name();
373  Rcout << cfg.prefix << " opstack = " << tmp << "\n";
374 
375  Rcout << cfg.prefix << " "
376  << "nrep"
377  << " = " << ci.nrep << "\n";
378  ;
379  Rcout << cfg.prefix << " "
380  << "increment_pattern"
381  << " = " << ci.increment_pattern << "\n";
382  ;
383  if (ci.which_periodic.size() > 0) {
384  Rcout << cfg.prefix << " "
385  << "which_periodic"
386  << " = " << ci.which_periodic << "\n";
387  ;
388  Rcout << cfg.prefix << " "
389  << "period_sizes"
390  << " = " << ci.period_sizes << "\n";
391  ;
392  Rcout << cfg.prefix << " "
393  << "period_offsets"
394  << " = " << ci.period_offsets << "\n";
395  ;
396  Rcout << cfg.prefix << " "
397  << "period_data"
398  << " = " << ci.period_data << "\n";
399  ;
400  }
401 
402  Rcout << "\n";
403 }
404 
405 Index StackOp::input_size() const { return ci.n; }
406 
407 Index StackOp::output_size() const { return ci.m * ci.nrep; }
408 
409 void StackOp::forward(ForwardArgs<Writer> &args) {
410  size_t n = ci.n, m = ci.m, nrep = ci.nrep;
411  std::vector<Index> inputs(n);
412  for (size_t i = 0; i < (size_t)n; i++) inputs[i] = args.input(i);
413  std::vector<Index> outputs(m);
414  for (size_t i = 0; i < (size_t)m; i++) outputs[i] = args.output(i);
415  Writer w;
416  size_t np = ci.which_periodic.size();
417  size_t sp = ci.period_data.size();
418  w << "for (int count = 0, ";
419  if (n > 0) {
420  w << "i[" << n << "]=" << inputs << ", "
421  << "ip[" << n << "]=" << ci.increment_pattern << ", ";
422  }
423  if (np > 0) {
424  w << "wp[" << np << "]=" << ci.which_periodic << ", "
425  << "ps[" << np << "]=" << ci.period_sizes << ", "
426  << "po[" << np << "]=" << ci.period_offsets << ", "
427  << "pd[" << sp << "]=" << ci.period_data << ", ";
428  }
429  w << "o[" << m << "]=" << outputs << "; "
430  << "count < " << nrep << "; count++) {\n";
431 
432  w << " ";
433  ForwardArgs<Writer> args_cpy = args;
434  args_cpy.set_indirect();
435  for (size_t k = 0; k < opstack.size(); k++) {
436  opstack[k]->forward_incr(args_cpy);
437  }
438  w << "\n";
439 
440  if (np > 0) {
441  w << " ";
442  for (size_t k = 0; k < np; k++)
443  w << "ip[wp[" << k << "]] = pd[po[" << k << "] + count % ps[" << k
444  << "]]; ";
445  w << "\n";
446  }
447  if (n > 0) {
448  w << " ";
449  for (size_t k = 0; k < n; k++) w << "i[" << k << "] += ip[" << k << "]; ";
450  w << "\n";
451  }
452  w << " ";
453  for (size_t k = 0; k < m; k++) w << "o[" << k << "] += " << m << "; ";
454  w << "\n";
455 
456  w << " ";
457  w << "}";
458 }
459 
460 void StackOp::reverse(ReverseArgs<Writer> &args) {
461  size_t n = ci.n, m = ci.m, nrep = ci.nrep;
462  std::vector<ptrdiff_t> inputs(input_size());
463  for (size_t i = 0; i < inputs.size(); i++) {
464  ptrdiff_t tmp;
465  if (-ci.input_diff[i] < ci.input_diff[i]) {
466  tmp = -((ptrdiff_t)-ci.input_diff[i]);
467  } else {
468  tmp = ci.input_diff[i];
469  }
470  inputs[i] = args.input(i) + tmp;
471  }
472  std::vector<Index> outputs(ci.m);
473  for (size_t i = 0; i < (size_t)ci.m; i++)
474  outputs[i] = args.output(i) + ci.m * ci.nrep;
475  Writer w;
476  size_t np = ci.which_periodic.size();
477  size_t sp = ci.period_data.size();
478  w << "for (int count = " << nrep << ", ";
479  if (n > 0) {
480  w << "i[" << n << "]=" << inputs << ", "
481  << "ip[" << n << "]=" << ci.increment_pattern << ", ";
482  }
483  if (np > 0) {
484  w << "wp[" << np << "]=" << ci.which_periodic << ", "
485  << "ps[" << np << "]=" << ci.period_sizes << ", "
486  << "po[" << np << "]=" << ci.period_offsets << ", "
487  << "pd[" << sp << "]=" << ci.period_data << ", ";
488  }
489  w << "o[" << m << "]=" << outputs << "; "
490  << "count > 0 ; ) {\n";
491 
492  w << " ";
493  w << "count--;\n";
494  if (np > 0) {
495  w << " ";
496  for (size_t k = 0; k < np; k++)
497  w << "ip[wp[" << k << "]] = pd[po[" << k << "] + count % ps[" << k
498  << "]]; ";
499  w << "\n";
500  }
501  if (n > 0) {
502  w << " ";
503  for (size_t k = 0; k < n; k++) w << "i[" << k << "] -= ip[" << k << "]; ";
504  w << "\n";
505  }
506  w << " ";
507  for (size_t k = 0; k < m; k++) w << "o[" << k << "] -= " << m << "; ";
508  w << "\n";
509 
510  w << " ";
511 
512  ReverseArgs<Writer> args_cpy = args;
513  args_cpy.set_indirect();
514  args_cpy.ptr.first = ci.n;
515  args_cpy.ptr.second = ci.m;
516  for (size_t k = opstack.size(); k > 0;) {
517  k--;
518  opstack[k]->reverse_decr(args_cpy);
519  }
520  w << "\n";
521 
522  w << " ";
523  w << "}";
524 }
525 
526 void StackOp::dependencies(Args<> args, Dependencies &dep) const {
527  std::vector<Index> lower;
528  std::vector<Index> upper;
529  ci.dependencies_intervals(args, lower, upper);
530  for (size_t i = 0; i < lower.size(); i++) {
531  dep.add_interval(lower[i], upper[i]);
532  }
533 }
534 
535 const char *StackOp::op_name() { return "StackOp"; }
536 
539  cfg.strong_inv = false;
540  cfg.strong_const = false;
541  cfg.strong_output = false;
542  cfg.reduce = false;
543  cfg.deterministic = false;
544  std::vector<hash_t> h = glob.hash_sweep(cfg);
545  std::vector<Index> remap = radix::first_occurance<Index>(h);
546 
547  TMBAD_ASSERT(all_allow_remap(glob));
548 
549  Args<> args(glob.inputs);
550  for (size_t i = 0; i < glob.opstack.size(); i++) {
551  Dependencies dep;
552  glob.opstack[i]->dependencies(args, dep);
553 
554  Index var = args.ptr.second;
555  toposort_remap<Index> fb(remap, var);
556  dep.apply(fb);
557  glob.opstack[i]->increment(args.ptr);
558  }
559 
560  std::vector<Index> ord = radix::order<Index>(remap);
561  std::vector<Index> v2o = glob.var2op();
562  glob.subgraph_seq = subset(v2o, ord);
563 
564  glob = glob.extract_sub();
565 }
566 
568  std::vector<Index> remap(glob.values.size(), Index(-1));
569  Args<> args(glob.inputs);
570  for (size_t i = 0; i < glob.opstack.size(); i++) {
571  Dependencies dep;
572  glob.opstack[i]->dependencies(args, dep);
573  sort_unique_inplace(dep);
574  Index var = args.ptr.second;
575  temporaries_remap<Index> fb(remap, var);
576  dep.apply(fb);
577  glob.opstack[i]->increment(args.ptr);
578  }
579 
580  for (size_t i = remap.size(); i > 0;) {
581  i--;
582  if (remap[i] == Index(-1))
583  remap[i] = i;
584  else
585  remap[i] = remap[remap[i]];
586  }
587 
588  std::vector<Index> ord = radix::order<Index>(remap);
589  std::vector<Index> v2o = glob.var2op();
590  glob.subgraph_seq = subset(v2o, ord);
591 
592  glob = glob.extract_sub();
593 }
594 
596  std::vector<bool> visited(glob.opstack.size(), false);
597  std::vector<Index> v2o = glob.var2op();
598  std::vector<Index> stack;
599  std::vector<Index> result;
600  Args<> args(glob.inputs);
601  glob.subgraph_cache_ptr();
602  for (size_t k = 0; k < glob.dep_index.size(); k++) {
603  Index dep_var = glob.dep_index[k];
604  Index i = v2o[dep_var];
605 
606  stack.push_back(i);
607  visited[i] = true;
608  while (stack.size() > 0) {
609  Index i = stack.back();
610  args.ptr = glob.subgraph_ptr[i];
611  Dependencies dep;
612  glob.opstack[i]->dependencies(args, dep);
613  dfs_add_to_stack<Index> add_to_stack(stack, visited, v2o);
614  size_t before = stack.size();
615  dep.apply(add_to_stack);
616  size_t after = stack.size();
617  if (before == after) {
618  result.push_back(i);
619  stack.pop_back();
620  }
621  }
622  }
623 
624  glob.subgraph_seq = result;
625  glob = glob.extract_sub();
626 
627  glob.shrink_to_fit();
628 }
629 
630 void compress(global &glob, size_t max_period_size) {
631  size_t min_period_rep = TMBAD_MIN_PERIOD_REP;
632  periodic<global::OperatorPure *> p(glob.opstack, max_period_size,
633  min_period_rep);
634  std::vector<period> periods = p.find_all();
635 
636  std::vector<period> periods_expand;
637  for (size_t i = 0; i < periods.size(); i++) {
638  std::vector<period> tmp = split_period(&glob, periods[i], max_period_size);
639 
640  if (tmp.size() > 10) {
641  tmp.resize(0);
642  tmp.push_back(periods[i]);
643  }
644 
645  for (size_t j = 0; j < tmp.size(); j++) {
646  if (tmp[j].rep > 1) periods_expand.push_back(tmp[j]);
647  }
648  }
649 
650  std::swap(periods, periods_expand);
651  OperatorPure *null_op = get_glob()->getOperator<global::NullOp>();
652  IndexPair ptr(0, 0);
653  Index k = 0;
654  for (size_t i = 0; i < periods.size(); i++) {
655  period p = periods[i];
656  TMBAD_ASSERT(p.rep >= 1);
657  while (k < p.begin) {
658  glob.opstack[k]->increment(ptr);
659  k++;
660  }
661 
662  OperatorPure *pOp =
663  get_glob()->getOperator<StackOp>(&glob, p, ptr, max_period_size);
664  Index ninp = 0;
665  for (size_t j = 0; j < p.size * p.rep; j++) {
666  ninp += glob.opstack[p.begin + j]->input_size();
667  glob.opstack[p.begin + j]->deallocate();
668  glob.opstack[p.begin + j] = null_op;
669  }
670  glob.opstack[p.begin] = pOp;
671  ninp -= pOp->input_size();
672  glob.opstack[p.begin + 1] =
673  get_glob()->getOperator<global::NullOp2>(ninp, 0);
674  }
675 
676  std::vector<bool> marks(glob.values.size(), true);
677  glob.extract_sub_inplace(marks);
678  glob.shrink_to_fit();
679 }
680 } // namespace TMBad
681 // Autogenerated - do not edit by hand !
682 #include "global.hpp"
683 namespace TMBad {
684 
685 global *global_ptr_data[TMBAD_MAX_NUM_THREADS] = {NULL};
686 global **global_ptr = global_ptr_data;
687 std::ostream *Writer::cout = 0;
688 bool global::fuse = 0;
689 
690 global *get_glob() { return global_ptr[TMBAD_THREAD_NUM]; }
691 
692 Dependencies::Dependencies() {}
693 
694 void Dependencies::clear() {
695  this->resize(0);
696  I.resize(0);
697 }
698 
699 void Dependencies::add_interval(Index a, Index b) {
700  I.push_back(std::pair<Index, Index>(a, b));
701 }
702 
703 void Dependencies::add_segment(Index start, Index size) {
704  if (size > 0) add_interval(start, start + size - 1);
705 }
706 
707 void Dependencies::monotone_transform_inplace(const std::vector<Index> &x) {
708  for (size_t i = 0; i < this->size(); i++) (*this)[i] = x[(*this)[i]];
709  for (size_t i = 0; i < I.size(); i++) {
710  I[i].first = x[I[i].first];
711  I[i].second = x[I[i].second];
712  }
713 }
714 
715 bool Dependencies::any(const std::vector<bool> &x) const {
716  for (size_t i = 0; i < this->size(); i++)
717  if (x[(*this)[i]]) return true;
718  for (size_t i = 0; i < I.size(); i++) {
719  for (Index j = I[i].first; j <= I[i].second; j++) {
720  if (x[j]) return true;
721  }
722  }
723  return false;
724 }
725 
726 std::string tostr(const Index &x) {
727  std::ostringstream strs;
728  strs << x;
729  return strs.str();
730 }
731 
732 std::string tostr(const Scalar &x) {
733  std::ostringstream strs;
734  strs << x;
735  return strs.str();
736 }
737 
738 Writer::Writer(std::string str) : std::string(str) {}
739 
740 Writer::Writer(Scalar x) : std::string(tostr(x)) {}
741 
742 Writer::Writer() {}
743 
744 std::string Writer::p(std::string x) { return "(" + x + ")"; }
745 
746 Writer Writer::operator+(const Writer &other) {
747  return p(*this + " + " + other);
748 }
749 
750 Writer Writer::operator-(const Writer &other) {
751  return p(*this + " - " + other);
752 }
753 
754 Writer Writer::operator-() { return " - " + *this; }
755 
756 Writer Writer::operator*(const Writer &other) { return *this + " * " + other; }
757 
758 Writer Writer::operator/(const Writer &other) { return *this + " / " + other; }
759 
760 Writer Writer::operator*(const Scalar &other) {
761  return *this + "*" + tostr(other);
762 }
763 
764 Writer Writer::operator+(const Scalar &other) {
765  return p(*this + "+" + tostr(other));
766 }
767 
768 void Writer::operator=(const Writer &other) {
769  *cout << *this + " = " + other << ";";
770 }
771 
772 void Writer::operator+=(const Writer &other) {
773  *cout << *this + " += " + other << ";";
774 }
775 
776 void Writer::operator-=(const Writer &other) {
777  *cout << *this + " -= " + other << ";";
778 }
779 
780 void Writer::operator*=(const Writer &other) {
781  *cout << *this + " *= " + other << ";";
782 }
783 
784 void Writer::operator/=(const Writer &other) {
785  *cout << *this + " /= " + other << ";";
786 }
787 
788 Position::Position(Index node, Index first, Index second)
789  : node(node), ptr(first, second) {}
790 
791 Position::Position() : node(0), ptr(0, 0) {}
792 
793 bool Position::operator<(const Position &other) const {
794  return this->node < other.node;
795 }
796 
797 graph::graph() {}
798 
799 size_t graph::num_neighbors(Index node) { return p[node + 1] - p[node]; }
800 
801 Index *graph::neighbors(Index node) { return &(j[p[node]]); }
802 
803 bool graph::empty() { return p.size() == 0; }
804 
805 size_t graph::num_nodes() { return (empty() ? 0 : p.size() - 1); }
806 
807 void graph::print() {
808  for (size_t node = 0; node < num_nodes(); node++) {
809  Rcout << node << ": ";
810  for (size_t i = 0; i < num_neighbors(node); i++) {
811  Rcout << " " << neighbors(node)[i];
812  }
813  Rcout << "\n";
814  }
815 }
816 
817 std::vector<Index> graph::rowcounts() {
818  std::vector<Index> ans(num_nodes());
819  for (size_t i = 0; i < ans.size(); i++) ans[i] = num_neighbors(i);
820  return ans;
821 }
822 
823 std::vector<Index> graph::colcounts() {
824  std::vector<Index> ans(num_nodes());
825  for (size_t i = 0; i < j.size(); i++) ans[j[i]]++;
826  return ans;
827 }
828 
829 void graph::bfs(const std::vector<Index> &start, std::vector<bool> &visited,
830  std::vector<Index> &result) {
831  for (size_t i = 0; i < start.size(); i++) {
832  Index node = start[i];
833  for (size_t j_ = 0; j_ < num_neighbors(node); j_++) {
834  Index k = neighbors(node)[j_];
835  if (!visited[k]) {
836  result.push_back(k);
837  visited[k] = true;
838  }
839  }
840  }
841 }
842 
843 void graph::search(std::vector<Index> &start, bool sort_input,
844  bool sort_output) {
845  if (mark.size() == 0) mark.resize(num_nodes(), false);
846 
847  search(start, mark, sort_input, sort_output);
848 
849  for (size_t i = 0; i < start.size(); i++) mark[start[i]] = false;
850 }
851 
852 void graph::search(std::vector<Index> &start, std::vector<bool> &visited,
853  bool sort_input, bool sort_output) {
854  if (sort_input) sort_unique_inplace(start);
855 
856  for (size_t i = 0; i < start.size(); i++) visited[start[i]] = true;
857 
858  bfs(start, visited, start);
859 
860  if (sort_output) sort_inplace(start);
861 }
862 
863 std::vector<Index> graph::boundary(const std::vector<Index> &subgraph) {
864  if (mark.size() == 0) mark.resize(num_nodes(), false);
865 
866  std::vector<Index> boundary;
867 
868  for (size_t i = 0; i < subgraph.size(); i++) mark[subgraph[i]] = true;
869 
870  bfs(subgraph, mark, boundary);
871 
872  for (size_t i = 0; i < subgraph.size(); i++) mark[subgraph[i]] = false;
873  for (size_t i = 0; i < boundary.size(); i++) mark[boundary[i]] = false;
874 
875  return boundary;
876 }
877 
878 graph::graph(size_t num_nodes, const std::vector<IndexPair> &edges) {
879  std::vector<IndexPair>::const_iterator it;
880  std::vector<Index> row_counts(num_nodes, 0);
881  for (it = edges.begin(); it != edges.end(); it++) {
882  row_counts[it->first]++;
883  }
884 
885  p.resize(num_nodes + 1);
886  p[0] = 0;
887  for (size_t i = 0; i < num_nodes; i++) {
888  p[i + 1] = p[i] + row_counts[i];
889  }
890 
891  std::vector<Index> k(p);
892  j.resize(edges.size());
893  for (it = edges.begin(); it != edges.end(); it++) {
894  j[k[it->first]++] = it->second;
895  }
896 }
897 
898 op_info::op_info() : code(0) {
899  static_assert(sizeof(IntRep) * 8 >= op_flag_count,
900  "'IntRep' not wide enough!");
901 }
902 
903 op_info::op_info(op_flag f) : code(1 << f) {}
904 
905 bool op_info::test(op_flag f) const { return code & 1 << f; }
906 
907 op_info &op_info::operator|=(const op_info &other) {
908  code |= other.code;
909  return *this;
910 }
911 
912 op_info &op_info::operator&=(const op_info &other) {
913  code &= other.code;
914  return *this;
915 }
916 
917 global::operation_stack::operation_stack() {}
918 
919 global::operation_stack::operation_stack(const operation_stack &other) {
920  (*this).copy_from(other);
921 }
922 
923 void global::operation_stack::push_back(OperatorPure *x) {
924  Base::push_back(x);
925 
926  any |= x->info();
927 }
928 
929 operation_stack &global::operation_stack::operator=(
930  const operation_stack &other) {
931  if (this != &other) {
932  (*this).clear();
933  (*this).copy_from(other);
934  }
935  return *this;
936 }
937 
938 global::operation_stack::~operation_stack() { (*this).clear(); }
939 
940 void global::operation_stack::clear() {
941  if (any.test(op_info::dynamic)) {
942  for (size_t i = 0; i < (*this).size(); i++) (*this)[i]->deallocate();
943  }
944  (*this).resize(0);
945 }
946 
947 void global::operation_stack::copy_from(const operation_stack &other) {
948  if (other.any.test(op_info::dynamic)) {
949  for (size_t i = 0; i < other.size(); i++) Base::push_back(other[i]->copy());
950  } else {
951  Base::operator=(other);
952  }
953  this->any = other.any;
954 }
955 
956 global::global()
957  : forward_compiled(NULL),
958  reverse_compiled(NULL),
959  parent_glob(NULL),
960  in_use(false) {}
961 
962 void global::clear() {
963  values.resize(0);
964  derivs.resize(0);
965  inputs.resize(0);
966  inv_index.resize(0);
967  dep_index.resize(0);
968  subgraph_ptr.resize(0);
969  subgraph_seq.resize(0);
970  opstack.clear();
971 }
972 
973 void global::shrink_to_fit(double tol) {
974  std::vector<Scalar>().swap(derivs);
975  std::vector<IndexPair>().swap(subgraph_ptr);
976  if (values.size() < tol * values.capacity())
977  std::vector<Scalar>(values).swap(values);
978  if (inputs.size() < tol * inputs.capacity())
979  std::vector<Index>(inputs).swap(inputs);
980  if (opstack.size() < tol * opstack.capacity())
981  std::vector<OperatorPure *>(opstack).swap(opstack);
982 }
983 
984 void global::clear_deriv(Position start) {
985  derivs.resize(values.size());
986  std::fill(derivs.begin() + start.ptr.second, derivs.end(), 0);
987 }
988 
989 Scalar &global::value_inv(Index i) { return values[inv_index[i]]; }
990 
991 Scalar &global::deriv_inv(Index i) { return derivs[inv_index[i]]; }
992 
993 Scalar &global::value_dep(Index i) { return values[dep_index[i]]; }
994 
995 Scalar &global::deriv_dep(Index i) { return derivs[dep_index[i]]; }
996 
997 Position global::begin() { return Position(0, 0, 0); }
998 
999 Position global::end() {
1000  return Position(opstack.size(), inputs.size(), values.size());
1001 }
1002 
1003 CONSTEXPR bool global::no_filter::operator[](size_t i) const { return true; }
1004 
1005 void global::forward(Position start) {
1006  if (forward_compiled != NULL) {
1007  forward_compiled(values.data());
1008  return;
1009  }
1010  ForwardArgs<Scalar> args(inputs, values, this);
1011  args.ptr = start.ptr;
1012  forward_loop(args, start.node);
1013 }
1014 
1015 void global::reverse(Position start) {
1016  if (reverse_compiled != NULL) {
1017  reverse_compiled(values.data(), derivs.data());
1018  return;
1019  }
1020  ReverseArgs<Scalar> args(inputs, values, derivs, this);
1021  reverse_loop(args, start.node);
1022 }
1023 
1024 void global::forward_sub() {
1025  ForwardArgs<Scalar> args(inputs, values, this);
1026  forward_loop_subgraph(args);
1027 }
1028 
1029 void global::reverse_sub() {
1030  ReverseArgs<Scalar> args(inputs, values, derivs, this);
1031  reverse_loop_subgraph(args);
1032 }
1033 
1034 void global::forward(std::vector<bool> &marks) {
1035  intervals<Index> marked_intervals;
1036  ForwardArgs<bool> args(inputs, marks, marked_intervals);
1037  forward_loop(args);
1038 }
1039 
1040 void global::reverse(std::vector<bool> &marks) {
1041  intervals<Index> marked_intervals;
1042  ReverseArgs<bool> args(inputs, marks, marked_intervals);
1043  reverse_loop(args);
1044 }
1045 
1046 void global::forward_sub(std::vector<bool> &marks,
1047  const std::vector<bool> &node_filter) {
1048  intervals<Index> marked_intervals;
1049  ForwardArgs<bool> args(inputs, marks, marked_intervals);
1050  if (node_filter.size() == 0)
1051  forward_loop_subgraph(args);
1052  else
1053  forward_loop(args, 0, node_filter);
1054 }
1055 
1056 void global::reverse_sub(std::vector<bool> &marks,
1057  const std::vector<bool> &node_filter) {
1058  intervals<Index> marked_intervals;
1059  ReverseArgs<bool> args(inputs, marks, marked_intervals);
1060  if (node_filter.size() == 0)
1061  reverse_loop_subgraph(args);
1062  else
1063  reverse_loop(args, 0, node_filter);
1064 }
1065 
1066 void global::forward_dense(std::vector<bool> &marks) {
1067  intervals<Index> marked_intervals;
1068  ForwardArgs<bool> args(inputs, marks, marked_intervals);
1069  for (size_t i = 0; i < opstack.size(); i++) {
1070  opstack[i]->forward_incr_mark_dense(args);
1071  }
1072 }
1073 
1074 intervals<Index> global::updating_intervals() const {
1075  Dependencies dep;
1076  intervals<Index> marked_intervals;
1077  Args<> args(inputs);
1078  for (size_t i = 0; i < opstack.size(); i++) {
1079  if (opstack[i]->info().test(op_info::updating)) {
1080  dep.clear();
1081  opstack[i]->dependencies(args, dep);
1082 
1083  for (size_t i = 0; i < dep.I.size(); i++) {
1084  Index a = dep.I[i].first;
1085  Index b = dep.I[i].second;
1086  marked_intervals.insert(a, b);
1087  }
1088  }
1089  opstack[i]->increment(args.ptr);
1090  }
1091  return marked_intervals;
1092 }
1093 
1094 intervals<Index> global::updating_intervals_sub() const {
1095  Dependencies dep;
1096  intervals<Index> marked_intervals;
1097  Args<> args(inputs);
1098  subgraph_cache_ptr();
1099  for (size_t j = 0; j < subgraph_seq.size(); j++) {
1100  Index i = subgraph_seq[j];
1101  args.ptr = subgraph_ptr[i];
1102  if (opstack[i]->info().test(op_info::updating)) {
1103  dep.clear();
1104  opstack[i]->dependencies(args, dep);
1105 
1106  for (size_t i = 0; i < dep.I.size(); i++) {
1107  Index a = dep.I[i].first;
1108  Index b = dep.I[i].second;
1109  marked_intervals.insert(a, b);
1110  }
1111  }
1112  }
1113  return marked_intervals;
1114 }
1115 
1116 Replay &global::replay::value_inv(Index i) { return values[orig.inv_index[i]]; }
1117 
1118 Replay &global::replay::deriv_inv(Index i) { return derivs[orig.inv_index[i]]; }
1119 
1120 Replay &global::replay::value_dep(Index i) { return values[orig.dep_index[i]]; }
1121 
1122 Replay &global::replay::deriv_dep(Index i) { return derivs[orig.dep_index[i]]; }
1123 
1124 global::replay::replay(const global &orig, global &target)
1125  : orig(orig), target(target) {
1126  TMBAD_ASSERT(&orig != &target);
1127 }
1128 
1129 void global::replay::start() {
1130  parent_glob = get_glob();
1131  if (&target != parent_glob) target.ad_start();
1132  values = std::vector<Replay>(orig.values.begin(), orig.values.end());
1133 }
1134 
1135 void global::replay::stop() {
1136  if (&target != parent_glob) target.ad_stop();
1137  TMBAD_ASSERT(parent_glob == get_glob());
1138 }
1139 
1140 void global::replay::add_updatable_derivs(const intervals<Index> &I) {
1141  struct {
1142  Replay *p;
1143  void operator()(Index a, Index b) {
1144  Index n = b - a + 1;
1145  global::ZeroOp Z(n);
1146  Z(p + a, n);
1147  }
1148  } F = {derivs.data()};
1149  I.apply(F);
1150 }
1151 
1152 void global::replay::clear_deriv() {
1153  derivs.resize(values.size());
1154  std::fill(derivs.begin(), derivs.end(), Replay(0));
1155 
1156  if (orig.opstack.any.test(op_info::updating)) {
1157  intervals<Index> I = orig.updating_intervals();
1158  add_updatable_derivs(I);
1159  }
1160 }
1161 
1162 void global::replay::forward(bool inv_tags, bool dep_tags, Position start,
1163  const std::vector<bool> &node_filter) {
1164  TMBAD_ASSERT(&target == get_glob());
1165  if (inv_tags) {
1166  for (size_t i = 0; i < orig.inv_index.size(); i++)
1167  value_inv(i).Independent();
1168  }
1169  ForwardArgs<Replay> args(orig.inputs, values);
1170  if (node_filter.size() > 0) {
1171  TMBAD_ASSERT(node_filter.size() == orig.opstack.size());
1172  orig.forward_loop(args, start.node, node_filter);
1173  } else {
1174  orig.forward_loop(args, start.node);
1175  }
1176  if (dep_tags) {
1177  for (size_t i = 0; i < orig.dep_index.size(); i++) value_dep(i).Dependent();
1178  }
1179 }
1180 
1181 void global::replay::reverse(bool dep_tags, bool inv_tags, Position start,
1182  const std::vector<bool> &node_filter) {
1183  TMBAD_ASSERT(&target == get_glob());
1184  if (inv_tags) {
1185  for (size_t i = 0; i < orig.dep_index.size(); i++)
1186  deriv_dep(i).Independent();
1187  }
1188  ReverseArgs<Replay> args(orig.inputs, values, derivs);
1189  if (node_filter.size() > 0) {
1190  TMBAD_ASSERT(node_filter.size() == orig.opstack.size());
1191  orig.reverse_loop(args, start.node, node_filter);
1192  } else {
1193  orig.reverse_loop(args, start.node);
1194  }
1195 
1196  std::fill(derivs.begin(), derivs.begin() + start.ptr.second, Replay(0));
1197  if (dep_tags) {
1198  for (size_t i = 0; i < orig.inv_index.size(); i++) deriv_inv(i).Dependent();
1199  }
1200 }
1201 
1202 void global::replay::forward_sub() {
1203  ForwardArgs<Replay> args(orig.inputs, values);
1204  orig.forward_loop_subgraph(args);
1205 }
1206 
1207 void global::replay::reverse_sub() {
1208  ReverseArgs<Replay> args(orig.inputs, values, derivs);
1209  orig.reverse_loop_subgraph(args);
1210 }
1211 
1212 void global::replay::clear_deriv_sub() {
1213  orig.clear_array_subgraph(derivs);
1214 
1215  if (orig.opstack.any.test(op_info::updating)) {
1216  intervals<Index> I = orig.updating_intervals_sub();
1217  add_updatable_derivs(I);
1218  }
1219 }
1220 
1221 void global::forward_replay(bool inv_tags, bool dep_tags) {
1222  global new_glob;
1223  global::replay replay(*this, new_glob);
1224  replay.start();
1225  replay.forward(inv_tags, dep_tags);
1226  replay.stop();
1227  *this = new_glob;
1228 }
1229 
1230 void global::subgraph_cache_ptr() const {
1231  if (subgraph_ptr.size() == opstack.size()) return;
1232  TMBAD_ASSERT(subgraph_ptr.size() < opstack.size());
1233  if (subgraph_ptr.size() == 0) subgraph_ptr.push_back(IndexPair(0, 0));
1234  for (size_t i = subgraph_ptr.size(); i < opstack.size(); i++) {
1235  IndexPair ptr = subgraph_ptr[i - 1];
1236  opstack[i - 1]->increment(ptr);
1237  subgraph_ptr.push_back(ptr);
1238  }
1239 }
1240 
1241 void global::set_subgraph(const std::vector<bool> &marks, bool append) {
1242  std::vector<Index> v2o = var2op();
1243  if (!append) subgraph_seq.resize(0);
1244  Index previous = (Index)-1;
1245  for (size_t i = 0; i < marks.size(); i++) {
1246  if (marks[i] && (v2o[i] != previous)) {
1247  subgraph_seq.push_back(v2o[i]);
1248  previous = v2o[i];
1249  }
1250  }
1251 }
1252 
1253 void global::mark_subgraph(std::vector<bool> &marks) {
1254  TMBAD_ASSERT(marks.size() == values.size());
1255  clear_array_subgraph(marks, true);
1256 }
1257 
1258 void global::unmark_subgraph(std::vector<bool> &marks) {
1259  TMBAD_ASSERT(marks.size() == values.size());
1260  clear_array_subgraph(marks, false);
1261 }
1262 
1263 void global::subgraph_trivial() {
1264  subgraph_cache_ptr();
1265  subgraph_seq.resize(0);
1266  for (size_t i = 0; i < opstack.size(); i++) subgraph_seq.push_back(i);
1267 }
1268 
1269 void global::clear_deriv_sub() { clear_array_subgraph(derivs); }
1270 
1271 global global::extract_sub(std::vector<Index> &var_remap, global new_glob) {
1272  subgraph_cache_ptr();
1273  TMBAD_ASSERT(var_remap.size() == 0 || var_remap.size() == values.size());
1274  var_remap.resize(values.size(), 0);
1275  std::vector<bool> independent_variable = inv_marks();
1276  std::vector<bool> dependent_variable = dep_marks();
1277  ForwardArgs<Scalar> args(inputs, values, this);
1278  for (size_t j = 0; j < subgraph_seq.size(); j++) {
1279  Index i = subgraph_seq[j];
1280  args.ptr = subgraph_ptr[i];
1281 
1282  size_t nout = opstack[i]->output_size();
1283  for (size_t k = 0; k < nout; k++) {
1284  Index new_index = new_glob.values.size();
1285  Index old_index = args.output(k);
1286  var_remap[old_index] = new_index;
1287  new_glob.values.push_back(args.y(k));
1288  if (independent_variable[old_index]) {
1289  independent_variable[old_index] = false;
1290  }
1291  if (dependent_variable[old_index]) {
1292  dependent_variable[old_index] = false;
1293  }
1294  }
1295 
1296  size_t nin = opstack[i]->input_size();
1297  for (size_t k = 0; k < nin; k++) {
1298  new_glob.inputs.push_back(var_remap[args.input(k)]);
1299  }
1300 
1301  new_glob.opstack.push_back(opstack[i]->copy());
1302  }
1303 
1304  independent_variable.flip();
1305  dependent_variable.flip();
1306 
1307  for (size_t i = 0; i < inv_index.size(); i++) {
1308  Index old_var = inv_index[i];
1309  if (independent_variable[old_var])
1310  new_glob.inv_index.push_back(var_remap[old_var]);
1311  }
1312  for (size_t i = 0; i < dep_index.size(); i++) {
1313  Index old_var = dep_index[i];
1314  if (dependent_variable[old_var])
1315  new_glob.dep_index.push_back(var_remap[old_var]);
1316  }
1317  return new_glob;
1318 }
1319 
1320 void global::extract_sub_inplace(std::vector<bool> marks) {
1321  TMBAD_ASSERT(marks.size() == values.size());
1322  std::vector<Index> var_remap(values.size(), 0);
1323  std::vector<bool> independent_variable = inv_marks();
1324  std::vector<bool> dependent_variable = dep_marks();
1325  intervals<Index> marked_intervals;
1326  ForwardArgs<bool> args(inputs, marks, marked_intervals);
1327  size_t s = 0, s_input = 0;
1328  std::vector<bool> opstack_deallocate(opstack.size(), false);
1329 
1330  for (size_t i = 0; i < opstack.size(); i++) {
1331  op_info info = opstack[i]->info();
1332 
1333  size_t nout = opstack[i]->output_size();
1334  bool any_marked_output = info.test(op_info::elimination_protected);
1335  for (size_t j = 0; j < nout; j++) {
1336  any_marked_output |= args.y(j);
1337  }
1338  if (info.test(op_info::updating) && nout == 0) {
1339  Dependencies dep;
1340  opstack[i]->dependencies_updating(args, dep);
1341  any_marked_output |= dep.any(args.values);
1342  }
1343 
1344  if (any_marked_output) {
1345  for (size_t k = 0; k < nout; k++) {
1346  Index new_index = s;
1347  Index old_index = args.output(k);
1348  var_remap[old_index] = new_index;
1349  values[new_index] = values[old_index];
1350  if (independent_variable[old_index]) {
1351  independent_variable[old_index] = false;
1352  }
1353  if (dependent_variable[old_index]) {
1354  dependent_variable[old_index] = false;
1355  }
1356  s++;
1357  }
1358 
1359  size_t nin = opstack[i]->input_size();
1360  for (size_t k = 0; k < nin; k++) {
1361  inputs[s_input] = var_remap[args.input(k)];
1362  s_input++;
1363  }
1364  }
1365  opstack[i]->increment(args.ptr);
1366  if (!any_marked_output) {
1367  opstack_deallocate[i] = true;
1368  }
1369  }
1370 
1371  independent_variable.flip();
1372  dependent_variable.flip();
1373  std::vector<Index> new_inv_index;
1374  for (size_t i = 0; i < inv_index.size(); i++) {
1375  Index old_var = inv_index[i];
1376  if (independent_variable[old_var])
1377  new_inv_index.push_back(var_remap[old_var]);
1378  }
1379  inv_index = new_inv_index;
1380  std::vector<Index> new_dep_index;
1381  for (size_t i = 0; i < dep_index.size(); i++) {
1382  Index old_var = dep_index[i];
1383  if (dependent_variable[old_var])
1384  new_dep_index.push_back(var_remap[old_var]);
1385  }
1386  dep_index = new_dep_index;
1387 
1388  inputs.resize(s_input);
1389  values.resize(s);
1390  size_t k = 0;
1391  for (size_t i = 0; i < opstack.size(); i++) {
1392  if (opstack_deallocate[i]) {
1393  opstack[i]->deallocate();
1394  } else {
1395  opstack[k] = opstack[i];
1396  k++;
1397  }
1398  }
1399  opstack.resize(k);
1400 
1401  if (opstack.any.test(op_info::dynamic)) this->forward();
1402 }
1403 
1404 global global::extract_sub() {
1405  std::vector<Index> var_remap;
1406  return extract_sub(var_remap);
1407 }
1408 
1409 std::vector<Index> global::var2op() {
1410  std::vector<Index> var2op(values.size());
1411  Args<> args(inputs);
1412  size_t j = 0;
1413  for (size_t i = 0; i < opstack.size(); i++) {
1414  opstack[i]->increment(args.ptr);
1415  for (; j < (size_t)args.ptr.second; j++) {
1416  var2op[j] = i;
1417  }
1418  }
1419  return var2op;
1420 }
1421 
1422 std::vector<bool> global::var2op(const std::vector<bool> &values) {
1423  std::vector<bool> ans(opstack.size(), false);
1424  Args<> args(inputs);
1425  size_t j = 0;
1426  for (size_t i = 0; i < opstack.size(); i++) {
1427  opstack[i]->increment(args.ptr);
1428  for (; j < (size_t)args.ptr.second; j++) {
1429  ans[i] = ans[i] || values[j];
1430  }
1431  }
1432  return ans;
1433 }
1434 
1435 std::vector<Index> global::op2var(const std::vector<Index> &seq) {
1436  std::vector<bool> seq_mark = mark_space(opstack.size(), seq);
1437  std::vector<Index> ans;
1438  Args<> args(inputs);
1439  size_t j = 0;
1440  for (size_t i = 0; i < opstack.size(); i++) {
1441  opstack[i]->increment(args.ptr);
1442  for (; j < (size_t)args.ptr.second; j++) {
1443  if (seq_mark[i]) ans.push_back(j);
1444  }
1445  }
1446  return ans;
1447 }
1448 
1449 std::vector<bool> global::op2var(const std::vector<bool> &seq_mark) {
1450  std::vector<bool> ans(values.size());
1451  Args<> args(inputs);
1452  size_t j = 0;
1453  for (size_t i = 0; i < opstack.size(); i++) {
1454  opstack[i]->increment(args.ptr);
1455  for (; j < (size_t)args.ptr.second; j++) {
1456  if (seq_mark[i]) ans[j] = true;
1457  }
1458  }
1459  return ans;
1460 }
1461 
1462 std::vector<Index> global::op2idx(const std::vector<Index> &var_subset,
1463  Index NA) {
1464  std::vector<Index> v2o = var2op();
1465  std::vector<Index> op2idx(opstack.size(), NA);
1466  for (size_t i = var_subset.size(); i > 0;) {
1467  i--;
1468  op2idx[v2o[var_subset[i]]] = i;
1469  }
1470  return op2idx;
1471 }
1472 
1473 std::vector<bool> global::mark_space(size_t n, const std::vector<Index> ind) {
1474  std::vector<bool> mark(n, false);
1475  for (size_t i = 0; i < ind.size(); i++) {
1476  mark[ind[i]] = true;
1477  }
1478  return mark;
1479 }
1480 
1481 std::vector<bool> global::inv_marks() {
1482  return mark_space(values.size(), inv_index);
1483 }
1484 
1485 std::vector<bool> global::dep_marks() {
1486  return mark_space(values.size(), dep_index);
1487 }
1488 
1489 std::vector<bool> global::subgraph_marks() {
1490  return mark_space(opstack.size(), subgraph_seq);
1491 }
1492 
1493 global::append_edges::append_edges(size_t &i, size_t num_nodes,
1494  const std::vector<bool> &keep_var,
1495  std::vector<Index> &var2op,
1496  std::vector<IndexPair> &edges)
1497  : i(i),
1498  keep_var(keep_var),
1499  var2op(var2op),
1500  edges(edges),
1501  op_marks(num_nodes, false),
1502  pos(0) {}
1503 
1504 void global::append_edges::operator()(Index dep_j) {
1505  if (keep_var[dep_j]) {
1506  size_t k = var2op[dep_j];
1507  if (i != k && !op_marks[k]) {
1508  IndexPair edge;
1509 
1510  edge.first = k;
1511  edge.second = i;
1512  edges.push_back(edge);
1513  op_marks[k] = true;
1514  }
1515  }
1516 }
1517 
1518 void global::append_edges::start_iteration() { pos = edges.size(); }
1519 
1520 void global::append_edges::end_iteration() {
1521  size_t n = edges.size() - pos;
1522  for (size_t j = 0; j < n; j++) op_marks[edges[pos + j].first] = false;
1523 }
1524 
1525 graph global::build_graph(bool transpose, const std::vector<bool> &keep_var) {
1526  TMBAD_ASSERT(keep_var.size() == values.size());
1527 
1528  std::vector<Index> var2op = this->var2op();
1529 
1530  bool any_updating = false;
1531 
1532  Args<> args(inputs);
1533  std::vector<IndexPair> edges;
1534  Dependencies dep;
1535  size_t i = 0;
1536  append_edges F(i, opstack.size(), keep_var, var2op, edges);
1537  for (; i < opstack.size(); i++) {
1538  any_updating |= opstack[i]->info().test(op_info::updating);
1539  dep.clear();
1540  opstack[i]->dependencies(args, dep);
1541  F.start_iteration();
1542  dep.apply(F);
1543  F.end_iteration();
1544  opstack[i]->increment(args.ptr);
1545  }
1546  if (any_updating) {
1547  size_t begin = edges.size();
1548  i = 0;
1549  args = Args<>(inputs);
1550  for (; i < opstack.size(); i++) {
1551  dep.clear();
1552  opstack[i]->dependencies_updating(args, dep);
1553  F.start_iteration();
1554  dep.apply(F);
1555  F.end_iteration();
1556  opstack[i]->increment(args.ptr);
1557  }
1558  for (size_t j = begin; j < edges.size(); j++)
1559  std::swap(edges[j].first, edges[j].second);
1560  }
1561 
1562  if (transpose) {
1563  for (size_t j = 0; j < edges.size(); j++)
1564  std::swap(edges[j].first, edges[j].second);
1565  }
1566 
1567  graph G(opstack.size(), edges);
1568 
1569  for (size_t i = 0; i < inv_index.size(); i++)
1570  G.inv2op.push_back(var2op[inv_index[i]]);
1571  for (size_t i = 0; i < dep_index.size(); i++)
1572  G.dep2op.push_back(var2op[dep_index[i]]);
1573  return G;
1574 }
1575 
1576 graph global::forward_graph(std::vector<bool> keep_var) {
1577  if (keep_var.size() == 0) {
1578  keep_var.resize(values.size(), true);
1579  }
1580  TMBAD_ASSERT(values.size() == keep_var.size());
1581  return build_graph(false, keep_var);
1582 }
1583 
1584 graph global::reverse_graph(std::vector<bool> keep_var) {
1585  if (keep_var.size() == 0) {
1586  keep_var.resize(values.size(), true);
1587  }
1588  TMBAD_ASSERT(values.size() == keep_var.size());
1589  return build_graph(true, keep_var);
1590 }
1591 
1592 bool global::identical(const global &other) const {
1593  if (inv_index != other.inv_index) return false;
1594  ;
1595  if (dep_index != other.dep_index) return false;
1596  ;
1597  if (opstack.size() != other.opstack.size()) return false;
1598  ;
1599  for (size_t i = 0; i < opstack.size(); i++) {
1600  if (opstack[i]->identifier() != other.opstack[i]->identifier())
1601  return false;
1602  ;
1603  }
1604  if (inputs != other.inputs) return false;
1605  ;
1606  if (values.size() != other.values.size()) return false;
1607  ;
1608  OperatorPure *constant = getOperator<ConstOp>();
1609  IndexPair ptr(0, 0);
1610  for (size_t i = 0; i < opstack.size(); i++) {
1611  if (opstack[i] == constant) {
1612  if (values[ptr.second] != other.values[ptr.second]) return false;
1613  ;
1614  }
1615  opstack[i]->increment(ptr);
1616  }
1617 
1618  return true;
1619 }
1620 
1621 hash_t global::hash() const {
1622  hash_t h = 37;
1623 
1624  hash(h, inv_index.size());
1625  ;
1626  for (size_t i = 0; i < inv_index.size(); i++) hash(h, inv_index[i]);
1627  ;
1628  ;
1629  hash(h, dep_index.size());
1630  ;
1631  for (size_t i = 0; i < dep_index.size(); i++) hash(h, dep_index[i]);
1632  ;
1633  ;
1634  hash(h, opstack.size());
1635  ;
1636  for (size_t i = 0; i < opstack.size(); i++) hash(h, opstack[i]);
1637  ;
1638  ;
1639  hash(h, inputs.size());
1640  ;
1641  for (size_t i = 0; i < inputs.size(); i++) hash(h, inputs[i]);
1642  ;
1643  ;
1644  hash(h, values.size());
1645  ;
1646  OperatorPure *constant = getOperator<ConstOp>();
1647  IndexPair ptr(0, 0);
1648  for (size_t i = 0; i < opstack.size(); i++) {
1649  if (opstack[i] == constant) {
1650  hash(h, values[ptr.second]);
1651  ;
1652  }
1653  opstack[i]->increment(ptr);
1654  }
1655 
1656  return h;
1657 }
1658 
1659 std::vector<hash_t> global::hash_sweep(hash_config cfg) const {
1660  std::vector<Index> opstack_id;
1661  if (cfg.deterministic) {
1662  std::vector<size_t> tmp(opstack.size());
1663  for (size_t i = 0; i < tmp.size(); i++)
1664  tmp[i] = (size_t)opstack[i]->identifier();
1665  opstack_id = radix::first_occurance<Index>(tmp);
1666  hash_t spread = (hash_t(1) << (sizeof(hash_t) * 4)) - 1;
1667  for (size_t i = 0; i < opstack_id.size(); i++)
1668  opstack_id[i] = (opstack_id[i] + 1) * spread;
1669  }
1670 
1671  std::vector<hash_t> hash_vec(values.size(), 37);
1672  Dependencies dep;
1673  OperatorPure *inv = getOperator<InvOp>();
1674  OperatorPure *constant = getOperator<ConstOp>();
1675 
1676  if (cfg.strong_inv) {
1677  bool have_inv_seed = (cfg.inv_seed.size() > 0);
1678  if (have_inv_seed) {
1679  TMBAD_ASSERT(cfg.inv_seed.size() == inv_index.size());
1680  }
1681  for (size_t i = 0; i < inv_index.size(); i++) {
1682  hash_vec[inv_index[i]] += (have_inv_seed ? cfg.inv_seed[i] + 1 : (i + 1));
1683  }
1684  }
1685 
1686  Args<> args(inputs);
1687  IndexPair &ptr = args.ptr;
1688  for (size_t i = 0; i < opstack.size(); i++) {
1689  if (opstack[i] == inv) {
1690  opstack[i]->increment(ptr);
1691  continue;
1692  }
1693  dep.clear();
1694 
1695  opstack[i]->dependencies(args, dep);
1696 
1697  hash_t h = 37;
1698  for (size_t j = 0; j < dep.size(); j++) {
1699  if (j == 0)
1700  h = hash_vec[dep[0]];
1701  else
1702  hash(h, hash_vec[dep[j]]);
1703  ;
1704  }
1705 
1706  if (!cfg.deterministic) {
1707  hash(h, opstack[i]->identifier());
1708  ;
1709  } else {
1710  hash(h, opstack_id[i]);
1711  ;
1712  }
1713 
1714  if (opstack[i] == constant && cfg.strong_const) {
1715  hash(h, values[ptr.second]);
1716  ;
1717 
1718  hash(h, values[ptr.second] > 0);
1719  ;
1720  }
1721 
1722  size_t noutput = opstack[i]->output_size();
1723  for (size_t j = 0; j < noutput; j++) {
1724  hash_vec[ptr.second + j] = h + j * cfg.strong_output;
1725  }
1726 
1727  opstack[i]->increment(ptr);
1728  }
1729  if (!cfg.reduce) return hash_vec;
1730  std::vector<hash_t> ans(dep_index.size());
1731  for (size_t j = 0; j < dep_index.size(); j++) {
1732  ans[j] = hash_vec[dep_index[j]];
1733  }
1734  return ans;
1735 }
1736 
1737 std::vector<hash_t> global::hash_sweep(bool weak) const {
1738  hash_config cfg;
1739  cfg.strong_inv = !weak;
1740  cfg.strong_const = true;
1741  cfg.strong_output = true;
1742  cfg.reduce = weak;
1743  cfg.deterministic = false;
1744  return hash_sweep(cfg);
1745 }
1746 
1747 void global::eliminate() {
1748  this->shrink_to_fit();
1749 
1750  std::vector<bool> marks;
1751  marks.resize(values.size(), false);
1752 
1753  for (size_t i = 0; i < inv_index.size(); i++) marks[inv_index[i]] = true;
1754  for (size_t i = 0; i < dep_index.size(); i++) marks[dep_index[i]] = true;
1755 
1756  reverse(marks);
1757 
1758  if (false) {
1759  set_subgraph(marks);
1760 
1761  *this = extract_sub();
1762  }
1763  this->extract_sub_inplace(marks);
1764  this->shrink_to_fit();
1765 }
1766 
1767 global::print_config::print_config() : prefix(""), mark("*"), depth(0) {}
1768 
1769 void global::print(print_config cfg) {
1770  using std::endl;
1771  using std::left;
1772  using std::setw;
1773  IndexPair ptr(0, 0);
1774  std::vector<bool> sgm = subgraph_marks();
1775  bool have_subgraph = (subgraph_seq.size() > 0);
1776  int v = 0;
1777  print_config cfg2 = cfg;
1778  cfg2.depth--;
1779  cfg2.prefix = cfg.prefix + "##";
1780  Rcout << cfg.prefix;
1781  Rcout << setw(7) << "OpName:" << setw(7 + have_subgraph)
1782  << "Node:" << setw(13) << "Value:" << setw(13) << "Deriv:" << setw(13)
1783  << "Index:";
1784  Rcout << " "
1785  << "Inputs:";
1786  Rcout << endl;
1787  for (size_t i = 0; i < opstack.size(); i++) {
1788  Rcout << cfg.prefix;
1789  Rcout << setw(7) << opstack[i]->op_name();
1790  if (have_subgraph) {
1791  if (sgm[i])
1792  Rcout << cfg.mark;
1793  else
1794  Rcout << " ";
1795  }
1796  Rcout << setw(7) << i;
1797  int numvar = opstack[i]->output_size();
1798  for (int j = 0; j < numvar + (numvar == 0); j++) {
1799  if (j > 0) Rcout << cfg.prefix;
1800  Rcout << setw((7 + 7) * (j > 0) + 13);
1801  if (numvar > 0)
1802  Rcout << values[v];
1803  else
1804  Rcout << "";
1805  Rcout << setw(13);
1806  if (numvar > 0) {
1807  if (derivs.size() == values.size())
1808  Rcout << derivs[v];
1809  else
1810  Rcout << "NA";
1811  } else {
1812  Rcout << "";
1813  }
1814  Rcout << setw(13);
1815  if (numvar > 0) {
1816  Rcout << v;
1817  } else {
1818  Rcout << "";
1819  }
1820  if (j == 0) {
1821  IndexPair ptr_old = ptr;
1822  opstack[i]->increment(ptr);
1823  int ninput = ptr.first - ptr_old.first;
1824  for (int k = 0; k < ninput; k++) {
1825  if (k == 0) Rcout << " ";
1826  Rcout << " " << inputs[ptr_old.first + k];
1827  }
1828  }
1829  Rcout << endl;
1830  if (numvar > 0) {
1831  v++;
1832  }
1833  }
1834  if (cfg.depth > 0) opstack[i]->print(cfg2);
1835  }
1836 }
1837 
1838 void global::print() { this->print(print_config()); }
1839 
1840 global::DynamicInputOutputOperator::DynamicInputOutputOperator(Index ninput,
1841  Index noutput)
1842  : ninput_(ninput), noutput_(noutput) {}
1843 
1844 Index global::DynamicInputOutputOperator::input_size() const {
1845  return this->ninput_;
1846 }
1847 
1848 Index global::DynamicInputOutputOperator::output_size() const {
1849  return this->noutput_;
1850 }
1851 
1852 const char *global::InvOp::op_name() { return "InvOp"; }
1853 
1854 const char *global::DepOp::op_name() { return "DepOp"; }
1855 
1856 void global::ConstOp::forward(ForwardArgs<Replay> &args) {
1857  args.y(0).addToTape();
1858 }
1859 
1860 const char *global::ConstOp::op_name() { return "ConstOp"; }
1861 
1862 void global::ConstOp::forward(ForwardArgs<Writer> &args) {
1863  if (args.const_literals) {
1864  args.y(0) = args.y_const(0);
1865  }
1866 }
1867 
1868 global::DataOp::DataOp(Index n) { Base::noutput = n; }
1869 
1870 const char *global::DataOp::op_name() { return "DataOp"; }
1871 
1872 void global::DataOp::forward(ForwardArgs<Writer> &args) { TMBAD_ASSERT(false); }
1873 
1874 global::ZeroOp::ZeroOp(Index n) { Base::noutput = n; }
1875 
1876 const char *global::ZeroOp::op_name() { return "ZeroOp"; }
1877 
1878 void global::ZeroOp::forward(ForwardArgs<Writer> &args) { TMBAD_ASSERT(false); }
1879 
1880 void global::ZeroOp::operator()(Replay *x, Index n) {
1881  Complete<ZeroOp> Z(n);
1882  ad_segment y = Z(ad_segment());
1883  for (size_t i = 0; i < n; i++) x[i] = y[i];
1884 }
1885 
1886 global::NullOp::NullOp() {}
1887 
1888 const char *global::NullOp::op_name() { return "NullOp"; }
1889 
1890 global::NullOp2::NullOp2(Index ninput, Index noutput)
1891  : global::DynamicInputOutputOperator(ninput, noutput) {}
1892 
1893 const char *global::NullOp2::op_name() { return "NullOp2"; }
1894 
1895 global::RefOp::RefOp(global *glob, Index i) : glob(glob), i(i) {}
1896 
1897 void global::RefOp::forward(ForwardArgs<Scalar> &args) {
1898  args.y(0) = glob->values[i];
1899 }
1900 
1901 void global::RefOp::forward(ForwardArgs<Replay> &args) {
1902  if (get_glob() == this->glob) {
1903  ad_plain tmp;
1904  tmp.index = i;
1905  args.y(0) = tmp;
1906  } else {
1907  global::OperatorPure *pOp =
1908  get_glob()->getOperator<RefOp>(this->glob, this->i);
1909  args.y(0) =
1910  get_glob()->add_to_stack<RefOp>(pOp, std::vector<ad_plain>(0))[0];
1911  }
1912 }
1913 
1914 void global::RefOp::reverse(ReverseArgs<Replay> &args) {
1915  if (get_glob() == this->glob) {
1916  args.dx(0) += args.dy(0);
1917  }
1918 }
1919 
1920 const char *global::RefOp::op_name() { return "RefOp"; }
1921 
1922 OperatorPure *global::Fuse(OperatorPure *Op1, OperatorPure *Op2) {
1923  if (Op1 == Op2)
1924  return Op1->self_fuse();
1925  else
1926  return Op1->other_fuse(Op2);
1927 }
1928 
1929 void global::set_fuse(bool flag) { fuse = flag; }
1930 
1931 void global::add_to_opstack(OperatorPure *pOp) {
1932  if (fuse) {
1933  while (this->opstack.size() > 0) {
1934  OperatorPure *OpTry = this->Fuse(this->opstack.back(), pOp);
1935  if (OpTry == NULL) break;
1936 
1937  this->opstack.pop_back();
1938  pOp = OpTry;
1939  }
1940  }
1941 
1942  this->opstack.push_back(pOp);
1943 }
1944 
1945 bool global::ad_plain::initialized() const { return index != NA; }
1946 
1947 bool global::ad_plain::on_some_tape() const { return initialized(); }
1948 
1949 void global::ad_plain::addToTape() const { TMBAD_ASSERT(initialized()); }
1950 
1951 global *global::ad_plain::glob() const {
1952  return (on_some_tape() ? get_glob() : NULL);
1953 }
1954 
1955 void global::ad_plain::override_by(const ad_plain &x) const {}
1956 
1957 global::ad_plain::ad_plain() : index(NA) {}
1958 
1959 global::ad_plain::ad_plain(Scalar x) {
1960  *this = get_glob()->add_to_stack<ConstOp>(x);
1961 }
1962 
1963 global::ad_plain::ad_plain(ad_aug x) {
1964  x.addToTape();
1965  *this = x.taped_value;
1966 }
1967 
1968 Replay global::ad_plain::CopyOp::eval(Replay x0) { return x0.copy(); }
1969 
1970 const char *global::ad_plain::CopyOp::op_name() { return "CopyOp"; }
1971 
1972 ad_plain global::ad_plain::copy() const {
1973  ad_plain ans = get_glob()->add_to_stack<CopyOp>(*this);
1974  return ans;
1975 }
1976 
1977 Replay global::ad_plain::ValOp::eval(Replay x0) { return x0.copy0(); }
1978 
1979 void global::ad_plain::ValOp::dependencies(Args<> &args,
1980  Dependencies &dep) const {}
1981 
1982 const char *global::ad_plain::ValOp::op_name() { return "ValOp"; }
1983 
1984 ad_plain global::ad_plain::copy0() const {
1985  ad_plain ans = get_glob()->add_to_stack<ValOp>(*this);
1986  return ans;
1987 }
1988 
1989 ad_plain global::ad_plain::operator+(const ad_plain &other) const {
1990  ad_plain ans;
1991  ans = get_glob()->add_to_stack<AddOp>(*this, other);
1992  return ans;
1993 }
1994 
1995 ad_plain global::ad_plain::operator-(const ad_plain &other) const {
1996  ad_plain ans;
1997  ans = get_glob()->add_to_stack<SubOp>(*this, other);
1998  return ans;
1999 }
2000 
2001 ad_plain global::ad_plain::operator*(const ad_plain &other) const {
2002  ad_plain ans = get_glob()->add_to_stack<MulOp>(*this, other);
2003  return ans;
2004 }
2005 
2006 ad_plain global::ad_plain::operator*(const Scalar &other) const {
2007  ad_plain ans =
2008  get_glob()->add_to_stack<MulOp_<true, false> >(*this, ad_plain(other));
2009  return ans;
2010 }
2011 
2012 ad_plain global::ad_plain::operator/(const ad_plain &other) const {
2013  ad_plain ans = get_glob()->add_to_stack<DivOp>(*this, other);
2014  return ans;
2015 }
2016 
2017 const char *global::ad_plain::NegOp::op_name() { return "NegOp"; }
2018 
2019 ad_plain global::ad_plain::operator-() const {
2020  ad_plain ans = get_glob()->add_to_stack<NegOp>(*this);
2021  return ans;
2022 }
2023 
2024 ad_plain &global::ad_plain::operator+=(const ad_plain &other) {
2025  *this = *this + other;
2026  return *this;
2027 }
2028 
2029 ad_plain &global::ad_plain::operator-=(const ad_plain &other) {
2030  *this = *this - other;
2031  return *this;
2032 }
2033 
2034 ad_plain &global::ad_plain::operator*=(const ad_plain &other) {
2035  *this = *this * other;
2036  return *this;
2037 }
2038 
2039 ad_plain &global::ad_plain::operator/=(const ad_plain &other) {
2040  *this = *this / other;
2041  return *this;
2042 }
2043 
2044 void global::ad_plain::Dependent() {
2045  *this = get_glob()->add_to_stack<DepOp>(*this);
2046  get_glob()->dep_index.push_back(this->index);
2047 }
2048 
2049 void global::ad_plain::Independent() {
2050  Scalar val = (index == NA ? NAN : this->Value());
2051  *this = get_glob()->add_to_stack<InvOp>(val);
2052  get_glob()->inv_index.push_back(this->index);
2053 }
2054 
2055 Scalar &global::ad_plain::Value() { return get_glob()->values[index]; }
2056 
2057 Scalar global::ad_plain::Value() const { return get_glob()->values[index]; }
2058 
2059 Scalar global::ad_plain::Value(global *glob) const {
2060  return glob->values[index];
2061 }
2062 
2063 Scalar &global::ad_plain::Deriv() { return get_glob()->derivs[index]; }
2064 
2065 void global::ad_start() {
2066  TMBAD_ASSERT2(!in_use, "Tape already in use");
2067  TMBAD_ASSERT(parent_glob == NULL);
2068  parent_glob = global_ptr[TMBAD_THREAD_NUM];
2069  global_ptr[TMBAD_THREAD_NUM] = this;
2070  in_use = true;
2071 }
2072 
2073 void global::ad_stop() {
2074  TMBAD_ASSERT2(in_use, "Tape not in use");
2075  global_ptr[TMBAD_THREAD_NUM] = parent_glob;
2076  parent_glob = NULL;
2077  in_use = false;
2078 }
2079 
2080 void global::Independent(std::vector<ad_plain> &x) {
2081  for (size_t i = 0; i < x.size(); i++) {
2082  x[i].Independent();
2083  }
2084 }
2085 
2086 global::ad_segment::ad_segment() : n(0), c(0) {}
2087 
2088 global::ad_segment::ad_segment(ad_plain x, size_t n) : x(x), n(n), c(1) {}
2089 
2090 global::ad_segment::ad_segment(ad_aug x) : x(ad_plain(x)), n(1), c(1) {}
2091 
2092 global::ad_segment::ad_segment(Scalar x) : x(ad_plain(x)), n(1), c(1) {}
2093 
2094 global::ad_segment::ad_segment(Index idx, size_t n) : n(n) { x.index = idx; }
2095 
2096 global::ad_segment::ad_segment(ad_plain x, size_t r, size_t c)
2097  : x(x), n(r * c), c(c) {}
2098 
2099 global::ad_segment::ad_segment(Replay *x, size_t n, bool zero_check)
2100  : n(n), c(1) {
2101  if (zero_check && all_zero(x, n)) return;
2102  if (all_constant(x, n)) {
2103  global *glob = get_glob();
2104  size_t m = glob->values.size();
2105  Complete<DataOp> D(n);
2106  D(ad_segment());
2107  for (size_t i = 0; i < n; i++) glob->values[m + i] = x[i].Value();
2108  this->x.index = m;
2109  return;
2110  }
2111  if (!is_contiguous(x, n)) {
2112  size_t before = get_glob()->values.size();
2113  this->x = x[0].copy();
2114  for (size_t i = 1; i < n; i++) x[i].copy();
2115  size_t after = get_glob()->values.size();
2116  TMBAD_ASSERT2(after - before == n,
2117  "Each invocation of copy() should construct a new variable");
2118  return;
2119  }
2120  if (n > 0) this->x = x[0];
2121 }
2122 
2123 bool global::ad_segment::identicalZero() { return !x.initialized(); }
2124 
2125 bool global::ad_segment::all_on_active_tape(Replay *x, size_t n) {
2126  global *cur_glob = get_glob();
2127  for (size_t i = 0; i < n; i++) {
2128  bool ok = x[i].on_some_tape() && (x[i].glob() == cur_glob);
2129  if (!ok) return false;
2130  }
2131  return true;
2132 }
2133 
2134 bool global::ad_segment::is_contiguous(Replay *x, size_t n) {
2135  if (!all_on_active_tape(x, n)) return false;
2136  for (size_t i = 1; i < n; i++) {
2137  if (x[i].index() != x[i - 1].index() + 1) return false;
2138  }
2139  return true;
2140 }
2141 
2142 bool global::ad_segment::all_zero(Replay *x, size_t n) {
2143  for (size_t i = 0; i < n; i++) {
2144  if (!x[i].identicalZero()) return false;
2145  }
2146  return true;
2147 }
2148 
2149 bool global::ad_segment::all_constant(Replay *x, size_t n) {
2150  for (size_t i = 0; i < n; i++) {
2151  if (!x[i].constant()) return false;
2152  }
2153  return true;
2154 }
2155 
2156 size_t global::ad_segment::size() const { return n; }
2157 
2158 size_t global::ad_segment::rows() const { return n / c; }
2159 
2160 size_t global::ad_segment::cols() const { return c; }
2161 
2162 ad_plain global::ad_segment::operator[](size_t i) const {
2163  ad_plain ans;
2164  ans.index = x.index + i;
2165  return ans;
2166 }
2167 
2168 ad_plain global::ad_segment::offset() const { return x; }
2169 
2170 Index global::ad_segment::index() const { return x.index; }
2171 
2172 bool global::ad_aug::on_some_tape() const { return taped_value.initialized(); }
2173 
2175  return on_some_tape() && (this->glob() == get_glob());
2176 }
2177 
2178 bool global::ad_aug::ontape() const { return on_some_tape(); }
2179 
2180 bool global::ad_aug::constant() const { return !taped_value.initialized(); }
2181 
2182 Index global::ad_aug::index() const { return taped_value.index; }
2183 
2184 global *global::ad_aug::glob() const {
2185  return (on_some_tape() ? data.glob : NULL);
2186 }
2187 
2188 Scalar global::ad_aug::Value() const {
2189  if (on_some_tape())
2190  return taped_value.Value(this->data.glob);
2191  else
2192  return data.value;
2193 }
2194 
2196 
2197 global::ad_aug::ad_aug(Scalar x) { data.value = x; }
2198 
2199 global::ad_aug::ad_aug(ad_plain x) : taped_value(x) { data.glob = get_glob(); }
2200 
2202  if (on_some_tape()) {
2203  if (data.glob != get_glob()) {
2204  TMBAD_ASSERT2(in_context_stack(data.glob), "Variable not initialized?");
2205  global::OperatorPure *pOp =
2206  get_glob()->getOperator<RefOp>(data.glob, taped_value.index);
2207  this->taped_value =
2208  get_glob()->add_to_stack<RefOp>(pOp, std::vector<ad_plain>(0))[0];
2209 
2210  this->data.glob = get_glob();
2211  }
2212  return;
2213  }
2214  this->taped_value = ad_plain(data.value);
2215  this->data.glob = get_glob();
2216 }
2217 
2218 void global::ad_aug::override_by(const ad_plain &x) const {
2219  this->taped_value = x;
2220  this->data.glob = get_glob();
2221 }
2222 
2224  global *cur_glob = get_glob();
2225  while (cur_glob != NULL) {
2226  if (cur_glob == glob) return true;
2227  cur_glob = cur_glob->parent_glob;
2228  }
2229  return false;
2230 }
2231 
2233  if (on_active_tape()) {
2234  return taped_value.copy();
2235  } else {
2236  ad_aug cpy = *this;
2237  cpy.addToTape();
2238  return cpy;
2239  }
2240 }
2241 
2243  ad_aug cpy = *this;
2244  if (!cpy.on_active_tape()) {
2245  cpy.addToTape();
2246  }
2247  return cpy.taped_value.copy0();
2248 }
2249 
2251  return constant() && data.value == Scalar(0);
2252 }
2253 
2255  return constant() && data.value == Scalar(1);
2256 }
2257 
2258 bool global::ad_aug::bothConstant(const ad_aug &other) const {
2259  return constant() && other.constant();
2260 }
2261 
2262 bool global::ad_aug::identical(const ad_aug &other) const {
2263  if (constant() && other.constant()) return (data.value == other.data.value);
2264 
2265  if (glob() == other.glob())
2266  return (taped_value.index == other.taped_value.index);
2267  return false;
2268 }
2269 
2271  if (bothConstant(other)) return Scalar(this->data.value + other.data.value);
2272  if (this->identicalZero()) return other;
2273  if (other.identicalZero()) return *this;
2274  return ad_plain(*this) + ad_plain(other);
2275 }
2276 
2278  if (bothConstant(other)) return Scalar(this->data.value - other.data.value);
2279  if (other.identicalZero()) return *this;
2280  if (this->identicalZero()) return -other;
2281  if (this->identical(other)) return Scalar(0);
2282  return ad_plain(*this) - ad_plain(other);
2283 }
2284 
2286  if (this->constant()) return Scalar(-(this->data.value));
2287  return -ad_plain(*this);
2288 }
2289 
2291  if (bothConstant(other)) return Scalar(this->data.value * other.data.value);
2292  if (this->identicalZero()) return *this;
2293  if (other.identicalZero()) return other;
2294  if (this->identicalOne()) return other;
2295  if (other.identicalOne()) return *this;
2296  if (this->constant()) return ad_plain(other) * Scalar(this->data.value);
2297  if (other.constant()) return ad_plain(*this) * Scalar(other.data.value);
2298  return ad_plain(*this) * ad_plain(other);
2299 }
2300 
2302  if (bothConstant(other)) return Scalar(this->data.value / other.data.value);
2303  if (this->identicalZero()) return *this;
2304  if (other.identicalOne()) return *this;
2305  return ad_plain(*this) / ad_plain(other);
2306 }
2307 
2309  *this = *this + other;
2310  return *this;
2311 }
2312 
2314  *this = *this - other;
2315  return *this;
2316 }
2317 
2319  *this = *this * other;
2320  return *this;
2321 }
2322 
2324  *this = *this / other;
2325  return *this;
2326 }
2327 
2329  this->addToTape();
2330  taped_value.Dependent();
2331 }
2332 
2334  taped_value.Independent();
2335  taped_value.Value() = this->data.value;
2336  this->data.glob = get_glob();
2337 }
2338 
2339 Scalar &global::ad_aug::Value() {
2340  if (on_some_tape())
2341 
2342  return taped_value.Value();
2343  else
2344  return data.value;
2345 }
2346 
2347 Scalar &global::ad_aug::Deriv() { return taped_value.Deriv(); }
2348 
2349 void global::Independent(std::vector<ad_aug> &x) {
2350  for (size_t i = 0; i < x.size(); i++) {
2351  x[i].Independent();
2352  }
2353 }
2354 
2355 std::ostream &operator<<(std::ostream &os, const global::ad_plain &x) {
2356  os << x.Value();
2357  return os;
2358 }
2359 
2360 std::ostream &operator<<(std::ostream &os, const global::ad_aug &x) {
2361  os << "{";
2362  if (x.on_some_tape()) {
2363  os << "value=" << x.data.glob->values[x.taped_value.index] << ", ";
2364  os << "index=" << x.taped_value.index << ", ";
2365  os << "tape=" << x.data.glob;
2366  } else {
2367  os << "const=" << x.data.value;
2368  }
2369  os << "}";
2370  return os;
2371 }
2372 
2373 ad_plain_index::ad_plain_index(const Index &i) { this->index = i; }
2374 
2375 ad_plain_index::ad_plain_index(const ad_plain &x) : ad_plain(x) {}
2376 
2377 ad_aug_index::ad_aug_index(const Index &i) : ad_aug(ad_plain_index(i)) {}
2378 
2379 ad_aug_index::ad_aug_index(const ad_aug &x) : ad_aug(x) {}
2380 
2381 ad_aug_index::ad_aug_index(const ad_plain &x) : ad_aug(x) {}
2382 
2383 Scalar Value(Scalar x) { return x; }
2384 
2385 ad_aug operator+(const double &x, const ad_aug &y) { return ad_aug(x) + y; }
2386 
2387 ad_aug operator-(const double &x, const ad_aug &y) { return ad_aug(x) - y; }
2388 
2389 ad_aug operator*(const double &x, const ad_aug &y) { return ad_aug(x) * y; }
2390 
2391 ad_aug operator/(const double &x, const ad_aug &y) { return ad_aug(x) / y; }
2392 
2393 bool operator<(const double &x, const ad_adapt &y) { return x < y.Value(); }
2394 
2395 bool operator<=(const double &x, const ad_adapt &y) { return x <= y.Value(); }
2396 
2397 bool operator>(const double &x, const ad_adapt &y) { return x > y.Value(); }
2398 
2399 bool operator>=(const double &x, const ad_adapt &y) { return x >= y.Value(); }
2400 
2401 bool operator==(const double &x, const ad_adapt &y) { return x == y.Value(); }
2402 
2403 bool operator!=(const double &x, const ad_adapt &y) { return x != y.Value(); }
2404 
2405 Writer floor(const Writer &x) {
2406  return "floor"
2407  "(" +
2408  x + ")";
2409 }
2410 const char *FloorOp::op_name() { return "FloorOp"; }
2411 ad_plain floor(const ad_plain &x) {
2412  return get_glob()->add_to_stack<FloorOp>(x);
2413 }
2414 ad_aug floor(const ad_aug &x) {
2415  if (x.constant())
2416  return Scalar(floor(x.Value()));
2417  else
2418  return floor(ad_plain(x));
2419 }
2420 
2421 Writer ceil(const Writer &x) {
2422  return "ceil"
2423  "(" +
2424  x + ")";
2425 }
2426 const char *CeilOp::op_name() { return "CeilOp"; }
2427 ad_plain ceil(const ad_plain &x) { return get_glob()->add_to_stack<CeilOp>(x); }
2428 ad_aug ceil(const ad_aug &x) {
2429  if (x.constant())
2430  return Scalar(ceil(x.Value()));
2431  else
2432  return ceil(ad_plain(x));
2433 }
2434 
2435 Writer trunc(const Writer &x) {
2436  return "trunc"
2437  "(" +
2438  x + ")";
2439 }
2440 const char *TruncOp::op_name() { return "TruncOp"; }
2441 ad_plain trunc(const ad_plain &x) {
2442  return get_glob()->add_to_stack<TruncOp>(x);
2443 }
2444 ad_aug trunc(const ad_aug &x) {
2445  if (x.constant())
2446  return Scalar(trunc(x.Value()));
2447  else
2448  return trunc(ad_plain(x));
2449 }
2450 
2451 Writer round(const Writer &x) {
2452  return "round"
2453  "(" +
2454  x + ")";
2455 }
2456 const char *RoundOp::op_name() { return "RoundOp"; }
2457 ad_plain round(const ad_plain &x) {
2458  return get_glob()->add_to_stack<RoundOp>(x);
2459 }
2460 ad_aug round(const ad_aug &x) {
2461  if (x.constant())
2462  return Scalar(round(x.Value()));
2463  else
2464  return round(ad_plain(x));
2465 }
2466 
2467 double sign(const double &x) { return (x >= 0) - (x < 0); }
2468 
2469 Writer sign(const Writer &x) {
2470  return "sign"
2471  "(" +
2472  x + ")";
2473 }
2474 const char *SignOp::op_name() { return "SignOp"; }
2475 ad_plain sign(const ad_plain &x) { return get_glob()->add_to_stack<SignOp>(x); }
2476 ad_aug sign(const ad_aug &x) {
2477  if (x.constant())
2478  return Scalar(sign(x.Value()));
2479  else
2480  return sign(ad_plain(x));
2481 }
2482 
2483 double ge0(const double &x) { return (x >= 0); }
2484 
2485 double lt0(const double &x) { return (x < 0); }
2486 
2487 Writer ge0(const Writer &x) {
2488  return "ge0"
2489  "(" +
2490  x + ")";
2491 }
2492 const char *Ge0Op::op_name() { return "Ge0Op"; }
2493 ad_plain ge0(const ad_plain &x) { return get_glob()->add_to_stack<Ge0Op>(x); }
2494 ad_aug ge0(const ad_aug &x) {
2495  if (x.constant())
2496  return Scalar(ge0(x.Value()));
2497  else
2498  return ge0(ad_plain(x));
2499 }
2500 
2501 Writer lt0(const Writer &x) {
2502  return "lt0"
2503  "(" +
2504  x + ")";
2505 }
2506 const char *Lt0Op::op_name() { return "Lt0Op"; }
2507 ad_plain lt0(const ad_plain &x) { return get_glob()->add_to_stack<Lt0Op>(x); }
2508 ad_aug lt0(const ad_aug &x) {
2509  if (x.constant())
2510  return Scalar(lt0(x.Value()));
2511  else
2512  return lt0(ad_plain(x));
2513 }
2514 
2515 Writer fabs(const Writer &x) {
2516  return "fabs"
2517  "(" +
2518  x + ")";
2519 }
2520 void AbsOp::reverse(ReverseArgs<Scalar> &args) {
2521  typedef Scalar Type;
2522  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * sign(args.x(0));
2523 }
2524 const char *AbsOp::op_name() { return "AbsOp"; }
2525 ad_plain fabs(const ad_plain &x) { return get_glob()->add_to_stack<AbsOp>(x); }
2526 ad_aug fabs(const ad_aug &x) {
2527  if (x.constant())
2528  return Scalar(fabs(x.Value()));
2529  else
2530  return fabs(ad_plain(x));
2531 }
2532 ad_adapt fabs(const ad_adapt &x) { return ad_adapt(fabs(ad_aug(x))); }
2533 
2534 Writer sin(const Writer &x) {
2535  return "sin"
2536  "(" +
2537  x + ")";
2538 }
2539 void SinOp::reverse(ReverseArgs<Scalar> &args) {
2540  typedef Scalar Type;
2541  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * cos(args.x(0));
2542 }
2543 const char *SinOp::op_name() { return "SinOp"; }
2544 ad_plain sin(const ad_plain &x) { return get_glob()->add_to_stack<SinOp>(x); }
2545 ad_aug sin(const ad_aug &x) {
2546  if (x.constant())
2547  return Scalar(sin(x.Value()));
2548  else
2549  return sin(ad_plain(x));
2550 }
2551 ad_adapt sin(const ad_adapt &x) { return ad_adapt(sin(ad_aug(x))); }
2552 
2553 Writer cos(const Writer &x) {
2554  return "cos"
2555  "(" +
2556  x + ")";
2557 }
2558 void CosOp::reverse(ReverseArgs<Scalar> &args) {
2559  typedef Scalar Type;
2560  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * -sin(args.x(0));
2561 }
2562 const char *CosOp::op_name() { return "CosOp"; }
2563 ad_plain cos(const ad_plain &x) { return get_glob()->add_to_stack<CosOp>(x); }
2564 ad_aug cos(const ad_aug &x) {
2565  if (x.constant())
2566  return Scalar(cos(x.Value()));
2567  else
2568  return cos(ad_plain(x));
2569 }
2570 ad_adapt cos(const ad_adapt &x) { return ad_adapt(cos(ad_aug(x))); }
2571 
2572 Writer exp(const Writer &x) {
2573  return "exp"
2574  "(" +
2575  x + ")";
2576 }
2577 void ExpOp::reverse(ReverseArgs<Scalar> &args) {
2578  typedef Scalar Type;
2579  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * args.y(0);
2580 }
2581 const char *ExpOp::op_name() { return "ExpOp"; }
2582 ad_plain exp(const ad_plain &x) { return get_glob()->add_to_stack<ExpOp>(x); }
2583 ad_aug exp(const ad_aug &x) {
2584  if (x.constant())
2585  return Scalar(exp(x.Value()));
2586  else
2587  return exp(ad_plain(x));
2588 }
2589 ad_adapt exp(const ad_adapt &x) { return ad_adapt(exp(ad_aug(x))); }
2590 
2591 Writer log(const Writer &x) {
2592  return "log"
2593  "(" +
2594  x + ")";
2595 }
2596 void LogOp::reverse(ReverseArgs<Scalar> &args) {
2597  typedef Scalar Type;
2598  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * Type(1.) / args.x(0);
2599 }
2600 const char *LogOp::op_name() { return "LogOp"; }
2601 ad_plain log(const ad_plain &x) { return get_glob()->add_to_stack<LogOp>(x); }
2602 ad_aug log(const ad_aug &x) {
2603  if (x.constant())
2604  return Scalar(log(x.Value()));
2605  else
2606  return log(ad_plain(x));
2607 }
2608 ad_adapt log(const ad_adapt &x) { return ad_adapt(log(ad_aug(x))); }
2609 
2610 Writer sqrt(const Writer &x) {
2611  return "sqrt"
2612  "(" +
2613  x + ")";
2614 }
2615 void SqrtOp::reverse(ReverseArgs<Scalar> &args) {
2616  typedef Scalar Type;
2617  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * Type(0.5) / args.y(0);
2618 }
2619 const char *SqrtOp::op_name() { return "SqrtOp"; }
2620 ad_plain sqrt(const ad_plain &x) { return get_glob()->add_to_stack<SqrtOp>(x); }
2621 ad_aug sqrt(const ad_aug &x) {
2622  if (x.constant())
2623  return Scalar(sqrt(x.Value()));
2624  else
2625  return sqrt(ad_plain(x));
2626 }
2627 ad_adapt sqrt(const ad_adapt &x) { return ad_adapt(sqrt(ad_aug(x))); }
2628 
2629 Writer tan(const Writer &x) {
2630  return "tan"
2631  "(" +
2632  x + ")";
2633 }
2634 void TanOp::reverse(ReverseArgs<Scalar> &args) {
2635  typedef Scalar Type;
2636  if (args.dy(0) != Type(0))
2637  args.dx(0) += args.dy(0) * Type(1.) / (cos(args.x(0)) * cos(args.x(0)));
2638 }
2639 const char *TanOp::op_name() { return "TanOp"; }
2640 ad_plain tan(const ad_plain &x) { return get_glob()->add_to_stack<TanOp>(x); }
2641 ad_aug tan(const ad_aug &x) {
2642  if (x.constant())
2643  return Scalar(tan(x.Value()));
2644  else
2645  return tan(ad_plain(x));
2646 }
2647 ad_adapt tan(const ad_adapt &x) { return ad_adapt(tan(ad_aug(x))); }
2648 
2649 Writer sinh(const Writer &x) {
2650  return "sinh"
2651  "(" +
2652  x + ")";
2653 }
2654 void SinhOp::reverse(ReverseArgs<Scalar> &args) {
2655  typedef Scalar Type;
2656  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * cosh(args.x(0));
2657 }
2658 const char *SinhOp::op_name() { return "SinhOp"; }
2659 ad_plain sinh(const ad_plain &x) { return get_glob()->add_to_stack<SinhOp>(x); }
2660 ad_aug sinh(const ad_aug &x) {
2661  if (x.constant())
2662  return Scalar(sinh(x.Value()));
2663  else
2664  return sinh(ad_plain(x));
2665 }
2666 ad_adapt sinh(const ad_adapt &x) { return ad_adapt(sinh(ad_aug(x))); }
2667 
2668 Writer cosh(const Writer &x) {
2669  return "cosh"
2670  "(" +
2671  x + ")";
2672 }
2673 void CoshOp::reverse(ReverseArgs<Scalar> &args) {
2674  typedef Scalar Type;
2675  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * sinh(args.x(0));
2676 }
2677 const char *CoshOp::op_name() { return "CoshOp"; }
2678 ad_plain cosh(const ad_plain &x) { return get_glob()->add_to_stack<CoshOp>(x); }
2679 ad_aug cosh(const ad_aug &x) {
2680  if (x.constant())
2681  return Scalar(cosh(x.Value()));
2682  else
2683  return cosh(ad_plain(x));
2684 }
2685 ad_adapt cosh(const ad_adapt &x) { return ad_adapt(cosh(ad_aug(x))); }
2686 
2687 Writer tanh(const Writer &x) {
2688  return "tanh"
2689  "(" +
2690  x + ")";
2691 }
2692 void TanhOp::reverse(ReverseArgs<Scalar> &args) {
2693  typedef Scalar Type;
2694  if (args.dy(0) != Type(0))
2695  args.dx(0) += args.dy(0) * Type(1.) / (cosh(args.x(0)) * cosh(args.x(0)));
2696 }
2697 const char *TanhOp::op_name() { return "TanhOp"; }
2698 ad_plain tanh(const ad_plain &x) { return get_glob()->add_to_stack<TanhOp>(x); }
2699 ad_aug tanh(const ad_aug &x) {
2700  if (x.constant())
2701  return Scalar(tanh(x.Value()));
2702  else
2703  return tanh(ad_plain(x));
2704 }
2705 ad_adapt tanh(const ad_adapt &x) { return ad_adapt(tanh(ad_aug(x))); }
2706 
2707 Writer expm1(const Writer &x) {
2708  return "expm1"
2709  "(" +
2710  x + ")";
2711 }
2712 void Expm1::reverse(ReverseArgs<Scalar> &args) {
2713  typedef Scalar Type;
2714  if (args.dy(0) != Type(0)) args.dx(0) += args.dy(0) * args.y(0) + Type(1.);
2715 }
2716 const char *Expm1::op_name() { return "Expm1"; }
2717 ad_plain expm1(const ad_plain &x) { return get_glob()->add_to_stack<Expm1>(x); }
2718 ad_aug expm1(const ad_aug &x) {
2719  if (x.constant())
2720  return Scalar(expm1(x.Value()));
2721  else
2722  return expm1(ad_plain(x));
2723 }
2724 ad_adapt expm1(const ad_adapt &x) { return ad_adapt(expm1(ad_aug(x))); }
2725 
2726 Writer log1p(const Writer &x) {
2727  return "log1p"
2728  "(" +
2729  x + ")";
2730 }
2731 void Log1p::reverse(ReverseArgs<Scalar> &args) {
2732  typedef Scalar Type;
2733  if (args.dy(0) != Type(0))
2734  args.dx(0) += args.dy(0) * Type(1.) / (args.x(0) + Type(1.));
2735 }
2736 const char *Log1p::op_name() { return "Log1p"; }
2737 ad_plain log1p(const ad_plain &x) { return get_glob()->add_to_stack<Log1p>(x); }
2738 ad_aug log1p(const ad_aug &x) {
2739  if (x.constant())
2740  return Scalar(log1p(x.Value()));
2741  else
2742  return log1p(ad_plain(x));
2743 }
2744 ad_adapt log1p(const ad_adapt &x) { return ad_adapt(log1p(ad_aug(x))); }
2745 
2746 Writer asin(const Writer &x) {
2747  return "asin"
2748  "(" +
2749  x + ")";
2750 }
2751 void AsinOp::reverse(ReverseArgs<Scalar> &args) {
2752  typedef Scalar Type;
2753  if (args.dy(0) != Type(0))
2754  args.dx(0) +=
2755  args.dy(0) * Type(1.) / sqrt(Type(1.) - args.x(0) * args.x(0));
2756 }
2757 const char *AsinOp::op_name() { return "AsinOp"; }
2758 ad_plain asin(const ad_plain &x) { return get_glob()->add_to_stack<AsinOp>(x); }
2759 ad_aug asin(const ad_aug &x) {
2760  if (x.constant())
2761  return Scalar(asin(x.Value()));
2762  else
2763  return asin(ad_plain(x));
2764 }
2765 ad_adapt asin(const ad_adapt &x) { return ad_adapt(asin(ad_aug(x))); }
2766 
2767 Writer acos(const Writer &x) {
2768  return "acos"
2769  "(" +
2770  x + ")";
2771 }
2772 void AcosOp::reverse(ReverseArgs<Scalar> &args) {
2773  typedef Scalar Type;
2774  if (args.dy(0) != Type(0))
2775  args.dx(0) +=
2776  args.dy(0) * Type(-1.) / sqrt(Type(1.) - args.x(0) * args.x(0));
2777 }
2778 const char *AcosOp::op_name() { return "AcosOp"; }
2779 ad_plain acos(const ad_plain &x) { return get_glob()->add_to_stack<AcosOp>(x); }
2780 ad_aug acos(const ad_aug &x) {
2781  if (x.constant())
2782  return Scalar(acos(x.Value()));
2783  else
2784  return acos(ad_plain(x));
2785 }
2786 ad_adapt acos(const ad_adapt &x) { return ad_adapt(acos(ad_aug(x))); }
2787 
2788 Writer atan(const Writer &x) {
2789  return "atan"
2790  "(" +
2791  x + ")";
2792 }
2793 void AtanOp::reverse(ReverseArgs<Scalar> &args) {
2794  typedef Scalar Type;
2795  if (args.dy(0) != Type(0))
2796  args.dx(0) += args.dy(0) * Type(1.) / (Type(1.) + args.x(0) * args.x(0));
2797 }
2798 const char *AtanOp::op_name() { return "AtanOp"; }
2799 ad_plain atan(const ad_plain &x) { return get_glob()->add_to_stack<AtanOp>(x); }
2800 ad_aug atan(const ad_aug &x) {
2801  if (x.constant())
2802  return Scalar(atan(x.Value()));
2803  else
2804  return atan(ad_plain(x));
2805 }
2806 ad_adapt atan(const ad_adapt &x) { return ad_adapt(atan(ad_aug(x))); }
2807 
2808 Writer asinh(const Writer &x) {
2809  return "asinh"
2810  "(" +
2811  x + ")";
2812 }
2813 void AsinhOp::reverse(ReverseArgs<Scalar> &args) {
2814  typedef Scalar Type;
2815  if (args.dy(0) != Type(0))
2816  args.dx(0) +=
2817  args.dy(0) * Type(1.) / sqrt(args.x(0) * args.x(0) + Type(1.));
2818 }
2819 const char *AsinhOp::op_name() { return "AsinhOp"; }
2820 ad_plain asinh(const ad_plain &x) {
2821  return get_glob()->add_to_stack<AsinhOp>(x);
2822 }
2823 ad_aug asinh(const ad_aug &x) {
2824  if (x.constant())
2825  return Scalar(asinh(x.Value()));
2826  else
2827  return asinh(ad_plain(x));
2828 }
2829 ad_adapt asinh(const ad_adapt &x) { return ad_adapt(asinh(ad_aug(x))); }
2830 
2831 Writer acosh(const Writer &x) {
2832  return "acosh"
2833  "(" +
2834  x + ")";
2835 }
2836 void AcoshOp::reverse(ReverseArgs<Scalar> &args) {
2837  typedef Scalar Type;
2838  if (args.dy(0) != Type(0))
2839  args.dx(0) +=
2840  args.dy(0) * Type(1.) / sqrt(args.x(0) * args.x(0) - Type(1.));
2841 }
2842 const char *AcoshOp::op_name() { return "AcoshOp"; }
2843 ad_plain acosh(const ad_plain &x) {
2844  return get_glob()->add_to_stack<AcoshOp>(x);
2845 }
2846 ad_aug acosh(const ad_aug &x) {
2847  if (x.constant())
2848  return Scalar(acosh(x.Value()));
2849  else
2850  return acosh(ad_plain(x));
2851 }
2852 ad_adapt acosh(const ad_adapt &x) { return ad_adapt(acosh(ad_aug(x))); }
2853 
2854 Writer atanh(const Writer &x) {
2855  return "atanh"
2856  "(" +
2857  x + ")";
2858 }
2859 void AtanhOp::reverse(ReverseArgs<Scalar> &args) {
2860  typedef Scalar Type;
2861  if (args.dy(0) != Type(0))
2862  args.dx(0) += args.dy(0) * Type(1.) / (Type(1) - args.x(0) * args.x(0));
2863 }
2864 const char *AtanhOp::op_name() { return "AtanhOp"; }
2865 ad_plain atanh(const ad_plain &x) {
2866  return get_glob()->add_to_stack<AtanhOp>(x);
2867 }
2868 ad_aug atanh(const ad_aug &x) {
2869  if (x.constant())
2870  return Scalar(atanh(x.Value()));
2871  else
2872  return atanh(ad_plain(x));
2873 }
2874 ad_adapt atanh(const ad_adapt &x) { return ad_adapt(atanh(ad_aug(x))); }
2875 
2876 Writer pow(const Writer &x1, const Writer &x2) {
2877  return "pow"
2878  "(" +
2879  x1 + "," + x2 + ")";
2880 }
2881 const char *PowOp::op_name() { return "PowOp"; }
2882 ad_plain pow(const ad_plain &x1, const ad_plain &x2) {
2883  return get_glob()->add_to_stack<PowOp>(x1, x2);
2884 }
2885 ad_aug pow(const ad_aug &x1, const ad_aug &x2) {
2886  if (x1.constant() && x2.constant())
2887  return Scalar(pow(x1.Value(), x2.Value()));
2888  else
2889  return pow(ad_plain(x1), ad_plain(x2));
2890 }
2891 ad_adapt pow(const ad_adapt &x1, const ad_adapt &x2) {
2892  return ad_adapt(pow(ad_aug(x1), ad_aug(x2)));
2893 }
2894 
2895 Writer atan2(const Writer &x1, const Writer &x2) {
2896  return "atan2"
2897  "(" +
2898  x1 + "," + x2 + ")";
2899 }
2900 const char *Atan2::op_name() { return "Atan2"; }
2901 ad_plain atan2(const ad_plain &x1, const ad_plain &x2) {
2902  return get_glob()->add_to_stack<Atan2>(x1, x2);
2903 }
2904 ad_aug atan2(const ad_aug &x1, const ad_aug &x2) {
2905  if (x1.constant() && x2.constant())
2906  return Scalar(atan2(x1.Value(), x2.Value()));
2907  else
2908  return atan2(ad_plain(x1), ad_plain(x2));
2909 }
2910 ad_adapt atan2(const ad_adapt &x1, const ad_adapt &x2) {
2911  return ad_adapt(atan2(ad_aug(x1), ad_aug(x2)));
2912 }
2913 
2914 Writer max(const Writer &x1, const Writer &x2) {
2915  return "max"
2916  "(" +
2917  x1 + "," + x2 + ")";
2918 }
2919 const char *MaxOp::op_name() { return "MaxOp"; }
2920 ad_plain max(const ad_plain &x1, const ad_plain &x2) {
2921  return get_glob()->add_to_stack<MaxOp>(x1, x2);
2922 }
2923 ad_aug max(const ad_aug &x1, const ad_aug &x2) {
2924  if (x1.constant() && x2.constant())
2925  return Scalar(max(x1.Value(), x2.Value()));
2926  else
2927  return max(ad_plain(x1), ad_plain(x2));
2928 }
2929 ad_adapt max(const ad_adapt &x1, const ad_adapt &x2) {
2930  return ad_adapt(max(ad_aug(x1), ad_aug(x2)));
2931 }
2932 
2933 Writer min(const Writer &x1, const Writer &x2) {
2934  return "min"
2935  "(" +
2936  x1 + "," + x2 + ")";
2937 }
2938 const char *MinOp::op_name() { return "MinOp"; }
2939 ad_plain min(const ad_plain &x1, const ad_plain &x2) {
2940  return get_glob()->add_to_stack<MinOp>(x1, x2);
2941 }
2942 ad_aug min(const ad_aug &x1, const ad_aug &x2) {
2943  if (x1.constant() && x2.constant())
2944  return Scalar(min(x1.Value(), x2.Value()));
2945  else
2946  return min(ad_plain(x1), ad_plain(x2));
2947 }
2948 ad_adapt min(const ad_adapt &x1, const ad_adapt &x2) {
2949  return ad_adapt(min(ad_aug(x1), ad_aug(x2)));
2950 }
2951 void CondExpEqOp::forward(ForwardArgs<Scalar> &args) {
2952  if (args.x(0) == args.x(1)) {
2953  args.y(0) = args.x(2);
2954  } else {
2955  args.y(0) = args.x(3);
2956  }
2957 }
2958 void CondExpEqOp::reverse(ReverseArgs<Scalar> &args) {
2959  if (args.x(0) == args.x(1)) {
2960  args.dx(2) += args.dy(0);
2961  } else {
2962  args.dx(3) += args.dy(0);
2963  }
2964 }
2965 void CondExpEqOp::forward(ForwardArgs<Replay> &args) {
2966  args.y(0) = CondExpEq(args.x(0), args.x(1), args.x(2), args.x(3));
2967 }
2968 void CondExpEqOp::reverse(ReverseArgs<Replay> &args) {
2969  Replay zero(0);
2970  args.dx(2) += CondExpEq(args.x(0), args.x(1), args.dy(0), zero);
2971  args.dx(3) += CondExpEq(args.x(0), args.x(1), zero, args.dy(0));
2972 }
2973 void CondExpEqOp::forward(ForwardArgs<Writer> &args) {
2974  Writer w;
2975  w << "if (" << args.x(0) << "==" << args.x(1) << ") ";
2976  args.y(0) = args.x(2);
2977  w << " else ";
2978  args.y(0) = args.x(3);
2979 }
2980 void CondExpEqOp::reverse(ReverseArgs<Writer> &args) {
2981  Writer w;
2982  w << "if (" << args.x(0) << "==" << args.x(1) << ") ";
2983  args.dx(2) += args.dy(0);
2984  w << " else ";
2985  args.dx(3) += args.dy(0);
2986 }
2987 const char *CondExpEqOp::op_name() {
2988  return "CExp"
2989  "Eq";
2990 }
2991 Scalar CondExpEq(const Scalar &x0, const Scalar &x1, const Scalar &x2,
2992  const Scalar &x3) {
2993  if (x0 == x1)
2994  return x2;
2995  else
2996  return x3;
2997 }
2998 ad_plain CondExpEq(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
2999  const ad_plain &x3) {
3000  OperatorPure *pOp = get_glob()->getOperator<CondExpEqOp>();
3001  std::vector<ad_plain> x(4);
3002  x[0] = x0;
3003  x[1] = x1;
3004  x[2] = x2;
3005  x[3] = x3;
3006  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpEqOp>(pOp, x);
3007  return y[0];
3008 }
3009 ad_aug CondExpEq(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3010  const ad_aug &x3) {
3011  if (x0.constant() && x1.constant()) {
3012  if (x0.Value() == x1.Value())
3013  return x2;
3014  else
3015  return x3;
3016  } else {
3017  return CondExpEq(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3018  }
3019 }
3020 void CondExpNeOp::forward(ForwardArgs<Scalar> &args) {
3021  if (args.x(0) != args.x(1)) {
3022  args.y(0) = args.x(2);
3023  } else {
3024  args.y(0) = args.x(3);
3025  }
3026 }
3027 void CondExpNeOp::reverse(ReverseArgs<Scalar> &args) {
3028  if (args.x(0) != args.x(1)) {
3029  args.dx(2) += args.dy(0);
3030  } else {
3031  args.dx(3) += args.dy(0);
3032  }
3033 }
3034 void CondExpNeOp::forward(ForwardArgs<Replay> &args) {
3035  args.y(0) = CondExpNe(args.x(0), args.x(1), args.x(2), args.x(3));
3036 }
3037 void CondExpNeOp::reverse(ReverseArgs<Replay> &args) {
3038  Replay zero(0);
3039  args.dx(2) += CondExpNe(args.x(0), args.x(1), args.dy(0), zero);
3040  args.dx(3) += CondExpNe(args.x(0), args.x(1), zero, args.dy(0));
3041 }
3042 void CondExpNeOp::forward(ForwardArgs<Writer> &args) {
3043  Writer w;
3044  w << "if (" << args.x(0) << "!=" << args.x(1) << ") ";
3045  args.y(0) = args.x(2);
3046  w << " else ";
3047  args.y(0) = args.x(3);
3048 }
3049 void CondExpNeOp::reverse(ReverseArgs<Writer> &args) {
3050  Writer w;
3051  w << "if (" << args.x(0) << "!=" << args.x(1) << ") ";
3052  args.dx(2) += args.dy(0);
3053  w << " else ";
3054  args.dx(3) += args.dy(0);
3055 }
3056 const char *CondExpNeOp::op_name() {
3057  return "CExp"
3058  "Ne";
3059 }
3060 Scalar CondExpNe(const Scalar &x0, const Scalar &x1, const Scalar &x2,
3061  const Scalar &x3) {
3062  if (x0 != x1)
3063  return x2;
3064  else
3065  return x3;
3066 }
3067 ad_plain CondExpNe(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
3068  const ad_plain &x3) {
3069  OperatorPure *pOp = get_glob()->getOperator<CondExpNeOp>();
3070  std::vector<ad_plain> x(4);
3071  x[0] = x0;
3072  x[1] = x1;
3073  x[2] = x2;
3074  x[3] = x3;
3075  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpNeOp>(pOp, x);
3076  return y[0];
3077 }
3078 ad_aug CondExpNe(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3079  const ad_aug &x3) {
3080  if (x0.constant() && x1.constant()) {
3081  if (x0.Value() != x1.Value())
3082  return x2;
3083  else
3084  return x3;
3085  } else {
3086  return CondExpNe(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3087  }
3088 }
3089 void CondExpGtOp::forward(ForwardArgs<Scalar> &args) {
3090  if (args.x(0) > args.x(1)) {
3091  args.y(0) = args.x(2);
3092  } else {
3093  args.y(0) = args.x(3);
3094  }
3095 }
3096 void CondExpGtOp::reverse(ReverseArgs<Scalar> &args) {
3097  if (args.x(0) > args.x(1)) {
3098  args.dx(2) += args.dy(0);
3099  } else {
3100  args.dx(3) += args.dy(0);
3101  }
3102 }
3103 void CondExpGtOp::forward(ForwardArgs<Replay> &args) {
3104  args.y(0) = CondExpGt(args.x(0), args.x(1), args.x(2), args.x(3));
3105 }
3106 void CondExpGtOp::reverse(ReverseArgs<Replay> &args) {
3107  Replay zero(0);
3108  args.dx(2) += CondExpGt(args.x(0), args.x(1), args.dy(0), zero);
3109  args.dx(3) += CondExpGt(args.x(0), args.x(1), zero, args.dy(0));
3110 }
3111 void CondExpGtOp::forward(ForwardArgs<Writer> &args) {
3112  Writer w;
3113  w << "if (" << args.x(0) << ">" << args.x(1) << ") ";
3114  args.y(0) = args.x(2);
3115  w << " else ";
3116  args.y(0) = args.x(3);
3117 }
3118 void CondExpGtOp::reverse(ReverseArgs<Writer> &args) {
3119  Writer w;
3120  w << "if (" << args.x(0) << ">" << args.x(1) << ") ";
3121  args.dx(2) += args.dy(0);
3122  w << " else ";
3123  args.dx(3) += args.dy(0);
3124 }
3125 const char *CondExpGtOp::op_name() {
3126  return "CExp"
3127  "Gt";
3128 }
3129 Scalar CondExpGt(const Scalar &x0, const Scalar &x1, const Scalar &x2,
3130  const Scalar &x3) {
3131  if (x0 > x1)
3132  return x2;
3133  else
3134  return x3;
3135 }
3136 ad_plain CondExpGt(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
3137  const ad_plain &x3) {
3138  OperatorPure *pOp = get_glob()->getOperator<CondExpGtOp>();
3139  std::vector<ad_plain> x(4);
3140  x[0] = x0;
3141  x[1] = x1;
3142  x[2] = x2;
3143  x[3] = x3;
3144  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpGtOp>(pOp, x);
3145  return y[0];
3146 }
3147 ad_aug CondExpGt(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3148  const ad_aug &x3) {
3149  if (x0.constant() && x1.constant()) {
3150  if (x0.Value() > x1.Value())
3151  return x2;
3152  else
3153  return x3;
3154  } else {
3155  return CondExpGt(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3156  }
3157 }
3158 void CondExpLtOp::forward(ForwardArgs<Scalar> &args) {
3159  if (args.x(0) < args.x(1)) {
3160  args.y(0) = args.x(2);
3161  } else {
3162  args.y(0) = args.x(3);
3163  }
3164 }
3165 void CondExpLtOp::reverse(ReverseArgs<Scalar> &args) {
3166  if (args.x(0) < args.x(1)) {
3167  args.dx(2) += args.dy(0);
3168  } else {
3169  args.dx(3) += args.dy(0);
3170  }
3171 }
3172 void CondExpLtOp::forward(ForwardArgs<Replay> &args) {
3173  args.y(0) = CondExpLt(args.x(0), args.x(1), args.x(2), args.x(3));
3174 }
3175 void CondExpLtOp::reverse(ReverseArgs<Replay> &args) {
3176  Replay zero(0);
3177  args.dx(2) += CondExpLt(args.x(0), args.x(1), args.dy(0), zero);
3178  args.dx(3) += CondExpLt(args.x(0), args.x(1), zero, args.dy(0));
3179 }
3180 void CondExpLtOp::forward(ForwardArgs<Writer> &args) {
3181  Writer w;
3182  w << "if (" << args.x(0) << "<" << args.x(1) << ") ";
3183  args.y(0) = args.x(2);
3184  w << " else ";
3185  args.y(0) = args.x(3);
3186 }
3187 void CondExpLtOp::reverse(ReverseArgs<Writer> &args) {
3188  Writer w;
3189  w << "if (" << args.x(0) << "<" << args.x(1) << ") ";
3190  args.dx(2) += args.dy(0);
3191  w << " else ";
3192  args.dx(3) += args.dy(0);
3193 }
3194 const char *CondExpLtOp::op_name() {
3195  return "CExp"
3196  "Lt";
3197 }
3198 Scalar CondExpLt(const Scalar &x0, const Scalar &x1, const Scalar &x2,
3199  const Scalar &x3) {
3200  if (x0 < x1)
3201  return x2;
3202  else
3203  return x3;
3204 }
3205 ad_plain CondExpLt(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
3206  const ad_plain &x3) {
3207  OperatorPure *pOp = get_glob()->getOperator<CondExpLtOp>();
3208  std::vector<ad_plain> x(4);
3209  x[0] = x0;
3210  x[1] = x1;
3211  x[2] = x2;
3212  x[3] = x3;
3213  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpLtOp>(pOp, x);
3214  return y[0];
3215 }
3216 ad_aug CondExpLt(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3217  const ad_aug &x3) {
3218  if (x0.constant() && x1.constant()) {
3219  if (x0.Value() < x1.Value())
3220  return x2;
3221  else
3222  return x3;
3223  } else {
3224  return CondExpLt(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3225  }
3226 }
3227 void CondExpGeOp::forward(ForwardArgs<Scalar> &args) {
3228  if (args.x(0) >= args.x(1)) {
3229  args.y(0) = args.x(2);
3230  } else {
3231  args.y(0) = args.x(3);
3232  }
3233 }
3234 void CondExpGeOp::reverse(ReverseArgs<Scalar> &args) {
3235  if (args.x(0) >= args.x(1)) {
3236  args.dx(2) += args.dy(0);
3237  } else {
3238  args.dx(3) += args.dy(0);
3239  }
3240 }
3241 void CondExpGeOp::forward(ForwardArgs<Replay> &args) {
3242  args.y(0) = CondExpGe(args.x(0), args.x(1), args.x(2), args.x(3));
3243 }
3244 void CondExpGeOp::reverse(ReverseArgs<Replay> &args) {
3245  Replay zero(0);
3246  args.dx(2) += CondExpGe(args.x(0), args.x(1), args.dy(0), zero);
3247  args.dx(3) += CondExpGe(args.x(0), args.x(1), zero, args.dy(0));
3248 }
3249 void CondExpGeOp::forward(ForwardArgs<Writer> &args) {
3250  Writer w;
3251  w << "if (" << args.x(0) << ">=" << args.x(1) << ") ";
3252  args.y(0) = args.x(2);
3253  w << " else ";
3254  args.y(0) = args.x(3);
3255 }
3256 void CondExpGeOp::reverse(ReverseArgs<Writer> &args) {
3257  Writer w;
3258  w << "if (" << args.x(0) << ">=" << args.x(1) << ") ";
3259  args.dx(2) += args.dy(0);
3260  w << " else ";
3261  args.dx(3) += args.dy(0);
3262 }
3263 const char *CondExpGeOp::op_name() {
3264  return "CExp"
3265  "Ge";
3266 }
3267 Scalar CondExpGe(const Scalar &x0, const Scalar &x1, const Scalar &x2,
3268  const Scalar &x3) {
3269  if (x0 >= x1)
3270  return x2;
3271  else
3272  return x3;
3273 }
3274 ad_plain CondExpGe(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
3275  const ad_plain &x3) {
3276  OperatorPure *pOp = get_glob()->getOperator<CondExpGeOp>();
3277  std::vector<ad_plain> x(4);
3278  x[0] = x0;
3279  x[1] = x1;
3280  x[2] = x2;
3281  x[3] = x3;
3282  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpGeOp>(pOp, x);
3283  return y[0];
3284 }
3285 ad_aug CondExpGe(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3286  const ad_aug &x3) {
3287  if (x0.constant() && x1.constant()) {
3288  if (x0.Value() >= x1.Value())
3289  return x2;
3290  else
3291  return x3;
3292  } else {
3293  return CondExpGe(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3294  }
3295 }
3296 void CondExpLeOp::forward(ForwardArgs<Scalar> &args) {
3297  if (args.x(0) <= args.x(1)) {
3298  args.y(0) = args.x(2);
3299  } else {
3300  args.y(0) = args.x(3);
3301  }
3302 }
3303 void CondExpLeOp::reverse(ReverseArgs<Scalar> &args) {
3304  if (args.x(0) <= args.x(1)) {
3305  args.dx(2) += args.dy(0);
3306  } else {
3307  args.dx(3) += args.dy(0);
3308  }
3309 }
3310 void CondExpLeOp::forward(ForwardArgs<Replay> &args) {
3311  args.y(0) = CondExpLe(args.x(0), args.x(1), args.x(2), args.x(3));
3312 }
3313 void CondExpLeOp::reverse(ReverseArgs<Replay> &args) {
3314  Replay zero(0);
3315  args.dx(2) += CondExpLe(args.x(0), args.x(1), args.dy(0), zero);
3316  args.dx(3) += CondExpLe(args.x(0), args.x(1), zero, args.dy(0));
3317 }
3318 void CondExpLeOp::forward(ForwardArgs<Writer> &args) {
3319  Writer w;
3320  w << "if (" << args.x(0) << "<=" << args.x(1) << ") ";
3321  args.y(0) = args.x(2);
3322  w << " else ";
3323  args.y(0) = args.x(3);
3324 }
3325 void CondExpLeOp::reverse(ReverseArgs<Writer> &args) {
3326  Writer w;
3327  w << "if (" << args.x(0) << "<=" << args.x(1) << ") ";
3328  args.dx(2) += args.dy(0);
3329  w << " else ";
3330  args.dx(3) += args.dy(0);
3331 }
3332 const char *CondExpLeOp::op_name() {
3333  return "CExp"
3334  "Le";
3335 }
3336 Scalar CondExpLe(const Scalar &x0, const Scalar &x1, const Scalar &x2,
3337  const Scalar &x3) {
3338  if (x0 <= x1)
3339  return x2;
3340  else
3341  return x3;
3342 }
3343 ad_plain CondExpLe(const ad_plain &x0, const ad_plain &x1, const ad_plain &x2,
3344  const ad_plain &x3) {
3345  OperatorPure *pOp = get_glob()->getOperator<CondExpLeOp>();
3346  std::vector<ad_plain> x(4);
3347  x[0] = x0;
3348  x[1] = x1;
3349  x[2] = x2;
3350  x[3] = x3;
3351  std::vector<ad_plain> y = get_glob()->add_to_stack<CondExpLeOp>(pOp, x);
3352  return y[0];
3353 }
3354 ad_aug CondExpLe(const ad_aug &x0, const ad_aug &x1, const ad_aug &x2,
3355  const ad_aug &x3) {
3356  if (x0.constant() && x1.constant()) {
3357  if (x0.Value() <= x1.Value())
3358  return x2;
3359  else
3360  return x3;
3361  } else {
3362  return CondExpLe(ad_plain(x0), ad_plain(x1), ad_plain(x2), ad_plain(x3));
3363  }
3364 }
3365 
3366 Index SumOp::input_size() const { return n; }
3367 
3368 Index SumOp::output_size() const { return 1; }
3369 
3370 SumOp::SumOp(size_t n) : n(n) {}
3371 
3372 const char *SumOp::op_name() { return "SumOp"; }
3373 
3374 Index LogSpaceSumOp::input_size() const { return this->n; }
3375 
3376 Index LogSpaceSumOp::output_size() const { return 1; }
3377 
3378 LogSpaceSumOp::LogSpaceSumOp(size_t n) : n(n) {}
3379 
3380 void LogSpaceSumOp::forward(ForwardArgs<Scalar> &args) {
3381  Scalar Max = -INFINITY;
3382  for (size_t i = 0; i < n; i++) {
3383  if (Max < args.x(i)) Max = args.x(i);
3384  }
3385  args.y(0) = 0;
3386  for (size_t i = 0; i < n; i++) {
3387  args.y(0) += exp(args.x(i) - Max);
3388  }
3389  args.y(0) = Max + log(args.y(0));
3390 }
3391 
3392 void LogSpaceSumOp::forward(ForwardArgs<Replay> &args) {
3393  std::vector<ad_plain> x(input_size());
3394  for (Index i = 0; i < input_size(); i++) x[i] = args.x(i);
3395  args.y(0) = logspace_sum(x);
3396 }
3397 
3398 const char *LogSpaceSumOp::op_name() { return "LSSumOp"; }
3399 
3400 ad_plain logspace_sum(const std::vector<ad_plain> &x) {
3401  OperatorPure *pOp = get_glob()->getOperator<LogSpaceSumOp>(x.size());
3402  return get_glob()->add_to_stack<LogSpaceSumOp>(pOp, x)[0];
3403 }
3404 
3405 Index LogSpaceSumStrideOp::number_of_terms() const { return stride.size(); }
3406 
3407 Index LogSpaceSumStrideOp::input_size() const { return number_of_terms(); }
3408 
3409 Index LogSpaceSumStrideOp::output_size() const { return 1; }
3410 
3411 LogSpaceSumStrideOp::LogSpaceSumStrideOp(std::vector<Index> stride, size_t n)
3412  : stride(stride), n(n) {}
3413 
3414 void LogSpaceSumStrideOp::forward(ForwardArgs<Scalar> &args) {
3415  Scalar Max = -INFINITY;
3416 
3417  size_t m = stride.size();
3418  std::vector<Scalar *> wrk(m);
3419  Scalar **px = &(wrk[0]);
3420  for (size_t i = 0; i < m; i++) {
3421  px[i] = args.x_ptr(i);
3422  }
3423 
3424  for (size_t i = 0; i < n; i++) {
3425  Scalar s = rowsum(px, i);
3426  if (Max < s) Max = s;
3427  }
3428 
3429  args.y(0) = 0;
3430  for (size_t i = 0; i < n; i++) {
3431  Scalar s = rowsum(px, i);
3432  args.y(0) += exp(s - Max);
3433  }
3434  args.y(0) = Max + log(args.y(0));
3435 }
3436 
3437 void LogSpaceSumStrideOp::forward(ForwardArgs<Replay> &args) {
3438  std::vector<ad_plain> x(input_size());
3439  for (Index i = 0; i < input_size(); i++) x[i] = args.x(i);
3440  args.y(0) = logspace_sum_stride(x, stride, n);
3441 }
3442 
3443 void LogSpaceSumStrideOp::dependencies(Args<> &args, Dependencies &dep) const {
3444  for (size_t j = 0; j < (size_t)number_of_terms(); j++) {
3445  size_t K = n * stride[j];
3446  dep.add_segment(args.input(j), K);
3447  }
3448 }
3449 
3450 const char *LogSpaceSumStrideOp::op_name() { return "LSStride"; }
3451 
3452 void LogSpaceSumStrideOp::forward(ForwardArgs<Writer> &args) {
3453  TMBAD_ASSERT(false);
3454 }
3455 
3456 void LogSpaceSumStrideOp::reverse(ReverseArgs<Writer> &args) {
3457  TMBAD_ASSERT(false);
3458 }
3459 
3460 ad_plain logspace_sum_stride(const std::vector<ad_plain> &x,
3461  const std::vector<Index> &stride, size_t n) {
3462  TMBAD_ASSERT(x.size() == stride.size());
3463  OperatorPure *pOp = get_glob()->getOperator<LogSpaceSumStrideOp>(stride, n);
3464  return get_glob()->add_to_stack<LogSpaceSumStrideOp>(pOp, x)[0];
3465 }
3466 } // namespace TMBad
3467 // Autogenerated - do not edit by hand !
3468 #include "graph2dot.hpp"
3469 namespace TMBad {
3470 
3471 void graph2dot(global glob, graph G, bool show_id, std::ostream &cout) {
3472  cout << "digraph graphname {\n";
3473  for (size_t i = 0; i < glob.opstack.size(); i++) {
3474  if (!show_id)
3475  cout << i << " [label=\"" << glob.opstack[i]->op_name() << "\"];\n";
3476  else
3477  cout << i << " [label=\"" << glob.opstack[i]->op_name() << " " << i
3478  << "\"];\n";
3479  }
3480  for (size_t node = 0; node < G.num_nodes(); node++) {
3481  for (size_t k = 0; k < G.num_neighbors(node); k++) {
3482  cout << node << " -> " << G.neighbors(node)[k] << ";\n";
3483  }
3484  }
3485  for (size_t i = 0; i < glob.subgraph_seq.size(); i++) {
3486  size_t node = glob.subgraph_seq[i];
3487  cout << node << " [style=\"filled\"];\n";
3488  }
3489 
3490  std::vector<Index> v2o = glob.var2op();
3491 
3492  cout << "{rank=same;";
3493  for (size_t i = 0; i < glob.inv_index.size(); i++) {
3494  cout << v2o[glob.inv_index[i]] << ";";
3495  }
3496  cout << "}\n";
3497 
3498  cout << "{rank=same;";
3499  for (size_t i = 0; i < glob.dep_index.size(); i++) {
3500  cout << v2o[glob.dep_index[i]] << ";";
3501  }
3502  cout << "}\n";
3503 
3504  cout << "}\n";
3505 }
3506 
3507 void graph2dot(global glob, bool show_id, std::ostream &cout) {
3508  graph G = glob.forward_graph();
3509  graph2dot(glob, G, show_id, cout);
3510 }
3511 
3512 void graph2dot(const char *filename, global glob, graph G, bool show_id) {
3513  std::ofstream myfile;
3514  myfile.open(filename);
3515  graph2dot(glob, G, show_id, myfile);
3516  myfile.close();
3517 }
3518 
3519 void graph2dot(const char *filename, global glob, bool show_id) {
3520  std::ofstream myfile;
3521  myfile.open(filename);
3522  graph2dot(glob, show_id, myfile);
3523  myfile.close();
3524 }
3525 } // namespace TMBad
3526 // Autogenerated - do not edit by hand !
3527 #include "graph_transform.hpp"
3528 namespace TMBad {
3529 
3530 std::vector<size_t> which(const std::vector<bool> &x) {
3531  return which<size_t>(x);
3532 }
3533 
3534 size_t prod_int(const std::vector<size_t> &x) {
3535  size_t ans = 1;
3536  for (size_t i = 0; i < x.size(); i++) ans *= x[i];
3537  return ans;
3538 }
3539 
3540 std::vector<bool> reverse_boundary(global &glob,
3541  const std::vector<bool> &vars) {
3542  std::vector<bool> boundary(vars);
3543  std::vector<bool> node_filter = glob.var2op(vars);
3544  glob.reverse_sub(boundary, node_filter);
3545 
3546  for (size_t i = 0; i < vars.size(); i++) boundary[i] = boundary[i] ^ vars[i];
3547  return boundary;
3548 }
3549 
3550 std::vector<Index> get_accumulation_tree(global &glob, bool boundary) {
3551  std::vector<OperatorPure *> &opstack = glob.opstack;
3552 
3553  std::vector<bool> node_subset(opstack.size(), false);
3554  for (size_t i = 0; i < opstack.size(); i++) {
3555  node_subset[i] = opstack[i]->info().test(op_info::is_linear);
3556  }
3557 
3558  node_subset.flip();
3559 
3560  std::vector<bool> var_subset = glob.op2var(node_subset);
3561 
3562  glob.reverse(var_subset);
3563 
3564  var_subset.flip();
3565 
3566  if (boundary) var_subset = reverse_boundary(glob, var_subset);
3567 
3568  node_subset = glob.var2op(var_subset);
3569 
3570  return which<Index>(node_subset);
3571 }
3572 
3573 std::vector<Index> find_op_by_name(global &glob, const char *name) {
3574  std::vector<Index> ans;
3575  std::vector<OperatorPure *> &opstack = glob.opstack;
3576  for (size_t i = 0; i < opstack.size(); i++) {
3577  if (!strcmp(opstack[i]->op_name(), name)) {
3578  ans.push_back(i);
3579  }
3580  }
3581  return ans;
3582 }
3583 
3584 std::vector<Index> substitute(global &glob, const std::vector<Index> &seq,
3585  bool inv_tags, bool dep_tags) {
3586  std::vector<OperatorPure *> &opstack = glob.opstack;
3587  std::vector<Index> seq2(seq);
3588  make_space_inplace(opstack, seq2);
3589  OperatorPure *invop = glob.getOperator<global::InvOp>();
3590  for (size_t i = 0; i < seq2.size(); i++) {
3591  OperatorPure *op = opstack[seq2[i]];
3592  if (inv_tags) TMBAD_ASSERT(op != invop);
3593  size_t nin = op->input_size();
3594  size_t nou = op->output_size();
3595  opstack[seq2[i] - 1] = glob.getOperator<global::NullOp2>(nin, 0);
3596  opstack[seq2[i]] = glob.getOperator<global::NullOp2>(0, nou);
3597  op->deallocate();
3598  }
3600  std::vector<Index> new_inv = glob.op2var(seq2);
3601  if (!inv_tags) glob.inv_index.resize(0);
3602  if (!dep_tags) glob.dep_index.resize(0);
3603  glob.inv_index.insert(glob.inv_index.end(), new_inv.begin(), new_inv.end());
3604  return new_inv;
3605 }
3606 
3607 std::vector<Index> substitute(global &glob, const char *name, bool inv_tags,
3608  bool dep_tags) {
3609  std::vector<Index> seq = find_op_by_name(glob, name);
3610  return substitute(glob, seq, inv_tags, dep_tags);
3611 }
3612 
3614  global glob_tree = glob;
3615 
3616  std::vector<Index> boundary = get_accumulation_tree(glob, true);
3617 
3618  substitute(glob_tree, boundary, false, true);
3619  glob_tree.eliminate();
3620 
3621  size_t n = glob_tree.inv_index.size();
3622 
3623  std::vector<Scalar> x0(n);
3624  for (size_t i = 0; i < n; i++) x0[i] = glob_tree.value_inv(i);
3625  glob_tree.forward();
3626  glob_tree.clear_deriv();
3627  glob_tree.deriv_dep(0) = 1;
3628  glob_tree.reverse();
3629  Scalar V = glob_tree.value_dep(0);
3630  std::vector<Scalar> J(n);
3631  for (size_t i = 0; i < n; i++) J[i] = glob_tree.deriv_inv(i);
3632 
3633  for (size_t i = 0; i < n; i++) V -= J[i] * x0[i];
3634 
3635  std::vector<Index> vars = glob.op2var(boundary);
3636  glob.dep_index.resize(0);
3637  glob.ad_start();
3638  std::vector<ad_aug_index> res(vars.begin(), vars.end());
3639  for (size_t i = 0; i < vars.size(); i++) {
3640  res[i] = res[i] * J[i];
3641  if (i == 0) res[i] += V;
3642  if (!sum_) res[i].Dependent();
3643  }
3644  if (sum_) {
3645  ad_aug sum_res = sum(res);
3646  sum_res.Dependent();
3647  }
3648  glob.ad_stop();
3649  glob.eliminate();
3650  return glob;
3651 }
3652 
3653 void aggregate(global &glob, int sign) {
3654  TMBAD_ASSERT((sign == 1) || (sign == -1));
3655  glob.ad_start();
3656  std::vector<ad_aug_index> x(glob.dep_index.begin(), glob.dep_index.end());
3657  ad_aug y = 0;
3658  for (size_t i = 0; i < x.size(); i++) y += x[i];
3659  if (sign < 0) y = -y;
3660  glob.dep_index.resize(0);
3661  y.Dependent();
3662  glob.ad_stop();
3663 }
3664 
3665 old_state::old_state(global &glob) : glob(glob) {
3666  dep_index = glob.dep_index;
3667  opstack_size = glob.opstack.size();
3668 }
3669 
3670 void old_state::restore() {
3671  glob.dep_index = dep_index;
3672  while (glob.opstack.size() > opstack_size) {
3673  Index input_size = glob.opstack.back()->input_size();
3674  Index output_size = glob.opstack.back()->output_size();
3675  glob.inputs.resize(glob.inputs.size() - input_size);
3676  glob.values.resize(glob.values.size() - output_size);
3677  glob.opstack.back()->deallocate();
3678  glob.opstack.pop_back();
3679  }
3680 }
3681 
3682 term_info::term_info(global &glob, bool do_init) : glob(glob) {
3683  if (do_init) initialize();
3684 }
3685 
3686 void term_info::initialize(std::vector<Index> inv_remap) {
3687  if (inv_remap.size() == 0) inv_remap.resize(glob.inv_index.size(), 0);
3688  inv_remap = radix::factor<Index>(inv_remap);
3689  std::vector<Index> remap = remap_identical_sub_expressions(glob, inv_remap);
3690  std::vector<Index> term_ids = subset(remap, glob.dep_index);
3691  id = radix::factor<Index>(term_ids);
3692  Index max_id = *std::max_element(id.begin(), id.end());
3693  count.resize(max_id + 1, 0);
3694  for (size_t i = 0; i < id.size(); i++) {
3695  count[id[i]]++;
3696  }
3697 }
3698 
3699 gk_config::gk_config()
3700  : debug(false), adaptive(false), nan2zero(true), ytol(1e-2), dx(1) {}
3701 
3703  size_t count = 1;
3704  for (size_t i = 0; i < bound.size(); i++)
3705  if (mask_[i]) count *= bound[i];
3706  return count;
3707 }
3708 
3709 multivariate_index::multivariate_index(size_t bound_, size_t dim, bool flag)
3710  : pointer(0) {
3711  bound.resize(dim, bound_);
3712  x.resize(dim, 0);
3713  mask_.resize(dim, flag);
3714 }
3715 
3716 multivariate_index::multivariate_index(std::vector<size_t> bound, bool flag)
3717  : pointer(0), bound(bound) {
3718  x.resize(bound.size(), 0);
3719  mask_.resize(bound.size(), flag);
3720 }
3721 
3722 void multivariate_index::flip() { mask_.flip(); }
3723 
3725  size_t N = 1;
3726  for (size_t i = 0; i < x.size(); i++) {
3727  if (mask_[i]) {
3728  if (x[i] < bound[i] - 1) {
3729  x[i]++;
3730  pointer += N;
3731  break;
3732  } else {
3733  x[i] = 0;
3734  pointer -= (bound[i] - 1) * N;
3735  }
3736  }
3737  N *= bound[i];
3738  }
3739  return *this;
3740 }
3741 
3742 multivariate_index::operator size_t() { return pointer; }
3743 
3744 size_t multivariate_index::index(size_t i) { return x[i]; }
3745 
3746 std::vector<size_t> multivariate_index::index() { return x; }
3747 
3748 std::vector<bool>::reference multivariate_index::mask(size_t i) {
3749  return mask_[i];
3750 }
3751 
3752 void multivariate_index::set_mask(const std::vector<bool> &mask) {
3753  TMBAD_ASSERT(mask.size() == mask_.size());
3754  mask_ = mask;
3755 }
3756 
3757 size_t clique::clique_size() { return indices.size(); }
3758 
3759 clique::clique() {}
3760 
3761 void clique::subset_inplace(const std::vector<bool> &mask) {
3762  indices = subset(indices, mask);
3763  dim = subset(dim, mask);
3764 }
3765 
3766 void clique::logsum_init() { logsum.resize(prod_int(dim)); }
3767 
3768 bool clique::empty() const { return (indices.size() == 0); }
3769 
3770 bool clique::contains(Index i) {
3771  bool ans = false;
3772  for (size_t j = 0; j < indices.size(); j++) ans |= (i == indices[j]);
3773  return ans;
3774 }
3775 
3776 void clique::get_stride(const clique &super, Index ind,
3777  std::vector<ad_plain> &offset, Index &stride) {
3778  stride = 1;
3779  for (size_t k = 0; (k < clique_size()) && (indices[k] < ind); k++) {
3780  stride *= dim[k];
3781  }
3782 
3783  multivariate_index mv(super.dim);
3784  size_t nx = mv.count();
3785  std::vector<bool> mask = lmatch(super.indices, this->indices);
3786  mask.flip();
3787  mv.set_mask(mask);
3788  std::vector<ad_plain> x(nx);
3789  size_t xa_count = mv.count();
3790  mv.flip();
3791  size_t xi_count = mv.count();
3792  mv.flip();
3793  TMBAD_ASSERT(x.size() == xa_count * xi_count);
3794  for (size_t i = 0; i < xa_count; i++, ++mv) {
3795  mv.flip();
3796  for (size_t j = 0; j < xi_count; j++, ++mv) {
3797  TMBAD_ASSERT(logsum[j].on_some_tape());
3798  x[mv] = logsum[j];
3799  }
3800  mv.flip();
3801  }
3802 
3803  mv = multivariate_index(super.dim);
3804  mask = lmatch(super.indices, std::vector<Index>(1, ind));
3805  mask.flip();
3806  mv.set_mask(mask);
3807 
3808  xa_count = mv.count();
3809  offset.resize(xa_count);
3810  for (size_t i = 0; i < xa_count; i++, ++mv) {
3811  offset[i] = x[mv];
3812  }
3813 }
3814 
3815 sr_grid::sr_grid() {}
3816 
3817 sr_grid::sr_grid(Scalar a, Scalar b, size_t n) : x(n), w(n) {
3818  Scalar h = (b - a) / n;
3819  for (size_t i = 0; i < n; i++) {
3820  x[i] = a + h / 2 + i * h;
3821  w[i] = h;
3822  }
3823 }
3824 
3825 sr_grid::sr_grid(size_t n) {
3826  for (size_t i = 0; i < n; i++) {
3827  x[i] = i;
3828  w[i] = 1. / (double)n;
3829  }
3830 }
3831 
3832 size_t sr_grid::size() { return x.size(); }
3833 
3834 ad_plain sr_grid::logw_offset() {
3835  if (logw.size() != w.size()) {
3836  logw.resize(w.size());
3837  for (size_t i = 0; i < w.size(); i++) logw[i] = log(w[i]);
3838  forceContiguous(logw);
3839  }
3840  return logw[0];
3841 }
3842 
3844  std::vector<Index> random,
3845  std::vector<sr_grid> grid,
3846  std::vector<Index> random2grid,
3847  bool perm)
3848  : grid(grid),
3849  glob(glob),
3850  random(random),
3851  replay(glob, new_glob),
3852  tinfo(glob, false) {
3853  inv2grid.resize(glob.inv_index.size(), 0);
3854  for (size_t i = 0; i < random2grid.size(); i++) {
3855  inv2grid[random[i]] = random2grid[i];
3856  }
3857 
3858  mark.resize(glob.values.size(), false);
3859  for (size_t i = 0; i < random.size(); i++)
3860  mark[glob.inv_index[random[i]]] = true;
3861  glob.forward(mark);
3862 
3863  forward_graph = glob.forward_graph(mark);
3864  reverse_graph = glob.reverse_graph(mark);
3865 
3866  glob.subgraph_cache_ptr();
3867 
3868  var_remap.resize(glob.values.size());
3869 
3870  op2inv_idx = glob.op2idx(glob.inv_index, NA);
3871  op2dep_idx = glob.op2idx(glob.dep_index, NA);
3872 
3873  if (perm) reorder_random();
3874 
3875  terms_done.resize(glob.dep_index.size(), false);
3876 
3877  std::vector<Index> inv_remap(glob.inv_index.size());
3878  for (size_t i = 0; i < inv_remap.size(); i++) inv_remap[i] = -(i + 1);
3879  for (size_t i = 0; i < random.size(); i++)
3880  inv_remap[random[i]] = inv2grid[random[i]];
3881  inv_remap = radix::factor<Index>(inv_remap);
3882  tinfo.initialize(inv_remap);
3883 }
3884 
3886  std::vector<IndexPair> edges;
3887  std::vector<Index> &inv2op = forward_graph.inv2op;
3888 
3889  for (size_t i = 0; i < random.size(); i++) {
3890  std::vector<Index> subgraph(1, inv2op[random[i]]);
3891  forward_graph.search(subgraph);
3892  reverse_graph.search(subgraph);
3893  for (size_t l = 0; l < subgraph.size(); l++) {
3894  Index inv_other = op2inv_idx[subgraph[l]];
3895  if (inv_other != NA) {
3896  IndexPair edge(random[i], inv_other);
3897  edges.push_back(edge);
3898  }
3899  }
3900  }
3901 
3902  size_t num_nodes = glob.inv_index.size();
3903  graph G(num_nodes, edges);
3904 
3905  std::vector<bool> visited(num_nodes, false);
3906  std::vector<Index> subgraph;
3907  for (size_t i = 0; i < random.size(); i++) {
3908  if (visited[random[i]]) continue;
3909  std::vector<Index> sg(1, random[i]);
3910  G.search(sg, visited, false, false);
3911  subgraph.insert(subgraph.end(), sg.begin(), sg.end());
3912  }
3913  std::reverse(subgraph.begin(), subgraph.end());
3914  TMBAD_ASSERT(random.size() == subgraph.size());
3915  random = subgraph;
3916 }
3917 
3918 std::vector<size_t> sequential_reduction::get_grid_bounds(
3919  std::vector<Index> inv_index) {
3920  std::vector<size_t> ans(inv_index.size());
3921  for (size_t i = 0; i < inv_index.size(); i++) {
3922  ans[i] = grid[inv2grid[inv_index[i]]].size();
3923  }
3924  return ans;
3925 }
3926 
3927 std::vector<sr_grid *> sequential_reduction::get_grid(
3928  std::vector<Index> inv_index) {
3929  std::vector<sr_grid *> ans(inv_index.size());
3930  for (size_t i = 0; i < inv_index.size(); i++) {
3931  ans[i] = &(grid[inv2grid[inv_index[i]]]);
3932  }
3933  return ans;
3934 }
3935 
3936 std::vector<ad_aug> sequential_reduction::tabulate(std::vector<Index> inv_index,
3937  Index dep_index) {
3938  size_t id = tinfo.id[dep_index];
3939  size_t count = tinfo.count[id];
3940  bool do_cache = (count >= 2);
3941  if (do_cache) {
3942  if (cache[id].size() > 0) {
3943  return cache[id];
3944  }
3945  }
3946 
3947  std::vector<sr_grid *> inv_grid = get_grid(inv_index);
3948  std::vector<size_t> grid_bounds = get_grid_bounds(inv_index);
3949  multivariate_index mv(grid_bounds);
3950  std::vector<ad_aug> ans(mv.count());
3951  for (size_t i = 0; i < ans.size(); i++, ++mv) {
3952  for (size_t j = 0; j < inv_index.size(); j++) {
3953  replay.value_inv(inv_index[j]) = inv_grid[j]->x[mv.index(j)];
3954  }
3955  replay.forward_sub();
3956  ans[i] = replay.value_dep(dep_index);
3957  }
3958 
3959  forceContiguous(ans);
3960  if (do_cache) {
3961  cache[id] = ans;
3962  }
3963  return ans;
3964 }
3965 
3967  std::vector<Index> super;
3968  size_t c = 0;
3969  for (std::list<clique>::iterator it = cliques.begin(); it != cliques.end();
3970  ++it) {
3971  if ((*it).contains(i)) {
3972  super.insert(super.end(), (*it).indices.begin(), (*it).indices.end());
3973  c++;
3974  }
3975  }
3976  sort_unique_inplace(super);
3977 
3978  std::vector<std::vector<ad_plain> > offset_by_clique(c);
3979  std::vector<Index> stride_by_clique(c);
3980  clique C;
3981  C.indices = super;
3982  C.dim = get_grid_bounds(super);
3983  std::list<clique>::iterator it = cliques.begin();
3984  c = 0;
3985  while (it != cliques.end()) {
3986  if ((*it).contains(i)) {
3987  (*it).get_stride(C, i, offset_by_clique[c], stride_by_clique[c]);
3988  it = cliques.erase(it);
3989  c++;
3990  } else {
3991  ++it;
3992  }
3993  }
3994 
3995  std::vector<bool> mask = lmatch(super, std::vector<Index>(1, i));
3996  mask.flip();
3997  C.subset_inplace(mask);
3998  C.logsum_init();
3999 
4000  grid[inv2grid[i]].logw_offset();
4001  size_t v_begin = get_glob()->values.size();
4002  for (size_t j = 0; j < C.logsum.size(); j++) {
4003  std::vector<ad_plain> x;
4004  std::vector<Index> stride;
4005  for (size_t k = 0; k < offset_by_clique.size(); k++) {
4006  x.push_back(offset_by_clique[k][j]);
4007  stride.push_back(stride_by_clique[k]);
4008  }
4009 
4010  x.push_back(grid[inv2grid[i]].logw_offset());
4011  stride.push_back(1);
4012  C.logsum[j] = logspace_sum_stride(x, stride, grid[inv2grid[i]].size());
4013  }
4014  size_t v_end = get_glob()->values.size();
4015  TMBAD_ASSERT(v_end - v_begin == C.logsum.size());
4016 
4017  cliques.push_back(C);
4018 }
4019 
4021  const std::vector<Index> &inv2op = forward_graph.inv2op;
4022 
4023  Index start_node = inv2op[i];
4024  std::vector<Index> subgraph(1, start_node);
4025  forward_graph.search(subgraph);
4026 
4027  std::vector<Index> dep_clique;
4028  std::vector<Index> subgraph_terms;
4029  for (size_t k = 0; k < subgraph.size(); k++) {
4030  Index node = subgraph[k];
4031  Index dep_idx = op2dep_idx[node];
4032  if (dep_idx != NA && !terms_done[dep_idx]) {
4033  terms_done[dep_idx] = true;
4034  subgraph_terms.push_back(node);
4035  dep_clique.push_back(dep_idx);
4036  }
4037  }
4038  for (size_t k = 0; k < subgraph_terms.size(); k++) {
4039  subgraph.resize(0);
4040  subgraph.push_back(subgraph_terms[k]);
4041 
4042  reverse_graph.search(subgraph);
4043 
4044  std::vector<Index> inv_clique;
4045  for (size_t l = 0; l < subgraph.size(); l++) {
4046  Index tmp = op2inv_idx[subgraph[l]];
4047  if (tmp != NA) inv_clique.push_back(tmp);
4048  }
4049 
4050  glob.subgraph_seq = subgraph;
4051 
4052  clique C;
4053  C.indices = inv_clique;
4054  C.dim = get_grid_bounds(inv_clique);
4055  C.logsum = tabulate(inv_clique, dep_clique[k]);
4056 
4057  cliques.push_back(C);
4058  }
4059 
4060  merge(i);
4061 }
4062 
4063 void sequential_reduction::show_cliques() {
4064  Rcout << "Cliques: ";
4065  std::list<clique>::iterator it;
4066  for (it = cliques.begin(); it != cliques.end(); ++it) {
4067  Rcout << it->indices << " ";
4068  }
4069  Rcout << "\n";
4070 }
4071 
4072 void sequential_reduction::update_all() {
4073  for (size_t i = 0; i < random.size(); i++) update(random[i]);
4074 }
4075 
4076 ad_aug sequential_reduction::get_result() {
4077  ad_aug ans = 0;
4078  std::list<clique>::iterator it;
4079  for (it = cliques.begin(); it != cliques.end(); ++it) {
4080  TMBAD_ASSERT(it->clique_size() == 0);
4081  TMBAD_ASSERT(it->logsum.size() == 1);
4082  ans += it->logsum[0];
4083  }
4084 
4085  for (size_t i = 0; i < terms_done.size(); i++) {
4086  if (!terms_done[i]) ans += replay.value_dep(i);
4087  }
4088  return ans;
4089 }
4090 
4091 global sequential_reduction::marginal() {
4092  replay.start();
4093  replay.forward(true, false);
4094  update_all();
4095  ad_aug ans = get_result();
4096  ans.Dependent();
4097  replay.stop();
4098  return new_glob;
4099 }
4100 
4101 autopar::autopar(global &glob, size_t num_threads)
4102  : glob(glob),
4103  num_threads(num_threads),
4104  do_aggregate(false),
4105  keep_all_inv(false) {
4106  reverse_graph = glob.reverse_graph();
4107 }
4108 
4109 std::vector<size_t> autopar::max_tree_depth() {
4110  std::vector<Index> max_tree_depth(glob.opstack.size(), 0);
4111  Dependencies dep;
4112  Args<> args(glob.inputs);
4113  for (size_t i = 0; i < glob.opstack.size(); i++) {
4114  dep.resize(0);
4115  glob.opstack[i]->dependencies(args, dep);
4116  for (size_t j = 0; j < dep.size(); j++) {
4117  max_tree_depth[i] = std::max(max_tree_depth[i], max_tree_depth[dep[j]]);
4118  }
4119 
4120  max_tree_depth[i]++;
4121 
4122  glob.opstack[i]->increment(args.ptr);
4123  }
4124  std::vector<size_t> ans(glob.dep_index.size());
4125  for (size_t j = 0; j < glob.dep_index.size(); j++) {
4126  ans[j] = max_tree_depth[glob.dep_index[j]];
4127  }
4128  return ans;
4129 }
4130 
4131 void autopar::run() {
4132  std::vector<size_t> ord = order(max_tree_depth());
4133  std::reverse(ord.begin(), ord.end());
4134  std::vector<bool> visited(glob.opstack.size(), false);
4135  std::vector<Index> start;
4136  std::vector<Index> dWork(ord.size());
4137  for (size_t i = 0; i < ord.size(); i++) {
4138  start.resize(1);
4139  start[0] = reverse_graph.dep2op[ord[i]];
4140  reverse_graph.search(start, visited, false, false);
4141  dWork[i] = start.size();
4142  if (false) {
4143  for (size_t k = 0; k < start.size(); k++) {
4144  Rcout << glob.opstack[start[k]]->op_name() << " ";
4145  }
4146  Rcout << "\n";
4147  }
4148  }
4149 
4150  std::vector<size_t> thread_assign(ord.size(), 0);
4151  std::vector<size_t> work_by_thread(num_threads, 0);
4152  for (size_t i = 0; i < dWork.size(); i++) {
4153  if (i == 0) {
4154  thread_assign[i] = 0;
4155  } else {
4156  if (dWork[i] <= 1)
4157  thread_assign[i] = thread_assign[i - 1];
4158  else
4159  thread_assign[i] = which_min(work_by_thread);
4160  }
4161  work_by_thread[thread_assign[i]] += dWork[i];
4162  }
4163 
4164  node_split.resize(num_threads);
4165  for (size_t i = 0; i < ord.size(); i++) {
4166  node_split[thread_assign[i]].push_back(reverse_graph.dep2op[ord[i]]);
4167  }
4168 
4169  for (size_t i = 0; i < num_threads; i++) {
4170  if (keep_all_inv)
4171  node_split[i].insert(node_split[i].begin(), reverse_graph.inv2op.begin(),
4172  reverse_graph.inv2op.end());
4173  reverse_graph.search(node_split[i]);
4174  }
4175 }
4176 
4178  vglob.resize(num_threads);
4179  inv_idx.resize(num_threads);
4180  dep_idx.resize(num_threads);
4181  std::vector<Index> tmp;
4182  for (size_t i = 0; i < num_threads; i++) {
4183  glob.subgraph_seq = node_split[i];
4184  vglob[i] = glob.extract_sub(tmp);
4185  if (do_aggregate) aggregate(vglob[i]);
4186  }
4187 
4188  Index NA = -1;
4189  std::vector<Index> op2inv_idx = glob.op2idx(glob.inv_index, NA);
4190  std::vector<Index> op2dep_idx = glob.op2idx(glob.dep_index, NA);
4191  for (size_t i = 0; i < num_threads; i++) {
4192  std::vector<Index> &seq = node_split[i];
4193  for (size_t j = 0; j < seq.size(); j++) {
4194  if (op2inv_idx[seq[j]] != NA) inv_idx[i].push_back(op2inv_idx[seq[j]]);
4195  if (op2dep_idx[seq[j]] != NA) dep_idx[i].push_back(op2dep_idx[seq[j]]);
4196  }
4197  if (do_aggregate) {
4198  dep_idx[i].resize(1);
4199  dep_idx[i][0] = i;
4200  }
4201  }
4202 }
4203 
4204 size_t autopar::input_size() const { return glob.inv_index.size(); }
4205 
4206 size_t autopar::output_size() const {
4207  return (do_aggregate ? num_threads : glob.dep_index.size());
4208 }
4209 
4210 Index ParalOp::input_size() const { return n; }
4211 
4212 Index ParalOp::output_size() const { return m; }
4213 
4214 ParalOp::ParalOp(const autopar &ap)
4215  : vglob(ap.vglob),
4216  inv_idx(ap.inv_idx),
4217  dep_idx(ap.dep_idx),
4218  n(ap.input_size()),
4219  m(ap.output_size()) {}
4220 
4221 void ParalOp::forward(ForwardArgs<Scalar> &args) {
4222  size_t num_threads = vglob.size();
4223 
4224 #ifdef _OPENMP
4225 #pragma omp parallel for
4226 #endif
4227 
4228  for (size_t i = 0; i < num_threads; i++) {
4229  for (size_t j = 0; j < inv_idx[i].size(); j++) {
4230  vglob[i].value_inv(j) = args.x(inv_idx[i][j]);
4231  }
4232  vglob[i].forward();
4233  }
4234 
4235  for (size_t i = 0; i < num_threads; i++) {
4236  for (size_t j = 0; j < dep_idx[i].size(); j++) {
4237  args.y(dep_idx[i][j]) = vglob[i].value_dep(j);
4238  }
4239  }
4240 }
4241 
4242 void ParalOp::reverse(ReverseArgs<Scalar> &args) {
4243  size_t num_threads = vglob.size();
4244 
4245 #ifdef _OPENMP
4246 #pragma omp parallel for
4247 #endif
4248 
4249  for (size_t i = 0; i < num_threads; i++) {
4250  vglob[i].clear_deriv();
4251  for (size_t j = 0; j < dep_idx[i].size(); j++) {
4252  vglob[i].deriv_dep(j) = args.dy(dep_idx[i][j]);
4253  }
4254  vglob[i].reverse();
4255  }
4256 
4257  for (size_t i = 0; i < num_threads; i++) {
4258  for (size_t j = 0; j < inv_idx[i].size(); j++) {
4259  args.dx(inv_idx[i][j]) += vglob[i].deriv_inv(j);
4260  }
4261  }
4262 }
4263 
4264 const char *ParalOp::op_name() { return "ParalOp"; }
4265 
4266 void ParalOp::print(global::print_config cfg) {
4267  size_t num_threads = vglob.size();
4268  for (size_t i = 0; i < num_threads; i++) {
4269  global::print_config cfg2 = cfg;
4270  std::stringstream ss;
4271  ss << i;
4272  std::string str = ss.str();
4273  cfg2.prefix = cfg2.prefix + str;
4274  vglob[i].print(cfg2);
4275  }
4276 }
4277 
4278 std::vector<Index> get_likely_expression_duplicates(
4279  const global &glob, std::vector<Index> inv_remap) {
4280  global::hash_config cfg;
4281  cfg.strong_inv = true;
4282  cfg.strong_const = true;
4283  cfg.strong_output = true;
4284  cfg.reduce = false;
4285  cfg.deterministic = false;
4286  cfg.inv_seed = inv_remap;
4287  std::vector<hash_t> h = glob.hash_sweep(cfg);
4288  return radix::first_occurance<Index>(h);
4289 }
4290 
4291 bool all_allow_remap(const global &glob) {
4292  Args<> args(glob.inputs);
4293  for (size_t i = 0; i < glob.opstack.size(); i++) {
4294  op_info info = glob.opstack[i]->info();
4295  if (!info.test(op_info::allow_remap)) {
4296  return false;
4297  }
4298  glob.opstack[i]->increment(args.ptr);
4299  }
4300  return true;
4301 }
4302 
4304  global &glob, std::vector<Index> inv_remap) {
4305  std::vector<Index> remap = get_likely_expression_duplicates(glob, inv_remap);
4306 
4307  for (size_t i = 0; i < glob.inv_index.size(); i++) {
4308  bool accept = false;
4309  Index var_i = glob.inv_index[i];
4310  if (inv_remap.size() > 0) {
4311  Index j = inv_remap[i];
4312  Index var_j = glob.inv_index[j];
4313  accept = remap[var_i] == remap[var_j];
4314  }
4315  if (!accept) remap[var_i] = var_i;
4316  }
4317 
4318  std::vector<Index> v2o = glob.var2op();
4319  std::vector<Index> dep;
4320  global::OperatorPure *invop = glob.getOperator<global::InvOp>();
4321  Dependencies dep1;
4322  Dependencies dep2;
4323  size_t reject = 0;
4324  size_t total = 0;
4325  Args<> args(glob.inputs);
4326 
4327  for (size_t j = 0, i = 0, nout = 0; j < glob.opstack.size(); j++, i += nout) {
4328  nout = glob.opstack[j]->output_size();
4329  bool any_remap = false;
4330  for (size_t k = i; k < i + nout; k++) {
4331  if (remap[k] != k) {
4332  any_remap = true;
4333  break;
4334  }
4335  }
4336  if (any_remap) {
4337  bool ok = true;
4338  total += nout;
4339 
4340  global::OperatorPure *CurOp = glob.opstack[v2o[i]];
4341  global::OperatorPure *RemOp = glob.opstack[v2o[remap[i]]];
4342  ok &= (CurOp->identifier() == RemOp->identifier());
4343 
4344  ok &= (CurOp->input_size() == RemOp->input_size());
4345  ok &= (CurOp->output_size() == RemOp->output_size());
4346 
4347  op_info CurInfo = CurOp->info();
4348 
4349  if (ok && (nout > 1)) {
4350  for (size_t k = 1; k < nout; k++) {
4351  ok &= (remap[i + k] < i);
4352 
4353  ok &= (v2o[remap[i + k]] == v2o[remap[i]]);
4354 
4355  ok &= (remap[i + k] == remap[i] + k);
4356  }
4357  }
4358 
4359  if (CurOp == invop) {
4360  ok = false;
4361  }
4362  if (ok) {
4363  if (CurInfo.test(op_info::is_constant)) {
4364  if (glob.values[i] != glob.values[remap[i]]) {
4365  ok = false;
4366  }
4367  }
4368  }
4369 
4370  if (ok) {
4371  glob.subgraph_cache_ptr();
4372 
4373  args.ptr = glob.subgraph_ptr[v2o[i]];
4374  dep1.resize(0);
4375  glob.opstack[v2o[i]]->dependencies(args, dep1);
4376 
4377  args.ptr = glob.subgraph_ptr[v2o[remap[i]]];
4378  dep2.resize(0);
4379  glob.opstack[v2o[remap[i]]]->dependencies(args, dep2);
4380 
4381  ok = (dep1.size() == dep2.size());
4382  if (ok) {
4383  bool all_equal = true;
4384  for (size_t j = 0; j < dep1.size(); j++) {
4385  all_equal &= (remap[dep1[j]] == remap[dep2[j]]);
4386  }
4387  ok = all_equal;
4388  }
4389  }
4390 
4391  if (!ok) {
4392  reject += nout;
4393  for (size_t k = i; k < i + nout; k++) remap[k] = k;
4394  }
4395  }
4396  }
4397 
4398  for (size_t i = 0; i < remap.size(); i++) {
4399  TMBAD_ASSERT(remap[i] <= i);
4400  TMBAD_ASSERT(remap[remap[i]] == remap[i]);
4401  }
4402 
4403  if (true) {
4404  Args<> args(glob.inputs);
4405  intervals<Index> visited;
4406  for (size_t i = 0; i < glob.opstack.size(); i++) {
4407  op_info info = glob.opstack[i]->info();
4408  if (!info.test(op_info::allow_remap)) {
4409  Dependencies dep;
4410  glob.opstack[i]->dependencies(args, dep);
4411  for (size_t j = 0; j < dep.I.size(); j++) {
4412  visited.insert(dep.I[j].first, dep.I[j].second);
4413  }
4414  }
4415  glob.opstack[i]->increment(args.ptr);
4416  }
4417 
4418  forbid_remap<std::vector<Index> > fb(remap);
4419  visited.apply(fb);
4420  }
4421  if (reject > 0) {
4422  ((void)(total));
4423  }
4424 
4425  return remap;
4426 }
4427 
4429  std::vector<Index> inv_remap(0);
4430  std::vector<Index> remap = remap_identical_sub_expressions(glob, inv_remap);
4431 
4432  for (size_t i = 0; i < glob.inputs.size(); i++) {
4433  glob.inputs[i] = remap[glob.inputs[i]];
4434  }
4435 }
4436 
4437 std::vector<Position> inv_positions(global &glob) {
4438  IndexPair ptr(0, 0);
4439  std::vector<bool> independent_variable = glob.inv_marks();
4440  std::vector<Position> ans(glob.inv_index.size());
4441  size_t k = 0;
4442  for (size_t i = 0; i < glob.opstack.size(); i++) {
4443  Index nout = glob.opstack[i]->output_size();
4444  for (Index j = 0; j < nout; j++) {
4445  if (independent_variable[ptr.second + j]) {
4446  ans[k].node = i;
4447  ans[k].ptr = ptr;
4448  k++;
4449  }
4450  }
4451  glob.opstack[i]->increment(ptr);
4452  }
4453  return ans;
4454 }
4455 
4456 void reorder_graph(global &glob, std::vector<Index> inv_idx) {
4457  if (!all_allow_remap(glob)) return;
4458  for (size_t i = 1; i < inv_idx.size(); i++) {
4459  TMBAD_ASSERT(inv_idx[i] > inv_idx[i - 1]);
4460  }
4461  std::vector<bool> marks(glob.values.size(), false);
4462  for (size_t i = 0; i < inv_idx.size(); i++)
4463  marks[glob.inv_index[inv_idx[i]]] = true;
4464  glob.forward_dense(marks);
4465  if (false) {
4466  int c = std::count(marks.begin(), marks.end(), true);
4467  Rcout << "marked proportion:" << (double)c / (double)marks.size() << "\n";
4468  }
4469 
4470  marks.flip();
4471  glob.set_subgraph(marks);
4472  marks.flip();
4473  glob.set_subgraph(marks, true);
4474  glob = glob.extract_sub();
4475 }
4476 } // namespace TMBad
4477 // Autogenerated - do not edit by hand !
4478 #include "integrate.hpp"
4479 namespace TMBad {
4480 
4481 double value(double x) { return x; }
4482 
4483 control::control(int subdivisions_, double reltol_, double abstol_)
4484  : subdivisions(subdivisions_), reltol(reltol_), abstol(abstol_) {}
4485 } // namespace TMBad
4486 // Autogenerated - do not edit by hand !
4487 #include "radix.hpp"
4488 namespace TMBad {}
4489 // Autogenerated - do not edit by hand !
4490 #include "tmbad_allow_comparison.hpp"
4491 namespace TMBad {
4492 
4493 bool operator<(const ad_aug &x, const ad_aug &y) {
4494  return x.Value() < y.Value();
4495 }
4496 bool operator<(const Scalar &x, const ad_aug &y) { return x < y.Value(); }
4497 
4498 bool operator<=(const ad_aug &x, const ad_aug &y) {
4499  return x.Value() <= y.Value();
4500 }
4501 bool operator<=(const Scalar &x, const ad_aug &y) { return x <= y.Value(); }
4502 
4503 bool operator>(const ad_aug &x, const ad_aug &y) {
4504  return x.Value() > y.Value();
4505 }
4506 bool operator>(const Scalar &x, const ad_aug &y) { return x > y.Value(); }
4507 
4508 bool operator>=(const ad_aug &x, const ad_aug &y) {
4509  return x.Value() >= y.Value();
4510 }
4511 bool operator>=(const Scalar &x, const ad_aug &y) { return x >= y.Value(); }
4512 
4513 bool operator==(const ad_aug &x, const ad_aug &y) {
4514  return x.Value() == y.Value();
4515 }
4516 bool operator==(const Scalar &x, const ad_aug &y) { return x == y.Value(); }
4517 
4518 bool operator!=(const ad_aug &x, const ad_aug &y) {
4519  return x.Value() != y.Value();
4520 }
4521 bool operator!=(const Scalar &x, const ad_aug &y) { return x != y.Value(); }
4522 } // namespace TMBad
4523 // Autogenerated - do not edit by hand !
4524 #include "vectorize.hpp"
4525 namespace TMBad {
4526 
4527 VSumOp::VSumOp(size_t n) : n(n) {}
4528 
4529 void VSumOp::dependencies(Args<> &args, Dependencies &dep) const {
4530  dep.add_segment(args.input(0), n);
4531 }
4532 
4533 void VSumOp::forward(ForwardArgs<Writer> &args) { TMBAD_ASSERT(false); }
4534 
4535 void VSumOp::reverse(ReverseArgs<Writer> &args) { TMBAD_ASSERT(false); }
4536 
4537 const char *VSumOp::op_name() { return "VSumOp"; }
4538 
4539 ad_aug sum(ad_segment x) {
4540  global::Complete<VSumOp> F(x.size());
4541  return F(x)[0];
4542 }
4543 
4544 Scalar *SegmentRef::value_ptr() { return (*glob_ptr).values.data() + offset; }
4545 
4546 Scalar *SegmentRef::deriv_ptr() { return (*glob_ptr).derivs.data() + offset; }
4547 
4548 SegmentRef::SegmentRef() {}
4549 
4550 SegmentRef::SegmentRef(const Scalar *x) {
4551  SegmentRef *sx = (SegmentRef *)x;
4552  *this = *sx;
4553 }
4554 
4555 SegmentRef::SegmentRef(global *g, Index o, Index s)
4556  : glob_ptr(g), offset(o), size(s) {}
4557 
4558 SegmentRef::SegmentRef(const ad_segment &x) {
4559  static const size_t K = ScalarPack<SegmentRef>::size;
4560  TMBAD_ASSERT(x.size() == K);
4561  Scalar buf[K];
4562  for (size_t i = 0; i < K; i++) buf[i] = x[i].Value();
4563  SegmentRef *sx = (SegmentRef *)buf;
4564  *this = *sx;
4565 }
4566 
4567 bool SegmentRef::isNull() { return (glob_ptr == NULL); }
4568 
4569 void SegmentRef::resize(ad_segment &pack, Index n) {
4570  Index i = pack.index();
4571  SegmentRef *p = (SegmentRef *)(get_glob()->values.data() + i);
4572  p->size = n;
4573 }
4574 
4575 PackOp::PackOp(const Index n) : n(n) {}
4576 
4578  SegmentRef *y = (SegmentRef *)args.y_ptr(0);
4579  y[0] = SegmentRef(args.glob_ptr, args.input(0), n);
4580 }
4581 
4583  ad_segment x(args.x_ptr(0), n);
4584  args.y_segment(0, K) = pack(x);
4585 }
4586 
4588  SegmentRef tmp(args.dy_ptr(0));
4589  if (tmp.glob_ptr != NULL) {
4590  Scalar *dx = SegmentRef(args.y_ptr(0)).deriv_ptr();
4591  Scalar *dy = SegmentRef(args.dy_ptr(0)).deriv_ptr();
4592  for (Index i = 0; i < n; i++) dx[i] += dy[i];
4593  }
4594 }
4595 
4597  ad_segment dy_packed(args.dy_ptr(0), K);
4598 
4599  if (SegmentRef(dy_packed).isNull()) {
4600  SegmentRef().resize(dy_packed, n);
4601  }
4602  ad_segment dy = unpack(dy_packed);
4603  ad_segment dx(args.dx_ptr(0), n, true);
4604  dx += dy;
4605  Replay *pdx = args.dx_ptr(0);
4606  for (Index i = 0; i < n; i++) pdx[i] = dx[i];
4607 }
4608 
4609 const char *PackOp::op_name() { return "PackOp"; }
4610 
4611 void PackOp::dependencies(Args<> &args, Dependencies &dep) const {
4612  dep.add_segment(args.input(0), n);
4613 }
4614 
4615 UnpkOp::UnpkOp(const Index n) : noutput(n) {}
4616 
4618  Scalar *y = args.y_ptr(0);
4619  SegmentRef srx(args.x_ptr(0));
4620  if (srx.isNull()) {
4621  for (Index i = 0; i < noutput; i++) y[i] = 0;
4622  return;
4623  }
4624  Scalar *x = srx.value_ptr();
4625  for (Index i = 0; i < noutput; i++) y[i] = x[i];
4626 
4627  ((SegmentRef *)args.x_ptr(0))->glob_ptr = NULL;
4628 }
4629 
4631  SegmentRef *dx = (SegmentRef *)args.dx_ptr(0);
4632  dx[0] = SegmentRef(args.glob_ptr, args.output(0), noutput);
4633 }
4634 
4636  ad_segment dy(args.dy_ptr(0), noutput);
4637  ad_segment dy_packed = pack(dy);
4638  Replay *pdx = args.dx_ptr(0);
4639  for (Index i = 0; i < dy_packed.size(); i++) pdx[i] = dy_packed[i];
4640 }
4641 
4642 const char *UnpkOp::op_name() { return "UnpkOp"; }
4643 
4644 void UnpkOp::dependencies(Args<> &args, Dependencies &dep) const {
4645  dep.add_segment(args.input(0), K);
4646 }
4647 
4649  global::Complete<PackOp> F(x.size());
4650  return F(x);
4651 }
4652 
4654  Index n = SegmentRef(x).size;
4656  return op(x);
4657 }
4658 
4659 Scalar *unpack(const std::vector<Scalar> &x, Index j) {
4660  Index K = ScalarPack<SegmentRef>::size;
4661  SegmentRef sr(&(x[j * K]));
4662  return sr.value_ptr();
4663 }
4664 
4665 std::vector<ad_aug> concat(const std::vector<ad_segment> &x) {
4666  std::vector<ad_aug> ans;
4667  for (size_t i = 0; i < x.size(); i++) {
4668  ad_segment xi = x[i];
4669  for (size_t j = 0; j < xi.size(); j++) {
4670  ans.push_back(xi[j]);
4671  }
4672  }
4673  return ans;
4674 }
4675 } // namespace TMBad
Automatic differentiation library designed for TMB.
Definition: TMB.hpp:157
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
size_t prod_int(const std::vector< size_t > &x)
Integer product function.
Definition: TMBad.cpp:3534
Add zero allocated workspace to the tape.
Definition: global.hpp:2354
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.
void shrink_to_fit(double tol=.9)
Release unnecessary workspace to the system.
Definition: TMBad.cpp:973
Is this a linear operator ?
Definition: global.hpp:744
Does this operator require dynamic allocation ?
Definition: global.hpp:740
Type y(Index j) const
j&#39;th output variable of this operator
Definition: global.hpp:320
Type * y_ptr(Index j)
pointer version - use with caution.
Definition: global.hpp:330
void reorder_temporaries(global &glob)
Re-order computational graph to make it more compressible.
Definition: TMBad.cpp:567
IntRep code
Internal integer representation.
Definition: global.hpp:736
std::vector< size_t > dim
Dimension of logsum array.
void reverse(Position start=Position(0, 0, 0))
Full or partial reverse sweep through the operation stack. Updates global::derivs.
Definition: TMBad.cpp:1015
size_t rep
Number of consecutive period replicates.
Definition: compression.hpp:17
virtual OperatorPure * other_fuse(OperatorPure *other)=0
Lookup table for operator fusion. Merge this OperatorPure with another operator. If no match return N...
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< Index > inv_seed
Optionally control seeding of InvOp in case strong_inv=true
Definition: global.hpp:1402
graph forward_graph(std::vector< bool > keep_var=std::vector< bool >(0))
Construct operator graph with forward connections.
Definition: TMBad.cpp:1576
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
ad_aug operator-() const
Negation.
Definition: TMBad.cpp:2285
size_t size
Size of the period.
Definition: compression.hpp:15
void subgraph_cache_ptr() const
Cache array pointers required by all subgraph routines.
Definition: TMBad.cpp:1230
const Index * inputs
Array for indirect access of operator inputs.
Definition: global.hpp:258
segment_ref< ForwardArgs, y_write > y_segment(Index from, Index size)
segment version
Definition: global.hpp:297
Position end()
The three pointers defining the end of the tape.
Definition: TMBad.cpp:999
multivariate_index & operator++()
Advance to next element of this sub slice.
Definition: TMBad.cpp:3724
IndexVector inputs
Pointers into global::values determining operator inputs.
Definition: global.hpp:945
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
Definition: TMBad.cpp:690
bool bothConstant(const ad_aug &other) const
If true &#39;this&#39; and &#39;other&#39; are both constants. If false nothing can be concluded (they might be const...
Definition: TMBad.cpp:2258
ad_plain add_to_stack(Scalar result=0)
Add nullary operator to the stack based on its result
Definition: global.hpp:2448
void reverse_loop_subgraph(ReverseArgs &args) const
Generic reverse sweep along global::subgraph_seq.
Definition: global.hpp:1056
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
Definition: global.hpp:311
F & apply(F &f) const
Apply a functor to each interval.
Definition: global.hpp:79
std::vector< Scalar > values
Contiguous workspace for taped variables (same length as global::derivs)
Definition: global.hpp:940
Is this a constant operator ?
Definition: global.hpp:746
Contiguous set of variables on the current tape.
Definition: global.hpp:2780
Position begin()
The three pointers defining the begining of the tape.
Definition: TMBad.cpp:997
ad_aug operator*(const ad_aug &other) const
Multiplication.
Definition: TMBad.cpp:2290
Type * y_ptr(Index j)
pointer version - use with caution.
Definition: global.hpp:291
void reorder_sub_expressions(global &glob)
Re-order computational graph to make it more compressible.
Definition: TMBad.cpp:537
void clear()
Clear the operation stack without freeing the container.
Definition: TMBad.cpp:940
void reorder_depth_first(global &glob)
Depth-first reordering of computational graph.
Definition: TMBad.cpp:595
Access input/output values during a forward pass. Write access granted for the output value only...
Definition: global.hpp:279
bool on_some_tape() const
Is this object on some (not necessarily active) tape?
Definition: TMBad.cpp:2172
void ad_stop()
Stop ad calculations from being piped to this glob.
Definition: TMBad.cpp:2073
void forceContiguous(V &x)
Make contiguous ad vector.
Definition: global.hpp:3083
Scalar & value_dep(Index i)
Reference to i&#39;th component of the function value.
Definition: TMBad.cpp:993
void forward_loop(ForwardArgs &args, size_t begin, const NodeFilter &node_filter) const
Generic forward sweep.
Definition: global.hpp:1010
Enable weak comparison operators of an ad type.
Definition: global.hpp:2969
void forward_loop_subgraph(ForwardArgs &args) const
Generic forward sweep along global::subgraph_seq.
Definition: global.hpp:1046
bool deterministic
Deterministic hash codes?
Definition: global.hpp:1400
void set_mask(const std::vector< bool > &mask)
Set all active dimensions of this multivariate_index
Definition: TMBad.cpp:3752
bool insert(T a, T b)
Insert new interval [a,b].
Definition: global.hpp:58
std::vector< Index > indices
Variable indices of this clique.
ad_aug operator/(const ad_aug &other) const
Division.
Definition: TMBad.cpp:2301
Period analyzer.
Definition: compression.hpp:41
global * glob() const
Get the tape of this ad_aug.
vector< Type > operator*(matrix< Type > A, vector< Type > x)
Definition: convenience.hpp:42
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
std::vector< Index > op2idx(const std::vector< Index > &var_subset, Index NA=(Index) -1)
General operator -> variable table generator.
Definition: TMBad.cpp:1462
The abstract operator for the operation stack global::opstack
Definition: global.hpp:811
Augmented AD type.
Definition: global.hpp:2831
virtual op_info info()=0
Get operator info.
Type x(Index j) const
j&#39;th input variable of this operator
Definition: global.hpp:285
std::vector< size_t > max_tree_depth()
Give an estimate (maximum tree depth) of the size of each reverse sub tree.
Definition: TMBad.cpp:4109
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
void reverse(ReverseArgs< Scalar > &args)
Unpack derivatives.
Definition: TMBad.cpp:4587
bool strong_inv
Use unique code for each independent variable? (see hash_sweep)
Definition: global.hpp:1391
ad_aug copy0() const
Deep copy existing ad_aug wihout derivatives.
Definition: TMBad.cpp:2242
Type * x_ptr(Index j)
pointer version - use with caution.
Definition: global.hpp:289
std::vector< Index > inv_index
Pointers into global::values determining independent variables.
Definition: global.hpp:948
Representation of a period in a sequence.
Definition: compression.hpp:11
ad_aug & operator+=(const ad_aug &other)
Compound assignment taking advantage of operator+ reductions.
Definition: TMBad.cpp:2308
Type & y(Index j)
j&#39;th output variable of this operator
Definition: global.hpp:287
bool strong_output
Use unique hash code for each output of an operator?
Definition: global.hpp:1396
size_t begin
Where does the period begin.
Definition: compression.hpp:13
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
Type x(Index j) const
j&#39;th input variable of this operator
Definition: global.hpp:318
void(* reverse_compiled)(Scalar *, Scalar *)
Optional pointer to compiled code.
Definition: global.hpp:958
op_info any
Bitwise max of operator flags in this stack.
Definition: global.hpp:920
void sort_unique_inplace(std::vector< T > &x)
Utility: sort unique inplace.
Definition: global.hpp:610
void get_stride(const clique &super, Index ind, std::vector< ad_plain > &offset, Index &stride)
Determine array offsets and stride of this clique.
Definition: TMBad.cpp:3776
Construct ad_plain from index.
Definition: global.hpp:3014
ad_aug copy() const
Deep copy existing ad_aug. Result will be last value of the current tape.
Definition: TMBad.cpp:2232
std::vector< I > which(const std::vector< bool > &x)
Convert logical vector to index vector.
void reorder_random()
Re-order random effects.
Definition: TMBad.cpp:3885
Empty operator with inputs and outputs.
Definition: global.hpp:2380
Copy value and set derivative to zero.
Definition: global.hpp:2625
void update(Index i)
Integrate independent variable number i, (inv_index[i]).
Definition: TMBad.cpp:4020
virtual void * identifier()=0
Operator identifier.
multivariate_index(size_t bound_, size_t dim, bool flag=true)
CTOR of multivariate_index representing {0,..,B-1}^D
Definition: TMBad.cpp:3709
ad_aug()
Default CTOR.
Definition: TMBad.cpp:2195
size_t output_size() const
Get info.
Definition: TMBad.cpp:4206
Type * dx_ptr(Index j)
pointer version - use with caution.
Definition: global.hpp:332
bool test(op_flag f) const
Test if a given flag is set.
Definition: TMBad.cpp:905
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
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
ad_aug & operator*=(const ad_aug &other)
Compound assignment taking advantage of operator* reductions.
Definition: TMBad.cpp:2318
void merge(Index i)
Merge all cliques that contain a given independent variable.
Definition: TMBad.cpp:3966
Split a computational graph using a simple heuristic.
void reverse_loop(ReverseArgs &args, size_t begin, const NodeFilter &node_filter) const
Generic reverse sweep.
Definition: global.hpp:1029
ad_aug & operator/=(const ad_aug &other)
Compound assignment taking advantage of operator/ reductions.
Definition: TMBad.cpp:2323
std::vector< size_t > index()
Get multivariate_index as a vector.
Definition: TMBad.cpp:3746
void set_subgraph(const std::vector< bool > &marks, bool append=false)
Convert selected variables to a subgraph sequence.
Definition: TMBad.cpp:1241
size_t input_size() const
Get info.
Definition: TMBad.cpp:4204
void aggregate(global &glob, int sign=1)
Reduce a multivariate output function by summing its range components.
Definition: TMBad.cpp:3653
ad_plain taped_value
If taped_value is initialized (see ad_plain::initialize) this is the value of ad_aug.
Definition: global.hpp:2834
ad_segment unpack(const ad_segment &x)
Unpack consecutive values on the tape.
Definition: TMBad.cpp:4653
Utilility class for sequential_reduction.
sequential_reduction(global &glob, std::vector< Index > random, std::vector< sr_grid > grid=std::vector< sr_grid >(1, sr_grid(-20, 20, 200)), std::vector< Index > random2grid=std::vector< Index >(0), bool perm=true)
CTOR of sequential reduction object.
Definition: TMBad.cpp:3843
Scalar Value() const
Return the underlying scalar value of this ad_aug.
Definition: TMBad.cpp:2188
matrix< Type > matmul(matrix< Type > x, matrix< Type > y)
Matrix multiply.
ad_segment pack(const ad_segment &x)
Pack consecutive values on the tape.
Definition: TMBad.cpp:4648
op_flag
Enumeration of selected boolean flags in global::Operator
Definition: global.hpp:738
virtual OperatorPure * self_fuse()=0
Lookup table for operator fusion. Merge this OperatorPure with an identical copy. If no match return ...
void push_back(OperatorPure *x)
Add new operator to this stack and update bitwise operator information.
Definition: TMBad.cpp:923
std::vector< std::vector< Index > > dep_idx
Result: Pointers into original dependent variables.
virtual void deallocate()=0
Deallocate this OperatorPure.
std::vector< Index > dep2op
Used to lookup operator (node) of a dependent variable.
Definition: global.hpp:632
Forbid remappings if not consecutive.
Type dy(Index j) const
Partial derivative of end result wrt. j&#39;th output variable of this operator.
Definition: global.hpp:326
Empty operator without inputs or outputs.
Definition: global.hpp:2371
void Dependent()
Set this ad_aug as dependent.
Definition: TMBad.cpp:2328
void reverse(ReverseArgs< Scalar > &args)
Pack derivatives.
Definition: TMBad.cpp:4630
std::vector< bool > inv_marks()
Boolean representation of independent variable positions.
Definition: TMBad.cpp:1481
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 index(size_t i)
Get given component of this multivariate_index
Definition: TMBad.cpp:3744
bool all_allow_remap(const global &glob)
Test if all operators in the stack allow input remapping.
Definition: TMBad.cpp:4291
Index output(Index j) const
Get variable index of j&#39;th output of current operator.
Definition: global.hpp:267
void forward_dense(std::vector< bool > &marks)
Full forward dependency sweep through the operation stack.
Definition: TMBad.cpp:1066
ad_aug & operator-=(const ad_aug &other)
Compound assignment taking advantage of operator- reductions.
Definition: TMBad.cpp:2313
void extract_sub_inplace(std::vector< bool > marks)
In-place subgraph extractor.
Definition: TMBad.cpp:1320
Scalar & value_inv(Index i)
Reference to i&#39;th input value (parameter)
Definition: TMBad.cpp:989
bool on_active_tape() const
Is this object on the current active tape?
Definition: TMBad.cpp:2174
bool reduce
Reduce returned hash values to one per dependent variable?
Definition: global.hpp:1398
bool identicalOne() const
If true this variable is identical one. If false nothing can be concluded.
Definition: TMBad.cpp:2254
std::vector< global > vglob
Result: Vector of computational graphs.
ad_segment()
Construct empty object.
Definition: TMBad.cpp:2086
void flip()
Flip the mask of active dimensions.
Definition: TMBad.cpp:3722
bool strong_const
Include numerical value as part of hash code for constants? (see hash_sweep)
Definition: global.hpp:1394
Type sum(Vector< Type > x)
Definition: convenience.hpp:33
std::vector< Scalar > derivs
Contiguous workspace for derivatives (same length as global::values)
Definition: global.hpp:943
void override_by(const ad_plain &x) const
Override this ad_plain and set glob to get_glob()
Definition: TMBad.cpp:2218
global * parent_glob
Previous ad context to be restored then this context ends.
Definition: global.hpp:2763
Representation of a specific contiguous set of values on a specific tape.
size_t count()
Number of elements indexed by this multivariate_index
Definition: TMBad.cpp:3702
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
Configuration of hash_sweep.
Definition: global.hpp:1388
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< hash_t > hash_sweep(hash_config cfg) const
Calculate hash codes of each dependent variable using a single forward sweep.
Definition: TMBad.cpp:1659
std::vector< period > split_period(global *glob, period p, size_t max_period_size)
Helper.
Definition: TMBad.cpp:190
double value(T x)
Namespace with utility functions for adaptive numerical integration.
bool identical(const ad_aug &other) const
If true &#39;this&#39; and &#39;other&#39; are identical. If false nothing can be concluded (they might be equal...
Definition: TMBad.cpp:2262
IndexPair ptr
Input/output pointers.
Definition: global.hpp:263
void reverse_sub()
Reverse sweep along a subgraph.
Definition: TMBad.cpp:1029
bool ontape() const
Alias for on_some_tape() (for backward compatibility only)
Definition: TMBad.cpp:2178
std::vector< Index > var2op()
Build variable -> operator node lookup table using a single forward pass. The resulting sequence is m...
Definition: TMBad.cpp:1409
void Independent()
Set this ad_aug as independent.
Definition: TMBad.cpp:2333
std::vector< bool >::reference mask(size_t i)
Get / set active dimensions of this multivariate_index
Definition: TMBad.cpp:3748
Type & dx(Index j)
Partial derivative of end result wrt. j&#39;th input variable of this operator.
Definition: global.hpp:323
std::vector< ad_aug > tabulate(std::vector< Index > inv_index, Index dep_index)
tabulate each combination of variables of a subgraph
Definition: TMBad.cpp:3936
Operator graph in compressed row storage.
Definition: global.hpp:617
void forward(ForwardArgs< Scalar > &args)
Pack values.
Definition: TMBad.cpp:4577
void forward(ForwardArgs< Scalar > &args)
Unpack values.
Definition: TMBad.cpp:4617
void addToTape() const
Force this variable to be put on the tape.
Definition: TMBad.cpp:2201
void extract()
Complete the parallel split.
Definition: TMBad.cpp:4177
Index input(Index j) const
Get variable index of j&#39;th input to current operator.
Definition: global.hpp:265
bool identicalZero() const
If true this variable is identical zero. If false nothing can be concluded.
Definition: TMBad.cpp:2250
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
ad_aug operator+(const ad_aug &other) const
Addition.
Definition: TMBad.cpp:2270
Bitwise collection of selected operator flags.
Definition: global.hpp:732
Type * dy_ptr(Index j)
pointer version - use with caution.
Definition: global.hpp:334
void(* forward_compiled)(Scalar *)
Optional pointer to compiled code.
Definition: global.hpp:956
std::vector< bool > lmatch(const std::vector< T > &x, const std::vector< T > &y)
Match x vector in y vector.
Is it safe to remap the inputs of this operator?
Definition: global.hpp:752
std::vector< Index > dep_index
Pointers into global::values determining dependent variables.
Definition: global.hpp:951
Utilility class for sequential_reduction.
void eliminate()
Very simple tape optimizer.
Definition: TMBad.cpp:1747
bool in_context_stack(global *glob) const
Check if &#39;glob&#39; exists in the active context stack.
Definition: TMBad.cpp:2223
bool constant() const
Is this object guarantied to be a constant?
Definition: TMBad.cpp:2180
Type max(const vector< Type > &x)
License: GPL v2