\(\newcommand{\W}[1]{ \; #1 \; }\) \(\newcommand{\R}[1]{ {\rm #1} }\) \(\newcommand{\B}[1]{ {\bf #1} }\) \(\newcommand{\D}[2]{ \frac{\partial #1}{\partial #2} }\) \(\newcommand{\DD}[3]{ \frac{\partial^2 #1}{\partial #2 \partial #3} }\) \(\newcommand{\Dpow}[2]{ \frac{\partial^{#1}}{\partial {#2}^{#1}} }\) \(\newcommand{\dpow}[2]{ \frac{ {\rm d}^{#1}}{{\rm d}\, {#2}^{#1}} }\)
atomic_four_vector¶
View page sourceAtomic Vector Element-wise Operators: Example and Test¶
Syntax¶
atomic_vector_op
vec_op ( name )op¶
The value op has the following possible values:
// atomic_vector::op_enum_t
typedef enum {
add_enum,
div_enum,
mul_enum,
neg_enum,
sub_enum,
number_op_enum
} op_enum_t;
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 = u op v
where op , u and v are defined below.
atomic_four¶
This example demonstrates all the callbacks for an atomic_four function.
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^k
copy_mat_to_vec(m, q, k, atu, au);
// av = v^k
copy_mat_to_vec(m, q, k, atv, av);
// ay = au + av
(*this)(add_enum, ax, ay); // atomic vector add
// y^k = ay
copy_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.
Contents¶
Name |
Title |
---|---|
atomic_four_vector_add.cpp |
|
atomic_four_vector_div.cpp |
|
atomic_four_vector_hes_sparsity.cpp |
|
atomic_four_vector_jac_sparsity.cpp |
|
atomic_four_vector_mul.cpp |
|
atomic_four_vector_neg.cpp |
|
atomic_four_vector_rev_depend.cpp |
|
atomic_four_vector_sub.cpp |
|
atomic_four_vector_implement |