xref: /petsc/src/mat/impls/aij/seq/aij.c (revision 0f4532802aec931eb5bdcbbf3345d7fc45a89f61)
1 #ifndef lint
2 static char vcid[] = "$Id: aij.c,v 1.149 1996/02/15 23:59:34 balay Exp balay $";
3 #endif
4 
5 /*
6     Defines the basic matrix operations for the AIJ (compressed row)
7   matrix storage format.
8 */
9 #include "aij.h"
10 #include "vec/vecimpl.h"
11 #include "inline/spops.h"
12 #include "petsc.h"
13 #include "inline/bitarray.h"
14 
15 extern int MatToSymmetricIJ_SeqAIJ(int,int*,int*,int,int**,int**);
16 
17 static int MatGetReordering_SeqAIJ(Mat A,MatOrdering type,IS *rperm, IS *cperm)
18 {
19   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
20   int        ierr, *ia, *ja,n,*idx,i;
21   /*Viewer     V1, V2;*/
22 
23   /*
24      this is tacky: In the future when we have written special factorization
25      and solve routines for the identity permutation we should use a
26      stride index set instead of the general one.
27   */
28   if (type  == ORDER_NATURAL) {
29     n = a->n;
30     idx = (int *) PetscMalloc( n*sizeof(int) ); CHKPTRQ(idx);
31     for ( i=0; i<n; i++ ) idx[i] = i;
32     ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,rperm); CHKERRQ(ierr);
33     ierr = ISCreateSeq(MPI_COMM_SELF,n,idx,cperm); CHKERRQ(ierr);
34     PetscFree(idx);
35     ISSetPermutation(*rperm);
36     ISSetPermutation(*cperm);
37     ISSetIdentity(*rperm);
38     ISSetIdentity(*cperm);
39     return 0;
40   }
41 
42   ierr = MatToSymmetricIJ_SeqAIJ(a->n,a->i,a->j,a->indexshift, &ia, &ja);CHKERRQ(ierr);
43   ierr = MatGetReordering_IJ(a->n,ia,ja,type,rperm,cperm); CHKERRQ(ierr);
44 
45   PetscFree(ia); PetscFree(ja);
46   return 0;
47 }
48 
49 #define CHUNKSIZE   15
50 
51 /* This version has row oriented v  */
52 static int MatSetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v,InsertMode is)
53 {
54   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
55   int        *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax, N, sorted = a->sorted;
56   int        *imax = a->imax, *ai = a->i, *ailen = a->ilen,roworiented = a->roworiented;
57   int        *aj = a->j, nonew = a->nonew,shift = a->indexshift;
58   Scalar     *ap,value, *aa = a->a;
59 
60   for ( k=0; k<m; k++ ) { /* loop over added rows */
61     row  = im[k];
62     if (row < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative row");
63     if (row >= a->m) SETERRQ(1,"MatSetValues_SeqAIJ:Row too large");
64     rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
65     rmax = imax[row]; nrow = ailen[row];
66     low = 0;
67     for ( l=0; l<n; l++ ) { /* loop over added columns */
68       if (in[l] < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative column");
69       if (in[l] >= a->n) SETERRQ(1,"MatSetValues_SeqAIJ:Column too large");
70       col = in[l] - shift;
71       if (roworiented) {
72         value = *v++;
73       }
74       else {
75         value = v[k + l*m];
76       }
77       if (!sorted) low = 0; high = nrow;
78       while (high-low > 5) {
79         t = (low+high)/2;
80         if (rp[t] > col) high = t;
81         else             low  = t;
82       }
83       for ( i=low; i<high; i++ ) {
84         if (rp[i] > col) break;
85         if (rp[i] == col) {
86           if (is == ADD_VALUES) ap[i] += value;
87           else                  ap[i] = value;
88           goto noinsert;
89         }
90       }
91       if (nonew) goto noinsert;
92       if (nrow >= rmax) {
93         /* there is no extra room in row, therefore enlarge */
94         int    new_nz = ai[a->m] + CHUNKSIZE,len,*new_i,*new_j;
95         Scalar *new_a;
96 
97         /* malloc new storage space */
98         len     = new_nz*(sizeof(int)+sizeof(Scalar))+(a->m+1)*sizeof(int);
99         new_a   = (Scalar *) PetscMalloc( len ); CHKPTRQ(new_a);
100         new_j   = (int *) (new_a + new_nz);
101         new_i   = new_j + new_nz;
102 
103         /* copy over old data into new slots */
104         for ( ii=0; ii<row+1; ii++ ) {new_i[ii] = ai[ii];}
105         for ( ii=row+1; ii<a->m+1; ii++ ) {new_i[ii] = ai[ii]+CHUNKSIZE;}
106         PetscMemcpy(new_j,aj,(ai[row]+nrow+shift)*sizeof(int));
107         len = (new_nz - CHUNKSIZE - ai[row] - nrow - shift);
108         PetscMemcpy(new_j+ai[row]+shift+nrow+CHUNKSIZE,aj+ai[row]+shift+nrow,
109                                                            len*sizeof(int));
110         PetscMemcpy(new_a,aa,(ai[row]+nrow+shift)*sizeof(Scalar));
111         PetscMemcpy(new_a+ai[row]+shift+nrow+CHUNKSIZE,aa+ai[row]+shift+nrow,
112                                                            len*sizeof(Scalar));
113         /* free up old matrix storage */
114         PetscFree(a->a);
115         if (!a->singlemalloc) {PetscFree(a->i);PetscFree(a->j);}
116         aa = a->a = new_a; ai = a->i = new_i; aj = a->j = new_j;
117         a->singlemalloc = 1;
118 
119         rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
120         rmax = imax[row] = imax[row] + CHUNKSIZE;
121         PLogObjectMemory(A,CHUNKSIZE*(sizeof(int) + sizeof(Scalar)));
122         a->maxnz += CHUNKSIZE;
123         a->reallocs++;
124       }
125       N = nrow++ - 1; a->nz++;
126       /* shift up all the later entries in this row */
127       for ( ii=N; ii>=i; ii-- ) {
128         rp[ii+1] = rp[ii];
129         ap[ii+1] = ap[ii];
130       }
131       rp[i] = col;
132       ap[i] = value;
133       noinsert:;
134       low = i + 1;
135     }
136     ailen[row] = nrow;
137   }
138   return 0;
139 }
140 
141 static int MatGetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v)
142 {
143   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
144   int        *rp, k, low, high, t, row, nrow, i, col, l, *aj = a->j;
145   int        *ai = a->i, *ailen = a->ilen, shift = a->indexshift;
146   Scalar     *ap, *aa = a->a, zero = 0.0;
147 
148   for ( k=0; k<m; k++ ) { /* loop over rows */
149     row  = im[k];
150     if (row < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative row");
151     if (row >= a->m) SETERRQ(1,"MatGetValues_SeqAIJ:Row too large");
152     rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
153     nrow = ailen[row];
154     for ( l=0; l<n; l++ ) { /* loop over columns */
155       if (in[l] < 0) SETERRQ(1,"MatGetValues_SeqAIJ:Negative column");
156       if (in[l] >= a->n) SETERRQ(1,"MatGetValues_SeqAIJ:Column too large");
157       col = in[l] - shift;
158       high = nrow; low = 0; /* assume unsorted */
159       while (high-low > 5) {
160         t = (low+high)/2;
161         if (rp[t] > col) high = t;
162         else             low  = t;
163       }
164       for ( i=low; i<high; i++ ) {
165         if (rp[i] > col) break;
166         if (rp[i] == col) {
167           *v++ = ap[i];
168           goto finished;
169         }
170       }
171       *v++ = zero;
172       finished:;
173     }
174   }
175   return 0;
176 }
177 
178 #include "draw.h"
179 #include "pinclude/pviewer.h"
180 #include "sysio.h"
181 
182 static int MatView_SeqAIJ_Binary(Mat A,Viewer viewer)
183 {
184   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
185   int        i, fd, *col_lens, ierr;
186 
187   ierr = ViewerFileGetDescriptor_Private(viewer,&fd); CHKERRQ(ierr);
188   col_lens = (int *) PetscMalloc( (4+a->m)*sizeof(int) ); CHKPTRQ(col_lens);
189   col_lens[0] = MAT_COOKIE;
190   col_lens[1] = a->m;
191   col_lens[2] = a->n;
192   col_lens[3] = a->nz;
193 
194   /* store lengths of each row and write (including header) to file */
195   for ( i=0; i<a->m; i++ ) {
196     col_lens[4+i] = a->i[i+1] - a->i[i];
197   }
198   ierr = SYWrite(fd,col_lens,4+a->m,SYINT,1); CHKERRQ(ierr);
199   PetscFree(col_lens);
200 
201   /* store column indices (zero start index) */
202   if (a->indexshift) {
203     for ( i=0; i<a->nz; i++ ) a->j[i]--;
204   }
205   ierr = SYWrite(fd,a->j,a->nz,SYINT,0); CHKERRQ(ierr);
206   if (a->indexshift) {
207     for ( i=0; i<a->nz; i++ ) a->j[i]++;
208   }
209 
210   /* store nonzero values */
211   ierr = SYWrite(fd,a->a,a->nz,SYSCALAR,0); CHKERRQ(ierr);
212   return 0;
213 }
214 
215 static int MatView_SeqAIJ_ASCII(Mat A,Viewer viewer)
216 {
217   Mat_SeqAIJ  *a = (Mat_SeqAIJ *) A->data;
218   int         ierr, i,j, m = a->m, shift = a->indexshift,format;
219   FILE        *fd;
220   char        *outputname;
221 
222   ierr = ViewerFileGetPointer(viewer,&fd); CHKERRQ(ierr);
223   ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr);
224   ierr = ViewerFileGetFormat_Private(viewer,&format);
225   if (format == FILE_FORMAT_INFO) {
226     /* no need to print additional information */ ;
227   }
228   else if (format == FILE_FORMAT_MATLAB) {
229     int nz, nzalloc, mem;
230     MatGetInfo(A,MAT_LOCAL,&nz,&nzalloc,&mem);
231     fprintf(fd,"%% Size = %d %d \n",m,a->n);
232     fprintf(fd,"%% Nonzeros = %d \n",nz);
233     fprintf(fd,"zzz = zeros(%d,3);\n",nz);
234     fprintf(fd,"zzz = [\n");
235 
236     for (i=0; i<m; i++) {
237       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
238 #if defined(PETSC_COMPLEX)
239         fprintf(fd,"%d %d  %18.16e  %18.16e \n",i+1,a->j[j]+!shift,real(a->a[j]),
240                    imag(a->a[j]));
241 #else
242         fprintf(fd,"%d %d  %18.16e\n", i+1, a->j[j]+!shift, a->a[j]);
243 #endif
244       }
245     }
246     fprintf(fd,"];\n %s = spconvert(zzz);\n",outputname);
247   }
248   else {
249     for ( i=0; i<m; i++ ) {
250       fprintf(fd,"row %d:",i);
251       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
252 #if defined(PETSC_COMPLEX)
253         if (imag(a->a[j]) != 0.0) {
254           fprintf(fd," %d %g + %g i",a->j[j]+shift,real(a->a[j]),imag(a->a[j]));
255         }
256         else {
257           fprintf(fd," %d %g ",a->j[j]+shift,real(a->a[j]));
258         }
259 #else
260         fprintf(fd," %d %g ",a->j[j]+shift,a->a[j]);
261 #endif
262       }
263       fprintf(fd,"\n");
264     }
265   }
266   fflush(fd);
267   return 0;
268 }
269 
270 static int MatView_SeqAIJ_Draw(Mat A,Viewer viewer)
271 {
272   Mat_SeqAIJ  *a = (Mat_SeqAIJ *) A->data;
273   int         ierr, i,j, m = a->m, shift = a->indexshift,pause,color;
274   double      xl,yl,xr,yr,w,h,xc,yc,scale = 1.0,x_l,x_r,y_l,y_r;
275   Draw     draw = (Draw) viewer;
276   DrawButton  button;
277 
278   xr  = a->n; yr = a->m; h = yr/10.0; w = xr/10.0;
279   xr += w;    yr += h;  xl = -w;     yl = -h;
280   ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr);
281   /* loop over matrix elements drawing boxes */
282   color = DRAW_BLUE;
283   for ( i=0; i<m; i++ ) {
284     y_l = m - i - 1.0; y_r = y_l + 1.0;
285     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
286       x_l = a->j[j] + shift; x_r = x_l + 1.0;
287 #if defined(PETSC_COMPLEX)
288       if (real(a->a[j]) >=  0.) continue;
289 #else
290       if (a->a[j] >=  0.) continue;
291 #endif
292       DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
293     }
294   }
295   color = DRAW_CYAN;
296   for ( i=0; i<m; i++ ) {
297     y_l = m - i - 1.0; y_r = y_l + 1.0;
298     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
299       x_l = a->j[j] + shift; x_r = x_l + 1.0;
300       if (a->a[j] !=  0.) continue;
301       DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
302     }
303   }
304   color = DRAW_RED;
305   for ( i=0; i<m; i++ ) {
306     y_l = m - i - 1.0; y_r = y_l + 1.0;
307     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
308       x_l = a->j[j] + shift; x_r = x_l + 1.0;
309 #if defined(PETSC_COMPLEX)
310       if (real(a->a[j]) <=  0.) continue;
311 #else
312       if (a->a[j] <=  0.) continue;
313 #endif
314       DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
315     }
316   }
317   DrawFlush(draw);
318   DrawGetPause(draw,&pause);
319   if (pause >= 0) { PetscSleep(pause); return 0;}
320 
321   /* allow the matrix to zoom or shrink */
322   ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0);
323   while (button != BUTTON_RIGHT) {
324     DrawClear(draw);
325     if (button == BUTTON_LEFT) scale = .5;
326     else if (button == BUTTON_CENTER) scale = 2.;
327     xl = scale*(xl + w - xc) + xc - w*scale;
328     xr = scale*(xr - w - xc) + xc + w*scale;
329     yl = scale*(yl + h - yc) + yc - h*scale;
330     yr = scale*(yr - h - yc) + yc + h*scale;
331     w *= scale; h *= scale;
332     ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr);
333     color = DRAW_BLUE;
334     for ( i=0; i<m; i++ ) {
335       y_l = m - i - 1.0; y_r = y_l + 1.0;
336       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
337         x_l = a->j[j] + shift; x_r = x_l + 1.0;
338 #if defined(PETSC_COMPLEX)
339         if (real(a->a[j]) >=  0.) continue;
340 #else
341         if (a->a[j] >=  0.) continue;
342 #endif
343         DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
344       }
345     }
346     color = DRAW_CYAN;
347     for ( i=0; i<m; i++ ) {
348       y_l = m - i - 1.0; y_r = y_l + 1.0;
349       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
350         x_l = a->j[j] + shift; x_r = x_l + 1.0;
351         if (a->a[j] !=  0.) continue;
352         DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
353       }
354     }
355     color = DRAW_RED;
356     for ( i=0; i<m; i++ ) {
357       y_l = m - i - 1.0; y_r = y_l + 1.0;
358       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
359         x_l = a->j[j] + shift; x_r = x_l + 1.0;
360 #if defined(PETSC_COMPLEX)
361         if (real(a->a[j]) <=  0.) continue;
362 #else
363         if (a->a[j] <=  0.) continue;
364 #endif
365         DrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);
366       }
367     }
368     ierr = DrawGetMouseButton(draw,&button,&xc,&yc,0,0);
369   }
370   return 0;
371 }
372 
373 static int MatView_SeqAIJ(PetscObject obj,Viewer viewer)
374 {
375   Mat         A = (Mat) obj;
376   Mat_SeqAIJ  *a = (Mat_SeqAIJ*) A->data;
377   PetscObject vobj = (PetscObject) viewer;
378 
379   if (!viewer) {
380     viewer = STDOUT_VIEWER_SELF; vobj = (PetscObject) viewer;
381   }
382   if (vobj->cookie == VIEWER_COOKIE) {
383     if (vobj->type == MATLAB_VIEWER) {
384       return ViewerMatlabPutSparse_Private(viewer,a->m,a->n,a->nz,a->a,a->i,a->j);
385     }
386     else if (vobj->type == ASCII_FILE_VIEWER || vobj->type == ASCII_FILES_VIEWER){
387       return MatView_SeqAIJ_ASCII(A,viewer);
388     }
389     else if (vobj->type == BINARY_FILE_VIEWER) {
390       return MatView_SeqAIJ_Binary(A,viewer);
391     }
392   }
393   else if (vobj->cookie == DRAW_COOKIE) {
394     if (vobj->type == NULLWINDOW) return 0;
395     else return MatView_SeqAIJ_Draw(A,viewer);
396   }
397   return 0;
398 }
399 extern int Mat_AIJ_CheckInode(Mat);
400 static int MatAssemblyEnd_SeqAIJ(Mat A,MatAssemblyType mode)
401 {
402   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
403   int        fshift = 0,i,j,*ai = a->i, *aj = a->j, *imax = a->imax,ierr;
404   int        m = a->m, *ip, N, *ailen = a->ilen,shift = a->indexshift;
405   Scalar     *aa = a->a, *ap;
406 
407   if (mode == FLUSH_ASSEMBLY) return 0;
408 
409   for ( i=1; i<m; i++ ) {
410     /* move each row back by the amount of empty slots (fshift) before it*/
411     fshift += imax[i-1] - ailen[i-1];
412     if (fshift) {
413       ip = aj + ai[i] + shift; ap = aa + ai[i] + shift;
414       N = ailen[i];
415       for ( j=0; j<N; j++ ) {
416         ip[j-fshift] = ip[j];
417         ap[j-fshift] = ap[j];
418       }
419     }
420     ai[i] = ai[i-1] + ailen[i-1];
421   }
422   if (m) {
423     fshift += imax[m-1] - ailen[m-1];
424     ai[m] = ai[m-1] + ailen[m-1];
425   }
426   /* reset ilen and imax for each row */
427   for ( i=0; i<m; i++ ) {
428     ailen[i] = imax[i] = ai[i+1] - ai[i];
429   }
430   a->nz = ai[m] + shift;
431 
432   /* diagonals may have moved, so kill the diagonal pointers */
433   if (fshift && a->diag) {
434     PetscFree(a->diag);
435     PLogObjectMemory(A,-(m+1)*sizeof(int));
436     a->diag = 0;
437   }
438   PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Unneeded storage space %d used %d rows %d\n",
439            fshift,a->nz,m);
440   PLogInfo((PetscObject)A,"MatAssemblyEnd_SeqAIJ:Number of mallocs during MatSetValues %d\n",
441            a->reallocs);
442   /* check out for identical nodes. If found, use inode functions */
443   ierr = Mat_AIJ_CheckInode(A); CHKERRQ(ierr);
444   return 0;
445 }
446 
447 static int MatZeroEntries_SeqAIJ(Mat A)
448 {
449   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
450   PetscMemzero(a->a,(a->i[a->m]+a->indexshift)*sizeof(Scalar));
451   return 0;
452 }
453 
454 int MatDestroy_SeqAIJ(PetscObject obj)
455 {
456   Mat        A  = (Mat) obj;
457   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
458 
459 #if defined(PETSC_LOG)
460   PLogObjectState(obj,"Rows=%d, Cols=%d, NZ=%d",a->m,a->n,a->nz);
461 #endif
462   PetscFree(a->a);
463   if (!a->singlemalloc) { PetscFree(a->i); PetscFree(a->j);}
464   if (a->diag) PetscFree(a->diag);
465   if (a->ilen) PetscFree(a->ilen);
466   if (a->imax) PetscFree(a->imax);
467   if (a->solve_work) PetscFree(a->solve_work);
468   if (a->inode.size) PetscFree(a->inode.size);
469   PetscFree(a);
470   PLogObjectDestroy(A);
471   PetscHeaderDestroy(A);
472   return 0;
473 }
474 
475 static int MatCompress_SeqAIJ(Mat A)
476 {
477   return 0;
478 }
479 
480 static int MatSetOption_SeqAIJ(Mat A,MatOption op)
481 {
482   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
483   if      (op == ROW_ORIENTED)              a->roworiented = 1;
484   else if (op == COLUMN_ORIENTED)           a->roworiented = 0;
485   else if (op == COLUMNS_SORTED)            a->sorted      = 1;
486   else if (op == NO_NEW_NONZERO_LOCATIONS)  a->nonew       = 1;
487   else if (op == YES_NEW_NONZERO_LOCATIONS) a->nonew       = 0;
488   else if (op == ROWS_SORTED ||
489            op == SYMMETRIC_MATRIX ||
490            op == STRUCTURALLY_SYMMETRIC_MATRIX ||
491            op == YES_NEW_DIAGONALS)
492     PLogInfo((PetscObject)A,"Info:MatSetOption_SeqAIJ:Option ignored\n");
493   else if (op == NO_NEW_DIAGONALS)
494     {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:NO_NEW_DIAGONALS");}
495   else if (op == INODE_LIMIT_1)            a->inode.limit  = 1;
496   else if (op == INODE_LIMIT_2)            a->inode.limit  = 2;
497   else if (op == INODE_LIMIT_3)            a->inode.limit  = 3;
498   else if (op == INODE_LIMIT_4)            a->inode.limit  = 4;
499   else if (op == INODE_LIMIT_5)            a->inode.limit  = 5;
500   else
501     {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:unknown option");}
502   return 0;
503 }
504 
505 static int MatGetDiagonal_SeqAIJ(Mat A,Vec v)
506 {
507   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
508   int        i,j, n,shift = a->indexshift;
509   Scalar     *x, zero = 0.0;
510 
511   VecSet(&zero,v);
512   VecGetArray(v,&x); VecGetLocalSize(v,&n);
513   if (n != a->m) SETERRQ(1,"MatGetDiagonal_SeqAIJ:Nonconforming matrix and vector");
514   for ( i=0; i<a->m; i++ ) {
515     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
516       if (a->j[j]+shift == i) {
517         x[i] = a->a[j];
518         break;
519       }
520     }
521   }
522   return 0;
523 }
524 
525 /* -------------------------------------------------------*/
526 /* Should check that shapes of vectors and matrices match */
527 /* -------------------------------------------------------*/
528 static int MatMultTrans_SeqAIJ(Mat A,Vec xx,Vec yy)
529 {
530   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
531   Scalar     *x, *y, *v, alpha;
532   int        m = a->m, n, i, *idx, shift = a->indexshift;
533 
534   VecGetArray(xx,&x); VecGetArray(yy,&y);
535   PetscMemzero(y,a->n*sizeof(Scalar));
536   y = y + shift; /* shift for Fortran start by 1 indexing */
537   for ( i=0; i<m; i++ ) {
538     idx   = a->j + a->i[i] + shift;
539     v     = a->a + a->i[i] + shift;
540     n     = a->i[i+1] - a->i[i];
541     alpha = x[i];
542     while (n-->0) {y[*idx++] += alpha * *v++;}
543   }
544   PLogFlops(2*a->nz - a->n);
545   return 0;
546 }
547 
548 static int MatMultTransAdd_SeqAIJ(Mat A,Vec xx,Vec zz,Vec yy)
549 {
550   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
551   Scalar     *x, *y, *v, alpha;
552   int        m = a->m, n, i, *idx,shift = a->indexshift;
553 
554   VecGetArray(xx,&x); VecGetArray(yy,&y);
555   if (zz != yy) VecCopy(zz,yy);
556   y = y + shift; /* shift for Fortran start by 1 indexing */
557   for ( i=0; i<m; i++ ) {
558     idx   = a->j + a->i[i] + shift;
559     v     = a->a + a->i[i] + shift;
560     n     = a->i[i+1] - a->i[i];
561     alpha = x[i];
562     while (n-->0) {y[*idx++] += alpha * *v++;}
563   }
564   return 0;
565 }
566 
567 static int MatMult_SeqAIJ(Mat A,Vec xx,Vec yy)
568 {
569   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
570   Scalar     *x, *y, *v, sum;
571   int        m = a->m, n, i, *idx, shift = a->indexshift,*ii;
572 
573   VecGetArray(xx,&x); VecGetArray(yy,&y);
574   x    = x + shift; /* shift for Fortran start by 1 indexing */
575   idx  = a->j;
576   v    = a->a;
577   ii   = a->i;
578   for ( i=0; i<m; i++ ) {
579     n    = ii[1] - ii[0]; ii++;
580     sum  = 0.0;
581     /* SPARSEDENSEDOT(sum,x,v,idx,n);  */
582     /* for ( j=n-1; j>-1; j--) sum += v[j]*x[idx[j]]; */
583     while (n--) sum += *v++ * x[*idx++];
584     y[i] = sum;
585   }
586   PLogFlops(2*a->nz - m);
587   return 0;
588 }
589 
590 static int MatMultAdd_SeqAIJ(Mat A,Vec xx,Vec yy,Vec zz)
591 {
592   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
593   Scalar     *x, *y, *z, *v, sum;
594   int        m = a->m, n, i, *idx, shift = a->indexshift,*ii;
595 
596   VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z);
597   x    = x + shift; /* shift for Fortran start by 1 indexing */
598   idx  = a->j;
599   v    = a->a;
600   ii   = a->i;
601   for ( i=0; i<m; i++ ) {
602     n    = ii[1] - ii[0]; ii++;
603     sum  = y[i];
604     /* SPARSEDENSEDOT(sum,x,v,idx,n);  */
605     while (n--) sum += *v++ * x[*idx++];
606     z[i] = sum;
607   }
608   PLogFlops(2*a->nz);
609   return 0;
610 }
611 
612 /*
613      Adds diagonal pointers to sparse matrix structure.
614 */
615 
616 int MatMarkDiag_SeqAIJ(Mat A)
617 {
618   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
619   int        i,j, *diag, m = a->m,shift = a->indexshift;
620 
621   diag = (int *) PetscMalloc( (m+1)*sizeof(int)); CHKPTRQ(diag);
622   PLogObjectMemory(A,(m+1)*sizeof(int));
623   for ( i=0; i<a->m; i++ ) {
624     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
625       if (a->j[j]+shift == i) {
626         diag[i] = j - shift;
627         break;
628       }
629     }
630   }
631   a->diag = diag;
632   return 0;
633 }
634 
635 static int MatRelax_SeqAIJ(Mat A,Vec bb,double omega,MatSORType flag,
636                            double fshift,int its,Vec xx)
637 {
638   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
639   Scalar     *x, *b, *bs,  d, *xs, sum, *v = a->a,*t,scale,*ts, *xb;
640   int        ierr, *idx, *diag,n = a->n, m = a->m, i, shift = a->indexshift;
641 
642   VecGetArray(xx,&x); VecGetArray(bb,&b);
643   if (!a->diag) {if ((ierr = MatMarkDiag_SeqAIJ(A))) return ierr;}
644   diag = a->diag;
645   xs   = x + shift; /* shifted by one for index start of a or a->j*/
646   if (flag == SOR_APPLY_UPPER) {
647    /* apply ( U + D/omega) to the vector */
648     bs = b + shift;
649     for ( i=0; i<m; i++ ) {
650         d    = fshift + a->a[diag[i] + shift];
651         n    = a->i[i+1] - diag[i] - 1;
652         idx  = a->j + diag[i] + (!shift);
653         v    = a->a + diag[i] + (!shift);
654         sum  = b[i]*d/omega;
655         SPARSEDENSEDOT(sum,bs,v,idx,n);
656         x[i] = sum;
657     }
658     return 0;
659   }
660   if (flag == SOR_APPLY_LOWER) {
661     SETERRQ(1,"MatRelax_SeqAIJ:SOR_APPLY_LOWER is not done");
662   }
663   else if (flag & SOR_EISENSTAT) {
664     /* Let  A = L + U + D; where L is lower trianglar,
665     U is upper triangular, E is diagonal; This routine applies
666 
667             (L + E)^{-1} A (U + E)^{-1}
668 
669     to a vector efficiently using Eisenstat's trick. This is for
670     the case of SSOR preconditioner, so E is D/omega where omega
671     is the relaxation factor.
672     */
673     t = (Scalar *) PetscMalloc( m*sizeof(Scalar) ); CHKPTRQ(t);
674     scale = (2.0/omega) - 1.0;
675 
676     /*  x = (E + U)^{-1} b */
677     for ( i=m-1; i>=0; i-- ) {
678       d    = fshift + a->a[diag[i] + shift];
679       n    = a->i[i+1] - diag[i] - 1;
680       idx  = a->j + diag[i] + (!shift);
681       v    = a->a + diag[i] + (!shift);
682       sum  = b[i];
683       SPARSEDENSEMDOT(sum,xs,v,idx,n);
684       x[i] = omega*(sum/d);
685     }
686 
687     /*  t = b - (2*E - D)x */
688     v = a->a;
689     for ( i=0; i<m; i++ ) { t[i] = b[i] - scale*(v[*diag++ + shift])*x[i]; }
690 
691     /*  t = (E + L)^{-1}t */
692     ts = t + shift; /* shifted by one for index start of a or a->j*/
693     diag = a->diag;
694     for ( i=0; i<m; i++ ) {
695       d    = fshift + a->a[diag[i]+shift];
696       n    = diag[i] - a->i[i];
697       idx  = a->j + a->i[i] + shift;
698       v    = a->a + a->i[i] + shift;
699       sum  = t[i];
700       SPARSEDENSEMDOT(sum,ts,v,idx,n);
701       t[i] = omega*(sum/d);
702     }
703 
704     /*  x = x + t */
705     for ( i=0; i<m; i++ ) { x[i] += t[i]; }
706     PetscFree(t);
707     return 0;
708   }
709   if (flag & SOR_ZERO_INITIAL_GUESS) {
710     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
711       for ( i=0; i<m; i++ ) {
712         d    = fshift + a->a[diag[i]+shift];
713         n    = diag[i] - a->i[i];
714         idx  = a->j + a->i[i] + shift;
715         v    = a->a + a->i[i] + shift;
716         sum  = b[i];
717         SPARSEDENSEMDOT(sum,xs,v,idx,n);
718         x[i] = omega*(sum/d);
719       }
720       xb = x;
721     }
722     else xb = b;
723     if ((flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) &&
724         (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP)) {
725       for ( i=0; i<m; i++ ) {
726         x[i] *= a->a[diag[i]+shift];
727       }
728     }
729     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
730       for ( i=m-1; i>=0; i-- ) {
731         d    = fshift + a->a[diag[i] + shift];
732         n    = a->i[i+1] - diag[i] - 1;
733         idx  = a->j + diag[i] + (!shift);
734         v    = a->a + diag[i] + (!shift);
735         sum  = xb[i];
736         SPARSEDENSEMDOT(sum,xs,v,idx,n);
737         x[i] = omega*(sum/d);
738       }
739     }
740     its--;
741   }
742   while (its--) {
743     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
744       for ( i=0; i<m; i++ ) {
745         d    = fshift + a->a[diag[i]+shift];
746         n    = a->i[i+1] - a->i[i];
747         idx  = a->j + a->i[i] + shift;
748         v    = a->a + a->i[i] + shift;
749         sum  = b[i];
750         SPARSEDENSEMDOT(sum,xs,v,idx,n);
751         x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]);
752       }
753     }
754     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
755       for ( i=m-1; i>=0; i-- ) {
756         d    = fshift + a->a[diag[i] + shift];
757         n    = a->i[i+1] - a->i[i];
758         idx  = a->j + a->i[i] + shift;
759         v    = a->a + a->i[i] + shift;
760         sum  = b[i];
761         SPARSEDENSEMDOT(sum,xs,v,idx,n);
762         x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]);
763       }
764     }
765   }
766   return 0;
767 }
768 
769 static int MatGetInfo_SeqAIJ(Mat A,MatInfoType flag,int *nz,int *nzalloc,int *mem)
770 {
771   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
772   *nz      = a->nz;
773   *nzalloc = a->maxnz;
774   *mem     = (int)A->mem;
775   return 0;
776 }
777 
778 extern int MatLUFactorSymbolic_SeqAIJ(Mat,IS,IS,double,Mat*);
779 extern int MatLUFactorNumeric_SeqAIJ(Mat,Mat*);
780 extern int MatLUFactor_SeqAIJ(Mat,IS,IS,double);
781 extern int MatSolve_SeqAIJ(Mat,Vec,Vec);
782 extern int MatSolveAdd_SeqAIJ(Mat,Vec,Vec,Vec);
783 extern int MatSolveTrans_SeqAIJ(Mat,Vec,Vec);
784 extern int MatSolveTransAdd_SeqAIJ(Mat,Vec,Vec,Vec);
785 
786 static int MatZeroRows_SeqAIJ(Mat A,IS is,Scalar *diag)
787 {
788   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
789   int         i,ierr,N, *rows,m = a->m - 1,shift = a->indexshift;
790 
791   ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr);
792   ierr = ISGetIndices(is,&rows); CHKERRQ(ierr);
793   if (diag) {
794     for ( i=0; i<N; i++ ) {
795       if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range");
796       if (a->ilen[rows[i]] > 0) { /* in case row was completely empty */
797         a->ilen[rows[i]] = 1;
798         a->a[a->i[rows[i]]+shift] = *diag;
799         a->j[a->i[rows[i]]+shift] = rows[i]+shift;
800       }
801       else {
802         ierr = MatSetValues_SeqAIJ(A,1,&rows[i],1,&rows[i],diag,INSERT_VALUES);
803         CHKERRQ(ierr);
804       }
805     }
806   }
807   else {
808     for ( i=0; i<N; i++ ) {
809       if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range");
810       a->ilen[rows[i]] = 0;
811     }
812   }
813   ISRestoreIndices(is,&rows);
814   ierr = MatAssemblyBegin(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
815   ierr = MatAssemblyEnd(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
816   return 0;
817 }
818 
819 static int MatGetSize_SeqAIJ(Mat A,int *m,int *n)
820 {
821   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
822   *m = a->m; *n = a->n;
823   return 0;
824 }
825 
826 static int MatGetOwnershipRange_SeqAIJ(Mat A,int *m,int *n)
827 {
828   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
829   *m = 0; *n = a->m;
830   return 0;
831 }
832 static int MatGetRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v)
833 {
834   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
835   int        *itmp,i,shift = a->indexshift;
836 
837   if (row < 0 || row >= a->m) SETERRQ(1,"MatGetRow_SeqAIJ:Row out of range");
838 
839   *nz = a->i[row+1] - a->i[row];
840   if (v) *v = a->a + a->i[row] + shift;
841   if (idx) {
842     if (*nz) {
843       itmp = a->j + a->i[row] + shift;
844       *idx = (int *) PetscMalloc( (*nz)*sizeof(int) ); CHKPTRQ(*idx);
845       for ( i=0; i<(*nz); i++ ) {(*idx)[i] = itmp[i] + shift;}
846     }
847     else *idx = 0;
848   }
849   return 0;
850 }
851 
852 static int MatRestoreRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v)
853 {
854   if (idx) {if (*idx) PetscFree(*idx);}
855   return 0;
856 }
857 
858 static int MatNorm_SeqAIJ(Mat A,NormType type,double *norm)
859 {
860   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
861   Scalar     *v = a->a;
862   double     sum = 0.0;
863   int        i, j,shift = a->indexshift;
864 
865   if (type == NORM_FROBENIUS) {
866     for (i=0; i<a->nz; i++ ) {
867 #if defined(PETSC_COMPLEX)
868       sum += real(conj(*v)*(*v)); v++;
869 #else
870       sum += (*v)*(*v); v++;
871 #endif
872     }
873     *norm = sqrt(sum);
874   }
875   else if (type == NORM_1) {
876     double *tmp;
877     int    *jj = a->j;
878     tmp = (double *) PetscMalloc( a->n*sizeof(double) ); CHKPTRQ(tmp);
879     PetscMemzero(tmp,a->n*sizeof(double));
880     *norm = 0.0;
881     for ( j=0; j<a->nz; j++ ) {
882         tmp[*jj++ + shift] += PetscAbsScalar(*v);  v++;
883     }
884     for ( j=0; j<a->n; j++ ) {
885       if (tmp[j] > *norm) *norm = tmp[j];
886     }
887     PetscFree(tmp);
888   }
889   else if (type == NORM_INFINITY) {
890     *norm = 0.0;
891     for ( j=0; j<a->m; j++ ) {
892       v = a->a + a->i[j] + shift;
893       sum = 0.0;
894       for ( i=0; i<a->i[j+1]-a->i[j]; i++ ) {
895         sum += PetscAbsScalar(*v); v++;
896       }
897       if (sum > *norm) *norm = sum;
898     }
899   }
900   else {
901     SETERRQ(1,"MatNorm_SeqAIJ:No support for two norm yet");
902   }
903   return 0;
904 }
905 
906 static int MatTranspose_SeqAIJ(Mat A,Mat *B)
907 {
908   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
909   Mat        C;
910   int        i, ierr, *aj = a->j, *ai = a->i, m = a->m, len, *col;
911   int        shift = a->indexshift;
912   Scalar     *array = a->a;
913 
914   if (B == PETSC_NULL && m != a->n)
915     SETERRQ(1,"MatTranspose_MPIAIJ:Square matrix only for in-place");
916   col = (int *) PetscMalloc((1+a->n)*sizeof(int)); CHKPTRQ(col);
917   PetscMemzero(col,(1+a->n)*sizeof(int));
918   if (shift) {
919     for ( i=0; i<ai[m]-1; i++ ) aj[i] -= 1;
920   }
921   for ( i=0; i<ai[m]+shift; i++ ) col[aj[i]] += 1;
922   ierr = MatCreateSeqAIJ(A->comm,a->n,m,0,col,&C); CHKERRQ(ierr);
923   PetscFree(col);
924   for ( i=0; i<m; i++ ) {
925     len = ai[i+1]-ai[i];
926     ierr = MatSetValues(C,len,aj,1,&i,array,INSERT_VALUES); CHKERRQ(ierr);
927     array += len; aj += len;
928   }
929   if (shift) {
930     for ( i=0; i<ai[m]-1; i++ ) aj[i] += 1;
931   }
932 
933   ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
934   ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
935 
936   if (B != PETSC_NULL) {
937     *B = C;
938   } else {
939     /* This isn't really an in-place transpose */
940     PetscFree(a->a);
941     if (!a->singlemalloc) {PetscFree(a->i); PetscFree(a->j);}
942     if (a->diag) PetscFree(a->diag);
943     if (a->ilen) PetscFree(a->ilen);
944     if (a->imax) PetscFree(a->imax);
945     if (a->solve_work) PetscFree(a->solve_work);
946     PetscFree(a);
947     PetscMemcpy(A,C,sizeof(struct _Mat));
948     PetscHeaderDestroy(C);
949   }
950   return 0;
951 }
952 
953 static int MatDiagonalScale_SeqAIJ(Mat A,Vec ll,Vec rr)
954 {
955   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
956   Scalar     *l,*r,x,*v;
957   int        i,j,m = a->m, n = a->n, M, nz = a->nz, *jj,shift = a->indexshift;
958 
959   if (ll) {
960     VecGetArray(ll,&l); VecGetSize(ll,&m);
961     if (m != a->m) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Left scaling vector wrong length");
962     v = a->a;
963     for ( i=0; i<m; i++ ) {
964       x = l[i];
965       M = a->i[i+1] - a->i[i];
966       for ( j=0; j<M; j++ ) { (*v++) *= x;}
967     }
968   }
969   if (rr) {
970     VecGetArray(rr,&r); VecGetSize(rr,&n);
971     if (n != a->n) SETERRQ(1,"MatDiagonalScale_SeqAIJ:Right scaling vector wrong length");
972     v = a->a; jj = a->j;
973     for ( i=0; i<nz; i++ ) {
974       (*v++) *= r[*jj++ + shift];
975     }
976   }
977   return 0;
978 }
979 
980 static int MatGetSubMatrix_SeqAIJ(Mat A,IS isrow,IS iscol,MatGetSubMatrixCall scall,Mat *B)
981 {
982   Mat_SeqAIJ   *a = (Mat_SeqAIJ *) A->data,*c;
983   int          nznew, *smap, i, k, kstart, kend, ierr, oldcols = a->n,*lens;
984   register int sum,lensi;
985   int          *irow, *icol, nrows, ncols, *cwork, shift = a->indexshift,*ssmap;
986   int          first,step,*starts,*j_new,*i_new,*aj = a->j, *ai = a->i,ii,*ailen = a->ilen;
987   Scalar       *vwork,*a_new;
988   Mat          C;
989 
990   ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr);
991   ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr);
992   ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr);
993 
994   if (ISStrideGetInfo(iscol,&first,&step) && step == 1) { /* no need to sort */
995     /* special case of contiguous rows */
996     lens   = (int *) PetscMalloc((2*ncols+1)*sizeof(int)); CHKPTRQ(lens);
997     starts = lens + ncols;
998     /* loop over new rows determining lens and starting points */
999     for (i=0; i<nrows; i++) {
1000       kstart  = ai[irow[i]]+shift;
1001       kend    = kstart + ailen[irow[i]];
1002       for ( k=kstart; k<kend; k++ ) {
1003         if (aj[k]+shift >= first) {
1004           starts[i] = k;
1005           break;
1006 	}
1007       }
1008       sum = 0;
1009       while (k < kend) {
1010         if (aj[k++]+shift >= first+ncols) break;
1011         sum++;
1012       }
1013       lens[i] = sum;
1014     }
1015     /* create submatrix */
1016     if (scall == MAT_REUSE_MATRIX) {
1017       int n_cols,n_rows;
1018       ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr);
1019       if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:");
1020       ierr = MatZeroEntries(*B); CHKERRQ(ierr);
1021       C = *B;
1022     }
1023     else {
1024       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1025     }
1026     c = (Mat_SeqAIJ*) C->data;
1027 
1028     /* loop over rows inserting into submatrix */
1029     a_new    = c->a;
1030     j_new    = c->j;
1031     i_new    = c->i;
1032     i_new[0] = -shift;
1033     for (i=0; i<nrows; i++) {
1034       ii    = starts[i];
1035       lensi = lens[i];
1036       for ( k=0; k<lensi; k++ ) {
1037         *j_new++ = aj[ii+k] - first;
1038       }
1039       PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(Scalar));
1040       a_new      += lensi;
1041       i_new[i+1]  = i_new[i] + lensi;
1042       c->ilen[i]  = lensi;
1043     }
1044     PetscFree(lens);
1045   }
1046   else {
1047     ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr);
1048     ierr = SYIsort(ncols,icol); CHKERRQ(ierr);
1049     smap  = (int *) PetscMalloc((1+oldcols)*sizeof(int)); CHKPTRQ(smap);
1050     ssmap = smap + shift;
1051     cwork = (int *) PetscMalloc((1+nrows+ncols)*sizeof(int)); CHKPTRQ(cwork);
1052     lens  = cwork + ncols;
1053     vwork = (Scalar *) PetscMalloc((1+ncols)*sizeof(Scalar)); CHKPTRQ(vwork);
1054     PetscMemzero(smap,oldcols*sizeof(int));
1055     for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1;
1056     /* determine lens of each row */
1057     for (i=0; i<nrows; i++) {
1058       kstart  = ai[irow[i]]+shift;
1059       kend    = kstart + a->ilen[irow[i]];
1060       lens[i] = 0;
1061       for ( k=kstart; k<kend; k++ ) {
1062         if (ssmap[aj[k]]) {
1063           lens[i]++;
1064         }
1065       }
1066     }
1067     /* Create and fill new matrix */
1068     if (scall == MAT_REUSE_MATRIX) {
1069       int n_cols,n_rows;
1070       ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr);
1071       if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:");
1072       ierr = MatZeroEntries(*B); CHKERRQ(ierr);
1073       C = *B;
1074     }
1075     else {
1076       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1077     }
1078     for (i=0; i<nrows; i++) {
1079       nznew  = 0;
1080       kstart = ai[irow[i]]+shift;
1081       kend   = kstart + a->ilen[irow[i]];
1082       for ( k=kstart; k<kend; k++ ) {
1083         if (ssmap[a->j[k]]) {
1084           cwork[nznew]   = ssmap[a->j[k]] - 1;
1085           vwork[nznew++] = a->a[k];
1086         }
1087       }
1088       ierr = MatSetValues(C,1,&i,nznew,cwork,vwork,INSERT_VALUES); CHKERRQ(ierr);
1089     }
1090     /* Free work space */
1091     ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr);
1092     PetscFree(smap); PetscFree(cwork); PetscFree(vwork);
1093   }
1094   ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
1095   ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
1096 
1097   ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr);
1098   *B = C;
1099   return 0;
1100 }
1101 
1102 /*
1103      note: This can only work for identity for row and col. It would
1104    be good to check this and otherwise generate an error.
1105 */
1106 static int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,double efill,int fill)
1107 {
1108   Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data;
1109   int        ierr;
1110   Mat        outA;
1111 
1112   if (fill != 0) SETERRQ(1,"MatILUFactor_SeqAIJ:Only fill=0 supported");
1113 
1114   outA          = inA;
1115   inA->factor   = FACTOR_LU;
1116   a->row        = row;
1117   a->col        = col;
1118 
1119   a->solve_work = (Scalar *) PetscMalloc( (a->m+1)*sizeof(Scalar)); CHKPTRQ(a->solve_work);
1120 
1121   if (!a->diag) {
1122     ierr = MatMarkDiag_SeqAIJ(inA); CHKERRQ(ierr);
1123   }
1124   ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA); CHKERRQ(ierr);
1125   return 0;
1126 }
1127 
1128 #include "pinclude/plapack.h"
1129 static int MatScale_SeqAIJ(Scalar *alpha,Mat inA)
1130 {
1131   Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data;
1132   int        one = 1;
1133   BLscal_( &a->nz, alpha, a->a, &one );
1134   PLogFlops(a->nz);
1135   return 0;
1136 }
1137 
1138 static int MatGetSubMatrices_SeqAIJ(Mat A,int n, IS *irow,IS *icol,MatGetSubMatrixCall scall,
1139                                     Mat **B)
1140 {
1141   int ierr,i;
1142 
1143   if (scall == MAT_INITIAL_MATRIX) {
1144     *B = (Mat *) PetscMalloc( (n+1)*sizeof(Mat) ); CHKPTRQ(*B);
1145   }
1146 
1147   for ( i=0; i<n; i++ ) {
1148     ierr = MatGetSubMatrix(A,irow[i],icol[i],scall,&(*B)[i]); CHKERRQ(ierr);
1149   }
1150   return 0;
1151 }
1152 
1153 static int MatIncreaseOverlap_SeqAIJ(Mat A, int is_max, IS *is, int ov)
1154 {
1155   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
1156   int        shift, row, i,j,k,l,m,n, *idx,ierr, *nidx, isz, val;
1157   int        start, end, *ai, *aj;
1158   char       *table;
1159   shift = a->indexshift;
1160   m     = a->m;
1161   ai    = a->i;
1162   aj    = a->j+shift;
1163 
1164   if (ov < 0)  SETERRQ(1,"MatIncreaseOverlap_SeqAIJ: illegal overlap value used");
1165 
1166   table = (char *) PetscMalloc((m/BITSPERBYTE +1)*sizeof(char)); CHKPTRQ(table);
1167   nidx  = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(nidx);
1168 
1169   for ( i=0; i<is_max; i++ ) {
1170     /* Initialise the two local arrays */
1171     isz  = 0;
1172     PetscMemzero(table,(m/BITSPERBYTE +1)*sizeof(char));
1173 
1174                 /* Extract the indices, assume there can be duplicate entries */
1175     ierr = ISGetIndices(is[i],&idx);  CHKERRQ(ierr);
1176     ierr = ISGetLocalSize(is[i],&n);  CHKERRQ(ierr);
1177 
1178     /* Enter these into the temp arrays i.e mark table[row], enter row into new index */
1179     for ( j=0; j<n ; ++j){
1180       if(!BT_LOOKUP(table, idx[j])) { nidx[isz++] = idx[j];}
1181     }
1182     ierr = ISRestoreIndices(is[i],&idx);  CHKERRQ(ierr);
1183     ierr = ISDestroy(is[i]); CHKERRQ(ierr);
1184 
1185     k = 0;
1186     for ( j=0; j<ov; j++){ /* for each overlap*/
1187       n = isz;
1188       for ( ; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */
1189         row   = nidx[k];
1190         start = ai[row];
1191         end   = ai[row+1];
1192         for ( l = start; l<end ; l++){
1193           val = aj[l] + shift;
1194           if (!BT_LOOKUP(table,val)) {nidx[isz++] = val;}
1195         }
1196       }
1197     }
1198     ierr = ISCreateSeq(MPI_COMM_SELF, isz, nidx, (is+i)); CHKERRQ(ierr);
1199   }
1200   PetscFree(table);
1201   PetscFree(nidx);
1202   return 0;
1203 }
1204 
1205 int MatPrintHelp_SeqAIJ(Mat A)
1206 {
1207   static int called = 0;
1208   MPI_Comm   comm = A->comm;
1209 
1210   if (called) return 0; else called = 1;
1211   MPIU_printf(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n");
1212   MPIU_printf(comm,"  -mat_lu_pivotthreshold <threshold>\n");
1213   MPIU_printf(comm,"  -mat_aij_oneindex - internal indices begin at 1 instead of the default 0.\n");
1214   MPIU_printf(comm,"  -mat_aij_no_inode  - Do not use inodes\n");
1215   MPIU_printf(comm,"  -mat_aij_inode_limit <limit> - Set inode limit (max limit=5)\n");
1216 #if defined(HAVE_ESSL)
1217   MPIU_printf(comm,"  -mat_aij_essl  - Use IBM sparse LU factorization and solve.\n");
1218 #endif
1219   return 0;
1220 }
1221 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg);
1222 /* -------------------------------------------------------------------*/
1223 static struct _MatOps MatOps = {MatSetValues_SeqAIJ,
1224        MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ,
1225        MatMult_SeqAIJ,MatMultAdd_SeqAIJ,
1226        MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ,
1227        MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ,
1228        MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ,
1229        MatLUFactor_SeqAIJ,0,
1230        MatRelax_SeqAIJ,
1231        MatTranspose_SeqAIJ,
1232        MatGetInfo_SeqAIJ,MatEqual_SeqAIJ,
1233        MatGetDiagonal_SeqAIJ,MatDiagonalScale_SeqAIJ,MatNorm_SeqAIJ,
1234        0,MatAssemblyEnd_SeqAIJ,
1235        MatCompress_SeqAIJ,
1236        MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ,
1237        MatGetReordering_SeqAIJ,
1238        MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0,
1239        MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ,
1240        MatILUFactorSymbolic_SeqAIJ,0,
1241        0,0,MatConvert_SeqAIJ,
1242        MatGetSubMatrix_SeqAIJ,0,
1243        MatConvertSameType_SeqAIJ,0,0,
1244        MatILUFactor_SeqAIJ,0,0,
1245        MatGetSubMatrices_SeqAIJ,MatIncreaseOverlap_SeqAIJ,
1246        MatGetValues_SeqAIJ,0,
1247        MatPrintHelp_SeqAIJ,
1248        MatScale_SeqAIJ};
1249 
1250 extern int MatUseSuperLU_SeqAIJ(Mat);
1251 extern int MatUseEssl_SeqAIJ(Mat);
1252 extern int MatUseDXML_SeqAIJ(Mat);
1253 
1254 /*@C
1255    MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format
1256    (the default parallel PETSc format).  For good matrix assembly performance
1257    the user should preallocate the matrix storage by setting the parameter nz
1258    (or nzz).  By setting these parameters accurately, performance can be
1259    increased by more than a factor of 50.
1260 
1261    Input Parameters:
1262 .  comm - MPI communicator, set to MPI_COMM_SELF
1263 .  m - number of rows
1264 .  n - number of columns
1265 .  nz - number of nonzeros per row (same for all rows)
1266 .  nzz - number of nonzeros per row or null (possibly different for each row)
1267 
1268    Output Parameter:
1269 .  A - the matrix
1270 
1271    Notes:
1272    The AIJ format (also called the Yale sparse matrix format or
1273    compressed row storage), is fully compatible with standard Fortran 77
1274    storage.  That is, the stored row and column indices can begin at
1275    either one (as in Fortran) or zero.  See the users manual for details.
1276 
1277    Specify the preallocated storage with either nz or nnz (not both).
1278    Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory
1279    allocation.  For additional details, see the users manual chapter on
1280    matrices and the file $(PETSC_DIR)/Performance.
1281 
1282    By default, this format uses inodes (identical nodes) when possible, to
1283    improve numerical efficiency of Matrix vector products and solves. We
1284    search for consecutive rows with the same nonzero structure, thereby
1285    reusing matrix information to achieve increased efficiency.
1286 
1287    Options Database Keys:
1288 $    -mat_aij_no_inode  - Do not use inodes
1289 $    -mat_aij_inode_limit <limit> - Set inode limit.
1290 $        (max limit=5)
1291 $    -mat_aij_oneindex - Internally use indexing starting at 1
1292 $        rather than 0.  Note: When calling MatSetValues(),
1293 $        the user still MUST index entries starting at 0!
1294 
1295 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues()
1296 @*/
1297 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A)
1298 {
1299   Mat        B;
1300   Mat_SeqAIJ *b;
1301   int        i,len,ierr, flg;
1302 
1303   *A      = 0;
1304   PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm);
1305   PLogObjectCreate(B);
1306   B->data             = (void *) (b = PetscNew(Mat_SeqAIJ)); CHKPTRQ(b);
1307   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
1308   B->destroy          = MatDestroy_SeqAIJ;
1309   B->view             = MatView_SeqAIJ;
1310   B->factor           = 0;
1311   B->lupivotthreshold = 1.0;
1312   ierr = OptionsGetDouble(PETSC_NULL,"-mat_lu_pivotthreshold",&B->lupivotthreshold,
1313                           &flg); CHKERRQ(ierr);
1314   b->ilu_preserve_row_sums = PETSC_FALSE;
1315   ierr = OptionsHasName(PETSC_NULL,"-pc_ilu_preserve_row_sums",
1316                         (int*) &b->ilu_preserve_row_sums); CHKERRQ(ierr);
1317   b->row              = 0;
1318   b->col              = 0;
1319   b->indexshift       = 0;
1320   b->reallocs         = 0;
1321   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_oneindex", &flg); CHKERRQ(ierr);
1322   if (flg) b->indexshift = -1;
1323 
1324   b->m       = m;
1325   b->n       = n;
1326   b->imax    = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(b->imax);
1327   if (nnz == PETSC_NULL) {
1328     if (nz == PETSC_DEFAULT) nz = 10;
1329     else if (nz <= 0)        nz = 1;
1330     for ( i=0; i<m; i++ ) b->imax[i] = nz;
1331     nz = nz*m;
1332   }
1333   else {
1334     nz = 0;
1335     for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];}
1336   }
1337 
1338   /* allocate the matrix space */
1339   len     = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int);
1340   b->a  = (Scalar *) PetscMalloc( len ); CHKPTRQ(b->a);
1341   b->j  = (int *) (b->a + nz);
1342   PetscMemzero(b->j,nz*sizeof(int));
1343   b->i  = b->j + nz;
1344   b->singlemalloc = 1;
1345 
1346   b->i[0] = -b->indexshift;
1347   for (i=1; i<m+1; i++) {
1348     b->i[i] = b->i[i-1] + b->imax[i-1];
1349   }
1350 
1351   /* b->ilen will count nonzeros in each row so far. */
1352   b->ilen = (int *) PetscMalloc((m+1)*sizeof(int));
1353   PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
1354   for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;}
1355 
1356   b->nz               = 0;
1357   b->maxnz            = nz;
1358   b->sorted           = 0;
1359   b->roworiented      = 1;
1360   b->nonew            = 0;
1361   b->diag             = 0;
1362   b->solve_work       = 0;
1363   b->spptr            = 0;
1364   b->inode.node_count = 0;
1365   b->inode.size       = 0;
1366   b->inode.limit      = 5;
1367   b->inode.max_limit  = 5;
1368 
1369   *A = B;
1370   /*  SuperLU is not currently supported through PETSc */
1371 #if defined(HAVE_SUPERLU)
1372   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_superlu", &flg); CHKERRQ(ierr);
1373   if (flg) { ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr); }
1374 #endif
1375   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_essl", &flg); CHKERRQ(ierr);
1376   if (flg) { ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr); }
1377   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_dxml", &flg); CHKERRQ(ierr);
1378   if (flg) {
1379     if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml");
1380     ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr);
1381   }
1382   ierr = OptionsHasName(PETSC_NULL,"-help", &flg); CHKERRQ(ierr);
1383   if (flg) {ierr = MatPrintHelp(B); CHKERRQ(ierr); }
1384   return 0;
1385 }
1386 
1387 int MatConvertSameType_SeqAIJ(Mat A,Mat *B,int cpvalues)
1388 {
1389   Mat        C;
1390   Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data;
1391   int        i,len, m = a->m,shift = a->indexshift;
1392 
1393   *B = 0;
1394   PetscHeaderCreate(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm);
1395   PLogObjectCreate(C);
1396   C->data       = (void *) (c = PetscNew(Mat_SeqAIJ)); CHKPTRQ(c);
1397   PetscMemcpy(&C->ops,&A->ops,sizeof(struct _MatOps));
1398   C->destroy    = MatDestroy_SeqAIJ;
1399   C->view       = MatView_SeqAIJ;
1400   C->factor     = A->factor;
1401   c->row        = 0;
1402   c->col        = 0;
1403   c->indexshift = shift;
1404   C->assembled  = PETSC_TRUE;
1405 
1406   c->m          = a->m;
1407   c->n          = a->n;
1408 
1409   c->imax       = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->imax);
1410   c->ilen       = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->ilen);
1411   for ( i=0; i<m; i++ ) {
1412     c->imax[i] = a->imax[i];
1413     c->ilen[i] = a->ilen[i];
1414   }
1415 
1416   /* allocate the matrix space */
1417   c->singlemalloc = 1;
1418   len     = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int));
1419   c->a  = (Scalar *) PetscMalloc( len ); CHKPTRQ(c->a);
1420   c->j  = (int *) (c->a + a->i[m] + shift);
1421   c->i  = c->j + a->i[m] + shift;
1422   PetscMemcpy(c->i,a->i,(m+1)*sizeof(int));
1423   if (m > 0) {
1424     PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int));
1425     if (cpvalues == COPY_VALUES) {
1426       PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar));
1427     }
1428   }
1429 
1430   PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
1431   c->sorted      = a->sorted;
1432   c->roworiented = a->roworiented;
1433   c->nonew       = a->nonew;
1434   c->ilu_preserve_row_sums = a->ilu_preserve_row_sums;
1435 
1436   if (a->diag) {
1437     c->diag = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(c->diag);
1438     PLogObjectMemory(C,(m+1)*sizeof(int));
1439     for ( i=0; i<m; i++ ) {
1440       c->diag[i] = a->diag[i];
1441     }
1442   }
1443   else c->diag          = 0;
1444   c->inode.limit        = a->inode.limit;
1445   c->inode.max_limit    = a->inode.max_limit;
1446   if (a->inode.size){
1447     c->inode.size       = (int *) PetscMalloc( m *sizeof(int) ); CHKPTRQ(c->inode.size);
1448     c->inode.node_count = a->inode.node_count;
1449     PetscMemcpy( c->inode.size, a->inode.size, m*sizeof(int));
1450   } else {
1451     c->inode.size       = 0;
1452     c->inode.node_count = 0;
1453   }
1454   c->nz                 = a->nz;
1455   c->maxnz              = a->maxnz;
1456   c->solve_work         = 0;
1457   c->spptr              = 0;      /* Dangerous -I'm throwing away a->spptr */
1458 
1459   *B = C;
1460   return 0;
1461 }
1462 
1463 int MatLoad_SeqAIJ(Viewer bview,MatType type,Mat *A)
1464 {
1465   Mat_SeqAIJ   *a;
1466   Mat          B;
1467   int          i, nz, ierr, fd, header[4],size,*rowlengths = 0,M,N,shift;
1468   PetscObject  vobj = (PetscObject) bview;
1469   MPI_Comm     comm = vobj->comm;
1470 
1471   MPI_Comm_size(comm,&size);
1472   if (size > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor");
1473   ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr);
1474   ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr);
1475   if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file");
1476   M = header[1]; N = header[2]; nz = header[3];
1477 
1478   /* read in row lengths */
1479   rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths);
1480   ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr);
1481 
1482   /* create our matrix */
1483   ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr);
1484   B = *A;
1485   a = (Mat_SeqAIJ *) B->data;
1486   shift = a->indexshift;
1487 
1488   /* read in column indices and adjust for Fortran indexing*/
1489   ierr = SYRead(fd,a->j,nz,SYINT); CHKERRQ(ierr);
1490   if (shift) {
1491     for ( i=0; i<nz; i++ ) {
1492       a->j[i] += 1;
1493     }
1494   }
1495 
1496   /* read in nonzero values */
1497   ierr = SYRead(fd,a->a,nz,SYSCALAR); CHKERRQ(ierr);
1498 
1499   /* set matrix "i" values */
1500   a->i[0] = -shift;
1501   for ( i=1; i<= M; i++ ) {
1502     a->i[i]      = a->i[i-1] + rowlengths[i-1];
1503     a->ilen[i-1] = rowlengths[i-1];
1504   }
1505   PetscFree(rowlengths);
1506 
1507   ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1508   ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1509   return 0;
1510 }
1511 
1512 
1513 
1514 /*
1515 
1516   flg =0 if error;
1517   flg =1 if both are equal;
1518   */
1519 int MatEqual_SeqAIJ(Mat A,Mat B, int* flg)
1520 {
1521   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data;
1522 
1523   if (B->type !=MATSEQAIJ)  SETERRQ(1,"MatEqual_SeqAIJ:Both matrices should be of type MATSEQAIJ");
1524 
1525   /* If the  matrix dimensions are not equal, or no of nonzeros or shift */
1526   if ((a->m != b->m ) || (a->n !=b->n) ||( a->nz != b->nz)||
1527       (a->indexshift != b->indexshift)) { *flg =0 ; return 0; }
1528 
1529   /* if the a->i are the same */
1530   if(PetscMemcmp((char *)a->i, (char*)b->i, (a->n+1)*sizeof(int))) { *flg =0 ; return 0;}
1531 
1532   /* if a->j are the same */
1533   if(PetscMemcmp((char *)a->j, (char*)b->j, (a->nz)*sizeof(int))) {
1534     *flg =0 ; return 0;
1535   }
1536 
1537   /* if a->j are the same */
1538   if(PetscMemcmp((char *)a->a, (char*)b->a, (a->nz)*sizeof(Scalar))) {
1539     *flg =0 ; return 0;
1540   }
1541   *flg =1 ;
1542   return 0;
1543 
1544 }
1545