///////////////////////////////////////////////////////////////////////////////// //// //// CRS sparse matrices manipulation routines //// Copyright (C) 2004 Manolis Lourakis (lourakis@ics.forth.gr) //// Institute of Computer Science, Foundation for Research & Technology - Hellas //// Heraklion, Crete, Greece. //// //// This program is free software; you can redistribute it and/or modify //// it under the terms of the GNU General Public License as published by //// the Free Software Foundation; either version 2 of the License, or //// (at your option) any later version. //// //// This program is distributed in the hope that it will be useful, //// but WITHOUT ANY WARRANTY; without even the implied warranty of //// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //// GNU General Public License for more details. //// /////////////////////////////////////////////////////////////////////////////////// #include #include #include "sba.h" static void sba_crsm_print(struct sba_crsm *sm, FILE *fp); static void sba_crsm_build(struct sba_crsm *sm, int *m, int nr, int nc); /* allocate a sparse CRS matrix */ void sba_crsm_alloc(struct sba_crsm *sm, int nr, int nc, int nnz) { int msz; sm->nr=nr; sm->nc=nc; sm->nnz=nnz; msz=2*nnz+nr+1; sm->val=(int *)malloc(msz*sizeof(int)); /* required memory is allocated in a single step */ if(!sm->val){ fprintf(stderr, "memory allocation request failed in sba_crsm_alloc() [nr=%d, nc=%d, nnz=%d]\n", nr, nc, nnz); exit(1); } sm->colidx=sm->val+nnz; sm->rowptr=sm->colidx+nnz; } /* free a sparse CRS matrix */ void sba_crsm_free(struct sba_crsm *sm) { sm->nr=sm->nc=sm->nnz=-1; free(sm->val); sm->val=sm->colidx=sm->rowptr=NULL; } static void sba_crsm_print(struct sba_crsm *sm, FILE *fp) { register int i; fprintf(fp, "matrix is %dx%d, %d non-zeros\nval: ", sm->nr, sm->nc, sm->nnz); for(i=0; innz; ++i) fprintf(fp, "%d ", sm->val[i]); fprintf(fp, "\ncolidx: "); for(i=0; innz; ++i) fprintf(fp, "%d ", sm->colidx[i]); fprintf(fp, "\nrowptr: "); for(i=0; i<=sm->nr; ++i) fprintf(fp, "%d ", sm->rowptr[i]); fprintf(fp, "\n"); } /* build a sparse CRS matrix from a dense one. intended to serve as an example for sm creation */ static void sba_crsm_build(struct sba_crsm *sm, int *m, int nr, int nc) { int nnz; register int i, j, k; /* count nonzeros */ for(i=nnz=0; irowptr[i]=k; for(j=0; jval[k]=m[i*nc+j]; sm->colidx[k++]=j; } } sm->rowptr[nr]=nnz; } /* returns the index of the (i, j) element. No bounds checking! */ int sba_crsm_elmidx(struct sba_crsm *sm, int i, int j) { register int low, high, mid; low=sm->rowptr[i]; high=sm->rowptr[i+1]-1; /* binary search for finding the element at column j */ while(low<=high){ if(jcolidx[low] || j>sm->colidx[high]) return -1; /* not found */ mid=(low+high)>>1; //(low+high)/2; if(jcolidx[mid]) high=mid-1; else if(j>sm->colidx[mid]) low=mid+1; else return mid; } return -1; /* not found */ } /* returns the number of nonzero elements in row i and * fills up the vidxs and jidxs arrays with the val and column * indexes of the elements found, respectively. * vidxs and jidxs are assumed preallocated and of max. size sm->nc */ int sba_crsm_row_elmidxs(struct sba_crsm *sm, int i, int *vidxs, int *jidxs) { register int j, k; for(j=sm->rowptr[i], k=0; jrowptr[i+1]; ++j, ++k){ vidxs[k]=j; jidxs[k]=sm->colidx[j]; } return k; } /* returns the number of nonzero elements in col j and * fills up the vidxs and iidxs arrays with the val and row * indexes of the elements found, respectively. * vidxs and iidxs are assumed preallocated and of max. size sm->nr */ int sba_crsm_col_elmidxs(struct sba_crsm *sm, int j, int *vidxs, int *iidxs) { register int *nextrowptr=sm->rowptr+1; register int i, l; register int low, high, mid; for(i=l=0; inr; ++i){ low=sm->rowptr[i]; high=nextrowptr[i]-1; /* binary search attempting to find an element at column j */ while(low<=high){ if(jcolidx[low] || j>sm->colidx[high]) break; /* not found */ mid=(low+high)>>1; //(low+high)/2; if(jcolidx[mid]) high=mid-1; else if(j>sm->colidx[mid]) low=mid+1; else{ /* found */ vidxs[l]=mid; iidxs[l++]=i; break; } } } return l; } /* a more straighforward (but slower) implementation of the above function */ /*** int sba_crsm_col_elmidxs(struct sba_crsm *sm, int j, int *vidxs, int *iidxs) { register int i, k, l; for(i=l=0; inr; ++i) for(k=sm->rowptr[i]; krowptr[i+1]; ++k) if(sm->colidx[k]==j){ vidxs[l]=k; iidxs[l++]=i; } return l; } ***/ #if 0 /* sample code using the above routines */ main() { int mat[7][6]={ {10, 0, 0, 0, -2, 0}, {3, 9, 0, 0, 0, 3}, {0, 7, 8, 7, 0, 0}, {3, 0, 8, 7, 5, 0}, {0, 8, 0, 9, 9, 13}, {0, 4, 0, 0, 2, -1}, {3, 7, 0, 9, 2, 0} }; struct sba_crsm sm; int i, j, k, l; int vidxs[7], /* max(6, 7) */ jidxs[6], iidxs[7]; sba_crsm_build(&sm, mat[0], 7, 6); sba_crsm_print(&sm, stdout); for(i=0; i<7; ++i){ for(j=0; j<6; ++j) printf("%3d ", ((k=sba_crsm_elmidx(&sm, i, j))!=-1)? sm.val[k] : 0); printf("\n"); } for(i=0; i<7; ++i){ k=sba_crsm_row_elmidxs(&sm, i, vidxs, jidxs); printf("row %d\n", i); for(l=0; l