Path: news.mathworks.com!not-for-mail
From: <HIDDEN>
Newsgroups: comp.soft-sys.matlab
Subject: Re: Convert array of class 'int8' to sparse
Date: Tue, 24 Mar 2009 10:55:03 +0000 (UTC)
Organization: University College Dublin
Lines: 182
Message-ID: <gqae67$vg$1@fred.mathworks.com>
References: <gfhh6c$dvr$1@fred.mathworks.com> <gq9bg5$3ra$1@fred.mathworks.com> <gqa8th$7j0$1@fred.mathworks.com>
Reply-To: <HIDDEN>
NNTP-Posting-Host: webapp-05-blr.mathworks.com
Content-Type: text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding: 8bit
X-Trace: fred.mathworks.com 1237892103 1008 172.30.248.35 (24 Mar 2009 10:55:03 GMT)
X-Complaints-To: news@mathworks.com
NNTP-Posting-Date: Tue, 24 Mar 2009 10:55:03 +0000 (UTC)
X-Newsreader: MATLAB Central Newsreader 87230
Xref: news.mathworks.com comp.soft-sys.matlab:527196


"James Tursa" <aclassyguywithaknotac@hotmail.com> wrote in message <gqa8th$7j0$1@fred.mathworks.com>...
> "Gus Lott" <lottg.nospam@janelia.hhmi.org> wrote in message <gq9bg5$3ra$1@fred.mathworks.com>...
> > I too am looking for this feature to come to matlab's sparse matrix tools.
> 
> All,
> 
> You could always just modify the MATLAB mex example fulltosparse.c of filling a sparse matrix and change the input from double to int8. The Mathworks comments seem to imply that this is the very purpose of the example code. E.g., the code is below. To mex it just do this:
> 
> >> mex -setup
>     (then select a C/C++ compiler, such as lcc)
> >> mex int8tosparse.c
> 
> Now you have a function int8tosparse that takes a 2-dimensional int8 input and directly converts it into a sparse double matrix without taking the intermediate step of converting to a full double matrix first. If there is some interest in this, I could work this up into a complete mex function that works for *all* integer classes and post it to the FEX. Let me know.
> 
> James Tursa
> 
> Caveat, I only tested this for a single 100x100 example. It got the same answer as converting to a double matrix first, so I would assume the code is correct. However, be advised this is the Mathworks example code, not mine. I just modified it for int8. If you have a later version of MATLAB you might want to change the int j,k,etc to mwSize j,k,etc.
> 
> -----------------------------------------------------------------------------------------------------
> 
> /*
>  * =============================================================
>  * int8tosparse.c
>  * This example demonstrates how to populate a sparse
>  * matrix.  For the purpose of this example, you must pass in a
>  * non-sparse 2-dimensional argument of type int8.
>  *
>  * Mathworks fulltosparse.c modified by J. Tursa for int8.
>  *
> =============================================================
>  */
> 
> #include <math.h> /* Needed for the ceil() prototype. */
> #include "mex.h"
> 
> void mexFunction(
>         int nlhs,       mxArray *plhs[],
>         int nrhs, const mxArray *prhs[]
>         )
> {
>   /* Declare variables. */
>   int j,k,m,n,nzmax,*irs,*jcs,cmplx,isfull;
>   double *si,*sr;
>   double percent_sparse;
>   signed char *pr, *pi;
> 
>   /* Check for proper number of input and output arguments. */    
>   if (nrhs != 1) {
>     mexErrMsgTxt("One input argument required.");
>   } 
>   if (nlhs > 1) {
>     mexErrMsgTxt("Too many output arguments.");
>   }
> 
>   /* Check data type of input argument. */
>   if (!(mxIsInt8(prhs[0]))) {
>     mexErrMsgTxt("Input argument must be of type int8.");
>   } 
> 
>   if (mxGetNumberOfDimensions(prhs[0]) != 2) {
>     mexErrMsgTxt("Input argument must be two dimensional\n");
>   }
> 
>   /* Get the size and pointers to input data. */
>   m  = mxGetM(prhs[0]);
>   n  = mxGetN(prhs[0]);
>   pr = mxGetPr(prhs[0]);
>   pi = mxGetPi(prhs[0]);
>   cmplx = (pi == NULL ? 0 : 1);
> 
>   /* Allocate space for sparse matrix. 
>    * NOTE:  Assume at most 20% of the data is sparse.  Use ceil
>    * to cause it to round up. 
>    */
> 
>   percent_sparse = 0.2;
>   nzmax = (int)ceil((double)m*(double)n*percent_sparse);
> 
>   plhs[0] = mxCreateSparse(m,n,nzmax,cmplx);
>   sr  = mxGetPr(plhs[0]);
>   si  = mxGetPi(plhs[0]);
>   irs = mxGetIr(plhs[0]);
>   jcs = mxGetJc(plhs[0]);
>     
>   /* Copy nonzeros. */
>   k = 0; 
>   isfull = 0;
>   for (j = 0; (j < n); j++) {
>     int i;
>     jcs[j] = k;
>     for (i = 0; (i < m); i++) {
>       if (pr[i] || (cmplx && pi[i])) {
> 
>         /* Check to see if non-zero element will fit in  
>          * allocated output array.  If not, increase 
>          * percent_sparse by 10%, recalculate nzmax, and augment 
>          * the sparse array. 
>          */
>         if (k >= nzmax) {
>           int oldnzmax = nzmax;
>           percent_sparse += 0.1;
>           nzmax = (int)ceil((double)m*(double)n*percent_sparse);
> 
>           /* Make sure nzmax increases atleast by 1. */
>           if (oldnzmax == nzmax) 
>             nzmax++;
> 
>           mxSetNzmax(plhs[0], nzmax); 
>           mxSetPr(plhs[0], mxRealloc(sr, nzmax*sizeof(double)));
>           if (si != NULL)
>           mxSetPi(plhs[0], mxRealloc(si, nzmax*sizeof(double)));
>           mxSetIr(plhs[0], mxRealloc(irs, nzmax*sizeof(int)));
> 
>           sr  = mxGetPr(plhs[0]);
>           si  = mxGetPi(plhs[0]);
>           irs = mxGetIr(plhs[0]);
>         }
>         sr[k] = pr[i];
>         if (cmplx) {
>           si[k] = pi[i];
>         }
>         irs[k] = i;
>         k++;
>       }
>     }
>     pr += m;
>     pi += m;
>   }
>   jcs[n] = k;
> } 



Dear John,

With
----------------------------------------------------
>> ver
MATLAB Version 7.6.0.324 (R2008a)
Operating System: Microsoft Windows Vista Version 6.0
 (Build 6001: Service Pack 1)
Java VM Version: Java 1.6.0 with Sun Microsystems Inc.
Java HotSpot(TM) 64-Bit Server VM mixed mode
-----------------------------------------------------

I ran

-----------------------------------------------------
>> mex -largeArrayDims int8tosparse.c
Microsoft (R) C/C++ Optimizing Compiler Version
15.00.21022.08 for x64 Copyright (C) Microsoft
Corporation.  All rights reserved.
-----------------------------------------------------

which generated the file int8tosparse.mexw64

I then ran

--------------------------------------------------------
>> n = 1000; Sp16 = sprand(n,n,0.001); D16 = full(Sp16);...
               D8 = int8(D16); Sp8 = int8tosparse(D8);...
               whos

  Name         Size                       Bytes  Class       Attributes


  Sp16     1000x1000                24,008   double    sparse
  D16      1000x1000            8,000,000   double
  D8        1000x1000            1,000,000   int8
  Sp8       1000x1000           3,208,008   double    sparse
  n           1x1                     8  double

commas added so I can read the sizes
-----------------------------------------------------------

I know nothing about C/C++ programming and compiling. Any suggestions?

A complete mex function that works for *all* integer classes would be very useful, especially when working with large sparse graphs.

Regards,

Derek O'Connor