Esempio n. 1
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;
}
Esempio n. 2
0
size_t ADFun<Base>::SparseJacobianReverse(
	const VectorBase&     x    ,
	const VectorSet&      p    ,
	const VectorSize&     row  ,
	const VectorSize&     col  ,
	VectorBase&           jac  ,
	sparse_jacobian_work& work )
{
	size_t m = Range();
	size_t n = Domain();
# ifndef NDEBUG
	size_t k, K = jac.size();
	CPPAD_ASSERT_KNOWN(
		size_t(x.size()) == n ,
		"SparseJacobianReverse: size of x not equal domain dimension for f."
	); 
	CPPAD_ASSERT_KNOWN(
		size_t(row.size()) == K && size_t(col.size()) == K ,
		"SparseJacobianReverse: either r or c does not have "
		"the same size as jac."
	); 
	CPPAD_ASSERT_KNOWN(
		work.color.size() == 0 || work.color.size() == m,
		"SparseJacobianReverse: invalid value in work."
	);
	for(k = 0; k < K; k++)
	{	CPPAD_ASSERT_KNOWN(
			row[k] < m,
			"SparseJacobianReverse: invalid value in r."
		);
		CPPAD_ASSERT_KNOWN(
			col[k] < n,
			"SparseJacobianReverse: invalid value in c."
		);
	}
	if( work.color.size() != 0 )
		for(size_t i = 0; i < m; i++) CPPAD_ASSERT_KNOWN(
			work.color[i] <= m,
			"SparseJacobianReverse: invalid value in work."
	);
# endif
 
	typedef typename VectorSet::value_type Set_type;
	typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type;
	Pattern_type s;
	if( work.color.size() == 0 )
	{	bool transpose = false;
		sparsity_user2internal(s, p, m, n, transpose);
	}
	size_t n_sweep = SparseJacobianRev(x, s, row, col, jac, work);
	return n_sweep;
}
Esempio n. 3
0
size_t ADFun<Base>::SparseHessian(
	const VectorBase&     x    ,
	const VectorBase&     w    ,
	const VectorSet&      p    ,
	const VectorSize&     row  ,
	const VectorSize&     col  ,
	VectorBase&           hes  ,
	sparse_hessian_work&  work )
{
	size_t n    = Domain();
# ifndef NDEBUG
	size_t k, K = hes.size();
	CPPAD_ASSERT_KNOWN(
		size_t(x.size()) == n ,
		"SparseHessian: size of x not equal domain dimension for f."
	); 
	CPPAD_ASSERT_KNOWN(
		size_t(row.size()) == K && size_t(col.size()) == K ,
		"SparseHessian: either r or c does not have the same size as ehs."
	); 
	CPPAD_ASSERT_KNOWN(
		work.color.size() == 0 || work.color.size() == n,
		"SparseHessian: invalid value in work."
	);
	for(k = 0; k < K; k++)
	{	CPPAD_ASSERT_KNOWN(
			row[k] < n,
			"SparseHessian: invalid value in r."
		);
		CPPAD_ASSERT_KNOWN(
			col[k] < n,
			"SparseHessian: invalid value in c."
		);
	}
	if( work.color.size() != 0 )
		for(size_t j = 0; j < n; j++) CPPAD_ASSERT_KNOWN(
			work.color[j] <= n,
			"SparseHessian: invalid value in work."
	);
# endif
	typedef typename VectorSet::value_type Set_type;
	typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type;
	Pattern_type s;
	if( work.color.size() == 0 )
	{	bool transpose = false;
		sparsity_user2internal(s, p, n, n, transpose);
	}
	size_t n_sweep = SparseHessianCompute(x, w, s, row, col, hes, work);
	return n_sweep;
}
Esempio n. 4
0
void index_sort(const VectorKey& keys, VectorSize& ind)
{	typedef typename VectorKey::value_type Compare;
	CheckSimpleVector<size_t, VectorSize>();

	typedef index_sort_element<Compare> element;

	CPPAD_ASSERT_KNOWN(
		size_t(keys.size()) == size_t(ind.size()),
		"index_sort: vector sizes do not match"
	);

	size_t size_work = size_t(keys.size());
	size_t size_out;
	element* work =
		thread_alloc::create_array<element>(size_work, size_out);

	// copy initial order into work
	size_t i;
	for(i = 0; i < size_work; i++)
	{	work[i].set_key( keys[i] );
		work[i].set_index( i );
	}

	// sort the work array
	std::sort(work, work+size_work);

	// copy the indices to the output vector
	for(i = 0; i < size_work; i++)
		ind[i] = work[i].get_index();

	// we are done with this work array
	thread_alloc::delete_array(work);

	return;
}
Esempio n. 5
0
size_t ADFun<Base>::SparseHessianCompute(
	const VectorBase&           x           ,
	const VectorBase&           w           ,
	      VectorSet&            sparsity    ,
	const VectorSize&           row         ,
	const VectorSize&           col         ,
	      VectorBase&           hes         ,
	      sparse_hessian_work&  work        )
{
	using   CppAD::vectorBool;
	size_t i, k, ell;

	CppAD::vector<size_t>& color(work.color);
	CppAD::vector<size_t>& order(work.order);

	size_t n = Domain();

	// some values
	const Base zero(0);
	const Base one(1);

	// check VectorBase is Simple Vector class with Base type elements
	CheckSimpleVector<Base, VectorBase>();

	CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n );
	CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n );

	// number of components of Hessian that are required
	size_t K = hes.size();
	CPPAD_ASSERT_UNKNOWN( row.size() == K );
	CPPAD_ASSERT_UNKNOWN( col.size() == K );

	// Point at which we are evaluating the Hessian
	Forward(0, x);

	// check for case where nothing (except Forward above) to do
	if( K == 0 )
		return 0;

	// Rows of the Hessian (i below) correspond to the forward mode index
	// and columns (j below) correspond to the reverse mode index.
	if( color.size() == 0 )
	{
		CPPAD_ASSERT_UNKNOWN( sparsity.n_set() ==  n );
		CPPAD_ASSERT_UNKNOWN( sparsity.end() ==  n );

		// execute coloring algorithm
		color.resize(n);
		color_general_cppad(sparsity, row, col, color);

		// put sorting indices in color order
		VectorSize key(K);
		order.resize(K);
		for(k = 0; k < K; k++)
			key[k] = color[ row[k] ];
		index_sort(key, order);

	}
	size_t n_color = 1;
	for(ell = 0; ell < n; ell++) if( color[ell] < n )
		n_color = std::max(n_color, color[ell] + 1);

	// direction vector for calls to forward (rows of the Hessian)
	VectorBase u(n);

	// location for return values from reverse (columns of the Hessian)
	VectorBase ddw(2 * n);

	// initialize the return value
	for(k = 0; k < K; k++)
		hes[k] = zero;

	// loop over colors
	k = 0;
	for(ell = 0; ell < n_color; ell++)
	{	CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell );

		// combine all rows with this color
		for(i = 0; i < n; i++)
		{	u[i] = zero;
			if( color[i] == ell )
				u[i] = one;
		}
		// call forward mode for all these rows at once
		Forward(1, u);

		// evaluate derivative of w^T * F'(x) * u
		ddw = Reverse(2, w);

		// set the corresponding components of the result
		while( k < K && color[ row[ order[k] ] ] == ell ) 
		{	hes[ order[k] ] = ddw[ col[ order[k] ] * 2 + 1 ];
			k++;
		}
	}
	return n_color;
}
Esempio n. 6
0
size_t ADFun<Base>::SparseJacobianRev(
	const VectorBase&           x           ,
	      VectorSet&            p           ,
	const VectorSize&           row         ,
	const VectorSize&           col         ,
	      VectorBase&           jac         ,
	      sparse_jacobian_work& work        )
{
	size_t i, k, ell;

	CppAD::vector<size_t>& order(work.order);
	CppAD::vector<size_t>& color(work.color);

	size_t m = Range();
	size_t n = Domain();

	// some values
	const Base zero(0);
	const Base one(1);

	// check VectorBase is Simple Vector class with Base type elements
	CheckSimpleVector<Base, VectorBase>();

	CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n );
	CPPAD_ASSERT_UNKNOWN (color.size() == m || color.size() == 0 );

	// number of components of Jacobian that are required
	size_t K = size_t(jac.size());
	CPPAD_ASSERT_UNKNOWN( row.size() == K );
	CPPAD_ASSERT_UNKNOWN( col.size() == K );

	// Point at which we are evaluating the Jacobian
	Forward(0, x);

	// check for case where nothing (except Forward above) to do
	if( K == 0 )
		return 0;

	if( color.size() == 0 )
	{
		CPPAD_ASSERT_UNKNOWN( p.n_set() == m );
		CPPAD_ASSERT_UNKNOWN( p.end()   == n );

		// execute the coloring algorithm
		color.resize(m);
		if(	work.color_method == "cppad" )
			color_general_cppad(p, row, col, color);
		else if( work.color_method == "colpack" )
		{
# if CPPAD_HAS_COLPACK
			color_general_colpack(p, row, col, color);
# else
			CPPAD_ASSERT_KNOWN(
				false,
				"SparseJacobianReverse: work.color_method = colpack "
				"and colpack_prefix missing from cmake command line."
			);
# endif
		}
		else CPPAD_ASSERT_KNOWN(
			false,
			"SparseJacobianReverse: work.color_method is not valid."
		);

		// put sorting indices in color order
		VectorSize key(K);
		order.resize(K);
		for(k = 0; k < K; k++)
			key[k] = color[ row[k] ];
		index_sort(key, order);
	}
	size_t n_color = 1;
	for(i = 0; i < m; i++) if( color[i] < m ) 
		n_color = std::max(n_color, color[i] + 1);

	// weighting vector for calls to reverse
	VectorBase w(m);

	// location for return values from Reverse
	VectorBase dw(n);

	// initialize the return value
	for(k = 0; k < K; k++)
		jac[k] = zero;

	// loop over colors
	k = 0;
	for(ell = 0; ell < n_color; ell++)
	{	CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell );

		// combine all the rows with this color
		for(i = 0; i < m; i++)
		{	w[i] = zero;
			if( color[i] == ell )
				w[i] = one;
		}
		// call reverse mode for all these rows at once
		dw = Reverse(1, w);

		// set the corresponding components of the result
		while( k < K && color[ row[order[k]] ]  == ell ) 
		{	jac[ order[k] ] = dw[col[order[k]]];
			k++;
		}
	}
	return n_color;
}
Esempio n. 7
0
size_t ADFun<Base>::SparseJacobianFor(
	const VectorBase&            x           ,
	      VectorSet&             p_transpose ,
	const VectorSize&            row         ,
	const VectorSize&            col         ,
	      VectorBase&            jac         ,
	       sparse_jacobian_work& work        )
{
	size_t j, k, ell;

	CppAD::vector<size_t>& order(work.order);
	CppAD::vector<size_t>& color(work.color);

	size_t m = Range();
	size_t n = Domain();

	// some values
	const Base zero(0);
	const Base one(1);

	// check VectorBase is Simple Vector class with Base type elements
	CheckSimpleVector<Base, VectorBase>();

	CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n );
	CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n );

	// number of components of Jacobian that are required
	size_t K = size_t(jac.size());
	CPPAD_ASSERT_UNKNOWN( row.size() == K );
	CPPAD_ASSERT_UNKNOWN( col.size() == K );

	// Point at which we are evaluating the Jacobian
	Forward(0, x);

	// check for case where nothing (except Forward above) to do
	if( K == 0 )
		return 0;

	if( color.size() == 0 )
	{
		CPPAD_ASSERT_UNKNOWN( p_transpose.n_set() ==  n );
		CPPAD_ASSERT_UNKNOWN( p_transpose.end() ==  m );

		// execute coloring algorithm
		color.resize(n);
		if(	work.color_method == "cppad" )
			color_general_cppad(p_transpose, col, row, color);
		else if( work.color_method == "colpack" )
		{
# if CPPAD_HAS_COLPACK
			color_general_colpack(p_transpose, col, row, color);
# else
			CPPAD_ASSERT_KNOWN(
				false,
				"SparseJacobianForward: work.color_method = colpack "
				"and colpack_prefix missing from cmake command line."
			);
# endif
		}
		else CPPAD_ASSERT_KNOWN(
			false,
			"SparseJacobianForward: work.color_method is not valid."
		);

		// put sorting indices in color order
		VectorSize key(K);
		order.resize(K);
		for(k = 0; k < K; k++)
			key[k] = color[ col[k] ];
		index_sort(key, order);
	}
	size_t n_color = 1;
	for(j = 0; j < n; j++) if( color[j] < n )
		n_color = std::max(n_color, color[j] + 1);

	// initialize the return value
	for(k = 0; k < K; k++)
		jac[k] = zero;

# if CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION == 1
	// direction vector and return values for calls to forward
	VectorBase dx(n), dy(m);

	// loop over colors
	k = 0;
	for(ell = 0; ell < n_color; ell++)
	{	CPPAD_ASSERT_UNKNOWN( color[ col[ order[k] ] ] == ell );

		// combine all columns with this color
		for(j = 0; j < n; j++)
		{	dx[j] = zero;
			if( color[j] == ell )
				dx[j] = one;
		}
		// call forward mode for all these columns at once
		dy = Forward(1, dx);

		// set the corresponding components of the result
		while( k < K && color[ col[order[k]] ] == ell ) 
		{	jac[ order[k] ] = dy[row[order[k]]];
			k++;
		}
	}
# else
	// abbreviation for this value
	size_t max_r = CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION;
	CPPAD_ASSERT_UNKNOWN( max_r > 1 );

	// count the number of colors done so far
	size_t count_color = 0;
	// count the sparse matrix entries done so far
	k = 0;
	while( count_color < n_color )
	{	// number of colors we will do this time
		size_t r = std::min(max_r , n_color - count_color);
		VectorBase dx(n * r), dy(m * r);

		// loop over colors we will do this tme
		for(ell = 0; ell < r; ell++) 	
		{	// combine all columns with this color
			for(j = 0; j < n; j++)
			{	dx[j * r + ell] = zero;
				if( color[j] == ell + count_color )
					dx[j * r + ell] = one;
			}
		}
		size_t q           = 1;
		dy = Forward(q, r, dx);

		// store results
		for(ell = 0; ell < r; ell++) 	
		{	// set the components of the result for this color
			while( k < K && color[ col[order[k]] ] == ell + count_color ) 
			{	jac[ order[k] ] = dy[ row[order[k]] * r + ell ];
				k++;
			}
		}
		count_color += r;
	}
# endif
	return n_color;
}
Esempio n. 8
0
size_t ADFun<Base>::SparseJacobianReverse(
	const VectorBase&     x    ,
	const VectorSet&      p    ,
	const VectorSize&     row  ,
	const VectorSize&     col  ,
	VectorBase&           jac  ,
	sparse_jacobian_work& work )
{
	size_t m = Range();
	size_t n = Domain();
	size_t k, K = jac.size();
	if( work.user_row.size() == 0 )
	{	// create version of (row, col, k) sorted by row row value
		work.user_col.resize(K+1);
		work.user_row.resize(K+1);
		work.sort_row.resize(K+1);

		// put sorted indices in user_row and user_col
		for(k = 0; k < K; k++)
		{	work.user_row[k] = row[k];
			work.user_col[k] = col[k];
		}
		work.user_row[K] = m;
		work.user_col[K] = n;

		// put sorting indices in sort_row
		index_sort(work.user_row, work.sort_row);
	}
# ifndef NDEBUG
	CPPAD_ASSERT_KNOWN(
		size_t(x.size()) == n ,
		"SparseJacobianReverse: size of x not equal domain dimension for f."
	); 
	CPPAD_ASSERT_KNOWN(
		size_t(row.size()) == K && size_t(col.size()) == K ,
		"SparseJacobianReverse: either r or c does not have "
		"the same size as jac."
	); 
	CPPAD_ASSERT_KNOWN(
		work.user_row.size() == K+1 &&
		work.user_col.size() == K+1 &&
		work.sort_row.size() == K+1 ,
		"SparseJacobianReverse: invalid value in work."
	);
	CPPAD_ASSERT_KNOWN(
		work.color.size() == 0 || work.color.size() == m,
		"SparseJacobianReverse: invalid value in work."
	);
	for(k = 0; k < K; k++)
	{	CPPAD_ASSERT_KNOWN(
			row[k] < m,
			"SparseJacobianReverse: invalid value in r."
		);
		CPPAD_ASSERT_KNOWN(
			col[k] < n,
			"SparseJacobianReverse: invalid value in c."
		);
		CPPAD_ASSERT_KNOWN(
			work.sort_row[k] < K,
			"SparseJacobianReverse: invalid value in work."
		);
		CPPAD_ASSERT_KNOWN(
			work.user_row[k] == row[k],
			"SparseJacobianReverse: invalid value in work."
		);
		CPPAD_ASSERT_KNOWN(
			work.user_col[k] == col[k],
			"SparseJacobianReverse: invalid value in work."
		);
	}
	if( work.color.size() != 0 )
		for(size_t i = 0; i < m; i++) CPPAD_ASSERT_KNOWN(
			work.color[i] < m,
			"SparseJacobianReverse: invalid value in work."
	);
# endif
 
	typedef typename VectorSet::value_type Set_type;
	typedef typename internal_sparsity<Set_type>::pattern_type Pattern_type;
	Pattern_type s;
	if( work.color.size() == 0 )
	{	bool transpose = false;
		sparsity_user2internal(s, p, m, n, transpose);
	}
	size_t n_sweep = SparseJacobianRev(x, s, jac, work);
	return n_sweep;
}