Purpose
This atomic function class can be used as a general purpose utility.
It is unclear how much benefit there is do doing so.
This is because the number of operations internal to an element-wise
atomic function is not much more than the work required to pass the
arguments to the atomic function.
Vector Operations
This atomic function unary operations
y = op(u)
and binary operations
y = uopv
where
op
,
u
and
v
are defined below.
base2ad
It include examples for how one can
define
AD<Base>
atomic operations using atomic operators.
This avoids expanding the atomic operator to an operator for each element
when recording derivative calculations.
For example, notice the difference between forward_add
for the double and the AD<double> cases
(note that copying an AD variable does not create a new variable):
template <class Base>
void atomic_vector<Base>::forward_add(
size_t m,
size_t p,
size_t q,
const CppAD::vector<Base>& tx,
CppAD::vector<Base>& ty)
{
for(size_t k = p; k < q; ++k)
{ for(size_t i = 0; i < m; ++i)
{ size_t u_index = i * q + k;
size_t v_index = (m + i) * q + k;
size_t y_index = i * q + k;
// y_i^k = u_i^k + v_i^k
ty[y_index] = tx[u_index] + tx[v_index];
}
}
}
template <class Base>
void atomic_vector<Base>::forward_add(
size_t m,
size_t p,
size_t q,
const CppAD::vector< CppAD::AD<Base> >& atx,
CppAD::vector< CppAD::AD<Base> >& aty)
{ size_t n = 2 * m;
assert( atx.size() == n * q );
assert( aty.size() == m * q );
//// atu, atv
ad_const_iterator atu = atx.begin();
ad_const_iterator atv = atu + ad_difference_type(m * q);
//// ax
ad_vector ax(n);
ad_iterator au = ax.begin();
ad_iterator av = au + ad_difference_type(m);
//// ay
ad_vector ay(m);
//for(size_t k = p; k < q; ++k)
{ // au = u^kcopy_mat_to_vec(m, q, k, atu, au);
// av = v^kcopy_mat_to_vec(m, q, k, atv, av);
// ay = au + av
(*this)(add_enum, ax, ay); // atomic vector add// y^k = aycopy_vec_to_mat(m, q, k, ay.begin(), aty.begin() );
}
}
x
We use
x
to denote the argument to the atomic function.
The length of
x
is denoted by
n
.
m
This is the length of the vectors in the operations.
In the case of unary (binary) operators
%m% = %n% (
m = n / 2
).
u
We use
u
to denote the following sub-vector of
x
:
u = ( x[1] , ... , x[m] )
v
For binary operators,
we use
v
to denote the following sub-vector of
x
:
v = ( x[m + 1] , ... , x[2 * m] )
y
We use
y
to denote the atomic function return value.
The length of
y
is equal to
m
.
AD<double>
During AD<double> operations, copying variables
from one vector to another does not add any operations to the
resulting tape.