1 #ifndef HAVE_GRAPH_TRANSFORM_HPP 2 #define HAVE_GRAPH_TRANSFORM_HPP 7 #include "checkpoint.hpp" 9 #include "integrate.hpp" 19 std::vector<bool>
lmatch(
const std::vector<T> &x,
const std::vector<T> &y) {
20 std::vector<bool> ans(x.size(),
false);
21 for (
size_t i = 0; i < x.size(); i++)
22 for (
size_t j = 0; j < y.size(); j++) ans[i] = ans[i] || (x[i] == y[j]);
28 std::vector<I>
which(
const std::vector<bool> &x) {
30 for (
size_t i = 0; i < x.size(); i++)
31 if (x[i]) y.push_back(i);
36 std::vector<size_t>
which(
const std::vector<bool> &x);
40 std::vector<T>
subset(
const std::vector<T> &x,
const std::vector<bool> &y) {
41 TMBAD_ASSERT(x.size() == y.size());
43 for (
size_t i = 0; i < x.size(); i++)
44 if (y[i]) ans.push_back(x[i]);
49 template <
class T,
class I>
50 std::vector<T>
subset(
const std::vector<T> &x,
const std::vector<I> &ind) {
51 std::vector<T> ans(ind.size());
52 for (
size_t i = 0; i < ind.size(); i++) ans[i] = x[ind[i]];
67 template <
class T,
class I>
69 std::vector<bool> mark(x.size(),
false);
70 for (
size_t k = 0; k < i.size(); k++) {
71 TMBAD_ASSERT(!mark[i[k]]);
76 for (
size_t k = 0; k < x.size(); k++) {
78 x_new.push_back(space);
79 i_new.push_back(x_new.size());
81 x_new.push_back(x[k]);
89 std::vector<T>
invperm(
const std::vector<T> &perm) {
90 std::vector<T> iperm(perm.size());
91 for (
size_t i = 0; i < perm.size(); i++) iperm[perm[i]] = i;
97 std::vector<size_t>
match(
const std::vector<T> &x,
const std::vector<T> &y) {
102 size_t prod_int(
const std::vector<size_t> &x);
117 std::vector<size_t>
order(std::vector<T> x) {
118 std::vector<std::pair<T, size_t> > y(x.size());
119 for (
size_t i = 0; i < x.size(); i++) {
124 std::vector<size_t> z(x.size());
125 for (
size_t i = 0; i < x.size(); i++) {
150 bool inv_tags =
true,
bool dep_tags =
true);
154 bool inv_tags =
true,
bool dep_tags =
true);
178 std::vector<Index> dep_index;
186 global &glob, std::vector<Index> inv_remap);
189 std::vector<Index> id;
190 std::vector<size_t> count;
191 term_info(
global &glob,
bool do_init =
true);
192 void initialize(std::vector<Index> inv_remap = std::vector<Index>(0));
208 template <
class Float = ad_adapt>
209 struct logIntegrate_t {
210 typedef Float Scalar;
212 double mu, sigma, f_mu;
221 return (f(x + .5 * cfg.dx) - f(x - .5 * cfg.dx)) / cfg.dx;
224 return (g(x + .5 * cfg.dx) - g(x - .5 * cfg.dx)) / cfg.dx;
232 void rescale_integrand(
const std::vector<ad_aug> &x) {
233 TMBAD_ASSERT(x.size() + 1 == glob.
inv_index.size());
234 if (cfg.debug) Rcout <<
"rescale integrand:\n";
235 for (
size_t i = 0; i < x.size(); i++) glob.
value_inv(i) = x[i].Value();
239 for (; i < 100; i++) {
242 if (std::isfinite(f_mu) && !std::isfinite(h_mu)) {
243 cfg.dx = cfg.dx * .5;
248 mu_new = mu - g_mu / h_mu;
250 mu_new = mu + (g_mu > 0 ? cfg.dx : -cfg.dx);
251 double f_mu_new = f(mu_new);
253 Rcout <<
"mu=" << mu <<
" mu_new=" << mu_new <<
" g_mu=" << g_mu
254 <<
" h_mu=" << h_mu <<
" f_mu=" << f_mu
255 <<
" f_mu_new=" << f_mu_new <<
"\n";
257 if (f_mu_new > f_mu + cfg.ytol) {
264 sigma = 1. / sqrt(-h(mu));
265 if (!std::isfinite(sigma)) sigma = 10000;
267 Rcout <<
"==> i=" << i <<
" mu=" << mu <<
" f_mu=" << f_mu
268 <<
" sigma=" << sigma <<
"\n";
271 logIntegrate_t(
global &glob, gk_config cfg)
272 : glob(glob), mu(0), sigma(1), f_mu(0), cfg(cfg) {
273 TMBAD_ASSERT(glob.
inv_index.size() >= 1);
274 TMBAD_ASSERT(glob.
dep_index.size() == 1);
277 global::replay *p_replay;
279 Float operator()(Float u) {
281 p_replay->value_inv(k - 1) = sigma * u + mu;
282 p_replay->forward(
false,
false);
283 Float ans = exp(p_replay->value_dep(0) - f_mu);
284 if (cfg.nan2zero && ans != ans) ans = 0;
288 std::vector<ad_aug> operator()(
const std::vector<ad_aug> &x) {
289 rescale_integrand(x);
290 global::replay replay(this->glob, *
get_glob());
294 for (Index i = 0; i < k - 1; i++) replay.value_inv(i) = x[i];
296 Float ans = log(I) + log(sigma) + f_mu;
298 return std::vector<ad_aug>(1, ans);
302 template <
class ADFun>
303 struct integrate_subgraph {
305 std::vector<Index> random;
308 std::vector<Index> var_remap;
309 std::vector<bool> mark;
314 integrate_subgraph(
global &glob, std::vector<Index> random,
315 gk_config cfg = gk_config())
322 mark.resize(glob.
opstack.size(),
false);
327 global &try_integrate_variable(Index i) {
328 const std::vector<Index> &inv2op = forward_graph.
inv2op;
330 Index start_node = inv2op[i];
331 glob.subgraph_seq.resize(0);
332 glob.subgraph_seq.push_back(start_node);
333 forward_graph.
search(glob.subgraph_seq);
335 if (glob.subgraph_seq.size() == 1)
return glob;
337 bool any_marked =
false;
338 for (Index i = 0; i < glob.subgraph_seq.size(); i++) {
339 any_marked |= mark[glob.subgraph_seq[i]];
345 for (Index i = 0; i < glob.subgraph_seq.size(); i++) {
346 mark[glob.subgraph_seq[i]] =
true;
349 std::vector<Index> boundary = reverse_graph.
boundary(glob.subgraph_seq);
352 var_remap.resize(glob.
values.size());
354 Index total_boundary_vars = 0;
355 std::vector<ad_plain> boundary_vars;
356 OperatorPure *constant = glob.getOperator<global::ConstOp>();
357 for (Index i = 0; i < boundary.size(); i++) {
358 Index m = glob.
opstack[boundary[i]]->output_size();
359 for (Index j = 0; j < m; j++) {
360 Index boundary_var = glob.subgraph_ptr[boundary[i]].second + j;
361 var_remap[boundary_var] = total_boundary_vars;
362 total_boundary_vars++;
363 if (glob.
opstack[boundary[i]] != constant) {
364 ad_plain().Independent();
366 tmp.index = boundary_var;
367 boundary_vars.push_back(tmp);
369 ad_plain(glob.
values[boundary_var]);
379 logIntegrate_t<> taped_integral(new_glob, cfg);
382 std::vector<ad_aug> boundary_vars2(boundary_vars.begin(),
383 boundary_vars.end());
388 taped_integral_operator(boundary_vars)[0].Dependent();
390 taped_integral(boundary_vars2)[0].Dependent();
396 for (Index i = 0; i < random.size(); i++) {
397 try_integrate_variable(random[i]);
400 std::vector<bool> keep_node = mark;
403 keep_node.resize(glob.
opstack.size(),
true);
405 std::vector<Index> v2o = glob.
var2op();
406 for (Index i = 0; i < glob.
inv_index.size(); i++) {
407 keep_node[v2o[glob.
inv_index[i]]] =
true;
410 glob.subgraph_seq.resize(0);
411 for (Index i = 0; i < keep_node.size(); i++) {
412 if (keep_node[i]) glob.subgraph_seq.push_back(i);
437 std::vector<size_t> x;
438 std::vector<bool> mask_;
440 std::vector<size_t> bound;
466 size_t index(
size_t i);
468 std::vector<size_t> index();
470 std::vector<bool>::reference mask(
size_t i);
472 void set_mask(
const std::vector<bool> &mask);
487 size_t clique_size();
489 void subset_inplace(
const std::vector<bool> &mask);
492 bool contains(Index i);
510 void get_stride(
const clique &super, Index ind, std::vector<ad_plain> &offset,
521 std::vector<Scalar> x;
522 std::vector<Scalar> w;
525 sr_grid(Scalar a, Scalar b,
size_t n);
530 std::vector<ad_plain> logw;
531 ad_plain logw_offset();
582 std::list<clique> cliques;
583 std::vector<sr_grid> grid;
584 std::vector<Index> inv2grid;
587 std::vector<Index> random;
588 global::replay replay;
589 std::vector<bool> mark;
592 std::vector<Index> var_remap;
593 const static Index NA = -1;
594 std::vector<Index> op2inv_idx;
595 std::vector<Index> op2dep_idx;
596 std::vector<bool> terms_done;
598 std::map<size_t, std::vector<ad_aug> > cache;
616 std::vector<sr_grid> grid =
617 std::vector<sr_grid>(1,
sr_grid(-20, 20, 200)),
618 std::vector<Index> random2grid = std::vector<Index>(0),
626 void reorder_random();
628 std::vector<size_t> get_grid_bounds(std::vector<Index> inv_index);
630 std::vector<sr_grid *> get_grid(std::vector<Index> inv_index);
642 std::vector<ad_aug> tabulate(std::vector<Index> inv_index, Index dep_index);
678 void update(Index i);
737 std::vector<size_t> max_tree_depth();
740 size_t which_min(
const std::vector<T> &x) {
741 return std::min_element(x.begin(), x.end()) - x.begin();
748 size_t input_size()
const;
750 size_t output_size()
const;
757 static const bool have_input_size_output_size =
true;
767 Index input_size()
const;
768 Index output_size()
const;
773 bool parallel_operator_used_with_valid_type =
false;
774 TMBAD_ASSERT(parallel_operator_used_with_valid_type);
776 static const bool add_forward_replay_copy =
true;
779 bool parallel_operator_used_with_valid_type =
false;
780 TMBAD_ASSERT(parallel_operator_used_with_valid_type);
785 const char *op_name();
789 std::vector<Index> get_likely_expression_duplicates(
790 const global &glob, std::vector<Index> inv_remap);
803 void operator()(Index a, Index b) {
805 for (Index i = a + 1; i <= b; i++) {
806 ok &= (remap[i] - remap[i - 1] == 1);
811 for (Index i = a; i <= b; i++) {
875 global &glob, std::vector<Index> inv_remap);
879 std::vector<Position> inv_positions(
global &glob);
889 #endif // HAVE_GRAPH_TRANSFORM_HPP Automatic differentiation library designed for TMB.
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.
size_t prod_int(const std::vector< size_t > &x)
Integer product function.
global accumulation_tree_split(global glob, bool sum_=false)
Split a computational graph by it's accumulation tree.
std::vector< size_t > dim
Dimension of logsum array.
void forward(Position start=Position(0, 0, 0))
Full or partial forward sweep through the operation stack. Updates global::values.
graph forward_graph(std::vector< bool > keep_var=std::vector< bool >(0))
Construct operator graph with forward connections.
std::vector< T > invperm(const std::vector< T > &perm)
Inverse permutation.
void reorder_graph(global &glob, std::vector< Index > inv_idx)
Reorder computational graph such that selected independent variables come last.
operation_stack opstack
Operation stack.
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.
bool keep_all_inv
Keep all independent variables for each thread?
void subgraph_cache_ptr() const
Cache array pointers required by all subgraph routines.
global * get_glob()
Get pointer to current global AD context (or NULL if no context is active).
std::vector< Index > boundary(const std::vector< Index > &subgraph)
Find boundary of subgraph.
Access input/output values and derivatives during a reverse pass. Write access granted for the input ...
std::vector< Scalar > values
Contiguous workspace for taped variables (same length as global::derivs)
std::vector< std::vector< Index > > node_split
Complete subgraphs by thread.
std::vector< global > vglob
Computational graphs by thread.
Access input/output values during a forward pass. Write access granted for the output value only...
Sequential reduction algorithm.
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.
Enable weak comparison operators of an ad type.
std::vector< Index > indices
Variable indices of this clique.
Configuration of print method.
std::vector< Index > inv2op
Used to lookup operator (node) of an independent variable.
The abstract operator for the operation stack global::opstack
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.
std::vector< std::vector< Index > > dep_idx
Indices to identify dependent variable subset calculated by thread.
std::vector< Index > inv_index
Pointers into global::values determining independent variables.
std::vector< bool > reverse_boundary(global &glob, const std::vector< bool > &vars)
Find boundary without using the graph.
std::vector< Index > get_accumulation_tree(global &glob, bool boundary=false)
Get node indices of the accumulation tree or its boundary.
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
std::vector< I > which(const std::vector< bool > &x)
Convert logical vector to index vector.
Integrand::Scalar integrate(Integrand f, typename Integrand::Scalar a=-INFINITY, typename Integrand::Scalar b=INFINITY, control c=control())
Integrate function over finite or infinite interval.
std::vector< size_t > match(const std::vector< T > &x, const std::vector< T > &y)
Match x vector in y vector.
std::vector< ad_aug > logsum
Log-probabilites of this clique.
std::vector< Index > remap_identical_sub_expressions(global &glob, std::vector< Index > inv_remap)
Remap identical sub-expressions.
void search(std::vector< Index > &start, bool sort_input=true, bool sort_output=true)
Find sub graph.
Struct defining the main AD context.
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.
Read the current tape's state and restore it on request.
Utilility class for sequential_reduction.
std::vector< std::vector< Index > > inv_idx
Indices to identify independent variable subset used by thread.
std::vector< std::vector< Index > > dep_idx
Result: Pointers into original dependent variables.
Forbid remappings if not consecutive.
std::vector< size_t > order(std::vector< T > x)
Get permutation that sorts a vector.
Operator auto-completion.
Operator that requires dynamic allocation. Compile time known input/output size.
bool all_allow_remap(const global &glob)
Test if all operators in the stack allow input remapping.
Scalar & value_inv(Index i)
Reference to i'th input value (parameter)
std::vector< global > vglob
Result: Vector of computational graphs.
Utilility class for sequential_reduction.
std::vector< Index > find_op_by_name(global &glob, const char *name)
Find nodes by name.
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?
Operator graph in compressed row storage.
Adaptive derivative table used by AtomOp
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.
std::vector< bool > lmatch(const std::vector< T > &x, const std::vector< T > &y)
Match x vector in y vector.
std::vector< Index > dep_index
Pointers into global::values determining dependent variables.
Utilility class for sequential_reduction.