Пример #1
20
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;
}
Пример #2
1
	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;
		}
	}
Пример #3
1
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;
}
Пример #4
1
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;
}
Пример #5
1
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;
}
Пример #6
1
	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)
		// ...
	}
Пример #7
1
		// 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];
		}
Пример #8
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;
	}
Пример #9
1
	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;
			}
		}
			
	}
Пример #10
1
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];
        }
    }
Пример #12
1
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;
                }
            }
        }
    }
Пример #14
1
	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;
			}
		}
	}
Пример #15
1
	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;
			}
		}
	}
Пример #16
1
/*!
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;
}
Пример #17
1
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;
}
Пример #18
1
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--)
Пример #19
1
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();
		}
	}
}
Пример #21
1
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();
		}
	}
}
Пример #23
1
// ----------------------------------------------------------------------
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;
}
Пример #24
0
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;
}
Пример #25
0
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();
		}
	}
}
Пример #26
0
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;
}
Пример #27
0
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;
}
Пример #28
0
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;
	}
}
Пример #29
0
/*!
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;
}
Пример #30
0
// -----------------------------------------------------------------------
// 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;
}