<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539</link>
    <title>MATLAB Central Newsreader - Sparse matrix product again</title>
    <description>Feed for thread: Sparse matrix product again</description>
    <language>en-us</language>
    <copyright>&amp;copy;1994-2008 by The MathWorks, Inc.</copyright>
    <webmaster>webmaster@mathworks.com</webmaster>
    <generator>MATLAB Central Newsreader</generator>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <ttl>60</ttl>
    <image>
      <title>The MathWorks</title>
      <url>http://www.mathworks.com/images/membrane_icon.gif</url>
    </image>
    <item>
      <pubDate>Mon, 12 May 2008 23:09:03 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431685</link>
      <author>James Tursa</author>
      <description>"Tim Davis" &amp;lt;davis@cise.ufl.edu&amp;gt; wrote in message &lt;br&gt;
&amp;lt;fvsiih$m48$1@fred.mathworks.com&amp;gt;...&lt;br&gt;
&amp;gt; Instead of "int" you should use mwSignedIndex.  It's &lt;br&gt;
safer,&lt;br&gt;
&amp;gt; if you ever go to a 64-bit platform.  I also recommend &lt;br&gt;
not&lt;br&gt;
&amp;gt; using mwIndex at all, but mwSignedIndex in its place.  &lt;br&gt;
The&lt;br&gt;
&amp;gt; problemis that mwIndex is unsigned, so codes like this:&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; mwIndex i, n ;&lt;br&gt;
&amp;gt; ...&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; for (i = n-1 ; i &amp;gt;= 0 ; i--)  { do something }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; fail in an infinite loop, since i is always &amp;gt;= 0.&lt;br&gt;
&lt;br&gt;
Tim,&lt;br&gt;
&lt;br&gt;
I also avoid unsigned integer types whenever possible for &lt;br&gt;
these types of concerns, but I think your advice is &lt;br&gt;
incomplete. For example, if a function returns an mwIndex &lt;br&gt;
and you stuff the result it into an mwSignedIndex variable &lt;br&gt;
without any overflow checking, you may get a negative &lt;br&gt;
number that will cause downstream problems.&lt;br&gt;
&lt;br&gt;
I prefer to get the return value of a function into the &lt;br&gt;
exact same typed variable and *then* deal with it. If you &lt;br&gt;
want to use only signed types in your code after that then &lt;br&gt;
go ahead and convert it but check the result first. e.g., &lt;br&gt;
suppose you know that mwIndex is unsigned, then consider &lt;br&gt;
the following:&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex si;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ui = (some function that returns an mwIndex type);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;si = (mwSignedIndex) ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( si &amp;lt; 0 )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow ... deal with the error;&lt;br&gt;
&lt;br&gt;
In the above code you will detect the overflow when the &lt;br&gt;
return value is very large and you can deal with it before &lt;br&gt;
causing downstream problems. But even the above code has a &lt;br&gt;
flaw if mwIndex and mwSignedIndex are not the same size.  &lt;br&gt;
So to be extra sure you might want to put in even more &lt;br&gt;
checks using sizeof, etc.&lt;br&gt;
&lt;br&gt;
James Tursa&lt;br&gt;
&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 12 May 2008 23:07:39 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431684</link>
      <author>James Tursa</author>
      <description>"Tim Davis" &amp;lt;davis@cise.ufl.edu&amp;gt; wrote in message &lt;br&gt;
&amp;lt;fvsiih$m48$1@fred.mathworks.com&amp;gt;...&lt;br&gt;
&amp;gt; Instead of "int" you should use mwSignedIndex.  It's &lt;br&gt;
safer,&lt;br&gt;
&amp;gt; if you ever go to a 64-bit platform.  I also recommend &lt;br&gt;
not&lt;br&gt;
&amp;gt; using mwIndex at all, but mwSignedIndex in its place.  &lt;br&gt;
The&lt;br&gt;
&amp;gt; problemis that mwIndex is unsigned, so codes like this:&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; mwIndex i, n ;&lt;br&gt;
&amp;gt; ...&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; for (i = n-1 ; i &amp;gt;= 0 ; i--)  { do something }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; fail in an infinite loop, since i is always &amp;gt;= 0.&lt;br&gt;
&lt;br&gt;
Tim,&lt;br&gt;
&lt;br&gt;
I also avoid unsigned integer types whenever possible for &lt;br&gt;
these types of concerns, but I think your advice is &lt;br&gt;
incomplete. For example, if a function returns an mwIndex &lt;br&gt;
and you stuff the result it into an mwSignedIndex variable &lt;br&gt;
without any overflow checking, you may get a negative &lt;br&gt;
number that will cause downstream problems.&lt;br&gt;
&lt;br&gt;
I prefer to get the return value of a function into the &lt;br&gt;
exact same typed variable and *then* deal with it. If you &lt;br&gt;
want to use only signed types in your code after that then &lt;br&gt;
go ahead and convert it but check the result first. e.g., &lt;br&gt;
suppose you know that mwIndex is unsigned, then consider &lt;br&gt;
the following:&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex si;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ui = (some function that returns an mwIndex type);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;si = (mwSignedIndex) ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( si &amp;lt; 0 )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow ... deal with the error;&lt;br&gt;
&lt;br&gt;
In the above code you will detect the overflow when the &lt;br&gt;
return value is very large and you can deal with it before &lt;br&gt;
causing downstream problems. But even the above code has a &lt;br&gt;
flaw if mwIndex and mwSignedIndex are not the same size.  &lt;br&gt;
So to be extra sure you might want to put in even more &lt;br&gt;
checks using sizeof, etc.&lt;br&gt;
&lt;br&gt;
James Tursa&lt;br&gt;
&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 12 May 2008 23:05:57 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431683</link>
      <author>James Tursa</author>
      <description>"Tim Davis" &amp;lt;davis@cise.ufl.edu&amp;gt; wrote in message &lt;br&gt;
&amp;lt;fvsiih$m48$1@fred.mathworks.com&amp;gt;...&lt;br&gt;
&amp;gt; Instead of "int" you should use mwSignedIndex.  It's &lt;br&gt;
safer,&lt;br&gt;
&amp;gt; if you ever go to a 64-bit platform.  I also recommend &lt;br&gt;
not&lt;br&gt;
&amp;gt; using mwIndex at all, but mwSignedIndex in its place.  &lt;br&gt;
The&lt;br&gt;
&amp;gt; problemis that mwIndex is unsigned, so codes like this:&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; mwIndex i, n ;&lt;br&gt;
&amp;gt; ...&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; for (i = n-1 ; i &amp;gt;= 0 ; i--)  { do something }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; fail in an infinite loop, since i is always &amp;gt;= 0.&lt;br&gt;
&lt;br&gt;
Tim,&lt;br&gt;
&lt;br&gt;
I also avoid unsigned integer types whenever possible for &lt;br&gt;
these types of concerns, but I think your advice is &lt;br&gt;
incomplete. For example, if a function returns an mwIndex &lt;br&gt;
and you stuff the result it into an mwSignedIndex variable &lt;br&gt;
without any overflow checking, you may get a negative &lt;br&gt;
number that will cause downstream problems.&lt;br&gt;
&lt;br&gt;
I prefer to get the return value of a function into the &lt;br&gt;
exact same typed variable and *then* deal with it. If you &lt;br&gt;
want to use only signed types in your code after that then &lt;br&gt;
go ahead and convert it but check the result first. e.g., &lt;br&gt;
suppose you know that mwIndex is unsigned, then consider &lt;br&gt;
the following:&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex si;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ui = (some function that returns an mwIndex type);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;si = (mwSignedIndex) ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( si &amp;lt; 0 )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow ... deal with the error;&lt;br&gt;
&lt;br&gt;
In the above code you will detect the overflow when the &lt;br&gt;
return value is very large and you can deal with it before &lt;br&gt;
causing downstream problems. But even the above code has a &lt;br&gt;
flaw if mwIndex and mwSignedIndex are not the same size.  &lt;br&gt;
So to be extra sure you might want to put in even more &lt;br&gt;
checks using sizeof, etc.&lt;br&gt;
&lt;br&gt;
James Tursa&lt;br&gt;
&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 12 May 2008 23:05:18 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431682</link>
      <author>James Tursa</author>
      <description>"Tim Davis" &amp;lt;davis@cise.ufl.edu&amp;gt; wrote in message &lt;br&gt;
&amp;lt;fvsiih$m48$1@fred.mathworks.com&amp;gt;...&lt;br&gt;
&amp;gt; Instead of "int" you should use mwSignedIndex.  It's &lt;br&gt;
safer,&lt;br&gt;
&amp;gt; if you ever go to a 64-bit platform.  I also recommend &lt;br&gt;
not&lt;br&gt;
&amp;gt; using mwIndex at all, but mwSignedIndex in its place.  &lt;br&gt;
The&lt;br&gt;
&amp;gt; problemis that mwIndex is unsigned, so codes like this:&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; mwIndex i, n ;&lt;br&gt;
&amp;gt; ...&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; for (i = n-1 ; i &amp;gt;= 0 ; i--)  { do something }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; fail in an infinite loop, since i is always &amp;gt;= 0.&lt;br&gt;
&lt;br&gt;
Tim,&lt;br&gt;
&lt;br&gt;
I also avoid unsigned integer types whenever possible for &lt;br&gt;
these types of concerns, but I think your advice is &lt;br&gt;
incomplete. For example, if a function returns an mwIndex &lt;br&gt;
and you stuff the result it into an mwSignedIndex variable &lt;br&gt;
without any overflow checking, you may get a negative &lt;br&gt;
number that will cause downstream problems.&lt;br&gt;
&lt;br&gt;
I prefer to get the return value of a function into the &lt;br&gt;
exact same typed variable and *then* deal with it. If you &lt;br&gt;
want to use only signed types in your code after that then &lt;br&gt;
go ahead and convert it but check the result first. e.g., &lt;br&gt;
suppose you know that mwIndex is unsigned, then consider &lt;br&gt;
the following:&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex si;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ui = (some function that returns an mwIndex type);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;si = (mwSignedIndex) ui;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if( si &amp;lt; 0 )&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow ... deal with the error;&lt;br&gt;
&lt;br&gt;
In the above code you will detect the overflow when the &lt;br&gt;
return value is very large and you can deal with it before &lt;br&gt;
causing downstream problems. But even the above code has a &lt;br&gt;
flaw if mwIndex and mwSignedIndex are not the same size.  &lt;br&gt;
So to be extra sure you might want to put in even more &lt;br&gt;
checks using sizeof, etc.&lt;br&gt;
&lt;br&gt;
James Tursa&lt;br&gt;
&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 12 May 2008 15:11:05 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431574</link>
      <author>Joachim Selke</author>
      <description>Andy Robb wrote:&lt;br&gt;
&amp;gt; Your code might not compile with some C compilers as you&lt;br&gt;
&amp;gt; intermix declarations and statements. I have replaced&lt;br&gt;
&amp;gt; separate declarations and assignments with 'definitions'.&lt;br&gt;
&lt;br&gt;
Thanks. I also changed the loop order of the inner loop as you suggested&lt;br&gt;
in your code. Testing for zero makes it slightly faster. Here is my&lt;br&gt;
updated code:&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
-------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
// In case you compile it with gcc:&lt;br&gt;
// mex -largeArrayDims CFLAGS='$CFLAGS -std=c99 -funroll-loops'&lt;br&gt;
COPTIMFLAGS='$COPTIMFLAGS -O3' sparsemult_mex.c&lt;br&gt;
&lt;br&gt;
#include "mex.h"&lt;br&gt;
&lt;br&gt;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray&lt;br&gt;
*prhs[]) {&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *a = prhs[0];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *b = prhs[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *x = prhs[2];&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mwSize m = mxGetM(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mwSize k = mxGetN(a);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mwSize n = mxGetN(x);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mxArray *lhs[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mxArray *rhs[1] = {mxDuplicateArray(a)};&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mexCallMATLAB(1, lhs, 1, rhs, "transpose");&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *atr = lhs[0];&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mxArray *ab = mxDuplicateArray(x);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex *rows_ab = mxGetIr(ab);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex *cols_ab = mxGetJc(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *data_atr = mxGetPr(atr);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *data_b = mxGetPr(b);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *data_ab = mxGetPr(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (mwSignedIndex j = 0; j &amp;lt; n; j++, data_b += k) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* data_b points to the first entry of B's j-th column*/&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (mwSignedIndex rows_left = cols_ab[j + 1] - cols_ab[j];&lt;br&gt;
rows_left &amp;gt; 0; rows_left--, data_ab++, rows_ab++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* rows_ab points to AB's current entry (i, j) */&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/* data_ab points to AB's current entry (i, j) */&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex i = *rows_ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double z = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (mwSignedIndex r = k - 1; r &amp;gt;= 0; r--) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z += data_atr[i * k + r] * data_b[r];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*data_ab = z;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plhs[0] = ab;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
-------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
Joachim&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 12 May 2008 15:04:14 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431573</link>
      <author>Joachim Selke</author>
      <description>Tim Davis wrote:&lt;br&gt;
&amp;gt; Instead of "int" you should use mwSignedIndex.  It's safer,&lt;br&gt;
&amp;gt; if you ever go to a 64-bit platform.  I also recommend not&lt;br&gt;
&amp;gt; using mwIndex at all, but mwSignedIndex in its place.&lt;br&gt;
&lt;br&gt;
Thanks for pointing this out.&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Thu, 08 May 2008 15:33:03 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#431076</link>
      <author>Andy Robb</author>
      <description>Your code might not compile with some C compilers as you&lt;br&gt;
intermix declarations and statements. I have replaced&lt;br&gt;
separate declarations and assignments with 'definitions'.&lt;br&gt;
&lt;br&gt;
I don't have a MEX compiler system handy so this is untested!&lt;br&gt;
&lt;br&gt;
#include "mex.h"&lt;br&gt;
&lt;br&gt;
void mexFunction&lt;br&gt;
( int nlhs, mxArray *plhs[]&lt;br&gt;
, int nrhs, const mxArray *prhs[]&lt;br&gt;
) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;const mxArray *atr = prhs[0], *b = prhs[1], *x = prhs[2];&lt;br&gt;
&amp;nbsp;&amp;nbsp;const mwSignedIndex m = mxGetM(x), n = mxGetN(x), k =&lt;br&gt;
mxGetM(atr);&lt;br&gt;
&amp;nbsp;&amp;nbsp;mxArray *ab = mxDuplicateArray(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;const mwIndex *rows = mxGetIr(ab), *cols = mxGetJc(ab);&lt;br&gt;
&amp;nbsp;&amp;nbsp;const double *data_atr = mxGetPr(atr), data_b = mxGetPr(b);&lt;br&gt;
&amp;nbsp;&amp;nbsp;double * data_ab = mxGetPr(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;while (--n &amp;gt;= 0) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *A = atr + cols[n];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *B = b + rows[n] * k;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double z = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSignedIndex i;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (i = 0; i &amp;lt; k; ++i) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z += *A * B[i];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;A += m;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab[n] = z;&lt;br&gt;
&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;plhs[0] = ab;&lt;br&gt;
}&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Wed, 07 May 2008 15:41:05 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#430840</link>
      <author>Tim Davis</author>
      <description>Instead of "int" you should use mwSignedIndex.  It's safer,&lt;br&gt;
if you ever go to a 64-bit platform.  I also recommend not&lt;br&gt;
using mwIndex at all, but mwSignedIndex in its place.  The&lt;br&gt;
problemis that mwIndex is unsigned, so codes like this:&lt;br&gt;
&lt;br&gt;
mwIndex i, n ;&lt;br&gt;
...&lt;br&gt;
&lt;br&gt;
for (i = n-1 ; i &amp;gt;= 0 ; i--)  { do something }&lt;br&gt;
&lt;br&gt;
fail in an infinite loop, since i is always &amp;gt;= 0.&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Wed, 07 May 2008 13:02:21 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#430809</link>
      <author>Joachim Selke</author>
      <description>Tim Davis wrote:&lt;br&gt;
&amp;gt; Looks fine to me.  I could suggest only one thing -&lt;br&gt;
&amp;gt; mxDuplicateArray is copying the numerical values of x into&lt;br&gt;
&amp;gt; the output ab, then later you overwrite them.  It would be&lt;br&gt;
&amp;gt; faster to create ab with mxCreateSparse, then fill the&lt;br&gt;
&amp;gt; matrix with both the pattern and the values (the Jc, Ir, and&lt;br&gt;
&amp;gt; data arrays).  But the improvement would be minor.&lt;br&gt;
&lt;br&gt;
I tried that and it really seems to be minor. In fact, my implementation&lt;br&gt;
of the copying (mxCreateSparse followed by memcopy) was slightly slower&lt;br&gt;
than using mxDuplicateArray.&lt;br&gt;
&lt;br&gt;
But I found two additional ways to speed things up:&lt;br&gt;
&amp;nbsp;(1) Replace the k write accesses to data_ab[ind_ab] in the inner loop&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;by write accesses to a temporary variable z and do a single write&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;operation to data_ab[ind_ab] after the loop has finished&lt;br&gt;
&amp;nbsp;(2) Linearize accesses to matrix A by using A's transpose instead of A&lt;br&gt;
&lt;br&gt;
The new code only needs 0.7 s in my example scenario, computing of A' in&lt;br&gt;
MATLAB included (old code: 1.3 s, M code: 2.3 s).&lt;br&gt;
&lt;br&gt;
Here is the code:&lt;br&gt;
&lt;br&gt;
---------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
#include "mex.h"&lt;br&gt;
&lt;br&gt;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray&lt;br&gt;
*prhs[]) {&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *atr, *b, *x;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;atr = prhs[0];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b = prhs[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x = prhs[2];&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSize m, n, k;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = mxGetM(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = mxGetN(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k = mxGetM(atr);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mxArray *ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ab = mxDuplicateArray(x);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex *rows_ab, *cols_ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows_ab = mxGetIr(ab);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cols_ab = mxGetJc(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *data_atr, *data_b, *data_ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_atr = mxGetPr(atr);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_b = mxGetPr(b);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab = mxGetPr(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double z;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i, j, r;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int ind_atr, ind_b, ind_ab, rows_left;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_ab = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (j = 0; j &amp;lt; n; j++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows_left = cols_ab[j + 1] - cols_ab[j];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (rows_left != 0) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i = rows_ab[ind_ab];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_atr = i * k;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_b = j * k;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (r = 0; r &amp;lt; k; r++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z += data_atr[ind_atr] * data_b[ind_b];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_atr++;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_b++;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab[ind_ab] = z;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_ab++;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows_left--;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plhs[0] = ab;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
---------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Now I think that this is all one can do to speed it up. Am I right? :-)&lt;br&gt;
&lt;br&gt;
Joachim&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 05 May 2008 12:14:04 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#430311</link>
      <author>Tim Davis</author>
      <description>Joachim Selke &amp;lt;j.selke@tu-bs.de&amp;gt; wrote in message&lt;br&gt;
&amp;lt;688agnF2rcjvjU1@mid.dfncis.de&amp;gt;...&lt;br&gt;
&amp;gt; Tim Davis wrote:&lt;br&gt;
&amp;gt; &amp;gt; I can't think of a better way ... except to go to a&lt;br&gt;
&amp;gt; &amp;gt; mexFunction of course.&lt;br&gt;
&amp;gt; &amp;gt; &lt;br&gt;
&amp;gt; &amp;gt; The reason I say that is because a mexFunction could do&lt;br&gt;
&amp;gt; &amp;gt; Atr(:,rows_j)'*B(:j) without forming the Atr(:,rows_j)&lt;br&gt;
&amp;gt; &amp;gt; matrix as an intermediate step.&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Wow, that really speeds it up. Thanks! :-)&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Again, I did some experiments using random matrices (m =&lt;br&gt;
50000,&lt;br&gt;
&amp;gt; n = 10000, k = 15). The total time needed for constructing&lt;br&gt;
the product&lt;br&gt;
&amp;gt; was around 1.3 seconds on my computer with a MEX function&lt;br&gt;
written in C&lt;br&gt;
&amp;gt; (compared to 2.3 seconds using my previous implementation).&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Since this is my first MEX function (and since I did not&lt;br&gt;
even program in&lt;br&gt;
&amp;gt; C before) it would help me a lot if you please could have&lt;br&gt;
a quick look&lt;br&gt;
&amp;gt; at my implementation. It is straight-forward and I am&lt;br&gt;
quite sure that&lt;br&gt;
&amp;gt; there is still room for improvement (maybe by doing some&lt;br&gt;
computations in&lt;br&gt;
&amp;gt; parallel?). Here is the code:&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;&lt;br&gt;
-------------------------------------------------------------------------&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; #include "mex.h"&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; void mexFunction(int nlhs, mxArray *plhs[], int nrhs,&lt;br&gt;
const mxArray&lt;br&gt;
&amp;gt; *prhs[]) {&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     const mxArray *a, *b, *x;&lt;br&gt;
&amp;gt;     a = prhs[0];&lt;br&gt;
&amp;gt;     b = prhs[1];&lt;br&gt;
&amp;gt;     x = prhs[2];&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     mwSize m, n, k;&lt;br&gt;
&amp;gt;     m = mxGetM(x);&lt;br&gt;
&amp;gt;     n = mxGetN(x);&lt;br&gt;
&amp;gt;     k = mxGetN(a);&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     mxArray *ab;&lt;br&gt;
&amp;gt;     ab = mxDuplicateArray(x);&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     mwIndex *rows_ab, *cols_ab;&lt;br&gt;
&amp;gt;     rows_ab = mxGetIr(ab);&lt;br&gt;
&amp;gt;     cols_ab = mxGetJc(ab);&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     double *data_a, *data_b, *data_ab;&lt;br&gt;
&amp;gt;     data_a = mxGetPr(a);&lt;br&gt;
&amp;gt;     data_b = mxGetPr(b);&lt;br&gt;
&amp;gt;     data_ab = mxGetPr(ab);&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     int i, j, r;&lt;br&gt;
&amp;gt;     int ind_a, ind_b, ind_ab, ind_ab_next;&lt;br&gt;
&amp;gt;     ind_ab = 0;&lt;br&gt;
&amp;gt;     for (j = 0; j &amp;lt; n; j++) {&lt;br&gt;
&amp;gt;         ind_ab_next = ind_ab + cols_ab[j + 1] - cols_ab[j];&lt;br&gt;
&amp;gt;         while (ind_ab &amp;lt; ind_ab_next) {&lt;br&gt;
&amp;gt;             i = rows_ab[ind_ab];&lt;br&gt;
&amp;gt;             data_ab[ind_ab] = 0;&lt;br&gt;
&amp;gt;             for (r = 0; r &amp;lt; k; r++) {&lt;br&gt;
&amp;gt;                 ind_a = r * m + i;&lt;br&gt;
&amp;gt;                 ind_b = j * k + r;&lt;br&gt;
&amp;gt;                 data_ab[ind_ab] += data_a[ind_a] *&lt;br&gt;
data_b[ind_b];&lt;br&gt;
&amp;gt;             }&lt;br&gt;
&amp;gt;             ind_ab++;&lt;br&gt;
&amp;gt;         }&lt;br&gt;
&amp;gt;     }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;     plhs[0] = ab;&lt;br&gt;
&amp;gt; }&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;&lt;br&gt;
-------------------------------------------------------------------------&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Joachim&lt;br&gt;
&lt;br&gt;
Looks fine to me.  I could suggest only one thing -&lt;br&gt;
mxDuplicateArray is copying the numerical values of x into&lt;br&gt;
the output ab, then later you overwrite them.  It would be&lt;br&gt;
faster to create ab with mxCreateSparse, then fill the&lt;br&gt;
matrix with both the pattern and the values (the Jc, Ir, and&lt;br&gt;
data arrays).  But the improvement would be minor.&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Mon, 05 May 2008 11:48:37 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#430304</link>
      <author>Joachim Selke</author>
      <description>Tim Davis wrote:&lt;br&gt;
&amp;gt; I can't think of a better way ... except to go to a&lt;br&gt;
&amp;gt; mexFunction of course.&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; The reason I say that is because a mexFunction could do&lt;br&gt;
&amp;gt; Atr(:,rows_j)'*B(:j) without forming the Atr(:,rows_j)&lt;br&gt;
&amp;gt; matrix as an intermediate step.&lt;br&gt;
&lt;br&gt;
Wow, that really speeds it up. Thanks! :-)&lt;br&gt;
&lt;br&gt;
Again, I did some experiments using random matrices (m = 50000,&lt;br&gt;
n = 10000, k = 15). The total time needed for constructing the product&lt;br&gt;
was around 1.3 seconds on my computer with a MEX function written in C&lt;br&gt;
(compared to 2.3 seconds using my previous implementation).&lt;br&gt;
&lt;br&gt;
Since this is my first MEX function (and since I did not even program in&lt;br&gt;
C before) it would help me a lot if you please could have a quick look&lt;br&gt;
at my implementation. It is straight-forward and I am quite sure that&lt;br&gt;
there is still room for improvement (maybe by doing some computations in&lt;br&gt;
parallel?). Here is the code:&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
-------------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
#include "mex.h"&lt;br&gt;
&lt;br&gt;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray&lt;br&gt;
*prhs[]) {&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const mxArray *a, *b, *x;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a = prhs[0];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b = prhs[1];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x = prhs[2];&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwSize m, n, k;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;m = mxGetM(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;n = mxGetN(x);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;k = mxGetN(a);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mxArray *ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ab = mxDuplicateArray(x);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mwIndex *rows_ab, *cols_ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows_ab = mxGetIr(ab);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cols_ab = mxGetJc(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;double *data_a, *data_b, *data_ab;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_a = mxGetPr(a);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_b = mxGetPr(b);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab = mxGetPr(ab);&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i, j, r;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int ind_a, ind_b, ind_ab, ind_ab_next;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_ab = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (j = 0; j &amp;lt; n; j++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_ab_next = ind_ab + cols_ab[j + 1] - cols_ab[j];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (ind_ab &amp;lt; ind_ab_next) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i = rows_ab[ind_ab];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab[ind_ab] = 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (r = 0; r &amp;lt; k; r++) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_a = r * m + i;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_b = j * k + r;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data_ab[ind_ab] += data_a[ind_a] * data_b[ind_b];&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ind_ab++;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;plhs[0] = ab;&lt;br&gt;
}&lt;br&gt;
&lt;br&gt;
-------------------------------------------------------------------------&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Joachim&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Fri, 02 May 2008 15:47:03 -0400</pubDate>
      <title>Re: Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#429949</link>
      <author>Tim Davis</author>
      <description>Joachim Selke &amp;lt;j.selke@tu-bs.de&amp;gt; wrote in message&lt;br&gt;
&amp;lt;67rg20F2pn19mU1@mid.dfncis.de&amp;gt;...&lt;br&gt;
&amp;gt; Hi,&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; in &amp;lt;news:frk8n2$dqp$1@newsserver.rrzn.uni-hannover.de&amp;gt; I&lt;br&gt;
asked how to&lt;br&gt;
&amp;gt; efficiently compute a "sparse matrix product":&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Given three matrices&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt;   A: m x k   (full)&lt;br&gt;
&amp;gt;   B: k x n   (full)&lt;br&gt;
&amp;gt;   X: m x n   (sparse, around 2% density)&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; where m and n are very large numbers and k is small, I&lt;br&gt;
want to compute&lt;br&gt;
&amp;gt; the matrix product of A and B but I only need the entries&lt;br&gt;
of A * B at&lt;br&gt;
&amp;gt; the places where X is non-zero.&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Thanks to Tim Davis and Roger Stafford I got two nice&lt;br&gt;
solutions that I&lt;br&gt;
&amp;gt; combined and optimized a bit further. My current best&lt;br&gt;
solution is the&lt;br&gt;
&amp;gt; following ("best" means fastest and memory-efficient enough):&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; % Basic idea: Construct the sparse product matrix row by row.&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Atr = A';&lt;br&gt;
&amp;gt; [rows, cols, vals] = find(X);&lt;br&gt;
&amp;gt; lX = logical(X);&lt;br&gt;
&amp;gt; nnz_bycol = full(sum(lX));&lt;br&gt;
&amp;gt; cumnnz_bycol = [0 cumsum(nnz_bycol)];&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; for j = 1:n&lt;br&gt;
&amp;gt;     t_start = cumnnz_bycol(j) + 1;&lt;br&gt;
&amp;gt;     t_end = cumnnz_bycol(j + 1);&lt;br&gt;
&amp;gt;     rows_j = rows(t_start:t_end);&lt;br&gt;
&amp;gt;     vals(t_start:t_end) = Atr(:, rows_j)' * B(:, j);&lt;br&gt;
&amp;gt; end&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; AB = sparse(rows, cols, vals, m, n);&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Now I did some experiments using random matrices (m =&lt;br&gt;
50000, n = 10000,&lt;br&gt;
&amp;gt; k = 15). The total time needed for constructing the&lt;br&gt;
product was around&lt;br&gt;
&amp;gt; 2.3 seconds on my computer. When looking at the details, I&lt;br&gt;
found that&lt;br&gt;
&amp;gt; almost the complete computation time is used by the statement&lt;br&gt;
&amp;gt; "Atr(:, rows_j)." So, obviously this algorithm is extremely&lt;br&gt;
&amp;gt; memory-bound. I tried a lot but was not able to solve this&lt;br&gt;
problem.&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Are there any known tricks what can I do to speed-up the&lt;br&gt;
memory accesses?&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; (I should note that I want to compute this product for&lt;br&gt;
many different&lt;br&gt;
&amp;gt; matrices A and B while keeping X fixed. Maybe this fact&lt;br&gt;
can be used in&lt;br&gt;
&amp;gt; optimization ...)&lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; &lt;br&gt;
&amp;gt; Joachim&lt;br&gt;
&lt;br&gt;
That looks about as good as you could get, to me.&lt;br&gt;
&lt;br&gt;
The Atr(:,rows_j)'*B(:j) is a neat trick; using a&lt;br&gt;
matrix-vector multiply to do lots of entries in AB at once.&lt;br&gt;
&amp;nbsp;I can't think of a better way ... except to go to a&lt;br&gt;
mexFunction of course.&lt;br&gt;
&lt;br&gt;
The reason I say that is because a mexFunction could do&lt;br&gt;
Atr(:,rows_j)'*B(:j) without forming the Atr(:,rows_j)&lt;br&gt;
matrix as an intermediate step.&lt;br&gt;
&lt;br&gt;
The subsref and subsasgn operations in MATLAB aren't speed&lt;br&gt;
demons, unfortunately, particularly for the sparse case&lt;br&gt;
(this is the dense case, though, since Atr is dense).&lt;br&gt;
&lt;br&gt;
</description>
    </item>
    <item>
      <pubDate>Wed, 30 Apr 2008 15:03:28 -0400</pubDate>
      <title>Sparse matrix product again</title>
      <link>http://www.mathworks.com/matlabcentral/newsreader/view_thread/168539#429606</link>
      <author>Joachim Selke</author>
      <description>Hi,&lt;br&gt;
&lt;br&gt;
in &amp;lt;news:frk8n2$dqp$1@newsserver.rrzn.uni-hannover.de&amp;gt; I asked how to&lt;br&gt;
efficiently compute a "sparse matrix product":&lt;br&gt;
&lt;br&gt;
Given three matrices&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;A: m x k   (full)&lt;br&gt;
&amp;nbsp;&amp;nbsp;B: k x n   (full)&lt;br&gt;
&amp;nbsp;&amp;nbsp;X: m x n   (sparse, around 2% density)&lt;br&gt;
&lt;br&gt;
where m and n are very large numbers and k is small, I want to compute&lt;br&gt;
the matrix product of A and B but I only need the entries of A * B at&lt;br&gt;
the places where X is non-zero.&lt;br&gt;
&lt;br&gt;
Thanks to Tim Davis and Roger Stafford I got two nice solutions that I&lt;br&gt;
combined and optimized a bit further. My current best solution is the&lt;br&gt;
following ("best" means fastest and memory-efficient enough):&lt;br&gt;
&lt;br&gt;
% Basic idea: Construct the sparse product matrix row by row.&lt;br&gt;
&lt;br&gt;
Atr = A';&lt;br&gt;
[rows, cols, vals] = find(X);&lt;br&gt;
lX = logical(X);&lt;br&gt;
nnz_bycol = full(sum(lX));&lt;br&gt;
cumnnz_bycol = [0 cumsum(nnz_bycol)];&lt;br&gt;
&lt;br&gt;
for j = 1:n&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;t_start = cumnnz_bycol(j) + 1;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;t_end = cumnnz_bycol(j + 1);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rows_j = rows(t_start:t_end);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vals(t_start:t_end) = Atr(:, rows_j)' * B(:, j);&lt;br&gt;
end&lt;br&gt;
&lt;br&gt;
AB = sparse(rows, cols, vals, m, n);&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Now I did some experiments using random matrices (m = 50000, n = 10000,&lt;br&gt;
k = 15). The total time needed for constructing the product was around&lt;br&gt;
2.3 seconds on my computer. When looking at the details, I found that&lt;br&gt;
almost the complete computation time is used by the statement&lt;br&gt;
"Atr(:, rows_j)." So, obviously this algorithm is extremely&lt;br&gt;
memory-bound. I tried a lot but was not able to solve this problem.&lt;br&gt;
&lt;br&gt;
Are there any known tricks what can I do to speed-up the memory accesses?&lt;br&gt;
&lt;br&gt;
(I should note that I want to compute this product for many different&lt;br&gt;
matrices A and B while keeping X fixed. Maybe this fact can be used in&lt;br&gt;
optimization ...)&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Joachim&lt;br&gt;
</description>
    </item>
  </channel>
</rss>
