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; // 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; // 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] /= b[0]; pb[j] *= Base(2); pb[0] -= pz[j] * z[j]; px[j] += pz[j] + pb[j] * x[0]; px[0] += 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] -= pz[j] * Base(k) * z[k]; pz[k] -= pz[j] * Base(k) * b[j-k]; px[k] += pb[j] * x[j-k]; } --j; } px[0] += pz[0] / b[0] + pb[0] * Base(2) * x[0]; }
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; // If pc 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(pc[i_d]); if( skip ) return; // 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(j); pc[j] /= Base(j); for(k = 1; k <= j; k++) { px[k] += ps[j] * Base(k) * c[j-k]; px[k] += pc[j] * Base(k) * s[j-k]; ps[j-k] += pc[j] * Base(k) * x[k]; pc[j-k] += ps[j] * Base(k) * x[k]; } --j; } px[0] += ps[0] * c[0]; px[0] += pc[0] * s[0]; }
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; // 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; size_t j = d; size_t k; Base base_two(2); while(j) { px[j] += pz[j]; pz[j] /= Base(j); for(k = 1; k <= j; k++) { px[k] += pz[j] * y[j-k] * Base(k); py[j-k] += pz[j] * x[k] * Base(k); } for(k = 0; k < j; k++) pz[k] += py[j-1] * z[j-k-1] * base_two; --j; } px[0] += pz[0] * (Base(1) + y[0]); }
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; // 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; // Using CondExp, it can make sense to divide by zero // so do not make it an error. 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] /= y[0]; px[j] += pz[j]; for(k = 1; k <= j; k++) { pz[j-k] -= pz[j] * y[k]; py[k] -= pz[j] * z[j-k]; } py[0] -= pz[j] * z[j]; } }
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; // 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; CPPAD_ASSERT_KNOWN( z[0] != Base(0), "Reverse: attempt to take derivatve of square root of zero" ) // number of indices to access size_t j = d; size_t k; while(j) { // scale partial w.r.t. z[j] pz[j] /= z[0]; pz[0] -= pz[j] * z[j]; px[j] += pz[j] / Base(2); for(k = 1; k < j; k++) pz[k] -= pz[j] * z[j-k]; --j; } px[0] += pz[0] / (Base(2) * z[0]); }
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(j); for(k = 1; k <= j; k++) { px[k] += pz[j] * Base(k) * z[j-k]; pz[j-k] += pz[j] * Base(k) * x[k]; } --j; } px[0] += pz[0] + pz[0] * z[0]; }
AD<Base> operator - (const AD<Base> &left , const AD<Base> &right) { ADTape<Base> *tape = AD<Base>::tape_ptr(); bool var_left, var_right; # ifdef NDEBUG if( tape == CPPAD_NULL ) { var_left = false; var_right = false; } else { var_left = left.id_ == tape->id_; var_right = right.id_ == tape->id_; } # else var_left = Variable(left); var_right = Variable(right); CPPAD_ASSERT_KNOWN( (! var_left) || left.id_ == tape->id_ , "- left operand is a variable for a different thread" ); CPPAD_ASSERT_KNOWN( (! var_right) || right.id_ == tape->id_ , "- right operand is a variable for a different thread" ); # endif AD<Base> result; result.value_ = left.value_ - right.value_; CPPAD_ASSERT_UNKNOWN( Parameter(result) ); if( var_left ) { if( var_right ) { // result = variable - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(left.taddr_, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(SubvvOp); // make result a variable result.id_ = tape->id_; } else if( IdenticalZero(right.value_) ) { // result = variable - 0 result.make_variable(left.id_, left.taddr_); } else { // result = variable - parameter CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); // put operand addresses in tape size_t p = tape->Rec_.PutPar(right.value_); tape->Rec_.PutArg(left.taddr_, p); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(SubvpOp); // make result a variable result.id_ = tape->id_; } } else if( var_right ) { // result = parameter - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); // put operand addresses in tape size_t p = tape->Rec_.PutPar(left.value_); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(SubpvOp); // make result a variable result.id_ = tape->id_; } return result; }
AD<Base> operator / (const AD<Base> &left , const AD<Base> &right) { // compute the Base part AD<Base> result; result.value_ = left.value_ / right.value_; CPPAD_ASSERT_UNKNOWN( Parameter(result) ); // 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_left = left.tape_id_ == tape_id; bool var_right = right.tape_id_ == tape_id; if( var_left ) { if( var_right ) { // result = variable / variable CPPAD_ASSERT_KNOWN( left.tape_id_ == right.tape_id_, "Dividing AD objects that are" " variables on different tapes." ); CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(left.taddr_, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(DivvvOp); // make result a variable result.tape_id_ = tape_id; } else if( IdenticalOne(right.value_) ) { // result = variable / 1 result.make_variable(left.tape_id_, left.taddr_); } else { // result = variable / parameter CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(right.value_); tape->Rec_.PutArg(left.taddr_, p); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(DivvpOp); // make result a variable result.tape_id_ = tape_id; } } else if( var_right ) { if( IdenticalZero(left.value_) ) { // result = 0 / variable } else { // result = parameter / variable CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(left.value_); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(DivpvOp); // make result a variable result.tape_id_ = tape_id; } } return result; }
// 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; }
AD<Base> operator / (const AD<Base> &left , const AD<Base> &right) { // compute the Base part AD<Base> result; result.value_ = left.value_ / right.value_; CPPAD_ASSERT_UNKNOWN( Parameter(result) ); // check if there is a recording in progress local::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 ); // check if left and right tapes match bool match_left = left.tape_id_ == tape_id; bool match_right = right.tape_id_ == tape_id; // check if left and right are dynamic parameters bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); // check if left and right are variables bool var_left = match_left & (left.ad_type_ != dynamic_enum); bool var_right = match_right & (right.ad_type_ != dynamic_enum); CPPAD_ASSERT_KNOWN( left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , "Divide: AD variables or dynamic parameters on different threads." ); if( var_left ) { if( var_right ) { // result = variable / variable CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(left.taddr_, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(local::DivvvOp); // make result a variable result.tape_id_ = tape_id; result.ad_type_ = variable_enum; } else if( (! dyn_right) & IdenticalOne(right.value_) ) { // result = variable / 1 result.make_variable(left.tape_id_, left.taddr_); } else { // result = variable / parameter CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvpOp) == 2 ); // put operand addresses in tape addr_t p = right.taddr_; if( ! dyn_right ) p = tape->Rec_.put_con_par(right.value_); tape->Rec_.PutArg(left.taddr_, p); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(local::DivvpOp); // make result a variable result.tape_id_ = tape_id; result.ad_type_ = variable_enum; } } else if( var_right ) { if( (! dyn_left) & IdenticalZero(left.value_) ) { // result = 0 / variable } else { // result = parameter / variable CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivpvOp) == 2 ); // put operand addresses in tape addr_t p = left.taddr_; if( ! dyn_left ) p = tape->Rec_.put_con_par(left.value_); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(local::DivpvOp); // make result a variable result.tape_id_ = tape_id; result.ad_type_ = variable_enum; } } else if( dyn_left | dyn_right ) { addr_t arg0 = left.taddr_; addr_t arg1 = right.taddr_; if( ! dyn_left ) arg0 = tape->Rec_.put_con_par(left.value_); if( ! dyn_right ) arg1 = tape->Rec_.put_con_par(right.value_); // // parameters with a dynamic parameter result result.taddr_ = tape->Rec_.put_dyn_par( result.value_, local::div_dyn, arg0, arg1 ); result.tape_id_ = tape_id; result.ad_type_ = dynamic_enum; } return result; }
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 ); // 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(j); for(size_t k = 1; k <= j; k++) { px[k] += pz_4[j] * z_3[j-k] * Base(k); pz_3[j-k] += pz_4[j] * x[k] * Base(k); } j--; } px[0] += pz_4[0] * z_3[0]; // z_3 = (2 / sqrt(pi)) * exp( - x * x ) addr[0] = arg[2]; // 2 / sqrt(pi) addr[1] = 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] = 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 ); }
AD<Base>& AD<Base>::operator -= (const AD<Base> &right) { ADTape<Base> *tape = AD<Base>::tape_ptr(); size_t tape_id = 0; if( tape != CPPAD_NULL ) tape_id = tape->id_; // id_ setting for parameters cannot match 0 bool var_left = id_ == tape_id; bool var_right = right.id_ == tape_id; CPPAD_ASSERT_KNOWN( Parameter(*this) || var_left , "-=: left operand is a variable for a different thread" ); CPPAD_ASSERT_KNOWN( Parameter(right) || var_right , "-=: right operand is a variable for a different thread" ); Base left; left = value_; value_ -= right.value_; if( var_left ) { if( var_right ) { // this = variable - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(taddr_, right.taddr_); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubvvOp); // make this a variable CPPAD_ASSERT_UNKNOWN( id_ == tape_id ); } else if( IdenticalZero( right.value_ ) ) { // this = variable - 0 } else { // this = variable - parameter CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(right.value_); tape->Rec_.PutArg(taddr_, p); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubvpOp); // make this a variable CPPAD_ASSERT_UNKNOWN( id_ == tape_id ); } } else if( var_right ) { // this = parameter - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(left); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubpvOp); // make this a variable id_ = tape_id; } return *this; }
AD<Base> operator + (const AD<Base> &left , const AD<Base> &right) { // compute the Base part of this AD object AD<Base> result; result.value_ = left.value_ + right.value_; CPPAD_ASSERT_UNKNOWN( Parameter(result) ); // 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_left = left.tape_id_ == tape_id; bool var_right = right.tape_id_ == tape_id; if( var_left ) { if( var_right ) { // result = variable + variable CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(left.taddr_, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(AddvvOp); // make result a variable result.tape_id_ = tape_id; } else if( IdenticalZero(right.value_) ) { // result = variable + 0 result.make_variable(left.tape_id_, left.taddr_); } else { // result = variable + parameter // = parameter + variable CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(right.value_); tape->Rec_.PutArg(p, left.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(AddpvOp); // make result a variable result.tape_id_ = tape_id; } } else if( var_right ) { if( IdenticalZero(left.value_) ) { // result = 0 + variable result.make_variable(right.tape_id_, right.taddr_); } else { // result = parameter + variable CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(left.value_); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(AddpvOp); // make result a variable result.tape_id_ = tape_id; } } return result; }
// case where x and y are AD<Base> ----------------------------------------- template <class Base> AD<Base> pow(const AD<Base> &x, const AD<Base> &y) { ADTape<Base> *tape = AD<Base>::tape_ptr(); bool var_x, var_y; # ifdef NDEBUG if( tape == CPPAD_NULL ) { var_x = false; var_y = false; } else { var_x = x.id_ == tape->id_; var_y = y.id_ == tape->id_; } # else var_x = Variable(x); var_y = Variable(y); CPPAD_ASSERT_KNOWN( (! var_x) || x.id_ == tape->id_ , "pow first operand is a variable for a different thread" ); CPPAD_ASSERT_KNOWN( (! var_y) || y.id_ == tape->id_ , "pow second operand is a variable for a different thread" ); # endif AD<Base> result; result.value_ = pow(x.value_, y.value_); CPPAD_ASSERT_UNKNOWN( Parameter(result) ); if( var_x ) { if( var_y ) { // result = variable^variable CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(x.taddr_, y.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(PowvvOp); // make result a variable result.id_ = tape->id_; } else if( IdenticalZero( y.value_ ) ) { // result = variable^0 } else { // result = variable^parameter CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 ); CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 ); // put operand addresses in tape size_t p = tape->Rec_.PutPar(y.value_); tape->Rec_.PutArg(x.taddr_, p); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(PowvpOp); // make result a variable result.id_ = tape->id_; } } else if( var_y ) { if( IdenticalZero(x.value_) ) { // result = 0^variable } else { // result = variable^parameter CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 ); CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 ); // put operand addresses in tape size_t p = tape->Rec_.PutPar(x.value_); tape->Rec_.PutArg(p, y.taddr_); // put operator in the tape result.taddr_ = tape->Rec_.PutOp(PowpvOp); // make result a variable result.id_ = tape->id_; } } return result; }
void forward_cskip_op_0( size_t i_z , const addr_t* arg , size_t num_par , const Base* parameter , size_t cap_order , Base* taylor , bool* cskip_op ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < size_t(CompareNe) ); CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); Base left, right; if( arg[1] & 1 ) { // If variable arg[2] <= i_z, it has already been computed, // but it will be skipped for higher orders. CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) <= i_z ); left = taylor[ size_t(arg[2]) * cap_order + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); left = parameter[ arg[2] ]; } if( arg[1] & 2 ) { // If variable arg[3] <= i_z, it has already been computed, // but it will be skipped for higher orders. CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) <= i_z ); right = taylor[ size_t(arg[3]) * cap_order + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); right = parameter[ arg[3] ]; } bool ok_to_skip = IdenticalCon(left) & IdenticalCon(right); if( ! ok_to_skip ) return; // initialize to avoid compiler warning bool true_case = false; Base diff = left - right; switch( CompareOp( arg[0] ) ) { case CompareLt: true_case = LessThanZero(diff); break; case CompareLe: true_case = LessThanOrZero(diff); break; case CompareEq: true_case = IdenticalZero(diff); break; case CompareGe: true_case = GreaterThanOrZero(diff); break; case CompareGt: true_case = GreaterThanZero(diff); break; case CompareNe: true_case = ! IdenticalZero(diff); break; default: CPPAD_ASSERT_UNKNOWN(false); } if( true_case ) { for(addr_t i = 0; i < arg[4]; i++) cskip_op[ arg[6+i] ] = true; } else { for(addr_t i = 0; i < arg[5]; i++) cskip_op[ arg[6+arg[4]+i] ] = true; } return; }
CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION bool IdenticalZero(const AD<Base> &x) { return Parameter(x) && IdenticalZero(x.value_); }
AD<Base>& AD<Base>::operator -= (const AD<Base> &right) { // compute the Base part Base left; left = value_; value_ -= right.value_; // check if there is a recording in progress ADTape<Base>* tape = AD<Base>::tape_ptr(); if( tape == CPPAD_NULL ) return *this; 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_left = tape_id_ == tape_id; bool var_right = right.tape_id_ == tape_id; if( var_left ) { if( var_right ) { // this = variable - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); // put operand addresses in tape tape->Rec_.PutArg(taddr_, right.taddr_); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubvvOp); // make this a variable CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); } else if( IdenticalZero( right.value_ ) ) { // this = variable - 0 } else { // this = variable - parameter CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(right.value_); tape->Rec_.PutArg(taddr_, p); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubvpOp); // make this a variable CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); } } else if( var_right ) { // this = parameter - variable CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); // put operand addresses in tape addr_t p = tape->Rec_.PutPar(left); tape->Rec_.PutArg(p, right.taddr_); // put operator in the tape taddr_ = tape->Rec_.PutOp(SubpvOp); // make this a variable tape_id_ = tape_id; } return *this; }