1 #ifndef STAN_MATH_REV_MAT_FUNCTOR_ADJ_JAC_APPLY_HPP
2 #define STAN_MATH_REV_MAT_FUNCTOR_ADJ_JAC_APPLY_HPP
3
4 #include <stan/math/prim/scal/meta/scalar_type.hpp>
5 #include <stan/math/prim/mat/fun/Eigen.hpp>
6 #include <stan/math/prim/mat/fun/value_of.hpp>
7 #include <stan/math/rev/scal/fun/value_of.hpp>
8 #include <stan/math/rev/scal/meta/is_var.hpp>
9 #include <limits>
10 #include <tuple>
11 #include <vector>
12
13 namespace stan {
14 namespace math {
15
16 namespace internal {
17 /**
18 * Invoke the functor f with arguments given in t and indexed in the index
19 * sequence I
20 *
21 * @tparam F Type of functor
22 * @tparam Tuple Type of tuple containing arguments
23 * @tparam I Index sequence going from 0 to std::tuple_size<T>::value - 1
24 * inclusive
25 * @param f functor callable
26 * @param t tuple of arguments
27 * @param i placeholder variable for index sequence
28 */
29 template <class F, class Tuple, std::size_t... I>
apply_impl(const F & f,const Tuple & t,std::index_sequence<I...> i)30 constexpr auto apply_impl(const F& f, const Tuple& t,
31 std::index_sequence<I...> i) {
32 return f(std::get<I>(t)...);
33 }
34
35 /**
36 * Call the functor f with the tuple of arguments t, like:
37 *
38 * f(std::get<0>(t), std::get<1>(t), ...)
39 *
40 * TODO: replace this with implementation in C++ std when C++17 is available
41 *
42 * @tparam F Type of functor
43 * @tparam Tuple Type of tuple containing arguments
44 * @param f functor callable
45 * @param t tuple of arguments
46 */
47 template <class F, class Tuple>
apply(const F & f,const Tuple & t)48 constexpr auto apply(const F& f, const Tuple& t) {
49 return apply_impl(f, t, std::make_index_sequence<std::tuple_size<Tuple>{}>{});
50 }
51
52 /**
53 * Store the adjoint in y_vi[0] in y_adj
54 *
55 * @tparam size dimensionality of M
56 * @param[in] y_vi pointer to pointer to vari
57 * @param[in] M
58 * @param[out] y_adj reference to variable where adjoint is to be stored
59 */
60 template <size_t size>
build_y_adj(vari ** y_vi,const std::array<int,size> & M,double & y_adj)61 void build_y_adj(vari** y_vi, const std::array<int, size>& M, double& y_adj) {
62 y_adj = y_vi[0]->adj_;
63 }
64
65 /**
66 * Store the adjoints from y_vi in y_adj
67 *
68 * @tparam size dimensionality of M
69 * @param[in] y_vi pointer to pointers to varis
70 * @param[in] M shape of y_adj
71 * @param[out] y_adj reference to std::vector where adjoints are to be stored
72 */
73 template <size_t size>
build_y_adj(vari ** y_vi,const std::array<int,size> & M,std::vector<double> & y_adj)74 void build_y_adj(vari** y_vi, const std::array<int, size>& M,
75 std::vector<double>& y_adj) {
76 y_adj.resize(M[0]);
77 for (size_t m = 0; m < y_adj.size(); ++m)
78 y_adj[m] = y_vi[m]->adj_;
79 }
80
81 /**
82 * Store the adjoints from y_vi in y_adj
83 *
84 * @tparam size dimensionality of M
85 * @param[in] y_vi pointer to pointers to varis
86 * @param[in] M shape of y_adj
87 * @param[out] y_adj reference to Eigen::Matrix where adjoints are to be stored
88 */
89 template <size_t size, int R, int C>
build_y_adj(vari ** y_vi,const std::array<int,size> & M,Eigen::Matrix<double,R,C> & y_adj)90 void build_y_adj(vari** y_vi, const std::array<int, size>& M,
91 Eigen::Matrix<double, R, C>& y_adj) {
92 y_adj.resize(M[0], M[1]);
93 for (int m = 0; m < y_adj.size(); ++m)
94 y_adj(m) = y_vi[m]->adj_;
95 }
96
97 /**
98 * Compute the dimensionality of the given template argument. The
99 * definition of dimensionality is deferred to specializations. By
100 * default don't have a value (fail to compile)
101 */
102 template <typename T>
103 struct compute_dims {};
104
105 /**
106 * Compute the dimensionality of the given template argument. Double
107 * types hav dimensionality zero.
108 */
109 template <>
110 struct compute_dims<double> {
111 static constexpr size_t value = 0;
112 };
113
114 /**
115 * Compute the dimensionality of the given template argument.
116 * std::vector has dimension 1
117 */
118 template <typename T>
119 struct compute_dims<std::vector<T>> {
120 static constexpr size_t value = 1;
121 };
122
123 /**
124 * compute the dimensionality of the given template argument.
125 * Eigen::Matrix types all have dimension two
126 */
127 template <typename T, int R, int C>
128 struct compute_dims<Eigen::Matrix<T, R, C>> {
129 static constexpr size_t value = 2;
130 };
131 } // namespace internal
132
133 /**
134 * adj_jac_vari interfaces a user supplied functor with the reverse mode
135 * autodiff. It allows someone to implement functions with custom reverse mode
136 * autodiff without having to deal with autodiff types.
137 *
138 * The requirements on the functor F are described in the documentation for
139 * adj_jac_apply
140 *
141 * Targs (the input argument types) can be any mix of double, var, or
142 * Eigen::Matrices with double or var scalar components
143 *
144 * @tparam F class of functor
145 * @tparam Targs Types of arguments
146 */
147 template <typename F, typename... Targs>
148 struct adj_jac_vari : public vari {
149 std::array<bool, sizeof...(Targs)> is_var_;
150 using FReturnType
151 = std::result_of_t<F(decltype(is_var_), decltype(value_of(Targs()))...)>;
152
153 F f_;
154 std::array<int, sizeof...(Targs)> offsets_;
155 vari** x_vis_;
156 std::array<int, internal::compute_dims<FReturnType>::value> M_;
157 vari** y_vi_;
158
159 /**
160 * count_memory returns count (the first argument) + the number of varis used
161 * in the second argument + the number of arguments used to encode the
162 * variadic tail args.
163 *
164 * The adj_jac_vari constructor uses this to figure out how much space to
165 * allocate in x_vis_.
166 *
167 * The array offsets_ is populated with values to indicate where in x_vis_ the
168 * vari pointers for each argument will be stored.
169 *
170 * Each of the arguments can be an Eigen::Matrix with var or double scalar
171 * types, a std::vector with var, double, or int scalar types, or a var, a
172 * double, or an int.
173 *
174 * @tparam R Eigen Matrix row type
175 * @tparam C Eigen Matrix column type
176 * @tparam Pargs Types of rest of arguments
177 * @param count rolling count of number of varis that must be allocated
178 * @param x next argument to have its varis counted
179 * @param args the rest of the arguments (that will be iterated through
180 * recursively)
181 */
182 template <int R, int C, typename... Pargs>
count_memorystan::math::adj_jac_vari183 size_t count_memory(size_t count, const Eigen::Matrix<var, R, C>& x,
184 const Pargs&... args) {
185 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
186 offsets_[t] = count;
187 count += x.size();
188 return count_memory(count, args...);
189 }
190
191 template <int R, int C, typename... Pargs>
count_memorystan::math::adj_jac_vari192 size_t count_memory(size_t count, const Eigen::Matrix<double, R, C>& x,
193 const Pargs&... args) {
194 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
195 offsets_[t] = count;
196 return count_memory(count, args...);
197 }
198
199 template <typename... Pargs>
count_memorystan::math::adj_jac_vari200 size_t count_memory(size_t count, const std::vector<var>& x,
201 const Pargs&... args) {
202 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
203 offsets_[t] = count;
204 count += x.size();
205 return count_memory(count, args...);
206 }
207
208 template <typename... Pargs>
count_memorystan::math::adj_jac_vari209 size_t count_memory(size_t count, const std::vector<double>& x,
210 const Pargs&... args) {
211 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
212 offsets_[t] = count;
213 return count_memory(count, args...);
214 }
215
216 template <typename... Pargs>
count_memorystan::math::adj_jac_vari217 size_t count_memory(size_t count, const std::vector<int>& x,
218 const Pargs&... args) {
219 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
220 offsets_[t] = count;
221 return count_memory(count, args...);
222 }
223
224 template <typename... Pargs>
count_memorystan::math::adj_jac_vari225 size_t count_memory(size_t count, const var& x, const Pargs&... args) {
226 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
227 offsets_[t] = count;
228 count += 1;
229 return count_memory(count, args...);
230 }
231
232 template <typename... Pargs>
count_memorystan::math::adj_jac_vari233 size_t count_memory(size_t count, const double& x, const Pargs&... args) {
234 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
235 offsets_[t] = count;
236 return count_memory(count, args...);
237 }
238
239 template <typename... Pargs>
count_memorystan::math::adj_jac_vari240 size_t count_memory(size_t count, const int& x, const Pargs&... args) {
241 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
242 offsets_[t] = count;
243 return count_memory(count, args...);
244 }
245
count_memorystan::math::adj_jac_vari246 size_t count_memory(size_t count) { return count; }
247
248 /**
249 * prepare_x_vis populates x_vis_ with the varis from each of its
250 * input arguments. The vari pointers for argument n are copied into x_vis_ at
251 * the index starting at offsets_[n]. For Eigen::Matrix types, this copying is
252 * done in with column major ordering.
253 *
254 * Each of the arguments can be an Eigen::Matrix with var or double scalar
255 * types, a std::vector with var, double, or int scalar types, or a var, a
256 * double, or an int.
257 *
258 * @tparam R Eigen Matrix row type
259 * @tparam C Eigen Matrix column type
260 * @tparam Pargs Types of the rest of the arguments to be processed
261 * @param x next argument to have its vari pointers copied if necessary
262 * @param args the rest of the arguments (that will be iterated through
263 * recursively)
264 */
265 template <int R, int C, typename... Pargs>
prepare_x_visstan::math::adj_jac_vari266 void prepare_x_vis(const Eigen::Matrix<var, R, C>& x, const Pargs&... args) {
267 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
268 for (int i = 0; i < x.size(); ++i) {
269 x_vis_[offsets_[t] + i] = x(i).vi_;
270 }
271 prepare_x_vis(args...);
272 }
273
274 template <int R, int C, typename... Pargs>
prepare_x_visstan::math::adj_jac_vari275 void prepare_x_vis(const Eigen::Matrix<double, R, C>& x,
276 const Pargs&... args) {
277 prepare_x_vis(args...);
278 }
279
280 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari281 void prepare_x_vis(const std::vector<var>& x, const Pargs&... args) {
282 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
283 for (size_t i = 0; i < x.size(); ++i) {
284 x_vis_[offsets_[t] + i] = x[i].vi_;
285 }
286 prepare_x_vis(args...);
287 }
288
289 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari290 void prepare_x_vis(const std::vector<double>& x, const Pargs&... args) {
291 prepare_x_vis(args...);
292 }
293
294 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari295 void prepare_x_vis(const std::vector<int>& x, const Pargs&... args) {
296 prepare_x_vis(args...);
297 }
298
299 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari300 void prepare_x_vis(const var& x, const Pargs&... args) {
301 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
302 x_vis_[offsets_[t]] = x.vi_;
303 prepare_x_vis(args...);
304 }
305
306 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari307 void prepare_x_vis(const double& x, const Pargs&... args) {
308 prepare_x_vis(args...);
309 }
310
311 template <typename... Pargs>
prepare_x_visstan::math::adj_jac_vari312 void prepare_x_vis(const int& x, const Pargs&... args) {
313 prepare_x_vis(args...);
314 }
315
316 /**
317 * Initializes is_var_ with true if the scalar type in each argument
318 * is a var (and false if not)
319 */
adj_jac_varistan::math::adj_jac_vari320 adj_jac_vari()
321 : vari(std::numeric_limits<double>::quiet_NaN()), // The val_ in this
322 // vari is unused
323 is_var_({{is_var<typename scalar_type<Targs>::type>::value...}}),
324 x_vis_(NULL),
325 y_vi_(NULL) {}
326
327 /**
328 * Return a var with a new vari holding the given value
329 *
330 * @param val_y output of F::operator()
331 * @return var
332 */
build_return_varis_and_varsstan::math::adj_jac_vari333 var build_return_varis_and_vars(const double& val_y) {
334 y_vi_ = ChainableStack::instance().memalloc_.alloc_array<vari*>(1);
335 y_vi_[0] = new vari(val_y, false);
336
337 return y_vi_[0];
338 }
339
340 /**
341 * Return a std::vector of vars created from newly allocated varis initialized
342 * with the values of val_y
343 *
344 * @param val_y output of F::operator()
345 * @return std::vector of vars
346 */
build_return_varis_and_varsstan::math::adj_jac_vari347 std::vector<var> build_return_varis_and_vars(
348 const std::vector<double>& val_y) {
349 M_[0] = val_y.size();
350 std::vector<var> var_y(M_[0]);
351
352 y_vi_
353 = ChainableStack::instance().memalloc_.alloc_array<vari*>(var_y.size());
354 for (size_t m = 0; m < var_y.size(); ++m) {
355 y_vi_[m] = new vari(val_y[m], false);
356 var_y[m] = y_vi_[m];
357 }
358
359 return var_y;
360 }
361
362 /**
363 * Return an Eigen::Matrix of vars created from newly allocated varis
364 * initialized with the values of val_y. The shape of the new matrix comes
365 * from M_
366 *
367 * @tparam R Eigen row type
368 * @tparam C Eigen column type
369 * @param val_y output of F::operator()
370 * @return Eigen::Matrix of vars
371 */
372 template <int R, int C>
build_return_varis_and_varsstan::math::adj_jac_vari373 Eigen::Matrix<var, R, C> build_return_varis_and_vars(
374 const Eigen::Matrix<double, R, C>& val_y) {
375 M_[0] = val_y.rows();
376 M_[1] = val_y.cols();
377 Eigen::Matrix<var, R, C> var_y(M_[0], M_[1]);
378
379 y_vi_
380 = ChainableStack::instance().memalloc_.alloc_array<vari*>(var_y.size());
381 for (int m = 0; m < var_y.size(); ++m) {
382 y_vi_[m] = new vari(val_y(m), false);
383 var_y(m) = y_vi_[m];
384 }
385
386 return var_y;
387 }
388
prepare_x_visstan::math::adj_jac_vari389 void prepare_x_vis() {}
390
391 /**
392 * The adj_jac_vari functor
393 * 1. Initializes an instance of the user defined functor F
394 * 2. Calls operator() on the F instance with the double values from the
395 * input args
396 * 3. Saves copies of the varis pointed to by the input vars for subsequent
397 * calls to chain
398 * 4. Calls build_return_varis_and_vars to construct the appropriate output
399 * data structure of vars
400 *
401 * Each of the arguments can be an Eigen::Matrix with var or double scalar
402 * types, a std::vector with var, double, or int scalar types, or a var, a
403 * double, or an int.
404 *
405 * @param args Input arguments
406 * @return Output of f_ as vars
407 */
operator ()stan::math::adj_jac_vari408 auto operator()(const Targs&... args) {
409 x_vis_ = ChainableStack::instance().memalloc_.alloc_array<vari*>(
410 count_memory(0, args...));
411
412 prepare_x_vis(args...);
413
414 return build_return_varis_and_vars(f_(is_var_, value_of(args)...));
415 }
416
417 /**
418 * Accumulate, if necessary, the values of y_adj_jac into the
419 * adjoints of the varis pointed to by the appropriate elements
420 * of x_vis_. Recursively calls accumulate_adjoints on the rest of the
421 * arguments.
422 *
423 * @tparam R Eigen Matrix row type
424 * @tparam C Eigen Matrix column type
425 * @tparam Pargs Types of the rest of adjoints to accumulate
426 * @param y_adj_jac set of values to be accumulated in adjoints
427 * @param args the rest of the arguments (that will be iterated through
428 * recursively)
429 */
430 template <int R, int C, typename... Pargs>
accumulate_adjointsstan::math::adj_jac_vari431 void accumulate_adjoints(const Eigen::Matrix<double, R, C>& y_adj_jac,
432 const Pargs&... args) {
433 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
434 if (is_var_[t]) {
435 for (int n = 0; n < y_adj_jac.size(); ++n) {
436 x_vis_[offsets_[t] + n]->adj_ += y_adj_jac(n);
437 }
438 }
439
440 accumulate_adjoints(args...);
441 }
442
443 /**
444 * Accumulate, if necessary, the values of y_adj_jac into the
445 * adjoints of the varis pointed to by the appropriate elements
446 * of x_vis_. Recursively calls accumulate_adjoints on the rest of the
447 * arguments.
448 *
449 * @tparam Pargs Types of the rest of adjoints to accumulate
450 * @param y_adj_jac set of values to be accumulated in adjoints
451 * @param args the rest of the arguments (that will be iterated through
452 * recursively)
453 */
454 template <typename... Pargs>
accumulate_adjointsstan::math::adj_jac_vari455 void accumulate_adjoints(const std::vector<double>& y_adj_jac,
456 const Pargs&... args) {
457 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
458 if (is_var_[t]) {
459 for (size_t n = 0; n < y_adj_jac.size(); ++n)
460 x_vis_[offsets_[t] + n]->adj_ += y_adj_jac[n];
461 }
462
463 accumulate_adjoints(args...);
464 }
465
466 /**
467 * Recursively call accumulate_adjoints with args. There are no adjoints to
468 * accumulate for std::vector<int> arguments.
469 *
470 * @tparam Pargs Types of the rest of adjoints to accumulate
471 * @param y_adj_jac ignored
472 * @param args the rest of the arguments (that will be iterated through
473 * recursively)
474 */
475 template <typename... Pargs>
accumulate_adjointsstan::math::adj_jac_vari476 void accumulate_adjoints(const std::vector<int>& y_adj_jac,
477 const Pargs&... args) {
478 accumulate_adjoints(args...);
479 }
480
481 /**
482 * Accumulate, if necessary, the value of y_adj_jac into the
483 * adjoint of the vari pointed to by the appropriate element
484 * of x_vis_. Recursively calls accumulate_adjoints on the rest of the
485 * arguments.
486 *
487 * @tparam Pargs Types of the rest of adjoints to accumulate
488 * @param y_adj_jac next set of adjoints to be accumulated
489 * @param args the rest of the arguments (that will be iterated through
490 * recursively)
491 */
492 template <typename... Pargs>
accumulate_adjointsstan::math::adj_jac_vari493 void accumulate_adjoints(const double& y_adj_jac, const Pargs&... args) {
494 static constexpr int t = sizeof...(Targs) - sizeof...(Pargs) - 1;
495 if (is_var_[t]) {
496 x_vis_[offsets_[t]]->adj_ += y_adj_jac;
497 }
498
499 accumulate_adjoints(args...);
500 }
501
502 /**
503 * Recursively call accumulate_adjoints with args. There are no adjoints to
504 * accumulate for int arguments.
505 *
506 * @tparam Pargs Types of the rest of adjoints to accumulate
507 * @param y_adj_jac ignored
508 * @param args the rest of the arguments (that will be iterated through
509 * recursively)
510 */
511 template <typename... Pargs>
accumulate_adjointsstan::math::adj_jac_vari512 void accumulate_adjoints(const int& y_adj_jac, const Pargs&... args) {
513 accumulate_adjoints(args...);
514 }
515
accumulate_adjointsstan::math::adj_jac_vari516 void accumulate_adjoints() {}
517
518 /**
519 * Propagate the adjoints at the output varis (y_vi_) back to the input
520 * varis (x_vis_) by:
521 * 1. packing the adjoints in an appropriate container using build_y_adj
522 * 2. using the multiply_adjoint_jacobian function of the user defined functor
523 * to compute what the adjoints on x_vis_ should be
524 * 3. accumulating the adjoints into the varis pointed to by elements of
525 * x_vis_ using accumulate_adjoints
526 *
527 * This operation may be called multiple times during the life of the vari
528 */
chainstan::math::adj_jac_vari529 void chain() {
530 FReturnType y_adj;
531
532 internal::build_y_adj(y_vi_, M_, y_adj);
533 auto y_adj_jacs = f_.multiply_adjoint_jacobian(is_var_, y_adj);
534
535 internal::apply(
536 [this](auto&&... args) { this->accumulate_adjoints(args...); },
537 y_adj_jacs);
538 }
539 };
540
541 /**
542 * Return the result of applying the function defined by a nullary construction
543 * of F to the specified input argument
544 *
545 * adj_jac_apply makes it possible to write efficient reverse-mode
546 * autodiff code without ever touching Stan's autodiff internals
547 *
548 * Mathematically, to use a function in reverse mode autodiff, you need to be
549 * able to evaluate the function (y = f(x)) and multiply the Jacobian of that
550 * function (df(x)/dx) by a vector.
551 *
552 * As an example, pretend there exists some large, complicated function, L(x1,
553 * x2), which contains our smaller function f(x1, x2). The goal of autodiff is
554 * to compute the partials dL/dx1 and dL/dx2. If we break the large function
555 * into pieces:
556 *
557 * y = f(x1, x2)
558 * L = g(y)
559 *
560 * If we were given dL/dy we could compute dL/dx1 by the product dL/dy * dy/dx1
561 * or dL/dx2 by the product dL/dy * dy/dx2
562 *
563 * Because y = f(x1, x2), dy/dx1 is just df(x1, x2)/dx1, the Jacobian of the
564 * function we're trying to define with x2 held fixed. A similar thing happens
565 * for dy/dx2. In vector form,
566 *
567 * dL/dx1 = (dL/dy)' * df(x1, x2)/dx1 and
568 * dL/dx2 = (dL/dy)' * df(x1, x2)/dx2
569 *
570 * So implementing f(x1, x2) and the products above are all that is required
571 * mathematically to implement reverse-mode autodiff for a function.
572 *
573 * adj_jac_apply takes as a template argument a functor F that supplies the
574 * non-static member functions (leaving exact template arguments off):
575 *
576 * (required) Eigen::VectorXd operator()(const std::array<bool, size>&
577 * needs_adj, const T1& x1..., const T2& x2, ...)
578 *
579 * where there can be any number of input arguments x1, x2, ... and T1, T2, ...
580 * can be either doubles or any Eigen::Matrix type with double scalar values.
581 * needs_adj is an array of size equal to the number of input arguments
582 * indicating whether or not the adjoint^T Jacobian product must be computed for
583 * each input argument. This argument is passed to operator() so that any
584 * unnecessary preparatory calculations for multiply_adjoint_jacobian can be
585 * avoided if possible.
586 *
587 * (required) std::tuple<T1, T2, ...> multiply_adjoint_jacobian(const
588 * std::array<bool, size>& needs_adj, const Eigen::VectorXd& adj)
589 *
590 * where T1, T2, etc. are the same types as in operator(), needs_adj is the same
591 * as in operator(), and adj is the vector dL/dy.
592 *
593 * operator() is responsible for computing f(x) and multiply_adjoint_jacobian is
594 * responsible for computing the necessary adjoint transpose Jacobian products
595 * (which frequently does not require the calculation of the full Jacobian).
596 *
597 * operator() will be called before multiply_adjoint_jacobian is called, and is
598 * only called once in the lifetime of the functor multiply_adjoint_jacobian is
599 * called after operator() and may be called multiple times for any single
600 * functor
601 *
602 * The functor supplied to adj_jac_apply must be careful to allocate any
603 * variables it defines in the autodiff arena because its destructor will
604 * never be called and memory will leak if allocated anywhere else.
605 *
606 * Targs (the input argument types) can be any mix of doubles, vars, ints,
607 * std::vectors with double, var, or int scalar components, or
608 * Eigen::Matrix s of any shape with var or double scalar components
609 *
610 * @tparam F functor to be connected to the autodiff stack
611 * @tparam Targs types of arguments to pass to functor
612 * @param args input to the functor
613 * @return the result of the specified operation wrapped up in vars
614 */
615 template <typename F, typename... Targs>
adj_jac_apply(const Targs &...args)616 auto adj_jac_apply(const Targs&... args) {
617 auto vi = new adj_jac_vari<F, Targs...>();
618
619 return (*vi)(args...);
620 }
621
622 } // namespace math
623 } // namespace stan
624 #endif
625