|
Prev
| Next
|
|
|
|
|
|
atomic_four_vector_mul_op.hpp |
|
@(@\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}} }@)@This is cppad-20221105 documentation. Here is a link to its
current documentation
.
Atomic Vector Multiply Operator: Example Implementation
Forward Mode
see theory for forward mode
multiplication
.
Reverse Mode
see theory for reverse mode
multiplication
.
Example
The file atomic_four_vector_mul.cpp
contains an example
and test for this operator.
Source
# include <cppad/example/atomic_four/vector/vector.hpp>
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
// --------------------------------------------------------------------------
// forward_mul
template <class Base>
void atomic_vector<Base>::forward_mul(
size_t m,
size_t p,
size_t q,
const CppAD::vector<Base>& tx,
CppAD::vector<Base>& ty)
{
for(size_t i = 0; i < m; ++i)
{ for(size_t k = p; k < q; ++k)
{ size_t y_index = i * q + k;
// y^k = 0
ty[y_index] = 0.0;
for(size_t d = 0; d <= k; d++)
{ size_t u_index = i * q + (k-d);
size_t v_index = (m + i) * q + d;
// y^k += u^{k-d} * v^d
ty[y_index] += tx[u_index] * tx[v_index];
}
}
}
}
template <class Base>
void atomic_vector<Base>::forward_mul(
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_mul
ad_vector ax_mul(n);
ad_iterator au_mul = ax_mul.begin();
ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
//
// ax_add
ad_vector ax_add(n);
ad_iterator au_add = ax_add.begin();
ad_iterator av_add = ax_add.begin() + ad_difference_type(m);
//
// ay
ad_vector ay(m);
//
for(size_t k = p; k < q; ++k)
{ // ay = 0
for(size_t i = 0; i < m; ++i)
ay[i] = 0.0;
for(size_t d = 0; d <= k; d++)
{ // u_add = ay
for(size_t i = 0; i < m; ++i)
au_add[i] = ay[i];
//
// au_mul = u^{k-d}
copy_mat_to_vec(m, q, k-d, atu, au_mul);
//
// av_mul = v^d
copy_mat_to_vec(m, q, d, atv, av_mul);
//
// ay = au_mul * av_mul
(*this)(mul_enum, ax_mul, ay); // atomic vector multiply
//
// v_add = ay
for(size_t i = 0; i < m; ++i)
av_add[i] = ay[i];
//
// ay = u_add + v_add
(*this)(add_enum, ax_add, ay); // atomic vector add
}
// y^k = ay
copy_vec_to_mat(m, q, k, ay.begin(), aty.begin());
}
}
// --------------------------------------------------------------------------
// reverse_mul
template <class Base>
void atomic_vector<Base>::reverse_mul(
size_t m,
size_t q,
const CppAD::vector<Base>& tx,
const CppAD::vector<Base>& ty,
CppAD::vector<Base>& px,
const CppAD::vector<Base>& py)
{ size_t n = 2 * m;
assert( tx.size() == n * q );
assert( ty.size() == m * q );
assert( px.size() == n * q );
assert( py.size() == m * q );
//
// px
for(size_t j = 0; j < n; ++j)
{ for(size_t k = 0; k < q; ++k)
px[j * q + k] = 0.0;
}
//
// px
for(size_t i = 0; i < m; ++i)
{ // k
size_t k = q;
while(k)
{ --k;
//
// y_index
size_t y_index = i * q + k;
//
// px
for(size_t d = 0; d <= k; ++d)
{ size_t u_index = i * q + (k-d);
size_t v_index = (m + i) * q + d;
//
// must use azmul becasue py[y_index] = 0 may mean that this
// component of the function was not selected.
px[u_index] += CppAD::azmul( py[y_index] , tx[v_index] );
px[v_index] += CppAD::azmul( py[y_index] , tx[u_index] );
}
}
}
}
template <class Base>
void atomic_vector<Base>::reverse_mul(
size_t m,
size_t q,
const CppAD::vector< CppAD::AD<Base> >& atx,
const CppAD::vector< CppAD::AD<Base> >& aty,
CppAD::vector< CppAD::AD<Base> >& apx,
const CppAD::vector< CppAD::AD<Base> >& apy)
{ size_t n = 2 * m;
assert( atx.size() == n * q );
assert( aty.size() == m * q );
assert( apx.size() == n * q );
assert( apy.size() == m * q );
//
// atu, atv, apu, apv
ad_const_iterator atu = atx.begin();
ad_const_iterator atv = atu + ad_difference_type(m * q);
ad_iterator apu = apx.begin();
ad_iterator apv = apu + ad_difference_type(m * q);
//
// ax_mul
// need azmul_op but it is not yet available
ad_vector ax_mul(n);
ad_iterator au_mul = ax_mul.begin();
ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
//
// ax_add
ad_vector ax_add(n);
ad_iterator au_add = ax_add.begin();
ad_iterator av_add = ax_add.begin() + ad_difference_type(m);
//
// ay
ad_vector ay(m);
//
// px
// assigning to the value zero does not create operators on the tape
for(size_t j = 0; j < n; ++j)
{ for(size_t k = 0; k < q; ++k)
apx[j * q + k] = 0.0;
}
//
// k
size_t k = q;
while(k)
{ --k;
//
// au_mul = apy^k
copy_mat_to_vec(m, q, k, apy.begin(), au_mul);
//
// d
for(size_t d = 0; d <=k; ++d)
{ // -------------------------------------------------------------
// reverse:
// px[v_index] += CppAD::azmul( py[y_index] , tx[u_index] );
// -------------------------------------------------------------
// av_mul = atu^{k-d}
copy_mat_to_vec(m, q, k-d, atu, av_mul);
//
// ay = au_mul * av_mul
(*this)(mul_enum, ax_mul, ay);
//
// au_add = ay
for(size_t i = 0; i < m; ++i)
au_add[i] = ay[i];
//
// av_add = apv^d
copy_mat_to_vec(m, q, d, apv, av_add);
//
// ay = au_add + av_add
(*this)(add_enum, ax_add, ay);
//
// apv^d = ay
copy_vec_to_mat(m, q, d, ay.begin(), apv);
// -------------------------------------------------------------
// reverse:
// px[u_index] += CppAD::azmul( py[y_index] , tx[v_index] );
// -------------------------------------------------------------
// av_mul = atv^{k-d}
copy_mat_to_vec(m, q, k-d, atv, av_mul);
//
// ay = au_mul * av_mul
(*this)(mul_enum, ax_mul, ay);
//
// au_add = ay
for(size_t i = 0; i < m; ++i)
au_add[i] = ay[i];
//
// av_add = apu^d
copy_mat_to_vec(m, q, d, apu, av_add);
//
// ay = au_add + av_add
(*this)(add_enum, ax_add, ay);
//
// apu^d = ay
copy_vec_to_mat(m, q, d, ay.begin(), apu);
}
}
}
} // END_CPPAD_NAMESPACE
Input File: include/cppad/example/atomic_four/vector/mul_op.hpp