Esempio n. 1
0
	void ad(size_t id, const ADVector& ax, ADVector& ay)
	{	size_t i, j, k;
		size_t n = ax.size();
		size_t m = ay.size();
		size_t thread = thread_alloc::thread_num();
# ifndef NDEBUG
		bool ok;
		std::string msg = "user_atomoc: ";
# endif
		vector <Base>& x  = x_[thread];
		vector <Base>& y  = y_[thread];
		vector <bool>& vx = vx_[thread];
		vector <bool>& vy = vy_[thread];
		//
		if( x.size() < n )
		{	x.resize(n);
			vx.resize(n);
		}
		if( y.size() < m )
		{	y.resize(m);
			vy.resize(m);
		}
		// 
		// Determine if we are going to have to tape this operation
		tape_id_t tape_id     = 0;
		ADTape<Base>* tape = CPPAD_NULL;
		for(j = 0; j < n; j++)
		{	x[j]   = ax[j].value_;
			vx[j]  = Variable( ax[j] );
			if ( (tape == CPPAD_NULL) & vx[j] )
			{	tape    = ax[j].tape_this();
				tape_id = ax[j].tape_id_;
			}
# ifndef NDEBUG
			ok  = (tape_id == 0) | Parameter(ax[j]);
			ok |= (tape_id == ax[j].tape_id_);
			if( ! ok )
			{	msg = msg + name_ + 
				": ax contains variables from different threads.";
				CPPAD_ASSERT_KNOWN(false, msg.c_str());
			}
# endif
		}
		// Use zero order forward mode to compute values
		k  = 0;
# if NDEBUG
		f_(id, k, n, m, vx, vy, x, y);  
# else
		ok = f_(id, k, n, m, vx, vy, x, y);  
		if( ! ok )
		{	msg = msg + name_ + ": ok returned false from "
				"zero order forward mode calculation.";
			CPPAD_ASSERT_KNOWN(false, msg.c_str());
		}
# endif
		// pass back values
		for(i = 0; i < m; i++)
		{	ay[i].value_ = y[i];

			// initialize entire vector as a constant (not on tape)
			ay[i].tape_id_ = 0;
			ay[i].taddr_   = 0;
		}
		// if tape is not null, ay is on the tape
		if( tape != CPPAD_NULL )
		{
			// Note the actual number of results is m
			CPPAD_ASSERT_UNKNOWN( NumRes(UserOp) == 0 );
			CPPAD_ASSERT_UNKNOWN( NumArg(UserOp) == 4 );

			// Begin operators corresponding to one user_atomic operation.
			// Put function index, domain size, range size, and id in tape
			tape->Rec_.PutArg(index_, id, n, m);
			tape->Rec_.PutOp(UserOp);
			// n + m operators follow for this one atomic operation

			// Now put the information for the argument vector in the tape
			CPPAD_ASSERT_UNKNOWN( NumRes(UsravOp) == 0 );
			CPPAD_ASSERT_UNKNOWN( NumRes(UsrapOp) == 0 );
			CPPAD_ASSERT_UNKNOWN( NumArg(UsravOp) == 1 );
			CPPAD_ASSERT_UNKNOWN( NumArg(UsrapOp) == 1 );
			for(j = 0; j < n; j++)
			{	if( vx[j] )
				{	// information for an argument that is a variable
					tape->Rec_.PutArg(ax[j].taddr_);
					tape->Rec_.PutOp(UsravOp);
				}
				else
				{	// information for an arugment that is parameter
					addr_t p = tape->Rec_.PutPar(ax[j].value_);
					tape->Rec_.PutArg(p);
					tape->Rec_.PutOp(UsrapOp);
				}
			}

			// Now put the information for the results in the tape
			CPPAD_ASSERT_UNKNOWN( NumArg(UsrrpOp) == 1 );
			CPPAD_ASSERT_UNKNOWN( NumRes(UsrrpOp) == 0 );
			CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 );
			CPPAD_ASSERT_UNKNOWN( NumRes(UsrrvOp) == 1 );
			for(i = 0; i < m; i++)
			{	if( vy[i] )
				{	ay[i].taddr_    = tape->Rec_.PutOp(UsrrvOp);
					ay[i].tape_id_  = tape_id;
				}
				else
				{	addr_t p = tape->Rec_.PutPar(ay[i].value_);
					tape->Rec_.PutArg(p);
					tape->Rec_.PutOp(UsrrpOp);
				}
			}

			// Put a duplicate UserOp at end of UserOp sequence
			tape->Rec_.PutArg(index_, id, n, m);
			tape->Rec_.PutOp(UserOp);
		} 
		return;
	}
Esempio n. 2
0
void operator()(
	const ADVector&  ax     ,
	      ADVector&  ay     ,
	size_t           id = 0 )
{	size_t i, j;
	size_t n = ax.size();
	size_t m = ay.size();
# ifndef NDEBUG
	bool ok;
	std::string msg = "atomic_base: " + afun_name() + ".eval: ";
	if( (n == 0) | (m == 0) )
	{	msg += "ax.size() or ay.size() is zero";
		CPPAD_ASSERT_KNOWN(false, msg.c_str() );
	}
# endif
	size_t thread = thread_alloc::thread_num();
	vector <Base>& tx  = afun_tx_[thread];
	vector <Base>& ty  = afun_ty_[thread];
	vector <bool>& vx  = afun_vx_[thread];
	vector <bool>& vy  = afun_vy_[thread];
	//
	if( vx.size() != n )
	{	vx.resize(n);
		tx.resize(n);
	}
	if( vy.size() != m )
	{	vy.resize(m);
		ty.resize(m);
	}
	// 
	// Determine tape corresponding to variables in ax
	tape_id_t     tape_id  = 0;
	ADTape<Base>* tape     = CPPAD_NULL;
	for(j = 0; j < n; j++)
	{	tx[j]  = ax[j].value_;
		vx[j]  = Variable( ax[j] );
		if( vx[j] )
		{
			if( tape_id == 0 )
			{	tape    = ax[j].tape_this();
				tape_id = ax[j].tape_id_;
				CPPAD_ASSERT_UNKNOWN( tape != CPPAD_NULL );
			}
# ifndef NDEBUG
			if( tape_id != ax[j].tape_id_ )
			{	msg += afun_name() + 
				": ax contains variables from different threads.";
				CPPAD_ASSERT_KNOWN(false, msg.c_str());
			}
# endif
		}
	}
	// Use zero order forward mode to compute values
	size_t q = 0, p = 0;
	set_id(id);
# ifdef NDEBUG
	forward(q, p, vx, vy, tx, ty);  
# else
	ok = forward(q, p, vx, vy, tx, ty);  
	if( ! ok )
	{	msg += afun_name() + ": ok is false for "
			"zero order forward mode calculation.";
		CPPAD_ASSERT_KNOWN(false, msg.c_str());
	}
# endif
	bool record_operation = false;
	for(i = 0; i < m; i++)
	{
		// pass back values
		ay[i].value_ = ty[i];

		// initialize entire vector parameters (not in tape)
		ay[i].tape_id_ = 0;
		ay[i].taddr_   = 0;

		// we need to record this operation if
		// any of the eleemnts of ay are variables,
		record_operation |= vy[i];
	}
# ifndef NDEBUG
	if( record_operation & (tape == CPPAD_NULL) )
	{	msg += 
		"all elements of vx are false but vy contains a true element";
		CPPAD_ASSERT_KNOWN(false, msg.c_str() );
	}
# endif
	// if tape is not null, ay is on the tape
	if( record_operation )
	{
		// Operator that marks beginning of this atomic operation
		CPPAD_ASSERT_UNKNOWN( NumRes(UserOp) == 0 );
		CPPAD_ASSERT_UNKNOWN( NumArg(UserOp) == 4 );
		tape->Rec_.PutArg(index_, id, n, m);
		tape->Rec_.PutOp(UserOp);

		// Now put n operators, one for each element of arugment vector
		CPPAD_ASSERT_UNKNOWN( NumRes(UsravOp) == 0 );
		CPPAD_ASSERT_UNKNOWN( NumRes(UsrapOp) == 0 );
		CPPAD_ASSERT_UNKNOWN( NumArg(UsravOp) == 1 );
		CPPAD_ASSERT_UNKNOWN( NumArg(UsrapOp) == 1 );
		for(j = 0; j < n; j++)
		{	if( vx[j] )
			{	// information for an argument that is a variable
				tape->Rec_.PutArg(ax[j].taddr_);
				tape->Rec_.PutOp(UsravOp);
			}
			else
			{	// information for an arugment that is parameter
				addr_t par = tape->Rec_.PutPar(ax[j].value_);
				tape->Rec_.PutArg(par);
				tape->Rec_.PutOp(UsrapOp);
			}
		}

		// Now put m operators, one for each element of result vector
		CPPAD_ASSERT_UNKNOWN( NumArg(UsrrpOp) == 1 );
		CPPAD_ASSERT_UNKNOWN( NumRes(UsrrpOp) == 0 );
		CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 );
		CPPAD_ASSERT_UNKNOWN( NumRes(UsrrvOp) == 1 );
		for(i = 0; i < m; i++)
		{	if( vy[i] )
			{	ay[i].taddr_    = tape->Rec_.PutOp(UsrrvOp);
				ay[i].tape_id_  = tape_id;
			}
			else
			{	addr_t par = tape->Rec_.PutPar(ay[i].value_);
				tape->Rec_.PutArg(par);
				tape->Rec_.PutOp(UsrrpOp);
			}
		}

		// Put a duplicate UserOp at end of UserOp sequence
		tape->Rec_.PutArg(index_, id, n, m);
		tape->Rec_.PutOp(UserOp);
	} 
	return;
}