4 #include "checkpoint.hpp" 6 #include "graph_transform.hpp" 10 template <
class ADFun>
12 template <
class ADFun>
14 template <
class ADFun>
20 std::vector<I> cumsum0(
const std::vector<bool> &x) {
21 std::vector<I> y(x.size(), 0);
22 for (
size_t i = 1; i < x.size(); i++) {
23 y[i] = y[i - 1] + x[i - 1];
56 template <
class Functor,
class InterfaceVector>
59 typedef typename InterfaceVector::value_type Scalar;
60 InterfaceVector tovec(
const InterfaceVector &x) {
return x; }
61 InterfaceVector tovec(
const Scalar &x) {
68 std::vector<T> operator()(
const std::vector<T> &x) {
69 InterfaceVector xi(x);
70 InterfaceVector yi = tovec(F(xi));
116 template <
class ad = ad_aug>
121 template <
class Functor,
class ScalarVector>
122 ADFun(Functor F,
const ScalarVector &x_) : force_update_flag(false) {
123 std::vector<ad> x(x_.size());
124 for (
size_t i = 0; i < x.size(); i++) x[i] = Value(x_[i]);
128 std::vector<ad> y = F(x);
132 TMBAD_ASSERT(glob_begin == glob_end);
138 template <
class Functor>
139 ADFun(Functor F, Scalar x0_) : force_update_flag(false) {
148 TMBAD_ASSERT(glob_begin == glob_end);
154 template <
class Functor>
155 ADFun(Functor F, Scalar x0_, Scalar x1_) : force_update_flag(false) {
166 TMBAD_ASSERT(glob_begin == glob_end);
169 ADFun() : force_update_flag(
false) {}
171 void forward() { glob.
forward(); }
172 void reverse() { glob.
reverse(); }
174 Scalar &deriv_inv(Index i) {
return glob.
deriv_inv(i); }
175 Scalar &deriv_dep(Index i) {
return glob.
deriv_dep(i); }
196 TMBAD_ASSERT2(inv_pos.size() == 0,
197 "Tape has 'cached independent variable positions' which " 198 "would be invalidated by the optimizer");
200 std::vector<bool> outer_mask;
201 if (inner_outer_in_use()) {
202 outer_mask = DomainOuterMask();
209 if (inner_outer_in_use()) {
210 TMBAD_ASSERT(outer_mask.size() == Domain());
211 set_inner_outer(*
this, outer_mask);
223 std::vector<Position> pos = inv_positions(glob);
238 std::vector<bool> outer_mask;
239 if (inner_outer_in_use()) {
240 outer_mask = DomainOuterMask();
244 if (inner_outer_in_use()) {
245 TMBAD_ASSERT(outer_mask.size() == Domain());
246 set_inner_outer(*
this, outer_mask);
251 size_t Domain()
const {
return glob.
inv_index.size(); }
252 size_t Range()
const {
return glob.
dep_index.size(); }
255 std::vector<bool> mark(glob.
values.size(),
false);
256 for (
size_t i = 0; i < glob.
dep_index.size(); i++)
263 std::vector<bool> mark(glob.
values.size(),
false);
264 for (
size_t i = 0; i < glob.
inv_index.size(); i++)
271 std::vector<Scalar> xd(Domain());
272 for (
size_t i = 0; i < xd.size(); i++) xd[i] = glob.
value_inv(i);
281 std::vector<bool> keep_y) {
282 std::vector<bool> keep_var(glob.
values.size(),
true);
283 if (keep_x.size() > 0 || keep_y.size() > 0) {
284 if (keep_x.size() == 0) keep_x.resize(glob.
inv_index.size(),
true);
285 if (keep_y.size() == 0) keep_y.resize(glob.
dep_index.size(),
true);
286 TMBAD_ASSERT(keep_x.size() == glob.
inv_index.size());
287 TMBAD_ASSERT(keep_y.size() == glob.
dep_index.size());
289 std::vector<bool> keep_var_init(keep_var.size(),
false);
290 for (
size_t i = 0; i < glob.
inv_index.size(); i++)
291 if (keep_x[i]) keep_var_init[glob.
inv_index[i]] =
true;
292 for (
size_t i = 0; i < glob.
dep_index.size(); i++)
293 if (keep_y[i]) keep_var_init[glob.
dep_index[i]] =
true;
295 std::vector<bool> keep_var_x = keep_var_init;
298 std::vector<bool> keep_var_y = keep_var_init;
301 for (
size_t i = 0; i < keep_var.size(); i++)
302 keep_var[i] = keep_var_x[i] && keep_var_y[i];
316 for (
size_t i = 0; i < inv_pos.size(); i++) {
317 if (inv_pos[i].ptr.second == inv)
return inv_pos[i];
319 return Position(0, 0, 0);
331 if (glob.
inv_index.size() == 0)
return true;
333 bool is_sorted = (inv_pos.size() == 0 && !inner_outer_in_use());
334 return is_sorted && (glob.
inv_index.size() ==
340 if (inv_pos.size() > 0) {
341 std::vector<Position> pos =
subset(inv_pos, random);
342 tail_start = *std::min_element(pos.begin(), pos.end());
344 tail_start = Position(0, 0, 0);
352 bool force_update_flag;
354 template <
class InplaceVector>
356 TMBAD_ASSERT(x.size() == Domain());
357 if (force_update_flag) {
358 for (
size_t i = 0; i < x.size(); i++) glob.
value_inv(i) = x[i];
359 force_update_flag =
false;
360 return Position(0, 0, 0);
362 if (inv_pos.size() > 0) {
363 if (inner_outer_in_use()) {
364 for (
size_t i = 0; i < x.size(); i++) glob.
value_inv(i) = x[i];
367 return find_pos(min_inv);
369 TMBAD_ASSERT(inv_pos.size() == Domain());
370 size_t min_var_changed = -1;
372 for (
size_t i = 0; i < x.size(); i++) {
379 if (min_var_changed == (
size_t)-1)
382 return inv_pos[i_min];
385 bool no_change =
true;
386 for (
size_t i = 0; i < x.size(); i++) {
392 if (no_change)
return glob.
end();
394 for (
size_t i = 0; i < x.size(); i++) glob.
value_inv(i) = x[i];
396 return Position(0, 0, 0);
399 template <
class Vector>
401 TMBAD_ASSERT((
size_t)x.size() == Domain());
402 for (
size_t i = 0; i < (size_t)x.size(); i++) glob.
value_inv(i) = x[i];
405 for (
size_t i = 0; i < (size_t)y.size(); i++) y[i] = glob.
value_dep(i);
409 template <
class Vector>
411 TMBAD_ASSERT((
size_t)w.size() == Range());
413 for (
size_t i = 0; i < (size_t)w.size(); i++) glob.
deriv_dep(i) = w[i];
416 for (
size_t i = 0; i < (size_t)d.size(); i++) d[i] = glob.
deriv_inv(i);
420 std::vector<Scalar>
operator()(
const std::vector<Scalar> &x) {
421 Position start = DomainVecSet(x);
428 Position start = DomainVecSet(x);
437 std::vector<ad>
operator()(
const std::vector<ad> &x_)
const {
438 std::vector<ad> x(x_.begin(), x_.end());
439 TMBAD_ASSERT(x.size() == Domain());
440 for (
size_t i = 0; i < x.size(); i++) {
444 for (
size_t i = 0; i < x.size(); i++) {
445 TMBAD_ASSERT(x[i].on_some_tape());
446 TMBAD_ASSERT(x[i].glob() == cur_glob);
448 global::replay replay(this->glob, *
get_glob());
450 for (
size_t i = 0; i < this->Domain(); i++) {
451 replay.value_inv(i) = x[i];
453 replay.forward(
false,
false);
454 std::vector<ad> y(this->Range());
455 for (
size_t i = 0; i < this->Range(); i++) {
456 y[i] = replay.value_dep(i);
464 TMBAD_ASSERT(Domain() == 1);
465 TMBAD_ASSERT(Range() == 1);
466 std::vector<ad> x(1);
468 return (*
this)(x)[0];
473 TMBAD_ASSERT(Domain() == 2);
474 TMBAD_ASSERT(Range() == 1);
475 std::vector<ad> x(2);
478 return (*
this)(x)[0];
484 std::vector<Scalar>
Jacobian(
const std::vector<Scalar> &x) {
485 Position start = DomainVecSet(x);
487 std::vector<Scalar> ans(Domain() * Range());
488 for (
size_t j = 0; j < Range(); j++) {
492 for (
size_t k = 0; k < Domain(); k++)
493 ans[j * Domain() + k] = glob.
deriv_inv(k);
503 std::vector<Scalar>
Jacobian(
const std::vector<Scalar> &x,
504 std::vector<bool> keep_x,
505 std::vector<bool> keep_y) {
506 std::vector<Scalar> ans;
508 std::vector<bool> keep_var = get_keep_var(keep_x, keep_y);
512 std::vector<size_t> which_keep_x =
which(keep_x);
513 std::vector<size_t> which_keep_y =
which(keep_y);
515 Position start = DomainVecSet(x);
518 for (
size_t w = 0; w < which_keep_y.size(); w++) {
519 size_t k = which_keep_y[w];
521 glob.subgraph_seq.resize(0);
522 glob.subgraph_seq.push_back(G.
dep2op[k]);
523 G.
search(glob.subgraph_seq);
526 for (
size_t l = 0; l < which_keep_x.size(); l++)
527 glob.
deriv_inv(which_keep_x[l]) = Scalar(0);
531 for (
size_t l = 0; l < which_keep_x.size(); l++) {
532 ans.push_back(glob.
deriv_inv(which_keep_x[l]));
542 std::vector<Scalar>
Jacobian(
const std::vector<Scalar> &x,
543 const std::vector<Scalar> &w) {
544 TMBAD_ASSERT(x.size() == Domain());
545 TMBAD_ASSERT(w.size() == Range());
546 Position start = DomainVecSet(x);
549 for (
size_t j = 0; j < Range(); j++) glob.
deriv_dep(j) = w[j];
557 TMBAD_ASSERT(x.size() == Domain());
558 TMBAD_ASSERT(w.size() == Range());
559 Position start = DomainVecSet(x);
562 for (
size_t j = 0; j < Range(); j++) glob.
deriv_dep(j) = w[j];
566 std::vector<ad> Jacobian(
const std::vector<ad> &x_,
567 const std::vector<ad> &w_) {
568 std::vector<ad> x(x_.begin(), x_.end());
569 std::vector<ad> w(w_.begin(), w_.end());
572 TMBAD_ASSERT(x.size() == Domain());
573 for (
size_t i = 0; i < x.size(); i++) {
576 for (
size_t i = 0; i < x.size(); i++) {
577 TMBAD_ASSERT(x[i].on_some_tape());
578 TMBAD_ASSERT(x[i].glob() == cur_glob);
581 TMBAD_ASSERT(w.size() == Range());
582 for (
size_t i = 0; i < w.size(); i++) {
585 for (
size_t i = 0; i < w.size(); i++) {
586 TMBAD_ASSERT(w[i].on_some_tape());
587 TMBAD_ASSERT(w[i].glob() == cur_glob);
590 global::replay replay(this->glob, *
get_glob());
592 for (
size_t i = 0; i < this->Domain(); i++) {
593 replay.value_inv(i) = x[i];
595 replay.forward(
false,
false);
596 replay.clear_deriv();
597 for (
size_t i = 0; i < this->Range(); i++) {
598 replay.deriv_dep(i) = w[i];
600 replay.reverse(
false,
false);
601 std::vector<ad> dx(this->Domain());
602 for (
size_t i = 0; i < dx.size(); i++) {
603 dx[i] = replay.deriv_inv(i);
608 template <
bool range_weight>
609 ADFun JacFun_(std::vector<bool> keep_x, std::vector<bool> keep_y) {
611 if (keep_x.size() == 0) keep_x.resize(Domain(),
true);
612 if (keep_y.size() == 0) keep_y.resize(Range(),
true);
613 std::vector<bool> keep = get_keep_var(keep_x, keep_y);
615 if (!range_weight && Range() > 1) {
619 global::replay replay(this->glob, ans.glob);
621 replay.forward(
true,
false);
624 for (
size_t i = 0; i < this->Range(); i++) {
625 if (!keep_y[i])
continue;
626 replay.clear_deriv();
627 replay.deriv_dep(i) = 1.;
628 replay.reverse(
false,
false, tail_start, keep);
629 for (
size_t j = 0; j < this->Domain(); j++) {
630 if (keep_x[j]) replay.deriv_inv(j).Dependent();
634 replay.clear_deriv();
635 for (
size_t i = 0; i < this->Range(); i++) {
636 if (!keep_y[i])
continue;
637 glob.subgraph_seq.resize(0);
638 glob.subgraph_seq.push_back(G.
dep2op[i]);
639 G.
search(glob.subgraph_seq);
640 replay.deriv_dep(i) = 1.;
641 replay.reverse_sub();
642 for (
size_t j = 0; j < this->Domain(); j++) {
643 if (keep_x[j]) replay.deriv_inv(j).Dependent();
645 replay.clear_deriv_sub();
649 replay.clear_deriv();
650 replay.reverse(
false,
true, tail_start, keep);
651 for (
size_t j = 0; j < this->Domain(); j++) {
652 if (keep_x[j]) replay.deriv_inv(j).Dependent();
656 set_inner_outer(ans);
681 std::vector<bool> keep_y = std::vector<bool>(0)) {
682 return JacFun_<false>(keep_x, keep_y);
703 std::vector<bool> keep_y = std::vector<bool>(0)) {
704 return JacFun_<true>(keep_x, keep_y);
709 std::vector<Scalar> x = DomainVec();
718 TMBAD_ASSERT(Range() == 1);
720 autopar ap(glob_split, num_threads);
725 std::vector<ADFun> ans(num_threads);
726 for (
size_t i = 0; i < num_threads; i++) ans[i].glob = ap.
vglob[i];
733 TMBAD_ASSERT(Range() == 1);
735 autopar ap(glob_split, num_threads);
741 ADFun F(f_parallel, DomainVec());
776 Sparse<ADFun>
SpJacFun(std::vector<bool> keep_x = std::vector<bool>(0),
777 std::vector<bool> keep_y = std::vector<bool>(0),
779 ADFun atomic_jac_row;
780 std::vector<Index> rowcounts;
787 if (keep_x.size() == 0) keep_x.resize(Domain(),
true);
788 if (keep_y.size() == 0) keep_y.resize(Range(),
true);
789 std::vector<bool> keep_var = get_keep_var(keep_x, keep_y);
791 size_t keep_x_count = std::count(keep_x.begin(), keep_x.end(),
true);
792 size_t keep_y_count = std::count(keep_y.begin(), keep_y.end(),
true);
796 global::replay replay(this->glob, ans.glob);
798 replay.forward(
true,
false);
803 std::fill(keep_var.begin(), keep_var.end(),
true);
805 std::vector<Index> col_idx;
806 for (
size_t k = 0; k < glob.
dep_index.size(); k++) {
809 glob.subgraph_seq.resize(0);
810 glob.subgraph_seq.push_back(G.dep2op[k]);
811 G.search(glob.subgraph_seq);
813 bool do_compress =
false;
814 if (config.compress) {
815 if (rowcounts.size() == 0) rowcounts = G.rowcounts();
818 for (
size_t i = 0; i < glob.subgraph_seq.size(); i++) {
819 cost1 += rowcounts[glob.subgraph_seq[i]];
822 size_t cost2 = Domain() + Range() + Domain();
824 if (cost2 < cost1) do_compress =
true;
834 for (
size_t l = 0; l < glob.subgraph_seq.size(); l++) {
835 Index idx = op2inv_idx[glob.subgraph_seq[l]];
837 Index nrep = glob.
opstack[glob.subgraph_seq[l]]->output_size();
838 for (Index r = 0; r < nrep; r++) {
845 ans.i.resize(ans.i.size() + col_idx.size(), k);
846 ans.j.insert(ans.j.end(), col_idx.begin(), col_idx.end());
848 replay.clear_deriv_sub();
850 replay.deriv_dep(k) = 1.;
852 replay.reverse_sub();
855 if (atomic_jac_row.Domain() == 0) {
856 Rcout <<
"Warning: This is an experimental compression method\n";
857 Rcout <<
"Disable: 'config(tmbad.sparse_hessian_compress=0)'\n";
858 atomic_jac_row = this->WgtJacFun(keep_x, keep_y);
863 atomic_jac_row = atomic_jac_row.
atomic();
865 replay.clear_deriv_sub();
868 TMBAD_ASSERT(atomic_jac_row.Domain() ==
869 this->Domain() + this->Range());
870 TMBAD_ASSERT(atomic_jac_row.Range() == keep_x_count);
872 std::vector<Replay> vec(atomic_jac_row.Domain(), Replay(0));
873 for (
size_t i = 0; i < this->Domain(); i++) {
874 vec[i] = replay.value_inv(i);
876 vec[this->Domain() + k] = 1.;
877 std::vector<Replay> r = atomic_jac_row(vec);
879 for (
size_t i = 0; i < this->Domain(); i++) {
880 if (keep_x[i]) replay.deriv_inv(i) = r[r_idx++];
883 for (
size_t l = 0; l < col_idx.size(); l++) {
884 replay.deriv_inv(col_idx[l]).Dependent();
888 if (config.index_remap) {
889 if (keep_x.size() > 0) {
890 std::vector<Index> remap_j = cumsum0<Index>(keep_x);
892 ans.n = keep_x_count;
894 if (keep_y.size() > 0) {
895 std::vector<Index> remap_i = cumsum0<Index>(keep_y);
897 ans.m = keep_y_count;
900 set_inner_outer(ans);
908 gk_config cfg = gk_config()) {
914 integrate_subgraph<ADFun> i_s(glob_split, random, cfg);
921 const std::vector<Index> &random2grid,
bool perm =
true) {
928 ans.glob = SR.marginal();
935 return marginal_sr(random, std::vector<sr_grid>(1, grid),
936 std::vector<Index>(0));
943 TMBAD_ASSERT2(other.Range() == this->Domain(),
944 "Compostion of incompatible functions");
948 composition(
const ADFun &f,
const ADFun &g) : f(f), g(g) {}
949 std::vector<ad> operator()(std::vector<ad> x) {
return f(g(x)); }
951 composition fg(*
this, other);
960 global &glob1 = ans.first.glob;
961 global &glob2 = ans.second.glob;
963 OperatorPure *invop = glob.getOperator<global::InvOp>();
964 std::vector<bool> keep(nodes.size(),
true);
965 for (
size_t i = 0; i < nodes.size(); i++)
966 if (glob.
opstack[nodes[i]] == invop) keep[i] =
false;
967 nodes =
subset(nodes, keep);
971 std::vector<Index> dep1 = glob1.
op2var(nodes);
973 for (
size_t i = 0; i < dep1.size(); i++) {
985 set_inner_outer(ans.first);
986 set_inner_outer(ans.second);
996 return decompose(nodes);
1005 std::vector<bool> keep_x(Domain(),
true);
1006 std::vector<bool> keep_y(Range(),
true);
1007 std::vector<bool> vars = get_keep_var(keep_x, keep_y);
1011 std::vector<Index> nodes = which<Index>(glob.
var2op(vars));
1015 size_t n_inner = decomp.first.Domain();
1016 size_t n_outer = decomp.first.Range();
1018 decomp.first.glob.inv_index.resize(0);
1020 std::vector<ad_aug> empty;
1021 std::vector<ad_aug> gx = decomp.first(empty);
1023 ADFun &f = decomp.second;
1027 TMBAD_ASSERT(n_inner + n_outer == f.Domain());
1030 TMBAD_ASSERT(gx.size() == n_outer);
1032 for (
size_t i = 0; i < n_outer; i++) {
1033 Index j = f.glob.
inv_index[n_inner + i];
1035 if (gx[i].constant()) {
1036 f.glob.
opstack[j] = glob.getOperator<global::ConstOp>();
1039 gx[i].data.glob, gx[i].taped_value.index);
1057 inner_inv_index.size() == 0 && outer_inv_index.size() == 0,
1058 "'resolve_refs' can only be run once for a given function object")
1062 std::vector<Replay> values(seq.size());
1063 std::vector<Index> dummy_inputs;
1065 for (
size_t i = 0; i < seq.size(); i++) {
1066 TMBAD_ASSERT(glob.
opstack[seq[i]]->input_size() == 0);
1067 TMBAD_ASSERT(glob.
opstack[seq[i]]->output_size() == 1);
1068 glob.
opstack[seq[i]]->forward_incr(args);
1069 glob.
opstack[seq[i]]->deallocate();
1073 outer_inv_index = glob.
op2var(seq);
1076 outer_inv_index.end());
1079 std::vector<Index> inner_inv_index;
1080 std::vector<Index> outer_inv_index;
1089 std::swap(glob.
inv_index, inner_inv_index);
1096 std::swap(glob.
inv_index, outer_inv_index);
1101 return (DomainInner() > 0) || (DomainOuter() > 0);
1105 std::vector<bool> mark_outer =
1117 if (inner_outer_in_use()) {
1118 std::vector<bool> mark(outer_mask);
1119 mark.resize(ans.Domain(),
false);
1128 void set_inner_outer(
ADFun &ans) {
1129 if (inner_outer_in_use()) {
1130 set_inner_outer(ans, DomainOuterMask());
1133 void DomainReduce(
const std::vector<bool> &inv_keep) {
1134 std::vector<bool> outer_mask = DomainOuterMask();
1135 outer_mask =
subset(outer_mask, inv_keep);
1137 set_inner_outer(*
this, outer_mask);
1145 for (
size_t i = 0; i < nodes.size(); i++) {
1164 template <
class Functor,
class Test = ParametersChanged>
1166 Test test = Test()) {
1173 template <
class dummy =
void>
1178 ad_segment operator()(
const std::vector<ad_segment> &x) {
1179 std::vector<ad_segment> xp(x.size());
1180 for (
size_t i = 0; i < xp.size(); i++) xp[i] =
pack(x[i]);
1181 std::vector<ad_aug> yp = Fp(concat(xp));
1184 bool initialized() {
return Fp.Domain() != 0; }
1193 template <
class Functor,
class Test>
1196 static const bool packed =
true;
1201 std::vector<ad_segment> xp(x.size());
1202 for (
size_t i = 0; i < xp.size(); i++) xp[i] =
pack(x[i]);
1203 std::vector<ad_aug> xp_ = concat(xp);
1204 PackWrap<Test> testp(test);
1206 ADFun<> TapeFp(Op, xp_);
1210 template <
class ADFun>
1211 struct Sparse :
ADFun {
1212 std::vector<Index> i;
1213 std::vector<Index> j;
1218 std::vector<Index> a2v(
const std::valarray<Index> &x)
const {
1219 return std::vector<Index>(&x[0], &x[0] + x.size());
1221 std::valarray<Index> v2a(
const std::vector<Index> &x)
const {
1222 return std::valarray<Index>(x.data(), x.size());
1224 std::valarray<Index> row()
const {
return v2a(i); }
1225 std::valarray<Index> col()
const {
return v2a(j); }
1226 void subset_inplace(
const std::valarray<bool> &x) {
1231 void transpose_inplace() {
1243 template <
class ADFun>
1244 struct Decomp2 : std::pair<ADFun, ADFun> {
1245 struct composition {
1249 composition(
const ADFun &f,
const ADFun &g) : f(f), g(g) {}
1250 std::vector<ad> operator()(std::vector<ad> x) {
1251 std::vector<ad> y = g(x);
1252 x.insert(x.end(), y.begin(), y.end());
1257 ADFun &g = this->first;
1258 ADFun &f = this->second;
1259 composition fg(f, g);
1286 bool sparse_1 =
true,
bool sparse_2 =
true,
1287 bool sparse_3 =
true) {
1288 ADFun &g = this->first;
1289 ADFun &f = this->second;
1291 TMBAD_ASSERT(f.Range() == 1);
1293 std::vector<bool> keep_f = std::vector<bool>(f.Range(),
true);
1294 std::vector<bool> keep_g = std::vector<bool>(g.Range(),
true);
1297 global &glob = ans.first.glob;
1300 size_t k = g.Range();
1301 size_t n = f.Domain() - k;
1303 std::vector<bool> mask_x(f.Domain(),
false);
1304 for (
size_t i = 0; i < n; i++) mask_x[i] =
true;
1305 std::vector<bool> mask_s(mask_x);
1308 std::vector<ad> x(x_.begin(), x_.end() - k);
1310 std::vector<ad> s = g(x);
1311 std::vector<ad> s0(s.size());
1313 for (
size_t i = 0; i < s.size(); i++) s0[i] = s[i].copy0();
1314 std::vector<ad> xs(x);
1315 xs.insert(xs.end(), s.begin(), s.end());
1316 std::vector<ad> xs0(x);
1317 xs0.insert(xs0.end(), s0.begin(), s0.end());
1319 TMBAD_ASSERT(keep_rc.size() == n || keep_rc.size() == 0);
1320 std::vector<bool> keep_xy(keep_rc);
1321 keep_xy.resize(f.Domain(),
true);
1325 std::vector<ad> z =
subset(f_grad(xs), mask_x);
1326 std::vector<ad> z0 =
subset(f_grad(xs0), mask_s);
1327 std::vector<ad> xw(x);
1328 xw.insert(xw.end(), z0.begin(), z0.end());
1330 for (
size_t i = 0; i < n; i++) z[i] += z1[i];
1334 ans.first.glob = glob;
1337 ans.first = ans.first.SpJacFun(keep_rc, keep_rc);
1339 ans.first = ans.first.JacFun(keep_rc, keep_rc);
1341 ans.first.glob.eliminate();
1347 ans.second = g.
JacFun(keep_rc);
1349 ans.second.glob.eliminate();
1353 B = f_grad.
SpJacFun(mask_s, mask_s);
1355 B = f_grad.
JacFun(mask_s, mask_s);
1357 ans.third.glob.ad_start();
1358 std::vector<ad> xx(x_.begin(), x_.end() - k);
1362 xs.insert(xs.end(), s.begin(), s.end());
1365 ans.third.glob.ad_stop();
1366 ans.third.glob.eliminate();
1384 template <
class ADFun>
1386 Sparse<ADFun> third;
1390 #endif // HAVE_TMBAD_HPP Automatic differentiation library designed for TMB.
std::vector< bool > get_keep_var(std::vector< bool > keep_x, std::vector< bool > keep_y)
Get necessary variables to keep for given input/output selection.
std::vector< Index > op2var(const std::vector< Index > &seq)
Get variables produces by a node seqence.
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.
Sparse< ADFun > SpJacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0), SpJacFun_config config=SpJacFun_config())
Sparse Jacobian function generator.
global accumulation_tree_split(global glob, bool sum_=false)
Split a computational graph by it's accumulation tree.
virtual Index output_size()=0
Number of outputs from this OperatorPure.
Decomp2< ADFun > decompose(const char *name)
Decompose this computational graph by operator name.
std::vector< bool > DomainOuterMask()
Helper: Boolean mask of outer parameters.
ADFun WgtJacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0))
Get weighted Jacobian function object.
std::vector< ad_aug > resolve_refs()
Resolve references of this ADFun object.
void forward_replay(bool inv_tags=true, bool dep_tags=true)
Replay this operation sequence to itself.
ADFun(Functor F, Scalar x0_, Scalar x1_)
Constructor of 2 scalar input / 1 scalar output function.
void reverse(Position start=Position(0, 0, 0))
Full or partial reverse sweep through the operation stack. Updates global::derivs.
void forward(Position start=Position(0, 0, 0))
Full or partial forward sweep through the operation stack. Updates global::values.
std::vector< T > invperm(const std::vector< T > &perm)
Inverse permutation.
IndirectAccessor< Scalar > RangeVec()
Get most recent result vector from the tape.
void reorder_graph(global &glob, std::vector< Index > inv_idx)
Reorder computational graph such that selected independent variables come last.
ADFun parallelize(size_t num_threads)
Parallelize this operation sequence.
operation_stack opstack
Operation stack.
bool keep_all_inv
Keep all independent variables for each thread?
ADFun atomic()
Turn this operation sequence into an atomic operator.
Position end()
The three pointers defining the end of the tape.
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
Decomposition of computational graph.
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
void unset_tail()
Inactivate tail sweep to get derivatives wrt all independent variables.
ADFun JacFun(std::vector< bool > keep_x=std::vector< bool >(0), std::vector< bool > keep_y=std::vector< bool >(0))
Get Jacobian function object.
std::vector< Scalar > values
Contiguous workspace for taped variables (same length as global::derivs)
Vector forward(const Vector &x)
Forward sweep any vector class.
void set_inv_positions()
Cache tape positions of independent variables.
Contiguous set of variables on the current tape.
ADFun marginal_sr(const std::vector< Index > &random, std::vector< sr_grid > grid, const std::vector< Index > &random2grid, bool perm=true)
Integrate using sequential reduction.
Provide inplace read access to value or derivative arrays.
ad operator()(ad x0)
Evaluate function scalar version.
void set_tail(const std::vector< Index > &random)
Set start position needed to get selected independent variable derivatives.
Sequential reduction algorithm.
Transform a functor to have packed input/output.
void ad_stop()
Stop ad calculations from being piped to this glob.
Automatic differentiation function object.
Scalar & value_dep(Index i)
Reference to i'th component of the function value.
void eliminate()
Dead operator elimination.
std::vector< bool > activeRange()
Which outputs are affected by some inputs.
ADFun compose(ADFun other)
Construct function composition.
Configuration of print method.
std::vector< Scalar > DomainVec()
Get most recent input parameter vector from the tape.
The abstract operator for the operation stack global::opstack
std::vector< Index > op2idx(const std::vector< Index > &var_subset, Index NA=(Index) -1)
General operator -> variable table generator.
std::vector< bool > mark_space(size_t n, const std::vector< Index > ind)
General boolean table generator.
std::vector< ad > operator()(const std::vector< ad > &x_) const
Evaluate function for ad vector input.
Position tail_start
Mark the tail of the operation sequence A 'tail sweep' is on the subsequence tail_start:end. Only used by teh reverse sweep.
std::vector< Index > inv_index
Pointers into global::values determining independent variables.
void reorder(std::vector< Index > last)
Reorder computational graph to allow quick updates of selected inputs.
std::vector< bool > reverse_boundary(global &glob, const std::vector< bool > &vars)
Find boundary without using the graph.
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
Position DomainVecSet(const InplaceVector &x)
Set the input parameter vector on the tape.
std::vector< I > which(const std::vector< bool > &x)
Convert logical vector to index vector.
std::vector< bool > activeDomain()
Which inputs are affecting some outputs.
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x, const std::vector< Scalar > &w)
Evaluate the Jacobian matrix multiplied by a vector.
Empty operator with inputs and outputs.
void print(print_config cfg)
Print workspace.
void print(print_config cfg=print_config())
Print AD workspace.
std::vector< Index > remap_identical_sub_expressions(global &glob, std::vector< Index > inv_remap)
Remap identical sub-expressions.
void search(std::vector< Index > &start, bool sort_input=true, bool sort_output=true)
Find sub graph.
Struct defining the main AD context.
Decomp2< ADFun > decompose(std::vector< Index > nodes)
Decompose this computational graph.
Scalar & deriv_inv(Index i)
Reference to i'th component of the gradient.
Scalar & deriv_dep(Index i)
Reference to i'th 'range direction' used to seed the derivative.
Provide read/write access to an array segment.
Split a computational graph using a simple heuristic.
void aggregate(global &glob, int sign=1)
Reduce a multivariate output function by summing its range components.
ADFun marginal_gk(const std::vector< Index > &random, gk_config cfg=gk_config())
Integrate as many univariate variables as possible.
Interoperability with other vector classes.
ad operator()(ad x0, ad x1)
Evaluate function scalar version.
Read the current tape's state and restore it on request.
ad_segment unpack(const ad_segment &x)
Unpack consecutive values on the tape.
ad_segment pack(const ad_segment &x)
Pack consecutive values on the tape.
void push_back(OperatorPure *x)
Add new operator to this stack and update bitwise operator information.
Vector reverse(const Vector &w)
Reverse sweep any vector class.
virtual void deallocate()=0
Deallocate this OperatorPure.
void SwapInner()
Temporarily regard this object as function of inner parameters.
std::vector< Index > dep2op
Used to lookup operator (node) of a dependent variable.
Position find_pos(Index inv)
Helper to find the tape position of an independent variable.
Configuration parameters for SpJacFun()
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.
Reference a variable on another tape.
size_t DomainInner() const
Number of inner parameters.
Scalar & value_inv(Index i)
Reference to i'th input value (parameter)
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x)
Evaluate the Jacobian matrix.
std::vector< global > vglob
Result: Vector of computational graphs.
void replay()
Replay this operation sequence to a new sequence.
ADFun marginal_sr(const std::vector< Index > &random, sr_grid grid=sr_grid())
Integrate using sequential reduction.
bool inner_outer_in_use()
Helper: Does tape have inner/outer information ?
void force_update()
Next forward pass must traverse the full graph.
std::vector< Scalar > derivs
Contiguous workspace for derivatives (same length as global::values)
Utilility class for sequential_reduction.
void clear_array_subgraph(Vector &array, typename Vector::value_type value=typename Vector::value_type(0)) const
Generic clear array along global::subgraph.
std::vector< Scalar > operator()(const std::vector< Scalar > &x)
Evaluate function for scalar vector input.
void clear_deriv(Position start=Position(0, 0, 0))
Set derivatives to zero.
std::vector< Index > find_op_by_name(global &glob, const char *name)
Find nodes by name.
std::vector< ADFun > parallel_accumulate(size_t num_threads)
Parallel split this operation sequence Split function f:R^n->R by its accumulation tree...
void reverse_sub()
Reverse sweep along a subgraph.
std::vector< Index > var2op()
Build variable -> operator node lookup table using a single forward pass. The resulting sequence is m...
bool do_aggregate
Sum up result for each thread?
ADFun ADFun_retaping(Functor &F, const std::vector< ad_aug > &x, Test test=Test())
Construct ADFun that automatically retapes.
void SwapOuter()
Temporarily regard this object as function of outer parameters.
void set_inner_outer(ADFun &ans, const std::vector< bool > &outer_mask)
Helper: Pass on inner/outer information to a new tape. Some parameters are marked as 'outer parameter...
Operator graph in compressed row storage.
void clear_deriv_sub()
Clear derivative array along a subgraph.
ADFun(Functor F, const ScalarVector &x_)
Constructor of vector input / vector output function.
Adaptive derivative table used by AtomOp
void extract()
Complete the parallel split.
std::vector< Scalar > Jacobian(const std::vector< Scalar > &x, std::vector< bool > keep_x, std::vector< bool > keep_y)
Evaluate the Jacobian matrix subset
void optimize()
Tape optimizer.
void ad_start()
Enable ad calulations to be piped to this glob.
bool inv_index_is_consecutive()
Are the independent variable indices consecutive?
void decompose_refs()
Optional optimization step before resolving references.
size_t DomainOuter() const
Number of outer parameters.
Decomp3< ADFun > HesFun(std::vector< bool > keep_rc=std::vector< bool >(0), bool sparse_1=true, bool sparse_2=true, bool sparse_3=true)
Calculate a sparse plus low rank representation of the Hessian.
std::vector< Index > dep_index
Pointers into global::values determining dependent variables.
std::vector< Position > inv_pos
Vector of positions by independent variables.
void eliminate()
Very simple tape optimizer.
Decomposition of computational graph.
ADFun(Functor F, Scalar x0_)
Constructor of 1 scalar input / 1 scalar output function.
Container of ADFun object with packed input and output.
void inactivate(std::vector< Index > nodes)
Substitute selected operators by void operators.