CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION bool IdenticalOne(const AD<Base> &x) { return Parameter(x) && IdenticalOne(x.value_); }
// 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 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; }
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; }