<?xml version='1.0'?>
<html xmlns='http://www.w3.org/1999/xhtml'
      xmlns:math='http://www.w3.org/1998/Math/MathML'
>
<head>
<title>Matrix Multiply as an Atomic Operation</title>
<meta name="description" id="description" content="Matrix Multiply as an Atomic Operation"/>
<meta name="keywords" id="keywords" content=" multiply matrix atomic operation "/>
<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='_atomic_matrix_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="atomic_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>atomic</option>
<option>atomic_base</option>
<option>atomic_mat_mul.cpp</option>
<option>atomic_matrix_mul.hpp</option>
</select>
</td>
<td>
<select onchange='choose_down3(this)'>
<option>atomic-&gt;</option>
<option>checkpoint</option>
<option>atomic_base</option>
</select>
</td>
<td>
<select onchange='choose_down2(this)'>
<option>atomic_base-&gt;</option>
<option>atomic_ctor</option>
<option>atomic_option</option>
<option>atomic_afun</option>
<option>atomic_forward</option>
<option>atomic_reverse</option>
<option>atomic_for_sparse_jac</option>
<option>atomic_rev_sparse_jac</option>
<option>atomic_rev_sparse_hes</option>
<option>atomic_base_clear</option>
<option>atomic_get_started.cpp</option>
<option>atomic_norm_sq.cpp</option>
<option>atomic_reciprocal.cpp</option>
<option>atomic_tangent.cpp</option>
<option>atomic_mat_mul.cpp</option>
</select>
</td>
<td>
<select onchange='choose_down1(this)'>
<option>atomic_mat_mul.cpp-&gt;</option>
<option>atomic_matrix_mul.hpp</option>
</select>
</td>
<td>atomic_matrix_mul.hpp</td>
<td>
<select onchange='choose_current0(this)'>
<option>Headings-&gt;</option>
<option>Start Class Definition</option>
<option>Constructor</option>
<option>Left Operand Element Index</option>
<option>Right Operand Element Index</option>
<option>Result Element Index</option>
<option>Forward Matrix Multipliy</option>
<option>Reverse Matrix Multipliy</option>
<option>forward</option>
<option>reverse</option>
<option>for_sparse_jac</option>
<option>rev_sparse_jac</option>
<option>rev_sparse_hes</option>
<option>End Class Definition</option>
</select>
</td>
</tr></table><br/>



<center><b><big><big>Matrix Multiply as an Atomic Operation</big></big></b></center>
<br/>
<b><big><a name="Start Class Definition" id="Start Class Definition">Start Class Definition</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
# include &lt;cppad/cppad.hpp&gt;
namespace { // Begin empty namespace
using CppAD::vector;
//
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);
}
//
// matrix result = left * right 
class matrix_mul : public CppAD::atomic_base&lt;double&gt; {
</pre></font></code>

<br/>
<br/>
<b><big><a name="Constructor" id="Constructor">Constructor</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	private:
	// number of rows in left operand and in the result
	const size_t nr_result_;
	// number of columns in left operand and rows in right operand
	const size_t n_middle_;
	// number of columns in right operand and in the result
	const size_t nc_result_;
	// dimension of the domain space
	const size_t n_;
	// dimension of the range space
	const size_t m_;
	public:
	// ---------------------------------------------------------------------
	// constructor
	matrix_mul(size_t nr_result, size_t n_middle, size_t nc_result)
	: CppAD::atomic_base&lt;double&gt;(&quot;matrix_mul&quot;),
	nr_result_(nr_result) ,
	n_middle_(n_middle)    ,
	nc_result_(nc_result) ,
	n_( nr_result * n_middle + n_middle * nc_result ) ,
	m_( n_middle * nc_result ) 
	{ }
	private:
</pre></font></code>

<br/>
<br/>
<b><big><a name="Left Operand Element Index" id="Left Operand Element Index">Left Operand Element Index</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// left matrix element index in the taylor coefficient vector tx.
	size_t left(
		size_t i  , // left matrix row index
		size_t j  , // left matrix column index
		size_t k  , // Taylor coeffocient order
		size_t nk ) // number of Taylor coefficients in tx 
	{	assert( i &lt; nr_result_ );
		assert( j &lt; n_middle_ );
		return (i * n_middle_ + j) * nk + k;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="Right Operand Element Index" id="Right Operand Element Index">Right Operand Element Index</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// right matrix element index in the taylor coefficient vector tx.
	size_t right(
		size_t i  , // right matrix row index
		size_t j  , // right matrix column index
		size_t k  , // Taylor coeffocient order
		size_t nk ) // number of Taylor coefficients in tx 
	{	assert( i &lt; n_middle_  );
		assert( j &lt; nc_result_ );
		size_t offset = nr_result_ * n_middle_;
		return (offset + i * nc_result_ + j) * nk + k; 
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="Result Element Index" id="Result Element Index">Result Element Index</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// result matrix element index in the taylor coefficient vector ty.
	size_t result(
		size_t i  , // result matrix row index
		size_t j  , // result matrix column index
		size_t k  , // Taylor coeffocient order
		size_t nk ) // number of Taylor coefficients in ty
	{	assert( i &lt; nr_result_  );
		assert( j &lt; nc_result_ );
		return (i * nc_result_ + j) * nk + k;
	}
</pre></font></code>

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

<code><font color='blue'><pre style='display:inline'> 
	// Forward mode multiply Taylor coefficients in tx and sum into ty
	// (for one pair of left and right orders)
	void forward_multiply(
		size_t                 k_left  , // order for left coefficients
		size_t                 k_right , // order for right coefficients
		const vector&lt;double&gt;&amp;  tx      , // domain space Taylor coefficients
		      vector&lt;double&gt;&amp;  ty      ) // range space Taylor coefficients 
	{	size_t nk       = tx.size() / n_;
		assert( nk == ty.size() / m_ );
		//
		size_t k_result = k_left + k_right;
		assert( k_result &lt; nk );
		//
		for(size_t i = 0; i &lt; nr_result_; i++)
		{	for(size_t j = 0; j &lt; nc_result_; j++)
			{	double sum = 0.0;
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k_left, nk);
					size_t i_right = right(ell, j,  k_right, nk);
					sum           += tx[i_left] * tx[i_right];
				}
				size_t i_result = result(i, j, k_result, nk);
				ty[i_result]   += sum;
			}
		}
	}
</pre></font></code>

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

<code><font color='blue'><pre style='display:inline'> 
	// Reverse mode partials of Taylor coefficients and sum into px
	// (for one pair of left and right orders)
	void reverse_multiply(
		size_t                 k_left  , // order for left coefficients
		size_t                 k_right , // order for right coefficients
		const vector&lt;double&gt;&amp;  tx      , // domain space Taylor coefficients
		const vector&lt;double&gt;&amp;  ty      , // range space Taylor coefficients 
		      vector&lt;double&gt;&amp;  px      , // partials w.r.t. tx
		const vector&lt;double&gt;&amp;  py      ) // partials w.r.t. ty 
	{	size_t nk       = tx.size() / n_;
		assert( nk == ty.size() / m_ );
		assert( tx.size() == px.size() );
		assert( ty.size() == py.size() );
		//
		size_t k_result = k_left + k_right;
		assert( k_result &lt; nk );
		//
		for(size_t i = 0; i &lt; nr_result_; i++)
		{	for(size_t j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k_result, nk);
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k_left, nk);
					size_t i_right = right(ell, j,  k_right, nk);
					// sum        += tx[i_left] * tx[i_right];
					px[i_left]    += tx[i_right] * py[i_result];
					px[i_right]   += tx[i_left]  * py[i_result];
				}
			}
		}
		return;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="forward" id="forward">forward</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// forward mode routine called by CppAD
	bool forward(
		size_t                    q ,
		size_t                    p ,
		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 p1 = p + 1;
		assert( vx.size() == 0 || n_ == vx.size() );
		assert( vx.size() == 0 || m_ == vy.size() );
		assert( n_ * p1 == tx.size() );
		assert( m_ * p1 == ty.size() );
		size_t i, j, ell;

		// check if we are computing vy information
		if( vx.size() &gt; 0 )
		{	size_t nk = 1;
			size_t k  = 0;
			for(i = 0; i &lt; nr_result_; i++)
			{	for(j = 0; j &lt; nc_result_; j++)
				{	bool var = false;
					for(ell = 0; ell &lt; n_middle_; ell++)
					{	size_t i_left  = left(i, ell, k, nk);
						size_t i_right = right(ell, j, k, nk);
						bool   nz_left = vx[i_left] |(tx[i_left]  != 0.);
						bool  nz_right = vx[i_right]|(tx[i_right] != 0.);
						// if not multiplying by the constant zero
						if( nz_left &amp; nz_right )
								var |= vx[i_left] | vx[i_right];
					}
					size_t i_result = result(i, j, k, nk);
					vy[i_result] = var;
				}
			}
		}

		// initialize result as zero
		size_t k;
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	for(k = q; k &lt;= p; k++)
					ty[ result(i, j, k, p1) ] = 0.0;
			}
		}
		for(k = q; k &lt;= p; k++)
		{	// sum the produces that result in order k
			for(ell = 0; ell &lt;= k; ell++)
				forward_multiply(ell, k - ell, tx, ty);
		}

		// all orders are implented, so always return true
		return true;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="reverse" id="reverse">reverse</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// reverse mode routine called by CppAD
	virtual bool reverse(
		size_t                     p ,
		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
	)
	{	size_t p1 = p + 1;
		assert( n_ * p1 == tx.size() );
		assert( m_ * p1 == ty.size() );
		assert( px.size() == tx.size() );
		assert( py.size() == ty.size() );

		// initialize summation
		for(size_t i = 0; i &lt; px.size(); i++)
			px[i] = 0.0;

		// number of orders to differentiate
		size_t k = p1;
		while(k--)
		{	// differentiate the produces that result in order k
			for(size_t ell = 0; ell &lt;= k; ell++)
				reverse_multiply(ell, k - ell, tx, ty, px, py);
		}

		// all orders are implented, so always return true
		return true;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="for_sparse_jac" id="for_sparse_jac">for_sparse_jac</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// forward Jacobian sparsity routine called by CppAD
	virtual bool for_sparse_jac(
		size_t                                q ,
		const vector&lt;bool&gt;&amp;                   r ,
		      vector&lt;bool&gt;&amp;                   s )
	{	assert( n_ * q == r.size() );
		assert( m_ * q == s.size() );
		size_t p;

		// sparsity for S(x) = f'(x) * R
		size_t nk = 1;
		size_t k  = 0;
		for(size_t i = 0; i &lt; nr_result_; i++)
		{	for(size_t j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				for(p = 0; p &lt; q; p++)
					s[i_result * q + p] = false; 
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					for(p = 0; p &lt; q; p++)
					{	s[i_result * q + p] |= r[i_left * q + p ]; 
						s[i_result * q + p] |= r[i_right * q + p ]; 
					}
				}
			}
		}
		return true;
	}
	virtual bool for_sparse_jac(
		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 )
	{	assert( n_ == r.size() );
		assert( m_ == s.size() );

		// sparsity for S(x) = f'(x) * R
		size_t nk = 1;
		size_t k  = 0;
		for(size_t i = 0; i &lt; nr_result_; i++)
		{	for(size_t j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				s[i_result].clear();
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					//
					my_union( s[i_result], s[i_result], r[i_left] );
					my_union( s[i_result], s[i_result], r[i_right] );
				}
			}
		}
		return true;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="rev_sparse_jac" id="rev_sparse_jac">rev_sparse_jac</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// reverse Jacobian sparsity routine called by CppAD
	virtual bool rev_sparse_jac(
		size_t                                q ,
		const vector&lt;bool&gt;&amp;                  rt ,
		      vector&lt;bool&gt;&amp;                  st )
	{	assert( n_ * q == st.size() );
		assert( m_ * q == rt.size() );
		size_t i, j, p;

		// initialize
		for(i = 0; i &lt; n_; i++)
		{	for(p = 0; p &lt; q; p++)
				st[ i * q + p ] = false;
		}

		// sparsity for S(x)^T = f'(x)^T * R^T
		size_t nk = 1;
		size_t k  = 0;
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					for(p = 0; p &lt; q; p++)
					{	st[i_left * q + p] |= rt[i_result * q + p];
						st[i_right* q + p] |= rt[i_result * q + p];
					}
				}
			}
		}
		return true;
	}
	virtual bool rev_sparse_jac(
		size_t                                q ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;    rt ,
		      vector&lt; std::set&lt;size_t&gt; &gt;&amp;    st )
	{	assert( n_ == st.size() );
		assert( m_ == rt.size() );
		size_t i, j;

		// initialize
		for(i = 0; i &lt; n_; i++)
			st[i].clear();

		// sparsity for S(x)^T = f'(x)^T * R^T
		size_t nk = 1;
		size_t k  = 0;
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					//
					my_union(st[i_left],  st[i_left],  rt[i_result]);
					my_union(st[i_right], st[i_right], rt[i_result]);
				}
			}
		}
		return true;
	}
</pre></font></code>

<br/>
<br/>
<b><big><a name="rev_sparse_hes" id="rev_sparse_hes">rev_sparse_hes</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
	// reverse Hessian sparsity routine called by CppAD
	virtual bool rev_sparse_hes(
		const vector&lt;bool&gt;&amp;                   vx,
		const vector&lt;bool&gt;&amp;                   s ,
		      vector&lt;bool&gt;&amp;                   t ,
		size_t                                q ,
		const vector&lt; std::set&lt;size_t&gt; &gt;&amp;     r ,
		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 n = vx.size();	
		assert( t.size() == n );
		assert( r.size() == n );
		assert( v.size() == n );
# ifndef NDEBUG
		size_t m = s.size();
		assert( u.size() == m );
# endif
		size_t i, j;
		//
		// initilaize sparsity patterns as false
		for(j = 0; j &lt; n; j++)
		{	t[j] = false;
			v[j].clear();
		}
		size_t nk = 1;
		size_t k  = 0;
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					//
					// Compute sparsity for T(x) = S(x) * f'(x).
					// We need not use vx with f'(x) back propagation.
					t[i_left]  |= s[i_result];
					t[i_right] |= s[i_result];

					// V(x) = f'(x)^T * U(x) +  S(x) * f''(x) * R 
					// U(x) = g''(y) * f'(x) * R
					// S(x) = g'(y)

					// back propagate f'(x)^T * U(x)
					// (no need to use vx with f'(x) propogation)
					my_union(v[i_left],  v[i_left],  u[i_result] );
					my_union(v[i_right], v[i_right], u[i_result] );

					// back propagate S(x) * f''(x) * R
					// (here is where we must check for cross terms)
					if( s[i_result] &amp; vx[i_left] &amp; vx[i_right] )
					{	my_union(v[i_left],  v[i_left],  r[i_right] );
						my_union(v[i_right], v[i_right], r[i_left]  );
					}
				}
			}
		}
		return true;
	}
	virtual bool rev_sparse_hes(
		const vector&lt;bool&gt;&amp;                   vx,
		const vector&lt;bool&gt;&amp;                   s ,
		      vector&lt;bool&gt;&amp;                   t ,
		size_t                                q ,
		const vector&lt;bool&gt;&amp;                   r ,
		const vector&lt;bool&gt;&amp;                   u ,
		      vector&lt;bool&gt;&amp;                   v )
	{	size_t n = vx.size();
		assert( t.size() == n );
		assert( r.size() == n * q );
		assert( v.size() == n * q );
# ifndef NDEBUG
		size_t m = s.size();
		assert( u.size() == m * q );
# endif
		size_t i, j, p;
		//
		// initilaize sparsity patterns as false
		for(j = 0; j &lt; n; j++)
		{	t[j] = false;
			for(p = 0; p &lt; q; p++)
				v[j * q + p] = false;
		}
		size_t nk = 1;
		size_t k  = 0;
		for(i = 0; i &lt; nr_result_; i++)
		{	for(j = 0; j &lt; nc_result_; j++)
			{	size_t i_result = result(i, j, k, nk);
				for(size_t ell = 0; ell &lt; n_middle_; ell++)
				{	size_t i_left  = left(i, ell, k, nk);
					size_t i_right = right(ell, j, k, nk);
					//
					// Compute sparsity for T(x) = S(x) * f'(x).
					// We so not need to use vx with f'(x) propagation.
					t[i_left]  |= s[i_result];
					t[i_right] |= s[i_result];

					// V(x) = f'(x)^T * U(x) +  S(x) * f''(x) * R 
					// U(x) = g''(y) * f'(x) * R
					// S(x) = g'(y)

					// back propagate f'(x)^T * U(x)
					// (no need to use vx with f'(x) propogation)
					for(p = 0; p &lt; q; p++)
					{	v[ i_left  * q + p] |= u[ i_result * q + p];
						v[ i_right * q + p] |= u[ i_result * q + p];
					}

					// back propagate S(x) * f''(x) * R
					// (here is where we must check for cross terms)
					if( s[i_result] &amp; vx[i_left] &amp; vx[i_right] )
					{	for(p = 0; p &lt; q; p++)
						{	v[i_left * q + p]  |= r[i_right * q + p];
							v[i_right * q + p] |= r[i_left * q + p];
						}
					}
				}
			}
		}
		return true;
	}

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

<br/>
<br/>
<b><big><a name="End Class Definition" id="End Class Definition">End Class Definition</a></big></b>

<code><font color='blue'><pre style='display:inline'> 
}; // End of matrix_mul class
}  // End empty namespace
</pre></font></code>

 

<hr/>Input File: cppad/example/matrix_mul.hpp

</body>
</html>
