external folder

This commit is contained in:
George Hotz
2020-01-17 10:33:21 -08:00
parent 23c2d02682
commit 6abffe0ede
578 changed files with 140675 additions and 0 deletions
+160
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+263
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+265
View File
@@ -0,0 +1,265 @@
# ifndef CPPAD_LOCAL_ACOSH_OP_HPP
# define CPPAD_LOCAL_ACOSH_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
# endif
+219
View File
@@ -0,0 +1,219 @@
# ifndef CPPAD_LOCAL_AD_TAPE_HPP
# define CPPAD_LOCAL_AD_TAPE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/core/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 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
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);
friend AD<Base> CppAD::operator / <Base>
(const AD<Base> &left, const AD<Base> &right);
// comparison operators
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);
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 Base &x);
// 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
);
// place a VecAD object in the tape
size_t AddVec(
size_t length,
const pod_vector<Base>& data
);
public:
// default constructor and destructor
// public function only used by CppAD::Independent
template <typename VectorADBase>
void Independent(VectorADBase &u);
template <typename VectorADBase>
void Independent(VectorADBase &u, size_t abort_op_index);
};
// ---------------------------------------------------------------------------
// Private functions
//
/*!
Place a parameter in the tape.
On rare occations it is necessary to place a parameter in the tape; e.g.,
when it is one of the dependent variabes.
\param z
value of the parameter that we are placing in the tape.
\return
variable index (for this recording) correpsonding to the parameter.
\par 2DO
All these operates are preformed in \c 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 Base &z)
{ addr_t z_taddr;
addr_t ind;
CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumArg(ParOp) == 1 );
z_taddr = Rec_.PutOp(ParOp);
ind = Rec_.PutPar(z);
Rec_.PutArg(ind);
return z_taddr;
}
/*!
Put initialization for a VecAD<Base> object in the tape.
This routine should be called once for each VecAD object when just
before it changes from a parameter to a variable.
\param length
size of the <tt>VecAD<Base></tt> object.
\param data
initial values for the <tt>VecAD<Base></tt> object
(values before it becomes a variable).
\return
index of the start of this vector in the list of vector indices.
The value for this vector index is the length of the vector.
There are \c length indices following for this vector.
The values for these vector indices are the corresponding
parameter indices in the tape for the initial value of the corresponding
vec_ad element.
\par 2DO
All these operates are preformed in \c Rec_, so we should
move this routine from <tt>ADTape<Base></tt> to <tt>recorder<Base></tt>.
*/
template <class Base>
size_t ADTape<Base>::AddVec(size_t length, const pod_vector<Base>& data)
{ CPPAD_ASSERT_UNKNOWN( length > 0 );
size_t i;
size_t value_index;
// store the length in VecInd
size_t start = Rec_.PutVecInd(length);
// store indices of the values in VecInd
for(i = 0; i < length; i++)
{
value_index = Rec_.PutPar( data[i] );
Rec_.PutVecInd( value_index );
}
// return the taddr of the length (where the vector starts)
return start;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+339
View File
@@ -0,0 +1,339 @@
// $Id: add_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_ADD_OP_HPP
# define CPPAD_LOCAL_ADD_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
inline 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 + arg[0] * num_taylor_per_var;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
inline 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 + arg[0] * nc_partial;
Base* py = partial + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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
+263
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+265
View File
@@ -0,0 +1,265 @@
# ifndef CPPAD_LOCAL_ASINH_OP_HPP
# define CPPAD_LOCAL_ASINH_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
# endif
+235
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+237
View File
@@ -0,0 +1,237 @@
# ifndef CPPAD_LOCAL_ATANH_OP_HPP
# define CPPAD_LOCAL_ATANH_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
# endif
+295
View File
@@ -0,0 +1,295 @@
# ifndef CPPAD_LOCAL_COLOR_GENERAL_HPP
# define CPPAD_LOCAL_COLOR_GENERAL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# 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 VectorSize
is a simple vector class with elements of type size_t.
\tparam VectorSet
is an unspecified type with the exception that it must support the
operations under pattern and the following operations where
p is a VectorSet object:
\n
<code>VectorSet p</code>
Constructs a new vector of sets object.
\n
<code>p.resize(ns, ne)</code>
resizes \c p to \c ns sets with elements between zero \c ne.
All of the \c ns sets are initially empty.
\n
<code>p.add_element(s, e)</code>
add element \c e to set with index \c s.
\param pattern [in]
Is a representation of the sparsity pattern for the matrix.
\n
<code>m = pattern.n_set()</code>
\n
sets \c m to the number of rows in the sparse matrix.
All of the row indices are less than this value.
\n
<code>n = pattern.end()</code>
\n
sets \c n to the number of columns in the sparse matrix.
All of the column indices are less than this value.
\n
<code>VectorSet::const_iterator itr(pattern, i)</code>
constructs an iterator that starts iterating over
columns in the i-th row of the sparsity pattern.
\n
<code>j = *itr</code>
Sets j to the next possibly non-zero column.
\n
<code>++itr</code>
Advances to the next possibly non-zero column.
\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 VectorSet, class VectorSize>
void color_general_cppad(
const VectorSet& pattern ,
const VectorSize& row ,
const VectorSize& col ,
CppAD::vector<size_t>& color )
{ size_t i, j, k, ell, r;
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(i = 0; i < m; i++)
row_appear[i] = false;
// rows and columns that appear
VectorSet c2r_appear, r2c_appear;
c2r_appear.resize(n, m);
r2c_appear.resize(m, n);
for(k = 0; k < K; k++)
{ CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k], col[k]) );
row_appear[ row[k] ] = true;
c2r_appear.add_element(col[k], row[k]);
r2c_appear.add_element(row[k], col[k]);
}
// for each column, which rows are non-zero and do not appear
VectorSet not_appear;
not_appear.resize(n, m);
for(i = 0; i < m; i++)
{ typename VectorSet::const_iterator pattern_itr(pattern, i);
j = *pattern_itr;
while( j != pattern.end() )
{ if( ! c2r_appear.is_element(j , i) )
not_appear.add_element(j, i);
j = *(++pattern_itr);
}
}
// initial coloring
color.resize(m);
ell = 0;
for(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(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 VectorSet::const_iterator pattern_itr(pattern, i);
j = *pattern_itr;
while( j != pattern.end() )
{ // for each row that appears with this column
typename VectorSet::const_iterator c2r_itr(c2r_appear, j);
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 VectorSet::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 VectorSet::const_iterator not_itr(not_appear, j);
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 VectorSet, class VectorSize>
void color_general_colpack(
const VectorSet& pattern ,
const VectorSize& row ,
const VectorSize& col ,
CppAD::vector<size_t>& color )
{ size_t i, j, k;
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(i = 0; i < m; i++)
{ n_nonzero[i] = 0;
typename VectorSet::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 VectorSet::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_general(color, m, n, adolc_pattern);
return;
}
# endif // CPPAD_HAS_COLPACK
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+344
View File
@@ -0,0 +1,344 @@
# 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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 VectorSize
is a simple vector class with elements of type size_t.
\tparam VectorSet
is an unspecified type with the exception that it must support the
operations under pattern and the following operations where
p is a VectorSet object:
\n
<code>VectorSet p</code>
Constructs a new vector of sets object.
\n
<code>p.resize(ns, ne)</code>
resizes \c p to ns sets with elements between zero and \c ne.
All of the sets are initially empty.
\n
<code>p.add_element(s, e)</code>
add element \c e to set with index \c s.
\param pattern [in]
Is a representation of the sparsity pattern for the matrix.
\n
<code>m = pattern.n_set()</code>
\n
sets m to the number of rows (and columns) in the sparse matrix.
All of the row indices are less than this value.
\n
<code>n = pattern.end()</code>
\n
sets n to the number of columns in the sparse matrix
(which must be equal to the number of rows).
All of the column indices are less than this value.
\n
<code>VectorSet::const_iterator itr(pattern, i)</code>
constructs an iterator that starts iterating over
columns in the i-th row of the sparsity pattern.
\n
<code>j = *itr</code>
Sets j to the next possibly non-zero column.
\n
<code>++itr</code>
Advances to the next possibly non-zero column.
\n
\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 \c 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 VectorSet>
void color_symmetric_cppad(
const VectorSet& pattern ,
CppAD::vector<size_t>& row ,
CppAD::vector<size_t>& col ,
CppAD::vector<size_t>& color )
{ size_t o1, o2, i1, i2, j1, j2, k1, c1, c2;
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(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(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(o1 = 0; o1 < m; o1++)
row2order[ order2row[o1] ] = o1;
// initial coloring
color.resize(m);
c1 = 0;
for(o1 = 0; o1 < m; o1++)
{ 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(o1 = 0; o1 < m; o1++) // for each row that appears (in order)
if( color[ order2row[o1] ] < m )
{ i1 = order2row[o1];
c1 = color[i1];
// initial all colors as ok for this row
// (value of forbidden for c > c1 does not matter)
for(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
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 VectorSet::const_iterator pattern_itr(pattern, j1);
i2 = *pattern_itr;
while( i2 != pattern.end() )
{ 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(o2 = 0; o2 < o1; o2++)
{ i2 = order2row[o2];
c2 = color[i2];
itr2 = pair_needed[i2].begin();
while( itr2 != pair_needed[i2].end() )
{ 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
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() )
{ 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(k1 = 0; k1 < row.size(); k1++)
{ i1 = row[k1];
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 VectorSet>
void color_symmetric_colpack(
const VectorSet& 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 VectorSet::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 VectorSet::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
size_t i1, i2, j1, j2, k1, k2;
for(k1 = 0; k1 < row.size(); k1++)
{ i1 = row[k1];
j1 = col[k1];
bool reflect = false;
for(i2 = 0; i2 < m; i2++) if( (i1 != i2) & (color[i1]==color[i2]) )
{ for(k2 = 1; k2 <= adolc_pattern[i2][0]; k2++)
{ 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
+305
View File
@@ -0,0 +1,305 @@
// $Id: comp_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_COMP_OP_HPP
# define CPPAD_LOCAL_COMP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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
taylor[ 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>
inline 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 + 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[ 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>
inline 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 + 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[ arg[0] * cap_order + 0 ] is the zero order Taylor coefficient
for the left operand and
taylor[ 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>
inline 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 + arg[0] * cap_order;
Base* y = taylor + arg[1] * cap_order;
count += GreaterThanZero(x[0] - y[0]);
}
// ------------------------------- < -------------------------------------
/*!
Zero order forward mode comparison check that left < right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
inline 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 + 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>
inline 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 + 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>
inline 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 + arg[0] * cap_order;
Base* y = taylor + arg[1] * cap_order;
count += GreaterThanOrZero(x[0] - y[0]);
}
// ------------------------------ == -------------------------------------
/*!
Zero order forward mode comparison check that left == right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
inline 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 + arg[1] * cap_order;
count += (x != y[0]);
}
/*!
Zero order forward mode comparison check that left == right
\copydetails CppAD::local::forward_levv_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + arg[1] * cap_order;
count += (x[0] != y[0]);
}
// -------------------------------- != -----------------------------------
/*!
Zero order forward mode comparison check that left != right
\copydetails CppAD::local::forward_lepv_op_0
*/
template <class Base>
inline 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 + arg[1] * cap_order;
count += (x == y[0]);
}
/*!
Zero order forward mode comparison check that left != right
\copydetails CppAD::local::forward_levv_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + arg[1] * cap_order;
count += (x[0] == y[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
File diff suppressed because it is too large Load Diff
+238
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+238
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+104
View File
@@ -0,0 +1,104 @@
// $Id: cppad_colpack.hpp 3845 2016-11-19 01:50:47Z bradbell $
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# ifndef CPPAD_LOCAL_CPPAD_COLPACK_HPP
# define CPPAD_LOCAL_CPPAD_COLPACK_HPP
# 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 \c m,
<code>adolc_pattern[i][0]</code> is the number of non-zeros in row \c 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 \c i.
\param color [out]
is a vector with size \c 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 \c 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 \c 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 \c n,
<code>adolc_pattern[i][0]</code> is the number of non-zeros in row \c 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 \c 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
+200
View File
@@ -0,0 +1,200 @@
# ifndef CPPAD_LOCAL_CSKIP_OP_HPP
# define CPPAD_LOCAL_CSKIP_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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
\a 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
\a arg[1] & 1
\n
If this is zero, left is an AD<Base> parameter.
Otherwise it is an AD<Base> variable.
\n
\n
\a arg[1] & 2
\n
If this is zero, right is an AD<Base> parameter.
Otherwise it is an AD<Base> variable.
\n
\a arg[2]
is the index corresponding to left in comparision.
\n
\a arg[3]
is the index corresponding to right in comparision.
\n
\a arg[4]
is the number of operations to skip if the comparision result is true.
\n
\a arg[5]
is the number of operations to skip if the comparision result is false.
\n
<tt>arg[5+i]</tt>
for <tt>i = 1 , ... , arg[4]</tt> are the operations to skip if the
comparision 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
comparision 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 [ arg[2] * cap_order + 0 ]</code>
is the zeroth order Taylor coefficient corresponding to left.
If right is an AD<Base> variable,
<code>taylor [ 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>
inline 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[ 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[ arg[3] * cap_order + 0 ];
}
else
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par );
right = parameter[ arg[3] ];
}
bool ok_to_skip = IdenticalPar(left) & IdenticalPar(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(size_t i = 0; i < size_t(arg[4]); i++)
cskip_op[ arg[6+i] ] = true;
}
else
{ for(size_t i = 0; i < size_t(arg[5]); i++)
cskip_op[ arg[6+arg[4]+i] ] = true;
}
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+623
View File
@@ -0,0 +1,623 @@
// $Id: csum_op.hpp 3845 2016-11-19 01:50:47Z bradbell $
# ifndef CPPAD_LOCAL_CSUM_OP_HPP
# define CPPAD_LOCAL_CSUM_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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(1) + ... + x(m) - y(1) - ... - y(n).
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a 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 \a taylor corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c s in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the variable index of <tt>x(i)</tt>.
\n
<tt>arg[2+arg[0]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the variable index of <tt>y(i)</tt>.
\param num_par
is the number of parameters in \a 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: <tt>taylor [ arg[2+i] * cap_order + k ]</tt>
for <tt>i = 1 , ... , m</tt>
and <tt>k = 0 , ... , q</tt>
is the k-th order Taylor coefficient corresponding to <tt>x(i)</tt>
\n
\b Input: <tt>taylor [ arg[2+m+i] * cap_order + k ]</tt>
for <tt>i = 1 , ... , n</tt>
and <tt>k = 0 , ... , q</tt>
is the k-th order Taylor coefficient corresponding to <tt>y(i)</tt>
\n
\b Input: <tt>taylor [ i_z * cap_order + k ]</tt>
for k = 0 , ... , p,
is the k-th order Taylor coefficient corresponding to z.
\n
\b Output: <tt>taylor [ i_z * cap_order + k ]</tt>
for k = p , ... , q,
is the \a k-th order Taylor coefficient corresponding to z.
*/
template <class Base>
inline 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);
size_t i, j, k;
// 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[2]) < num_par );
CPPAD_ASSERT_UNKNOWN(
arg[0] + arg[1] == arg[ arg[0] + arg[1] + 3 ]
);
// Taylor coefficients corresponding to result
Base* z = taylor + i_z * cap_order;
for(k = p; k <= q; k++)
z[k] = zero;
if( p == 0 )
z[p] = parameter[ arg[2] ];
Base* x;
i = arg[0];
j = 2;
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
x = taylor + arg[++j] * cap_order;
for(k = p; k <= q; k++)
z[k] += x[k];
}
i = arg[1];
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
x = taylor + arg[++j] * cap_order;
for(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(1) + ... + x(m) - y(1) - ... - y(n).
\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
\a 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 \a taylor corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c s in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the variable index of <tt>x(i)</tt>.
\n
<tt>arg[2+arg[0]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the variable index of <tt>y(i)</tt>.
\param num_par
is the number of parameters in \a 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: <tt>taylor [ arg[2+i]*((cap_order-1)*r + 1) + 0 ]</tt>
for <tt>i = 1 , ... , m</tt>
is the 0-th order Taylor coefficient corresponding to <tt>x(i)</tt> and
<tt>taylor [ arg[2+i]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ]</tt>
for <tt>i = 1 , ... , m</tt>,
<tt>ell = 0 , ... , r-1</tt>
is the q-th order Taylor coefficient corresponding to <tt>x(i)</tt>
and direction ell.
\n
\b Input: <tt>taylor [ arg[2+m+i]*((cap_order-1)*r + 1) + 0 ]</tt>
for <tt>i = 1 , ... , n</tt>
is the 0-th order Taylor coefficient corresponding to <tt>y(i)</tt> and
<tt>taylor [ arg[2+m+i]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ]</tt>
for <tt>i = 1 , ... , n</tt>,
<tt>ell = 0 , ... , r-1</tt>
is the q-th order Taylor coefficient corresponding to <tt>y(i)</tt>
and direction ell.
\n
\b Output: <tt>taylor [ i_z*((cap_order-1)*r+1) + (q-1)*r + ell + 1 ]</tt>
is the \a q-th order Taylor coefficient corresponding to z
for direction <tt>ell = 0 , ... , r-1</tt>.
*/
template <class Base>
inline 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);
size_t i, j, ell;
// 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[2]) < num_par );
CPPAD_ASSERT_UNKNOWN(
arg[0] + arg[1] == arg[ arg[0] + arg[1] + 3 ]
);
// 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(ell = 0; ell < r; ell++)
z[ell] = zero;
Base* x;
i = arg[0];
j = 2;
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
x = taylor + arg[++j] * num_taylor_per_var + m;
for(ell = 0; ell < r; ell++)
z[ell] += x[ell];
}
i = arg[1];
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
x = taylor + arg[++j] * num_taylor_per_var + m;
for(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(1) + ... + x(m) - y(1) - ... - y(n).
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< \a Base > and computations by this routine are done using type
\a 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 \a taylor corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c q in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the value <tt>x(i)</tt>.
\n
<tt>arg[2+arg[0]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the value <tt>y(i)</tt>.
\param nc_partial
number of colums in the matrix containing all the partial derivatives.
\param partial
\b Input: <tt>partial [ arg[2+i] * nc_partial + k ]</tt>
for <tt>i = 1 , ... , m</tt>
and <tt>k = 0 , ... , d</tt>
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to <tt>x(i)</tt>
\n
\b Input: <tt>partial [ arg[2+m+i] * nc_partial + k ]</tt>
for <tt>i = 1 , ... , n</tt>
and <tt>k = 0 , ... , d</tt>
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to <tt>y(i)</tt>
\n
\b Input: <tt>partial [ i_z * nc_partial + k ]</tt>
for <tt>i = 1 , ... , n</tt>
and <tt>k = 0 , ... , d</tt>
is the partial derivative of G(z, y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to \c z.
\n
\b Output: <tt>partial [ arg[2+i] * nc_partial + k ]</tt>
for <tt>i = 1 , ... , m</tt>
and <tt>k = 0 , ... , d</tt>
is the partial derivative of H(y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to <tt>x(i)</tt>
\n
\b Output: <tt>partial [ arg[2+m+i] * nc_partial + k ]</tt>
for <tt>i = 1 , ... , n</tt>
and <tt>k = 0 , ... , d</tt>
is the partial derivative of H(y, x, w, ...) with respect to the
k-th order Taylor coefficient corresponding to <tt>y(i)</tt>
*/
template <class Base>
inline 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 i, j, k;
size_t d1 = d + 1;
i = arg[0];
j = 2;
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
px = partial + arg[++j] * nc_partial;
k = d1;
while(k--)
px[k] += pz[k];
}
i = arg[1];
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
px = partial + arg[++j] * nc_partial;
k = d1;
while(k--)
px[k] -= pz[k];
}
}
/*!
Forward mode Jacobian sparsity pattern for CSumOp operator.
This operation is
\verbatim
z = q + x(1) + ... + x(m) - y(1) - ... - y(n).
\endverbatim
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in \a sparsity corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m + n</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c q in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the value <tt>x(i)</tt>.
\n
<tt>arg[2+arg[1]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the value <tt>y(i)</tt>.
\param sparsity
\b Input:
For <tt>i = 1 , ... , m</tt>,
the set with index \a arg[2+i] in \a sparsity
is the sparsity bit pattern for <tt>x(i)</tt>.
This identifies which of the independent variables the variable
<tt>x(i)</tt> depends on.
\n
\b Input:
For <tt>i = 1 , ... , n</tt>,
the set with index \a arg[2+arg[0]+i] in \a sparsity
is the sparsity bit pattern for <tt>x(i)</tt>.
This identifies which of the independent variables the variable
<tt>y(i)</tt> depends on.
\n
\b Output:
The set with index \a i_z in \a sparsity
is the sparsity bit pattern for z.
This identifies which of the independent variables the variable z
depends on.
*/
template <class Vector_set>
inline void forward_sparse_jacobian_csum_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{ sparsity.clear(i_z);
size_t i, j;
i = arg[0] + arg[1];
j = 2;
while(i--)
{ CPPAD_ASSERT_UNKNOWN( size_t(arg[j+1]) < i_z );
sparsity.binary_union(
i_z , // index in sparsity for result
i_z , // index in sparsity for left operand
arg[++j] , // 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(1) + ... + x(m) - y(1) - ... - y(n).
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 or sparse_list.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in \a sparsity corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m + n</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c q in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the value <tt>x(i)</tt>.
\n
<tt>arg[2+arg[1]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the value <tt>y(i)</tt>.
\param sparsity
For <tt>i = 1 , ... , m</tt>,
the set with index \a arg[2+i] in \a sparsity
is the sparsity bit pattern for <tt>x(i)</tt>.
This identifies which of the dependent variables depend on <tt>x(i)</tt>.
On input, the sparsity patter corresponds to \c G,
and on ouput it corresponds to \c H.
\n
For <tt>i = 1 , ... , m</tt>,
the set with index \a arg[2+arg[0]+i] in \a sparsity
is the sparsity bit pattern for <tt>y(i)</tt>.
This identifies which of the dependent variables depend on <tt>y(i)</tt>.
On input, the sparsity patter corresponds to \c G,
and on ouput it corresponds to \c H.
\n
\b Input:
The set with index \a i_z in \a sparsity
is the sparsity bit pattern for z.
On input it corresponds to \c G and on output it is undefined.
*/
template <class Vector_set>
inline void reverse_sparse_jacobian_csum_op(
size_t i_z ,
const addr_t* arg ,
Vector_set& sparsity )
{
size_t i, j;
i = arg[0] + arg[1];
j = 2;
while(i--)
{ ++j;
CPPAD_ASSERT_UNKNOWN( size_t(arg[j]) < i_z );
sparsity.binary_union(
arg[j] , // index in sparsity for result
arg[j] , // 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(1) + ... + x(m) - y(1) - ... - y(n).
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 or sparse_list.
\param i_z
variable index corresponding to the result for this operation;
i.e. the index in \a sparsity corresponding to z.
\param arg
\a arg[0]
is the number of addition variables in this cummulative summation; i.e.,
<tt>m + n</tt>.
\n
\a arg[1]
is the number of subtraction variables in this cummulative summation; i.e.,
\c m.
\n
<tt>parameter[ arg[2] ]</tt>
is the parameter value \c q in this cummunative summation.
\n
<tt>arg[2+i]</tt>
for <tt>i = 1 , ... , m</tt> is the value <tt>x(i)</tt>.
\n
<tt>arg[2+arg[0]+i]</tt>
for <tt>i = 1 , ... , n</tt> is the value <tt>y(i)</tt>.
\param rev_jacobian
<tt>rev_jacobian[i_z]</tt>
is all false (true) if the Jabobian of G with respect to z must be zero
(may be non-zero).
\n
\n
For <tt>i = 1 , ... , m</tt>
<tt>rev_jacobian[ arg[2+i] ]</tt>
is all false (true) if the Jacobian with respect to <tt>x(i)</tt>
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 <tt>i = 1 , ... , n</tt>
<tt>rev_jacobian[ arg[2+arg[0]+i] ]</tt>
is all false (true) if the Jacobian with respect to <tt>y(i)</tt>
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 \a i_z in in \a 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 <tt>i = 1 , ... , m</tt>
The set with index <tt>arg[2+i]</tt> in \a rev_hes_sparsity
is the Hessian sparsity pattern
where one of the partials derivative is with respect to <tt>x(i)</tt>.
On input, it corresponds to the function G,
and on output it corresponds to the function H.
\n
\n
For <tt>i = 1 , ... , n</tt>
The set with index <tt>arg[2+arg[0]+i]</tt> in \a rev_hes_sparsity
is the Hessian sparsity pattern
where one of the partials derivative is with respect to <tt>y(i)</tt>.
On input, it corresponds to the function G,
and on output it corresponds to the function H.
*/
template <class Vector_set>
inline void reverse_sparse_hessian_csum_op(
size_t i_z ,
const addr_t* arg ,
bool* rev_jacobian ,
Vector_set& rev_hes_sparsity )
{
size_t i, j;
i = arg[0] + arg[1];
j = 2;
while(i--)
{ ++j;
CPPAD_ASSERT_UNKNOWN( size_t(arg[j]) < i_z );
rev_hes_sparsity.binary_union(
arg[j] , // index in sparsity for result
arg[j] , // index in sparsity for left operand
i_z , // index for right operand
rev_hes_sparsity // sparsity vector for right operand
);
rev_jacobian[arg[j]] |= rev_jacobian[i_z];
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+177
View File
@@ -0,0 +1,177 @@
# ifndef CPPAD_LOCAL_DECLARE_AD_HPP
# define CPPAD_LOCAL_DECLARE_AD_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/configure.hpp>
# if CPPAD_USE_CPLUSPLUS_2011
# include <cstdint>
# endif
/*!
\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 ADFun;
template <class Base> class atomic_base;
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 Parameter (const VecAD<Base> &u);
template <class Base> bool Variable (const VecAD<Base> &u);
// functions with one AD<Base> argument
template <class Base> int Integer (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> bool IdenticalZero (const AD<Base> &u);
template <class Base> bool IdenticalOne (const AD<Base> &u);
template <class Base> bool IdenticalPar (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);
// 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
);
// IdenticalEqualPar
template <class Base>
bool IdenticalEqualPar (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
+121
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-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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< \a Base > and computations by this routine are done using type
\a 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 \a taylor corresponding to z.
\param arg
\a arg[0]
\n
is the index, in the order of the discrete functions defined by the user,
for this discrete function.
\n
\n
\a arg[1]
variable index corresponding to the argument for this operator;
i.e. the row index in \a 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>
inline 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 + arg[1] * num_taylor_per_var;
Base* z = taylor + i_z * num_taylor_per_var;
if( p == 0 )
{ z[0] = discrete<Base>::eval(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
+574
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-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
inline 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 + arg[0] * num_taylor_per_var;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
inline 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 + arg[1] * cap_order;
const Base* z = taylor + i_z * cap_order;
// Partial derivatives corresponding to arguments and result
Base* px = partial + arg[0] * nc_partial;
Base* py = partial + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + arg[1] * cap_order;
const Base* z = taylor + i_z * cap_order;
// Partial derivatives corresponding to arguments and result
Base* py = partial + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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
+564
View File
@@ -0,0 +1,564 @@
# ifndef CPPAD_LOCAL_ERF_OP_HPP
# define CPPAD_LOCAL_ERF_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# 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).
*/
/*!
Forward mode Taylor coefficient for result of op = ErfOp.
The C++ source code corresponding to this operation is
\verbatim
z = erf(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\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 \a taylor corresponding to z.
The auxillary results are called y_j have index \a 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 \c taylor array.
\param taylor
\b Input:
taylor [ 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.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 5
\li q < cap_order
\li p <= q
\li std::numeric_limits<addr_t>::max() >= i_z + 2
*/
template <class Base>
inline void forward_erf_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(ErfOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(ErfOp) == 5 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
CPPAD_ASSERT_UNKNOWN( 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 + 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)]
z_4[0] = erf(x[0]);
p++;
}
for(size_t j = p; j <= q; j++)
{ // z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t)
// z_4[1] + 2 * z_4[2] * t + ... =
// (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] += (Base(double(k)) / base_j) * x[k] * z_3[j-k];
}
}
/*!
Zero order Forward mode Taylor coefficient for result of op = ErfOp.
The C++ source code corresponding to this operation is
\verbatim
z = erf(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\param i_z
variable index corresponding to the last (primary) result for this operation;
i.e. the row index in \a taylor corresponding to z.
The auxillary results are called y_j have index \a 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 \c taylor array.
\param taylor
\b Input:
taylor [ 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.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 5
\li q < cap_order
\li p <= q
\li std::numeric_limits<addr_t>::max() >= i_z + 2
*/
template <class Base>
inline void forward_erf_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(ErfOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(ErfOp) == 5 );
CPPAD_ASSERT_UNKNOWN( 0 < cap_order );
CPPAD_ASSERT_UNKNOWN( 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 + arg[0] * cap_order;
Base* z_4 = taylor + (i_z + 4) * cap_order;
z_4[0] = erf(x[0]);
}
/*!
Forward mode Taylor coefficient for result of op = ErfOp.
The C++ source code corresponding to this operation is
\verbatim
z = erf(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\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 \a 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 \c 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.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 5
\li 0 < q < cap_order
*/
template <class Base>
inline void forward_erf_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(ErfOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(ErfOp) == 5 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( 0 < q );
CPPAD_ASSERT_UNKNOWN( 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 + 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;
// z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t)
// z_4[1] + 2 * z_4[2] * t + ... =
// (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] = 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;
z_4[m] += (Base(double(k)) / base_q) * x[x_index] * z_3[z3_index];
}
}
}
/*!
Compute reverse mode partial derivatives for result of op = ErfOp.
The C++ source code corresponding to this operation is
\verbatim
z = erf(x)
\endverbatim
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\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 \a taylor corresponding to z.
The auxillary results are called y_j have index \a 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 \c taylor array.
\param taylor
\b Input:
taylor [ 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 [ 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 [ 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.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 5
\li q < cap_order
\li p <= q
*/
template <class Base>
inline void reverse_erf_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(ErfOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(ErfOp) == 5 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( 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 + arg[0] * cap_order;
Base* px = partial + 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;
// 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] += azmul(pz_4[j], z_3[j-k]) * Base(double(k));
pz_3[j-k] += azmul(pz_4[j], x[k]) * Base(double(k));
}
j--;
}
px[0] += 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_USE_CPLUSPLUS_2011
# endif // CPPAD_ERF_OP_INCLUDED
+194
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+200
View File
@@ -0,0 +1,200 @@
# ifndef CPPAD_LOCAL_EXPM1_OP_HPP
# define CPPAD_LOCAL_EXPM1_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
# endif
+572
View File
@@ -0,0 +1,572 @@
# ifndef CPPAD_LOCAL_FOR_HES_SWEEP_HPP
# define CPPAD_LOCAL_FOR_HES_SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file for_hes_sweep.hpp
Compute Forward mode Hessian sparsity patterns.
*/
/*!
\def CPPAD_FOR_HES_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every rev_hes_sweep computation is printed.
*/
# define CPPAD_FOR_HES_SWEEP_TRACE 0
/*!
Given the forward Jacobian sparsity pattern for all the variables,
and the reverse Jacobian sparsity pattern for the dependent variables,
ForHesSweep computes the Hessian sparsity pattern for all the independent
variables.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape; i.e.,
\a play->num_var_rec().
This is also the number of rows in the entire sparsity pattern
\a for_hes_sparse.
\param play
The information stored in \a play
is a recording of the operations corresponding to a function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables
and \f$ m \f$ is the number of dependent variables.
The object \a play is effectly constant.
It is not declared const because while playing back the tape
the object \a play holds information about the current location
with in the tape and this changes during playback.
\param for_jac_sparse
For i = 0 , ... , \a numvar - 1,
(for all the variables on the tape),
the forward Jacobian sparsity pattern for the variable with index i
corresponds to the set with index i in \a for_jac_sparse.
\param rev_jac_sparse
\b Input:
For i = 0, ... , \a numvar - 1
the if the function we are computing the Hessian for has a non-zero
derivative w.r.t. variable with index i,
the set with index i has element zero.
Otherwise it has no elements.
\param for_hes_sparse
The forward Hessian sparsity pattern for the variable with index i
corresponds to the set with index i in \a for_hes_sparse.
The number of rows in this sparsity patter is n+1 and the row
with index zero is not used.
\n
\n
\b Input: For i = 1 , ... , \a n
the forward Hessian sparsity pattern for the variable with index i is empty.
\n
\n
\b Output: For j = 1 , ... , \a n,
the forward Hessian sparsity pattern for the independent dependent variable
with index (j-1) is given by the set with index j
in \a for_hes_sparse.
*/
template <class Base, class Vector_set>
void ForHesSweep(
size_t n,
size_t numvar,
local::player<Base>* play,
const Vector_set& for_jac_sparse,
const Vector_set& rev_jac_sparse,
Vector_set& for_hes_sparse
)
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
size_t i, j, k;
// check numvar argument
size_t limit = n+1;
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.n_set() == numvar );
CPPAD_ASSERT_UNKNOWN( for_hes_sparse.n_set() == limit );
CPPAD_ASSERT_UNKNOWN( numvar > 0 );
// upper limit exclusive for set elements
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.end() == limit );
CPPAD_ASSERT_UNKNOWN( for_hes_sparse.end() == limit );
// vecad_sparsity contains a sparsity pattern for each VecAD object.
// vecad_ind maps a VecAD index (beginning of the VecAD object)
// to the index for the corresponding set in vecad_sparsity.
size_t num_vecad_ind = play->num_vec_ind_rec();
size_t num_vecad_vec = play->num_vecad_vec_rec();
Vector_set vecad_sparse;
vecad_sparse.resize(num_vecad_vec, limit);
pod_vector<size_t> vecad_ind;
pod_vector<bool> vecad_jac;
if( num_vecad_vec > 0 )
{ size_t length;
vecad_ind.extend(num_vecad_ind);
vecad_jac.extend(num_vecad_vec);
j = 0;
for(i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
length = play->GetVecInd(j);
// set vecad_ind to proper index for this VecAD
vecad_ind[j] = i;
// make all other values for this vector invalid
for(k = 1; k <= length; k++)
vecad_ind[j+k] = num_vecad_vec;
// start of next VecAD
j += length + 1;
// initialize this vector's reverse jacobian value
vecad_jac[i] = false;
}
CPPAD_ASSERT_UNKNOWN( j == play->num_vec_ind_rec() );
}
// ------------------------------------------------------------------------
// user's atomic op calculator
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
//
// work space used by UserOp.
vector<Base> user_x; // value of parameter arguments to function
vector<size_t> user_ix; // variable index (on tape) for each argument
vector<size_t> user_iy; // variable index (on tape) for each result
//
// information set by forward_user (initialization to avoid warnings)
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
// information set by forward_user (necessary initialization)
enum_user_state user_state = start_user;
// -------------------------------------------------------------------------
//
// pointer to the beginning of the parameter vector
// (used by user atomic functions)
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
// Initialize
play->forward_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
bool more_operators = true;
# if CPPAD_FOR_HES_SWEEP_TRACE
vector<size_t> user_usrrp; // parameter index for UsrrpOp operators
std::cout << std::endl;
CppAD::vectorBool zf_value(limit);
CppAD::vectorBool zh_value(limit * limit);
# endif
bool flag; // temporary for use in switch cases below
while(more_operators)
{
// next op
play->forward_next(op, arg, i_op, i_var);
# ifndef NDEBUG
if( i_op <= n )
{ CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
}
else CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
# endif
// does the Hessian in question have a non-zero derivative
// with respect to this variable
bool include = rev_jac_sparse.is_element(i_var, 0);
//
// operators to include even if derivative is zero
include |= op == EndOp;
include |= op == CSkipOp;
include |= op == CSumOp;
include |= op == UserOp;
include |= op == UsrapOp;
include |= op == UsravOp;
include |= op == UsrrpOp;
include |= op == UsrrvOp;
//
if( include ) switch( op )
{ // operators that should not occurr
// case BeginOp
// -------------------------------------------------
// operators that do not affect hessian
case AbsOp:
case AddvvOp:
case AddpvOp:
case CExpOp:
case DisOp:
case DivvpOp:
case InvOp:
case LdpOp:
case LdvOp:
case MulpvOp:
case ParOp:
case PriOp:
case SignOp:
case StppOp:
case StpvOp:
case StvpOp:
case StvvOp:
case SubvvOp:
case SubpvOp:
case SubvpOp:
case ZmulpvOp:
case ZmulvpOp:
break;
// -------------------------------------------------
// nonlinear unary operators
case AcosOp:
case AsinOp:
case AtanOp:
case CosOp:
case CoshOp:
case ExpOp:
case LogOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
case AsinhOp:
case AtanhOp:
case Expm1Op:
case Log1pOp:
# endif
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 )
forward_sparse_hessian_nonlinear_unary_op(
arg[0], for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->forward_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->forward_csum(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case DivvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
forward_sparse_hessian_div_op(
arg, for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
forward_sparse_hessian_nonlinear_unary_op(
arg[1], for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case EndOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
more_operators = false;
break;
// -------------------------------------------------
case ErfOp:
// arg[1] is always the parameter 0
// arg[2] is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
forward_sparse_hessian_nonlinear_unary_op(
arg[0], for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
// -------------------------------------------------
// logical comparision operators
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
break;
// -------------------------------------------------
case MulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
forward_sparse_hessian_mul_op(
arg, for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
forward_sparse_hessian_nonlinear_unary_op(
arg[1], for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
forward_sparse_hessian_nonlinear_unary_op(
arg[0], for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case PowvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
forward_sparse_hessian_pow_op(
arg, for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
case UserOp:
CPPAD_ASSERT_UNKNOWN(
user_state == start_user || user_state == end_user
);
flag = user_state == start_user;
user_atom = play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ // start of user atomic operation sequence
user_x.resize( user_n );
user_ix.resize( user_n );
user_iy.resize( user_m );
# if CPPAD_FOR_HES_SWEEP_TRACE
user_usrrp.resize( user_m );
# endif
}
else
{ // end of user atomic operation sequence
user_atom->set_old(user_old);
user_atom->for_sparse_hes(
user_x, user_ix, user_iy,
for_jac_sparse, rev_jac_sparse, for_hes_sparse
);
}
break;
case UsrapOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
// argument parameter value
user_x[user_j] = parameter[arg[0]];
// special variable user for parameters
user_ix[user_j] = 0;
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsravOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
// arguemnt varialbes not avaialbe during sparisty calculations
user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
// varialbe index for this argument
user_ix[user_j] = arg[0];
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
// special variable index user for parameters
user_iy[user_i] = 0;
# if CPPAD_FOR_HES_SWEEP_TRACE
// remember argument for delayed tracing
user_usrrp[user_i] = arg[0];
# endif
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrvOp:
// variable index for this result
user_iy[user_i] = i_var;
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
// -------------------------------------------------
case ZmulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
forward_sparse_hessian_mul_op(
arg, for_jac_sparse, for_hes_sparse
);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_FOR_HES_SWEEP_TRACE
typedef typename Vector_set::const_iterator const_iterator;
if( op == UserOp && user_state == start_user )
{ // print operators that have been delayed
CPPAD_ASSERT_UNKNOWN( user_m == user_iy.size() );
CPPAD_ASSERT_UNKNOWN( i_op > user_m );
CPPAD_ASSERT_NARG_NRES(UsrrpOp, 1, 0);
CPPAD_ASSERT_NARG_NRES(UsrrvOp, 0, 1);
addr_t arg_tmp[1];
for(k = 0; k < user_m; k++)
{ size_t k_var = user_iy[k];
// value for this variable
for(i = 0; i < limit; i++)
{ zf_value[i] = false;
for(j = 0; j < limit; j++)
zh_value[i * limit + j] = false;
}
const_iterator itr_1(for_jac_sparse, i_var);
j = *itr_1;
while( j < limit )
{ zf_value[j] = true;
j = *(++itr_1);
}
for(i = 0; i < limit; i++)
{ const_iterator itr_2(for_hes_sparse, i);
j = *itr_2;
while( j < limit )
{ zh_value[i * limit + j] = true;
j = *(++itr_2);
}
}
OpCode op_tmp = UsrrvOp;
if( k_var == 0 )
{ op_tmp = UsrrpOp;
arg_tmp[0] = user_usrrp[k];
}
// k_var is zero when there is no result
printOp(
std::cout,
play,
i_op - user_m + k,
k_var,
op_tmp,
arg_tmp
);
if( k_var > 0 ) printOpResult(
std::cout,
1,
&zf_value,
1,
&zh_value
);
std::cout << std::endl;
}
}
const addr_t* arg_tmp = arg;
if( op == CSumOp )
arg_tmp = arg - arg[-1] - 4;
if( op == CSkipOp )
arg_tmp = arg - arg[-1] - 7;
for(i = 0; i < limit; i++)
{ zf_value[i] = false;
for(j = 0; j < limit; j++)
zh_value[i * limit + j] = false;
}
const_iterator itr_1(for_jac_sparse, i_var);
j = *itr_1;
while( j < limit )
{ zf_value[j] = true;
j = *(++itr_1);
}
for(i = 0; i < limit; i++)
{ const_iterator itr_2(for_hes_sparse, i);
j = *itr_2;
while( j < limit )
{ zh_value[i * limit + j] = true;
j = *(++itr_2);
}
}
// must delay print for these cases till after atomic user call
bool delay_print = op == UsrrpOp;
delay_print |= op == UsrrvOp;
if( ! delay_print )
{ printOp(
std::cout,
play,
i_op,
i_var,
op,
arg_tmp
);
if( NumRes(op) > 0 && (! delay_print) ) printOpResult(
std::cout,
1,
&zf_value,
1,
&zh_value
);
std::cout << std::endl;
}
}
std::cout << std::endl;
# else
}
# endif
// value corresponding to EndOp
CPPAD_ASSERT_UNKNOWN( i_var + 1 == play->num_var_rec() );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_FOR_HES_SWEEP_TRACE
# endif
+815
View File
@@ -0,0 +1,815 @@
# ifndef CPPAD_LOCAL_FOR_JAC_SWEEP_HPP
# define CPPAD_LOCAL_FOR_JAC_SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <set>
# include <cppad/local/pod_vector.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file for_jac_sweep.hpp
Compute Forward mode Jacobian sparsity patterns.
*/
/*!
\def CPPAD_FOR_JAC_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every for_jac_sweep computation is printed.
*/
# define CPPAD_FOR_JAC_SWEEP_TRACE 0
/*!
Given the sparsity pattern for the independent variables,
ForJacSweep computes the sparsity pattern for all the other variables.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param dependency
Are the derivatives with respect to left and right of the expression below
considered to be non-zero:
\code
CondExpRel(left, right, if_true, if_false)
\endcode
This is used by the optimizer to obtain the correct dependency relations.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape; i.e.,
\a play->num_var_rec().
\param play
The information stored in \a play
is a recording of the operations corresponding to a function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables
and \f$ m \f$ is the number of dependent variables.
The object \a play is effectly constant.
It is not declared const because while playing back the tape
the object \a play holds information about the current location
with in the tape and this changes during playback.
\param var_sparsity
\b Input: For j = 1 , ... , \a n,
the sparsity pattern for the independent variable with index (j-1)
corresponds to the set with index j in \a var_sparsity.
\n
\n
\b Output: For i = \a n + 1 , ... , \a numvar - 1,
the sparsity pattern for the variable with index i on the tape
corresponds to the set with index i in \a var_sparsity.
\par Checked Assertions:
\li numvar == var_sparsity.n_set()
\li numvar == play->num_var_rec()
*/
template <class Base, class Vector_set>
void ForJacSweep(
bool dependency ,
size_t n ,
size_t numvar ,
local::player<Base>* play ,
Vector_set& var_sparsity )
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
size_t i, j, k;
// check numvar argument
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( var_sparsity.n_set() == numvar );
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
// cum_sparsity accumulates sparsity pattern a cummulative sum
size_t limit = var_sparsity.end();
// vecad_sparsity contains a sparsity pattern from each VecAD object
// to all the other variables.
// vecad_ind maps a VecAD index (the beginning of the
// VecAD object) to its from index in vecad_sparsity
size_t num_vecad_ind = play->num_vec_ind_rec();
size_t num_vecad_vec = play->num_vecad_vec_rec();
Vector_set vecad_sparsity;
vecad_sparsity.resize(num_vecad_vec, limit);
pod_vector<size_t> vecad_ind;
if( num_vecad_vec > 0 )
{ size_t length;
vecad_ind.extend(num_vecad_ind);
j = 0;
for(i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
length = play->GetVecInd(j);
// set to proper index for this VecAD
vecad_ind[j] = i;
for(k = 1; k <= length; k++)
vecad_ind[j+k] = num_vecad_vec; // invalid index
// start of next VecAD
j += length + 1;
}
CPPAD_ASSERT_UNKNOWN( j == play->num_vec_ind_rec() );
}
// --------------------------------------------------------------
// user's atomic op calculator
atomic_base<Base>* user_atom = CPPAD_NULL;
//
// work space used by UserOp.
vector<Base> user_x; // value of parameter arguments to function
vector<size_t> user_ix; // variable index (on tape) for each argument
vector<size_t> user_iy; // variable index (on tape) for each result
//
// information set by forward_user (initialization to avoid warnings)
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
// information set by forward_user (necessary initialization)
enum_user_state user_state = start_user;
// --------------------------------------------------------------
//
// pointer to the beginning of the parameter vector
// (used by user atomic functions)
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
# if CPPAD_FOR_JAC_SWEEP_TRACE
vector<size_t> user_usrrp; // parameter index for UsrrpOp operators
std::cout << std::endl;
CppAD::vectorBool z_value(limit);
# endif
// skip the BeginOp at the beginning of the recording
play->forward_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
bool more_operators = true;
while(more_operators)
{ bool flag; // temporary for use in switch cases.
// this op
play->forward_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) );
CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) );
CPPAD_ASSERT_ARG_BEFORE_RESULT(op, arg, i_var);
// rest of information depends on the case
switch( op )
{
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case AddvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case CSkipOp:
// CSipOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
play->forward_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
forward_sparse_jacobian_csum_op(
i_var, arg, var_sparsity
);
play->forward_csum(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CExpOp:
forward_sparse_jacobian_cond_op(
dependency, i_var, arg, num_par, var_sparsity
);
break;
// --------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case DisOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
// derivative is identically zero but dependency is not
if( dependency ) forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
else
var_sparsity.clear(i_var);
break;
// -------------------------------------------------
case DivvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case EndOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
more_operators = false;
break;
// -------------------------------------------------
case ErfOp:
// arg[1] is always the parameter 0
// arg[0] is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case ExpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
// sparsity pattern is already defined
break;
// -------------------------------------------------
case LdpOp:
forward_sparse_load_op(
dependency,
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case LdvOp:
forward_sparse_load_op(
dependency,
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
break;
// -------------------------------------------------
case LogOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case MulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
var_sparsity.clear(i_var);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case PowvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
break;
// -------------------------------------------------
case SignOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
// derivative is identically zero but dependency is not
if( dependency ) forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
else
var_sparsity.clear(i_var);
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case SqrtOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case StppOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
// if both arguments are parameters does not affect sparsity
// or dependency
break;
// -------------------------------------------------
case StpvOp:
forward_sparse_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case StvpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
forward_sparse_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case StvvOp:
forward_sparse_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case SubvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case UserOp:
CPPAD_ASSERT_UNKNOWN(
user_state == start_user || user_state == end_user
);
flag = user_state == start_user;
user_atom = play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ // start of user atomic operation sequence
user_x.resize( user_n );
user_ix.resize( user_n );
user_iy.resize( user_m );
# if CPPAD_FOR_JAC_SWEEP_TRACE
user_usrrp.resize( user_m );
# endif
}
else
{ // end of user atomic operation sequence
user_atom->set_old(user_old);
user_atom->for_sparse_jac(
user_x, user_ix, user_iy, var_sparsity
);
}
break;
case UsrapOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
// argument parameter value
user_x[user_j] = parameter[arg[0]];
// special variable index used for parameters
user_ix[user_j] = 0;
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsravOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
// argument variables not avaiable during sparsity calculations
user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
// variable index for this argument
user_ix[user_j] = arg[0];
//
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrpOp:
// special variable index used for parameters
user_iy[user_i] = 0;
# if CPPAD_FOR_JAC_SWEEP_TRACE
// remember argument for delayed tracing
user_usrrp[user_i] = arg[0];
# endif
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrvOp:
// variable index for this result
user_iy[user_i] = i_var;
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case ZmulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
forward_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_FOR_JAC_SWEEP_TRACE
if( op == UserOp && user_state == start_user )
{ // print operators that have been delayed
CPPAD_ASSERT_UNKNOWN( user_m == user_iy.size() );
CPPAD_ASSERT_UNKNOWN( i_op > user_m );
CPPAD_ASSERT_NARG_NRES(UsrrpOp, 1, 0);
CPPAD_ASSERT_NARG_NRES(UsrrvOp, 0, 1);
addr_t arg_tmp[1];
for(i = 0; i < user_m; i++)
{ size_t j_var = user_iy[i];
// value for this variable
for(j = 0; j < limit; j++)
z_value[j] = false;
typename Vector_set::const_iterator itr(var_sparsity, j_var);
j = *itr;
while( j < limit )
{ z_value[j] = true;
j = *(++itr);
}
OpCode op_tmp = UsrrvOp;
if( j_var == 0 )
{ op_tmp = UsrrpOp;
arg_tmp[0] = user_usrrp[i];
}
// j_var is zero when there is no result.
printOp(
std::cout,
play,
i_op - user_m + i,
j_var,
op_tmp,
arg_tmp
);
if( j_var > 0 ) printOpResult(
std::cout,
1,
&z_value,
0,
(CppAD::vectorBool *) CPPAD_NULL
);
std::cout << std::endl;
}
}
const addr_t* arg_tmp = arg;
if( op == CSumOp )
arg_tmp = arg - arg[-1] - 4;
if( op == CSkipOp )
arg_tmp = arg - arg[-1] - 7;
//
// value for this variable
for(j = 0; j < limit; j++)
z_value[j] = false;
typename Vector_set::const_iterator itr(var_sparsity, i_var);
j = *itr;
while( j < limit )
{ z_value[j] = true;
j = *(++itr);
}
// must delay print for these cases till after atomic user call
bool delay_print = op == UsrrpOp;
delay_print |= op == UsrrvOp;
if( ! delay_print )
{ printOp(
std::cout,
play,
i_op,
i_var,
op,
arg_tmp
);
if( NumRes(op) > 0 && (! delay_print) ) printOpResult(
std::cout,
1,
&z_value,
0,
(CppAD::vectorBool *) CPPAD_NULL
);
std::cout << std::endl;
}
}
std::cout << std::endl;
# else
}
# endif
CPPAD_ASSERT_UNKNOWN( i_var + 1 == play->num_var_rec() );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_FOR_JAC_SWEEP_TRACE
# endif
+955
View File
@@ -0,0 +1,955 @@
# ifndef CPPAD_LOCAL_FORWARD0SWEEP_HPP
# define CPPAD_LOCAL_FORWARD0SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file forward0sweep.hpp
Compute zero order forward mode Taylor coefficients.
*/
/*
\def CPPAD_ATOMIC_CALL
This avoids warnings when NDEBUG is defined and user_ok is not used.
If NDEBUG is defined, this resolves to
\code
user_atom->forward
\endcode
otherwise, it respolves to
\code
user_ok = user_atom->forward
\endcode
This maco is undefined at the end of this file to facillitate is
use with a different definition in other files.
*/
# ifdef NDEBUG
# define CPPAD_ATOMIC_CALL user_atom->forward
# else
# define CPPAD_ATOMIC_CALL user_ok = user_atom->forward
# endif
/*!
\def CPPAD_FORWARD0SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every forward0sweep computation is printed.
(Note that forward0sweep is not used if CPPAD_USE_FORWARD0SWEEP is zero).
*/
# define CPPAD_FORWARD0SWEEP_TRACE 0
/*!
Compute zero order forward mode Taylor coefficients.
<!-- define forward0sweep_doc_define -->
\tparam Base
The type used during the forward mode computations; i.e., the corresponding
recording of operations used the type AD<Base>.
\param s_out
Is the stream where output corresponding to PriOp operations will
be written.
\param print
If print is false,
suppress the output that is otherwise generated by the c PriOp instructions.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape.
This is also equal to the number of rows in the matrix taylor; i.e.,
play->num_var_rec().
\param play
The information stored in play
is a recording of the operations corresponding to the function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables and
\f$ m \f$ is the number of dependent variables.
\n
\n
The object play is effectly constant.
The exception to this is that while palying back the tape
the object play holds information about the current location
with in the tape and this changes during palyback.
\param J
Is the number of columns in the coefficient matrix taylor.
This must be greater than or equal one.
<!-- end forward0sweep_doc_define -->
\param taylor
\n
\b Input:
For i = 1 , ... , n,
<code>taylor [i * J + 0]</code>
variable with index j on the tape
(these are the independent variables).
\n
\n
\b Output:
For i = n + 1, ... , numvar - 1,
<code>taylor [i * J + 0]</code>
is the zero order Taylor coefficient for the variable with
index i on the tape.
\param cskip_op
Is a vector with size play->num_op_rec().
The input value of the elements does not matter.
Upon return, if cskip_op[i] is true, the operator index i
does not affect any of the dependent variable
(given the value of the independent variables).
\param var_by_load_op
Is a vector with size play->num_load_op_rec().
The input value of the elements does not matter.
Upon return,
it is the variable index corresponding the result for each load operator.
In the case where the index is zero,
the load operator results in a parameter (not a variable).
Note that the is no variable with index zero on the tape.
\param compare_change_count
Is the count value for changing number and op_index during
zero order foward mode.
\param compare_change_number
If compare_change_count is zero, this value is set to zero.
Otherwise, the return value is the number of comparision operations
that have a different result from when the information in
play was recorded.
\param compare_change_op_index
If compare_change_count is zero, this value is set to zero.
Otherwise it is the operator index (see forward_next) for the count-th
comparision operation that has a different result from when the information in
play was recorded.
*/
template <class Base>
void forward0sweep(
std::ostream& s_out,
bool print,
size_t n,
size_t numvar,
local::player<Base>* play,
size_t J,
Base* taylor,
bool* cskip_op,
pod_vector<addr_t>& var_by_load_op,
size_t compare_change_count,
size_t& compare_change_number,
size_t& compare_change_op_index
)
{ CPPAD_ASSERT_UNKNOWN( J >= 1 );
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
// use p, q, r so other forward sweeps can use code defined here
size_t p = 0;
size_t q = 0;
size_t r = 1;
/*
<!-- define forward0sweep_code_define -->
*/
// op code for current instruction
OpCode op;
// index for current instruction
size_t i_op;
// next variables
size_t i_var;
// operation argument indices
const addr_t* arg = CPPAD_NULL;
// initialize the comparision operator counter
if( p == 0 )
{ compare_change_number = 0;
compare_change_op_index = 0;
}
// If this includes a zero calculation, initialize this information
pod_vector<bool> isvar_by_ind;
pod_vector<size_t> index_by_ind;
if( p == 0 )
{ size_t i;
// this includes order zero calculation, initialize vector indices
size_t num = play->num_vec_ind_rec();
if( num > 0 )
{ isvar_by_ind.extend(num);
index_by_ind.extend(num);
for(i = 0; i < num; i++)
{ index_by_ind[i] = play->GetVecInd(i);
isvar_by_ind[i] = false;
}
}
// includes zero order, so initialize conditional skip flags
num = play->num_op_rec();
for(i = 0; i < num; i++)
cskip_op[i] = false;
}
// work space used by UserOp.
vector<bool> user_vx; // empty vecotor
vector<bool> user_vy; // empty vecotor
vector<Base> user_tx; // argument vector Taylor coefficients
vector<Base> user_ty; // result vector Taylor coefficients
//
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
# ifndef NDEBUG
bool user_ok = false; // atomic op return value
# endif
//
// information defined by forward_user
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
enum_user_state user_state = start_user; // proper initialization
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
// pointer to the beginning of the parameter vector
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
// length of the text vector (used by CppAD assert macros)
const size_t num_text = play->num_text_rec();
// pointer to the beginning of the text vector
const char* text = CPPAD_NULL;
if( num_text > 0 )
text = play->GetTxt(0);
/*
<!-- end forward0sweep_code_define -->
*/
# if CPPAD_FORWARD0SWEEP_TRACE
// flag as to when to trace user function values
bool user_trace = false;
// variable indices for results vector
// (done differently for order zero).
vector<size_t> user_iy;
# endif
// skip the BeginOp at the beginning of the recording
play->forward_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
# if CPPAD_FORWARD0SWEEP_TRACE
std::cout << std::endl;
# endif
bool flag; // a temporary flag to use in switch cases
bool more_operators = true;
while(more_operators)
{
// this op
play->forward_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) );
CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) );
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
CPPAD_ASSERT_ARG_BEFORE_RESULT(op, arg, i_var);
// check if we are skipping this operation
while( cskip_op[i_op] )
{ switch(op)
{ case CSumOp:
// CSumOp has a variable number of arguments
play->forward_csum(op, arg, i_op, i_var);
break;
case CSkipOp:
// CSkip has a variable number of arguments
play->forward_cskip(op, arg, i_op, i_var);
break;
case UserOp:
{ // skip all operations in this user atomic call
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
size_t n_skip = user_m + user_n + 1;
for(size_t i = 0; i < n_skip; i++)
{ play->forward_next(op, arg, i_op, i_var);
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
}
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
}
break;
default:
break;
}
play->forward_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
}
// action to take depends on the case
switch( op )
{
case AbsOp:
forward_abs_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case AddvvOp:
forward_addvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_addpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_acos_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_acosh_op_0(i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_asin_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_asinh_op_0(i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_atan_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_atanh_op_0(i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case CExpOp:
// Use the general case with d == 0
// (could create an optimzied verison for this case)
forward_cond_op_0(
i_var, arg, num_par, parameter, J, taylor
);
break;
// ---------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_cos_op_0(i_var, arg[0], J, taylor);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_cosh_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
forward_cskip_op_0(
i_var, arg, num_par, parameter, J, taylor, cskip_op
);
play->forward_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
forward_csum_op(
0, 0, i_var, arg, num_par, parameter, J, taylor
);
play->forward_csum(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case DisOp:
forward_dis_op(p, q, r, i_var, arg, J, taylor);
break;
// -------------------------------------------------
case DivvvOp:
forward_divvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_divpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_divvp_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case EndOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
more_operators = false;
break;
// -------------------------------------------------
case EqpvOp:
if( compare_change_count )
{ forward_eqpv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case EqvvOp:
if( compare_change_count )
{ forward_eqvv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case ErfOp:
forward_erf_op_0(i_var, arg, parameter, J, taylor);
break;
# endif
// -------------------------------------------------
case ExpOp:
forward_exp_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
forward_expm1_op_0(i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
break;
// ---------------------------------------------------
case LdpOp:
forward_load_p_op_0(
play,
i_var,
arg,
parameter,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data(),
var_by_load_op.data()
);
break;
// -------------------------------------------------
case LdvOp:
forward_load_v_op_0(
play,
i_var,
arg,
parameter,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data(),
var_by_load_op.data()
);
break;
// -------------------------------------------------
case LepvOp:
if( compare_change_count )
{ forward_lepv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case LevpOp:
if( compare_change_count )
{ forward_levp_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case LevvOp:
if( compare_change_count )
{ forward_levv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case LogOp:
forward_log_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
forward_log1p_op_0(i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case LtpvOp:
if( compare_change_count )
{ forward_ltpv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case LtvpOp:
if( compare_change_count )
{ forward_ltvp_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case LtvvOp:
if( compare_change_count )
{ forward_ltvv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_mulpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case MulvvOp:
forward_mulvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case NepvOp:
if( compare_change_count )
{ forward_nepv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case NevvOp:
if( compare_change_count )
{ forward_nevv_op_0(
compare_change_number, arg, parameter, J, taylor
);
{ if( compare_change_count == compare_change_number )
compare_change_op_index = i_op;
}
}
break;
// -------------------------------------------------
case ParOp:
forward_par_op_0(
i_var, arg, num_par, parameter, J, taylor
);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_powvp_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_powpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PowvvOp:
forward_powvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PriOp:
if( print ) forward_pri_0(s_out,
arg, num_text, text, num_par, parameter, J, taylor
);
break;
// -------------------------------------------------
case SignOp:
// cos(x), sin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sign_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sin_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sinh_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SqrtOp:
forward_sqrt_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case StppOp:
forward_store_pp_op_0(
i_var,
arg,
num_par,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data()
);
break;
// -------------------------------------------------
case StpvOp:
forward_store_pv_op_0(
i_var,
arg,
num_par,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data()
);
break;
// -------------------------------------------------
case StvpOp:
forward_store_vp_op_0(
i_var,
arg,
num_par,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data()
);
break;
// -------------------------------------------------
case StvvOp:
forward_store_vv_op_0(
i_var,
arg,
num_par,
J,
taylor,
isvar_by_ind.data(),
index_by_ind.data()
);
break;
// -------------------------------------------------
case SubvvOp:
forward_subvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_subpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_subvp_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_tan_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_tanh_op_0(i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case UserOp:
// start or end an atomic operation sequence
flag = user_state == start_user;
user_atom = play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ user_tx.resize(user_n);
user_ty.resize(user_m);
# if CPPAD_FORWARD0SWEEP_TRACE
user_iy.resize(user_m);
# endif
}
else
{
# ifndef NDEBUG
if( ! user_ok )
{ std::string msg =
user_atom->afun_name()
+ ": atomic_base.forward: returned false";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
# if CPPAD_FORWARD0SWEEP_TRACE
user_trace = true;
# endif
}
break;
case UsrapOp:
// parameter argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par );
user_tx[user_j] = parameter[ arg[0] ];
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( user_j == user_n )
{ // call users function for this operation
user_atom->set_old(user_old);
CPPAD_ATOMIC_CALL(p, q,
user_vx, user_vy, user_tx, user_ty
);
}
break;
case UsravOp:
// variable argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
user_tx[user_j] = taylor[ arg[0] * J + 0 ];
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( user_j == user_n )
{ // call users function for this operation
user_atom->set_old(user_old);
CPPAD_ATOMIC_CALL(p, q,
user_vx, user_vy, user_tx, user_ty
);
}
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
# if CPPAD_FORWARD0SWEEP_TRACE
user_iy[user_i] = 0;
# endif
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrvOp:
// variable result in an atomic operation sequence
# if CPPAD_FORWARD0SWEEP_TRACE
user_iy[user_i] = i_var;
# endif
taylor[ i_var * J + 0 ] = user_ty[user_i];
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_zmulpv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_zmulvp_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case ZmulvvOp:
forward_zmulvv_op_0(i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(false);
}
# if CPPAD_FORWARD0SWEEP_TRACE
size_t d = 0;
if( user_trace )
{ user_trace = false;
CPPAD_ASSERT_UNKNOWN( op == UserOp );
CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 );
for(size_t i = 0; i < user_m; i++) if( user_iy[i] > 0 )
{ size_t i_tmp = (i_op + i) - user_m;
printOp(
std::cout,
play,
i_tmp,
user_iy[i],
UsrrvOp,
CPPAD_NULL
);
Base* Z_tmp = taylor + user_iy[i] * J;
printOpResult(
std::cout,
d + 1,
Z_tmp,
0,
(Base *) CPPAD_NULL
);
std::cout << std::endl;
}
}
Base* Z_tmp = taylor + i_var * J;
const addr_t* arg_tmp = arg;
if( op == CSumOp )
arg_tmp = arg - arg[-1] - 4;
if( op == CSkipOp )
arg_tmp = arg - arg[-1] - 7;
if( op != UsrrvOp )
{
printOp(
std::cout,
play,
i_op,
i_var,
op,
arg_tmp
);
if( NumRes(op) > 0 ) printOpResult(
std::cout,
d + 1,
Z_tmp,
0,
(Base *) CPPAD_NULL
);
std::cout << std::endl;
}
}
std::cout << std::endl;
# else
}
# endif
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
CPPAD_ASSERT_UNKNOWN( i_var + 1 == play->num_var_rec() );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_FORWARD0SWEEP_TRACE
# undef CPPAD_ATOMIC_CALL
# endif
File diff suppressed because it is too large Load Diff
+795
View File
@@ -0,0 +1,795 @@
# ifndef CPPAD_LOCAL_FORWARD2SWEEP_HPP
# define CPPAD_LOCAL_FORWARD2SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file forward2sweep.hpp
Compute one Taylor coefficient for each direction requested.
*/
/*
\def CPPAD_ATOMIC_CALL
This avoids warnings when NDEBUG is defined and user_ok is not used.
If NDEBUG is defined, this resolves to
\code
user_atom->forward
\endcode
otherwise, it respolves to
\code
user_ok = user_atom->forward
\endcode
This macro is undefined at the end of this file to facillitate its
use with a different definition in other files.
*/
# ifdef NDEBUG
# define CPPAD_ATOMIC_CALL user_atom->forward
# else
# define CPPAD_ATOMIC_CALL user_ok = user_atom->forward
# endif
/*!
\def CPPAD_FORWARD2SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every forward2sweep computation is printed.
*/
# define CPPAD_FORWARD2SWEEP_TRACE 0
/*!
Compute multiple directions forward mode Taylor coefficients.
\tparam Base
The type used during the forward mode computations; i.e., the corresponding
recording of operations used the type AD<Base>.
\param q
is the order of the Taylor coefficients
that are computed during this call;
<code>q > 0</code>.
\param r
is the number of Taylor coefficients
that are computed during this call.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape.
This is also equal to the number of rows in the matrix taylor; i.e.,
play->num_var_rec().
\param play
The information stored in play
is a recording of the operations corresponding to the function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables and
\f$ m \f$ is the number of dependent variables.
\n
\n
The object play is effectly constant.
The exception to this is that while palying back the tape
the object play holds information about the current location
with in the tape and this changes during palyback.
\param J
Is the number of columns in the coefficient matrix taylor.
This must be greater than or equal one.
\param taylor
\n
\b Input:
For <code>i = 1 , ... , numvar-1</code>,
<code>taylor[ (J-1)*r*i + i + 0 ]</code>
is the zero order Taylor coefficient corresponding to
the i-th variable and all directions.
For <code>i = 1 , ... , numvar-1</code>,
For <code>k = 1 , ... , q-1</code>,
<code>ell = 0 , ... , r-1</code>,
<code>taylor[ (J-1)*r*i + i + (k-1)*r + ell + 1 ]</code>
is the k-th order Taylor coefficient corresponding to
the i-th variabel and ell-th direction.
\n
\n
\b Input:
For <code>i = 1 , ... , n</code>,
<code>ell = 0 , ... , r-1</code>,
<code>taylor[ (J-1)*r*i + i + (q-1)*r + ell + 1 ]</code>
is the q-th order Taylor coefficient corresponding to
the i-th variable and ell-th direction
(these are the independent varaibles).
\n
\n
\b Output:
For <code>i = n+1 , ... , numvar-1</code>,
<code>ell = 0 , ... , r-1</code>,
<code>taylor[ (J-1)*r*i + i + (q-1)*r + ell + 1 ]</code>
is the q-th order Taylor coefficient corresponding to
the i-th variable and ell-th direction.
\param cskip_op
Is a vector with size play->num_op_rec().
If cskip_op[i] is true, the operator with index i
does not affect any of the dependent variable (given the value
of the independent variables).
\param var_by_load_op
is a vector with size play->num_load_op_rec().
It is the variable index corresponding to each the
load instruction.
In the case where the index is zero,
the instruction corresponds to a parameter (not variable).
*/
template <class Base>
void forward2sweep(
const size_t q,
const size_t r,
const size_t n,
const size_t numvar,
local::player<Base>* play,
const size_t J,
Base* taylor,
const bool* cskip_op,
const pod_vector<addr_t>& var_by_load_op
)
{
CPPAD_ASSERT_UNKNOWN( q > 0 );
CPPAD_ASSERT_UNKNOWN( J >= q + 1 );
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
// used to avoid compiler errors until all operators are implemented
size_t p = q;
// op code for current instruction
OpCode op;
// index for current instruction
size_t i_op;
// next variables
size_t i_var;
// operation argument indices
const addr_t* arg = CPPAD_NULL;
// work space used by UserOp.
vector<bool> user_vx; // empty vecotor
vector<bool> user_vy; // empty vecotor
vector<Base> user_tx_one; // argument vector Taylor coefficients
vector<Base> user_tx_all;
vector<Base> user_ty_one; // result vector Taylor coefficients
vector<Base> user_ty_all;
//
// information defined by forward_user
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
enum_user_state user_state = start_user; // proper initialization
//
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
# ifndef NDEBUG
bool user_ok = false; // atomic op return value
# endif
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
// pointer to the beginning of the parameter vector
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
// temporary indices
size_t i, j, k, ell;
// number of orders for this user calculation
// (not needed for order zero)
const size_t user_q1 = q+1;
// variable indices for results vector
// (done differently for order zero).
vector<size_t> user_iy;
// skip the BeginOp at the beginning of the recording
play->forward_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == BeginOp );
# if CPPAD_FORWARD2SWEEP_TRACE
bool user_trace = false;
std::cout << std::endl;
CppAD::vector<Base> Z_vec(q+1);
# endif
bool flag; // a temporary flag to use in switch cases
bool more_operators = true;
while(more_operators)
{
// this op
play->forward_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) );
CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) );
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
CPPAD_ASSERT_ARG_BEFORE_RESULT(op, arg, i_var);
// check if we are skipping this operation
while( cskip_op[i_op] )
{ switch(op)
{ case CSumOp:
// CSumOp has a variable number of arguments
play->forward_csum(op, arg, i_op, i_var);
break;
case CSkipOp:
// CSkip has a variable number of arguments
play->forward_cskip(op, arg, i_op, i_var);
break;
case UserOp:
{ // skip all operations in this user atomic call
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
size_t n_skip = user_m + user_n + 1;
for(i = 0; i < n_skip; i++)
{ play->forward_next(op, arg, i_op, i_var);
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
}
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
}
break;
default:
break;
}
play->forward_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
}
// action depends on the operator
switch( op )
{
case AbsOp:
forward_abs_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case AddvvOp:
forward_addvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_addpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_acos_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_acosh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_asin_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_asinh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_atan_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_atanh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case CExpOp:
forward_cond_op_dir(
q, r, i_var, arg, num_par, parameter, J, taylor
);
break;
// ---------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_cos_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_cosh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
play->forward_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// forward_next thinks it has no arguments.
// we must inform forward_next of this special case.
forward_csum_op_dir(
q, r, i_var, arg, num_par, parameter, J, taylor
);
play->forward_csum(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case DisOp:
forward_dis_op(p, q, r, i_var, arg, J, taylor);
break;
// -------------------------------------------------
case DivvvOp:
forward_divvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_divpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_divvp_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case EndOp:
// needed for sparse_jacobian test
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
more_operators = false;
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case ErfOp:
forward_erf_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
# endif
case ExpOp:
forward_exp_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
forward_expm1_op_dir(q, r, i_var, arg[0], J, taylor);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
break;
// -------------------------------------------------
case LdpOp:
case LdvOp:
forward_load_op(
play,
op,
p,
q,
r,
J,
i_var,
arg,
var_by_load_op.data(),
taylor
);
break;
// ---------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_UNKNOWN(q > 0 );
break;
// -------------------------------------------------
case LogOp:
forward_log_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// ---------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
forward_log1p_op_dir(q, r, i_var, arg[0], J, taylor);
break;
# endif
// ---------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_mulpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case MulvvOp:
forward_mulvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case ParOp:
k = i_var*(J-1)*r + i_var + (q-1)*r + 1;
for(ell = 0; ell < r; ell++)
taylor[k + ell] = Base(0.0);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_powpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_powvp_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PowvvOp:
forward_powvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case PriOp:
CPPAD_ASSERT_UNKNOWN(q > 0);
break;
// -------------------------------------------------
case SignOp:
// sign(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sign_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sin_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_sinh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case SqrtOp:
forward_sqrt_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case StppOp:
case StpvOp:
case StvpOp:
case StvvOp:
CPPAD_ASSERT_UNKNOWN(q > 0 );
break;
// -------------------------------------------------
case SubvvOp:
forward_subvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_subpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_subvp_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_tan_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
forward_tanh_op_dir(q, r, i_var, arg[0], J, taylor);
break;
// -------------------------------------------------
case UserOp:
// start or end an atomic operation sequence
flag = user_state == start_user;
user_atom = play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ user_tx_one.resize(user_n * user_q1);
user_tx_all.resize(user_n * (q * r + 1));
//
user_ty_one.resize(user_m * user_q1);
user_ty_all.resize(user_m * (q * r + 1));
//
user_iy.resize(user_m);
}
else
{ // call users function for this operation
user_atom->set_old(user_old);
for(ell = 0; ell < r; ell++)
{ // set user_tx
for(j = 0; j < user_n; j++)
{ size_t j_all = j * (q * r + 1);
size_t j_one = j * user_q1;
user_tx_one[j_one+0] = user_tx_all[j_all+0];
for(k = 1; k < user_q1; k++)
{ size_t k_all = j_all + (k-1)*r+1+ell;
size_t k_one = j_one + k;
user_tx_one[k_one] = user_tx_all[k_all];
}
}
// set user_ty
for(i = 0; i < user_m; i++)
{ size_t i_all = i * (q * r + 1);
size_t i_one = i * user_q1;
user_ty_one[i_one+0] = user_ty_all[i_all+0];
for(k = 1; k < q; k++)
{ size_t k_all = i_all + (k-1)*r+1+ell;
size_t k_one = i_one + k;
user_ty_one[k_one] = user_ty_all[k_all];
}
}
CPPAD_ATOMIC_CALL(
q, q, user_vx, user_vy, user_tx_one, user_ty_one
);
# ifndef NDEBUG
if( ! user_ok )
{ std::string msg =
user_atom->afun_name()
+ ": atomic_base.forward: returned false";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
for(i = 0; i < user_m; i++)
{ if( user_iy[i] > 0 )
{ size_t i_taylor = user_iy[i]*((J-1)*r+1);
size_t q_taylor = i_taylor + (q-1)*r+1+ell;
size_t q_one = i * user_q1 + q;
taylor[q_taylor] = user_ty_one[q_one];
}
}
}
# if CPPAD_FORWARD2SWEEP_TRACE
user_trace = true;
# endif
}
break;
case UsrapOp:
// parameter argument in an atomic operation sequence
user_tx_all[user_j*(q*r+1) + 0] = parameter[ arg[0]];
for(ell = 0; ell < r; ell++)
for(k = 1; k < user_q1; k++)
user_tx_all[user_j*(q*r+1) + (k-1)*r+1+ell] = Base(0.0);
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsravOp:
// variable argument in an atomic operation sequence
user_tx_all[user_j*(q*r+1)+0] = taylor[arg[0]*((J-1)*r+1)+0];
for(ell = 0; ell < r; ell++)
{ for(k = 1; k < user_q1; k++)
{ user_tx_all[user_j*(q*r+1) + (k-1)*r+1+ell] =
taylor[arg[0]*((J-1)*r+1) + (k-1)*r+1+ell];
}
}
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
user_iy[user_i] = 0;
user_ty_all[user_i*(q*r+1) + 0] = parameter[ arg[0]];
for(ell = 0; ell < r; ell++)
for(k = 1; k < user_q1; k++)
user_ty_all[user_i*(q*r+1) + (k-1)*r+1+ell] = Base(0.0);
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
case UsrrvOp:
// variable result in an atomic operation sequence
user_iy[user_i] = i_var;
user_ty_all[user_i*(q*r+1)+0] = taylor[i_var*((J-1)*r+1)+0];
for(ell = 0; ell < r; ell++)
{ for(k = 1; k < user_q1; k++)
{ user_ty_all[user_i*(q*r+1) + (k-1)*r+1+ell] =
taylor[i_var*((J-1)*r+1) + (k-1)*r+1+ell];
}
}
play->forward_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
forward_zmulpv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
forward_zmulvp_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
case ZmulvvOp:
forward_zmulvv_op_dir(q, r, i_var, arg, parameter, J, taylor);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_FORWARD2SWEEP_TRACE
if( user_trace )
{ user_trace = false;
CPPAD_ASSERT_UNKNOWN( op == UserOp );
CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 );
for(i = 0; i < user_m; i++) if( user_iy[i] > 0 )
{ size_t i_tmp = (i_op + i) - user_m;
printOp(
std::cout,
play,
i_tmp,
user_iy[i],
UsrrvOp,
CPPAD_NULL
);
Base* Z_tmp = taylor + user_iy[i]*((J-1) * r + 1);
{ Z_vec[0] = Z_tmp[0];
for(ell = 0; ell < r; ell++)
{ std::cout << std::endl << " ";
for(size_t p_tmp = 1; p_tmp <= q; p_tmp++)
Z_vec[p_tmp] = Z_tmp[(p_tmp-1)*r+ell+1];
printOpResult(
std::cout,
q + 1,
Z_vec.data(),
0,
(Base *) CPPAD_NULL
);
}
}
std::cout << std::endl;
}
}
const addr_t* arg_tmp = arg;
if( op == CSumOp )
arg_tmp = arg - arg[-1] - 4;
if( op == CSkipOp )
arg_tmp = arg - arg[-1] - 7;
if( op != UsrrvOp )
{ printOp(
std::cout,
play,
i_op,
i_var,
op,
arg_tmp
);
Base* Z_tmp = CPPAD_NULL;
if( op == UsravOp )
Z_tmp = taylor + arg[0]*((J-1) * r + 1);
else if( NumRes(op) > 0 )
Z_tmp = taylor + i_var*((J-1)*r + 1);
if( Z_tmp != CPPAD_NULL )
{ Z_vec[0] = Z_tmp[0];
for(ell = 0; ell < r; ell++)
{ std::cout << std::endl << " ";
for(size_t p_tmp = 1; p_tmp <= q; p_tmp++)
Z_vec[p_tmp] = Z_tmp[ (p_tmp-1)*r + ell + 1];
printOpResult(
std::cout,
q + 1,
Z_vec.data(),
0,
(Base *) CPPAD_NULL
);
}
}
std::cout << std::endl;
}
}
std::cout << std::endl;
# else
}
# endif
CPPAD_ASSERT_UNKNOWN( user_state == start_user );
CPPAD_ASSERT_UNKNOWN( i_var + 1 == play->num_var_rec() );
return;
}
// preprocessor symbols that are local to this file
# undef CPPAD_FORWARD2SWEEP_TRACE
# undef CPPAD_ATOMIC_CALL
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+251
View File
@@ -0,0 +1,251 @@
# ifndef CPPAD_LOCAL_HASH_CODE_HPP
# define CPPAD_LOCAL_HASH_CODE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# 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 \c std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
\li \c sizeof(value) is even
\li \c 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 \c 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 \a npar containing the parameters
for this operation sequence; i.e.,
given a parameter index of \c i, the corresponding parameter value is
\a par[i].
\return
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
\par Checked Assertions
\c op must be one of the operators specified above. In addition,
\li \c std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
\li \c sizeof(size_t) is even
\li \c sizeof(Base) is even
\li \c sizeof(unsigned short) == 2
\li \c 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;
// number of shorts per Base value
size_t short_base = sizeof(Base) / 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 );
v = reinterpret_cast<const unsigned short*>(par + arg[0]);
i = short_base;
while(i--)
code += v[i];
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];
v = reinterpret_cast<const unsigned short*>(par + arg[1]);
i = short_base;
while(i--)
code += v[i];
break;
// Unary operators
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case ErfOp:
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
+74
View File
@@ -0,0 +1,74 @@
// $Id: independent.hpp 3845 2016-11-19 01:50:47Z bradbell $
# ifndef CPPAD_LOCAL_INDEPENDENT_HPP
# define CPPAD_LOCAL_INDEPENDENT_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*
\file local/independent.hpp
Implement the declaration of the independent variables
*/
/*!
Implementation of the declaration of independent variables (in local namespace).
\tparam VectorAD
This is simple vector type with elements of type AD<Base>.
\param x
Vector of the independent variablerd.
\param abort_op_index
operator index at which execution will be aborted (during the recording
of operations). The value zero corresponds to not aborting (will not match).
*/
template <typename Base>
template <typename VectorAD>
void ADTape<Base>::Independent(VectorAD &x, size_t abort_op_index)
{
// check VectorAD is Simple Vector class with AD<Base> elements
CheckSimpleVector< AD<Base>, VectorAD>();
// 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 );
// set the abort index before doing anything else
Rec_.set_abort_op_index(abort_op_index);
// 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);
size_t j;
for(j = 0; j < n; j++)
{ // tape address for this independent variable
x[j].taddr_ = Rec_.PutOp(InvOp);
x[j].tape_id_ = id_;
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;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+689
View File
@@ -0,0 +1,689 @@
# ifndef CPPAD_LOCAL_LOAD_OP_HPP
# define CPPAD_LOCAL_LOAD_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file load_op.hpp
Setting a variable so that it corresponds to current value of a VecAD element.
*/
/*
==============================================================================
<!-- 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 = index_by_ind[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
==============================================================================
*/
/*!
Shared documentation for zero order forward mode implementation of
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_v_x = index_by_ind[ 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 i_z
is the AD variable index corresponding to the variable z.
\param arg
\n
arg[0]
is the offset of this VecAD vector relative to the beginning
of the isvar_by_ind and index_by_ind arrays.
\n
\n
arg[1]
\n
If this is the LdpOp operation (if x is a parameter),
i_vec is defined by
\verbatim
i_vec = arg[1]
\endverbatim
If this is the LdvOp operation (if x is a variable),
i_vec is defined by
\verbatim
i_vec = floor( taylor[ arg[1] * cap_order + 0 ] )
\endverbatim
where floor(c) is the greatest integer less that or equal c.
\n
\n
arg[2]
Is the index of this vecad load instruction in the
var_by_load_op array.
\param parameter
If v[x] is a parameter, <code>parameter[ i_v_x ]</code> is its value.
This vector has size play->num_par_rec().
\param cap_order
number of columns in the matrix containing the Taylor coefficients.
\param taylor
\n
Input
\n
In LdvOp case, <code>taylor[ arg[1] * cap_order + 0 ]</code>
is used to compute the index in the definition of i_vec above.
If v[x] is a variable, <code>taylor[ i_v_x * cap_order + 0 ]</code>
is the zero order Taylor coefficient for v[x].
\n
\n
Output
\n
<code>taylor[ i_z * cap_order + 0 ]</code>
is set to the zero order Taylor coefficient for the variable z.
\param isvar_by_ind
If <code>isvar_by_ind[ arg[0] + i_vec ] </code> is true,
v[x] is a variable. Otherwise it is a parameter.
This vector has size play->num_vec_ind_rec().
\param index_by_ind
<code>index_by_ind[ arg[0] - 1 ]</code>
is the number of elements in the user vector containing this element.
<code>index_by_ind[ arg[0] + i_vec ]</code> is the variable or
parameter index for this element,
This array has size play->num_vec_ind_rec().
\param var_by_load_op
is a vector with size play->num_load_op_rec().
The input value of its elements does not matter.
Upon return, 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).
This array has size play->num_load_op_rec().
\par Check User Errors
\li In the LdvOp case check that the index is with in range; i.e.
<code>i_vec < index_by_ind[ arg[0] - 1 ]</code>.
Note that, if x is a parameter,
the corresponding vector index and it does not change.
In this case, the error above should be detected during tape recording.
*/
template <class Base>
inline void forward_load_op_0(
local::player<Base>* play ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind ,
addr_t* var_by_load_op )
{
// This routine is only for documentaiton, it should not be used
CPPAD_ASSERT_UNKNOWN( false );
}
/*!
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_v_x = index_by_ind[ 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 or sparse_list.
\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 \a i_z in \a var_sparsity is the sparsity pattern
correpsonding to z.
\param arg
\n
\a 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
\a combined[ \a arg[0] - 1 ]
is the index of the set corresponding to the vector v in \a vecad_sparsity.
We use the notation i_v for this value; i.e.,
\verbatim
i_v = combined[ \a arg[0] - 1 ]
\endverbatim
\param var_sparsity
The set with index \a i_z in \a 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 \a 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 < \a arg[0]
\li \a arg[0] < \a num_combined
\li i_v < \a vecad_sparsity.n_set()
*/
template <class Vector_set>
inline void sparse_load_op(
OpCode op ,
size_t i_z ,
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 );
}
/*!
Zero order forward mode implementation of op = LdpOp.
\copydetails CppAD::local::forward_load_op_0
*/
template <class Base>
inline void forward_load_p_op_0(
local::player<Base>* play ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind ,
addr_t* var_by_load_op )
{ CPPAD_ASSERT_UNKNOWN( NumArg(LdpOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(LdpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_load_op_rec() );
CPPAD_ASSERT_UNKNOWN( std::numeric_limits<addr_t>::max() >= i_z );
// Because the index is a parameter, this indexing error should have been
// caught and reported to the user when the tape is recording.
size_t i_vec = arg[1];
CPPAD_ASSERT_UNKNOWN( i_vec < index_by_ind[ arg[0] - 1 ] );
CPPAD_ASSERT_UNKNOWN( arg[0] + i_vec < play->num_vec_ind_rec() );
size_t i_v_x = index_by_ind[ arg[0] + i_vec ];
Base* z = taylor + i_z * cap_order;
if( isvar_by_ind[ arg[0] + i_vec ] )
{ CPPAD_ASSERT_UNKNOWN( i_v_x < i_z );
var_by_load_op[ arg[2] ] = addr_t( i_v_x );
Base* v_x = taylor + i_v_x * cap_order;
z[0] = v_x[0];
}
else
{ CPPAD_ASSERT_UNKNOWN( i_v_x < play->num_par_rec() );
var_by_load_op[ arg[2] ] = 0;
Base v_x = parameter[i_v_x];
z[0] = v_x;
}
}
/*!
Zero order forward mode implementation of op = LdvOp.
\copydetails CppAD::local::forward_load_op_0
*/
template <class Base>
inline void forward_load_v_op_0(
local::player<Base>* play ,
size_t i_z ,
const addr_t* arg ,
const Base* parameter ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind ,
addr_t* var_by_load_op )
{ CPPAD_ASSERT_UNKNOWN( NumArg(LdvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(LdvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_load_op_rec() );
CPPAD_ASSERT_UNKNOWN( std::numeric_limits<addr_t>::max() >= i_z );
size_t i_vec = Integer( taylor[ arg[1] * cap_order + 0 ] );
CPPAD_ASSERT_KNOWN(
i_vec < index_by_ind[ arg[0] - 1 ] ,
"VecAD: index during zero order forward sweep is out of range"
);
CPPAD_ASSERT_UNKNOWN( arg[0] + i_vec < play->num_vec_ind_rec() );
size_t i_v_x = index_by_ind[ arg[0] + i_vec ];
Base* z = taylor + i_z * cap_order;
if( isvar_by_ind[ arg[0] + i_vec ] )
{ CPPAD_ASSERT_UNKNOWN( i_v_x < i_z );
var_by_load_op[ arg[2] ] = addr_t( i_v_x );
Base* v_x = taylor + i_v_x * cap_order;
z[0] = v_x[0];
}
else
{ CPPAD_ASSERT_UNKNOWN( i_v_x < play->num_par_rec() );
var_by_load_op[ arg[2] ] = 0;
Base v_x = parameter[i_v_x];
z[0] = v_x;
}
}
/*!
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_v_x = index_by_ind[ 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 var_by_load_op array.
\param var_by_load_op
is a vector with size play->num_load_op_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( var_by_load_op[ 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 Base>
inline 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_t* arg ,
const addr_t* var_by_load_op ,
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_load_op_rec() );
size_t i_var = size_t( var_by_load_op[ 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_v_x = index_by_ind[ 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< \a Base > and computations by this routine are done using type
\a 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
\a arg[2]
Is the index of this vecad load instruction in the
var_by_load_op 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 \a arg[2] is zero).
\param partial
If \a arg[2] is zero, y[x] is a parameter
and no values need to be modified; i.e., \a partial is not used.
Otherwise, y[x] is a variable and:
\n
\n
\a partial [ \a i_z * \a nc_partial + k ]
for k = 0 , ... , \a d
is the partial derivative of G
with respect to the k-th order Taylor coefficient for z.
\n
\n
If \a arg[2] is not zero,
\a partial [ \a arg[2] * \a nc_partial + k ]
for k = 0 , ... , \a 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 var_by_load_op
is a vector with size play->num_load_op_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 Base>
inline void reverse_load_op(
OpCode op ,
size_t d ,
size_t i_z ,
const addr_t* arg ,
size_t cap_order ,
const Base* taylor ,
size_t nc_partial ,
Base* partial ,
const addr_t* var_by_load_op )
{ size_t i_load = size_t( var_by_load_op[ 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>
inline void forward_sparse_load_op(
bool dependency ,
OpCode op ,
size_t i_z ,
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) == 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, 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>
inline void reverse_sparse_jacobian_load_op(
bool dependency ,
OpCode op ,
size_t i_z ,
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) == 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(arg[1], 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
\a 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
\a 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>
inline void reverse_sparse_hessian_load_op(
OpCode op ,
size_t i_z ,
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) == 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
+204
View File
@@ -0,0 +1,204 @@
# ifndef CPPAD_LOCAL_LOG1P_OP_HPP
# define CPPAD_LOCAL_LOG1P_OP_HPP
# if CPPAD_USE_CPLUSPLUS_2011
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
# endif
+202
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+359
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-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
inline 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 + arg[0] * num_taylor_per_var;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
inline 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 + arg[0] * cap_order;
const Base* y = taylor + arg[1] * cap_order;
// Partial derivatives corresponding to arguments and result
Base* px = partial + arg[0] * nc_partial;
Base* py = partial + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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
+60
View File
@@ -0,0 +1,60 @@
// $Id: op.hpp 3876 2017-02-10 12:45:08Z bradbell $
# ifndef CPPAD_LOCAL_OP_HPP
# define CPPAD_LOCAL_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
// used by the sparse operators
# include <cppad/local/sparse_internal.hpp>
// operations
# include <cppad/core/std_math_98.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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,72 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP
# define CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/local/declare_ad.hpp> // defines CompareOp
# include <cppad/utility/vector.hpp>
/*!
\file cexp_info.hpp
Information about one conditional expression.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Information about one conditional expression.
*/
struct struct_cexp_info {
/// The operator index for this conditional expression operation
size_t i_op;
/// (flag & 1) is true if and only if left is a variable
/// (flag & 2) is true if and only if right is a variable
size_t flag;
/// variable or parameter index for left comparison operand
size_t left;
/// variable or parameter index for right comparison operand
size_t right;
/// maximum variable index between left and right (ignoring parameters).
size_t max_left_right;
/// set of operator that are not used when comparison result is true
/// Note that UsrapOp, UsravOp, UsrrpOp, and UsrrvOp, are not in this
/// vector and should be skipped when the corresponding UserOp are skipped.
CppAD::vector<size_t> skip_op_true;
/// set of variables that are not used when comparison result is false
/// Note that UsrapOp, UsravOp, UsrrpOp, and UsrrvOp, are not in this
/// vector and should be skipped when the corresponding UserOp are skipped.
CppAD::vector<size_t> skip_op_false;
/// comparision operator for this conditional expression
CompareOp cop;
};
// Information about the conditional skip in the new operation sequence
struct struct_cskip_new {
/// new variable or parameter index for left comparison operand
size_t left;
/// new variable or parameter index for right comparison operand
size_t right;
/// maximum variable index between left and right (ignoring parameters).
size_t max_left_right;
/// index where this conditional skips arguments start
size_t i_arg;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
@@ -0,0 +1,38 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP
# define CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <stack>
# include <cppad/local/optimize/csum_variable.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_variable> op_stack;
/// old variable indices to be added
std::stack<size_t > add_stack;
/// old variavle indices to be subtracted
std::stack<size_t > sub_stack;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
@@ -0,0 +1,42 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_VARIABLE_HPP
# define CPPAD_LOCAL_OPTIMIZE_CSUM_VARIABLE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/local/op_code.hpp>
# include <cppad/local/declare_ad.hpp> // defines addr_t
/*!
\file csum_variable.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_variable {
/// 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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP
# define CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\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
(num_arg <= 2).
\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 op ,
size_t num_arg ,
const addr_t* arg )
{
//
CPPAD_ASSERT_UNKNOWN(num_arg <= 2 );
size_t sum = size_t(arg[0]) + size_t(op);
if( 1 < num_arg )
sum += size_t(arg[1]);
//
return sum % CPPAD_HASH_TABLE_SIZE;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
+269
View File
@@ -0,0 +1,269 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP
# define CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/local/optimize/hash_code.hpp>
/*!
\file match_op.hpp
Check if current operator matches a previous operator.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Search for a previous operator that matches the current one.
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.
\param var2op
mapping from variable index to operator index.
\param op_info
Mapping from operator index to operator information.
The input value of op_info[current].previous is assumed to be zero.
If a match if found,
the output value of op_info[current].previous is set to the
matching operator index, otherwise it is left as is.
Note that op_info[current].previous < current.
\param current
is the index of the current operator which must be an unary
or binary operator. Note that NumArg(ErfOp) == 3 but it is effectivey
a unary operator and is allowed otherwise NumArg( op_info[current].op) < 3.
It is assumed that hash_table_op is initialized as a vector of emtpy
sets. After this initialization, the value of current inceases with
each call to match_op.
\li
This must be a unary or binary
operator; hence, NumArg( op_info[current].op ) is one or two.
There is one exception, NumRes( ErfOp ) == 3, but arg[0]
is the only true arguments (the others are always the same).
\li
This must not be a VecAD load or store operation; i.e.,
LtpvOp, LtvpOp, LtvvOp, StppOp, StpvOp, StvpOp, StvvOp.
It also must not be an independent variable operator InvOp.
\param hash_table_op
is a vector of sets,
hash_table_op.n_set() == CPPAD_HASH_TABLE_SIZE and
hash_table_op.end() == op_info.size().
If i_op is an element of set[j],
then the operation op_info[i_op] has hash code j,
and op_info[i_op] does not match any other element of set[j].
An entry will be added each time match_op is called
and a match for the current operator is not found.
*/
inline void match_op(
const vector<addr_t>& var2op ,
vector<struct_op_info>& op_info ,
size_t current ,
sparse_list& hash_table_op )
{ size_t num_op = op_info.size();
//
CPPAD_ASSERT_UNKNOWN( op_info[current].previous == 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 );
//
// current operator
OpCode op = op_info[current].op;
const addr_t* arg = op_info[current].arg;
//
// which arguments are variable
size_t num_arg = NumArg(op);
//
bool variable[2];
variable[0] = false;
variable[1] = false;
switch(op)
{ //
case ErfOp:
num_arg = 1; // other arugments are always the same
//
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case ExpOp:
case Expm1Op:
case LogOp:
case Log1pOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
CPPAD_ASSERT_UNKNOWN( num_arg == 1 );
variable[0] = true;
break;
case AddpvOp:
case DisOp:
case DivpvOp:
case EqpvOp:
case LepvOp:
case LtpvOp:
case MulpvOp:
case NepvOp:
case PowpvOp:
case SubpvOp:
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( num_arg == 2 );
variable[1] = true;
break;
case DivvpOp:
case LevpOp:
case LtvpOp:
case PowvpOp:
case SubvpOp:
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( num_arg == 2 );
variable[0] = true;
break;
case AddvvOp:
case DivvvOp:
case EqvvOp:
case LevvOp:
case LtvvOp:
case MulvvOp:
case NevvOp:
case PowvvOp:
case SubvvOp:
case ZmulvvOp:
CPPAD_ASSERT_UNKNOWN( num_arg == 2 );
variable[0] = true;
variable[1] = true;
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
//
// If i-th argument to current operator has a previous operator,
// this is the i-th argument for previous operator.
// Otherwise, it is the i-th argument for the current operator
// (if a previous variable exists)
addr_t arg_match[2];
for(size_t j = 0; j < num_arg; ++j)
{ arg_match[j] = arg[j];
if( variable[j] )
{ size_t previous = op_info[ var2op[arg[j]] ].previous;
if( previous != 0 )
{ CPPAD_ASSERT_UNKNOWN( op_info[previous].previous == 0 );
//
arg_match[j] = op_info[previous].i_var;
}
}
}
size_t code = optimize_hash_code(op, num_arg, arg_match);
//
// iterator for the set with this hash code
sparse_list_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_info[candidate].previous == 0 );
//
// check for a match
bool match = op == op_info[candidate].op;
if( match )
{ for(size_t j = 0; j < num_arg; j++)
{ if( variable[j] )
{ size_t previous =
op_info[ var2op[op_info[candidate].arg[j]] ].previous;
if( previous != 0 )
{ CPPAD_ASSERT_UNKNOWN(op_info[previous].previous == 0);
//
match &=
arg_match[j] == addr_t( op_info[previous].i_var );
}
else
match &= arg_match[j] == op_info[candidate].arg[j];
}
}
}
if( match )
{ op_info[current].previous = static_cast<addr_t>( candidate );
return;
}
++itr;
}
// special case where operator is commutative
if( (op == AddvvOp) | (op == MulvvOp ) )
{ CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
std::swap( arg_match[0], arg_match[1] );
//
code = optimize_hash_code(op, num_arg, arg_match);
sparse_list_const_iterator itr_swap(hash_table_op, code);
while( *itr_swap != num_op )
{
size_t candidate = *itr_swap;
CPPAD_ASSERT_UNKNOWN( candidate < current );
CPPAD_ASSERT_UNKNOWN( op_info[candidate].previous == 0 );
//
bool match = op == op_info[candidate].op;
if( match )
{ for(size_t j = 0; j < num_arg; j++)
{ CPPAD_ASSERT_UNKNOWN( variable[j] )
size_t previous =
op_info[ var2op[op_info[candidate].arg[j]] ].previous;
if( previous != 0 )
{ CPPAD_ASSERT_UNKNOWN(op_info[previous].previous == 0);
//
match &=
arg_match[j] == addr_t( op_info[previous].i_var );
}
else
match &= arg_match[j] == op_info[candidate].arg[j];
}
}
if( match )
{ op_info[current].previous = static_cast<addr_t>( candidate );
return;
}
++itr_swap;
}
}
CPPAD_ASSERT_UNKNOWN( count < 11 );
if( count == 10 )
{ // restart the list
hash_table_op.clear(code);
}
// no match was found, add this operator the the set for this hash code
hash_table_op.add_element(code, current);
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
+34
View File
@@ -0,0 +1,34 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_OLD2NEW_HPP
# define CPPAD_LOCAL_OPTIMIZE_OLD2NEW_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\file old2new.hpp
Information that maps old an old operator to a new opeator and new variable.
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Information that maps old an old operator to a new opeator and new variable.
*/
struct struct_old2new {
/// New operator index for this old operator.
addr_t new_op;
/// New varaible index for this old operator.
addr_t new_var;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
+51
View File
@@ -0,0 +1,51 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_OP_INFO_HPP
# define CPPAD_LOCAL_OPTIMIZE_OP_INFO_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/local/op_code.hpp>
# include <cppad/local/optimize/usage.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/// information for one operator
struct struct_op_info {
/// arguments
const addr_t* arg;
/// Primary (not auxillary) variable index for this operator. If the
// operator has not results, this is num_var (an invalid variable index).
addr_t i_var;
/*!
previous operator that can be used in place of this operator.
\li
If previous == 0, no such operator was found.
\li
If previous != 0,
op_info[pevious].previous == 0 and
op_info[previous].usage == yes_usage.
*/
addr_t previous;
/// op code
OpCode op;
/// How is this operator used to compute the dependent variables.
/// If usage = csum_usage or usage = no_usage, previous = 0.
enum_usage usage;
};
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
@@ -0,0 +1,922 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP
# define CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <stack>
# include <iterator>
# include <cppad/local/optimize/usage.hpp>
# include <cppad/local/optimize/get_op_info.hpp>
# include <cppad/local/optimize/old2new.hpp>
# include <cppad/local/optimize/size_pair.hpp>
# include <cppad/local/optimize/csum_variable.hpp>
# include <cppad/local/optimize/csum_stacks.hpp>
# include <cppad/local/optimize/cexp_info.hpp>
# include <cppad/local/optimize/match_op.hpp>
# include <cppad/local/optimize/record_pv.hpp>
# include <cppad/local/optimize/record_vp.hpp>
# include <cppad/local/optimize/record_vv.hpp>
# include <cppad/local/optimize/record_csum.hpp>
/*!
\file optimize_run.hpp
Convert a player object to an optimized recorder object
*/
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Convert a player object to an optimized recorder object
\tparam Base
base type for the operator; i.e., this operation was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\param options
\li
If the sub-string "no_conditional_skip" appears,
conditional skip operations will not be generated.
This may make the optimize routine use significantly less memory
and take significantly less time.
\li
If the sub-string "no_compare_op" appears,
then comparison operators will be removed from the optimized tape.
These operators are necessary for the compare_change function to be
be meaningful in the resulting recording.
On the other hand, they are not necessary and take extra time
when compare_change is not used.
\li
If the sub-string "no_print_for" appears,
then print forward (PriOp) operators will be removed from the optimized tape.
These operators are useful for reporting problems evaluating derivatives
at independent variable values different from those used to record a function.
\param n
is the number of independent variables on the tape.
\param dep_taddr
On input this vector contains the indices for each of the dependent
variable values in the operation sequence corresponding to \a play.
Upon return it contains the indices for the same variables but in
the operation sequence corresponding to \a rec.
\param play
This is the operation sequence that we are optimizing.
It is essentially const, except for play back state which
changes while it plays back the operation seqeunce.
\param rec
The input contents of this recording does not matter.
Upon return, it contains an optimized verison of the
operation sequence corresponding to \a play.
*/
template <class Base>
void optimize_run(
const std::string& options ,
size_t n ,
CppAD::vector<size_t>& dep_taddr ,
player<Base>* play ,
recorder<Base>* rec )
{
bool conditional_skip = true;
bool compare_op = true;
bool print_for_op = true;
size_t index = 0;
while( index < options.size() )
{ while( index < options.size() && options[index] == ' ' )
++index;
std::string option;
while( index < options.size() && options[index] != ' ' )
option += options[index++];
if( option != "" )
{ if( option == "no_conditional_skip" )
conditional_skip = false;
else if( option == "no_compare_op" )
compare_op = false;
else if( option == "no_print_for_op" )
print_for_op = false;
else
{ option += " is not a valid optimize option";
CPPAD_ASSERT_KNOWN( false , option.c_str() );
}
}
}
// number of operators in the player
const size_t num_op = play->num_op_rec();
CPPAD_ASSERT_UNKNOWN(
num_op < size_t( std::numeric_limits<addr_t>::max() )
);
// number of variables in the player
const size_t num_var = play->num_var_rec();
// number of VecAD indices
size_t num_vecad_ind = play->num_vec_ind_rec();
// number of VecAD vectors
size_t num_vecad_vec = play->num_vecad_vec_rec();
// operator information
vector<addr_t> var2op;
vector<struct_cexp_info> cexp_info;
sparse_list skip_op_true;
sparse_list skip_op_false;
vector<bool> vecad_used;
vector<struct_op_info> op_info;
get_op_info(
conditional_skip,
compare_op,
print_for_op,
play,
dep_taddr,
var2op,
cexp_info,
skip_op_true,
skip_op_false,
vecad_used,
op_info
);
// nan with type Base
Base base_nan = Base( std::numeric_limits<double>::quiet_NaN() );
// -------------------------------------------------------------
// information for current operator
size_t i_op; // index
OpCode op; // operator
const addr_t* arg; // arguments
size_t i_var; // variable index of primary (last) result
enum_user_state user_state;
// -------------------------------------------------------------
// conditional expression information
//
// Size of the conditional expression information structure.
// This is equal to the number of conditional expressions when
// conditional_skip is true, otherwise it is zero.
size_t num_cexp = cexp_info.size();
CPPAD_ASSERT_UNKNOWN( conditional_skip || num_cexp == 0 );
//
// sort the conditional expression information by max_left_right
// this is the conditional skip order
vector<size_t> cskip_order(num_cexp);
if( num_cexp > 0 )
{ CppAD::vector<size_t> keys(num_cexp);
for(size_t i = 0; i < num_cexp; i++)
keys[i] = cexp_info[i].max_left_right;
CppAD::index_sort(keys, cskip_order);
}
// initial index in conditional skip order
size_t cskip_order_next = 0;
//
// initialize index in conditional expression order
size_t cexp_next = 0;
// mapping from conditional expression index to conditional skip
// information on new tape
vector<struct_cskip_new> cskip_new(num_cexp);
//
// flag used to indicate that there is no conditional skip
// for this conditional expression
for(size_t i = 0; i < num_cexp; i++)
cskip_new[i].i_arg = 0;
// -------------------------------------------------------------
// Erase all information in the old recording
rec->free();
// initialize mapping from old VecAD index to new VecAD index
CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<addr_t>::max() >= num_vecad_ind
);
CppAD::vector<addr_t> new_vecad_ind(num_vecad_ind);
for(size_t i = 0; i < num_vecad_ind; i++)
new_vecad_ind[i] = addr_t( num_vecad_ind ); // invalid index
{
size_t j = 0; // index into the old set of indices
for(size_t i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
size_t length = play->GetVecInd(j);
if( vecad_used[i] )
{ // Put this VecAD vector in new recording
CPPAD_ASSERT_UNKNOWN(length < num_vecad_ind);
new_vecad_ind[j] = rec->PutVecInd(length);
for(size_t k = 1; k <= length; k++) new_vecad_ind[j+k] =
rec->PutVecInd(
rec->PutPar(
play->GetPar(
play->GetVecInd(j+k)
) ) );
}
// start of next VecAD
j += length + 1;
}
CPPAD_ASSERT_UNKNOWN( j == num_vecad_ind );
}
//
// Mapping from old operator index to new operator information
// (zero is invalid except for old2new[0].new_op and old2new[0].i_var)
vector<struct_old2new> old2new(num_op);
for(size_t i = 0; i < num_op; i++)
{ old2new[i].new_op = 0;
old2new[i].new_var = 0;
}
// temporary buffer for new argument values
addr_t new_arg[6];
// temporary work space used by record_csum
// (decalared here to avoid realloaction of memory)
struct_csum_stacks csum_work;
// tempory used to hold a size_pair
struct_size_pair size_pair;
user_state = start_user;
for(i_op = 0; i_op < num_op; ++i_op)
{ addr_t mask; // temporary used in some switch cases
//
// this operator information
op = op_info[i_op].op;
arg = op_info[i_op].arg;
i_var = op_info[i_op].i_var;
//
// determine if we should insert a conditional skip here
bool skip = conditional_skip;
skip &= cskip_order_next < num_cexp;
skip &= op != BeginOp;
skip &= op != InvOp;
skip &= user_state == start_user;
if( skip )
{ size_t j = cskip_order[cskip_order_next];
if( NumRes(op) > 0 )
skip &= cexp_info[j].max_left_right < i_var;
else
skip &= cexp_info[j].max_left_right <= i_var;
}
if( skip )
{ size_t j = cskip_order[cskip_order_next];
cskip_order_next++;
size_t n_true = skip_op_true.number_elements(j);
size_t n_false = skip_op_false.number_elements(j);
skip &= n_true > 0 || n_false > 0;
if( skip )
{ CPPAD_ASSERT_UNKNOWN( NumRes(CSkipOp) == 0 );
size_t n_arg = 7 + n_true + n_false;
// reserve space for the arguments to this operator but
// delay setting them until we have all the new addresses
cskip_new[j].i_arg = rec->ReserveArg(n_arg);
// i_arg == 0 is used to check if conditional expression
// has been skipped.
CPPAD_ASSERT_UNKNOWN( cskip_new[j].i_arg > 0 );
// There is no corresponding old operator in this case
rec->PutOp(CSkipOp);
}
}
if( op == UserOp )
{ if( user_state == start_user )
user_state = end_user;
else
{ CPPAD_ASSERT_UNKNOWN( user_state == end_user );
user_state = start_user;
}
}
size_t previous;
//
CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<addr_t>::max() >= rec->num_op_rec()
);
//
if( op_info[i_op].usage != yes_usage )
{ if( op == CExpOp )
++cexp_next;
}
else switch( op )
{
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
// Put BeginOp at beginning of recording
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(BeginOp);
rec->PutArg(arg[0]);
break;
// --------------------------------------------------------------
// Unary operators, argument a variable, one result
case AbsOp:
case AcosOp:
case AcoshOp:
case AsinOp:
case AsinhOp:
case AtanOp:
case AtanhOp:
case CosOp:
case CoshOp:
case ErfOp:
case ExpOp:
case Expm1Op:
case LogOp:
case Log1pOp:
case SignOp:
case SinOp:
case SinhOp:
case SqrtOp:
case TanOp:
case TanhOp:
previous = op_info[i_op].previous;
if( previous > 0 )
{ size_t j_op = previous;
old2new[i_op].new_var = old2new[j_op].new_var;
}
else
{ //
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
rec->PutArg( new_arg[0] );
//
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(op);
CPPAD_ASSERT_UNKNOWN(
new_arg[0] < old2new[var2op[i_var]].new_var
);
if( op == ErfOp )
{ CPPAD_ASSERT_NARG_NRES(op, 3, 5);
// Error function is a special case
// second argument is always the parameter 0
// third argument is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_UNKNOWN( NumArg(ErfOp) == 3 );
rec->PutArg( rec->PutPar( Base(0.0) ) );
rec->PutArg( rec->PutPar(
Base( 1.0 / std::sqrt( std::atan(1.0) ) )
) );
}
else
{ // some of these operators have an auxillary result;
// e.g. sine and cosine are computed together.
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(op) ==1 || NumRes(op) == 2 );
}
}
break;
// ---------------------------------------------------
// Binary operators, left variable, right parameter, one result
case SubvpOp:
// check if this is the top of a csum connection
if( op_info[i_op].usage == csum_usage )
break;
if( op_info[ var2op[arg[0]] ].usage == csum_usage )
{
// convert to a sequence of summation operators
size_pair = record_csum(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
csum_work
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
// abort rest of this case
break;
}
case DivvpOp:
case PowvpOp:
case ZmulvpOp:
previous = op_info[i_op].previous;
if( previous > 0 )
{ size_t j_op = previous;
old2new[i_op].new_var = old2new[j_op].new_var;
}
else
{ //
size_pair = record_vp(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
op ,
arg
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
}
break;
// ---------------------------------------------------
// Binary operators, left index, right variable, one result
case DisOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
previous = op_info[i_op].previous;
if( previous > 0 )
{ size_t j_op = previous;
old2new[i_op].new_var = old2new[j_op].new_var;
}
else
{ //
new_arg[0] = arg[0];
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
rec->PutArg( new_arg[0], new_arg[1] );
//
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(op);
CPPAD_ASSERT_UNKNOWN(
new_arg[1] < old2new[var2op[i_var]].new_var
);
}
break;
// ---------------------------------------------------
// Binary operators, left parameter, right variable, one result
case SubpvOp:
case AddpvOp:
// check if this is the top of a csum connection
if( op_info[i_op].usage == csum_usage )
break;
if( op_info[ var2op[arg[1]] ].usage == csum_usage )
{
// convert to a sequence of summation operators
size_pair = record_csum(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
csum_work
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
// abort rest of this case
break;
}
case DivpvOp:
case MulpvOp:
case PowpvOp:
case ZmulpvOp:
previous = op_info[i_op].previous;
if( previous > 0 )
{ size_t j_op = previous;
old2new[i_op].new_var = old2new[j_op].new_var;
}
else
{ //
size_pair = record_pv(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
op ,
arg
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
}
break;
// ---------------------------------------------------
// Binary operator, left and right variables, one result
case AddvvOp:
case SubvvOp:
// check if this is the top of a csum connection
if( op_info[i_op].usage == csum_usage )
break;
if(
op_info[ var2op[arg[0]] ].usage == csum_usage ||
op_info[ var2op[arg[1]] ].usage == csum_usage
)
{
// convert to a sequence of summation operators
size_pair = record_csum(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
csum_work
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
// abort rest of this case
break;
}
case DivvvOp:
case MulvvOp:
case PowvvOp:
case ZmulvvOp:
previous = op_info[i_op].previous;
if( previous > 0 )
{ size_t j_op = previous;
old2new[i_op].new_var = old2new[j_op].new_var;
}
else
{ //
size_pair = record_vv(
var2op ,
op_info ,
old2new ,
i_var ,
play->num_par_rec() ,
play->GetPar() ,
rec ,
op ,
arg
);
old2new[i_op].new_op = addr_t( size_pair.i_op );
old2new[i_op].new_var = addr_t( size_pair.i_var );
}
break;
// ---------------------------------------------------
// Conditional expression operators
case CExpOp:
CPPAD_ASSERT_NARG_NRES(op, 6, 1);
new_arg[0] = arg[0];
new_arg[1] = arg[1];
mask = 1;
for(size_t i = 2; i < 6; i++)
{ if( arg[1] & mask )
{ new_arg[i] = old2new[ var2op[arg[i]] ].new_var;
CPPAD_ASSERT_UNKNOWN(
size_t(new_arg[i]) < num_var
);
}
else new_arg[i] = rec->PutPar(
play->GetPar( arg[i] )
);
mask = mask << 1;
}
rec->PutArg(
new_arg[0] ,
new_arg[1] ,
new_arg[2] ,
new_arg[3] ,
new_arg[4] ,
new_arg[5]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(op);
//
// The new addresses for left and right are used during
// fill in the arguments for the CSkip operations. This does not
// affect max_left_right which is used during this sweep.
if( conditional_skip )
{ CPPAD_ASSERT_UNKNOWN( cexp_next < num_cexp );
CPPAD_ASSERT_UNKNOWN( cexp_info[cexp_next].i_op == i_op );
cskip_new[ cexp_next ].left = new_arg[2];
cskip_new[ cexp_next ].right = new_arg[3];
++cexp_next;
}
break;
// ---------------------------------------------------
// Operations with no arguments and no results
case EndOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 0);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// ---------------------------------------------------
// Operations with two arguments and no results
case LepvOp:
case LtpvOp:
case EqpvOp:
case NepvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
rec->PutArg(new_arg[0], new_arg[1]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
//
case LevpOp:
case LtvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
rec->PutArg(new_arg[0], new_arg[1]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
//
case LevvOp:
case LtvvOp:
case EqvvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
rec->PutArg(new_arg[0], new_arg[1]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// ---------------------------------------------------
// Operations with no arguments and one result
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(op);
break;
// ---------------------------------------------------
// Unary operators, argument a parameter, one result
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
new_arg[0] = rec->PutPar( play->GetPar(arg[0] ) );
rec->PutArg( new_arg[0] );
//
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(op);
break;
// ---------------------------------------------------
// print forward operator
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
// arg[0]
new_arg[0] = arg[0];
//
// arg[1]
if( arg[0] & 1 )
{ new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
}
else
{ new_arg[1] = rec->PutPar( play->GetPar( arg[1] ) );
}
//
// arg[3]
if( arg[0] & 2 )
{ new_arg[3] = old2new[ var2op[arg[3]] ].new_var;
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[3]) < num_var );
}
else
{ new_arg[3] = rec->PutPar( play->GetPar( arg[3] ) );
}
new_arg[2] = rec->PutTxt( play->GetTxt(arg[2]) );
new_arg[4] = rec->PutTxt( play->GetTxt(arg[4]) );
//
rec->PutArg(
new_arg[0] ,
new_arg[1] ,
new_arg[2] ,
new_arg[3] ,
new_arg[4]
);
// new operator
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
// no new variable
rec->PutOp(op);
break;
// ---------------------------------------------------
// VecAD operators
// Load using a parameter index
case LdpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 1);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = arg[1];
CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<addr_t>::max() >= rec->num_load_op_rec()
);
new_arg[2] = addr_t( rec->num_load_op_rec() );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutLoadOp(op);
break;
// Load using a variable index
case LdvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 1);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<addr_t>::max() >= rec->num_load_op_rec()
);
new_arg[2] = addr_t( rec->num_load_op_rec() );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutLoadOp(op);
break;
// Store a parameter using a parameter index
case StppOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
new_arg[2] = rec->PutPar( play->GetPar(arg[2]) );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// Store a parameter using a variable index
case StvpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
new_arg[2] = rec->PutPar( play->GetPar(arg[2]) );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// Store a variable using a parameter index
case StpvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = rec->PutPar( play->GetPar(arg[1]) );
new_arg[2] = old2new[ var2op[arg[2]] ].new_var;
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// Store a variable using a variable index
case StvvOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
new_arg[0] = new_vecad_ind[ arg[0] ];
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
new_arg[2] = old2new[ var2op[arg[2]] ].new_var;
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var );
CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var );
rec->PutArg(
new_arg[0],
new_arg[1],
new_arg[2]
);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(op);
break;
// -----------------------------------------------------------
// user atomic function call operators
case UserOp:
CPPAD_ASSERT_NARG_NRES(op, 4, 0);
// user_old, user_n, user_m
rec->PutArg(arg[0], arg[1], arg[2], arg[3]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(UserOp);
break;
case UsrapOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
rec->PutArg(new_arg[0]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(UsrapOp);
break;
case UsravOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
if( size_t(new_arg[0]) < num_var )
{ rec->PutArg(new_arg[0]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(UsravOp);
}
else
{ // This argument does not affect the result and
// has been optimized out so use nan in its place.
new_arg[0] = rec->PutPar( base_nan );
rec->PutArg(new_arg[0]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(UsrapOp);
}
break;
case UsrrpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 0);
new_arg[0] = rec->PutPar( play->GetPar(arg[0]) );
rec->PutArg(new_arg[0]);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
rec->PutOp(UsrrpOp);
break;
case UsrrvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
old2new[i_op].new_op = addr_t( rec->num_op_rec() );
old2new[i_op].new_var = rec->PutOp(UsrrvOp);
break;
// ---------------------------------------------------
// all cases should be handled above
default:
CPPAD_ASSERT_UNKNOWN(false);
}
}
// modify the dependent variable vector to new indices
for(size_t i = 0; i < dep_taddr.size(); i++ )
{ dep_taddr[i] = old2new[ var2op[dep_taddr[i]] ].new_var;
CPPAD_ASSERT_UNKNOWN( size_t(dep_taddr[i]) < num_var );
}
# ifndef NDEBUG
for(i_op = 0; i_op < num_op; i_op++)
if( NumRes( op_info[i_op].op ) > 0 )
CPPAD_ASSERT_UNKNOWN(
size_t(old2new[i_op].new_op) < rec->num_op_rec()
);
# endif
// make sure that all the conditional expressions have been
// checked to see if they are still present
CPPAD_ASSERT_UNKNOWN( cskip_order_next == num_cexp );
// fill in the arguments for the CSkip operations
for(size_t i = 0; i < num_cexp; i++)
{ // if cskip_new[i].i_arg == 0, this conditional expression was skipped
if( cskip_new[i].i_arg > 0 )
{ struct_cexp_info info = cexp_info[i];
size_t n_true = skip_op_true.number_elements(i);
size_t n_false = skip_op_false.number_elements(i);
size_t i_arg = cskip_new[i].i_arg;
size_t left = cskip_new[i].left;
size_t right = cskip_new[i].right;
rec->ReplaceArg(i_arg++, info.cop );
rec->ReplaceArg(i_arg++, info.flag );
rec->ReplaceArg(i_arg++, left );
rec->ReplaceArg(i_arg++, right );
rec->ReplaceArg(i_arg++, n_true );
rec->ReplaceArg(i_arg++, n_false );
sparse_list::const_iterator itr_true(skip_op_true, i);
while( *itr_true != skip_op_true.end() )
{ i_op = *itr_true;
// op_info[i_op].usage == yes_usage
CPPAD_ASSERT_UNKNOWN( old2new[i_op].new_op != 0 );
rec->ReplaceArg(i_arg++, old2new[i_op].new_op );
//
++itr_true;
}
sparse_list::const_iterator itr_false(skip_op_false, i);
while( *itr_false != skip_op_false.end() )
{ i_op = *itr_false;
// op_info[i_op].usage == yes_usage
CPPAD_ASSERT_UNKNOWN( old2new[i_op].new_op != 0 );
rec->ReplaceArg(i_arg++, old2new[i_op].new_op );
//
++itr_false;
}
rec->ReplaceArg(i_arg++, n_true + n_false);
# ifndef NDEBUG
size_t n_arg = 7 + n_true + n_false;
CPPAD_ASSERT_UNKNOWN( cskip_new[i].i_arg + n_arg == i_arg );
# endif
}
}
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
@@ -0,0 +1,259 @@
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\file record_csum.hpp
Recording a cummulative cummulative summation.
*/
# include <cppad/local/optimize/old2new.hpp>
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
/*!
Recording a cummulative cummulative summation.
\param var2op
mapping from old variable index to old operator index.
\param op_info
mapping from old index to operator index to operator information
\param old2new
mapping from old operator index to information about the new recording.
\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
We use the notation i_op = var2op[current].
It follows that NumRes( op_info[i_op].op ) > 0.
If 0 < j_op < i_op, either op_info[j_op].usage == csum_usage,
op_info[j_op].usage = no_usage, or old2new[j_op].new_var != 0.
\param npar
is the number of parameters corresponding to the old operation sequence.
\param par
is a 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].
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
\param work
Is temporary work space. On input and output,
work.op_stack, work.add_stack, and work.sub_stack, are all empty.
These stacks are passed in so that they are created once
and then be reused with calls to record_csum.
\par Assumptions
op_info[i_o].op
must be one of AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp.
op_info[i_op].usage != no_usage and ! op_info[i_op].usage == csum_usage.
Furthermore op_info[j_op].usage == csum_usage is true from some
j_op that corresponds to a variable that is an argument to
op_info[i_op].
*/
template <class Base>
struct_size_pair record_csum(
const vector<addr_t>& var2op ,
const vector<struct_op_info>& op_info ,
const CppAD::vector<struct struct_old2new>& old2new ,
size_t current ,
size_t npar ,
const Base* par ,
recorder<Base>* rec ,
// local information passed so stacks need not be allocated for every call
struct_csum_stacks& work )
{
// check assumption about work space
CPPAD_ASSERT_UNKNOWN( work.op_stack.empty() );
CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() );
CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() );
//
size_t i_op = var2op[current];
CPPAD_ASSERT_UNKNOWN( ! ( op_info[i_op].usage == csum_usage ) );
//
size_t i;
OpCode op;
const addr_t* arg;
bool add;
struct struct_csum_variable var;
//
// information corresponding to the root node in the cummulative summation
var.op = op_info[i_op].op; // this operator
var.arg = op_info[i_op].arg; // arguments for this operator
var.add = true; // was parrent operator positive or negative
//
// initialize stack as containing this one operator
work.op_stack.push( var );
//
// initialize sum of parameter values as zero
Base sum_par(0);
//
# ifndef NDEBUG
bool ok = false;
struct_op_info info = op_info[i_op];
if( var.op == SubvpOp )
ok = op_info[ var2op[info.arg[0]] ].usage == csum_usage;
if( var.op == AddpvOp || var.op == SubpvOp )
ok = op_info[ var2op[info.arg[1]] ].usage == csum_usage;
if( var.op == AddvvOp || var.op == SubvvOp )
{ ok = op_info[ var2op[info.arg[0]] ].usage == csum_usage;
ok |= op_info[ var2op[info.arg[1]] ].usage == csum_usage;
}
CPPAD_ASSERT_UNKNOWN( ok );
# endif
//
// while there are operators left on the stack
while( ! work.op_stack.empty() )
{ // get this summation operator
var = work.op_stack.top();
work.op_stack.pop();
op = var.op;
arg = var.arg;
add = var.add;
//
// process first argument to this operator
switch(op)
{ // cases where first argument is a parameter
case AddpvOp:
case SubpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
// first argument has same sign as parent node
if( add )
sum_par += par[arg[0]];
else sum_par -= par[arg[0]];
break;
// cases where first argument is a variable
case AddvvOp:
case SubvpOp:
case SubvvOp:
//
// check if the first argument has csum usage
if( op_info[var2op[arg[0]]].usage == csum_usage )
{ CPPAD_ASSERT_UNKNOWN(
size_t( old2new[ var2op[arg[0]] ].new_var) == 0
);
// push the operator corresponding to the first argument
var.op = op_info[ var2op[arg[0]] ].op;
var.arg = op_info[ var2op[arg[0]] ].arg;
// first argument has same sign as parent node
var.add = add;
work.op_stack.push( var );
}
else
{ // there are no nodes below this one
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < current );
if( add )
work.add_stack.push(arg[0]);
else work.sub_stack.push(arg[0]);
}
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
// process second argument to this operator
switch(op)
{ // cases where second argument is a parameter
case SubvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
// second argument has opposite sign of parent node
if( add )
sum_par -= par[arg[1]];
else sum_par += par[arg[1]];
break;
// cases where second argument is a variable and has opposite sign
case SubvvOp:
case SubpvOp:
add = ! add;
// cases where second argument is a variable and has same sign
case AddvvOp:
case AddpvOp:
// check if the second argument has csum usage
if( op_info[var2op[arg[1]]].usage == csum_usage )
{ CPPAD_ASSERT_UNKNOWN(
size_t( old2new[ var2op[arg[1]] ].new_var) == 0
);
// push the operator corresoponding to the second arugment
var.op = op_info[ var2op[arg[1]] ].op;
var.arg = op_info[ var2op[arg[1]] ].arg;
var.add = add;
work.op_stack.push( var );
}
else
{ // there are no nodes below this one
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
if( add )
work.add_stack.push(arg[1]);
else work.sub_stack.push(arg[1]);
}
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
}
// number of variables to add in this cummulative sum operator
size_t n_add = work.add_stack.size();
// number of variables to subtract in this cummulative sum operator
size_t n_sub = work.sub_stack.size();
//
CPPAD_ASSERT_UNKNOWN(
std::numeric_limits<addr_t>::max() >= n_add + n_sub
);
//
rec->PutArg( addr_t(n_add) ); // arg[0]
rec->PutArg( addr_t(n_sub) ); // arg[1]
addr_t new_arg = rec->PutPar(sum_par);
rec->PutArg(new_arg); // arg[2]
// addition arguments
for(i = 0; i < n_add; i++)
{ CPPAD_ASSERT_UNKNOWN( ! work.add_stack.empty() );
size_t old_arg = work.add_stack.top();
new_arg = old2new[ var2op[old_arg] ].new_var;
CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
rec->PutArg(new_arg); // arg[3+i]
work.add_stack.pop();
}
// subtraction arguments
for(i = 0; i < n_sub; i++)
{ CPPAD_ASSERT_UNKNOWN( ! work.sub_stack.empty() );
size_t old_arg = work.sub_stack.top();
new_arg = old2new[ var2op[old_arg] ].new_var;
CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current );
rec->PutArg(new_arg); // arg[3 + arg[0] + i]
work.sub_stack.pop();
}
// number of additions plus number of subtractions
rec->PutArg( addr_t(n_add + n_sub) ); // arg[3 + arg[0] + arg[1]]
//
// return value
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = rec->PutOp(CSumOp);
//
return ret;
}
} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
# endif
@@ -0,0 +1,105 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\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 var2op
mapping from old variable index to old operator index.
\param op_info
mapping from old index to operator index to operator information
\param old2new
mapping from old operator index to information about the new recording.
\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
We use the notation i_op = var2op[current].
It follows that NumRes( op_info[i_op].op ) > 0.
If 0 < j_op < i_op, either op_info[j_op].csum_connected,
op_info[j_op].usage = 0, or old2new[j_op].new_var != 0.
\param npar
is the number of parameters corresponding to the old operation sequence.
\param par
is a 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].
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
\param op
is the operator that we are recording which must be one of the following:
AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp.
\param arg
is the vector of arguments for this operator.
*/
template <class Base>
struct_size_pair record_pv(
const vector<addr_t>& var2op ,
const vector<struct_op_info>& op_info ,
const CppAD::vector<struct struct_old2new>& old2new ,
size_t current ,
size_t npar ,
const Base* par ,
recorder<Base>* rec ,
OpCode op ,
const addr_t* arg )
{
# ifndef NDEBUG
switch(op)
{ case AddpvOp:
case DivpvOp:
case MulpvOp:
case PowpvOp:
case SubpvOp:
case ZmulpvOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
# endif
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
addr_t new_arg[2];
new_arg[0] = rec->PutPar( par[arg[0]] );
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
rec->PutArg( new_arg[0], new_arg[1] );
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = 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
@@ -0,0 +1,104 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\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 var2op
mapping from old variable index to old operator index.
\param op_info
mapping from old index to operator index to operator information
\param old2new
mapping from old operator index to information about the new recording.
\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
We use the notation i_op = var2op[current].
It follows that NumRes( op_info[i_op].op ) > 0.
If 0 < j_op < i_op, either op_info[j_op].csum_connected,
op_info[j_op].usage = 0, or old2new[j_op].new_var != 0.
\param npar
is the number of parameters corresponding to the old operation sequence.
\param par
is a 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].
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
\param op
is the operator that we are recording which must be one of the following:
DivvpOp, PowvpOp, SubvpOp, ZmulvpOp.
\param arg
is the vector of arguments for this operator.
*/
template <class Base>
struct_size_pair record_vp(
const vector<addr_t>& var2op ,
const vector<struct_op_info>& op_info ,
const CppAD::vector<struct struct_old2new>& old2new ,
size_t current ,
size_t npar ,
const Base* par ,
recorder<Base>* rec ,
OpCode op ,
const addr_t* arg )
{
# ifndef NDEBUG
switch(op)
{ case DivvpOp:
case PowvpOp:
case SubvpOp:
case ZmulvpOp:
break;
default:
CPPAD_ASSERT_UNKNOWN(false);
}
# endif
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < current );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar );
addr_t new_arg[2];
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
new_arg[1] = rec->PutPar( 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 = 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
@@ -0,0 +1,105 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP
# define CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\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 var2op
mapping from old variable index to old operator index.
\param op_info
mapping from old index to operator index to operator information
\param old2new
mapping from old operator index to information about the new recording.
\param current
is the index in the old operation sequence for
the variable corresponding to the result for the current operator.
We use the notation i_op = var2op[current].
It follows that NumRes( op_info[i_op].op ) > 0.
If 0 < j_op < i_op, either op_info[j_op].csum_connected,
op_info[j_op].usage = 0, or old2new[j_op].new_var != 0.
\param npar
is the number of parameters corresponding to the old operation sequence.
\param par
is a 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].
\param rec
is the object that will record the new operations.
\return
is the operator and variable indices in the new operation sequence.
\param op
is the operator that we are recording which must be one of the following:
AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp.
\param arg
is the vector of arguments for this operator.
*/
template <class Base>
struct_size_pair record_vv(
const vector<addr_t>& var2op ,
const vector<struct_op_info>& op_info ,
const CppAD::vector<struct struct_old2new>& old2new ,
size_t current ,
size_t npar ,
const Base* par ,
recorder<Base>* rec ,
OpCode op ,
const addr_t* arg )
{
# 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( size_t(arg[0]) < current );
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < current );
addr_t new_arg[2];
new_arg[0] = old2new[ var2op[arg[0]] ].new_var;
new_arg[1] = old2new[ var2op[arg[1]] ].new_var;
rec->PutArg( new_arg[0], new_arg[1] );
struct_size_pair ret;
ret.i_op = rec->num_op_rec();
ret.i_var = 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
@@ -0,0 +1,32 @@
// $Id$
# 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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
/*!
\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
+35
View File
@@ -0,0 +1,35 @@
// $Id$
# ifndef CPPAD_LOCAL_OPTIMIZE_USAGE_HPP
# define CPPAD_LOCAL_OPTIMIZE_USAGE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
namespace CppAD { namespace local { namespace optimize {
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
+90
View File
@@ -0,0 +1,90 @@
// $Id: parameter_op.hpp 3845 2016-11-19 01:50:47Z bradbell $
# 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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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< \a Base > and computations by this routine are done using type
\a Base .
\param i_z
variable index corresponding to the result for this operation;
i.e. the row index in \a taylor corresponding to the component of y
that is a parameter.
\param arg
\a arg[0]
\n
index corresponding to the parameter value for this operator.
\param num_par
is the number of parameters in \a parameter.
\param parameter
\b Input: \a parameter[ \a 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: \a taylor [ \a i_z * \a 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 \a size_t(arg[0]) < num_par
\li \a 0 < \a cap_order
*/
template <class Base>
inline 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
File diff suppressed because it is too large Load Diff
+293
View File
@@ -0,0 +1,293 @@
// $Id: pod_vector.hpp 3845 2016-11-19 01:50:47Z bradbell $
# ifndef CPPAD_LOCAL_POD_VECTOR_HPP
# define CPPAD_LOCAL_POD_VECTOR_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# if CPPAD_CSTDINT_HAS_8_TO_64
# include <cstdint>
# endif
# include <algorithm>
# include <cppad/utility/thread_alloc.hpp>
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/op_code.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file pod_vector.hpp
File used to define pod_vector class
*/
/*
A list of which Types pod_vector<Type> consideres to be plain old data
*/
/// default value is false
template <class Type> inline bool is_pod(void) { return false; }
/// system pod types so far:
template <> inline bool is_pod<bool>(void) { return true; }
template <> inline bool is_pod<float>(void) { return true; }
template <> inline bool is_pod<double>(void) { return true; }
# if CPPAD_CSTDINT_HAS_8_TO_64
template <> inline bool is_pod<int8_t>(void) { return true; }
template <> inline bool is_pod<int16_t>(void) { return true; }
template <> inline bool is_pod<int32_t>(void) { return true; }
template <> inline bool is_pod<int64_t>(void) { return true; }
//
template <> inline bool is_pod<uint8_t>(void) { return true; }
template <> inline bool is_pod<uint16_t>(void) { return true; }
template <> inline bool is_pod<uint32_t>(void) { return true; }
template <> inline bool is_pod<uint64_t>(void) { return true; }
# else // CPPAD_CSTDINT_HAS_8_TO_64
template <> inline bool is_pod<char>(void) { return true; }
template <> inline bool is_pod<short int>(void) { return true; }
template <> inline bool is_pod<int>(void) { return true; }
//
template <> inline bool is_pod<unsigned char>(void) { return true; }
template <> inline bool is_pod<unsigned short int>(void) { return true; }
template <> inline bool is_pod<unsigned int>(void) { return true; }
# if CPPAD_SIZE_T_NOT_UNSIGNED_INT
template <> inline bool is_pod<size_t>(void) { return true; }
# endif
# endif // CPPAD_CSTDINT_HAS_8_TO_64
/// CppAD pod types so far:
template <> inline bool is_pod<OpCode>(void) { return true; }
// ---------------------------------------------------------------------------
/*!
A vector class with Type element that does not use element constructors
or destructors when Type is Plain Old Data (pod).
*/
template <class Type>
class pod_vector {
private:
/// maximum number of elements that should ever be in this vector
size_t max_length_;
/// number of elements currently in this vector
size_t length_;
/// maximum number of Type elements current allocation can hold
size_t capacity_;
/// 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(const pod_vector& )
{ CPPAD_ASSERT_UNKNOWN(false); }
public:
/// Constructors set capacity, length, and data to zero.
///
/// \param max_length
/// value for maximum number of elements in this vector.
inline pod_vector(
size_t max_length = std::numeric_limits<size_t>::max()
)
: max_length_(max_length), length_(0), capacity_(0), data_(CPPAD_NULL)
{ }
// ----------------------------------------------------------------------
/// Destructor: returns allocated memory to \c thread_alloc;
/// see \c extend. If this is not plain old data,
/// the destructor for each element is called.
~pod_vector(void)
{ if( capacity_ > 0 )
{ void* v_ptr = reinterpret_cast<void*>( data_ );
if( ! is_pod<Type>() )
{ // call destructor for each element
size_t i;
for(i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
thread_alloc::return_memory(v_ptr);
}
}
// ----------------------------------------------------------------------
/// current number of elements in this vector.
inline size_t size(void) const
{ return length_; }
/// current capacity (amount of allocated storage) for this vector.
inline size_t capacity(void) const
{ return capacity_; }
/// current data pointer, no longer valid after any of the following:
/// extend, erase, operator=, and ~pod_vector.
/// Take extreem care when using this function.
inline Type* data(void)
{ return data_; }
/// const version of \c data pointer
inline const Type* data(void) const
{ return data_; }
// ----------------------------------------------------------------------
/*!
Increase the number of elements the end of this vector.
\param n
is the number of elements to add to end of this vector.
\return
is the number of elements in the vector before \c extend was extended.
- If \c 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 is the only routine that allocates memory for \c pod_vector.
and it uses thread_alloc for this allocation, hence this determines
which thread corresponds to this vector (when in parallel mode).
- If the resulting length of the vector would be more than \c max_length_,
and \c NDEBUG is not defined, a CPPAD_ASSERT is generated.
*/
inline size_t extend(size_t n)
{ size_t old_length = length_;
length_ += n;
CPPAD_ASSERT_KNOWN(
length_ <= max_length_ ,
"pod_vector.hpp: attempt to create to large a vector.\n"
"If Type is CPPAD_TYPE_ADDR_TYPE, tape is too long for Type."
);
// check if we can use current memory
if( capacity_ >= length_ )
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);
CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ );
size_t i;
if( ! is_pod<Type>() )
{ // call constructor for each new element
for(i = 0; i < capacity_; i++)
new(data_ + i) Type();
}
// copy old data to new data
for(i = 0; i < old_length; i++)
data_[i] = old_data[i];
// return old memory to available pool
if( old_capacity > 0 )
{ v_ptr = reinterpret_cast<void*>( old_data );
if( ! is_pod<Type>() )
{ for(i = 0; i < old_capacity; i++)
(old_data + i)->~Type();
}
thread_alloc::return_memory(v_ptr);
}
// return value for extend(n) is the old length
return old_length;
}
// ----------------------------------------------------------------------
/// 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];
}
// ----------------------------------------------------------------------
/// 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];
}
// ----------------------------------------------------------------------
/*!
Remove all the elements from this vector but leave the capacity
and data pointer as is.
*/
void erase(void)
{ length_ = 0;
return;
}
// ----------------------------------------------------------------------
/*!
Remove all the elements from this vector and delete its memory.
*/
void free(void)
{ if( capacity_ > 0 )
{ void* v_ptr = reinterpret_cast<void*>( data_ );
if( ! is_pod<Type>() )
{ // call destructor for each element
size_t i;
for(i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
thread_alloc::return_memory(v_ptr);
}
data_ = CPPAD_NULL;
capacity_ = 0;
length_ = 0;
}
/// vector assignment operator
/// If the resulting length of the vector would be more than
/// \c max_length_, and \c NDEBUG is not defined,
/// a CPPAD_ASSERT is generated.
void operator=(
/// right hand size of the assingment operation
const pod_vector& x
)
{ size_t i;
if( x.length_ <= capacity_ )
{ // use existing allocation for this vector
length_ = x.length_;
CPPAD_ASSERT_KNOWN(
length_ <= max_length_ ,
"pod_vector.hpp: attempt to create to large a vector.\n"
"If Type is CPPAD_TYPE_ADDR_TYPE, tape long for Type."
);
}
else
{ // free old memory and get new memory of sufficient length
if( capacity_ > 0 )
{ void* v_ptr = reinterpret_cast<void*>( data_ );
if( ! is_pod<Type>() )
{ // call destructor for each element
for(i = 0; i < capacity_; i++)
(data_ + i)->~Type();
}
thread_alloc::return_memory(v_ptr);
}
length_ = capacity_ = 0;
extend( x.length_ );
}
CPPAD_ASSERT_UNKNOWN( length_ == x.length_ );
for(i = 0; i < length_; i++)
{ data_[i] = x.data_[i]; }
}
/*!
Swap all properties of this vector with another.
\param other
is the other vector that we are swapping this vector with.
*/
void swap(pod_vector& other)
{ std::swap(capacity_, other.capacity_);
std::swap(length_, other.length_);
std::swap(data_, other.data_);
}
};
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+659
View File
@@ -0,0 +1,659 @@
# ifndef CPPAD_LOCAL_POW_OP_HPP
# define CPPAD_LOCAL_POW_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 \a parameter is not used.
\copydetails CppAD::local::forward_pow_op
*/
template <class Base>
inline 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( std::numeric_limits<addr_t>::max() >= i_z );
// z_0 = log(x)
forward_log_op(p, q, i_z, 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 + arg[0] * cap_order;
Base* y = taylor + 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>
inline 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( std::numeric_limits<addr_t>::max() >= i_z );
// z_0 = log(x)
forward_log_op_dir(q, r, i_z, 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 \a parameter is not used.
\copydetails CppAD::local::forward_pow_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::reverse_pow_op
*/
template <class Base>
inline 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( 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, 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>
inline 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(
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 + 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>
inline 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(
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>
inline 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 + 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>
inline 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(
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>
inline 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( std::numeric_limits<addr_t>::max() >= i_z );
// z_0 = log(x)
forward_log_op(p, q, i_z, 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 + 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>
inline 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( std::numeric_limits<addr_t>::max() >= i_z );
// z_0 = log(x)
forward_log_op_dir(q, r, i_z, 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>
inline 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 + 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>
inline 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( 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, arg[0], cap_order, taylor, nc_partial, partial
);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+148
View File
@@ -0,0 +1,148 @@
// $Id: print_op.hpp 3845 2016-11-19 01:50:47Z bradbell $
# ifndef CPPAD_LOCAL_PRINT_OP_HPP
# define CPPAD_LOCAL_PRINT_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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< \a Base > and computations by this routine are done using type
\a Base .
\param s_out
the results are printed on this output stream.
\param arg
\a arg[0] & 1
\n
If this is zero, \a pos is a parameter. Otherwise it is a variable.
\n
\a arg[0] & 2
\n
If this is zero, \a var is a parameter. Otherwise it is a variable.
\n
\n
\a arg[1]
\n
If \a pos is a parameter, <code>parameter[arg[1]]</code> is its value.
Othwise <code>taylor[ arg[1] * cap_order + 0 ]</code> is the zero
order Taylor coefficient for \a pos.
\n
\n
\a arg[2]
\n
index of the text to be printed before \a var
if \a pos is not a positive value.
\n
\n
\a arg[3]
\n
If \a var is a parameter, <code>parameter[arg[3]]</code> is its value.
Othwise <code>taylor[ arg[3] * cap_order + 0 ]</code> is the zero
order Taylor coefficient for \a var.
\n
\n
\a arg[4]
\n
index of the text to be printed after \a var
if \a 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 \a 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 != CPPAD_NULL
\li arg[1] < num_text
\li if \a pos is a parameter, arg[1] < num_par
\li if \a var is a parameter, arg[3] < num_par
*/
template <class Base>
inline 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[ 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[ 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
+618
View File
@@ -0,0 +1,618 @@
# ifndef CPPAD_LOCAL_RECORDER_HPP
# define CPPAD_LOCAL_RECORDER_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/core/hash_code.hpp>
# include <cppad/local/pod_vector.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< \a Base > operation sequence recording; i.e.,
it records operations of type AD< \a Base >.
*/
template <class Base>
class recorder {
friend class player<Base>;
private:
/// operator index at which to abort recording with an error
/// (do not abort when zero)
size_t abort_op_index_;
/// offset for this thread in the static hash table
const size_t thread_offset_;
/// Number of variables in the recording.
size_t num_var_rec_;
/// Number vecad load operations (LdpOp or LdvOp) currently in recording.
size_t num_load_op_rec_;
/// The operators in the recording.
pod_vector<CPPAD_OP_CODE_TYPE> op_rec_;
/// The VecAD indices in the recording.
pod_vector<addr_t> vecad_ind_rec_;
/// The argument indices in the recording
pod_vector<addr_t> op_arg_rec_;
/// The parameters in the recording.
/// Note that Base may not be plain old data, so use false in consructor.
pod_vector<Base> par_rec_;
/// Character strings ('\\0' terminated) in the recording.
pod_vector<char> text_rec_;
// ---------------------- Public Functions -----------------------------------
public:
/// Default constructor
recorder(void) :
thread_offset_( thread_alloc::thread_num() * CPPAD_HASH_TABLE_SIZE ) ,
num_var_rec_(0) ,
num_load_op_rec_(0) ,
op_rec_( std::numeric_limits<addr_t>::max() ) ,
vecad_ind_rec_( std::numeric_limits<addr_t>::max() ) ,
op_arg_rec_( std::numeric_limits<addr_t>::max() ) ,
par_rec_( std::numeric_limits<addr_t>::max() ) ,
text_rec_( std::numeric_limits<addr_t>::max() )
{
abort_op_index_ = 0;
}
/// Set the abort index
void set_abort_op_index(size_t abort_op_index)
{ abort_op_index_ = abort_op_index; }
/// Get the abort index
size_t get_abort_op_index(void)
{ return abort_op_index_; }
/// Destructor
~recorder(void)
{ }
/*!
Frees all information in recording.
Frees the operation sequence store in this recording
(the operation sequence is empty after this operation).
The buffers used to store the current recording are returned
to the system (so as to conserve on memory).
*/
void free(void)
{ num_var_rec_ = 0;
num_load_op_rec_ = 0;
op_rec_.free();
vecad_ind_rec_.free();
op_arg_rec_.free();
par_rec_.free();
text_rec_.free();
}
/// Put next operator in the operation sequence.
inline addr_t PutOp(OpCode op);
/// Put a vecad load operator in the operation sequence (special case)
inline addr_t PutLoadOp(OpCode op);
/// Add a value to the end of the current vector of VecAD indices.
inline addr_t PutVecInd(size_t vec_ind);
/// Find or add a parameter to the current vector of parameters.
inline addr_t PutPar(const Base &par);
/// Put one operation argument index in the recording
inline void PutArg(addr_t arg0);
/// Put two operation argument index in the recording
inline void PutArg(addr_t arg0, addr_t arg1);
/// Put three operation argument index in the recording
inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2);
/// Put four operation argument index in the recording
inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3);
/// Put five operation argument index in the recording
inline 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
inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
addr_t arg4, addr_t arg5);
// Reserve space for a specified number of arguments
inline size_t ReserveArg(size_t n_arg);
// Replace an argument value
void ReplaceArg(size_t i_arg, size_t value);
/// Put a character string in the text for this recording.
inline addr_t PutTxt(const char *text);
/// Number of variables currently stored in the recording.
size_t num_var_rec(void) const
{ return num_var_rec_; }
/// Number of LdpOp and LdvOp operations currently in the recording.
size_t num_load_op_rec(void) const
{ return num_load_op_rec_; }
/// Number of operators currently stored in the recording.
size_t num_op_rec(void) const
{ return op_rec_.size(); }
/// Approximate amount of memory used by the recording
size_t Memory(void) const
{ return op_rec_.capacity() * sizeof(CPPAD_OP_CODE_TYPE)
+ vecad_ind_rec_.capacity() * sizeof(size_t)
+ op_arg_rec_.capacity() * sizeof(addr_t)
+ par_rec_.capacity() * sizeof(Base)
+ text_rec_.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
and after each call to Erase.
*/
template <class Base>
inline addr_t recorder<Base>::PutOp(OpCode op)
{ size_t i = op_rec_.extend(1);
CPPAD_ASSERT_KNOWN(
(abort_op_index_ == 0) || (abort_op_index_ != i),
"Operator index equals abort_op_index in Independent"
);
op_rec_[i] = static_cast<CPPAD_OP_CODE_TYPE>(op);
CPPAD_ASSERT_UNKNOWN( op_rec_.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
and after each call to Erase.
\par num_load_op_rec()
The return value for <code>num_load_op_rec()</code>
increases by one after each call to this function
(and starts at zero after the default constructor or Erase).
*/
template <class Base>
inline addr_t recorder<Base>::PutLoadOp(OpCode op)
{ size_t i = op_rec_.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_rec_[i] = static_cast<CPPAD_OP_CODE_TYPE>(op);
CPPAD_ASSERT_UNKNOWN( op_rec_.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_load_op_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 );
}
/*!
Add a value to the end of the current vector of VecAD indices.
For each VecAD vector, this routine is used to store the length
of the vector followed by the parameter index corresponding to each
value in the vector.
This value for the elements of the VecAD vector corresponds to the
beginning of the operation sequence.
\param vec_ind
is the index to be palced at the end of the vector of VecAD indices.
\return
is the index in the vector of VecAD indices corresponding to this value.
This index starts at zero after the recorder default constructor
and after each call to Erase.
It increments by one for each call to PutVecInd..
*/
template <class Base>
inline addr_t recorder<Base>::PutVecInd(size_t vec_ind)
{ size_t i = vecad_ind_rec_.extend(1);
CPPAD_ASSERT_UNKNOWN( std::numeric_limits<addr_t>::max() >= vec_ind );
vecad_ind_rec_[i] = addr_t( vec_ind );
CPPAD_ASSERT_UNKNOWN( vecad_ind_rec_.size() == i + 1 );
CPPAD_ASSERT_KNOWN(
std::numeric_limits<addr_t>::max() >= i,
"cppad_tape_addr_type maximum value has been exceeded"
);
return static_cast<addr_t>( i );
}
/*!
Find or add a parameter to the current vector of 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>::PutPar(const Base &par)
{ static size_t hash_table[CPPAD_HASH_TABLE_SIZE * CPPAD_MAX_NUM_THREADS];
size_t i;
size_t code;
CPPAD_ASSERT_UNKNOWN(
thread_offset_ / CPPAD_HASH_TABLE_SIZE
==
thread_alloc::thread_num()
);
// get hash code for this value
code = static_cast<size_t>( hash_code(par) );
CPPAD_ASSERT_UNKNOWN( code < CPPAD_HASH_TABLE_SIZE );
// If we have a match, return the parameter index
i = hash_table[code + thread_offset_];
if( i < par_rec_.size() && IdenticalEqualPar(par_rec_[i], par) )
{ CPPAD_ASSERT_KNOWN(
static_cast<size_t>( std::numeric_limits<addr_t>::max() ) >= i,
"cppad_tape_addr_type maximum value has been exceeded"
)
return static_cast<addr_t>( i );
}
// place a new value in the table
i = par_rec_.extend(1);
par_rec_[i] = par;
CPPAD_ASSERT_UNKNOWN( par_rec_.size() == i + 1 );
// make the hash code point to this new value
hash_table[code + thread_offset_] = i;
// return the parameter index
CPPAD_ASSERT_KNOWN(
static_cast<size_t>( std::numeric_limits<addr_t>::max() ) >= i,
"cppad_tape_addr_type maximum value has been exceeded"
)
return static_cast<addr_t>( i );
}
// -------------------------- 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.
\a arg0 comes before \a 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 and each call to Erase.
It increases by the number of indices placed by each call to PutArg.
*/
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>
inline void recorder<Base>::PutArg(addr_t arg0)
{
size_t i = op_arg_rec_.extend(1);
op_arg_rec_[i] = static_cast<addr_t>( arg0 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
{
size_t i = op_arg_rec_.extend(2);
op_arg_rec_[i++] = static_cast<addr_t>( arg0 );
op_arg_rec_[i] = static_cast<addr_t>( arg1 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
{
size_t i = op_arg_rec_.extend(3);
op_arg_rec_[i++] = static_cast<addr_t>( arg0 );
op_arg_rec_[i++] = static_cast<addr_t>( arg1 );
op_arg_rec_[i] = static_cast<addr_t>( arg2 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
addr_t arg3)
{
size_t i = op_arg_rec_.extend(4);
op_arg_rec_[i++] = static_cast<addr_t>( arg0 );
op_arg_rec_[i++] = static_cast<addr_t>( arg1 );
op_arg_rec_[i++] = static_cast<addr_t>( arg2 );
op_arg_rec_[i] = static_cast<addr_t>( arg3 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
addr_t arg3, addr_t arg4)
{
size_t i = op_arg_rec_.extend(5);
op_arg_rec_[i++] = static_cast<addr_t>( arg0 );
op_arg_rec_[i++] = static_cast<addr_t>( arg1 );
op_arg_rec_[i++] = static_cast<addr_t>( arg2 );
op_arg_rec_[i++] = static_cast<addr_t>( arg3 );
op_arg_rec_[i] = static_cast<addr_t>( arg4 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline 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 = op_arg_rec_.extend(6);
op_arg_rec_[i++] = static_cast<addr_t>( arg0 );
op_arg_rec_[i++] = static_cast<addr_t>( arg1 );
op_arg_rec_[i++] = static_cast<addr_t>( arg2 );
op_arg_rec_[i++] = static_cast<addr_t>( arg3 );
op_arg_rec_[i++] = static_cast<addr_t>( arg4 );
op_arg_rec_[i] = static_cast<addr_t>( arg5 );
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline size_t recorder<Base>::ReserveArg(size_t n_arg)
{
size_t i = op_arg_rec_.extend(n_arg);
CPPAD_ASSERT_UNKNOWN( op_arg_rec_.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>
inline void recorder<Base>::ReplaceArg(size_t i_arg, size_t value)
{ op_arg_rec_[i_arg] = static_cast<addr_t>( 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>
inline 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_rec_.extend(n);
size_t j;
for(j = 0; j < n; j++)
text_rec_[i + j] = text[j];
CPPAD_ASSERT_UNKNOWN( text_rec_.size() == i + n );
CPPAD_ASSERT_KNOWN(
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
# endif
+783
View File
@@ -0,0 +1,783 @@
# ifndef CPPAD_LOCAL_REV_HES_SWEEP_HPP
# define CPPAD_LOCAL_REV_HES_SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file rev_hes_sweep.hpp
Compute Reverse mode Hessian sparsity patterns.
*/
/*!
\def CPPAD_REV_HES_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every rev_hes_sweep computation is printed.
*/
# define CPPAD_REV_HES_SWEEP_TRACE 0
/*!
Given the forward Jacobian sparsity pattern for all the variables,
and the reverse Jacobian sparsity pattern for the dependent variables,
RevHesSweep computes the Hessian sparsity pattern for all the independent
variables.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape; i.e.,
\a play->num_var_rec().
This is also the number of rows in the entire sparsity pattern
\a rev_hes_sparse.
\param play
The information stored in \a play
is a recording of the operations corresponding to a function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables
and \f$ m \f$ is the number of dependent variables.
The object \a play is effectly constant.
It is not declared const because while playing back the tape
the object \a play holds information about the current location
with in the tape and this changes during playback.
\param for_jac_sparse
For i = 0 , ... , \a numvar - 1,
(for all the variables on the tape),
the forward Jacobian sparsity pattern for the variable with index i
corresponds to the set with index i in \a for_jac_sparse.
\param RevJac
\b Input:
For i = 0, ... , \a numvar - 1
the if the variable with index i on the tape is an dependent variable and
included in the Hessian, \a RevJac[ i ] is equal to true,
otherwise it is equal to false.
\n
\n
\b Output: The values in \a RevJac upon return are not specified; i.e.,
it is used for temporary work space.
\param rev_hes_sparse
The reverse Hessian sparsity pattern for the variable with index i
corresponds to the set with index i in \a rev_hes_sparse.
\n
\n
\b Input: For i = 0 , ... , \a numvar - 1
the reverse Hessian sparsity pattern for the variable with index i is empty.
\n
\n
\b Output: For j = 1 , ... , \a n,
the reverse Hessian sparsity pattern for the independent dependent variable
with index (j-1) is given by the set with index j
in \a rev_hes_sparse.
The values in the rest of \a rev_hes_sparse are not specified; i.e.,
they are used for temporary work space.
*/
template <class Base, class Vector_set>
void RevHesSweep(
size_t n,
size_t numvar,
local::player<Base>* play,
const Vector_set& for_jac_sparse,
bool* RevJac,
Vector_set& rev_hes_sparse
)
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
size_t i, j, k;
// check numvar argument
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.n_set() == numvar );
CPPAD_ASSERT_UNKNOWN( rev_hes_sparse.n_set() == numvar );
CPPAD_ASSERT_UNKNOWN( numvar > 0 );
// upper limit exclusive for set elements
size_t limit = rev_hes_sparse.end();
CPPAD_ASSERT_UNKNOWN( for_jac_sparse.end() == limit );
// check number of sets match
CPPAD_ASSERT_UNKNOWN(
for_jac_sparse.n_set() == rev_hes_sparse.n_set()
);
// vecad_sparsity contains a sparsity pattern for each VecAD object.
// vecad_ind maps a VecAD index (beginning of the VecAD object)
// to the index for the corresponding set in vecad_sparsity.
size_t num_vecad_ind = play->num_vec_ind_rec();
size_t num_vecad_vec = play->num_vecad_vec_rec();
Vector_set vecad_sparse;
vecad_sparse.resize(num_vecad_vec, limit);
pod_vector<size_t> vecad_ind;
pod_vector<bool> vecad_jac;
if( num_vecad_vec > 0 )
{ size_t length;
vecad_ind.extend(num_vecad_ind);
vecad_jac.extend(num_vecad_vec);
j = 0;
for(i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
length = play->GetVecInd(j);
// set vecad_ind to proper index for this VecAD
vecad_ind[j] = i;
// make all other values for this vector invalid
for(k = 1; k <= length; k++)
vecad_ind[j+k] = num_vecad_vec;
// start of next VecAD
j += length + 1;
// initialize this vector's reverse jacobian value
vecad_jac[i] = false;
}
CPPAD_ASSERT_UNKNOWN( j == play->num_vec_ind_rec() );
}
// ----------------------------------------------------------------------
// user's atomic op calculator
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
//
// work space used by UserOp.
vector<Base> user_x; // parameters in x as integers
vector<size_t> user_ix; // variable indices for argument vector
vector<size_t> user_iy; // variable indices for result vector
//
// information set by forward_user (initialization to avoid warnings)
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
// information set by forward_user (necessary initialization)
enum_user_state user_state = end_user; // proper initialization
// ----------------------------------------------------------------------
//
// pointer to the beginning of the parameter vector
// (used by atomic functions
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
//
// Initialize
play->reverse_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == EndOp );
# if CPPAD_REV_HES_SWEEP_TRACE
std::cout << std::endl;
CppAD::vectorBool zf_value(limit);
CppAD::vectorBool zh_value(limit);
# endif
bool more_operators = true;
while(more_operators)
{ bool flag; // temporary for use in switch cases
//
// next op
play->reverse_next(op, arg, i_op, i_var);
# ifndef NDEBUG
if( i_op <= n )
{ CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
}
else CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
# endif
// rest of information depends on the case
switch( op )
{
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AddvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_addsub_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
more_operators = false;
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_csum(op, arg, i_op, i_var);
reverse_sparse_hessian_csum_op(
i_var, arg, RevJac, rev_hes_sparse
);
break;
// -------------------------------------------------
case CExpOp:
reverse_sparse_hessian_cond_op(
i_var, arg, num_par, RevJac, rev_hes_sparse
);
break;
// ---------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DisOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
// derivativve is identically zero
break;
// -------------------------------------------------
case DivvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_div_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ErfOp:
// arg[1] is always the parameter 0
// arg[2] is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ExpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1)
// Z is already defined
break;
// -------------------------------------------------
case LdpOp:
reverse_sparse_hessian_load_op(
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case LdvOp:
reverse_sparse_hessian_load_op(
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
break;
// -------------------------------------------------
case LogOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
# endif
// -------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case MulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_mul_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PowvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3)
reverse_sparse_hessian_pow_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
break;
// -------------------------------------------------
case SignOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
// Derivative is identiaclly zero
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SqrtOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case StppOp:
// sparsity cannot propagate through a parameter
CPPAD_ASSERT_NARG_NRES(op, 3, 0)
break;
// -------------------------------------------------
case StpvOp:
reverse_sparse_hessian_store_op(
op,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case StvpOp:
// sparsity cannot propagate through a parameter
CPPAD_ASSERT_NARG_NRES(op, 3, 0)
break;
// -------------------------------------------------
case StvvOp:
reverse_sparse_hessian_store_op(
op,
arg,
num_vecad_ind,
vecad_ind.data(),
rev_hes_sparse,
vecad_sparse,
RevJac,
vecad_jac.data()
);
break;
// -------------------------------------------------
case SubvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_addsub_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2)
reverse_sparse_hessian_nonlinear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case UserOp:
CPPAD_ASSERT_UNKNOWN(
user_state == start_user || user_state == end_user
);
flag = user_state == end_user;
user_atom = play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ user_x.resize(user_n);
user_ix.resize(user_n);
user_iy.resize(user_m);
}
else
{ // call users function for this operation
user_atom->set_old(user_old);
user_atom->rev_sparse_hes(
user_x, user_ix, user_iy,
for_jac_sparse, RevJac, rev_hes_sparse
);
}
break;
case UsrapOp:
// parameter argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument parameter value
user_x[user_j] = parameter[arg[0]];
// special variable index used for parameters
user_ix[user_j] = 0;
break;
case UsravOp:
// variable argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument variables not available during sparsity calculations
user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
// variable index for this argument
user_ix[user_j] = arg[0];
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// special variable index used for parameters
user_iy[user_i] = 0;
break;
case UsrrvOp:
// variable result in an atomic operation sequence
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// variable index for this result
user_iy[user_i] = i_var;
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[1], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_linear_unary_op(
i_var, arg[0], RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
case ZmulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1)
reverse_sparse_hessian_mul_op(
i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse
);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_REV_HES_SWEEP_TRACE
for(j = 0; j < limit; j++)
{ zf_value[j] = false;
zh_value[j] = false;
}
typename Vector_set::const_iterator itr_jac(for_jac_sparse, i_var);
j = *itr_jac;
while( j < limit )
{ zf_value[j] = true;
j = *(++itr_jac);
}
typename Vector_set::const_iterator itr_hes(rev_hes_sparse, i_var);
j = *itr_hes;
while( j < limit )
{ zh_value[j] = true;
j = *(++itr_hes);
}
printOp(
std::cout,
play,
i_op,
i_var,
op,
arg
);
// should also print RevJac[i_var], but printOpResult does not
// yet allow for this
if( NumRes(op) > 0 && op != BeginOp ) printOpResult(
std::cout,
1,
&zf_value,
1,
&zh_value
);
std::cout << std::endl;
}
std::cout << std::endl;
# else
}
# endif
// values corresponding to BeginOp
CPPAD_ASSERT_UNKNOWN( i_op == 0 );
CPPAD_ASSERT_UNKNOWN( i_var == 0 );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_REV_HES_SWEEP_TRACE
# endif
+758
View File
@@ -0,0 +1,758 @@
# ifndef CPPAD_LOCAL_REV_JAC_SWEEP_HPP
# define CPPAD_LOCAL_REV_JAC_SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file rev_jac_sweep.hpp
Compute Reverse mode Jacobian sparsity patterns.
*/
/*!
\def CPPAD_REV_JAC_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every rev_jac_sweep computation is printed.
*/
# define CPPAD_REV_JAC_SWEEP_TRACE 0
/*!
Given the sparsity pattern for the dependent variables,
RevJacSweep computes the sparsity pattern for all the independent variables.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\tparam Vector_set
is the type used for vectors of sets. It can be either
sparse_pack or sparse_list.
\param dependency
Are the derivatives with respect to left and right of the expression below
considered to be non-zero:
\code
CondExpRel(left, right, if_true, if_false)
\endcode
This is used by the optimizer to obtain the correct dependency relations.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape; i.e.,
\a play->num_var_rec().
This is also the number of rows in the entire sparsity pattern \a RevJac.
\param play
The information stored in \a play
is a recording of the operations corresponding to a function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables
and \f$ m \f$ is the number of dependent variables.
The object \a play is effectly constant.
It is not declared const because while playing back the tape
the object \a play holds information about the current location
with in the tape and this changes during playback.
\param var_sparsity
For i = 0 , ... , \a numvar - 1,
(all the variables on the tape)
the forward Jacobian sparsity pattern for variable i
corresponds to the set with index i in \a var_sparsity.
\b
\b
\b Input:
For i = 0 , ... , \a numvar - 1,
the forward Jacobian sparsity pattern for variable i is an input
if i corresponds to a dependent variable.
Otherwise the sparsity patten is empty.
\n
\n
\b Output: For j = 1 , ... , \a n,
the sparsity pattern for the dependent variable with index (j-1)
is given by the set with index index j in \a var_sparsity.
*/
template <class Base, class Vector_set>
void RevJacSweep(
bool dependency,
size_t n,
size_t numvar,
local::player<Base>* play,
Vector_set& var_sparsity
)
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
size_t i, j, k;
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
// check numvar argument
CPPAD_ASSERT_UNKNOWN( numvar > 0 );
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( var_sparsity.n_set() == numvar );
// upper limit (exclusive) for elements in the set
size_t limit = var_sparsity.end();
// vecad_sparsity contains a sparsity pattern for each VecAD object.
// vecad_ind maps a VecAD index (beginning of the VecAD object)
// to the index of the corresponding set in vecad_sparsity.
size_t num_vecad_ind = play->num_vec_ind_rec();
size_t num_vecad_vec = play->num_vecad_vec_rec();
Vector_set vecad_sparsity;
vecad_sparsity.resize(num_vecad_vec, limit);
pod_vector<size_t> vecad_ind;
if( num_vecad_vec > 0 )
{ size_t length;
vecad_ind.extend(num_vecad_ind);
j = 0;
for(i = 0; i < num_vecad_vec; i++)
{ // length of this VecAD
length = play->GetVecInd(j);
// set to proper index for this VecAD
vecad_ind[j] = i;
for(k = 1; k <= length; k++)
vecad_ind[j+k] = num_vecad_vec; // invalid index
// start of next VecAD
j += length + 1;
}
CPPAD_ASSERT_UNKNOWN( j == play->num_vec_ind_rec() );
}
// ----------------------------------------------------------------------
// user's atomic op calculator
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
//
// work space used by UserOp.
vector<Base> user_x; // parameters in x as integers
vector<size_t> user_ix; // variable indices for argument vector
vector<size_t> user_iy; // variable indices for result vector
//
// information set by forward_user (initialization to avoid warnings)
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
// information set by forward_user (necessary initialization)
enum_user_state user_state = end_user; // proper initialization
// ----------------------------------------------------------------------
//
// pointer to the beginning of the parameter vector
// (used by atomic functions
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
//
// Initialize
play->reverse_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == EndOp );
# if CPPAD_REV_JAC_SWEEP_TRACE
std::cout << std::endl;
CppAD::vectorBool z_value(limit);
# endif
bool more_operators = true;
while(more_operators)
{ bool flag; // temporary for use in switch cases
//
// next op
play->reverse_next(op, arg, i_op, i_var);
# ifndef NDEBUG
if( i_op <= n )
{ CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp));
}
else CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp));
# endif
// rest of information depends on the case
switch( op )
{
case AbsOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case AddvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
more_operators = false;
break;
// -------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_cskip(op, arg, i_op, i_var);
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
play->reverse_csum(op, arg, i_op, i_var);
reverse_sparse_jacobian_csum_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case CExpOp:
reverse_sparse_jacobian_cond_op(
dependency, i_var, arg, num_par, var_sparsity
);
break;
// ---------------------------------------------------
case CosOp:
// sin(x), cos(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// ---------------------------------------------------
case CoshOp:
// sinh(x), cosh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case DisOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
// derivative is identically zero but dependency is not
if( dependency ) reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case DivvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case ErfOp:
// arg[1] is always the parameter 0
// arg[0] is always the parameter 2 / sqrt(pi)
CPPAD_ASSERT_NARG_NRES(op, 3, 5);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case ExpOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case InvOp:
CPPAD_ASSERT_NARG_NRES(op, 0, 1);
break;
// -------------------------------------------------
case LdpOp:
reverse_sparse_jacobian_load_op(
dependency,
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case LdvOp:
reverse_sparse_jacobian_load_op(
dependency,
op,
i_var,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 0);
break;
// -------------------------------------------------
case LogOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
# endif
// -------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case MulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case ParOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
break;
// -------------------------------------------------
case PowvpOp:
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case PowvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 3);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case PriOp:
CPPAD_ASSERT_NARG_NRES(op, 5, 0);
break;
// -------------------------------------------------
case SignOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
// derivative is identically zero but dependency is not
if( dependency ) reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case SinOp:
// cos(x), sin(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case SinhOp:
// cosh(x), sinh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case SqrtOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case StppOp:
// does not affect sparsity or dependency when both are parameters
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
break;
// -------------------------------------------------
case StpvOp:
reverse_sparse_jacobian_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case StvpOp:
CPPAD_ASSERT_NARG_NRES(op, 3, 0);
// storing a parameter only affects dependency
reverse_sparse_jacobian_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case StvvOp:
reverse_sparse_jacobian_store_op(
dependency,
op,
arg,
num_vecad_ind,
vecad_ind.data(),
var_sparsity,
vecad_sparsity
);
break;
// -------------------------------------------------
case SubvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case TanOp:
// tan(x)^2, tan(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case TanhOp:
// tanh(x)^2, tanh(x)
CPPAD_ASSERT_NARG_NRES(op, 1, 2);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case UserOp:
CPPAD_ASSERT_UNKNOWN(
user_state == start_user || user_state == end_user
);
flag = user_state == end_user;
user_atom = play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ // start of user atomic operation sequence
user_x.resize( user_n );
user_ix.resize( user_n );
user_iy.resize( user_m );
}
else
{ // end of users atomic operation sequence
user_atom->set_old(user_old);
user_atom->rev_sparse_jac(
user_x, user_ix, user_iy, var_sparsity
);
}
break;
case UsrapOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument parameter value
user_x[user_j] = parameter[arg[0]];
// special variable index used for parameters
user_ix[user_j] = 0;
//
break;
case UsravOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// argument variables not available during sparsity calculations
user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN();
// variable index for this argument
user_ix[user_j] = arg[0];
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// special variable index used for parameters
user_iy[user_i] = 0;
break;
case UsrrvOp:
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
// variable index for this result
user_iy[user_i] = i_var;
break;
// -------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[1], var_sparsity
);
break;
// -------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_unary_op(
i_var, arg[0], var_sparsity
);
break;
// -------------------------------------------------
case ZmulvvOp:
CPPAD_ASSERT_NARG_NRES(op, 2, 1);
reverse_sparse_jacobian_binary_op(
i_var, arg, var_sparsity
);
break;
// -------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(0);
}
# if CPPAD_REV_JAC_SWEEP_TRACE
for(j = 0; j < limit; j++)
z_value[j] = false;
typename Vector_set::const_iterator itr(var_sparsity, i_var);
j = *itr;
while( j < limit )
{ z_value[j] = true;
j = *(++itr);
}
printOp(
std::cout,
play,
i_op,
i_var,
op,
arg
);
// Note that sparsity for UsrrvOp are computed before call to
// atomic function so no need to delay printing (as in forward mode)
if( NumRes(op) > 0 && op != BeginOp ) printOpResult(
std::cout,
0,
(CppAD::vectorBool *) CPPAD_NULL,
1,
&z_value
);
std::cout << std::endl;
}
std::cout << std::endl;
# else
}
# endif
// values corresponding to BeginOp
CPPAD_ASSERT_UNKNOWN( i_op == 0 );
CPPAD_ASSERT_UNKNOWN( i_var == 0 );
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_REV_JAC_SWEEP_TRACE
# undef CPPAD_ATOMIC_CALL
# endif
+824
View File
@@ -0,0 +1,824 @@
// $Id: reverse_sweep.hpp 3853 2016-12-14 14:40:11Z bradbell $
# ifndef CPPAD_LOCAL_REVERSE_SWEEP_HPP
# define CPPAD_LOCAL_REVERSE_SWEEP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file reverse_sweep.hpp
Compute derivatives of arbitrary order Taylor coefficients.
*/
/*
\def CPPAD_ATOMIC_CALL
This avoids warnings when NDEBUG is defined and user_ok is not used.
If \c NDEBUG is defined, this resolves to
\code
user_atom->reverse
\endcode
otherwise, it respolves to
\code
user_ok = user_atom->reverse
\endcode
This maco is undefined at the end of this file to facillitate is
use with a different definition in other files.
*/
# ifdef NDEBUG
# define CPPAD_ATOMIC_CALL user_atom->reverse
# else
# define CPPAD_ATOMIC_CALL user_ok = user_atom->reverse
# endif
/*!
\def CPPAD_REVERSE_SWEEP_TRACE
This value is either zero or one.
Zero is the normal operational value.
If it is one, a trace of every reverse_sweep computation is printed.
*/
# define CPPAD_REVERSE_SWEEP_TRACE 0
/*!
Compute derivative of arbitrary order forward mode Taylor coefficients.
\tparam Base
base type for the operator; i.e., this operation sequence was recorded
using AD< \a Base > and computations by this routine are done using type
\a Base.
\param d
is the highest order Taylor coefficients that
we are computing the derivative of.
\param n
is the number of independent variables on the tape.
\param numvar
is the total number of variables on the tape.
This is also equal to the number of rows in the matrix \a Taylor; i.e.,
play->num_var_rec().
\param play
The information stored in \a play
is a recording of the operations corresponding to the function
\f[
F : {\bf R}^n \rightarrow {\bf R}^m
\f]
where \f$ n \f$ is the number of independent variables and
\f$ m \f$ is the number of dependent variables.
We define \f$ u^{(k)} \f$ as the value of <code>x_k</code> in the previous call
of the form
<code>
f.Forward(k, x_k)
</code>
We define
\f$ X : {\bf R}^{n \times d} \rightarrow {\bf R}^n \f$ by
\f[
X(t, u) = u^{(0)} + u^{(1)} t + \cdots + u^{(d)} t^d
\f]
We define
\f$ Y : {\bf R}^{n \times d} \rightarrow {\bf R}^m \f$ by
\f[
Y(t, u) = F[ X(t, u) ]
\f]
We define the function
\f$ W : {\bf R}^{n \times d} \rightarrow {\bf R} \f$ by
\f[
W(u)
=
\sum_{k=0}^{d} ( w^{(k)} )^{\rm T}
\frac{1}{k !} \frac{\partial^k}{\partial t^k} Y(0, u)
\f]
(The matrix \f$ w \in {\bf R}^m \f$,
is defined below under the heading Partial.)
Note that the scale factor 1 / k converts
the k-th partial derivative to the k-th order Taylor coefficient.
This routine computes the derivative of \f$ W(u) \f$
with respect to all the Taylor coefficients
\f$ u^{(k)} \f$ for \f$ k = 0 , ... , d \f$.
\n
\n
The object \a play is effectly constant.
There is an exception to this,
while palying back the tape
the object \a play holds information about the current location
with in the tape and this changes during palyback.
\param J
Is the number of columns in the coefficient matrix \a Taylor.
This must be greater than or equal \a d + 1.
\param Taylor
For i = 1 , ... , \a numvar, and for k = 0 , ... , \a d,
\a Taylor [ i * J + k ]
is the k-th order Taylor coefficient corresponding to
variable with index i on the tape.
The value \f$ u \in {\bf R}^{n \times d} \f$,
at which the derivative is computed,
is defined by
\f$ u_j^{(k)} \f$ = \a Taylor [ j * J + k ]
for j = 1 , ... , \a n, and for k = 0 , ... , \a d.
\param K
Is the number of columns in the partial derivative matrix \a Partial.
It must be greater than or equal \a d + 1.
\param Partial
\b Input:
The last \f$ m \f$ rows of \a Partial are inputs.
The matrix \f$ w \f$, used to define \f$ W(u) \f$,
is specified by these rows.
For i = 0 , ... , m - 1,
for k = 0 , ... , d,
<code>Partial [ (numvar - m + i ) * K + k ] = w[i,k]</code>.
\n
\n
\b Temporary:
For i = n+1 , ... , \a numvar - 1 and for k = 0 , ... , d,
the value of \a Partial [ i * K + k ] is used for temporary work space
and its output value is not defined.
\n
\n
\b Output:
For j = 1 , ... , n and for k = 0 , ... , d,
\a Partial [ j * K + k ]
is the partial derivative of \f$ W( u ) \f$ with
respect to \f$ u_j^{(k)} \f$.
\param cskip_op
Is a vector with size play->num_op_rec().
If cskip_op[i] is true, the operator index i in the recording
does not affect any of the dependent variable (given the value
of the independent variables).
Note that all the operators in an atomic function call are skipped as a block,
so only the last UserOp fore each call needs to have cskip_op[i] true.
\param var_by_load_op
is a vector with size play->num_load_op_rec().
Is 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 Assumptions
The first operator on the tape is a BeginOp,
and the next \a n operators are InvOp operations for the
corresponding independent variables.
*/
template <class Base>
void ReverseSweep(
size_t d,
size_t n,
size_t numvar,
local::player<Base>* play,
size_t J,
const Base* Taylor,
size_t K,
Base* Partial,
bool* cskip_op,
const pod_vector<addr_t>& var_by_load_op
)
{
OpCode op;
size_t i_op;
size_t i_var;
const addr_t* arg = CPPAD_NULL;
// check numvar argument
CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar );
CPPAD_ASSERT_UNKNOWN( numvar > 0 );
// length of the parameter vector (used by CppAD assert macros)
const size_t num_par = play->num_par_rec();
// pointer to the beginning of the parameter vector
const Base* parameter = CPPAD_NULL;
if( num_par > 0 )
parameter = play->GetPar();
// work space used by UserOp.
const size_t user_k = d; // highest order we are differentiating
const size_t user_k1 = d+1; // number of orders for this calculation
vector<size_t> user_ix; // variable indices for argument vector
vector<Base> user_tx; // argument vector Taylor coefficients
vector<Base> user_ty; // result vector Taylor coefficients
vector<Base> user_px; // partials w.r.t argument vector
vector<Base> user_py; // partials w.r.t. result vector
//
atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator
# ifndef NDEBUG
bool user_ok = false; // atomic op return value
# endif
//
// information defined by forward_user
size_t user_old=0, user_m=0, user_n=0, user_i=0, user_j=0;
enum_user_state user_state = end_user; // proper initialization
// temporary indices
size_t j, ell;
// Initialize
play->reverse_start(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( op == EndOp );
# if CPPAD_REVERSE_SWEEP_TRACE
std::cout << std::endl;
# endif
bool more_operators = true;
while(more_operators)
{ bool flag; // temporary for use in switch cases
//
// next op
play->reverse_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN((i_op > n) | (op == InvOp) | (op == BeginOp));
CPPAD_ASSERT_UNKNOWN((i_op <= n) | (op != InvOp) | (op != BeginOp));
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
// check if we are skipping this operation
while( cskip_op[i_op] )
{ switch(op)
{ case CSumOp:
// CSumOp has a variable number of arguments
play->reverse_csum(op, arg, i_op, i_var);
break;
case CSkipOp:
// CSkip has a variable number of arguments
play->reverse_cskip(op, arg, i_op, i_var);
break;
case UserOp:
{ // skip all operations in this user atomic call
CPPAD_ASSERT_UNKNOWN( user_state == end_user );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
size_t n_skip = user_m + user_n + 1;
for(size_t i = 0; i < n_skip; i++)
{ play->reverse_next(op, arg, i_op, i_var);
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
}
CPPAD_ASSERT_UNKNOWN( user_state == end_user );
}
break;
default:
break;
}
play->reverse_next(op, arg, i_op, i_var);
CPPAD_ASSERT_UNKNOWN( i_op < play->num_op_rec() );
}
// rest of informaiton depends on the case
# if CPPAD_REVERSE_SWEEP_TRACE
if( op == CSumOp )
{ // CSumOp has a variable number of arguments
play->reverse_csum(op, arg, i_op, i_var);
}
if( op == CSkipOp )
{ // CSkip has a variable number of arguments
play->reverse_cskip(op, arg, i_op, i_var);
}
size_t i_tmp = i_var;
const Base* Z_tmp = Taylor + i_var * J;
const Base* pZ_tmp = Partial + i_var * K;
printOp(
std::cout,
play,
i_op,
i_tmp,
op,
arg
);
if( NumRes(op) > 0 && op != BeginOp ) printOpResult(
std::cout,
d + 1,
Z_tmp,
d + 1,
pZ_tmp
);
std::cout << std::endl;
# endif
switch( op )
{
case AbsOp:
reverse_abs_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case AcosOp:
// sqrt(1 - x * x), acos(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_acos_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AcoshOp:
// sqrt(x * x - 1), acosh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_acosh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
# endif
// --------------------------------------------------
case AddvvOp:
reverse_addvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case AddpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_addpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case AsinOp:
// sqrt(1 - x * x), asin(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_asin_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AsinhOp:
// sqrt(1 + x * x), asinh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_asinh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
# endif
// --------------------------------------------------
case AtanOp:
// 1 + x * x, atan(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_atan_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// -------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case AtanhOp:
// 1 - x * x, atanh(x)
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_atanh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
# endif
// -------------------------------------------------
case BeginOp:
CPPAD_ASSERT_NARG_NRES(op, 1, 1);
more_operators = false;
break;
// --------------------------------------------------
case CSkipOp:
// CSkipOp has a variable number of arguments and
// forward_next thinks it one has one argument.
// we must inform reverse_next of this special case.
# if ! CPPAD_REVERSE_SWEEP_TRACE
play->reverse_cskip(op, arg, i_op, i_var);
# endif
break;
// -------------------------------------------------
case CSumOp:
// CSumOp has a variable number of arguments and
// reverse_next thinks it one has one argument.
// We must inform reverse_next of this special case.
# if ! CPPAD_REVERSE_SWEEP_TRACE
play->reverse_csum(op, arg, i_op, i_var);
# endif
reverse_csum_op(
d, i_var, arg, K, Partial
);
// end of a cummulative summation
break;
// -------------------------------------------------
case CExpOp:
reverse_cond_op(
d,
i_var,
arg,
num_par,
parameter,
J,
Taylor,
K,
Partial
);
break;
// --------------------------------------------------
case CosOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_cos_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case CoshOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_cosh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case DisOp:
// Derivative of discrete operation is zero so no
// contribution passes through this operation.
break;
// --------------------------------------------------
case DivvvOp:
reverse_divvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case DivpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_divpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case DivvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
reverse_divvp_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case ErfOp:
reverse_erf_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
# endif
// --------------------------------------------------
case ExpOp:
reverse_exp_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Expm1Op:
reverse_expm1_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
# endif
// --------------------------------------------------
case InvOp:
break;
// --------------------------------------------------
case LdpOp:
reverse_load_op(
op, d, i_var, arg, J, Taylor, K, Partial, var_by_load_op.data()
);
break;
// -------------------------------------------------
case LdvOp:
reverse_load_op(
op, d, i_var, arg, J, Taylor, K, Partial, var_by_load_op.data()
);
break;
// --------------------------------------------------
case EqpvOp:
case EqvvOp:
case LtpvOp:
case LtvpOp:
case LtvvOp:
case LepvOp:
case LevpOp:
case LevvOp:
case NepvOp:
case NevvOp:
break;
// -------------------------------------------------
case LogOp:
reverse_log_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
# if CPPAD_USE_CPLUSPLUS_2011
case Log1pOp:
reverse_log1p_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
# endif
// --------------------------------------------------
case MulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_mulpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case MulvvOp:
reverse_mulvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case ParOp:
break;
// --------------------------------------------------
case PowvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
reverse_powvp_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case PowpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_powpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case PowvvOp:
reverse_powvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case PriOp:
// no result so nothing to do
break;
// --------------------------------------------------
case SignOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_sign_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case SinOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_sin_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case SinhOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_sinh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case SqrtOp:
reverse_sqrt_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case StppOp:
break;
// --------------------------------------------------
case StpvOp:
break;
// -------------------------------------------------
case StvpOp:
break;
// -------------------------------------------------
case StvvOp:
break;
// --------------------------------------------------
case SubvvOp:
reverse_subvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case SubpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_subpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case SubvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
reverse_subvp_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case TanOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_tan_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// -------------------------------------------------
case TanhOp:
CPPAD_ASSERT_UNKNOWN( i_var < numvar );
reverse_tanh_op(
d, i_var, arg[0], J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case UserOp:
// start or end an atomic operation sequence
flag = user_state == end_user;
user_atom = play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
if( flag )
{ user_ix.resize(user_n);
if(user_tx.size() != user_n * user_k1)
{ user_tx.resize(user_n * user_k1);
user_px.resize(user_n * user_k1);
}
if(user_ty.size() != user_m * user_k1)
{ user_ty.resize(user_m * user_k1);
user_py.resize(user_m * user_k1);
}
}
else
{ // call users function for this operation
user_atom->set_old(user_old);
CPPAD_ATOMIC_CALL(
user_k, user_tx, user_ty, user_px, user_py
);
# ifndef NDEBUG
if( ! user_ok )
{ std::string msg =
user_atom->afun_name()
+ ": atomic_base.reverse: returned false";
CPPAD_ASSERT_KNOWN(false, msg.c_str() );
}
# endif
for(j = 0; j < user_n; j++) if( user_ix[j] > 0 )
{ for(ell = 0; ell < user_k1; ell++)
Partial[user_ix[j] * K + ell] +=
user_px[j * user_k1 + ell];
}
}
break;
case UsrapOp:
// parameter argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
user_ix[user_j] = 0;
user_tx[user_j * user_k1 + 0] = parameter[ arg[0]];
for(ell = 1; ell < user_k1; ell++)
user_tx[user_j * user_k1 + ell] = Base(0.);
break;
case UsravOp:
// variable argument in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
user_ix[user_j] = arg[0];
for(ell = 0; ell < user_k1; ell++)
user_tx[user_j*user_k1 + ell] = Taylor[ arg[0] * J + ell];
break;
case UsrrpOp:
// parameter result in an atomic operation sequence
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
for(ell = 0; ell < user_k1; ell++)
{ user_py[user_i * user_k1 + ell] = Base(0.);
user_ty[user_i * user_k1 + ell] = Base(0.);
}
user_ty[user_i * user_k1 + 0] = parameter[ arg[0] ];
break;
case UsrrvOp:
// variable result in an atomic operation sequence
play->reverse_user(op, user_state,
user_old, user_m, user_n, user_i, user_j
);
for(ell = 0; ell < user_k1; ell++)
{ user_py[user_i * user_k1 + ell] =
Partial[i_var * K + ell];
user_ty[user_i * user_k1 + ell] =
Taylor[i_var * J + ell];
}
break;
// ------------------------------------------------------------
case ZmulpvOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par );
reverse_zmulpv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case ZmulvpOp:
CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
reverse_zmulvp_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
case ZmulvvOp:
reverse_zmulvv_op(
d, i_var, arg, parameter, J, Taylor, K, Partial
);
break;
// --------------------------------------------------
default:
CPPAD_ASSERT_UNKNOWN(false);
}
}
# if CPPAD_REVERSE_SWEEP_TRACE
std::cout << std::endl;
# endif
// values corresponding to BeginOp
CPPAD_ASSERT_UNKNOWN( i_op == 0 );
CPPAD_ASSERT_UNKNOWN( i_var == 0 );
}
} } // END_CPPAD_LOCAL_NAMESPACE
// preprocessor symbols that are local to this file
# undef CPPAD_REVERSE_SWEEP_TRACE
# undef CPPAD_ATOMIC_CALL
# endif
@@ -0,0 +1,67 @@
// $Id$
# ifndef CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP
# define CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# 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 CPPAD_NULL (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) = CPPAD_NULL;
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 == CPPAD_NULL || in_parallel_user() == false);
return false;
}
//
if( in_parallel_user == CPPAD_NULL )
return false;
//
return in_parallel_user();
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+154
View File
@@ -0,0 +1,154 @@
// $Id: sign_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# 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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+240
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+239
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+485
View File
@@ -0,0 +1,485 @@
// $Id: sparse_binary_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_SPARSE_BINARY_OP_HPP
# define CPPAD_LOCAL_SPARSE_BINARY_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_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 or sparse_list.
\param i_z
variable index corresponding to the result for this operation;
i.e., z.
\param arg
\a 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 \a arg[0] in \a 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 \a arg[1] in \a 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 \a i_z in \a sparsity
is the sparsity bit pattern for z.
This identifies which of the independent variables the variable z
depends on.
\par Checked Assertions:
\li \a arg[0] < \a i_z
\li \a arg[1] < \a i_z
*/
template <class Vector_set>
inline void forward_sparse_jacobian_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, arg[0], 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 or sparse_list.
\param i_z
variable index corresponding to the result for this operation;
i.e., z.
\param arg
\a 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 \a i_z in \a sparsity
is the sparsity pattern for z corresponding ot the function G.
\n
\n
The set with index \a arg[0] in \a 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 \a arg[1] in \a 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 \a arg[0] < \a i_z
\li \a arg[1] < \a i_z
*/
template <class Vector_set>
inline void reverse_sparse_jacobian_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(arg[0], arg[0], i_z, sparsity);
sparsity.binary_union(arg[1], 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>
inline void reverse_sparse_hessian_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 );
rev_hes_sparsity.binary_union(arg[0], arg[0], i_z, rev_hes_sparsity);
rev_hes_sparsity.binary_union(arg[1], arg[1], i_z, rev_hes_sparsity);
jac_reverse[arg[0]] |= jac_reverse[i_z];
jac_reverse[arg[1]] |= jac_reverse[i_z];
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>
inline void reverse_sparse_hessian_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 );
rev_hes_sparsity.binary_union(arg[0], arg[0], i_z, rev_hes_sparsity);
rev_hes_sparsity.binary_union(arg[1], arg[1], i_z, rev_hes_sparsity);
if( jac_reverse[i_z] )
{ rev_hes_sparsity.binary_union(
arg[0], arg[0], arg[1], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[1], arg[1], arg[0], for_jac_sparsity);
}
jac_reverse[arg[0]] |= jac_reverse[i_z];
jac_reverse[arg[1]] |= jac_reverse[i_z];
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>
inline void reverse_sparse_hessian_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 );
rev_hes_sparsity.binary_union(arg[0], arg[0], i_z, rev_hes_sparsity);
rev_hes_sparsity.binary_union(arg[1], arg[1], i_z, rev_hes_sparsity);
if( jac_reverse[i_z] )
{ rev_hes_sparsity.binary_union(
arg[0], arg[0], arg[1], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[1], arg[1], arg[0], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[1], arg[1], arg[1], for_jac_sparsity);
}
jac_reverse[arg[0]] |= jac_reverse[i_z];
jac_reverse[arg[1]] |= jac_reverse[i_z];
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>
inline void reverse_sparse_hessian_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 );
rev_hes_sparsity.binary_union(arg[0], arg[0], i_z, rev_hes_sparsity);
rev_hes_sparsity.binary_union(arg[1], arg[1], i_z, rev_hes_sparsity);
if( jac_reverse[i_z] )
{
rev_hes_sparsity.binary_union(
arg[0], arg[0], arg[0], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[0], arg[0], arg[1], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[1], arg[1], arg[0], for_jac_sparsity);
rev_hes_sparsity.binary_union(
arg[1], arg[1], 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]] |= jac_reverse[i_z];
jac_reverse[arg[1]] |= jac_reverse[i_z];
return;
}
// ---------------------------------------------------------------------------
/*!
Forward mode Hessian sparsity pattern for multiplication operator.
The C++ source code corresponding to this operation is
\verbatim
w(x) = v0(x) * v1(x)
\endverbatim
\param arg
is the index of the argument vector for the multiplication operation; i.e.,
arg[0], arg[1] are the left and right operands.
\param for_jac_sparsity
for_jac_sparsity(arg[0]) constains the Jacobian sparsity for v0(x),
for_jac_sparsity(arg[1]) constains the Jacobian sparsity for v1(x).
\param for_hes_sparsity
On input, for_hes_sparsity includes the Hessian sparsity for v0(x)
and v1(x); i.e., the sparsity can be a super set.
Upon return it includes the Hessian sparsity for w(x)
*/
template <class Vector_set>
inline void forward_sparse_hessian_mul_op(
const addr_t* arg ,
const Vector_set& for_jac_sparsity ,
Vector_set& for_hes_sparsity )
{ // --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_jac_sparsity, arg[0]);
// loop over dependent variables with non-zero partial
size_t i_x = *itr_0;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v1)
for_hes_sparsity.binary_union(i_x, i_x, arg[1], for_jac_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_jac_sparsity, arg[1]);
// loop over dependent variables with non-zero partial
i_x = *itr_1;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v0)
for_hes_sparsity.binary_union(i_x, i_x, arg[0], for_jac_sparsity);
i_x = *(++itr_1);
}
return;
}
/*!
Forward mode Hessian sparsity pattern for division operator.
The C++ source code corresponding to this operation is
\verbatim
w(x) = v0(x) / v1(x)
\endverbatim
\param arg
is the index of the argument vector for the division operation; i.e.,
arg[0], arg[1] are the left and right operands.
\param for_jac_sparsity
for_jac_sparsity(arg[0]) constains the Jacobian sparsity for v0(x),
for_jac_sparsity(arg[1]) constains the Jacobian sparsity for v1(x).
\param for_hes_sparsity
On input, for_hes_sparsity includes the Hessian sparsity for v0(x)
and v1(x); i.e., the sparsity can be a super set.
Upon return it includes the Hessian sparsity for w(x)
*/
template <class Vector_set>
inline void forward_sparse_hessian_div_op(
const addr_t* arg ,
const Vector_set& for_jac_sparsity ,
Vector_set& for_hes_sparsity )
{ // --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_jac_sparsity, arg[0]);
// loop over dependent variables with non-zero partial
size_t i_x = *itr_0;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v1)
for_hes_sparsity.binary_union(i_x, i_x, arg[1], for_jac_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_jac_sparsity, arg[1]);
// loop over dependent variables with non-zero partial
i_x = *itr_1;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v0)
for_hes_sparsity.binary_union(i_x, i_x, arg[0], for_jac_sparsity);
// N(i_x) = N(i_x) union L(v1)
for_hes_sparsity.binary_union(i_x, i_x, arg[1], for_jac_sparsity);
i_x = *(++itr_1);
}
return;
}
/*!
Forward mode Hessian sparsity pattern for power operator.
The C++ source code corresponding to this operation is
\verbatim
w(x) = pow( v0(x) , v1(x) )
\endverbatim
\param arg
is the index of the argument vector for the power operation; i.e.,
arg[0], arg[1] are the left and right operands.
\param for_jac_sparsity
for_jac_sparsity(arg[0]) constains the Jacobian sparsity for v0(x),
for_jac_sparsity(arg[1]) constains the Jacobian sparsity for v1(x).
\param for_hes_sparsity
On input, for_hes_sparsity includes the Hessian sparsity for v0(x)
and v1(x); i.e., the sparsity can be a super set.
Upon return it includes the Hessian sparsity for w(x)
*/
template <class Vector_set>
inline void forward_sparse_hessian_pow_op(
const addr_t* arg ,
const Vector_set& for_jac_sparsity ,
Vector_set& for_hes_sparsity )
{ // --------------------------------------------------
// set of independent variables that v0 depends on
typename Vector_set::const_iterator itr_0(for_jac_sparsity, arg[0]);
// loop over dependent variables with non-zero partial
size_t i_x = *itr_0;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v0)
for_hes_sparsity.binary_union(i_x, i_x, arg[0], for_jac_sparsity);
// N(i_x) = N(i_x) union L(v1)
for_hes_sparsity.binary_union(i_x, i_x, arg[1], for_jac_sparsity);
i_x = *(++itr_0);
}
// --------------------------------------------------
// set of independent variables that v1 depends on
typename Vector_set::const_iterator itr_1(for_jac_sparsity, arg[1]);
// loop over dependent variables with non-zero partial
i_x = *itr_1;
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(v0)
for_hes_sparsity.binary_union(i_x, i_x, arg[0], for_jac_sparsity);
// N(i_x) = N(i_x) union L(v1)
for_hes_sparsity.binary_union(i_x, i_x, arg[1], for_jac_sparsity);
i_x = *(++itr_1);
}
return;
}
// ---------------------------------------------------------------------------
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+440
View File
@@ -0,0 +1,440 @@
# ifndef CPPAD_LOCAL_SPARSE_INTERNAL_HPP
# define CPPAD_LOCAL_SPARSE_INTERNAL_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
// necessary definitions
# include <cppad/core/define.hpp>
# include <cppad/local/sparse_pack.hpp>
# include <cppad/local/sparse_list.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\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_sparsity<Element_type>::pattern_type</code>
is the type of the corresponding internal sparsity pattern.
*/
template <class Element_type> struct internal_sparsity;
/// Specilization for \c bool elements.
template <>
struct internal_sparsity<bool>
{
typedef sparse_pack pattern_type;
};
/// Specilization for <code>std::set<size_t></code> elements.
template <>
struct internal_sparsity< std::set<size_t> >
{
typedef sparse_list 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 or sparse_list.
\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_sparsity 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_sparsity(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const vector<size_t>& internal_index ,
InternalSparsity& internal_pattern ,
const sparse_rc<SizeVector>& pattern_in )
{
# ifndef NDEBUG
size_t nr = internal_index.size();
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.add_element( internal_index[r], c );
}
}
template <class InternalSparsity>
void set_internal_sparsity(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const 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.add_element( i_var, j);
}
}
}
return;
}
template <class InternalSparsity>
void set_internal_sparsity(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const 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.add_element( i_var, j);
}
}
}
return;
}
template <class InternalSparsity>
void set_internal_sparsity(
bool zero_empty ,
bool input_empty ,
bool transpose ,
const 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.add_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.add_element( i_var, j);
++itr;
}
}
}
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 or sparse_list.
\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_sparsity(
bool transpose ,
const 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_sparsity(
bool transpose ,
const 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_sparsity(
bool transpose ,
const 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_sparsity(
bool transpose ,
const 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_NAMESPACE
# endif
File diff suppressed because it is too large Load Diff
+544
View File
@@ -0,0 +1,544 @@
# ifndef CPPAD_LOCAL_SPARSE_PACK_HPP
# define CPPAD_LOCAL_SPARSE_PACK_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/core/cppad_assert.hpp>
# include <cppad/local/pod_vector.hpp>
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file sparse_pack.hpp
Vector of sets of positive integers stored as a packed array of bools.
*/
// ==========================================================================
/*!
Vector of sets of postivie integers, each set stored as a packed boolean array.
*/
class sparse_pack_const_iterator;
class sparse_pack {
friend class sparse_pack_const_iterator;
private:
/// Type used to pack elements (should be the same as corresponding
/// typedef in multiple_n_bit() in test_more/sparse_hacobian.cpp)
typedef size_t Pack;
/// Number of bits per Pack value
const size_t n_bit_;
/// Number of sets that we are representing
/// (set by constructor and resize).
size_t n_set_;
/// Possible elements in each set are 0, 1, ..., end_ - 1
/// (set by constructor and resize).
size_t end_;
/// Number of \c Pack values necessary to represent \c end_ bits.
/// (set by constructor and resize).
size_t n_pack_;
/// Data for all the sets.
pod_vector<Pack> data_;
public:
/// declare a const iterator
typedef sparse_pack_const_iterator const_iterator;
// -----------------------------------------------------------------
/*! Default constructor (no sets)
*/
sparse_pack(void) :
n_bit_( std::numeric_limits<Pack>::digits ),
n_set_(0) ,
end_(0) ,
n_pack_(0)
{ }
// -----------------------------------------------------------------
/*! Make use of copy constructor an error
\param v
vector that we are attempting to make a copy of.
*/
sparse_pack(const sparse_pack& v) :
n_bit_( std::numeric_limits<Pack>::digits )
{ // Error:
// Probably a sparse_pack argument has been passed by value
CPPAD_ASSERT_UNKNOWN(0);
}
// -----------------------------------------------------------------
/*! Destructor
*/
~sparse_pack(void)
{ }
// -----------------------------------------------------------------
/*! Change number of sets, set end, and initialize all sets as empty
If \c n_set_in is zero, any memory currently allocated for this object
is freed. Otherwise, new memory may be allocated for the sets (if needed).
\param n_set_in
is the number of sets in this vector of sets.
\param end_in
is the maximum element plus one. The minimum element is 0 and
end must be greater than zero (unless n_set is also zero).
*/
void resize(size_t n_set_in, size_t end_in)
{ CPPAD_ASSERT_UNKNOWN( n_set_in == 0 || 0 < end_in );
n_set_ = n_set_in;
end_ = end_in;
if( n_set_ == 0 )
{ data_.free();
return;
}
// now start a new vector with empty sets
Pack zero(0);
data_.erase();
n_pack_ = ( 1 + (end_ - 1) / n_bit_ );
size_t i = n_set_ * n_pack_;
if( i > 0 )
{ data_.extend(i);
while(i--)
data_[i] = zero;
}
}
// -----------------------------------------------------------------
/*!
Count number of elements in a set.
\param index
is the index in of the set we are counting the elements of.
*/
size_t number_elements(size_t index) const
{ static Pack one(1);
CPPAD_ASSERT_UNKNOWN( index < n_set_ );
size_t count = 0;
for(size_t k = 0; k < n_pack_; k++)
{ Pack unit = data_[ index * n_pack_ + k ];
Pack mask = one;
size_t n = std::min(n_bit_, end_ - n_bit_ * k);
for(size_t bit = 0; bit < n; bit++)
{ CPPAD_ASSERT_UNKNOWN( mask > one || bit == 0);
if( mask & unit )
++count;
mask = mask << 1;
}
}
return count;
}
// -----------------------------------------------------------------
/*! Add one element to a set.
\param index
is the index for this set in the vector of sets.
\param element
is the element we are adding to the set.
\par Checked Assertions
\li index < n_set_
\li element < end_
*/
void add_element(size_t index, size_t element)
{ static Pack one(1);
CPPAD_ASSERT_UNKNOWN( index < n_set_ );
CPPAD_ASSERT_UNKNOWN( element < end_ );
size_t j = element / n_bit_;
size_t k = element - j * n_bit_;
Pack mask = one << k;
data_[ index * n_pack_ + j] |= mask;
}
// -----------------------------------------------------------------
/*! Is an element of a set.
\param index
is the index for this set in the vector of sets.
\param element
is the element we are checking to see if it is in the set.
\par Checked Assertions
\li index < n_set_
\li element < end_
*/
bool is_element(size_t index, size_t element) const
{ static Pack one(1);
static Pack zero(0);
CPPAD_ASSERT_UNKNOWN( index < n_set_ );
CPPAD_ASSERT_UNKNOWN( element < end_ );
size_t j = element / n_bit_;
size_t k = element - j * n_bit_;
Pack mask = one << k;
return (data_[ index * n_pack_ + j] & mask) != zero;
}
// -----------------------------------------------------------------
/*! Assign the empty set to one of the sets.
\param target
is the index of the set we are setting to the empty set.
\par Checked Assertions
\li target < n_set_
*/
void clear(size_t target)
{ // value with all its bits set to false
static Pack zero(0);
CPPAD_ASSERT_UNKNOWN( target < n_set_ );
size_t t = target * n_pack_;
size_t j = n_pack_;
while(j--)
data_[t++] = zero;
}
// -----------------------------------------------------------------
/*! Assign one set equal to another set.
\param this_target
is the index (in this \c sparse_pack object) of the set being assinged.
\param other_value
is the index (in the other \c sparse_pack object) of the
that we are using as the value to assign to the target set.
\param other
is the other \c sparse_pack object (which may be the same as this
\c sparse_pack object).
\par Checked Assertions
\li this_target < n_set_
\li other_value < other.n_set_
\li n_pack_ == other.n_pack_
*/
void assignment(
size_t this_target ,
size_t other_value ,
const sparse_pack& other )
{ 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++];
}
// -----------------------------------------------------------------
/*! Assing a set equal to the union of two other sets.
\param this_target
is the index (in this \c sparse_pack object) of the set being assinged.
\param this_left
is the index (in this \c sparse_pack object) of the
left operand for the union operation.
It is OK for \a this_target and \a this_left to be the same value.
\param other_right
is the index (in the other \c sparse_pack object) of the
right operand for the union operation.
It is OK for \a this_target and \a other_right to be the same value.
\param other
is the other \c sparse_pack object (which may be the same as this
\c sparse_pack object).
\par Checked Assertions
\li this_target < n_set_
\li this_left < n_set_
\li other_right < other.n_set_
\li n_pack_ == other.n_pack_
*/
void binary_union(
size_t this_target ,
size_t this_left ,
size_t other_right ,
const sparse_pack& other )
{ 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++] );
}
// -----------------------------------------------------------------
/*! Assing a set equal to the intersection of two other sets.
\param this_target
is the index (in this \c sparse_pack object) of the set being assinged.
\param this_left
is the index (in this \c sparse_pack object) of the
left operand for the intersection operation.
It is OK for \a this_target and \a this_left to be the same value.
\param other_right
is the index (in the other \c sparse_pack object) of the
right operand for the intersection operation.
It is OK for \a this_target and \a other_right to be the same value.
\param other
is the other \c sparse_pack object (which may be the same as this
\c sparse_pack object).
\par Checked Assertions
\li this_target < n_set_
\li this_left < n_set_
\li other_right < other.n_set_
\li n_pack_ == other.n_pack_
*/
void binary_intersection(
size_t this_target ,
size_t this_left ,
size_t other_right ,
const sparse_pack& other )
{ 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++] );
}
// -----------------------------------------------------------------
/*! Fetch n_set for vector of sets object.
\return
Number of from sets for this vector of sets object
*/
size_t n_set(void) const
{ return n_set_; }
// -----------------------------------------------------------------
/*! Fetch end for this vector of sets object.
\return
is the maximum element value plus one (the minimum element value is 0).
*/
size_t end(void) const
{ return end_; }
// -----------------------------------------------------------------
/*! Amount of memory used by this vector of sets
\return
The amount of memory in units of type unsigned char memory.
*/
size_t memory(void) const
{ return data_.capacity() * sizeof(Pack);
}
/*!
Print the vector of sets (used for debugging)
*/
void print(void) const;
};
// ==========================================================================
/*!
cons_iterator for one set of positive integers in a sparse_pack object.
*/
class sparse_pack_const_iterator {
private:
/// Type used to pack elements in sparse_pack
typedef sparse_pack::Pack Pack;
/// data for the entire vector of sets
const pod_vector<Pack>& data_;
/// Number of bits per Pack value
const size_t n_bit_;
/// Number of Pack values necessary to represent end_ bits.
const size_t n_pack_;
/// Possible elements in each set are 0, 1, ..., end_ - 1;
const size_t end_;
/// index of this set in the vector of sets;
const size_t index_;
/// value of the next element in this set
/// (use end_ for no such element exists; i.e., past end of the set).
size_t next_element_;
public:
/// construct a const_iterator for a set in a sparse_pack object
sparse_pack_const_iterator (const sparse_pack& pack, size_t index)
:
data_ ( pack.data_ ) ,
n_bit_ ( pack.n_bit_ ) ,
n_pack_ ( pack.n_pack_ ) ,
end_ ( pack.end_ ) ,
index_ ( index )
{ static Pack one(1);
CPPAD_ASSERT_UNKNOWN( index < pack.n_set_ );
//
next_element_ = 0;
if( next_element_ < end_ )
{ Pack check = data_[ index_ * n_pack_ + 0 ];
if( check & one )
return;
}
// element with index zero is not in this set of integers,
// advance to first element or end
++(*this);
}
/// advance to next element in this set
sparse_pack_const_iterator& operator++(void)
{ static Pack one(1);
CPPAD_ASSERT_UNKNOWN( next_element_ <= end_ );
if( next_element_ == end_ )
return *this;
//
++next_element_;
if( next_element_ == end_ )
return *this;
//
// initialize packed data index
size_t j = next_element_ / n_bit_;
// initialize bit index
size_t k = next_element_ - j * n_bit_;
// initialize mask
size_t mask = one << k;
// start search at this packed value
Pack check = data_[ index_ * n_pack_ + j ];
//
while( true )
{ // check if this element is in the set
if( check & mask )
return *this;
// increment next element before checking this one
next_element_++;
if( next_element_ == end_ )
return *this;
// shift mask to left one bit so corresponds to next_element_
// (use mask <<= 1. not one << k, so compiler knows value)
k++;
mask <<= 1;
CPPAD_ASSERT_UNKNOWN( k <= n_bit_ );
// check if we must go to next packed data index
if( k == n_bit_ )
{ // get next packed value
k = 0;
mask = one;
j++;
CPPAD_ASSERT_UNKNOWN( j < n_pack_ );
check = data_[ index_ * n_pack_ + j ];
}
}
// should never get here
CPPAD_ASSERT_UNKNOWN(false);
return *this;
}
/// obtain value of this element of the set of positive integers
/// (end_ for no such element)
size_t operator*(void) const
{ return next_element_; }
};
// =========================================================================
/*!
Print the vector of sets (used for debugging)
*/
inline void sparse_pack::print(void) const
{ std::cout << "sparse_pack:\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;
}
// ==========================================================================
/*!
Copy a user vector of sets sparsity pattern to an internal sparse_pack object.
\tparam VectorSet
is a simple vector with elements of type std::set<size_t>.
\param internal
The input value of sparisty does not matter.
Upon return it contains the same sparsity pattern as \c user
(or the transposed sparsity pattern).
\param user
sparsity pattern that we are placing internal.
\param n_set
number of sets (rows) in the internal sparsity pattern.
\param end
end of set value (number of columns) in the interanl sparsity pattern.
\param transpose
if true, the user sparsity patter is the transposed.
\param error_msg
is the error message to display if some values in the user sparstiy
pattern are not valid.
*/
template<class VectorSet>
void sparsity_user2internal(
sparse_pack& internal ,
const VectorSet& user ,
size_t n_set ,
size_t end ,
bool transpose ,
const char* error_msg )
{ 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++)
{ 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++)
{ if( user[ i * end + j ] )
internal.add_element(i, j);
}
}
}
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+250
View File
@@ -0,0 +1,250 @@
// $Id: sparse_unary_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_SPARSE_UNARY_OP_HPP
# define CPPAD_LOCAL_SPARSE_UNARY_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\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 or sparse_list.
\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 \a arg[0] in \a 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 \a i_z in \a 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 \a i_x < \a i_z
*/
template <class Vector_set>
inline void forward_sparse_jacobian_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 or sparse_list.
\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 \a i_z in \a sparsity
is the sparsity bit pattern for G with respect to the variable z.
\n
\b Input:
The set with index \a i_x in \a sparsity
is the sparsity bit pattern for G with respect to the variable x.
\n
\b Output:
The set with index \a i_x in \a sparsity
is the sparsity bit pattern for H with respect to the variable x.
\par Checked Assertions:
\li \a i_x < \a i_z
*/
template <class Vector_set>
inline void reverse_sparse_jacobian_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>
inline void reverse_sparse_hessian_linear_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 );
rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity);
rev_jacobian[i_x] |= rev_jacobian[i_z];
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>
inline void reverse_sparse_hessian_nonlinear_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 );
rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity);
if( rev_jacobian[i_z] )
rev_hes_sparsity.binary_union(i_x, i_x, i_x, for_jac_sparsity);
rev_jacobian[i_x] |= rev_jacobian[i_z];
return;
}
// ---------------------------------------------------------------------------
/*!
Forward mode Hessian sparsity pattern for non-linear unary operators.
The C++ source code corresponding to this operation is
\verbatim
w(x) = fun( v(x) )
\endverbatim
where fun is a non-linear function.
\param i_v
is the index of the argument variable v
\param for_jac_sparsity
for_jac_sparsity(i_v) constains the Jacobian sparsity for v(x).
\param for_hes_sparsity
On input, for_hes_sparsity includes the Hessian sparsity for v(x); i.e.,
the sparsity can be a super set.
Upon return it includes the Hessian sparsity for w(x)
*/
template <class Vector_set>
inline void forward_sparse_hessian_nonlinear_unary_op(
size_t i_v ,
const Vector_set& for_jac_sparsity ,
Vector_set& for_hes_sparsity )
{
// set of independent variables that v depends on
typename Vector_set::const_iterator itr(for_jac_sparsity, i_v);
// next independent variables that v depends on
size_t i_x = *itr;
// loop over dependent variables with non-zero partial
while( i_x < for_jac_sparsity.end() )
{ // N(i_x) = N(i_x) union L(i_v)
for_hes_sparsity.binary_union(i_x, i_x, i_v, for_jac_sparsity);
i_x = *(++itr);
}
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+193
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 multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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>
inline 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>
inline 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>
inline 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>
inline 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
+53
View File
@@ -0,0 +1,53 @@
// $Id: std_set.hpp 3845 2016-11-19 01:50:47Z bradbell $
# ifndef CPPAD_LOCAL_STD_SET_HPP
# define CPPAD_LOCAL_STD_SET_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
# include <cppad/core/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
+498
View File
@@ -0,0 +1,498 @@
// $Id: store_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_STORE_OP_HPP
# define CPPAD_LOCAL_STORE_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file store_op.hpp
Changing the current value of a VecAD element.
*/
/*
==============================================================================
<!-- 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 = index_by_ind[ arg[0] + i_vec ]
\endverbatim
where i_vec is defined under the heading arg[1] below:
<!-- end preamble -->
==============================================================================
*/
/*!
Shared documentation for zero order forward implementation of
op = StppOp, StpvOp, StvpOp, or StvvOp (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_v_x = index_by_ind[ 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 i_z
is the index corresponding to the previous variable on the tape
(only used for error checking).
\param arg
\n
arg[0]
\n
is the offset of this VecAD vector relative to the beginning
of the isvar_by_ind and index_by_ind arrays.
\n
\n
arg[1]
\n
If this is a StppOp or StpvOp operation (if x is a parameter),
i_vec is defined by
\verbatim
i_vec = arg[1]
\endverbatim
If this is a StvpOp or StvvOp operation (if x is a variable),
i_vec is defined by
\verbatim
i_vec = floor( taylor[ arg[1] * cap_order + 0 ] )
\endverbatim
where floor(c) is the greatest integer less that or equal c.
\n
\n
arg[2]
\n
index corresponding to the third operand for this operator;
i.e. the index corresponding to y.
\param num_par
is the total number of parameters on the tape
(only used for error checking).
\param cap_order
number of columns in the matrix containing the Taylor coefficients.
\param taylor
In StvpOp and StvvOp cases, <code><taylor[ arg[1] * cap_order + 0 ]</code>
is used to compute the index in the definition of i_vec above.
\param isvar_by_ind
If y is a varable (StpvOp and StvvOp cases),
<code>isvar_by_ind[ arg[0] + i_vec ] </code> is set to true.
Otherwise y is a paraemter (StppOp and StvpOp cases) and
<code>isvar_by_ind[ arg[0] + i_vec ] </code> is set to false.
\param index_by_ind
<code>index_by_ind[ arg[0] - 1 ]</code>
is the number of elements in the user vector containing this element.
The value <code>index_by_ind[ arg[0] + i_vec]</code>
is set equal to arg[2].
\par Check User Errors
\li Check that the index is with in range; i.e.
<code>i_vec < index_by_ind[ arg[0] - 1 ]</code>
Note that, if x is a parameter,
the corresponding vector index and it does not change.
In this case, the error above should be detected during tape recording.
\par Checked Assertions
\li NumArg(op) == 3
\li NumRes(op) == 0
\li 0 < arg[0]
\li if y is a parameter, arg[2] < num_par
*/
template <class Base>
inline void forward_store_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind )
{
// This routine is only for documentaiton, it should not be used
CPPAD_ASSERT_UNKNOWN( false );
}
/*!
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 or sparse_list.
\param op
is the code corresponding to this operator;
i.e., StpvOp, StvpOp, or StvvOp.
\param arg
\n
\a arg[0]
is the offset corresponding to this VecAD vector in the combined array.
\n
\n
\a arg[2]
\n
The set with index \a arg[2] in \a var_sparsity
is the sparsity pattern corresponding to y.
(Note that \a arg[2] > 0 because y is a variable.)
\param num_combined
is the total number of elements in the VecAD address array.
\param combined
\a combined [ arg[0] - 1 ]
is the index of the set in \a 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[ \a arg[0] - 1 ]
\endverbatim
\param var_sparsity
The set with index \a arg[2] in \a 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 \a i_v in \a 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 < \a arg[0]
\li \a arg[0] < \a num_combined
\li \a arg[2] < \a var_sparsity.n_set()
\li i_v < \a vecad_sparsity.n_set()
*/
template <class Vector_set>
inline 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 );
}
/*!
Zero order forward mode implementation of op = StppOp.
\copydetails CppAD::local::forward_store_op_0
*/
template <class Base>
inline void forward_store_pp_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind )
{ size_t i_vec = arg[1];
// Because the index is a parameter, this indexing error should be
// caught and reported to the user when the tape is recording.
CPPAD_ASSERT_UNKNOWN( i_vec < index_by_ind[ arg[0] - 1 ] );
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 );
isvar_by_ind[ arg[0] + i_vec ] = false;
index_by_ind[ arg[0] + i_vec ] = arg[2];
}
/*!
Zero order forward mode implementation of op = StpvOp.
\copydetails CppAD::local::forward_store_op_0
*/
template <class Base>
inline void forward_store_pv_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind )
{ size_t i_vec = arg[1];
// Because the index is a parameter, this indexing error should be
// caught and reported to the user when the tape is recording.
CPPAD_ASSERT_UNKNOWN( i_vec < index_by_ind[ arg[0] - 1 ] );
CPPAD_ASSERT_UNKNOWN( NumArg(StpvOp) == 3 );
CPPAD_ASSERT_UNKNOWN( NumRes(StpvOp) == 0 );
CPPAD_ASSERT_UNKNOWN( 0 < arg[0] );
isvar_by_ind[ arg[0] + i_vec ] = true;
index_by_ind[ arg[0] + i_vec ] = arg[2];
}
/*!
Zero order forward mode implementation of op = StvpOp.
\copydetails CppAD::local::forward_store_op_0
*/
template <class Base>
inline void forward_store_vp_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind )
{
size_t i_vec = Integer( taylor[ arg[1] * cap_order + 0 ] );
CPPAD_ASSERT_KNOWN(
i_vec < index_by_ind[ 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] );
CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par );
isvar_by_ind[ arg[0] + i_vec ] = false;
index_by_ind[ arg[0] + i_vec ] = arg[2];
}
/*!
Zero order forward mode implementation of op = StvvOp.
\copydetails CppAD::local::forward_store_op_0
*/
template <class Base>
inline void forward_store_vv_op_0(
size_t i_z ,
const addr_t* arg ,
size_t num_par ,
size_t cap_order ,
Base* taylor ,
bool* isvar_by_ind ,
size_t* index_by_ind )
{
size_t i_vec = Integer( taylor[ arg[1] * cap_order + 0 ] );
CPPAD_ASSERT_KNOWN(
i_vec < index_by_ind[ 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] );
isvar_by_ind[ arg[0] + i_vec ] = true;
index_by_ind[ arg[0] + i_vec ] = arg[2];
}
/*!
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 = index_by_ind[ 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>
inline 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, arg[1], var_sparsity);
if( (op == StpvOp) | (op == StvvOp ) )
vecad_sparsity.binary_union(i_v, i_v, 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 = index_by_ind[ 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>
inline 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(arg[1], arg[1], i_v, vecad_sparsity);
if( (op == StpvOp) | (op == StvvOp) )
var_sparsity.binary_union(arg[2], 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 = index_by_ind[ 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
\a var_jacobian[ \a arg[2] ]
is false (true) if the Jacobian of G with respect to y is always zero
(may be non-zero).
\param vecad_jacobian
\a 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>
inline 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(arg[2], arg[2], i_v, vecad_sparsity);
var_jacobian[ arg[2] ] |= vecad_jacobian[i_v];
return;
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+501
View File
@@ -0,0 +1,501 @@
// $Id: sub_op.hpp 3865 2017-01-19 01:57:55Z bradbell $
# ifndef CPPAD_LOCAL_SUB_OP_HPP
# define CPPAD_LOCAL_SUB_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
inline 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 + arg[0] * num_taylor_per_var + m;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
inline 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 + arg[0] * cap_order;
Base* y = taylor + 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 \a parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
inline 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 + arg[0] * nc_partial;
Base* py = partial + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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>
inline 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 + 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
+231
View File
@@ -0,0 +1,231 @@
# ifndef CPPAD_LOCAL_TAN_OP_HPP
# define CPPAD_LOCAL_TAN_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file tan_op.hpp
Forward and reverse mode calculations for z = tan(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tan(x)
\endverbatim
The auxillary result is
\verbatim
y = tan(x)^2
\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>
inline void forward_tan_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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* y = z - cap_order;
size_t k;
if( p == 0 )
{ z[0] = tan( x[0] );
y[0] = z[0] * z[0];
p++;
}
for(size_t j = p; j <= q; j++)
{ Base base_j = static_cast<Base>(double(j));
z[j] = x[j];
for(k = 1; k <= j; k++)
z[j] += Base(double(k)) * x[k] * y[j-k] / base_j;
y[j] = z[0] * z[j];
for(k = 1; k <= j; k++)
y[j] += z[k] * z[j-k];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tan(x)
\endverbatim
The auxillary result is
\verbatim
y = tan(x)^2
\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>
inline void forward_tan_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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* y = z - num_taylor_per_var;
size_t k;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * ( x[m+ell] + x[m+ell] * y[0]);
for(k = 1; k < q; k++)
z[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * y[(q-k-1)*r+1+ell];
z[m+ell] /= Base(double(q));
//
y[m+ell] = Base(2.0) * z[m+ell] * z[0];
for(k = 1; k < q; k++)
y[m+ell] += z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tan(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>
inline void forward_tan_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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; // called z in documentation
Base* y = z - cap_order; // called y in documentation
z[0] = tan( x[0] );
y[0] = z[0] * z[0];
}
/*!
Compute reverse mode partial derivatives for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tan(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>
inline void reverse_tan_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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; // called z in doc
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* y = z - cap_order; // called y in documentation
Base* py = pz - nc_partial;
size_t j = d;
size_t k;
Base base_two(2);
while(j)
{
px[j] += pz[j];
pz[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{ px[k] += azmul(pz[j], y[j-k]) * Base(double(k));
py[j-k] += azmul(pz[j], x[k]) * Base(double(k));
}
for(k = 0; k < j; k++)
pz[k] += azmul(py[j-1], z[j-k-1]) * base_two;
--j;
}
px[0] += azmul(pz[0], Base(1.0) + y[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+230
View File
@@ -0,0 +1,230 @@
# ifndef CPPAD_LOCAL_TANH_OP_HPP
# define CPPAD_LOCAL_TANH_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file tanh_op.hpp
Forward and reverse mode calculations for z = tanh(x).
*/
/*!
Compute forward mode Taylor coefficient for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tanh(x)
\endverbatim
The auxillary result is
\verbatim
y = tanh(x)^2
\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>
inline void forward_tanh_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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* y = z - cap_order;
size_t k;
if( p == 0 )
{ z[0] = tanh( x[0] );
y[0] = z[0] * z[0];
p++;
}
for(size_t j = p; j <= q; j++)
{ Base base_j = static_cast<Base>(double(j));
z[j] = x[j];
for(k = 1; k <= j; k++)
z[j] -= Base(double(k)) * x[k] * y[j-k] / base_j;
y[j] = z[0] * z[j];
for(k = 1; k <= j; k++)
y[j] += z[k] * z[j-k];
}
}
/*!
Multiple directions forward mode Taylor coefficient for op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tanh(x)
\endverbatim
The auxillary result is
\verbatim
y = tanh(x)^2
\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>
inline void forward_tanh_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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* y = z - num_taylor_per_var;
size_t k;
size_t m = (q-1) * r + 1;
for(size_t ell = 0; ell < r; ell++)
{ z[m+ell] = Base(double(q)) * ( x[m+ell] - x[m+ell] * y[0] );
for(k = 1; k < q; k++)
z[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * y[(q-k-1)*r+1+ell];
z[m+ell] /= Base(double(q));
//
y[m+ell] = Base(2.0) * z[m+ell] * z[0];
for(k = 1; k < q; k++)
y[m+ell] += z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell];
}
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tanh(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>
inline void forward_tanh_op_0(
size_t i_z ,
size_t i_x ,
size_t cap_order ,
Base* taylor )
{
// check assumptions
CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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; // called z in documentation
Base* y = z - cap_order; // called y in documentation
z[0] = tanh( x[0] );
y[0] = z[0] * z[0];
}
/*!
Compute reverse mode partial derivatives for result of op = TanOp.
The C++ source code corresponding to this operation is
\verbatim
z = tanh(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>
inline void reverse_tanh_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(TanOp) == 1 );
CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 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; // called z in doc
Base* pz = partial + i_z * nc_partial;
// Taylor coefficients and partials corresponding to auxillary result
const Base* y = z - cap_order; // called y in documentation
Base* py = pz - nc_partial;
size_t j = d;
size_t k;
Base base_two(2);
while(j)
{
px[j] += pz[j];
pz[j] /= Base(double(j));
for(k = 1; k <= j; k++)
{ px[k] -= azmul(pz[j], y[j-k]) * Base(double(k));
py[j-k] -= azmul(pz[j], x[k]) * Base(double(k));
}
for(k = 0; k < j; k++)
pz[k] += azmul(py[j-1], z[j-k-1]) * base_two;
--j;
}
px[0] += azmul(pz[0], Base(1.0) - y[0]);
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+32
View File
@@ -0,0 +1,32 @@
// $Id$
# ifndef CPPAD_LOCAL_USER_STATE_HPP
# define CPPAD_LOCAL_USER_STATE_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
enum enum_user_state {
/// next UserOp marks beginning of a user atomic call
start_user,
/// next UsrapOp (UsravOp) is a parameter (variable) argument
arg_user,
/// next UsrrpOp (UsrrvOp) is a parameter (variable) result
ret_user,
/// next UserOp marks end of a user atomic call
end_user
};
} } // END_CPPAD_LOCAL_NAMESPACE
# endif
+517
View File
@@ -0,0 +1,517 @@
# ifndef CPPAD_LOCAL_ZMUL_OP_HPP
# define CPPAD_LOCAL_ZMUL_OP_HPP
/* --------------------------------------------------------------------------
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
CppAD is distributed under multiple licenses. This distribution is under
the terms of the
Eclipse Public License Version 1.0.
A copy of this license is included in the COPYING file of this distribution.
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
-------------------------------------------------------------------------- */
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
/*!
\file mul_op.hpp
Forward and reverse mode calculations for z = azmul(x, y).
*/
// --------------------------- Zmulvv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = ZmulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument \a parameter is not used.
\copydetails CppAD::local::forward_binary_op
*/
template <class Base>
inline void forward_zmulvv_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(ZmulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + arg[0] * cap_order;
Base* y = taylor + 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] += azmul(x[d-k], y[k]);
}
}
/*!
Multiple directions forward mode Taylor coefficients for op = ZmulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_dir
*/
template <class Base>
inline void forward_zmulvv_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(ZmulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 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 + arg[0] * num_taylor_per_var;
Base* y = taylor + 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] = azmul(x[0], y[m]) + azmul(x[m], y[0]);
for(k = 1; k < q; k++)
z[m] += azmul(x[(q-k-1)*r + ell + 1], y[(k-1)*r + ell + 1]);
}
}
/*!
Compute zero order forward mode Taylor coefficients for result of op = ZmulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument \a parameter is not used.
\copydetails CppAD::local::forward_binary_op_0
*/
template <class Base>
inline void forward_zmulvv_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(ZmulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + arg[0] * cap_order;
Base* y = taylor + arg[1] * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = azmul(x[0], y[0]);
}
/*!
Compute reverse mode partial derivatives for result of op = ZmulvvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(x, y)
\endverbatim
In the documentation below,
this operations is for the case where both x and y are variables
and the argument \a parameter is not used.
\copydetails CppAD::local::reverse_binary_op
*/
template <class Base>
inline void reverse_zmulvv_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(ZmulvvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
const Base* x = taylor + arg[0] * cap_order;
const Base* y = taylor + arg[1] * cap_order;
// Partial derivatives corresponding to arguments and result
Base* px = partial + arg[0] * nc_partial;
Base* py = partial + 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]);
}
}
}
// --------------------------- Zmulpv -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = ZmulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulpv_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(ZmulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + 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] = azmul(x, y[d]);
}
/*!
Multiple directions forward mode Taylor coefficients for op = ZmulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulpv_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(ZmulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 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 + 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] = azmul(x, y[ell]);
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = ZmulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulpv_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(ZmulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 );
// Paraemter value
Base x = parameter[ arg[0] ];
// Taylor coefficients corresponding to arguments and result
Base* y = taylor + arg[1] * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = azmul(x, y[0]);
}
/*!
Compute reverse mode partial derivative for result of op = ZmulpvOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void reverse_zmulpv_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(ZmulpvOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 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 + 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);
}
}
// --------------------------- Zmulvp -----------------------------------------
/*!
Compute forward mode Taylor coefficients for result of op = ZmulvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulvp_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(ZmulvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( q < cap_order );
CPPAD_ASSERT_UNKNOWN( p <= q );
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + arg[0] * cap_order;
Base* z = taylor + i_z * cap_order;
// Paraemter value
Base y = parameter[ arg[1] ];
for(size_t d = p; d <= q; d++)
z[d] = azmul(x[d], y);
}
/*!
Multiple directions forward mode Taylor coefficients for op = ZmulvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulvp_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(ZmulvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 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 + arg[0] * num_taylor_per_var + m;
Base* z = taylor + i_z * num_taylor_per_var + m;
// Paraemter value
Base y = parameter[ arg[1] ];
for(size_t ell = 0; ell < r; ell++)
z[ell] = azmul(x[ell], y);
}
/*!
Compute zero order forward mode Taylor coefficient for result of op = ZmulvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void forward_zmulvp_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(ZmulvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 );
// Paraemter value
Base y = parameter[ arg[1] ];
// Taylor coefficients corresponding to arguments and result
Base* x = taylor + arg[0] * cap_order;
Base* z = taylor + i_z * cap_order;
z[0] = azmul(x[0], y);
}
/*!
Compute reverse mode partial derivative for result of op = ZmulvpOp.
The C++ source code corresponding to this operation is
\verbatim
z = azmul(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>
inline void reverse_zmulvp_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(ZmulvpOp) == 2 );
CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 );
CPPAD_ASSERT_UNKNOWN( d < cap_order );
CPPAD_ASSERT_UNKNOWN( d < nc_partial );
// Arguments
Base y = parameter[ arg[1] ];
// Partial derivatives corresponding to arguments and result
Base* px = partial + arg[0] * nc_partial;
Base* pz = partial + i_z * nc_partial;
// number of indices to access
size_t j = d + 1;
while(j)
{ --j;
px[j] += azmul(pz[j], y);
}
}
} } // END_CPPAD_LOCAL_NAMESPACE
# endif