<?xml version='1.0'?>
<html xmlns='http://www.w3.org/1999/xhtml'
      xmlns:math='http://www.w3.org/1998/Math/MathML'
>
<head>
<title>Define Matrix Multiply as a User Atomic Operation</title>
<meta name="description" id="description" content="Define Matrix Multiply as a User Atomic Operation"/>
<meta name="keywords" id="keywords" content=" mat_mul define matrix multiply user_atomic test example "/>
<style type='text/css'>
body { color : black }
body { background-color : white }
A:link { color : blue }
A:visited { color : purple }
A:active { color : purple }
</style>
<script type='text/javascript' language='JavaScript' src='_mat_mul.hpp_xml.js'>
</script>
</head>
<body>
<table><tr>
<td>
<a href="http://www.coin-or.org/CppAD/" target="_top"><img border="0" src="_image.gif"/></a>
</td>
<td><a href="mat_mul.cpp.xml" target="_top">Prev</a>
</td><td><a href="boolvalued.xml" target="_top">Next</a>
</td><td>
<select onchange='choose_across0(this)'>
<option>Index-&gt;</option>
<option>contents</option>
<option>reference</option>
<option>index</option>
<option>search</option>
<option>external</option>
</select>
</td>
<td>
<select onchange='choose_up0(this)'>
<option>Up-&gt;</option>
<option>CppAD</option>
<option>AD</option>
<option>ADValued</option>
<option>user_atomic</option>
<option>mat_mul.cpp</option>
<option>mat_mul.hpp</option>
</select>
</td>
<td>
<select onchange='choose_down3(this)'>
<option>ADValued-&gt;</option>
<option>Arithmetic</option>
<option>std_math_ad</option>
<option>MathOther</option>
<option>CondExp</option>
<option>Discrete</option>
<option>user_atomic</option>
</select>
</td>
<td>
<select onchange='choose_down2(this)'>
<option>user_atomic-&gt;</option>
<option>user_tan.cpp</option>
<option>mat_mul.cpp</option>
</select>
</td>
<td>
<select onchange='choose_down1(this)'>
<option>mat_mul.cpp-&gt;</option>
<option>mat_mul.hpp</option>
</select>
</td>
<td>mat_mul.hpp</td>
<td>
<select onchange='choose_current0(this)'>
<option>Headings-&gt;</option>
<option>Syntax</option>
<option>Example</option>
<option>Begin Source</option>
<option>Extra Call Information</option>
<option>Matrix Indexing</option>
<option>One Matrix Multiply</option>
<option>Reverse Partials One Order</option>
<option>Set Union</option>
<option>CppAD User Atomic Callback Functions</option>
<option>Declare mat_mul Function</option>
</select>
</td>
</tr></table><br/>




<center><b><big><big>Define Matrix Multiply as a User Atomic Operation</big></big></b></center>
<br/>
<b><big><a name="Syntax" id="Syntax">Syntax</a></big></b>
<br/>
This file is located in the <code><font color="blue">example</font></code> directory.
It can be copied to the current working directory and included
with the syntax

<code><font color="blue"><span style='white-space: nowrap'><br/>
&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;#&#xA0;include&#xA0;&quot;mat_mul.hpp&quot;<br/>
</span></font></code>
<br/>
<b><big><a name="Example" id="Example">Example</a></big></b>
<br/>
The file <a href="mat_mul.cpp.xml" target="_top"><span style='white-space: nowrap'>mat_mul.cpp</span></a>
 contains an example use of 
<code><font color="blue">mat_mul.hpp</font></code>.
It returns true if it succeeds and false otherwise.

<br/>
<br/>
<b><big><a name="Begin Source" id="Begin Source">Begin Source</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
# include &lt;cppad/cppad.hpp&gt;      // Include CppAD definitions
namespace {                      // Begin empty namespace 
	using CppAD::vector;        // Let vector denote CppAD::vector 
</pre></font></code>


<br/>
<br/>
<b><big><a name="Extra Call Information" id="Extra Call Information">Extra Call Information</a></big></b>
 
<code><font color='blue'><pre style='display:inline'> 
	// Information we will attach to each mat_mul call
	struct call_info {
		size_t nr_result;
		size_t n_middle;
		size_t nc_result;
		vector&lt;bool&gt;  vx;
	};
	vector&lt;call_info&gt; info_; // vector of call information

	// number of orders for this operation (k + 1)
	size_t n_order_ = 0;
	// number of rows in the result matrix
	size_t nr_result_ = 0;
	// number of columns in left matrix and number of rows in right matrix
	size_t n_middle_ = 0;
	// number of columns in the result matrix
	size_t nc_result_ = 0;
	// which components of x are variables
	vector&lt;bool&gt;* vx_ = 0;

	// get the information corresponding to this call
	void get_info(size_t id, size_t k, size_t n, size_t m)
	{	n_order_   = k + 1;	
		nr_result_ = info_[id].nr_result; 
		n_middle_  = info_[id].n_middle;
		nc_result_ = info_[id].nc_result;
		vx_        = &amp;(info_[id].vx);

		assert(n == nr_result_ * n_middle_ + n_middle_ * nc_result_);
		assert(m ==  nr_result_ * nc_result_);
	}

</pre></font></code>

<br/>
<br/>
<b><big><a name="Matrix Indexing" id="Matrix Indexing">Matrix Indexing</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// Convert left matrix index pair and order to a single argument index 
	size_t left(size_t i, size_t j, size_t ell)
	{	assert( i &lt; nr_result_ );
		assert( j &lt; n_middle_ );
		return (i * n_middle_ + j) * n_order_ + ell;
	}
	// Convert right matrix index pair and order to a single argument index 
	size_t right(size_t i, size_t j, size_t ell)
	{	assert( i &lt; n_middle_ );
		assert( j &lt; nc_result_ );
		size_t offset = nr_result_ * n_middle_;
		return (offset + i * nc_result_ + j) * n_order_ + ell;
	}
	// Convert result matrix index pair and order to a single result index 
	size_t result(size_t i, size_t j, size_t ell)
	{	assert( i &lt; nr_result_ );
		assert( j &lt; nc_result_ );
		return (i * nc_result_ + j) * n_order_ + ell;
	}
</pre></font></code>


<br/>
<br/>
<b><big><a name="One Matrix Multiply" id="One Matrix Multiply">One Matrix Multiply</a></big></b>
<br/>
Forward mode matrix multiply left times right and sum into result:
<code><font color='blue'><pre style='display:inline'> 
	void multiply_and_sum(
		size_t                order_left , 
		size_t                order_right, 
		const vector&lt;double&gt;&amp;         tx ,
		vector&lt;double&gt;&amp;               ty ) 
	{	size_t i, j;
		size_t order_result = order_left + order_right; 
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	double sum = 0.;
				size_t middle, im_left, mj_right, ij_result;
				for(middle = 0; middle &lt; n_middle_; middle++)
				{	im_left  = left(i, middle, order_left);
					mj_right = right(middle, j, order_right);
					sum     += tx[im_left] * tx[mj_right];
				}
				ij_result = result(i, j, order_result);
				ty[ ij_result ] += sum;
			}
		}
		return;
	}
</pre></font></code>


<br/>
<br/>
<b><big><a name="Reverse Partials One Order" id="Reverse Partials One Order">Reverse Partials One Order</a></big></b>
<br/>
Compute reverse mode partials for one order and sum into px:
<code><font color='blue'><pre style='display:inline'> 
	void reverse_multiply(
		size_t                order_left , 
		size_t                order_right, 
		const vector&lt;double&gt;&amp;         tx ,
		const vector&lt;double&gt;&amp;         ty ,
		vector&lt;double&gt;&amp;               px ,
		const vector&lt;double&gt;          py ) 
	{	size_t i, j;
		size_t order_result = order_left + order_right; 
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	size_t middle, im_left, mj_right, ij_result;
				for(middle = 0; middle &lt; n_middle_; middle++)
				{	ij_result = result(i, j, order_result);
					im_left   = left(i, middle, order_left);
					mj_right  = right(middle, j, order_right);
					// sum       += tx[im_left]  * tx[mj_right];
					px[im_left]  += tx[mj_right] * py[ij_result];
					px[mj_right] += tx[im_left]  * py[ij_result];
				}
			}
		}
		return;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="Set Union" id="Set Union">Set Union</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	void my_union(
		std::set&lt;size_t&gt;&amp;         result  ,
		const std::set&lt;size_t&gt;&amp;   left    ,
		const std::set&lt;size_t&gt;&amp;   right   )
	{	std::set&lt;size_t&gt; temp;
		std::set_union(
			left.begin()              ,
			left.end()                ,
			right.begin()             ,
			right.end()               ,
			std::inserter(temp, temp.begin())
		);
		result.swap(temp);
	}
</pre></font></code>


<br/>
<br/>
<b><big><a name="CppAD User Atomic Callback Functions" id="CppAD User Atomic Callback Functions">CppAD User Atomic Callback Functions</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// ----------------------------------------------------------------------
	// forward mode routine called by CppAD
	bool mat_mul_forward(
		size_t                   id ,
		size_t                    k ,
		size_t                    n ,
		size_t                    m ,
		const vector&lt;bool&gt;&amp;      vx ,
		vector&lt;bool&gt;&amp;            vy ,
		const vector&lt;double&gt;&amp;    tx ,
		vector&lt;double&gt;&amp;          ty
	)
	{	size_t i, j, ell;
		get_info(id, k, n, m);

		// check if this is during the call to mat_mul(id, ax, ay)
		if( vx.size() &gt; 0 )
		{	assert( k == 0 &amp;&amp; vx.size() &gt; 0 );

			// store the vx information in info_
			assert( vx_-&gt;size() == 0 );
			info_[id].vx.resize(n);
			for(j = 0; j &lt; n; j++)
				info_[id].vx[j] = vx[j];
			assert( vx_-&gt;size() == n );
			
			// now compute vy
			for(i = 0; i &lt; nr_result_; i++)
			{	for(j = 0; j &lt; nc_result_; j++)
				{	// compute vy[ result(i, j, 0) ]
					bool   var = false;
					bool   nz_left, nz_right;
					size_t middle, im_left, mj_right, ij_result;
					for(middle = 0; middle &lt; n_middle_; middle++)
					{	im_left  = left(i, middle, k);
						mj_right = right(middle, j, k);
						nz_left  = vx[im_left]  | (tx[im_left] != 0.);
						nz_right = vx[mj_right] | (tx[mj_right]!= 0.);
						// if not multiplying by the constant zero
						if( nz_left &amp; nz_right )
							var |= (vx[im_left] | vx[mj_right]);
					}
					ij_result     = result(i, j, k);
					vy[ij_result] = var;
				}
			}
		}

		// initialize result as zero
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
				ty[ result(i, j, k) ] = 0.;
		}
		// sum the product of proper orders
		for(ell = 0; ell &lt;=k; ell++)
			multiply_and_sum(ell, k-ell, tx, ty);

		// All orders are implemented and there are no possible error
		// conditions, so always return true.
		return true;
	}
	// ----------------------------------------------------------------------
	// reverse mode routine called by CppAD
	bool mat_mul_reverse(
		size_t                   id ,
		size_t                    k ,
		size_t                    n ,
		size_t                    m ,
		const vector&lt;double&gt;&amp;    tx ,
		const vector&lt;double&gt;&amp;    ty ,
		vector&lt;double&gt;&amp;          px ,
		const vector&lt;double&gt;&amp;    py
	)
	{	get_info(id, k, n, m);

		size_t ell = n * n_order_;
		while(ell--)
			px[ell] = 0.;

		size_t order = n_order_;
		while(order--)
		{	// reverse sum the products for specified order
			for(ell = 0; ell &lt;=order; ell++)
				reverse_multiply(ell, order-ell, tx, ty, px, py);
		}

		// All orders are implemented and there are no possible error
		// conditions, so always return true.
		return true;
	}

	// ----------------------------------------------------------------------
	// forward Jacobian sparsity routine called by CppAD
	bool mat_mul_for_jac_sparse(
		size_t                               id ,             
		size_t                                n ,
		size_t                                m ,
		size_t                                q ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;     r ,
		vector&lt; std::set&lt;size_t&gt; &gt;&amp;           s )
	{	size_t i, j, k, im_left, middle, mj_right, ij_result;
		k = 0;
		get_info(id, k, n, m);
	
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	ij_result = result(i, j, k);
				s[ij_result].clear();
				for(middle = 0; middle &lt; n_middle_; middle++)
				{	im_left   = left(i, middle, k);
					mj_right  = right(middle, j, k);

					// s[ij_result] = union( s[ij_result], r[im_left] )
					my_union(s[ij_result], s[ij_result], r[im_left]);

					// s[ij_result] = union( s[ij_result], r[mj_right] )
					my_union(s[ij_result], s[ij_result], r[mj_right]);
				}
			}
		}
		return true;
	}
	// ----------------------------------------------------------------------
	// reverse Jacobian sparsity routine called by CppAD
	bool mat_mul_rev_jac_sparse(
		size_t                               id ,             
		size_t                                n ,
		size_t                                m ,
		size_t                                q ,
		vector&lt; std::set&lt;size_t&gt; &gt;&amp;           r ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;     s )
	{	size_t i, j, k, im_left, middle, mj_right, ij_result;
		k = 0;
		get_info(id, k, n, m);
	
		for(j = 0; j &lt; n; j++)
			r[j].clear();

		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	ij_result = result(i, j, k);
				for(middle = 0; middle &lt; n_middle_; middle++)
				{	im_left   = left(i, middle, k);
					mj_right  = right(middle, j, k);

					// r[im_left] = union( r[im_left], s[ij_result] )
					my_union(r[im_left], r[im_left], s[ij_result]);

					// r[mj_right] = union( r[mj_right], s[ij_result] )
					my_union(r[mj_right], r[mj_right], s[ij_result]);
				}
			}
		}
		return true;
	}
	// ----------------------------------------------------------------------
	// reverse Hessian sparsity routine called by CppAD
	bool mat_mul_rev_hes_sparse(
		size_t                               id ,             
		size_t                                n ,
		size_t                                m ,
		size_t                                q ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;     r ,
		const vector&lt;bool&gt;&amp;                   s ,
		vector&lt;bool&gt;&amp;                         t ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;     u ,
		vector&lt; std::set&lt;size_t&gt; &gt;&amp;           v )
	{	size_t i, j, k, im_left, middle, mj_right, ij_result;
		k = 0;
		get_info(id, k, n, m);
	
		for(j = 0; j &lt; n; j++)
		{	t[j] = false;	
			v[j].clear();
		}

		assert( vx_-&gt;size() == n );
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	ij_result = result(i, j, k);
				for(middle = 0; middle &lt; n_middle_; middle++)
				{	im_left   = left(i, middle, k);
					mj_right  = right(middle, j, k);

					// back propagate Jacobian sparsity
					t[im_left]   = (t[im_left] | s[ij_result]);
					t[mj_right]  = (t[mj_right] | s[ij_result]);
					// Visual Studio C++ 2008 warns unsafe mix of int and
					// bool if we use the following code directly above:
					// t[im_left]  |= s[ij_result];
					// t[mj_right] |= s[ij_result];

					// back propagate Hessian sparsity 
					// v[im_left]  = union( v[im_left],  u[ij_result] )
					// v[mj_right] = union( v[mj_right], u[ij_result] )
					my_union(v[im_left],  v[im_left],  u[ij_result] );
					my_union(v[mj_right], v[mj_right], u[ij_result] );

					// Check for case where the (i,j) result element
					// is in reverse Jacobian and both left and right
					// operands in multiplication are variables 
					if(s[ij_result] &amp; (*vx_)[im_left] &amp; (*vx_)[mj_right])
					{	// v[im_left] = union( v[im_left], r[mj_right] )
						my_union(v[im_left], v[im_left], r[mj_right] );
						// v[mj_right] = union( v[mj_right], r[im_left] )
						my_union(v[mj_right], v[mj_right], r[im_left] );
					}
				}
			}
		}
		return true;
	}
</pre></font></code>


<br/>
<br/>
<b><big><a name="Declare mat_mul Function" id="Declare mat_mul Function">Declare mat_mul Function</a></big></b>
<br/>
Declare the <code><font color="blue">AD&lt;double&gt;</font></code> routine 
<code><font color="blue"><span style='white-space: nowrap'>mat_mul(</span></font><i><font color="black"><span style='white-space: nowrap'>id</span></font></i><font color="blue"><span style='white-space: nowrap'>,&#xA0;</span></font><i><font color="black"><span style='white-space: nowrap'>ax</span></font></i><font color="blue"><span style='white-space: nowrap'>,&#xA0;</span></font><i><font color="black"><span style='white-space: nowrap'>ay</span></font></i><font color="blue"><span style='white-space: nowrap'>)</span></font></code>

and end empty namespace:
<code><font color='blue'><pre style='display:inline'> 
	CPPAD_USER_ATOMIC(
		mat_mul                 , 
		CPPAD_TEST_VECTOR       ,
		double                  , 
		mat_mul_forward         , 
		mat_mul_reverse         ,
		mat_mul_for_jac_sparse  ,
		mat_mul_rev_jac_sparse  ,
		mat_mul_rev_hes_sparse  
	)
} // End empty namespace
</pre></font></code>


<hr/>Input File: example/mat_mul.hpp

</body>
</html>

