void put_check_for_nan(const CppAD::vector<Base>& vec, std::string& file_name) { size_t char_size = sizeof(Base) * vec.size(); const char* char_ptr = reinterpret_cast<const char*>( vec.data() ); # if CPPAD_HAS_MKSTEMP char pattern[] = "/tmp/fileXXXXXX"; int fd = mkstemp(pattern); file_name = pattern; write(fd, char_ptr, char_size); close(fd); # else # if CPPAD_HAS_TMPNAM_S std::vector<char> name(L_tmpnam_s); if( tmpnam_s( name.data(), L_tmpnam_s ) != 0 ) { CPPAD_ASSERT_KNOWN( false, "Cannot create a temporary file name" ); } file_name = name.data(); # else file_name = tmpnam( CPPAD_NULL ); # endif std::fstream file_out(file_name.c_str(), std::ios::out|std::ios::binary ); file_out.write(char_ptr, char_size); file_out.close(); # endif return; }
void ode_z( const Float &t , const CppAD::vector<Float> &z , CppAD::vector<Float> &h ) { // z = [ y ; y_x ] // z_t = h(t, x, z) = [ y_t , y_x_t ] size_t i, j; size_t n = x_.size(); CPPAD_ASSERT_UNKNOWN( z.size() == n + n * n ); // y_t for(i = 0; i < n; i++) { h[i] = x_[i] * z[i]; // initialize y_x_t as zero for(j = 0; j < n; j++) h[n + i * n + j] = 0.; } for(i = 0; i < n; i++) { // partial of g_i w.r.t y_i Float gi_yi = x_[i]; // partial of g_i w.r.t x_i Float gi_xi = z[i]; // partial of y_i w.r.t x_i Float yi_xi = z[n + i * n + i]; // derivative of yi_xi with respect to t h[n + i * n + i] = gi_xi + gi_yi * yi_xi; } }
void ode_evaluate( CppAD::vector<Float> &x , size_t m , CppAD::vector<Float> &fm ) { typedef CppAD::vector<Float> Vector; size_t n = x.size(); size_t ell; CPPAD_ASSERT_KNOWN( m == 0 || m == 1, "ode_evaluate: m is not zero or one" ); CPPAD_ASSERT_KNOWN( ((m==0) & (fm.size()==n)) || ((m==1) & (fm.size()==n*n)), "ode_evaluate: the size of fm is not correct" ); if( m == 0 ) ell = n; else ell = n + n * n; // set up the case we are integrating Float ti = 0.; Float tf = 1.; Float smin = 1e-5; Float smax = 1.; Float scur = 1.; Float erel = 0.; vector<Float> yi(ell), eabs(ell); size_t i, j; for(i = 0; i < ell; i++) { eabs[i] = 1e-10; if( i < n ) yi[i] = 1.; else yi[i] = 0.; } // return values Vector yf(ell), ef(ell), maxabs(ell); size_t nstep; // construct ode method for taking one step ode_evaluate_method<Float> method(m, x); // solve differential equation yf = OdeErrControl(method, ti, tf, yi, smin, smax, scur, eabs, erel, ef, maxabs, nstep); if( m == 0 ) { for(i = 0; i < n; i++) fm[i] = yf[i]; } else { for(i = 0; i < n; i++) for(j = 0; j < n; j++) fm[i * n + j] = yf[n + i * n + j]; } return; }
bool is_tape_point_constant(size_t index){ bool ok_index= (index<=tp_.size()-2); if(!ok_index) return false; tape_point tp1=tp_[index]; tape_point tp2=tp_[index+1]; const addr_t* op_arg; op_arg=tp1.op_arg; int numarg=tp2.op_arg - op_arg; // Handle the user operator special case if(tp1.op == UsrrvOp || tp1.op == UsrrpOp){ // Result of user atomic operation bool constant=true; size_t i=index; while(tp_[i].op != UserOp){ i--; constant = constant && constant_tape_point_[i]; if(tp_[i].op == UsrrvOp || tp_[i].op == UsrrpOp)break; } return constant; } if(numarg==0)return false; // E.g. begin or end operators bool ans=true; for(int i=0;i<numarg;i++){ ans = ans && ( constant_tape_point_[var2op_[op_arg[i]]] || (!isDepArg(&op_arg[i])) ) ; } return ans; }
bool link_ode( size_t size , size_t repeat , CppAD::vector<double> &x , CppAD::vector<double> &jacobian ) { // ------------------------------------------------------------- // setup size_t n = size; assert( x.size() == n ); size_t m = 0; CppAD::vector<double> f(n); while(repeat--) { // choose next x value uniform_01(n, x); // evaluate function CppAD::ode_evaluate(x, m, f); } size_t i; for(i = 0; i < n; i++) jacobian[i] = f[i]; return true; }
void ode_y( const Float &t, const CppAD::vector<Float> &y, CppAD::vector<Float> &g) { // y_t = g(t, x, y) CPPAD_ASSERT_UNKNOWN( y.size() == x_.size() ); size_t i; size_t n = x_.size(); for(i = 0; i < n; i++) g[i] = x_[i] * y[i]; // because y_i(0) = 1, solution for this equation is // y_0 (t) = t // y_1 (t) = exp(x_1 * t) // y_2 (t) = exp(2 * x_2 * t) // ... }
// Given that y_i (0) = x_i, // the following y_i (t) satisfy the ODE below: // y_0 (t) = x[0] // y_1 (t) = x[1] + x[0] * t // y_2 (t) = x[2] + x[1] * t + x[0] * t^2/2 // y_3 (t) = x[3] + x[2] * t + x[1] * t^2/2 + x[0] * t^3 / 3! // ... void Ode( const Float& t, const CppAD::vector<Float>& y, CppAD::vector<Float>& f) { size_t n = y.size(); f[0] = 0.; for(size_t k = 1; k < n; k++) f[k] = y[k-1]; }
// The following routine is not yet used or tested. void cppad_colpack_symmetric( CppAD::vector<size_t>& color , size_t n , const CppAD::vector<unsigned int*>& adolc_pattern ) { size_t i, k; CPPAD_ASSERT_UNKNOWN( adolc_pattern.size() == n ); // Use adolc sparsity pattern to create corresponding bipartite graph ColPack::GraphColoringInterface graph( SRC_MEM_ADOLC, adolc_pattern.data(), n ); // Color the graph with the speciied ordering // graph.Coloring("SMALLEST_LAST", "STAR") is slower in adolc testing graph.Coloring("SMALLEST_LAST", "ACYCLIC_FOR_INDIRECT_RECOVERY"); // Use coloring information to create seed matrix int n_seed_row; int n_seed_col; double** seed_matrix = graph.GetSeedMatrix(&n_seed_row, &n_seed_col); CPPAD_ASSERT_UNKNOWN( size_t(n_seed_col) == n ); // now return coloring in format required by CppAD for(i = 0; i < n; i++) color[i] = n; for(k = 0; k < size_t(n_seed_row); k++) { for(i = 0; i < n; i++) { if( seed_matrix[k][i] != 0.0 ) { CPPAD_ASSERT_UNKNOWN( color[i] == n ); color[i] = k; } } } # ifndef NDEBUG for(i = 0; i < n; i++) CPPAD_ASSERT_UNKNOWN(color[i] < n || adolc_pattern[i][0] == 0); // The coloring above will probably fail this test. // Check that no rows with the same color have overlapping entries: CppAD::vector<bool> found(n); for(k = 0; k < size_t(n_seed_row); k++) { size_t j, ell; for(j = 0; j < n; j++) found[j] = false; for(i = 0; i < n; i++) if( color[i] == k ) { for(ell = 0; ell < adolc_pattern[i][0]; ell++) { j = adolc_pattern[i][1 + ell]; CPPAD_ASSERT_UNKNOWN( ! found[j] ); found[j] = true; } } } # endif return; }
void sparse_hes_fun( size_t n , const FloatVector& x , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , size_t p , FloatVector& fp ) { // check numeric type specifications CheckNumericType<Float>(); // check value of p CPPAD_ASSERT_KNOWN( p < 3, "sparse_hes_fun: p > 2" ); size_t i, j, k; size_t size = 1; for(k = 0; k < p; k++) size *= n; for(k = 0; k < size; k++) fp[k] = Float(0); size_t K = row.size(); Float t; Float dt_i; Float dt_j; for(k = 0; k < K; k++) { i = row[k]; j = col[k]; t = exp( x[i] * x[j] ); dt_i = t * x[j]; dt_j = t * x[i]; switch(p) { case 0: fp[0] += t; break; case 1: fp[i] += dt_i; fp[j] += dt_j; break; case 2: fp[i * n + i] += dt_i * x[j]; fp[i * n + j] += t + dt_j * x[j]; // fp[j * n + i] += t + dt_i * x[i]; fp[j * n + j] += dt_j * x[i]; break; } } }
bool link_sparse_hessian( size_t repeat , CppAD::vector<double> &x , CppAD::vector<size_t> &i , CppAD::vector<size_t> &j , CppAD::vector<double> &hessian ) { // ----------------------------------------------------- // setup using CppAD::vector; size_t order = 0; // derivative order corresponding to function size_t n = x.size(); // argument space dimension size_t ell = i.size(); // size of index vectors vector<double> y(1); // function value // temporaries size_t k; vector<double> tmp(2 * ell); // choose a value for x CppAD::uniform_01(n, x); // ------------------------------------------------------ while(repeat--) { // get the next set of indices CppAD::uniform_01(2 * ell, tmp); for(k = 0; k < ell; k++) { i[k] = size_t( n * tmp[k] ); i[k] = std::min(n-1, i[k]); // j[k] = size_t( n * tmp[k + ell] ); j[k] = std::min(n-1, j[k]); } // computation of the function CppAD::sparse_evaluate(x, i, j, order, y); } hessian[0] = y[0]; return true; }
/** * Evaluates the Jacobian and the Hessian of the loop model * * @param individualColoring whether or not there are atomic * functions in the model */ inline void evalLoopModelJacobianHessian(bool individualColoring) { using namespace CppAD::extra; using CppAD::vector; ADFun<CG<Base> >& fun = model->getTape(); const std::vector<IterEquationGroup<Base> >& eqGroups = model->getEquationsGroups(); vector<vector<CG<Base> > > vw(1); vw[0].resize(w.size()); vector<CG<Base> > y; size_t nEqGroups = equationGroups.size(); vector<std::set<size_t> > empty; vector<std::map<size_t, CG<Base> > > emptyJac; for (size_t g = 0; g < nEqGroups; g++) { const IterEquationGroup<Base>& group = eqGroups[g]; vector<std::map<size_t, std::map<size_t, CG<Base> > > > vhess; for (size_t i = 0; i < w.size(); i++) { vw[0][i] = Base(0); } for (size_t itI : group.tapeI) { vw[0][itI] = w[itI]; } generateLoopForJacHes(fun, x, vw, y, model->getJacobianSparsity(), g == 0 ? evalJacSparsity : empty, g == 0 ? dyiDzk : emptyJac, model->getHessianSparsity(), equationGroups[g].evalHessSparsity, vhess, individualColoring); //Hessian equationGroups[g].hess = vhess[0]; } }
void get_check_for_nan(CppAD::vector<Base>& vec, const std::string& file_name) { // size_t n = vec.size(); size_t char_size = sizeof(Base) * n; char* char_ptr = reinterpret_cast<char*>( vec.data() ); // std::fstream file_in(file_name.c_str(), std::ios::in|std::ios::binary ); file_in.read(char_ptr, char_size); // return; }
virtual void zeroOrderDependency(const CppAD::vector<bool>& vx, CppAD::vector<bool>& vy) override { using CppAD::vector; size_t m = vy.size(); size_t n = vx.size(); vector<std::set<size_t> > rt(m); for (size_t j = 0; j < m; j++) { rt[j].insert(j); } vector<std::set<size_t> > st(n); rev_sparse_jac(m, rt, st); for (size_t j = 0; j < n; j++) { for (size_t i : st[j]) { if (vx[j]) { vy[i] = true; } } } }
void sparse_jac_fun( size_t m , size_t n , const FloatVector& x , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , size_t p , FloatVector& fp ) { // check numeric type specifications CheckNumericType<Float>(); // check value of p CPPAD_ASSERT_KNOWN( p == 0 || p == 1, "sparse_jac_fun: p != 0 and p != 1" ); size_t K = row.size(); CPPAD_ASSERT_KNOWN( K >= m, "sparse_jac_fun: row.size() < m" ); size_t i, j, k; if( p == 0 ) for(i = 0; i < m; i++) fp[i] = Float(0); Float t; for(k = 0; k < K; k++) { i = row[k]; j = col[k]; t = exp( x[j] * x[j] / 2.0 ); switch(p) { case 0: fp[i] += t; break; case 1: fp[k] = t * x[j]; break; } } }
void sparse_jac_fun( size_t m , size_t n , const FloatVector& x , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , size_t p , FloatVector& fp ) { // check numeric type specifications CheckNumericType<Float>(); // check value of p CPPAD_ASSERT_KNOWN( p < 2, "sparse_jac_fun: p > 1" ); size_t i, j, k; size_t size = m; if( p > 0 ) size *= n; for(k = 0; k < size; k++) fp[k] = Float(0); size_t K = row.size(); Float t; for(k = 0; k < K; k++) { i = row[k]; j = col[k]; t = exp( x[j] * x[j] / 2.0 ); switch(p) { case 0: fp[i] += t; break; case 1: fp[i * n + j] += t * x[j]; break; } } }
/*! Create a two vector sparsity representation from a vector of maps. \param sparse Is a vector of maps representation of sparsity as well as the index in the two vector representation. To be specific; \verbatim for(i = 0; i < sparse.size(); i++) { for(itr = sparse[i].begin(); itr != sparse[i].end(); itr++) { j = itr->first; // (i, j) is a possibly non-zero entry in sparsity pattern // k == itr->second, is corresponding index in i_row and j_col k++; } } \endverbatim \param n_nz is the total number of possibly non-zero entries. \param i_row The input size and element values for \c i_row do not matter. On output, it has size \c n_nz and <tt>i_row[k]</tt> contains the row index corresponding to the \c k-th possibly non-zero entry. \param j_col The input size and element values for \c j_col do not matter. On output, it has size \c n_nz and <tt>j_col[k]</tt> contains the column index corresponding to the \c k-th possibly non-zero entry. */ void sparse_map2vec( const CppAD::vector< std::map<size_t, size_t> > sparse, size_t& n_nz , CppAD::vector<size_t>& i_row , CppAD::vector<size_t>& j_col ) { size_t i, j, k, m; // number of rows in sparse m = sparse.size(); // itererator for one row std::map<size_t, size_t>::const_iterator itr; // count the number of possibly non-zeros in sparse n_nz = 0; for(i = 0; i < m; i++) for(itr = sparse[i].begin(); itr != sparse[i].end(); itr++) ++n_nz; // resize the return vectors to accomidate n_nz entries i_row.resize(n_nz); j_col.resize(n_nz); // set the row and column indices and check assumptions on sparse k = 0; for(i = 0; i < m; i++) { for(itr = sparse[i].begin(); itr != sparse[i].end(); itr++) { j = itr->first; CPPAD_ASSERT_UNKNOWN( k == itr->second ); i_row[k] = i; j_col[k] = j; ++k; } } return; }
bool link_sparse_hessian( size_t size , size_t repeat , CppAD::vector<double>& x , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , CppAD::vector<double>& hessian ) { // ----------------------------------------------------- // setup typedef vector<double> DblVector; typedef vector< std::set<size_t> > SetVector; typedef CppAD::AD<double> ADScalar; typedef vector<ADScalar> ADVector; size_t i, j, k; size_t order = 0; // derivative order corresponding to function size_t m = 1; // number of dependent variables size_t n = size; // number of independent variables size_t K = row.size(); // number of non-zeros in lower triangle ADVector a_x(n); // AD domain space vector ADVector a_y(m); // AD range space vector DblVector w(m); // double range space vector DblVector hes(K); // non-zeros in lower triangle CppAD::ADFun<double> f; // AD function object // weights for hessian calculation (only one component of f) w[0] = 1.; // use the unspecified fact that size is non-decreasing between calls static size_t previous_size = 0; bool print = (repeat > 1) & (previous_size != size); previous_size = size; // declare sparsity pattern # if USE_SET_SPARSITY SetVector sparsity(n); # else typedef vector<bool> BoolVector; BoolVector sparsity(n * n); # endif // initialize all entries as zero for(i = 0; i < n; i++) { for(j = 0; j < n; j++) hessian[ i * n + j] = 0.; } // ------------------------------------------------------ extern bool global_retape; if( global_retape) while(repeat--) { // choose a value for x CppAD::uniform_01(n, x); for(j = 0; j < n; j++) a_x[j] = x[j]; // declare independent variables Independent(a_x); // AD computation of f(x) CppAD::sparse_hes_fun<ADScalar>(n, a_x, row, col, order, a_y); // create function object f : X -> Y f.Dependent(a_x, a_y); extern bool global_optimize; if( global_optimize ) { print_optimize(f, print, "cppad_sparse_hessian_optimize", size); print = false; } // calculate the Hessian sparsity pattern for this function calc_sparsity(sparsity, f); // structure that holds some of work done by SparseHessian CppAD::sparse_hessian_work work; // calculate this Hessian at this x f.SparseHessian(x, w, sparsity, row, col, hes, work); for(k = 0; k < K; k++) { hessian[ row[k] * n + col[k] ] = hes[k]; hessian[ col[k] * n + row[k] ] = hes[k]; } } else { // choose a value for x CppAD::uniform_01(n, x); for(j = 0; j < n; j++) a_x[j] = x[j]; // declare independent variables Independent(a_x); // AD computation of f(x) CppAD::sparse_hes_fun<ADScalar>(n, a_x, row, col, order, a_y); // create function object f : X -> Y f.Dependent(a_x, a_y); extern bool global_optimize; if( global_optimize ) { print_optimize(f, print, "cppad_sparse_hessian_optimize", size); print = false; } // calculate the Hessian sparsity pattern for this function calc_sparsity(sparsity, f); // declare structure that holds some of work done by SparseHessian CppAD::sparse_hessian_work work; while(repeat--) { // choose a value for x CppAD::uniform_01(n, x); // calculate sparsity at this x f.SparseHessian(x, w, sparsity, row, col, hes, work); for(k = 0; k < K; k++) { hessian[ row[k] * n + col[k] ] = hes[k]; hessian[ col[k] * n + row[k] ] = hes[k]; } } } return true; }
bool link_sparse_jacobian( size_t size , size_t repeat , size_t m , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , CppAD::vector<double>& x_return , CppAD::vector<double>& jacobian , size_t& n_sweep ) { if( global_atomic || (! global_colpack) ) return false; if( global_memory || global_optimize ) return false; // ----------------------------------------------------- // setup typedef unsigned int* SizeVector; typedef double* DblVector; typedef adouble ADScalar; typedef ADScalar* ADVector; size_t i, j, k; // temporary indices size_t n = size; // number of independent variables size_t order = 0; // derivative order corresponding to function // set up for thread_alloc memory allocator (fast and checks for leaks) using CppAD::thread_alloc; // the allocator size_t capacity; // capacity of an allocation // tape identifier int tag = 0; // AD domain space vector ADVector a_x = thread_alloc::create_array<ADScalar>(n, capacity); // AD range space vector ADVector a_y = thread_alloc::create_array<ADScalar>(m, capacity); // argument value in double DblVector x = thread_alloc::create_array<double>(n, capacity); // function value in double DblVector y = thread_alloc::create_array<double>(m, capacity); // options that control sparse_jac int options[4]; extern bool global_boolsparsity; if( global_boolsparsity ) options[0] = 1; // sparsity by propagation of bit pattern else options[0] = 0; // sparsity pattern by index domains options[1] = 0; // (0 = safe mode, 1 = tight mode) options[2] = 0; // see changing to -1 and back to 0 below options[3] = 0; // (0 = column compression, 1 = row compression) // structure that holds some of the work done by sparse_jac int nnz; // number of non-zero values SizeVector rind = CPPAD_NULL; // row indices SizeVector cind = CPPAD_NULL; // column indices DblVector values = CPPAD_NULL; // Jacobian values // choose a value for x CppAD::uniform_01(n, x); // declare independent variables int keep = 0; // keep forward mode results trace_on(tag, keep); for(j = 0; j < n; j++) a_x[j] <<= x[j]; // AD computation of f (x) CppAD::sparse_jac_fun<ADScalar>(m, n, a_x, row, col, order, a_y); // create function object f : x -> y for(i = 0; i < m; i++) a_y[i] >>= y[i]; trace_off(); // Retrieve n_sweep using undocumented feature of sparsedrivers.cpp int same_pattern = 0; options[2] = -1; n_sweep = sparse_jac(tag, int(m), int(n), same_pattern, x, &nnz, &rind, &cind, &values, options ); options[2] = 0; // ---------------------------------------------------------------------- if( ! global_onetape ) while(repeat--) { // choose a value for x CppAD::uniform_01(n, x); // declare independent variables trace_on(tag, keep); for(j = 0; j < n; j++) a_x[j] <<= x[j]; // AD computation of f (x) CppAD::sparse_jac_fun<ADScalar>(m, n, a_x, row, col, order, a_y); // create function object f : x -> y for(i = 0; i < m; i++) a_y[i] >>= y[i]; trace_off(); // is this a repeat call with the same sparsity pattern same_pattern = 0; // calculate the jacobian at this x rind = CPPAD_NULL; cind = CPPAD_NULL; values = CPPAD_NULL; sparse_jac(tag, int(m), int(n), same_pattern, x, &nnz, &rind, &cind, &values, options ); // only needed last time through loop if( repeat == 0 ) { size_t K = row.size(); for(int ell = 0; ell < nnz; ell++) { i = size_t(rind[ell]); j = size_t(cind[ell]); for(k = 0; k < K; k++) { if( row[k]==i && col[k]==j ) jacobian[k] = values[ell]; } } } // free raw memory allocated by sparse_jac free(rind); free(cind); free(values); } else { while(repeat--)
bool link_sparse_hessian( size_t size , size_t repeat , const CppAD::vector<size_t>& row , const CppAD::vector<size_t>& col , CppAD::vector<double>& x_return , CppAD::vector<double>& hessian , size_t& n_sweep ) { if( global_atomic || (! global_colpack) ) return false; if( global_memory || global_optimize || global_boolsparsity ) return false; // ----------------------------------------------------- // setup typedef unsigned int* SizeVector; typedef double* DblVector; typedef adouble ADScalar; typedef ADScalar* ADVector; size_t i, j, k; // temporary indices size_t order = 0; // derivative order corresponding to function size_t m = 1; // number of dependent variables size_t n = size; // number of independent variables // setup for thread_alloc memory allocator (fast and checks for leaks) using CppAD::thread_alloc; // the allocator size_t capacity; // capacity of an allocation // tape identifier int tag = 0; // AD domain space vector ADVector a_x = thread_alloc::create_array<ADScalar>(n, capacity); // AD range space vector ADVector a_y = thread_alloc::create_array<ADScalar>(m, capacity); // double argument value DblVector x = thread_alloc::create_array<double>(n, capacity); // double function value double f; // options that control sparse_hess int options[2]; options[0] = 0; // safe mode options[1] = 0; // indirect recovery // structure that holds some of the work done by sparse_hess int nnz; // number of non-zero values SizeVector rind = CPPAD_NULL; // row indices SizeVector cind = CPPAD_NULL; // column indices DblVector values = CPPAD_NULL; // Hessian values // ---------------------------------------------------------------------- if( ! global_onetape ) while(repeat--) { // choose a value for x CppAD::uniform_01(n, x); // declare independent variables int keep = 0; // keep forward mode results trace_on(tag, keep); for(j = 0; j < n; j++) a_x[j] <<= x[j]; // AD computation of f (x) CppAD::sparse_hes_fun<ADScalar>(n, a_x, row, col, order, a_y); // create function object f : x -> y a_y[0] >>= f; trace_off(); // is this a repeat call with the same sparsity pattern int same_pattern = 0; // calculate the hessian at this x rind = CPPAD_NULL; cind = CPPAD_NULL; values = CPPAD_NULL; sparse_hess(tag, int(n), same_pattern, x, &nnz, &rind, &cind, &values, options ); // only needed last time through loop if( repeat == 0 ) { size_t K = row.size(); for(int ell = 0; ell < nnz; ell++) { i = size_t(rind[ell]); j = size_t(cind[ell]); for(k = 0; k < K; k++) { if( (row[k]==i && col[k]==j) || (row[k]==j && col[k]==i) ) hessian[k] = values[ell]; } } } // free raw memory allocated by sparse_hess free(rind); free(cind); free(values); } else { // choose a value for x
void ForSparseJacSet( bool transpose , size_t q , const VectorSet& r , VectorSet& s , size_t total_num_var , CppAD::vector<size_t>& dep_taddr , CppAD::vector<size_t>& ind_taddr , CppAD::player<Base>& play , CPPAD_INTERNAL_SPARSE_SET& for_jac_sparsity ) { // temporary indices size_t i, j; std::set<size_t>::const_iterator itr; // range and domain dimensions for F size_t m = dep_taddr.size(); size_t n = ind_taddr.size(); CPPAD_ASSERT_KNOWN( q > 0, "RevSparseJac: q is not greater than zero" ); CPPAD_ASSERT_KNOWN( size_t(r.size()) == n || transpose, "RevSparseJac: size of r is not equal to n and transpose is false." ); CPPAD_ASSERT_KNOWN( size_t(r.size()) == q || ! transpose, "RevSparseJac: size of r is not equal to q and transpose is true." ); // allocate memory for the requested sparsity calculation for_jac_sparsity.resize(total_num_var, q); // set values corresponding to independent variables if( transpose ) { for(i = 0; i < q; i++) { // add the elements that are present itr = r[i].begin(); while( itr != r[i].end() ) { j = *itr++; CPPAD_ASSERT_KNOWN( j < n, "ForSparseJac: transpose is true and element of the set\n" "r[j] has value greater than or equal n." ); CPPAD_ASSERT_UNKNOWN( ind_taddr[j] < total_num_var ); // operator for j-th independent variable CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[j] ) == InvOp ); for_jac_sparsity.add_element( ind_taddr[j], i); } } } else { for(i = 0; i < n; i++) { CPPAD_ASSERT_UNKNOWN( ind_taddr[i] < total_num_var ); // ind_taddr[i] is operator taddr for i-th independent variable CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[i] ) == InvOp ); // add the elements that are present itr = r[i].begin(); while( itr != r[i].end() ) { j = *itr++; CPPAD_ASSERT_KNOWN( j < q, "ForSparseJac: an element of the set r[i] " "has value greater than or equal q." ); for_jac_sparsity.add_element( ind_taddr[i], j); } } } // evaluate the sparsity patterns ForJacSweep( n, total_num_var, &play, for_jac_sparsity ); // return values corresponding to dependent variables CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m || transpose ); CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == q || ! transpose ); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr[i] < total_num_var ); // extract results from for_jac_sparsity // and add corresponding elements to sets in s CPPAD_ASSERT_UNKNOWN( for_jac_sparsity.end() == q ); for_jac_sparsity.begin( dep_taddr[i] ); j = for_jac_sparsity.next_element(); while( j < q ) { if( transpose ) s[j].insert(i); else s[i].insert(j); j = for_jac_sparsity.next_element(); } } }
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 ForSparseJacBool( bool transpose , size_t q , const VectorSet& r , VectorSet& s , size_t total_num_var , CppAD::vector<size_t>& dep_taddr , CppAD::vector<size_t>& ind_taddr , CppAD::player<Base>& play , sparse_pack& for_jac_sparsity ) { // temporary indices size_t i, j; // range and domain dimensions for F size_t m = dep_taddr.size(); size_t n = ind_taddr.size(); CPPAD_ASSERT_KNOWN( q > 0, "ForSparseJac: q is not greater than zero" ); CPPAD_ASSERT_KNOWN( size_t(r.size()) == n * q, "ForSparseJac: size of r is not equal to\n" "q times domain dimension for ADFun object." ); // allocate memory for the requested sparsity calculation result for_jac_sparsity.resize(total_num_var, q); // set values corresponding to independent variables for(i = 0; i < n; i++) { CPPAD_ASSERT_UNKNOWN( ind_taddr[i] < total_num_var ); // ind_taddr[i] is operator taddr for i-th independent variable CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[i] ) == InvOp ); // set bits that are true if( transpose ) { for(j = 0; j < q; j++) if( r[ j * n + i ] ) for_jac_sparsity.add_element( ind_taddr[i], j); } else { for(j = 0; j < q; j++) if( r[ i * q + j ] ) for_jac_sparsity.add_element( ind_taddr[i], j); } } // evaluate the sparsity patterns ForJacSweep( n, total_num_var, &play, for_jac_sparsity ); // return values corresponding to dependent variables CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m * q ); for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr[i] < total_num_var ); // extract the result from for_jac_sparsity if( transpose ) { for(j = 0; j < q; j++) s[ j * m + i ] = false; } else { for(j = 0; j < q; j++) s[ i * q + j ] = false; } CPPAD_ASSERT_UNKNOWN( for_jac_sparsity.end() == q ); for_jac_sparsity.begin( dep_taddr[i] ); j = for_jac_sparsity.next_element(); while( j < q ) { if( transpose ) s[j * m + i] = true; else s[i * q + j] = true; j = for_jac_sparsity.next_element(); } } }
// ---------------------------------------------------------------------- void cppad_colpack_general( CppAD::vector<size_t>& color , size_t m , size_t n , const CppAD::vector<unsigned int*>& adolc_pattern ) { size_t i, k; CPPAD_ASSERT_UNKNOWN( adolc_pattern.size() == m ); CPPAD_ASSERT_UNKNOWN( color.size() == m ); // Use adolc sparsity pattern to create corresponding bipartite graph ColPack::BipartiteGraphPartialColoringInterface graph( SRC_MEM_ADOLC, adolc_pattern.data(), m, n ); // row ordered Partial-Distance-Two-Coloring of the bipartite graph graph.PartialDistanceTwoColoring( "SMALLEST_LAST", "ROW_PARTIAL_DISTANCE_TWO" ); // Use coloring information to create seed matrix int n_seed_row; int n_seed_col; double** seed_matrix = graph.GetSeedMatrix(&n_seed_row, &n_seed_col); CPPAD_ASSERT_UNKNOWN( size_t(n_seed_col) == m ); // now return coloring in format required by CppAD for(i = 0; i < m; i++) color[i] = m; for(k = 0; k < size_t(n_seed_row); k++) { for(i = 0; i < m; i++) { if( seed_matrix[k][i] != 0.0 ) { // check that no row appears twice in the coloring CPPAD_ASSERT_UNKNOWN( color[i] == m ); color[i] = k; } } } # ifndef NDEBUG // check that all non-zero rows appear in the coloring for(i = 0; i < m; i++) CPPAD_ASSERT_UNKNOWN(color[i] < m || adolc_pattern[i][0] == 0); // check that no rows with the same color have overlapping entries CppAD::vector<bool> found(n); for(k = 0; k < size_t(n_seed_row); k++) { size_t j, ell; for(j = 0; j < n; j++) found[j] = false; for(i = 0; i < m; i++) if( color[i] == k ) { for(ell = 0; ell < adolc_pattern[i][0]; ell++) { j = adolc_pattern[i][1 + ell]; CPPAD_ASSERT_UNKNOWN( ! found[j] ); found[j] = true; } } } # endif return; }
size_t optimize_record_csum( const CppAD::vector<struct optimize_old_variable>& tape , size_t current , size_t npar , const Base* par , recorder<Base>* rec , optimize_csum_stacks& work ) { CPPAD_ASSERT_UNKNOWN( work.op_stack.empty() ); CPPAD_ASSERT_UNKNOWN( work.add_stack.empty() ); CPPAD_ASSERT_UNKNOWN( work.sub_stack.empty() ); CPPAD_ASSERT_UNKNOWN( tape[current].connect == yes_connected ); size_t i; OpCode op; const size_t* arg; bool add; struct optimize_csum_variable var; var.op = tape[current].op; var.arg = tape[current].arg; var.add = true; work.op_stack.push( var ); Base sum_par(0); while( ! work.op_stack.empty() ) { var = work.op_stack.top(); work.op_stack.pop(); op = var.op; arg = var.arg; add = var.add; // process first argument to this operator switch(op) { case AddpvOp: case SubpvOp: CPPAD_ASSERT_UNKNOWN( arg[0] < npar ); if( add ) sum_par += par[arg[0]]; else sum_par -= par[arg[0]]; break; case AddvvOp: case SubvpOp: case SubvvOp: if( tape[arg[0]].connect == csum_connected ) { CPPAD_ASSERT_UNKNOWN( tape[arg[0]].new_var == tape.size() ); var.op = tape[arg[0]].op; var.arg = tape[arg[0]].arg; var.add = add; work.op_stack.push( var ); } else if( add ) work.add_stack.push(arg[0]); else work.sub_stack.push(arg[0]); break; default: CPPAD_ASSERT_UNKNOWN(false); } // process second argument to this operator switch(op) { case SubvpOp: CPPAD_ASSERT_UNKNOWN( arg[1] < npar ); if( add ) sum_par -= par[arg[1]]; else sum_par += par[arg[1]]; break; case SubvvOp: case SubpvOp: add = ! add; case AddvvOp: case AddpvOp: if( tape[arg[1]].connect == csum_connected ) { CPPAD_ASSERT_UNKNOWN( tape[arg[1]].new_var == tape.size() ); var.op = tape[arg[1]].op; var.arg = tape[arg[1]].arg; var.add = add; work.op_stack.push( var ); } else if( add ) work.add_stack.push(arg[1]); else work.sub_stack.push(arg[1]); break; default: CPPAD_ASSERT_UNKNOWN(false); } } // number of variables in this cummulative sum operator size_t n_add = work.add_stack.size(); size_t n_sub = work.sub_stack.size(); size_t old_arg, new_arg; rec->PutArg(n_add); // arg[0] rec->PutArg(n_sub); // arg[1] new_arg = rec->PutPar( sum_par ); rec->PutArg(new_arg); // arg[2] for(i = 0; i < n_add; i++) { CPPAD_ASSERT_UNKNOWN( ! work.add_stack.empty() ); old_arg = work.add_stack.top(); new_arg = tape[old_arg].new_var; CPPAD_ASSERT_UNKNOWN( new_arg < tape.size() ); rec->PutArg(new_arg); // arg[3+i] work.add_stack.pop(); } for(i = 0; i < n_sub; i++) { CPPAD_ASSERT_UNKNOWN( ! work.sub_stack.empty() ); old_arg = work.sub_stack.top(); new_arg = tape[old_arg].new_var; CPPAD_ASSERT_UNKNOWN( new_arg < tape.size() ); rec->PutArg(new_arg); // arg[3 + arg[0] + i] work.sub_stack.pop(); } rec->PutArg(n_add + n_sub); // arg[3 + arg[0] + arg[1]] i = rec->PutOp(CSumOp); CPPAD_ASSERT_UNKNOWN(new_arg < tape.size()); return i; }
void RevSparseJacSet( size_t p , const VectorSet& s , VectorSet& r , size_t total_num_var , CppAD::vector<size_t>& dep_taddr , CppAD::vector<size_t>& ind_taddr , CppAD::player<Base>& play ) { // temporary indices size_t i, j; std::set<size_t>::const_iterator itr; // check VectorSet is Simple Vector class with sets for elements static std::set<size_t> two, three; if( two.empty() ) { two.insert(2); three.insert(3); } CPPAD_ASSERT_UNKNOWN( two.size() == 1 ); CPPAD_ASSERT_UNKNOWN( three.size() == 1 ); CheckSimpleVector<std::set<size_t>, VectorSet>(two, three); // range and domain dimensions for F size_t m = dep_taddr.size(); size_t n = ind_taddr.size(); CPPAD_ASSERT_KNOWN( p > 0, "RevSparseJac: p (first argument) is not greater than zero" ); CPPAD_ASSERT_KNOWN( s.size() == p, "RevSparseJac: s (second argument) length is not equal to " "p (first argument)." ); // vector of sets that will hold the results sparse_set var_sparsity; var_sparsity.resize(total_num_var, p); // The sparsity pattern corresponding to the dependent variables for(i = 0; i < p; i++) { itr = s[i].begin(); while(itr != s[i].end()) { j = *itr++; CPPAD_ASSERT_KNOWN( j < m, "RevSparseJac: an element of the set s[i] " "has value greater than or equal m." ); CPPAD_ASSERT_UNKNOWN( dep_taddr[j] < total_num_var ); var_sparsity.add_element( dep_taddr[j], i ); } } // evaluate the sparsity patterns RevJacSweep( n, total_num_var, &play, var_sparsity ); // return values corresponding to dependent variables CPPAD_ASSERT_UNKNOWN( r.size() == p ); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr[j] == (j+1) ); // ind_taddr[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[j] ) == InvOp ); // extract result from rev_hes_sparsity // and add corresponding elements to sets in r CPPAD_ASSERT_UNKNOWN( var_sparsity.end() == p ); var_sparsity.begin(j+1); i = var_sparsity.next_element(); while( i < p ) { r[i].insert(j); i = var_sparsity.next_element(); } } }
void RevSparseHesBool( bool transpose , size_t q , const VectorSet& s , VectorSet& h , size_t num_var , CppAD::vector<size_t>& dep_taddr , CppAD::vector<size_t>& ind_taddr , CppAD::player<Base>& play , sparse_pack& for_jac_sparsity ) { // temporary indices size_t i, j; // check Vector is Simple VectorSet class with bool elements CheckSimpleVector<bool, VectorSet>(); // range and domain dimensions for F size_t m = dep_taddr.size(); size_t n = ind_taddr.size(); CPPAD_ASSERT_KNOWN( q == for_jac_sparsity.end(), "RevSparseHes: q is not equal to its value\n" "in the previous call to ForSparseJac with this ADFun object." ); CPPAD_ASSERT_KNOWN( size_t(s.size()) == m, "RevSparseHes: size of s is not equal to\n" "range dimension for ADFun object." ); // Array that will hold reverse Jacobian dependency flag. // Initialize as true for the dependent variables. pod_vector<bool> RevJac; RevJac.extend(num_var); for(i = 0; i < num_var; i++) RevJac[i] = false; for(i = 0; i < m; i++) { CPPAD_ASSERT_UNKNOWN( dep_taddr[i] < num_var ); RevJac[ dep_taddr[i] ] = s[i]; } // vector of sets that will hold reverse Hessain values sparse_pack rev_hes_sparsity; rev_hes_sparsity.resize(num_var, q); // compute the Hessian sparsity patterns RevHesSweep( n, num_var, &play, for_jac_sparsity, RevJac.data(), rev_hes_sparsity ); // return values corresponding to independent variables CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n * q ); for(j = 0; j < n; j++) { for(i = 0; i < q; i++) { if( transpose ) h[ j * q + i ] = false; else h[ i * n + j ] = false; } } // j is index corresponding to reverse mode partial for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr[j] < num_var ); // ind_taddr[j] is operator taddr for j-th independent variable CPPAD_ASSERT_UNKNOWN( ind_taddr[j] == j + 1 ); CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[j] ) == InvOp ); // extract the result from rev_hes_sparsity CPPAD_ASSERT_UNKNOWN( rev_hes_sparsity.end() == q ); rev_hes_sparsity.begin(j + 1); i = rev_hes_sparsity.next_element(); while( i < q ) { if( transpose ) h[ j * q + i ] = true; else h[ i * n + j ] = true; i = rev_hes_sparsity.next_element(); } } return; }
void RevSparseHesSet( bool transpose , size_t q , const VectorSet& s , VectorSet& h , size_t num_var , CppAD::vector<size_t>& dep_taddr , CppAD::vector<size_t>& ind_taddr , CppAD::player<Base>& play , CPPAD_INTERNAL_SPARSE_SET& for_jac_sparsity ) { // temporary indices size_t i, j; std::set<size_t>::const_iterator itr; // 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>() ); // range and domain dimensions for F # ifndef NDEBUG size_t m = dep_taddr.size(); # endif size_t n = ind_taddr.size(); CPPAD_ASSERT_KNOWN( q == for_jac_sparsity.end(), "RevSparseHes: q is not equal to its value\n" "in the previous call to ForSparseJac with this ADFun object." ); CPPAD_ASSERT_KNOWN( s.size() == 1, "RevSparseHes: size of s is not equal to one." ); // Array that will hold reverse Jacobian dependency flag. // Initialize as true for the dependent variables. pod_vector<bool> RevJac; RevJac.extend(num_var); for(i = 0; i < num_var; i++) RevJac[i] = false; itr = s[0].begin(); while( itr != s[0].end() ) { i = *itr++; CPPAD_ASSERT_KNOWN( i < m, "RevSparseHes: an element of the set s[0] has value " "greater than or equal m" ); CPPAD_ASSERT_UNKNOWN( dep_taddr[i] < num_var ); RevJac[ dep_taddr[i] ] = true; } // vector of sets that will hold reverse Hessain values CPPAD_INTERNAL_SPARSE_SET rev_hes_sparsity; rev_hes_sparsity.resize(num_var, q); // compute the Hessian sparsity patterns RevHesSweep( n, num_var, &play, for_jac_sparsity, RevJac.data(), rev_hes_sparsity ); // return values corresponding to independent variables // j is index corresponding to reverse mode partial CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == q || transpose ); CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n || ! transpose ); for(j = 0; j < n; j++) { CPPAD_ASSERT_UNKNOWN( ind_taddr[j] < num_var ); CPPAD_ASSERT_UNKNOWN( ind_taddr[j] == j + 1 ); CPPAD_ASSERT_UNKNOWN( play.GetOp( ind_taddr[j] ) == InvOp ); // extract the result from rev_hes_sparsity // and add corresponding elements to result sets in h CPPAD_ASSERT_UNKNOWN( rev_hes_sparsity.end() == q ); rev_hes_sparsity.begin(j+1); i = rev_hes_sparsity.next_element(); while( i < q ) { if( transpose ) h[j].insert(i); else h[i].insert(j); i = rev_hes_sparsity.next_element(); } } return; }
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; } }
/*! Determine which rows of a symmetrix sparse matrix can be computed together. \param color is a vector with color.size() == m. For i = 0 , ... , m-1, color[i] is the color for the corresponding row of the matrix. We say that a sparsity pattern entry (i, j) is valid if for all i1, such that i1 != i and color[i1]==color[i], and all j1, such that (i1, j1) is in sparsity pattern, j1 != j. The coloring is chosen so that for all (i, j) in the sparsity pattern; either (i, j) or (j, i) is valid (possibly both). \param m is the number of rows (and columns) in the matrix. \param adolc_pattern is a vector with adolc_pattern.size() == m. For i = 0 , ... , m-1, and for k = 1, ... ,adolc_pattern[i][0], the entry with index (i, adolc_pattern[i][k]) is in the sparsity pattern for the symmetric matrix. */ void cppad_colpack_symmetric( CppAD::vector<size_t>& color , size_t m , const CppAD::vector<unsigned int*>& adolc_pattern ) { size_t i; CPPAD_ASSERT_UNKNOWN( adolc_pattern.size() == m ); CPPAD_ASSERT_UNKNOWN( color.size() == m ); // Use adolc sparsity pattern to create corresponding bipartite graph ColPack::GraphColoringInterface graph( SRC_MEM_ADOLC, adolc_pattern.data(), m ); // Use STAR coloring because it has a direct recovery scheme; i.e., // not necessary to solve equations to extract values. graph.Coloring("SMALLEST_LAST", "STAR"); // Use coloring information to create seed matrix int n_seed_row; int n_seed_col; double** seed_matrix = graph.GetSeedMatrix(&n_seed_row, &n_seed_col); CPPAD_ASSERT_UNKNOWN( size_t(n_seed_row) == m ); // now return coloring for each row in format required by CppAD for(i = 0; i < m; i++) color[i] = m; for(i = 0; i < m; i++) { for(size_t k = 0; k < size_t(n_seed_col); k++) { if( seed_matrix[i][k] != 0.0 ) { CPPAD_ASSERT_UNKNOWN( color[i] == m ); color[i] = k; } } } # ifndef NDEBUG // check that every entry in the symetric matrix can be direclty recovered size_t i1, i2, j1, j2, k1, k2, nz1, nz2; for(i1 = 0; i1 < m; i1++) { nz1 = size_t(adolc_pattern[i1][0]); for(k1 = 1; k1 <= nz1; k1++) { j1 = adolc_pattern[i1][k1]; // check of a forward on color[i1] followed by a reverse // can recover entry (i1, j1) bool color_i1_ok = true; for(i2 = 0; i2 < m; i2++) if( i1 != i2 && color[i1] == color[i2] ) { nz2 = adolc_pattern[i2][0]; for(k2 = 1; k2 <= nz2; k2++) { j2 = adolc_pattern[i2][k2]; color_i1_ok &= (j1 != j2); } } // check of a forward on color[j1] followed by a reverse // can recover entry (j1, i1) bool color_j1_ok = true; for(j2 = 0; j2 < m; j2++) if( j1 != j2 && color[j1] == color[j2] ) { nz2 = adolc_pattern[j2][0]; for(k2 = 1; k2 <= nz2; k2++) { i2 = adolc_pattern[j2][k2]; color_j1_ok &= (i1 != i2); } } CPPAD_ASSERT_UNKNOWN( color_i1_ok || color_j1_ok ); } } # endif return; }
// ----------------------------------------------------------------------- // get the result of the work bool multi_newton_combine(CppAD::vector<double>& xout) { // number of threads in the calculation size_t num_threads = std::max(num_threads_, size_t(1)); // remove duplicates and points that are not solutions xout.resize(0); bool ok = true; size_t thread_num; // initialize as more that sub_lenght_ / 2 from any possible solution double xlast = - sub_length_; for(thread_num = 0; thread_num < num_threads; thread_num++) { vector<double>& x = work_all_[thread_num]->x; size_t i; for(i = 0; i < x.size(); i++) { // check for case where this point is lower limit for this // thread and upper limit for previous thread if( fabs(x[i] - xlast) >= sub_length_ ) { xout.push_back( x[i] ); xlast = x[i]; } else { double fcur, flast, df; fun_(x[i], fcur, df); fun_(xlast, flast, df); if( fabs(fcur) < fabs(flast) ) { xout[ xout.size() - 1] = x[i]; xlast = x[i]; } } } ok &= work_all_[thread_num]->ok; } // go down so free memory for other threads before memory for master thread_num = num_threads; while(thread_num--) { # if USE_THREAD_ALLOC_FOR_WORK_ALL // call the destructor for CppAD::vector destructor work_all_[thread_num]->x.~vector<double>(); // delete the raw memory allocation void* v_ptr = static_cast<void*>( work_all_[thread_num] ); thread_alloc::return_memory( v_ptr ); # else delete work_all_[thread_num]; # endif // Note that xout corresponds to memroy that is inuse by master // (so we can only chech have freed all their memory). if( thread_num > 0 ) { // check that there is no longer any memory inuse by this thread ok &= thread_alloc::inuse(thread_num) == 0; // return all memory being held for future use by this thread thread_alloc::free_available(thread_num); } } // now we are done with the work_all_ vector so free its memory // (becasue it is a static variable) work_all_.clear(); return ok; }