VectorBase ADFun<Base>::SparseHessian( const VectorBase& x, const VectorBase& w, const VectorSet& p ) { size_t i, j, k; size_t n = Domain(); VectorBase hes(n * n); CPPAD_ASSERT_KNOWN( size_t(x.size()) == n, "SparseHessian: size of x not equal domain size for f." ); typedef typename VectorSet::value_type Set_type; typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type; // initialize the return value as zero Base zero(0); for(i = 0; i < n; i++) for(j = 0; j < n; j++) hes[i * n + j] = zero; // arguments to SparseHessianCompute Pattern_type s; CppAD::vector<size_t> row; CppAD::vector<size_t> col; sparse_hessian_work work; bool transpose = false; sparsity_user2internal(s, p, n, n, transpose); k = 0; for(i = 0; i < n; i++) { s.begin(i); j = s.next_element(); while( j != s.end() ) { row.push_back(i); col.push_back(j); k++; j = s.next_element(); } } size_t K = k; VectorBase H(K); // now we have folded this into the following case SparseHessianCompute(x, w, s, row, col, H, work); // now set the non-zero return values for(k = 0; k < K; k++) hes[ row[k] * n + col[k] ] = H[k]; return hes; }
void VectorBase<scalar,index,SizeAtCompileTime>::stCombine(const VectorBase& v1,const VectorBase& v2,VectorBase& v) { v.resize(v1.size()+v2.size()); index n = v1.size(); for ( index i = 0 ; i < n ; ++ i ) v[i] = v1[i]; for ( index i = 0 ; i < v2.size() ; ++ i ) v[i+n] = v2[i]; }
typename VectorBase<scalar,index,SizeAtCompileTime>::scalar VectorBase<scalar,index,SizeAtCompileTime>::dot(const VectorBase<scalar,index,S> &vec) const { if(this->size()!=vec.size()) { std::cerr<<"one size is "<<this->size()<<" and another size is "<<vec.size()<<std::endl; throw COException("VectorBase dot operation error: the length of two VectorBases do not equal to each other"); } else{ scalar sum = blas::copt_blas_dot(this->size(),this->dataPtr(),this->interval(),vec.dataPtr(),vec.interval()); return sum; } }
size_t ADFun<Base>::SparseJacobianReverse( const VectorBase& x , const VectorSet& p , const VectorSize& row , const VectorSize& col , VectorBase& jac , sparse_jacobian_work& work ) { size_t m = Range(); size_t n = Domain(); # ifndef NDEBUG size_t k, K = jac.size(); CPPAD_ASSERT_KNOWN( size_t(x.size()) == n , "SparseJacobianReverse: size of x not equal domain dimension for f." ); CPPAD_ASSERT_KNOWN( size_t(row.size()) == K && size_t(col.size()) == K , "SparseJacobianReverse: either r or c does not have " "the same size as jac." ); CPPAD_ASSERT_KNOWN( work.color.size() == 0 || work.color.size() == m, "SparseJacobianReverse: invalid value in work." ); for(k = 0; k < K; k++) { CPPAD_ASSERT_KNOWN( row[k] < m, "SparseJacobianReverse: invalid value in r." ); CPPAD_ASSERT_KNOWN( col[k] < n, "SparseJacobianReverse: invalid value in c." ); } if( work.color.size() != 0 ) for(size_t i = 0; i < m; i++) CPPAD_ASSERT_KNOWN( work.color[i] <= m, "SparseJacobianReverse: invalid value in work." ); # endif typedef typename VectorSet::value_type Set_type; typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type; Pattern_type s; if( work.color.size() == 0 ) { bool transpose = false; sparsity_user2internal(s, p, m, n, transpose); } size_t n_sweep = SparseJacobianRev(x, s, row, col, jac, work); return n_sweep; }
VectorBase<scalar,index,SizeAtCompileTime> VectorBase<scalar,index,SizeAtCompileTime>::operator- (const VectorBase<scalar,index,S> &vec) const { if(this->size()!=vec.size()) { std::cerr<<"one size is "<<this->size()<<" another size is "<<vec.size()<<std::endl; throw COException("VectorBase summation error: the length of two VectorBases do not equal to each other"); } VectorBase<scalar,index,Dynamic> result(this->size()); for ( index i = 0 ; i < this->size() ; ++ i ){ result[i] = this->operator[](i)-vec[i]; } return result; }
size_t ADFun<Base>::SparseHessian( const VectorBase& x , const VectorBase& w , const VectorSet& p , const VectorSize& row , const VectorSize& col , VectorBase& hes , sparse_hessian_work& work ) { size_t n = Domain(); # ifndef NDEBUG size_t k, K = hes.size(); CPPAD_ASSERT_KNOWN( size_t(x.size()) == n , "SparseHessian: size of x not equal domain dimension for f." ); CPPAD_ASSERT_KNOWN( size_t(row.size()) == K && size_t(col.size()) == K , "SparseHessian: either r or c does not have the same size as ehs." ); CPPAD_ASSERT_KNOWN( work.color.size() == 0 || work.color.size() == n, "SparseHessian: invalid value in work." ); for(k = 0; k < K; k++) { CPPAD_ASSERT_KNOWN( row[k] < n, "SparseHessian: invalid value in r." ); CPPAD_ASSERT_KNOWN( col[k] < n, "SparseHessian: invalid value in c." ); } if( work.color.size() != 0 ) for(size_t j = 0; j < n; j++) CPPAD_ASSERT_KNOWN( work.color[j] <= n, "SparseHessian: invalid value in work." ); # endif typedef typename VectorSet::value_type Set_type; typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type; Pattern_type s; if( work.color.size() == 0 ) { bool transpose = false; sparsity_user2internal(s, p, n, n, transpose); } size_t n_sweep = SparseHessianCompute(x, w, s, row, col, hes, work); return n_sweep; }
VectorBase<scalar,index,SizeAtCompileTime>::VectorBase( const VectorBase& vec ) : Array(), AbstractVector() { if (vec.isReferred()) { // the vector is a referred vector this->setReferredArray(vec.size(),const_cast<scalar*>(vec.dataPtr()),vec.interval()); } else{ // copy the vector data this->setArray(vec.size(),vec.dataPtr(),vec.interval()); } }
VectorBase subset(const VectorBase& x, size_t tapeid, int p=1){ VectorBase y; y.resize(vecind(tapeid).size()*p); for(int i=0;i<y.size()/p;i++) for(int j=0;j<p;j++) {y(i*p+j)=x(vecind(tapeid)[i]*p+j);} return y; }
bool VectorBase<scalar,index,SizeAtCompileTime>::operator!=(const VectorBase<scalar,index,S>& vec)const { if ( this->size() != vec.size() ) return true; for ( index i = 0 ; i < this->size() ; ++ i ){ if(this->operator[](i)!=vec[i]) return true; } return false; }
MatrixBase<scalar,index,Dynamic,Dynamic> VectorBase<scalar,index,SizeAtCompileTime>::mulTrans(const VectorBase<scalar,index,SizeAtCompileTime>& vec) const { index m = this->size(); index n = vec.size(); DMatrix result(m,n); for ( index i = 0 ; i < m ; ++ i ) for ( index j = 0 ; j < n ; ++ j ) result(i,j) = this->operator[](i)*vec[j]; return result; }
void VectorBase<scalar,index,SizeAtCompileTime>::blockFromVector(const VectorBase& vec,const std::vector<index>& indices) { this->resize(indices.size()); for ( index i = 0 ; i < indices.size() ; ++ i ){ if(indices[i] >= vec.size() ) { throw COException("Index out of range in Vector blocking!"); } this->operator[](i)=vec[indices[i]]; } }
void VectorBase<scalar,index,SizeAtCompileTime>::blockFromVector(const VectorBase& vec,const std::set<index>& indices) { if( *indices.rbegin() >= vec.size() ) { throw COException("Index out of range in Vector blocking!"); } this->resize(indices.size()); index i = 0; for ( const auto& s : indices ){ this->operator[](i) = vec[s]; ++ i; } }
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; }
void ADFun<Base>::SparseJacobianCase( const std::set<size_t>& set_type , const VectorBase& x , const VectorSet& p , VectorBase& jac ) { typedef CppAD::vector<size_t> SizeVector; typedef CppAD::vectorBool VectorBool; size_t i, j, k; size_t m = Range(); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorSet is Simple Vector class with sets for elements CheckSimpleVector<std::set<size_t>, VectorSet>( one_element_std_set<size_t>(), two_element_std_set<size_t>() ); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( x.size() == n, "SparseJacobian: size of x not equal domain dimension for f" ); CPPAD_ASSERT_KNOWN( p.size() == m, "SparseJacobian: using sets and size of p " "not equal range dimension for f" ); CPPAD_ASSERT_UNKNOWN(jac.size() == m * n); // point at which we are evaluating the Jacobian Forward(0, x); // initialize the return value for(i = 0; i < m; i++) for(j = 0; j < n; j++) jac[i * n + j] = zero; // create a copy of the transpose sparsity pattern VectorSet q(n); std::set<size_t>::const_iterator itr_i, itr_j; for(i = 0; i < m; i++) { itr_j = p[i].begin(); while( itr_j != p[i].end() ) { j = *itr_j++; q[j].insert(i); } } if( n <= m ) { // use forward mode ---------------------------------------- // initial coloring SizeVector color(n); for(j = 0; j < n; j++) color[j] = j; // See GreedyPartialD2Coloring Algorithm Section 3.6.2 of // Graph Coloring in Optimization Revisited by // Assefaw Gebremedhin, Fredrik Maane, Alex Pothen VectorBool forbidden(n); for(j = 0; j < n; j++) { // initial all colors as ok for this column for(k = 0; k < n; k++) forbidden[k] = false; // for each row connected to column j itr_i = q[j].begin(); while( itr_i != q[j].end() ) { i = *itr_i++; // for each column connected to row i itr_j = p[i].begin(); while( itr_j != p[i].end() ) { // if this is not j, forbid it k = *itr_j++; forbidden[ color[k] ] = (k != j); } } k = 0; while( forbidden[k] && k < n ) { k++; CPPAD_ASSERT_UNKNOWN( k < n ); } color[j] = k; } size_t n_color = 1; for(k = 0; k < n; k++) n_color = std::max(n_color, color[k] + 1); // direction vector for calls to forward VectorBase dx(n); // location for return values from Reverse VectorBase dy(m); // loop over colors size_t c; for(c = 0; c < n_color; c++) { // determine all the colums with this color for(j = 0; j < n; j++) { if( color[j] == c ) dx[j] = one; else dx[j] = zero; } // call forward mode for all these columns at once dy = Forward(1, dx); // set the corresponding components of the result for(j = 0; j < n; j++) if( color[j] == c ) { itr_i = q[j].begin(); while( itr_i != q[j].end() ) { i = *itr_i++; jac[i * n + j] = dy[i]; } } } } else { // use reverse mode ---------------------------------------- // initial coloring SizeVector color(m); for(i = 0; i < m; i++) color[i] = i; // See GreedyPartialD2Coloring Algorithm Section 3.6.2 of // Graph Coloring in Optimization Revisited by // Assefaw Gebremedhin, Fredrik Maane, Alex Pothen VectorBool forbidden(m); for(i = 0; i < m; i++) { // initial all colors as ok for this row for(k = 0; k < m; k++) forbidden[k] = false; // for each column connected to row i itr_j = p[i].begin(); while( itr_j != p[i].end() ) { j = *itr_j++; // for each row connected to column j itr_i = q[j].begin(); while( itr_i != q[j].end() ) { // if this is not i, forbid it k = *itr_i++; forbidden[ color[k] ] = (k != i); } } k = 0; while( forbidden[k] && k < m ) { k++; CPPAD_ASSERT_UNKNOWN( k < n ); } color[i] = k; } size_t n_color = 1; for(k = 0; k < m; k++) n_color = std::max(n_color, color[k] + 1); // weight vector for calls to reverse VectorBase w(m); // location for return values from Reverse VectorBase dw(n); // loop over colors size_t c; for(c = 0; c < n_color; c++) { // determine all the rows with this color for(i = 0; i < m; i++) { if( color[i] == c ) w[i] = one; else w[i] = zero; } // call reverse mode for all these rows at once dw = Reverse(1, w); // set the corresponding components of the result for(i = 0; i < m; i++) if( color[i] == c ) { itr_j = p[i].begin(); while( itr_j != p[i].end() ) { j = *itr_j++; jac[i * n + j] = dw[j]; } } } } }
size_t ADFun<Base>::SparseJacobianRev( const VectorBase& x , VectorSet& p , const VectorSize& row , const VectorSize& col , VectorBase& jac , sparse_jacobian_work& work ) { size_t i, k, ell; CppAD::vector<size_t>& order(work.order); CppAD::vector<size_t>& color(work.color); size_t m = Range(); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); CPPAD_ASSERT_UNKNOWN (color.size() == m || color.size() == 0 ); // number of components of Jacobian that are required size_t K = size_t(jac.size()); CPPAD_ASSERT_UNKNOWN( row.size() == K ); CPPAD_ASSERT_UNKNOWN( col.size() == K ); // Point at which we are evaluating the Jacobian Forward(0, x); // check for case where nothing (except Forward above) to do if( K == 0 ) return 0; if( color.size() == 0 ) { CPPAD_ASSERT_UNKNOWN( p.n_set() == m ); CPPAD_ASSERT_UNKNOWN( p.end() == n ); // execute the coloring algorithm color.resize(m); if( work.color_method == "cppad" ) color_general_cppad(p, row, col, color); else if( work.color_method == "colpack" ) { # if CPPAD_HAS_COLPACK color_general_colpack(p, row, col, color); # else CPPAD_ASSERT_KNOWN( false, "SparseJacobianReverse: work.color_method = colpack " "and colpack_prefix missing from cmake command line." ); # endif } else CPPAD_ASSERT_KNOWN( false, "SparseJacobianReverse: work.color_method is not valid." ); // put sorting indices in color order VectorSize key(K); order.resize(K); for(k = 0; k < K; k++) key[k] = color[ row[k] ]; index_sort(key, order); } size_t n_color = 1; for(i = 0; i < m; i++) if( color[i] < m ) n_color = std::max(n_color, color[i] + 1); // weighting vector for calls to reverse VectorBase w(m); // location for return values from Reverse VectorBase dw(n); // initialize the return value for(k = 0; k < K; k++) jac[k] = zero; // loop over colors k = 0; for(ell = 0; ell < n_color; ell++) { CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell ); // combine all the rows with this color for(i = 0; i < m; i++) { w[i] = zero; if( color[i] == ell ) w[i] = one; } // call reverse mode for all these rows at once dw = Reverse(1, w); // set the corresponding components of the result while( k < K && color[ row[order[k]] ] == ell ) { jac[ order[k] ] = dw[col[order[k]]]; k++; } } return n_color; }
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>::ForTwo( const VectorBase &x, const VectorSize_t &j, const VectorSize_t &k) { size_t i; size_t j1; size_t k1; size_t l; size_t n = Domain(); size_t m = Range(); size_t p = j.size(); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); // check VectorSize_t is Simple Vector class with size_t elements CheckSimpleVector<size_t, VectorSize_t>(); CPPAD_ASSERT_KNOWN( x.size() == n, "ForTwo: Length of x not equal domain dimension for f." ); CPPAD_ASSERT_KNOWN( j.size() == k.size(), "ForTwo: Lenght of the j and k vectors are not equal." ); // point at which we are evaluating the second partials Forward(0, x); // dimension the return value VectorBase ddy(m * p); // allocate memory to hold all possible diagonal Taylor coefficients // (for large sparse cases, this is not efficient) VectorBase D(m * n); // boolean flag for which diagonal coefficients are computed CppAD::vector<bool> c(n); for(j1 = 0; j1 < n; j1++) c[j1] = false; // direction vector in argument space VectorBase dx(n); for(j1 = 0; j1 < n; j1++) dx[j1] = Base(0); // result vector in range space VectorBase dy(m); // compute the diagonal coefficients that are needed for(l = 0; l < p; l++) { j1 = j[l]; k1 = k[l]; CPPAD_ASSERT_KNOWN( j1 < n, "ForTwo: an element of j not less than domain dimension for f." ); CPPAD_ASSERT_KNOWN( k1 < n, "ForTwo: an element of k not less than domain dimension for f." ); size_t count = 2; while(count) { count--; if( ! c[j1] ) { // diagonal term in j1 direction c[j1] = true; dx[j1] = Base(1); Forward(1, dx); dx[j1] = Base(0); dy = Forward(2, dx); for(i = 0; i < m; i++) D[i * n + j1 ] = dy[i]; } j1 = k1; } } // compute all the requested cross partials for(l = 0; l < p; l++) { j1 = j[l]; k1 = k[l]; if( j1 == k1 ) { for(i = 0; i < m; i++) ddy[i * p + l] = Base(2) * D[i * n + j1]; } else { // cross term in j1 and k1 directions dx[j1] = Base(1); dx[k1] = Base(1); Forward(1, dx); dx[j1] = Base(0); dx[k1] = Base(0); dy = Forward(2, dx); // place result in return value for(i = 0; i < m; i++) ddy[i * p + l] = dy[i] - D[i*n+j1] - D[i*n+k1]; } } return ddy; }
void addinsert(VectorBase& x, const VectorBase& y, size_t tapeid, int p=1){ for(int i=0;i<y.size()/p;i++) for(int j=0;j<p;j++) {x(vecind(tapeid)[i]*p+j)+=y(i*p+j);} }
VectorBase ADFun<Base>::RevTwo( const VectorBase &x, const VectorSize_t &i, const VectorSize_t &j) { size_t i1; size_t j1; size_t k; size_t l; size_t n = Domain(); size_t m = Range(); size_t p = i.size(); // check VectorBase is Simple Vector class with Base elements CheckSimpleVector<Base, VectorBase>(); // check VectorSize_t is Simple Vector class with size_t elements CheckSimpleVector<size_t, VectorSize_t>(); CPPAD_ASSERT_KNOWN( x.size() == n, "RevTwo: Length of x not equal domain dimension for f." ); CPPAD_ASSERT_KNOWN( i.size() == j.size(), "RevTwo: Lenght of the i and j vectors are not equal." ); // point at which we are evaluating the second partials Forward(0, x); // dimension the return value VectorBase ddw(n * p); // direction vector in argument space VectorBase dx(n); for(j1 = 0; j1 < n; j1++) dx[j1] = Base(0); // direction vector in range space VectorBase w(m); for(i1 = 0; i1 < m; i1++) w[i1] = Base(0); // place to hold the results of a reverse calculation VectorBase r(n * 2); // check the indices in i and j for(l = 0; l < p; l++) { i1 = i[l]; j1 = j[l]; CPPAD_ASSERT_KNOWN( i1 < m, "RevTwo: an eleemnt of i not less than range dimension for f." ); CPPAD_ASSERT_KNOWN( j1 < n, "RevTwo: an element of j not less than domain dimension for f." ); } // loop over all forward directions for(j1 = 0; j1 < n; j1++) { // first order forward mode calculation done bool first_done = false; for(l = 0; l < p; l++) if( j[l] == j1 ) { if( ! first_done ) { first_done = true; // first order forward mode in j1 direction dx[j1] = Base(1); Forward(1, dx); dx[j1] = Base(0); } // execute a reverse in this component direction i1 = i[l]; w[i1] = Base(1); r = Reverse(2, w); w[i1] = Base(0); // place the reverse result in return value for(k = 0; k < n; k++) ddw[k * p + l] = r[k * 2 + 1]; } } return ddw; }
VectorBase ADFun<Base>::Reverse(size_t p, const VectorBase &w) const { // 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(); Base *Partial = CPPAD_NULL; Partial = CPPAD_TRACK_NEW_VEC(total_num_var_ * p, Partial); // update maximum memory requirement // memoryMax = std::max( memoryMax, // Memory() + total_num_var_ * p * sizeof(Base) // ); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( w.size() == m, "Argument w to Reverse does not have length equal to\n" "the dimension of the range for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( p > 0, "The first argument to Reverse must be greater than zero." ); CPPAD_ASSERT_KNOWN( taylor_per_var_ >= p, "Less that p taylor_ coefficients are currently stored" " in this ADFun object." ); // initialize entire Partial matrix to zero for(i = 0; i < total_num_var_; i++) for(j = 0; j < p; j++) Partial[i * p + j] = Base(0); // 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] < total_num_var_ ); Partial[dep_taddr_[i] * p + p - 1] += w[i]; } // evaluate the derivatives ReverseSweep( p - 1, total_num_var_, &play_, taylor_col_dim_, taylor_, p, Partial ); // return the derivative values VectorBase value(n * p); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < total_num_var_ ); // 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^{(p-1)} w.r.t. u^{(p - 1 - k)} for(k = 0; k < p; k++) value[j * p + k ] = Partial[ind_taddr_[j] * p + p - 1 - k]; } // done with the Partial array CPPAD_TRACK_DEL_VEC(Partial); return value; }
SEXP attribute_hidden do_subassign_dflt(SEXP call, SEXP op, SEXP argsarg, SEXP rho) { GCStackRoot<PairList> args(SEXP_downcast<PairList*>(argsarg)); SEXP ignored, x, y; PairList* subs; int nsubs = SubAssignArgs(args, &x, &subs, &y); /* If there are multiple references to an object we must */ /* duplicate it so that only the local version is mutated. */ /* This will duplicate more often than necessary, but saves */ /* over always duplicating. */ if (MAYBE_SHARED(CAR(args))) { x = SETCAR(args, shallow_duplicate(CAR(args))); } bool S4 = IS_S4_OBJECT(x); SEXPTYPE xorigtype = TYPEOF(x); if (xorigtype == LISTSXP || xorigtype == LANGSXP) x = PairToVectorList(x); /* bug PR#2590 coerce only if null */ if (!x) x = coerceVector(x, TYPEOF(y)); switch (TYPEOF(x)) { case LGLSXP: case INTSXP: case REALSXP: case CPLXSXP: case STRSXP: case EXPRSXP: case VECSXP: case RAWSXP: { VectorBase* xv = static_cast<VectorBase*>(x); if (xv->size() == 0 && Rf_length(y) == 0) return x; size_t nsubs = listLength(subs); switch (nsubs) { case 0: x = VectorAssign(call, x, R_MissingArg, y); break; case 1: x = VectorAssign(call, x, subs->car(), y); break; default: x = ArrayAssign(call, x, subs, y); break; } } break; default: error(R_MSG_ob_nonsub, TYPEOF(x)); break; } if (xorigtype == LANGSXP) { if(Rf_length(x)) { GCStackRoot<PairList> xlr(static_cast<PairList*>(VectorToPairList(x))); GCStackRoot<Expression> xr(ConsCell::convert<Expression>(xlr)); x = xr; } else error(_("result is zero-length and so cannot be a language object")); } /* Note the setting of NAMED(x) to zero here. This means */ /* that the following assignment will not duplicate the value. */ /* This works because at this point, x is guaranteed to have */ /* at most one symbol bound to it. It does mean that there */ /* will be multiple reference problems if "[<-" is used */ /* in a naked fashion. */ SET_NAMED(x, 0); if (S4) SET_S4_OBJECT(x); return x; }
size_t ADFun<Base>::SparseJacobianRev( const VectorBase& x , VectorSet& p , VectorBase& jac , sparse_jacobian_work& work ) { using CppAD::vectorBool; size_t i, j, k, ell; CppAD::vector<size_t>& row(work.user_row); CppAD::vector<size_t>& col(work.user_col); CppAD::vector<size_t>& sort_row(work.sort_row); CppAD::vector<size_t>& color(work.color); size_t m = Range(); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); CPPAD_ASSERT_UNKNOWN (color.size() == m || color.size() == 0 ); // number of components of Jacobian that are required size_t K = size_t(jac.size()); CPPAD_ASSERT_UNKNOWN( row.size() == K+1 ); CPPAD_ASSERT_UNKNOWN( col.size() == K+1 ); CPPAD_ASSERT_UNKNOWN( row[K] == m ); CPPAD_ASSERT_UNKNOWN( col[K] == n ); // Point at which we are evaluating the Jacobian Forward(0, x); if( color.size() == 0 ) { CPPAD_ASSERT_UNKNOWN( p.n_set() == m ); CPPAD_ASSERT_UNKNOWN( p.end() == n ); // rows and columns that are in the returned jacobian VectorSet r_used, c_used; r_used.resize(n, m); c_used.resize(m, n); k = 0; while( k < K ) { CPPAD_ASSERT_UNKNOWN( row[sort_row[k]] < m && col[sort_row[k]] < n ); CPPAD_ASSERT_UNKNOWN( k == 0 || row[sort_row[k-1]] <= row[sort_row[k]] ); CPPAD_ASSERT_KNOWN( p.is_element(row[sort_row[k]], col[sort_row[k]]) , "SparseJacobianReverse: " "an (row, col) pair is not in sparsity pattern." ); r_used.add_element(col[sort_row[k]], row[sort_row[k]]); c_used.add_element(row[sort_row[k]], col[sort_row[k]]); k++; } // given a column index, which rows are non-zero and not used VectorSet not_used; not_used.resize(n, m); for(i = 0; i < m; i++) { p.begin(i); j = p.next_element(); while( j != p.end() ) { if( ! r_used.is_element(j , i) ) not_used.add_element(j, i); j = p.next_element(); } } // initial coloring color.resize(m); for(i = 0; i < m; i++) color[i] = i; // See GreedyPartialD2Coloring Algorithm Section 3.6.2 of // Graph Coloring in Optimization Revisited by // Assefaw Gebremedhin, Fredrik Maane, Alex Pothen vectorBool forbidden(m); for(i = 1; i < m; i++) { // initial all colors as ok for this row // (value of forbidden for ell > i does not matter) for(ell = 0; ell <= i; ell++) forbidden[ell] = false; // ----------------------------------------------------- // Forbid colors for which this row would destroy results // for each column that is non-zero for this row p.begin(i); j = p.next_element(); while( j != p.end() ) { // for each row that this column uses r_used.begin(j); ell = r_used.next_element(); while( ell != r_used.end() ) { // if this is not the same row, forbid its color if( ell < i ) forbidden[ color[ell] ] = true; ell = r_used.next_element(); } j = p.next_element(); } // ----------------------------------------------------- // Forbid colors that would destroy results for this row. // for each column that this row uses c_used.begin(i); j = c_used.next_element(); while( j != c_used.end() ) { // For each row that is non-zero for this column // (the used rows have already been checked above). not_used.begin(j); ell = not_used.next_element(); while( ell != not_used.end() ) { // if this is not the same row, forbid its color if( ell < i ) forbidden[ color[ell] ] = true; ell = not_used.next_element(); } j = c_used.next_element(); } // pick the color with smallest index ell = 0; while( forbidden[ell] ) { ell++; CPPAD_ASSERT_UNKNOWN( ell <= i ); } color[i] = ell; } } size_t n_color = 1; for(ell = 0; ell < m; ell++) n_color = std::max(n_color, color[ell] + 1); // weighting vector for calls to reverse VectorBase w(m); // location for return values from Reverse VectorBase dw(n); // initialize the return value for(k = 0; k < K; k++) jac[k] = zero; // loop over colors size_t n_sweep = 0; for(ell = 0; ell < n_color; ell++) { bool any = false; k = 0; for(i = 0; i < m; i++) if( color[i] == ell ) { // find first k such that row[sort_row[k]] has color ell if( ! any ) { while( row[sort_row[k]] < i ) k++; any = row[sort_row[k]] == i; } } if( any ) { n_sweep++; // combine all the rows with this color for(i = 0; i < m; i++) { w[i] = zero; if( color[i] == ell ) w[i] = one; } // call reverse mode for all these rows at once dw = Reverse(1, w); // set the corresponding components of the result for(i = 0; i < m; i++) if( color[i] == ell ) { // find first index in r for this row while( row[sort_row[k]] < i ) k++; // extract the row results for this row while( row[sort_row[k]] == i ) { jac[ sort_row[k] ] = dw[col[sort_row[k]]]; k++; } } } } return n_sweep; }
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; }
size_t ADFun<Base>::SparseJacobianReverse( const VectorBase& x , const VectorSet& p , const VectorSize& row , const VectorSize& col , VectorBase& jac , sparse_jacobian_work& work ) { size_t m = Range(); size_t n = Domain(); size_t k, K = jac.size(); if( work.user_row.size() == 0 ) { // create version of (row, col, k) sorted by row row value work.user_col.resize(K+1); work.user_row.resize(K+1); work.sort_row.resize(K+1); // put sorted indices in user_row and user_col for(k = 0; k < K; k++) { work.user_row[k] = row[k]; work.user_col[k] = col[k]; } work.user_row[K] = m; work.user_col[K] = n; // put sorting indices in sort_row index_sort(work.user_row, work.sort_row); } # ifndef NDEBUG CPPAD_ASSERT_KNOWN( size_t(x.size()) == n , "SparseJacobianReverse: size of x not equal domain dimension for f." ); CPPAD_ASSERT_KNOWN( size_t(row.size()) == K && size_t(col.size()) == K , "SparseJacobianReverse: either r or c does not have " "the same size as jac." ); CPPAD_ASSERT_KNOWN( work.user_row.size() == K+1 && work.user_col.size() == K+1 && work.sort_row.size() == K+1 , "SparseJacobianReverse: invalid value in work." ); CPPAD_ASSERT_KNOWN( work.color.size() == 0 || work.color.size() == m, "SparseJacobianReverse: invalid value in work." ); for(k = 0; k < K; k++) { CPPAD_ASSERT_KNOWN( row[k] < m, "SparseJacobianReverse: invalid value in r." ); CPPAD_ASSERT_KNOWN( col[k] < n, "SparseJacobianReverse: invalid value in c." ); CPPAD_ASSERT_KNOWN( work.sort_row[k] < K, "SparseJacobianReverse: invalid value in work." ); CPPAD_ASSERT_KNOWN( work.user_row[k] == row[k], "SparseJacobianReverse: invalid value in work." ); CPPAD_ASSERT_KNOWN( work.user_col[k] == col[k], "SparseJacobianReverse: invalid value in work." ); } if( work.color.size() != 0 ) for(size_t i = 0; i < m; i++) CPPAD_ASSERT_KNOWN( work.color[i] < m, "SparseJacobianReverse: invalid value in work." ); # endif typedef typename VectorSet::value_type Set_type; typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type; Pattern_type s; if( work.color.size() == 0 ) { bool transpose = false; sparsity_user2internal(s, p, m, n, transpose); } size_t n_sweep = SparseJacobianRev(x, s, jac, work); return n_sweep; }
size_t ADFun<Base>::SparseHessianCompute( const VectorBase& x , const VectorBase& w , VectorSet& sparsity , const VectorSize& row , const VectorSize& col , VectorBase& hes , sparse_hessian_work& work ) { using CppAD::vectorBool; size_t i, k, ell; CppAD::vector<size_t>& color(work.color); CppAD::vector<size_t>& order(work.order); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n ); // number of components of Hessian that are required size_t K = hes.size(); CPPAD_ASSERT_UNKNOWN( row.size() == K ); CPPAD_ASSERT_UNKNOWN( col.size() == K ); // Point at which we are evaluating the Hessian Forward(0, x); // check for case where nothing (except Forward above) to do if( K == 0 ) return 0; // Rows of the Hessian (i below) correspond to the forward mode index // and columns (j below) correspond to the reverse mode index. if( color.size() == 0 ) { CPPAD_ASSERT_UNKNOWN( sparsity.n_set() == n ); CPPAD_ASSERT_UNKNOWN( sparsity.end() == n ); // execute coloring algorithm color.resize(n); color_general_cppad(sparsity, row, col, color); // put sorting indices in color order VectorSize key(K); order.resize(K); for(k = 0; k < K; k++) key[k] = color[ row[k] ]; index_sort(key, order); } size_t n_color = 1; for(ell = 0; ell < n; ell++) if( color[ell] < n ) n_color = std::max(n_color, color[ell] + 1); // direction vector for calls to forward (rows of the Hessian) VectorBase u(n); // location for return values from reverse (columns of the Hessian) VectorBase ddw(2 * n); // initialize the return value for(k = 0; k < K; k++) hes[k] = zero; // loop over colors k = 0; for(ell = 0; ell < n_color; ell++) { CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell ); // combine all rows with this color for(i = 0; i < n; i++) { u[i] = zero; if( color[i] == ell ) u[i] = one; } // call forward mode for all these rows at once Forward(1, u); // evaluate derivative of w^T * F'(x) * u ddw = Reverse(2, w); // set the corresponding components of the result while( k < K && color[ row[ order[k] ] ] == ell ) { hes[ order[k] ] = ddw[ col[ order[k] ] * 2 + 1 ]; k++; } } return n_color; }
size_t ADFun<Base>::SparseJacobianFor( const VectorBase& x , VectorSet& p_transpose , const VectorSize& row , const VectorSize& col , VectorBase& jac , sparse_jacobian_work& work ) { size_t j, k, ell; CppAD::vector<size_t>& order(work.order); CppAD::vector<size_t>& color(work.color); size_t m = Range(); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n ); // number of components of Jacobian that are required size_t K = size_t(jac.size()); CPPAD_ASSERT_UNKNOWN( row.size() == K ); CPPAD_ASSERT_UNKNOWN( col.size() == K ); // Point at which we are evaluating the Jacobian Forward(0, x); // check for case where nothing (except Forward above) to do if( K == 0 ) return 0; if( color.size() == 0 ) { CPPAD_ASSERT_UNKNOWN( p_transpose.n_set() == n ); CPPAD_ASSERT_UNKNOWN( p_transpose.end() == m ); // execute coloring algorithm color.resize(n); if( work.color_method == "cppad" ) color_general_cppad(p_transpose, col, row, color); else if( work.color_method == "colpack" ) { # if CPPAD_HAS_COLPACK color_general_colpack(p_transpose, col, row, color); # else CPPAD_ASSERT_KNOWN( false, "SparseJacobianForward: work.color_method = colpack " "and colpack_prefix missing from cmake command line." ); # endif } else CPPAD_ASSERT_KNOWN( false, "SparseJacobianForward: work.color_method is not valid." ); // put sorting indices in color order VectorSize key(K); order.resize(K); for(k = 0; k < K; k++) key[k] = color[ col[k] ]; index_sort(key, order); } size_t n_color = 1; for(j = 0; j < n; j++) if( color[j] < n ) n_color = std::max(n_color, color[j] + 1); // initialize the return value for(k = 0; k < K; k++) jac[k] = zero; # if CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION == 1 // direction vector and return values for calls to forward VectorBase dx(n), dy(m); // loop over colors k = 0; for(ell = 0; ell < n_color; ell++) { CPPAD_ASSERT_UNKNOWN( color[ col[ order[k] ] ] == ell ); // combine all columns with this color for(j = 0; j < n; j++) { dx[j] = zero; if( color[j] == ell ) dx[j] = one; } // call forward mode for all these columns at once dy = Forward(1, dx); // set the corresponding components of the result while( k < K && color[ col[order[k]] ] == ell ) { jac[ order[k] ] = dy[row[order[k]]]; k++; } } # else // abbreviation for this value size_t max_r = CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION; CPPAD_ASSERT_UNKNOWN( max_r > 1 ); // count the number of colors done so far size_t count_color = 0; // count the sparse matrix entries done so far k = 0; while( count_color < n_color ) { // number of colors we will do this time size_t r = std::min(max_r , n_color - count_color); VectorBase dx(n * r), dy(m * r); // loop over colors we will do this tme for(ell = 0; ell < r; ell++) { // combine all columns with this color for(j = 0; j < n; j++) { dx[j * r + ell] = zero; if( color[j] == ell + count_color ) dx[j * r + ell] = one; } } size_t q = 1; dy = Forward(q, r, dx); // store results for(ell = 0; ell < r; ell++) { // set the components of the result for this color while( k < K && color[ col[order[k]] ] == ell + count_color ) { jac[ order[k] ] = dy[ row[order[k]] * r + ell ]; k++; } } count_color += r; } # endif return n_color; }
VectorBase ADFun<Base>::Reverse(size_t p, 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(total_num_var_ * p); // update maximum memory requirement // memoryMax = std::max( memoryMax, // Memory() + total_num_var_ * p * 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 * p), "Argument w to Reverse does not have length equal to\n" "the dimension of the range for the corresponding ADFun." ); CPPAD_ASSERT_KNOWN( p > 0, "The first argument to Reverse must be greater than zero." ); CPPAD_ASSERT_KNOWN( taylor_per_var_ >= p, "Less that p taylor_ coefficients are currently stored" " in this ADFun object." ); // initialize entire Partial matrix to zero for(i = 0; i < total_num_var_; i++) for(j = 0; j < p; j++) Partial[i * p + 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] < total_num_var_ ); if( size_t(w.size()) == m ) Partial[dep_taddr_[i] * p + p - 1] += w[i]; else { for(k = 0; k < p; k++) // ? should use += here, first make test to demonstrate bug Partial[ dep_taddr_[i] * p + k ] = w[i * p + k ]; } } // evaluate the derivatives ReverseSweep( p - 1, n, total_num_var_, &play_, taylor_col_dim_, taylor_.data(), p, Partial.data(), cskip_op_ ); // return the derivative values VectorBase value(n * p); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < total_num_var_ ); // 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^{(p-1)} w.r.t. u^{(p - 1 - k)} if( size_t(w.size()) == m ) { for(k = 0; k < p; k++) value[j * p + k ] = Partial[ind_taddr_[j] * p + p - 1 - k]; } else { for(k = 0; k < p; k++) value[j * p + k ] = Partial[ind_taddr_[j] * p + k]; } } CPPAD_ASSERT_KNOWN( ! ( hasnan(value) && check_for_nan_ ) , "dw = f.Reverse(p, w): has a nan,\n" "but none of its Taylor coefficents are nan." ); return value; }
void ADFun<Base>::SparseJacobianCase( bool set_type , const VectorBase& x , const VectorSet& p , VectorBase& jac ) { typedef CppAD::vector<size_t> SizeVector; typedef CppAD::vectorBool VectorBool; size_t i, j, k; size_t m = Range(); size_t n = Domain(); // some values const Base zero(0); const Base one(1); // check VectorSet is Simple Vector class with bool elements CheckSimpleVector<bool, VectorSet>(); // check VectorBase is Simple Vector class with Base type elements CheckSimpleVector<Base, VectorBase>(); CPPAD_ASSERT_KNOWN( x.size() == n, "SparseJacobian: size of x not equal domain dimension for f" ); CPPAD_ASSERT_KNOWN( p.size() == m * n, "SparseJacobian: using bool values and size of p " " not equal range dimension times domain dimension for f" ); CPPAD_ASSERT_UNKNOWN(jac.size() == m * n); // point at which we are evaluating the Jacobian Forward(0, x); // initialize the return value for(i = 0; i < m; i++) for(j = 0; j < n; j++) jac[i * n + j] = zero; if( n <= m ) { // use forward mode ---------------------------------------- // initial coloring SizeVector color(n); for(j = 0; j < n; j++) color[j] = j; // See GreedyPartialD2Coloring Algorithm Section 3.6.2 of // Graph Coloring in Optimization Revisited by // Assefaw Gebremedhin, Fredrik Maane, Alex Pothen VectorBool forbidden(n); for(j = 0; j < n; j++) { // initial all colors as ok for this column for(k = 0; k < n; k++) forbidden[k] = false; // for each row that is connected to column j for(i = 0; i < m; i++) if( p[i * n + j] ) { // for each column that is connected to row i for(k = 0; k < n; k++) if( p[i * n + k] & (j != k) ) forbidden[ color[k] ] = true; } k = 0; while( forbidden[k] && k < n ) { k++; CPPAD_ASSERT_UNKNOWN( k < n ); } color[j] = k; } size_t n_color = 1; for(k = 0; k < n; k++) n_color = std::max(n_color, color[k] + 1); // direction vector for calls to forward VectorBase dx(n); // location for return values from Reverse VectorBase dy(m); // loop over colors size_t c; for(c = 0; c < n_color; c++) { // determine all the colums with this color for(j = 0; j < n; j++) { if( color[j] == c ) dx[j] = one; else dx[j] = zero; } // call forward mode for all these columns at once dy = Forward(1, dx); // set the corresponding components of the result for(j = 0; j < n; j++) if( color[j] == c ) { for(i = 0; i < m; i++) if( p[ i * n + j ] ) jac[i * n + j] = dy[i]; } } } else { // use reverse mode ---------------------------------------- // initial coloring SizeVector color(m); for(i = 0; i < m; i++) color[i] = i; // See GreedyPartialD2Coloring Algorithm Section 3.6.2 of // Graph Coloring in Optimization Revisited by // Assefaw Gebremedhin, Fredrik Maane, Alex Pothen VectorBool forbidden(m); for(i = 0; i < m; i++) { // initial all colors as ok for this row for(k = 0; k < m; k++) forbidden[k] = false; // for each column that is connected to row i for(j = 0; j < n; j++) if( p[i * n + j] ) { // for each row that is connected to column j for(k = 0; k < m; k++) if( p[k * n + j] & (i != k) ) forbidden[ color[k] ] = true; } k = 0; while( forbidden[k] && k < m ) { k++; CPPAD_ASSERT_UNKNOWN( k < n ); } color[i] = k; } size_t n_color = 1; for(k = 0; k < m; k++) n_color = std::max(n_color, color[k] + 1); // weight vector for calls to reverse VectorBase w(m); // location for return values from Reverse VectorBase dw(n); // loop over colors size_t c; for(c = 0; c < n_color; c++) { // determine all the rows with this color for(i = 0; i < m; i++) { if( color[i] == c ) w[i] = one; else w[i] = zero; } // call reverse mode for all these rows at once dw = Reverse(1, w); // set the corresponding components of the result for(i = 0; i < m; i++) if( color[i] == c ) { for(j = 0; j < n; j++) if( p[ i * n + j ] ) jac[i * n + j] = dw[j]; } } } }
VectorBase ADFun<Base>::SparseJacobian( const VectorBase& x, const VectorSet& p ) { size_t i, j, k; size_t m = Range(); size_t n = Domain(); VectorBase jac(m * n); CPPAD_ASSERT_KNOWN( size_t(x.size()) == n, "SparseJacobian: size of x not equal domain size for f." ); CheckSimpleVector<Base, VectorBase>(); typedef typename VectorSet::value_type Set_type; typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type; // initialize the return value as zero Base zero(0); for(i = 0; i < m; i++) for(j = 0; j < n; j++) jac[i * n + j] = zero; sparse_jacobian_work work; CppAD::vector<size_t> row; CppAD::vector<size_t> col; if( n <= m ) { // need an internal copy of sparsity pattern Pattern_type s_transpose; bool transpose = true; sparsity_user2internal(s_transpose, p, m, n, transpose); k = 0; for(j = 0; j < n; j++) { s_transpose.begin(j); i = s_transpose.next_element(); while( i != s_transpose.end() ) { row.push_back(i); col.push_back(j); k++; i = s_transpose.next_element(); } } size_t K = k; VectorBase J(K); // now we have folded this into the following case SparseJacobianFor(x, s_transpose, row, col, J, work); // now set the non-zero return values for(k = 0; k < K; k++) jac[ row[k] * n + col[k] ] = J[k]; } else { // need an internal copy of sparsity pattern Pattern_type s; bool transpose = false; sparsity_user2internal(s, p, m, n, transpose); k = 0; for(i = 0; i < m; i++) { s.begin(i); j = s.next_element(); while( j != s.end() ) { row.push_back(i); col.push_back(j); k++; j = s.next_element(); } } size_t K = k; VectorBase J(K); // now we have folded this into the following case SparseJacobianRev(x, s, row, col, J, work); // now set the non-zero return values for(k = 0; k < K; k++) jac[ row[k] * n + col[k] ] = J[k]; } return jac; }