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.