xref: /petsc/src/mat/impls/aij/seq/aij.c (revision f63b844a08011cbceb00a6ecbb68fd67c9b34e11)
1 
2 #ifndef lint
3 static char vcid[] = "$Id: aij.c,v 1.161 1996/03/23 20:42:31 bsmith Exp balay $";
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 "sys.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 = ViewerBinaryGetDescriptor(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 = PetscBinaryWrite(fd,col_lens,4+a->m,BINARY_INT,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 = PetscBinaryWrite(fd,a->j,a->nz,BINARY_INT,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 = PetscBinaryWrite(fd,a->a,a->nz,BINARY_SCALAR,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 = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
249   ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr);
250   ierr = ViewerGetFormat(viewer,&format);
251   if (format == ASCII_FORMAT_INFO) {
252     return 0;
253   }
254   else if (format == ASCII_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 == ASCII_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(A,"MatAssemblyEnd_SeqAIJ:Unneeded storage space %d used %d rows %d\n",
475            fshift,a->nz,m);
476   PLogInfo(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(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 = ISGetSize(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   int          row,mat_i,*mat_j,tcol,first,step,*mat_ilen;
1024   register int sum,lensi;
1025   int          *irow, *icol, nrows, ncols, shift = a->indexshift,*ssmap;
1026   int          *starts,*j_new,*i_new,*aj = a->j, *ai = a->i,ii,*ailen = a->ilen;
1027   Scalar       *a_new,*mat_a;
1028   Mat          C;
1029 
1030   ierr = ISSorted(iscol,(PetscTruth*)&i);
1031   if (!i) SETERRQ(1,"MatGetSubmatrices_SeqAIJ:IS is not sorted");
1032 
1033   ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr);
1034   ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr);
1035   ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr);
1036 
1037   if (ISStrideGetInfo(iscol,&first,&step) && step == 1) { /* no need to sort */
1038     /* special case of contiguous rows */
1039     lens   = (int *) PetscMalloc((ncols+nrows+1)*sizeof(int)); CHKPTRQ(lens);
1040     starts = lens + ncols;
1041     /* loop over new rows determining lens and starting points */
1042     for (i=0; i<nrows; i++) {
1043       kstart  = ai[irow[i]]+shift;
1044       kend    = kstart + ailen[irow[i]];
1045       for ( k=kstart; k<kend; k++ ) {
1046         if (aj[k]+shift >= first) {
1047           starts[i] = k;
1048           break;
1049 	}
1050       }
1051       sum = 0;
1052       while (k < kend) {
1053         if (aj[k++]+shift >= first+ncols) break;
1054         sum++;
1055       }
1056       lens[i] = sum;
1057     }
1058     /* create submatrix */
1059     if (scall == MAT_REUSE_MATRIX) {
1060       int n_cols,n_rows;
1061       ierr = MatGetSize(*B,&n_rows,&n_cols); CHKERRQ(ierr);
1062       if (n_rows != nrows || n_cols != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:");
1063       ierr = MatZeroEntries(*B); CHKERRQ(ierr);
1064       C = *B;
1065     }
1066     else {
1067       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1068     }
1069     c = (Mat_SeqAIJ*) C->data;
1070 
1071     /* loop over rows inserting into submatrix */
1072     a_new    = c->a;
1073     j_new    = c->j;
1074     i_new    = c->i;
1075     i_new[0] = -shift;
1076     for (i=0; i<nrows; i++) {
1077       ii    = starts[i];
1078       lensi = lens[i];
1079       for ( k=0; k<lensi; k++ ) {
1080         *j_new++ = aj[ii+k] - first;
1081       }
1082       PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(Scalar));
1083       a_new      += lensi;
1084       i_new[i+1]  = i_new[i] + lensi;
1085       c->ilen[i]  = lensi;
1086     }
1087     PetscFree(lens);
1088   }
1089   else {
1090     ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr);
1091     smap  = (int *) PetscMalloc((1+oldcols)*sizeof(int)); CHKPTRQ(smap);
1092     ssmap = smap + shift;
1093     lens  = (int *) PetscMalloc((1+nrows)*sizeof(int)); CHKPTRQ(lens);
1094     PetscMemzero(smap,oldcols*sizeof(int));
1095     for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1;
1096     /* determine lens of each row */
1097     for (i=0; i<nrows; i++) {
1098       kstart  = ai[irow[i]]+shift;
1099       kend    = kstart + a->ilen[irow[i]];
1100       lens[i] = 0;
1101       for ( k=kstart; k<kend; k++ ) {
1102         if (ssmap[aj[k]]) {
1103           lens[i]++;
1104         }
1105       }
1106     }
1107     /* Create and fill new matrix */
1108     if (scall == MAT_REUSE_MATRIX) {
1109       c = (Mat_SeqAIJ *)((*B)->data);
1110 
1111       if (c->m  != nrows || c->n != ncols) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:");
1112       if (PetscMemcmp(c->ilen,lens, c->m *sizeof(int))) {
1113         SETERRQ(1,"MatGetSubmatrices_SeqAIJ:Cannot reuse matrix. wrong no of nonzeros");
1114       }
1115       PetscMemzero(c->ilen,c->m*sizeof(int));
1116       C = *B;
1117     }
1118     else {
1119       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1120     }
1121     c = (Mat_SeqAIJ *)(C->data);
1122     for (i=0; i<nrows; i++) {
1123       row    = irow[i];
1124       nznew  = 0;
1125       kstart = ai[row]+shift;
1126       kend   = kstart + a->ilen[row];
1127       mat_i  = c->i[i]+shift;
1128       mat_j  = c->j + mat_i;
1129       mat_a  = c->a + mat_i;
1130       mat_ilen = c->ilen + i;
1131       for ( k=kstart; k<kend; k++ ) {
1132         if ((tcol=ssmap[a->j[k]])) {
1133           *mat_j++ = tcol - (!shift);
1134           *mat_a++ = a->a[k];
1135           (*mat_ilen)++;
1136 
1137         }
1138       }
1139     }
1140     /* Free work space */
1141     ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr);
1142     PetscFree(smap); PetscFree(lens);
1143   }
1144   ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
1145   ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
1146 
1147   ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr);
1148   *B = C;
1149   return 0;
1150 }
1151 
1152 /*
1153      note: This can only work for identity for row and col. It would
1154    be good to check this and otherwise generate an error.
1155 */
1156 static int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,double efill,int fill)
1157 {
1158   Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data;
1159   int        ierr;
1160   Mat        outA;
1161 
1162   if (fill != 0) SETERRQ(1,"MatILUFactor_SeqAIJ:Only fill=0 supported");
1163 
1164   outA          = inA;
1165   inA->factor   = FACTOR_LU;
1166   a->row        = row;
1167   a->col        = col;
1168 
1169   a->solve_work = (Scalar *) PetscMalloc( (a->m+1)*sizeof(Scalar)); CHKPTRQ(a->solve_work);
1170 
1171   if (!a->diag) {
1172     ierr = MatMarkDiag_SeqAIJ(inA); CHKERRQ(ierr);
1173   }
1174   ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA); CHKERRQ(ierr);
1175   return 0;
1176 }
1177 
1178 #include "pinclude/plapack.h"
1179 static int MatScale_SeqAIJ(Scalar *alpha,Mat inA)
1180 {
1181   Mat_SeqAIJ *a = (Mat_SeqAIJ *) inA->data;
1182   int        one = 1;
1183   BLscal_( &a->nz, alpha, a->a, &one );
1184   PLogFlops(a->nz);
1185   return 0;
1186 }
1187 
1188 static int MatGetSubMatrices_SeqAIJ(Mat A,int n, IS *irow,IS *icol,MatGetSubMatrixCall scall,
1189                                     Mat **B)
1190 {
1191   int ierr,i;
1192 
1193   if (scall == MAT_INITIAL_MATRIX) {
1194     *B = (Mat *) PetscMalloc( (n+1)*sizeof(Mat) ); CHKPTRQ(*B);
1195   }
1196 
1197   for ( i=0; i<n; i++ ) {
1198     ierr = MatGetSubMatrix(A,irow[i],icol[i],scall,&(*B)[i]); CHKERRQ(ierr);
1199   }
1200   return 0;
1201 }
1202 
1203 static int MatIncreaseOverlap_SeqAIJ(Mat A, int is_max, IS *is, int ov)
1204 {
1205   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
1206   int        shift, row, i,j,k,l,m,n, *idx,ierr, *nidx, isz, val;
1207   int        start, end, *ai, *aj;
1208   char       *table;
1209   shift = a->indexshift;
1210   m     = a->m;
1211   ai    = a->i;
1212   aj    = a->j+shift;
1213 
1214   if (ov < 0)  SETERRQ(1,"MatIncreaseOverlap_SeqAIJ: illegal overlap value used");
1215 
1216   table = (char *) PetscMalloc((m/BITSPERBYTE +1)*sizeof(char)); CHKPTRQ(table);
1217   nidx  = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(nidx);
1218 
1219   for ( i=0; i<is_max; i++ ) {
1220     /* Initialise the two local arrays */
1221     isz  = 0;
1222     PetscMemzero(table,(m/BITSPERBYTE +1)*sizeof(char));
1223 
1224                 /* Extract the indices, assume there can be duplicate entries */
1225     ierr = ISGetIndices(is[i],&idx);  CHKERRQ(ierr);
1226     ierr = ISGetSize(is[i],&n);  CHKERRQ(ierr);
1227 
1228     /* Enter these into the temp arrays i.e mark table[row], enter row into new index */
1229     for ( j=0; j<n ; ++j){
1230       if(!BT_LOOKUP(table, idx[j])) { nidx[isz++] = idx[j];}
1231     }
1232     ierr = ISRestoreIndices(is[i],&idx);  CHKERRQ(ierr);
1233     ierr = ISDestroy(is[i]); CHKERRQ(ierr);
1234 
1235     k = 0;
1236     for ( j=0; j<ov; j++){ /* for each overlap*/
1237       n = isz;
1238       for ( ; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */
1239         row   = nidx[k];
1240         start = ai[row];
1241         end   = ai[row+1];
1242         for ( l = start; l<end ; l++){
1243           val = aj[l] + shift;
1244           if (!BT_LOOKUP(table,val)) {nidx[isz++] = val;}
1245         }
1246       }
1247     }
1248     ierr = ISCreateSeq(MPI_COMM_SELF, isz, nidx, (is+i)); CHKERRQ(ierr);
1249   }
1250   PetscFree(table);
1251   PetscFree(nidx);
1252   return 0;
1253 }
1254 
1255 int MatPrintHelp_SeqAIJ(Mat A)
1256 {
1257   static int called = 0;
1258   MPI_Comm   comm = A->comm;
1259 
1260   if (called) return 0; else called = 1;
1261   PetscPrintf(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n");
1262   PetscPrintf(comm,"  -mat_lu_pivotthreshold <threshold>\n");
1263   PetscPrintf(comm,"  -mat_aij_oneindex - internal indices begin at 1 instead of the default 0.\n");
1264   PetscPrintf(comm,"  -mat_aij_no_inode  - Do not use inodes\n");
1265   PetscPrintf(comm,"  -mat_aij_inode_limit <limit> - Set inode limit (max limit=5)\n");
1266 #if defined(HAVE_ESSL)
1267   PetscPrintf(comm,"  -mat_aij_essl  - Use IBM sparse LU factorization and solve.\n");
1268 #endif
1269   return 0;
1270 }
1271 int MatEqual_SeqAIJ(Mat A,Mat B, PetscTruth* flg);
1272 /* -------------------------------------------------------------------*/
1273 static struct _MatOps MatOps = {MatSetValues_SeqAIJ,
1274        MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ,
1275        MatMult_SeqAIJ,MatMultAdd_SeqAIJ,
1276        MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ,
1277        MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ,
1278        MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ,
1279        MatLUFactor_SeqAIJ,0,
1280        MatRelax_SeqAIJ,
1281        MatTranspose_SeqAIJ,
1282        MatGetInfo_SeqAIJ,MatEqual_SeqAIJ,
1283        MatGetDiagonal_SeqAIJ,MatDiagonalScale_SeqAIJ,MatNorm_SeqAIJ,
1284        0,MatAssemblyEnd_SeqAIJ,
1285        MatCompress_SeqAIJ,
1286        MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ,
1287        MatGetReordering_SeqAIJ,
1288        MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0,
1289        MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ,
1290        MatILUFactorSymbolic_SeqAIJ,0,
1291        0,0,MatConvert_SeqAIJ,
1292        MatGetSubMatrix_SeqAIJ,0,
1293        MatConvertSameType_SeqAIJ,0,0,
1294        MatILUFactor_SeqAIJ,0,0,
1295        MatGetSubMatrices_SeqAIJ,MatIncreaseOverlap_SeqAIJ,
1296        MatGetValues_SeqAIJ,0,
1297        MatPrintHelp_SeqAIJ,
1298        MatScale_SeqAIJ};
1299 
1300 extern int MatUseSuperLU_SeqAIJ(Mat);
1301 extern int MatUseEssl_SeqAIJ(Mat);
1302 extern int MatUseDXML_SeqAIJ(Mat);
1303 
1304 /*@C
1305    MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format
1306    (the default parallel PETSc format).  For good matrix assembly performance
1307    the user should preallocate the matrix storage by setting the parameter nz
1308    (or nzz).  By setting these parameters accurately, performance can be
1309    increased by more than a factor of 50.
1310 
1311    Input Parameters:
1312 .  comm - MPI communicator, set to MPI_COMM_SELF
1313 .  m - number of rows
1314 .  n - number of columns
1315 .  nz - number of nonzeros per row (same for all rows)
1316 .  nzz - number of nonzeros per row or null (possibly different for each row)
1317 
1318    Output Parameter:
1319 .  A - the matrix
1320 
1321    Notes:
1322    The AIJ format (also called the Yale sparse matrix format or
1323    compressed row storage), is fully compatible with standard Fortran 77
1324    storage.  That is, the stored row and column indices can begin at
1325    either one (as in Fortran) or zero.  See the users manual for details.
1326 
1327    Specify the preallocated storage with either nz or nnz (not both).
1328    Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory
1329    allocation.  For additional details, see the users manual chapter on
1330    matrices and the file $(PETSC_DIR)/Performance.
1331 
1332    By default, this format uses inodes (identical nodes) when possible, to
1333    improve numerical efficiency of Matrix vector products and solves. We
1334    search for consecutive rows with the same nonzero structure, thereby
1335    reusing matrix information to achieve increased efficiency.
1336 
1337    Options Database Keys:
1338 $    -mat_aij_no_inode  - Do not use inodes
1339 $    -mat_aij_inode_limit <limit> - Set inode limit.
1340 $        (max limit=5)
1341 $    -mat_aij_oneindex - Internally use indexing starting at 1
1342 $        rather than 0.  Note: When calling MatSetValues(),
1343 $        the user still MUST index entries starting at 0!
1344 
1345 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues()
1346 @*/
1347 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A)
1348 {
1349   Mat        B;
1350   Mat_SeqAIJ *b;
1351   int        i,len,ierr, flg;
1352 
1353   *A      = 0;
1354   PetscHeaderCreate(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm);
1355   PLogObjectCreate(B);
1356   B->data             = (void *) (b = PetscNew(Mat_SeqAIJ)); CHKPTRQ(b);
1357   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
1358   B->destroy          = MatDestroy_SeqAIJ;
1359   B->view             = MatView_SeqAIJ;
1360   B->factor           = 0;
1361   B->lupivotthreshold = 1.0;
1362   ierr = OptionsGetDouble(PETSC_NULL,"-mat_lu_pivotthreshold",&B->lupivotthreshold,
1363                           &flg); CHKERRQ(ierr);
1364   b->ilu_preserve_row_sums = PETSC_FALSE;
1365   ierr = OptionsHasName(PETSC_NULL,"-pc_ilu_preserve_row_sums",
1366                         (int*) &b->ilu_preserve_row_sums); CHKERRQ(ierr);
1367   b->row              = 0;
1368   b->col              = 0;
1369   b->indexshift       = 0;
1370   b->reallocs         = 0;
1371   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_oneindex", &flg); CHKERRQ(ierr);
1372   if (flg) b->indexshift = -1;
1373 
1374   b->m       = m;
1375   b->n       = n;
1376   b->imax    = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(b->imax);
1377   if (nnz == PETSC_NULL) {
1378     if (nz == PETSC_DEFAULT) nz = 10;
1379     else if (nz <= 0)        nz = 1;
1380     for ( i=0; i<m; i++ ) b->imax[i] = nz;
1381     nz = nz*m;
1382   }
1383   else {
1384     nz = 0;
1385     for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];}
1386   }
1387 
1388   /* allocate the matrix space */
1389   len     = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int);
1390   b->a  = (Scalar *) PetscMalloc( len ); CHKPTRQ(b->a);
1391   b->j  = (int *) (b->a + nz);
1392   PetscMemzero(b->j,nz*sizeof(int));
1393   b->i  = b->j + nz;
1394   b->singlemalloc = 1;
1395 
1396   b->i[0] = -b->indexshift;
1397   for (i=1; i<m+1; i++) {
1398     b->i[i] = b->i[i-1] + b->imax[i-1];
1399   }
1400 
1401   /* b->ilen will count nonzeros in each row so far. */
1402   b->ilen = (int *) PetscMalloc((m+1)*sizeof(int));
1403   PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
1404   for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;}
1405 
1406   b->nz               = 0;
1407   b->maxnz            = nz;
1408   b->sorted           = 0;
1409   b->roworiented      = 1;
1410   b->nonew            = 0;
1411   b->diag             = 0;
1412   b->solve_work       = 0;
1413   b->spptr            = 0;
1414   b->inode.node_count = 0;
1415   b->inode.size       = 0;
1416   b->inode.limit      = 5;
1417   b->inode.max_limit  = 5;
1418 
1419   *A = B;
1420   /*  SuperLU is not currently supported through PETSc */
1421 #if defined(HAVE_SUPERLU)
1422   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_superlu", &flg); CHKERRQ(ierr);
1423   if (flg) { ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr); }
1424 #endif
1425   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_essl", &flg); CHKERRQ(ierr);
1426   if (flg) { ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr); }
1427   ierr = OptionsHasName(PETSC_NULL,"-mat_aij_dxml", &flg); CHKERRQ(ierr);
1428   if (flg) {
1429     if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml");
1430     ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr);
1431   }
1432   ierr = OptionsHasName(PETSC_NULL,"-help", &flg); CHKERRQ(ierr);
1433   if (flg) {ierr = MatPrintHelp(B); CHKERRQ(ierr); }
1434   return 0;
1435 }
1436 
1437 int MatConvertSameType_SeqAIJ(Mat A,Mat *B,int cpvalues)
1438 {
1439   Mat        C;
1440   Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data;
1441   int        i,len, m = a->m,shift = a->indexshift;
1442 
1443   *B = 0;
1444   PetscHeaderCreate(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm);
1445   PLogObjectCreate(C);
1446   C->data       = (void *) (c = PetscNew(Mat_SeqAIJ)); CHKPTRQ(c);
1447   PetscMemcpy(&C->ops,&A->ops,sizeof(struct _MatOps));
1448   C->destroy    = MatDestroy_SeqAIJ;
1449   C->view       = MatView_SeqAIJ;
1450   C->factor     = A->factor;
1451   c->row        = 0;
1452   c->col        = 0;
1453   c->indexshift = shift;
1454   C->assembled  = PETSC_TRUE;
1455 
1456   c->m          = a->m;
1457   c->n          = a->n;
1458 
1459   c->imax       = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->imax);
1460   c->ilen       = (int *) PetscMalloc((m+1)*sizeof(int)); CHKPTRQ(c->ilen);
1461   for ( i=0; i<m; i++ ) {
1462     c->imax[i] = a->imax[i];
1463     c->ilen[i] = a->ilen[i];
1464   }
1465 
1466   /* allocate the matrix space */
1467   c->singlemalloc = 1;
1468   len     = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int));
1469   c->a  = (Scalar *) PetscMalloc( len ); CHKPTRQ(c->a);
1470   c->j  = (int *) (c->a + a->i[m] + shift);
1471   c->i  = c->j + a->i[m] + shift;
1472   PetscMemcpy(c->i,a->i,(m+1)*sizeof(int));
1473   if (m > 0) {
1474     PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int));
1475     if (cpvalues == COPY_VALUES) {
1476       PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar));
1477     }
1478   }
1479 
1480   PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
1481   c->sorted      = a->sorted;
1482   c->roworiented = a->roworiented;
1483   c->nonew       = a->nonew;
1484   c->ilu_preserve_row_sums = a->ilu_preserve_row_sums;
1485 
1486   if (a->diag) {
1487     c->diag = (int *) PetscMalloc( (m+1)*sizeof(int) ); CHKPTRQ(c->diag);
1488     PLogObjectMemory(C,(m+1)*sizeof(int));
1489     for ( i=0; i<m; i++ ) {
1490       c->diag[i] = a->diag[i];
1491     }
1492   }
1493   else c->diag          = 0;
1494   c->inode.limit        = a->inode.limit;
1495   c->inode.max_limit    = a->inode.max_limit;
1496   if (a->inode.size){
1497     c->inode.size       = (int *) PetscMalloc( m *sizeof(int) ); CHKPTRQ(c->inode.size);
1498     c->inode.node_count = a->inode.node_count;
1499     PetscMemcpy( c->inode.size, a->inode.size, m*sizeof(int));
1500   } else {
1501     c->inode.size       = 0;
1502     c->inode.node_count = 0;
1503   }
1504   c->nz                 = a->nz;
1505   c->maxnz              = a->maxnz;
1506   c->solve_work         = 0;
1507   c->spptr              = 0;      /* Dangerous -I'm throwing away a->spptr */
1508 
1509   *B = C;
1510   return 0;
1511 }
1512 
1513 int MatLoad_SeqAIJ(Viewer viewer,MatType type,Mat *A)
1514 {
1515   Mat_SeqAIJ   *a;
1516   Mat          B;
1517   int          i, nz, ierr, fd, header[4],size,*rowlengths = 0,M,N,shift;
1518   MPI_Comm     comm;
1519 
1520   PetscObjectGetComm((PetscObject) viewer,&comm);
1521   MPI_Comm_size(comm,&size);
1522   if (size > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor");
1523   ierr = ViewerBinaryGetDescriptor(viewer,&fd); CHKERRQ(ierr);
1524   ierr = PetscBinaryRead(fd,header,4,BINARY_INT); CHKERRQ(ierr);
1525   if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file");
1526   M = header[1]; N = header[2]; nz = header[3];
1527 
1528   /* read in row lengths */
1529   rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths);
1530   ierr = PetscBinaryRead(fd,rowlengths,M,BINARY_INT); CHKERRQ(ierr);
1531 
1532   /* create our matrix */
1533   ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr);
1534   B = *A;
1535   a = (Mat_SeqAIJ *) B->data;
1536   shift = a->indexshift;
1537 
1538   /* read in column indices and adjust for Fortran indexing*/
1539   ierr = PetscBinaryRead(fd,a->j,nz,BINARY_INT); CHKERRQ(ierr);
1540   if (shift) {
1541     for ( i=0; i<nz; i++ ) {
1542       a->j[i] += 1;
1543     }
1544   }
1545 
1546   /* read in nonzero values */
1547   ierr = PetscBinaryRead(fd,a->a,nz,BINARY_SCALAR); CHKERRQ(ierr);
1548 
1549   /* set matrix "i" values */
1550   a->i[0] = -shift;
1551   for ( i=1; i<= M; i++ ) {
1552     a->i[i]      = a->i[i-1] + rowlengths[i-1];
1553     a->ilen[i-1] = rowlengths[i-1];
1554   }
1555   PetscFree(rowlengths);
1556 
1557   ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1558   ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1559   return 0;
1560 }
1561 
1562 static int MatEqual_SeqAIJ(Mat A,Mat B, PetscTruth* flg)
1563 {
1564   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data, *b = (Mat_SeqAIJ *)B->data;
1565 
1566   if (B->type !=MATSEQAIJ)SETERRQ(1,"MatEqual_SeqAIJ:Matrices must be same type");
1567 
1568   /* If the  matrix dimensions are not equal, or no of nonzeros or shift */
1569   if ((a->m != b->m ) || (a->n !=b->n) ||( a->nz != b->nz)||
1570       (a->indexshift != b->indexshift)) {
1571     *flg = PETSC_FALSE; return 0;
1572   }
1573 
1574   /* if the a->i are the same */
1575   if (PetscMemcmp(a->i,b->i, (a->n+1)*sizeof(int))) {
1576     *flg = PETSC_FALSE; return 0;
1577   }
1578 
1579   /* if a->j are the same */
1580   if (PetscMemcmp(a->j, b->j, (a->nz)*sizeof(int))) {
1581     *flg = PETSC_FALSE; return 0;
1582   }
1583 
1584   /* if a->a are the same */
1585   if (PetscMemcmp(a->a, b->a, (a->nz)*sizeof(Scalar))) {
1586     *flg = PETSC_FALSE; return 0;
1587   }
1588   *flg = PETSC_TRUE;
1589   return 0;
1590 
1591 }
1592