void color_general_cppad( const VectorSet& pattern , const VectorSize& row , const VectorSize& col , CppAD::vector<size_t>& color ) { size_t i, j, k, ell, r; size_t K = row.size(); size_t m = pattern.n_set(); size_t n = pattern.end(); CPPAD_ASSERT_UNKNOWN( size_t( col.size() ) == K ); CPPAD_ASSERT_UNKNOWN( size_t( color.size() ) == m ); // We define the set of rows, columns, and pairs that appear // by the set ( row[k], col[k] ) for k = 0, ... , K-1. // initialize rows that appear CppAD::vector<bool> row_appear(m); for(i = 0; i < m; i++) row_appear[i] = false; // rows and columns that appear VectorSet c2r_appear, r2c_appear; c2r_appear.resize(n, m); r2c_appear.resize(m, n); for(k = 0; k < K; k++) { CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k], col[k]) ); row_appear[ row[k] ] = true; c2r_appear.add_element(col[k], row[k]); r2c_appear.add_element(row[k], col[k]); } // for each column, which rows are non-zero and do not appear VectorSet not_appear; not_appear.resize(n, m); for(i = 0; i < m; i++) { typename VectorSet::const_iterator pattern_itr(pattern, i); j = *pattern_itr; while( j != pattern.end() ) { if( ! c2r_appear.is_element(j , i) ) not_appear.add_element(j, i); j = *(++pattern_itr); } } // initial coloring color.resize(m); ell = 0; for(i = 0; i < m; i++) { if( row_appear[i] ) color[i] = ell++; else color[i] = m; } /* See GreedyPartialD2Coloring Algorithm Section 3.6.2 of Graph Coloring in Optimization Revisited by Assefaw Gebremedhin, Fredrik Maane, Alex Pothen The algorithm above was modified (by Brad Bell) to take advantage of the fact that only the entries (subset of the sparsity pattern) specified by row and col need to be computed. */ CppAD::vector<bool> forbidden(m); for(i = 1; i < m; i++) // for each row that appears if( color[i] < m ) { // initial all colors as ok for this row // (value of forbidden for ell > initial color[i] does not matter) for(ell = 0; ell <= color[i]; ell++) forbidden[ell] = false; // ----------------------------------------------------- // Forbid colors for which this row would destroy results: // // for each column that is non-zero for this row typename VectorSet::const_iterator pattern_itr(pattern, i); j = *pattern_itr; while( j != pattern.end() ) { // for each row that appears with this column typename VectorSet::const_iterator c2r_itr(c2r_appear, j); r = *c2r_itr; while( r != c2r_appear.end() ) { // if this is not the same row, forbid its color if( (r < i) & (color[r] < m) ) forbidden[ color[r] ] = true; r = *(++c2r_itr); } j = *(++pattern_itr); } // ----------------------------------------------------- // Forbid colors that destroy results needed for this row. // // for each column that appears with this row typename VectorSet::const_iterator r2c_itr(r2c_appear, i); j = *r2c_itr; while( j != r2c_appear.end() ) { // For each row that is non-zero for this column // (the appear rows have already been checked above). typename VectorSet::const_iterator not_itr(not_appear, j); r = *not_itr; while( r != not_appear.end() ) { // if this is not the same row, forbid its color if( (r < i) & (color[r] < m) ) forbidden[ color[r] ] = true; r = *(++not_itr); } j = *(++r2c_itr); } // pick the color with smallest index ell = 0; while( forbidden[ell] ) { ell++; CPPAD_ASSERT_UNKNOWN( ell <= color[i] ); } color[i] = ell; } return; }
void color_general_colpack( const VectorSet& pattern , const VectorSize& row , const VectorSize& col , CppAD::vector<size_t>& color ) { size_t i, j, k; size_t m = pattern.n_set(); size_t n = pattern.end(); // Determine number of non-zero entries in each row CppAD::vector<size_t> n_nonzero(m); size_t n_nonzero_total = 0; for(i = 0; i < m; i++) { n_nonzero[i] = 0; typename VectorSet::const_iterator pattern_itr(pattern, i); j = *pattern_itr; while( j != pattern.end() ) { n_nonzero[i]++; j = *(++pattern_itr); } n_nonzero_total += n_nonzero[i]; } // Allocate memory and fill in Adolc sparsity pattern CppAD::vector<unsigned int*> adolc_pattern(m); CppAD::vector<unsigned int> adolc_memory(m + n_nonzero_total); size_t i_memory = 0; for(i = 0; i < m; i++) { adolc_pattern[i] = adolc_memory.data() + i_memory; CPPAD_ASSERT_KNOWN( std::numeric_limits<unsigned int>::max() >= n_nonzero[i], "Matrix is too large for colpack" ); adolc_pattern[i][0] = static_cast<unsigned int>( n_nonzero[i] ); typename VectorSet::const_iterator pattern_itr(pattern, i); j = *pattern_itr; k = 1; while(j != pattern.end() ) { CPPAD_ASSERT_KNOWN( std::numeric_limits<unsigned int>::max() >= j, "Matrix is too large for colpack" ); adolc_pattern[i][k++] = static_cast<unsigned int>( j ); j = *(++pattern_itr); } CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] ); i_memory += k; } CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total ); // Must use an external routine for this part of the calculation because // ColPack/ColPackHeaders.h has as 'using namespace std' at global level. cppad_colpack_general(color, m, n, adolc_pattern); return; }
void color_general_colpack( VectorSet& pattern , const VectorSize& row , const VectorSize& col , CppAD::vector<size_t>& color ) { size_t i, j, k; size_t m = pattern.n_set(); size_t n = pattern.end(); // Determine number of non-zero entries in each row CppAD::vector<size_t> n_nonzero(m); size_t n_nonzero_total = 0; for(i = 0; i < m; i++) { n_nonzero[i] = 0; pattern.begin(i); j = pattern.next_element(); while( j != pattern.end() ) { n_nonzero[i]++; j = pattern.next_element(); } n_nonzero_total += n_nonzero[i]; } // Allocate memory and fill in Adolc sparsity pattern CppAD::vector<unsigned int*> adolc_pattern(m); CppAD::vector<unsigned int> adolc_memory(m + n_nonzero_total); size_t i_memory = 0; for(i = 0; i < m; i++) { adolc_pattern[i] = adolc_memory.data() + i_memory; adolc_pattern[i][0] = n_nonzero[i]; pattern.begin(i); j = pattern.next_element(); k = 1; while(j != pattern.end() ) { adolc_pattern[i][k++] = j; j = pattern.next_element(); } CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] ); i_memory += k; } CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total ); // Must use an external routine for this part of the calculation because // ColPack/ColPackHeaders.h has as 'using namespace std' at global level. cppad_colpack_general(color, m, n, adolc_pattern); return; }
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>::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; }
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; }
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; }