void RevJacSweep( bool nz_compare, size_t n, size_t numvar, 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() ); } // work space used by UserOp. typedef std::set<size_t> size_set; size_set::iterator set_itr; // iterator for a standard set size_set::iterator set_end; // end of iterator sequence vector< size_set > set_r; // set sparsity pattern for the argument x vector< size_set > set_s; // set sparisty pattern for the result y // vector<bool> bool_r; // bool sparsity pattern for the argument x vector<bool> bool_s; // bool sparisty pattern for the result y // const size_t user_q = limit; // maximum element plus one size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator bool user_bool = false; // use bool or set sparsity ? # ifndef NDEBUG bool user_ok = false; // atomic op return value # endif // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end } user_state = user_end; // 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) { // 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; // ------------------------------------------------- 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; // ------------------------------------------------- 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; // ------------------------------------------------- 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( nz_compare, 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 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; // ------------------------------------------------- case InvOp: CPPAD_ASSERT_NARG_NRES(op, 0, 1); break; // ------------------------------------------------- case LdpOp: reverse_sparse_jacobian_load_op( op, i_var, arg, num_vecad_ind, vecad_ind.data(), var_sparsity, vecad_sparsity ); break; // ------------------------------------------------- case LdvOp: reverse_sparse_jacobian_load_op( 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; // ------------------------------------------------- case MulvvOp: CPPAD_ASSERT_NARG_NRES(op, 2, 1); reverse_sparse_jacobian_binary_op( i_var, arg, var_sparsity ); break; // ------------------------------------------------- case MulpvOp: CPPAD_ASSERT_NARG_NRES(op, 2, 1); reverse_sparse_jacobian_unary_op( i_var, arg[1], 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 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: // sparsity cannot proagate through a parameter CPPAD_ASSERT_NARG_NRES(op, 3, 0); break; // ------------------------------------------------- case StpvOp: reverse_sparse_jacobian_store_op( op, arg, num_vecad_ind, vecad_ind.data(), var_sparsity, vecad_sparsity ); break; // ------------------------------------------------- case StvpOp: CPPAD_ASSERT_NARG_NRES(op, 3, 0); break; // ------------------------------------------------- case StvvOp: reverse_sparse_jacobian_store_op( 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: // start or end atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_end ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif user_bool = user_atom->sparsity() == atomic_base<Base>::bool_sparsity_enum; if( user_bool ) { if( bool_r.size() != user_m * user_q ) bool_r.resize( user_m * user_q ); if( bool_s.size() != user_n * user_q ) bool_s.resize( user_n * user_q ); for(i = 0; i < user_m; i++) for(j = 0; j < user_q; j++) bool_r[ i * user_q + j] = false; } else { if(set_r.size() != user_m ) set_r.resize(user_m); if(set_s.size() != user_n ) set_s.resize(user_n); for(i = 0; i < user_m; i++) set_r[i].clear(); } user_j = user_n; user_i = user_m; user_state = user_ret; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_start ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); # ifndef NDEBUG if( ! user_ok ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base.rev_sparse_jac: returned false"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif user_state = user_end; } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j <= user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); --user_j; if( user_j == 0 ) user_state = user_start; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j <= user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); --user_j; // It might be faster if we add set union to var_sparsity // where one of the sets is not in var_sparsity. if( user_bool ) { for(j = 0; j < user_q; j++) if( bool_s[ user_j * user_q + j ] ) var_sparsity.add_element(arg[0], j); } else { set_itr = set_s[user_j].begin(); set_end = set_s[user_j].end(); while( set_itr != set_end ) var_sparsity.add_element(arg[0], *set_itr++); } if( user_j == 0 ) user_state = user_start; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i <= user_m ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); --user_i; if( user_i == 0 ) { // call users function for this operation user_atom->set_id(user_id); if( user_bool) CPPAD_ATOMIC_CALL( user_q, bool_r, bool_s ); else CPPAD_ATOMIC_CALL( user_q, set_r, set_s ); user_state = user_arg; } break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i <= user_m ); --user_i; var_sparsity.begin(i_var); i = var_sparsity.next_element(); while( i < user_q ) { if( user_bool ) bool_r[ user_i * user_q + i ] = true; else set_r[user_i].insert(i); i = var_sparsity.next_element(); } if( user_i == 0 ) { // call users function for this operation user_atom->set_id(user_id); if( user_bool) CPPAD_ATOMIC_CALL( user_q, bool_r, bool_s ); else CPPAD_ATOMIC_CALL( user_q, set_r, set_s ); user_state = user_arg; } break; // ------------------------------------------------- default: CPPAD_ASSERT_UNKNOWN(0); } # if CPPAD_REV_JAC_SWEEP_TRACE for(j = 0; j < limit; j++) z_value[j] = false; var_sparsity.begin(i_var); j = var_sparsity.next_element(); while( j < limit ) { z_value[j] = true; j = var_sparsity.next_element(); } printOp( std::cout, play, i_op, i_var, op, arg ); 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 }
void optimize( size_t n , CppAD::vector<size_t>& dep_taddr , player<Base>* play , recorder<Base>* rec ) { // temporary indices size_t i, j, k; // temporary variables OpCode op; // current operator const size_t *arg; // operator arguments size_t i_var; // index of first result for current operator // range and domain dimensions for F size_t m = dep_taddr.size(); // number of variables in the player const size_t num_var = play->num_rec_var(); // number of VecAD indices size_t num_vecad_ind = play->num_rec_vecad_ind(); // number of VecAD vectors size_t num_vecad_vec = play->num_rec_vecad_vec(); // ------------------------------------------------------------- // data structure that maps variable index in original operation // sequence to corresponding operator information CppAD::vector<struct optimize_old_variable> tape(num_var); // ------------------------------------------------------------- // Determine how each variable is connected to the dependent variables // initialize all variables has having no connections for(i = 0; i < num_var; i++) tape[i].connect = not_connected; for(j = 0; j < m; j++) { // mark dependent variables as having one or more connections tape[ dep_taddr[j] ].connect = yes_connected; } // vecad_connect contains a value for each VecAD object. // vecad maps a VecAD index (which corresponds to the beginning of the // VecAD object) to the vecad_connect falg for the VecAD object. CppAD::vector<optimize_connection> vecad_connect(num_vecad_vec); CppAD::vector<size_t> vecad(num_vecad_ind); j = 0; for(i = 0; i < num_vecad_vec; i++) { vecad_connect[i] = not_connected; // length of this VecAD size_t length = play->GetVecInd(j); // set to proper index for this VecAD vecad[j] = i; for(k = 1; k <= length; k++) vecad[j+k] = num_vecad_vec; // invalid index // start of next VecAD j += length + 1; } CPPAD_ASSERT_UNKNOWN( j == num_vecad_ind ); // Initialize a reverse mode sweep through the operation sequence size_t i_op; play->start_reverse(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( op == EndOp ); size_t mask; while(op != BeginOp) { // next op play->next_reverse(op, arg, i_op, i_var); // This if is not necessary becasue last assignment // with this value of i_var will have NumRes(op) > 0 if( NumRes(op) > 0 ) { tape[i_var].op = op; tape[i_var].arg = arg; } # ifndef NDEBUG if( i_op <= n ) { CPPAD_ASSERT_UNKNOWN((op == InvOp) | (op == BeginOp)); } else CPPAD_ASSERT_UNKNOWN((op != InvOp) & (op != BeginOp)); # endif switch( op ) { // Unary operator where operand is arg[0] case AbsOp: case AcosOp: case AsinOp: case AtanOp: case CosOp: case CoshOp: case DisOp: case DivvpOp: case ExpOp: case LogOp: case PowvpOp: case SinOp: case SinhOp: case SqrtOp: if( tape[i_var].connect != not_connected ) tape[arg[0]].connect = yes_connected; break; // -------------------------------------------- // Unary operator where operand is arg[1] case DivpvOp: case MulpvOp: case PowpvOp: case PrivOp: if( tape[i_var].connect != not_connected ) tape[arg[1]].connect = yes_connected; break; // -------------------------------------------- // Special case for SubvpOp case SubvpOp: if( tape[i_var].connect != not_connected ) { if( tape[arg[0]].connect == not_connected ) tape[arg[0]].connect = sum_connected; else tape[arg[0]].connect = yes_connected; if( tape[i_var].connect == sum_connected ) tape[i_var].connect = csum_connected; } break; // -------------------------------------------- // Special case for AddpvOp and SubpvOp case AddpvOp: case SubpvOp: if( tape[i_var].connect != not_connected ) { if( tape[arg[1]].connect == not_connected ) tape[arg[1]].connect = sum_connected; else tape[arg[1]].connect = yes_connected; if( tape[i_var].connect == sum_connected ) tape[i_var].connect = csum_connected; } break; // -------------------------------------------- // Special case for AddvvOp and SubvvOp case AddvvOp: case SubvvOp: if( tape[i_var].connect != not_connected ) { if( tape[arg[0]].connect == not_connected ) tape[arg[0]].connect = sum_connected; else tape[arg[0]].connect = yes_connected; if( tape[arg[1]].connect == not_connected ) tape[arg[1]].connect = sum_connected; else tape[arg[1]].connect = yes_connected; if( tape[i_var].connect == sum_connected ) tape[i_var].connect = csum_connected; } break; // -------------------------------------------- // Other binary operators // where operands are arg[0], arg[1] case DivvvOp: case MulvvOp: case PowvvOp: if( tape[i_var].connect != not_connected ) { tape[arg[0]].connect = yes_connected; tape[arg[1]].connect = yes_connected; } break; // -------------------------------------------- // Conditional expression operators case CExpOp: CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); if( tape[i_var].connect != not_connected ) { mask = 1; for(i = 2; i < 6; i++) { if( arg[1] & mask ) { CPPAD_ASSERT_UNKNOWN( arg[i] < i_var ); tape[arg[i]].connect = yes_connected; } mask = mask << 1; } } break; // -------------------------------------------- // Operations where there is noting to do case BeginOp: case ComOp: case EndOp: case InvOp: case ParOp: case PripOp: case StppOp: break; // -------------------------------------------- // Load using a parameter index case LdpOp: if( tape[i_var].connect != not_connected ) { i = vecad[ arg[0] - 1 ]; vecad_connect[i] = yes_connected; } break; // -------------------------------------------- // Load using a variable index case LdvOp: if( tape[i_var].connect != not_connected ) { i = vecad[ arg[0] - 1 ]; vecad_connect[i] = yes_connected; tape[arg[1]].connect = yes_connected; } break; // -------------------------------------------- // Store a variable using a parameter index case StpvOp: i = vecad[ arg[0] - 1 ]; if( vecad_connect[i] != not_connected ) tape[arg[2]].connect = yes_connected; break; // -------------------------------------------- // Store a variable using a variable index case StvvOp: i = vecad[ arg[0] - 1 ]; if( vecad_connect[i] ) { tape[arg[1]].connect = yes_connected; tape[arg[2]].connect = yes_connected; } break; // -------------------------------------------- // all cases should be handled above default: CPPAD_ASSERT_UNKNOWN(0); } } // values corresponding to BeginOp CPPAD_ASSERT_UNKNOWN( i_op == 0 && i_var == 0 && op == BeginOp ); tape[i_var].op = op; // ------------------------------------------------------------- // Erase all information in the recording rec->Erase(); // Initilaize table mapping hash code to variable index in tape // as pointing to the BeginOp at the beginning of the tape CppAD::vector<size_t> hash_table_var(CPPAD_HASH_TABLE_SIZE); for(i = 0; i < CPPAD_HASH_TABLE_SIZE; i++) hash_table_var[i] = 0; CPPAD_ASSERT_UNKNOWN( tape[0].op == BeginOp ); // initialize mapping from old variable index to new variable index for(i = 0; i < num_var; i++) tape[i].new_var = num_var; // invalid index // initialize mapping from old VecAD index to new VecAD index CppAD::vector<size_t> new_vecad_ind(num_vecad_ind); for(i = 0; i < num_vecad_ind; i++) new_vecad_ind[i] = num_vecad_ind; // invalid index j = 0; // index into the old set of indices for(i = 0; i < num_vecad_vec; i++) { // length of this VecAD size_t length = play->GetVecInd(j); if( vecad_connect[i] != not_connected ) { // Put this VecAD vector in new recording CPPAD_ASSERT_UNKNOWN(length < num_vecad_ind); new_vecad_ind[j] = rec->PutVecInd(length); for(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 ); // start playing the operations in the forward direction play->start_forward(op, arg, i_op, i_var); // playing forward skips BeginOp at the beginning, but not EndOp at // the end. Put BeginOp at beginning of recording CPPAD_ASSERT_UNKNOWN( op == BeginOp ); CPPAD_ASSERT_NARG_NRES(BeginOp, 0, 1); tape[i_var].new_var = rec->PutOp(BeginOp); // temporary buffer for new argument values size_t new_arg[6]; // temporary work space used by optimize_record_csum // (decalared here to avoid realloaction of memory) optimize_csum_stacks csum_work; while(op != EndOp) { // next op play->next_forward(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) ); CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); // determine if we should keep this operation in the new // operation sequence bool keep; switch( op ) { case ComOp: case PripOp: case PrivOp: keep = false; break; case InvOp: case EndOp: keep = true; break; case StppOp: case StvpOp: case StpvOp: case StvvOp: CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); i = vecad[ arg[0] - 1 ]; keep = vecad_connect[i] != not_connected; break; case AddpvOp: case AddvvOp: case SubpvOp: case SubvpOp: case SubvvOp: keep = tape[i_var].connect != not_connected; keep &= tape[i_var].connect != csum_connected; break; default: keep = tape[i_var].connect != not_connected; break; } size_t match_var = 0; unsigned short code = 0; bool replace_hash = false; if( keep ) switch( op ) { // Unary operator where operand is arg[0] case AbsOp: case AcosOp: case AsinOp: case AtanOp: case CosOp: case CoshOp: case DisOp: case ExpOp: case LogOp: case SinOp: case SinhOp: case SqrtOp: match_var = optimize_unary_match( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , hash_table_var , code // outputs ); if( match_var > 0 ) tape[i_var].new_var = match_var; else { replace_hash = true; new_arg[0] = tape[ arg[0] ].new_var; rec->PutArg( new_arg[0] ); i = rec->PutOp(op); tape[i_var].new_var = i; CPPAD_ASSERT_UNKNOWN( new_arg[0] < i ); } break; // --------------------------------------------------- // Binary operators where // left is a variable and right is a parameter case SubvpOp: if( tape[arg[0]].connect == csum_connected ) { // convert to a sequence of summation operators tape[i_var].new_var = optimize_record_csum( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , csum_work ); // abort rest of this case break; } case DivvpOp: case PowvpOp: match_var = optimize_binary_match( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , hash_table_var , code // outputs ); if( match_var > 0 ) tape[i_var].new_var = match_var; else { tape[i_var].new_var = optimize_record_vp( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , op , arg ); replace_hash = true; } break; // --------------------------------------------------- // Binary operators where // left is a parameter and right is a variable case SubpvOp: case AddpvOp: if( tape[arg[1]].connect == csum_connected ) { // convert to a sequence of summation operators tape[i_var].new_var = optimize_record_csum( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , csum_work ); // abort rest of this case break; } case DivpvOp: case MulpvOp: case PowpvOp: match_var = optimize_binary_match( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , hash_table_var , code // outputs ); if( match_var > 0 ) tape[i_var].new_var = match_var; else { tape[i_var].new_var = optimize_record_pv( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , op , arg ); replace_hash = true; } break; // --------------------------------------------------- // Binary operator where // both operators are variables case AddvvOp: case SubvvOp: if( (tape[arg[0]].connect == csum_connected) | (tape[arg[1]].connect == csum_connected) ) { // convert to a sequence of summation operators tape[i_var].new_var = optimize_record_csum( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , csum_work ); // abort rest of this case break; } case DivvvOp: case MulvvOp: case PowvvOp: match_var = optimize_binary_match( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , hash_table_var , code // outputs ); if( match_var > 0 ) tape[i_var].new_var = match_var; else { tape[i_var].new_var = optimize_record_vv( tape , // inputs i_var , play->num_rec_par() , play->GetPar() , rec , op , arg ); replace_hash = true; } 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(i = 2; i < 6; i++) { if( arg[1] & mask ) { new_arg[i] = tape[arg[i]].new_var; CPPAD_ASSERT_UNKNOWN( 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] ); tape[i_var].new_var = rec->PutOp(op); break; // --------------------------------------------------- // Operations with no arguments and no results case EndOp: CPPAD_ASSERT_NARG_NRES(op, 0, 0); rec->PutOp(op); break; // --------------------------------------------------- // Operations with no arguments and one result case InvOp: CPPAD_ASSERT_NARG_NRES(op, 0, 1); tape[i_var].new_var = rec->PutOp(op); break; // --------------------------------------------------- // Operations with one argument that is a parameter case ParOp: CPPAD_ASSERT_NARG_NRES(op, 1, 1); new_arg[0] = rec->PutPar( play->GetPar(arg[0] ) ); rec->PutArg( new_arg[0] ); tape[i_var].new_var = rec->PutOp(op); break; // --------------------------------------------------- // 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( new_arg[0] < num_vecad_ind ); rec->PutArg( new_arg[0], new_arg[1], 0 ); tape[i_var].new_var = rec->PutOp(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] = tape[arg[1]].new_var; CPPAD_ASSERT_UNKNOWN( new_arg[0] < num_vecad_ind ); CPPAD_ASSERT_UNKNOWN( new_arg[1] < num_var ); rec->PutArg( new_arg[0], new_arg[1], 0 ); tape[i_var].new_var = rec->PutOp(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( new_arg[0] < num_vecad_ind ); rec->PutArg( new_arg[0], new_arg[1], new_arg[2] ); 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] = tape[arg[1]].new_var; new_arg[2] = rec->PutPar( play->GetPar(arg[2]) ); CPPAD_ASSERT_UNKNOWN( new_arg[0] < num_vecad_ind ); CPPAD_ASSERT_UNKNOWN( new_arg[1] < num_var ); rec->PutArg( new_arg[0], new_arg[1], new_arg[2] ); 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] = tape[arg[2]].new_var; CPPAD_ASSERT_UNKNOWN( new_arg[0] < num_vecad_ind ); CPPAD_ASSERT_UNKNOWN( new_arg[1] < num_var ); CPPAD_ASSERT_UNKNOWN( new_arg[2] < num_var ); rec->PutArg( new_arg[0], new_arg[1], new_arg[2] ); 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] = tape[arg[1]].new_var; new_arg[2] = tape[arg[2]].new_var; CPPAD_ASSERT_UNKNOWN( new_arg[0] < num_vecad_ind ); CPPAD_ASSERT_UNKNOWN( new_arg[1] < num_var ); CPPAD_ASSERT_UNKNOWN( new_arg[2] < num_var ); rec->PutArg( new_arg[0], new_arg[1], new_arg[2] ); rec->PutOp(op); break; // --------------------------------------------------- // all cases should be handled above default: CPPAD_ASSERT_UNKNOWN(false); } if( replace_hash ) { // The old variable index i_var corresponds to the // new variable index tape[i_var].new_var. In addition // this is the most recent variable that has this code. hash_table_var[code] = i_var; } } // modify the dependent variable vector to new indices for(i = 0; i < dep_taddr.size(); i++ ) { CPPAD_ASSERT_UNKNOWN( tape[ dep_taddr[i] ].new_var < num_var ); dep_taddr[i] = tape[ dep_taddr[i] ].new_var; } }
inline void reverse_asin_op( size_t d , size_t i_z , size_t i_x , size_t nc_taylor , 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( i_x + 1 < i_z ); CPPAD_ASSERT_UNKNOWN( d < nc_taylor ); CPPAD_ASSERT_UNKNOWN( d < nc_partial ); // Taylor coefficients and partials corresponding to argument const Base* x = taylor + i_x * nc_taylor; Base* px = partial + i_x * nc_partial; // Taylor coefficients and partials corresponding to first result const Base* z = taylor + i_z * nc_taylor; Base* pz = partial + i_z * nc_partial; // Taylor coefficients and partials corresponding to auxillary result const Base* b = z - nc_taylor; // called y in documentation Base* pb = pz - nc_partial; // 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] /= b[0]; // scale partials w.r.t z[j] by 1 / b[0] pz[j] /= b[0]; // update partials w.r.t b^0 pb[0] -= pz[j] * z[j] + pb[j] * b[j]; // update partial w.r.t. x^0 px[0] -= pb[j] * x[j]; // update partial w.r.t. x^j px[j] += pz[j] - 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) * pz[j] * z[k] + pb[j] * b[k]; // update partials w.r.t. x^k px[k] -= pb[j] * x[j-k]; // update partials w.r.t. z^k pz[k] -= pz[j] * Base(k) * b[j-k]; } --j; } // j == 0 case px[0] += ( pz[0] - pb[0] * x[0]) / b[0]; }
void ADTape<Base>::RecordCondExp( enum CompareOp cop , AD<Base> &returnValue , const AD<Base> &left , const AD<Base> &right , const AD<Base> &if_true , const AD<Base> &if_false ) { size_t ind0, ind1, ind2, ind3, ind4, ind5; size_t returnValue_taddr; // taddr_ of this variable CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); returnValue_taddr = Rec_.PutOp(CExpOp); // ind[0] = cop ind0 = addr_t( cop ); // ind[1] = base 2 representaion of the value // [Var(left), Var(right), Var(if_true), Var(if_false)] ind1 = 0; // Make sure returnValue is in the list of variables and set its taddr if( Parameter(returnValue) ) returnValue.make_variable(id_, returnValue_taddr ); else returnValue.taddr_ = returnValue_taddr; // ind[2] = left address if( Parameter(left) ) ind2 = Rec_.PutPar(left.value_); else { ind1 += 1; ind2 = left.taddr_; } // ind[3] = right address if( Parameter(right) ) ind3 = Rec_.PutPar(right.value_); else { ind1 += 2; ind3 = right.taddr_; } // ind[4] = if_true address if( Parameter(if_true) ) ind4 = Rec_.PutPar(if_true.value_); else { ind1 += 4; ind4 = if_true.taddr_; } // ind[5] = if_false address if( Parameter(if_false) ) ind5 = Rec_.PutPar(if_false.value_); else { ind1 += 8; ind5 = if_false.taddr_; } CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); CPPAD_ASSERT_UNKNOWN( ind1 > 0 ); Rec_.PutArg(ind0, ind1, ind2, ind3, ind4, ind5); // check that returnValue is a dependent variable CPPAD_ASSERT_UNKNOWN( Variable(returnValue) ); }
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 }
inline void reverse_cond_op( size_t d , size_t i_z , const addr_t* arg , size_t num_par , const Base* parameter , size_t nc_taylor , const Base* taylor , size_t nc_partial , Base* partial ) { Base y_0, y_1; Base zero(0); Base* pz; Base* py_2; Base* py_3; CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast<size_t> (CompareNe) ); CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); pz = partial + i_z * nc_partial + 0; if( arg[1] & 1 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < i_z ); y_0 = taylor[ arg[2] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); y_0 = parameter[ arg[2] ]; } if( arg[1] & 2 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < i_z ); y_1 = taylor[ arg[3] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); y_1 = parameter[ arg[3] ]; } if( arg[1] & 4 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < i_z ); py_2 = partial + arg[4] * nc_partial; size_t j = d + 1; while(j--) { py_2[j] += CondExpOp( CompareOp( arg[0] ), y_0, y_1, pz[j], zero ); } } if( arg[1] & 8 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < i_z ); py_3 = partial + arg[5] * nc_partial; size_t j = d + 1; while(j--) { py_3[j] += CondExpOp( CompareOp( arg[0] ), y_0, y_1, zero, pz[j] ); } } return; }
void for_hes( const local::player<Base>* play, size_t n, size_t numvar, const Vector_set& for_jac_sparse, const Vector_set& rev_jac_sparse, Vector_set& for_hes_sparse, const RecBase& not_used_rec_base ) { // 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; pod_vector<size_t> vecad_ind; pod_vector<bool> vecad_jac; if( num_vecad_vec > 0 ) { size_t length; vecad_sparse.resize(num_vecad_vec, limit); 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() ); } // ------------------------------------------------------------------------ // work space used by AFunOp. vector<Base> atom_x; //// value of parameter arguments to function vector<ad_type_enum> type_x; // argument types pod_vector<size_t> atom_ix; // variable index (on tape) for each argument pod_vector<size_t> atom_iy; // variable index (on tape) for each result // // information set by atomic forward (initialization to avoid warnings) size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; // information set by atomic forward (necessary initialization) enum_atom_state atom_state = start_atom; // ------------------------------------------------------------------------- // // pointer to the beginning of the parameter vector // (used by atomic functions) const Base* parameter = CPPAD_NULL; if( num_par > 0 ) parameter = play->GetPar(); // // which parametes are dynamic const pod_vector<bool>& dyn_par_is( play->dyn_par_is() ); // // skip the BeginOp at the beginning of the recording play::const_sequential_iterator itr = play->begin(); // op_info OpCode op; size_t i_var; const Addr* arg; itr.op_info(op, arg, i_var); CPPAD_ASSERT_UNKNOWN( op == BeginOp ); # if CPPAD_FOR_HES_TRACE vector<size_t> atom_funrp; // parameter index for FunrpOp 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 bool more_operators = true; while(more_operators) { // next op (++itr).op_info(op, arg, i_var); // does the Hessian in question have a non-zero derivative // with respect to this variable bool include = NumRes(op) > 0; if( include ) 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 == AFunOp; include |= op == FunapOp; include |= op == FunavOp; include |= op == FunrpOp; include |= op == FunrvOp; // 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( size_t(arg[0]), for_jac_sparse, for_hes_sparse ); break; // ------------------------------------------------- case CSkipOp: itr.correct_before_increment(); break; // ------------------------------------------------- case CSumOp: itr.correct_before_increment(); 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( size_t(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( size_t(arg[0]), for_jac_sparse, for_hes_sparse ); break; // ------------------------------------------------- // ------------------------------------------------- // logical comparision operators case EqppOp: case EqpvOp: case EqvvOp: case LtppOp: case LtpvOp: case LtvpOp: case LtvvOp: case LeppOp: case LepvOp: case LevpOp: case LevvOp: case NepvOp: case NeppOp: 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( size_t(arg[1]), for_jac_sparse, for_hes_sparse ); break; // ------------------------------------------------- case PowvpOp: CPPAD_ASSERT_NARG_NRES(op, 2, 3) forward_sparse_hessian_nonlinear_unary_op( size_t(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 AFunOp: // start or end an atomic function call CPPAD_ASSERT_UNKNOWN( atom_state == start_atom || atom_state == end_atom ); flag = atom_state == start_atom; play::atom_op_info<RecBase>( op, arg, atom_index, atom_old, atom_m, atom_n ); if( flag ) { atom_state = arg_atom; atom_i = 0; atom_j = 0; // atom_x.resize( atom_n ); type_x.resize( atom_n ); atom_ix.resize( atom_n ); atom_iy.resize( atom_m ); # if CPPAD_FOR_HES_TRACE atom_funrp.resize( atom_m ); # endif } else { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); atom_state = start_atom; // call_atomic_for_hes_sparsity<Base,RecBase>( atom_index, atom_old, atom_x, type_x, atom_ix, atom_iy, for_jac_sparse, rev_jac_sparse, for_hes_sparse ); } break; case FunapOp: // parameter argument for a atomic function CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); // atom_x[atom_j] = parameter[arg[0]]; // argument type if( dyn_par_is[arg[0]] ) type_x[atom_j] = dynamic_enum; else type_x[atom_j] = constant_enum; atom_ix[atom_j] = 0; // special variable used for parameters // ++atom_j; if( atom_j == atom_n ) atom_state = ret_atom; break; case FunavOp: // variable argument for a atomic function CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); // // arguemnt variables not avaialbe during sparisty calculations atom_x[atom_j] = CppAD::numeric_limits<Base>::quiet_NaN(); type_x[atom_j] = variable_enum; atom_ix[atom_j] = size_t(arg[0]); // variable for this argument // ++atom_j; if( atom_j == atom_n ) atom_state = ret_atom; break; case FunrpOp: // parameter result for a atomic function CPPAD_ASSERT_NARG_NRES(op, 1, 0); CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); // atom_iy[atom_i] = 0; // special variable used for parameters # if CPPAD_FOR_HES_TRACE // remember argument for delayed tracing atom_funrp[atom_i] = arg[0]; # endif ++atom_i; if( atom_i == atom_m ) atom_state = end_atom; break; case FunrvOp: // variable result for a atomic function CPPAD_ASSERT_NARG_NRES(op, 0, 1); CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); // atom_iy[atom_i] = i_var; // variable index for this result // ++atom_i; if( atom_i == atom_m ) atom_state = end_atom; 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_TRACE typedef typename Vector_set::const_iterator const_iterator; if( op == AFunOp && atom_state == start_atom ) { // print operators that have been delayed CPPAD_ASSERT_UNKNOWN( atom_m == atom_iy.size() ); CPPAD_ASSERT_UNKNOWN( itr.op_index() > atom_m ); CPPAD_ASSERT_NARG_NRES(FunrpOp, 1, 0); CPPAD_ASSERT_NARG_NRES(FunrvOp, 0, 1); addr_t arg_tmp[1]; for(k = 0; k < atom_m; k++) { size_t k_var = atom_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 = FunrvOp; if( k_var == 0 ) { op_tmp = FunrpOp; arg_tmp[0] = atom_funrp[k]; } // k_var is zero when there is no result printOp<Base, RecBase>( std::cout, play, itr.op_index() - atom_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; } } 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 function call bool delay_print = op == FunrpOp; delay_print |= op == FunrvOp; if( ! delay_print ) { printOp<Base, RecBase>( std::cout, play, itr.op_index(), i_var, op, arg ); if( NumRes(op) > 0 && (! delay_print) ) printOpResult( std::cout, 1, &zf_value, 1, &zh_value ); std::cout << std::endl; } } std::cout << std::endl; # else }
void ForHesSweep( size_t n, size_t numvar, player<Base> *play, Vector_set& for_jac_sparse, // should be const Vector_set& rev_jac_sparse, // should be const 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() ); } // work space used by UserOp. vector<size_t> user_ix; // variable indices for argument vector x vector<Base> user_x; // parameters in x as integers // // typedef std::set<size_t> size_set; vector< size_set > set_h; // forward Hessian sparsity vector<bool> bool_h; // forward Hessian sparsity vectorBool pack_h; // forward Hessian sparstiy // vector<bool> user_vx; // which components of x are variables vector<bool> user_r; // forward Jacobian sparsity for x vector<bool> user_s; // reverse Jacobian sparsity for y // size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator bool user_pack = false; // sparsity pattern type is pack bool user_bool = false; // sparsity pattern type is bool bool user_set = false; // sparsity pattern type is set bool user_ok = false; // atomic op return value // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end } user_state = user_start; // // 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 std::cout << std::endl; CppAD::vectorBool zf_value(limit); CppAD::vectorBool zh_value(limit * limit); # endif 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 == 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->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); 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: // start or end an atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_start ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif user_x.resize( user_n ); // user_pack = user_atom->sparsity() == atomic_base<Base>::pack_sparsity_enum; user_bool = user_atom->sparsity() == atomic_base<Base>::bool_sparsity_enum; user_set = user_atom->sparsity() == atomic_base<Base>::set_sparsity_enum; CPPAD_ASSERT_UNKNOWN( user_pack || user_bool || user_set ); user_ix.resize(user_n); user_vx.resize(user_n); user_r.resize(user_n); user_s.resize(user_m); // simpler to initialize sparsity patterns as empty for(i = 0; i < user_m; i++) user_s[i] = false; for(i = 0; i < user_n; i++) user_r[i] = false; if( user_pack ) { pack_h.resize(user_n * user_n); for(i = 0; i < user_n; i++) { for(j = 0; j < user_n; j++) pack_h[ i * user_n + j] = false; } } if( user_bool ) { bool_h.resize(user_n * user_n); for(i = 0; i < user_n; i++) { for(j = 0; j < user_n; j++) bool_h[ i * user_n + j] = false; } } if( user_set ) { set_h.resize(user_n); for(i = 0; i < user_n; i++) set_h[i].clear(); } user_j = 0; user_i = 0; user_state = user_arg; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); // call users function for this operation user_atom->set_id(user_id); if( user_pack ) { user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, pack_h, user_x ); if( ! user_ok ) user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, pack_h ); } if( user_bool ) { user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, bool_h, user_x ); if( ! user_ok ) user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, bool_h ); } if( user_set ) { user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, set_h, user_x ); if( ! user_ok ) user_ok = user_atom->for_sparse_hes( user_vx, user_r, user_s, set_h ); } if( ! user_ok ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base.for_sparse_hes: returned false\n"; if( user_pack ) msg += "sparsity = pack_sparsity_enum"; if( user_bool ) msg += "sparsity = bool_sparsity_enum"; if( user_set ) msg += "sparsity = set_sparsity_enum"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } for(i = 0; i < user_n; i++) for(j = 0; j < user_n; j++) { if( user_ix[i] > 0 && user_ix[j] > 0 ) { bool flag = false; if( user_pack ) flag = pack_h[i * user_n + j]; if( user_bool ) flag = bool_h[i * user_n + j]; if( user_set ) flag = set_h[i].find(j) != set_h[i].end(); if( flag ) { size_t i_x = user_ix[i]; size_t j_x = user_ix[j]; for_hes_sparse.binary_union( i_x, i_x, j_x, for_jac_sparse ); for_hes_sparse.binary_union( j_x, j_x, i_x, for_jac_sparse ); } } } // user_state = user_start; } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); user_ix[user_j] = 0; user_vx[user_j] = false; // // parameters as integers user_x[user_j] = parameter[arg[0]]; // ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); user_ix[user_j] = arg[0]; user_vx[user_j] = true; // variables as integers user_x[user_j] = CppAD::numeric_limits<Base>::quiet_NaN(); // for_jac_sparse.begin(arg[0]); i = for_jac_sparse.next_element(); if( i < for_jac_sparse.end() ) user_r[user_j] = true; ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); ++user_i; if( user_i == user_m ) user_state = user_end; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); if( rev_jac_sparse.is_element(i_var, 0) ) user_s[user_i] = true; ++user_i; if( user_i == user_m ) user_state = user_end; 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 if( include ) { for(i = 0; i < limit; i++) { zf_value[i] = false; for(j = 0; j < limit; j++) zh_value[i * limit + j] = false; } for_jac_sparse.begin(i_var);; j = for_jac_sparse.next_element();; while( j < limit ) { zf_value[j] = true; j = for_jac_sparse.next_element(); } for(i = 0; i < limit; i++) { for_hes_sparse.begin(i);; j = for_hes_sparse.next_element();; while( j < limit ) { zh_value[i * limit + j] = true; j = for_hes_sparse.next_element(); } } 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 }
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; }
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 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 //); } } } 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 // ); } } } # else }
size_t forward_sweep( std::ostream& s_out, bool print, size_t d, size_t n, size_t numvar, player<Base> *Rec, size_t J, Base *Taylor ) { CPPAD_ASSERT_UNKNOWN( J >= d + 1 ); // op code for current instruction OpCode op; // index for current instruction size_t i_op; // next variables size_t i_var; CPPAD_ASSERT_UNKNOWN( d == 0 || ! print ); # if CPPAD_USE_FORWARD0SWEEP CPPAD_ASSERT_UNKNOWN( d > 0 ); # else addr_t* non_const_arg; # endif const addr_t* arg = 0; // temporary indices size_t i, ell; // initialize the comparision operator (ComOp) counter size_t compareCount = 0; // if this is an order zero calculation, initialize vector indices pod_vector<size_t> VectorInd; // address for each element pod_vector<bool> VectorVar; // is element a variable i = Rec->num_rec_vecad_ind(); if( i > 0 ) { VectorInd.extend(i); VectorVar.extend(i); while(i--) { VectorInd[i] = Rec->GetVecInd(i); VectorVar[i] = false; } } // work space used by UserOp. const size_t user_k = d; // order of this forward mode calculation const size_t user_k1 = d+1; // number of orders for this calculation vector<Base> user_tx; // argument vector Taylor coefficients vector<Base> user_ty; // result vector Taylor coefficients vector<size_t> user_iy; // variable indices for results vector size_t user_index = 0; // indentifier for this user_atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end } user_state = user_start; // check numvar argument CPPAD_ASSERT_UNKNOWN( Rec->num_rec_var() == numvar ); // length of the parameter vector (used by CppAD assert macros) const size_t num_par = Rec->num_rec_par(); // pointer to the beginning of the parameter vector const Base* parameter = 0; if( num_par > 0 ) parameter = Rec->GetPar(); # if ! CPPAD_USE_FORWARD0SWEEP // length of the text vector (used by CppAD assert macros) const size_t num_text = Rec->num_rec_text(); // pointer to the beginning of the text vector const char* text = 0; if( num_text > 0 ) text = Rec->GetTxt(0); # endif // skip the BeginOp at the beginning of the recording Rec->start_forward(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( op == BeginOp ); # if CPPAD_FORWARD_SWEEP_TRACE std::cout << std::endl; # endif while(op != EndOp) { // this op Rec->next_forward(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) ); CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); // action depends on the operator switch( op ) { case AbsOp: forward_abs_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AddvvOp: forward_addvv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case AddpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_addpv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case AcosOp: // sqrt(1 - x * x), acos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_acos_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AsinOp: // sqrt(1 - x * x), asin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_asin_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AtanOp: // 1 + x * x, atan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_atan_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case CSumOp: // CSumOp has a variable number of arguments and // next_forward thinks it one has one argument. // we must inform next_forward of this special case. Rec->forward_csum(op, arg, i_op, i_var); forward_csum_op( d, i_var, arg, num_par, parameter, J, Taylor ); break; // ------------------------------------------------- case CExpOp: forward_cond_op( d, i_var, arg, num_par, parameter, J, Taylor ); break; // --------------------------------------------------- case ComOp: # if ! USE_FORWARD0SWEEP if( d == 0 ) forward_comp_op_0( compareCount, arg, num_par, parameter, J, Taylor ); # endif break; // --------------------------------------------------- case CosOp: // sin(x), cos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cos_op(d, i_var, arg[0], J, Taylor); break; // --------------------------------------------------- case CoshOp: // sinh(x), cosh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cosh_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case DisOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) forward_dis_op_0(i_var, arg, J, Taylor); else # endif { Taylor[ i_var * J + d] = Base(0); } break; // ------------------------------------------------- case DivvvOp: forward_divvv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case DivpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_divpv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case DivvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_divvp_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case EndOp: CPPAD_ASSERT_NARG_NRES(op, 0, 0); break; // ------------------------------------------------- case ExpOp: forward_exp_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case InvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); break; // ------------------------------------------------- case LdpOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { non_const_arg = Rec->forward_non_const_arg(); forward_load_p_op_0( i_var, non_const_arg, num_par, parameter, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } else # endif { forward_load_op( op, d, i_var, arg, J, Taylor); } break; // ------------------------------------------------- case LdvOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { non_const_arg = Rec->forward_non_const_arg(); forward_load_v_op_0( i_var, non_const_arg, num_par, parameter, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } else # endif { forward_load_op( op, d, i_var, arg, J, Taylor); } break; // ------------------------------------------------- case LogOp: forward_log_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case MulvvOp: forward_mulvv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case MulpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_mulpv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case ParOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) forward_par_op_0( i_var, arg, num_par, parameter, J, Taylor ); else # endif { Taylor[ i_var * J + d] = Base(0); } break; // ------------------------------------------------- case PowvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_powvp_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PowpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_powpv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PowvvOp: forward_powvv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PriOp: # if ! CPPAD_USE_FORWARD0SWEEP if( print ) forward_pri_0(s_out, i_var, arg, num_text, text, num_par, parameter, J, Taylor ); # endif break; // ------------------------------------------------- case SignOp: // cos(x), sin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sign_op(d, i_var, arg[0], J, Taylor); break; case SinOp: // cos(x), sin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sin_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case SinhOp: // cosh(x), sinh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sinh_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case SqrtOp: forward_sqrt_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case StppOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { forward_store_pp_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } # endif break; // ------------------------------------------------- case StpvOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { forward_store_pv_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } # endif break; // ------------------------------------------------- case StvpOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { forward_store_vp_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } # endif break; // ------------------------------------------------- case StvvOp: # if ! CPPAD_USE_FORWARD0SWEEP if( d == 0 ) { forward_store_vv_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } # endif break; // ------------------------------------------------- case SubvvOp: forward_subvv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case SubpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_subpv_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case SubvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_subvp_op(d, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case TanOp: // tan(x)^2, tan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tan_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case TanhOp: // tanh(x)^2, tanh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tanh_op(d, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case UserOp: // start or end an atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_start ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; if(user_tx.size() < user_n * user_k1) user_tx.resize(user_n * user_k1); if(user_ty.size() < user_m * user_k1) user_ty.resize(user_m * user_k1); if(user_iy.size() < user_m) user_iy.resize(user_m); user_j = 0; user_i = 0; user_state = user_arg; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); user_state = user_start; // call users function for this operation user_atomic<Base>::forward(user_index, user_id, user_k, user_n, user_m, user_tx, user_ty ); for(i = 0; i < user_m; i++) if( user_iy[i] > 0 ) Taylor[ user_iy[i] * J + user_k ] = user_ty[ i * user_k1 + user_k ]; } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 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); ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); for(ell = 0; ell < user_k1; ell++) user_tx[user_j * user_k1 + ell] = Taylor[ arg[0] * J + ell]; ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = 0; user_ty[user_i * user_k1 + 0] = parameter[ arg[0]]; for(ell = 1; ell < user_k; ell++) user_ty[user_i * user_k1 + ell] = Base(0); user_i++; if( user_i == user_m ) user_state = user_end; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = i_var; for(ell = 0; ell < user_k; ell++) user_ty[user_i * user_k1 + ell] = Taylor[ i_var * J + ell]; user_i++; if( user_i == user_m ) user_state = user_end; break; // ------------------------------------------------- default: CPPAD_ASSERT_UNKNOWN(0); } # if CPPAD_FORWARD_SWEEP_TRACE size_t i_tmp = i_var; Base* Z_tmp = Taylor + J * i_var; printOp( std::cout, Rec, i_tmp, op, arg, d + 1, Z_tmp, 0, (Base *) CPPAD_NULL ); } std::cout << std::endl; # else }
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; }
void printOp( std::ostream &os , const player<Base> *Rec , size_t i_var , OpCode op , const addr_t *ind , size_t nfz , const Value *fz , size_t nrz , const Value *rz ) { size_t i; CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel() , "cannot print trace of AD operations in parallel mode" ); static const char *CompareOpName[] = { "Lt", "Le", "Eq", "Ge", "Gt", "Ne" }; static const char *OpName[] = { "Abs" , "Acos" , "Addpv" , "Addvv" , "Asin" , "Atan" , "Begin" , "CExp" , "Com" , "Cos" , "Cosh" , "CSum" , "Dis" , "Divpv" , "Divvp" , "Divvv" , "End" , "Exp" , "Inv" , "Ldp" , "Ldv" , "Log" , "Mulpv" , "Mulvv" , "Par" , "Powpv" , "Powvp" , "Powvv" , "Pri" , "Sign" , "Sin" , "Sinh" , "Sqrt" , "Stpp" , "Stpv" , "Stvp" , "Stvv" , "Subpv" , "Subvp" , "Subvv" , "Tan" , "Tanh" , "User" , "Usrap" , "Usrav" , "Usrrp" , "Usrrv" }; CPPAD_ASSERT_UNKNOWN( size_t(NumberOp) == sizeof(OpName) / sizeof(OpName[0]) ); // print operator printOpField(os, "i=", i_var, 5); if( op == CExpOp ) { printOpField(os, "op=", OpName[op], 4); printOpField(os, "", CompareOpName[ ind[0] ], 3); } else if( op == ComOp ) { printOpField(os, "op=", OpName[op], 3); printOpField(os, "", CompareOpName[ ind[0] ], 4); } else printOpField(os, "op=", OpName[op], 7); // print other fields size_t ncol = 5; switch( op ) { case CSumOp: /* ind[0] = number of addition variables in summation ind[1] = number of subtraction variables in summation ind[2] = index of parameter that initializes summation ind[3], ... , ind[2+ind[0]] = index for positive variables ind[3+ind[0]], ..., ind[2+ind[0]+ind[1]] = negative variables ind[3+ind[0]+ind[1]] = ind[0] + ind[1] */ CPPAD_ASSERT_UNKNOWN( ind[3+ind[0]+ind[1]] == ind[0]+ind[1] ); printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); for(i = 0; i < ind[0]; i++) printOpField(os, " +v=", ind[3+i], ncol); for(i = 0; i < ind[1]; i++) printOpField(os, " -v=", ind[3+ind[0]+i], ncol); break; case LdpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, "idx=", ind[1], ncol); break; case LdvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, " v=", ind[1], ncol); break; case StppOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, "idx=", ind[1], ncol); printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); break; case StpvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, "idx=", ind[1], ncol); printOpField(os, " vr=", ind[2], ncol); break; case StvpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, " vl=", ind[1], ncol); printOpField(os, " pr=", Rec->GetPar(ind[2]), ncol); break; case StvvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", ind[0], ncol); printOpField(os, " vl=", ind[1], ncol); printOpField(os, " vr=", ind[2], ncol); break; case AddvvOp: case DivvvOp: case MulvvOp: case PowvvOp: case SubvvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " vl=", ind[0], ncol); printOpField(os, " vr=", ind[1], ncol); break; case AddpvOp: case SubpvOp: case MulpvOp: case PowpvOp: case DivpvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " pl=", Rec->GetPar(ind[0]), ncol); printOpField(os, " vr=", ind[1], ncol); break; case DivvpOp: case PowvpOp: case SubvpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " vl=", ind[0], ncol); printOpField(os, " pr=", Rec->GetPar(ind[1]), ncol); break; case AbsOp: case AcosOp: case AsinOp: case AtanOp: case CosOp: case CoshOp: case ExpOp: case LogOp: case SignOp: case SinOp: case SinhOp: case SqrtOp: case UsravOp: case TanOp: case TanhOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); printOpField(os, " v=", ind[0], ncol); break; case ParOp: case UsrapOp: case UsrrpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); printOpField(os, " p=", Rec->GetPar(ind[0]), ncol); break; case UserOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); { const char* name = user_atomic<Base>::name(ind[0]); printOpField(os, " f=", name, ncol); printOpField(os, " i=", ind[1], ncol); printOpField(os, " n=", ind[2], ncol); printOpField(os, " m=", ind[3], ncol); } break; case PriOp: CPPAD_ASSERT_NARG_NRES(op, 5, 0); if( ind[0] & 1 ) printOpField(os, " v=", ind[1], ncol); else printOpField(os, " p=", Rec->GetPar(ind[1]), ncol); os << "before=\"" << Rec->GetTxt(ind[2]) << "\""; if( ind[0] & 2 ) printOpField(os, " v=", ind[3], ncol); else printOpField(os, " p=", Rec->GetPar(ind[3]), ncol); os << "after=\"" << Rec->GetTxt(ind[4]) << "\""; break; case BeginOp: case EndOp: case InvOp: case UsrrvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); break; case DisOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); { const char* name = discrete<Base>::name(ind[0]); printOpField(os, " f=", name, ncol); printOpField(os, " x=", ind[1], ncol); } break; case CExpOp: CPPAD_ASSERT_UNKNOWN(ind[1] != 0); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 6 ); if( ind[1] & 1 ) printOpField(os, " vl=", ind[2], ncol); else printOpField(os, " pl=", Rec->GetPar(ind[2]), ncol); if( ind[1] & 2 ) printOpField(os, " vr=", ind[3], ncol); else printOpField(os, " pr=", Rec->GetPar(ind[3]), ncol); if( ind[1] & 4 ) printOpField(os, " vt=", ind[4], ncol); else printOpField(os, " pt=", Rec->GetPar(ind[4]), ncol); if( ind[1] & 8 ) printOpField(os, " vf=", ind[5], ncol); else printOpField(os, " pf=", Rec->GetPar(ind[5]), ncol); break; case ComOp: CPPAD_ASSERT_UNKNOWN(ind[1] != 0); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); if( ind[1] & 1 ) printOpField(os, "res=", 1, ncol); else printOpField(os, "res=", 0, ncol); if( ind[1] & 2 ) printOpField(os, " vl=", ind[2], ncol); else printOpField(os, " pl=", Rec->GetPar(ind[2]), ncol); if( ind[1] & 4 ) printOpField(os, " vr=", ind[3], ncol); else printOpField(os, " pr=", Rec->GetPar(ind[3]), ncol); break; default: CPPAD_ASSERT_UNKNOWN(0); } size_t k; if( NumRes(op) > 0 && (op != BeginOp) ) { for(k = 0; k < nfz; k++) std::cout << "| fz[" << k << "]=" << fz[k]; for(k = 0; k < nrz; k++) std::cout << "| rz[" << k << "]=" << rz[k]; } std::cout << std::endl; }
void my_init(vector<bool> keepcol){ Partial.extend(num_var_tape_ * 1); arg_mark_.resize(play_.op_arg_rec_.size()); for(size_t i=0;i<arg_mark_.size();i++)arg_mark_[i]=false; /* Run a reverse test-sweep to store pointers once */ tape_point tp; play_.reverse_start(tp.op, tp.op_arg, tp.op_index, tp.var_index); tp_.resize(tp.op_index+1); var2op_.resize(tp.var_index+1); op_mark_.resize(tp.op_index+1); for(size_t i=0;i<op_mark_.size();i++)op_mark_[i]=0; user_region_mark_.resize(tp.op_index+1); for(size_t i=0;i<user_region_mark_.size();i++)user_region_mark_[i]=0; tp_[tp.op_index]=tp; /* 1. We need to be able to find out, for a given variable, what operator created the variable. This is easiest done by looping through the _operators_ because for a given op we have access to all the resulting variables it creates. 2. We precompute the a vector of "tape_points" so that instead of calling "reverse_next", we simply get the next tape entry by tp_[i-1]. */ while(tp.op != BeginOp ){ /* tp.op_index is decremented by one in each iteration ... */ // printTP(tp); /* For debugging */ play_.reverse_next(tp.op, tp.op_arg, tp.op_index, tp.var_index); /* Csum is special case - see remarks in player.hpp and reverse_sweep.hpp */ if(tp.op == CSumOp)play_.reverse_csum(tp.op, tp.op_arg, tp.op_index, tp.var_index); for(size_t i=0;i<NumRes(tp.op);i++)var2op_[tp.var_index-i]=tp.op_index; tp_[tp.op_index]=tp; markArgs(tp); } /* Lookup table: is tape_point within a UserOp region? */ bool user_within=false; user_region_.resize(tp_.size()); for(size_t i=0;i<tp_.size();i++){ if(tp_[i].op==UserOp){ user_region_[i]=true; user_within=!user_within; } else { user_region_[i]=user_within; } } /* Lookup table: is tape_point a constant (=only fixed effect dependent) ? */ constant_tape_point_.resize(tp_.size()); int indep_var_number=0; for(size_t i=0;i<tp_.size();i++){ if(tp_[i].op==InvOp){ /* All independent variables are marked according to being random or fixed effect */ constant_tape_point_[i]=!keepcol[indep_var_number]; indep_var_number++; } else { /* Mark operator as constant if _all_ arguments are constant */ constant_tape_point_[i] = is_tape_point_constant(i); } //std::cout << constant_tape_point_[i] << " "; printTP(tp_[i]); } // std::cout << "Total: " << constant_tape_point_.size() << "\n"; // int sum=0; for(int i=0;i<constant_tape_point_.size();i++)sum+=constant_tape_point_[i]; // std::cout << "Constant:" << sum << "\n"; // Calculate pattern int m=Range(); colpattern.resize(m); for(int i=0;i<m;i++)my_pattern(i); for(size_t i=0;i<op_mark_.size();i++)op_mark_[i]=0; /* remember to reset marks */ for(size_t i=0;i<user_region_mark_.size();i++)user_region_mark_[i]=0; /* remember to reset marks */ }
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; }
void random_setup( size_t num_var , const pod_vector<opcode_t>& op_vec , const pod_vector<addr_t>& arg_vec , pod_vector<Addr>* op2arg_vec , pod_vector<Addr>* op2var_vec , pod_vector<Addr>* var2op_vec ) { if( op2arg_vec->size() != 0 ) { CPPAD_ASSERT_UNKNOWN( op2arg_vec->size() == op_vec.size() ); CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == op_vec.size() ); CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == num_var ); return; } CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 ); CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 ); CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == 0 ); CPPAD_ASSERT_UNKNOWN( OpCode( op_vec[0] ) == BeginOp ); CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1); // size_t num_op = op_vec.size(); size_t var_index = 0; size_t arg_index = 0; // op2arg_vec->resize( num_op ); op2var_vec->resize( num_op ); var2op_vec->resize( num_var ); # ifndef NDEBUG // value of var2op for auxillary variables is num_op (invalid) for(size_t i_var = 0; i_var < num_var; ++i_var) (*var2op_vec)[i_var] = Addr( num_op ); // value of op2var is num_var (invalid) when NumRes(op) = 0 for(size_t i_op = 0; i_op < num_op; ++i_op) (*op2var_vec)[i_op] = Addr( num_var ); # endif for(size_t i_op = 0; i_op < num_op; ++i_op) { OpCode op = OpCode( op_vec[i_op] ); // // index of first argument for this operator (*op2arg_vec)[i_op] = Addr( arg_index ); arg_index += NumArg(op); // // index of first result for next operator var_index += NumRes(op); if( NumRes(op) > 0 ) { // index of last (primary) result for this operator (*op2var_vec)[i_op] = Addr( var_index - 1 ); // // mapping from primary variable to its operator (*var2op_vec)[var_index - 1] = Addr( i_op ); } // CSumOp if( op == CSumOp ) { CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); // // pointer to first argument for this operator const addr_t* op_arg = arg_vec.data() + arg_index; // // The actual number of arugments for this operator is // op_arg[4] + 1 // Correct index of first argument for next operator arg_index += size_t(op_arg[4] + 1); } // // CSkip if( op == CSkipOp ) { CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); // // pointer to first argument for this operator const addr_t* op_arg = arg_vec.data() + arg_index; // // The actual number of arugments for this operator is // 7 + op_arg[4] + op_arg[5]. // Correct index of first argument for next operator. arg_index += size_t(7 + op_arg[4] + op_arg[5]); } } }
inline void forward_cond_op( size_t q , size_t p , size_t i_z , const addr_t* arg , size_t num_par , const Base* parameter , size_t nc_taylor , Base* taylor ) { Base y_0, y_1, y_2, y_3; Base zero(0); Base* z = taylor + i_z * nc_taylor; CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast<size_t> (CompareNe) ); CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); if( arg[1] & 1 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < i_z ); y_0 = taylor[ arg[2] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); y_0 = parameter[ arg[2] ]; } if( arg[1] & 2 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < i_z ); y_1 = taylor[ arg[3] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); y_1 = parameter[ arg[3] ]; } if( q == 0 ) { if( arg[1] & 4 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < i_z ); y_2 = taylor[ arg[4] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < num_par ); y_2 = parameter[ arg[4] ]; } if( arg[1] & 8 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < i_z ); y_3 = taylor[ arg[5] * nc_taylor + 0 ]; } else { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < num_par ); y_3 = parameter[ arg[5] ]; } z[0] = CondExpOp( CompareOp( arg[0] ), y_0, y_1, y_2, y_3 ); q++; } for(size_t d = q; d <= p; d++) { if( arg[1] & 4 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < i_z ); y_2 = taylor[ arg[4] * nc_taylor + d]; } else y_2 = zero; if( arg[1] & 8 ) { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < i_z ); y_3 = taylor[ arg[5] * nc_taylor + d]; } else y_3 = zero; z[d] = CondExpOp( CompareOp( arg[0] ), y_0, y_1, y_2, y_3 ); } return; }
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 ); }
void RevHesSweep( size_t n, size_t numvar, player<Base> *play, Vector_set& for_jac_sparse, // should be const 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() ); } // work space used by UserOp. vector<size_t> user_ix; // variable indices for argument vector x typedef std::set<size_t> size_set; size_set::iterator set_itr; // iterator for a standard set size_set::iterator set_end; // end of iterator sequence vector< size_set > set_r; // forward Jacobian sparsity for x vector< size_set > set_u; // reverse Hessian sparsity for y vector< size_set > set_v; // reverse Hessian sparsity for x // vector<bool> bool_r; // bool forward Jacobian sparsity for x vector<bool> bool_u; // bool reverse Hessian sparsity for y vector<bool> bool_v; // bool reverse Hessian sparsity for x // vectorBool pack_r; // pack forward Jacobian sparsity for x vectorBool pack_u; // pack reverse Hessian sparsity for y vectorBool pack_v; // pack reverse Hessian sparsity for x // vector<bool> user_vx; // which components of x are variables vector<bool> user_s; // reverse Jacobian sparsity for y vector<bool> user_t; // reverse Jacobian sparsity for x const size_t user_q = limit; // maximum element plus one size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator bool user_pack = false; // sparsity pattern type is pack bool user_bool = false; // sparsity pattern type is bool bool user_set = false; // sparsity pattern type is set # ifndef NDEBUG bool user_ok = false; // atomic op return value # endif // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end } user_state = user_end; // 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) { // 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: // start or end an atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_end ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif user_pack = user_atom->sparsity() == atomic_base<Base>::pack_sparsity_enum; user_bool = user_atom->sparsity() == atomic_base<Base>::bool_sparsity_enum; user_set = user_atom->sparsity() == atomic_base<Base>::set_sparsity_enum; CPPAD_ASSERT_UNKNOWN( user_pack || user_bool || user_set ); user_ix.resize(user_n); user_vx.resize(user_n); user_s.resize(user_m); user_t.resize(user_n); // simpler to initialize all sparsity patterns as empty for(i = 0; i < user_m; i++) user_s[i] = false; for(i = 0; i < user_n; i++) user_t[i] = false; if( user_pack ) { pack_r.resize(user_n * user_q); pack_u.resize(user_m * user_q); pack_v.resize(user_n * user_q); // simpler to initialize all patterns as empty for(i = 0; i < user_m; i++) { for(j = 0; j < user_q; j++) pack_u[ i * user_q + j] = false; } for(i = 0; i < user_n; i++) { for(j = 0; j < user_q; j++) { pack_r[ i * user_q + j] = false; pack_v[ i * user_q + j] = false; } } } if( user_bool ) { bool_r.resize(user_n * user_q); bool_u.resize(user_m * user_q); bool_v.resize(user_n * user_q); // simpler to initialize all patterns as empty for(i = 0; i < user_m; i++) { for(j = 0; j < user_q; j++) bool_u[ i * user_q + j] = false; } for(i = 0; i < user_n; i++) { for(j = 0; j < user_q; j++) { bool_r[ i * user_q + j] = false; bool_v[ i * user_q + j] = false; } } } if( user_set ) { set_r.resize(user_n); set_u.resize(user_m); set_v.resize(user_n); for(i = 0; i < user_m; i++) set_u[i].clear(); for(i = 0; i < user_n; i++) { set_r[i].clear(); set_v[i].clear(); } } user_j = user_n; user_i = user_m; user_state = user_ret; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_start ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); user_state = user_end; // call users function for this operation user_atom->set_id(user_id); # ifdef NDEBUG if( user_pack ) user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, pack_r, pack_u, pack_v ); if( user_bool ) user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, bool_r, bool_u, bool_v ); if( user_set ) user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, set_r, set_u, set_v ); # else if( user_pack ) user_ok = user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, pack_r, pack_u, pack_v ); if( user_bool ) user_ok = user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, bool_r, bool_u, bool_v ); if( user_set ) user_ok = user_atom->rev_sparse_hes(user_vx, user_s, user_t, user_q, set_r, set_u, set_v ); if( ! user_ok ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base.rev_sparse_hes: returned false\n"; if( user_pack ) msg += "sparsity = pack_sparsity_enum"; if( user_bool ) msg += "sparsity = bool_sparsity_enum"; if( user_set ) msg += "sparsity = set_sparsity_enum"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif for(i = 0; i < user_n; i++) if( user_ix[i] > 0 ) { size_t i_x = user_ix[i]; if( user_t[i] ) RevJac[i_x] = true; if( user_pack ) { for(j = 0; j < user_q; j++) if( pack_v[ i * user_q + j ] ) rev_hes_sparse.add_element(i_x, j); } if( user_bool ) { for(j = 0; j < user_q; j++) if( bool_v[ i * user_q + j ] ) rev_hes_sparse.add_element(i_x, j); } if( user_set ) { set_itr = set_v[i].begin(); set_end = set_v[i].end(); while( set_itr != set_end ) rev_hes_sparse.add_element(i_x, *set_itr++); } } } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j <= user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); --user_j; user_ix[user_j] = 0; user_vx[user_j] = false; if( user_j == 0 ) user_state = user_start; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( 0 < user_j && user_j <= user_n ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); --user_j; user_ix[user_j] = arg[0]; user_vx[user_j] = true; for_jac_sparse.begin(arg[0]); i = for_jac_sparse.next_element(); while( i < user_q ) { if( user_pack ) pack_r[ user_j * user_q + i ] = true; if( user_bool ) bool_r[ user_j * user_q + i ] = true; if( user_set ) set_r[user_j].insert(i); i = for_jac_sparse.next_element(); } if( user_j == 0 ) user_state = user_start; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i <= user_m ); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); --user_i; if( user_i == 0 ) user_state = user_arg; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( 0 < user_i && user_i <= user_m ); --user_i; if( RevJac[i_var] ) { user_s[user_i] = true; } rev_hes_sparse.begin(i_var); j = rev_hes_sparse.next_element(); while( j < user_q ) { if( user_pack ) pack_u[user_i * user_q + j] = true; if( user_bool ) bool_u[user_i * user_q + j] = true; if( user_set ) set_u[user_i].insert(j); j = rev_hes_sparse.next_element(); } if( user_i == 0 ) user_state = user_arg; 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; } for_jac_sparse.begin(i_var);; j = for_jac_sparse.next_element();; while( j < limit ) { zf_value[j] = true; j = for_jac_sparse.next_element(); } rev_hes_sparse.begin(i_var);; j = rev_hes_sparse.next_element();; while( j < limit ) { zh_value[j] = true; j = rev_hes_sparse.next_element(); } 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 }
// 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; }
size_t forward_sweep( std::ostream& s_out, const bool print, const size_t q, const size_t p, const size_t n, const size_t numvar, player<Base> *Rec, const size_t J, Base *Taylor, CppAD::vector<bool>& cskip_op ) { CPPAD_ASSERT_UNKNOWN( J >= p + 1 ); CPPAD_ASSERT_UNKNOWN( q <= p ); // op code for current instruction OpCode op; // index for current instruction size_t i_op; // next variables size_t i_var; // arg (not as a constant) addr_t* non_const_arg = CPPAD_NULL; // arg (as a constant) const addr_t* arg = CPPAD_NULL; // temporary indices size_t i, ell; // initialize the comparision operator (ComOp) counter size_t compareCount = 0; pod_vector<size_t> VectorInd; // address for each element pod_vector<bool> VectorVar; // is element a variable if( q == 0 ) { // this includes order zero calculation, initialize vector indices i = Rec->num_rec_vecad_ind(); if( i > 0 ) { VectorInd.extend(i); VectorVar.extend(i); while(i--) { VectorInd[i] = Rec->GetVecInd(i); VectorVar[i] = false; } } // includes zero order, so initialize conditional skip flags for(i = 0; i < Rec->num_rec_op(); i++) cskip_op[i] = false; } // Work space used by UserOp. Note User assumes q = p. const size_t user_p1 = p+1; // number of orders for this user calculation vector<bool> user_vx; // empty vector vector<bool> user_vy; // empty vector vector<Base> user_tx; // argument vector Taylor coefficients vector<Base> user_ty; // result vector Taylor coefficients vector<size_t> user_iy; // variable indices for results vector size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator # ifndef NDEBUG bool user_ok = false; // atomic op return value # endif // // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end } user_state = user_start; // check numvar argument CPPAD_ASSERT_UNKNOWN( Rec->num_rec_var() == numvar ); // length of the parameter vector (used by CppAD assert macros) const size_t num_par = Rec->num_rec_par(); // pointer to the beginning of the parameter vector const Base* parameter = CPPAD_NULL; if( num_par > 0 ) parameter = Rec->GetPar(); // length of the text vector (used by CppAD assert macros) const size_t num_text = Rec->num_rec_text(); // pointer to the beginning of the text vector const char* text = CPPAD_NULL; if( num_text > 0 ) text = Rec->GetTxt(0); // skip the BeginOp at the beginning of the recording Rec->start_forward(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( op == BeginOp ); # if CPPAD_FORWARD_SWEEP_TRACE std::cout << std::endl; # endif bool more_operators = true; while(more_operators) { // this op Rec->next_forward(op, arg, i_op, i_var); CPPAD_ASSERT_UNKNOWN( (i_op > n) | (op == InvOp) ); CPPAD_ASSERT_UNKNOWN( (i_op <= n) | (op != InvOp) ); // check if we are skipping this operation while( cskip_op[i_op] ) { if( op == CSumOp ) { // CSumOp has a variable number of arguments Rec->forward_csum(op, arg, i_op, i_var); } Rec->next_forward(op, arg, i_op, i_var); } // action depends on the operator switch( op ) { case AbsOp: forward_abs_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AddvvOp: forward_addvv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case AddpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_addpv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case AcosOp: // sqrt(1 - x * x), acos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_acos_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AsinOp: // sqrt(1 - x * x), asin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_asin_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case AtanOp: // 1 + x * x, atan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_atan_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case CExpOp: forward_cond_op( q, p, i_var, arg, num_par, parameter, J, Taylor ); break; // --------------------------------------------------- case ComOp: if( q == 0 ) forward_comp_op_0( compareCount, arg, num_par, parameter, J, Taylor ); break; // --------------------------------------------------- case CosOp: // sin(x), cos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cos_op(q, p, i_var, arg[0], J, Taylor); break; // --------------------------------------------------- case CoshOp: // sinh(x), cosh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cosh_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case CSkipOp: // CSkipOp has a variable number of arguments and // next_forward thinks it one has one argument. // we must inform next_forward of this special case. Rec->forward_cskip(op, arg, i_op, i_var); if( q == 0 ) { forward_cskip_op_0( i_var, arg, num_par, parameter, J, Taylor, cskip_op ); } break; // ------------------------------------------------- case CSumOp: // CSumOp has a variable number of arguments and // next_forward thinks it one has one argument. // we must inform next_forward of this special case. Rec->forward_csum(op, arg, i_op, i_var); forward_csum_op( q, p, i_var, arg, num_par, parameter, J, Taylor ); break; // ------------------------------------------------- case DisOp: i = q; if( i == 0 ) { forward_dis_op_0(i_var, arg, J, Taylor); i++; } while(i <= p) { Taylor[ i_var * J + i] = Base(0); i++; } break; // ------------------------------------------------- case DivvvOp: forward_divvv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case DivpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_divpv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case DivvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_divvp_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case EndOp: CPPAD_ASSERT_NARG_NRES(op, 0, 0); more_operators = false; break; // ------------------------------------------------- case ExpOp: forward_exp_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case InvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); break; // ------------------------------------------------- case LdpOp: if( q == 0 ) { non_const_arg = Rec->forward_non_const_arg(); forward_load_p_op_0( i_var, non_const_arg, num_par, parameter, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); if( q < p ) forward_load_op( op, q+1, p, i_var, arg, J, Taylor); } else { forward_load_op( op, q, p, i_var, arg, J, Taylor); } break; // ------------------------------------------------- case LdvOp: if( q == 0 ) { non_const_arg = Rec->forward_non_const_arg(); forward_load_v_op_0( i_var, non_const_arg, num_par, parameter, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); if( q < p ) forward_load_op( op, q+1, p, i_var, arg, J, Taylor); } else { forward_load_op( op, q, p, i_var, arg, J, Taylor); } break; // ------------------------------------------------- case LogOp: forward_log_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case MulvvOp: forward_mulvv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case MulpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_mulpv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case ParOp: i = q; if( i == 0 ) { forward_par_op_0( i_var, arg, num_par, parameter, J, Taylor ); i++; } while(i <= p) { Taylor[ i_var * J + i] = Base(0); i++; } break; // ------------------------------------------------- case PowvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_powvp_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PowpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_powpv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PowvvOp: forward_powvv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case PriOp: if( (q == 0) & print ) forward_pri_0(s_out, i_var, arg, num_text, text, num_par, parameter, J, Taylor ); break; // ------------------------------------------------- case SignOp: // sign(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sign_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case SinOp: // cos(x), sin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sin_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case SinhOp: // cosh(x), sinh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sinh_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case SqrtOp: forward_sqrt_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case StppOp: if( q == 0 ) { forward_store_pp_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } break; // ------------------------------------------------- case StpvOp: if( q == 0 ) { forward_store_pv_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } break; // ------------------------------------------------- case StvpOp: if( q == 0 ) { forward_store_vp_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } break; // ------------------------------------------------- case StvvOp: if( q == 0 ) { forward_store_vv_op_0( i_var, arg, num_par, J, Taylor, Rec->num_rec_vecad_ind(), VectorVar.data(), VectorInd.data() ); } break; // ------------------------------------------------- case SubvvOp: forward_subvv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case SubpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_subpv_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case SubvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_subvp_op(q, p, i_var, arg, parameter, J, Taylor); break; // ------------------------------------------------- case TanOp: // tan(x)^2, tan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tan_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case TanhOp: // tanh(x)^2, tanh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tanh_op(q, p, i_var, arg[0], J, Taylor); break; // ------------------------------------------------- case UserOp: // start or end an atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_start ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif if(user_tx.size() != user_n * user_p1) user_tx.resize(user_n * user_p1); if(user_ty.size() != user_m * user_p1) user_ty.resize(user_m * user_p1); if(user_iy.size() != user_m) user_iy.resize(user_m); user_j = 0; user_i = 0; user_state = user_arg; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); // call users function for this operation user_atom->set_id(user_id); CPPAD_ATOMIC_CALL( q, p, user_vx, user_vy, user_tx, user_ty ); # ifndef NDEBUG if( ! user_ok ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": 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 ) for(ell = q; ell <= p; ell++) Taylor[ user_iy[i] * J + ell ] = user_ty[ i * user_p1 + ell ]; user_state = user_start; } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); user_tx[user_j * user_p1 + 0] = parameter[ arg[0]]; for(ell = 1; ell < user_p1; ell++) user_tx[user_j * user_p1 + ell] = Base(0); ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); for(ell = 0; ell < user_p1; ell++) user_tx[user_j * user_p1 + ell] = Taylor[ arg[0] * J + ell]; ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = 0; user_ty[user_i * user_p1 + 0] = parameter[ arg[0]]; for(ell = 1; ell < q; ell++) user_ty[user_i * user_p1 + ell] = Base(0); user_i++; if( user_i == user_m ) user_state = user_end; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = i_var; for(ell = 0; ell < q; ell++) user_ty[user_i * user_p1 + ell] = Taylor[ i_var * J + ell]; user_i++; if( user_i == user_m ) user_state = user_end; break; // ------------------------------------------------- default: CPPAD_ASSERT_UNKNOWN(0); } # if CPPAD_FORWARD_SWEEP_TRACE size_t i_tmp = i_var; Base* Z_tmp = Taylor + J * i_var; printOp( std::cout, Rec, i_op, i_tmp, op, arg, p + 1, Z_tmp, 0, (Base *) CPPAD_NULL ); } std::cout << std::endl; # else }
void subgraph_info::get_rev( const play::const_random_iterator<Addr>& random_itr , const pod_vector<size_t>& dep_taddr , addr_t i_dep , pod_vector<addr_t>& subgraph ) { // check sizes CPPAD_ASSERT_UNKNOWN( map_user_op_.size() == n_op_ ); // process_range_ CPPAD_ASSERT_UNKNOWN( process_range_[i_dep] == false ); process_range_[i_dep] = true; // special value; see init_rev_in_subgraph addr_t depend_yes = addr_t( n_dep_ ); // assumption on i_dep CPPAD_ASSERT_UNKNOWN( i_dep < depend_yes ); // start with an empty subgraph for this dependent variable subgraph.resize(0); // tape index corresponding to this dependent variable size_t i_var = dep_taddr[i_dep]; // operator corresponding to this dependent variable size_t i_op = random_itr.var2op(i_var); i_op = size_t( map_user_op_[i_op] ); // if this variable depends on the selected indepent variables // process its subgraph CPPAD_ASSERT_UNKNOWN( in_subgraph_[i_op] != i_dep ) if( in_subgraph_[i_op] <= depend_yes ) { subgraph.push_back( addr_t(i_op) ); in_subgraph_[i_op] = i_dep; } // space used to return set of arguments that are variables pod_vector<size_t> argument_variable; // temporary space used by get_argument_variable pod_vector<bool> work; // scan all the operators in this subgraph size_t sub_index = 0; while(sub_index < subgraph.size() ) { // this operator connected to this dependent and selected independent i_op = size_t( subgraph[sub_index] ); CPPAD_ASSERT_UNKNOWN( in_subgraph_[i_op] == i_dep ); // // There must be a result for this operator # ifndef NDEBUG OpCode op = random_itr.get_op(i_op); CPPAD_ASSERT_UNKNOWN(op == AFunOp || NumRes(op) > 0 ); # endif // // which variables are connected to this operator get_argument_variable(random_itr, i_op, argument_variable, work); for(size_t j = 0; j < argument_variable.size(); ++j) { // add the corresponding operators to the subgraph size_t j_var = argument_variable[j]; size_t j_op = random_itr.var2op(j_var); j_op = size_t( map_user_op_[j_op] ); bool add = in_subgraph_[j_op] <= depend_yes; add &= in_subgraph_[j_op] != i_dep; if( random_itr.get_op(j_op) == InvOp ) { CPPAD_ASSERT_UNKNOWN( j_op == j_var ); add &= select_domain_[j_var - 1]; } if( add ) { subgraph.push_back( addr_t(j_op) ); in_subgraph_[j_op] = i_dep; } } // we are done scaning this subgraph operator ++sub_index; } }
void forward1sweep( std::ostream& s_out, const bool print, const size_t p, const size_t q, const size_t n, const size_t numvar, player<Base>* play, const 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 ) { // number of directions const size_t r = 1; CPPAD_ASSERT_UNKNOWN( p <= q ); CPPAD_ASSERT_UNKNOWN( J >= q + 1 ); CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); /* <!-- replace 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 size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator # ifndef NDEBUG bool user_ok = false; // atomic op return value # endif // // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end, user_trace } user_state = user_start; // 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 --> */ // temporary indices size_t i, k; // 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_FORWARD1SWEEP_TRACE std::cout << std::endl; # endif 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] ) { if( op == CSumOp ) { // CSumOp has a variable number of arguments play->forward_csum(op, arg, i_op, i_var); } CPPAD_ASSERT_UNKNOWN( op != CSkipOp ); // if( op == CSkipOp ) // { // CSkip has a variable number of arguments // play->forward_cskip(op, arg, i_op, i_var); // } 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(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case AddvvOp: forward_addvv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case AddpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_addpv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case AcosOp: // sqrt(1 - x * x), acos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_acos_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case AsinOp: // sqrt(1 - x * x), asin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_asin_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case AtanOp: // 1 + x * x, atan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_atan_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case CExpOp: forward_cond_op( p, q, i_var, arg, num_par, parameter, J, taylor ); break; // --------------------------------------------------- case CosOp: // sin(x), cos(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cos_op(p, q, i_var, arg[0], J, taylor); break; // --------------------------------------------------- case CoshOp: // sinh(x), cosh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_cosh_op(p, q, 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. if( p == 0 ) { 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( p, q, 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(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case DivpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_divpv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case DivvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_divvp_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case EndOp: CPPAD_ASSERT_NARG_NRES(op, 0, 0); more_operators = false; break; // ------------------------------------------------- case EqpvOp: if( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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_COMPILER_HAS_ERF case ErfOp: CPPAD_ASSERT_UNKNOWN( CPPAD_COMPILER_HAS_ERF ); // 2DO: implement zero order version of this function forward_erf_op(p, q, i_var, arg, parameter, J, taylor); break; # endif // ------------------------------------------------- case ExpOp: forward_exp_op(p, q, i_var, arg[0], J, taylor); break; // --------------------------------------------------- case InvOp: CPPAD_ASSERT_NARG_NRES(op, 0, 1); break; // ------------------------------------------------- case LdpOp: if( p == 0 ) { 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() ); if( p < q ) forward_load_op( play, op, p+1, q, r, J, i_var, arg, var_by_load_op.data(), taylor ); } else forward_load_op( play, op, p, q, r, J, i_var, arg, var_by_load_op.data(), taylor ); break; // ------------------------------------------------- case LdvOp: if( p == 0 ) { 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() ); if( p < q ) forward_load_op( play, op, p+1, q, r, J, i_var, arg, var_by_load_op.data(), taylor ); } else forward_load_op( play, op, p, q, r, J, i_var, arg, var_by_load_op.data(), taylor ); break; // ------------------------------------------------- case LepvOp: if( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case LtpvOp: if( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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 MulvvOp: forward_mulvv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case MulpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_mulpv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case NepvOp: if( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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( ( p == 0 ) & ( compare_change_count > 0 ) ) { 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: i = p; if( i == 0 ) { forward_par_op_0( i_var, arg, num_par, parameter, J, taylor ); i++; } while(i <= q) { taylor[ i_var * J + i] = Base(0); i++; } break; // ------------------------------------------------- case PowvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_powvp_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case PowpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_powpv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case PowvvOp: forward_powvv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case PriOp: if( (p == 0) & print ) forward_pri_0(s_out, arg, num_text, text, num_par, parameter, J, taylor ); break; // ------------------------------------------------- case SignOp: // sign(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sign_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case SinOp: // cos(x), sin(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sin_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case SinhOp: // cosh(x), sinh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_sinh_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case SqrtOp: forward_sqrt_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case StppOp: if( p == 0 ) { forward_store_pp_op_0( i_var, arg, num_par, J, taylor, isvar_by_ind.data(), index_by_ind.data() ); } break; // ------------------------------------------------- case StpvOp: if( p == 0 ) { forward_store_pv_op_0( i_var, arg, num_par, J, taylor, isvar_by_ind.data(), index_by_ind.data() ); } break; // ------------------------------------------------- case StvpOp: if( p == 0 ) { forward_store_vp_op_0( i_var, arg, num_par, J, taylor, isvar_by_ind.data(), index_by_ind.data() ); } break; // ------------------------------------------------- case StvvOp: if( p == 0 ) { 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(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case SubpvOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); forward_subpv_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case SubvpOp: CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); forward_subvp_op(p, q, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- case TanOp: // tan(x)^2, tan(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tan_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case TanhOp: // tanh(x)^2, tanh(x) CPPAD_ASSERT_UNKNOWN( i_var < numvar ); forward_tanh_op(p, q, i_var, arg[0], J, taylor); break; // ------------------------------------------------- case UserOp: // start or end an atomic operation sequence CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_start ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif if(user_tx.size() != user_n * user_q1) user_tx.resize(user_n * user_q1); if(user_ty.size() != user_m * user_q1) user_ty.resize(user_m * user_q1); if(user_iy.size() != user_m) user_iy.resize(user_m); user_j = 0; user_i = 0; user_state = user_arg; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); // call users function for this operation user_atom->set_id(user_id); CPPAD_ATOMIC_CALL( p, q, user_vx, user_vy, user_tx, user_ty ); # ifndef NDEBUG if( ! user_ok ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": 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 ) for(k = p; k <= q; k++) taylor[ user_iy[i] * J + k ] = user_ty[ i * user_q1 + k ]; # if CPPAD_FORWARD1SWEEP_TRACE user_state = user_trace; # else user_state = user_start; # endif } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); user_tx[user_j * user_q1 + 0] = parameter[ arg[0]]; for(k = 1; k < user_q1; k++) user_tx[user_j * user_q1 + k] = Base(0); ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); for(k = 0; k < user_q1; k++) user_tx[user_j * user_q1 + k] = taylor[ arg[0] * J + k]; ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = 0; user_ty[user_i * user_q1 + 0] = parameter[ arg[0]]; for(k = 1; k < p; k++) user_ty[user_i * user_q1 + k] = Base(0); user_i++; if( user_i == user_m ) user_state = user_end; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); user_iy[user_i] = i_var; for(k = 0; k < p; k++) user_ty[user_i * user_q1 + k] = taylor[ i_var * J + k]; user_i++; if( user_i == user_m ) user_state = user_end; break; // ------------------------------------------------- default: CPPAD_ASSERT_UNKNOWN(0); } # if CPPAD_FORWARD1SWEEP_TRACE if( user_state == user_trace ) { user_state = user_start; 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; printOpResult( std::cout, q + 1, Z_tmp, 0, (Base *) CPPAD_NULL ); std::cout << std::endl; } } Base* Z_tmp = taylor + J * i_var; 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, q + 1, Z_tmp, 0, (Base *) CPPAD_NULL ); std::cout << std::endl; } } std::cout << std::endl; # else }
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; // 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 b[j] by 1 / b[0] pb[j] /= b[0]; // scale partials w.r.t z[j] by 1 / b[0] pz[j] /= b[0]; // update partials w.r.t b^0 pb[0] -= pz[j] * z[j] + pb[j] * b[j]; // update partial w.r.t. x^0 px[0] -= pb[j] * x[j]; // update partial w.r.t. x^j px[j] -= pz[j] + 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) * pz[j] * z[k] + pb[j] * b[k]; // update partials w.r.t. x^k px[k] -= pb[j] * x[j-k]; // update partials w.r.t. z^k pz[k] -= pz[j] * Base(k) * b[j-k]; } --j; } // j == 0 case px[0] -= ( pz[0] + pb[0] * x[0]) / b[0]; }
inline size_t optimize_binary_match( const CppAD::vector<struct optimize_old_variable>& tape , size_t current , size_t npar , const Base* par , const CppAD::vector<size_t>& hash_table_var , unsigned short& code ) { OpCode op = tape[current].op; const size_t* arg = tape[current].arg; size_t new_arg[2]; bool parameter[2]; // initialize return value size_t match_var = 0; CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); switch(op) { // parameter op variable ---------------------------------- case AddpvOp: case MulpvOp: case DivpvOp: case PowpvOp: case SubpvOp: // arg[0] parameter[0] = true; new_arg[0] = arg[0]; CPPAD_ASSERT_UNKNOWN( arg[0] < npar ); // arg[1] parameter[1] = false; new_arg[1] = tape[arg[1]].new_var; CPPAD_ASSERT_UNKNOWN( arg[1] < current ); break; // variable op parameter ----------------------------------- case DivvpOp: case PowvpOp: case SubvpOp: // arg[0] parameter[0] = false; new_arg[0] = tape[arg[0]].new_var; CPPAD_ASSERT_UNKNOWN( arg[0] < current ); // arg[1] parameter[1] = true; new_arg[1] = arg[1]; CPPAD_ASSERT_UNKNOWN( arg[1] < npar ); break; // variable op variable ----------------------------------- case AddvvOp: case MulvvOp: case DivvvOp: case PowvvOp: case SubvvOp: // arg[0] parameter[0] = false; new_arg[0] = tape[arg[0]].new_var; CPPAD_ASSERT_UNKNOWN( arg[0] < current ); // arg[1] parameter[1] = false; new_arg[1] = tape[arg[1]].new_var; CPPAD_ASSERT_UNKNOWN( arg[1] < current ); break; // must be one of the cases above default: CPPAD_ASSERT_UNKNOWN(false); } code = hash_code( op , new_arg , npar , par ); size_t i = hash_table_var[code]; CPPAD_ASSERT_UNKNOWN( i < current ); if( op == tape[i].op ) { bool match = true; size_t j; for(j = 0; j < 2; j++) { size_t k = tape[i].arg[j]; if( parameter[j] ) { CPPAD_ASSERT_UNKNOWN( k < npar ); match &= IdenticalEqualPar( par[ arg[j] ], par[k] ); } else { CPPAD_ASSERT_UNKNOWN( k < i ); match &= (new_arg[j] == tape[k].new_var); } } if( match ) match_var = tape[i].new_var; } if( (match_var > 0) | ( (op != AddvvOp) & (op != MulvvOp ) ) ) return match_var; // check for match with argument order switched ---------------------- CPPAD_ASSERT_UNKNOWN( op == AddvvOp || op == MulvvOp ); i = new_arg[0]; new_arg[0] = new_arg[1]; new_arg[1] = i; unsigned short code_switch = hash_code( op , new_arg , npar , par ); i = hash_table_var[code_switch]; CPPAD_ASSERT_UNKNOWN( i < current ); if( op == tape[i].op ) { bool match = true; size_t j; for(j = 0; j < 2; j++) { size_t k = tape[i].arg[j]; CPPAD_ASSERT_UNKNOWN( k < i ); match &= (new_arg[j] == tape[k].new_var); } if( match ) match_var = tape[i].new_var; } return match_var; }
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; }
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) / 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); }
void forward2sweep( const size_t q, const size_t r, const size_t n, const size_t numvar, 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; size_t user_index = 0; // indentifier for this atomic operation size_t user_id = 0; // user identifier for this call to operator size_t user_i = 0; // index in result vector size_t user_j = 0; // index in argument vector size_t user_m = 0; // size of result vector size_t user_n = 0; // size of arugment vector // atomic_base<Base>* user_atom = CPPAD_NULL; // user's atomic op calculator # ifndef NDEBUG bool user_ok = false; // atomic op return value # endif // // next expected operator in a UserOp sequence enum { user_start, user_arg, user_ret, user_end, user_trace } user_state = user_start; // 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 std::cout << std::endl; CppAD::vector<Base> Z_vec(q+1); # endif 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] ) { if( op == CSumOp ) { // CSumOp has a variable number of arguments play->forward_csum(op, arg, i_op, i_var); } CPPAD_ASSERT_UNKNOWN( op != CSkipOp ); // if( op == CSkipOp ) // { // CSkip has a variable number of arguments // play->forward_cskip(op, arg, i_op, i_var); // } 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; // ------------------------------------------------- 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 MulvvOp: forward_mulvv_op_dir(q, r, i_var, arg, parameter, J, taylor); break; // ------------------------------------------------- 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 ParOp: k = i_var*(J-1)*r + i_var + (q-1)*r + 1; for(ell = 0; ell < r; ell++) taylor[k + ell] = Base(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 CPPAD_ASSERT_UNKNOWN( NumRes( UserOp ) == 0 ); CPPAD_ASSERT_UNKNOWN( NumArg( UserOp ) == 4 ); if( user_state == user_start ) { user_index = arg[0]; user_id = arg[1]; user_n = arg[2]; user_m = arg[3]; user_atom = atomic_base<Base>::class_object(user_index); # ifndef NDEBUG if( user_atom == CPPAD_NULL ) { std::string msg = atomic_base<Base>::class_name(user_index) + ": atomic_base function has been deleted"; CPPAD_ASSERT_KNOWN(false, msg.c_str() ); } # endif if(user_tx_one.size() != user_n * user_q1) user_tx_one.resize(user_n * user_q1); if( user_tx_all.size() != user_n * (q * r + 1) ) user_tx_all.resize(user_n * (q * r + 1)); // if(user_ty_one.size() != user_m * user_q1) user_ty_one.resize(user_m * user_q1); if( user_ty_all.size() != user_m * (q * r + 1) ) user_ty_all.resize(user_m * (q * r + 1)); // if(user_iy.size() != user_m) user_iy.resize(user_m); user_j = 0; user_i = 0; user_state = user_arg; } else { CPPAD_ASSERT_UNKNOWN( user_state == user_end ); CPPAD_ASSERT_UNKNOWN( user_index == size_t(arg[0]) ); CPPAD_ASSERT_UNKNOWN( user_id == size_t(arg[1]) ); CPPAD_ASSERT_UNKNOWN( user_n == size_t(arg[2]) ); CPPAD_ASSERT_UNKNOWN( user_m == size_t(arg[3]) ); // call users function for this operation user_atom->set_id(user_id); 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 = atomic_base<Base>::class_name(user_index) + ": 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_state = user_trace; # else user_state = user_start; # endif } break; case UsrapOp: // parameter argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); 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); ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsravOp: // variable argument in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_arg ); CPPAD_ASSERT_UNKNOWN( user_j < user_n ); CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); 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]; } } ++user_j; if( user_j == user_n ) user_state = user_ret; break; case UsrrpOp: // parameter result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); 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); user_i++; if( user_i == user_m ) user_state = user_end; break; case UsrrvOp: // variable result in an atomic operation sequence CPPAD_ASSERT_UNKNOWN( user_state == user_ret ); CPPAD_ASSERT_UNKNOWN( user_i < user_m ); 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]; } } user_i++; if( user_i == user_m ) user_state = user_end; break; // ------------------------------------------------- default: CPPAD_ASSERT_UNKNOWN(0); } # if CPPAD_FORWARD2SWEEP_TRACE if( user_state == user_trace ) { user_state = user_start; 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 }
void ADFun<Base>::Dependent(ADTape<Base> *tape, const ADvector &y) { size_t m = y.size(); size_t n = tape->size_independent_; size_t i, j; size_t y_taddr; // check ADvector is Simple Vector class with AD<Base> elements CheckSimpleVector< AD<Base>, ADvector>(); CPPAD_ASSERT_KNOWN( y.size() > 0, "ADFun operation sequence dependent variable size is zero size" ); // --------------------------------------------------------------------- // Begin setting ad_fun.hpp private member data // --------------------------------------------------------------------- // dep_parameter_, dep_taddr_ CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 ); dep_parameter_.resize(m); dep_taddr_.resize(m); for(i = 0; i < m; i++) { dep_parameter_[i] = CppAD::Parameter(y[i]); if( dep_parameter_[i] ) { // make a tape copy of dependent variables that are parameters, y_taddr = tape->RecordParOp( y[i].value_ ); } else y_taddr = y[i].taddr_; CPPAD_ASSERT_UNKNOWN( y_taddr > 0 ); dep_taddr_[i] = y_taddr; } // put an EndOp at the end of the tape tape->Rec_.PutOp(EndOp); // some size_t values in ad_fun.hpp has_been_optimized_ = false; compare_change_count_ = 1; compare_change_number_ = 0; compare_change_op_index_ = 0; num_order_taylor_ = 0; num_direction_taylor_ = 0; cap_order_taylor_ = 0; // num_var_tape_ // Now that all the variables are in the tape, we can set this value. num_var_tape_ = tape->Rec_.num_var_rec(); // taylor_ taylor_.erase(); // cskip_op_ cskip_op_.erase(); cskip_op_.extend( tape->Rec_.num_op_rec() ); // load_op_ load_op_.erase(); load_op_.extend( tape->Rec_.num_load_op_rec() ); // play_ // Now that each dependent variable has a place in the tape, // and there is a EndOp at the end of the tape, we can transfer the // recording to the player and and erase the tape. play_.get(tape->Rec_); // ind_taddr_ // Note that play_ has been set, we can use it to check operators ind_taddr_.resize(n); CPPAD_ASSERT_UNKNOWN( n < num_var_tape_); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( play_.GetOp(j+1) == InvOp ); ind_taddr_[j] = j+1; } // for_jac_sparse_pack_, for_jac_sparse_set_ for_jac_sparse_pack_.resize(0, 0); for_jac_sparse_set_.resize(0,0); // --------------------------------------------------------------------- // End set ad_fun.hpp private member data // --------------------------------------------------------------------- // now we can delete the tape AD<Base>::tape_manage(tape_manage_delete); // total number of varables in this recording CPPAD_ASSERT_UNKNOWN( num_var_tape_ == play_.num_var_rec() ); // used to determine if there is an operation sequence in *this CPPAD_ASSERT_UNKNOWN( num_var_tape_ > 0 ); }
void printOp( std::ostream& os , const local::player<Base>* play, size_t i_op , size_t i_var , OpCode op , const addr_t* arg ) { CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel() , "cannot print trace of AD operations in parallel mode" ); static const char *CompareOpName[] = { "Lt", "Le", "Eq", "Ge", "Gt", "Ne" }; // print operator printOpField(os, "o=", i_op, 5); if( NumRes(op) > 0 && op != BeginOp ) printOpField(os, "v=", i_var, 5); else printOpField(os, "v=", "", 5); if( op == CExpOp || op == CSkipOp ) { printOpField(os, "", OpName(op), 5); printOpField(os, "", CompareOpName[ arg[0] ], 3); } else printOpField(os, "", OpName(op), 8); // print other fields size_t ncol = 5; switch( op ) { case CSkipOp: /* arg[0] = the Rel operator: Lt, Le, Eq, Ge, Gt, or Ne arg[1] & 1 = is left a variable arg[1] & 2 = is right a variable arg[2] = index correspoding to left arg[3] = index correspoding to right arg[4] = number of operations to skip if CExpOp comparision is true arg[5] = number of operations to skip if CExpOp comparision is false arg[6] -> arg[5+arg[4]] = skip operations if true arg[6+arg[4]] -> arg[5+arg[4]+arg[5]] = skip operations if false arg[6+arg[4]+arg[5]] = arg[4] + arg[5] */ CPPAD_ASSERT_UNKNOWN( arg[6+arg[4]+arg[5]] == arg[4]+arg[5] ); CPPAD_ASSERT_UNKNOWN(arg[1] != 0); if( arg[1] & 1 ) printOpField(os, " vl=", arg[2], ncol); else printOpField(os, " pl=", play->GetPar(arg[2]), ncol); if( arg[1] & 2 ) printOpField(os, " vr=", arg[3], ncol); else printOpField(os, " pr=", play->GetPar(arg[3]), ncol); if( size_t(arg[4]) < 3 ) { for(addr_t i = 0; i < arg[4]; i++) printOpField(os, " ot=", arg[6+i], ncol); } else { printOpField(os, "\n\tot=", arg[6+0], ncol); for(addr_t i = 1; i < arg[4]; i++) printOpField(os, " ot=", arg[6+i], ncol); } if( size_t(arg[5]) < 3 ) { for(addr_t i = 0; i < arg[5]; i++) printOpField(os, " of=", arg[6+arg[4]+i], ncol); } else { printOpField(os, "\n\tof=", arg[6+arg[4]+0], ncol); { for(addr_t i = 1; i < arg[5]; i++) printOpField(os, " of=", arg[6+arg[4]+i], ncol); } } break; case CSumOp: /* arg[0] = index of parameter that initializes summation arg[1] = end in arg of addition variables in summation arg[2] = end in arg of subtraction variables in summation arg[3] = end in arg of addition dynamic parameters in summation arg[4] = end in arg of subtraction dynamic parameters in summation arg[5], ... , arg[arg[1]-1]: indices for addition variables arg[arg[1]], ... , arg[arg[2]-1]: indices for subtraction variables arg[arg[2]], ... , arg[arg[3]-1]: indices for additon dynamics arg[arg[3]], ... , arg[arg[4]-1]: indices for subtraction dynamics arg[arg[4]] = arg[4] */ CPPAD_ASSERT_UNKNOWN( arg[arg[4]] == arg[4] ); printOpField(os, " pr=", play->GetPar(arg[0]), ncol); for(addr_t i = 5; i < arg[1]; i++) printOpField(os, " +v=", arg[i], ncol); for(addr_t i = arg[1]; i < arg[2]; i++) printOpField(os, " -v=", arg[i], ncol); for(addr_t i = arg[2]; i < arg[3]; i++) printOpField(os, " +d=", play->GetPar(arg[i]), ncol); for(addr_t i = arg[3]; i < arg[4]; i++) printOpField(os, " -d=", play->GetPar(arg[i]), ncol); break; case LdpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, "idx=", arg[1], ncol); break; case LdvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, " v=", arg[1], ncol); break; case StppOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, "idx=", arg[1], ncol); printOpField(os, " pr=", play->GetPar(arg[2]), ncol); break; case StpvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, "idx=", arg[1], ncol); printOpField(os, " vr=", arg[2], ncol); break; case StvpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, " vl=", arg[1], ncol); printOpField(os, " pr=", play->GetPar(arg[2]), ncol); break; case StvvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); printOpField(os, "off=", arg[0], ncol); printOpField(os, " vl=", arg[1], ncol); printOpField(os, " vr=", arg[2], ncol); break; case AddvvOp: case DivvvOp: case EqvvOp: case LevvOp: case LtvvOp: case NevvOp: case MulvvOp: case PowvvOp: case SubvvOp: case ZmulvvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " vl=", arg[0], ncol); printOpField(os, " vr=", arg[1], ncol); break; case AddpvOp: case EqpvOp: case DivpvOp: case LepvOp: case LtpvOp: case NepvOp: case SubpvOp: case MulpvOp: case PowpvOp: case ZmulpvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " pl=", play->GetPar(arg[0]), ncol); printOpField(os, " vr=", arg[1], ncol); break; case DivvpOp: case LevpOp: case LtvpOp: case PowvpOp: case SubvpOp: case ZmulvpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " vl=", arg[0], ncol); printOpField(os, " pr=", play->GetPar(arg[1]), ncol); break; 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 FunavOp: case TanOp: case TanhOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); printOpField(os, " v=", arg[0], ncol); break; case ErfOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); // arg[1] points to the parameter 0 // arg[2] points to the parameter 2 / sqrt(pi) printOpField(os, " v=", arg[0], ncol); break; case ParOp: case FunapOp: case FunrpOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); printOpField(os, " p=", play->GetPar(arg[0]), ncol); break; case AFunOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); { // get the name of this atomic function bool set_null = false; size_t atom_index = size_t( arg[0] ); size_t type = 0; // set to avoid warning std::string name; void* v_ptr = CPPAD_NULL; // set to avoid warning atomic_index<RecBase>(set_null, atom_index, type, &name, v_ptr); printOpField(os, " f=", name.c_str(), ncol); printOpField(os, " i=", arg[1], ncol); printOpField(os, " n=", arg[2], ncol); printOpField(os, " m=", arg[3], ncol); } break; case PriOp: CPPAD_ASSERT_NARG_NRES(op, 5, 0); if( arg[0] & 1 ) printOpField(os, " v=", arg[1], ncol); else printOpField(os, " p=", play->GetPar(arg[1]), ncol); os << "before=\"" << play->GetTxt(arg[2]) << "\""; if( arg[0] & 2 ) printOpField(os, " v=", arg[3], ncol); else printOpField(os, " p=", play->GetPar(arg[3]), ncol); os << "after=\"" << play->GetTxt(arg[4]) << "\""; break; case BeginOp: // argument not used (created by independent) CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); break; case EndOp: case InvOp: case FunrvOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); break; case DisOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); { const char* name = discrete<Base>::name(arg[0]); printOpField(os, " f=", name, ncol); printOpField(os, " x=", arg[1], ncol); } break; case CExpOp: CPPAD_ASSERT_UNKNOWN(arg[1] != 0); CPPAD_ASSERT_UNKNOWN( NumArg(op) == 6 ); if( arg[1] & 1 ) printOpField(os, " vl=", arg[2], ncol); else printOpField(os, " pl=", play->GetPar(arg[2]), ncol); if( arg[1] & 2 ) printOpField(os, " vr=", arg[3], ncol); else printOpField(os, " pr=", play->GetPar(arg[3]), ncol); if( arg[1] & 4 ) printOpField(os, " vt=", arg[4], ncol); else printOpField(os, " pt=", play->GetPar(arg[4]), ncol); if( arg[1] & 8 ) printOpField(os, " vf=", arg[5], ncol); else printOpField(os, " pf=", play->GetPar(arg[5]), ncol); break; case EqppOp: case LeppOp: case LtppOp: case NeppOp: CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); printOpField(os, " pl=", play->GetPar(arg[0]), ncol); printOpField(os, " pr=", play->GetPar(arg[1]), ncol); break; default: CPPAD_ASSERT_UNKNOWN(0); } }