void ad(size_t id, const ADVector& ax, ADVector& ay) { size_t i, j, k; size_t n = ax.size(); size_t m = ay.size(); size_t thread = thread_alloc::thread_num(); # ifndef NDEBUG bool ok; std::string msg = "user_atomoc: "; # endif vector <Base>& x = x_[thread]; vector <Base>& y = y_[thread]; vector <bool>& vx = vx_[thread]; vector <bool>& vy = vy_[thread]; // if( x.size() < n ) { x.resize(n); vx.resize(n); } if( y.size() < m ) { y.resize(m); vy.resize(m); } // // Determine if we are going to have to tape this operation tape_id_t tape_id = 0; ADTape<Base>* tape = CPPAD_NULL; for(j = 0; j < n; j++) { x[j] = ax[j].value_; vx[j] = Variable( ax[j] ); if ( (tape == CPPAD_NULL) & vx[j] ) { tape = ax[j].tape_this(); tape_id = ax[j].tape_id_; } # ifndef NDEBUG ok = (tape_id == 0) | Parameter(ax[j]); ok |= (tape_id == ax[j].tape_id_); if( ! ok ) { msg = msg + name_ + ": ax contains variables from different threads."; CPPAD_ASSERT_KNOWN(false, msg.c_str()); } # endif } // Use zero order forward mode to compute values k = 0; # if NDEBUG f_(id, k, n, m, vx, vy, x, y); # else ok = f_(id, k, n, m, vx, vy, x, y); if( ! ok ) { msg = msg + name_ + ": ok returned false from " "zero order forward mode calculation."; CPPAD_ASSERT_KNOWN(false, msg.c_str()); } # endif // pass back values for(i = 0; i < m; i++) { ay[i].value_ = y[i]; // initialize entire vector as a constant (not on tape) ay[i].tape_id_ = 0; ay[i].taddr_ = 0; } // if tape is not null, ay is on the tape if( tape != CPPAD_NULL ) { // Note the actual number of results is m CPPAD_ASSERT_UNKNOWN( NumRes(UserOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UserOp) == 4 ); // Begin operators corresponding to one user_atomic operation. // Put function index, domain size, range size, and id in tape tape->Rec_.PutArg(index_, id, n, m); tape->Rec_.PutOp(UserOp); // n + m operators follow for this one atomic operation // Now put the information for the argument vector in the tape CPPAD_ASSERT_UNKNOWN( NumRes(UsravOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrapOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsravOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsrapOp) == 1 ); for(j = 0; j < n; j++) { if( vx[j] ) { // information for an argument that is a variable tape->Rec_.PutArg(ax[j].taddr_); tape->Rec_.PutOp(UsravOp); } else { // information for an arugment that is parameter addr_t p = tape->Rec_.PutPar(ax[j].value_); tape->Rec_.PutArg(p); tape->Rec_.PutOp(UsrapOp); } } // Now put the information for the results in the tape CPPAD_ASSERT_UNKNOWN( NumArg(UsrrpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrrpOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrrvOp) == 1 ); for(i = 0; i < m; i++) { if( vy[i] ) { ay[i].taddr_ = tape->Rec_.PutOp(UsrrvOp); ay[i].tape_id_ = tape_id; } else { addr_t p = tape->Rec_.PutPar(ay[i].value_); tape->Rec_.PutArg(p); tape->Rec_.PutOp(UsrrpOp); } } // Put a duplicate UserOp at end of UserOp sequence tape->Rec_.PutArg(index_, id, n, m); tape->Rec_.PutOp(UserOp); } return; }
void operator()( const ADVector& ax , ADVector& ay , size_t id = 0 ) { size_t i, j; size_t n = ax.size(); size_t m = ay.size(); # ifndef NDEBUG bool ok; std::string msg = "atomic_base: " + afun_name() + ".eval: "; if( (n == 0) | (m == 0) ) { msg += "ax.size() or ay.size() is zero"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif size_t thread = thread_alloc::thread_num(); vector <Base>& tx = afun_tx_[thread]; vector <Base>& ty = afun_ty_[thread]; vector <bool>& vx = afun_vx_[thread]; vector <bool>& vy = afun_vy_[thread]; // if( vx.size() != n ) { vx.resize(n); tx.resize(n); } if( vy.size() != m ) { vy.resize(m); ty.resize(m); } // // Determine tape corresponding to variables in ax tape_id_t tape_id = 0; ADTape<Base>* tape = CPPAD_NULL; for(j = 0; j < n; j++) { tx[j] = ax[j].value_; vx[j] = Variable( ax[j] ); if( vx[j] ) { if( tape_id == 0 ) { tape = ax[j].tape_this(); tape_id = ax[j].tape_id_; CPPAD_ASSERT_UNKNOWN( tape != CPPAD_NULL ); } # ifndef NDEBUG if( tape_id != ax[j].tape_id_ ) { msg += afun_name() + ": ax contains variables from different threads."; CPPAD_ASSERT_KNOWN(false, msg.c_str()); } # endif } } // Use zero order forward mode to compute values size_t q = 0, p = 0; set_id(id); # ifdef NDEBUG forward(q, p, vx, vy, tx, ty); # else ok = forward(q, p, vx, vy, tx, ty); if( ! ok ) { msg += afun_name() + ": ok is false for " "zero order forward mode calculation."; CPPAD_ASSERT_KNOWN(false, msg.c_str()); } # endif bool record_operation = false; for(i = 0; i < m; i++) { // pass back values ay[i].value_ = ty[i]; // initialize entire vector parameters (not in tape) ay[i].tape_id_ = 0; ay[i].taddr_ = 0; // we need to record this operation if // any of the eleemnts of ay are variables, record_operation |= vy[i]; } # ifndef NDEBUG if( record_operation & (tape == CPPAD_NULL) ) { msg += "all elements of vx are false but vy contains a true element"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif // if tape is not null, ay is on the tape if( record_operation ) { // Operator that marks beginning of this atomic operation CPPAD_ASSERT_UNKNOWN( NumRes(UserOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UserOp) == 4 ); tape->Rec_.PutArg(index_, id, n, m); tape->Rec_.PutOp(UserOp); // Now put n operators, one for each element of arugment vector CPPAD_ASSERT_UNKNOWN( NumRes(UsravOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrapOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsravOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsrapOp) == 1 ); for(j = 0; j < n; j++) { if( vx[j] ) { // information for an argument that is a variable tape->Rec_.PutArg(ax[j].taddr_); tape->Rec_.PutOp(UsravOp); } else { // information for an arugment that is parameter addr_t par = tape->Rec_.PutPar(ax[j].value_); tape->Rec_.PutArg(par); tape->Rec_.PutOp(UsrapOp); } } // Now put m operators, one for each element of result vector CPPAD_ASSERT_UNKNOWN( NumArg(UsrrpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrrpOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 ); CPPAD_ASSERT_UNKNOWN( NumRes(UsrrvOp) == 1 ); for(i = 0; i < m; i++) { if( vy[i] ) { ay[i].taddr_ = tape->Rec_.PutOp(UsrrvOp); ay[i].tape_id_ = tape_id; } else { addr_t par = tape->Rec_.PutPar(ay[i].value_); tape->Rec_.PutArg(par); tape->Rec_.PutOp(UsrrpOp); } } // Put a duplicate UserOp at end of UserOp sequence tape->Rec_.PutArg(index_, id, n, m); tape->Rec_.PutOp(UserOp); } return; }