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