void ADFun<Base>::capacity_order(size_t c) { size_t r; if( (c == 0) | (c == 1) ) { r = c; capacity_order(c, r); return; } r = num_direction_taylor_; if( r == 0 ) r = 1; capacity_order(c, r); return; }
VectorBase ADFun<Base>::Forward( size_t q , const VectorBase& xq , std::ostream& s ) { // temporary indices size_t i, j, k; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); // check Vector is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( size_t(xq.size()) == n || size_t(xq.size()) == n*(q+1), "Forward(q, xq): xq.size() is not equal n or n*(q+1)" ); // lowest order we are computing size_t p = q + 1 - size_t(xq.size()) / n; CPPAD_ASSERT_UNKNOWN( p == 0 || p == q ); CPPAD_ASSERT_KNOWN( q <= num_order_taylor_ || p == 0, "Forward(q, xq): Number of Taylor coefficient orders stored in this" " ADFun\nis less than q and xq.size() != n*(q+1)." ); CPPAD_ASSERT_KNOWN( p <= 1 || num_direction_taylor_ == 1, "Forward(q, xq): computing order q >= 2" " and number of directions is not one." "\nMust use Forward(q, r, xq) for this case" ); // does taylor_ need more orders or fewer directions if( (cap_order_taylor_ <= q) | (num_direction_taylor_ != 1) ) { if( p == 0 ) { // no need to copy old values during capacity_order num_order_taylor_ = 0; } else num_order_taylor_ = q; size_t c = std::max(q + 1, cap_order_taylor_); size_t r = 1; capacity_order(c, r); } CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ > q ); CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == 1 ); // short hand notation for order capacity size_t C = cap_order_taylor_; // set Taylor coefficients for independent variables for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); if( p == q ) taylor_[ C * ind_taddr_[j] + q] = xq[j]; else { for(k = 0; k <= q; k++) taylor_[ C * ind_taddr_[j] + k] = xq[ (q+1)*j + k]; } } // evaluate the derivatives CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); CPPAD_ASSERT_UNKNOWN( load_op_.size() == play_.num_load_op_rec() ); if( q == 0 ) { forward0sweep(s, true, n, num_var_tape_, &play_, C, taylor_.data(), cskip_op_.data(), load_op_, compare_change_count_, compare_change_number_, compare_change_op_index_ ); } else { forward1sweep(s, true, p, q, n, num_var_tape_, &play_, C, taylor_.data(), cskip_op_.data(), load_op_, compare_change_count_, compare_change_number_, compare_change_op_index_ ); } // return Taylor coefficients for dependent variables VectorBase yq; if( p == q ) { yq.resize(m); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); yq[i] = taylor_[ C * dep_taddr_[i] + q]; } } else { yq.resize(m * (q+1) ); for(i = 0; i < m; i++) { for(k = 0; k <= q; k++) yq[ (q+1) * i + k] = taylor_[ C * dep_taddr_[i] + k ]; } } # ifndef NDEBUG if( check_for_nan_ ) { bool ok = true; if( p == 0 ) { for(i = 0; i < m; i++) { // Visual Studio 2012, CppAD required in front of isnan ? ok &= ! CppAD::isnan( yq[ (q+1) * i + 0 ] ); } } CPPAD_ASSERT_KNOWN(ok, "yq = f.Forward(q, xq): has a zero order Taylor coefficient " "with the value nan." ); if( 0 < q ) { for(i = 0; i < m; i++) { for(k = p; k <= q; k++) { // Studio 2012, CppAD required in front of isnan ? ok &= ! CppAD::isnan( yq[ (q+1-p)*i + k-p ] ); } } } CPPAD_ASSERT_KNOWN(ok, "yq = f.Forward(q, xq): has a non-zero order Taylor coefficient\n" "with the value nan (but zero order coefficients are not nan)." ); } # endif // now we have q + 1 taylor_ coefficient orders per variable num_order_taylor_ = q + 1; return yq; }
VectorBase ADFun<Base>::Reverse(size_t q, const VectorBase &w) { // constants const Base zero(0); // temporary indices size_t i, j, k; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); pod_vector<Base> Partial; Partial.extend(num_var_tape_ * q); // update maximum memory requirement // memoryMax = std::max( memoryMax, // Memory() + num_var_tape_ * q * sizeof(Base) // ); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( size_t(w.size()) == m || size_t(w.size()) == (m * q), "Argument w to Reverse does not have length equal to\n" "the dimension of the range for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( q > 0, "The first argument to Reverse must be greater than zero." ); CPPAD_ASSERT_KNOWN( num_order_taylor_ >= q, "Less that q taylor_ coefficients are currently stored" " in this ADFun object." ); // special case where multiple forward directions have been computed, // but we are only using the one direction zero order results if( (q == 1) & (num_direction_taylor_ > 1) ) { num_order_taylor_ = 1; // number of orders to copy size_t c = cap_order_taylor_; // keep the same capacity setting size_t r = 1; // only keep one direction capacity_order(c, r); } CPPAD_ASSERT_KNOWN( num_direction_taylor_ == 1, "Reverse mode for Forward(q, r, xq) with more than one direction" "\n(r > 1) is not yet supported for q > 1." ); // initialize entire Partial matrix to zero for(i = 0; i < num_var_tape_; i++) for(j = 0; j < q; j++) Partial[i * q + j] = zero; // set the dependent variable direction // (use += because two dependent variables can point to same location) for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); if( size_t(w.size()) == m ) Partial[dep_taddr_[i] * q + q - 1] += w[i]; else { for(k = 0; k < q; k++) // ? should use += here, first make test to demonstrate bug Partial[ dep_taddr_[i] * q + k ] = w[i * q + k ]; } } // evaluate the derivatives CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); CPPAD_ASSERT_UNKNOWN( load_op_.size() == play_.num_load_op_rec() ); ReverseSweep( q - 1, n, num_var_tape_, &play_, cap_order_taylor_, taylor_.data(), q, Partial.data(), cskip_op_.data(), load_op_ ); // return the derivative values VectorBase value(n * q); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // independent variable taddr equals its operator taddr CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); // by the Reverse Identity Theorem // partial of y^{(k)} w.r.t. u^{(0)} is equal to // partial of y^{(q-1)} w.r.t. u^{(q - 1 - k)} if( size_t(w.size()) == m ) { for(k = 0; k < q; k++) value[j * q + k ] = Partial[ind_taddr_[j] * q + q - 1 - k]; } else { for(k = 0; k < q; k++) value[j * q + k ] = Partial[ind_taddr_[j] * q + k]; } } CPPAD_ASSERT_KNOWN( ! ( hasnan(value) && check_for_nan_ ) , "dw = f.Reverse(q, w): has a nan,\n" "but none of its Taylor coefficents are nan." ); return value; }
VectorBase ADFun<Base>::Forward( size_t q , size_t r , const VectorBase& xq ) { // temporary indices size_t i, j, ell; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); // check Vector is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( q > 0, "Forward(q, r, xq): q == 0" ); CPPAD_ASSERT_KNOWN( size_t(xq.size()) == r * n, "Forward(q, r, xq): xq.size() is not equal r * n" ); CPPAD_ASSERT_KNOWN( q <= num_order_taylor_ , "Forward(q, r, xq): Number of Taylor coefficient orders stored in" " this ADFun is less than q" ); CPPAD_ASSERT_KNOWN( q == 1 || num_direction_taylor_ == r , "Forward(q, r, xq): q > 1 and number of Taylor directions r" " is not same as previous Forward(1, r, xq)" ); // does taylor_ need more orders or new number of directions if( cap_order_taylor_ <= q || num_direction_taylor_ != r ) { if( num_direction_taylor_ != r ) num_order_taylor_ = 1; size_t c = std::max(q + 1, cap_order_taylor_); capacity_order(c, r); } CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ > q ); CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == r ) // short hand notation for order capacity size_t c = cap_order_taylor_; // set Taylor coefficients for independent variables for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == InvOp ); for(ell = 0; ell < r; ell++) { size_t index = ((c-1)*r + 1)*ind_taddr_[j] + (q-1)*r + ell + 1; taylor_[ index ] = xq[ r * j + ell ]; } } // evaluate the derivatives CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); CPPAD_ASSERT_UNKNOWN( load_op_.size() == play_.num_load_op_rec() ); forward2sweep( q, r, n, num_var_tape_, &play_, c, taylor_.data(), cskip_op_.data(), load_op_ ); // return Taylor coefficients for dependent variables VectorBase yq; yq.resize(r * m); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); for(ell = 0; ell < r; ell++) { size_t index = ((c-1)*r + 1)*dep_taddr_[i] + (q-1)*r + ell + 1; yq[ r * i + ell ] = taylor_[ index ]; } } # ifndef NDEBUG if( check_for_nan_ ) { bool ok = true; for(i = 0; i < m; i++) { for(ell = 0; ell < r; ell++) { // Studio 2012, CppAD required in front of isnan ? ok &= ! CppAD::isnan( yq[ r * i + ell ] ); } } CPPAD_ASSERT_KNOWN(ok, "yq = f.Forward(q, r, xq): has a non-zero order Taylor coefficient\n" "with the value nan (but zero order coefficients are not nan)." ); } # endif // now we have q + 1 taylor_ coefficient orders per variable num_order_taylor_ = q + 1; return yq; }
VectorBase ADFun<Base>::Forward( size_t q , const VectorBase& xq , std::ostream& s ) { // temporary indices size_t i, j, k; // number of independent variables size_t n = ind_taddr_.size(); // number of dependent variables size_t m = dep_taddr_.size(); // check Vector is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( size_t(xq.size()) == n || size_t(xq.size()) == n*(q+1), "Forward(q, xq): xq.size() is not equal n or n*(q+1)" ); // lowest order we are computing size_t p = q + 1 - size_t(xq.size()) / n; CPPAD_ASSERT_UNKNOWN( p == 0 || p == q ); CPPAD_ASSERT_KNOWN( q <= num_order_taylor_ || p == 0, "Forward(q, xq): Number of Taylor coefficient orders stored in this" " ADFun\nis less than q and xq.size() != n*(q+1)." ); CPPAD_ASSERT_KNOWN( p <= 1 || num_direction_taylor_ == 1, "Forward(q, xq): computing order q >= 2" " and number of directions is not one." "\nMust use Forward(q, r, xq) for this case" ); // does taylor_ need more orders or fewer directions if( (cap_order_taylor_ <= q) | (num_direction_taylor_ != 1) ) { if( p == 0 ) { // no need to copy old values during capacity_order num_order_taylor_ = 0; } else num_order_taylor_ = q; size_t c = std::max(q + 1, cap_order_taylor_); size_t r = 1; capacity_order(c, r); } CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ > q ); CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == 1 ); // short hand notation for order capacity size_t C = cap_order_taylor_; // The optimizer may skip a step that does not affect dependent variables. // Initilaizing zero order coefficients avoids following valgrind warning: // "Conditional jump or move depends on uninitialised value(s)". for(j = 0; j < num_var_tape_; j++) { for(k = p; k <= q; k++) taylor_[C * j + k] = CppAD::numeric_limits<Base>::quiet_NaN(); } // set Taylor coefficients for independent variables for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); // ind_taddr_[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); if( p == q ) taylor_[ C * ind_taddr_[j] + q] = xq[j]; else { for(k = 0; k <= q; k++) taylor_[ C * ind_taddr_[j] + k] = xq[ (q+1)*j + k]; } } // evaluate the derivatives CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); CPPAD_ASSERT_UNKNOWN( load_op_.size() == play_.num_load_op_rec() ); if( q == 0 ) { local::forward0sweep(s, true, n, num_var_tape_, &play_, C, taylor_.data(), cskip_op_.data(), load_op_, compare_change_count_, compare_change_number_, compare_change_op_index_ ); } else { local::forward1sweep(s, true, p, q, n, num_var_tape_, &play_, C, taylor_.data(), cskip_op_.data(), load_op_, compare_change_count_, compare_change_number_, compare_change_op_index_ ); } // return Taylor coefficients for dependent variables VectorBase yq; if( p == q ) { yq.resize(m); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); yq[i] = taylor_[ C * dep_taddr_[i] + q]; } } else { yq.resize(m * (q+1) ); for(i = 0; i < m; i++) { for(k = 0; k <= q; k++) yq[ (q+1) * i + k] = taylor_[ C * dep_taddr_[i] + k ]; } } # ifndef NDEBUG if( check_for_nan_ ) { bool ok = true; size_t index = m; if( p == 0 ) { for(i = 0; i < m; i++) { // Visual Studio 2012, CppAD required in front of isnan ? if( CppAD::isnan( yq[ (q+1) * i + 0 ] ) ) { ok = false; if( index == m ) index = i; } } } if( ! ok ) { CPPAD_ASSERT_UNKNOWN( index < m ); // CppAD::vector<Base> x0(n); for(j = 0; j < n; j++) x0[j] = taylor_[ C * ind_taddr_[j] + 0 ]; std::string file_name; put_check_for_nan(x0, file_name); std::stringstream ss; ss << "yq = f.Forward(q, xq): a zero order Taylor coefficient is nan.\n" "Corresponding independent variables vector was written " "to binary a file.\n" "vector_size = " << n << "\n" << "file_name = " << file_name << "\n" << "index = " << index << "\n"; // ss.str() returns a string object with a copy of the current // contents in the stream buffer. std::string msg_str = ss.str(); // msg_str.c_str() returns a pointer to the c-string // representation of the string object's value. const char* msg_char_star = msg_str.c_str(); ErrorHandler::Call( true, __LINE__, __FILE__, "if( CppAD::isnan( yq[ (q+1) * index + 0 ] )", msg_char_star ); } CPPAD_ASSERT_KNOWN(ok, "with the value nan." ); if( 0 < q ) { for(i = 0; i < m; i++) { for(k = p; k <= q; k++) { // Studio 2012, CppAD required in front of isnan ? ok &= ! CppAD::isnan( yq[ (q+1-p)*i + k-p ] ); } } } CPPAD_ASSERT_KNOWN(ok, "yq = f.Forward(q, xq): has a non-zero order Taylor coefficient\n" "with the value nan (but zero order coefficients are not nan)." ); } # endif // now we have q + 1 taylor_ coefficient orders per variable num_order_taylor_ = q + 1; return yq; }