build(CppAD): brought in CppAD for autodiff

we need an autodiff library at some point (or we need to roll our own but I do not think that makes sense). CppAD is well tested and header only and easy to include. It is also Liscene compatible with GPL v3.0. Here we bring it in as a dependency
This commit is contained in:
2025-06-19 14:51:02 -04:00
parent 76662db03e
commit 856ab51b4c
367 changed files with 108392 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
# ifndef CPPAD_LOCAL_ABS_OP_HPP
# define CPPAD_LOCAL_ABS_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file abs_op.hpp
Forward and reverse mode calculations for z = fabs(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = AbsOp.
The C++ source code corresponding to this operation is
\verbatim
z = fabs(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_abs_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
for(size_t j = p; j <= q; j++)
z[j] = sign(x[0]) * x[j];
}
/*!
Multiple directions forward mode Taylor coefficient for op = AbsOp.
The C++ source code corresponding to this operation is
\verbatim
z = fabs(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_abs_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
z[m + ell] = sign(x[0]) * x[m + ell];
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AbsOp.
The C++ source code corresponding to this operation is
\verbatim
z = fabs(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_abs_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base x0 = *(taylor + i_x * cap_order);
Base* z = taylor + i_z * cap_order;
z[0] = fabs(x0);
}
/*!
Compute reverse mode partial derivatives for result of op = AbsOp.
The C++ source code corresponding to this operation is
\verbatim
z = fabs(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_abs_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{ size_t j;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
Base* pz = partial + i_z * nc_partial;
// do not need azmul because sign is either +1, -1, or zero
for(j = 0; j <= d; j++)
px[j] += sign(x[0]) * pz[j];
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,263 @@
# ifndef CPPAD_LOCAL_ACOS_OP_HPP
# define CPPAD_LOCAL_ACOS_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file acos_op.hpp
Forward and reverse mode calculations for z = acos(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = AcosOp.
The C++ source code corresponding to this operation is
\verbatim
z = acos(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 - x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_acos_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
Base uj;
if( p == 0 )
{ z[0] = acos( x[0] );
uj = Base(1.0) - x[0] * x[0];
b[0] = sqrt( uj );
p++;
}
for(size_t j = p; j <= q; j++)
{ uj = Base(0.0);
for(k = 0; k <= j; k++)
uj -= x[k] * x[j-k];
b[j] = Base(0.0);
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] -= Base(double(k)) * b[k] * b[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
b[j] /= Base(double(j));
z[j] /= Base(double(j));
//
b[j] += uj / Base(2.0);
z[j] -= x[j];
//
b[j] /= b[0];
z[j] /= b[0];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = AcosOp.
The C++ source code corresponding to this operation is
\verbatim
z = acos(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 - x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_acos_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t k, ell;
size_t m = (q-1) * r + 1;
for(ell = 0; ell < r; ell ++)
{ Base uq = - 2.0 * x[m + ell] * x[0];
for(k = 1; k < q; k++)
uq -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
b[m+ell] = Base(0.0);
z[m+ell] = Base(0.0);
for(k = 1; k < q; k++)
{ b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0];
z[m+ell] = -( x[m+ell] + z[m+ell] / Base(double(q)) ) / b[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AcosOp.
The C++ source code corresponding to this operation is
\verbatim
z = acos(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 - x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_acos_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = acos( x[0] );
b[0] = sqrt( Base(1.0) - x[0] * x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = AcosOp.
The C++ source code corresponding to this operation is
\verbatim
z = acos(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 - x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_acos_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{
// scale partials w.r.t b[j] by 1 / b[0]
pb[j] = azmul(pb[j], inv_b0);
// scale partials w.r.t z[j] by 1 / b[0]
pz[j] = azmul(pz[j], inv_b0);
// update partials w.r.t b^0
pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]);
// update partial w.r.t. x^0
px[0] -= azmul(pb[j], x[j]);
// update partial w.r.t. x^j
px[j] -= pz[j] + azmul(pb[j], x[0]);
// further scale partial w.r.t. z[j] by 1 / j
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ // update partials w.r.t b^(j-k)
pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]);
// update partials w.r.t. x^k
px[k] -= azmul(pb[j], x[j-k]);
// update partials w.r.t. z^k
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
}
--j;
}
// j == 0 case
px[0] -= azmul( pz[0] + azmul(pb[0], x[0]), inv_b0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,264 @@
# ifndef CPPAD_LOCAL_ACOSH_OP_HPP
# define CPPAD_LOCAL_ACOSH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file acosh_op.hpp
Forward and reverse mode calculations for z = acosh(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = AcoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = acosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(x * x - 1)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_acosh_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
Base uj;
if( p == 0 )
{ z[0] = acosh( x[0] );
uj = x[0] * x[0] - Base(1.0);
b[0] = sqrt( uj );
p++;
}
for(size_t j = p; j <= q; j++)
{ uj = Base(0.0);
for(k = 0; k <= j; k++)
uj += x[k] * x[j-k];
b[j] = Base(0.0);
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] -= Base(double(k)) * b[k] * b[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
b[j] /= Base(double(j));
z[j] /= Base(double(j));
//
b[j] += uj / Base(2.0);
z[j] += x[j];
//
b[j] /= b[0];
z[j] /= b[0];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = AcoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = acosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(x * x - 1)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_acosh_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t k, ell;
size_t m = (q-1) * r + 1;
for(ell = 0; ell < r; ell ++)
{ Base uq = 2.0 * x[m + ell] * x[0];
for(k = 1; k < q; k++)
uq += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
b[m+ell] = Base(0.0);
z[m+ell] = Base(0.0);
for(k = 1; k < q; k++)
{ b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0];
z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AcoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = acosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( x * x - 1 )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_acosh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = acosh( x[0] );
b[0] = sqrt( x[0] * x[0] - Base(1.0) );
}
/*!
Compute reverse mode partial derivatives for result of op = AcoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = acosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( x * x - 1 )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_acosh_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{
// scale partials w.r.t b[j] by 1 / b[0]
pb[j] = azmul(pb[j], inv_b0);
// scale partials w.r.t z[j] by 1 / b[0]
pz[j] = azmul(pz[j], inv_b0);
// update partials w.r.t b^0
pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]);
// update partial w.r.t. x^0
px[0] += azmul(pb[j], x[j]);
// update partial w.r.t. x^j
px[j] += pz[j] + azmul(pb[j], x[0]);
// further scale partial w.r.t. z[j] by 1 / j
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ // update partials w.r.t b^(j-k)
pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]);
// update partials w.r.t. x^k
px[k] += azmul(pb[j], x[j-k]);
// update partials w.r.t. z^k
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
}
--j;
}
// j == 0 case
px[0] += azmul(pz[0] + azmul(pb[0], x[0]), inv_b0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,186 @@
# ifndef CPPAD_LOCAL_AD_TAPE_HPP
# define CPPAD_LOCAL_AD_TAPE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/define.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL__NAMESPACE
/*!
Class used to hold tape that records AD<Base> operations.
\tparam Base
An <tt>AD<Base></tt> object is used to recording <tt>AD<Base></tt> operations.
*/
template <class Base>
class ADTape {
// Friends =============================================================
// classes -------------------------------------------------------------
friend class AD<Base>;
friend class ADFun<Base>;
friend class atomic_base<Base>;
friend class atomic_three<Base>;
friend class discrete<Base>;
friend class VecAD<Base>;
friend class VecAD_reference<Base>;
// functions -----------------------------------------------------------
// PrintFor
friend void CppAD::PrintFor <Base> (
const AD<Base>& flag ,
const char* before ,
const AD<Base>& var ,
const char* after
);
// CondExpOp
friend AD<Base> CppAD::CondExpOp <Base> (
enum CompareOp cop ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &trueCase ,
const AD<Base> &falseCase
);
// pow
friend AD<Base> CppAD::pow <Base>
(const AD<Base> &x, const AD<Base> &y);
// azmul
friend AD<Base> CppAD::azmul <Base>
(const AD<Base> &x, const AD<Base> &y);
// Parameter
friend bool CppAD::Parameter <Base>
(const AD<Base> &u);
// Variable
friend bool CppAD::Variable <Base>
(const AD<Base> &u);
// operators -----------------------------------------------------------
// arithematic binary operators
# if _MSC_VER
// see https://stackoverflow.com/questions/63288453
template <class Type> friend AD<Type> CppAD::operator * <Type>
(const AD<Type> &left, const AD<Type> &right);
# else
friend AD<Base> CppAD::operator * <Base>
(const AD<Base> &left, const AD<Base> &right);
# endif
friend AD<Base> CppAD::operator + <Base>
(const AD<Base> &left, const AD<Base> &right);
friend AD<Base> CppAD::operator - <Base>
(const AD<Base> &left, const AD<Base> &right);
friend AD<Base> CppAD::operator / <Base>
(const AD<Base> &left, const AD<Base> &right);
// comparison operators
# if _MSC_VER
template <class Type> friend bool CppAD::operator == <Type>
(const AD<Type> &left, const AD<Type> &right);
template <class Type> friend bool CppAD::operator != <Type>
(const AD<Type> &left, const AD<Type> &right);
# else
friend bool CppAD::operator == <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool CppAD::operator != <Base>
(const AD<Base> &left, const AD<Base> &right);
# endif
friend bool CppAD::operator < <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool CppAD::operator <= <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool CppAD::operator > <Base>
(const AD<Base> &left, const AD<Base> &right);
friend bool CppAD::operator >= <Base>
(const AD<Base> &left, const AD<Base> &right);
// ======================================================================
// --------------------------------------------------------------------------
private:
// ----------------------------------------------------------------------
// private data
/*!
Unique identifier for this tape. It is always greater than
CPPAD_MAX_NUM_THREADS, and different for every tape (even ones that have
been deleted). In addition, id_ % CPPAD_MAX_NUM_THREADS is the thread
number for this tape. Set by Independent and effectively const
*/
tape_id_t id_;
/// Number of independent variables in this tapes reconding.
/// Set by Independent and effectively const
size_t size_independent_;
/// This is where the information is recorded.
local::recorder<Base> Rec_;
// ----------------------------------------------------------------------
// private functions
//
// add a parameter to the tape
addr_t RecordParOp(const AD<Base>& y);
// see CondExp.h
void RecordCondExp(
enum CompareOp cop ,
AD<Base> &returnValue ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &trueCase ,
const AD<Base> &falseCase
);
public:
// public function only used by CppAD::Independent
template <class ADBaseVector>
void Independent(
ADBaseVector& x ,
size_t abort_op_index ,
bool record_compare ,
ADBaseVector& dynamic
);
};
// ---------------------------------------------------------------------------
// Private functions
//
/*!
Place a parameter in the tape as a variable.
On rare occations it is necessary to place a parameter in the tape; e.g.,
when it is one of the dependent variabes.
\param y
value of the parameter that we are placing in the tape as a variable.
\return
variable index (for this recording) correpsonding to the parameter.
\par 2DO
All these operates are preformed in Rec_, so we should
move this routine from <tt>ADTape<Base></tt> to <tt>recorder<Base></tt>.
*/
template <class Base>
addr_t ADTape<Base>::RecordParOp(const AD<Base>& y)
{ CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumArg(ParOp) == 1 );
addr_t z_taddr = Rec_.PutOp(ParOp);
if( Dynamic(y) )
{ addr_t ind = y.taddr_;
Rec_.PutArg(ind);
}
else
{ addr_t ind = Rec_.put_con_par(y.value_);
Rec_.PutArg(ind);
}
return z_taddr;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,338 @@
# ifndef CPPAD_LOCAL_ADD_OP_HPP
# define CPPAD_LOCAL_ADD_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file add_op.hpp
Forward and reverse mode calculations for z = x + y.
*/
// --------------------------- Addvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = AddvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_addvv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
for(size_t j = p; j <= q; j++)
z[j] = x[j] + y[j];
}
/*!
Multiple directions forward mode Taylor coefficients for op = AddvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_addvv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1)*r + 1 ;
for(size_t ell = 0; ell < r; ell++)
z[m+ell] = x[m+ell] + y[m+ell];
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = AddvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_addvv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] + y[0];
}
/*!
Compute reverse mode partial derivatives for result of op = AddvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_addvv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t i = d + 1;
while(i)
{ --i;
px[i] += pz[i];
py[i] += pz[i];
}
}
// --------------------------- Addpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = AddpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_addpv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
if( p == 0 )
{ // Paraemter value
Base x = parameter[ arg[0] ];
z[0] = x + y[0];
p++;
}
for(size_t j = p; j <= q; j++)
z[j] = y[j];
}
/*!
Multiple directions forward mode Taylor coefficients for op = AddpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_addpv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q-1) * r + 1;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m;
Base* z = taylor + i_z * num_taylor_per_var + m;
for(size_t ell = 0; ell < r; ell++)
z[ell] = y[ell];
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AddpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_addpv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x + y[0];
}
/*!
Compute reverse mode partial derivative for result of op = AddpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x + y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_addpv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Partial derivatives corresponding to arguments and result
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t i = d + 1;
while(i)
{ --i;
py[i] += pz[i];
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,263 @@
# ifndef CPPAD_LOCAL_ASIN_OP_HPP
# define CPPAD_LOCAL_ASIN_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file asin_op.hpp
Forward and reverse mode calculations for z = asin(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = AsinOp.
The C++ source code corresponding to this operation is
\verbatim
z = asin(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 - x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_asin_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
Base uj;
if( p == 0 )
{ z[0] = asin( x[0] );
uj = Base(1.0) - x[0] * x[0];
b[0] = sqrt( uj );
p++;
}
for(size_t j = p; j <= q; j++)
{ uj = Base(0.0);
for(k = 0; k <= j; k++)
uj -= x[k] * x[j-k];
b[j] = Base(0.0);
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] -= Base(double(k)) * b[k] * b[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
b[j] /= Base(double(j));
z[j] /= Base(double(j));
//
b[j] += uj / Base(2.0);
z[j] += x[j];
//
b[j] /= b[0];
z[j] /= b[0];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = AsinOp.
The C++ source code corresponding to this operation is
\verbatim
z = asin(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 - x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_asin_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t k, ell;
size_t m = (q-1) * r + 1;
for(ell = 0; ell < r; ell ++)
{ Base uq = - 2.0 * x[m + ell] * x[0];
for(k = 1; k < q; k++)
uq -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
b[m+ell] = Base(0.0);
z[m+ell] = Base(0.0);
for(k = 1; k < q; k++)
{ b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0];
z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AsinOp.
The C++ source code corresponding to this operation is
\verbatim
z = asin(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 - x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_asin_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = asin( x[0] );
b[0] = sqrt( Base(1.0) - x[0] * x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = AsinOp.
The C++ source code corresponding to this operation is
\verbatim
z = asin(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 - x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_asin_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{
// scale partials w.r.t b[j] by 1 / b[0]
pb[j] = azmul(pb[j], inv_b0);
// scale partials w.r.t z[j] by 1 / b[0]
pz[j] = azmul(pz[j], inv_b0);
// update partials w.r.t b^0
pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]);
// update partial w.r.t. x^0
px[0] -= azmul(pb[j], x[j]);
// update partial w.r.t. x^j
px[j] += pz[j] - azmul(pb[j], x[0]);
// further scale partial w.r.t. z[j] by 1 / j
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ // update partials w.r.t b^(j-k)
pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]);
// update partials w.r.t. x^k
px[k] -= azmul(pb[j], x[j-k]);
// update partials w.r.t. z^k
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
}
--j;
}
// j == 0 case
px[0] += azmul(pz[0] - azmul(pb[0], x[0]), inv_b0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,264 @@
# ifndef CPPAD_LOCAL_ASINH_OP_HPP
# define CPPAD_LOCAL_ASINH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file asinh_op.hpp
Forward and reverse mode calculations for z = asinh(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = AsinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = asinh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 + x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_asinh_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
Base uj;
if( p == 0 )
{ z[0] = asinh( x[0] );
uj = Base(1.0) + x[0] * x[0];
b[0] = sqrt( uj );
p++;
}
for(size_t j = p; j <= q; j++)
{ uj = Base(0.0);
for(k = 0; k <= j; k++)
uj += x[k] * x[j-k];
b[j] = Base(0.0);
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] -= Base(double(k)) * b[k] * b[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
b[j] /= Base(double(j));
z[j] /= Base(double(j));
//
b[j] += uj / Base(2.0);
z[j] += x[j];
//
b[j] /= b[0];
z[j] /= b[0];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = AsinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = asinh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt(1 + x * x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_asinh_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t k, ell;
size_t m = (q-1) * r + 1;
for(ell = 0; ell < r; ell ++)
{ Base uq = 2.0 * x[m + ell] * x[0];
for(k = 1; k < q; k++)
uq += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
b[m+ell] = Base(0.0);
z[m+ell] = Base(0.0);
for(k = 1; k < q; k++)
{ b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0];
z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = AsinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = asinh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 + x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_asinh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = asinh( x[0] );
b[0] = sqrt( Base(1.0) + x[0] * x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = AsinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = asinh(x)
\endverbatim
The auxillary result is
\verbatim
y = sqrt( 1 + x * x )
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_asinh_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{
// scale partials w.r.t b[j] by 1 / b[0]
pb[j] = azmul(pb[j], inv_b0);
// scale partials w.r.t z[j] by 1 / b[0]
pz[j] = azmul(pz[j], inv_b0);
// update partials w.r.t b^0
pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]);
// update partial w.r.t. x^0
px[0] += azmul(pb[j], x[j]);
// update partial w.r.t. x^j
px[j] += pz[j] + azmul(pb[j], x[0]);
// further scale partial w.r.t. z[j] by 1 / j
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ // update partials w.r.t b^(j-k)
pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]);
// update partials w.r.t. x^k
px[k] += azmul(pb[j], x[j-k]);
// update partials w.r.t. z^k
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
}
--j;
}
// j == 0 case
px[0] += azmul(pz[0] + azmul(pb[0], x[0]), inv_b0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,235 @@
# ifndef CPPAD_LOCAL_ATAN_OP_HPP
# define CPPAD_LOCAL_ATAN_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file atan_op.hpp
Forward and reverse mode calculations for z = atan(x).
*/
/*!
Forward mode Taylor coefficient for result of op = AtanOp.
The C++ source code corresponding to this operation is
\verbatim
z = atan(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 + x * x
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_atan_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
if( p == 0 )
{ z[0] = atan( x[0] );
b[0] = Base(1.0) + x[0] * x[0];
p++;
}
for(size_t j = p; j <= q; j++)
{
b[j] = Base(2.0) * x[0] * x[j];
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] += x[k] * x[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
z[j] /= Base(double(j));
z[j] += x[j];
z[j] /= b[0];
}
}
/*!
Multiple direction Taylor coefficient for op = AtanOp.
The C++ source code corresponding to this operation is
\verbatim
z = atan(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 + x * x
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_atan_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ b[m+ell] = Base(2.0) * x[m+ell] * x[0];
z[m+ell] = Base(double(q)) * x[m+ell];
for(size_t k = 1; k < q; k++)
{ b[m+ell] += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
z[m+ell] /= ( Base(double(q)) * b[0] );
}
}
/*!
Zero order forward mode Taylor coefficient for result of op = AtanOp.
The C++ source code corresponding to this operation is
\verbatim
z = atan(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 + x * x
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_atan_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = atan( x[0] );
b[0] = Base(1.0) + x[0] * x[0];
}
/*!
Reverse mode partial derivatives for result of op = AtanOp.
The C++ source code corresponding to this operation is
\verbatim
z = atan(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 + x * x
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_atan_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{ // scale partials w.r.t z[j] and b[j]
pz[j] = azmul(pz[j], inv_b0);
pb[j] *= Base(2.0);
pb[0] -= azmul(pz[j], z[j]);
px[j] += pz[j] + azmul(pb[j], x[0]);
px[0] += azmul(pb[j], x[j]);
// more scaling of partials w.r.t z[j]
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]);
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
px[k] += azmul(pb[j], x[j-k]);
}
--j;
}
px[0] += azmul(pz[0], inv_b0) + Base(2.0) * azmul(pb[0], x[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,236 @@
# ifndef CPPAD_LOCAL_ATANH_OP_HPP
# define CPPAD_LOCAL_ATANH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file atanh_op.hpp
Forward and reverse mode calculations for z = atanh(x).
*/
/*!
Forward mode Taylor coefficient for result of op = AtanhOp.
The C++ source code corresponding to this operation is
\verbatim
z = atanh(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 - x * x
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_atanh_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
size_t k;
if( p == 0 )
{ z[0] = atanh( x[0] );
b[0] = Base(1.0) - x[0] * x[0];
p++;
}
for(size_t j = p; j <= q; j++)
{
b[j] = - Base(2.0) * x[0] * x[j];
z[j] = Base(0.0);
for(k = 1; k < j; k++)
{ b[j] -= x[k] * x[j-k];
z[j] -= Base(double(k)) * z[k] * b[j-k];
}
z[j] /= Base(double(j));
z[j] += x[j];
z[j] /= b[0];
}
}
/*!
Multiple direction Taylor coefficient for op = AtanhOp.
The C++ source code corresponding to this operation is
\verbatim
z = atanh(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 - x * x
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_atanh_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
Base* b = z - num_taylor_per_var; // called y in documentation
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ b[m+ell] = - Base(2.0) * x[m+ell] * x[0];
z[m+ell] = Base(double(q)) * x[m+ell];
for(size_t k = 1; k < q; k++)
{ b[m+ell] -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell];
}
z[m+ell] /= ( Base(double(q)) * b[0] );
}
}
/*!
Zero order forward mode Taylor coefficient for result of op = AtanhOp.
The C++ source code corresponding to this operation is
\verbatim
z = atanh(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 - x * x
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_atanh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
Base* b = z - cap_order; // called y in documentation
z[0] = atanh( x[0] );
b[0] = Base(1.0) - x[0] * x[0];
}
/*!
Reverse mode partial derivatives for result of op = AtanhOp.
The C++ source code corresponding to this operation is
\verbatim
z = atanh(x)
\endverbatim
The auxillary result is
\verbatim
y = 1 - x * x
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_atanh_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* b = z - cap_order; // called y in documentation
Base* pb = pz - nc_partial;
Base inv_b0 = Base(1.0) / b[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{ // scale partials w.r.t z[j] and b[j]
pz[j] = azmul(pz[j], inv_b0);
pb[j] *= Base(2.0);
pb[0] -= azmul(pz[j], z[j]);
px[j] += pz[j] - azmul(pb[j], x[0]);
px[0] -= azmul(pb[j], x[j]);
// more scaling of partials w.r.t z[j]
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]);
pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]);
px[k] -= azmul(pb[j], x[j-k]);
}
--j;
}
px[0] += azmul(pz[0], inv_b0) - Base(2.0) * azmul(pb[0], x[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,32 @@
# ifndef CPPAD_LOCAL_ATOM_STATE_HPP
# define CPPAD_LOCAL_ATOM_STATE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
enum enum_atom_state {
/// next AFunOp marks beginning of a atomic function call
start_atom,
/// next FunapOp (FunavOp) is a parameter (variable) argument
arg_atom,
/// next FunrpOp (FunrvOp) is a parameter (variable) result
ret_atom,
/// next AFunOp marks end of a atomic function call
end_atom
};
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,161 @@
# ifndef CPPAD_LOCAL_ATOMIC_INDEX_HPP
# define CPPAD_LOCAL_ATOMIC_INDEX_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
$begin atomic_index$$
$spell
ptr
$$
$section Store and Retrieve Atomic Function Information by Index$$
$head Syntax$$
$icode%index_out% = local::atomic_index<%Base%>(
%set_null%, %index_in%, %type%, %name%, %ptr%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_ATOMIC_INDEX%// END_PROTOTYPE%1
%$$
$head Base$$
Is the base type for the tape for the atomic functions
that we are using an index to identify.
$head Special Case$$
In the special case,
$icode set_null$$ is true and $icode index_in$$ is zero.
For this case, $icode index_out$$ is set to
the number of atomic functions stored in $codei%atomic_index<%Base%>%$$
and no information is stored or changed.
In this case, the atomic functions correspond to $icode index_in$$ from
one to $icode index_out$$ inclusive.
$head set_null$$
If this is not the special case:
This value should only be true during a call to an atomic function destructor.
If it is true, the $icode ptr$$ corresponding to $icode index_in$$
is set to null.
$head index_in$$
If this is not the special case:
$subhead zero$$
The value $icode index_in$$ should only be zero
during a call to an atomic function constructor.
In this case, a copy of the input value of
$icode type$$, $codei%*%name%$$, and $icode ptr$$ are stored.
The value $icode index_out$$
is the $icode index_in$$ value corresponding to these input values.
$subhead non-zero$$
If $icode index_in$$ is non-zero,
the information corresponding to this index is returned.
$head type$$
If this is not the special case:
If $icode index_in$$ is zero, $icode type$$ is an input.
Otherwise it is set to the value corresponding to this index.
The type corresponding to an index
is intended to be $code 2$$ for $cref atomic_two$$ functions
and $code 3$$ for $cref atomic_three$$ functions.
$head name$$
If this is not the special case:
If $icode index_in$$ is zero, $code name$$ is an input and must not be null.
Otherwise, if $icode name$$ is not null, $codei%*%name%$$
is set to the name corresponding to $icode index_in$$.
Allowing for $icode name$$ to be null avoids
a string copy when it is not needed.
$head ptr$$
If this is not the special case:
If $icode index_in$$ is zero, $icode ptr$$ is an input.
Otherwise it is set to the value corresponding to $icode index_in$$.
In the special case where $icode set_null$$ is true,
$icode ptr$$ is set to the null pointer and this is the $icode ptr$$ value
corresponding to $icode index_in$$ for future calls to $code atomic_index$$.
$head index_out$$
If this is not the special case:
If $icode index_in$$ is zero,
$icode index_out$$ is non-zero and is the index value
corresponding to the input values for
$icode type$$, $codei%*%name%$$, and $icode ptr$$.
Otherwise, $index_out$$ is zero.
$end
*/
# include <vector>
# include <cppad/utility/thread_alloc.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
struct atomic_index_info {
size_t type;
std::string name;
void* ptr;
};
// BEGIN_ATOMIC_INDEX
template <class Base>
size_t atomic_index(
bool set_null ,
const size_t& index_in ,
size_t& type ,
std::string* name ,
void*& ptr )
// END_PROTOTYPE
{ //
// information for each index
static std::vector<atomic_index_info> vec;
# ifndef NDEBUG
if( index_in == 0 || set_null )
{ CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel(),
"calling atomic function constructor or destructor in parallel mode"
);
}
# endif
if( set_null & (index_in == 0) )
return vec.size();
//
// case were we are retreving informaiton for an atomic function
if( 0 < index_in )
{ CPPAD_ASSERT_UNKNOWN( index_in <= vec.size() )
//
// case where we are setting the pointer to null
if( set_null )
vec[index_in-1].ptr = nullptr;
//
atomic_index_info& entry = vec[index_in - 1];
type = entry.type;
ptr = entry.ptr;
if( name != nullptr )
*name = entry.name;
return 0;
}
//
// case where we are storing information for an atomic function
atomic_index_info entry;
entry.type = type;
entry.name = *name;
entry.ptr = ptr;
vec.push_back(entry);
//
return vec.size();
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,275 @@
# ifndef CPPAD_LOCAL_COLOR_GENERAL_HPP
# define CPPAD_LOCAL_COLOR_GENERAL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# include <cppad/local/cppad_colpack.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file color_general.hpp
Coloring algorithm for a general sparse matrix.
*/
// --------------------------------------------------------------------------
/*!
Determine which rows of a general sparse matrix can be computed together;
i.e., do not have non-zero entries with the same column index.
\tparam SizeVector
is a simple vector class with elements of type size_t.
\tparam SetVector
is vector_of_sets class.
\param pattern [in]
Is a representation of the sparsity pattern for the matrix.
\param row [in]
is a vector specifying which row indices to compute.
\param col [in]
is a vector, with the same size as row,
that specifies which column indices to compute.
For each valid index k, the index pair
<code>(row[k], col[k])</code> must be present in the sparsity pattern.
It may be that some entries in the sparsity pattern do not need to be computed;
i.e, do not appear in the set of
<code>(row[k], col[k])</code> entries.
\param color [out]
is a vector with size m.
The input value of its elements does not matter.
Upon return, it is a coloring for the rows of the sparse matrix.
\n
\n
If for some i, <code>color[i] == m</code>, then
the i-th row does not appear in the vector row.
Otherwise, <code>color[i] < m</code>.
\n
\n
Suppose two differen rows, <code>i != r</code> have the same color and
column index j is such that both of the pairs
<code>(i, j)</code> and <code>(r, j)</code> appear in the sparsity pattern.
It follows that neither of these pairs appear in the set of
<code>(row[k], col[k])</code> entries.
\n
\n
This routine tries to minimize, with respect to the choice of colors,
the maximum, with respct to k, of <code>color[ row[k] ]</code>
(not counting the indices k for which row[k] == m).
*/
template <class SetVector, class SizeVector>
void color_general_cppad(
const SetVector& pattern ,
const SizeVector& row ,
const SizeVector& col ,
CppAD::vector<size_t>& color )
{
size_t K = row.size();
size_t m = pattern.n_set();
size_t n = pattern.end();
CPPAD_ASSERT_UNKNOWN( size_t( col.size() ) == K );
CPPAD_ASSERT_UNKNOWN( size_t( color.size() ) == m );
// We define the set of rows, columns, and pairs that appear
// by the set ( row[k], col[k] ) for k = 0, ... , K-1.
// initialize rows that appear
CppAD::vector<bool> row_appear(m);
for(size_t i = 0; i < m; i++)
row_appear[i] = false;
// rows and columns that appear
SetVector c2r_appear, r2c_appear;
c2r_appear.resize(n, m);
r2c_appear.resize(m, n);
for(size_t k = 0; k < K; k++)
{ CPPAD_ASSERT_KNOWN( pattern.is_element(row[k], col[k]) ,
"color_general_cppad: requesting value for a matrix element\n"
"that is not in the matrice's sparsity pattern.\n"
"Such a value must be zero."
);
row_appear[ row[k] ] = true;
c2r_appear.post_element(col[k], row[k]);
r2c_appear.post_element(row[k], col[k]);
}
// process posts
for(size_t j = 0; j < n; ++j)
c2r_appear.process_post(j);
for(size_t i = 0; i < m; ++i)
r2c_appear.process_post(i);
// for each column, which rows are non-zero and do not appear
SetVector not_appear;
not_appear.resize(n, m);
for(size_t i = 0; i < m; i++)
{ typename SetVector::const_iterator pattern_itr(pattern, i);
size_t j = *pattern_itr;
while( j != pattern.end() )
{ if( ! c2r_appear.is_element(j , i) )
not_appear.post_element(j, i);
j = *(++pattern_itr);
}
}
// process posts
for(size_t j = 0; j < n; ++j)
not_appear.process_post(j);
// initial coloring
color.resize(m);
size_t ell = 0;
for(size_t i = 0; i < m; i++)
{ if( row_appear[i] )
color[i] = ell++;
else
color[i] = m;
}
/*
See GreedyPartialD2Coloring Algorithm Section 3.6.2 of
Graph Coloring in Optimization Revisited by
Assefaw Gebremedhin, Fredrik Maane, Alex Pothen
The algorithm above was modified (by Brad Bell) to take advantage of the
fact that only the entries (subset of the sparsity pattern) specified by
row and col need to be computed.
*/
CppAD::vector<bool> forbidden(m);
for(size_t i = 1; i < m; i++) // for each row that appears
if( color[i] < m )
{
// initial all colors as ok for this row
// (value of forbidden for ell > initial color[i] does not matter)
for(ell = 0; ell <= color[i]; ell++)
forbidden[ell] = false;
// -----------------------------------------------------
// Forbid colors for which this row would destroy results:
//
// for each column that is non-zero for this row
typename SetVector::const_iterator pattern_itr(pattern, i);
size_t j = *pattern_itr;
while( j != pattern.end() )
{ // for each row that appears with this column
typename SetVector::const_iterator c2r_itr(c2r_appear, j);
size_t r = *c2r_itr;
while( r != c2r_appear.end() )
{ // if this is not the same row, forbid its color
if( (r < i) & (color[r] < m) )
forbidden[ color[r] ] = true;
r = *(++c2r_itr);
}
j = *(++pattern_itr);
}
// -----------------------------------------------------
// Forbid colors that destroy results needed for this row.
//
// for each column that appears with this row
typename SetVector::const_iterator r2c_itr(r2c_appear, i);
j = *r2c_itr;
while( j != r2c_appear.end() )
{ // For each row that is non-zero for this column
// (the appear rows have already been checked above).
typename SetVector::const_iterator not_itr(not_appear, j);
size_t r = *not_itr;
while( r != not_appear.end() )
{ // if this is not the same row, forbid its color
if( (r < i) & (color[r] < m) )
forbidden[ color[r] ] = true;
r = *(++not_itr);
}
j = *(++r2c_itr);
}
// pick the color with smallest index
ell = 0;
while( forbidden[ell] )
{ ell++;
CPPAD_ASSERT_UNKNOWN( ell <= color[i] );
}
color[i] = ell;
}
return;
}
# if CPPAD_HAS_COLPACK
/*!
Colpack version of determining which rows of a sparse matrix
can be computed together.
\copydetails color_general
*/
template <class SetVector, class SizeVector>
void color_general_colpack(
const SetVector& pattern ,
const SizeVector& row ,
const SizeVector& col ,
CppAD::vector<size_t>& color )
{
size_t m = pattern.n_set();
size_t n = pattern.end();
// Determine number of non-zero entries in each row
CppAD::vector<size_t> n_nonzero(m);
size_t n_nonzero_total = 0;
for(size_t i = 0; i < m; i++)
{ n_nonzero[i] = 0;
typename SetVector::const_iterator pattern_itr(pattern, i);
size_t j = *pattern_itr;
while( j != pattern.end() )
{ n_nonzero[i]++;
j = *(++pattern_itr);
}
n_nonzero_total += n_nonzero[i];
}
// Allocate memory and fill in Adolc sparsity pattern
CppAD::vector<unsigned int*> adolc_pattern(m);
CppAD::vector<unsigned int> adolc_memory(m + n_nonzero_total);
size_t i_memory = 0;
for(size_t i = 0; i < m; i++)
{ adolc_pattern[i] = adolc_memory.data() + i_memory;
CPPAD_ASSERT_KNOWN(
std::numeric_limits<unsigned int>::max() >= n_nonzero[i],
"Matrix is too large for colpack"
);
adolc_pattern[i][0] = static_cast<unsigned int>( n_nonzero[i] );
typename SetVector::const_iterator pattern_itr(pattern, i);
size_t j = *pattern_itr;
size_t k = 1;
while(j != pattern.end() )
{
CPPAD_ASSERT_KNOWN(
std::numeric_limits<unsigned int>::max() >= j,
"Matrix is too large for colpack"
);
adolc_pattern[i][k++] = static_cast<unsigned int>( j );
j = *(++pattern_itr);
}
CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] );
i_memory += k;
}
CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total );
// Must use an external routine for this part of the calculation because
// ColPack/ColPackHeaders.h has as 'using namespace std' at global level.
cppad_colpack_general(color, m, n, adolc_pattern);
return;
}
# endif // CPPAD_HAS_COLPACK
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,309 @@
# ifndef CPPAD_LOCAL_COLOR_SYMMETRIC_HPP
# define CPPAD_LOCAL_COLOR_SYMMETRIC_HPP
# include <cppad/configure.hpp>
# include <cppad/local/cppad_colpack.hpp>
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file color_symmetric.hpp
Coloring algorithm for a symmetric sparse matrix.
*/
// --------------------------------------------------------------------------
/*!
CppAD algorithm for determining which rows of a symmetric sparse matrix can be
computed together.
\tparam SizeVector
is a simple vector class with elements of type size_t.
\tparam SetVector
is a vector_of_sets class.
\param pattern [in]
Is a representation of the sparsity pattern for the matrix.
\param row [in/out]
is a vector specifying which row indices to compute.
\param col [in/out]
is a vector, with the same size as row,
that specifies which column indices to compute.
\n
\n
Input:
For each valid index k, the index pair
<code>(row[k], col[k])</code> must be present in the sparsity pattern.
It may be that some entries in the sparsity pattern do not need to be computed;
i.e, do not appear in the set of
<code>(row[k], col[k])</code> entries.
\n
\n
Output:
On output, some of row and column indices may have been swapped
\code
std::swap( row[k], col[k] )
\endcode
So the the the color for row[k] can be used to compute entry
(row[k], col[k]).
\param color [out]
is a vector with size m.
The input value of its elements does not matter.
Upon return, it is a coloring for the rows of the sparse matrix.
Note that if color[i] == m, then there is no index k for which
row[k] == i (for the return value of row).
\n
\n
Fix any (i, j) in the sparsity pattern.
Suppose that there is a row index i1 with
i1 != i, color[i1] == color[i] and (i1, j) is in the sparsity pattern.
If follows that for all j1 with
j1 != j and color[j1] == color[j],
(j1, i ) is not in the sparsity pattern.
\n
\n
This routine tries to minimize, with respect to the choice of colors,
the maximum, with respect to k, of <code>color[ row[k] ]</code>.
*/
template <class SetVector>
void color_symmetric_cppad(
const SetVector& pattern ,
CppAD::vector<size_t>& row ,
CppAD::vector<size_t>& col ,
CppAD::vector<size_t>& color )
{
size_t K = row.size();
size_t m = pattern.n_set();
CPPAD_ASSERT_UNKNOWN( m == pattern.end() );
CPPAD_ASSERT_UNKNOWN( color.size() == m );
CPPAD_ASSERT_UNKNOWN( col.size() == K );
// row, column pairs that appear in ( row[k], col[k] )
CppAD::vector< std::set<size_t> > pair_needed(m);
std::set<size_t>::iterator itr1, itr2;
for(size_t k1 = 0; k1 < K; k1++)
{ CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k1], col[k1]) );
pair_needed[ row[k1] ].insert( col[k1] );
pair_needed[ col[k1] ].insert( row[k1] );
}
// order the rows decending by number of pairs needed
CppAD::vector<size_t> key(m), order2row(m);
for(size_t i1 = 0; i1 < m; i1++)
{ CPPAD_ASSERT_UNKNOWN( pair_needed[i1].size() <= m );
key[i1] = m - pair_needed[i1].size();
}
CppAD::index_sort(key, order2row);
// mapping from order index to row index
CppAD::vector<size_t> row2order(m);
for(size_t o1 = 0; o1 < m; o1++)
row2order[ order2row[o1] ] = o1;
// initial coloring
color.resize(m);
size_t c1 = 0;
for(size_t o1 = 0; o1 < m; o1++)
{ size_t i1 = order2row[o1];
if( pair_needed[i1].empty() )
color[i1] = m;
else
color[i1] = c1++;
}
// which colors are forbidden for this row
CppAD::vector<bool> forbidden(m);
// must start with row zero so that we remove results computed for it
for(size_t o1 = 0; o1 < m; o1++) // for each row that appears (in order)
if( color[ order2row[o1] ] < m )
{ size_t i1 = order2row[o1];
c1 = color[i1];
// initial all colors as ok for this row
// (value of forbidden for c > c1 does not matter)
for(size_t c2 = 0; c2 <= c1; c2++)
forbidden[c2] = false;
// -----------------------------------------------------
// Forbid grouping with rows that would destroy results that are
// needed for this row.
itr1 = pair_needed[i1].begin();
while( itr1 != pair_needed[i1].end() )
{ // entry (i1, j1) is needed for this row
size_t j1 = *itr1;
// Forbid rows i2 != i1 that have non-zero sparsity at (i2, j1).
// Note that this is the same as non-zero sparsity at (j1, i2)
typename SetVector::const_iterator pattern_itr(pattern, j1);
size_t i2 = *pattern_itr;
while( i2 != pattern.end() )
{ size_t c2 = color[i2];
if( c2 < c1 )
forbidden[c2] = true;
i2 = *(++pattern_itr);
}
itr1++;
}
// -----------------------------------------------------
// Forbid grouping with rows that this row would destroy results for
for(size_t o2 = 0; o2 < o1; o2++)
{ size_t i2 = order2row[o2];
size_t c2 = color[i2];
itr2 = pair_needed[i2].begin();
while( itr2 != pair_needed[i2].end() )
{ size_t j2 = *itr2;
// row i2 needs pair (i2, j2).
// Forbid grouping with i1 if (i1, j2) has non-zero sparsity
if( pattern.is_element(i1, j2) )
forbidden[c2] = true;
itr2++;
}
}
// pick the color with smallest index
size_t c2 = 0;
while( forbidden[c2] )
{ c2++;
CPPAD_ASSERT_UNKNOWN( c2 <= c1 );
}
color[i1] = c2;
// no longer need results that are computed by this row
itr1 = pair_needed[i1].begin();
while( itr1 != pair_needed[i1].end() )
{ size_t j1 = *itr1;
if( row2order[j1] > o1 )
{ itr2 = pair_needed[j1].find(i1);
if( itr2 != pair_needed[j1].end() )
{ pair_needed[j1].erase(itr2);
if( pair_needed[j1].empty() )
color[j1] = m;
}
}
itr1++;
}
}
// determine which sparsity entries need to be reflected
for(size_t k1 = 0; k1 < row.size(); k1++)
{ size_t i1 = row[k1];
size_t j1 = col[k1];
itr1 = pair_needed[i1].find(j1);
if( itr1 == pair_needed[i1].end() )
{ row[k1] = j1;
col[k1] = i1;
# ifndef NDEBUG
itr1 = pair_needed[j1].find(i1);
CPPAD_ASSERT_UNKNOWN( itr1 != pair_needed[j1].end() );
# endif
}
}
return;
}
// --------------------------------------------------------------------------
/*!
Colpack algorithm for determining which rows of a symmetric sparse matrix
can be computed together.
\copydetails CppAD::local::color_symmetric_cppad
*/
template <class SetVector>
void color_symmetric_colpack(
const SetVector& pattern ,
CppAD::vector<size_t>& row ,
CppAD::vector<size_t>& col ,
CppAD::vector<size_t>& color )
{
# if ! CPPAD_HAS_COLPACK
CPPAD_ASSERT_UNKNOWN(false);
return;
# else
size_t i, j, k;
size_t m = pattern.n_set();
CPPAD_ASSERT_UNKNOWN( m == pattern.end() );
CPPAD_ASSERT_UNKNOWN( row.size() == col.size() );
// Determine number of non-zero entries in each row
CppAD::vector<size_t> n_nonzero(m);
size_t n_nonzero_total = 0;
for(i = 0; i < m; i++)
{ n_nonzero[i] = 0;
typename SetVector::const_iterator pattern_itr(pattern, i);
j = *pattern_itr;
while( j != pattern.end() )
{ n_nonzero[i]++;
j = *(++pattern_itr);
}
n_nonzero_total += n_nonzero[i];
}
// Allocate memory and fill in Adolc sparsity pattern
CppAD::vector<unsigned int*> adolc_pattern(m);
CppAD::vector<unsigned int> adolc_memory(m + n_nonzero_total);
size_t i_memory = 0;
for(i = 0; i < m; i++)
{ adolc_pattern[i] = adolc_memory.data() + i_memory;
CPPAD_ASSERT_KNOWN(
std::numeric_limits<unsigned int>::max() >= n_nonzero[i],
"Matrix is too large for colpack"
);
adolc_pattern[i][0] = static_cast<unsigned int>( n_nonzero[i] );
typename SetVector::const_iterator pattern_itr(pattern, i);
j = *pattern_itr;
k = 1;
while(j != pattern.end() )
{
CPPAD_ASSERT_KNOWN(
std::numeric_limits<unsigned int>::max() >= j,
"Matrix is too large for colpack"
);
adolc_pattern[i][k++] = static_cast<unsigned int>( j );
j = *(++pattern_itr);
}
CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] );
i_memory += k;
}
CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total );
// Must use an external routine for this part of the calculation because
// ColPack/ColPackHeaders.h has as 'using namespace std' at global level.
cppad_colpack_symmetric(color, m, adolc_pattern);
// determine which sparsity entries need to be reflected
for(size_t k1 = 0; k1 < row.size(); k1++)
{ size_t i1 = row[k1];
size_t j1 = col[k1];
bool reflect = false;
for(size_t i2 = 0; i2 < m; i2++)
if( (i1 != i2) & (color[i1]==color[i2]) )
{ for(size_t k2 = 1; k2 <= adolc_pattern[i2][0]; k2++)
{ size_t j2 = adolc_pattern[i2][k2];
reflect |= (j1 == j2);
}
}
if( reflect )
{ row[k1] = j1;
col[k1] = i1;
}
}
return;
# endif // CPPAD_HAS_COLPACK
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,420 @@
# ifndef CPPAD_LOCAL_COMP_OP_HPP
# define CPPAD_LOCAL_COMP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file comp_op.hpp
Zero order forward mode check how many comparisons changed.
*/
// -------------------------------- <= -----------------------------------
/*!
Zero order forward mode comparison check that left <= right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
parameter[ arg[0] ] is the left operand and
parameter[ arg[1] ] is the right operand.
\param parameter
vector of parameter values.
*/
template <class Base>
void forward_lepp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LeppOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LeppOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base y = parameter[ arg[1] ];
count += size_t( GreaterThanZero(x - y) );
}
/*!
Zero order forward mode comparison check that left <= right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
parameter[ arg[0] ] is the left operand and
taylor[ size_t(arg[1]) * cap_order + 0 ] is the zero order Taylor coefficient
for the right operand.
\param parameter
vector of parameter values.
\param cap_order
number of Taylor coefficients allocated for each variable
\param taylor
vector of taylor coefficients.
*/
template <class Base>
void forward_lepv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LepvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LepvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base* y = taylor + size_t(arg[1]) * cap_order;
count += GreaterThanZero(x - y[0]);
}
/*!
Zero order forward mode comparison check that left <= right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
taylor[ size_t(arg[0]) * cap_order + 0 ] is the zero order Taylor coefficient
for the left operand and parameter[ arg[1] ] is the right operand
\param parameter
vector of parameter values.
\param cap_order
number of Taylor coefficients allocated for each variable
\param taylor
vector of taylor coefficients.
*/
template <class Base>
void forward_levp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LevpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LevpOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base y = parameter[ arg[1] ];
count += GreaterThanZero(x[0] - y);
}
/*!
Zero order forward mode comparison check that left <= right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
taylor[ size_t(arg[0]) * cap_order + 0 ] is the zero order Taylor coefficient
for the left operand and
taylor[ size_t(arg[1]) * cap_order + 0 ] is the zero order Taylor coefficient
for the right operand.
\param parameter
vector of parameter values.
\param cap_order
number of Taylor coefficients allocated for each variable
\param taylor
vector of taylor coefficients.
*/
template <class Base>
void forward_levv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LevvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LevvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
count += GreaterThanZero(x[0] - y[0]);
}
// ------------------------------- < -------------------------------------
/*!
Zero order forward mode comparison check that left < right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
parameter[ arg[0] ] is the left operand and
parameter[ arg[1] ] is the right operand.
\param parameter
vector of parameter values.
*/
template <class Base>
void forward_ltpp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LtppOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LtppOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base y = parameter[ arg[1] ];
count += GreaterThanOrZero(x - y);
}
/*!
Zero order forward mode comparison check that left < right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
void forward_ltpv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LtpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LtpvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base* y = taylor + size_t(arg[1]) * cap_order;
count += GreaterThanOrZero(x - y[0]);
}
/*!
Zero order forward mode comparison check that left < right
\copydetails CppAD::local::forward_levp_op_0
*/
template <class Base>
void forward_ltvp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LtvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LtvpOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base y = parameter[ arg[1] ];
count += GreaterThanOrZero(x[0] - y);
}
/*!
Zero order forward mode comparison check that left < right
\copydetails CppAD::local::forward_levv_op_0
*/
template <class Base>
void forward_ltvv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LtvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(LtvvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
count += GreaterThanOrZero(x[0] - y[0]);
}
// ------------------------------ == -------------------------------------
/*!
Zero order forward mode comparison check that left == right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
parameter[ arg[0] ] is the left operand and
parameter[ arg[1] ] is the right operand.
\param parameter
vector of parameter values.
*/
template <class Base>
void forward_eqpp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(EqppOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(EqppOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base y = parameter[ arg[1] ];
count += size_t(x != y);
}
/*!
Zero order forward mode comparison check that left == right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
void forward_eqpv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(EqpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(EqpvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base* y = taylor + size_t(arg[1]) * cap_order;
count += size_t(x != y[0]);
}
/*!
Zero order forward mode comparison check that left == right
\copydetails CppAD::local::forward_levv_op_0
*/
template <class Base>
void forward_eqvv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(EqvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(EqvvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
count += size_t(x[0] != y[0]);
}
// -------------------------------- != -----------------------------------
/*!
Zero order forward mode comparison check that left != right
\param count
It the condition is not true, ths counter is incremented by one.
\param arg
parameter[ arg[0] ] is the left operand and
parameter[ arg[1] ] is the right operand.
\param parameter
vector of parameter values.
*/
template <class Base>
void forward_nepp_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(NeppOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(NeppOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base y = parameter[ arg[1] ];
count += size_t(x == y);
}
/*!
Zero order forward mode comparison check that left != right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
void forward_nepv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(NepvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(NepvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base x = parameter[ arg[0] ];
Base* y = taylor + size_t(arg[1]) * cap_order;
count += size_t(x == y[0]);
}
/*!
Zero order forward mode comparison check that left != right
\copydetails CppAD::local::forward_levv_op_0
*/
template <class Base>
void forward_nevv_op_0(
size_t& count ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(NevvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(NevvOp) == 0 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
count += size_t(x[0] == y[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,238 @@
# ifndef CPPAD_LOCAL_COS_OP_HPP
# define CPPAD_LOCAL_COS_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file cos_op.hpp
Forward and reverse mode calculations for z = cos(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = CosOp.
The C++ source code corresponding to this operation is
\verbatim
z = cos(x)
\endverbatim
The auxillary result is
\verbatim
y = sin(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_cos_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* c = taylor + i_z * cap_order;
Base* s = c - cap_order;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op.
// (except that there is a sign difference for the hyperbolic case).
size_t k;
if( p == 0 )
{ s[0] = sin( x[0] );
c[0] = cos( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
s[j] = Base(0.0);
c[j] = Base(0.0);
for(k = 1; k <= j; k++)
{ s[j] += Base(double(k)) * x[k] * c[j-k];
c[j] -= Base(double(k)) * x[k] * s[j-k];
}
s[j] /= Base(double(j));
c[j] /= Base(double(j));
}
}
/*!
Compute forward mode Taylor coefficient for result of op = CosOp.
The C++ source code corresponding to this operation is
\verbatim
z = cos(x)
\endverbatim
The auxillary result is
\verbatim
y = sin(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_cos_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* c = taylor + i_z * num_taylor_per_var;
Base* s = c - num_taylor_per_var;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op
// (except that there is a sign difference for the hyperbolic case).
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ s[m+ell] = Base(double(q)) * x[m + ell] * c[0];
c[m+ell] = - Base(double(q)) * x[m + ell] * s[0];
for(size_t k = 1; k < q; k++)
{ s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell];
c[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell];
}
s[m+ell] /= Base(double(q));
c[m+ell] /= Base(double(q));
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = CosOp.
The C++ source code corresponding to this operation is
\verbatim
z = cos(x)
\endverbatim
The auxillary result is
\verbatim
y = sin(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_cos_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* c = taylor + i_z * cap_order; // called z in documentation
Base* s = c - cap_order; // called y in documentation
c[0] = cos( x[0] );
s[0] = sin( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = CosOp.
The C++ source code corresponding to this operation is
\verbatim
z = cos(x)
\endverbatim
The auxillary result is
\verbatim
y = sin(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_cos_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* c = taylor + i_z * cap_order; // called z in doc
Base* pc = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* s = c - cap_order; // called y in documentation
Base* ps = pc - nc_partial;
// rest of this routine is identical for the following cases:
// reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op.
size_t j = d;
size_t k;
while(j)
{
ps[j] /= Base(double(j));
pc[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{
px[k] += Base(double(k)) * azmul(ps[j], c[j-k]);
px[k] -= Base(double(k)) * azmul(pc[j], s[j-k]);
ps[j-k] -= Base(double(k)) * azmul(pc[j], x[k]);
pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]);
}
--j;
}
px[0] += azmul(ps[0], c[0]);
px[0] -= azmul(pc[0], s[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,238 @@
# ifndef CPPAD_LOCAL_COSH_OP_HPP
# define CPPAD_LOCAL_COSH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file cosh_op.hpp
Forward and reverse mode calculations for z = cosh(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = CoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = cosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sinh(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_cosh_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* c = taylor + i_z * cap_order;
Base* s = c - cap_order;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op.
// (except that there is a sign difference for hyperbolic case).
size_t k;
if( p == 0 )
{ s[0] = sinh( x[0] );
c[0] = cosh( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
s[j] = Base(0.0);
c[j] = Base(0.0);
for(k = 1; k <= j; k++)
{ s[j] += Base(double(k)) * x[k] * c[j-k];
c[j] += Base(double(k)) * x[k] * s[j-k];
}
s[j] /= Base(double(j));
c[j] /= Base(double(j));
}
}
/*!
Compute forward mode Taylor coefficient for result of op = CoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = cosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sinh(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_cosh_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* s = taylor + i_z * num_taylor_per_var;
Base* c = s - num_taylor_per_var;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op
// (except that there is a sign difference for the hyperbolic case).
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ s[m+ell] = Base(double(q)) * x[m + ell] * c[0];
c[m+ell] = Base(double(q)) * x[m + ell] * s[0];
for(size_t k = 1; k < q; k++)
{ s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell];
c[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell];
}
s[m+ell] /= Base(double(q));
c[m+ell] /= Base(double(q));
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = CoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = cosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sinh(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_cosh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* c = taylor + i_z * cap_order; // called z in documentation
Base* s = c - cap_order; // called y in documentation
c[0] = cosh( x[0] );
s[0] = sinh( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = CoshOp.
The C++ source code corresponding to this operation is
\verbatim
z = cosh(x)
\endverbatim
The auxillary result is
\verbatim
y = sinh(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_cosh_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* c = taylor + i_z * cap_order; // called z in doc
Base* pc = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* s = c - cap_order; // called y in documentation
Base* ps = pc - nc_partial;
// rest of this routine is identical for the following cases:
// reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op.
size_t j = d;
size_t k;
while(j)
{
ps[j] /= Base(double(j));
pc[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{
px[k] += Base(double(k)) * azmul(ps[j], c[j-k]);
px[k] += Base(double(k)) * azmul(pc[j], s[j-k]);
ps[j-k] += Base(double(k)) * azmul(pc[j], x[k]);
pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]);
}
--j;
}
px[0] += azmul(ps[0], c[0]);
px[0] += azmul(pc[0], s[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,104 @@
# ifndef CPPAD_LOCAL_CPPAD_COLPACK_HPP
# define CPPAD_LOCAL_CPPAD_COLPACK_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# if CPPAD_HAS_COLPACK
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file cppad_colpack.hpp
External interface to Colpack routines used by cppad.
*/
// ---------------------------------------------------------------------------
/*!
Link from CppAD to ColPack used for general sparse matrices.
This CppAD library routine is necessary because
<code>ColPack/ColPackHeaders.h</code> has a
<code>using namespace std</code> at the global level.
\param m [in]
is the number of rows in the sparse matrix
\param n [in]
is the nubmer of columns in the sparse matrix.
\param adolc_pattern [in]
This vector has size m,
<code>adolc_pattern[i][0]</code> is the number of non-zeros in row i.
For <code>j = 1 , ... , adolc_sparsity[i]<code>,
<code>adolc_pattern[i][j]</code> is the column index (base zero) for the
non-zeros in row i.
\param color [out]
is a vector with size m.
The input value of its elements does not matter.
Upon return, it is a coloring for the rows of the sparse matrix.
\n
\n
If for some i, <code>color[i] == m</code>, then
<code>adolc_pattern[i][0] == 0</code>.
Otherwise, <code>color[i] < m</code>.
\n
\n
Suppose two differen rows, <code>i != r</code> have the same color.
It follows that for all column indices j;
it is not the case that both
<code>(i, j)</code> and <code>(r, j)</code> appear in the sparsity pattern.
\n
\n
This routine tries to minimize, with respect to the choice of colors,
the number of colors.
*/
extern void cppad_colpack_general(
CppAD::vector<size_t>& color ,
size_t m ,
size_t n ,
const CppAD::vector<unsigned int*>& adolc_pattern
);
/*!
Link from CppAD to ColPack used for symmetric sparse matrices
(not yet used or tested).
This CppAD library routine is necessary because
<code>ColPack/ColPackHeaders.h</code> has a
<code>using namespace std</code> at the global level.
\param n [in]
is the nubmer of rows and columns in the symmetric sparse matrix.
\param adolc_pattern [in]
This vector has size n,
<code>adolc_pattern[i][0]</code> is the number of non-zeros in row i.
For <code>j = 1 , ... , adolc_sparsity[i]<code>,
<code>adolc_pattern[i][j]</code> is the column index (base zero) for the
non-zeros in row i.
\param color [out]
The input value of its elements does not matter.
Upon return, it is a coloring for the rows of the sparse matrix.
The properties of this coloring have not yet been determined; see
Efficient Computation of Sparse Hessians Using Coloring
and Automatic Differentiation (pdf/ad/gebemedhin14.pdf)
*/
extern void cppad_colpack_symmetric(
CppAD::vector<size_t>& color ,
size_t n ,
const CppAD::vector<unsigned int*>& adolc_pattern
);
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
# endif

View File

@@ -0,0 +1,199 @@
# ifndef CPPAD_LOCAL_CSKIP_OP_HPP
# define CPPAD_LOCAL_CSKIP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file cskip_op.hpp
Zero order forward mode set which operations to skip.
*/
/*!
Zero order forward mode execution of op = CSkipOp.
\par Parameters and Variables
The terms parameter and variable depend on if we are referring to its
AD<Base> or Base value.
We use Base parameter and Base variable to refer to the
correspond Base value.
We use AD<Base> parameter and AD<Base> variable to refer to the
correspond AD<Base> value.
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
\param i_z
variable index corresponding to the result of the previous operation.
This is used for error checking. To be specific,
the left and right operands for the CExpOp operation must have indexes
less than or equal this value.
\param arg [in]
\n
arg[0]
is static cast to size_t from the enum type
\verbatim
enum CompareOp {
CompareLt,
CompareLe,
CompareEq,
CompareGe,
CompareGt,
CompareNe
}
\endverbatim
for this operation.
Note that arg[0] cannot be equal to CompareNe.
\n
\n
arg[1] & 1
\n
If this is zero, left is an AD<Base> parameter.
Otherwise it is an AD<Base> variable.
\n
\n
arg[1] & 2
\n
If this is zero, right is an AD<Base> parameter.
Otherwise it is an AD<Base> variable.
\n
arg[2]
is the index corresponding to left in comparison.
\n
arg[3]
is the index corresponding to right in comparison.
\n
arg[4]
is the number of operations to skip if the comparison result is true.
\n
arg[5]
is the number of operations to skip if the comparison result is false.
\n
<tt>arg[5+i]</tt>
for <tt>i = 1 , ... , arg[4]</tt> are the operations to skip if the
comparison result is true and both left and right are
identically Base parameters.
\n
<tt>arg[5+arg[4]+i]</tt>
for <tt>i = 1 , ... , arg[5]</tt> are the operations to skip if the
comparison result is false and both left and right are
identically Base parameters.
\param num_par [in]
is the total number of values in the vector parameter.
\param parameter [in]
If left is an AD<Base> parameter,
<code>parameter [ arg[2] ]</code> is its value.
If right is an AD<Base> parameter,
<code>parameter [ arg[3] ]</code> is its value.
\param cap_order [in]
number of columns in the matrix containing the Taylor coefficients.
\param taylor [in]
If left is an AD<Base> variable,
<code>taylor [ size_t(arg[2]) * cap_order + 0 ]</code>
is the zeroth order Taylor coefficient corresponding to left.
If right is an AD<Base> variable,
<code>taylor [ size_t(arg[3]) * cap_order + 0 ]</code>
is the zeroth order Taylor coefficient corresponding to right.
\param cskip_op [in,out]
is vector specifying which operations are at this point are know to be
unecessary and can be skipped.
This is both an input and an output.
*/
template <class Base>
void forward_cskip_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
bool* cskip_op )
{
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < size_t(CompareNe) );
CPPAD_ASSERT_UNKNOWN( arg[1] != 0 );
Base left, right;
if( arg[1] & 1 )
{ // If variable arg[2] <= i_z, it has already been computed,
// but it will be skipped for higher orders.
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) <= i_z );
left = taylor[ size_t(arg[2]) * cap_order + 0 ];
}
else
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
left = parameter[ arg[2] ];
}
if( arg[1] & 2 )
{ // If variable arg[3] <= i_z, it has already been computed,
// but it will be skipped for higher orders.
CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) <= i_z );
right = taylor[ size_t(arg[3]) * cap_order + 0 ];
}
else
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par );
right = parameter[ arg[3] ];
}
bool ok_to_skip = IdenticalCon(left) & IdenticalCon(right);
if( ! ok_to_skip )
return;
// initialize to avoid compiler warning
bool true_case = false;
Base diff = left - right;
switch( CompareOp( arg[0] ) )
{
case CompareLt:
true_case = LessThanZero(diff);
break;
case CompareLe:
true_case = LessThanOrZero(diff);
break;
case CompareEq:
true_case = IdenticalZero(diff);
break;
case CompareGe:
true_case = GreaterThanOrZero(diff);
break;
case CompareGt:
true_case = GreaterThanZero(diff);
break;
case CompareNe:
true_case = ! IdenticalZero(diff);
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
if( true_case )
{ for(addr_t i = 0; i < arg[4]; i++)
cskip_op[ arg[6+i] ] = true;
}
else
{ for(addr_t i = 0; i < arg[5]; i++)
cskip_op[ arg[6+arg[4]+i] ] = true;
}
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,612 @@
# ifndef CPPAD_LOCAL_CSUM_OP_HPP
# define CPPAD_LOCAL_CSUM_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file csum_op.hpp
Forward, reverse and sparsity calculations for cummulative summation.
*/
/*!
Compute forward mode Taylor coefficients for result of op = CsumOp.
This operation is
\verbatim
z = s + x(0) + ... + x(n1-1) - y(0) - ... - y(n2-1)
+ p(0) + ... + p(n3-1) - q(0) - ... - q(n4-1).
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base.
\param p
lowest order of the Taylor coefficient that we are computing.
\param q
highest order of the Taylor coefficient that we are computing.
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in taylor corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(n1-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n2-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
arg[arg[2]] , ... , arg[arg[3]-1] correspond to p(0), ... , p(n3-1)
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
arg[arg[3]] , ... , arg[arg[4]-1] correspond to q(0), ... , q(n4-1)
\param num_par
is the number of parameters in parameter.
\param parameter
is the parameter vector for this operation sequence.
\param cap_order
number of colums in the matrix containing all the Taylor coefficients.
\param taylor
\b Input: taylor [ arg[5+i] * cap_order + k ]
for i = 0, ..., n1-1
and k = 0 , ... , q
is the k-th order Taylor coefficient corresponding to x(i)
\n
\b Input: taylor [ arg[arg[1]+1] * cap_order + k ]
for i = 0, ..., n2-1
and k = 0 , ... , q
is the k-th order Taylor coefficient corresponding to y(i)
\n
\b Input: taylor [ i_z * cap_order + k ]
for k = 0 , ... , p,
is the k-th order Taylor coefficient corresponding to z.
\n
\b Output: taylor [ i_z * cap_order + k ]
for k = p , ... , q,
is the k-th order Taylor coefficient corresponding to z.
*/
template <class Base>
void forward_csum_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{ Base zero(0);
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
CPPAD_ASSERT_UNKNOWN(
arg[arg[4]] == arg[4]
);
// Taylor coefficients corresponding to result
Base* z = taylor + i_z * cap_order;
for(size_t k = p; k <= q; k++)
z[k] = zero;
if( p == 0 )
{ // normal parameters in the sum
z[p] = parameter[ arg[0] ];
// addition dynamic parameters
for(size_t i = size_t(arg[2]); i < size_t(arg[3]); ++i)
z[p] += parameter[ arg[i] ];
// subtraction dynamic parameters
for(size_t i = size_t(arg[3]); i < size_t(arg[4]); ++i)
z[p] -= parameter[ arg[i] ];
}
Base* x;
for(size_t i = 5; i < size_t(arg[1]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
x = taylor + size_t(arg[i]) * cap_order;
for(size_t k = p; k <= q; k++)
z[k] += x[k];
}
for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
x = taylor + size_t(arg[i]) * cap_order;
for(size_t k = p; k <= q; k++)
z[k] -= x[k];
}
}
/*!
Multiple direction forward mode Taylor coefficients for op = CsumOp.
This operation is
\verbatim
z = s + x(0) + ... + x(m-1) - y(0) - ... - y(n-1).
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type
Base.
\param q
order ot the Taylor coefficients that we are computing.
\param r
number of directions for Taylor coefficients that we are computing.
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in taylor corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
\param num_par
is the number of parameters in parameter.
\param parameter
is the parameter vector for this operation sequence.
\param cap_order
number of colums in the matrix containing all the Taylor coefficients.
\param taylor
\b Input: taylor [ arg[5+i]*((cap_order-1)*r + 1) + 0 ]
for i = 0, ..., m-1
is the 0-th order Taylor coefficient corresponding to x(i) and
taylor [ arg[5+i]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ]
for i = 0, ..., m-1,
ell = 0 , ... , r-1
is the q-th order Taylor coefficient corresponding to x(i)
and direction ell.
\n
\b Input: taylor [ arg[arg[1]+1]*((cap_order-1)*r + 1) + 0 ]
for i = 0, ..., n-1
is the 0-th order Taylor coefficient corresponding to y(i) and
taylor [ arg[arg[1]+1]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ]
for i = 0, ..., n-1,
ell = 0 , ... , r-1
is the q-th order Taylor coefficient corresponding to y(i)
and direction ell.
\n
\b Output: taylor [ i_z*((cap_order-1)*r+1) + (q-1)*r + ell + 1 ]
is the q-th order Taylor coefficient corresponding to z
for direction ell = 0 , ... , r-1.
*/
template <class Base>
void forward_csum_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{ Base zero(0);
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
CPPAD_ASSERT_UNKNOWN(
arg[arg[4]] == arg[4]
);
// Taylor coefficients corresponding to result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q-1)*r + 1;
Base* z = taylor + i_z * num_taylor_per_var + m;
for(size_t ell = 0; ell < r; ell++)
z[ell] = zero;
Base* x;
for(size_t i = 5; i < size_t(arg[1]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
x = taylor + size_t(arg[i]) * num_taylor_per_var + m;
for(size_t ell = 0; ell < r; ell++)
z[ell] += x[ell];
}
for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
x = taylor + size_t(arg[i]) * num_taylor_per_var + m;
for(size_t ell = 0; ell < r; ell++)
z[ell] -= x[ell];
}
}
/*!
Compute reverse mode Taylor coefficients for result of op = CsumOp.
This operation is
\verbatim
z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1).
H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ]
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base.
\param d
order the highest order Taylor coefficient that we are computing
the partial derivatives with respect to.
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in taylor corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
\param nc_partial
number of colums in the matrix containing all the partial derivatives.
\param partial
\b Input: partial [ arg[5+i] * nc_partial + k ]
for i = 0, ..., m-1
and k = 0 , ... , d
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to x(i)
\n
\b Input: partial [ arg[arg[1]+1] * nc_partial + k ]
for i = 0, ..., n-1
and k = 0 , ... , d
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to y(i)
\n
\b Input: partial [ i_z * nc_partial + k ]
for i = 0, ..., n-1
and k = 0 , ... , d
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to z.
\n
\b Output: partial [ arg[5+i] * nc_partial + k ]
for i = 0, ..., m-1
and k = 0 , ... , d
is the partial derivative of H(y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to x(i)
\n
\b Output: partial [ arg[arg[1]+1] * nc_partial + k ]
for i = 0, ..., n-1
and k = 0 , ... , d
is the partial derivative of H(y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to y(i)
*/
template <class Base>
void reverse_csum_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partial derivative corresponding to result
Base* pz = partial + i_z * nc_partial;
Base* px;
size_t d1 = d + 1;
for(size_t i = 5; i < size_t(arg[1]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
px = partial + size_t(arg[i]) * nc_partial;
size_t k = d1;
while(k--)
px[k] += pz[k];
}
for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
px = partial + size_t(arg[i]) * nc_partial;
size_t k = d1;
while(k--)
px[k] -= pz[k];
}
}
/*!
Forward mode Jacobian sparsity pattern for CSumOp operator.
This operation is
\verbatim
z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1).
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in sparsity corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
\param sparsity
\b Input:
For i = 0, ..., m-1,
the set with index arg[5+i] in sparsity
is the sparsity bit pattern for x(i).
This identifies which of the independent variables the variable
x(i) depends on.
\n
\b Input:
For i = 0, ..., n-1,
the set with index arg[2+arg[0]+i] in sparsity
is the sparsity bit pattern for x(i).
This identifies which of the independent variables the variable
y(i) depends on.
\n
\b Output:
The set with index i_z in sparsity
is the sparsity bit pattern for z.
This identifies which of the independent variables the variable z
depends on.
*/
template <class Vector_set>
void forward_sparse_jacobian_csum_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{ sparsity.clear(i_z);
for(size_t i = 5; i < size_t(arg[2]); ++i)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
sparsity.binary_union(
i_z , // index in sparsity for result
i_z , // index in sparsity for left operand
size_t(arg[i]), // index for right operand
sparsity // sparsity vector for right operand
);
}
}
/*!
Reverse mode Jacobian sparsity pattern for CSumOp operator.
This operation is
\verbatim
z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1).
H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ]
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in sparsity corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
\param sparsity
For i = 0, ..., m-1,
the set with index arg[5+i] in sparsity
is the sparsity bit pattern for x(i).
This identifies which of the dependent variables depend on x(i).
On input, the sparsity patter corresponds to G,
and on ouput it corresponds to H.
\n
For i = 0, ..., m-1,
the set with index arg[2+arg[0]+i] in sparsity
is the sparsity bit pattern for y(i).
This identifies which of the dependent variables depend on y(i).
On input, the sparsity patter corresponds to G,
and on ouput it corresponds to H.
\n
\b Input:
The set with index i_z in sparsity
is the sparsity bit pattern for z.
On input it corresponds to G and on output it is undefined.
*/
template <class Vector_set>
void reverse_sparse_jacobian_csum_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{
for(size_t i = 5; i < size_t(arg[2]); ++i)
{
CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
sparsity.binary_union(
size_t(arg[i]), // index in sparsity for result
size_t(arg[i]), // index in sparsity for left operand
i_z , // index for right operand
sparsity // sparsity vector for right operand
);
}
}
/*!
Reverse mode Hessian sparsity pattern for CSumOp operator.
This operation is
\verbatim
z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1).
H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ]
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in sparsity corresponding to z.
\param arg
-- arg[0]
parameter[arg[0]] is the parameter value s in this cummunative summation.
-- arg[1]
end in arg of addition variables in summation.
arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1)
-- arg[2]
end in arg of subtraction variables in summation.
arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1)
-- arg[3]
end in arg of addition dynamic parameters in summation.
-- arg[4]
end in arg of subtraction dynamic parameters in summation.
\param rev_jacobian
rev_jacobian[i_z]
is all false (true) if the Jabobian of G with respect to z must be zero
(may be non-zero).
\n
\n
For i = 0, ..., m-1
rev_jacobian[ arg[5+i] ]
is all false (true) if the Jacobian with respect to x(i)
is zero (may be non-zero).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
\n
\n
For i = 0, ..., n-1
rev_jacobian[ arg[2+arg[0]+i] ]
is all false (true) if the Jacobian with respect to y(i)
is zero (may be non-zero).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
\param rev_hes_sparsity
The set with index i_z in in rev_hes_sparsity
is the Hessian sparsity pattern for the fucntion G
where one of the partials derivative is with respect to z.
\n
\n
For i = 0, ..., m-1
The set with index arg[5+i] in rev_hes_sparsity
is the Hessian sparsity pattern
where one of the partials derivative is with respect to x(i).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
\n
\n
For i = 0, ..., n-1
The set with index arg[2+arg[0]+i] in rev_hes_sparsity
is the Hessian sparsity pattern
where one of the partials derivative is with respect to y(i).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
*/
template <class Vector_set>
void reverse_sparse_hessian_csum_op(
size_t i_z ,
const addr_t* arg ,
bool* rev_jacobian ,
Vector_set& rev_hes_sparsity )
{
for(size_t i = 5; i < size_t(arg[2]); ++i)
{
CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z );
rev_hes_sparsity.binary_union(
size_t(arg[i]), // index in sparsity for result
size_t(arg[i]), // index in sparsity for left operand
i_z , // index for right operand
rev_hes_sparsity // sparsity vector for right operand
);
rev_jacobian[arg[i]] |= rev_jacobian[i_z];
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,183 @@
# ifndef CPPAD_LOCAL_DECLARE_AD_HPP
# define CPPAD_LOCAL_DECLARE_AD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# include <cstdint>
/*!
\file declare_ad.hpp CppAD forward declarations; i.e., before definition
*/
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
template <class Base> class ADTape;
template <class Base> class player;
template <class Base> class recorder;
} } // END_CPPAD_LOCAL_NAMESPACE
namespace CppAD {
// The conditional expression operator enum type
enum CompareOp
{ CompareLt, // less than
CompareLe, // less than or equal
CompareEq, // equal
CompareGe, // greater than or equal
CompareGt, // greater than
CompareNe // not equal
};
// simple typedefs
typedef CPPAD_TAPE_ADDR_TYPE addr_t;
typedef CPPAD_TAPE_ID_TYPE tape_id_t;
// classes
class sparse_hes_work;
class sparse_jac_work;
class sparse_jacobian_work;
class sparse_hessian_work;
template <class Base> class AD;
template <class Base, class RecBase=Base> class ADFun;
template <class Base> class atomic_base;
template <class Base> class atomic_three;
template <class Base> class discrete;
template <class Base> class VecAD;
template <class Base> class VecAD_reference;
// functions with one VecAD<Base> argument
template <class Base> bool Constant (const VecAD<Base> &u);
template <class Base> bool Dynamic (const VecAD<Base> &u);
template <class Base> bool Parameter (const VecAD<Base> &u);
template <class Base> bool Variable (const VecAD<Base> &u);
// functions with one AD<Base> argument
template <class Base> bool Constant (const AD<Base> &u);
template <class Base> bool Dynamic (const AD<Base> &u);
template <class Base> bool Parameter (const AD<Base> &u);
template <class Base> bool Variable (const AD<Base> &u);
//
template <class Base> int Integer (const AD<Base> &u);
template <class Base> bool IdenticalZero (const AD<Base> &u);
template <class Base> bool IdenticalOne (const AD<Base> &u);
template <class Base> bool IdenticalCon (const AD<Base> &u);
template <class Base> bool LessThanZero (const AD<Base> &u);
template <class Base> bool LessThanOrZero (const AD<Base> &u);
template <class Base> bool GreaterThanZero (const AD<Base> &u);
template <class Base> bool GreaterThanOrZero (const AD<Base> &u);
template <class Base> AD<Base> Var2Par (const AD<Base> &u);
template <class Base> AD<Base> abs (const AD<Base> &u);
template <class Base> AD<Base> acos (const AD<Base> &u);
template <class Base> AD<Base> asin (const AD<Base> &u);
template <class Base> AD<Base> atan (const AD<Base> &u);
template <class Base> AD<Base> cos (const AD<Base> &u);
template <class Base> AD<Base> cosh (const AD<Base> &u);
template <class Base> AD<Base> exp (const AD<Base> &u);
template <class Base> AD<Base> log (const AD<Base> &u);
template <class Base> AD<Base> log10 (const AD<Base> &u);
template <class Base> AD<Base> sin (const AD<Base> &u);
template <class Base> AD<Base> sinh (const AD<Base> &u);
template <class Base> AD<Base> sqrt (const AD<Base> &u);
template <class Base> AD<Base> tan (const AD<Base> &u);
//
template <class Base> unsigned short hash_code(const AD<Base>& u);
// arithematic operators
template <class Base> AD<Base> operator + (
const AD<Base> &left, const AD<Base> &right);
template <class Base> AD<Base> operator - (
const AD<Base> &left, const AD<Base> &right);
template <class Base> AD<Base> operator * (
const AD<Base> &left, const AD<Base> &right);
template <class Base> AD<Base> operator / (
const AD<Base> &left, const AD<Base> &right);
// comparison operators
template <class Base> bool operator < (
const AD<Base> &left, const AD<Base> &right);
template <class Base> bool operator <= (
const AD<Base> &left, const AD<Base> &right);
template <class Base> bool operator > (
const AD<Base> &left, const AD<Base> &right);
template <class Base> bool operator >= (
const AD<Base> &left, const AD<Base> &right);
template <class Base> bool operator == (
const AD<Base> &left, const AD<Base> &right);
template <class Base> bool operator != (
const AD<Base> &left, const AD<Base> &right);
// pow
template <class Base> AD<Base> pow (
const AD<Base> &x, const AD<Base> &y);
// azmul
template <class Base> AD<Base> azmul (
const AD<Base> &x, const AD<Base> &y);
// NearEqual
template <class Base> bool NearEqual(
const AD<Base> &x, const AD<Base> &y, const Base &r, const Base &a);
template <class Base> bool NearEqual(
const Base &x, const AD<Base> &y, const Base &r, const Base &a);
template <class Base> bool NearEqual(
const AD<Base> &x, const Base &y, const Base &r, const Base &a);
// CondExpOp
template <class Base> AD<Base> CondExpOp (
enum CompareOp cop ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &trueCase ,
const AD<Base> &falseCase
);
// IdenticalEqualCon
template <class Base>
bool IdenticalEqualCon (const AD<Base> &u, const AD<Base> &v);
// EqualOpSeq
template <class Base>
bool EqualOpSeq (const AD<Base> &u, const AD<Base> &v);
// PrintFor
template <class Base>
void PrintFor(
const AD<Base>& flag ,
const char* before ,
const AD<Base>& var ,
const char* after
);
// Value
template <class Base> Base Value(const AD<Base> &x);
// Pow function
template <class Base> AD<Base> pow
(const AD<Base> &x, const AD<Base> &y);
// input operator
template <class Base> std::istream&
operator >> (std::istream &is, AD<Base> &x);
// output operator
template <class Base> std::ostream&
operator << (std::ostream &os, const AD<Base> &x);
template <class Base> std::ostream&
operator << (std::ostream &os, const VecAD_reference<Base> &e);
template <class Base> std::ostream&
operator << (std::ostream &os, const VecAD<Base> &vec);
}
# endif

View File

@@ -0,0 +1,321 @@
# ifndef CPPAD_LOCAL_DEFINE_HPP
# define CPPAD_LOCAL_DEFINE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file define.hpp
Define processor symbols and macros that are used by CppAD.
*/
/*!
\def CPPAD_VEC_ENUM_TYPE
Is the type used to store vectors of enum values when the vector
may be large and we want to conserve memory. The following must hold for
any enum_value that is stored using the type CPPAD_VEC_ENUM_TYPE:
<code>
size_t(enum_value) <= std::numeric_limits<CPPAD_VEC_ENUM_TYPE>::max()
&& is_pod<CPPAD_VEC_ENUM_TYPE>
</code>
*/
# define CPPAD_VEC_ENUM_TYPE unsigned char
// ----------------------------------------------------------------------------
/*!
\def CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
A version of the inline command that works with MC compiler.
Microsoft Visual C++ version 9.0 generates a warning if a template
function is declared as a friend
(this was not a problem for version 7.0).
The warning identifier is
\verbatim
warning C4396
\endverbatim
and it contains the text
\verbatim
the inline specifier cannot be used when a friend declaration refers
to a specialization of a function template
\endverbatim
This happens even if the function is not a specialization.
This macro is defined as empty for Microsoft compilers.
*/
# ifdef _MSC_VER
# define CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION
# else
# define CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION inline
# endif
// ----------------------------------------------------------------------------
/*!
\def CPPAD_LIB_EXPORT
Special macro for exporting windows DLL symbols; see
https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/BuildingWinDLL
*/
# ifdef _MSC_VER
# ifdef cppad_lib_EXPORTS
# define CPPAD_LIB_EXPORT __declspec(dllexport)
# else
# define CPPAD_LIB_EXPORT __declspec(dllimport)
# endif // cppad_lib_EXPORTS
# else // _MSC_VER
# define CPPAD_LIB_EXPORT
# endif
// ============================================================================
/*!
\def CPPAD_FOLD_ASSIGNMENT_OPERATOR(Op)
Declares automatic coercion for certain AD assignment operations.
This macro assumes that the operator
\verbatim
left Op right
\endverbatim
is defined for the case where left and right have type AD<Base>.
It uses this case to define the cases where
left has type AD<Base> and right has type
VecAD_reference<Base>,
Base, or
double.
The argument right is const and call by reference.
This macro converts the operands to AD<Base> and then
uses the definition of the same operation for that case.
*/
# define CPPAD_FOLD_ASSIGNMENT_OPERATOR(Op) \
/* ----------------------------------------------------------------*/ \
template <class Base> \
AD<Base>& operator Op \
(AD<Base> &left, double right) \
{ return left Op AD<Base>(right); } \
\
template <class Base> \
AD<Base>& operator Op \
(AD<Base> &left, const Base &right) \
{ return left Op AD<Base>(right); } \
\
inline AD<double>& operator Op \
(AD<double> &left, const double &right) \
{ return left Op AD<double>(right); } \
\
template <class Base> \
AD<Base>& operator Op \
(AD<Base> &left, const VecAD_reference<Base> &right) \
{ return left Op right.ADBase(); }
// =====================================================================
/*!
\def CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(Op)
Declares automatic coercion for certain binary operations with AD result.
This macro assumes that the operator
\verbatim
left Op right
\endverbatim
is defined for the case where left and right
and the result of the operation all
have type AD<Base>.
It uses this case to define the cases either left
or right has type VecAD_reference<Base> or AD<Base>
and the type of the other operand is one of the following:
VecAD_reference<Base>, AD<Base>, Base, double.
All of the arguments are const and call by reference.
This macro converts the operands to AD<Base> and then
uses the definition of the same operation for that case.
*/
# define CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(Op) \
/* ----------------------------------------------------------------*/ \
/* Operations with VecAD_reference<Base> and AD<Base> only*/ \
\
template <class Base> \
AD<Base> operator Op \
(const AD<Base> &left, const VecAD_reference<Base> &right) \
{ return left Op right.ADBase(); } \
\
template <class Base> \
AD<Base> operator Op \
(const VecAD_reference<Base> &left, const VecAD_reference<Base> &right)\
{ return left.ADBase() Op right.ADBase(); } \
\
template <class Base> \
AD<Base> operator Op \
(const VecAD_reference<Base> &left, const AD<Base> &right) \
{ return left.ADBase() Op right; } \
/* ----------------------------------------------------------------*/ \
/* Operations Base */ \
\
template <class Base> \
AD<Base> operator Op \
(const Base &left, const AD<Base> &right) \
{ return AD<Base>(left) Op right; } \
\
template <class Base> \
AD<Base> operator Op \
(const Base &left, const VecAD_reference<Base> &right) \
{ return AD<Base>(left) Op right.ADBase(); } \
\
template <class Base> \
AD<Base> operator Op \
(const AD<Base> &left, const Base &right) \
{ return left Op AD<Base>(right); } \
\
template <class Base> \
AD<Base> operator Op \
(const VecAD_reference<Base> &left, const Base &right) \
{ return left.ADBase() Op AD<Base>(right); } \
\
/* ----------------------------------------------------------------*/ \
/* Operations double */ \
\
template <class Base> \
AD<Base> operator Op \
(const double &left, const AD<Base> &right) \
{ return AD<Base>(left) Op right; } \
\
template <class Base> \
AD<Base> operator Op \
(const double &left, const VecAD_reference<Base> &right) \
{ return AD<Base>(left) Op right.ADBase(); } \
\
template <class Base> \
AD<Base> operator Op \
(const AD<Base> &left, const double &right) \
{ return left Op AD<Base>(right); } \
\
template <class Base> \
AD<Base> operator Op \
(const VecAD_reference<Base> &left, const double &right) \
{ return left.ADBase() Op AD<Base>(right); } \
/* ----------------------------------------------------------------*/ \
/* Special case to avoid ambuigity when Base is double */ \
\
inline AD<double> operator Op \
(const double &left, const AD<double> &right) \
{ return AD<double>(left) Op right; } \
\
inline AD<double> operator Op \
(const double &left, const VecAD_reference<double> &right) \
{ return AD<double>(left) Op right.ADBase(); } \
\
inline AD<double> operator Op \
(const AD<double> &left, const double &right) \
{ return left Op AD<double>(right); } \
\
inline AD<double> operator Op \
(const VecAD_reference<double> &left, const double &right) \
{ return left.ADBase() Op AD<double>(right); }
// =======================================================================
/*!
\def CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(Op)
Declares automatic coercion for certain binary operations with bool result.
This macro assumes that the operator
\verbatim
left Op right
\endverbatim
is defined for the case where left and right
have type AD<Base> and the result has type bool.
It uses this case to define the cases either left
or right has type
VecAD_reference<Base> or AD<Base>
and the type of the other operand is one of the following:
VecAD_reference<Base>, AD<Base>, Base, double.
All of the arguments are const and call by reference.
This macro converts the operands to AD<Base> and then
uses the definition of the same operation for that case.
*/
# define CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(Op) \
/* ----------------------------------------------------------------*/ \
/* Operations with VecAD_reference<Base> and AD<Base> only*/ \
\
template <class Base> \
bool operator Op \
(const AD<Base> &left, const VecAD_reference<Base> &right) \
{ return left Op right.ADBase(); } \
\
template <class Base> \
bool operator Op \
(const VecAD_reference<Base> &left, const VecAD_reference<Base> &right)\
{ return left.ADBase() Op right.ADBase(); } \
\
template <class Base> \
bool operator Op \
(const VecAD_reference<Base> &left, const AD<Base> &right) \
{ return left.ADBase() Op right; } \
/* ----------------------------------------------------------------*/ \
/* Operations Base */ \
\
template <class Base> \
bool operator Op \
(const Base &left, const AD<Base> &right) \
{ return AD<Base>(left) Op right; } \
\
template <class Base> \
bool operator Op \
(const Base &left, const VecAD_reference<Base> &right) \
{ return AD<Base>(left) Op right.ADBase(); } \
\
template <class Base> \
bool operator Op \
(const AD<Base> &left, const Base &right) \
{ return left Op AD<Base>(right); } \
\
template <class Base> \
bool operator Op \
(const VecAD_reference<Base> &left, const Base &right) \
{ return left.ADBase() Op AD<Base>(right); } \
\
/* ----------------------------------------------------------------*/ \
/* Operations double */ \
\
template <class Base> \
bool operator Op \
(const double &left, const AD<Base> &right) \
{ return AD<Base>(left) Op right; } \
\
template <class Base> \
bool operator Op \
(const double &left, const VecAD_reference<Base> &right) \
{ return AD<Base>(left) Op right.ADBase(); } \
\
template <class Base> \
bool operator Op \
(const AD<Base> &left, const double &right) \
{ return left Op AD<Base>(right); } \
\
template <class Base> \
bool operator Op \
(const VecAD_reference<Base> &left, const double &right) \
{ return left.ADBase() Op AD<Base>(right); } \
/* ----------------------------------------------------------------*/ \
/* Special case to avoid ambuigity when Base is double */ \
\
inline bool operator Op \
(const double &left, const AD<double> &right) \
{ return AD<double>(left) Op right; } \
\
inline bool operator Op \
(const double &left, const VecAD_reference<double> &right) \
{ return AD<double>(left) Op right.ADBase(); } \
\
inline bool operator Op \
(const AD<double> &left, const double &right) \
{ return left Op AD<double>(right); } \
\
inline bool operator Op \
(const VecAD_reference<double> &left, const double &right) \
{ return left.ADBase() Op AD<double>(right); }
# endif

View File

@@ -0,0 +1,121 @@
# ifndef CPPAD_LOCAL_DISCRETE_OP_HPP
# define CPPAD_LOCAL_DISCRETE_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file discrete_op.hpp
Forward mode for z = f(x) where f is piecewise constant.
*/
/*!
forward mode Taylor coefficient for result of op = DisOp.
The C++ source code corresponding to this operation is
\verbatim
z = f(x)
\endverbatim
where f is a piecewise constant function (and it's derivative is always
calculated as zero).
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base .
\param p
is the lowest order Taylor coefficient that will be calculated.
\param q
is the highest order Taylor coefficient that will be calculated.
\param r
is the number of directions, for each order,
that will be calculated (except for order zero wich only has one direction).
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in taylor corresponding to z.
\param arg
arg[0]
\n
is the index, in the order of the discrete functions defined by the user,
for this discrete function.
\n
\n
arg[1]
variable index corresponding to the argument for this operator;
i.e. the row index in taylor corresponding to x.
\param cap_order
maximum number of orders that will fit in the taylor array.
\par tpv
We use the notation
<code>tpv = (cap_order-1) * r + 1</code>
which is the number of Taylor coefficients per variable
\param taylor
\b Input: <code>taylor [ arg[1] * tpv + 0 ]</code>
is the zero order Taylor coefficient corresponding to x.
\n
\b Output: if <code>p == 0</code>
<code>taylor [ i_z * tpv + 0 ]</code>
is the zero order Taylor coefficient corresponding to z.
For k = max(p, 1), ... , q,
<code>taylor [ i_z * tpv + (k-1)*r + 1 + ell ]</code>
is the k-th order Taylor coefficient corresponding to z
(which is zero).
\par Checked Assertions where op is the unary operator with one result:
\li NumArg(op) == 2
\li NumRes(op) == 1
\li q < cap_order
\li 0 < r
*/
template <class Base>
void forward_dis_op(
size_t p ,
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DisOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DisOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < r );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[1]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
if( p == 0 )
{ z[0] = discrete<Base>::eval(size_t(arg[0]), x[0]);
p++;
}
for(size_t ell = 0; ell < r; ell++)
for(size_t k = p; k <= q; k++)
z[ (k-1) * r + 1 + ell ] = Base(0.0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,574 @@
# ifndef CPPAD_LOCAL_DIV_OP_HPP
# define CPPAD_LOCAL_DIV_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file div_op.hpp
Forward and reverse mode calculations for z = x / y.
*/
// --------------------------- Divvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_divvv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Using CondExp, it can make sense to divide by zero,
// so do not make it an error.
size_t k;
for(size_t d = p; d <= q; d++)
{ z[d] = x[d];
for(k = 1; k <= d; k++)
z[d] -= z[d-k] * y[k];
z[d] /= y[0];
}
}
/*!
Multiple directions forward mode Taylor coefficients for op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_divvv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
// Using CondExp, it can make sense to divide by zero,
// so do not make it an error.
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = x[m+ell] - z[0] * y[m+ell];
for(size_t k = 1; k < q; k++)
z[m+ell] -= z[(q-k-1)*r+1+ell] * y[(k-1)*r+1+ell];
z[m+ell] /= y[0];
}
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_divvv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] / y[0];
}
/*!
Compute reverse mode partial derivatives for result of op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_divvv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
const Base* y = taylor + size_t(arg[1]) * cap_order;
const Base* z = taylor + i_z * cap_order;
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// Using CondExp, it can make sense to divide by zero
// so do not make it an error.
Base inv_y0 = Base(1.0) / y[0];
size_t k;
// number of indices to access
size_t j = d + 1;
while(j)
{ --j;
// scale partial w.r.t. z[j]
pz[j] = azmul(pz[j], inv_y0);
px[j] += pz[j];
for(k = 1; k <= j; k++)
{ pz[j-k] -= azmul(pz[j], y[k] );
py[k] -= azmul(pz[j], z[j-k]);
}
py[0] -= azmul(pz[j], z[j]);
}
}
// --------------------------- Divpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = DivpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_divpv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Paraemter value
Base x = parameter[ arg[0] ];
// Using CondExp, it can make sense to divide by zero,
// so do not make it an error.
size_t k;
if( p == 0 )
{ z[0] = x / y[0];
p++;
}
for(size_t d = p; d <= q; d++)
{ z[d] = Base(0.0);
for(k = 1; k <= d; k++)
z[d] -= z[d-k] * y[k];
z[d] /= y[0];
}
}
/*!
Multiple directions forward mode Taylor coefficients for op = DivpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_divpv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
// Using CondExp, it can make sense to divide by zero,
// so do not make it an error.
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = - z[0] * y[m+ell];
for(size_t k = 1; k < q; k++)
z[m+ell] -= z[(q-k-1)*r+1+ell] * y[(k-1)*r+1+ell];
z[m+ell] /= y[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = DivpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_divpv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x / y[0];
}
/*!
Compute reverse mode partial derivative for result of op = DivpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_divpv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
const Base* y = taylor + size_t(arg[1]) * cap_order;
const Base* z = taylor + i_z * cap_order;
// Partial derivatives corresponding to arguments and result
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// Using CondExp, it can make sense to divide by zero so do not
// make it an error.
Base inv_y0 = Base(1.0) / y[0];
size_t k;
// number of indices to access
size_t j = d + 1;
while(j)
{ --j;
// scale partial w.r.t z[j]
pz[j] = azmul(pz[j], inv_y0);
for(k = 1; k <= j; k++)
{ pz[j-k] -= azmul(pz[j], y[k] );
py[k] -= azmul(pz[j], z[j-k] );
}
py[0] -= azmul(pz[j], z[j]);
}
}
// --------------------------- Divvp -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_divvp_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Parameter value
Base y = parameter[ arg[1] ];
// Using CondExp and multiple levels of AD, it can make sense
// to divide by zero so do not make it an error.
for(size_t d = p; d <= q; d++)
z[d] = x[d] / y;
}
/*!
Multiple direction forward mode Taylor coefficients for op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_divvp_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
// Parameter value
Base y = parameter[ arg[1] ];
// Using CondExp and multiple levels of AD, it can make sense
// to divide by zero so do not make it an error.
size_t m = (q-1)*r + 1;
for(size_t ell = 0; ell < r; ell++)
z[m + ell] = x[m + ell] / y;
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = DivvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_divvp_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 );
// Parameter value
Base y = parameter[ arg[1] ];
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] / y;
}
/*!
Compute reverse mode partial derivative for result of op = DivvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = x / y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_divvp_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Argument values
Base y = parameter[ arg[1] ];
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// Using CondExp, it can make sense to divide by zero
// so do not make it an error.
Base inv_y = Base(1.0) / y;
// number of indices to access
size_t j = d + 1;
while(j)
{ --j;
px[j] += azmul(pz[j], inv_y);
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,598 @@
# ifndef CPPAD_LOCAL_ERF_OP_HPP
# define CPPAD_LOCAL_ERF_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/mul_op.hpp>
# include <cppad/local/sub_op.hpp>
# include <cppad/local/exp_op.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file erf_op.hpp
Forward and reverse mode calculations for z = erf(x) or erfc(x).
*/
/*!
Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp.
The C++ source code corresponding to this operation is one of
\verbatim
z = erf(x)
z = erfc(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type Base.
\param op
must be either ErfOp or ErfcOp and indicates if this is
z = erf(x) or z = erfc(x).
\param p
lowest order of the Taylor coefficients that we are computing.
\param q
highest order of the Taylor coefficients that we are computing.
\param i_z
variable index corresponding to the last (primary) result for this operation;
i.e. the row index in taylor corresponding to z.
The auxillary results are called y_j have index i_z - j.
\param arg
arg[0]: is the variable index corresponding to x.
\n
arg[1]: is the parameter index corresponding to the value zero.
\n
arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi).
\param parameter
parameter[ arg[1] ] is the value zero,
and parameter[ arg[2] ] is the value 2 / sqrt(pi).
\param cap_order
maximum number of orders that will fit in the taylor array.
\param taylor
\b Input:
taylor [ size_t(arg[0]) * cap_order + k ]
for k = 0 , ... , q,
is the k-th order Taylor coefficient corresponding to x.
\n
\b Input:
taylor [ i_z * cap_order + k ]
for k = 0 , ... , p - 1,
is the k-th order Taylor coefficient corresponding to z.
\n
\b Input:
taylor [ ( i_z - j) * cap_order + k ]
for k = 0 , ... , p-1,
and j = 0 , ... , 4,
is the k-th order Taylor coefficient corresponding to the j-th result for z.
\n
\b Output:
taylor [ (i_z-j) * cap_order + k ],
for k = p , ... , q,
and j = 0 , ... , 4,
is the k-th order Taylor coefficient corresponding to the j-th result for z.
*/
template <class Base>
void forward_erf_op(
OpCode op ,
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp );
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z + 2
);
// array used to pass parameter values for sub-operations
addr_t addr[2];
// convert from final result to first result
i_z -= 4; // 4 = NumRes(ErfOp) - 1;
// z_0 = x * x
addr[0] = arg[0]; // x
addr[1] = arg[0]; // x
forward_mulvv_op(p, q, i_z+0, addr, parameter, cap_order, taylor);
// z_1 = - x * x
addr[0] = arg[1]; // zero
addr[1] = addr_t( i_z ); // z_0
forward_subpv_op(p, q, i_z+1, addr, parameter, cap_order, taylor);
// z_2 = exp( - x * x )
forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor);
// z_3 = (2 / sqrt(pi)) * exp( - x * x )
addr[0] = arg[2]; // 2 / sqrt(pi)
addr[1] = addr_t( i_z + 2 ); // z_2
forward_mulpv_op(p, q, i_z+3, addr, parameter, cap_order, taylor);
// pointers to taylor coefficients for x , z_3, and z_4
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z_3 = taylor + (i_z+3) * cap_order;
Base* z_4 = taylor + (i_z+4) * cap_order;
// calculte z_4 coefficients
if( p == 0 )
{ // z4 (t) = erf[x(t)]
if( op == ErfOp )
z_4[0] = erf(x[0]);
else
z_4[0] = erfc(x[0]);
p++;
}
// sign
Base sign(1.0);
if( op == ErfcOp )
sign = Base(-1.0);
//
for(size_t j = p; j <= q; j++)
{ // erf: z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t)
// erfc: z_4' (t) = - erf'[x(t)] * x'(t) = - z3(t) * x'(t)
// z_4[1] + 2 * z_4[2] * t + ... =
// sign * (z_3[0] + z_3[1] * t + ...) * (x[1] + 2 * x[2] * t + ...)
Base base_j = static_cast<Base>(double(j));
z_4[j] = static_cast<Base>(0);
for(size_t k = 1; k <= j; k++)
z_4[j] += sign * (Base(double(k)) / base_j) * x[k] * z_3[j-k];
}
}
/*!
Zero order Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp.
The C++ source code corresponding to this operation one of
\verbatim
z = erf(x)
z = erfc(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type Base.
\param op
must be either ErfOp or ErfcOp and indicates if this is
z = erf(x) or z = erfc(x).
\param i_z
variable index corresponding to the last (primary) result for this operation;
i.e. the row index in taylor corresponding to z.
The auxillary results are called y_j have index i_z - j.
\param arg
arg[0]: is the variable index corresponding to x.
\n
arg[1]: is the parameter index corresponding to the value zero.
\n
arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi).
\param parameter
parameter[ arg[1] ] is the value zero,
and parameter[ arg[2] ] is the value 2 / sqrt(pi).
\param cap_order
maximum number of orders that will fit in the taylor array.
\param taylor
\b Input:
taylor [ size_t(arg[0]) * cap_order + 0 ]
is the zero order Taylor coefficient corresponding to x.
\n
\b Input:
taylor [ i_z * cap_order + 0 ]
is the zero order Taylor coefficient corresponding to z.
\n
\b Output:
taylor [ (i_z-j) * cap_order + 0 ],
for j = 0 , ... , 4,
is the zero order Taylor coefficient for j-th result corresponding to z.
*/
template <class Base>
void forward_erf_op_0(
OpCode op ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp );
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z + 2
);
// array used to pass parameter values for sub-operations
addr_t addr[2];
// convert from final result to first result
i_z -= 4; // 4 = NumRes(ErfOp) - 1;
// z_0 = x * x
addr[0] = arg[0]; // x
addr[1] = arg[0]; // x
forward_mulvv_op_0(i_z+0, addr, parameter, cap_order, taylor);
// z_1 = - x * x
addr[0] = arg[1]; // zero
addr[1] = addr_t(i_z); // z_0
forward_subpv_op_0(i_z+1, addr, parameter, cap_order, taylor);
// z_2 = exp( - x * x )
forward_exp_op_0(i_z+2, i_z+1, cap_order, taylor);
// z_3 = (2 / sqrt(pi)) * exp( - x * x )
addr[0] = arg[2]; // 2 / sqrt(pi)
addr[1] = addr_t(i_z + 2); // z_2
forward_mulpv_op_0(i_z+3, addr, parameter, cap_order, taylor);
// zero order Taylor coefficient for z_4
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z_4 = taylor + (i_z + 4) * cap_order;
if( op == ErfOp )
z_4[0] = erf(x[0]);
else
z_4[0] = erfc(x[0]);
}
/*!
Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp.
The C++ source code corresponding to this operation is one of
\verbatim
z = erf(x)
z = erfc(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type Base.
\param op
must be either ErfOp or ErfcOp and indicates if this is
z = erf(x) or z = erfc(x).
\param q
order of the Taylor coefficients that we are computing.
\param r
number of directions for the Taylor coefficients that we afre computing.
\param i_z
variable index corresponding to the last (primary) result for this operation;
i.e. the row index in taylor corresponding to z.
The auxillary results have index i_z - j for j = 0 , ... , 4
(and include z).
\param arg
arg[0]: is the variable index corresponding to x.
\n
arg[1]: is the parameter index corresponding to the value zero.
\n
arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi).
\param parameter
parameter[ arg[1] ] is the value zero,
and parameter[ arg[2] ] is the value 2 / sqrt(pi).
\param cap_order
maximum number of orders that will fit in the taylor array.
\par tpv
We use the notation
<code>tpv = (cap_order-1) * r + 1</code>
which is the number of Taylor coefficients per variable
\param taylor
\b Input: If x is a variable,
<code>taylor [ arg[0] * tpv + 0 ]</code>,
is the zero order Taylor coefficient for all directions and
<code>taylor [ arg[0] * tpv + (k-1)*r + ell + 1 ]</code>,
for k = 1 , ... , q,
ell = 0, ..., r-1,
is the k-th order Taylor coefficient
corresponding to x and the ell-th direction.
\n
\b Input:
taylor [ (i_z - j) * tpv + 0 ]
is the zero order Taylor coefficient for all directions and the
j-th result for z.
for k = 1 , ... , q-1,
ell = 0, ... , r-1,
<code>
taylor[ (i_z - j) * tpv + (k-1)*r + ell + 1]
</code>
is the Taylor coefficient for the k-th order, ell-th direction,
and j-th auzillary result.
\n
\b Output:
taylor [ (i_z-j) * tpv + (q-1)*r + ell + 1 ],
for ell = 0 , ... , r-1,
is the Taylor coefficient for the q-th order, ell-th direction,
and j-th auzillary result.
*/
template <class Base>
void forward_erf_op_dir(
OpCode op ,
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp );
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z + 2
);
// array used to pass parameter values for sub-operations
addr_t addr[2];
// convert from final result to first result
i_z -= 4; // 4 = NumRes(ErfOp) - 1;
// z_0 = x * x
addr[0] = arg[0]; // x
addr[1] = arg[0]; // x
forward_mulvv_op_dir(q, r, i_z+0, addr, parameter, cap_order, taylor);
// z_1 = - x * x
addr[0] = arg[1]; // zero
addr[1] = addr_t( i_z ); // z_0
forward_subpv_op_dir(q, r, i_z+1, addr, parameter, cap_order, taylor);
// z_2 = exp( - x * x )
forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor);
// z_3 = (2 / sqrt(pi)) * exp( - x * x )
addr[0] = arg[2]; // 2 / sqrt(pi)
addr[1] = addr_t( i_z + 2 ); // z_2
forward_mulpv_op_dir(q, r, i_z+3, addr, parameter, cap_order, taylor);
// pointers to taylor coefficients for x , z_3, and z_4
size_t num_taylor_per_var = (cap_order - 1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* z_3 = taylor + (i_z+3) * num_taylor_per_var;
Base* z_4 = taylor + (i_z+4) * num_taylor_per_var;
// sign
Base sign(1.0);
if( op == ErfcOp )
sign = Base(-1.0);
// erf: z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t)
// erfc: z_4' (t) = - erf'[x(t)] * x'(t) = z3(t) * x'(t)
// z_4[1] + 2 * z_4[2] * t + ... =
// sign * (z_3[0] + z_3[1] * t + ...) * (x[1] + 2 * x[2] * t + ...)
Base base_q = static_cast<Base>(double(q));
for(size_t ell = 0; ell < r; ell++)
{ // index in z_4 and x for q-th order term
size_t m = (q-1)*r + ell + 1;
// initialize q-th order term summation
z_4[m] = sign * z_3[0] * x[m];
for(size_t k = 1; k < q; k++)
{ size_t x_index = (k-1)*r + ell + 1;
size_t z3_index = (q-k-1)*r + ell + 1;
Base bk = Base(double(k));
z_4[m] += sign * (bk / base_q) * x[x_index] * z_3[z3_index];
}
}
}
/*!
Compute reverse mode partial derivatives for result of op = ErfOp or ErfcOp.
The C++ source code corresponding to this operation is one of
\verbatim
z = erf(x)
z = erfc(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type Base.
\param op
must be either ErfOp or ErfcOp and indicates if this is
z = erf(x) or z = erfc(x).
\param d
highest order Taylor of the Taylor coefficients that we are computing
the partial derivatives with respect to.
\param i_z
variable index corresponding to the last (primary) result for this operation;
i.e. the row index in taylor corresponding to z.
The auxillary results are called y_j have index i_z - j.
\param arg
arg[0]: is the variable index corresponding to x.
\n
arg[1]: is the parameter index corresponding to the value zero.
\n
arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi).
\param parameter
parameter[ arg[1] ] is the value zero,
and parameter[ arg[2] ] is the value 2 / sqrt(pi).
\param cap_order
maximum number of orders that will fit in the taylor array.
\param taylor
\b Input:
taylor [ size_t(arg[0]) * cap_order + k ]
for k = 0 , ... , d,
is the k-th order Taylor coefficient corresponding to x.
\n
taylor [ (i_z - j) * cap_order + k ]
for k = 0 , ... , d,
and for j = 0 , ... , 4,
is the k-th order Taylor coefficient corresponding to the j-th result
for this operation.
\param nc_partial
number of columns in the matrix containing all the partial derivatives
\param partial
\b Input:
partial [ size_t(arg[0]) * nc_partial + k ]
for k = 0 , ... , d,
is the partial derivative of G( z , x , w , u , ... ) with respect to
the k-th order Taylor coefficient for x.
\n
\b Input:
partial [ (i_z - j) * nc_partial + k ]
for k = 0 , ... , d,
and for j = 0 , ... , 4,
is the partial derivative of G( z , x , w , u , ... ) with respect to
the k-th order Taylor coefficient for the j-th result of this operation.
\n
\b Output:
partial [ size_t(arg[0]) * nc_partial + k ]
for k = 0 , ... , d,
is the partial derivative of H( x , w , u , ... ) with respect to
the k-th order Taylor coefficient for x.
\n
\b Output:
partial [ (i_z-j) * nc_partial + k ]
for k = 0 , ... , d,
and for j = 0 , ... , 4,
may be used as work space; i.e., may change in an unspecified manner.
*/
template <class Base>
void reverse_erf_op(
OpCode op ,
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp );
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z + 2
);
// array used to pass parameter values for sub-operations
addr_t addr[2];
// If pz is zero, make sure this operation has no effect
// (zero times infinity or nan would be non-zero).
Base* pz = partial + i_z * nc_partial;
bool skip(true);
for(size_t i_d = 0; i_d <= d; i_d++)
skip &= IdenticalZero(pz[i_d]);
if( skip )
return;
// convert from final result to first result
i_z -= 4; // 4 = NumRes(ErfOp) - 1;
// Taylor coefficients and partials corresponding to x
const Base* x = taylor + size_t(arg[0]) * cap_order;
Base* px = partial + size_t(arg[0]) * nc_partial;
// Taylor coefficients and partials corresponding to z_3
const Base* z_3 = taylor + (i_z+3) * cap_order;
Base* pz_3 = partial + (i_z+3) * nc_partial;
// Taylor coefficients and partials corresponding to z_4
Base* pz_4 = partial + (i_z+4) * nc_partial;
// sign
Base sign(1.0);
if( op == ErfcOp )
sign = Base(-1.0);
// Reverse z_4
size_t j = d;
while(j)
{ pz_4[j] /= Base(double(j));
for(size_t k = 1; k <= j; k++)
{ px[k] += sign * azmul(pz_4[j], z_3[j-k]) * Base(double(k));
pz_3[j-k] += sign * azmul(pz_4[j], x[k]) * Base(double(k));
}
j--;
}
px[0] += sign * azmul(pz_4[0], z_3[0]);
// z_3 = (2 / sqrt(pi)) * exp( - x * x )
addr[0] = arg[2]; // 2 / sqrt(pi)
addr[1] = addr_t( i_z + 2 ); // z_2
reverse_mulpv_op(
d, i_z+3, addr, parameter, cap_order, taylor, nc_partial, partial
);
// z_2 = exp( - x * x )
reverse_exp_op(
d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial
);
// z_1 = - x * x
addr[0] = arg[1]; // zero
addr[1] = addr_t( i_z ); // z_0
reverse_subpv_op(
d, i_z+1, addr, parameter, cap_order, taylor, nc_partial, partial
);
// z_0 = x * x
addr[0] = arg[0]; // x
addr[1] = arg[0]; // x
reverse_mulvv_op(
d, i_z+0, addr, parameter, cap_order, taylor, nc_partial, partial
);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif // CPPAD_ERF_OP_INCLUDED

View File

@@ -0,0 +1,194 @@
# ifndef CPPAD_LOCAL_EXP_OP_HPP
# define CPPAD_LOCAL_EXP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file exp_op.hpp
Forward and reverse mode calculations for z = exp(x).
*/
/*!
Forward mode Taylor coefficient for result of op = ExpOp.
The C++ source code corresponding to this operation is
\verbatim
z = exp(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_exp_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
size_t k;
if( p == 0 )
{ z[0] = exp( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
z[j] = x[1] * z[j-1];
for(k = 2; k <= j; k++)
z[j] += Base(double(k)) * x[k] * z[j-k];
z[j] /= Base(double(j));
}
}
/*!
Multiple direction forward mode Taylor coefficient for op = ExpOp.
The C++ source code corresponding to this operation is
\verbatim
z = exp(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_exp_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1)*r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * x[m+ell] * z[0];
for(size_t k = 1; k < q; k++)
z[m+ell] += Base(double(k)) * x[(k-1)*r+ell+1] * z[(q-k-1)*r+ell+1];
z[m+ell] /= Base(double(q));
}
}
/*!
Zero order forward mode Taylor coefficient for result of op = ExpOp.
The C++ source code corresponding to this operation is
\verbatim
z = exp(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_exp_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = exp( x[0] );
}
/*!
Reverse mode partial derivatives for result of op = ExpOp.
The C++ source code corresponding to this operation is
\verbatim
z = exp(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_exp_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// If pz is zero, make sure this operation has no effect
// (zero times infinity or nan would be non-zero).
bool skip(true);
for(size_t i_d = 0; i_d <= d; i_d++)
skip &= IdenticalZero(pz[i_d]);
if( skip )
return;
// loop through orders in reverse
size_t j, k;
j = d;
while(j)
{ // scale partial w.r.t z[j]
pz[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{ px[k] += Base(double(k)) * azmul(pz[j], z[j-k]);
pz[j-k] += Base(double(k)) * azmul(pz[j], x[k]);
}
--j;
}
px[0] += azmul(pz[0], z[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,199 @@
# ifndef CPPAD_LOCAL_EXPM1_OP_HPP
# define CPPAD_LOCAL_EXPM1_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file expm1_op.hpp
Forward and reverse mode calculations for z = expm1(x).
*/
/*!
Forward mode Taylor coefficient for result of op = Expm1Op.
The C++ source code corresponding to this operation is
\verbatim
z = expm1(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_expm1_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
size_t k;
if( p == 0 )
{ z[0] = expm1( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
z[j] = x[1] * z[j-1];
for(k = 2; k <= j; k++)
z[j] += Base(double(k)) * x[k] * z[j-k];
z[j] /= Base(double(j));
z[j] += x[j];
}
}
/*!
Multiple direction forward mode Taylor coefficient for op = Expm1Op.
The C++ source code corresponding to this operation is
\verbatim
z = expm1(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_expm1_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1)*r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * x[m+ell] * z[0];
for(size_t k = 1; k < q; k++)
z[m+ell] += Base(double(k)) * x[(k-1)*r+ell+1] * z[(q-k-1)*r+ell+1];
z[m+ell] /= Base(double(q));
z[m+ell] += x[m+ell];
}
}
/*!
Zero order forward mode Taylor coefficient for result of op = Expm1Op.
The C++ source code corresponding to this operation is
\verbatim
z = expm1(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_expm1_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = expm1( x[0] );
}
/*!
Reverse mode partial derivatives for result of op = Expm1Op.
The C++ source code corresponding to this operation is
\verbatim
z = expm1(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_expm1_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
// If pz is zero, make sure this operation has no effect
// (zero times infinity or nan would be non-zero).
bool skip(true);
for(size_t i_d = 0; i_d <= d; i_d++)
skip &= IdenticalZero(pz[i_d]);
if( skip )
return;
// loop through orders in reverse
size_t j, k;
j = d;
while(j)
{ px[j] += pz[j];
// scale partial w.r.t z[j]
pz[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{ px[k] += Base(double(k)) * azmul(pz[j], z[j-k]);
pz[j-k] += Base(double(k)) * azmul(pz[j], x[k]);
}
--j;
}
px[0] += pz[0] + azmul(pz[0], z[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,386 @@
# ifndef CPPAD_LOCAL_GRAPH_CPP_GRAPH_ITR_HPP
# define CPPAD_LOCAL_GRAPH_CPP_GRAPH_ITR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/utility/vector.hpp>
# include <cppad/local/graph/cpp_graph_op.hpp>
// BEGIN_CPPAD_LOCAL_GRAPH_NAMESPACE
namespace CppAD { namespace local { namespace graph {
class cpp_graph_itr {
/*
$begin cpp_graph_itr_data$$
$spell
Iterator
$$
$section C++ AD Graph Iterator Private Member Data$$
$srccode%hpp% */
private:
// valuse set by constructor
const vector<graph_op_enum>* operator_vec_;
const vector<size_t>* operator_arg_;
//
// set by constructor and ++
size_t op_index_;
size_t first_arg_;
//
// set by get_value
size_t first_node_;
graph_op_enum op_enum_;
vector<size_t> str_index_;
size_t n_result_;
vector<size_t> arg_node_;
/* %$$
$end
------------------------------------------------------------------------------
$begin cpp_graph_itr_get_value$$
$spell
obj
op
arg
vec
enum
Iterator
itr
str
$$
$section C++ AD Graph Iterator get_value()$$
$head Syntax$$
$icode%itr%.get_value()%$$
$head op_index_$$
This input is the operator index for the value we are retrieving.
$head first_arg_$$
This input is the first argument index for the value we are retrieving.
$head first_node_$$
The input value of this argument does not matter.
It is set to the index in $code operator_arg_$$
of the first node argument for this operator.
$head op_enum_$$
The input value of this argument does not matter.
It is set to the $cref graph_op_enum$$ for the operator
$head str_index_$$
The input value of this argument does not matter.
Upon return its size is zero except for the special cases
listed below:
$subhead atom_graph_op$$
If $icode op_enum_$$ is $code atom_graph_op$$,
$code str_index_.size() == 1$$ and
$code str_index_[0]$$ is the index in
$cref/atomic_name_vec/cpp_ad_graph/atomic_name_vec/$$
for the function called by this operator.
$subhead discrete_graph_op$$
If $icode op_enum_$$ is $code discrete_graph_op$$,
$code str_index_.size() == 1$$ and
$code str_index_[0]$$ is the index in
$cref/discrete_name_vec/cpp_ad_graph/discrete_name_vec/$$
for the function called by this operator.
$subhead print_graph_op$$
If $icode op_enum_$$ is $code print_graph_op$$,
$code str_index_.size() == 2$$ and
$code str_index_[0]$$ ( $code str_index_[1]$$ )
is the index in
$cref/print_text_vec/cpp_ad_graph/print_text_vec/$$ for the
$cref/before/PrintFor/before/$$ ($cref/after/PrintFor/after/$$) text.
$head n_result_$$
The input value of this argument does not matter.
This is set to the number of result nodes for this operator.
$head arg_node_$$
The input value of this argument does not matter.
Upon return, its size is the number of arguments,
that are node indices, for this operator usage.
The value of the elements are the node indices.
$head Prototype$$
$srccode%hpp% */
void get_value(void)
/* %$$
$end
*/
{ // initialize output values
size_t invalid_index = std::numeric_limits<size_t>::max();
size_t n_arg = invalid_index;
first_node_ = invalid_index;
n_result_ = invalid_index;
str_index_.resize(0);
arg_node_.resize(0);
//
// op_enum
op_enum_ = (*operator_vec_)[op_index_];
//
// n_result_, n_arg, str_index_
switch( op_enum_ )
{
// unary operators
case abs_graph_op:
case acos_graph_op:
case acosh_graph_op:
case asin_graph_op:
case asinh_graph_op:
case atan_graph_op:
case atanh_graph_op:
case cos_graph_op:
case cosh_graph_op:
case erf_graph_op:
case erfc_graph_op:
case exp_graph_op:
case expm1_graph_op:
case log1p_graph_op:
case log_graph_op:
case sign_graph_op:
case sin_graph_op:
case sinh_graph_op:
case sqrt_graph_op:
case tan_graph_op:
case tanh_graph_op:
first_node_ = first_arg_;
n_result_ = 1;
n_arg = 1;
break;
// binary operators
case add_graph_op:
case azmul_graph_op:
case div_graph_op:
case mul_graph_op:
case pow_graph_op:
case sub_graph_op:
first_node_ = first_arg_;
n_result_ = 1;
n_arg = 2;
break;
// discrete_graph_op
case discrete_graph_op:
first_node_ = first_arg_ + 1;
str_index_.push_back( (*operator_arg_)[first_node_ - 1] );
n_result_ = 1;
n_arg = 1;
break;
// atom_graph_op
case atom_graph_op:
first_node_ = first_arg_ + 3;
str_index_.push_back( (*operator_arg_)[first_node_ - 3] );
n_result_ = (*operator_arg_)[first_node_ - 2];
n_arg = (*operator_arg_)[first_node_ - 1];
break;
// print_graph_op
case print_graph_op:
first_node_ = first_arg_ + 2;
str_index_.push_back( (*operator_arg_)[first_node_ - 2] );
str_index_.push_back( (*operator_arg_)[first_node_ - 1] );
n_result_ = 0;
n_arg = 2;
break;
// conditional expressions
case cexp_eq_graph_op:
case cexp_le_graph_op:
case cexp_lt_graph_op:
first_node_ = first_arg_;
n_result_ = 1;
n_arg = 4;
break;
// comparison operators
case comp_eq_graph_op:
case comp_le_graph_op:
case comp_lt_graph_op:
case comp_ne_graph_op:
first_node_ = first_arg_;
n_result_ = 0;
n_arg = 2;
break;
// sum_graph_op
case sum_graph_op:
first_node_ = first_arg_ + 1;
n_result_ = 1;
n_arg = (*operator_arg_)[first_node_ - 1];
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
break;
}
// set arg_node
arg_node_.resize(n_arg);
for(size_t i = 0; i < n_arg; i++)
arg_node_[i] = (*operator_arg_)[first_node_ + i];
return;
}
/* %$$
$end
-------------------------------------------------------------------------------
$begin cpp_graph_itr_types$$
$spell
Iterator
$$
$section C++ AD Graph Iterator Types$$
$srccode%hpp% */
public:
typedef struct {
graph_op_enum op_enum;
const vector<size_t>* str_index_ptr;
size_t n_result;
const vector<size_t>* arg_node_ptr;
} value_type;
typedef std::input_iterator_tag iterator_category;
/* %$$
$end
------------------------------------------------------------------------------
$begin cpp_graph_itr_ctor$$
$spell
Iterator
itr
vec
arg
op
cpp
$$
$section C++ AD Graph Iterator Constructors$$
$head Syntax$$
$codei%cpp_graph_itr %default%
%$$
$codei%cpp_graph_itr %itr%(%operator_vec%, %operator_arg%, %op_index%
%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_CTOR%// END_CTOR%1
%$$
$head default$$
The result of the default constructor can only be used as a target
for the assignment operator.
$head operator_vec$$
Is the $cref/operator_vec/cpp_ad_graph/operator_vec/$$
for the $code cpp_graph$$ container that this iterator refers to.
$head operator_arg$$
Is the $cref/operator_arg/cpp_ad_graph/operator_vec/$$
for the $code cpp_graph$$ container that this iterator refers to.
$head op_index$$
This must be either zero (the $code begin()$$ for the container)
or equal to the size of $icode operator_vec$$
(the $code end()$$ for the container).
$end
*/
cpp_graph_itr(void)
: operator_vec_(nullptr), operator_arg_(nullptr)
{ }
// BEGIN_CTOR
cpp_graph_itr(
const vector<graph_op_enum>& operator_vec ,
const vector<size_t>& operator_arg ,
size_t op_index )
// END_CTOR
:
operator_vec_(&operator_vec) ,
operator_arg_(&operator_arg) ,
op_index_(op_index)
{ // end constructor
if( op_index == operator_vec.size() )
return;
//
// begin constructor
CPPAD_ASSERT_KNOWN( op_index == 0,
"cpp_graph_itr: constructor op_index not 0 or operator_vec.size()"
);
// start at the beginning of operator_vec
first_arg_ = 0;
//
// get the value, and first_node_, for this operator
get_value();
}
/* %$$
------------------------------------------------------------------------------
$begin cpp_graph_itr_input$$
$spell
Iterator
$$
$section C++ AD Graph Iterator Input Operations$$
$srccode%hpp% */
// itr == other
bool operator==(const cpp_graph_itr& other) const
{ return op_index_ == other.op_index_;
}
// itr != other
bool operator!=(const cpp_graph_itr& other) const
{ return op_index_ != other.op_index_;
}
// *itr
value_type operator*(void)
{ CPPAD_ASSERT_KNOWN( operator_vec_ != nullptr,
"cpp_graph_itr: attempt to dereference default iterator"
);
CPPAD_ASSERT_KNOWN( op_index_ < operator_vec_->size(),
"cpp_graph_itr: attempt to dereference past last element in graph"
);
value_type ret;
ret.op_enum = op_enum_;
ret.str_index_ptr = &str_index_;
ret.n_result = n_result_;
ret.arg_node_ptr = &arg_node_;
return ret;
}
// ++itr
cpp_graph_itr& operator++(void)
{ ++op_index_;
first_arg_ = first_node_ + arg_node_.size();
get_value();
return *this;
}
// itr++
cpp_graph_itr operator++(int)
{ cpp_graph_itr ret(*this);
++op_index_;
first_arg_ = first_node_ + arg_node_.size();
get_value();
return ret;
}
/* %$$
$end
*/
};
} } } // END_CPPAD_LOCAL_GRAPH_NAMESPACE
# endif

View File

@@ -0,0 +1,23 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-------------------------------------------------------------------------- */
$begin cpp_graph_itr$$
$spell
Iterator
$$
$section C++ AD Graph Iterator Class$$
$childtable%
include/cppad/local/graph/cpp_graph_itr.hpp
%$$
$end

View File

@@ -0,0 +1,94 @@
# ifndef CPPAD_LOCAL_GRAPH_CPP_GRAPH_OP_HPP
# define CPPAD_LOCAL_GRAPH_CPP_GRAPH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-------------------------------------------------------------------------- */
# include <cstddef>
# include <string>
# include <map>
# include <cppad/utility/vector.hpp>
# include <cppad/configure.hpp>
# include <cppad/core/graph/graph_op_enum.hpp>
namespace CppAD { namespace local { namespace graph {
/*
$begin cpp_graph_op$$
$spell
vec
asinh
acosh
atanh
erf
erfc
expm
namespace
enum
struct
op
arg
CppAD
addr_t
$$
$section C++ AD Graph Operators$$
$head Namespace$$
All of these definitions
are in the $code CppAD::local::graph$$ namespace.
$head CppAD::graph$$
$srccode%hpp% */
using namespace CppAD::graph;
/* %$$
$head addr_t$$
$srccode%hpp% */
typedef CPPAD_TAPE_ADDR_TYPE addr_t;
/* %$$
$head op_name2enum$$
This is a mapping from the operator name to its enum value.
The name is the operator enum without the $code _operator$$ at the end.
$srccode%hpp% */
extern std::map< std::string, graph_op_enum > op_name2enum;
/* %$$
$head op_enum2fixed_n_arg$$
This is the number of arguments for the operators that have
a fixed number of arguments and one result.
For other operators, this value is zero.
$srccode%hpp% */
extern size_t op_enum2fixed_n_arg[];
/* %$$
$head op_enum2name$$
This is mapping from operator enum value to its name.
In the $code local::graph$$ namespace:
$srccode%hpp% */
extern const char* op_enum2name[];
/* %$$
$head set_operator_info$$
This routine sets the values in
$code op_enum2fixed_n_arg$$,
$code op_enum2name$$, and
$code op_name2enum$$.
$srccode%hpp% */
extern void set_operator_info(void);
/* %$$
$end
*/
} } } // END_CPPAD_LOCAL_GRAPH_NAMESPACE
# endif

View File

@@ -0,0 +1,28 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-----------------------------------------------------------------------------
$begin dev_graph$$
$spell
Json
$$
$section Developer AD Graph Documentation$$
$childtable%
include/cppad/local/graph/cpp_graph_itr.omh%
include/cppad/local/graph/cpp_graph_op.hpp%
include/cppad/local/graph/json_lexer.omh%
include/cppad/local/graph/json_parser.hpp%
include/cppad/local/graph/json_writer.hpp
%$$
$end

View File

@@ -0,0 +1,389 @@
# ifndef CPPAD_LOCAL_GRAPH_JSON_LEXER_HPP
# define CPPAD_LOCAL_GRAPH_JSON_LEXER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-------------------------------------------------------------------------- */
# include <string>
# include <cppad/core/cppad_assert.hpp>
// BEGIN_NAMESPACE_CPPAD_LOCAL_GRAPH
namespace CppAD { namespace local { namespace graph {
// ===========================================================================
class json_lexer {
// ===========================================================================
/*
-------------------------------------------------------------------------------
$begin json_lexer_member_data$$
$spell
json
lexer
$$
$section json lexer: Private Data$$
$head graph_$$
The $cref json_ad_graph$$.
$head index_$$
is the index in the graph for the current character.
If a token is returned, this corresponds to the last character
it the token.
$head line_number_$$
line number in the graph for the current character
$head char_number_$$
character number in the graph for the current character
$head token_$$
used to return tokens.
$head function_name_$$
is the function name for this graph.
This is initialized as empty,
should be set as soon as it is parsed,
and is used for error reporting.
$head token$$
returns current value of $code token_$$.
$head line_number$$
returns current value of $code line_number_$$
(which corresponds to last character in the token).
$head char_number$$
returns current value of $code char_number_$$.
(which corresponds to last character in the token).
$head set_function_name$$
sets the value of $code function_name_$$.
$head Source Code$$
$srccode%hpp% */
private:
const std::string& json_;
size_t index_;
size_t line_number_;
size_t char_number_;
std::string token_;
std::string function_name_;
public:
const std::string& token(void) const;
size_t line_number(void) const;
size_t char_number(void) const;
void set_function_name(const std::string& function_name);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_report_error$$
$spell
json
lexer
CppAD
$$
$section json lexer: Report an Error$$
$head Syntax$$
$codei%
%json_lexer%.report_error(%expected%, %found%)
%$$
$head json_lexer$$
is a $code local::graph::json_lexer$$ object.
$head expected$$
is the token that is expected.
$head found$$
is the token or text that was found.
$head Report$$
The current CppAD $cref ErrorHandler$$ is used to report
an error parsing this Json AD graph.
$head Prototype$$
$srccode%hpp% */
public:
void report_error(const std::string& expected, const std::string& found);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_next_index$$
$spell
json
lexer
$$
$section json lexer: Advance Index by One$$
$head Syntax$$
$codei%
%json_lexer%.next_index()
%$$
$head json_lexer$$
is a $code local::graph::json_lexer$$ object.
$head index_$$
The input value of $code index_$$ is increased by one.
It is an error to call this routine when the input value
of $code index_$$ is greater than or equal $code json_.size()$$.
$head line_number_$$
If the previous character, before the call, was a new line,
$code line_number_$$ is increased by one.
$head char_number_$$
If the previous character, before the call, was a new line,
$code char_number$$ is set to one.
Otherwise, $code char_number_$$ is increased by one.
$head Prototype$$
$srccode%hpp% */
private:
void next_index(void);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_skip_white_space$$
$spell
json
lexer
$$
$section json lexer: Skip White Space That Separates Tokens$$
$head Syntax$$
$codei%
%json_lexer%.skip_white_space()
%$$
$head json_lexer$$
is a json lexer object.
$head Discussion$$
This member functions is used to increase $code index_$$ until either
a non-white space character is found or $code index_$$ is equal
to $code json_.size()$$.
$head Prototype$$
$srccode%hpp% */
private:
void skip_white_space(void);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_constructor$$
$spell
json
lexer
enum
op
arg
$$
$section json lexer: Constructor$$
$head Syntax$$
$codei%
local::graph::lexer %json_lexer%(%json%)
%$$
$head json$$
The argument $icode json$$ is an $cref json_ad_graph$$
and it is assumed that $icode json$$ does not change
for as long as $icode json_lexer$$ exists.
$head Initialization$$
The current token, index, line number, and character number
are set to the first non white space character in $code json_$$.
If this is not a left brace character $code '{'$$,
the error is reported and the constructor does not return.
$head Side Effect$$
If $code local::graph::op_name2enum.size() == 0$$,
the routine $cref/set_operator_info/cpp_graph_op/set_operator_info/$$
is called to initialize
$code op_enum2fixed_n_arg$$,
$code op_enum2name$$, and
$code op_name2enum$$.
This initialization cannot be done in
$cref/parallel mode/ta_in_parallel/$$.
$head Prototype$$
$srccode%hpp% */
public:
json_lexer(const std::string& json);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_check_next_char$$
$spell
json
lexer
ch
$$
$section Get and Check Next Single Character Token$$
$head Syntax$$
$codei%
%json_lexer%.check_next_char(%ch%)
%$$
$head index_$$
The search for the character starts
at one greater than the input value for $code index_$$ and skips white space.
$head ch$$
Is a non white space
single character token that is expected.
If this character is not found,
the error is reported and this function does not return.
In the special case where $icode ch$$ is $code '\0'$$,
any non-white space character will be accepted
(but there must be such a character).
$head token_$$
If this routine returns, $code token_$$ has size one
and contains the character that is found.
$head Prototype$$
$srccode%hpp% */
public:
void check_next_char(char ch);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_check_next_string$$
$spell
json
lexer
$$
$section Get and Check Next Single Character Token$$
$head Syntax$$
$codei%
%json_lexer%.check_next_string(%expected%)
%$$
$head index_$$
The search for the string starts
at one greater than the input value for $code index_$$ and skips white space.
$head expected$$
Is the value (not including double quotes) for the string that is expected.
If this string is not found, the error is reported
and this function does not return.
In the special case where $icode expected$$ is empty,
any string will be accepted.
$head token_$$
If this routine returns,
$icode token_$$ is the string that was found.
$head Prototype$$
$srccode%hpp% */
public:
void check_next_string(const std::string& expected);
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_next_non_neg_int$$
$spell
json
lexer
neg
$$
$section Get Next Non-Negative Integer$$
$head Syntax$$
$codei%
%json_lexer%.next_non_neg_int()
%value% = %json_lexer%.token2size_t()
%$$
$head index_$$
The search for the non-negative integer starts
at one greater than the input value for $code index_$$ and skips white space.
$head token_$$
is set to the non-negative integer.
If the next token is not a non-negative integer,
the error is reported and this function does not return.
$head value$$
If the current token is a non-negative integer,
$icode value$$ is the corresponding value.
$head Prototype$$
$srccode%hpp% */
public:
void next_non_neg_int(void);
size_t token2size_t(void) const;
/* %$$
$end
-------------------------------------------------------------------------------
$begin json_lexer_next_float$$
$spell
json
lexer
$$
$section Get Next Floating Point Number$$
$head Syntax$$
$codei%
%ok% = %json_lexer%.next_float()
%value% = %json_lexer%.token2double()
%$$
$head index_$$
The search for the floating point number starts
at one greater than the input value for $code index_$$ and skips white space.
$head token_$$
is set to the floating point number.
If the next token is not a floating point number,
the error is reported and this function does not return.
$head value$$
If the current token is a floating point number,
$icode value$$ is the corresponding value.
$head Prototype$$
$srccode%hpp% */
public:
void next_float(void);
double token2double(void) const;
/* %$$
$end
*/
// ==========================================================================
}; // end class lexer
// ==========================================================================
} } } // END_NAMESPACE_CPPAD_LOCAL_GRAPH
# endif

View File

@@ -0,0 +1,24 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-----------------------------------------------------------------------------
$begin json_lexer$$
$spell
Json
$$
$section Lexical Analysis Class for a Json AD Graph$$.
$childtable%
include/cppad/local/graph/json_lexer.hpp
%$$
$end

View File

@@ -0,0 +1,55 @@
# ifndef CPPAD_LOCAL_GRAPH_JSON_PARSER_HPP
# define CPPAD_LOCAL_GRAPH_JSON_PARSER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-------------------------------------------------------------------------- */
# include <string>
# include <cppad/utility/vector.hpp>
# include <cppad/local/graph/cpp_graph_op.hpp>
# include <cppad/core/graph/cpp_graph.hpp>
/*
$begin json_parser$$
$spell
Json
CppAD
obj
$$
$section Json AD Graph Parser$$
$head Syntax$$
$codei%json_parser(%json%, %graph_obj%)%$$
$head json$$
The $cref json_ad_graph$$.
$head graph_obj$$
This is a $code cpp_graph$$ object.
The input value of the object does not matter.
Upon return it is a $cref cpp_ad_graph$$ representation of this function.
$head Prototype$$
$srccode%hpp% */
namespace CppAD { namespace local { namespace graph {
void json_parser(
const std::string& json ,
cpp_graph& graph_obj
);
} } }
/* %$$
$end
*/
# endif

View File

@@ -0,0 +1,54 @@
# ifndef CPPAD_LOCAL_GRAPH_JSON_WRITER_HPP
# define CPPAD_LOCAL_GRAPH_JSON_WRITER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-------------------------------------------------------------------------- */
# include <string>
# include <cppad/utility/vector.hpp>
# include <cppad/local/graph/cpp_graph_op.hpp>
# include <cppad/utility/to_string.hpp>
/*
$begin json_writer$$
$spell
Json
CppAD
obj
$$
$section Json AD Graph Writer$$
$head Syntax$$
$codei%json_writer( %json%, %graph_obj% )%$$
$head json$$
The input value of $icode json$$ does not matter,
upon return it a $cref/json/json_ad_graph/$$ representation of the AD graph.
$head graph_obj$$
This is a $code cpp_graph$$ object.
$head Prototype$$
$srccode%hpp% */
namespace CppAD { namespace local { namespace graph {
void json_writer(
std::string& json ,
const cpp_graph& graph_obj
);
} } }
/* %$$
$end
*/
# endif

View File

@@ -0,0 +1,244 @@
# ifndef CPPAD_LOCAL_HASH_CODE_HPP
# define CPPAD_LOCAL_HASH_CODE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/core/base_hash.hpp>
/*!
\file local/hash_code.hpp
CppAD hashing utility.
*/
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
General purpose hash code for an arbitrary value.
\tparam Value
is the type of the argument being hash coded.
It should be a plain old data class; i.e.,
the values included in the equality operator in the object and
not pointed to by the object.
\param value
the value that we are generating a hash code for.
All of the fields in value should have been set before the hash code
is computed (otherwise undefined values are used).
\return
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
\par Checked Assertions
\li std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
\li sizeof(value) is even
\li sizeof(unsigned short) == 2
*/
template <class Value>
unsigned short local_hash_code(const Value& value)
{ CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<unsigned short>::max()
>=
CPPAD_HASH_TABLE_SIZE
);
CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 );
CPPAD_ASSERT_UNKNOWN( sizeof(value) % 2 == 0 );
//
const unsigned short* v
= reinterpret_cast<const unsigned short*>(& value);
//
size_t i = sizeof(value) / 2 - 1;
//
size_t sum = v[i];
//
while(i--)
sum += v[i];
//
unsigned short code = static_cast<unsigned short>(
sum % CPPAD_HASH_TABLE_SIZE
);
return code;
}
/*!
Specialized hash code for a CppAD operator and its arguments.
\param op
is the operator that we are computing a hash code for.
If it is not one of the following operartors, the operator is not
hash coded and zero is returned:
\li unary operators:
AbsOp, AcosOp, AcoshOp, AsinOp, AsinhOp, AtanOp, AtanhOp, CosOp, CoshOp
ExpOp, Expm1Op, LogOp, Log1pOp, SinOp, SinhOp, SqrtOp, TanOp, TanhOp
\li binary operators where first argument is a parameter:
AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp
\li binary operators where second argument is a parameter:
DivvpOp, PowvpOp, SubvpOp, Zmulvp
\li binary operators where first is an index and second is a variable:
DisOp
\li binary operators where both arguments are variables:
AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp
\param arg
is a vector of length NumArg(op) or 2 (which ever is smaller),
containing the corresponding argument indices for this operator.
\param npar
is the number of parameters corresponding to this operation sequence.
\param par
is a vector of length npar containing the parameters
for this operation sequence; i.e.,
given a parameter index of i, the corresponding parameter value is
par[i].
\return
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
\par Checked Assertions
op must be one of the operators specified above. In addition,
\li std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
\li sizeof(size_t) is even
\li sizeof(Base) is even
\li sizeof(unsigned short) == 2
\li size_t(op) < size_t(NumberOp) <= CPPAD_HASH_TABLE_SIZE
\li if the j-th argument for this operation is a parameter, arg[j] < npar.
*/
template <class Base>
unsigned short local_hash_code(
OpCode op ,
const addr_t* arg ,
size_t npar ,
const Base* par )
{ CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<unsigned short>::max()
>=
CPPAD_HASH_TABLE_SIZE
);
CPPAD_ASSERT_UNKNOWN( size_t (op) < size_t(NumberOp) );
CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 );
CPPAD_ASSERT_UNKNOWN( sizeof(addr_t) % 2 == 0 );
CPPAD_ASSERT_UNKNOWN( sizeof(Base) % 2 == 0 );
unsigned short op_fac = static_cast<unsigned short> (
CPPAD_HASH_TABLE_SIZE / static_cast<unsigned short>(NumberOp)
);
CPPAD_ASSERT_UNKNOWN( op_fac > 0 );
// number of shorts per addr_t value
size_t short_addr_t = sizeof(addr_t) / 2;
// initialize with value that separates operators as much as possible
unsigned short code = static_cast<unsigned short>(
static_cast<unsigned short>(op) * op_fac
);
// now code in the operands
size_t i;
const unsigned short* v;
// first argument
switch(op)
{ // Binary operators where first arugment is a parameter.
// Code parameters by value instead of
// by index for two reasons. One, it gives better separation.
// Two, different indices can be same parameter value.
case AddpvOp:
case DivpvOp:
case MulpvOp:
case PowpvOp:
case SubpvOp:
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
code += hash_code( par[arg[0]] );
//
v = reinterpret_cast<const unsigned short*>(arg + 1);
i = short_addr_t;
while(i--)
code += v[i];
break;
// Binary operator where first argument is an index and
// second is a variable (same as both variables).
case DisOp:
// Binary operators where both arguments are variables
case AddvvOp:
case DivvvOp:
case MulvvOp:
case PowvvOp:
case SubvvOp:
case ZmulvvOp:
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
v = reinterpret_cast<const unsigned short*>(arg + 0);
i = 2 * short_addr_t;
while(i--)
code += v[i];
break;
// Binary operators where second arugment is a parameter.
case DivvpOp:
case PowvpOp:
case SubvpOp:
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
v = reinterpret_cast<const unsigned short*>(arg + 0);
i = short_addr_t;
while(i--)
code += v[i];
code += hash_code( par[arg[1]] );
break;
// Unary operators
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case ErfOp:
case ErfcOp:
case ExpOp:
case Expm1Op:
case LogOp:
case Log1pOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 || op == ErfOp );
v = reinterpret_cast<const unsigned short*>(arg + 0);
i = short_addr_t;
while(i--)
code += v[i];
break;
// should have been one of he cases above
default:
CPPAD_ASSERT_UNKNOWN(false);
}
return code % CPPAD_HASH_TABLE_SIZE;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,119 @@
# ifndef CPPAD_LOCAL_INDEPENDENT_HPP
# define CPPAD_LOCAL_INDEPENDENT_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
\file local/independent.hpp
Start recording AD<Base> operations.
*/
/*!
Start recording AD<Base> operations: Implementation in local namespace.
\tparam ADVector
This is simple vector type with elements of type AD<Base>.
\param x
Vector of the independent variables.
\param abort_op_index
operator index at which execution will be aborted (during the recording
\param record_compare
should comparison operators be recorded.
of operations). The value zero corresponds to not aborting (will not match).
\param dynamic
Vector of dynamic parameters.
*/
template <class Base>
template <class ADVector>
void ADTape<Base>::Independent(
ADVector& x ,
size_t abort_op_index ,
bool record_compare ,
ADVector& dynamic
) {
// check ADVector is Simple Vector class with AD<Base> elements
CheckSimpleVector< AD<Base>, ADVector>();
// dimension of the domain space
size_t n = x.size();
CPPAD_ASSERT_KNOWN(
n > 0,
"Indepdendent: the argument vector x has zero size"
);
CPPAD_ASSERT_UNKNOWN( Rec_.num_var_rec() == 0 );
CPPAD_ASSERT_UNKNOWN( Rec_.get_abort_op_index() == 0 );
CPPAD_ASSERT_UNKNOWN( Rec_.get_record_compare() == true );
CPPAD_ASSERT_UNKNOWN( Rec_.get_num_dynamic_ind() == 0 );
// set record_compare and abort_op_index before doing anything else
Rec_.set_record_compare(record_compare);
Rec_.set_abort_op_index(abort_op_index);
Rec_.set_num_dynamic_ind( dynamic.size() );
// mark the beginning of the tape and skip the first variable index
// (zero) because parameters use taddr zero
CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1);
Rec_.PutOp(BeginOp);
Rec_.PutArg(0);
// place each of the independent variables in the tape
CPPAD_ASSERT_NARG_NRES(InvOp, 0, 1);
for(size_t j = 0; j < n; j++)
{ // tape address for this independent variable
CPPAD_ASSERT_UNKNOWN( ! Variable(x[j] ) );
x[j].taddr_ = Rec_.PutOp(InvOp);
x[j].tape_id_ = id_;
x[j].ad_type_ = variable_enum;
CPPAD_ASSERT_UNKNOWN( size_t(x[j].taddr_) == j+1 );
CPPAD_ASSERT_UNKNOWN( Variable(x[j] ) );
}
// done specifying all of the independent variables
size_independent_ = n;
// parameter index zero is used by dynamic parameter tape
// to indicate that an argument is a variable
Base nan = CppAD::numeric_limits<Base>::quiet_NaN();
# ifndef NDEBUG
CPPAD_ASSERT_UNKNOWN( Rec_.put_con_par(nan) == 0 );
# else
Rec_.put_con_par(nan);
# endif
// Place independent dynamic parameters at beginning of parameter vector,
// just after the nan at index zero.
for(size_t j = 0; j < Rec_.get_num_dynamic_ind(); ++j)
{ CPPAD_ASSERT_UNKNOWN( ! Dynamic( dynamic[j] ) );
CPPAD_ASSERT_UNKNOWN( Parameter( dynamic[j] ) );
//
// dynamic parameters are placed at the end, so i == j
# ifndef NDEBUG
addr_t i = Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn);
CPPAD_ASSERT_UNKNOWN( size_t(i) == j+1 );
# else
Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn);
# endif
//
// make this parameter dynamic
dynamic[j].taddr_ = static_cast<addr_t>(j+1);
dynamic[j].tape_id_ = id_;
dynamic[j].ad_type_ = dynamic_enum;
CPPAD_ASSERT_UNKNOWN( Dynamic( dynamic[j] ) );
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,79 @@
# ifndef CPPAD_LOCAL_IS_POD_HPP
# define CPPAD_LOCAL_IS_POD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*
$begin is_pod$$
$spell
nullptr
CppAD
namespace
bool
inline
$$
$section The is_pod Template Function$$
$head Default Definition$$
The default template definition is that
$codei%
is_pod<%Type%>()
%$$
is false for all types.
$head Fundamental Types$$
This file specializes $codei%is_pod<%Type%>%$$ to be true where $icode Type$$
is any of the c++11 fundamental types that hold data; i.e.,
$code void$$ and $code nullptr_t$$ are excluded.
$head Other Type$$
You can inform CppAD that a particular $icode Type$$ is plain old data by
defining
$codei%
namespace CppAD { namespace local {
template <> inline bool is_pod<%Type%>(void) { return true; }
} }
%$$
$end
*/
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
//
template <class T> inline bool is_pod(void) { return false; }
// bool
template <> inline bool is_pod<bool>(void) {return true;}
// short
template <> inline bool is_pod<short int>(void) {return true;}
template <> inline bool is_pod<unsigned short int>(void) {return true;}
// int
template <> inline bool is_pod<int>(void) {return true;}
template <> inline bool is_pod<unsigned int>(void) {return true;}
// long
template <> inline bool is_pod<long int>(void) {return true;}
template <> inline bool is_pod<unsigned long int>(void) {return true;}
// long long
template <> inline bool is_pod<long long int>(void) {return true;}
template <> inline bool is_pod<unsigned long long int>(void) {return true;}
// Character types
template <> inline bool is_pod<char>(void) {return true;}
template <> inline bool is_pod<signed char>(void) {return true;}
template <> inline bool is_pod<unsigned char>(void) {return true;}
template <> inline bool is_pod<wchar_t>(void) {return true;}
template <> inline bool is_pod<char16_t>(void) {return true;}
template <> inline bool is_pod<char32_t>(void) {return true;}
// floating point types
template <> inline bool is_pod<float>(void) {return true;}
template <> inline bool is_pod<double>(void) {return true;}
template <> inline bool is_pod<long double>(void) {return true;}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,41 @@
# ifndef CPPAD_LOCAL_IS_POD_HPP
# define CPPAD_LOCAL_IS_POD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// make sure size_t is defined because autotools version of
// is_pod_specialize_98 uses it
# include <cstddef>
/*!
\file is_pod.hpp
File that defines is_pod<Type>(void)
*/
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
Is this type plain old data; i.e., its constructor need not be called.
The default definition is false. This include file defines it as true
for all the fundamental types except for void and nullptr_t.
*/
template <class T> bool is_pod(void) { return false; }
// The following command suppresses doxygen processing for the code below
/// \cond
// C++98 Fundamental types
@is_pod_specialize_98@
// C++11 Fundamental types
@is_pod_specialize_11@
/// \endcond
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,697 @@
# ifndef CPPAD_LOCAL_LOAD_OP_HPP
# define CPPAD_LOCAL_LOAD_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
------------------------------------------------------------------------------
$begin load_op_var$$
$spell
pv
Vec
op
var
isvar
ind
Taylor
arg
num
Addr
vecad
$$
$section Accessing an Element in a Variable VecAD Vector$$
$head See Also$$
$cref/op_code_var load/op_code_var/Load/$$.
$head Syntax$$
$codei%forward_load_%I%_op_0(
%play%,
%i_z%,
%arg%,
%parameter%,
%cap_order%,
%taylor%,
%vec_ad2isvar%,
%vec_ad2index%,
%load_op2var%
)
%$$
where the index type $icode I$$ is $code p$$ (for parameter)
or $code v$$ (for variable).
$head Prototype$$
$srcthisfile%
0%// BEGIN_FORWARD_LOAD_P_OP_0%// END_FORWARD_LOAD_P_OP_0%1
%$$
The prototype for $code forward_load_v_op_0$$ is the same
except for the function name.
$head Notation$$
$subhead v$$
We use $icode v$$ to denote the $cref VecAD$$ vector for this operation.
$subhead x$$
We use $icode x$$ to denote the $codei%AD%<%Base%>%$$
index for this operation.
$subhead i_vec$$
We use $icode i_vec$$ to denote the $code size_t$$ value
corresponding to $icode x$$.
$subhead n_load$$
This is the number of load instructions in this recording; i.e.,
$icode%play%->num_var_load_rec()%$$.
$subhead n_all$$
This is the number of values in the single array that includes
all the vectors together with the size of each vector; i.e.,
$icode%play%->num_var_vecad_ind_rec()%$$.
$head Addr$$
Is the type used for address on this tape.
$head Base$$
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
$head play$$
is the tape that this operation appears in.
This is for error detection and not used when NDEBUG is defined.
$head i_z$$
is the AD variable index corresponding to the result of this load operation.
$head arg$$
$subhead arg[0]$$
is the offset of this VecAD vector relative to the beginning
of the $icode vec_ad2isvar$$ and $icode vec_ad2index$$ arrays.
$subhead arg[1]$$
If this is
$code forward_load_p_op_0$$ ($code forward_load_v_op_0$$)
$icode%arg%[%1%]%$$ is the parameter index (variable index)
corresponding to $cref/i_vec/load_op_var/Notation/i_vec/$$.
$subhead arg[2]$$
Is the index of this VecAD load instruction in the
$icode load_op2var$$ array.
$head parameter$$
This is the vector of parameters for this recording which has size
$icode%play%->num_par_rec()%$$.
$head cap_order$$
number of columns in the matrix containing the Taylor coefficients.
$head taylor$$
Is the matrix of Taylor coefficients.
$subhead Input$$
In the $code forward_load_v_op_0$$ case,
$codei%
size_t( %taylor%[ %arg%[1]% * %cap_order% + 0 ] )
%$$
is the index in this VecAD vector.
$subhead Output$$
$icode%taylor%[ %i_z% * %cap_order% + 0 ]%$$
is set to the zero order Taylor coefficient for the result of this operator.
$head vec_ad2isvar$$
This vector has size $icode n_all$$.
If $icode%vec_ad2isvar%[ %arg%[%0%] + %i_vec% ]%$$ is false (true),
the vector element is parameter (variable).
$subhead i_pv$$
If this element is a parameter (variable),
$codei%
%i_pv% = %vec_ad2index%[ %arg%[%0%] + %i_vec% ]
%$$
is the corresponding parameter (variable) index;
$head vec_ad2index$$
This array has size $icode n_all$$
The value $icode%vec_ad2index%[ %arg%[0] - 1 ]%$$
is the number of elements in the user vector containing this load.
$icode%vec_ad2index%[%i_pv%]%$$ is the variable or
parameter index for this element,
$head load_op2var$$
is a vector with size $icode n_load$$.
The input value of its elements does not matter.
If the result of this load is a variable,
$codei%
%load_op2var%[%arg%[2]] = %i_pv%
%$$
Otherwise,
$codei%
%load_op2var%[%arg%[2]] = 0
%$$
$end
*/
// BEGIN_FORWARD_LOAD_P_OP_0
template <class Addr, class Base>
void forward_load_p_op_0(
const local::player<Base>* play ,
size_t i_z ,
const Addr* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
const bool* vec_ad2isvar ,
const size_t* vec_ad2index ,
Addr* load_op2var )
// END_FORWARD_LOAD_P_OP_0
{ CPPAD_ASSERT_UNKNOWN( NumArg(LdpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(LdpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < play->num_par_rec() );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) );
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: dynamic parmaeter index out or range during zero order forward"
);
CPPAD_ASSERT_UNKNOWN( size_t(arg[0] + i_vec) < play->num_var_vecad_ind_rec() );
size_t i_pv = vec_ad2index[ arg[0] + i_vec ];
Base* z = taylor + i_z * cap_order;
if( vec_ad2isvar[ arg[0] + i_vec ] )
{ CPPAD_ASSERT_UNKNOWN( i_pv < i_z );
load_op2var[ arg[2] ] = addr_t( i_pv );
Base* v_x = taylor + i_pv * cap_order;
z[0] = v_x[0];
}
else
{ CPPAD_ASSERT_UNKNOWN( i_pv < play->num_par_rec() );
load_op2var[ arg[2] ] = 0;
Base v_x = parameter[i_pv];
z[0] = v_x;
}
}
template <class Addr, class Base>
void forward_load_v_op_0(
const local::player<Base>* play ,
size_t i_z ,
const Addr* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
const bool* vec_ad2isvar ,
const size_t* vec_ad2index ,
Addr* load_op2var )
{ CPPAD_ASSERT_UNKNOWN( NumArg(LdvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(LdvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
addr_t i_vec = addr_t(Integer(taylor[ size_t(arg[1]) * cap_order + 0 ] ));
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: variable index out or range during zero order forward"
);
CPPAD_ASSERT_UNKNOWN( size_t(arg[0] + i_vec) < play->num_var_vecad_ind_rec() );
size_t i_pv = vec_ad2index[ arg[0] + i_vec ];
Base* z = taylor + i_z * cap_order;
if( vec_ad2isvar[ arg[0] + i_vec ] )
{ CPPAD_ASSERT_UNKNOWN( i_pv < i_z );
load_op2var[ arg[2] ] = addr_t( i_pv );
Base* v_x = taylor + i_pv * cap_order;
z[0] = v_x[0];
}
else
{ CPPAD_ASSERT_UNKNOWN( i_pv < play->num_par_rec() );
load_op2var[ arg[2] ] = 0;
Base v_x = parameter[i_pv];
z[0] = v_x;
}
}
/*!
------------------------------------------------------------------------------
Shared documentation for sparsity operations corresponding to
op = LdpOp or LdvOp (not called).
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_pv = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param op
is the code corresponding to this operator;
i.e., LdpOp or LdvOp.
\param i_z
is the AD variable index corresponding to the variable z; i.e.,
the set with index i_z in var_sparsity is the sparsity pattern
corresponding to z.
\param arg
\n
arg[0]
is the offset corresponding to this VecAD vector in the VecAD combined array.
\param num_combined
is the total number of elements in the VecAD combinded array.
\param combined
is the VecAD combined array.
\n
\n
combined[ arg[0] - 1 ]
is the index of the set corresponding to the vector v in vecad_sparsity.
We use the notation i_v for this value; i.e.,
\verbatim
i_v = combined[ arg[0] - 1 ]
\endverbatim
\param var_sparsity
The set with index i_z in var_sparsity is the sparsity pattern for z.
This is an output for forward mode operations,
and an input for reverse mode operations.
\param vecad_sparsity
The set with index i_v is the sparsity pattern for the vector v.
This is an input for forward mode operations.
For reverse mode operations,
the sparsity pattern for z is added to the sparsity pattern for v.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 1
\li 0 < arg[0]
\li arg[0] < num_combined
\li i_v < vecad_sparsity.n_set()
*/
template <class Vector_set, class Addr>
void sparse_load_op(
OpCode op ,
size_t i_z ,
const Addr* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
// This routine is only for documentaiton, it should not be used
CPPAD_ASSERT_UNKNOWN( false );
}
/*!
Forward mode, except for zero order, for op = LdpOp or op = LdvOp
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_pv = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
\param play
is the tape that this operation appears in.
This is for error detection and not used when NDEBUG is defined.
\param op
is the code corresponding to this operator; i.e., LdpOp or LdvOp
(only used for error checking).
\param p
is the lowest order of the Taylor coefficient that we are computing.
\param q
is the highest order of the Taylor coefficient that we are computing.
\param r
is the number of directions for the Taylor coefficients that we
are computing.
\param cap_order
number of columns in the matrix containing the Taylor coefficients.
\par tpv
We use the notation
<code>tpv = (cap_order-1) * r + 1</code>
which is the number of Taylor coefficients per variable
\param i_z
is the AD variable index corresponding to the variable z.
\param arg
arg[2]
Is the index of this vecad load instruction in the load_op2var array.
\param load_op2var
is a vector with size play->num_var_load_rec().
It contains the variable index corresponding to each load instruction.
In the case where the index is zero,
the instruction corresponds to a parameter (not variable).
\par i_var
We use the notation
\verbatim
i_var = size_t( load_op2var[ arg[2] ] )
\endverbatim
\param taylor
\n
Input
\n
If <code>i_var > 0</code>, v[x] is a variable and
for k = 1 , ... , q
<code>taylor[ i_var * tpv + (k-1)*r+1+ell ]</code>
is the k-th order coefficient for v[x] in the ell-th direction,
\n
\n
Output
\n
for k = p , ... , q,
<code>taylor[ i_z * tpv + (k-1)*r+1+ell ]</code>
is set to the k-order Taylor coefficient for z in the ell-th direction.
*/
template <class Addr, class Base>
void forward_load_op(
const local::player<Base>* play,
OpCode op ,
size_t p ,
size_t q ,
size_t r ,
size_t cap_order ,
size_t i_z ,
const Addr* arg ,
const Addr* load_op2var ,
Base* taylor )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < r);
CPPAD_ASSERT_UNKNOWN( 0 < p);
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() );
size_t i_var = size_t( load_op2var[ arg[2] ] );
CPPAD_ASSERT_UNKNOWN( i_var < i_z );
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* z = taylor + i_z * num_taylor_per_var;
if( i_var > 0 )
{ Base* v_x = taylor + i_var * num_taylor_per_var;
for(size_t ell = 0; ell < r; ell++)
{ for(size_t k = p; k <= q; k++)
{ size_t m = (k-1) * r + 1 + ell;
z[m] = v_x[m];
}
}
}
else
{ for(size_t ell = 0; ell < r; ell++)
{ for(size_t k = p; k <= q; k++)
{ size_t m = (k-1) * r + 1 + ell;
z[m] = Base(0.0);
}
}
}
}
/*!
Reverse mode for op = LdpOp or LdvOp.
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_pv = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
This routine is given the partial derivatives of a function
G(z , y[x] , w , u ... )
and it uses them to compute the partial derivatives of
\verbatim
H( y[x] , w , u , ... ) = G[ z( y[x] ) , y[x] , w , u , ... ]
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base.
\param op
is the code corresponding to this operator; i.e., LdpOp or LdvOp
(only used for error checking).
\param d
highest order the Taylor coefficient that we are computing the partial
derivative with respect to.
\param i_z
is the AD variable index corresponding to the variable z.
\param arg
arg[2]
Is the index of this vecad load instruction in the
load_op2var array.
\param cap_order
number of columns in the matrix containing the Taylor coefficients
(not used).
\param taylor
matrix of Taylor coefficients (not used).
\param nc_partial
number of colums in the matrix containing all the partial derivatives
(not used if arg[2] is zero).
\param partial
If arg[2] is zero, y[x] is a parameter
and no values need to be modified; i.e., partial is not used.
Otherwise, y[x] is a variable and:
\n
\n
partial [ i_z * nc_partial + k ]
for k = 0 , ... , d
is the partial derivative of G
with respect to the k-th order Taylor coefficient for z.
\n
\n
If arg[2] is not zero,
partial [ arg[2] * nc_partial + k ]
for k = 0 , ... , d
is the partial derivative with respect to
the k-th order Taylor coefficient for x.
On input, it corresponds to the function G,
and on output it corresponds to the the function H.
\param load_op2var
is a vector with size play->num_var_load_rec().
It contains the variable index corresponding to each load instruction.
In the case where the index is zero,
the instruction corresponds to a parameter (not variable).
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 1
\li d < cap_order
\li size_t(arg[2]) < i_z
*/
template <class Addr, class Base>
void reverse_load_op(
OpCode op ,
size_t d ,
size_t i_z ,
const Addr* arg ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial ,
const Addr* load_op2var )
{ size_t i_load = size_t( load_op2var[ arg[2] ] );
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( i_load < i_z );
if( i_load > 0 )
{
Base* pz = partial + i_z * nc_partial;
Base* py_x = partial + i_load * nc_partial;
size_t j = d + 1;
while(j--)
py_x[j] += pz[j];
}
}
/*!
Forward mode sparsity operations for LdpOp and LdvOp
\param dependency
is this a dependency (or sparsity) calculation.
\copydetails CppAD::local::sparse_load_op
*/
template <class Vector_set, class Addr>
void forward_sparse_load_op(
bool dependency ,
OpCode op ,
size_t i_z ,
const Addr* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
var_sparsity.assignment(i_z, i_v, vecad_sparsity);
if( dependency & (op == LdvOp) )
var_sparsity.binary_union(i_z, i_z, size_t(arg[1]), var_sparsity);
return;
}
/*!
Reverse mode Jacobian sparsity operations for LdpOp and LdvOp
\param dependency
is this a dependency (or sparsity) calculation.
\copydetails CppAD::local::sparse_load_op
*/
template <class Vector_set, class Addr>
void reverse_sparse_jacobian_load_op(
bool dependency ,
OpCode op ,
size_t i_z ,
const Addr* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
vecad_sparsity.binary_union(i_v, i_v, i_z, var_sparsity);
if( dependency & (op == LdvOp) )
var_sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_z, var_sparsity);
return;
}
/*!
Reverse mode Hessian sparsity operations for LdpOp and LdvOp
\copydetails CppAD::local::sparse_load_op
\param var_jacobian
var_jacobian[i_z]
is false (true) if the Jacobian of G with respect to z is always zero
(many be non-zero).
\param vecad_jacobian
vecad_jacobian[i_v]
is false (true) if the Jacobian with respect to x is always zero
(may be non-zero).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
*/
template <class Vector_set, class Addr>
void reverse_sparse_hessian_load_op(
OpCode op ,
size_t i_z ,
const Addr* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity ,
bool* var_jacobian ,
bool* vecad_jacobian )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
vecad_sparsity.binary_union(i_v, i_v, i_z, var_sparsity);
vecad_jacobian[i_v] |= var_jacobian[i_z];
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,203 @@
# ifndef CPPAD_LOCAL_LOG1P_OP_HPP
# define CPPAD_LOCAL_LOG1P_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file log1p_op.hpp
Forward and reverse mode calculations for z = log1p(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = Log1pOp.
The C++ source code corresponding to this operation is
\verbatim
z = log1p(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_log1p_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
size_t k;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
if( p == 0 )
{ z[0] = log1p( x[0] );
p++;
if( q == 0 )
return;
}
if ( p == 1 )
{ z[1] = x[1] / (Base(1.0) + x[0]);
p++;
}
for(size_t j = p; j <= q; j++)
{
z[j] = -z[1] * x[j-1];
for(k = 2; k < j; k++)
z[j] -= Base(double(k)) * z[k] * x[j-k];
z[j] /= Base(double(j));
z[j] += x[j];
z[j] /= (Base(1.0) + x[0]);
}
}
/*!
Muiltiple directions Taylor coefficient for op = Log1pOp.
The C++ source code corresponding to this operation is
\verbatim
z = log1p(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_log1p_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * x[m+ell];
for(size_t k = 1; k < q; k++)
z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
z[m+ell] /= (Base(double(q)) + Base(q) * x[0]);
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = Log1pOp.
The C++ source code corresponding to this operation is
\verbatim
z = log1p(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_log1p_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = log1p( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = Log1pOp.
The C++ source code corresponding to this operation is
\verbatim
z = log1p(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_log1p_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{ size_t j, k;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
Base inv_1px0 = Base(1.0) / (Base(1) + x[0]);
j = d;
while(j)
{ // scale partial w.r.t z[j]
pz[j] = azmul(pz[j] , inv_1px0);
px[0] -= azmul(pz[j], z[j]);
px[j] += pz[j];
// further scale partial w.r.t. z[j]
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ pz[k] -= Base(double(k)) * azmul(pz[j], x[j-k]);
px[j-k] -= Base(double(k)) * azmul(pz[j], z[k]);
}
--j;
}
px[0] += azmul(pz[0], inv_1px0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,202 @@
# ifndef CPPAD_LOCAL_LOG_OP_HPP
# define CPPAD_LOCAL_LOG_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file log_op.hpp
Forward and reverse mode calculations for z = log(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = LogOp.
The C++ source code corresponding to this operation is
\verbatim
z = log(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_log_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
size_t k;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
if( p == 0 )
{ z[0] = log( x[0] );
p++;
if( q == 0 )
return;
}
if ( p == 1 )
{ z[1] = x[1] / x[0];
p++;
}
for(size_t j = p; j <= q; j++)
{
z[j] = -z[1] * x[j-1];
for(k = 2; k < j; k++)
z[j] -= Base(double(k)) * z[k] * x[j-k];
z[j] /= Base(double(j));
z[j] += x[j];
z[j] /= x[0];
}
}
/*!
Muiltiple directions Taylor coefficient for op = LogOp.
The C++ source code corresponding to this operation is
\verbatim
z = log(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_log_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * x[m+ell];
for(size_t k = 1; k < q; k++)
z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell];
z[m+ell] /= (Base(double(q)) * x[0]);
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = LogOp.
The C++ source code corresponding to this operation is
\verbatim
z = log(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_log_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = log( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = LogOp.
The C++ source code corresponding to this operation is
\verbatim
z = log(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_log_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{ size_t j, k;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
Base inv_x0 = Base(1.0) / x[0];
j = d;
while(j)
{ // scale partial w.r.t z[j]
pz[j] = azmul(pz[j] , inv_x0);
px[0] -= azmul(pz[j], z[j]);
px[j] += pz[j];
// further scale partial w.r.t. z[j]
pz[j] /= Base(double(j));
for(k = 1; k < j; k++)
{ pz[k] -= Base(double(k)) * azmul(pz[j], x[j-k]);
px[j-k] -= Base(double(k)) * azmul(pz[j], z[k]);
}
--j;
}
px[0] += azmul(pz[0], inv_x0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,359 @@
# ifndef CPPAD_LOCAL_MUL_OP_HPP
# define CPPAD_LOCAL_MUL_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file mul_op.hpp
Forward and reverse mode calculations for z = x * y.
*/
// --------------------------- Mulvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = MulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_mulvv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
size_t k;
for(size_t d = p; d <= q; d++)
{ z[d] = Base(0.0);
for(k = 0; k <= d; k++)
z[d] += x[d-k] * y[k];
}
}
/*!
Multiple directions forward mode Taylor coefficients for op = MulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_mulvv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
size_t k, ell, m;
for(ell = 0; ell < r; ell++)
{ m = (q-1)*r + ell + 1;
z[m] = x[0] * y[m] + x[m] * y[0];
for(k = 1; k < q; k++)
z[m] += x[(q-k-1)*r + ell + 1] * y[(k-1)*r + ell + 1];
}
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = MulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_mulvv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] * y[0];
}
/*!
Compute reverse mode partial derivatives for result of op = MulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_mulvv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
const Base* x = taylor + size_t(arg[0]) * cap_order;
const Base* y = taylor + size_t(arg[1]) * cap_order;
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t j = d + 1;
size_t k;
while(j)
{ --j;
for(k = 0; k <= j; k++)
{
px[j-k] += azmul(pz[j], y[k]);
py[k] += azmul(pz[j], x[j-k]);
}
}
}
// --------------------------- Mulpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = MulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_mulpv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Paraemter value
Base x = parameter[ arg[0] ];
for(size_t d = p; d <= q; d++)
z[d] = x * y[d];
}
/*!
Multiple directions forward mode Taylor coefficients for op = MulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_mulpv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q-1) * r + 1;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m;
Base* z = taylor + i_z * num_taylor_per_var + m;
// Paraemter value
Base x = parameter[ arg[0] ];
for(size_t ell = 0; ell < r; ell++)
z[ell] = x * y[ell];
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = MulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_mulpv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x * y[0];
}
/*!
Compute reverse mode partial derivative for result of op = MulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x * y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_mulpv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
Base x = parameter[ arg[0] ];
// Partial derivatives corresponding to arguments and result
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t j = d + 1;
while(j)
{ --j;
py[j] += azmul(pz[j], x);
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,59 @@
# ifndef CPPAD_LOCAL_OP_HPP
# define CPPAD_LOCAL_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// used by the sparse operators
# include <cppad/local/sparse/internal.hpp>
// operations
# include <cppad/core/std_math_11.hpp>
# include <cppad/local/abs_op.hpp>
# include <cppad/local/add_op.hpp>
# include <cppad/local/acos_op.hpp>
# include <cppad/local/acosh_op.hpp>
# include <cppad/local/asin_op.hpp>
# include <cppad/local/asinh_op.hpp>
# include <cppad/local/atan_op.hpp>
# include <cppad/local/atanh_op.hpp>
# include <cppad/local/comp_op.hpp>
# include <cppad/local/cond_op.hpp>
# include <cppad/local/cos_op.hpp>
# include <cppad/local/cosh_op.hpp>
# include <cppad/local/cskip_op.hpp>
# include <cppad/local/csum_op.hpp>
# include <cppad/local/discrete_op.hpp>
# include <cppad/local/div_op.hpp>
# include <cppad/local/erf_op.hpp>
# include <cppad/local/exp_op.hpp>
# include <cppad/local/expm1_op.hpp>
# include <cppad/local/load_op.hpp>
# include <cppad/local/log_op.hpp>
# include <cppad/local/log1p_op.hpp>
# include <cppad/local/mul_op.hpp>
# include <cppad/local/parameter_op.hpp>
# include <cppad/local/pow_op.hpp>
# include <cppad/local/print_op.hpp>
# include <cppad/local/sign_op.hpp>
# include <cppad/local/sin_op.hpp>
# include <cppad/local/sinh_op.hpp>
# include <cppad/local/sqrt_op.hpp>
# include <cppad/local/sub_op.hpp>
# include <cppad/local/sparse/binary_op.hpp>
# include <cppad/local/sparse/unary_op.hpp>
# include <cppad/local/store_op.hpp>
# include <cppad/local/tan_op.hpp>
# include <cppad/local/tanh_op.hpp>
# include <cppad/local/zmul_op.hpp>
# endif

View File

@@ -0,0 +1,439 @@
# ifndef CPPAD_LOCAL_OP_CODE_DYN_HPP
# define CPPAD_LOCAL_OP_CODE_DYN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
$begin op_code_dyn$$
$spell
vec
Op
dyn
arg
hpp
cond_exp
ind
zmul
Namespace
enum
CppAD
$$
$section Dynamic Parameter Op Codes$$
$head Namespace$$
The $code op_code_dyn$$ enum type is in the $code CppAD::local$$ namespace.
$head AD Type$$
All the operators below have no variable arguments,
at least one dynamic parameter argument,
and at most one constant argument; see
$cref ad_type_enum$$.
For example, all the unary operators have one dynamic parameter argument
and one dynamic parameter result.
$head Unary$$
The number of arguments for a unary operator is one
and it is a parameter index.
All the unary operators have one result that is a dynamic parameter.
$head Binary$$
The number of arguments for a binary operator is two
and they are parameter indices.
All the binary operators have one result that is a dynamic parameter.
For binary operators the first argument is the left operand
and the second is the right operand.
$subhead zmul_dyn$$
This binary operator has a non-standard name; see $cref azmul$$ for
its definition.
$head ind_dyn$$
This is an independent dynamic parameter operator.
It has no arguments and one result which is the value of the corresponding
independent dynamic parameter in the call to $cref new_dynamic$$.
$comment ----------------------------------------------------------------- $$
$head atom_dyn$$
This operator is a call to an atomic function.
The number of arguments to this operator is
$icode%arg%[4+%n%+%m%]%$$; see below.
$subhead arg[0]$$
This is the index that identifies this atomic function; see
$code local/atomic_index.hpp$$.
$subhead arg[1]$$
This is the number of arguments to this atomic function.
We use the notation $icode%n% = %arg%[1]%$$ below.
$subhead arg[2]$$
This is the number of results for this atomic function.
We use the notation $icode%m% = %arg%[2]%$$ below.
$subhead arg[3]$$
This is the number of result values that are dynamic parameters
for this function call.
$subhead arg[4+j]$$
For $icode%j% = 0 , %...% , %n%-1%$$,
this is the parameter index for the $th j$$ argument to this atomic
function call.
$subhead arg[4+n+i]$$
For $icode%i% = 0 , %...% , %m%-1%$$,
this is the parameter index for the $th i$$ result to this atomic
function call.
$subhead arg[4+n+m]$$
This is the number of arguments to this operator; i.e.,
$codei%5+%n%+%m%$$.
$head result_dyn$$
This is a place holder for a result of an atomic function call
that is a dynamic parameter.
It has no arguments, no results, and is only there so that the
number of dynamic parameters and the number of dynamic operators are equal.
$comment ----------------------------------------------------------------- $$
$head cond_exp_dyn$$
This is a conditional expression operator and has five arguments
and one result.
$subhead arg[0]$$
This is the
$cref/CompareOp/base_cond_exp/CompareOp/$$ value for this operator.
$subhead arg[1]$$
This is the parameter index for the left operand to the comparison.
$subhead arg[2]$$
This is the parameter index for the right operand to the comparison.
$subhead arg[3]$$
This is the index of the parameter equal to the operator result if
the comparison result is true.
$subhead arg[4]$$
This is the index of the parameter equal to the operator result if
the comparison result is false.
$comment ----------------------------------------------------------------- $$
$head dis_dyn$$
This is a call to a discrete function.
The discrete function has one argument and one result.
This operator has two arguments and one result.
It is not a binary operator because the first argument
is not the index of a parameter.
$subhead arg[0]$$
Is the discrete function index which depends on the $icode Base$$
type used when this function was recorded.
$subhead arg[1]$$
Is the parameter index for the argument to the function.
$comment ----------------------------------------------------------------- $$
$head Source$$
$srcthisfile%
0%// BEGIN_OP_CODE_DYN%// END_OP_CODE_DYN%1
%$$
$end
*/
// BEGIN_SORT_THIS_LINE_PLUS_3
// BEGIN_OP_CODE_DYN
enum op_code_dyn {
abs_dyn, // unary
acos_dyn, // unary
acosh_dyn, // unary
add_dyn, // binary
asin_dyn, // unary
asinh_dyn, // unary
atan_dyn, // unary
atanh_dyn, // unary
atom_dyn, // ? arguments: atomic function call
cond_exp_dyn, // 5 arguments: conditional expression
cos_dyn, // unary
cosh_dyn, // unary
dis_dyn, // 2 arguments: discrete function
div_dyn, // binary
erfc_dyn, // unary
erf_dyn, // unary
exp_dyn, // unary
expm1_dyn, // unary
fabs_dyn, // unary
ind_dyn, // 0 arguments: independent parameter
log1p_dyn, // unary
log_dyn, // unary
mul_dyn, // binary
pow_dyn, // binary
result_dyn, // 0 arguments: atomic function result
sign_dyn, // unary
sin_dyn, // unary
sinh_dyn, // unary
sqrt_dyn, // unary
sub_dyn, // binary
tan_dyn, // unary
tanh_dyn, // unary
zmul_dyn, // binary
number_dyn // number of operator codes and invalid operator value
};
// END_OP_CODE_DYN
// END_SORT_THIS_LINE_MINUS_4
/*
$begin num_arg_dyn$$
$spell
num_arg_dyn
op
enum
$$
$section Number of Arguments to a Dynamic Parameter Operator$$
$head Syntax$$
$icode%n_arg% = local::num_arg_dyn(%op%)
%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_NUM_ARG_DYN_PROTOTYPE%// END_NUM_ARG_DYN_PROTOTYPE%1
%$$
$head Parallel Mode$$
This routine has static data so its first call cannot be in Parallel mode.
$head op$$
is the operator in question.
$head n_arg$$
The return value is the number of arguments as commented in the
$cref/source/op_code_dyn/Source/$$ for $code enum op_code_dyn$$.
There is one exception: if $icode op$$ is $code atom_dyn$$,
$icode n_arg$$ is zero; see $cref/atom_dyn/op_code_dyn/atom_dyn/$$
for the true number of arguments in this case.
$head atom_dyn$$
All of the dynamic parameter operators have a fixed number of arguments
except for the $cref/atom_dyn/op_code_dyn/atom_dyn/$$
operator which calls an atomic functions.
In this special case the return value $icode n_arg$$ is zero
which is not correct.
$end
*/
// BEGIN_NUM_ARG_DYN_PROTOTYPE
inline size_t num_arg_dyn(op_code_dyn op)
// END_NUM_ARG_DYN_PROTOTYPE
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
// BEGIN_SORT_THIS_LINE_PLUS_2
static const size_t num_arg_table[] = {
/* abs_dyn */ 1,
/* acos_dyn */ 1,
/* acosh_dyn */ 1,
/* add_dyn */ 2,
/* asin_dyn */ 1,
/* asinh_dyn */ 1,
/* atan_dyn */ 1,
/* atanh_dyn */ 1,
/* atom_dyn */ 0,
/* cond_exp_dyn */ 5,
/* cos_dyn */ 1,
/* cosh_dyn */ 1,
/* dis_dyn */ 2,
/* div_dyn */ 2,
/* erfc_dyn */ 1,
/* erf_dyn */ 1,
/* exp_dyn */ 1,
/* expm1_dyn */ 1,
/* fabs_dyn */ 1,
/* ind_dyn */ 0,
/* log1p_dyn */ 1,
/* log_dyn */ 1,
/* mul_dyn */ 2,
/* pow_dyn */ 2,
/* result_dyn */ 0,
/* sign_dyn */ 1,
/* sin_dyn */ 1,
/* sinh_dyn */ 1,
/* sqrt_dyn */ 1,
/* sub_dyn */ 2,
/* tan_dyn */ 1,
/* tanh_dyn */ 1,
/* zmul_dyn */ 2,
0 // number_dyn (not used)
};
// END_SORT_THIS_LINE_MINUS_3
//
static bool first = true;
if( first )
{ CPPAD_ASSERT_UNKNOWN(
size_t(number_dyn)+1 == sizeof(num_arg_table)/sizeof(num_arg_table[0])
);
first = false;
}
return num_arg_table[op];
}
/*
$begin op_name_dyn$$
$spell
dyn
op
enum
cond_exp
$$
$section Number of Arguments to a Dynamic Parameter Operator$$
$head Syntax$$
$icode%name% = local::op_name_dyn(%op%)
%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_OP_NAME_DYN_PROTOTYPE%// END_OP_NAME_DYN_PROTOTYPE%1
%$$
$head Parallel Mode$$
This routine has static data so its first call cannot be in Parallel mode.
$head op$$
is the operator in question.
$head name$$
The return value $icode name$$ is the same as the operator enum symbol
(see $cref/source/op_code_dyn/Source/$$ for $code enum op_code_dyn$$)
without the $code _dyn$$ at the end. For example,
the name corresponding to the
$cref/cond_exp_dyn/op_code_dyn/cond_exp_dyn/$$ operator is $code cond_exp$$.
$end
*/
// BEGIN_OP_NAME_DYN_PROTOTYPE
inline const char* op_name_dyn(op_code_dyn op)
// END_OP_NAME_DYN_PROTOTYPE
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
// BEGIN_SORT_THIS_LINE_PLUS_2
static const char* op_name_table[] = {
/* abs_dyn */ "abs",
/* acos_dyn */ "acos",
/* acosh_dyn */ "acosh",
/* add_dyn */ "add",
/* asin_dyn */ "asin",
/* asinh_dyn */ "asinh",
/* atan_dyn */ "atan",
/* atanh_dyn */ "atanh",
/* atom_dyn */ "call",
/* cond_exp_dyn */ "cond_exp",
/* cos_dyn */ "cos",
/* cosh_dyn */ "cosh",
/* dis_dyn */ "dis",
/* div_dyn */ "div",
/* erfc_dyn */ "erfc",
/* erf_dyn */ "erf",
/* exp_dyn */ "exp",
/* expm1_dyn */ "expm1",
/* fabs_dyn */ "fabs",
/* ind_dyn */ "ind",
/* log1p_dyn */ "log1p",
/* log_dyn */ "log",
/* mul_dyn */ "mul",
/* pow_dyn */ "pow",
/* result_dyn */ "result",
/* sign_dyn */ "sign",
/* sin_dyn */ "sin",
/* sinh_dyn */ "sinh",
/* sqrt_dyn */ "sqrt",
/* sub_dyn */ "sub",
/* tan_dyn */ "tan",
/* tanh_dyn */ "tanh",
/* zmul_dyn */ "zmul",
/* number_dyn */ "number"
};
// END_SORT_THIS_LINE_MINUS_3
static bool first = true;
if( first )
{ CPPAD_ASSERT_UNKNOWN(
size_t(number_dyn)+1 == sizeof(op_name_table)/sizeof(op_name_table[0])
);
first = false;
}
return op_name_table[op];
}
/*
$begin num_non_par_arg_dyn$$
$spell
arg
dyn
op
num
$$
$section Number Non-Parameter Arguments to a Dynamic Parameters Operator$$
$head Syntax$$
$icode%num% = local::num_non_par_arg_dyn(%op%)
%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_NUM_NON_PAR_ARG_DYN%// END_NUM_NON_PAR_ARG_DYN%1
%$$
$head op$$
is the operator in question.
$head num$$
The return value $icode num$$ is the number of arguments,
for this operator $icode op$$, that are not parameters indices.
All of the non-parameter arguments come first
so $icode num$$ is also the offset for the
first argument that is a parameter index.
$head atom_dyn$$
The $cref/atom_dyn/op_code_dyn/atom_dyn/$$ case is special,
$icode num$$ is zero for this case but it is not as documented above; see
$cref/atom_dyn/op_code_dyn/atom_dyn/$$.
$end
*/
// BEGIN_NUM_NON_PAR_ARG_DYN
inline size_t num_non_par_arg_dyn(op_code_dyn op)
// END_NUM_NON_PAR_ARG_DYN
{
size_t num;
switch(op)
{ case atom_dyn:
num = 4;
break;
case cond_exp_dyn:
case dis_dyn:
num = 1;
break;
default:
num = 0;
}
//
return num;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP
# define CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/declare_ad.hpp> // defines CompareOp
# include <cppad/utility/vector.hpp>
/*!
$begin optimize_cexp_info$$
$spell
struct
cexp
op
Funap
Funav
Funrp
Funrv
cskip
arg
$$
$section Optimization Information About Conditional Expressions$$
$head struct_cexp_info$$
information about a conditional expression
in the old operation sequence (before optimization).
$srcthisfile%
0%// BEGIN_STRUCT_CEXP_INFO%// END_STRUCT_CEXP_INFO%1
%$$
$subhead i_op$$
is the operator index for this conditional expression.
$subhead left$$
is the variable or parameter index (depending on flag)
for left operand in the comparison.
$subhead right$$
is the variable or parameter index (depending on flag)
for right operand in the comparison.
$subhead max_left_right$$
is the maximum of the left and right variable indices.
This is a variable index, so parameters correspond to index zero.
$subhead cop$$
is the comparison operator for this conditional expression.
$subhead flag$$
$list number$$
(flag & 1) is true if and only if left is a variable
$lnext
(flag & 2) is true if and only if right is a variable
$lend
$head struct_cskip_new$$
information about a conditional expression
in thew new operation sequence (after optimization).
$srcthisfile%
0%// BEGIN_STRUCT_CSKIP_NEW%// END_STRUCT_CSKIP_NEW%1
%$$
$subhead left$$
is the variable or parameter index (depending on flag)
for left operand in the comparison.
$subhead right$$
is the variable or parameter index (depending on flag)
for right operand in the comparison.
$subhead max_left_right$$
is the maximum of the left and right variable indices.
This is a variable index, so parameters correspond to index zero.
$subhead i_arg$$
index where this conditional skips arguments start
(in the vector or arguments for all operators).
$end
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Information about one conditional expression.
*/
// BEGIN_STRUCT_CEXP_INFO
struct struct_cexp_info {
addr_t i_op;
addr_t left;
addr_t right;
addr_t max_left_right;
CompareOp cop;
unsigned char flag;
};
// END_STRUCT_CEXP_INFO
// BEGIN_STRUCT_CSKIP_NEW
struct struct_cskip_new {
size_t left;
size_t right;
size_t max_left_right;
size_t i_arg;
};
// END_STRUCT_CSKIP_NEW
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local {
template <> inline bool is_pod<optimize::struct_cskip_new>(void)
{ return true; }
} }
# endif

View File

@@ -0,0 +1,42 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_OP_INFO_HPP
# define CPPAD_LOCAL_OPTIMIZE_CSUM_OP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/op_code_var.hpp>
# include <cppad/local/declare_ad.hpp> // defines addr_t
/*!
\file csum_op_info.hpp
Information about one old variable that is part of a new CSumOp operation.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Information about one old variable that is part of a new CSumOp operation.
*/
struct struct_csum_op_info {
/// Pointer to first argument (child) for this old operator.
/// Set by the reverse sweep at beginning of optimization.
const addr_t* arg;
/// Was this old variable added to the summation
/// (if not it was subtracted)
bool add;
/// Operator for which this old variable is the result, NumRes(op) > 0.
OpCode op;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,47 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP
# define CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <stack>
# include <cppad/local/optimize/csum_op_info.hpp>
/*!
\file csum_stacks.hpp
Information about one cumulative summation operation.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Information about one cumulative summation operation.
*/
struct struct_csum_stacks {
/// old operator indices for this cummulative summation
std::stack<struct struct_csum_op_info> op_info;
/// old variable indices to be added
std::stack<addr_t> add_var;
/// old variable indices to be subtracted
std::stack<addr_t> sub_var;
/// dynamic parameter indices to be added
std::stack<addr_t> add_dyn;
/// dynamic parameter indices to be subtracted
std::stack<addr_t> sub_dyn;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,260 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP
# define CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/optimize/match_op.hpp>
# include <cppad/local/optimize/cexp_info.hpp>
# include <cppad/local/optimize/usage.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
$begin optimize_get_cexp_info.hpp$$
$spell
cexp
itr
op
iterator
bool
Exp
deallocate
Funap
Funav
Funrp
Funrv
num
var
$$
$section Information for Each Conditional Expression$$
$head Syntax$$
$codei%get_cexp_info(
%play%,
%random_itr%,
%op_previous%,
%op_usage%,
%cexp2op%,
%cexp_set%,
%cexp_info%,
%skip_op_true%,
%skip_op_false%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Restrictions$$
Do not call this routine unless you are optimizing conditional expressions
and there are conditional expressions in the operation sequence.
$head Base$$
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
$head play$$
This is the old operation sequence.
$head random_itr$$
This is a random iterator for the old operation sequence.
$head cexp2op$$
This is the number of conditional expressions in the operation sequence
and must be non-zero.
$head cexp_set$$
This is a vector of sets, the i-th set, set[i],
is a set of elements for the i-th operator.
If e is an element of set[i], let j = e / 2 and k = e % 2.
If the comparison for the j-th conditional expression is equal to bool(k),
the i-th operator can be skipped (is not used by any of the results).
Note that j indexes the subset of operators that are conditional expressions
in the old operation sequence.
$head cexp_info$$
The input size of this vector must be zero.
Upon return cexp_info has size equal to the number of conditional expressions
in the operation sequence; i.e., the number of CExpOp operators.
The value cexp_info[j] is the information corresponding to the j-th
conditional expression in the operation sequence.
This vector is in the same order as the operation sequence; i.e.
if j1 > j2, cexp_info[j1].i_op > cexp_info[j2].i_op.
Note that skip_op_true and skip_op_false could be part of this structure,
but then we would allocate and deallocate two vectors for each conditional
expression in the operation sequence.
$head skip_op_true$$
This vector of sets is empty on input.
Upon return, the j-th set is the operators that are not used when
comparison result for cexp_info[j] is true.
Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this
set and should be skipped when the corresponding AFunOp are skipped.
$head skip_op_false$$
This vector of sets is empty on input.
Upon return, the j-th set is the operators that are not used when
comparison result for cexp_info[j] is false.
Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this
set and should be skipped when the corresponding AFunOp are skipped.
$head op_previous$$
This argument has size equal to the number of operators
in the operation sequence; i.e., num_op = play->nun_var_rec().
If op_previous[i] == 0, no replacement was found for the i-th operator.
If op_previous[i] != 0, op_usage[ op_previous[i] ] == usage_t(yes_usage).
$head op_usage$$
This argument has size equal to the number of operators
in the operation sequence; i.e., num_op = play->nun_var_rec().
The value op_usage[i] is the usage for
the i-th operator in the operation sequence.
$end
*/
// BEGIN_PROTOTYPE
template <class Addr, class Base>
void get_cexp_info(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<addr_t>& op_previous ,
const pod_vector<usage_t>& op_usage ,
const pod_vector<addr_t>& cexp2op ,
const sparse::list_setvec& cexp_set ,
vector<struct_cexp_info>& cexp_info ,
sparse::list_setvec& skip_op_true ,
sparse::list_setvec& skip_op_false )
// END_PROTOTYPE
{
CPPAD_ASSERT_UNKNOWN( cexp_set.n_set() > 0 );
CPPAD_ASSERT_UNKNOWN( cexp_info.size() == 0 );
// number of operators in the tape
const size_t num_op = play->num_op_rec();
CPPAD_ASSERT_UNKNOWN( op_usage.size() == num_op );
CPPAD_ASSERT_UNKNOWN( op_previous.size() == num_op );
//
// number of conditional expressions in the tape
size_t num_cexp_op = cexp2op.size();
//
// initialize mapping from variable index to operator index
CPPAD_ASSERT_UNKNOWN(
size_t( (std::numeric_limits<addr_t>::max)() ) >= num_op
);
// ----------------------------------------------------------------------
// compute cexp_info
// ----------------------------------------------------------------------
//
// initialize information for each conditional expression
cexp_info.resize(num_cexp_op);
skip_op_true.resize(num_cexp_op, num_op);
skip_op_false.resize(num_cexp_op, num_op);
//
for(size_t i = 0; i < num_cexp_op; i++)
{ size_t i_op = size_t( cexp2op[i] );
CPPAD_ASSERT_UNKNOWN(
op_previous[i_op] == 0 || op_usage[i_op] == usage_t(yes_usage)
);
OpCode op; // operator
const addr_t* arg; // arguments
size_t i_var; // variable index of first result
random_itr.op_info(i_op, op, arg, i_var);
CPPAD_ASSERT_UNKNOWN( op == CExpOp );
//
struct_cexp_info info;
info.i_op = addr_t(i_op);
info.cop = CompareOp( arg[0] );
info.flag = static_cast<unsigned char>(arg[1]);
info.left = arg[2];
info.right = arg[3];
//
// max_left_right
addr_t index = 0;
if( arg[1] & 1 )
index = std::max<addr_t>(index, info.left);
if( arg[1] & 2 )
index = std::max<addr_t>(index, info.right);
info.max_left_right = index;
//
cexp_info[i] = info;
};
// Determine which operators can be conditionally skipped
size_t i_op = 0;
while(i_op < num_op)
{ size_t j_op = i_op;
bool keep = op_usage[i_op] != usage_t(no_usage);
keep &= op_usage[i_op] != usage_t(csum_usage);
keep &= op_previous[i_op] == 0;
if( keep )
{ sparse::list_setvec_const_iterator itr(cexp_set, i_op);
if( *itr != cexp_set.end() )
{ if( play->GetOp(i_op) == AFunOp )
{ // i_op is the first operations in this atomic function call.
// Find the last operation in this call.
++j_op;
while( play->GetOp(j_op) != AFunOp )
{ switch( play->GetOp(j_op) )
{ case FunapOp:
case FunavOp:
case FunrpOp:
case FunrvOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
++j_op;
}
}
}
while( *itr != cexp_set.end() )
{ size_t element = *itr;
size_t index = element / 2;
bool compare = bool( element % 2 );
if( compare == false )
{ // cexp_info[index].skip_op_false.push_back(i_op);
skip_op_false.post_element(index, i_op);
if( j_op != i_op )
{ // cexp_info[index].skip_op_false.push_back(j_op);
skip_op_false.post_element(index, j_op);
}
}
else
{ // cexp_info[index].skip_op_true.push_back(i_op);
skip_op_true.post_element(index, i_op);
if( j_op != i_op )
{ // cexp_info[index].skip_op_true.push_back(j_op);
skip_op_true.post_element(index, j_op);
}
}
++itr;
}
}
CPPAD_ASSERT_UNKNOWN( i_op <= j_op );
i_op += (1 + j_op) - i_op;
}
// process postings for skip_op_false, skip_op_true
for(size_t i = 0; i < num_cexp_op; ++i)
{ skip_op_false.process_post(i);
skip_op_true.process_post(i);
}
return;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,447 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_GET_DYN_PREVIOUS_HPP
# define CPPAD_LOCAL_OPTIMIZE_GET_DYN_PREVIOUS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file get_cexp_info.hpp
Create operator information tables
*/
# include <cppad/local/optimize/match_op.hpp>
# include <cppad/local/optimize/usage.hpp>
# include <cppad/local/optimize/hash_code.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
mapping from a dynamic parameter index to its arguments
\param i_dyn
is the dynamic parameter index
\param dyn_ind2par_ind
is the mapping from dynamic parameter index to parameter index
(size is number of dynamic parameters).
\param dyn_par_is
i-th element is true (false) if i-th parameter is (is not) dynamic
(size is number of parameters).
\param dyn_arg_offset
j-th element is the offset in dyn_par_arg of the first argument for j-th
dynamic parameter's operator (size is number of dynamic parameters).
This is only defined for dynamic parameters indices less than or equal i_dyn.
\param dyn_par_arg
it the vector of arguments for all the dynamic parameter operators.
This is only defined for dynamic parameters indices less than or equal i_dyn.
\param par_ind2dyn_ind
is the mapping from parameter index to dynamic parameter index
(size is number of parameters). This is only defined for parameter
indices less than or equal the parameter index corresponding to i_dyn.
\param dyn_previous
is the mapping from dynamic parameter index to previous dynamic parameter
that can be used as a replacement (size is number of dynamic parameters).
This is only defined for dynamic parameters indices less than or equal i_dyn.
\param arg_match
Size of this vector must be number of arguments for operator for i_dyn.
The input value of its elements does not matter.
Upn return it containts the parameter indices for the arguments
to use when matching this operator
Arguments that are dynamic prarameters, and have previous matches,
have been replaced by their previous matches.
*/
inline void dyn_arg_match(
size_t i_dyn ,
const pod_vector<addr_t>& dyn_ind2par_ind ,
const pod_vector<bool> & dyn_par_is ,
const pod_vector<addr_t>& dyn_arg_offset ,
const pod_vector<addr_t>& dyn_par_arg ,
const pod_vector<addr_t>& par_ind2dyn_ind ,
const pod_vector<addr_t>& dyn_previous ,
pod_vector<addr_t>& arg_match )
{
// number of dynamic parameters
addr_t num_dynamic_par = addr_t( dyn_ind2par_ind.size() );
//
// check some assumptions
CPPAD_ASSERT_UNKNOWN( size_t( num_dynamic_par ) == dyn_arg_offset.size() );
CPPAD_ASSERT_UNKNOWN( size_t( num_dynamic_par ) == dyn_previous.size() );
CPPAD_ASSERT_UNKNOWN( dyn_par_is.size() == par_ind2dyn_ind.size() );
//
// number of arguments for this operator
addr_t n_arg = addr_t( arg_match.size() );
//
// index in dyn_par_arg of first argument for this operator
addr_t i_arg = dyn_arg_offset[i_dyn];
//
// loop over arguments for this operator
for(addr_t j = 0; j < n_arg; ++j)
{ // parameter index for this argument
addr_t j_par = dyn_par_arg[i_arg + j];
CPPAD_ASSERT_UNKNOWN( j_par < dyn_ind2par_ind[i_dyn] );
//
// map dynamic parameters arguments to previous matches
if( dyn_par_is[j_par] )
{ addr_t j_dyn = par_ind2dyn_ind[j_par];
if( dyn_previous[j_dyn] != num_dynamic_par )
{ CPPAD_ASSERT_UNKNOWN( dyn_previous[j_dyn] < j_dyn );
// previous dynamic parameter
j_dyn = dyn_previous[j_dyn];
// correspoding parameter
j_par = dyn_ind2par_ind[j_dyn];
}
}
arg_match[j] = j_par;
}
return;
}
/*!
Get mapping from each dynamic parameter to a previous dynamic parameter
that can be used to replace it (if one exists).
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base.
\param play
This is the old operation sequence.
\param random_itr
This is a random iterator for the old operation sequence.
\param par_usage
The size of this vector is the number of parameters in the
operation sequence.i.e., play->nun_var_rec().
It is the usage counting previous operator optimization of operators.
\param dyn_previous
The input size of this vector must be zero.
Upon return it has size equal to the number of dynamic parameters in the
operation sequence; i.e., num_dyn = play->num_dynamic_par().
Let k = dyn_parvious[j]. If k == num_dyn, no replacement was found for the
j-th dynamic parameter. If k != num_dyn, the k-th dynamic parameter can be
used in place of the j-th dynamic parameter, k < j, dyn_previous[k] != num_dyn,
par_usage[dyn_ind2par_ind[k]] == true.
*/
template <class Addr, class Base>
void get_dyn_previous(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
pod_vector<bool>& par_usage ,
pod_vector<addr_t>& dyn_previous )
{
// number of parameters in the recording
size_t num_par = play->num_par_rec();
// number of dynamic parameters in the recording
size_t num_dynamic_par = play->num_dynamic_par();
// number of independent dynamic parameters in the recording
size_t num_dynamic_ind = play->num_dynamic_ind();
// check some assumptions
CPPAD_ASSERT_UNKNOWN( dyn_previous.size() == 0 );
CPPAD_ASSERT_UNKNOWN( par_usage.size() == num_par );
CPPAD_ASSERT_UNKNOWN( num_dynamic_par <= num_par );
CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= num_dynamic_par );
CPPAD_ASSERT_UNKNOWN( num_arg_dyn( ind_dyn ) == 0 );
// dynamic parameter information
dyn_previous.resize( num_dynamic_par );
const pod_vector<addr_t>& dyn_ind2par_ind( play->dyn_ind2par_ind() );
const pod_vector<bool>& dyn_par_is( play->dyn_par_is() );
const pod_vector<opcode_t>& dyn_par_op( play->dyn_par_op() );
const pod_vector<addr_t>& dyn_par_arg( play->dyn_par_arg() );
// mapping from parameter index to dynamic parameter index
// only defined when dyn_par_is is true
pod_vector<addr_t> par_ind2dyn_ind(num_par);
// mapping from dynamic parameter index to first argument index
pod_vector<addr_t> dyn_arg_offset(num_dynamic_par);
// ----------------------------------------------------------------------
// compute dyn_previous
// ----------------------------------------------------------------------
sparse::list_setvec hash_table_dyn;
hash_table_dyn.resize(CPPAD_HASH_TABLE_SIZE, num_dynamic_par);
//
// Initialize in dyn_par_arg
// (independent dynamic parameters do not have any arguments)
size_t i_arg = 0;
//
// independent dynamic parameters
for(size_t i_dyn = 0; i_dyn < num_dynamic_ind; ++i_dyn)
{ // parameter index
size_t i_par = size_t( dyn_ind2par_ind[i_dyn] );
// dynamic parameter index is one greater because phantom parameter
// at index 0 is not dynamic
CPPAD_ASSERT_UNKNOWN( i_par == i_dyn + 1 );
// mapping from parameter index to dynamic parameter index
par_ind2dyn_ind[i_par] = addr_t( i_dyn );
// never get optimized out
dyn_previous[i_dyn] = addr_t( num_dynamic_par );
}
//
// other dynamic parameters
for(size_t i_dyn = num_dynamic_ind; i_dyn < num_dynamic_par; ++i_dyn)
{ // Initialize previous for this dynamic parameter. This is only
// defined for dynamic parameter indices less than or equal i_dyn
dyn_previous[i_dyn] = addr_t( num_dynamic_par );
//
// mapping from dynamic parameter index to argument offset
// is only defined for j_dyn <= i_dyn
dyn_arg_offset[i_dyn] = addr_t( i_arg );
//
// parameter index for this dynamic parameter
size_t i_par = size_t( dyn_ind2par_ind[i_dyn] );
//
// mapping from parameter indices to dynamic parameter indices
// is only defined when dyn_par_is[i_par] is true and for parameter
// indices less than or equal i_par
CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] );
par_ind2dyn_ind[i_par] = addr_t( i_dyn );
//
// operator for this dynamic parameter
op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] );
//
// temporary used below and decaled here to reduce memory allocation
pod_vector<addr_t> arg_match;
//
// temporaries used below and decaled here to reduce indentation level
bool match;
size_t code;
size_t count;
//
// check for a previous match for i_dyn
if( par_usage[i_par] ) switch( op )
{
// ---------------------------------------------------------------
// unary operators
case abs_dyn:
case acos_dyn:
case acosh_dyn:
case asin_dyn:
case asinh_dyn:
case atan_dyn:
case atanh_dyn:
case cos_dyn:
case cosh_dyn:
case erf_dyn:
case erfc_dyn:
case exp_dyn:
case expm1_dyn:
case fabs_dyn:
case log_dyn:
case log1p_dyn:
case sign_dyn:
case sin_dyn:
case sinh_dyn:
case sqrt_dyn:
case tan_dyn:
case tanh_dyn:
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 1);
CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] );
{ size_t num_arg = 1;
arg_match.resize(num_arg);
dyn_arg_match(
i_dyn,
dyn_ind2par_ind,
dyn_par_is,
dyn_arg_offset,
dyn_par_arg,
par_ind2dyn_ind,
dyn_previous,
arg_match
);
opcode_t op_t = opcode_t(op);
code = optimize_hash_code(
op_t, num_arg, arg_match.data()
);
//
// iterator for the set with this hash code
sparse::list_setvec_const_iterator itr(hash_table_dyn, code);
//
// check for a match
count = 0;
match = false;
while( ! match && *itr != num_dynamic_par )
{ ++count;
//
// candidate for current dynamic parameter
size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
//
// argument offset for the candidate
addr_t k_arg = dyn_arg_offset[k_dyn];
//
match = op_t == dyn_par_op[k_dyn];
match &= arg_match[0] == dyn_par_arg[k_arg + 0];
if( ! match )
++itr;
}
if( match )
{ size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
dyn_previous[i_dyn] = addr_t( k_dyn );
}
else
{ CPPAD_ASSERT_UNKNOWN( count < 11 );
if( count == 10 )
{ // restart list for this hash code
hash_table_dyn.clear(code);
}
// Add this entry to hash table.
// Not using post_element becasue we need to iterate for
// this code before adding another element for this code.
hash_table_dyn.add_element(code, i_dyn);
}
}
break;
// ---------------------------------------------------------------
// binary operators
case add_dyn:
case div_dyn:
case mul_dyn:
case pow_dyn:
case sub_dyn:
case zmul_dyn:
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 2);
CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] );
match = false;
{ size_t num_arg = 2;
arg_match.resize(num_arg);
dyn_arg_match(
i_dyn,
dyn_ind2par_ind,
dyn_par_is,
dyn_arg_offset,
dyn_par_arg ,
par_ind2dyn_ind,
dyn_previous,
arg_match
);
opcode_t op_t = opcode_t(op);
code = optimize_hash_code(
op_t, num_arg, arg_match.data()
);
//
// iterator for the set with this hash code
sparse::list_setvec_const_iterator itr(hash_table_dyn, code);
//
// check for a match
count = 0;
while( ! match && *itr != num_dynamic_par )
{ ++count;
//
// candidate for current dynamic parameter
size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
//
// argument offset for the candidate
addr_t k_arg = dyn_arg_offset[k_dyn];
//
match = op_t == dyn_par_op[k_dyn];
match &= arg_match[0] == dyn_par_arg[k_arg + 0];
match &= arg_match[1] == dyn_par_arg[k_arg + 1];
if( ! match )
++itr;
}
if( match )
{ size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
dyn_previous[i_dyn] = addr_t( k_dyn );
}
}
if( (! match) & ( (op == add_dyn) | (op == mul_dyn) ) )
{ size_t num_arg = 2;
std::swap( arg_match[0], arg_match[1] );
opcode_t op_t = opcode_t(op);
size_t code_swp = optimize_hash_code(
op_t, num_arg, arg_match.data()
);
//
// iterator for the set with this hash code
sparse::list_setvec_const_iterator itr(hash_table_dyn, code_swp);
//
// check for a match
while( ! match && *itr != num_dynamic_par )
{ //
// candidate for current dynamic parameter
size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
//
// argument offset for the candidate
addr_t k_arg = dyn_arg_offset[k_dyn];
//
match = op_t == dyn_par_op[k_dyn];
match &= arg_match[0] == dyn_par_arg[k_arg + 0];
match &= arg_match[1] == dyn_par_arg[k_arg + 1];
if( ! match )
++itr;
}
if( match )
{ size_t k_dyn = *itr;
CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn );
dyn_previous[i_dyn] = addr_t( k_dyn );
}
}
if( ! match )
{ CPPAD_ASSERT_UNKNOWN( count < 11 );
if( count == 10 )
{ // restart list for this hash code
hash_table_dyn.clear(code);
}
// Add the entry to hash table
// Not using post_element becasue we need to iterate for
// this code before adding another element for this code.
hash_table_dyn.add_element(code, i_dyn);
}
// --------------------------------------------------------------
// skipping these cases for now
case dis_dyn:
case cond_exp_dyn:
case atom_dyn:
case result_dyn:
break;
// --------------------------------------------------------------
// should be no other cases; e.g., no ind_dyn or number_dyn.
default:
CPPAD_ASSERT_UNKNOWN(false);
break;
}
i_arg += num_arg_dyn(op);
if( op == atom_dyn )
{ CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 0 );
size_t n = size_t( dyn_par_arg[i_arg + 1] );
size_t m = size_t( dyn_par_arg[i_arg + 2] );
size_t n_arg = 5 + n + m;
i_arg += n_arg;
}
}
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,269 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_GET_OP_PREVIOUS_HPP
# define CPPAD_LOCAL_OPTIMIZE_GET_OP_PREVIOUS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/optimize/match_op.hpp>
# include <cppad/local/optimize/usage.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*
$begin optimize_get_op_previous$$
$spell
itr
iterator
bool
Exp
num
var
Op
cexp
Arg
Res
$$
$section Get Mapping From Op to Previous Op That is Equivalent$$
$head Syntax$$
$icode%exceed_collision_limit% = get_op_previous(
%collision_limit%,
%play%,
%random_itr%,
%cexp_set%,
%op_previous%,
%op_usage%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Base$$
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
$head collision_limit$$
is the maximum number of collisions (matches)
allowed in the hash expression has table.
$head play$$
is the old operation sequence.
$head random_itr$$
is a random iterator for the old operation sequence.
$head cexp_set$$
set[i] is a set of elements for the i-th operator.
Suppose that e is an element of set[i], j = e / 2, k = e % 2.
If the comparison for the j-th conditional expression is equal to bool(k),
the i-th operator can be skipped (is not used by any of the results).
Note the j indexes the CExpOp operators in the operation sequence.
On input, cexp_set is does not count previous optimization.
On output, it does count previous optimization.
$head op_previous$$
The input size of this vector must be zero.
Upon return it has size equal to the number of operators
in the operation sequence; i.e., num_op = play->nun_var_rec().
Let j = op_previous[i]. If j = 0, no replacement was found for i-th operator.
If j != 0:
$list number$$
j < i
$lnext
op_previous[j] == 0
$lnext
op_usage[j] == usage_t(yes_usage)
$lnext
i-th operator has NumArg(op) <= 3
$lnext
i-th operator has 0 < NumRes(op)
$lnext
i-th operator is not one of the following:
$nospell PriOp, ParOp, InvOp, EndOp, CexpOp, BeginOp.$$
$lnext
i-th operator is not one of the load store operator:
$nospell LtpvOp, LtvpOp, LtvvOp, StppOp, StpvOp, StvpOp, StvvOp.$$
$lnext
i-th operator is not a atomic function operator:
$nospell AFunOp, FunapOp, FunavOp, FunrpOp, FunrvOp.$$
$lend
$head op_usage$$
The size of this vector is the number of operators in the
old operation sequence.i.e., play->nun_var_rec().
On input, op_usage[i] is the usage for
the i-th operator in the operation sequence not counting previous
optimization.
On output, it is the usage counting previous operator optimization.
$head exceed_collision_limit$$
If the $icode collision_limit$$ is exceeded (is not exceeded),
the return value is true (false).
$end
*/
// BEGIN_PROTOTYPE
template <class Addr, class Base>
bool get_op_previous(
size_t collision_limit ,
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
sparse::list_setvec& cexp_set ,
pod_vector<addr_t>& op_previous ,
pod_vector<usage_t>& op_usage )
// END_PROTOTYPE
{ bool exceed_collision_limit = false;
//
// number of operators in the tape
const size_t num_op = random_itr.num_op();
CPPAD_ASSERT_UNKNOWN( op_previous.size() == 0 );
CPPAD_ASSERT_UNKNOWN( op_usage.size() == num_op );
op_previous.resize( num_op );
//
// number of conditional expressions in the tape
//
// initialize mapping from variable index to operator index
CPPAD_ASSERT_UNKNOWN(
size_t( (std::numeric_limits<addr_t>::max)() ) >= num_op
);
// ----------------------------------------------------------------------
// compute op_previous
// ----------------------------------------------------------------------
sparse::list_setvec hash_table_op;
hash_table_op.resize(CPPAD_HASH_TABLE_SIZE, num_op);
//
pod_vector<bool> work_bool;
pod_vector<addr_t> work_addr_t;
for(size_t i_op = 0; i_op < num_op; ++i_op)
{ op_previous[i_op] = 0;
if( op_usage[i_op] == usage_t(yes_usage) )
switch( random_itr.get_op(i_op) )
{
// ----------------------------------------------------------------
// these operators never match pevious operators
case BeginOp:
case CExpOp:
case CSkipOp:
case CSumOp:
case EndOp:
case InvOp:
case LdpOp:
case LdvOp:
case ParOp:
case PriOp:
case StppOp:
case StpvOp:
case StvpOp:
case StvvOp:
case AFunOp:
case FunapOp:
case FunavOp:
case FunrpOp:
case FunrvOp:
break;
// ----------------------------------------------------------------
// check for a previous match
case AbsOp:
case AcosOp:
case AcoshOp:
case AddpvOp:
case AddvvOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case DisOp:
case DivpvOp:
case DivvpOp:
case DivvvOp:
case EqpvOp:
case EqvvOp:
case ErfOp:
case ErfcOp:
case ExpOp:
case Expm1Op:
case LepvOp:
case LevpOp:
case LevvOp:
case LogOp:
case Log1pOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case MulpvOp:
case MulvvOp:
case NepvOp:
case NevvOp:
case PowpvOp:
case PowvpOp:
case PowvvOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case SubpvOp:
case SubvpOp:
case SubvvOp:
case TanOp:
case TanhOp:
case ZmulpvOp:
case ZmulvpOp:
case ZmulvvOp:
exceed_collision_limit |= match_op(
collision_limit,
random_itr,
op_previous,
i_op,
hash_table_op,
work_bool,
work_addr_t
);
if( op_previous[i_op] != 0 )
{ // like a unary operator that assigns i_op equal to previous.
size_t previous = size_t( op_previous[i_op] );
bool sum_op = false;
CPPAD_ASSERT_UNKNOWN( previous < i_op );
op_inc_arg_usage(
play, sum_op, i_op, previous, op_usage, cexp_set
);
}
break;
// ----------------------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(false);
break;
}
}
/* ---------------------------------------------------------------------
// Print out hash code usage summary
CppAD::vector<size_t> count(collision_limit + 1);
for(size_t i = 0; i <= collision_limit; ++i)
count[i] = 0;
for(size_t code = 0; code < CPPAD_HASH_TABLE_SIZE; ++code)
{ size_t size = hash_table_op.number_elements(code);
++count[size];
}
std::cout << "count = " << count << "\n";
--------------------------------------------------------------------- */
return exceed_collision_limit;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,853 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_GET_OP_USAGE_HPP
# define CPPAD_LOCAL_OPTIMIZE_GET_OP_USAGE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/optimize/cexp_info.hpp>
# include <cppad/local/optimize/usage.hpp>
# include <cppad/local/sweep/call_atomic.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/// Is this an addition or subtraction operator
inline bool op_add_or_sub(
OpCode op ///< operator we are checking
)
{ bool result;
switch(op)
{
case AddpvOp:
case AddvvOp:
case SubpvOp:
case SubvpOp:
case SubvvOp:
result = true;
break;
default:
result = false;
break;
}
return result;
}
/*!
$begin optimize_op_inc_arg_usage$$
$spell
cexp
op
arg
csum
optimizer
$$
$section
Increase Argument Usage and Propagate cexp_set From Result to Argument
$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_OP_INC_ARG_USAGE%// END_PROTOTYPE%1
%$$
$head play$$
is the player for the old operation sequence.
$head check_csum$$
is result an addition or subtraction operator,
and the optimizer is allowed to generate cumulative sum operators.
$head i_result$$
is the operator index for the result operator.
There are no posting waiting to be processed for the corresponding cexp_set.
$head i_arg$$
is the operator index for the argument to the result operator.
There may be postings waiting to be processed for the corresponding cexp_set.
$head op_usage$$
structure that holds the information for each of the operators.
The output value of op_usage[i_arg] is increased; to be specific,
If check_csum is true and the input value of op_usage[i_arg]
is usage_t(no_usage), its output value is usage_t(csum_usage).
Otherwise, the output value of op_usage[i_arg] is usage_t(yes_usage).
$head cexp_set$$
This is a vector of sets with one set for each operator.
We denote the i-th set by set[i].
These are the conditional expression conditions that must be
satisfied for this argument to be used.
$list number$$
In the special case where cexp_set.n_set() is zero,
cexp_set is not changed.
$lnext
If cexp_set.n_set() != 0 and op_usage[i_arg] == usage_t(no_usage),
the input value of set[i_arg] must be empty.
In this case the output value if set[i_arg] is equal to set[i_result]
(which may also be empty).
$lnext
If cexp_set.n_set() != 0 and op_usage[i_arg] != usage_t(no_usage),
the output value of set[i_arg] is the intersection of
its input value and set[i_result].
$lend
$end
*/
// BEGIN_OP_INC_ARG_USAGE
template <class Base>
void op_inc_arg_usage(
const player<Base>* play ,
bool check_csum ,
size_t i_result ,
size_t i_arg ,
pod_vector<usage_t>& op_usage ,
sparse::list_setvec& cexp_set )
// END_PROTOTYPE
{ // value of argument input on input to this routine
enum_usage arg_usage = enum_usage( op_usage[i_arg] );
//
// new value for usage
op_usage[i_arg] = usage_t(yes_usage);
if( check_csum )
{ if( arg_usage == no_usage )
{ OpCode op_a = play->GetOp(i_arg);
if( op_add_or_sub( op_a ) )
{ op_usage[i_arg] = usage_t(csum_usage);
}
}
}
//
// cexp_set
if( cexp_set.n_set() == 0 )
return;
//
if( arg_usage == no_usage )
{ // set[i_arg] = set[i_result]
// not necessary to process posts for set i_result
cexp_set.assignment(i_arg, i_result, cexp_set);
}
else
{ // set[i_arg] = set[i_arg] intersect set[i_result]
// is necessary to process postts for set i_arg
cexp_set.process_post(i_arg);
cexp_set.binary_intersection(i_arg, i_arg, i_result, cexp_set);
}
//
return;
}
/*!
$begin optimize_get_op_usage$$
$spell
Ind
var
itr
dep_taddr
cexp
vecad
Addr
iterator
NumRes
PriOp
Exp
bool
Vec
$$
$section
Use Reverse Activity Analysis to Get Usage Information for Each Operator
$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_GET_OP_USAGE%// END_PROTOTYPE%1
%$$
$head Base$$
Base type for the operator; i.e., this operation was recorded
using $codei%AD<%Base%>%$$ and computations by this routine are done
using type $icode Base$$.
$head Addr$$
Type used by random iterator for the player.
$head cumulative_sum_op$$
If this is true (false), cumulative summation operator are allowed
(not allowed) to be generated by the optimization.
$head compare_op$$
if this is true, arguments are considered used if they appear in compare
operators. This is a side effect because compare operators have boolean
results (and the result is not in the tape; i.e. NumRes(op) is zero
for these operators. (This is an example of a side effect.)
$head print_for_op$$
if this is true, arguments are considered used if they appear in
print forward operators; i.e., PriOp.
This is also a side effect; i.e. NumRes(PriOp) is zero.
$head conditional_skip$$
If this is true,
the conditional expression information cexp_info will be calculated.
This may be time intensive and may not have much benefit in the optimized
recording.
$head play$$
This is the operation sequence.
$head random_itr$$
This is a random iterator for the operation sequence.
$head dep_taddr$$
is a vector of indices for the dependent variables
(where the reverse activity analysis starts).
$head cexp2op$$
The input size of this vector must be zero.
Upon return it has size equal to the number of conditional expressions,
CExpOp operators. The value $icode%cexp2op[%j%]%$$ is the operator
index corresponding to the $th j$$ conditional expressions.
$head cexp_set$$
This is a vector of sets that is empty on input.
If $icode conditional_skip$$ is false, $icode cexp_usage$$ is not modified.
Otherwise, set[i] is a set of elements for the i-th operator.
Suppose that e is an element of set[i], j = e / 2, k = e % 2.
If the comparison for the j-th conditional expression is equal to bool(k),
the i-th operator can be skipped (is not used by any of the results).
Note that j indexes the CExpOp operators in the operation sequence.
$head vecad_used$$
The input size of this vector must be zero.
Upon return it has size equal to the number of VecAD vectors
in the operations sequences; i.e., play->num_var_vecad_rec().
The VecAD vectors are indexed in the order that their indices appear
in the one large play->GetVecInd that holds all the VecAD vectors.
$head op_usage$$
The input size of this vector must be zero.
Upon return it has size equal to the number of operators
in the operation sequence; i.e., num_op = play->nun_var_rec().
The value $icode%op_usage%[%i%]%$$ has been set to the usage for
the i-th operator in the operation sequence.
Atomic function calls are a special case,
the first and second AFunOp have usage corresponding to the entire call.
The arguments have the usage for particular parameter or variable.
This usage is only for creating variables, not for creating
dynamic parameters.
$end
*/
// BEGIN_GET_OP_USAGE
template <class Addr, class Base>
void get_op_usage(
bool conditional_skip ,
bool compare_op ,
bool print_for_op ,
bool cumulative_sum_op ,
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<size_t>& dep_taddr ,
pod_vector<addr_t>& cexp2op ,
sparse::list_setvec& cexp_set ,
pod_vector<bool>& vecad_used ,
pod_vector<usage_t>& op_usage )
// END_PROTOTYPE
{
CPPAD_ASSERT_UNKNOWN( cexp_set.n_set() == 0 );
CPPAD_ASSERT_UNKNOWN( vecad_used.size() == 0 );
CPPAD_ASSERT_UNKNOWN( op_usage.size() == 0 );
// number of operators in the tape
const size_t num_op = play->num_op_rec();
//
// initialize mapping from variable index to operator index
CPPAD_ASSERT_UNKNOWN(
size_t( (std::numeric_limits<addr_t>::max)() ) >= num_op
);
// -----------------------------------------------------------------------
// information about current operator
OpCode op; // operator
const addr_t* arg; // arguments
size_t i_op; // operator index
size_t i_var; // variable index of first result
// -----------------------------------------------------------------------
// information about atomic function calls
size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0;
enum_atom_state atom_state;
//
// work space used by user atomic functions
vector<Base> atom_x; // value of parameters in x
vector<ad_type_enum> type_x; // type for each argument
vector<size_t> atom_ix; // variables indices for argument vector
vector<bool> depend_y; // results that are used
vector<bool> depend_x; // arguments that are used
//
// parameter information (used by atomic function calls)
# ifndef NDEBUG
size_t num_par = play->num_par_rec();
# endif
CPPAD_ASSERT_UNKNOWN( num_par > 0 )
const Base* parameter = play->GetPar();
// -----------------------------------------------------------------------
// vecad information
size_t num_vecad = play->num_var_vecad_rec();
size_t num_vecad_ind = play->num_var_vecad_ind_rec();
//
vecad_used.resize(num_vecad);
for(size_t i = 0; i < num_vecad; i++)
vecad_used[i] = false;
//
vector<size_t> arg2vecad(num_vecad_ind);
for(size_t i = 0; i < num_vecad_ind; i++)
arg2vecad[i] = num_vecad; // invalid value
size_t arg_0 = 1; // value of arg[0] for theh first vecad
for(size_t i = 0; i < num_vecad; i++)
{
// mapping from arg[0] value to index for this vecad object.
arg2vecad[arg_0] = i;
//
// length of this vecad object
size_t length = play->GetVecInd(arg_0 - 1);
//
// set to proper index in GetVecInd for next VecAD arg[0] value
arg_0 += length + 1;
}
CPPAD_ASSERT_UNKNOWN( arg_0 == num_vecad_ind + 1 );
// -----------------------------------------------------------------------
// conditional expression information
//
size_t num_cexp_op = 0;
if( conditional_skip )
{ for(i_op = 0; i_op < num_op; ++i_op)
{ if( random_itr.get_op(i_op) == CExpOp )
{ // count the number of conditional expressions.
++num_cexp_op;
}
}
}
//
cexp2op.resize( num_cexp_op );
//
// number of sets
size_t num_set = 0;
if( conditional_skip && num_cexp_op > 0)
num_set = num_op;
//
// conditional expression index = element / 2
// conditional expression compare = bool ( element % 2)
size_t end_set = 2 * num_cexp_op;
//
if( num_set > 0 )
cexp_set.resize(num_set, end_set);
// -----------------------------------------------------------------------
// initilaize operator usage for reverse dependency analysis.
op_usage.resize( num_op );
for(i_op = 0; i_op < num_op; ++i_op)
op_usage[i_op] = usage_t(no_usage);
for(size_t i = 0; i < dep_taddr.size(); i++)
{ i_op = random_itr.var2op(dep_taddr[i]);
op_usage[i_op] = usage_t(yes_usage); // dependent variables
}
// ----------------------------------------------------------------------
// Reverse pass to compute usage and cexp_set for each operator
// ----------------------------------------------------------------------
//
// Initialize reverse pass
size_t last_atom_i_op = 0;
size_t cexp_index = num_cexp_op;
atom_state = end_atom;
i_op = num_op;
while(i_op != 0 )
{ --i_op;
if( num_set > 0 )
{ // no more elements will be added to this set
cexp_set.process_post(i_op);
}
//
// this operator information
random_itr.op_info(i_op, op, arg, i_var);
//
// Is the result of this operation used.
// (This only makes sense when NumRes(op) > 0.)
usage_t use_result = op_usage[i_op];
//
bool check_csum = false;
switch( op )
{
// =============================================================
// normal operators
// =============================================================
// Only one variable with index arg[0]
case SubvpOp:
check_csum = cumulative_sum_op;
//
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case DivvpOp:
case ErfOp:
case ErfcOp:
case ExpOp:
case Expm1Op:
case LogOp:
case Log1pOp:
case PowvpOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( use_result != usage_t(no_usage) )
{ size_t j_op = random_itr.var2op(size_t(arg[0]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
break; // --------------------------------------------
// Only one variable with index arg[1]
case AddpvOp:
case SubpvOp:
check_csum = cumulative_sum_op;
//
case DisOp:
case DivpvOp:
case MulpvOp:
case PowpvOp:
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( use_result != usage_t(no_usage) )
{ size_t j_op = random_itr.var2op(size_t(arg[1]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
break; // --------------------------------------------
// arg[0] and arg[1] are the only variables
case AddvvOp:
case SubvvOp:
check_csum = cumulative_sum_op;
//
case DivvvOp:
case MulvvOp:
case PowvvOp:
case ZmulvvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( use_result != usage_t(no_usage) )
{ for(size_t i = 0; i < 2; i++)
{ size_t j_op = random_itr.var2op(size_t(arg[i]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
}
break; // --------------------------------------------
// Conditional expression operators
// arg[2], arg[3], arg[4], arg[5] are parameters or variables
case CExpOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( conditional_skip )
{ --cexp_index;
cexp2op[ cexp_index ] = addr_t(i_op);
}
if( use_result != usage_t(no_usage) )
{ CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 );
// propgate from result to left argument
if( arg[1] & 1 )
{ size_t j_op = random_itr.var2op(size_t(arg[2]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
// propgate from result to right argument
if( arg[1] & 2 )
{ size_t j_op = random_itr.var2op(size_t(arg[3]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
// are if_true and if_false cases the same variable
bool same_variable = (arg[1] & 4) != 0;
same_variable &= (arg[1] & 8) != 0;
same_variable &= arg[4] == arg[5];
//
// if_true
if( arg[1] & 4 )
{ size_t j_op = random_itr.var2op(size_t(arg[4]));
bool can_skip = conditional_skip & (! same_variable);
can_skip &= op_usage[j_op] == usage_t(no_usage);
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
if( can_skip )
{ // j_op corresponds to the value used when the
// comparison result is true. It can be skipped when
// the comparison is false (0).
size_t element = 2 * cexp_index + 0;
cexp_set.post_element(j_op, element);
//
op_usage[j_op] = usage_t(yes_usage);
}
}
//
// if_false
if( arg[1] & 8 )
{ size_t j_op = random_itr.var2op(size_t(arg[5]));
bool can_skip = conditional_skip & (! same_variable);
can_skip &= op_usage[j_op] == usage_t(no_usage);
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
if( can_skip )
{ // j_op corresponds to the value used when the
// comparison result is false. It can be skipped when
// the comparison is true (0).
size_t element = 2 * cexp_index + 1;
cexp_set.post_element(j_op, element);
//
op_usage[j_op] = usage_t(yes_usage);
}
}
}
break; // --------------------------------------------
// Operations that are never used
// (new CSkip options are generated if conditional_skip is true)
case CSkipOp:
case ParOp:
break;
// Operators that are always used
case InvOp:
case BeginOp:
case EndOp:
op_usage[i_op] = usage_t(yes_usage);
break; // -----------------------------------------------
// The print forward operator
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
if( print_for_op )
{ op_usage[i_op] = usage_t(yes_usage);
if( arg[0] & 1 )
{ // arg[1] is a variable
size_t j_op = random_itr.var2op(size_t(arg[1]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
if( arg[0] & 2 )
{ // arg[3] is a variable
size_t j_op = random_itr.var2op(size_t(arg[3]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
}
break; // -----------------------------------------------------
// =============================================================
// Comparison operators
// =============================================================
// Compare operators where arg[1] is only variable
case LepvOp:
case LtpvOp:
case EqpvOp:
case NepvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
if( compare_op )
{ op_usage[i_op] = usage_t(yes_usage);
//
size_t j_op = random_itr.var2op(size_t(arg[1]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
break; // ----------------------------------------------
// Compare operators where arg[0] is only variable
case LevpOp:
case LtvpOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
if( compare_op )
{ op_usage[i_op] = usage_t(yes_usage);
//
size_t j_op = random_itr.var2op(size_t(arg[0]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
break; // ----------------------------------------------
// Compare operators where arg[0] and arg[1] are variables
case LevvOp:
case LtvvOp:
case EqvvOp:
case NevvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
if( compare_op )
{ op_usage[i_op] = usage_t(yes_usage);
//
for(size_t i = 0; i < 2; i++)
{ size_t j_op = random_itr.var2op(size_t(arg[i]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
}
break; // ----------------------------------------------
// =============================================================
// VecAD operators
// =============================================================
// load operator using a parameter index
case LdpOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( use_result != usage_t(no_usage) )
{ size_t i_vec = arg2vecad[ arg[0] ];
vecad_used[i_vec] = true;
}
break; // --------------------------------------------
// load operator using a variable index
case LdvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
if( use_result != usage_t(no_usage) )
{ size_t i_vec = arg2vecad[ arg[0] ];
vecad_used[i_vec] = true;
//
size_t j_op = random_itr.var2op(size_t(arg[1]));
op_usage[j_op] = usage_t(yes_usage);
}
break; // --------------------------------------------
// Store a variable using a parameter index
case StpvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
if( vecad_used[ arg2vecad[ arg[0] ] ] )
{ op_usage[i_op] = usage_t(yes_usage);
//
size_t j_op = random_itr.var2op(size_t(arg[2]));
op_usage[j_op] = usage_t(yes_usage);
}
break; // --------------------------------------------
// Store a variable using a variable index
case StvvOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
if( vecad_used[ arg2vecad[ arg[0] ] ] )
{ op_usage[i_op] = usage_t(yes_usage);
//
size_t j_op = random_itr.var2op(size_t(arg[1]));
op_usage[j_op] = usage_t(yes_usage);
size_t k_op = random_itr.var2op(size_t(arg[2]));
op_usage[k_op] = usage_t(yes_usage);
}
break; // -----------------------------------------------------
// =============================================================
// cumulative summation operator
// ============================================================
case CSumOp:
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
{
for(size_t i = 5; i < size_t(arg[2]); i++)
{ size_t j_op = random_itr.var2op(size_t(arg[i]));
op_inc_arg_usage(
play, check_csum, i_op, j_op, op_usage, cexp_set
);
}
}
break;
// =============================================================
// user defined atomic operators
// ============================================================
case AFunOp:
// start or end atomic operation sequence
if( atom_state == end_atom )
{ // reverse_user using random_itr instead of play
atom_index = size_t(arg[0]);
atom_old = size_t(arg[1]);
atom_n = size_t(arg[2]);
atom_m = size_t(arg[3]);
atom_j = atom_n;
atom_i = atom_m;
atom_state = ret_atom;
// -------------------------------------------------------
last_atom_i_op = i_op;
CPPAD_ASSERT_UNKNOWN( i_op > atom_n + atom_m + 1 );
CPPAD_ASSERT_UNKNOWN(
op_usage[last_atom_i_op] == usage_t(no_usage)
);
# ifndef NDEBUG
if( cexp_set.n_set() > 0 )
{ cexp_set.process_post(last_atom_i_op);
CPPAD_ASSERT_UNKNOWN(
cexp_set.number_elements(last_atom_i_op) == 0
);
}
# endif
//
atom_x.resize( atom_n );
type_x.resize( atom_n );
atom_ix.resize( atom_n );
//
depend_y.resize( atom_m );
depend_x.resize( atom_n );
for(size_t i = 0; i < atom_m; i++)
depend_y[ i ] = false;
}
else
{ // reverse_user using random_itr instead of play
CPPAD_ASSERT_UNKNOWN( atom_state == start_atom );
CPPAD_ASSERT_UNKNOWN( atom_n == size_t(arg[2]) );
CPPAD_ASSERT_UNKNOWN( atom_m == size_t(arg[3]) );
CPPAD_ASSERT_UNKNOWN( atom_j == 0 );
CPPAD_ASSERT_UNKNOWN( atom_i == 0 );
atom_state = end_atom;
// -------------------------------------------------------
CPPAD_ASSERT_UNKNOWN(
i_op + atom_n + atom_m + 1 == last_atom_i_op
);
if( op_usage[last_atom_i_op] != usage_t(no_usage) )
{ // call atomic function for this operation
sweep::call_atomic_rev_depend<Base, Base>(
atom_index, atom_old, atom_x, type_x, depend_x, depend_y
);
for(size_t j = 0; j < atom_n; j++)
if( depend_x[j] )
{ // The parameter or variable correspnding to the j-th
// argument gets used
op_usage[i_op + 1 + j] = true;
if( type_x[j] == variable_enum )
{ CPPAD_ASSERT_UNKNOWN( atom_ix[j] > 0 );
if( depend_x[j] )
{ size_t j_op = random_itr.var2op(atom_ix[j]);
op_inc_arg_usage(play, check_csum,
last_atom_i_op, j_op, op_usage, cexp_set
);
}
}
}
}
// copy set infomation from last to first
if( cexp_set.n_set() > 0 )
{ cexp_set.process_post(last_atom_i_op);
cexp_set.assignment(i_op, last_atom_i_op, cexp_set);
}
// copy usage information from last to first
op_usage[i_op] = op_usage[last_atom_i_op];
}
break; // -------------------------------------------------------
case FunapOp:
// parameter argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
//
// reverse_user using random_itr instead of play
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
CPPAD_ASSERT_UNKNOWN( 0 < atom_j && atom_j <= atom_n );
--atom_j;
if( atom_j == 0 )
atom_state = start_atom;
// -------------------------------------------------------------
atom_ix[atom_j] = 0;
//
// parameter arguments
atom_x[atom_j] = parameter[arg[0]];
if( play->dyn_par_is()[arg[0]] )
type_x[atom_j] = dynamic_enum;
else
type_x[atom_j] = constant_enum;
//
break;
case FunavOp:
// variable argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
//
// reverse_user using random_itr instead of play
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
CPPAD_ASSERT_UNKNOWN( 0 < atom_j && atom_j <= atom_n );
--atom_j;
if( atom_j == 0 )
atom_state = start_atom;
// -------------------------------------------------------------
atom_ix[atom_j] = size_t(arg[0]);
//
// variable arguments as parameters
atom_x[atom_j] = CppAD::numeric_limits<Base>::quiet_NaN();
type_x[atom_j] = variable_enum;
//
break;
case FunrvOp:
// variable result in an atomic operation sequence
//
// reverse_user using random_itr instead of play
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
CPPAD_ASSERT_UNKNOWN( 0 < atom_i && atom_i <= atom_m );
--atom_i;
if( atom_i == 0 )
atom_state = arg_atom;
// -------------------------------------------------------------
if( use_result )
{ depend_y[atom_i] = true;
op_inc_arg_usage(
play, check_csum, i_op, last_atom_i_op, op_usage, cexp_set
);
}
break; // --------------------------------------------------------
case FunrpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
//
// reverse_user using random_itr instead of play
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
CPPAD_ASSERT_UNKNOWN( 0 < atom_i && atom_i <= atom_m );
--atom_i;
if( atom_i == 0 )
atom_state = arg_atom;
break;
// ============================================================
// all cases should be handled above
default:
CPPAD_ASSERT_UNKNOWN(0);
}
}
return;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,506 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_GET_PAR_USAGE_HPP
# define CPPAD_LOCAL_OPTIMIZE_GET_PAR_USAGE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file get_cexp_info.hpp
Create operator information tables
*/
# include <cppad/local/optimize/get_op_usage.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
$begin optimize_get_par_usage$$
$spell
Addr
iterator
itr
op
num
var
vecad
Vec
Ind
$$
$section Use Reverse Activity Analysis to Get Usage for Each Parameter$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_GET_PAR_USAGE%// END_PROTOTYPE%1
%$$
$head Base$$
Base type for the operator; i.e., this operation was recorded
using $codei%AD<%Base%>%$$
and computations by this routine are done using type $icode Base$$.
$head Addr$$
Type used by random iterator for the player.
$head play$$
This is the operation sequence.
$head random_itr$$
This is a random iterator for the operation sequence.
$head op_usage$$
This argument has size equal to the number of operators
in the operation sequence; i.e., num_op = play->nun_var_rec().
The value $icode%op_usage%[%i%]%$$ have been set to the usage for
the i-th operator in the operation sequence.
$head vecad_used$$
This argument has size equal to the number of VecAD vectors
in the operations sequences; i.e., play->num_var_vecad_rec().
The VecAD vectors are indexed in the order that their indices appear
in the one large play->GetVecInd that holds all the VecAD vectors.
$head par_usage$$
The input size of this vector must be zero.
Upon return it has size equal to the number of parameters
in the operation sequence; i.e., play->num_par_rec();
The value $icode%par_usage%[%i%]%$$ is true if an only if
the i-th parameter is used to compute a dependent variable
or parameter.
The nan at the beginning of the parameter vector
and the independent dynamic parameters are always used.
$end
*/
// BEGIN_GET_PAR_USAGE
template <class Addr, class Base>
void get_par_usage(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<usage_t>& op_usage ,
pod_vector<bool>& vecad_used ,
pod_vector<bool>& par_usage )
// END_PROTOTYPE
{
CPPAD_ASSERT_UNKNOWN( op_usage.size() == play->num_op_rec() );
CPPAD_ASSERT_UNKNOWN( par_usage.size() == 0 );
//
// number of operators in the tape
const size_t num_op = play->num_op_rec();
//
// number of parameters in the tape
const size_t num_par = play->num_par_rec();
//
// number of dynamic parameters
const size_t num_dynamic_par = play->num_dynamic_par();
//
// number of independent dynamic parameters
size_t num_dynamic_ind = play->num_dynamic_ind();
//
// number of VecAD vectors
size_t num_vecad_vec = play->num_var_vecad_rec();
//
// dynamic parameter information
const pod_vector<bool>& dyn_par_is( play->dyn_par_is() );
const pod_vector<opcode_t>& dyn_par_op( play->dyn_par_op() );
const pod_vector<addr_t>& dyn_par_arg( play->dyn_par_arg() );
const pod_vector<addr_t>& dyn_ind2par_ind( play->dyn_ind2par_ind() );
const pod_vector_maybe<Base>& all_par_vec( play->all_par_vec() );
// -----------------------------------------------------------------------
// initialize par_usage
par_usage.resize(num_par);
par_usage[0] = true; // true for nan at beginning of parameter vector
for(size_t i_par = 1; i_par <= num_dynamic_ind; ++i_par)
par_usage[i_par] = true; // true for independent dynamic parameters
for(size_t i_par = num_dynamic_ind+1; i_par < num_par; ++i_par)
par_usage[i_par] = false; // initialize as false for other parameters
//
// -----------------------------------------------------------------------
// set usage to true for VecAD parameters that get used
size_t start_this_vector = 0;
for(size_t i_vec = 0; i_vec < num_vecad_vec; ++i_vec)
{ // length of this vector (note length is not a parameter)
size_t length = play->GetVecInd(start_this_vector);
//
if( vecad_used[i_vec] )
{ // this vector gets used
for(size_t k = 1; k <= length; ++k)
{ // index of parameter used by this VecAD vector
size_t i_par = play->GetVecInd(start_this_vector + k);
// must not be a dynamic parameter
CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[i_par] );
// set usage for this parameter
par_usage[i_par] = true;
}
}
start_this_vector += length + 1;
}
CPPAD_ASSERT_UNKNOWN( start_this_vector == play->num_var_vecad_ind_rec() );
//
// -----------------------------------------------------------------------
// forward pass to mark which parameters are used by necessary operators
// -----------------------------------------------------------------------
//
// information about atomic function calls
size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0;
enum_atom_state atom_state = start_atom;
//
// work space used by user atomic functions
vector<Base> parameter_x; // value of parameters in x
vector<ad_type_enum> type_x; // type for each component of z
vector<size_t> atom_ix; // variables indices for argument vector
vector<bool> depend_y; // results that are used
vector<bool> depend_x; // arguments that are used
//
for(size_t i_op = 0; i_op < num_op; ++i_op)
{
// information about current operator
OpCode op; // operator
const addr_t* arg; // arguments
size_t i_var; // variable index of first result
random_itr.op_info(i_op, op, arg, i_var);
//
bool skip = op_usage[i_op] == usage_t(no_usage);
skip &= atom_state == start_atom;
if( ! skip ) switch( op )
{
// add or subtract with left a parameter and right a variable
case AddpvOp:
case SubpvOp:
if( dyn_par_is[ arg[0] ] )
par_usage[ arg[0] ] = true;
else
{ // determine if this parameter will be absorbed by csum
if( ! (op_usage[i_op] == csum_usage) )
{ // determine operator corresponding to variable
size_t j_op = random_itr.var2op(size_t(arg[1]));
CPPAD_ASSERT_UNKNOWN( op_usage[j_op] != no_usage );
if( op_usage[j_op] != csum_usage )
par_usage[ arg[0] ] = true;
}
}
break;
// subtract with left a variable and right a parameter
case SubvpOp:
if( dyn_par_is[ arg[1] ] )
par_usage[ arg[1] ] = true;
else
{ // determine if this parameter will be absorbed by csum
if( ! (op_usage[i_op] == csum_usage) )
{ // determine operator corresponding to variable
size_t j_op = random_itr.var2op(size_t(arg[0]));
CPPAD_ASSERT_UNKNOWN( op_usage[j_op] != no_usage );
if( op_usage[j_op] != csum_usage )
par_usage[ arg[1] ] = true;
}
}
break;
// cases with no parameter arguments
case AbsOp:
case AcosOp:
case AcoshOp:
case AddvvOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case BeginOp:
case CosOp:
case CoshOp:
case CSkipOp:
case DisOp:
case DivvvOp:
case EndOp:
case EqvvOp:
case ExpOp:
case Expm1Op:
case InvOp:
case LdvOp:
case LevvOp:
case LogOp:
case Log1pOp:
case LtvvOp:
case MulvvOp:
case NevvOp:
case PowvvOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case StvvOp:
case SubvvOp:
case TanOp:
case TanhOp:
case ZmulvvOp:
break;
// cases where first and second arguments are parameters
case EqppOp:
case LeppOp:
case LtppOp:
case NeppOp:
CPPAD_ASSERT_UNKNOWN( 2 <= NumArg(op) )
par_usage[arg[0]] = true;
par_usage[arg[1]] = true;
break;
// cases where only first argument is a parameter
case CSumOp:
case EqpvOp:
case DivpvOp:
case LepvOp:
case LtpvOp:
case MulpvOp:
case NepvOp:
case ParOp:
case PowpvOp:
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( 1 <= NumArg(op) || op == CSumOp )
par_usage[arg[0]] = true;
break;
// cases where only second argument is a parameter
case DivvpOp:
case LevpOp:
case LdpOp:
case LtvpOp:
case PowvpOp:
case StpvOp:
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( 2 <= NumArg(op) )
par_usage[arg[1]] = true;
break;
// cases where second and thrid arguments are parameters
case ErfOp:
case ErfcOp:
case StppOp:
CPPAD_ASSERT_UNKNOWN( 3 <= NumArg(op) )
par_usage[arg[1]] = true;
par_usage[arg[2]] = true;
break;
// cases where only third argument is a parameter
case StvpOp:
CPPAD_ASSERT_UNKNOWN( 3 <= NumArg(op) )
par_usage[arg[2]] = true;
break;
// conditional expression operator
case CExpOp:
CPPAD_ASSERT_UNKNOWN( 6 == NumArg(op) )
if( (arg[1] & 1) == 0 )
par_usage[arg[2]] = true;
if( (arg[1] & 2) == 0 )
par_usage[arg[3]] = true;
if( (arg[1] & 4) == 0 )
par_usage[arg[4]] = true;
if( (arg[1] & 8) == 0 )
par_usage[arg[5]] = true;
break;
// print function
case PriOp:
if( (arg[0] & 1) == 0 )
par_usage[arg[1]] = true;
if( (arg[0] & 2) == 0 )
par_usage[arg[3]] = true;
CPPAD_ASSERT_UNKNOWN( 5 == NumArg(op) )
break;
// --------------------------------------------------------------
// atomic function calls
case AFunOp:
if( atom_state == start_atom )
{ atom_index = size_t(arg[0]);
atom_old = size_t(arg[1]);
atom_n = size_t(arg[2]);
atom_m = size_t(arg[3]);
atom_j = 0;
atom_i = 0;
atom_state = arg_atom;
// -------------------------------------------------------
parameter_x.resize( atom_n );
type_x.resize( atom_n );
atom_ix.resize( atom_n );
//
depend_y.resize( atom_m );
depend_x.resize( atom_n );
}
else
{ CPPAD_ASSERT_UNKNOWN( atom_state == end_atom );
CPPAD_ASSERT_UNKNOWN( atom_n == size_t(arg[2]) );
CPPAD_ASSERT_UNKNOWN( atom_m == size_t(arg[3]) );
CPPAD_ASSERT_UNKNOWN( atom_j == atom_n );
CPPAD_ASSERT_UNKNOWN( atom_i == atom_m );
atom_state = start_atom;
//
// call atomic function for this operation
sweep::call_atomic_rev_depend<Base, Base>(
atom_index, atom_old, parameter_x, type_x, depend_x, depend_y
);
for(size_t j = 0; j < atom_n; j++)
if( depend_x[j] && type_x[j] != variable_enum )
{ // This user argument is a parameter that is needed
CPPAD_ASSERT_UNKNOWN( atom_ix[j] > 0 );
par_usage[ atom_ix[j] ] = true;
}
}
break;
case FunavOp:
// this argument is a variable
CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom );
atom_ix[atom_j] = 0;
parameter_x[atom_j] = all_par_vec[0]; // variables get value nan
type_x[atom_j] = variable_enum;
++atom_j;
if( atom_j == atom_n )
atom_state = ret_atom;
break;
case FunapOp:
// this argument is a parameter
CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom );
atom_ix[atom_j] = size_t( arg[0] );
parameter_x[atom_j] = all_par_vec[arg[0]]; // parameter value
if( dyn_par_is[arg[0]] )
type_x[atom_j] = dynamic_enum;
else
type_x[atom_j] = dynamic_enum;
++atom_j;
if( atom_j == atom_n )
atom_state = ret_atom;
break;
case FunrpOp:
// this result is a parameter
CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom );
depend_y[atom_i] = op_usage[i_op] != usage_t(no_usage);
++atom_i;
if( atom_i == atom_m )
atom_state = end_atom;
break;
case FunrvOp:
// this result is a variable
CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom );
depend_y[atom_i] = op_usage[i_op] != usage_t(no_usage);
++atom_i;
if( atom_i == atom_m )
atom_state = end_atom;
break;
// --------------------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(false);
}
}
// -----------------------------------------------------------------------
// reverse pass to determine which dynamic parameters are necessary
// -----------------------------------------------------------------------
size_t i_arg = dyn_par_arg.size(); // index in dyn_par_arg
size_t i_dyn = num_dynamic_par; // index in dyn_ind2par_ind
while(i_dyn)
{ // next dynamic parameter in reverse order
--i_dyn;
op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] );
while( op == result_dyn )
{ --i_dyn;
op = op_code_dyn( dyn_par_op[i_dyn] );
CPPAD_ASSERT_UNKNOWN( op == result_dyn || op == atom_dyn );
}
if( op == atom_dyn )
{ // number of arguments for this operator
size_t n_arg = size_t( dyn_par_arg[i_arg - 1] );
//
// index of first argument for this operation
i_arg -= n_arg;
//
atom_index = size_t( dyn_par_arg[i_arg + 0] );
size_t n = size_t( dyn_par_arg[i_arg + 1] );
size_t m = size_t( dyn_par_arg[i_arg + 2] );
CPPAD_ASSERT_UNKNOWN( n_arg == 5 + n + m );
//
// parameter_x, type_x
parameter_x.resize(n);
type_x.resize(n);
for(size_t j = 0; j < n; ++j)
{ // parameter index zero is used for variable
CPPAD_ASSERT_UNKNOWN( isnan( all_par_vec[0] ) );
addr_t arg_j = dyn_par_arg[i_arg + 4 + j];
parameter_x[j] = all_par_vec[arg_j];
if( arg_j == 0 )
type_x[j] = variable_enum;
else if( dyn_par_is[arg_j] )
type_x[j] = dynamic_enum;
else
type_x[j] = constant_enum;
}
//
// depend_y
depend_y.resize(m);
for(size_t i = 0; i < m; ++i)
{ // a constant prameter cannot depend on a dynamic parameter
// so do not worry about constant parameters in depend_y
size_t i_par = size_t( dyn_par_arg[i_arg + 4 + n + i] );
depend_y[i] = par_usage[i_par];
}
//
// call back to atomic function for this operation
depend_x.resize(n);
atom_old = 0; // not used with dynamic parameters
sweep::call_atomic_rev_depend<Base, Base>(
atom_index, atom_old, parameter_x, type_x, depend_x, depend_y
);
//
// transfer depend_x to par_usage
for(size_t j = 0; j < n; ++j)
{ size_t i_par = size_t( dyn_par_arg[i_arg + 4 + j] );
par_usage[i_par] = par_usage[i_par] | depend_x[j];
}
}
else
{ // corresponding parameter index
size_t i_par = size_t( dyn_ind2par_ind[i_dyn] );
CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] );
//
// number of argumens to this operator
size_t n_arg = num_arg_dyn(op);
//
// index of first argument for this operator
CPPAD_ASSERT_UNKNOWN( op != atom_dyn );
i_arg -= n_arg;
//
// if this dynamic parameter is needed
if( par_usage[i_par] )
{ // need dynamic parameters that are used to generate this one
size_t offset = num_non_par_arg_dyn(op);
for(size_t i = offset; i < n_arg; ++i)
par_usage[ dyn_par_arg[i_arg + i] ] = true;
}
}
}
CPPAD_ASSERT_UNKNOWN( i_arg == 0 );
//
return;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,57 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP
# define CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file local/optimize/hash_code.hpp
CppAD hashing utility.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Specialized hash code for a CppAD operator and its arguments
(used during optimization).
\param op
is the operator that we are computing a hash code for.
\param num_arg
number of elements of arg to include in the hash code.
\param arg
is a vector of length num_arg
containing the corresponding argument indices for this operator.
\return
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
*/
inline size_t optimize_hash_code(
opcode_t op ,
size_t num_arg ,
const addr_t* arg )
{ CPPAD_ASSERT_UNKNOWN( num_arg < 4 );
size_t prime = 1;
size_t sum = prime * size_t(op);
for(size_t i = 0; i < num_arg; i++)
{ prime = prime + 2; // 3, 5, 7 in that order
sum += prime * size_t(arg[i]);
}
//
return sum % CPPAD_HASH_TABLE_SIZE;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,292 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP
# define CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/optimize/hash_code.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*
$begin optimize_match_op$$
$section Search for a Previous Operator that Matches Current Operator$$
$spell
op
itr
bool
addr
erf
erfc
iterator
$$
$head Syntax$$
$codei%exceed_collision_limit% = match_op(
%collision_limit%,
%random_itr%,
%op_previous%,
%current%,
%hash_tape_op%,
%work_bool%,
%work_addr_t%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
%$$
$head Operator Arguments$$
If an argument for the current operator is a variable,
and the argument has previous match,
the previous match for the argument is used when checking for a match
for the current operator.
$head collision_limit$$
is the maximum number of collisions (matches) allowed for one
expression hash code value.
$head random_itr$$
is a random iterator for the old operation sequence.
$head op_previous$$
Mapping from operator index to previous operator that can replace this one.
The input value of
$codei%
%previous% = %op_previous%[%current%]
%$$
is assumed to be zero. If a match if found, the output value of
$icode previous$$ is set to the matching operator index,
otherwise it is left as is. Note that $icode%previous% < %current%$$
and $icode%op_previous[%previous%]%$$ is zero.
$head current$$
is the index of the current operator which cannot be any of the
operators in the list below:
$srcthisfile%
0%// BEGIN_INVALID_OP%// END_INVALID_OP%1
%$$
After this initialization, the value of $icode current$$
increases with each call to match_op.
$subhead erf$$
The operators $code ErfOp$$ and $code ErfcOp$$ have
three arguments, but only one true argument (the others are always the same).
$head hash_table_op$$
is assumed to be initialized as a vector of empty sets before the
first call to match_op (for a pass of the operation sequence).
$codei%
%hash_table_op%.n_set() == CPPAD_HASH_TABLE_SIZE
%hash_table_op%.end() == %op_previous%.size()
%$$
If $icode i_op$$ is an element of the j-th set,
then the operation $icode%op_previous%[%i_op%]%$$ has hash code j,
and does not match any other element of the j-th set.
An entry to j-th set for the current operator is added each time
match_op is called and a match for the current operator is not found.
$head work_bool$$
work space that is used by match_op between calls to increase speed.
Should be empty on first call for this forward pass of the operation
sequence and not modified until forward pass is done
$head work_addr_t$$
work space that is used by match_op between calls to increase speed.
Should be empty on first call for this forward pass of the operation
sequence and not modified until forward pass is done
$head exceed_collision_limit$$
If the $icode collision_limit$$ is exceeded (is not exceeded),
the return value is true (false).
$end
*/
// BEGIN_PROTOTYPE
template <class Addr>
bool match_op(
size_t collision_limit ,
const play::const_random_iterator<Addr>& random_itr ,
pod_vector<addr_t>& op_previous ,
size_t current ,
sparse::list_setvec& hash_table_op ,
pod_vector<bool>& work_bool ,
pod_vector<addr_t>& work_addr_t )
// END_PROTOTYPE
{
# ifndef NDEBUG
switch( random_itr.get_op(current) )
{
// BEGIN_INVALID_OP
case BeginOp:
case CExpOp:
case CSkipOp:
case CSumOp:
case EndOp:
case InvOp:
case LdpOp:
case LdvOp:
case ParOp:
case PriOp:
case StppOp:
case StpvOp:
case StvpOp:
case StvvOp:
case AFunOp:
case FunapOp:
case FunavOp:
case FunrpOp:
case FunrvOp:
// END_INVALID_OP
CPPAD_ASSERT_UNKNOWN(false);
break;
default:
break;
}
# endif
// initialize return value
bool exceed_collision_limit = false;
// num_op
size_t num_op = random_itr.num_op();
//
// num_var
size_t num_var = random_itr.num_var();
//
// variable is a reference to, and better name for, work_bool
pod_vector<bool>& variable(work_bool);
//
// var2previous_var is a reference to, and better name for, work_addr_t
pod_vector<addr_t>& var2previous_var(work_addr_t);
if( var2previous_var.size() == 0 )
{ var2previous_var.resize(num_var);
for(size_t i = 0; i < num_var; ++i)
var2previous_var[i] = addr_t(i);
}
//
CPPAD_ASSERT_UNKNOWN( var2previous_var.size() == num_var );
CPPAD_ASSERT_UNKNOWN( num_op == op_previous.size() );
CPPAD_ASSERT_UNKNOWN( op_previous[current] == 0 );
CPPAD_ASSERT_UNKNOWN(
hash_table_op.n_set() == CPPAD_HASH_TABLE_SIZE
);
CPPAD_ASSERT_UNKNOWN( hash_table_op.end() == num_op );
CPPAD_ASSERT_UNKNOWN( current < num_op );
//
// op, arg, i_var
OpCode op;
const addr_t* arg;
size_t i_var;
random_itr.op_info(current, op, arg, i_var);
//
// num_arg
size_t num_arg = NumArg(op);
CPPAD_ASSERT_UNKNOWN( 0 < num_arg );
CPPAD_ASSERT_UNKNOWN(
(num_arg < 3) | ( (num_arg == 3) & (op == ErfOp || op == ErfcOp) )
);
//
arg_is_variable(op, arg, variable);
CPPAD_ASSERT_UNKNOWN( variable.size() == num_arg );
//
// If j-th argument to this operator is a variable, and a previous
// variable will be used in its place, use the previous variable for
// hash coding and matching.
addr_t arg_match[] = {
// Invalid value that will not be used. This initialization avoid
// a wraning on some compilers
std::numeric_limits<addr_t>::max(),
std::numeric_limits<addr_t>::max(),
std::numeric_limits<addr_t>::max()
};
if( (op == AddvvOp) | (op == MulvvOp ) )
{ // in special case where operator is commutative and operands are variables,
// put lower index first so hash code does not depend on operator order
CPPAD_ASSERT_UNKNOWN( num_arg == 2 );
arg_match[0] = var2previous_var[ arg[0] ];
arg_match[1] = var2previous_var[ arg[1] ];
if( arg_match[1] < arg_match[0] )
std::swap( arg_match[0], arg_match[1] );
}
else for(size_t j = 0; j < num_arg; ++j)
{ arg_match[j] = arg[j];
if( variable[j] )
arg_match[j] = var2previous_var[ arg[j] ];
}
//
size_t code = optimize_hash_code(opcode_t(op), num_arg, arg_match);
//
// iterator for the set with this hash code
sparse::list_setvec_const_iterator itr(hash_table_op, code);
//
// check for a match
size_t count = 0;
while( *itr != num_op )
{ ++count;
//
// candidate previous for current operator
size_t candidate = *itr;
CPPAD_ASSERT_UNKNOWN( candidate < current );
CPPAD_ASSERT_UNKNOWN( op_previous[candidate] == 0 );
//
OpCode op_c;
const addr_t* arg_c;
size_t i_var_c;
random_itr.op_info(candidate, op_c, arg_c, i_var_c);
//
// check for a match
bool match = op == op_c;
size_t j = 0;
while( match & (j < num_arg) )
{ if( variable[j] )
match &= arg_match[j] == var2previous_var[ arg_c[j] ];
else
match &= arg_match[j] == arg_c[j];
++j;
}
if( (! match) & ( (op == AddvvOp) | (op == MulvvOp) ) )
{ // communative so check for reverse order match
match = op == op_c;
match &= arg_match[0] == var2previous_var[ arg_c[1] ];
match &= arg_match[1] == var2previous_var[ arg_c[0] ];
}
if( match )
{ op_previous[current] = static_cast<addr_t>( candidate );
if( NumRes(op) > 0 )
{ CPPAD_ASSERT_UNKNOWN( i_var_c < i_var );
var2previous_var[i_var] = addr_t( i_var_c );
}
return exceed_collision_limit;
}
++itr;
}
// see print (that is commented out) at bottom of get_op_previous.hpp
CPPAD_ASSERT_UNKNOWN( count <= collision_limit );
if( count == collision_limit )
{ // restart the list
hash_table_op.clear(code);
// limit has been exceeded
exceed_collision_limit = true;
}
// No match was found. Add this operator to the set for this hash code
// Not using post_element becasue we need to iterate for
// this code before adding another element for this code.
hash_table_op.add_element(code, current);
//
return exceed_collision_limit;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,386 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
$begin optimize_record_csum$$
$spell
iutr
iterator
op
var
itr
NumRes
csum
Addpv
Addvv
Subpv
Subvp
Subvv
$$
$section Recording a Cumulative Summation Operator$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_RECORD_CSUM%// END_PROROTYPE%1
%$$
$head play$$
player object corresponding to the old recording.
$head random_itr$$
is a random iterator corresponding to the old operation sequence.
$head op_usage$$
mapping from old operator index to how it is used.
$head new_par$$
mapping from old parameter index to parameter index in new recording.
$head new_var$$
mapping from old operator index to variable index in new recording.
$head current$$
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
We use the notation $icode%i_op% = %random_itr%.var2op(%current%)%$$.
It follows that NumRes( random_itr.get_op[i_op] ) > 0.
If 0 < j_op < i_op, either op_usage[j_op] == usage_t(csum_usage),
op_usage[j_op] = usage_t(no_usage), or new_var[j_op] != 0.
$head rec$$
is the object that will record the new operations.
$head return$$
is the operator and variable indices in the new operation sequence.
$head stack$$
Is temporary work space. On input and output,
stack.op_info, stack.add_var, and stack.sub_var, are all empty.
These stacks are passed in so that they are created once
and then be reused with calls to $code record_csum$$.
$head Assumptions$$
$list number$$
random_itr.get_op[i_op] must be one of the following:
CSumOp, AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp.
$lnext
op_usage[i_op] == usage_t(yes_usage).
$lnext
Either this is a CSumOp, or
op_usage[j_op] == usage_t(csum_usage) is true from some
j_op that corresponds to a variable that is an argument to
random_itr.get_op[i_op].
$lend
$end
*/
// BEGIN_RECORD_CSUM
template <class Addr, class Base>
struct_size_pair record_csum(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<usage_t>& op_usage ,
const pod_vector<addr_t>& new_par ,
const pod_vector<addr_t>& new_var ,
size_t current ,
recorder<Base>* rec ,
// local information passed so stacks need not be allocated for every call
struct_csum_stacks& stack )
// END_PROROTYPE
{
# ifndef NDEBUG
// number of parameters corresponding to the old operation sequence.
size_t npar = play->num_par_rec();
# endif
// vector of length npar containing the parameters the old operation
// sequence; i.e., given a parameter index i < npar, the corresponding
// parameter value is par[i].
const Base* par = play->GetPar();
// which parameters are dynamic
const pod_vector<bool>& dyn_par_is( play->dyn_par_is() );
// check assumption about work space
CPPAD_ASSERT_UNKNOWN( stack.op_info.empty() );
CPPAD_ASSERT_UNKNOWN( stack.add_var.empty() );
CPPAD_ASSERT_UNKNOWN( stack.sub_var.empty() );
//
// this operator is not csum connected to some other result
size_t i_op = random_itr.var2op(current);
CPPAD_ASSERT_UNKNOWN( ! ( op_usage[i_op] == usage_t(csum_usage) ) );
//
// information corresponding to the root node in the cummulative summation
struct struct_csum_op_info info;
size_t not_used;
random_itr.op_info(i_op, info.op, info.arg, not_used);
info.add = true; // was parrent operator positive or negative
//
// initialize stack as containing this one operator
stack.op_info.push( info );
//
// initialize sum of parameter values as zero
Base sum_par(0);
//
# ifndef NDEBUG
// one argument of this operator must have been csum connected to it
bool ok = info.op == CSumOp;
if( (! ok) & (info.op != SubpvOp) & (info.op != AddpvOp) )
{ // first argument is a varialbe being added
i_op = random_itr.var2op(size_t(info.arg[0]));
ok |= op_usage[i_op] == usage_t(csum_usage);
}
if( (! ok) & (info.op != SubvpOp) )
{ // second argument is a varialbe being added or subtracted
i_op = random_itr.var2op(size_t(info.arg[1]));
ok |= op_usage[i_op] == usage_t(csum_usage);
}
CPPAD_ASSERT_UNKNOWN( ok );
# endif
//
// while there are operators left on the stack
while( ! stack.op_info.empty() )
{ // get this summation operator
info = stack.op_info.top();
stack.op_info.pop();
OpCode op = info.op;
const addr_t* arg = info.arg;
bool add = info.add;
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 );
//
if( op == CSumOp )
{ // ---------------------------------------------------------------
// Begin op == CSumOp
//
// arg[0] is constant parameter that initializes the sum
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[ arg[0] ] );
if( add )
sum_par += par[arg[0]];
else
sum_par -= par[arg[0]];
//
// stack entries for addition variable
size_t var_start = 5; // start addition variables
size_t var_end = size_t( arg[1] ); // end addition variables
bool add_var = add; // addition variables
for(size_t j = 0; j < 2; ++j)
{ for(size_t i = var_start; i < var_end; ++i)
{ //
// check if the i-th argument has csum usage
i_op = random_itr.var2op(size_t(arg[i]));
if( op_usage[i_op] == usage_t(csum_usage) )
{ // there is no result corresponding to i-th argument
CPPAD_ASSERT_UNKNOWN( size_t( new_var[i_op]) == 0 );
// push operator corresponding to the i-th argument
random_itr.op_info(i_op, info.op, info.arg, not_used);
info.add = add;
stack.op_info.push( info );
}
else
{ // there are no nodes below this one
CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < current );
if( add_var )
stack.add_var.push(arg[i]);
else
stack.sub_var.push(arg[i]);
}
}
var_start = var_end; // start subtraction variables
var_end = size_t( arg[2] ); // end subtraction variables
add_var = ! add; // subtraction variables
}
//
// stack entries for addition dynamic parameters
size_t dyn_start = var_end; // start addition dynamics
size_t dyn_end = size_t( arg[3] ); // end addition dynamics
bool dny_add = add; // addition dynamics
for(size_t j = 0; j < 2; ++j)
{ for(size_t i = dyn_start; i < dyn_end; ++i)
{ // i-th argument is a dynamic parameter
// (can't yet be a result, so no nodes below)
CPPAD_ASSERT_UNKNOWN( dyn_par_is[ arg[i] ] );
if( dny_add )
stack.add_dyn.push(arg[i]);
else
stack.sub_dyn.push(arg[i]);
}
dyn_start = dyn_end; // start subtraction dynamics
dyn_end = size_t( arg[4] ); // end subtraction dynamics
dny_add = ! add; // subtraction dynamics
}
// End op == CSumOp
// ---------------------------------------------------------------
}
else
{ // ---------------------------------------------------------------
// Begin op != CSumOp
//
// is this a subtraction operator
bool subtract = (op==SubpvOp) | (op==SubvpOp) | (op==SubvvOp);
//
// is the i-th arguemnt a parameter
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
bool par_arg[2];
switch(op)
{ case SubpvOp:
case AddpvOp:
par_arg[0] = true;
par_arg[1] = false;
break;
//
case SubvpOp:
par_arg[0] = false;
par_arg[1] = true;
break;
//
default:
par_arg[0] = false;
par_arg[1] = false;
break;
}
//
// loop over the arguments to this operator
for(size_t i = 0; i < 2; ++i)
{ if( subtract & (i == 1) )
add = ! add;
if( par_arg[i] )
{ // case where i-th argument is a parameter
CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < npar );
//
if( dyn_par_is[ arg[i] ] )
{ // i-th argument is a dynamic parameter
// (can't yet be a result, so no nodes below)
if( add )
stack.add_dyn.push(arg[i]);
else
stack.sub_dyn.push(arg[i]);
}
else
{ // i-th argument is constant parameter
if( add )
sum_par += par[arg[i]];
else
sum_par -= par[arg[i]];
}
}
else
{ // case where i-th argument is a variable
//
// check if the i-th argument has csum usage
i_op = random_itr.var2op(size_t(arg[i]));
if( op_usage[i_op] == usage_t(csum_usage) )
{ // there is no result corresponding to i-th argument
CPPAD_ASSERT_UNKNOWN( size_t( new_var[i_op]) == 0 );
// push operator corresponding to the i-th argument
random_itr.op_info(i_op, info.op, info.arg, not_used);
info.add = add;
stack.op_info.push( info );
}
else
{ // there are no nodes below this one
CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < current );
if( add )
stack.add_var.push(arg[i]);
else
stack.sub_var.push(arg[i]);
}
}
}
// End op != CSumOp
// ---------------------------------------------------------------
}
}
// number of variables to add in this cummulative sum operator
size_t n_add_var = stack.add_var.size();
// number of variables to subtract in this cummulative sum operator
size_t n_sub_var = stack.sub_var.size();
// number of dynamics to add in this cummulative sum operator
size_t n_add_dyn = stack.add_dyn.size();
// number of dynamics to subtract in this cummulative sum operator
size_t n_sub_dyn = stack.sub_dyn.size();
// first five arguments to cumulative sum operator
addr_t new_arg = rec->put_con_par(sum_par);
rec->PutArg(new_arg); // arg[0]: initial sum
size_t end = n_add_var + 5;
rec->PutArg( addr_t(end) ); // arg[1]: end for add variables
end += n_sub_var;
rec->PutArg( addr_t(end) ); // arg[2]: end for sub variables
end += n_add_dyn;
rec->PutArg( addr_t(end) ); // arg[3]: end for add dynamics
end += n_sub_dyn;
rec->PutArg( addr_t(end) ); // arg[4]: end for sub dynamics
// addition variable arguments
for(size_t i = 0; i < n_add_var; i++)
{ CPPAD_ASSERT_UNKNOWN( ! stack.add_var.empty() );
addr_t old_arg = stack.add_var.top();
new_arg = new_var[ random_itr.var2op(size_t(old_arg)) ];
CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
rec->PutArg(new_arg); // arg[5+i]
stack.add_var.pop();
}
// subtraction variable arguments
for(size_t i = 0; i < n_sub_var; i++)
{ CPPAD_ASSERT_UNKNOWN( ! stack.sub_var.empty() );
addr_t old_arg = stack.sub_var.top();
new_arg = new_var[ random_itr.var2op(size_t(old_arg)) ];
CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
rec->PutArg(new_arg); // arg[arg[1] + i]
stack.sub_var.pop();
}
// addition dynamic arguments
for(size_t i = 0; i < n_add_dyn; ++i)
{ addr_t old_arg = stack.add_dyn.top();
new_arg = new_par[ old_arg ];
rec->PutArg(new_arg); // arg[arg[2] + i]
stack.add_dyn.pop();
}
// subtraction dynamic arguments
for(size_t i = 0; i < n_sub_dyn; ++i)
{ addr_t old_arg = stack.sub_dyn.top();
new_arg = new_par[ old_arg ];
rec->PutArg(new_arg); // arg[arg[3] + i]
stack.sub_dyn.pop();
}
// number of additions plus number of subtractions
rec->PutArg( addr_t(end) ); // arg[arg[4]] = arg[4]
//
// return value
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = size_t(rec->PutOp(CSumOp));
//
return ret;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,102 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file record_pv.hpp
Record an operation of the form (parameter op variable).
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Record an operation of the form (parameter op variable).
\param play
player object corresponding to the old recroding.
\param random_itr
random iterator corresponding to old recording.
\param new_par
mapping from old parameter index to parameter index in new recording.
\param new_var
mapping from old operator index to variable index in new recording.
\param i_op
is the index in the old operation sequence for this operator.
The operator must be one of the following:
AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp.
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
*/
template <class Addr, class Base>
struct_size_pair record_pv(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<addr_t>& new_par ,
const pod_vector<addr_t>& new_var ,
size_t i_op ,
recorder<Base>* rec )
{
// get_op_info
OpCode op;
const addr_t* arg;
size_t i_var;
random_itr.op_info(i_op, op, arg, i_var);
//
# ifndef NDEBUG
switch(op)
{ case AddpvOp:
case DivpvOp:
case MulpvOp:
case PowpvOp:
case SubpvOp:
case ZmulpvOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
// number of parameters corresponding to the old operation sequence.
size_t npar = play->num_par_rec();
# endif
//
// vector of length npar containing the parameters the old operation
// sequence; i.e., given a parameter index i < npar, the corresponding
// parameter value is par[i].
//
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_var ); // DAG condition
//
addr_t new_arg[2];
new_arg[0] = new_par[ arg[0] ];
new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ];
rec->PutArg( new_arg[0], new_arg[1] );
//
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = size_t(rec->PutOp(op));
CPPAD_ASSERT_UNKNOWN( 0 < new_arg[1] && size_t(new_arg[1]) < ret.i_var );
return ret;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,101 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file record_vp.hpp
Record an operation of the form (variable op parameter).
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Record an operation of the form (variable op parameter).
\param play
player object corresponding to the old recroding.
\param random_itr
is a random iterator corresponding to the old recording.
\param new_par
mapping from old parameter index to parameter index in new recording.
\param new_var
mapping from old operator index to variable index in new recording.
\param i_op
is the index in the old operation sequence for this operator.
the must be one of the following:
DivvpOp, PowvpOp, SubvpOp, ZmulvpOp.
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
*/
template <class Addr, class Base>
struct_size_pair record_vp(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<addr_t>& new_par ,
const pod_vector<addr_t>& new_var ,
size_t i_op ,
recorder<Base>* rec )
{
// get_op_info
OpCode op;
const addr_t* arg;
size_t i_var;
random_itr.op_info(i_op, op, arg, i_var);
//
# ifndef NDEBUG
switch(op)
{ case DivvpOp:
case PowvpOp:
case SubvpOp:
case ZmulvpOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
// number of parameters corresponding to the old operation sequence.
size_t npar = play->num_par_rec();
# endif
// vector of length npar containing the parameters the old operation
// sequence; i.e., given a parameter index i < npar, the corresponding
// parameter value is par[i].
//
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_var ); // DAG condition
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
//
addr_t new_arg[2];
new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ];
new_arg[1] = new_par[ arg[1] ];
rec->PutArg( new_arg[0], new_arg[1] );
//
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = size_t(rec->PutOp(op));
CPPAD_ASSERT_UNKNOWN( 0 < new_arg[0] && size_t(new_arg[0]) < ret.i_var );
return ret;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,91 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file record_vv.hpp
Record an operation of the form (variable op variable).
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Record an operation of the form (variable op variable).
\param play
player object corresponding to the old recroding.
\param random_itr
random iterator corresponding to the old recording.
\param new_var
mapping from old operator index to variable index in new recording.
\param i_op
is the index in the old operation sequence for this operator.
the must be one of the following:
AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp.
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
*/
template <class Addr, class Base>
struct_size_pair record_vv(
const player<Base>* play ,
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<addr_t>& new_var ,
size_t i_op ,
recorder<Base>* rec )
{
// get_op_info
OpCode op;
const addr_t* arg;
size_t i_var;
random_itr.op_info(i_op, op, arg, i_var);
//
# ifndef NDEBUG
switch(op)
{ case AddvvOp:
case DivvvOp:
case MulvvOp:
case PowvvOp:
case SubvvOp:
case ZmulvvOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
# endif
CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_var ); // DAG condition
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_var ); // DAG condition
//
addr_t new_arg[2];
new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ];
new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ];
rec->PutArg( new_arg[0], new_arg[1] );
//
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = size_t(rec->PutOp(op));
CPPAD_ASSERT_UNKNOWN( 0 < new_arg[0] && size_t(new_arg[0]) < ret.i_var );
CPPAD_ASSERT_UNKNOWN( 0 < new_arg[1] && size_t(new_arg[1]) < ret.i_var );
return ret;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,32 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_SIZE_PAIR_HPP
# define CPPAD_LOCAL_OPTIMIZE_SIZE_PAIR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
/*!
\file size_pair.hpp
Information for one variable and one operation sequence.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
\file size_pair.hpp
Information for one variable in one operation sequence.
*/
struct struct_size_pair {
size_t i_op; /// operator index for this variable
size_t i_var; /// variable index for this variable
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,39 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_USAGE_HPP
# define CPPAD_LOCAL_OPTIMIZE_USAGE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/define.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
typedef CPPAD_VEC_ENUM_TYPE usage_t;
enum enum_usage {
/// This operator is not used.
no_usage,
/// This operator is used one or more times.
yes_usage,
/*!
This operator is only used once, it is a summation operator,
and its parrent is a summation operator. Furthermore, its result is not
a dependent variable. Hence case it can be removed as part of a
cumulative summation starting at its parent or above.
*/
csum_usage
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif

View File

@@ -0,0 +1,89 @@
# ifndef CPPAD_LOCAL_PARAMETER_OP_HPP
# define CPPAD_LOCAL_PARAMETER_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file parameter_op.hpp
Zero order forward mode for ParOp
*/
/*!
Compute zero order forward mode Taylor coefficient for result of op = ParOp.
The C++ source code corresponding to this operation is one of the following
\verbatim
ADFun<Base> f(x, y)
f.Dependent(x, y)
\endverbatim
where some of the components of the vector y are parameters.
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base .
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in taylor corresponding to the component of y
that is a parameter.
\param arg
arg[0]
\n
index corresponding to the parameter value for this operator.
\param num_par
is the number of parameters in parameter.
\param parameter
\b Input: parameter[ arg[0] ] is the value of a component
of y that is a parameter.
\param cap_order
number of colums in the matrix containing all the Taylor coefficients.
\param taylor
\b Output: taylor [ i_z * cap_order + 0 ]
is the zero order Taylor coefficient corresponding to z.
\par Checked Assertions where op is the unary operator with one result:
\li NumArg(op) == 1
\li NumRes(op) == 1
\li size_t(arg[0]) < num_par
\li 0 < cap_order
*/
template <class Base>
void forward_par_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(ParOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
Base* z = taylor + i_z * cap_order;
z[0] = parameter[ arg[0] ];
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,30 @@
# ifndef CPPAD_LOCAL_PLAY_ADDR_ENUM_HPP
# define CPPAD_LOCAL_PLAY_ADDR_ENUM_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file addr_enum.hpp
*/
/// enum corresponding to type used for addressing iterators for a player
enum addr_enum {
unsigned_short_enum ,
unsigned_int_enum ,
size_t_enum
};
} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,89 @@
# ifndef CPPAD_LOCAL_PLAY_ATOM_OP_INFO_HPP
# define CPPAD_LOCAL_PLAY_ATOM_OP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file atom_op_info.hpp
*/
/*!
\brief
Unpack extra information corresponding to a AFunOp
\param op [in]
must be a AFunOp
\param op_arg [in]
is the arguments for this operator
\param atom_old [out]
is the extra information passed to the old style atomic functions.
\param atom_index [out]
is the index in local::atomic_index corresponding to this atomic functions.
\param atom_m [out]
is the number of results for this user atmoic function.
\param atom_n [out]
is the number of arguments for this user atmoic function.
\return
Is a pointer to this atomic function.
*/
// MUSTDO: change return to void once all sweeps switch to use call_atomic.
template <class Base>
atomic_base<Base>* atom_op_info(
const OpCode op ,
const addr_t* op_arg ,
size_t& atom_index ,
size_t& atom_old ,
size_t& atom_m ,
size_t& atom_n )
{ atomic_base<Base>* atom_fun;
//
CPPAD_ASSERT_UNKNOWN( op == AFunOp );
CPPAD_ASSERT_NARG_NRES(op, 4, 0);
//
atom_index = size_t(op_arg[0]);
atom_old = size_t(op_arg[1]);
atom_n = size_t(op_arg[2]);
atom_m = size_t(op_arg[3]);
CPPAD_ASSERT_UNKNOWN( atom_n > 0 );
//
bool set_null = false;
size_t type = 0; // set to avoid warning
std::string* name_ptr = nullptr;
void* v_ptr = nullptr; // set to avoid warning
local::atomic_index<Base>(set_null, atom_index, type, name_ptr, v_ptr);
if( type == 3 )
return nullptr;
# ifndef NDEBUG
if( v_ptr == nullptr )
{ // atom_fun is null so cannot use atom_fun->atomic_name()
std::string msg = atomic_base<Base>::class_name(atom_index)
+ ": atomic_base function has been deleted";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
// the atomic_base object corresponding to this atomic function
atom_fun = reinterpret_cast< atomic_base<Base>* >( v_ptr );
return atom_fun;
}
} } } // END_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,853 @@
# ifndef CPPAD_LOCAL_PLAY_PLAYER_HPP
# define CPPAD_LOCAL_PLAY_PLAYER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/play/addr_enum.hpp>
# include <cppad/local/play/sequential_iterator.hpp>
# include <cppad/local/play/subgraph_iterator.hpp>
# include <cppad/local/play/random_setup.hpp>
# include <cppad/local/atom_state.hpp>
# include <cppad/local/is_pod.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file player.hpp
File used to define the player class.
*/
/*!
Class used to store and play back an operation sequence recording.
\tparam Base
These were AD< Base > operations when recorded. Operations during playback
are done using the type Base .
*/
template <class Base>
class player {
// player<Base> must be a friend of player< AD<Base> > for base2ad to work
template <class AnotherBase> friend class player;
private:
// ----------------------------------------------------------------------
// information that defines the recording
/// Number of independent dynamic parameters
size_t num_dynamic_ind_;
/// Number of variables in the recording.
size_t num_var_rec_;
/// number of vecad load opeations in the reconding
size_t num_var_load_rec_;
/// Number of VecAD vectors in the recording
size_t num_var_vecad_rec_;
/// The operators in the recording.
pod_vector<opcode_t> op_vec_;
/// The operation argument indices in the recording
pod_vector<addr_t> arg_vec_;
/// Character strings ('\\0' terminated) in the recording.
pod_vector<char> text_vec_;
/// The VecAD indices in the recording.
pod_vector<addr_t> all_var_vecad_ind_;
/// All of the parameters in the recording.
/// Use pod_maybe because Base may not be plain old data.
pod_vector_maybe<Base> all_par_vec_;
/// Which elements of all_par_vec_ are dynamic parameters
/// (size equal number of parametrers)
pod_vector<bool> dyn_par_is_;
/// mapping from dynamic parameter index to parameter index
/// 1: size equal to number of dynamic parameters
/// 2: dyn_ind2par_ind_[j] < dyn_ind2par_ind_[j+1]
pod_vector<addr_t> dyn_ind2par_ind_;
/// operators for just the dynamic parameters
/// (size equal number of dynamic parameters)
pod_vector<opcode_t> dyn_par_op_;
/// arguments for the dynamic parameter operators
pod_vector<addr_t> dyn_par_arg_;
// ----------------------------------------------------------------------
// Information needed to use member functions that begin with random_
// and for using const_subgraph_iterator.
/// index in arg_vec_ corresonding to the first argument for each operator
pod_vector<unsigned char> op2arg_vec_;
/*!
Index of the result variable for each operator. If the operator has
no results, this is not defined. The invalid index num_var_rec_ is used
when NDEBUG is not defined. If the operator has more than one result, this
is the primary result; i.e., the last result. Auxillary are only used by
the operator and not used by other operators.
*/
pod_vector<unsigned char> op2var_vec_;
/// Mapping from primary variable index to corresponding operator index.
/// This is used to traverse sub-graphs of the operation sequence.
/// This value is valid (invalid) for primary (auxillary) variables.
pod_vector<unsigned char> var2op_vec_;
public:
// =================================================================
/// default constructor
// set all scalars to zero to avoid valgraind warning when ani assignment
// occures before values get set.
player(void) :
num_dynamic_ind_(0) ,
num_var_rec_(0) ,
num_var_load_rec_(0) ,
num_var_vecad_rec_(0)
{ }
// move semantics constructor
// (none of the default constructor values matter to the destructor)
player(player& play)
{ swap(play); }
// =================================================================
/// destructor
~player(void)
{ }
// ======================================================================
/// type used for addressing iterators for this player
play::addr_enum address_type(void) const
{
// required
size_t required = 0;
required = std::max(required, num_var_rec_ ); // number variables
required = std::max(required, op_vec_.size() ); // number operators
required = std::max(required, arg_vec_.size() ); // number arguments
//
// unsigned short
if( required <= std::numeric_limits<unsigned short>::max() )
return play::unsigned_short_enum;
//
// unsigned int
if( required <= std::numeric_limits<unsigned int>::max() )
return play::unsigned_int_enum;
//
// unsigned size_t
CPPAD_ASSERT_UNKNOWN(
required <= std::numeric_limits<size_t>::max()
);
return play::size_t_enum;
}
// ===============================================================
/*!
Moving an operation sequence from a recorder to this player
\param rec
the object that was used to record the operation sequence. After this
operation, the state of the recording is no longer defined. For example,
the pod_vector member variables in this have been swapped with rec.
\param n_ind
the number of independent variables (only used for error checking
when NDEBUG is not defined).
\par
Use an assert to check that the length of the following vectors is
less than the maximum possible value for addr_t; i.e., that an index
in these vectors can be represented using the type addr_t:
op_vec_, all_var_vecad_ind_, arg_vec_, test_vec_, all_par_vec_, text_vec_,
dyn_par_arg_.
*/
void get_recording(recorder<Base>& rec, size_t n_ind)
{
# ifndef NDEBUG
size_t addr_t_max = size_t( std::numeric_limits<addr_t>::max() );
# endif
// just set size_t values
num_dynamic_ind_ = rec.num_dynamic_ind_;
num_var_rec_ = rec.num_var_rec_;
num_var_load_rec_ = rec.num_var_load_rec_;
// op_vec_
op_vec_.swap(rec.op_vec_);
CPPAD_ASSERT_UNKNOWN(op_vec_.size() < addr_t_max );
// op_arg_vec_
arg_vec_.swap(rec.arg_vec_);
CPPAD_ASSERT_UNKNOWN(arg_vec_.size() < addr_t_max );
// all_par_vec_
all_par_vec_.swap(rec.all_par_vec_);
CPPAD_ASSERT_UNKNOWN(all_par_vec_.size() < addr_t_max );
// dyn_par_is_, dyn_par_op_, dyn_par_arg_
dyn_par_is_.swap( rec.dyn_par_is_ );
dyn_par_op_.swap( rec.dyn_par_op_ );
dyn_par_arg_.swap( rec.dyn_par_arg_ );
CPPAD_ASSERT_UNKNOWN(dyn_par_arg_.size() < addr_t_max );
// text_rec_
text_vec_.swap(rec.text_vec_);
CPPAD_ASSERT_UNKNOWN(text_vec_.size() < addr_t_max );
// all_var_vecad_ind_
all_var_vecad_ind_.swap(rec.all_var_vecad_ind_);
CPPAD_ASSERT_UNKNOWN(all_var_vecad_ind_.size() < addr_t_max );
// num_var_vecad_rec_
num_var_vecad_rec_ = 0;
{ // all_var_vecad_ind_ contains size of each VecAD followed by
// the parameter indices used to inialize it.
size_t i = 0;
while( i < all_var_vecad_ind_.size() )
{ num_var_vecad_rec_++;
i += size_t( all_var_vecad_ind_[i] ) + 1;
}
CPPAD_ASSERT_UNKNOWN( i == all_var_vecad_ind_.size() );
}
// mapping from dynamic parameter index to parameter index
dyn_ind2par_ind_.resize( dyn_par_op_.size() );
size_t i_dyn = 0;
for(size_t i_par = 0; i_par < all_par_vec_.size(); ++i_par)
{ if( dyn_par_is_[i_par] )
{ dyn_ind2par_ind_[i_dyn] = addr_t( i_par );
++i_dyn;
}
}
CPPAD_ASSERT_UNKNOWN( i_dyn == dyn_ind2par_ind_.size() );
// random access information
clear_random();
// some checks
check_inv_op(n_ind);
check_variable_dag();
check_dynamic_dag();
}
// ----------------------------------------------------------------------
/*!
Check that InvOp operators start with second operator and are contiguous,
and there are n_ind of them.
*/
# ifdef NDEBUG
void check_inv_op(size_t n_ind) const
{ return; }
# else
void check_inv_op(size_t n_ind) const
{ play::const_sequential_iterator itr = begin();
OpCode op;
const addr_t* op_arg;
size_t var_index;
itr.op_info(op, op_arg, var_index);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
size_t i_op = 0;
while( op != EndOp )
{ // start at second operator
(++itr).op_info(op, op_arg, var_index);
++i_op;
CPPAD_ASSERT_UNKNOWN( (op == InvOp) == (i_op <= n_ind) );
}
return;
}
# endif
// ----------------------------------------------------------------------
/*!
Check variable graph to make sure arguments have value less
than or equal to the previously created variable. This is the directed
acyclic graph condition (DAG).
*/
# ifdef NDEBUG
void check_variable_dag(void) const
{ return; }
# else
void check_variable_dag(void) const
{ play::const_sequential_iterator itr = begin();
OpCode op;
const addr_t* op_arg;
size_t var_index;
itr.op_info(op, op_arg, var_index);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
//
addr_t arg_var_bound = 0;
while( op != EndOp )
{ (++itr).op_info(op, op_arg, var_index);
switch(op)
{
// cases where nothing to do
case BeginOp:
case EndOp:
case EqppOp:
case InvOp:
case LdpOp:
case LeppOp:
case LtppOp:
case NeppOp:
case ParOp:
case AFunOp:
case FunapOp:
case FunrpOp:
case FunrvOp:
case StppOp:
break;
// only first argument is a variable
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case DivvpOp:
case ErfOp:
case ErfcOp:
case ExpOp:
case Expm1Op:
case LevpOp:
case LogOp:
case Log1pOp:
case LtvpOp:
case PowvpOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case SubvpOp:
case TanOp:
case TanhOp:
case FunavOp:
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound );
break;
// only second argument is a variable
case AddpvOp:
case DisOp:
case DivpvOp:
case EqpvOp:
case LdvOp:
case LepvOp:
case LtpvOp:
case MulpvOp:
case NepvOp:
case PowpvOp:
case StvpOp:
case SubpvOp:
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
break;
// only first and second arguments are variables
case AddvvOp:
case DivvvOp:
case EqvvOp:
case LevvOp:
case LtvvOp:
case MulvvOp:
case NevvOp:
case PowvvOp:
case SubvvOp:
case ZmulvvOp:
CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound );
CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
break;
// StpvOp
case StpvOp:
CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound );
break;
// StvvOp
case StvvOp:
CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound );
CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound );
break;
// CSumOp
case CSumOp:
{ CPPAD_ASSERT_UNKNOWN( 5 < op_arg[2] );
for(addr_t j = 5; j < op_arg[2]; j++)
CPPAD_ASSERT_UNKNOWN(op_arg[j] <= arg_var_bound);
}
itr.correct_before_increment();
break;
// CExpOp
case CExpOp:
if( op_arg[1] & 1 )
CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound);
if( op_arg[1] & 2 )
CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
if( op_arg[1] & 4 )
CPPAD_ASSERT_UNKNOWN( op_arg[4] <= arg_var_bound);
if( op_arg[1] & 8 )
CPPAD_ASSERT_UNKNOWN( op_arg[5] <= arg_var_bound);
break;
// PriOp
case PriOp:
if( op_arg[0] & 1 )
CPPAD_ASSERT_UNKNOWN( op_arg[1] <= arg_var_bound);
if( op_arg[0] & 2 )
CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
break;
// CSkipOp
case CSkipOp:
if( op_arg[1] & 1 )
CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound);
if( op_arg[1] & 2 )
CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound);
itr.correct_before_increment();
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
break;
}
if( NumRes(op) > 0 )
{ if( var_index > 0 )
{ CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) < var_index);
}
else
{ CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) == var_index);
}
//
arg_var_bound = addr_t(var_index);
}
}
return;
}
# endif
// ----------------------------------------------------------------------
/*!
Check dynamic parameter graph to make sure arguments have value less
than or equal to the previously created dynamic parameter.
This is the directed acyclic graph condition (DAG).
*/
# ifdef NDEBUG
void check_dynamic_dag(void) const
{ return; }
# else
void check_dynamic_dag(void) const
{ // number of dynamic parameters
size_t num_dyn = dyn_par_op_.size();
//
size_t i_arg = 0; // initialize dynamic parameter argument index
for(size_t i_dyn = 0; i_dyn < num_dyn; ++i_dyn)
{ // i_par is parameter index
addr_t i_par = dyn_ind2par_ind_[i_dyn];
CPPAD_ASSERT_UNKNOWN( dyn_par_is_[i_par] );
//
// operator for this dynamic parameter
op_code_dyn op = op_code_dyn( dyn_par_op_[i_dyn] );
//
// number of arguments for this dynamic parameter
size_t n_arg = num_arg_dyn(op);
if( op == atom_dyn )
{ size_t n = size_t( dyn_par_arg_[i_arg + 1] );
size_t m = size_t( dyn_par_arg_[i_arg + 2] );
n_arg = 5 + n + m;
CPPAD_ASSERT_UNKNOWN(
n_arg == size_t( dyn_par_arg_[i_arg + 4 + n + m] )
);
for(size_t i = 4; i < n - 1; ++i)
CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par );
# ifndef NDEBUG
for(size_t i = 4+n; i < 4+n+m; ++i)
{ addr_t j_par = dyn_par_arg_[i_arg + i];
CPPAD_ASSERT_UNKNOWN( (j_par == 0) || (j_par >= i_par) );
}
# endif
}
else
{ size_t num_non_par = num_non_par_arg_dyn(op);
for(size_t i = num_non_par; i < n_arg; ++i)
CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par);
}
//
// next dynamic parameter
i_arg += n_arg;
}
return;
}
# endif
// ===============================================================
/*!
Copy a player<Base> to another player<Base>
\param play
object that contains the operatoion sequence to copy.
*/
void operator=(const player& play)
{
// size_t objects
num_dynamic_ind_ = play.num_dynamic_ind_;
num_var_rec_ = play.num_var_rec_;
num_var_load_rec_ = play.num_var_load_rec_;
num_var_vecad_rec_ = play.num_var_vecad_rec_;
//
// pod_vectors
op_vec_ = play.op_vec_;
arg_vec_ = play.arg_vec_;
text_vec_ = play.text_vec_;
all_var_vecad_ind_ = play.all_var_vecad_ind_;
dyn_par_is_ = play.dyn_par_is_;
dyn_ind2par_ind_ = play.dyn_ind2par_ind_;
dyn_par_op_ = play.dyn_par_op_;
dyn_par_arg_ = play.dyn_par_arg_;
op2arg_vec_ = play.op2arg_vec_;
op2var_vec_ = play.op2var_vec_;
var2op_vec_ = play.var2op_vec_;
//
// pod_maybe_vectors
all_par_vec_ = play.all_par_vec_;
}
// ===============================================================
/// Create a player< AD<Base> > from this player<Base>
player< AD<Base> > base2ad(void) const
{ player< AD<Base> > play;
//
// size_t objects
play.num_dynamic_ind_ = num_dynamic_ind_;
play.num_var_rec_ = num_var_rec_;
play.num_var_load_rec_ = num_var_load_rec_;
play.num_var_vecad_rec_ = num_var_vecad_rec_;
//
// pod_vectors
play.op_vec_ = op_vec_;
play.arg_vec_ = arg_vec_;
play.text_vec_ = text_vec_;
play.all_var_vecad_ind_ = all_var_vecad_ind_;
play.dyn_par_is_ = dyn_par_is_;
play.dyn_ind2par_ind_ = dyn_ind2par_ind_;
play.dyn_par_op_ = dyn_par_op_;
play.dyn_par_arg_ = dyn_par_arg_;
play.op2arg_vec_ = op2arg_vec_;
play.op2var_vec_ = op2var_vec_;
play.var2op_vec_ = var2op_vec_;
//
// pod_maybe_vector< AD<Base> > = pod_maybe_vector<Base>
play.all_par_vec_.resize( all_par_vec_.size() );
for(size_t i = 0; i < all_par_vec_.size(); ++i)
play.all_par_vec_[i] = all_par_vec_[i];
//
return play;
}
// ===============================================================
/// swap this recording with another recording
/// (used for move semantics version of ADFun assignment operation)
void swap(player& other)
{ // size_t objects
std::swap(num_dynamic_ind_, other.num_dynamic_ind_);
std::swap(num_var_rec_, other.num_var_rec_);
std::swap(num_var_load_rec_, other.num_var_load_rec_);
std::swap(num_var_vecad_rec_, other.num_var_vecad_rec_);
//
// pod_vectors
op_vec_.swap( other.op_vec_);
arg_vec_.swap( other.arg_vec_);
text_vec_.swap( other.text_vec_);
all_var_vecad_ind_.swap( other.all_var_vecad_ind_);
dyn_par_is_.swap( other.dyn_par_is_);
dyn_ind2par_ind_.swap( other.dyn_ind2par_ind_);
dyn_par_op_.swap( other.dyn_par_op_);
dyn_par_arg_.swap( other.dyn_par_arg_);
op2arg_vec_.swap( other.op2arg_vec_);
op2var_vec_.swap( other.op2var_vec_);
var2op_vec_.swap( other.var2op_vec_);
//
// pod_maybe_vectors
all_par_vec_.swap( other.all_par_vec_);
}
// move semantics assignment
void operator=(player&& play)
{ swap(play); }
// =================================================================
/// Enable use of const_subgraph_iterator and member functions that begin
// with random_(no work if already setup).
template <class Addr>
void setup_random(void)
{ play::random_setup(
num_var_rec_ ,
op_vec_ ,
arg_vec_ ,
op2arg_vec_.pod_vector_ptr<Addr>() ,
op2var_vec_.pod_vector_ptr<Addr>() ,
var2op_vec_.pod_vector_ptr<Addr>()
);
}
/// Free memory used for functions that begin with random_
/// and random iterators and subgraph iterators
void clear_random(void)
{
op2arg_vec_.clear();
op2var_vec_.clear();
var2op_vec_.clear();
CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 );
}
/// get non-const version of all_par_vec
pod_vector_maybe<Base>& all_par_vec(void)
{ return all_par_vec_; }
/// get non-const version of all_par_vec
const pod_vector_maybe<Base>& all_par_vec(void) const
{ return all_par_vec_; }
// ================================================================
// const functions that retrieve infromation from this player
// ================================================================
/// const version of dynamic parameter flag
const pod_vector<bool>& dyn_par_is(void) const
{ return dyn_par_is_; }
/// const version of dynamic parameter index to parameter index
const pod_vector<addr_t>& dyn_ind2par_ind(void) const
{ return dyn_ind2par_ind_; }
/// const version of dynamic parameter operator
const pod_vector<opcode_t>& dyn_par_op(void) const
{ return dyn_par_op_; }
/// const version of dynamic parameter arguments
const pod_vector<addr_t>& dyn_par_arg(void) const
{ return dyn_par_arg_; }
/*!
\brief
fetch an operator from the recording.
\return
the i-th operator in the recording.
\param i
the index of the operator in recording
*/
OpCode GetOp (size_t i) const
{ return OpCode(op_vec_[i]); }
/*!
\brief
Fetch a VecAD index from the recording.
\return
the i-th VecAD index in the recording.
\param i
the index of the VecAD index in recording
*/
size_t GetVecInd (size_t i) const
{ return size_t( all_var_vecad_ind_[i] ); }
/*!
\brief
Fetch a parameter from the recording.
\return
the i-th parameter in the recording.
\param i
the index of the parameter in recording
*/
Base GetPar(size_t i) const
{ return all_par_vec_[i]; }
/*!
\brief
Fetch entire parameter vector from the recording.
\return
the entire parameter vector.
*/
const Base* GetPar(void) const
{ return all_par_vec_.data(); }
/*!
\brief
Fetch a '\\0' terminated string from the recording.
\return
the beginning of the string.
\param i
the index where the string begins.
*/
const char *GetTxt(size_t i) const
{ CPPAD_ASSERT_UNKNOWN(i < text_vec_.size() );
return text_vec_.data() + i;
}
/// Fetch number of independent dynamic parameters in the recording
size_t num_dynamic_ind(void) const
{ return num_dynamic_ind_; }
/// Fetch number of dynamic parameters in the recording
size_t num_dynamic_par(void) const
{ return dyn_par_op_.size(); }
/// Fetch number of dynamic parameters operator arguments in the recording
size_t num_dynamic_arg(void) const
{ return dyn_par_arg_.size(); }
/// Fetch number of variables in the recording.
size_t num_var_rec(void) const
{ return num_var_rec_; }
/// Fetch number of vecad load operations
size_t num_var_load_rec(void) const
{ return num_var_load_rec_; }
/// Fetch number of operators in the recording.
size_t num_op_rec(void) const
{ return op_vec_.size(); }
/// Fetch number of VecAD indices in the recording.
size_t num_var_vecad_ind_rec(void) const
{ return all_var_vecad_ind_.size(); }
/// Fetch number of VecAD vectors in the recording
size_t num_var_vecad_rec(void) const
{ return num_var_vecad_rec_; }
/// Fetch number of argument indices in the recording.
size_t num_op_arg_rec(void) const
{ return arg_vec_.size(); }
/// Fetch number of parameters in the recording.
size_t num_par_rec(void) const
{ return all_par_vec_.size(); }
/// Fetch number of characters (representing strings) in the recording.
size_t num_text_rec(void) const
{ return text_vec_.size(); }
/// A measure of amount of memory used to store
/// the operation sequence, just lengths, not capacities.
/// In user api as f.size_op_seq(); see the file seq_property.omh.
size_t size_op_seq(void) const
{ // check assumptions made by ad_fun<Base>::size_op_seq()
CPPAD_ASSERT_UNKNOWN( op_vec_.size() == num_op_rec() );
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == num_op_arg_rec() );
CPPAD_ASSERT_UNKNOWN( all_par_vec_.size() == num_par_rec() );
CPPAD_ASSERT_UNKNOWN( text_vec_.size() == num_text_rec() );
CPPAD_ASSERT_UNKNOWN( all_var_vecad_ind_.size() == num_var_vecad_ind_rec() );
return op_vec_.size() * sizeof(opcode_t)
+ arg_vec_.size() * sizeof(addr_t)
+ all_par_vec_.size() * sizeof(Base)
+ dyn_par_is_.size() * sizeof(bool)
+ dyn_ind2par_ind_.size() * sizeof(addr_t)
+ dyn_par_op_.size() * sizeof(opcode_t)
+ dyn_par_arg_.size() * sizeof(addr_t)
+ text_vec_.size() * sizeof(char)
+ all_var_vecad_ind_.size() * sizeof(addr_t)
;
}
/// A measure of amount of memory used for random access routine
/// In user api as f.size_random(); see the file seq_property.omh.
size_t size_random(void) const
{
# ifndef NDEBUG
if( op2arg_vec_.size() == 0 )
{ CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 );
CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 );
}
else
{ size_t size = 0;
switch( address_type() )
{ case play::unsigned_short_enum:
size = sizeof(unsigned short);
break;
//
case play::unsigned_int_enum:
size = sizeof(unsigned int);
break;
//
case play::size_t_enum:
size = sizeof(size_t);
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
break;
}
CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size()/size == num_op_rec() );
CPPAD_ASSERT_UNKNOWN( op2var_vec_.size()/size == num_op_rec() );
CPPAD_ASSERT_UNKNOWN( var2op_vec_.size()/size == num_var_rec() );
}
# endif
CPPAD_ASSERT_UNKNOWN( sizeof(unsigned char) == 1 );
return op2arg_vec_.size()
+ op2var_vec_.size()
+ var2op_vec_.size()
;
}
// -----------------------------------------------------------------------
/// const sequential iterator begin
play::const_sequential_iterator begin(void) const
{ size_t op_index = 0;
size_t num_var = num_var_rec_;
return play::const_sequential_iterator(
num_var, &op_vec_, &arg_vec_, op_index
);
}
/// const sequential iterator end
play::const_sequential_iterator end(void) const
{ size_t op_index = op_vec_.size() - 1;
size_t num_var = num_var_rec_;
return play::const_sequential_iterator(
num_var, &op_vec_, &arg_vec_, op_index
);
}
// -----------------------------------------------------------------------
/// const subgraph iterator begin
play::const_subgraph_iterator<addr_t> begin_subgraph(
const play::const_random_iterator<addr_t>& random_itr ,
const pod_vector<addr_t>* subgraph ) const
{ size_t subgraph_index = 0;
return play::const_subgraph_iterator<addr_t>(
random_itr,
subgraph,
subgraph_index
);
}
/// const subgraph iterator end
template <class Addr>
play::const_subgraph_iterator<Addr> end_subgraph(
const play::const_random_iterator<Addr>& random_itr ,
const pod_vector<addr_t>* subgraph ) const
{ size_t subgraph_index = subgraph->size() - 1;
return play::const_subgraph_iterator<Addr>(
random_itr,
subgraph,
subgraph_index
);
}
// -----------------------------------------------------------------------
/// const random iterator
template <class Addr>
play::const_random_iterator<Addr> get_random(void) const
{ return play::const_random_iterator<Addr>(
op_vec_,
arg_vec_,
op2arg_vec_.pod_vector_ptr<Addr>(),
op2var_vec_.pod_vector_ptr<Addr>(),
var2op_vec_.pod_vector_ptr<Addr>()
);
}
};
} } // END_CPPAD_lOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,152 @@
# ifndef CPPAD_LOCAL_PLAY_RANDOM_ITERATOR_HPP
# define CPPAD_LOCAL_PLAY_RANDOM_ITERATOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file random_iterator.hpp
*/
/*!
Constant random iterator for a player object.
\tparam Addr
An integer type capable of representing the largest value in the vectors
arg_vec, op2arg_vec, op2var_vec, var2op_vec.
*/
template <class Addr>
class const_random_iterator {
private:
/// vector of operators on the tape
const pod_vector<opcode_t>* op_vec_;
/// vector of arguments for all the operators
/// (note that this is same type as used in recorder; i.e., addr_t)
const pod_vector<addr_t>* arg_vec_;
/// mapping from operator index to index of first argument in arg_vec_
const pod_vector<Addr>* op2arg_vec_;
/// mapping from operator index to index of primary (last) result
const pod_vector<Addr>* op2var_vec_;
/// mapping from primary variable index to operator index
/// (only specified for primary variables)
const pod_vector<Addr>* var2op_vec_;
public:
/// default constructor
const_random_iterator(void) :
op_vec_(nullptr) ,
arg_vec_(nullptr) ,
op2arg_vec_(nullptr) ,
op2var_vec_(nullptr) ,
var2op_vec_(nullptr)
{ }
/// default assignment operator
void operator=(const const_random_iterator& rhs)
{
op_vec_ = rhs.op_vec_;
op2arg_vec_ = rhs.op2arg_vec_;
op2var_vec_ = rhs.op2var_vec_;
var2op_vec_ = rhs.var2op_vec_;
return;
}
/*!
Create a random iterator
\par var2op_vec
This variable is not needed and can be null if the var2op member
function is not used.
*/
const_random_iterator(
const pod_vector<opcode_t>& op_vec , ///< op_vec_
const pod_vector<addr_t>& arg_vec , ///< arg_vec_
const pod_vector<Addr>* op2arg_vec , ///< op2ar_vec_
const pod_vector<Addr>* op2var_vec , ///< op2var_vec_
const pod_vector<Addr>* var2op_vec ) ///< var2op_vec_
:
op_vec_ ( &op_vec ) ,
arg_vec_ ( &arg_vec ) ,
op2arg_vec_ ( op2arg_vec ) ,
op2var_vec_ ( op2var_vec ) ,
var2op_vec_ ( var2op_vec )
{ }
/*!
\brief
fetch the information corresponding to an operator
\param op_index
index for this operator [in]
\param op [out]
op code for this operator.
\param op_arg [out]
pointer to the first arguement to this operator.
\param var_index [out]
index of the last variable (primary variable) for this operator.
If there is no primary variable for this operator, i_var not sepcified
and could have any value.
*/
void op_info(
size_t op_index ,
OpCode& op ,
const addr_t*& op_arg ,
size_t& var_index ) const
{ op = OpCode( (*op_vec_)[op_index] );
op_arg = (*op2arg_vec_)[op_index] + arg_vec_->data();
var_index = (*op2var_vec_)[op_index];
return;
}
/*!
\brief
map variable index to operator index.
\param var_index
must be the index of a primary variable.
\return
is the index of the operator corresponding to this primary variable.
*/
size_t var2op(size_t var_index) const
{ // check that var2op_vec was not null in constructor
CPPAD_ASSERT_UNKNOWN( var2op_vec_ != nullptr );
//
// operator index
size_t op_index = size_t( (*var2op_vec_)[var_index] );
//
// check that var_index is a primary variable index (see random_setup)
CPPAD_ASSERT_UNKNOWN( op_index < op_vec_->size() );
//
return op_index;
}
/// get operator corresponding to operator index
OpCode get_op(size_t op_index) const
{ return OpCode( (*op_vec_)[op_index] );
}
/// number of operators
size_t num_op(void) const
{ return op_vec_->size(); }
//
/// number of variables
size_t num_var(void) const
{ return var2op_vec_->size(); }
};
} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,144 @@
# ifndef CPPAD_LOCAL_PLAY_RANDOM_SETUP_HPP
# define CPPAD_LOCAL_PLAY_RANDOM_SETUP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file random_setup.hpp
*/
/*!
Set up random access to a player object.
\tparam Addr
An integer type capable of representing the largest value in the vectors
arg_vec, op2arg_vec, op2var_vec, var2op_vec.
\param num_var
num_var is the number of variables in this operation sequence.
\param op_vec
The mapping
<code>op = OpCode[ op_vec[op_index] ]</code>
maps from operator index op_index to the operator op.
\param arg_vec
is a vector of all the arguments for all the operators.
The mapping op2arg_vec will map from operator indices
to index in this vector.
\param op2arg_vec
On input, op2arg_vec is either the empty vector
(or contains the proper result from a previous call to random_setup).
Upon return it maps each operator index to the index in op_arg_vec of its
first argument for the operator.
\param op2var_vec
On input, op2var_vec is either the empty vector
(or contains the proper result from a previous call to random_setup).
Upon return it maps each operator index to the primary (last)
result for the operator. If there are no results for the operator,
the return value map value is not specified.
\param var2op_vec
On input, var2op_vec is either the empty vector
(or contains the proper result from a previous call to random_setup).
Upon return it maps each primary variable index to the corresponding
operator index. The value of the map is only specifed for primary variable
indices.
*/
template <class Addr>
void random_setup(
size_t num_var ,
const pod_vector<opcode_t>& op_vec ,
const pod_vector<addr_t>& arg_vec ,
pod_vector<Addr>* op2arg_vec ,
pod_vector<Addr>* op2var_vec ,
pod_vector<Addr>* var2op_vec )
{
if( op2arg_vec->size() != 0 )
{ CPPAD_ASSERT_UNKNOWN( op2arg_vec->size() == op_vec.size() );
CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == op_vec.size() );
CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == num_var );
return;
}
CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 );
CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 );
CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == 0 );
CPPAD_ASSERT_UNKNOWN( OpCode( op_vec[0] ) == BeginOp );
CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1);
//
size_t num_op = op_vec.size();
size_t var_index = 0;
size_t arg_index = 0;
//
op2arg_vec->resize( num_op );
op2var_vec->resize( num_op );
var2op_vec->resize( num_var );
# ifndef NDEBUG
// value of var2op for auxillary variables is num_op (invalid)
for(size_t i_var = 0; i_var < num_var; ++i_var)
(*var2op_vec)[i_var] = Addr( num_op );
// value of op2var is num_var (invalid) when NumRes(op) = 0
for(size_t i_op = 0; i_op < num_op; ++i_op)
(*op2var_vec)[i_op] = Addr( num_var );
# endif
for(size_t i_op = 0; i_op < num_op; ++i_op)
{ OpCode op = OpCode( op_vec[i_op] );
//
// index of first argument for this operator
(*op2arg_vec)[i_op] = Addr( arg_index );
arg_index += NumArg(op);
//
// index of first result for next operator
var_index += NumRes(op);
if( NumRes(op) > 0 )
{ // index of last (primary) result for this operator
(*op2var_vec)[i_op] = Addr( var_index - 1 );
//
// mapping from primary variable to its operator
(*var2op_vec)[var_index - 1] = Addr( i_op );
}
// CSumOp
if( op == CSumOp )
{ CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
//
// pointer to first argument for this operator
const addr_t* op_arg = arg_vec.data() + arg_index;
//
// The actual number of arugments for this operator is
// op_arg[4] + 1
// Correct index of first argument for next operator
arg_index += size_t(op_arg[4] + 1);
}
//
// CSkip
if( op == CSkipOp )
{ CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
//
// pointer to first argument for this operator
const addr_t* op_arg = arg_vec.data() + arg_index;
//
// The actual number of arugments for this operator is
// 7 + op_arg[4] + op_arg[5].
// Correct index of first argument for next operator.
arg_index += size_t(7 + op_arg[4] + op_arg[5]);
}
}
}
} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,290 @@
# ifndef CPPAD_LOCAL_PLAY_SEQUENTIAL_ITERATOR_HPP
# define CPPAD_LOCAL_PLAY_SEQUENTIAL_ITERATOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file sequential_iterator.hpp
*/
/*!
Constant sequential iterator for a player object.
\tparam Addr
An integer type capable of representing the largest value in the vectors
arg_vec, op2arg_vec, op2var_vec, var2op_vec.
\par
Except for constructor, the public API for this class is the same as
for the subgraph_iterator class.
*/
class const_sequential_iterator {
private:
/// pointer to the first operator in the player, BeginOp = *op_begin_
const opcode_t* op_begin_;
/// pointer one past last operator in the player, EndOp = *(op_end_ - 1)
const opcode_t* op_end_;
/// pointer to the first argument for the first operator
const addr_t* arg_begin_;
/// pointer on past last argumemnt for last operator
const addr_t* arg_end_;
/// pointer to current operator
const opcode_t* op_cur_;
/// pointer to first argument for current operator
const addr_t* arg_;
/// number of variables in tape (not const for assignment operator)
size_t num_var_;
/// index of last result for current operator
size_t var_index_;
/// value of current operator; i.e. op_ = *op_cur_
OpCode op_;
public:
/// default constructor
const_sequential_iterator(void) :
op_begin_(nullptr) ,
op_end_(nullptr) ,
arg_begin_(nullptr) ,
arg_end_(nullptr) ,
op_cur_(nullptr) ,
arg_(nullptr) ,
num_var_(0) ,
var_index_(0) ,
op_(NumberOp)
{ }
/// assignment operator
void operator=(const const_sequential_iterator& rhs)
{
op_begin_ = rhs.op_begin_;
op_end_ = rhs.op_end_;
arg_begin_ = rhs.arg_begin_;
arg_end_ = rhs.arg_end_;
op_cur_ = rhs.op_cur_;
arg_ = rhs.arg_;
num_var_ = rhs.num_var_;
var_index_ = rhs.var_index_;
op_ = rhs.op_;
return;
}
/*!
Create a sequential iterator starting either at beginning or end of tape
\param num_var
is the number of variables in the tape.
\param op_vec
is the vector of operators on the tape.
\param arg_vec
is the vector of arguments for all the operators
\param op_index
is the operator index that iterator will start at.
It must be zero or op_vec_->size() - 1.
\par Assumptions
- OpCode(op_vec_[0]) == BeginOp
- OpCode(op_vec_[op_vec_->size() - 1]) == EndOp
*/
const_sequential_iterator(
size_t num_var ,
const pod_vector<opcode_t>* op_vec ,
const pod_vector<addr_t>* arg_vec ,
size_t op_index )
:
op_begin_ ( op_vec->data() ) ,
op_end_ ( op_vec->data() + op_vec->size() ) ,
arg_begin_ ( arg_vec->data() ) ,
arg_end_ ( arg_vec->data() + arg_vec->size() ),
num_var_ ( num_var )
{ if( op_index == 0 )
{
// index of last result for BeginOp
var_index_ = 0;
//
// first argument to BeginOp
arg_ = arg_vec->data();
//
// BeginOp
op_cur_ = op_begin_;
op_ = OpCode( *op_cur_ );
CPPAD_ASSERT_UNKNOWN( op_ == BeginOp );
CPPAD_ASSERT_NARG_NRES(op_, 1, 1);
}
else
{ CPPAD_ASSERT_UNKNOWN(op_index == op_vec->size()-1);
//
// index of last result for EndOp
var_index_ = num_var - 1;
//
// first argument to EndOp (has no arguments)
arg_ = arg_vec->data() + arg_vec->size();
//
// EndOp
op_cur_ = op_end_ - 1;
op_ = OpCode( *op_cur_ );
CPPAD_ASSERT_UNKNOWN( op_ == EndOp );
CPPAD_ASSERT_NARG_NRES(op_, 0, 0);
}
}
/*!
Advance iterator to next operator
*/
const_sequential_iterator& operator++(void)
{
// first argument for next operator
arg_ += NumArg(op_);
//
// next operator
++op_cur_;
op_ = OpCode( *op_cur_ );
//
// last result for next operator
var_index_ += NumRes(op_);
//
return *this;
}
/*!
Correction applied before ++ operation when current operator
is CSumOp or CSkipOp.
*/
void correct_before_increment(void)
{ // number of arguments for this operator depends on argument data
CPPAD_ASSERT_UNKNOWN( NumArg(op_) == 0 );
const addr_t* arg = arg_;
//
// CSumOp
if( op_ == CSumOp )
{ // add actual number of arguments to arg_
arg_ += arg[4] + 1;
}
//
// CSkip
else
{ CPPAD_ASSERT_UNKNOWN( op_ == CSkipOp );
//
CPPAD_ASSERT_UNKNOWN( arg + 5 < arg_end_ );
addr_t n_skip = arg[4] + arg[5];
CPPAD_ASSERT_UNKNOWN( n_skip == arg[6 + n_skip] );
//
// add actual number of arguments to arg_
arg_ += 7 + n_skip;
}
return;
}
/*!
Backup iterator to previous operator
*/
const_sequential_iterator& operator--(void)
{ //
// last result for next operator
var_index_ -= NumRes(op_);
//
// next operator
--op_cur_;
op_ = OpCode( *op_cur_ );
//
// first argument for next operator
arg_ -= NumArg(op_);
//
return *this;
}
/*!
Correction applied after -- operation when current operator
is CSumOp or CSkipOp.
\param arg [out]
corrected point to arguments for this operation.
*/
void correct_after_decrement(const addr_t*& arg)
{ // number of arguments for this operator depends on argument data
CPPAD_ASSERT_UNKNOWN( NumArg(op_) == 0 );
//
// infromation for number of arguments is stored in arg_ - 1
CPPAD_ASSERT_UNKNOWN( arg_begin_ < arg_ );
//
// CSumOp
if( op_ == CSumOp )
{ // index of arg[4]
addr_t arg_4 = *(arg_ - 1);
//
// corrected index of first argument to this operator
arg = arg_ -= arg_4 + 1;
//
CPPAD_ASSERT_UNKNOWN( arg[arg[4] ] == arg[4] );
}
//
// CSkip
else
{ CPPAD_ASSERT_UNKNOWN( op_ == CSkipOp );
//
// number to possibly skip is stored in last argument
addr_t n_skip = *(arg_ - 1);
//
// corrected index of frist argument to this operator
arg = arg_ -= 7 + n_skip;
//
CPPAD_ASSERT_UNKNOWN( arg[4] + arg[5] == n_skip );
}
CPPAD_ASSERT_UNKNOWN( arg_begin_ <= arg );
CPPAD_ASSERT_UNKNOWN( arg + NumArg(op_) <= arg_end_ );
}
/*!
\brief
Get information corresponding to current operator.
\param op [out]
op code for this operator.
\param arg [out]
pointer to the first arguement to this operator.
\param var_index [out]
index of the last variable (primary variable) for this operator.
If there is no primary variable for this operator, var_index
is not sepcified and could have any value.
*/
void op_info(
OpCode& op ,
const addr_t*& arg ,
size_t& var_index ) const
{ // op
CPPAD_ASSERT_UNKNOWN( op_begin_ <= op_cur_ && op_cur_ < op_end_ )
op = op_;
//
// arg
arg = arg_;
CPPAD_ASSERT_UNKNOWN( arg_begin_ <= arg );
CPPAD_ASSERT_UNKNOWN( arg + NumArg(op) <= arg_end_ );
//
// var_index
CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_ || NumRes(op) == 0 );
var_index = var_index_;
}
/// current operator index
size_t op_index(void)
{ return size_t(op_cur_ - op_begin_); }
};
} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,132 @@
# ifndef CPPAD_LOCAL_PLAY_SUBGRAPH_ITERATOR_HPP
# define CPPAD_LOCAL_PLAY_SUBGRAPH_ITERATOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/play/random_iterator.hpp>
// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
namespace CppAD { namespace local { namespace play {
/*!
\file random_iterator.hpp
*/
/*!
Constant subgraph iterator for a player object.
\tparam Addr
An integer type capable of representing the largest value in the vectors
arg_vec, op2arg_vec, op2var_vec, var2op_vec.
Except for constructor, the public API for this class is the same as
for the sequential iterator class.
*/
template <class Addr>
class const_subgraph_iterator {
private:
/// a random iterator used to access player information
const const_random_iterator<Addr>* random_itr_;
/// sorted subset of operator indices that we will include
const pod_vector<addr_t>* subgraph_;
/// index in subgraph of current operator
/// The initial value for this index must be zero or subgraph.size()-1.
size_t subgraph_index_;
public:
/// default constructor
const_subgraph_iterator(void) :
random_itr_(nullptr) ,
subgraph_(nullptr) ,
subgraph_index_(0)
{ }
/// default assignment operator
void operator=(const const_subgraph_iterator& rhs)
{
random_itr_ = rhs.random_itr_;
subgraph_ = rhs.subgraph_;
subgraph_index_ = rhs.subgraph_index_;
return;
}
/*!
Create a subgraph iterator starting either at beginning or end of subgraph
*/
const_subgraph_iterator(
const const_random_iterator<Addr>& random_itr , ///< random_itr_
const pod_vector<addr_t>* subgraph , ///< subgraph_
size_t subgraph_index ) ///< subgraph_index_
:
random_itr_ ( &random_itr ) ,
subgraph_ ( subgraph ) ,
subgraph_index_ ( subgraph_index )
{ CPPAD_ASSERT_UNKNOWN(
subgraph_index == 0 || subgraph_index == subgraph->size() - 1
);
}
/*!
Advance iterator to next operator
*/
const_subgraph_iterator<Addr>& operator++(void)
{ ++subgraph_index_;
return *this;
}
/// No correction necessary when using random access to player
void correct_before_increment(void)
{ return; }
/*!
Backup iterator to previous operator
*/
const_subgraph_iterator<Addr>& operator--(void)
{ --subgraph_index_;
return *this;
}
/*!
No correction necessary when using random access to player.
\param op_arg
not used or modified.
*/
void correct_after_decrement(const addr_t*& op_arg)
{ return; }
/*!
\brief
Get information corresponding to current operator.
\param op [out]
op code for this operator.
\param op_arg [out]
pointer to the first arguement to this operator.
\param var_index [out]
index of the last variable (primary variable) for this operator.
If there is no primary variable for this operator, var_index
is not sepcified and could have any value.
*/
void op_info(
OpCode& op ,
const addr_t*& op_arg ,
size_t& var_index ) const
{ // op
size_t op_index = size_t( (*subgraph_)[subgraph_index_] );
random_itr_->op_info(op_index, op, op_arg, var_index);
}
/// current operator index
size_t op_index(void)
{ return size_t( (*subgraph_)[subgraph_index_] ); }
};
} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE
# endif

View File

@@ -0,0 +1,565 @@
# ifndef CPPAD_LOCAL_POD_VECTOR_HPP
# define CPPAD_LOCAL_POD_VECTOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# if CPPAD_CSTDINT_HAS_8_TO_64
# include <cstdint>
# endif
# include <cstring>
# include <algorithm>
# include <cppad/utility/thread_alloc.hpp>
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/is_pod.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file pod_vector.hpp
File used to define pod_vector classes
*/
// ---------------------------------------------------------------------------
/*!
A vector class with that does not use element constructors or destructors
(elements are Plain Old Data; i.e., is_pod<Type> must be true).
*/
template <class Type>
class pod_vector {
private:
/// maximum number of bytes current allocation can hold
size_t byte_capacity_;
/// number of bytes currently in this vector
size_t byte_length_;
/// pointer to the first type elements
/// (not defined and should not be used when byte_capacity_ = 0)
Type *data_;
/// do not use the copy constructor
explicit pod_vector(const pod_vector& )
{ CPPAD_ASSERT_UNKNOWN(false); }
public:
/// default constructor sets byte_capacity_ = byte_length_ = data_ = 0
pod_vector(void)
: byte_capacity_(0), byte_length_(0), data_(nullptr)
{ CPPAD_ASSERT_UNKNOWN( is_pod<Type>() );
}
/// sizing constructor
pod_vector(
/// number of elements in this vector
size_t n )
: byte_capacity_(0), byte_length_(0), data_(nullptr)
{ CPPAD_ASSERT_UNKNOWN( is_pod<Type>() );
extend(n);
}
/// Destructor: returns allocated memory to thread_alloc;
/// see extend and resize. If this is not plain old data,
/// the destructor for each element is called.
~pod_vector(void)
{ if( byte_capacity_ > 0 )
{
void* v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
}
/*
Return a pointer to a pod_vector with a different type of element.
- This vector and the other share the same memory.
- The the other vector should not be deleted.
- The following operations work the same for this and the other vector:
swap, clear, assignment.
*/
template <class Other>
pod_vector<Other>* pod_vector_ptr(void)
{ return reinterpret_cast< pod_vector<Other>* >(this);
}
template <class Other>
const pod_vector<Other>* pod_vector_ptr(void) const
{ return reinterpret_cast< const pod_vector<Other>* >(this);
}
/// current number of elements in this vector.
size_t size(void) const
{ return byte_length_ / sizeof(Type); }
/// current capacity (amount of allocated storage) for this vector.
size_t capacity(void) const
{ return byte_capacity_ / sizeof(Type); }
/// current data pointer is no longer valid after any of the following:
/// extend, resize, erase, clear, assignment and destructor.
Type* data(void)
{ return data_; }
/// const version of data pointer (see non-const documentation)
const Type* data(void) const
{ return data_; }
// ----------------------------------------------------------------------
/// non-constant element access; i.e., we can change this element value
Type& operator[](
/// element index, must be less than length
size_t i
)
{ CPPAD_ASSERT_UNKNOWN( i * sizeof(Type) < byte_length_ );
return data_[i];
}
/// non-constant element access; i.e., we can change this element value
template <class Index>
Type& operator[](
/// element index, must be less than length and convertable to size_t
Index i
)
{ return (*this)[size_t(i)]; }
// ----------------------------------------------------------------------
/// constant element access; i.e., we cannot change this element value
const Type& operator[](
/// element index, must be less than length
size_t i
) const
{ CPPAD_ASSERT_UNKNOWN( i * sizeof(Type) < byte_length_ );
return data_[i];
}
/// constant element access; i.e., we cannot change this element value
template <class Index>
const Type& operator[](
/// element index, must be less than length and convertable to size_t
Index i
) const
{ return (*this)[size_t(i)]; }
// ----------------------------------------------------------------------
/*!
Add an element to theh back of this vector
\param e
is the element we are adding to the back of the vector.
*/
void push_back(const Type& e)
{ size_t i = extend(1);
data_[i] = e;
}
/*!
Swap all properties of this vector with another.
This is useful when moving a vector that grows after it has reached
its final size (without copying every element).
\param other
is the other vector that we are swapping this vector with.
*/
void swap(pod_vector& other)
{ std::swap(byte_capacity_, other.byte_capacity_);
std::swap(byte_length_, other.byte_length_);
std::swap(data_, other.data_);
}
// ----------------------------------------------------------------------
/*!
Increase the number of elements the end of this vector
(existing elements are always preserved).
\param n
is the number of elements to add to end of this vector.
\return
is the number of elements in the vector before it was extended.
This is the index of the first new element added to the vector.
- If Type is plain old data, new elements are not initialized;
i.e., their constructor is not called. Otherwise, the constructor
is called for each new element.
- This and resize are the only routine that allocate memory for
pod_vector. They uses thread_alloc for this allocation.
*/
size_t extend(size_t n)
{ size_t old_length = byte_length_;
byte_length_ += n * sizeof(Type);
// check if we can use current memory
if( byte_length_ <= byte_capacity_ )
return old_length / sizeof(Type);
// save more old information
size_t old_capacity = byte_capacity_;
void* old_v_ptr = reinterpret_cast<void*>(data_);
// get new memory and set capacity
void* v_ptr = thread_alloc::get_memory(byte_length_, byte_capacity_);
data_ = reinterpret_cast<Type*>(v_ptr);
// copy old data to new
if( old_length > 0 )
std::memcpy(v_ptr, old_v_ptr, old_length);
// return old memory to available pool
if( old_capacity > 0 )
thread_alloc::return_memory(old_v_ptr);
// return value for extend(n) is the old length
CPPAD_ASSERT_UNKNOWN( byte_length_ <= byte_capacity_ );
return old_length / sizeof(Type);
}
// ----------------------------------------------------------------------
/*!
resize the vector (existing elements preserved when n <= capacity() ).
\param n
is the new size for this vector.
\par
if n <= capacity(), no memory is freed or allocated, the capacity
is not changed, and existing elements are preserved.
If n > capacity(), new memory is allocates and all the
data in the vector is lost.
- If Type is plain old data, new elements are not initialized;
i.e., their constructor is not called. Otherwise, the constructor
is called for each new element.
- This and extend are the only routine that allocate memory for
pod_vector. They uses thread_alloc for this allocation.
*/
void resize(size_t n)
{ byte_length_ = n * sizeof(Type);
// check if we must allocate new memory
if( byte_capacity_ < byte_length_ )
{ void* v_ptr;
//
if( byte_capacity_ > 0 )
{ // return old memory to available pool
v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
//
// get new memory and set capacity
v_ptr = thread_alloc::get_memory(byte_length_, byte_capacity_);
data_ = reinterpret_cast<Type*>(v_ptr);
//
}
CPPAD_ASSERT_UNKNOWN( byte_length_ <= byte_capacity_ );
}
// ----------------------------------------------------------------------
/*!
Remove all the elements from this vector and free its memory.
*/
void clear(void)
{ if( byte_capacity_ > 0 )
{
void* v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
data_ = nullptr;
byte_capacity_ = 0;
byte_length_ = 0;
}
// -----------------------------------------------------------------------
/// vector assignment operator
void operator=(
/// right hand size of the assingment operation
const pod_vector& x
)
{ CPPAD_ASSERT_UNKNOWN( x.byte_length_ % sizeof(Type) == 0 );
resize( x.byte_length_ / sizeof(Type) );
if( byte_length_ > 0 )
{
void* v_ptr = reinterpret_cast<void*>( data_ );
void* v_ptr_x = reinterpret_cast<void*>( x.data_ );
std::memcpy(v_ptr, v_ptr_x, byte_length_);
}
}
};
// ---------------------------------------------------------------------------
/*!
A vector class with that does not use element constructors or destructors
when is_pod<Type> is true.
*/
template <class Type>
class pod_vector_maybe {
private:
/// maximum number of Type elements current allocation can hold
size_t capacity_;
/// number of elements currently in this vector
size_t length_;
/// pointer to the first type elements
/// (not defined and should not be used when capacity_ = 0)
Type *data_;
/// do not use the copy constructor
explicit pod_vector_maybe(const pod_vector_maybe& )
{ CPPAD_ASSERT_UNKNOWN(false); }
public:
/// default constructor sets capacity_ = length_ = data_ = 0
pod_vector_maybe(void)
: capacity_(0), length_(0), data_(nullptr)
{ CPPAD_ASSERT_UNKNOWN( is_pod<size_t>() );
}
/// sizing constructor
pod_vector_maybe(
/// number of elements in this vector
size_t n )
: capacity_(0), length_(0), data_(nullptr)
{ extend(n); }
/// Destructor: returns allocated memory to thread_alloc;
/// see extend and resize. If this is not plain old data,
/// the destructor for each element is called.
~pod_vector_maybe(void)
{ if( capacity_ > 0 )
{ if( ! is_pod<Type>() )
{ // call destructor for each element
for(size_t i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
void* v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
}
/// current number of elements in this vector.
size_t size(void) const
{ return length_; }
/// current capacity (amount of allocated storage) for this vector.
size_t capacity(void) const
{ return capacity_; }
/// current data pointer is no longer valid after any of the following:
/// extend, resize, erase, clear, assignment, and destructor.
Type* data(void)
{ return data_; }
/// const version of data pointer (see non-const documentation)
const Type* data(void) const
{ return data_; }
// ----------------------------------------------------------------------
/// non-constant element access; i.e., we can change this element value
Type& operator[](
/// element index, must be less than length
size_t i
)
{ CPPAD_ASSERT_UNKNOWN( i < length_ );
return data_[i];
}
/// non-constant element access; i.e., we can change this element value
template <class Index>
Type& operator[](
/// element index, must be less than length and convertable to size_t
Index i
)
{ return (*this)[size_t(i)]; }
// ----------------------------------------------------------------------
/// constant element access; i.e., we cannot change this element value
const Type& operator[](
/// element index, must be less than length
size_t i
) const
{ CPPAD_ASSERT_UNKNOWN( i < length_ );
return data_[i];
}
/// constant element access; i.e., we cannot change this element value
template <class Index>
const Type& operator[](
/// element index, must be less than length and convertable to size_t
Index i
) const
{ return (*this)[size_t(i)]; }
// ----------------------------------------------------------------------
/*!
Add an element to theh back of this vector
\param e
is the element we are adding to the back of the vector.
*/
void push_back(const Type& e)
{ size_t i = extend(1);
data_[i] = e;
}
/*!
Swap all properties of this vector with another.
This is useful when moving a vector that grows after it has reached
its final size (without copying every element).
\param other
is the other vector that we are swapping this vector with.
*/
void swap(pod_vector_maybe& other)
{ std::swap(capacity_, other.capacity_);
std::swap(length_, other.length_);
std::swap(data_, other.data_);
}
// ----------------------------------------------------------------------
/*!
Increase the number of elements the end of this vector
(existing elements are always preserved).
\param n
is the number of elements to add to end of this vector.
\return
is the number of elements in the vector before it was extended.
This is the index of the first new element added to the vector.
- If Type is plain old data, new elements are not initialized;
i.e., their constructor is not called. Otherwise, the constructor
is called for each new element.
- This and resize are the only routine that allocate memory for
pod_vector_maybe. They uses thread_alloc for this allocation.
*/
size_t extend(size_t n)
{ size_t old_length = length_;
length_ += n;
// check if we can use current memory
if( length_ <= capacity_ )
return old_length;
// save more old information
size_t old_capacity = capacity_;
Type* old_data = data_;
// get new memory and set capacity
size_t length_bytes = length_ * sizeof(Type);
size_t capacity_bytes;
void* v_ptr = thread_alloc::get_memory(length_bytes, capacity_bytes);
capacity_ = capacity_bytes / sizeof(Type);
data_ = reinterpret_cast<Type*>(v_ptr);
if( ! is_pod<Type>() )
{ // call constructor for each new element
for(size_t i = 0; i < capacity_; i++)
new(data_ + i) Type();
}
// copy old data to new
for(size_t i = 0; i < old_length; i++)
data_[i] = old_data[i];
// return old memory to available pool
if( old_capacity > 0 )
{ if( ! is_pod<Type>() )
{ for(size_t i = 0; i < old_capacity; i++)
(old_data + i)->~Type();
}
v_ptr = reinterpret_cast<void*>( old_data );
thread_alloc::return_memory(v_ptr);
}
// return value for extend(n) is the old length
CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ );
return old_length;
}
// ----------------------------------------------------------------------
/*!
resize the vector (existing elements preserved when n <= capacity_).
\param n
is the new size for this vector.
\par
if n <= capacity(), no memory is freed or allocated, the capacity
is not changed, and existing elements are preserved.
If n > capacity(), new memory is allocates and all the
data in the vector is lost.
- If Type is plain old data, new elements are not initialized;
i.e., their constructor is not called. Otherwise, the constructor
is called for each new element.
- This and extend are the only routine that allocate memory for
pod_vector_maybe. They uses thread_alloc for this allocation.
*/
void resize(size_t n)
{ length_ = n;
// check if we must allocate new memory
if( capacity_ < length_ )
{ void* v_ptr;
//
// return old memory to available pool
if( capacity_ > 0 )
{ if( ! is_pod<Type>() )
{ // call destructor for each old element
for(size_t i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
//
// get new memory and set capacity
size_t length_bytes = length_ * sizeof(Type);
size_t capacity_bytes;
v_ptr = thread_alloc::get_memory(length_bytes, capacity_bytes);
capacity_ = capacity_bytes / sizeof(Type);
data_ = reinterpret_cast<Type*>(v_ptr);
//
CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ );
//
if( ! is_pod<Type>() )
{ // call constructor for each new element
for(size_t i = 0; i < capacity_; i++)
new(data_ + i) Type();
}
}
}
// ----------------------------------------------------------------------
/*!
Remove all the elements from this vector and free its memory.
*/
void clear(void)
{ if( capacity_ > 0 )
{ if( ! is_pod<Type>() )
{ // call destructor for each element
for(size_t i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
void* v_ptr = reinterpret_cast<void*>( data_ );
thread_alloc::return_memory(v_ptr);
}
data_ = nullptr;
capacity_ = 0;
length_ = 0;
}
// -----------------------------------------------------------------------
/// vector assignment operator
void operator=(
/// right hand size of the assingment operation
const pod_vector_maybe& x
)
{ resize( x.length_ );
//
CPPAD_ASSERT_UNKNOWN( length_ == x.length_ );
for(size_t i = 0; i < length_; i++)
{ data_[i] = x.data_[i]; }
}
};
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,672 @@
# ifndef CPPAD_LOCAL_POW_OP_HPP
# define CPPAD_LOCAL_POW_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file pow_op.hpp
Forward and reverse mode calculations for z = pow(x, y).
*/
// --------------------------- Powvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = PowvvOp.
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_pow_op
*/
template <class Base>
void forward_powvv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowvvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_0 = log(x)
forward_log_op(p, q, i_z, size_t(arg[0]), cap_order, taylor);
// z_1 = z_0 * y
addr_t adr[2];
adr[0] = addr_t( i_z );
adr[1] = arg[1];
forward_mulvv_op(p, q, i_z+1, adr, parameter, cap_order, taylor);
// z_2 = exp(z_1)
// final result for zero order case is exactly the same as for Base
if( p == 0 )
{ // Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z_2 = taylor + (i_z+2) * cap_order;
z_2[0] = pow(x[0], y[0]);
p++;
}
if( p <= q )
forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Multiple directions forward mode Taylor coefficients for op = PowvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_pow_op_dir
*/
template <class Base>
void forward_powvv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowvvOp) - 1
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_0 = log(x)
forward_log_op_dir(q, r, i_z, size_t(arg[0]), cap_order, taylor);
// z_1 = y * z_0
addr_t adr[2];
adr[0] = addr_t( i_z );
adr[1] = arg[1];
forward_mulvv_op_dir(q, r, i_z+1, adr, parameter, cap_order, taylor);
// z_2 = exp(z_1)
forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = PowvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_pow_op_0
*/
template <class Base>
void forward_powvv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowvvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z_0 = taylor + i_z * cap_order;
Base* z_1 = z_0 + cap_order;
Base* z_2 = z_1 + cap_order;
z_0[0] = log( x[0] );
z_1[0] = z_0[0] * y[0];
z_2[0] = pow(x[0], y[0]);
}
/*!
Compute reverse mode partial derivatives for result of op = PowvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::reverse_pow_op
*/
template <class Base>
void reverse_powvv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowvvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_2 = exp(z_1)
reverse_exp_op(
d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial
);
// z_1 = z_0 * y
addr_t adr[2];
adr[0] = addr_t( i_z );
adr[1] = arg[1];
reverse_mulvv_op(
d, i_z+1, adr, parameter, cap_order, taylor, nc_partial, partial
);
// z_0 = log(x)
reverse_log_op(
d, i_z, size_t(arg[0]), cap_order, taylor, nc_partial, partial
);
}
// --------------------------- Powpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = PowpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_pow_op
*/
template <class Base>
void forward_powpv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowpvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* z_0 = taylor + i_z * cap_order;
// z_0 = log(x)
Base x = parameter[ arg[0] ];
size_t d;
for(d = p; d <= q; d++)
{ if( d == 0 )
z_0[d] = log(x);
else
z_0[d] = Base(0.0);
}
// 2DO: remove requirement that i_z * cap_order <= max addr_t value
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z * cap_order,
"cppad_tape_addr_type maximum value has been exceeded\n"
"This is due to a kludge in the pow operation and should be fixed."
);
// z_1 = z_0 * y
addr_t adr[2];
// offset of z_i in taylor (as if it were a parameter); i.e., log(x)
adr[0] = addr_t( i_z * cap_order );
// offset of y in taylor (as a variable)
adr[1] = arg[1];
// Trick: use taylor both for the parameter vector and variable values
forward_mulpv_op(p, q, i_z+1, adr, taylor, cap_order, taylor);
// z_2 = exp(z_1)
// zero order case exactly same as Base type operation
if( p == 0 )
{ Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z_2 = taylor + (i_z+2) * cap_order;
z_2[0] = pow(x, y[0]);
p++;
}
if( p <= q )
forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Multiple directions forward mode Taylor coefficients for op = PowpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_pow_op_dir
*/
template <class Base>
void forward_powpv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowpvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* z_0 = taylor + i_z * num_taylor_per_var;
// z_0 = log(x)
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
z_0[m+ell] = Base(0.0);
// 2DO: remove requirement i_z * num_taylor_per_var <= max addr_t value
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z * num_taylor_per_var,
"cppad_tape_addr_type maximum value has been exceeded\n"
"This is due to a kludge in the pow operation and should be fixed."
);
// z_1 = z_0 * y
addr_t adr[2];
// offset of z_0 in taylor (as if it were a parameter); i.e., log(x)
adr[0] = addr_t( i_z * num_taylor_per_var );
// ofset of y in taylor (as a variable)
adr[1] = arg[1];
// Trick: use taylor both for the parameter vector and variable values
forward_mulpv_op_dir(q, r, i_z+1, adr, taylor, cap_order, taylor);
// z_2 = exp(z_1)
forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = PowpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_pow_op_0
*/
template <class Base>
void forward_powpv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowpvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z_0 = taylor + i_z * cap_order;
Base* z_1 = z_0 + cap_order;
Base* z_2 = z_1 + cap_order;
// z_0 = log(x)
z_0[0] = log(x);
// z_1 = z_0 * y
z_1[0] = z_0[0] * y[0];
// z_2 = exp(z_1)
// zero order case exactly same as Base type operation
z_2[0] = pow(x, y[0]);
}
/*!
Compute reverse mode partial derivative for result of op = PowpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::reverse_pow_op
*/
template <class Base>
void reverse_powpv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowpvOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// z_2 = exp(z_1)
reverse_exp_op(
d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial
);
// 2DO: remove requirement that i_z * cap_order <= max addr_t value
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z * cap_order,
"cppad_tape_addr_type maximum value has been exceeded\n"
"This is due to a kludge in the pow operation and should be fixed."
);
// z_1 = z_0 * y
addr_t adr[2];
adr[0] = addr_t( i_z * cap_order ); // offset of z_0[0] in taylor
adr[1] = arg[1]; // index of y in taylor and partial
// use taylor both for parameter and variable values
reverse_mulpv_op(
d, i_z+1, adr, taylor, cap_order, taylor, nc_partial, partial
);
// z_0 = log(x)
// x is a parameter
}
// --------------------------- Powvp -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = PowvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_pow_op
*/
template <class Base>
void forward_powvp_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowvpOp) - 1
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_0 = log(x)
forward_log_op(p, q, i_z, size_t(arg[0]), cap_order, taylor);
// z_1 = y * z_0
addr_t adr[2];
adr[0] = arg[1];
adr[1] = addr_t( i_z );
forward_mulpv_op(p, q, i_z+1, adr, parameter, cap_order, taylor);
// z_2 = exp(z_1)
// zero order case exactly same as Base type operation
if( p == 0 )
{ Base* z_2 = taylor + (i_z+2) * cap_order;
Base* x = taylor + size_t(arg[0]) * cap_order;
Base y = parameter[ arg[1] ];
z_2[0] = pow(x[0], y);
p++;
}
if( p <= q )
forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Multiple directions forward mode Taylor coefficients for op = PowvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_pow_op_dir
*/
template <class Base>
void forward_powvp_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // 2 = NumRes(PowvpOp) - 1
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_0 = log(x)
forward_log_op_dir(q, r, i_z, size_t(arg[0]), cap_order, taylor);
// z_1 = y * z_0
addr_t adr[2];
adr[0] = arg[1];
adr[1] = addr_t( i_z );
forward_mulpv_op_dir(q, r, i_z+1, adr, parameter, cap_order, taylor);
// z_2 = exp(z_1)
forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor);
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = PowvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_pow_op_0
*/
template <class Base>
void forward_powvp_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowvpOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 );
// Paraemter value
Base y = parameter[ arg[1] ];
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z_0 = taylor + i_z * cap_order;
Base* z_1 = z_0 + cap_order;
Base* z_2 = z_1 + cap_order;
// z_0 = log(x)
z_0[0] = log(x[0]);
// z_1 = z_0 * y
z_1[0] = z_0[0] * y;
// z_2 = exp(z_1)
// zero order case exactly same as Base type operation
z_2[0] = pow(x[0], y);
}
/*!
Compute reverse mode partial derivative for result of op = PowvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = pow(x, y)
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::reverse_pow_op
*/
template <class Base>
void reverse_powvp_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// convert from final result to first result
i_z -= 2; // NumRes(PowvpOp) - 1;
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
CPPAD_ASSERT_UNKNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i_z
);
// z_2 = exp(z_1)
reverse_exp_op(
d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial
);
// z_1 = y * z_0
addr_t adr[2];
adr[0] = arg[1];
adr[1] = addr_t( i_z );
reverse_mulpv_op(
d, i_z+1, adr, parameter, cap_order, taylor, nc_partial, partial
);
// z_0 = log(x)
reverse_log_op(
d, i_z, size_t(arg[0]), cap_order, taylor, nc_partial, partial
);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,147 @@
# ifndef CPPAD_LOCAL_PRINT_OP_HPP
# define CPPAD_LOCAL_PRINT_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
Print operation for parameters; i.e., op = PriOp.
The C++ source code corresponding to this operation is
\verbatim
f.Forward(0, x)
PrintFor(before, var)
PrintFor(pos, before, var, after)
\endverbatim
The PrintFor call puts the print operation on the tape
and the print occurs during the zero order forward mode computation.
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< Base > and computations by this routine are done using type
Base .
\param s_out
the results are printed on this output stream.
\param arg
arg[0] & 1
\n
If this is zero, pos is a parameter. Otherwise it is a variable.
\n
arg[0] & 2
\n
If this is zero, var is a parameter. Otherwise it is a variable.
\n
\n
arg[1]
\n
If pos is a parameter, <code>parameter[arg[1]]</code> is its value.
Othwise <code>taylor[ size_t(arg[1]) * cap_order + 0 ]</code> is the zero
order Taylor coefficient for pos.
\n
\n
arg[2]
\n
index of the text to be printed before var
if pos is not a positive value.
\n
\n
arg[3]
\n
If var is a parameter, <code>parameter[arg[3]]</code> is its value.
Othwise <code>taylor[ size_t(arg[3]) * cap_order + 0 ]</code> is the zero
order Taylor coefficient for var.
\n
\n
arg[4]
\n
index of the text to be printed after var
if pos is not a positive value.
\param num_text
is the total number of text characters on the tape
(only used for error checking).
\param text
\b Input: <code>text[arg[1]]</code> is the first character of the text
that will be printed. All the characters from there to (but not including)
the first '\\0' are printed.
\param num_par
is the total number of values in the parameter vector
\param parameter
Contains the value of parameters.
\param cap_order
number of colums in the matrix containing all the Taylor coefficients.
\param taylor
Contains the value of variables.
\par Checked Assertions:
\li NumArg(PriOp) == 5
\li NumRes(PriOp) == 0
\li text != nullptr
\li arg[1] < num_text
\li if pos is a parameter, arg[1] < num_par
\li if var is a parameter, arg[3] < num_par
*/
template <class Base>
void forward_pri_0(
std::ostream& s_out ,
const addr_t* arg ,
size_t num_text ,
const char* text ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor )
{ Base pos, var;
const char* before;
const char* after;
CPPAD_ASSERT_NARG_NRES(PriOp, 5, 0);
// pos
if( arg[0] & 1 )
{ pos = taylor[ size_t(arg[1]) * cap_order + 0 ];
}
else
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
pos = parameter[ arg[1] ];
}
// before
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_text );
before = text + arg[2];
// var
if( arg[0] & 2 )
{ var = taylor[ size_t(arg[3]) * cap_order + 0 ];
}
else
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par );
var = parameter[ arg[3] ];
}
// after
CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < num_text );
after = text + arg[4];
if( ! GreaterThanZero( pos ) )
s_out << before << var << after;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
# ifndef CPPAD_LOCAL_RECORD_COMP_OP_HPP
# define CPPAD_LOCAL_RECORD_COMP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/record/recorder.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
$begin recorder_put_comp_op$$
$spell
rel
aleft
eq
le
lt
var
dyn
taddr
$$
$section Put Compare Operators in Recording$$
$head Syntax$$
$icode%rec%.put_comp_%rel%( %aleft%, %aright%, %result%)
%$$
$subhead rel$$
The text $icode rel$$ in the function name above
is $code eq$$ (for equals),
$code le$$ (for less than or equal), or
$code lt$$ (for less than).
$head Prototype$$
$srcthisfile%
0%// BEGIN_COMP_EQ%// END_COMP_EQ%1
%$$
The other prototypes for the functions $code comp_le$$ and $code comp_lt$$
are same except for the function name.
$head var_left$$
is true if the left operand is a variable.
$head var_right$$
is true if the right operand is a variable.
$head dyn_left$$
is true if the left operand is a dynamic parameter.
$head dyn_right$$
is true if the right operand is a dynamic parameter.
$head aleft$$
is the compare operator left operand.
$head aright$$
is the compare operator right operand.
$head taddr_$$
The values $icode%aleft.taddr_%$$ and $icode%aright%.taddr_%$$
are the proper address for dynamic parameters and variables
and does not matter for constants.
$head value_$$
The values $icode%aleft.value_%$$ and $icode%aright%.value_%$$
are the proper address for constants and does not matter
for variables and dynamic parameters.
$head result$$
This is the result for this comparison corresponding to this
recording (sequence of operations).
$end
*/
// BEGIN_COMP_EQ
template <class Base>
void recorder<Base>::comp_eq(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result )
// END_COMP_EQ
{ if( var_left )
{ if( var_right )
{ // variable == variable
PutArg(aleft.taddr_, aright.taddr_);
if( result )
PutOp(EqvvOp);
else
PutOp(NevvOp);
}
else
{ // variable == parameter
addr_t p = aright.taddr_;
if( ! dyn_right )
p = put_con_par(aright.value_);
PutArg(p, aleft.taddr_);
if( result )
PutOp(EqpvOp);
else
PutOp(NepvOp);
}
}
else if ( var_right )
{ // parameter == variable
addr_t p = aleft.taddr_;
if( ! dyn_left )
p = put_con_par(aleft.value_);
PutArg(p, aright.taddr_);
if( result )
PutOp(EqpvOp);
else
PutOp(NepvOp);
}
else if( dyn_left | dyn_right )
{ // parameter == parameter
addr_t arg0 = aleft.taddr_;
addr_t arg1 = aright.taddr_;
if( ! dyn_left )
arg0 = put_con_par(aleft.value_);
if( ! dyn_right )
arg1 = put_con_par(aright.value_);
//
PutArg(arg0, arg1);
if( result )
PutOp(EqppOp);
else
PutOp(NeppOp);
}
}
// ---------------------------------------------------------------------------
// comp_le
template <class Base>
void recorder<Base>::comp_le(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result )
{
if( var_left )
{ if( var_right )
{ // variable <= variable
if( result )
{ PutOp(LevvOp);
PutArg(aleft.taddr_, aright.taddr_);
}
else
{ PutOp(LtvvOp);
PutArg(aright.taddr_, aleft.taddr_);
}
}
else
{ // variable <= parameter
addr_t p = aright.taddr_;
if( ! dyn_right )
p = put_con_par(aright.value_);
if( result )
{ PutOp(LevpOp);
PutArg(aleft.taddr_, p);
}
else
{ PutOp(LtpvOp);
PutArg(p, aleft.taddr_);
}
}
}
else if ( var_right )
{ // parameter <= variable
addr_t p = aleft.taddr_;
if( ! dyn_left )
p = put_con_par(aleft.value_);
if( result )
{ PutOp(LepvOp);
PutArg(p, aright.taddr_);
}
else
{ PutOp(LtvpOp);
PutArg(aright.taddr_, p);
}
}
else if( dyn_left | dyn_right )
{ // parameter <= parameter
addr_t arg0 = aleft.taddr_;
addr_t arg1 = aright.taddr_;
if( ! dyn_left )
arg0 = put_con_par(aleft.value_);
if( ! dyn_right )
arg1 = put_con_par(aright.value_);
//
if( result )
{ PutOp(LeppOp);
PutArg(arg0, arg1);
}
else
{ PutOp(LtppOp);
PutArg(arg1, arg0);
}
}
}
// --------------------------------------------------------------------------
// comp_lt
template <class Base>
void recorder<Base>::comp_lt(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result )
{
if( var_left )
{ if( var_right )
{ // variable < variable
if( result )
{ PutOp(LtvvOp);
PutArg(aleft.taddr_, aright.taddr_);
}
else
{ PutOp(LevvOp);
PutArg(aright.taddr_, aleft.taddr_);
}
}
else
{ // variable < parameter
addr_t p = aright.taddr_;
if( ! dyn_right )
p = put_con_par(aright.value_);
if( result )
{ PutOp(LtvpOp);
PutArg(aleft.taddr_, p);
}
else
{ PutOp(LepvOp);
PutArg(p, aleft.taddr_);
}
}
}
else if ( var_right )
{ // parameter < variable
addr_t p = aleft.taddr_;
if( ! dyn_left )
p = put_con_par(aleft.value_);
if( result )
{ PutOp(LtpvOp);
PutArg(p, aright.taddr_);
}
else
{ PutOp(LevpOp);
PutArg(aright.taddr_, p);
}
}
else if( dyn_left | dyn_right )
{ // parameter < parameter
addr_t arg0 = aleft.taddr_;
addr_t arg1 = aright.taddr_;
if( ! dyn_left )
arg0 = put_con_par(aleft.value_);
if( ! dyn_right )
arg1 = put_con_par(aright.value_);
//
if( result )
{ PutOp(LtppOp);
PutArg(arg0, arg1);
}
else
{ PutOp(LeppOp);
PutArg(arg1, arg0);
}
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,176 @@
# ifndef CPPAD_LOCAL_RECORD_COND_EXP_HPP
# define CPPAD_LOCAL_RECORD_COND_EXP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/record/recorder.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
$begin recorder_cond_exp$$
$spell
cond_exp
ptr
$$
$section Record a Variable or Dynamic Parameter Conditional Expression$$
$head Syntax$$
$icode%rec%.cond_exp(
%tape_id%, %cop%, %result%, %left%, %right%, %if_true%, %if_false%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_COND_EXP%// END_COND_EXP%1
%$$
$head tape_id$$
identifier for the tape that this operation is being recorded on.
Passing tape_id avoids having to call tape_ptr() in case where
left, right, if_true, and if_false are all be constant at this AD level
(but left and right are not identically constant).
$head cop$$
Which $cref/comparison operator/base_cond_exp/CompareOp/$$;
i.e., <, <=, ==, >=, >, or !=.
$head result$$
is the result for this operation conditional expression.
On input, $icode%result%.value_%$$ is the proper value and
the other fields do not matter.
Upon return, the other fields have been set to their proper values.
It is an error to call this routine when all the arguments are constants; i.e.,
when the result is a constant.
$head left$$
value of the left operand in the comparison.
If $icode%left%.tape_id_%$$ is not zero it must equal $icode tape_id$$.
$head right$$
value of the right operand in the comparison.
If $icode%right%.tape_id_%$$ is not zero it must equal $icode tape_id$$.
$head if_true$$
value of the result if the comparison value is true.
If $icode%if_true%.tape_id_%$$ is not zero it must equal $icode tape_id$$.
$head if_false$$
value of the result if the comparison value is false.
If $icode%if_false%.tape_id_%$$ is not zero it must equal $icode tape_id$$.
$end
*/
// BEGIN_COND_EXP
template <class Base>
void recorder<Base>::cond_exp(
tape_id_t tape_id ,
enum CompareOp cop ,
AD<Base> &result ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &if_true ,
const AD<Base> &if_false )
// END_COND_EXP
{ // check for invalid tape_id
CPPAD_ASSERT_UNKNOWN( tape_id != 0 );
// arg[0] = cop
addr_t arg0 = addr_t( cop );
// arg[1] = base 2 represenation of the value
// [Var(left), Var(right), Var(if_true), Var(if_false)]
addr_t arg1 = 0;
// arg[2] = left address
// set first bit in arg1
addr_t arg2 = left.taddr_;
if( Constant(left) )
arg2 = put_con_par(left.value_);
else
{ CPPAD_ASSERT_KNOWN( tape_id == left.tape_id_ ,
"CondExpRel: arguments are variables or dynamics for different thread"
);
if(left.ad_type_ != dynamic_enum)
arg1 += 1;
}
// arg[3] = right address
// set second bit in arg1
addr_t arg3 = right.taddr_;
if( Constant(right) )
arg3 = put_con_par(right.value_);
else
{ CPPAD_ASSERT_KNOWN( tape_id == right.tape_id_ ,
"CondExpRel: arguments are variables or dynamics for different thread"
);
if(right.ad_type_ != dynamic_enum)
arg1 += 2;
}
// arg[4] = if_true address
// set third bit in arg1
addr_t arg4 = if_true.taddr_;
if( Constant(if_true) )
arg4 = put_con_par(if_true.value_);
else
{ CPPAD_ASSERT_KNOWN( tape_id == if_true.tape_id_ ,
"CondExpRel: arguments are variables or dynamics for different thread"
);
if(if_true.ad_type_ != dynamic_enum)
arg1 += 4;
}
// arg[5] = if_false address
// set fourth bit in arg1
addr_t arg5 = if_false.taddr_;
if( Constant(if_false) )
arg5 = put_con_par(if_false.value_);
else
{ CPPAD_ASSERT_KNOWN( tape_id == if_false.tape_id_ ,
"CondExpRel: arguments are variables or dynamics for different thread"
);
if(if_false.ad_type_ != dynamic_enum)
arg1 += 8;
}
if( arg1 == 0 )
{ // none of the arguments are variables, record cond_exp_dyn
// put the result at the end of the parameter vector as dynamic
// put_dyn_cond_exp(par, cop, left, right, if_true, if_false)
result.taddr_ = put_dyn_cond_exp(
result.value_, CompareOp(arg0), arg2, arg3, arg4, arg5
);
result.ad_type_ = dynamic_enum;
result.tape_id_ = tape_id;
// check that result is a dynamic parameter
CPPAD_ASSERT_UNKNOWN( Dynamic(result) );
}
else
{ CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 );
CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 );
// put operator in tape
result.taddr_ = PutOp(CExpOp);
PutArg(arg0, arg1, arg2, arg3, arg4, arg5);
// make result a variable
CPPAD_ASSERT_UNKNOWN( result.ad_type_ == constant_enum );
result.ad_type_ = variable_enum;
result.tape_id_ = tape_id;
// check that result is a variable
CPPAD_ASSERT_UNKNOWN( Variable(result) );
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,169 @@
# ifndef CPPAD_LOCAL_RECORD_PUT_DYN_ATOMIC_HPP
# define CPPAD_LOCAL_RECORD_PUT_DYN_ATOMIC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/record/recorder.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
$begin recorder_put_dyn_atomic$$
$spell
ptr
dyn
enum
taddr
$$
$section Put a Dynamic Parameter Atomic Call Operator in Recording$$
$head Syntax$$
$icode%rec%.put_dyn_atomic(
%tape_id%, %atomic_index%, %type_x%, %type_y%, %ax%, %ay%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PUT_DYN_ATOMIC%// END_PROTOTYPE%1
%$$
$head tape_id$$
identifies the tape that this recording corresponds to.
This is zero if and only if there is no tape for this recording; i.e.
$codei%AD<%Base%>.tape_ptr()%$$ is null.
$head atomic_index$$
is the $cref atomic_index$$ for this atomic function.
$head type_x$$
is the $cref ad_type_enum$$ for each of the atomic function arguments.
$head type_y$$
is the $code ad_type_enum$$ for each of the atomic function results.
$head ax$$
is the atomic function argument vector for this call.
$subhead value_$$
The value $icode%ax%[%j%].value_%$$ is the proper value for
parameters and does not matter for variables.
$subhead taddr_$$
The value $icode%ax%[%j%].taddr_%$$ is the proper address for
dynamic parameters and does not matter for constants or variables.
$head ay$$
is the atomic function result vector for this call.
$subhead Input$$
On input, $icode%ay%[%j%].value_%$$ has the proper value for parameters
(result for the atomic function).
$subhead Output$$
Upon return, if the $th i$$ result is a dynamic parameter,
$codei%
%ay%[%i%].ad_type_ = dynamic_enum
%ay%[%i%].tape_id_ = %tape_id%
%ay%[%i%].taddr_ = %p_index%
%$$
where $icode p_index$$ is the index of this dynamic parameter
in the vector of all parameters.
$end
*/
// BEGIN_PUT_DYN_ATOMIC
template <class Base> template <class VectorAD>
void recorder<Base>::put_dyn_atomic(
tape_id_t tape_id ,
size_t atomic_index ,
const vector<ad_type_enum>& type_x ,
const vector<ad_type_enum>& type_y ,
const VectorAD& ax ,
VectorAD& ay )
// END_PROTOTYPE
{ CPPAD_ASSERT_UNKNOWN(
(tape_id == 0) == (AD<Base>::tape_ptr() == nullptr)
);
CPPAD_ASSERT_UNKNOWN( ax.size() == type_x.size() );
CPPAD_ASSERT_UNKNOWN( ay.size() == type_y.size() );
size_t n = ax.size();
size_t m = ay.size();
size_t num_dyn = 0;
for(size_t i = 0; i < m; ++i)
if( type_y[i] == dynamic_enum )
++num_dyn;
CPPAD_ASSERT_UNKNOWN( num_dyn > 0 );
//
dyn_par_arg_.push_back( addr_t(atomic_index )); // arg[0] = atomic_index
dyn_par_arg_.push_back( addr_t( n ) ); // arg[1] = n
dyn_par_arg_.push_back( addr_t( m ) ); // arg[2] = m
dyn_par_arg_.push_back( addr_t( num_dyn ) ); // arg[3] = num_dyn
// arg[4 + j] for j = 0, ... , n-1
for(size_t j = 0; j < n; ++j)
{ addr_t arg = 0;
switch( type_x[j] )
{ case constant_enum:
arg = put_con_par( ax[j].value_ );
break;
case dynamic_enum:
arg = ax[j].taddr_;
break;
case variable_enum:
arg = 0; // phantom parameter index
CPPAD_ASSERT_UNKNOWN( isnan( all_par_vec_[arg] ) )
break;
default:
arg = 0;
CPPAD_ASSERT_UNKNOWN( false );
}
dyn_par_arg_.push_back( arg ); // arg[4 + j]
}
// arg[4 + n + i] for i = 0, ... , m-1
bool first_dynamic_result = true;
for(size_t i = 0; i < m; ++i)
{ addr_t arg;
switch( type_y[i] )
{ case constant_enum:
arg = 0; // phantom parameter index
break;
case dynamic_enum:
// one operator for each dynamic parameter result
// so number of operators is equal number of dynamic parameters
if( first_dynamic_result )
arg = put_dyn_par(ay[i].value_, atom_dyn ); // atom_dyn
else
arg = put_dyn_par(ay[i].value_, result_dyn ); // result_dyn
ay[i].ad_type_ = dynamic_enum;
ay[i].taddr_ = arg;
ay[i].tape_id_ = tape_id;
first_dynamic_result = false;
break;
case variable_enum:
arg = 0; // phantom parameter (has value nan)
break;
default:
arg = 0;
CPPAD_ASSERT_UNKNOWN( false );
}
dyn_par_arg_.push_back( arg ); // arg[4 + n + i]
}
dyn_par_arg_.push_back( addr_t(5 + n + m) ); // arg[4 + n + m]
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,150 @@
# ifndef CPPAD_LOCAL_RECORD_PUT_VAR_ATOMIC_HPP
# define CPPAD_LOCAL_RECORD_PUT_VAR_ATOMIC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/record/recorder.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
$begin recorder_put_var_atomic$$
$spell
ptr
var
enum
taddr
$$
$section Put a Variable Atomic Call Operator in Recording$$
$head Syntax$$
$icode%rec%.put_var_atomic(
%tape_id%, %atomic_index%, %type_x%, %type_y%, %ax%, %ay%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PUT_VAR_ATOMIC%// END_PROTOTYPE%1
%$$
$head tape_id$$
identifies the tape that this recording corresponds to.
This is zero if and only if there is no tape for this recording; i.e.
$codei%AD<%Base%>.tape_ptr()%$$ is null.
$head atomic_index$$
is the $cref atomic_index$$ for this atomic function.
$head type_x$$
is the $cref ad_type_enum$$ for each of the atomic function arguments.
$head type_y$$
is the $code ad_type_enum$$ for each of the atomic function results.
$head ax$$
is the atomic function argument vector for this call.
$subhead value_$$
The value $icode%ax%[%j%].value_%$$ is the proper value for all arguments.
$subhead taddr_$$
The value $icode%ax%[%j%].taddr_%$$ is the proper address
for dynamic parameters and variables and does not matter for constants.
$head ay$$
is the atomic function result vector for this call.
$subhead Input$$
On input, $icode%ay%[%i%]%$$ has all the correct values for
parameters and does not matter for variables.
$subhead Output$$
Upon return, if the $th i$$ result is a variable,
$codei%
%ay%[%i%].ad_type_ = dynamic_enum
%ay%[%i%].tape_id_ = %tape_id%
%ay%[%i%].taddr_ = %v_index%
%$$
where $icode v_index$$ is the index of this variable
in the arrays containing all the variables.
$end
*/
// BEGIN_PUT_VAR_ATOMIC
template <class Base> template <class VectorAD>
void recorder<Base>::put_var_atomic(
tape_id_t tape_id ,
size_t atomic_index ,
const vector<ad_type_enum>& type_x ,
const vector<ad_type_enum>& type_y ,
const VectorAD& ax ,
VectorAD& ay )
// END_PROTOTYPE
{ CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >=
std::max( std::max(atomic_index, ax.size() ), ay.size() ),
"atomic_three: cppad_tape_addr_type maximum not large enough"
);
CPPAD_ASSERT_UNKNOWN(
(tape_id == 0) == (AD<Base>::tape_ptr() == nullptr)
);
// Operator that marks beginning of this atomic operation
CPPAD_ASSERT_NARG_NRES(local::AFunOp, 4, 0 );
addr_t old_id = 0; // used by atomic_two to implement atomic_one interface
size_t n = ax.size();
size_t m = ay.size();
PutArg(addr_t(atomic_index), old_id, addr_t(n), addr_t(m));
PutOp(local::AFunOp);
// Now put n operators, one for each element of argument vector
CPPAD_ASSERT_NARG_NRES(local::FunavOp, 1, 0 );
CPPAD_ASSERT_NARG_NRES(local::FunapOp, 1, 0 );
for(size_t j = 0; j < n; j++)
{ if( type_x[j] == variable_enum )
{ // information for an argument that is a variable
PutArg(ax[j].taddr_);
PutOp(local::FunavOp);
}
else
{ // information for an argument that is parameter
addr_t par = ax[j].taddr_;
if( type_x[j] == constant_enum )
par = put_con_par(ax[j].value_);
PutArg(par);
PutOp(local::FunapOp);
}
}
// Now put m operators, one for each element of result vector
CPPAD_ASSERT_NARG_NRES(local::FunrvOp, 0, 1);
CPPAD_ASSERT_NARG_NRES(local::FunrpOp, 1, 0);
for(size_t i = 0; i < m; i++)
{ if( type_y[i] == variable_enum )
{ ay[i].taddr_ = PutOp(local::FunrvOp);
ay[i].tape_id_ = tape_id;
ay[i].ad_type_ = variable_enum;
}
else
{ addr_t par = ay[i].taddr_;
if( type_y[i] == constant_enum )
par = put_con_par( ay[i].value_ );
PutArg(par);
PutOp(local::FunrpOp);
}
}
// Put a duplicate AFunOp at end of AFunOp sequence
PutArg(addr_t(atomic_index), old_id, addr_t(n), addr_t(m));
PutOp(local::AFunOp);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,130 @@
# ifndef CPPAD_LOCAL_RECORD_PUT_VAR_VECAD_HPP
# define CPPAD_LOCAL_RECORD_PUT_VAR_VECAD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/record/recorder.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
------------------------------------------------------------------------------
$begin put_var_vecad_ind$$
$spell
Vec
var
vecad
ind
taddr
$$
$section Add One Index to End of Combined Variable VecAD Vector$$
$head Syntax$$
$icode%offset% = %rec%.put_var_vecad_ind(%vec_ind%)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PUT_VAR_VECAD_IND%// END_PUT_VAR_VECAD_IND%1
%$$
$head Purpose$$
For each variable VecAD vector, this routine is used to store the length
of the vector followed by the parameter index corresponding to initial
value in the vector; i.e., the values just before it changed from a parameter
to a variable.
$head vec_ind$$
is the index to be placed at the end of the combined vector of VecAD indices.
$head offset$$
is the index in the combined variable VecAD vector
where the value $icode vec_ind$$ is stored.
This index starts at zero after the recorder default constructor and
increments by one for each call to put_var_vecad_ind.
$end
*/
// BEGIN_PUT_VAR_VECAD_IND
template <class Base>
addr_t recorder<Base>::put_var_vecad_ind(addr_t vec_ind)
// END_PUT_VAR_VECAD_IND
{ size_t offset = all_var_vecad_ind_.size();
all_var_vecad_ind_.push_back( vec_ind );
CPPAD_ASSERT_KNOWN(
size_t( addr_t( offset ) ) == offset,
"cppad_tape_addr_type cannot support needed index range"
);
return static_cast<addr_t>( offset );
}
/*
------------------------------------------------------------------------------
$begin recorder_put_var_vecad$$
$spell
Vec
var
vecad
taddr
$$
$section Tape Initialization for a Variable VecAD Object$$
$head Syntax$$
$icode%offset% = %rec%.put_var_vecad(%length%, %taddr%)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_PUT_VAR_VECAD_VEC%// END_PUT_VAR_VECAD_VEC%1
%$$
$head Usage$$
This routine should be called once for each variable VecAD object just
before it changes from a parameter to a variable.
$head length$$
is the size of the VecAD object.
$head taddr$$
vector of parameter indices corresponding to the value of this VecAD vector
just before it becomes a variable.
$head offset$$
index of the start of this VecAD vector in the combined variable VecAD vector.
The value corresponding to $icode offset$$ is the length of this VecAD vector.
There are $icode length$$ more indices following the length.
These values are the parameter indices.
$end
*/
// BEGIN_PUT_VAR_VECAD_VEC
template <class Base>
addr_t recorder<Base>::put_var_vecad(
size_t length ,
const pod_vector<addr_t>& taddr )
// END_PUT_VAR_VECAD_VEC
{ CPPAD_ASSERT_UNKNOWN( length > 0 );
CPPAD_ASSERT_UNKNOWN( length == taddr.size() );
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= length,
"A VecAD vector length is too large fur cppad_tape_addr_type"
);
// store the length in VecInd
addr_t start = put_var_vecad_ind( addr_t(length) );
// store indices of the values in VecInd
for(size_t i = 0; i < length; i++)
put_var_vecad_ind( taddr[i] );
// return the taddr of the length (where the vector starts)
return start;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,848 @@
# ifndef CPPAD_LOCAL_RECORD_RECORDER_HPP
# define CPPAD_LOCAL_RECORD_RECORDER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/core/hash_code.hpp>
# include <cppad/local/pod_vector.hpp>
# include <cppad/core/ad_type.hpp>
// ----------------------------------------------------------------------------
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file recorder.hpp
File used to define the recorder class.
*/
/*!
Class used to store an operation sequence while it is being recorded
(the operation sequence is copied to the player class for playback).
\tparam Base
This is an AD< Base > operation sequence recording; i.e.,
it records operations of type AD< Base >.
*/
template <class Base>
class recorder {
friend class player<Base>;
private:
/// are comparison operators being recorded
bool record_compare_;
/// operator index at which to abort recording with an error
/// (do not abort when zero)
size_t abort_op_index_;
/// Number of variables in the recording.
size_t num_var_rec_;
/// Number of dynamic parameters in the recording
size_t num_dynamic_ind_;
/// Number vecad load operations (LdpOp or LdvOp) currently in recording.
size_t num_var_load_rec_;
/// The operators in the recording.
pod_vector<opcode_t> op_vec_;
/// The VecAD indices in the recording.
pod_vector<addr_t> all_dyn_vecad_ind_;
pod_vector<addr_t> all_var_vecad_ind_;
/// The argument indices in the recording
pod_vector<addr_t> arg_vec_;
/// Character strings ('\\0' terminated) in the recording.
pod_vector<char> text_vec_;
/// Hash table to reduced number of duplicate parameters in all_par_vec_
pod_vector<addr_t> par_hash_table_;
/// Vector containing all the parameters in the recording.
/// Use pod_vector_maybe because Base may not be plain old data.
pod_vector_maybe<Base> all_par_vec_;
/// Which elements of all_par_vec_ are dynamic parameters
/// (same size are all_par_vec_)
pod_vector<bool> dyn_par_is_;
/// operators for just the dynamic parameters in all_par_vec_
pod_vector<opcode_t> dyn_par_op_;
/// arguments for the dynamic parameter operators
pod_vector<addr_t> dyn_par_arg_;
// ---------------------- Public Functions -----------------------------------
public:
/// Default constructor
recorder(void) :
num_var_rec_(0) ,
num_dynamic_ind_(0) ,
num_var_load_rec_(0) ,
par_hash_table_( CPPAD_HASH_TABLE_SIZE )
{ record_compare_ = true;
abort_op_index_ = 0;
// It does not matter if unitialized hash codes match but this
// initilaization is here to avoid valgrind warnings.
void* ptr = static_cast<void*>( par_hash_table_.data() );
int value = 0;
size_t num = CPPAD_HASH_TABLE_SIZE * sizeof(addr_t);
std::memset(ptr, value, num);
}
/// Set record_compare option
void set_record_compare(bool record_compare)
{ record_compare_ = record_compare; }
/// Set the abort index
void set_abort_op_index(size_t abort_op_index)
{ abort_op_index_ = abort_op_index; }
/// Set number of independent dynamic parameters
void set_num_dynamic_ind(size_t num_dynamic_ind)
{ num_dynamic_ind_ = num_dynamic_ind; }
/// Get record_compare option
bool get_record_compare(void) const
{ return record_compare_; }
/// Get the abort_op_index
size_t get_abort_op_index(void) const
{ return abort_op_index_; }
/// Get number of independent dynamic parameters
size_t get_num_dynamic_ind(void) const
{ return num_dynamic_ind_; }
/// Destructor
~recorder(void)
{ }
/// Put a dynamic parameter in all_par_vec_.
addr_t put_dyn_par(
const Base &par, op_code_dyn op
);
addr_t put_dyn_par(
const Base &par, op_code_dyn op, addr_t arg0
);
addr_t put_dyn_par(
const Base &par, op_code_dyn op, addr_t arg0, addr_t arg1
);
addr_t put_dyn_cond_exp(
const Base &par, CompareOp cop,
addr_t left, addr_t right, addr_t if_true, addr_t if_false
);
/// Put a vector of dynamic parameter arguments at end of tape
void put_dyn_arg_vec(const pod_vector<addr_t>& arg);
/// Put next operator in the operation sequence.
addr_t PutOp(OpCode op);
/// Put a vecad load operator in the operation sequence (special case)
addr_t PutLoadOp(OpCode op);
// VecAD operations
addr_t put_var_vecad_ind(addr_t vec_ind);
addr_t put_var_vecad(size_t length, const pod_vector<addr_t>& taddr);
/// Find or add a constant parameter to the vector of all parameters.
addr_t put_con_par(const Base &par);
/// Put one operation argument index in the recording
void PutArg(addr_t arg0);
/// Put two operation argument index in the recording
void PutArg(addr_t arg0, addr_t arg1);
/// Put three operation argument index in the recording
void PutArg(addr_t arg0, addr_t arg1, addr_t arg2);
/// Put four operation argument index in the recording
void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3);
/// Put five operation argument index in the recording
void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
addr_t arg4);
/// Put six operation argument index in the recording
void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
addr_t arg4, addr_t arg5);
//
// put_dyn_atomic
template <class VectorAD>
void put_dyn_atomic(
tape_id_t tape_id ,
size_t atom_index ,
const vector<ad_type_enum>& type_x ,
const vector<ad_type_enum>& type_y ,
const VectorAD& ax ,
VectorAD& ay
);
//
// put_var_atomic
template <class VectorAD>
void put_var_atomic(
tape_id_t tape_id ,
size_t atom_index ,
const vector<ad_type_enum>& type_x ,
const vector<ad_type_enum>& type_y ,
const VectorAD& ax ,
VectorAD& ay
);
// Reserve space for a specified number of arguments
size_t ReserveArg(size_t n_arg);
// Replace an argument value
void ReplaceArg(size_t i_arg, addr_t value);
/// Put a character string in the text for this recording.
addr_t PutTxt(const char *text);
/// record a variable or dynamic parameter conditional expression
void cond_exp(
tape_id_t tape_id ,
enum CompareOp cop ,
AD<Base> &result ,
const AD<Base> &left ,
const AD<Base> &right ,
const AD<Base> &if_true ,
const AD<Base> &if_false
);
/// record a comparison operators for varialbes or just dynamic parameters
void comp_eq(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result
);
void comp_le(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result
);
void comp_lt(
bool var_left ,
bool var_right ,
bool dyn_left ,
bool dyn_right ,
const AD<Base>& aleft ,
const AD<Base>& aright ,
bool result
);
// -----------------------------------------------------------------------
// functions implemented here
/// Number of variables currently stored in the recording.
size_t num_var_rec(void) const
{ return num_var_rec_; }
/// Number LdpOp, LdvOp, and load_dyn operations currently in recording
size_t num_var_load_rec(void) const
{ return num_var_load_rec_; }
/// Number of operators currently stored in the recording.
size_t num_op_rec(void) const
{ return op_vec_.size(); }
/// current parameter vector
const pod_vector_maybe<Base>& all_par_vec(void) const
{ return all_par_vec_; }
/// Approximate amount of memory used by the recording
size_t Memory(void) const
{ return op_vec_.capacity() * sizeof(opcode_t)
+ all_dyn_vecad_ind_.capacity() * sizeof(addr_t)
+ all_var_vecad_ind_.capacity() * sizeof(addr_t)
+ arg_vec_.capacity() * sizeof(addr_t)
+ all_par_vec_.capacity() * sizeof(Base)
+ text_vec_.capacity() * sizeof(char);
}
};
/*!
Put next operator in the operation sequence.
This sets the op code for the next operation in this recording.
This call must be followed by putting the corresponding
\verbatim
NumArg(op)
\endverbatim
argument indices in the recording.
\param op
Is the op code corresponding to the the operation that is being
recorded (which must not be LdpOp or LdvOp).
\return
The return value is the index of the primary (last) variable
corresponding to the result of this operation.
The number of variables corresponding to the operation is given by
\verbatim
NumRes(op)
\endverbatim
With each call to PutOp or PutLoadOp,
the return index increases by the number of variables corresponding
to the call.
This index starts at zero after the default constructor.
*/
template <class Base>
addr_t recorder<Base>::PutOp(OpCode op)
{ size_t i = op_vec_.extend(1);
CPPAD_ASSERT_KNOWN(
(abort_op_index_ == 0) || (abort_op_index_ != i),
"Operator index equals abort_op_index in Independent"
);
op_vec_[i] = static_cast<opcode_t>(op);
CPPAD_ASSERT_UNKNOWN( op_vec_.size() == i + 1 );
CPPAD_ASSERT_UNKNOWN( (op != LdpOp) & (op != LdvOp) );
// first operator should be a BeginOp and NumRes( BeginOp ) > 0
num_var_rec_ += NumRes(op);
CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 );
// index of last variable corresponding to this operation
// (if NumRes(op) > 0)
CPPAD_ASSERT_KNOWN(
(size_t) std::numeric_limits<addr_t>::max() >= num_var_rec_ - 1,
"cppad_tape_addr_type maximum value has been exceeded"
)
return static_cast<addr_t>( num_var_rec_ - 1 );
}
/*!
Put next LdpOp or LdvOp operator in operation sequence (special cases).
This sets the op code for the next operation in this recording.
This call must be followed by putting the corresponding
\verbatim
NumArg(op)
\endverbatim
argument indices in the recording.
\param op
Is the op code corresponding to the the operation that is being
recorded (which must be LdpOp or LdvOp).
\return
The return value is the index of the primary (last) variable
corresponding to the result of this operation.
The number of variables corresponding to the operation is given by
\verbatim
NumRes(op)
\endverbatim
which must be one for this operation.
With each call to PutLoadOp or PutOp,
the return index increases by the number of variables corresponding
to this call to the call.
This index starts at zero after the default constructor.
\par num_var_load_rec()
The return value for <code>num_var_load_rec()</code>
increases by one after each call to this function.
*/
template <class Base>
addr_t recorder<Base>::PutLoadOp(OpCode op)
{ size_t i = op_vec_.extend(1);
CPPAD_ASSERT_KNOWN(
(abort_op_index_ == 0) || (abort_op_index_ != i),
"This is the abort operator index specified by "
"Independent(x, abort_op_index)."
);
op_vec_[i] = op;
CPPAD_ASSERT_UNKNOWN( op_vec_.size() == i + 1 );
CPPAD_ASSERT_UNKNOWN( (op == LdpOp) | (op == LdvOp) );
// first operator should be a BeginOp and NumRes( BeginOp ) > 0
num_var_rec_ += NumRes(op);
CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 );
// count this vecad load operation
num_var_load_rec_++;
// index of last variable corresponding to this operation
// (if NumRes(op) > 0)
CPPAD_ASSERT_KNOWN(
(size_t) std::numeric_limits<addr_t>::max() >= num_var_rec_ - 1,
"cppad_tape_addr_type maximum value has been exceeded"
)
return static_cast<addr_t>( num_var_rec_ - 1 );
}
/*!
Put a dynamic parameter at the end of the vector for all parameters.
\param par
is value of dynamic parameter to be placed at the end of the vector.
\param op
is the operator for this dynamic parameter.
There are no arguments to this operator, so numarg(op) == 0.
\return
is the index in all_par_vec_ corresponding to this dynamic parameter value.
*/
template <class Base>
addr_t recorder<Base>::put_dyn_par(const Base &par, op_code_dyn op)
{ // independent parameters come first
CPPAD_ASSERT_UNKNOWN(
op == ind_dyn || op == result_dyn || op == atom_dyn
);
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 0 );
all_par_vec_.push_back( par );
dyn_par_is_.push_back(true);
dyn_par_op_.push_back( opcode_t(op) );
return static_cast<addr_t>( all_par_vec_.size() - 1 );
}
/*!
Put a dynamic parameter at the end of the vector for all parameters.
\param par
is value of dynamic parameter to be placed at the end of the vector.
\param op
is the operator for this dynamic parameter.
There is one argument to this operator, so numarg(op) == 1.
\param arg0
this is the argument to the operator represented
as an index in the all_par_vec_ vector.
\return
is the index in all_par_vec_ corresponding to this dynamic parameter value.
*/
template <class Base>
addr_t recorder<Base>::put_dyn_par(
const Base &par, op_code_dyn op, addr_t arg0
)
{ // independent parameters come first
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 1 );
all_par_vec_.push_back( par );
dyn_par_is_.push_back(true);
dyn_par_op_.push_back( opcode_t(op) );
dyn_par_arg_.push_back(arg0);
return static_cast<addr_t>( all_par_vec_.size() - 1 );
}
/*!
Put a dynamic parameter at the end of the vector for all parameters.
\param par
is value of dynamic parameter to be placed at the end of the vector.
\param op
is the operator for this dynamic parameter.
There are two arguments to this operator, so numarg(op) == 2.
\param arg0
this is the first argument to the operator represented
as an index in the all_par_vec_ vector.
\param arg1
this is the second argument to the operator represented
as an index in the all_par_vec_ vector.
One of the two arguments must be a dynamic parameter.
\return
is the index in all_par_vec_ corresponding to this dynamic parameter value.
*/
template <class Base>
addr_t recorder<Base>::put_dyn_par(
const Base &par, op_code_dyn op, addr_t arg0, addr_t arg1
)
{ // independent parameters come first
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 2 );
all_par_vec_.push_back( par );
dyn_par_is_.push_back(true);
dyn_par_op_.push_back( opcode_t(op) );
dyn_par_arg_.push_back(arg0);
dyn_par_arg_.push_back(arg1);
return static_cast<addr_t>( all_par_vec_.size() - 1 );
}
/*!
Put a dynamic parameter, that is result of conditional expression,
at the end of the vector for all parameters.
\param par
is value of dynamic parameter to be placed at the end of the vector.
\param cop
is the operator comparison operator; i.e., Lt, Le, Eq, Ge, Gt, Ne.
\param left
is the left argument in conditional expression (which is a parameter).
\param right
is the right argument in conditional expression (which is a parameter).
\param if_true
is the if_true argument in conditional expression (which is a parameter).
\param if_false
is the if_false argument in conditional expression (which is a parameter).
\return
is the index in all_par_vec_ corresponding to this dynamic parameter value.
*/
template <class Base>
addr_t recorder<Base>::put_dyn_cond_exp(const Base &par, CompareOp cop,
addr_t left, addr_t right, addr_t if_true, addr_t if_false
)
{ // independent parameters come first
CPPAD_ASSERT_UNKNOWN( num_arg_dyn(cond_exp_dyn) == 5 );
addr_t ret = addr_t( all_par_vec_.size() );
all_par_vec_.push_back( par );
dyn_par_is_.push_back(true);
dyn_par_op_.push_back( opcode_t(cond_exp_dyn) );
dyn_par_arg_.push_back( addr_t(cop) );
dyn_par_arg_.push_back(left);
dyn_par_arg_.push_back(right);
dyn_par_arg_.push_back(if_true);
dyn_par_arg_.push_back(if_false);
return ret;
}
// ---------------------------------------------------------------------------
/*!
Puts a vector of arguments at the end of the current dynamic parameter tape
\param arg_vec [in]
is the vector of values to be added at the end of the tape.
*/
template <class Base>
void recorder<Base>::put_dyn_arg_vec(const pod_vector<addr_t>& arg_vec)
{ for(size_t i = 0; i < arg_vec.size(); ++i)
dyn_par_arg_.push_back( arg_vec[i] );
}
// ---------------------------------------------------------------------------
/*!
Find or add a constant parameter to the current vector of all parameters.
\param par
is the parameter to be found or placed in the vector of parameters.
\return
is the index in the parameter vector corresponding to this parameter value.
This value is not necessarily placed at the end of the vector
(because values that are identically equal may be reused).
*/
template <class Base>
addr_t recorder<Base>::put_con_par(const Base &par)
{
# ifndef NDEBUG
// index zero is used to signify that a value is not a parameter;
// i.e., it is a variable.
if( all_par_vec_.size() == 0 )
CPPAD_ASSERT_UNKNOWN( isnan(par) );
# endif
// ---------------------------------------------------------------------
// check for a match with a previous parameter
//
// get hash code for this value
size_t code = static_cast<size_t>( hash_code(par) );
// current index in all_par_vec_ corresponding to this hash code
size_t index = static_cast<size_t>( par_hash_table_[code] );
// check if the old parameter matches the new one
if( (0 < index) & (index < all_par_vec_.size()) )
{ if( ! dyn_par_is_[index] )
if( IdenticalEqualCon(all_par_vec_[index], par) )
return static_cast<addr_t>( index );
}
// ---------------------------------------------------------------------
// put paramerter in all_par_vec_ and replace hash entry for this codee
//
index = all_par_vec_.size();
all_par_vec_.push_back( par );
dyn_par_is_.push_back(false);
//
// change the hash table for this code to point to new value
par_hash_table_[code] = static_cast<addr_t>( index );
//
// return the parameter index
CPPAD_ASSERT_KNOWN(
static_cast<size_t>( std::numeric_limits<addr_t>::max() ) >= index,
"cppad_tape_addr_type maximum value has been exceeded"
)
return static_cast<addr_t>( index );
}
// -------------------------- PutArg --------------------------------------
/*!
Prototype for putting operation argument indices in the recording.
The following syntax
\verbatim
rec.PutArg(arg0)
rec.PutArg(arg0, arg1)
.
.
.
rec.PutArg(arg0, arg1, ..., arg5)
\endverbatim
places the values passed to PutArg at the current end of the
operation argument indices for the recording.
arg0 comes before arg1, etc.
The proper number of operation argument indices
corresponding to the operation code op is given by
\verbatim
NumArg(op)
\endverbatim
The number of the operation argument indices starts at zero
after the default constructor.
*/
inline void prototype_put_arg(void)
{ // This routine should not be called
CPPAD_ASSERT_UNKNOWN(false);
}
/*!
Put one operation argument index in the recording
\param arg0
The operation argument index
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0)
{
size_t i = arg_vec_.extend(1);
arg_vec_[i] = arg0;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
/*!
Put two operation argument index in the recording
\param arg0
First operation argument index.
\param arg1
Second operation argument index.
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
{
size_t i = arg_vec_.extend(2);
arg_vec_[i++] = arg0;
arg_vec_[i] = arg1;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
/*!
Put three operation argument index in the recording
\param arg0
First operation argument index.
\param arg1
Second operation argument index.
\param arg2
Third operation argument index.
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
{
size_t i = arg_vec_.extend(3);
arg_vec_[i++] = arg0;
arg_vec_[i++] = arg1;
arg_vec_[i] = arg2;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
/*!
Put four operation argument index in the recording
\param arg0
First operation argument index.
\param arg1
Second operation argument index.
\param arg2
Third operation argument index.
\param arg3
Fourth operation argument index.
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
addr_t arg3)
{
size_t i = arg_vec_.extend(4);
arg_vec_[i++] = arg0;
arg_vec_[i++] = arg1;
arg_vec_[i++] = arg2;
arg_vec_[i] = arg3;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
/*!
Put five operation argument index in the recording
\param arg0
First operation argument index.
\param arg1
Second operation argument index.
\param arg2
Third operation argument index.
\param arg3
Fourth operation argument index.
\param arg4
Fifth operation argument index.
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
addr_t arg3, addr_t arg4)
{
size_t i = arg_vec_.extend(5);
arg_vec_[i++] = arg0;
arg_vec_[i++] = arg1;
arg_vec_[i++] = arg2;
arg_vec_[i++] = arg3;
arg_vec_[i] = arg4;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
/*!
Put six operation argument index in the recording
\param arg0
First operation argument index.
\param arg1
Second operation argument index.
\param arg2
Third operation argument index.
\param arg3
Fourth operation argument index.
\param arg4
Fifth operation argument index.
\param arg5
Sixth operation argument index.
\copydetails prototype_put_arg
*/
template <class Base>
void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
addr_t arg3, addr_t arg4, addr_t arg5)
{
size_t i = arg_vec_.extend(6);
arg_vec_[i++] = arg0;
arg_vec_[i++] = arg1;
arg_vec_[i++] = arg2;
arg_vec_[i++] = arg3;
arg_vec_[i++] = arg4;
arg_vec_[i] = arg5;
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 );
}
// --------------------------------------------------------------------------
/*!
Reserve space for arguments, but delay placing values there.
\param n_arg
number of arguements to reserve space for
\return
is the index in the argument vector corresponding to the
first of the arguments being reserved.
*/
template <class Base>
size_t recorder<Base>::ReserveArg(size_t n_arg)
{
size_t i = arg_vec_.extend(n_arg);
CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + n_arg );
return i;
}
/*!
\brief
Replace an argument value in the recording
(intended to fill in reserved values).
\param i_arg
is the index, in argument vector, for the value that is replaced.
\param value
is the new value for the argument with the specified index.
*/
template <class Base>
void recorder<Base>::ReplaceArg(size_t i_arg, addr_t value)
{ arg_vec_[i_arg] = value; }
// --------------------------------------------------------------------------
/*!
Put a character string in the text for this recording.
\param text
is a '\\0' terminated character string that is to be put in the
vector of characters corresponding to this recording.
The terminator '\\0' will be included.
\return
is the offset with in the text vector for this recording at which
the character string starts.
*/
template <class Base>
addr_t recorder<Base>::PutTxt(const char *text)
{
// determine length of the text including terminating '\0'
size_t n = 0;
while( text[n] != '\0' )
n++;
CPPAD_ASSERT_UNKNOWN( n <= 1000 );
n++;
CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' );
// copy text including terminating '\0'
size_t i = text_vec_.extend(n);
size_t j;
for(j = 0; j < n; j++)
text_vec_[i + j] = text[j];
CPPAD_ASSERT_UNKNOWN( text_vec_.size() == i + n );
CPPAD_ASSERT_KNOWN(
size_t( std::numeric_limits<addr_t>::max() ) >= i,
"cppad_tape_addr_type maximum value has been exceeded"
);
//
return static_cast<addr_t>( i );
}
} } // END_CPPAD_LOCAL_NAMESPACE
// ----------------------------------------------------------------------------
// member function implementations
# include <cppad/local/record/put_var_vecad.hpp>
# include <cppad/local/record/put_dyn_atomic.hpp>
# include <cppad/local/record/put_var_atomic.hpp>
# include <cppad/local/record/cond_exp.hpp>
# include <cppad/local/record/comp_op.hpp>
# endif

View File

@@ -0,0 +1,25 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-----------------------------------------------------------------------------
$begin recorder$$
$section Recorder Class Documentation$$
$childtable%
include/cppad/local/record/put_var_vecad.hpp%
include/cppad/local/record/put_dyn_atomic.hpp%
include/cppad/local/record/put_var_atomic.hpp%
include/cppad/local/record/cond_exp.hpp%
include/cppad/local/record/comp_op.hpp
%$$
$end

View File

@@ -0,0 +1,66 @@
# ifndef CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP
# define CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cassert>
# include <cppad/configure.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file set_get_in_parallel.hpp
File used to set and get user in_parallel routine.
*/
/*!
Set and call the routine that determine if we are in parallel execution mode.
\return
value retuned by most recent setting for in_parallel_new.
If set is true,
or the most recent setting is nullptr (its initial value),
the return value is false.
Otherwise the function corresponding to the most recent setting
is called and its value returned by set_get_in_parallel.
\param in_parallel_new [in]
If set is false, in_parallel_new it is not used.
Otherwise, the current value of in_parallel_new becomes the
most recent setting for in_parallel_user.
\param set
If set is true, then parallel_new is becomes the most
recent setting for this set_get_in_parallel.
In this case, it is assumed that we are currently in sequential execution mode.
*/
static bool set_get_in_parallel(
bool (*in_parallel_new)(void) ,
bool set = false )
{ static bool (*in_parallel_user)(void) = nullptr;
if( set )
{ in_parallel_user = in_parallel_new;
// Doing a raw assert in this case because set_get_in_parallel is used
// by ErrorHandler and hence cannot use ErrorHandler.
// CPPAD_ASSERT_UNKNOWN( in_parallel_user() == false )
assert(in_parallel_user == nullptr || in_parallel_user() == false);
return false;
}
//
if( in_parallel_user == nullptr )
return false;
//
return in_parallel_user();
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,153 @@
# ifndef CPPAD_LOCAL_SIGN_OP_HPP
# define CPPAD_LOCAL_SIGN_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sign_op.hpp
Forward and reverse mode calculations for z = sign(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = SignOp.
The C++ source code corresponding to this operation is
\verbatim
z = sign(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_sign_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
if( p == 0 )
{ z[0] = sign(x[0]);
p++;
}
for(size_t j = p; j <= q; j++)
z[j] = Base(0.);
}
/*!
Multiple direction forward mode Taylor coefficient for op = SignOp.
The C++ source code corresponding to this operation is
\verbatim
z = sign(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_sign_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q - 1) * r + 1;
Base* z = taylor + i_z * num_taylor_per_var;
for(size_t ell = 0; ell < r; ell++)
z[m+ell] = Base(0.);
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = SignOp.
The C++ source code corresponding to this operation is
\verbatim
z = sign(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_sign_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base x0 = *(taylor + i_x * cap_order);
Base* z = taylor + i_z * cap_order;
z[0] = sign(x0);
}
/*!
Compute reverse mode partial derivatives for result of op = SignOp.
The C++ source code corresponding to this operation is
\verbatim
z = sign(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_sign_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// nothing to do because partials of sign are zero
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,240 @@
# ifndef CPPAD_LOCAL_SIN_OP_HPP
# define CPPAD_LOCAL_SIN_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sin_op.hpp
Forward and reverse mode calculations for z = sin(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = SinOp.
The C++ source code corresponding to this operation is
\verbatim
z = sin(x)
\endverbatim
The auxillary result is
\verbatim
y = cos(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_sin_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* s = taylor + i_z * cap_order;
Base* c = s - cap_order;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op.
// (except that there is a sign difference for the hyperbolic case).
size_t k;
if( p == 0 )
{ s[0] = sin( x[0] );
c[0] = cos( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
s[j] = Base(0.0);
c[j] = Base(0.0);
for(k = 1; k <= j; k++)
{ s[j] += Base(double(k)) * x[k] * c[j-k];
c[j] -= Base(double(k)) * x[k] * s[j-k];
}
s[j] /= Base(double(j));
c[j] /= Base(double(j));
}
}
/*!
Compute forward mode Taylor coefficient for result of op = SinOp.
The C++ source code corresponding to this operation is
\verbatim
z = sin(x)
\endverbatim
The auxillary result is
\verbatim
y = cos(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_sin_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* s = taylor + i_z * num_taylor_per_var;
Base* c = s - num_taylor_per_var;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op
// (except that there is a sign difference for the hyperbolic case).
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ s[m+ell] = Base(double(q)) * x[m + ell] * c[0];
c[m+ell] = - Base(double(q)) * x[m + ell] * s[0];
for(size_t k = 1; k < q; k++)
{ s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell];
c[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell];
}
s[m+ell] /= Base(double(q));
c[m+ell] /= Base(double(q));
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = SinOp.
The C++ source code corresponding to this operation is
\verbatim
z = sin(x)
\endverbatim
The auxillary result is
\verbatim
y = cos(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_sin_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* s = taylor + i_z * cap_order; // called z in documentation
Base* c = s - cap_order; // called y in documentation
s[0] = sin( x[0] );
c[0] = cos( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = SinOp.
The C++ source code corresponding to this operation is
\verbatim
z = sin(x)
\endverbatim
The auxillary result is
\verbatim
y = cos(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_sin_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* s = taylor + i_z * cap_order; // called z in doc
Base* ps = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* c = s - cap_order; // called y in documentation
Base* pc = ps - nc_partial;
// rest of this routine is identical for the following cases:
// reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op.
size_t j = d;
size_t k;
while(j)
{
ps[j] /= Base(double(j));
pc[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{
px[k] += Base(double(k)) * azmul(ps[j], c[j-k]);
px[k] -= Base(double(k)) * azmul(pc[j], s[j-k]);
ps[j-k] -= Base(double(k)) * azmul(pc[j], x[k]);
pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]);
}
--j;
}
px[0] += azmul(ps[0], c[0]);
px[0] -= azmul(pc[0], s[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,239 @@
# ifndef CPPAD_LOCAL_SINH_OP_HPP
# define CPPAD_LOCAL_SINH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sinh_op.hpp
Forward and reverse mode calculations for z = sinh(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = SinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = sinh(x)
\endverbatim
The auxillary result is
\verbatim
y = cosh(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op
*/
template <class Base>
void forward_sinh_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* s = taylor + i_z * cap_order;
Base* c = s - cap_order;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op
// (except that there is a sign difference for hyperbolic case).
size_t k;
if( p == 0 )
{ s[0] = sinh( x[0] );
c[0] = cosh( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
s[j] = Base(0.0);
c[j] = Base(0.0);
for(k = 1; k <= j; k++)
{ s[j] += Base(double(k)) * x[k] * c[j-k];
c[j] += Base(double(k)) * x[k] * s[j-k];
}
s[j] /= Base(double(j));
c[j] /= Base(double(j));
}
}
/*!
Compute forward mode Taylor coefficient for result of op = SinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = sinh(x)
\endverbatim
The auxillary result is
\verbatim
y = cosh(x)
\endverbatim
The value of y, and its derivatives, are computed along with the value
and derivatives of z.
\copydetails CppAD::local::forward_unary2_op_dir
*/
template <class Base>
void forward_sinh_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + i_x * num_taylor_per_var;
Base* s = taylor + i_z * num_taylor_per_var;
Base* c = s - num_taylor_per_var;
// rest of this routine is identical for the following cases:
// forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op
// (except that there is a sign difference for the hyperbolic case).
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ s[m+ell] = Base(double(q)) * x[m + ell] * c[0];
c[m+ell] = Base(double(q)) * x[m + ell] * s[0];
for(size_t k = 1; k < q; k++)
{ s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell];
c[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell];
}
s[m+ell] /= Base(double(q));
c[m+ell] /= Base(double(q));
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = SinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = sinh(x)
\endverbatim
The auxillary result is
\verbatim
y = cosh(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::forward_unary2_op_0
*/
template <class Base>
void forward_sinh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* s = taylor + i_z * cap_order; // called z in documentation
Base* c = s - cap_order; // called y in documentation
s[0] = sinh( x[0] );
c[0] = cosh( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = SinhOp.
The C++ source code corresponding to this operation is
\verbatim
z = sinh(x)
\endverbatim
The auxillary result is
\verbatim
y = cosh(x)
\endverbatim
The value of y is computed along with the value of z.
\copydetails CppAD::local::reverse_unary2_op
*/
template <class Base>
void reverse_sinh_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
const Base* x = taylor + i_x * cap_order;
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to first result
const Base* s = taylor + i_z * cap_order; // called z in doc
Base* ps = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* c = s - cap_order; // called y in documentation
Base* pc = ps - nc_partial;
// rest of this routine is identical for the following cases:
// reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op.
size_t j = d;
size_t k;
while(j)
{
ps[j] /= Base(double(j));
pc[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{
px[k] += Base(double(k)) * azmul(ps[j], c[j-k]);
px[k] += Base(double(k)) * azmul(pc[j], s[j-k]);
ps[j-k] += Base(double(k)) * azmul(pc[j], x[k]);
pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]);
}
--j;
}
px[0] += azmul(ps[0], c[0]);
px[0] += azmul(pc[0], s[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,617 @@
# ifndef CPPAD_LOCAL_SPARSE_BINARY_OP_HPP
# define CPPAD_LOCAL_SPARSE_BINARY_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE
namespace CppAD { namespace local { namespace sparse {
// END_DECLARE_NAMESPACE
/*!
\file sparse_binary_op.hpp
Forward and reverse mode sparsity patterns for binary operators.
*/
/*!
Forward mode Jacobian sparsity pattern for all binary operators.
The C++ source code corresponding to a binary operation has the form
\verbatim
z = fun(x, y)
\endverbatim
where fun is a C++ binary function and both x and y are variables,
or it has the form
\verbatim
z = x op y
\endverbatim
where op is a C++ binary unary operator and both x and y are variables.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e., z.
\param arg
arg[0]
variable index corresponding to the left operand for this operator;
i.e., x.
\n
\n arg[1]
variable index corresponding to the right operand for this operator;
i.e., y.
\param sparsity
\b Input:
The set with index arg[0] in sparsity
is the sparsity bit pattern for x.
This identifies which of the independent variables the variable x
depends on.
\n
\n
\b Input:
The set with index arg[1] in sparsity
is the sparsity bit pattern for y.
This identifies which of the independent variables the variable y
depends on.
\n
\n
\b Output:
The set with index i_z in sparsity
is the sparsity bit pattern for z.
This identifies which of the independent variables the variable z
depends on.
\par Checked Assertions:
\li arg[0] < i_z
\li arg[1] < i_z
*/
template <class Vector_set>
void for_jac_binary_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
sparsity.binary_union(i_z, size_t(arg[0]), size_t(arg[1]), sparsity);
return;
}
/*!
Reverse mode Jacobian sparsity pattern for all binary operators.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = fun(x, y)
\endverbatim
where fun is a C++ unary function and x and y are variables,
or it has the form
\verbatim
z = x op y
\endverbatim
where op is a C++ bianry operator and x and y are variables.
This routine is given the sparsity patterns
for a function G(z, y, x, ... )
and it uses them to compute the sparsity patterns for
\verbatim
H( y, x, w , u , ... ) = G[ z(x,y) , y , x , w , u , ... ]
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e., z.
\param arg
arg[0]
variable index corresponding to the left operand for this operator;
i.e., x.
\n
\n arg[1]
variable index corresponding to the right operand for this operator;
i.e., y.
\param sparsity
The set with index i_z in sparsity
is the sparsity pattern for z corresponding ot the function G.
\n
\n
The set with index arg[0] in sparsity
is the sparsity pattern for x.
On input, it corresponds to the function G,
and on output it corresponds to H.
\n
\n
The set with index arg[1] in sparsity
is the sparsity pattern for y.
On input, it corresponds to the function G,
and on output it corresponds to H.
\n
\n
\par Checked Assertions:
\li arg[0] < i_z
\li arg[1] < i_z
*/
template <class Vector_set>
void rev_jac_binary_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
sparsity.binary_union( size_t(arg[0]), size_t(arg[0]), i_z, sparsity);
sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_z, sparsity);
return;
}
// ---------------------------------------------------------------------------
/*!
Reverse mode Hessian sparsity pattern for add and subtract operators.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = x op y
\endverbatim
where op is + or - and x, y are variables.
\copydetails CppAD::local::reverse_sparse_hessian_binary_op
*/
template <class Vector_set>
void rev_hes_addsub_op(
size_t i_z ,
const addr_t* arg ,
bool* jac_reverse ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
// check for no effect
if( ! jac_reverse[i_z] )
return;
// propagate hessian sparsity from i_z to arg[0] and arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity
);
jac_reverse[arg[0]] = true;
jac_reverse[arg[1]] = true;
return;
}
/*!
Reverse mode Hessian sparsity pattern for multiplication operator.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = x * y
\endverbatim
where x and y are variables.
\copydetails CppAD::local::reverse_sparse_hessian_binary_op
*/
template <class Vector_set>
void rev_hes_mul_op(
size_t i_z ,
const addr_t* arg ,
bool* jac_reverse ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
// check for no effect
if( ! jac_reverse[i_z] )
return;
// progagate hessian sparsity from i_z to arg[0] and arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity
);
// new hessian sparsity terms between i_z and arg[0], arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity
);
jac_reverse[arg[0]] = true;
jac_reverse[arg[1]] = true;
return;
}
/*!
Reverse mode Hessian sparsity pattern for division operator.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = x / y
\endverbatim
where x and y are variables.
\copydetails CppAD::local::reverse_sparse_hessian_binary_op
*/
template <class Vector_set>
void rev_hes_div_op(
size_t i_z ,
const addr_t* arg ,
bool* jac_reverse ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
// check for no effect
if( ! jac_reverse[i_z] )
return;
// propagate hessian sparsity from i_z to arg[0] and arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity
);
// new hessian sparsity terms between i_z and arg[0], arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), size_t(arg[1]), for_jac_sparsity
);
jac_reverse[arg[0]] = true;
jac_reverse[arg[1]] = true;
return;
}
/*!
Reverse mode Hessian sparsity pattern for power function.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = pow(x, y)
\endverbatim
where x and y are variables.
\copydetails CppAD::local::reverse_sparse_hessian_binary_op
*/
template <class Vector_set>
void rev_hes_pow_op(
size_t i_z ,
const addr_t* arg ,
bool* jac_reverse ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z );
// check for no effect
if( ! jac_reverse[i_z] )
return;
// propigate hessian sparsity from i_z to arg[0] and arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity
);
// new hessian sparsity terms between i_z and arg[0], arg[1]
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), size_t(arg[0]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity
);
rev_hes_sparsity.binary_union(
size_t(arg[1]), size_t(arg[1]), size_t(arg[1]), for_jac_sparsity
);
// I cannot think of a case where this is necessary, but it including
// it makes it like the other cases.
jac_reverse[arg[0]] = true;
jac_reverse[arg[1]] = true;
return;
}
// ---------------------------------------------------------------------------
/*
$begin sparse_for_hes_nl_binary_op$$
$spell
hes
div
op
np
numvar
Jacobian
arg
mul
Namespace
$$
$section Forward Hessian Sparsity for Nonlinear Binary Operators$$
$head Namespace$$
$srcthisfile%
0%// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE%// END_DECLARE_NAMESPACE%0
%$$
$head for_hes_mul_op$$
$subhead Syntax$$
$codei%for_hes_mul_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$
$subhead Prototype$$
$srcthisfile%
0%// BEGIN_for_hes_mul_op%// END_for_hes_mul_op%1
%$$
$head for_hes_div_op$$
$subhead Syntax$$
$codei%for_hes_div_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$
$subhead Prototype$$
$srcthisfile%
0%// BEGIN_for_hes_div_op%// END_for_hes_div_op%1
%$$
$head for_hes_pow_op$$
$subhead Syntax$$
$codei%for_hes_pow_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$
$subhead Prototype$$
$srcthisfile%
0%// BEGIN_for_hes_pow_op%// END_for_hes_pow_op%1
%$$
$head C++ Source$$
The C++ source code corresponding to this operation is
$codei%
%w% = %v0% * %v1%
%w% = %v0% / %v1%
%w% = pow(%v0% , %v1%)
%$$
$head np1$$
This is the number of independent variables plus one;
i.e. size of $icode x$$ plus one.
$head numvar$$
This is the total number of variables in the tape.
$head i_w$$
is the index of the variable corresponding to the result $icode w$$.
$head arg$$
is the index of the argument vector for the nonlinear binary operation; i.e.,
$icode%arg%[0]%$$, $icode%arg%[1]%$$ are the left and right operands; i.e.,
corresponding to $icode v0$$, $icode v1$$.
$head for_sparsity$$
We have the conditions $icode%np1% = %for_sparsity%.end()%$$
and $icode%for_sparsity%.n_set() = %np1% + %numvar%$$.
$subhead Input Jacobian Sparsity$$
For $icode%i%= 0, ..., %i_w%-1%$$,
the $icode%np1%+%i%$$ row of $icode for_sparsity$$ is the Jacobian sparsity
for the $th i$$ variable. These values do not change.
Note that $icode%i%=0%$$ corresponds to a parameter and
the corresponding Jacobian sparsity is empty.
$subhead Input Hessian Sparsity$$
For $icode%j%=1, ..., %n%$$,
the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity
before including the function $latex w(x)$$.
$subhead Output Jacobian Sparsity$$
the $icode i_w$$ row of $icode for_sparsity$$ is the Jacobian sparsity
for the variable $icode w$$.
$subhead Output Hessian Sparsity$$
For $icode%j%=1, ..., %n%$$,
the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity
after including the function $latex w(x)$$.
$end
*/
// BEGIN_for_hes_mul_op
template <class Vector_set>
void for_hes_mul_op(
size_t np1 ,
size_t numvar ,
size_t i_w ,
const addr_t* arg ,
Vector_set& for_sparsity )
// END_for_hes_mul_op
{ //
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
//
size_t i_v0 = size_t(arg[0]);
size_t i_v1 = size_t(arg[1]);
CPPAD_ASSERT_UNKNOWN( i_v0 < i_w );
CPPAD_ASSERT_UNKNOWN( i_v1 < i_w );
CPPAD_ASSERT_UNKNOWN( i_w < numvar );
// set Jacobian sparsity J(i_w)
for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity);
// --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1);
// loop over independent variables non-zero partial for v0
size_t i_x = *itr_0;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v1)
for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1);
// loop over independent variables with non-zero partial for v1
i_x = *itr_1;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v0)
for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity);
i_x = *(++itr_1);
}
return;
}
// BEGIN_for_hes_div_op
template <class Vector_set>
void for_hes_div_op(
size_t np1 ,
size_t numvar ,
size_t i_w ,
const addr_t* arg ,
Vector_set& for_sparsity )
// END_for_hes_div_op
{ //
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
//
size_t i_v0 = size_t(arg[0]);
size_t i_v1 = size_t(arg[1]);
CPPAD_ASSERT_UNKNOWN( i_v0 < i_w );
CPPAD_ASSERT_UNKNOWN( i_v1 < i_w );
CPPAD_ASSERT_UNKNOWN( i_w < numvar );
// set Jacobian sparsity J(i_w)
for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity);
// --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1);
// loop over independent variables non-zero partial for v0
size_t i_x = *itr_0;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v1)
for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1);
// loop over independent variables with non-zero partial for v1
i_x = *itr_1;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v0)
for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity);
// N(i_x) = N(i_x) union J(v1)
for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity);
i_x = *(++itr_1);
}
return;
}
// BEGIN_for_hes_pow_op
template <class Vector_set>
void for_hes_pow_op(
size_t np1 ,
size_t numvar ,
size_t i_w ,
const addr_t* arg ,
Vector_set& for_sparsity )
// END_for_hes_pow_op
{ //
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
//
size_t i_v0 = size_t(arg[0]);
size_t i_v1 = size_t(arg[1]);
CPPAD_ASSERT_UNKNOWN( i_v0 < i_w );
CPPAD_ASSERT_UNKNOWN( i_v1 < i_w );
CPPAD_ASSERT_UNKNOWN( i_w < numvar );
// set Jacobian sparsity J(i_w)
for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity);
// --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1);
// loop over independent variables non-zero partial for v0
size_t i_x = *itr_0;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v0)
for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity);
// N(i_x) = N(i_x) union J(v1)
for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1);
// loop over independent variables with non-zero partial for v1
i_x = *itr_1;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(v0)
for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity);
// N(i_x) = N(i_x) union J(v1)
for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity);
i_x = *(++itr_1);
}
return;
}
// ---------------------------------------------------------------------------
} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE
# endif

View File

@@ -0,0 +1,23 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
-----------------------------------------------------------------------------
$begin dev_sparse$$
$section Developer Sparse Documentation$$
$childtable%
include/cppad/local/sparse/unary_op.hpp%
include/cppad/local/sparse/binary_op.hpp%
include/cppad/local/sparse/setvector.omh
%$$
$end

View File

@@ -0,0 +1,455 @@
# ifndef CPPAD_LOCAL_SPARSE_INTERNAL_HPP
# define CPPAD_LOCAL_SPARSE_INTERNAL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// necessary definitions
# include <cppad/local/define.hpp>
# include <cppad/local/sparse/pack_setvec.hpp>
# include <cppad/local/sparse/list_setvec.hpp>
# include <cppad/local/sparse/svec_setvec.hpp>
// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE
namespace CppAD { namespace local { namespace sparse {
/*!
\file sparse_internal.hpp
Routines that enable code to be independent of which internal spasity pattern
is used.
*/
// ---------------------------------------------------------------------------
/*!
Template structure used obtain the internal sparsity pattern type
form the corresponding element type.
The general form is not valid, must use a specialization.
\tparam Element_type
type of an element in the sparsity structrue.
\par <code>internal_pattern<Element_type>::pattern_type</code>
is the type of the corresponding internal sparsity pattern.
*/
template <class Element_type> struct internal_pattern;
/// Specilization for bool elements.
template <>
struct internal_pattern<bool>
{
typedef sparse::pack_setvec pattern_type;
};
/// Specilization for <code>std::set<size_t></code> elements.
template <>
struct internal_pattern< std::set<size_t> >
{
typedef list_setvec pattern_type;
};
// ---------------------------------------------------------------------------
/*!
Update the internal sparsity pattern for a sub-set of rows
\tparam SizeVector
The type used for index sparsity patterns. This is a simple vector
with elements of type size_t.
\tparam InternalSparsitiy
The type used for intenal sparsity patterns. This can be either
sparse::pack_setvec or list_setvec.
\param zero_empty
If this is true, the internal sparstity pattern corresponds to row zero
must be empty on input and will be emtpy output; i.e., any corresponding
values in pattern_in will be ignored.
\param input_empty
If this is true, the initial sparsity pattern for row
internal_index[i] is empty for all i.
In this case, one is setting the sparsity patterns; i.e.,
the output pattern in row internal_index[i] is the corresponding
entries in pattern.
\param transpose
If this is true, pattern_in is transposed.
\param internal_index
This specifies the sub-set of rows in internal_pattern that we are updating.
If traspose is false (true),
this is the mapping from row (column) index in pattern_in to the corresponding
row index in the internal_pattern.
\param internal_pattern
On input, the number of sets internal_pattern.n_set(),
and possible elements internal_pattern.end(), have been set.
If input_empty is true, and all of the sets
in internal_index are empty on input.
On output, the entries in pattern_in are added to internal_pattern.
To be specific, suppose transpose is false, and (i, j) is a possibly
non-zero entry in pattern_in, the entry (internal_index[i], j) is added
to internal_pattern.
On the other hand, if transpose is true,
the entry (internal_index[j], i) is added to internal_pattern.
\param pattern_in
This is the sparsity pattern for variables,
or its transpose, depending on the value of transpose.
*/
template <class SizeVector, class InternalSparsity>
void set_internal_pattern(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const pod_vector<size_t>& internal_index ,
InternalSparsity& internal_pattern ,
const sparse_rc<SizeVector>& pattern_in )
{
size_t nr = internal_index.size();
# ifndef NDEBUG
size_t nc = internal_pattern.end();
if( transpose )
{ CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nc );
CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nr );
}
else
{ CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nr );
CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nc );
}
if( input_empty ) for(size_t i = 0; i < nr; i++)
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
}
# endif
const SizeVector& row( pattern_in.row() );
const SizeVector& col( pattern_in.col() );
size_t nnz = row.size();
for(size_t k = 0; k < nnz; k++)
{ size_t r = row[k];
size_t c = col[k];
if( transpose )
std::swap(r, c);
//
size_t i_var = internal_index[r];
CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
CPPAD_ASSERT_UNKNOWN( c < nc );
bool ignore = zero_empty && i_var == 0;
if( ! ignore )
internal_pattern.post_element( internal_index[r], c );
}
// process posts
for(size_t i = 0; i < nr; ++i)
internal_pattern.process_post( internal_index[i] );
}
template <class InternalSparsity>
void set_internal_pattern(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const pod_vector<size_t>& internal_index ,
InternalSparsity& internal_pattern ,
const vectorBool& pattern_in )
{ size_t nr = internal_index.size();
size_t nc = internal_pattern.end();
# ifndef NDEBUG
CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc );
if( input_empty ) for(size_t i = 0; i < nr; i++)
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
}
# endif
for(size_t i = 0; i < nr; i++)
{ for(size_t j = 0; j < nc; j++)
{ bool flag = pattern_in[i * nc + j];
if( transpose )
flag = pattern_in[j * nr + i];
if( flag )
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
CPPAD_ASSERT_UNKNOWN( j < nc );
bool ignore = zero_empty && i_var == 0;
if( ! ignore )
internal_pattern.post_element( i_var, j);
}
}
}
// process posts
for(size_t i = 0; i < nr; ++i)
internal_pattern.process_post( internal_index[i] );
return;
}
template <class InternalSparsity>
void set_internal_pattern(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const pod_vector<size_t>& internal_index ,
InternalSparsity& internal_pattern ,
const vector<bool>& pattern_in )
{ size_t nr = internal_index.size();
size_t nc = internal_pattern.end();
# ifndef NDEBUG
CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc );
if( input_empty ) for(size_t i = 0; i < nr; i++)
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
}
# endif
for(size_t i = 0; i < nr; i++)
{ for(size_t j = 0; j < nc; j++)
{ bool flag = pattern_in[i * nc + j];
if( transpose )
flag = pattern_in[j * nr + i];
if( flag )
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
CPPAD_ASSERT_UNKNOWN( j < nc );
bool ignore = zero_empty && i_var == 0;
if( ! ignore )
internal_pattern.post_element( i_var, j);
}
}
}
// process posts
for(size_t i = 0; i < nr; ++i)
internal_pattern.process_post( internal_index[i] );
return;
}
template <class InternalSparsity>
void set_internal_pattern(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const pod_vector<size_t>& internal_index ,
InternalSparsity& internal_pattern ,
const vector< std::set<size_t> >& pattern_in )
{ size_t nr = internal_index.size();
size_t nc = internal_pattern.end();
# ifndef NDEBUG
if( input_empty ) for(size_t i = 0; i < nr; i++)
{ size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
}
# endif
if( transpose )
{ CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nc );
for(size_t j = 0; j < nc; j++)
{ std::set<size_t>::const_iterator itr( pattern_in[j].begin() );
while( itr != pattern_in[j].end() )
{ size_t i = *itr;
size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
CPPAD_ASSERT_UNKNOWN( j < nc );
bool ignore = zero_empty && i_var == 0;
if( ! ignore )
internal_pattern.post_element( i_var, j);
++itr;
}
}
}
else
{ CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr );
for(size_t i = 0; i < nr; i++)
{ std::set<size_t>::const_iterator itr( pattern_in[i].begin() );
while( itr != pattern_in[i].end() )
{ size_t j = *itr;
size_t i_var = internal_index[i];
CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
CPPAD_ASSERT_UNKNOWN( j < nc );
bool ignore = zero_empty && i_var == 0;
if( ! ignore )
internal_pattern.post_element( i_var, j);
++itr;
}
}
}
// process posts
for(size_t i = 0; i < nr; ++i)
internal_pattern.process_post( internal_index[i] );
return;
}
// ---------------------------------------------------------------------------
/*!
Get sparsity pattern for a sub-set of variables
\tparam SizeVector
The type used for index sparsity patterns. This is a simple vector
with elements of type size_t.
\tparam InternalSparsitiy
The type used for intenal sparsity patterns. This can be either
sparse::pack_setvec or list_setvec.
\param transpose
If this is true, pattern_out is transposed.
\param internal_index
If transpose is false (true)
this is the mapping from row (column) an index in pattern_out
to the corresponding row index in internal_pattern.
\param internal_pattern
This is the internal sparsity pattern.
\param pattern_out
The input value of pattern_out does not matter.
Upon return it is an index sparsity pattern for each of the variables
in internal_index, or its transpose, depending on the value of transpose.
*/
template <class SizeVector, class InternalSparsity>
void get_internal_pattern(
bool transpose ,
const pod_vector<size_t>& internal_index ,
const InternalSparsity& internal_pattern ,
sparse_rc<SizeVector>& pattern_out )
{ typedef typename InternalSparsity::const_iterator iterator;
// number variables
size_t nr = internal_index.size();
// column size of interanl sparstiy pattern
size_t nc = internal_pattern.end();
// determine nnz, the number of possibly non-zero index pairs
size_t nnz = 0;
for(size_t i = 0; i < nr; i++)
{ CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ ++nnz;
j = *(++itr);
}
}
// transposed
if( transpose )
{ pattern_out.resize(nc, nr, nnz);
//
size_t k = 0;
for(size_t i = 0; i < nr; i++)
{ iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ pattern_out.set(k++, j, i);
j = *(++itr);
}
}
return;
}
// not transposed
pattern_out.resize(nr, nc, nnz);
//
size_t k = 0;
for(size_t i = 0; i < nr; i++)
{ iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ pattern_out.set(k++, i, j);
j = *(++itr);
}
}
return;
}
template <class InternalSparsity>
void get_internal_pattern(
bool transpose ,
const pod_vector<size_t>& internal_index ,
const InternalSparsity& internal_pattern ,
vectorBool& pattern_out )
{ typedef typename InternalSparsity::const_iterator iterator;
// number variables
size_t nr = internal_index.size();
//
// column size of interanl sparstiy pattern
size_t nc = internal_pattern.end();
//
pattern_out.resize(nr * nc);
for(size_t ij = 0; ij < nr * nc; ij++)
pattern_out[ij] = false;
//
for(size_t i = 0; i < nr; i++)
{ CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ if( transpose )
pattern_out[j * nr + i] = true;
else
pattern_out[i * nc + j] = true;
j = *(++itr);
}
}
return;
}
template <class InternalSparsity>
void get_internal_pattern(
bool transpose ,
const pod_vector<size_t>& internal_index ,
const InternalSparsity& internal_pattern ,
vector<bool>& pattern_out )
{ typedef typename InternalSparsity::const_iterator iterator;
// number variables
size_t nr = internal_index.size();
//
// column size of interanl sparstiy pattern
size_t nc = internal_pattern.end();
//
pattern_out.resize(nr * nc);
for(size_t ij = 0; ij < nr * nc; ij++)
pattern_out[ij] = false;
//
for(size_t i = 0; i < nr; i++)
{ CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ if( transpose )
pattern_out[j * nr + i] = true;
else
pattern_out[i * nc + j] = true;
j = *(++itr);
}
}
return;
}
template <class InternalSparsity>
void get_internal_pattern(
bool transpose ,
const pod_vector<size_t>& internal_index ,
const InternalSparsity& internal_pattern ,
vector< std::set<size_t> >& pattern_out )
{ typedef typename InternalSparsity::const_iterator iterator;
// number variables
size_t nr = internal_index.size();
//
// column size of interanl sparstiy pattern
size_t nc = internal_pattern.end();
//
if( transpose )
pattern_out.resize(nc);
else
pattern_out.resize(nr);
for(size_t k = 0; k < pattern_out.size(); k++)
pattern_out[k].clear();
//
for(size_t i = 0; i < nr; i++)
{ CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
iterator itr(internal_pattern, internal_index[i]);
size_t j = *itr;
while( j < nc )
{ if( transpose )
pattern_out[j].insert(i);
else
pattern_out[i].insert(j);
j = *(++itr);
}
}
return;
}
} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE
# endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
------------------------------------------------------------------------------
$begin list_setvec$$
$spell
Namespace
CppAD
setvec
$$
$section Implement SetVector Using Singly Linked Lists$$
$head Namespace$$
This class is in the $code CppAD::local::sparse$$ namespace.
$head Public$$
The public member function for the $code list_setvec$$ class implement the
$cref SetVector$$ concept.
$childtable%
include/cppad/local/sparse/list_setvec.hpp
%$$
$end

View File

@@ -0,0 +1,910 @@
# ifndef CPPAD_LOCAL_SPARSE_PACK_SETVEC_HPP
# define CPPAD_LOCAL_SPARSE_PACK_SETVEC_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/pod_vector.hpp>
// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE
namespace CppAD { namespace local { namespace sparse {
// forward declaration of iterator class
class pack_setvec_const_iterator;
// ============================================================================
class pack_setvec {
// ============================================================================
/*
$begin pack_setvec_member_data$$
$spell
setvec
resize
$$
$section class pack_setvec: Private Member Data$$
$head Pack$$
Type used to pack multiple elements of a set (multiple bits) onto one
$icode Pack$$ value.
$head n_bit_$$
Number of bits (elements) per $icode Pack$$ value.
$head zero_$$
The $icode Pack$$ value with all bits zero.
$head one_$$
The $icode Pack$$ value with all bits zero, except for the lowest order bit.
$head n_set_$$
Number of sets that we are representing.
$head end_$$
The possible elements in each set are $code 0$$, $code 1$$, ...,
$code end_-1$$.
$head n_pack_$$
Number of Pack values used to represent one set in the vector; i.e.,
to represent $code end_$$ bits.
$head data_$$
Data for all of the sets.
$head Source Code$$
$srccode%hpp% */
private:
typedef size_t Pack;
const size_t n_bit_;
const Pack zero_;
const Pack one_;
size_t n_set_;
size_t end_;
size_t n_pack_;
pod_vector<Pack> data_;
/* %$$
$end
-----------------------------------------------------------------------------
$begin pack_setvec_vec_memory$$
$spell
setvec
$$
$section class pack_setvec: Approximate Memory Used by Vector$$
$head Public$$
This function is declared public, but is not part of
$cref SetVector$$ concept.
$head Implementation$$
$srccode%hpp% */
public:
size_t memory(void) const
{ return data_.capacity() * sizeof(Pack); }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_vec_print$$
$spell
setvec
$$
$section class pack_setvec: Print a Vector of Sets$$
$head Public$$
This function is declared public, but is not part of
$cref SetVector$$ concept.
$head Prototype$$
$srccode%hpp% */
public:
void print(void) const;
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_iterators$$
$spell
setvec
Iterators
typedef
const_iterator
$$
$section class pack_setvec: Iterators$$
$head SetVector Concept$$
$cref/const_iterator/SetVector/const_iterator/$$
$head typedef$$
$srccode%hpp% */
public:
/// declare a const iterator
friend class pack_setvec_const_iterator;
typedef pack_setvec_const_iterator const_iterator;
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_default_ctor$$
$spell
setvec
$$
$section class pack_setvec: Default Constructor$$
$head SetVector Concept$$
$cref/constructor/SetVector/Vector Operations/Constructor/$$
$head n_bit_$$
This member variable is set to the number of bits in a $icode Pack$$ value.
$head one_$$
This member variable has only its lowest order bit non-zero;
$head data_$$
This member is initialized as the empty vector; i.e., size zero..
$head Other$$
All the other member data are $code size_t$$ values
that are initialized as zero.
$head Implementation$$
$srccode%hpp% */
public:
pack_setvec(void) :
n_bit_( std::numeric_limits<Pack>::digits ),
zero_(0), one_(1), n_set_(0), end_(0), n_pack_(0), data_(0)
{ }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_destructor$$
$spell
setvec
$$
$section class pack_setvec: Destructor$$
$head Implementation$$
$srccode%hpp% */
public:
~pack_setvec(void)
{ }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_copy_ctor$$
$spell
setvec
CppAD
$$
$section class pack_setvec: Copy Constructor$$
$head v$$
The vector of sets that we are attempting to make a copy of.
$head Implementation$$
Using the copy constructor is probably due to a $code pack_setvec$$
being passed by value instead of by reference.
This is a CppAD programing error (not CppAD user error).
$srccode%hpp% */
public:
pack_setvec(const pack_setvec& v) :
n_bit_( std::numeric_limits<Pack>::digits ), zero_(0), one_(1)
{ CPPAD_ASSERT_UNKNOWN(0); }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_vec_resize$$
$spell
setvec
resize
$$
$section class pack_setvec: Vector resize$$
$head SetVector Concept$$
$cref/vector resize/SetVector/Vector Operations/resize/$$
$head Prototype$$
$srccode%hpp% */
public:
void resize(size_t n_set, size_t end)
/* %$$
$end
*/
{ n_set_ = n_set;
end_ = end;
if( n_set_ == 0 )
{ CPPAD_ASSERT_UNKNOWN( end == 0 );
data_.clear();
return;
}
// now start a new vector with empty sets
Pack zero(0);
//
n_pack_ = ( 1 + (end_ - 1) / n_bit_ );
size_t i = n_set_ * n_pack_;
//
data_.resize(i);
while(i--)
data_[i] = zero;
}
/* %$$
-------------------------------------------------------------------------------
$begin pack_setvec_vec_n_set$$
$spell
setvec
$$
$section class pack_setvec: Number of Sets$$
$head SetVector Concept$$
$cref/n_set/SetVector/Vector Operations/n_set/$$
$head Implementation$$
$srccode%hpp% */
public:
size_t n_set(void) const
{ return n_set_; }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_vec_end$$
$spell
setvec
$$
$section class pack_setvec: End Value$$
$head SetVector Concept$$
$cref/end/SetVector/Vector Operations/end/$$
$head Implementation$$
$srccode%hpp% */
public:
size_t end(void) const
{ return end_; }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_vec_assignment$$
$spell
setvec
$$
$section class pack_setvec: Vector Assignment$$
$head SetVector Concept$$
$cref/vector assignment/SetVector/Vector Operations/Assignment/$$
$head Prototype$$
$srccode%hpp% */
public:
void operator=(const pack_setvec& other)
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( n_bit_ == other.n_bit_);
CPPAD_ASSERT_UNKNOWN( zero_ == other.zero_);
CPPAD_ASSERT_UNKNOWN( one_ == other.one_);
n_set_ = other.n_set_;
end_ = other.end_;
n_pack_ = other.n_pack_;
data_ = other.data_;
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_vec_swap$$
$spell
setvec
$$
$section class pack_setvec: Vector Swap$$
$head SetVector Concept$$
$cref/vector swap/SetVector/Vector Operations/swap/$$
$head Prototype$$
$srccode%hpp% */
public:
void swap(pack_setvec& other)
/* %$$
$end
*/
{ // size_t objects
CPPAD_ASSERT_UNKNOWN( n_bit_ == other.n_bit_);
CPPAD_ASSERT_UNKNOWN( zero_ == other.zero_);
CPPAD_ASSERT_UNKNOWN( one_ == other.one_);
std::swap(n_set_ , other.n_set_);
std::swap(end_ , other.end_);
std::swap(n_pack_ , other.n_pack_);
//
// pod_vectors
data_.swap(other.data_);
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_number_elements$$
$spell
setvec
$$
$section class pack_setvec: Number of Elements in a Set$$
$head SetVector Concept$$
$cref/number_elements/SetVector/number_elements/$$
$head Prototype$$
$srccode%hpp% */
public:
size_t number_elements(size_t i) const
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( i < n_set_ );
//
// special case where data_[i] is 0 or 1
if( end_ == 1 )
{ CPPAD_ASSERT_UNKNOWN( n_pack_ == 1 );
return size_t( data_[i] );
}
//
// initialize count of non-zero bits in this set
size_t count = 0;
//
// mask corresonding to first bit in Pack
Pack mask = one_;
//
// number of bits in last Packing unit
size_t n_last = (end_ - 1) % n_bit_ + 1;
//
// count bits in last unit
Pack unit = data_[(i + 1) * n_pack_ - 1];
for(size_t bit = 0; bit < n_last; ++bit)
{ CPPAD_ASSERT_UNKNOWN( mask >= one_ );
if( mask & unit )
++count;
mask = mask << 1;
}
if( n_pack_ == 1 )
return count;
//
// count bits in other units
for(size_t bit = 0; bit < n_bit_; ++bit)
{ CPPAD_ASSERT_UNKNOWN( mask >= one_ );
size_t k = n_pack_;
while(--k)
{ if( data_[i * n_pack_ + k] & mask )
++count;
}
mask = mask << 1;
}
return count;
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_add_element$$
$spell
setvec
$$
$section class pack_setvec: Add an Elements to a Set$$
$head SetVector Concept$$
$cref/add_element/SetVector/add_element/$$
$head Prototype$$
$srccode%hpp% */
public:
void add_element(size_t i, size_t element)
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( i < n_set_ );
CPPAD_ASSERT_UNKNOWN( element < end_ );
if( end_ == 1 )
data_[i] |= one_;
else
{ size_t j = element / n_bit_;
size_t k = element - j * n_bit_;
Pack mask = one_ << k;
data_[ i * n_pack_ + j] |= mask;
}
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_post_element$$
$spell
setvec
$$
$section class pack_setvec: Add an Elements to a Set$$
$head SetVector Concept$$
$cref/post_element/SetVector/post_element/$$
$head Implementation$$
$srccode%hpp% */
public:
void post_element(size_t i, size_t element)
{ add_element(i, element); }
/* %$$
$end
*/
/*
-------------------------------------------------------------------------------
$begin pack_setvec_process_post$$
$spell
setvec
$$
$section class pack_setvec: Add Posted Elements to a Set$$
$head SetVector Concept$$
$cref/process_post/SetVector/process_post/$$
$head Implementation$$
$srccode%hpp% */
public:
void process_post(size_t i)
{ return; }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_is_element$$
$spell
setvec
$$
$section class pack_setvec: Is an Element in a Set$$
$head SetVector Concept$$
$cref/is_element/SetVector/is_element/$$
$head Prototype$$
$srccode%hpp% */
public:
bool is_element(size_t i, size_t element) const
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( i < n_set_ );
CPPAD_ASSERT_UNKNOWN( element < end_ );
if( end_ == 1 )
return data_[i] != zero_;
//
size_t j = element / n_bit_;
size_t k = element - j * n_bit_;
Pack mask = one_ << k;
return (data_[i * n_pack_ + j] & mask) != zero_;
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_clear$$
$spell
setvec
$$
$section class pack_setvec: Assign a Set to be Empty$$
$head SetVector Concept$$
$cref/clear/SetVector/clear/$$
$head Prototype$$
$srccode%hpp% */
public:
void clear(size_t target)
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( target < n_set_ );
size_t t = target * n_pack_;
size_t j = n_pack_;
while(j--)
data_[t++] = zero_;
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_assignment$$
$spell
setvec
$$
$section class pack_setvec: Assign a Set To Equal Another Set$$
$head SetVector Concept$$
$cref/assignment/SetVector/assignment/$$
$head Prototype$$
$srccode%hpp% */
public:
void assignment(
size_t this_target ,
size_t other_value ,
const pack_setvec& other )
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( this_target < n_set_ );
CPPAD_ASSERT_UNKNOWN( other_value < other.n_set_ );
CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ );
size_t t = this_target * n_pack_;
size_t v = other_value * n_pack_;
size_t j = n_pack_;
while(j--)
data_[t++] = other.data_[v++];
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_binary_union$$
$spell
setvec
$$
$section class pack_setvec: Assign a Set To Equal Union of Two Sets$$
$head SetVector Concept$$
$cref/binary_union/SetVector/binary_union/$$
$head Prototype$$
$srccode%hpp% */
public:
void binary_union(
size_t this_target ,
size_t this_left ,
size_t other_right ,
const pack_setvec& other )
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( this_target < n_set_ );
CPPAD_ASSERT_UNKNOWN( this_left < n_set_ );
CPPAD_ASSERT_UNKNOWN( other_right < other.n_set_ );
CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ );
size_t t = this_target * n_pack_;
size_t l = this_left * n_pack_;
size_t r = other_right * n_pack_;
size_t j = n_pack_;
while(j--)
data_[t++] = ( data_[l++] | other.data_[r++] );
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_binary_intersection$$
$spell
setvec
$$
$section class pack_setvec: Assign a Set To Intersection of Two Sets$$
$head SetVector Concept$$
$cref/binary_intersection/SetVector/binary_intersection/$$
$head Prototype$$
$srccode%hpp% */
public:
void binary_intersection(
size_t this_target ,
size_t this_left ,
size_t other_right ,
const pack_setvec& other )
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( this_target < n_set_ );
CPPAD_ASSERT_UNKNOWN( this_left < n_set_ );
CPPAD_ASSERT_UNKNOWN( other_right < other.n_set_ );
CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ );
size_t t = this_target * n_pack_;
size_t l = this_left * n_pack_;
size_t r = other_right * n_pack_;
size_t j = n_pack_;
while(j--)
data_[t++] = ( data_[l++] & other.data_[r++] );
}
// ==========================================================================
}; // END_CLASS_PACK_SETVEC
// ==========================================================================
// =========================================================================
class pack_setvec_const_iterator { // BEGIN_CLASS_PACK_SETVEC_CONST_ITERATOR
// =========================================================================
/*
$begin pack_setvec_const_iterator_member_data$$
$spell
setvec
const_iterator
$$
$section class pack_setvec_const_iterator private: Member Data$$
$head Pack$$
This is the same type as
$cref/pack_setvec Pack/pack_setvec_member_data/Pack/$$.
$head n_bit_$$
This is a reference to
$cref/pack_setvec n_bit_/pack_setvec_member_data/n_bit_/$$.
$head one_$$
This is a reference to
$cref/pack_setvec one_/pack_setvec_member_data/one_/$$.
$head n_pack_$$
This is a reference to
$cref/pack_setvec n_pack_/pack_setvec_member_data/n_pack_/$$.
$head end_$$
This is a reference to
$cref/pack_setvec end_/pack_setvec_member_data/end_/$$.
$head data_$$
This is a reference to
$cref/pack_setvec data_/pack_setvec_member_data/data_/$$.
$head data_index_$$
Index in $code data_$$ where the next element is located.
$head next_element$$
Value of the next element in this set
If $code next_element_$$ equals $code end_$$,
no next element exists; i.e., past end of the set.
$head Source Code$$
$srccode%hpp% */
private:
typedef pack_setvec::Pack Pack;
const size_t& n_bit_;
const Pack& one_;
const size_t& n_pack_;
const size_t& end_;
const pod_vector<Pack>& data_;
size_t data_index_;
size_t next_element_;
public:
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_const_iterator_ctor$$
$spell
setvec
const_iterator
$$
$section class pack_setvec_const_iterator: Constructor$$
$head SetVector Concept$$
$cref/iterator constructor/SetVector/const_iterator/Constructor/$$
$head Prototype$$
$srccode%hpp% */
public:
pack_setvec_const_iterator (const pack_setvec& pack, size_t set_index)
/* %$$
$end
*/
:
n_bit_ ( pack.n_bit_ ) ,
one_ ( pack.one_ ) ,
n_pack_ ( pack.n_pack_ ) ,
end_ ( pack.end_ ) ,
data_ ( pack.data_ ) ,
data_index_ ( set_index * n_pack_ )
{ CPPAD_ASSERT_UNKNOWN( set_index < pack.n_set_ );
CPPAD_ASSERT_UNKNOWN( 0 < end_ );
//
next_element_ = 0;
if( data_[data_index_] & one_ )
return;
//
// element with index zero is not in this set of integers,
// advance to first element or end
++(*this);
}
/*
-------------------------------------------------------------------------------
$begin pack_setvec_const_iterator_dereference$$
$spell
setvec
const_iterator
Dereference
$$
$section class pack_setvec_const_iterator: Dereference$$
$head SetVector Concept$$
$cref/iterator deference/SetVector/const_iterator/Dereference/$$
$head Implementation$$
$srccode%hpp% */
size_t operator*(void) const
{ return next_element_; }
/* %$$
$end
-------------------------------------------------------------------------------
$begin pack_setvec_const_iterator_increment$$
$spell
setvec
const_iterator
$$
$section class pack_setvec_const_iterator: Increment$$
$head SetVector Concept$$
$cref/iterator increment/SetVector/const_iterator/Increment/$$
$head Prototype$$
$srccode%hpp% */
public:
pack_setvec_const_iterator& operator++(void)
/* %$$
$end
*/
{ CPPAD_ASSERT_UNKNOWN( next_element_ <= end_ );
if( next_element_ == end_ )
return *this;
//
++next_element_;
if( next_element_ == end_ )
return *this;
//
// bit index corresponding to next element
size_t bit = next_element_ % n_bit_;
//
// check if we have advanced to the next data index
if( bit == 0 )
++data_index_;
//
// initialize mask
size_t mask = one_ << bit;
//
while( next_element_ < end_ )
{ // check if this element is in the set
if( data_[data_index_] & mask )
return *this;
//
// try next larger element
++next_element_;
++bit;
mask <<= 1;
//
// check if we must go to next packed data index
CPPAD_ASSERT_UNKNOWN( bit <= n_bit_ );
if( bit == n_bit_ )
{ // get next packed value
bit = 0;
mask = one_;
++data_index_;
}
}
CPPAD_ASSERT_UNKNOWN( next_element_ == end_ );
return *this;
}
// =========================================================================
}; // END_CLASS_PACK_SETVEC_CONST_ITERATOR
// =========================================================================
// Implemented after pack_setvec_const_iterator so can use it
inline void pack_setvec::print(void) const
{ std::cout << "pack_setvec:\n";
for(size_t i = 0; i < n_set(); i++)
{ std::cout << "set[" << i << "] = {";
const_iterator itr(*this, i);
while( *itr != end() )
{ std::cout << *itr;
if( *(++itr) != end() )
std::cout << ",";
}
std::cout << "}\n";
}
return;
}
// ----------------------------------------------------------------------------
/*
$begin sparsity_user2internal_pack_setvec$$
$spell
setvec
bool
$$
$section Copy A Boolean Sparsity Pattern To A pack_setvec Object$$
$head SetVector$$
is a $cref/simple vector/SimpleVector/$$ type with elements of type
$code bool$$ containing the input sparsity pattern.
$head internal$$
The input value of this object does not matter.
Upon return it contains the same sparsity pattern as $icode user$$
(or its transpose).
$head user$$
is the sparsity pattern we are copying to $icode internal$$.
$head n_set$$
is the number of sets in the output sparsity pattern $icode internal$$.
$head end$$
is the end value for the output sparsity pattern $icode internal$$.
$head transpose$$
If $icode transpose$$ is false,
element $icode j$$ is in the $th i$$ $icode internal$$ set if
$codei%
%user%[ %i% * %end% + %j% ]
%$$
Otherwise,
element $icode j$$ is in the $th i$$ $icode internal$$ set if
$codei%
%user%[ %i% * %n_set% + %j% ]
%$$
$head error_msg$$
is the error message to display if
$codei%
%n_set% * %end% != %user%.size()
%$$
$head Prototype$$
$srccode%hpp% */
template<class SetVector>
void sparsity_user2internal(
pack_setvec& internal ,
const SetVector& user ,
size_t n_set ,
size_t end ,
bool transpose ,
const char* error_msg )
/* %$$
$end
*/
{ CPPAD_ASSERT_KNOWN(size_t( user.size() ) == n_set * end, error_msg );
// size of internal sparsity pattern
internal.resize(n_set, end);
if( transpose )
{ // transposed pattern case
for(size_t j = 0; j < end; j++)
{ for(size_t i = 0; i < n_set; i++)
{ // no advantage to using post_element for pack_setvec
if( user[ j * n_set + i ] )
internal.add_element(i, j);
}
}
return;
}
else
{ for(size_t i = 0; i < n_set; i++)
{ for(size_t j = 0; j < end; j++)
{ // no advantage to using post_element for pack_setvec
if( user[ i * end + j ] )
internal.add_element(i, j);
}
}
}
return;
}
} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE
# endif

View File

@@ -0,0 +1,32 @@
-----------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
------------------------------------------------------------------------------
$begin pack_setvec$$
$spell
Namespace
CppAD
setvec
$$
$section Implement SetVector Using Packed Boolean Values$$
$head Namespace$$
This class is in the $code CppAD::local::sparse$$ namespace.
$head Public$$
The public member function for the $code list_setvec$$ class implement the
$cref SetVector$$ concept.
$childtable%
include/cppad/local/sparse/pack_setvec.hpp
%$$
$end

View File

@@ -0,0 +1,254 @@
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
$begin SetVector$$
$spell
dereference
itr
iterator
const
resize
vec
CppAD
bool
$$
$section C++ Concept: Vector of Sets With size_t Elements$$
$head Purpose$$
The main CppAD use of this C++ Concept is to compute sparsity patterns
as fast as possible.
It is also used for conditional expression optimization.
We refer to a type that supports this concept as $icode SetVector$$ below.
$head Vector Operations$$
$subhead Constructor$$
In the specifications below, $icode vec$$ and $icode other$$
are $icode SetVector$$ objects created using the default constructor; e.g.,
$codei%
%SetVector% %vec%, %other%;
%$$
After this constructor the vectors are empty; i.e.,
there are no sets in either vector.
The $code resize$$ for $icode vec$$ and $icode other$$ can
have different $cref/n_set/SetVector/Vector Operations/n_set/$$ values,
but must have the same $cref/end/SetVector/Vector Operations/end/$$ value.
$subhead resize$$
This operation has the following syntax:
$codei%
%vec%.resize(%n_set%, %end%)
%$$
The argument $icode n_set$$ has type $code size_t$$ and is the
number of sets in $icode vec$$.
The argument $icode end$$ has type $code size_t$$ and is greater than
any element allowed in any set in $icode vec$$.
Any information in $icode vec$$ before this operation is lost.
After this operation, all the sets in $icode vec$$ are empty.
If $icode n_set$$ is zero,
any allocated memory to keep track of this vector of sets is freed.
$subhead n_set$$
The syntax
$codei%
%n_set% = %vec%.n_set()
%$$
sets the $code size_t$$ value $icode n_set$$ equal to the
number of sets in $icode vec$$.
The $icode vec$$ object is $code const$$ for this operation.
$subhead end$$
The syntax
$codei%
%end% = %vec%.end()
%$$
sets the $code size_t$$ value $icode end$$ equal to the
end value for the sets in $icode vec$$.
(This is one greater than the maximum value for any element
in any set in $icode vec$$.)
The $icode vec$$ object is $code const$$ for this operation.
$subhead Assignment$$
The following
makes $icode vec$$ into a separate copy of $icode other$$:
$codei%
%vec% = %other%
%$$
The $icode other$$ object is $code const$$ for this operation.
$subhead swap$$
The following
exchanges to vector of sets in $icode vec$$ and $icode other$$:
$codei%
%vec%.swap(%other%)
%$$
$head number_elements$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$,
$codei%
%count% = %vec%.number_elements(%i%)
%$$
returns the $code size_t$$ value $icode count$$
equal to the number of elements in the $th i$$ set.
The $icode vec$$ object is $code const$$ for this operation.
It is an error to have postings to $th i$$ that have not been processed.
$head add_element$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$
and $icode element$$ is a $code size_t$$ value less than $icode end$$,
$codei%
%vec%.add_element(%i%, %element%)
%$$
adds the specified element to the $th i$$ set.
$head post_element$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$
and $icode element$$ is a $code size_t$$ value less than $icode end$$,
$codei%
%vec%.post_element(%i%, %element%)
%$$
post the specified element for addition to the $th i$$ set.
Posting multiple elements to one set and then processing them may be faster
than adding one element at a time.
It is an error to use $icode vec$$,
in a way that depends on the values in the $th i$$ set,
between a $code post_element$$ and the corresponding $code process_post$$.
$head process_post$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$,
$codei%
%vec%.process_post(%i%)
%$$
Processes all of the posts that have been made for the $th i$$ set; i.e.,
adds the posted elements to the set.
$head is_element$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$
and $icode element$$ is a $code size_t$$ value less than $icode end$$,
$codei%
%find% = %vec%.is_element(%i%, %element%)
%$$
returns the $code bool$$ value $icode find$$
which is true (false) if the specified element is in
(is not in) the $th i$$ set.
The $icode vec$$ object is $code const$$ for this operation.
$head clear$$
If $icode i$$ is a $code size_t$$ value less than $icode n_set$$,
$codei%
%vec%.clear(%i%)
%$$
assigns the empty set to the $th i$$ set.
It is OK to have postings to $th i$$ that have not been processed
(they are removed).
$head assignment$$
If $icode this_target$$ and $icode other_source$$
are $code size_t$$ with value less than the end value,
$codei%
%vec%.assignment(%this_target%, %other_source%, %other%)
%$$
sets the $icode this_target$$ set in $icode vec$$
equal to the $icode other_source$$ set in $icode other$$.
If $icode vec$$ and $icode other$$ are the same object,
this operation may save memory and time using smart pointers.
The $icode other$$ object is $code const$$ for this operation.
It is OK (is an error) to have postings to $icode this_target$$
($icode other_source$$) that have not been processed.
$head binary_union$$
If $icode this_target$$, $icode this_left$$, and $icode other_right$$
are $code size_t$$ with value less than the end value,
$codei%
%vec%.binary_union(
%this_target%, %this_left%, %other_right%, %other%
)
%$$
sets the $icode this_target$$ set in $icode vec$$ equal to the union of
the $icode this_left$$ set in $icode vec$$ and
the $icode other_right$$ set in $icode other$$.
If the resulting set is equal to the left set (right set),
this operation may use save memory and time using smart pointers
(provided $icode vec$$ and $icode other$$ are the same object),
The $icode other$$ object is $code const$$ for this operation.
It is OK (is an error) to have postings to $icode this_target$$
($icode this_left$$ and $code other_right$$) that have not been processed.
$head binary_intersection$$
If $icode this_target$$, $icode this_left$$, and $icode other_right$$
are $code size_t$$ with value less than the end value,
$codei%
%vec%.binary_intersection(
%this_target%, %this_left%, %other_right%, %other%
)
%$$
sets the $icode this_target$$ set in $icode vec$$ equal to the intersection of
the $icode this_left$$ set in $icode vec$$ and
the $icode other_right$$ set in $icode other$$.
If the resulting set is equal to the left set (right set),
this operation may use save memory and time using smart pointers
(provided $icode vec$$ and $icode other$$ are the same object),
The $icode other$$ object is $code const$$ for this operation.
It is OK (is an error) to have postings to $icode this_target$$
($icode this_left$$ and $code other_right$$) that have not been processed.
$head const_iterator$$
$subhead Constructor$$
Given a $icode SetVector$$ object $icode vec$$,
and a $code size_t$$ index $icode i$$,
a constant iterator $icode itr$$ is constructed as follows:
$codei%
%SetVector%::const_iterator %itr%(%vec%, %i%)
%$$
After this constructor, $icode itr$$ points to the first
(smallest) element in the $th i$$ set.
The $icode vec$$ object is $code const$$ for this operation.
It is an error to have postings to $th i$$ that have not been processed.
$subhead Dereference$$
The operation
$codei%
%element% = *%itr
%$$
sets the $code size_t$$ value $icode element$$ to the current element value.
If $icode element$$ is equal to value $icode%vec%.end()%$$,
we have iterated through all the elements of the set
($icode element$$ is not in the set).
It is an error to have postings to $th i$$ that have not been processed.
$subhead Increment$$
The operation $codei%++%itr%$$ points $icode itr$$ to the next larger
element in the set.
The increment operation is not defined when the value of
$codei%*%itr%$$ is equal to $icode%vec%.end()%$$.
The operation
$codei%
%element% = *(++%itr%)
%$$
increments the iterator $icode itr$$ and sets $icode element$$
to the deference after the increment (see dereference above).
It is an error to have postings to $th i$$ that have not been processed.
$head Implementation$$
$children%
include/cppad/local/sparse/list_setvec.omh%
include/cppad/local/sparse/pack_setvec.omh
%$$
$table
$rref list_setvec$$
$rref pack_setvec$$
$tend
$end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,317 @@
# ifndef CPPAD_LOCAL_SPARSE_UNARY_OP_HPP
# define CPPAD_LOCAL_SPARSE_UNARY_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE
namespace CppAD { namespace local { namespace sparse {
/*!
\file sparse_unary_op.hpp
Forward and reverse mode sparsity patterns for unary operators.
*/
/*!
Forward mode Jacobian sparsity pattern for all unary operators.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = fun(x)
\endverbatim
where fun is a C++ unary function, or it has the form
\verbatim
z = x op q
\endverbatim
where op is a C++ binary unary operator and q is a parameter.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e., z.
\param i_x
variable index corresponding to the argument for this operator;
i.e., x.
\param sparsity
\b Input: The set with index arg[0] in sparsity
is the sparsity bit pattern for x.
This identifies which of the independent variables the variable x
depends on.
\n
\n
\b Output: The set with index i_z in sparsity
is the sparsity bit pattern for z.
This identifies which of the independent variables the variable z
depends on.
\n
\par Checked Assertions:
\li i_x < i_z
*/
template <class Vector_set>
void for_jac_unary_op(
size_t i_z ,
size_t i_x ,
Vector_set& sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( i_x < i_z );
sparsity.assignment(i_z, i_x, sparsity);
}
/*!
Reverse mode Jacobian sparsity pattern for all unary operators.
The C++ source code corresponding to a unary operation has the form
\verbatim
z = fun(x)
\endverbatim
where fun is a C++ unary function, or it has the form
\verbatim
z = x op q
\endverbatim
where op is a C++ bianry operator and q is a parameter.
This routine is given the sparsity patterns
for a function G(z, y, ... )
and it uses them to compute the sparsity patterns for
\verbatim
H( x , w , u , ... ) = G[ z(x) , x , w , u , ... ]
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in sparsity corresponding to z.
\param i_x
variable index corresponding to the argument for this operator;
i.e. the row index in sparsity corresponding to x.
\param sparsity
\b Input:
The set with index i_z in sparsity
is the sparsity bit pattern for G with respect to the variable z.
\n
\b Input:
The set with index i_x in sparsity
is the sparsity bit pattern for G with respect to the variable x.
\n
\b Output:
The set with index i_x in sparsity
is the sparsity bit pattern for H with respect to the variable x.
\par Checked Assertions:
\li i_x < i_z
*/
template <class Vector_set>
void rev_jac_unary_op(
size_t i_z ,
size_t i_x ,
Vector_set& sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( i_x < i_z );
sparsity.binary_union(i_x, i_x, i_z, sparsity);
return;
}
// ---------------------------------------------------------------------------
/*!
Reverse mode Hessian sparsity pattern for linear unary operators.
The C++ source code corresponding to this operation is
\verbatim
z = fun(x)
\endverbatim
where fun is a linear functions; e.g. abs, or
\verbatim
z = x op q
\endverbatim
where op is a C++ binary operator and q is a parameter.
\copydetails CppAD::local::reverse_sparse_hessian_unary_op
*/
template <class Vector_set>
void rev_hes_lin_unary_op(
size_t i_z ,
size_t i_x ,
bool* rev_jacobian ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( i_x < i_z );
// check for no effect
if( ! rev_jacobian[i_z] )
return;
rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity);
rev_jacobian[i_x] = true;
return;
}
/*!
Reverse mode Hessian sparsity pattern for non-linear unary operators.
The C++ source code corresponding to this operation is
\verbatim
z = fun(x)
\endverbatim
where fun is a non-linear functions; e.g. sin. or
\verbatim
z = q / x
\endverbatim
where q is a parameter.
\copydetails CppAD::local::reverse_sparse_hessian_unary_op
*/
template <class Vector_set>
void rev_hes_nl_unary_op(
size_t i_z ,
size_t i_x ,
bool* rev_jacobian ,
const Vector_set& for_jac_sparsity ,
Vector_set& rev_hes_sparsity )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( i_x < i_z );
// check for no effect
if( ! rev_jacobian[i_z] )
return;
rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity);
rev_hes_sparsity.binary_union(i_x, i_x, i_x, for_jac_sparsity);
rev_jacobian[i_x] = true;
return;
}
// ---------------------------------------------------------------------------
/*
$begin for_hes_nl_unary_op$$
$spell
hes
nl
op
np
numvar
Jacobian
$$
$section Forward Hessian Sparsity for Non-linear Unary Operators$$
$head Syntax$$
$codei%local::for_hes_nl_unary_op(
%np1%, %numvar%, %i_v%, %for_sparsity%
)%$$
$head Prototype$$
$srcthisfile%
0%// BEGIN_for_hes_nl_unary_op%// END_for_hes_nl_unary_op%1
%$$
$head C++ Source$$
The C++ source code corresponding to this operation is
$codei%
%w% = %fun%( %v% )
%$$
where $icode fun$$ is a non-linear function.
$head np1$$
This is the number of independent variables plus one;
i.e. size of $icode x$$ plus one.
$head numvar$$
This is the total number of variables in the tape.
$head i_w$$
is the index of the variable corresponding to the result $icode w$$.
$head i_v$$
is the index of the variable corresponding to the argument $icode v$$.
$head for_sparsity$$
We have the conditions $icode%np1% = %for_sparsity%.end()%$$
and $icode%for_sparsity%.n_set() = %np1% + %numvar%$$.
$subhead Input Jacobian Sparsity$$
For $icode%i%= 0, ..., %i_w%-1%$$,
the $icode%np1%+%i%$$ row of $icode for_sparsity$$ is the Jacobian sparsity
for the $th i$$ variable. These values do not change.
Note that $icode%i%=0%$$ corresponds to a parameter and
the corresponding Jacobian sparsity is empty.
$subhead Input Hessian Sparsity$$
For $icode%j%=1, ..., %n%$$,
the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity
before including the function $latex w(x)$$.
$subhead Output Jacobian Sparsity$$
the $icode i_w$$ row of $icode for_sparsity$$ is the Jacobian sparsity
for the variable $icode w$$.
$subhead Output Hessian Sparsity$$
For $icode%j%=1, ..., %n%$$,
the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity
after including the function $latex w(x)$$.
$end
*/
// BEGIN_for_hes_nl_unary_op
template <class Vector_set>
void for_hes_nl_unary_op(
size_t np1 ,
size_t numvar ,
size_t i_w ,
size_t i_v ,
Vector_set& for_sparsity )
// END_for_hes_nl_unary_op
{ CPPAD_ASSERT_UNKNOWN( i_v < i_w );
CPPAD_ASSERT_UNKNOWN( i_w < numvar );
CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 );
CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar );
CPPAD_ASSERT_UNKNOWN( for_sparsity.number_elements(np1) == 0 );
// set Jacobian sparsity J(i_w)
for_sparsity.assignment(np1 + i_w, np1 + i_v, for_sparsity);
// set of independent variables that v depends on
typename Vector_set::const_iterator itr(for_sparsity, i_v + np1);
// loop over independent variables with non-zero partial for v
size_t i_x = *itr;
while( i_x < np1 )
{ // N(i_x) = N(i_x) union J(i_v)
for_sparsity.binary_union(i_x, i_x, i_v + np1, for_sparsity);
i_x = *(++itr);
}
return;
}
} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE
# endif

View File

@@ -0,0 +1,193 @@
# ifndef CPPAD_LOCAL_SQRT_OP_HPP
# define CPPAD_LOCAL_SQRT_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sqrt_op.hpp
Forward and reverse mode calculations for z = sqrt(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = SqrtOp.
The C++ source code corresponding to this operation is
\verbatim
z = sqrt(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op
*/
template <class Base>
void forward_sqrt_op(
size_t p ,
size_t q ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
size_t k;
if( p == 0 )
{ z[0] = sqrt( x[0] );
p++;
}
for(size_t j = p; j <= q; j++)
{
z[j] = Base(0.0);
for(k = 1; k < j; k++)
z[j] -= Base(double(k)) * z[k] * z[j-k];
z[j] /= Base(double(j));
z[j] += x[j] / Base(2.0);
z[j] /= z[0];
}
}
/*!
Multiple direction forward mode Taylor coefficient for op = SqrtOp.
The C++ source code corresponding to this operation is
\verbatim
z = sqrt(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_dir
*/
template <class Base>
void forward_sqrt_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to argument and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* z = taylor + i_z * num_taylor_per_var;
Base* x = taylor + i_x * num_taylor_per_var;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(0.0);
for(size_t k = 1; k < q; k++)
z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell];
z[m+ell] /= Base(double(q));
z[m+ell] += x[m+ell] / Base(2.0);
z[m+ell] /= z[0];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = SqrtOp.
The C++ source code corresponding to this operation is
\verbatim
z = sqrt(x)
\endverbatim
\copydetails CppAD::local::forward_unary1_op_0
*/
template <class Base>
void forward_sqrt_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
// Taylor coefficients corresponding to argument and result
Base* x = taylor + i_x * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = sqrt( x[0] );
}
/*!
Compute reverse mode partial derivatives for result of op = SqrtOp.
The C++ source code corresponding to this operation is
\verbatim
z = sqrt(x)
\endverbatim
\copydetails CppAD::local::reverse_unary1_op
*/
template <class Base>
void reverse_sqrt_op(
size_t d ,
size_t i_z ,
size_t i_x ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Taylor coefficients and partials corresponding to argument
Base* px = partial + i_x * nc_partial;
// Taylor coefficients and partials corresponding to result
const Base* z = taylor + i_z * cap_order;
Base* pz = partial + i_z * nc_partial;
Base inv_z0 = Base(1.0) / z[0];
// number of indices to access
size_t j = d;
size_t k;
while(j)
{
// scale partial w.r.t. z[j]
pz[j] = azmul(pz[j], inv_z0);
pz[0] -= azmul(pz[j], z[j]);
px[j] += pz[j] / Base(2.0);
for(k = 1; k < j; k++)
pz[k] -= azmul(pz[j], z[j-k]);
--j;
}
px[0] += azmul(pz[0], inv_z0) / Base(2.0);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,52 @@
# ifndef CPPAD_LOCAL_STD_SET_HPP
# define CPPAD_LOCAL_STD_SET_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
# include <cppad/local/define.hpp>
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
# include <cppad/utility/thread_alloc.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file std_set.hpp
Two constant standard sets (currently used for concept checking).
*/
/*!
A standard set with one element.
*/
template <class Scalar>
const std::set<Scalar>& one_element_std_set(void)
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
static std::set<Scalar> one;
if( one.empty() )
one.insert(1);
return one;
}
/*!
A standard set with a two elements.
*/
template <class Scalar>
const std::set<Scalar>& two_element_std_set(void)
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
static std::set<Scalar> two;
if( two.empty() )
{ two.insert(1);
two.insert(2);
}
return two;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,489 @@
# ifndef CPPAD_LOCAL_STORE_OP_HPP
# define CPPAD_LOCAL_STORE_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
$begin store_op_var$$
$spell
pv
vp
vv
Vec
op
var
isvar
ind
Taylor
arg
num
Addr
$$
$section Changing an Element in a Variable VecAD Vector$$
$head See Also$$
$cref/op_code_var store/op_code_var/Store/$$.
$head Syntax$$
$codei%forward_store_%IV%_op_0(
%i_z%,
%arg%,
%num_par%,
%parameter%,
%cap_order%,
%taylor%,
%vec_ad2isvar%,
%vec_ad2index%
)
%$$
where the index type $icode I$$ and the value being stored type $icode V$$
are $code p$$ (for parameter) or $code v$$ (for variable).
$head Prototype$$
$srcthisfile%
0%// BEGIN_FORWARD_STORE_PP_OP_0%// END_FORWARD_STORE_PP_OP_0%1
%$$
The prototype for
$code forward_store_pv_op_0$$,
$code forward_store_vp_op_0$$, and
$code forward_store_vv_op_0$$,
are the same except for the function name.
$head Notation$$
$subhead v$$
We use $icode v$$ to denote the $cref VecAD$$ vector for this operation.
$subhead x$$
We use $icode x$$ to denote the $codei%AD%<%Base%>%$$
index for this operation.
$subhead i_vec$$
We use $icode i_vec$$ to denote the $code size_t$$ value
corresponding to $icode x$$.
$subhead n_load$$
This is the number of load instructions in this recording.
$subhead n_all$$
This is the number of values in the single array that includes
all the vectors together with the size of each vector.
$head Base$$
base type for the operator; i.e., this operation was recorded
using AD<Base> and computations by this routine are done using type Base.
$head i_z$$
is the AD variable index corresponding to the result of this load operation.
$head arg$$
$subhead arg[0]$$
is the offset of this VecAD vector relative to the beginning
of the $icode vec_ad2isvar$$ and $icode vec_ad2index$$ arrays.
$subhead arg[1]$$
If this is
$code forward_load_p_op_0$$ ($code forward_load_v_op_0$$)
$icode%arg%[%1%]%$$ is the parameter index (variable index)
corresponding to $cref/i_vec/load_op_var/Notation/i_vec/$$.
$subhead arg[2]$$
Is the index of this VecAD load instruction in the
$icode load_op2var$$ array.
$head num_par$$
is the number of parameters in this recording.
$head parameter$$
This is the vector of parameters for this recording which has size
$icode num_par$$.
$head cap_order$$
number of columns in the matrix containing the Taylor coefficients.
$head taylor$$
Is the matrix of Taylor coefficients for all the variables.
$head vec_ad2isvar$$
This vector has size $icode n_all$$ and
the input values of its elements does not matter.
If the value being stored is a parameter (variable),
$icode%vec_ad2isvar%[ %arg%[0] + %i_vec% ]%$$
is set to false (true).
$head vec_ad2index$$
This array has size $icode n_all$$
and the input value of its elements does not matter.
If the value being stored is a parameter (variable),
$icode%vec_ad2index%[ %arg%[0] + %i_vec% ]%$$
is set to the parameter (variable) index
corresponding to the value being stored.
$end
*/
// BEGIN_FORWARD_STORE_PP_OP_0
template <class Base>
void forward_store_pp_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
bool* vec_ad2isvar ,
size_t* vec_ad2index )
// END_FORWARD_STORE_PP_OP_0
{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) );
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: zero order forward dynamic parameter index out of range"
);
CPPAD_ASSERT_UNKNOWN( NumArg(StppOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(StppOp) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
vec_ad2isvar[ arg[0] + i_vec ] = false;
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
}
template <class Base>
void forward_store_pv_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
bool* vec_ad2isvar ,
size_t* vec_ad2index )
{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) );
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: zero order forward dynamic parameter index out of range"
);
CPPAD_ASSERT_UNKNOWN( NumArg(StpvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(StpvOp) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
vec_ad2isvar[ arg[0] + i_vec ] = true;
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
}
template <class Base>
void forward_store_vp_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
const Base* taylor ,
bool* vec_ad2isvar ,
size_t* vec_ad2index )
{
addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] ));
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: zero order forward variable index out of range"
);
CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
vec_ad2isvar[ arg[0] + i_vec ] = false;
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
}
template <class Base>
void forward_store_vv_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
const Base* taylor ,
bool* vec_ad2isvar ,
size_t* vec_ad2index )
{
addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] ));
CPPAD_ASSERT_KNOWN(
size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] ,
"VecAD: index during zero order forward sweep is out of range"
);
CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
vec_ad2isvar[ arg[0] + i_vec ] = true;
vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]);
}
// ---------------------------------------------------------------------------
/*
==============================================================================
<!-- define preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_v_x = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
==============================================================================
*/
/*!
Shared documnetation for sparsity operations corresponding to
op = StpvOp or StvvOp (not called).
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse::pack_setvec or sparse::list_setvec.
\param op
is the code corresponding to this operator;
i.e., StpvOp, StvpOp, or StvvOp.
\param arg
\n
arg[0]
is the offset corresponding to this VecAD vector in the combined array.
\n
\n
arg[2]
\n
The set with index arg[2] in var_sparsity
is the sparsity pattern corresponding to y.
(Note that arg[2] > 0 because y is a variable.)
\param num_combined
is the total number of elements in the VecAD address array.
\param combined
combined [ arg[0] - 1 ]
is the index of the set in vecad_sparsity corresponding
to the sparsity pattern for the vector v.
We use the notation i_v below which is defined by
\verbatim
i_v = combined[ arg[0] - 1 ]
\endverbatim
\param var_sparsity
The set with index arg[2] in var_sparsity
is the sparsity pattern for y.
This is an input for forward mode operations.
For reverse mode operations:
The sparsity pattern for v is added to the spartisy pattern for y.
\param vecad_sparsity
The set with index i_v in vecad_sparsity
is the sparsity pattern for v.
This is an input for reverse mode operations.
For forward mode operations, the sparsity pattern for y is added
to the sparsity pattern for the vector v.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 0
\li 0 < arg[0]
\li arg[0] < num_combined
\li arg[2] < var_sparsity.n_set()
\li i_v < vecad_sparsity.n_set()
*/
template <class Vector_set>
void sparse_store_op(
OpCode op ,
const addr_t* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
// This routine is only for documentaiton, it should not be used
CPPAD_ASSERT_UNKNOWN( false );
}
/*!
Forward mode sparsity operations for StpvOp and StvvOp
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_v_x = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
\param dependency
is this a dependency (or sparsity) calculation.
\copydetails CppAD::local::sparse_store_op
*/
template <class Vector_set>
void forward_sparse_store_op(
bool dependency ,
OpCode op ,
const addr_t* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
if( dependency & ( (op == StvvOp) | (op == StvpOp) ) )
vecad_sparsity.binary_union(i_v, i_v, size_t(arg[1]), var_sparsity);
if( (op == StpvOp) | (op == StvvOp ) )
vecad_sparsity.binary_union(i_v, i_v, size_t(arg[2]), var_sparsity);
return;
}
/*!
Reverse mode sparsity operations for StpvOp, StvpOp, and StvvOp
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_v_x = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
This routine is given the sparsity patterns for
G(v[x], y , w , u ... ) and it uses them to compute the
sparsity patterns for
\verbatim
H(y , w , u , ... ) = G[ v[x], y , w , u , ... ]
\endverbatim
\param dependency
is this a dependency (or sparsity) calculation.
\copydetails CppAD::local::sparse_store_op
*/
template <class Vector_set>
void reverse_sparse_jacobian_store_op(
bool dependency ,
OpCode op ,
const addr_t* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
if( dependency & ( (op == StvpOp) | (op == StvvOp) ) )
var_sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_v, vecad_sparsity);
if( (op == StpvOp) | (op == StvvOp) )
var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity);
return;
}
/*!
Reverse mode sparsity operations for StpvOp and StvvOp
<!-- replace preamble -->
The C++ source code corresponding to this operation is
\verbatim
v[x] = y
\endverbatim
where v is a VecAD<Base> vector, x is an AD<Base> object,
and y is AD<Base> or Base objects.
We define the index corresponding to v[x] by
\verbatim
i_v_x = vec_ad2index[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
This routine is given the sparsity patterns for
G(v[x], y , w , u ... )
and it uses them to compute the sparsity patterns for
\verbatim
H(y , w , u , ... ) = G[ v[x], y , w , u , ... ]
\endverbatim
\copydetails CppAD::local::sparse_store_op
\param var_jacobian
var_jacobian[ arg[2] ]
is false (true) if the Jacobian of G with respect to y is always zero
(may be non-zero).
\param vecad_jacobian
vecad_jacobian[i_v]
is false (true) if the Jacobian with respect to x is always zero
(may be non-zero).
On input, it corresponds to the function G,
and on output it corresponds to the function H.
*/
template <class Vector_set>
void reverse_sparse_hessian_store_op(
OpCode op ,
const addr_t* arg ,
size_t num_combined ,
const size_t* combined ,
Vector_set& var_sparsity ,
Vector_set& vecad_sparsity ,
bool* var_jacobian ,
bool* vecad_jacobian )
{
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined );
size_t i_v = combined[ arg[0] - 1 ];
CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() );
var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity);
var_jacobian[ arg[2] ] |= vecad_jacobian[i_v];
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

View File

@@ -0,0 +1,500 @@
# ifndef CPPAD_LOCAL_SUB_OP_HPP
# define CPPAD_LOCAL_SUB_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
CppAD is distributed under the terms of the
Eclipse Public License Version 2.0.
This Source Code may also be made available under the following
Secondary License when the conditions for such availability set forth
in the Eclipse Public License, Version 2.0 are satisfied:
GNU General Public License, Version 2.0 or later.
---------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sub_op.hpp
Forward and reverse mode calculations for z = x - y.
*/
// --------------------------- Subvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_subvv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
for(size_t d = p; d <= q; d++)
z[d] = x[d] - y[d];
}
/*!
Multiple directions forward mode Taylor coefficients for op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_subvv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var + m;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m;
Base* z = taylor + i_z * num_taylor_per_var + m;
for(size_t ell = 0; ell < r; ell++)
z[ell] = x[ell] - y[ell];
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_subvv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] - y[0];
}
/*!
Compute reverse mode partial derivatives for result of op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_subvv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t i = d + 1;
while(i)
{ --i;
px[i] += pz[i];
py[i] -= pz[i];
}
}
// --------------------------- Subpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = SubpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_subpv_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Paraemter value
Base x = parameter[ arg[0] ];
if( p == 0 )
{ z[0] = x - y[0];
p++;
}
for(size_t d = p; d <= q; d++)
z[d] = - y[d];
}
/*!
Multiple directions forward mode Taylor coefficients for op = SubpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_subpv_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
size_t m = (q-1) * r + 1;
Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m;
Base* z = taylor + i_z * num_taylor_per_var + m;
// Paraemter value
for(size_t ell = 0; ell < r; ell++)
z[ell] = - y[ell];
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = SubpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_subpv_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + size_t(arg[1]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x - y[0];
}
/*!
Compute reverse mode partial derivative for result of op = SubpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a parameter and y is a variable.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_subpv_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Partial derivatives corresponding to arguments and result
Base* py = partial + size_t(arg[1]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t i = d + 1;
while(i)
{ --i;
py[i] -= pz[i];
}
}
// --------------------------- Subvp -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
void forward_subvp_op(
size_t p ,
size_t q ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z = taylor + i_z * cap_order;
// Parameter value
Base y = parameter[ arg[1] ];
if( p == 0 )
{ z[0] = x[0] - y;
p++;
}
for(size_t d = p; d <= q; d++)
z[d] = x[d];
}
/*!
Multiple directions forward mode Taylor coefficients for op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
void forward_subvp_op_dir(
size_t q ,
size_t r ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
// Taylor coefficients corresponding to arguments and result
size_t num_taylor_per_var = (cap_order-1) * r + 1;
Base* x = taylor + size_t(arg[0]) * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
// Parameter value
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
z[m+ell] = x[m+ell];
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = SubvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
void forward_subvp_op_0(
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 );
// Parameter value
Base y = parameter[ arg[1] ];
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + size_t(arg[0]) * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = x[0] - y;
}
/*!
Compute reverse mode partial derivative for result of op = SubvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = x - y
\endverbatim
In the documentation below,
this operations is for the case where x is a variable and y is a parameter.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
void reverse_subvp_op(
size_t d ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Partial derivatives corresponding to arguments and result
Base* px = partial + size_t(arg[0]) * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t i = d + 1;
while(i)
{ --i;
px[i] += pz[i];
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif

Some files were not shown because too many files have changed in this diff Show More