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]); } }
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) / 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); 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(j); for(k = 1; k < j; k++) { pb[j-k] -= Base(k) * azmul(pz[j], z[k]); pz[k] -= Base(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) * azmul(pb[0], x[0]); }
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); } }
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); }
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); }
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); for(k = 0; k <= d; k++) z[d] += azmul(x[d-k], y[k]); } }
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(j); for(k = 1; k <= j; k++) { px[k] += Base(k) * azmul(pz[j], z[j-k]); pz[j-k] += Base(k) * azmul(pz[j], x[k]); } --j; } px[0] += azmul(pz[0], z[0]); }
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); }
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) / 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); for(k = 1; k < j; k++) pz[k] -= azmul(pz[j], z[j-k]); --j; } px[0] += azmul(pz[0], inv_z0) / Base(2); }
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]); } } }
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]); }
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]); }
// case where x and y are AD<Base> ------------------------------------------- template <class Base> AD<Base> azmul(const AD<Base>& x, const AD<Base>& y) { // compute the Base part AD<Base> result; result.value_ = azmul(x.value_, y.value_); // check if there is a recording in progress ADTape<Base>* tape = AD<Base>::tape_ptr(); if( tape == CPPAD_NULL ) return result; tape_id_t tape_id = tape->id_; // tape_id cannot match the default value for tape_id_; i.e., 0 CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); bool var_x = x.tape_id_ == tape_id; bool var_y = y.tape_id_ == tape_id; if( var_x ) { if( var_y ) { // result = azmul(variable, variable) CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(x.taddr_, y.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(ZmulvvOp); // make result a variable result.tape_id_ = tape_id; } else if( IdenticalZero( y.value_ ) ) { // result = variable * 0 } else if( IdenticalOne( y.value_ ) ) { // result = variable * 1 result.make_variable(x.tape_id_, x.taddr_); } else { // result = zmul(variable, parameter) CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvpOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(y.value_); tape->Rec_.PutArg(x.taddr_, p); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(ZmulvpOp); // make result a variable result.tape_id_ = tape_id; } } else if( var_y ) { if( IdenticalZero(x.value_) ) { // result = 0 * variable } else if( IdenticalOne( x.value_ ) ) { // result = 1 * variable result.make_variable(y.tape_id_, y.taddr_); } else { // result = zmul(parameter, variable) CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(ZmulpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(x.value_); tape->Rec_.PutArg(p, y.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(ZmulpvOp); // make result a variable result.tape_id_ = tape_id; } } return result; }
template <class Base> AD<Base> azmul(const VecAD_reference<Base>& x, const Base& y) { return azmul(x.ADBase(), AD<Base>(y)); }
template <class Base> AD<Base> azmul(const AD<Base>& x, const Base& y) { return azmul(x, AD<Base>(y)); }
template <class Base> AD<Base> azmul(const Base& x, const AD<Base>& y) { return azmul(AD<Base>(x), y); }
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) / 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(j); for(k = 1; k < j; k++) { // update partials w.r.t b^(j-k) pb[j-k] -= Base(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(k) * azmul(pz[j], b[j-k]); } --j; } // j == 0 case px[0] -= azmul( pz[0] + azmul(pb[0], x[0]), inv_b0); }
template <class Base> AD<Base> azmul(const Base& x, const VecAD_reference<Base>& y) { return azmul(AD<Base>(x), y.ADBase()); }