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