xref: /petsc/src/mat/impls/aij/seq/aij.c (revision 2a9937bb311a378a87a0018d0cfd8fa6df4c06bc)
1 /*$Id: aij.c,v 1.385 2001/09/07 20:09:22 bsmith Exp $*/
2 /*
3     Defines the basic matrix operations for the AIJ (compressed row)
4   matrix storage format.
5 */
6 
7 #include "src/mat/impls/aij/seq/aij.h"          /*I "petscmat.h" I*/
8 #include "src/vec/vecimpl.h"
9 #include "src/inline/spops.h"
10 #include "src/inline/dot.h"
11 #include "petscbt.h"
12 
13 
14 EXTERN int MatToSymmetricIJ_SeqAIJ(int,int*,int*,int,int,int**,int**);
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "MatGetRowIJ_SeqAIJ"
18 int MatGetRowIJ_SeqAIJ(Mat A,int oshift,PetscTruth symmetric,int *m,int **ia,int **ja,PetscTruth *done)
19 {
20   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
21   int        ierr,i,ishift;
22 
23   PetscFunctionBegin;
24   *m     = A->m;
25   if (!ia) PetscFunctionReturn(0);
26   ishift = a->indexshift;
27   if (symmetric && !A->structurally_symmetric) {
28     ierr = MatToSymmetricIJ_SeqAIJ(A->m,a->i,a->j,ishift,oshift,ia,ja);CHKERRQ(ierr);
29   } else if (oshift == 0 && ishift == -1) {
30     int nz = a->i[A->m] - 1;
31     /* malloc space and  subtract 1 from i and j indices */
32     ierr = PetscMalloc((A->m+1)*sizeof(int),ia);CHKERRQ(ierr);
33     ierr = PetscMalloc((nz+1)*sizeof(int),ja);CHKERRQ(ierr);
34     for (i=0; i<nz; i++) (*ja)[i] = a->j[i] - 1;
35     for (i=0; i<A->m+1; i++) (*ia)[i] = a->i[i] - 1;
36   } else if (oshift == 1 && ishift == 0) {
37     int nz = a->i[A->m];
38     /* malloc space and  add 1 to i and j indices */
39     ierr = PetscMalloc((A->m+1)*sizeof(int),ia);CHKERRQ(ierr);
40     ierr = PetscMalloc((nz+1)*sizeof(int),ja);CHKERRQ(ierr);
41     for (i=0; i<nz; i++) (*ja)[i] = a->j[i] + 1;
42     for (i=0; i<A->m+1; i++) (*ia)[i] = a->i[i] + 1;
43   } else {
44     *ia = a->i; *ja = a->j;
45   }
46   PetscFunctionReturn(0);
47 }
48 
49 #undef __FUNCT__
50 #define __FUNCT__ "MatRestoreRowIJ_SeqAIJ"
51 int MatRestoreRowIJ_SeqAIJ(Mat A,int oshift,PetscTruth symmetric,int *n,int **ia,int **ja,PetscTruth *done)
52 {
53   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
54   int        ishift = a->indexshift,ierr;
55 
56   PetscFunctionBegin;
57   if (!ia) PetscFunctionReturn(0);
58   if ((symmetric && !A->structurally_symmetric) || (oshift == 0 && ishift == -1) || (oshift == 1 && ishift == 0)) {
59     ierr = PetscFree(*ia);CHKERRQ(ierr);
60     ierr = PetscFree(*ja);CHKERRQ(ierr);
61   }
62   PetscFunctionReturn(0);
63 }
64 
65 #undef __FUNCT__
66 #define __FUNCT__ "MatGetColumnIJ_SeqAIJ"
67 int MatGetColumnIJ_SeqAIJ(Mat A,int oshift,PetscTruth symmetric,int *nn,int **ia,int **ja,PetscTruth *done)
68 {
69   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
70   int        ierr,i,ishift = a->indexshift,*collengths,*cia,*cja,n = A->n,m = A->m;
71   int        nz = a->i[m]+ishift,row,*jj,mr,col;
72 
73   PetscFunctionBegin;
74   *nn     = A->n;
75   if (!ia) PetscFunctionReturn(0);
76   if (symmetric) {
77     ierr = MatToSymmetricIJ_SeqAIJ(A->m,a->i,a->j,ishift,oshift,ia,ja);CHKERRQ(ierr);
78   } else {
79     ierr = PetscMalloc((n+1)*sizeof(int),&collengths);CHKERRQ(ierr);
80     ierr = PetscMemzero(collengths,n*sizeof(int));CHKERRQ(ierr);
81     ierr = PetscMalloc((n+1)*sizeof(int),&cia);CHKERRQ(ierr);
82     ierr = PetscMalloc((nz+1)*sizeof(int),&cja);CHKERRQ(ierr);
83     jj = a->j;
84     for (i=0; i<nz; i++) {
85       collengths[jj[i] + ishift]++;
86     }
87     cia[0] = oshift;
88     for (i=0; i<n; i++) {
89       cia[i+1] = cia[i] + collengths[i];
90     }
91     ierr = PetscMemzero(collengths,n*sizeof(int));CHKERRQ(ierr);
92     jj   = a->j;
93     for (row=0; row<m; row++) {
94       mr = a->i[row+1] - a->i[row];
95       for (i=0; i<mr; i++) {
96         col = *jj++ + ishift;
97         cja[cia[col] + collengths[col]++ - oshift] = row + oshift;
98       }
99     }
100     ierr = PetscFree(collengths);CHKERRQ(ierr);
101     *ia = cia; *ja = cja;
102   }
103   PetscFunctionReturn(0);
104 }
105 
106 #undef __FUNCT__
107 #define __FUNCT__ "MatRestoreColumnIJ_SeqAIJ"
108 int MatRestoreColumnIJ_SeqAIJ(Mat A,int oshift,PetscTruth symmetric,int *n,int **ia,int **ja,PetscTruth *done)
109 {
110   int ierr;
111 
112   PetscFunctionBegin;
113   if (!ia) PetscFunctionReturn(0);
114 
115   ierr = PetscFree(*ia);CHKERRQ(ierr);
116   ierr = PetscFree(*ja);CHKERRQ(ierr);
117 
118   PetscFunctionReturn(0);
119 }
120 
121 #define CHUNKSIZE   15
122 
123 #undef __FUNCT__
124 #define __FUNCT__ "MatSetValues_SeqAIJ"
125 int MatSetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,PetscScalar *v,InsertMode is)
126 {
127   Mat_SeqAIJ  *a = (Mat_SeqAIJ*)A->data;
128   int         *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax,N,sorted = a->sorted;
129   int         *imax = a->imax,*ai = a->i,*ailen = a->ilen;
130   int         *aj = a->j,nonew = a->nonew,shift = a->indexshift,ierr;
131   PetscScalar *ap,value,*aa = a->a;
132   PetscTruth  ignorezeroentries = ((a->ignorezeroentries && is == ADD_VALUES) ? PETSC_TRUE:PETSC_FALSE);
133   PetscTruth  roworiented = a->roworiented;
134 
135   PetscFunctionBegin;
136   for (k=0; k<m; k++) { /* loop over added rows */
137     row  = im[k];
138     if (row < 0) continue;
139 #if defined(PETSC_USE_BOPT_g)
140     if (row >= A->m) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %d max %d",row,A->m);
141 #endif
142     rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
143     rmax = imax[row]; nrow = ailen[row];
144     low = 0;
145     for (l=0; l<n; l++) { /* loop over added columns */
146       if (in[l] < 0) continue;
147 #if defined(PETSC_USE_BOPT_g)
148       if (in[l] >= A->n) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Column too large: col %d max %d",in[l],A->n);
149 #endif
150       col = in[l] - shift;
151       if (roworiented) {
152         value = v[l + k*n];
153       } else {
154         value = v[k + l*m];
155       }
156       if (value == 0.0 && ignorezeroentries) continue;
157 
158       if (!sorted) low = 0; high = nrow;
159       while (high-low > 5) {
160         t = (low+high)/2;
161         if (rp[t] > col) high = t;
162         else             low  = t;
163       }
164       for (i=low; i<high; i++) {
165         if (rp[i] > col) break;
166         if (rp[i] == col) {
167           if (is == ADD_VALUES) ap[i] += value;
168           else                  ap[i] = value;
169           goto noinsert;
170         }
171       }
172       if (nonew == 1) goto noinsert;
173       else if (nonew == -1) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Inserting a new nonzero at (%d,%d) in the matrix",row,col);
174       if (nrow >= rmax) {
175         /* there is no extra room in row, therefore enlarge */
176         int         new_nz = ai[A->m] + CHUNKSIZE,*new_i,*new_j;
177         size_t      len;
178         PetscScalar *new_a;
179 
180         if (nonew == -2) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Inserting a new nonzero at (%d,%d) in the matrix requiring new malloc()",row,col);
181 
182         /* malloc new storage space */
183         len     = ((size_t) new_nz)*(sizeof(int)+sizeof(PetscScalar))+(A->m+1)*sizeof(int);
184 	ierr    = PetscMalloc(len,&new_a);CHKERRQ(ierr);
185         new_j   = (int*)(new_a + new_nz);
186         new_i   = new_j + new_nz;
187 
188         /* copy over old data into new slots */
189         for (ii=0; ii<row+1; ii++) {new_i[ii] = ai[ii];}
190         for (ii=row+1; ii<A->m+1; ii++) {new_i[ii] = ai[ii]+CHUNKSIZE;}
191         ierr = PetscMemcpy(new_j,aj,(ai[row]+nrow+shift)*sizeof(int));CHKERRQ(ierr);
192         len  = (((size_t) new_nz) - CHUNKSIZE - ai[row] - nrow - shift);
193         ierr = PetscMemcpy(new_j+ai[row]+shift+nrow+CHUNKSIZE,aj+ai[row]+shift+nrow,len*sizeof(int));CHKERRQ(ierr);
194         ierr = PetscMemcpy(new_a,aa,(((size_t) ai[row])+nrow+shift)*sizeof(PetscScalar));CHKERRQ(ierr);
195         ierr = PetscMemcpy(new_a+ai[row]+shift+nrow+CHUNKSIZE,aa+ai[row]+shift+nrow,len*sizeof(PetscScalar));CHKERRQ(ierr);
196         /* free up old matrix storage */
197         ierr = PetscFree(a->a);CHKERRQ(ierr);
198         if (!a->singlemalloc) {
199           ierr = PetscFree(a->i);CHKERRQ(ierr);
200           ierr = PetscFree(a->j);CHKERRQ(ierr);
201         }
202         aa = a->a = new_a; ai = a->i = new_i; aj = a->j = new_j;
203         a->singlemalloc = PETSC_TRUE;
204 
205         rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
206         rmax = imax[row] = imax[row] + CHUNKSIZE;
207         PetscLogObjectMemory(A,CHUNKSIZE*(sizeof(int) + sizeof(PetscScalar)));
208         a->maxnz += CHUNKSIZE;
209         a->reallocs++;
210       }
211       N = nrow++ - 1; a->nz++;
212       /* shift up all the later entries in this row */
213       for (ii=N; ii>=i; ii--) {
214         rp[ii+1] = rp[ii];
215         ap[ii+1] = ap[ii];
216       }
217       rp[i] = col;
218       ap[i] = value;
219       noinsert:;
220       low = i + 1;
221     }
222     ailen[row] = nrow;
223   }
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "MatGetValues_SeqAIJ"
229 int MatGetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,PetscScalar *v)
230 {
231   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
232   int          *rp,k,low,high,t,row,nrow,i,col,l,*aj = a->j;
233   int          *ai = a->i,*ailen = a->ilen,shift = a->indexshift;
234   PetscScalar  *ap,*aa = a->a,zero = 0.0;
235 
236   PetscFunctionBegin;
237   for (k=0; k<m; k++) { /* loop over rows */
238     row  = im[k];
239     if (row < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative row: %d",row);
240     if (row >= A->m) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Row too large: %d",row);
241     rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
242     nrow = ailen[row];
243     for (l=0; l<n; l++) { /* loop over columns */
244       if (in[l] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative column: %d",in[l]);
245       if (in[l] >= A->n) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Column too large: %d",in[l]);
246       col = in[l] - shift;
247       high = nrow; low = 0; /* assume unsorted */
248       while (high-low > 5) {
249         t = (low+high)/2;
250         if (rp[t] > col) high = t;
251         else             low  = t;
252       }
253       for (i=low; i<high; i++) {
254         if (rp[i] > col) break;
255         if (rp[i] == col) {
256           *v++ = ap[i];
257           goto finished;
258         }
259       }
260       *v++ = zero;
261       finished:;
262     }
263   }
264   PetscFunctionReturn(0);
265 }
266 
267 
268 #undef __FUNCT__
269 #define __FUNCT__ "MatView_SeqAIJ_Binary"
270 int MatView_SeqAIJ_Binary(Mat A,PetscViewer viewer)
271 {
272   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
273   int        i,fd,*col_lens,ierr;
274 
275   PetscFunctionBegin;
276   ierr = PetscViewerBinaryGetDescriptor(viewer,&fd);CHKERRQ(ierr);
277   ierr = PetscMalloc((4+A->m)*sizeof(int),&col_lens);CHKERRQ(ierr);
278   col_lens[0] = MAT_FILE_COOKIE;
279   col_lens[1] = A->m;
280   col_lens[2] = A->n;
281   col_lens[3] = a->nz;
282 
283   /* store lengths of each row and write (including header) to file */
284   for (i=0; i<A->m; i++) {
285     col_lens[4+i] = a->i[i+1] - a->i[i];
286   }
287   ierr = PetscBinaryWrite(fd,col_lens,4+A->m,PETSC_INT,1);CHKERRQ(ierr);
288   ierr = PetscFree(col_lens);CHKERRQ(ierr);
289 
290   /* store column indices (zero start index) */
291   if (a->indexshift) {
292     for (i=0; i<a->nz; i++) a->j[i]--;
293   }
294   ierr = PetscBinaryWrite(fd,a->j,a->nz,PETSC_INT,0);CHKERRQ(ierr);
295   if (a->indexshift) {
296     for (i=0; i<a->nz; i++) a->j[i]++;
297   }
298 
299   /* store nonzero values */
300   ierr = PetscBinaryWrite(fd,a->a,a->nz,PETSC_SCALAR,0);CHKERRQ(ierr);
301   PetscFunctionReturn(0);
302 }
303 
304 extern int MatSeqAIJFactorInfo_SuperLU(Mat,PetscViewer);
305 extern int MatMPIAIJFactorInfo_SuperLu(Mat,PetscViewer);
306 extern int MatFactorInfo_Spooles(Mat,PetscViewer);
307 extern int MatSeqAIJFactorInfo_UMFPACK(Mat,PetscViewer);
308 
309 #undef __FUNCT__
310 #define __FUNCT__ "MatView_SeqAIJ_ASCII"
311 int MatView_SeqAIJ_ASCII(Mat A,PetscViewer viewer)
312 {
313   Mat_SeqAIJ        *a = (Mat_SeqAIJ*)A->data;
314   int               ierr,i,j,m = A->m,shift = a->indexshift;
315   char              *name;
316   PetscViewerFormat format;
317 
318   PetscFunctionBegin;
319   ierr = PetscObjectGetName((PetscObject)A,&name);CHKERRQ(ierr);
320   ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
321   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_INFO) {
322     if (a->inode.size) {
323       ierr = PetscViewerASCIIPrintf(viewer,"using I-node routines: found %d nodes, limit used is %d\n",a->inode.node_count,a->inode.limit);CHKERRQ(ierr);
324     } else {
325       ierr = PetscViewerASCIIPrintf(viewer,"not using I-node routines\n");CHKERRQ(ierr);
326     }
327   } else if (format == PETSC_VIEWER_ASCII_MATLAB) {
328     int nofinalvalue = 0;
329     if ((a->i[m] == a->i[m-1]) || (a->j[a->nz-1] != A->n-!shift)) {
330       nofinalvalue = 1;
331     }
332     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr);
333     ierr = PetscViewerASCIIPrintf(viewer,"%% Size = %d %d \n",m,A->n);CHKERRQ(ierr);
334     ierr = PetscViewerASCIIPrintf(viewer,"%% Nonzeros = %d \n",a->nz);CHKERRQ(ierr);
335     ierr = PetscViewerASCIIPrintf(viewer,"zzz = zeros(%d,3);\n",a->nz+nofinalvalue);CHKERRQ(ierr);
336     ierr = PetscViewerASCIIPrintf(viewer,"zzz = [\n");CHKERRQ(ierr);
337 
338     for (i=0; i<m; i++) {
339       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
340 #if defined(PETSC_USE_COMPLEX)
341         ierr = PetscViewerASCIIPrintf(viewer,"%d %d  %18.16e + %18.16ei \n",i+1,a->j[j]+!shift,PetscRealPart(a->a[j]),PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
342 #else
343         ierr = PetscViewerASCIIPrintf(viewer,"%d %d  %18.16e\n",i+1,a->j[j]+!shift,a->a[j]);CHKERRQ(ierr);
344 #endif
345       }
346     }
347     if (nofinalvalue) {
348       ierr = PetscViewerASCIIPrintf(viewer,"%d %d  %18.16e\n",m,A->n,0.0);CHKERRQ(ierr);
349     }
350     ierr = PetscViewerASCIIPrintf(viewer,"];\n %s = spconvert(zzz);\n",name);CHKERRQ(ierr);
351     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr);
352   } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
353 #if defined(PETSC_HAVE_SUPERLU) && !defined(PETSC_USE_SINGLE) && !defined(PETSC_USE_COMPLEX)
354      ierr = MatSeqAIJFactorInfo_SuperLU(A,viewer);CHKERRQ(ierr);
355 #endif
356 #if defined(PETSC_HAVE_SUPERLUDIST) && !defined(PETSC_USE_SINGLE) && !defined(PETSC_USE_COMPLEX)
357      ierr = MatMPIAIJFactorInfo_SuperLu(A,viewer);CHKERRQ(ierr);
358 #endif
359 #if defined(PETSC_HAVE_SPOOLES) && !defined(PETSC_USE_SINGLE) && !defined(PETSC_USE_COMPLEX)
360      ierr = MatFactorInfo_Spooles(A,viewer);CHKERRQ(ierr);
361 #endif
362 #if defined(PETSC_HAVE_UMFPACK) && !defined(PETSC_USE_SINGLE) && !defined(PETSC_USE_COMPLEX)
363      ierr = MatSeqAIJFactorInfo_UMFPACK(A,viewer);CHKERRQ(ierr);
364 #endif
365      PetscFunctionReturn(0);
366   } else if (format == PETSC_VIEWER_ASCII_COMMON) {
367     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr);
368     for (i=0; i<m; i++) {
369       ierr = PetscViewerASCIIPrintf(viewer,"row %d:",i);CHKERRQ(ierr);
370       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
371 #if defined(PETSC_USE_COMPLEX)
372         if (PetscImaginaryPart(a->a[j]) > 0.0 && PetscRealPart(a->a[j]) != 0.0) {
373           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g + %g i)",a->j[j]+shift,PetscRealPart(a->a[j]),PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
374         } else if (PetscImaginaryPart(a->a[j]) < 0.0 && PetscRealPart(a->a[j]) != 0.0) {
375           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g - %g i)",a->j[j]+shift,PetscRealPart(a->a[j]),-PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
376         } else if (PetscRealPart(a->a[j]) != 0.0) {
377           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g) ",a->j[j]+shift,PetscRealPart(a->a[j]));CHKERRQ(ierr);
378         }
379 #else
380         if (a->a[j] != 0.0) {ierr = PetscViewerASCIIPrintf(viewer," (%d, %g) ",a->j[j]+shift,a->a[j]);CHKERRQ(ierr);}
381 #endif
382       }
383       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
384     }
385     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr);
386   } else if (format == PETSC_VIEWER_ASCII_SYMMODU) {
387     int nzd=0,fshift=1,*sptr;
388     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr);
389     ierr = PetscMalloc((m+1)*sizeof(int),&sptr);CHKERRQ(ierr);
390     for (i=0; i<m; i++) {
391       sptr[i] = nzd+1;
392       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
393         if (a->j[j] >= i) {
394 #if defined(PETSC_USE_COMPLEX)
395           if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) nzd++;
396 #else
397           if (a->a[j] != 0.0) nzd++;
398 #endif
399         }
400       }
401     }
402     sptr[m] = nzd+1;
403     ierr = PetscViewerASCIIPrintf(viewer," %d %d\n\n",m,nzd);CHKERRQ(ierr);
404     for (i=0; i<m+1; i+=6) {
405       if (i+4<m) {ierr = PetscViewerASCIIPrintf(viewer," %d %d %d %d %d %d\n",sptr[i],sptr[i+1],sptr[i+2],sptr[i+3],sptr[i+4],sptr[i+5]);CHKERRQ(ierr);}
406       else if (i+3<m) {ierr = PetscViewerASCIIPrintf(viewer," %d %d %d %d %d\n",sptr[i],sptr[i+1],sptr[i+2],sptr[i+3],sptr[i+4]);CHKERRQ(ierr);}
407       else if (i+2<m) {ierr = PetscViewerASCIIPrintf(viewer," %d %d %d %d\n",sptr[i],sptr[i+1],sptr[i+2],sptr[i+3]);CHKERRQ(ierr);}
408       else if (i+1<m) {ierr = PetscViewerASCIIPrintf(viewer," %d %d %d\n",sptr[i],sptr[i+1],sptr[i+2]);CHKERRQ(ierr);}
409       else if (i<m)   {ierr = PetscViewerASCIIPrintf(viewer," %d %d\n",sptr[i],sptr[i+1]);CHKERRQ(ierr);}
410       else            {ierr = PetscViewerASCIIPrintf(viewer," %d\n",sptr[i]);CHKERRQ(ierr);}
411     }
412     ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
413     ierr = PetscFree(sptr);CHKERRQ(ierr);
414     for (i=0; i<m; i++) {
415       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
416         if (a->j[j] >= i) {ierr = PetscViewerASCIIPrintf(viewer," %d ",a->j[j]+fshift);CHKERRQ(ierr);}
417       }
418       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
419     }
420     ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
421     for (i=0; i<m; i++) {
422       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
423         if (a->j[j] >= i) {
424 #if defined(PETSC_USE_COMPLEX)
425           if (PetscImaginaryPart(a->a[j]) != 0.0 || PetscRealPart(a->a[j]) != 0.0) {
426             ierr = PetscViewerASCIIPrintf(viewer," %18.16e %18.16e ",PetscRealPart(a->a[j]),PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
427           }
428 #else
429           if (a->a[j] != 0.0) {ierr = PetscViewerASCIIPrintf(viewer," %18.16e ",a->a[j]);CHKERRQ(ierr);}
430 #endif
431         }
432       }
433       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
434     }
435     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr);
436   } else if (format == PETSC_VIEWER_ASCII_DENSE) {
437     int         cnt = 0,jcnt;
438     PetscScalar value;
439 
440     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr);
441     for (i=0; i<m; i++) {
442       jcnt = 0;
443       for (j=0; j<A->n; j++) {
444         if (jcnt < a->i[i+1]-a->i[i] && j == a->j[cnt]) {
445           value = a->a[cnt++];
446           jcnt++;
447         } else {
448           value = 0.0;
449         }
450 #if defined(PETSC_USE_COMPLEX)
451         ierr = PetscViewerASCIIPrintf(viewer," %7.5e+%7.5e i ",PetscRealPart(value),PetscImaginaryPart(value));CHKERRQ(ierr);
452 #else
453         ierr = PetscViewerASCIIPrintf(viewer," %7.5e ",value);CHKERRQ(ierr);
454 #endif
455       }
456       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
457     }
458     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr);
459   } else {
460     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_NO);CHKERRQ(ierr);
461     for (i=0; i<m; i++) {
462       ierr = PetscViewerASCIIPrintf(viewer,"row %d:",i);CHKERRQ(ierr);
463       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
464 #if defined(PETSC_USE_COMPLEX)
465         if (PetscImaginaryPart(a->a[j]) > 0.0) {
466           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g + %g i)",a->j[j]+shift,PetscRealPart(a->a[j]),PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
467         } else if (PetscImaginaryPart(a->a[j]) < 0.0) {
468           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g - %g i)",a->j[j]+shift,PetscRealPart(a->a[j]),-PetscImaginaryPart(a->a[j]));CHKERRQ(ierr);
469         } else {
470           ierr = PetscViewerASCIIPrintf(viewer," (%d, %g) ",a->j[j]+shift,PetscRealPart(a->a[j]));CHKERRQ(ierr);
471         }
472 #else
473         ierr = PetscViewerASCIIPrintf(viewer," (%d, %g) ",a->j[j]+shift,a->a[j]);CHKERRQ(ierr);
474 #endif
475       }
476       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
477     }
478     ierr = PetscViewerASCIIUseTabs(viewer,PETSC_YES);CHKERRQ(ierr);
479   }
480   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
481   PetscFunctionReturn(0);
482 }
483 
484 #undef __FUNCT__
485 #define __FUNCT__ "MatView_SeqAIJ_Draw_Zoom"
486 int MatView_SeqAIJ_Draw_Zoom(PetscDraw draw,void *Aa)
487 {
488   Mat               A = (Mat) Aa;
489   Mat_SeqAIJ        *a = (Mat_SeqAIJ*)A->data;
490   int               ierr,i,j,m = A->m,shift = a->indexshift,color;
491   PetscReal         xl,yl,xr,yr,x_l,x_r,y_l,y_r,maxv = 0.0;
492   PetscViewer       viewer;
493   PetscViewerFormat format;
494 
495   PetscFunctionBegin;
496   ierr = PetscObjectQuery((PetscObject)A,"Zoomviewer",(PetscObject*)&viewer);CHKERRQ(ierr);
497   ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
498 
499   ierr = PetscDrawGetCoordinates(draw,&xl,&yl,&xr,&yr);CHKERRQ(ierr);
500   /* loop over matrix elements drawing boxes */
501 
502   if (format != PETSC_VIEWER_DRAW_CONTOUR) {
503     /* Blue for negative, Cyan for zero and  Red for positive */
504     color = PETSC_DRAW_BLUE;
505     for (i=0; i<m; i++) {
506       y_l = m - i - 1.0; y_r = y_l + 1.0;
507       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
508         x_l = a->j[j] + shift; x_r = x_l + 1.0;
509 #if defined(PETSC_USE_COMPLEX)
510         if (PetscRealPart(a->a[j]) >=  0.) continue;
511 #else
512         if (a->a[j] >=  0.) continue;
513 #endif
514         ierr = PetscDrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);CHKERRQ(ierr);
515       }
516     }
517     color = PETSC_DRAW_CYAN;
518     for (i=0; i<m; i++) {
519       y_l = m - i - 1.0; y_r = y_l + 1.0;
520       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
521         x_l = a->j[j] + shift; x_r = x_l + 1.0;
522         if (a->a[j] !=  0.) continue;
523         ierr = PetscDrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);CHKERRQ(ierr);
524       }
525     }
526     color = PETSC_DRAW_RED;
527     for (i=0; i<m; i++) {
528       y_l = m - i - 1.0; y_r = y_l + 1.0;
529       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
530         x_l = a->j[j] + shift; x_r = x_l + 1.0;
531 #if defined(PETSC_USE_COMPLEX)
532         if (PetscRealPart(a->a[j]) <=  0.) continue;
533 #else
534         if (a->a[j] <=  0.) continue;
535 #endif
536         ierr = PetscDrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);CHKERRQ(ierr);
537       }
538     }
539   } else {
540     /* use contour shading to indicate magnitude of values */
541     /* first determine max of all nonzero values */
542     int    nz = a->nz,count;
543     PetscDraw   popup;
544     PetscReal scale;
545 
546     for (i=0; i<nz; i++) {
547       if (PetscAbsScalar(a->a[i]) > maxv) maxv = PetscAbsScalar(a->a[i]);
548     }
549     scale = (245.0 - PETSC_DRAW_BASIC_COLORS)/maxv;
550     ierr  = PetscDrawGetPopup(draw,&popup);CHKERRQ(ierr);
551     if (popup) {ierr  = PetscDrawScalePopup(popup,0.0,maxv);CHKERRQ(ierr);}
552     count = 0;
553     for (i=0; i<m; i++) {
554       y_l = m - i - 1.0; y_r = y_l + 1.0;
555       for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
556         x_l = a->j[j] + shift; x_r = x_l + 1.0;
557         color = PETSC_DRAW_BASIC_COLORS + (int)(scale*PetscAbsScalar(a->a[count]));
558         ierr  = PetscDrawRectangle(draw,x_l,y_l,x_r,y_r,color,color,color,color);CHKERRQ(ierr);
559         count++;
560       }
561     }
562   }
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "MatView_SeqAIJ_Draw"
568 int MatView_SeqAIJ_Draw(Mat A,PetscViewer viewer)
569 {
570   int        ierr;
571   PetscDraw  draw;
572   PetscReal  xr,yr,xl,yl,h,w;
573   PetscTruth isnull;
574 
575   PetscFunctionBegin;
576   ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
577   ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr);
578   if (isnull) PetscFunctionReturn(0);
579 
580   ierr = PetscObjectCompose((PetscObject)A,"Zoomviewer",(PetscObject)viewer);CHKERRQ(ierr);
581   xr  = A->n; yr = A->m; h = yr/10.0; w = xr/10.0;
582   xr += w;    yr += h;  xl = -w;     yl = -h;
583   ierr = PetscDrawSetCoordinates(draw,xl,yl,xr,yr);CHKERRQ(ierr);
584   ierr = PetscDrawZoom(draw,MatView_SeqAIJ_Draw_Zoom,A);CHKERRQ(ierr);
585   ierr = PetscObjectCompose((PetscObject)A,"Zoomviewer",PETSC_NULL);CHKERRQ(ierr);
586   PetscFunctionReturn(0);
587 }
588 
589 #undef __FUNCT__
590 #define __FUNCT__ "MatView_SeqAIJ"
591 int MatView_SeqAIJ(Mat A,PetscViewer viewer)
592 {
593   Mat_SeqAIJ  *a = (Mat_SeqAIJ*)A->data;
594   int         ierr;
595   PetscTruth  issocket,isascii,isbinary,isdraw;
596 
597   PetscFunctionBegin;
598   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_SOCKET,&issocket);CHKERRQ(ierr);
599   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
600   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_BINARY,&isbinary);CHKERRQ(ierr);
601   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_DRAW,&isdraw);CHKERRQ(ierr);
602   if (issocket) {
603     if (a->indexshift) {
604       SETERRQ(1,"Can only socket send sparse matrix with 0 based indexing");
605     }
606     ierr = PetscViewerSocketPutSparse_Private(viewer,A->m,A->n,a->nz,a->a,a->i,a->j);CHKERRQ(ierr);
607   } else if (isascii) {
608     ierr = MatView_SeqAIJ_ASCII(A,viewer);CHKERRQ(ierr);
609   } else if (isbinary) {
610     ierr = MatView_SeqAIJ_Binary(A,viewer);CHKERRQ(ierr);
611   } else if (isdraw) {
612     ierr = MatView_SeqAIJ_Draw(A,viewer);CHKERRQ(ierr);
613   } else {
614     SETERRQ1(1,"Viewer type %s not supported by SeqAIJ matrices",((PetscObject)viewer)->type_name);
615   }
616   PetscFunctionReturn(0);
617 }
618 
619 EXTERN int Mat_AIJ_CheckInode(Mat,PetscTruth);
620 #undef __FUNCT__
621 #define __FUNCT__ "MatAssemblyEnd_SeqAIJ"
622 int MatAssemblyEnd_SeqAIJ(Mat A,MatAssemblyType mode)
623 {
624   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
625   int          fshift = 0,i,j,*ai = a->i,*aj = a->j,*imax = a->imax,ierr;
626   int          m = A->m,*ip,N,*ailen = a->ilen,shift = a->indexshift,rmax = 0;
627   PetscScalar  *aa = a->a,*ap;
628 #if defined(PETSC_HAVE_SUPERLUDIST) || defined(PETSC_HAVE_SPOOLES) || defined(PETSC_HAVE_UMFPACK)
629   PetscTruth   flag;
630 #endif
631 
632   PetscFunctionBegin;
633   if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(0);
634 
635   if (m) rmax = ailen[0]; /* determine row with most nonzeros */
636   for (i=1; i<m; i++) {
637     /* move each row back by the amount of empty slots (fshift) before it*/
638     fshift += imax[i-1] - ailen[i-1];
639     rmax   = PetscMax(rmax,ailen[i]);
640     if (fshift) {
641       ip = aj + ai[i] + shift;
642       ap = aa + ai[i] + shift;
643       N  = ailen[i];
644       for (j=0; j<N; j++) {
645         ip[j-fshift] = ip[j];
646         ap[j-fshift] = ap[j];
647       }
648     }
649     ai[i] = ai[i-1] + ailen[i-1];
650   }
651   if (m) {
652     fshift += imax[m-1] - ailen[m-1];
653     ai[m]  = ai[m-1] + ailen[m-1];
654   }
655   /* reset ilen and imax for each row */
656   for (i=0; i<m; i++) {
657     ailen[i] = imax[i] = ai[i+1] - ai[i];
658   }
659   a->nz = ai[m] + shift;
660 
661   /* diagonals may have moved, so kill the diagonal pointers */
662   if (fshift && a->diag) {
663     ierr = PetscFree(a->diag);CHKERRQ(ierr);
664     PetscLogObjectMemory(A,-(m+1)*sizeof(int));
665     a->diag = 0;
666   }
667   PetscLogInfo(A,"MatAssemblyEnd_SeqAIJ:Matrix size: %d X %d; storage space: %d unneeded,%d used\n",m,A->n,fshift,a->nz);
668   PetscLogInfo(A,"MatAssemblyEnd_SeqAIJ:Number of mallocs during MatSetValues() is %d\n",a->reallocs);
669   PetscLogInfo(A,"MatAssemblyEnd_SeqAIJ:Most nonzeros in any row is %d\n",rmax);
670   a->reallocs          = 0;
671   A->info.nz_unneeded  = (double)fshift;
672   a->rmax              = rmax;
673 
674   /* check out for identical nodes. If found, use inode functions */
675   ierr = Mat_AIJ_CheckInode(A,(PetscTruth)(!fshift));CHKERRQ(ierr);
676 
677 #if defined(PETSC_HAVE_SUPERLUDIST)
678   ierr = PetscOptionsHasName(A->prefix,"-mat_aij_superlu_dist",&flag);CHKERRQ(ierr);
679   if (flag) { ierr = MatUseSuperLU_DIST_MPIAIJ(A);CHKERRQ(ierr); }
680 #endif
681 
682 #if defined(PETSC_HAVE_SPOOLES)
683   ierr = PetscOptionsHasName(A->prefix,"-mat_aij_spooles",&flag);CHKERRQ(ierr);
684   if (flag) { ierr = MatUseSpooles_SeqAIJ(A);CHKERRQ(ierr); }
685 #endif
686 
687 #if defined(PETSC_HAVE_UMFPACK)
688   ierr = PetscOptionsHasName(A->prefix,"-mat_aij_umfpack",&flag);CHKERRQ(ierr);
689   if (flag) { ierr = MatUseUMFPACK_SeqAIJ(A);CHKERRQ(ierr); }
690 #endif
691 
692   PetscFunctionReturn(0);
693 }
694 
695 #undef __FUNCT__
696 #define __FUNCT__ "MatZeroEntries_SeqAIJ"
697 int MatZeroEntries_SeqAIJ(Mat A)
698 {
699   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
700   int        ierr;
701 
702   PetscFunctionBegin;
703   ierr = PetscMemzero(a->a,(a->i[A->m]+a->indexshift)*sizeof(PetscScalar));CHKERRQ(ierr);
704   PetscFunctionReturn(0);
705 }
706 
707 #undef __FUNCT__
708 #define __FUNCT__ "MatDestroy_SeqAIJ"
709 int MatDestroy_SeqAIJ(Mat A)
710 {
711   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
712   int        ierr;
713 
714   PetscFunctionBegin;
715 #if defined(PETSC_USE_LOG)
716   PetscLogObjectState((PetscObject)A,"Rows=%d, Cols=%d, NZ=%d",A->m,A->n,a->nz);
717 #endif
718   if (a->freedata) {
719     ierr = PetscFree(a->a);CHKERRQ(ierr);
720     if (!a->singlemalloc) {
721       ierr = PetscFree(a->i);CHKERRQ(ierr);
722       ierr = PetscFree(a->j);CHKERRQ(ierr);
723     }
724   }
725   if (a->row) {
726     ierr = ISDestroy(a->row);CHKERRQ(ierr);
727   }
728   if (a->col) {
729     ierr = ISDestroy(a->col);CHKERRQ(ierr);
730   }
731   if (a->diag) {ierr = PetscFree(a->diag);CHKERRQ(ierr);}
732   if (a->ilen) {ierr = PetscFree(a->ilen);CHKERRQ(ierr);}
733   if (a->imax) {ierr = PetscFree(a->imax);CHKERRQ(ierr);}
734   if (a->idiag) {ierr = PetscFree(a->idiag);CHKERRQ(ierr);}
735   if (a->solve_work) {ierr = PetscFree(a->solve_work);CHKERRQ(ierr);}
736   if (a->inode.size) {ierr = PetscFree(a->inode.size);CHKERRQ(ierr);}
737   if (a->icol) {ierr = ISDestroy(a->icol);CHKERRQ(ierr);}
738   if (a->saved_values) {ierr = PetscFree(a->saved_values);CHKERRQ(ierr);}
739   if (a->coloring) {ierr = ISColoringDestroy(a->coloring);CHKERRQ(ierr);}
740   ierr = PetscFree(a);CHKERRQ(ierr);
741   PetscFunctionReturn(0);
742 }
743 
744 #undef __FUNCT__
745 #define __FUNCT__ "MatCompress_SeqAIJ"
746 int MatCompress_SeqAIJ(Mat A)
747 {
748   PetscFunctionBegin;
749   PetscFunctionReturn(0);
750 }
751 
752 #undef __FUNCT__
753 #define __FUNCT__ "MatSetOption_SeqAIJ"
754 int MatSetOption_SeqAIJ(Mat A,MatOption op)
755 {
756   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
757 
758   PetscFunctionBegin;
759   switch (op) {
760     case MAT_ROW_ORIENTED:
761       a->roworiented       = PETSC_TRUE;
762       break;
763     case MAT_KEEP_ZEROED_ROWS:
764       a->keepzeroedrows    = PETSC_TRUE;
765       break;
766     case MAT_COLUMN_ORIENTED:
767       a->roworiented       = PETSC_FALSE;
768       break;
769     case MAT_COLUMNS_SORTED:
770       a->sorted            = PETSC_TRUE;
771       break;
772     case MAT_COLUMNS_UNSORTED:
773       a->sorted            = PETSC_FALSE;
774       break;
775     case MAT_NO_NEW_NONZERO_LOCATIONS:
776       a->nonew             = 1;
777       break;
778     case MAT_NEW_NONZERO_LOCATION_ERR:
779       a->nonew             = -1;
780       break;
781     case MAT_NEW_NONZERO_ALLOCATION_ERR:
782       a->nonew             = -2;
783       break;
784     case MAT_YES_NEW_NONZERO_LOCATIONS:
785       a->nonew             = 0;
786       break;
787     case MAT_IGNORE_ZERO_ENTRIES:
788       a->ignorezeroentries = PETSC_TRUE;
789       break;
790     case MAT_USE_INODES:
791       a->inode.use         = PETSC_TRUE;
792       break;
793     case MAT_DO_NOT_USE_INODES:
794       a->inode.use         = PETSC_FALSE;
795       break;
796     case MAT_ROWS_SORTED:
797     case MAT_ROWS_UNSORTED:
798     case MAT_YES_NEW_DIAGONALS:
799     case MAT_IGNORE_OFF_PROC_ENTRIES:
800     case MAT_USE_HASH_TABLE:
801     case MAT_USE_SINGLE_PRECISION_SOLVES:
802       PetscLogInfo(A,"MatSetOption_SeqAIJ:Option ignored\n");
803       break;
804     case MAT_NO_NEW_DIAGONALS:
805       SETERRQ(PETSC_ERR_SUP,"MAT_NO_NEW_DIAGONALS");
806     case MAT_INODE_LIMIT_1:
807       a->inode.limit  = 1;
808       break;
809     case MAT_INODE_LIMIT_2:
810       a->inode.limit  = 2;
811       break;
812     case MAT_INODE_LIMIT_3:
813       a->inode.limit  = 3;
814       break;
815     case MAT_INODE_LIMIT_4:
816       a->inode.limit  = 4;
817       break;
818     case MAT_INODE_LIMIT_5:
819       a->inode.limit  = 5;
820       break;
821     default:
822       SETERRQ(PETSC_ERR_SUP,"unknown option");
823   }
824   PetscFunctionReturn(0);
825 }
826 
827 #undef __FUNCT__
828 #define __FUNCT__ "MatGetDiagonal_SeqAIJ"
829 int MatGetDiagonal_SeqAIJ(Mat A,Vec v)
830 {
831   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
832   int          i,j,n,shift = a->indexshift,ierr;
833   PetscScalar  *x,zero = 0.0;
834 
835   PetscFunctionBegin;
836   ierr = VecSet(&zero,v);CHKERRQ(ierr);
837   ierr = VecGetArray(v,&x);CHKERRQ(ierr);
838   ierr = VecGetLocalSize(v,&n);CHKERRQ(ierr);
839   if (n != A->m) SETERRQ(PETSC_ERR_ARG_SIZ,"Nonconforming matrix and vector");
840   for (i=0; i<A->m; i++) {
841     for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
842       if (a->j[j]+shift == i) {
843         x[i] = a->a[j];
844         break;
845       }
846     }
847   }
848   ierr = VecRestoreArray(v,&x);CHKERRQ(ierr);
849   PetscFunctionReturn(0);
850 }
851 
852 
853 #undef __FUNCT__
854 #define __FUNCT__ "MatMultTransposeAdd_SeqAIJ"
855 int MatMultTransposeAdd_SeqAIJ(Mat A,Vec xx,Vec zz,Vec yy)
856 {
857   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
858   PetscScalar  *x,*y;
859   int          ierr,m = A->m,shift = a->indexshift;
860 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ)
861   PetscScalar  *v,alpha;
862   int          n,i,*idx;
863 #endif
864 
865   PetscFunctionBegin;
866   if (zz != yy) {ierr = VecCopy(zz,yy);CHKERRQ(ierr);}
867   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
868   ierr = VecGetArray(yy,&y);CHKERRQ(ierr);
869   y = y + shift; /* shift for Fortran start by 1 indexing */
870 
871 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTTRANSPOSEAIJ)
872   fortranmulttransposeaddaij_(&m,x,a->i,a->j+shift,a->a+shift,y);
873 #else
874   for (i=0; i<m; i++) {
875     idx   = a->j + a->i[i] + shift;
876     v     = a->a + a->i[i] + shift;
877     n     = a->i[i+1] - a->i[i];
878     alpha = x[i];
879     while (n-->0) {y[*idx++] += alpha * *v++;}
880   }
881 #endif
882   PetscLogFlops(2*a->nz);
883   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
884   ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr);
885   PetscFunctionReturn(0);
886 }
887 
888 #undef __FUNCT__
889 #define __FUNCT__ "MatMultTranspose_SeqAIJ"
890 int MatMultTranspose_SeqAIJ(Mat A,Vec xx,Vec yy)
891 {
892   PetscScalar  zero = 0.0;
893   int          ierr;
894 
895   PetscFunctionBegin;
896   ierr = VecSet(&zero,yy);CHKERRQ(ierr);
897   ierr = MatMultTransposeAdd_SeqAIJ(A,xx,yy,yy);CHKERRQ(ierr);
898   PetscFunctionReturn(0);
899 }
900 
901 
902 #undef __FUNCT__
903 #define __FUNCT__ "MatMult_SeqAIJ"
904 int MatMult_SeqAIJ(Mat A,Vec xx,Vec yy)
905 {
906   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
907   PetscScalar  *x,*y,*v;
908   int          ierr,m = A->m,*idx,shift = a->indexshift,*ii;
909 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTAIJ)
910   int          n,i,jrow,j;
911   PetscScalar  sum;
912 #endif
913 
914 #if defined(PETSC_HAVE_PRAGMA_DISJOINT)
915 #pragma disjoint(*x,*y,*v)
916 #endif
917 
918   PetscFunctionBegin;
919   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
920   ierr = VecGetArray(yy,&y);CHKERRQ(ierr);
921   x    = x + shift;    /* shift for Fortran start by 1 indexing */
922   idx  = a->j;
923   v    = a->a;
924   ii   = a->i;
925 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTAIJ)
926   fortranmultaij_(&m,x,ii,idx+shift,v+shift,y);
927 #else
928   v    += shift; /* shift for Fortran start by 1 indexing */
929   idx  += shift;
930   for (i=0; i<m; i++) {
931     jrow = ii[i];
932     n    = ii[i+1] - jrow;
933     sum  = 0.0;
934     for (j=0; j<n; j++) {
935       sum += v[jrow]*x[idx[jrow]]; jrow++;
936      }
937     y[i] = sum;
938   }
939 #endif
940   PetscLogFlops(2*a->nz - m);
941   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
942   ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr);
943   PetscFunctionReturn(0);
944 }
945 
946 #undef __FUNCT__
947 #define __FUNCT__ "MatMultAdd_SeqAIJ"
948 int MatMultAdd_SeqAIJ(Mat A,Vec xx,Vec yy,Vec zz)
949 {
950   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
951   PetscScalar  *x,*y,*z,*v;
952   int          ierr,m = A->m,*idx,shift = a->indexshift,*ii;
953 #if !defined(PETSC_USE_FORTRAN_KERNEL_MULTADDAIJ)
954   int          n,i,jrow,j;
955 PetscScalar    sum;
956 #endif
957 
958   PetscFunctionBegin;
959   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
960   ierr = VecGetArray(yy,&y);CHKERRQ(ierr);
961   if (zz != yy) {
962     ierr = VecGetArray(zz,&z);CHKERRQ(ierr);
963   } else {
964     z = y;
965   }
966   x    = x + shift; /* shift for Fortran start by 1 indexing */
967   idx  = a->j;
968   v    = a->a;
969   ii   = a->i;
970 #if defined(PETSC_USE_FORTRAN_KERNEL_MULTADDAIJ)
971   fortranmultaddaij_(&m,x,ii,idx+shift,v+shift,y,z);
972 #else
973   v   += shift; /* shift for Fortran start by 1 indexing */
974   idx += shift;
975   for (i=0; i<m; i++) {
976     jrow = ii[i];
977     n    = ii[i+1] - jrow;
978     sum  = y[i];
979     for (j=0; j<n; j++) {
980       sum += v[jrow]*x[idx[jrow]]; jrow++;
981      }
982     z[i] = sum;
983   }
984 #endif
985   PetscLogFlops(2*a->nz);
986   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
987   ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr);
988   if (zz != yy) {
989     ierr = VecRestoreArray(zz,&z);CHKERRQ(ierr);
990   }
991   PetscFunctionReturn(0);
992 }
993 
994 /*
995      Adds diagonal pointers to sparse matrix structure.
996 */
997 #undef __FUNCT__
998 #define __FUNCT__ "MatMarkDiagonal_SeqAIJ"
999 int MatMarkDiagonal_SeqAIJ(Mat A)
1000 {
1001   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1002   int        i,j,*diag,m = A->m,shift = a->indexshift,ierr;
1003 
1004   PetscFunctionBegin;
1005   if (a->diag) PetscFunctionReturn(0);
1006 
1007   ierr = PetscMalloc((m+1)*sizeof(int),&diag);CHKERRQ(ierr);
1008   PetscLogObjectMemory(A,(m+1)*sizeof(int));
1009   for (i=0; i<A->m; i++) {
1010     diag[i] = a->i[i+1];
1011     for (j=a->i[i]+shift; j<a->i[i+1]+shift; j++) {
1012       if (a->j[j]+shift == i) {
1013         diag[i] = j - shift;
1014         break;
1015       }
1016     }
1017   }
1018   a->diag = diag;
1019   PetscFunctionReturn(0);
1020 }
1021 
1022 /*
1023      Checks for missing diagonals
1024 */
1025 #undef __FUNCT__
1026 #define __FUNCT__ "MatMissingDiagonal_SeqAIJ"
1027 int MatMissingDiagonal_SeqAIJ(Mat A)
1028 {
1029   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1030   int        *diag,*jj = a->j,i,shift = a->indexshift,ierr;
1031 
1032   PetscFunctionBegin;
1033   ierr = MatMarkDiagonal_SeqAIJ(A);CHKERRQ(ierr);
1034   diag = a->diag;
1035   for (i=0; i<A->m; i++) {
1036     if (jj[diag[i]+shift] != i-shift) {
1037       SETERRQ1(1,"Matrix is missing diagonal number %d",i);
1038     }
1039   }
1040   PetscFunctionReturn(0);
1041 }
1042 
1043 #undef __FUNCT__
1044 #define __FUNCT__ "MatRelax_SeqAIJ"
1045 int MatRelax_SeqAIJ(Mat A,Vec bb,PetscReal omega,MatSORType flag,PetscReal fshift,int its,int lits,Vec xx)
1046 {
1047   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
1048   PetscScalar  *x,*b,*bs, d,*xs,sum,*v = a->a,*t=0,scale,*ts,*xb,*idiag=0;
1049   int          ierr,*idx,*diag,n = A->n,m = A->m,i,shift = a->indexshift;
1050 
1051   PetscFunctionBegin;
1052   its = its*lits;
1053   if (its <= 0) SETERRQ2(PETSC_ERR_ARG_WRONG,"Relaxation requires global its %d and local its %d both positive",its,lits);
1054 
1055   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
1056   if (xx != bb) {
1057     ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
1058   } else {
1059     b = x;
1060   }
1061 
1062   if (!a->diag) {ierr = MatMarkDiagonal_SeqAIJ(A);CHKERRQ(ierr);}
1063   diag = a->diag;
1064   xs   = x + shift; /* shifted by one for index start of a or a->j*/
1065   if (flag == SOR_APPLY_UPPER) {
1066    /* apply (U + D/omega) to the vector */
1067     bs = b + shift;
1068     for (i=0; i<m; i++) {
1069         d    = fshift + a->a[diag[i] + shift];
1070         n    = a->i[i+1] - diag[i] - 1;
1071 	PetscLogFlops(2*n-1);
1072         idx  = a->j + diag[i] + (!shift);
1073         v    = a->a + diag[i] + (!shift);
1074         sum  = b[i]*d/omega;
1075         SPARSEDENSEDOT(sum,bs,v,idx,n);
1076         x[i] = sum;
1077     }
1078     ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
1079     if (bb != xx) {ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);}
1080     PetscFunctionReturn(0);
1081   }
1082 
1083   /* setup workspace for Eisenstat */
1084   if (flag & SOR_EISENSTAT) {
1085     if (!a->idiag) {
1086       ierr     = PetscMalloc(2*m*sizeof(PetscScalar),&a->idiag);CHKERRQ(ierr);
1087       a->ssor  = a->idiag + m;
1088       v        = a->a;
1089       for (i=0; i<m; i++) { a->idiag[i] = 1.0/v[diag[i]];}
1090     }
1091     t     = a->ssor;
1092     idiag = a->idiag;
1093   }
1094     /* Let  A = L + U + D; where L is lower trianglar,
1095     U is upper triangular, E is diagonal; This routine applies
1096 
1097             (L + E)^{-1} A (U + E)^{-1}
1098 
1099     to a vector efficiently using Eisenstat's trick. This is for
1100     the case of SSOR preconditioner, so E is D/omega where omega
1101     is the relaxation factor.
1102     */
1103 
1104   if (flag == SOR_APPLY_LOWER) {
1105     SETERRQ(PETSC_ERR_SUP,"SOR_APPLY_LOWER is not implemented");
1106   } else if ((flag & SOR_EISENSTAT) && omega == 1.0 && shift == 0 && fshift == 0.0) {
1107     /* special case for omega = 1.0 saves flops and some integer ops */
1108     PetscScalar *v2;
1109 
1110     v2    = a->a;
1111     /*  x = (E + U)^{-1} b */
1112     for (i=m-1; i>=0; i--) {
1113       n    = a->i[i+1] - diag[i] - 1;
1114       idx  = a->j + diag[i] + 1;
1115       v    = a->a + diag[i] + 1;
1116       sum  = b[i];
1117       SPARSEDENSEMDOT(sum,xs,v,idx,n);
1118       x[i] = sum*idiag[i];
1119 
1120       /*  t = b - (2*E - D)x */
1121       t[i] = b[i] - (v2[diag[i]])*x[i];
1122     }
1123 
1124     /*  t = (E + L)^{-1}t */
1125     diag = a->diag;
1126     for (i=0; i<m; i++) {
1127       n    = diag[i] - a->i[i];
1128       idx  = a->j + a->i[i];
1129       v    = a->a + a->i[i];
1130       sum  = t[i];
1131       SPARSEDENSEMDOT(sum,t,v,idx,n);
1132       t[i]  = sum*idiag[i];
1133 
1134       /*  x = x + t */
1135       x[i] += t[i];
1136     }
1137 
1138     PetscLogFlops(3*m-1 + 2*a->nz);
1139     ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
1140     if (bb != xx) {ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);}
1141     PetscFunctionReturn(0);
1142   } else if (flag & SOR_EISENSTAT) {
1143     /* Let  A = L + U + D; where L is lower trianglar,
1144     U is upper triangular, E is diagonal; This routine applies
1145 
1146             (L + E)^{-1} A (U + E)^{-1}
1147 
1148     to a vector efficiently using Eisenstat's trick. This is for
1149     the case of SSOR preconditioner, so E is D/omega where omega
1150     is the relaxation factor.
1151     */
1152     scale = (2.0/omega) - 1.0;
1153 
1154     /*  x = (E + U)^{-1} b */
1155     for (i=m-1; i>=0; i--) {
1156       d    = fshift + a->a[diag[i] + shift];
1157       n    = a->i[i+1] - diag[i] - 1;
1158       idx  = a->j + diag[i] + (!shift);
1159       v    = a->a + diag[i] + (!shift);
1160       sum  = b[i];
1161       SPARSEDENSEMDOT(sum,xs,v,idx,n);
1162       x[i] = omega*(sum/d);
1163     }
1164 
1165     /*  t = b - (2*E - D)x */
1166     v = a->a;
1167     for (i=0; i<m; i++) { t[i] = b[i] - scale*(v[*diag++ + shift])*x[i]; }
1168 
1169     /*  t = (E + L)^{-1}t */
1170     ts = t + shift; /* shifted by one for index start of a or a->j*/
1171     diag = a->diag;
1172     for (i=0; i<m; i++) {
1173       d    = fshift + a->a[diag[i]+shift];
1174       n    = diag[i] - a->i[i];
1175       idx  = a->j + a->i[i] + shift;
1176       v    = a->a + a->i[i] + shift;
1177       sum  = t[i];
1178       SPARSEDENSEMDOT(sum,ts,v,idx,n);
1179       t[i] = omega*(sum/d);
1180       /*  x = x + t */
1181       x[i] += t[i];
1182     }
1183 
1184     PetscLogFlops(6*m-1 + 2*a->nz);
1185     ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
1186     if (bb != xx) {ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);}
1187     PetscFunctionReturn(0);
1188   }
1189   if (flag & SOR_ZERO_INITIAL_GUESS) {
1190     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
1191 #if defined(PETSC_USE_FORTRAN_KERNEL_RELAXAIJ)
1192       fortranrelaxaijforwardzero_(&m,&omega,x,a->i,a->j,diag,a->a,b);
1193 #else
1194       for (i=0; i<m; i++) {
1195         d    = fshift + a->a[diag[i]+shift];
1196         n    = diag[i] - a->i[i];
1197 	PetscLogFlops(2*n-1);
1198         idx  = a->j + a->i[i] + shift;
1199         v    = a->a + a->i[i] + shift;
1200         sum  = b[i];
1201         SPARSEDENSEMDOT(sum,xs,v,idx,n);
1202         x[i] = omega*(sum/d);
1203       }
1204 #endif
1205       xb = x;
1206     } else xb = b;
1207     if ((flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) &&
1208         (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP)) {
1209       for (i=0; i<m; i++) {
1210         x[i] *= a->a[diag[i]+shift];
1211       }
1212       PetscLogFlops(m);
1213     }
1214     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
1215 #if defined(PETSC_USE_FORTRAN_KERNEL_RELAXAIJ)
1216       fortranrelaxaijbackwardzero_(&m,&omega,x,a->i,a->j,diag,a->a,xb);
1217 #else
1218       for (i=m-1; i>=0; i--) {
1219         d    = fshift + a->a[diag[i] + shift];
1220         n    = a->i[i+1] - diag[i] - 1;
1221 	PetscLogFlops(2*n-1);
1222         idx  = a->j + diag[i] + (!shift);
1223         v    = a->a + diag[i] + (!shift);
1224         sum  = xb[i];
1225         SPARSEDENSEMDOT(sum,xs,v,idx,n);
1226         x[i] = omega*(sum/d);
1227       }
1228 #endif
1229     }
1230     its--;
1231   }
1232   while (its--) {
1233     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
1234 #if defined(PETSC_USE_FORTRAN_KERNEL_RELAXAIJ)
1235       fortranrelaxaijforward_(&m,&omega,x,a->i,a->j,diag,a->a,b);
1236 #else
1237       for (i=0; i<m; i++) {
1238         d    = fshift + a->a[diag[i]+shift];
1239         n    = a->i[i+1] - a->i[i];
1240 	PetscLogFlops(2*n-1);
1241         idx  = a->j + a->i[i] + shift;
1242         v    = a->a + a->i[i] + shift;
1243         sum  = b[i];
1244         SPARSEDENSEMDOT(sum,xs,v,idx,n);
1245         x[i] = (1. - omega)*x[i] + omega*(sum + a->a[diag[i]+shift]*x[i])/d;
1246       }
1247 #endif
1248     }
1249     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
1250 #if defined(PETSC_USE_FORTRAN_KERNEL_RELAXAIJ)
1251       fortranrelaxaijbackward_(&m,&omega,x,a->i,a->j,diag,a->a,b);
1252 #else
1253       for (i=m-1; i>=0; i--) {
1254         d    = fshift + a->a[diag[i] + shift];
1255         n    = a->i[i+1] - a->i[i];
1256 	PetscLogFlops(2*n-1);
1257         idx  = a->j + a->i[i] + shift;
1258         v    = a->a + a->i[i] + shift;
1259         sum  = b[i];
1260         SPARSEDENSEMDOT(sum,xs,v,idx,n);
1261         x[i] = (1. - omega)*x[i] + omega*(sum + a->a[diag[i]+shift]*x[i])/d;
1262       }
1263 #endif
1264     }
1265   }
1266   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
1267   if (bb != xx) {ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);}
1268   PetscFunctionReturn(0);
1269 }
1270 
1271 #undef __FUNCT__
1272 #define __FUNCT__ "MatGetInfo_SeqAIJ"
1273 int MatGetInfo_SeqAIJ(Mat A,MatInfoType flag,MatInfo *info)
1274 {
1275   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1276 
1277   PetscFunctionBegin;
1278   info->rows_global    = (double)A->m;
1279   info->columns_global = (double)A->n;
1280   info->rows_local     = (double)A->m;
1281   info->columns_local  = (double)A->n;
1282   info->block_size     = 1.0;
1283   info->nz_allocated   = (double)a->maxnz;
1284   info->nz_used        = (double)a->nz;
1285   info->nz_unneeded    = (double)(a->maxnz - a->nz);
1286   info->assemblies     = (double)A->num_ass;
1287   info->mallocs        = (double)a->reallocs;
1288   info->memory         = A->mem;
1289   if (A->factor) {
1290     info->fill_ratio_given  = A->info.fill_ratio_given;
1291     info->fill_ratio_needed = A->info.fill_ratio_needed;
1292     info->factor_mallocs    = A->info.factor_mallocs;
1293   } else {
1294     info->fill_ratio_given  = 0;
1295     info->fill_ratio_needed = 0;
1296     info->factor_mallocs    = 0;
1297   }
1298   PetscFunctionReturn(0);
1299 }
1300 
1301 EXTERN int MatLUFactorSymbolic_SeqAIJ(Mat,IS,IS,MatLUInfo*,Mat*);
1302 EXTERN int MatLUFactorNumeric_SeqAIJ(Mat,Mat*);
1303 EXTERN int MatLUFactor_SeqAIJ(Mat,IS,IS,MatLUInfo*);
1304 EXTERN int MatSolve_SeqAIJ(Mat,Vec,Vec);
1305 EXTERN int MatSolveAdd_SeqAIJ(Mat,Vec,Vec,Vec);
1306 EXTERN int MatSolveTranspose_SeqAIJ(Mat,Vec,Vec);
1307 EXTERN int MatSolveTransposeAdd_SeqAIJ(Mat,Vec,Vec,Vec);
1308 
1309 #undef __FUNCT__
1310 #define __FUNCT__ "MatZeroRows_SeqAIJ"
1311 int MatZeroRows_SeqAIJ(Mat A,IS is,PetscScalar *diag)
1312 {
1313   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1314   int         i,ierr,N,*rows,m = A->m - 1,shift = a->indexshift;
1315 
1316   PetscFunctionBegin;
1317   ierr = ISGetLocalSize(is,&N);CHKERRQ(ierr);
1318   ierr = ISGetIndices(is,&rows);CHKERRQ(ierr);
1319   if (a->keepzeroedrows) {
1320     for (i=0; i<N; i++) {
1321       if (rows[i] < 0 || rows[i] > m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"row out of range");
1322       ierr = PetscMemzero(&a->a[a->i[rows[i]]+shift],a->ilen[rows[i]]*sizeof(PetscScalar));CHKERRQ(ierr);
1323     }
1324     if (diag) {
1325       ierr = MatMissingDiagonal_SeqAIJ(A);CHKERRQ(ierr);
1326       ierr = MatMarkDiagonal_SeqAIJ(A);CHKERRQ(ierr);
1327       for (i=0; i<N; i++) {
1328         a->a[a->diag[rows[i]]] = *diag;
1329       }
1330     }
1331   } else {
1332     if (diag) {
1333       for (i=0; i<N; i++) {
1334         if (rows[i] < 0 || rows[i] > m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"row out of range");
1335         if (a->ilen[rows[i]] > 0) {
1336           a->ilen[rows[i]]          = 1;
1337           a->a[a->i[rows[i]]+shift] = *diag;
1338           a->j[a->i[rows[i]]+shift] = rows[i]+shift;
1339         } else { /* in case row was completely empty */
1340           ierr = MatSetValues_SeqAIJ(A,1,&rows[i],1,&rows[i],diag,INSERT_VALUES);CHKERRQ(ierr);
1341         }
1342       }
1343     } else {
1344       for (i=0; i<N; i++) {
1345         if (rows[i] < 0 || rows[i] > m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"row out of range");
1346         a->ilen[rows[i]] = 0;
1347       }
1348     }
1349   }
1350   ierr = ISRestoreIndices(is,&rows);CHKERRQ(ierr);
1351   ierr = MatAssemblyEnd_SeqAIJ(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1352   PetscFunctionReturn(0);
1353 }
1354 
1355 #undef __FUNCT__
1356 #define __FUNCT__ "MatGetRow_SeqAIJ"
1357 int MatGetRow_SeqAIJ(Mat A,int row,int *nz,int **idx,PetscScalar **v)
1358 {
1359   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1360   int        *itmp,i,shift = a->indexshift,ierr;
1361 
1362   PetscFunctionBegin;
1363   if (row < 0 || row >= A->m) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Row %d out of range",row);
1364 
1365   *nz = a->i[row+1] - a->i[row];
1366   if (v) *v = a->a + a->i[row] + shift;
1367   if (idx) {
1368     itmp = a->j + a->i[row] + shift;
1369     if (*nz && shift) {
1370       ierr = PetscMalloc((*nz)*sizeof(int),idx);CHKERRQ(ierr);
1371       for (i=0; i<(*nz); i++) {(*idx)[i] = itmp[i] + shift;}
1372     } else if (*nz) {
1373       *idx = itmp;
1374     }
1375     else *idx = 0;
1376   }
1377   PetscFunctionReturn(0);
1378 }
1379 
1380 #undef __FUNCT__
1381 #define __FUNCT__ "MatRestoreRow_SeqAIJ"
1382 int MatRestoreRow_SeqAIJ(Mat A,int row,int *nz,int **idx,PetscScalar **v)
1383 {
1384   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1385   int ierr;
1386 
1387   PetscFunctionBegin;
1388   if (idx) {if (*idx && a->indexshift) {ierr = PetscFree(*idx);CHKERRQ(ierr);}}
1389   PetscFunctionReturn(0);
1390 }
1391 
1392 #undef __FUNCT__
1393 #define __FUNCT__ "MatNorm_SeqAIJ"
1394 int MatNorm_SeqAIJ(Mat A,NormType type,PetscReal *nrm)
1395 {
1396   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
1397   PetscScalar  *v = a->a;
1398   PetscReal    sum = 0.0;
1399   int          i,j,shift = a->indexshift,ierr;
1400 
1401   PetscFunctionBegin;
1402   if (type == NORM_FROBENIUS) {
1403     for (i=0; i<a->nz; i++) {
1404 #if defined(PETSC_USE_COMPLEX)
1405       sum += PetscRealPart(PetscConj(*v)*(*v)); v++;
1406 #else
1407       sum += (*v)*(*v); v++;
1408 #endif
1409     }
1410     *nrm = sqrt(sum);
1411   } else if (type == NORM_1) {
1412     PetscReal *tmp;
1413     int    *jj = a->j;
1414     ierr = PetscMalloc((A->n+1)*sizeof(PetscReal),&tmp);CHKERRQ(ierr);
1415     ierr = PetscMemzero(tmp,A->n*sizeof(PetscReal));CHKERRQ(ierr);
1416     *nrm = 0.0;
1417     for (j=0; j<a->nz; j++) {
1418         tmp[*jj++ + shift] += PetscAbsScalar(*v);  v++;
1419     }
1420     for (j=0; j<A->n; j++) {
1421       if (tmp[j] > *nrm) *nrm = tmp[j];
1422     }
1423     ierr = PetscFree(tmp);CHKERRQ(ierr);
1424   } else if (type == NORM_INFINITY) {
1425     *nrm = 0.0;
1426     for (j=0; j<A->m; j++) {
1427       v = a->a + a->i[j] + shift;
1428       sum = 0.0;
1429       for (i=0; i<a->i[j+1]-a->i[j]; i++) {
1430         sum += PetscAbsScalar(*v); v++;
1431       }
1432       if (sum > *nrm) *nrm = sum;
1433     }
1434   } else {
1435     SETERRQ(PETSC_ERR_SUP,"No support for two norm");
1436   }
1437   PetscFunctionReturn(0);
1438 }
1439 
1440 #undef __FUNCT__
1441 #define __FUNCT__ "MatTranspose_SeqAIJ"
1442 int MatTranspose_SeqAIJ(Mat A,Mat *B)
1443 {
1444   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
1445   Mat          C;
1446   int          i,ierr,*aj = a->j,*ai = a->i,m = A->m,len,*col;
1447   int          shift = a->indexshift;
1448   PetscScalar  *array = a->a;
1449 
1450   PetscFunctionBegin;
1451   if (!B && m != A->n) SETERRQ(PETSC_ERR_ARG_SIZ,"Square matrix only for in-place");
1452   ierr = PetscMalloc((1+A->n)*sizeof(int),&col);CHKERRQ(ierr);
1453   ierr = PetscMemzero(col,(1+A->n)*sizeof(int));CHKERRQ(ierr);
1454   if (shift) {
1455     for (i=0; i<ai[m]-1; i++) aj[i] -= 1;
1456   }
1457   for (i=0; i<ai[m]+shift; i++) col[aj[i]] += 1;
1458   ierr = MatCreateSeqAIJ(A->comm,A->n,m,0,col,&C);CHKERRQ(ierr);
1459   ierr = PetscFree(col);CHKERRQ(ierr);
1460   for (i=0; i<m; i++) {
1461     len    = ai[i+1]-ai[i];
1462     ierr   = MatSetValues(C,len,aj,1,&i,array,INSERT_VALUES);CHKERRQ(ierr);
1463     array += len;
1464     aj    += len;
1465   }
1466   if (shift) {
1467     for (i=0; i<ai[m]-1; i++) aj[i] += 1;
1468   }
1469 
1470   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1471   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1472 
1473   if (B) {
1474     *B = C;
1475   } else {
1476     ierr = MatHeaderCopy(A,C);CHKERRQ(ierr);
1477   }
1478   PetscFunctionReturn(0);
1479 }
1480 
1481 #undef __FUNCT__
1482 #define __FUNCT__ "MatDiagonalScale_SeqAIJ"
1483 int MatDiagonalScale_SeqAIJ(Mat A,Vec ll,Vec rr)
1484 {
1485   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
1486   PetscScalar  *l,*r,x,*v;
1487   int          ierr,i,j,m = A->m,n = A->n,M,nz = a->nz,*jj,shift = a->indexshift;
1488 
1489   PetscFunctionBegin;
1490   if (ll) {
1491     /* The local size is used so that VecMPI can be passed to this routine
1492        by MatDiagonalScale_MPIAIJ */
1493     ierr = VecGetLocalSize(ll,&m);CHKERRQ(ierr);
1494     if (m != A->m) SETERRQ(PETSC_ERR_ARG_SIZ,"Left scaling vector wrong length");
1495     ierr = VecGetArray(ll,&l);CHKERRQ(ierr);
1496     v = a->a;
1497     for (i=0; i<m; i++) {
1498       x = l[i];
1499       M = a->i[i+1] - a->i[i];
1500       for (j=0; j<M; j++) { (*v++) *= x;}
1501     }
1502     ierr = VecRestoreArray(ll,&l);CHKERRQ(ierr);
1503     PetscLogFlops(nz);
1504   }
1505   if (rr) {
1506     ierr = VecGetLocalSize(rr,&n);CHKERRQ(ierr);
1507     if (n != A->n) SETERRQ(PETSC_ERR_ARG_SIZ,"Right scaling vector wrong length");
1508     ierr = VecGetArray(rr,&r);CHKERRQ(ierr);
1509     v = a->a; jj = a->j;
1510     for (i=0; i<nz; i++) {
1511       (*v++) *= r[*jj++ + shift];
1512     }
1513     ierr = VecRestoreArray(rr,&r);CHKERRQ(ierr);
1514     PetscLogFlops(nz);
1515   }
1516   PetscFunctionReturn(0);
1517 }
1518 
1519 #undef __FUNCT__
1520 #define __FUNCT__ "MatGetSubMatrix_SeqAIJ"
1521 int MatGetSubMatrix_SeqAIJ(Mat A,IS isrow,IS iscol,int csize,MatReuse scall,Mat *B)
1522 {
1523   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data,*c;
1524   int          *smap,i,k,kstart,kend,ierr,oldcols = A->n,*lens;
1525   int          row,mat_i,*mat_j,tcol,first,step,*mat_ilen,sum,lensi;
1526   int          *irow,*icol,nrows,ncols,shift = a->indexshift,*ssmap;
1527   int          *starts,*j_new,*i_new,*aj = a->j,*ai = a->i,ii,*ailen = a->ilen;
1528   PetscScalar  *a_new,*mat_a;
1529   Mat          C;
1530   PetscTruth   stride;
1531 
1532   PetscFunctionBegin;
1533   ierr = ISSorted(isrow,(PetscTruth*)&i);CHKERRQ(ierr);
1534   if (!i) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"ISrow is not sorted");
1535   ierr = ISSorted(iscol,(PetscTruth*)&i);CHKERRQ(ierr);
1536   if (!i) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"IScol is not sorted");
1537 
1538   ierr = ISGetIndices(isrow,&irow);CHKERRQ(ierr);
1539   ierr = ISGetLocalSize(isrow,&nrows);CHKERRQ(ierr);
1540   ierr = ISGetLocalSize(iscol,&ncols);CHKERRQ(ierr);
1541 
1542   ierr = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
1543   ierr = ISStride(iscol,&stride);CHKERRQ(ierr);
1544   if (stride && step == 1) {
1545     /* special case of contiguous rows */
1546     ierr   = PetscMalloc((2*nrows+1)*sizeof(int),&lens);CHKERRQ(ierr);
1547     starts = lens + nrows;
1548     /* loop over new rows determining lens and starting points */
1549     for (i=0; i<nrows; i++) {
1550       kstart  = ai[irow[i]]+shift;
1551       kend    = kstart + ailen[irow[i]];
1552       for (k=kstart; k<kend; k++) {
1553         if (aj[k]+shift >= first) {
1554           starts[i] = k;
1555           break;
1556 	}
1557       }
1558       sum = 0;
1559       while (k < kend) {
1560         if (aj[k++]+shift >= first+ncols) break;
1561         sum++;
1562       }
1563       lens[i] = sum;
1564     }
1565     /* create submatrix */
1566     if (scall == MAT_REUSE_MATRIX) {
1567       int n_cols,n_rows;
1568       ierr = MatGetSize(*B,&n_rows,&n_cols);CHKERRQ(ierr);
1569       if (n_rows != nrows || n_cols != ncols) SETERRQ(PETSC_ERR_ARG_SIZ,"Reused submatrix wrong size");
1570       ierr = MatZeroEntries(*B);CHKERRQ(ierr);
1571       C = *B;
1572     } else {
1573       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1574     }
1575     c = (Mat_SeqAIJ*)C->data;
1576 
1577     /* loop over rows inserting into submatrix */
1578     a_new    = c->a;
1579     j_new    = c->j;
1580     i_new    = c->i;
1581     i_new[0] = -shift;
1582     for (i=0; i<nrows; i++) {
1583       ii    = starts[i];
1584       lensi = lens[i];
1585       for (k=0; k<lensi; k++) {
1586         *j_new++ = aj[ii+k] - first;
1587       }
1588       ierr = PetscMemcpy(a_new,a->a + starts[i],lensi*sizeof(PetscScalar));CHKERRQ(ierr);
1589       a_new      += lensi;
1590       i_new[i+1]  = i_new[i] + lensi;
1591       c->ilen[i]  = lensi;
1592     }
1593     ierr = PetscFree(lens);CHKERRQ(ierr);
1594   } else {
1595     ierr  = ISGetIndices(iscol,&icol);CHKERRQ(ierr);
1596     ierr  = PetscMalloc((1+oldcols)*sizeof(int),&smap);CHKERRQ(ierr);
1597     ssmap = smap + shift;
1598     ierr  = PetscMalloc((1+nrows)*sizeof(int),&lens);CHKERRQ(ierr);
1599     ierr  = PetscMemzero(smap,oldcols*sizeof(int));CHKERRQ(ierr);
1600     for (i=0; i<ncols; i++) smap[icol[i]] = i+1;
1601     /* determine lens of each row */
1602     for (i=0; i<nrows; i++) {
1603       kstart  = ai[irow[i]]+shift;
1604       kend    = kstart + a->ilen[irow[i]];
1605       lens[i] = 0;
1606       for (k=kstart; k<kend; k++) {
1607         if (ssmap[aj[k]]) {
1608           lens[i]++;
1609         }
1610       }
1611     }
1612     /* Create and fill new matrix */
1613     if (scall == MAT_REUSE_MATRIX) {
1614       PetscTruth equal;
1615 
1616       c = (Mat_SeqAIJ *)((*B)->data);
1617       if ((*B)->m  != nrows || (*B)->n != ncols) SETERRQ(PETSC_ERR_ARG_SIZ,"Cannot reuse matrix. wrong size");
1618       ierr = PetscMemcmp(c->ilen,lens,(*B)->m*sizeof(int),&equal);CHKERRQ(ierr);
1619       if (!equal) {
1620         SETERRQ(PETSC_ERR_ARG_SIZ,"Cannot reuse matrix. wrong no of nonzeros");
1621       }
1622       ierr = PetscMemzero(c->ilen,(*B)->m*sizeof(int));CHKERRQ(ierr);
1623       C = *B;
1624     } else {
1625       ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,lens,&C);CHKERRQ(ierr);
1626     }
1627     c = (Mat_SeqAIJ *)(C->data);
1628     for (i=0; i<nrows; i++) {
1629       row    = irow[i];
1630       kstart = ai[row]+shift;
1631       kend   = kstart + a->ilen[row];
1632       mat_i  = c->i[i]+shift;
1633       mat_j  = c->j + mat_i;
1634       mat_a  = c->a + mat_i;
1635       mat_ilen = c->ilen + i;
1636       for (k=kstart; k<kend; k++) {
1637         if ((tcol=ssmap[a->j[k]])) {
1638           *mat_j++ = tcol - (!shift);
1639           *mat_a++ = a->a[k];
1640           (*mat_ilen)++;
1641 
1642         }
1643       }
1644     }
1645     /* Free work space */
1646     ierr = ISRestoreIndices(iscol,&icol);CHKERRQ(ierr);
1647     ierr = PetscFree(smap);CHKERRQ(ierr);
1648     ierr = PetscFree(lens);CHKERRQ(ierr);
1649   }
1650   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1651   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1652 
1653   ierr = ISRestoreIndices(isrow,&irow);CHKERRQ(ierr);
1654   *B = C;
1655   PetscFunctionReturn(0);
1656 }
1657 
1658 /*
1659 */
1660 #undef __FUNCT__
1661 #define __FUNCT__ "MatILUFactor_SeqAIJ"
1662 int MatILUFactor_SeqAIJ(Mat inA,IS row,IS col,MatILUInfo *info)
1663 {
1664   Mat_SeqAIJ *a = (Mat_SeqAIJ*)inA->data;
1665   int        ierr;
1666   Mat        outA;
1667   PetscTruth row_identity,col_identity;
1668 
1669   PetscFunctionBegin;
1670   if (info->levels != 0) SETERRQ(PETSC_ERR_SUP,"Only levels=0 supported for in-place ilu");
1671   ierr = ISIdentity(row,&row_identity);CHKERRQ(ierr);
1672   ierr = ISIdentity(col,&col_identity);CHKERRQ(ierr);
1673   if (!row_identity || !col_identity) {
1674     SETERRQ(1,"Row and column permutations must be identity for in-place ILU");
1675   }
1676 
1677   outA          = inA;
1678   inA->factor   = FACTOR_LU;
1679   a->row        = row;
1680   a->col        = col;
1681   ierr = PetscObjectReference((PetscObject)row);CHKERRQ(ierr);
1682   ierr = PetscObjectReference((PetscObject)col);CHKERRQ(ierr);
1683 
1684   /* Create the inverse permutation so that it can be used in MatLUFactorNumeric() */
1685   if (a->icol) {ierr = ISDestroy(a->icol);CHKERRQ(ierr);} /* need to remove old one */
1686   ierr = ISInvertPermutation(col,PETSC_DECIDE,&a->icol);CHKERRQ(ierr);
1687   PetscLogObjectParent(inA,a->icol);
1688 
1689   if (!a->solve_work) { /* this matrix may have been factored before */
1690      ierr = PetscMalloc((inA->m+1)*sizeof(PetscScalar),&a->solve_work);CHKERRQ(ierr);
1691   }
1692 
1693   if (!a->diag) {
1694     ierr = MatMarkDiagonal_SeqAIJ(inA);CHKERRQ(ierr);
1695   }
1696   ierr = MatLUFactorNumeric_SeqAIJ(inA,&outA);CHKERRQ(ierr);
1697   PetscFunctionReturn(0);
1698 }
1699 
1700 #include "petscblaslapack.h"
1701 #undef __FUNCT__
1702 #define __FUNCT__ "MatScale_SeqAIJ"
1703 int MatScale_SeqAIJ(PetscScalar *alpha,Mat inA)
1704 {
1705   Mat_SeqAIJ *a = (Mat_SeqAIJ*)inA->data;
1706   int        one = 1;
1707 
1708   PetscFunctionBegin;
1709   BLscal_(&a->nz,alpha,a->a,&one);
1710   PetscLogFlops(a->nz);
1711   PetscFunctionReturn(0);
1712 }
1713 
1714 #undef __FUNCT__
1715 #define __FUNCT__ "MatGetSubMatrices_SeqAIJ"
1716 int MatGetSubMatrices_SeqAIJ(Mat A,int n,IS *irow,IS *icol,MatReuse scall,Mat **B)
1717 {
1718   int ierr,i;
1719 
1720   PetscFunctionBegin;
1721   if (scall == MAT_INITIAL_MATRIX) {
1722     ierr = PetscMalloc((n+1)*sizeof(Mat),B);CHKERRQ(ierr);
1723   }
1724 
1725   for (i=0; i<n; i++) {
1726     ierr = MatGetSubMatrix_SeqAIJ(A,irow[i],icol[i],PETSC_DECIDE,scall,&(*B)[i]);CHKERRQ(ierr);
1727   }
1728   PetscFunctionReturn(0);
1729 }
1730 
1731 #undef __FUNCT__
1732 #define __FUNCT__ "MatGetBlockSize_SeqAIJ"
1733 int MatGetBlockSize_SeqAIJ(Mat A,int *bs)
1734 {
1735   PetscFunctionBegin;
1736   *bs = 1;
1737   PetscFunctionReturn(0);
1738 }
1739 
1740 #undef __FUNCT__
1741 #define __FUNCT__ "MatIncreaseOverlap_SeqAIJ"
1742 int MatIncreaseOverlap_SeqAIJ(Mat A,int is_max,IS *is,int ov)
1743 {
1744   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1745   int        shift,row,i,j,k,l,m,n,*idx,ierr,*nidx,isz,val;
1746   int        start,end,*ai,*aj;
1747   PetscBT    table;
1748 
1749   PetscFunctionBegin;
1750   shift = a->indexshift;
1751   m     = A->m;
1752   ai    = a->i;
1753   aj    = a->j+shift;
1754 
1755   if (ov < 0)  SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"illegal overlap value used");
1756 
1757   ierr = PetscMalloc((m+1)*sizeof(int),&nidx);CHKERRQ(ierr);
1758   ierr = PetscBTCreate(m,table);CHKERRQ(ierr);
1759 
1760   for (i=0; i<is_max; i++) {
1761     /* Initialize the two local arrays */
1762     isz  = 0;
1763     ierr = PetscBTMemzero(m,table);CHKERRQ(ierr);
1764 
1765     /* Extract the indices, assume there can be duplicate entries */
1766     ierr = ISGetIndices(is[i],&idx);CHKERRQ(ierr);
1767     ierr = ISGetLocalSize(is[i],&n);CHKERRQ(ierr);
1768 
1769     /* Enter these into the temp arrays. I.e., mark table[row], enter row into new index */
1770     for (j=0; j<n ; ++j){
1771       if(!PetscBTLookupSet(table,idx[j])) { nidx[isz++] = idx[j];}
1772     }
1773     ierr = ISRestoreIndices(is[i],&idx);CHKERRQ(ierr);
1774     ierr = ISDestroy(is[i]);CHKERRQ(ierr);
1775 
1776     k = 0;
1777     for (j=0; j<ov; j++){ /* for each overlap */
1778       n = isz;
1779       for (; k<n ; k++){ /* do only those rows in nidx[k], which are not done yet */
1780         row   = nidx[k];
1781         start = ai[row];
1782         end   = ai[row+1];
1783         for (l = start; l<end ; l++){
1784           val = aj[l] + shift;
1785           if (!PetscBTLookupSet(table,val)) {nidx[isz++] = val;}
1786         }
1787       }
1788     }
1789     ierr = ISCreateGeneral(PETSC_COMM_SELF,isz,nidx,(is+i));CHKERRQ(ierr);
1790   }
1791   ierr = PetscBTDestroy(table);CHKERRQ(ierr);
1792   ierr = PetscFree(nidx);CHKERRQ(ierr);
1793   PetscFunctionReturn(0);
1794 }
1795 
1796 /* -------------------------------------------------------------- */
1797 #undef __FUNCT__
1798 #define __FUNCT__ "MatPermute_SeqAIJ"
1799 int MatPermute_SeqAIJ(Mat A,IS rowp,IS colp,Mat *B)
1800 {
1801   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
1802   PetscScalar  *vwork;
1803   int          i,ierr,nz,m = A->m,n = A->n,*cwork;
1804   int          *row,*col,*cnew,j,*lens;
1805   IS           icolp,irowp;
1806 
1807   PetscFunctionBegin;
1808   ierr = ISInvertPermutation(rowp,PETSC_DECIDE,&irowp);CHKERRQ(ierr);
1809   ierr = ISGetIndices(irowp,&row);CHKERRQ(ierr);
1810   ierr = ISInvertPermutation(colp,PETSC_DECIDE,&icolp);CHKERRQ(ierr);
1811   ierr = ISGetIndices(icolp,&col);CHKERRQ(ierr);
1812 
1813   /* determine lengths of permuted rows */
1814   ierr = PetscMalloc((m+1)*sizeof(int),&lens);CHKERRQ(ierr);
1815   for (i=0; i<m; i++) {
1816     lens[row[i]] = a->i[i+1] - a->i[i];
1817   }
1818   ierr = MatCreateSeqAIJ(A->comm,m,n,0,lens,B);CHKERRQ(ierr);
1819   ierr = PetscFree(lens);CHKERRQ(ierr);
1820 
1821   ierr = PetscMalloc(n*sizeof(int),&cnew);CHKERRQ(ierr);
1822   for (i=0; i<m; i++) {
1823     ierr = MatGetRow(A,i,&nz,&cwork,&vwork);CHKERRQ(ierr);
1824     for (j=0; j<nz; j++) { cnew[j] = col[cwork[j]];}
1825     ierr = MatSetValues(*B,1,&row[i],nz,cnew,vwork,INSERT_VALUES);CHKERRQ(ierr);
1826     ierr = MatRestoreRow(A,i,&nz,&cwork,&vwork);CHKERRQ(ierr);
1827   }
1828   ierr = PetscFree(cnew);CHKERRQ(ierr);
1829   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1830   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1831   ierr = ISRestoreIndices(irowp,&row);CHKERRQ(ierr);
1832   ierr = ISRestoreIndices(icolp,&col);CHKERRQ(ierr);
1833   ierr = ISDestroy(irowp);CHKERRQ(ierr);
1834   ierr = ISDestroy(icolp);CHKERRQ(ierr);
1835   PetscFunctionReturn(0);
1836 }
1837 
1838 #undef __FUNCT__
1839 #define __FUNCT__ "MatPrintHelp_SeqAIJ"
1840 int MatPrintHelp_SeqAIJ(Mat A)
1841 {
1842   static PetscTruth called = PETSC_FALSE;
1843   MPI_Comm          comm = A->comm;
1844   int               ierr;
1845 
1846   PetscFunctionBegin;
1847   if (called) {PetscFunctionReturn(0);} else called = PETSC_TRUE;
1848   ierr = (*PetscHelpPrintf)(comm," Options for MATSEQAIJ and MATMPIAIJ matrix formats (the defaults):\n");CHKERRQ(ierr);
1849   ierr = (*PetscHelpPrintf)(comm,"  -mat_lu_pivotthreshold <threshold>: Set pivoting threshold\n");CHKERRQ(ierr);
1850   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_oneindex: internal indices begin at 1 instead of the default 0.\n");CHKERRQ(ierr);
1851   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_no_inode: Do not use inodes\n");CHKERRQ(ierr);
1852   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_inode_limit <limit>: Set inode limit (max limit=5)\n");CHKERRQ(ierr);
1853 #if defined(PETSC_HAVE_ESSL)
1854   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_essl: Use IBM sparse LU factorization and solve.\n");CHKERRQ(ierr);
1855 #endif
1856 #if defined(PETSC_HAVE_LUSOL)
1857   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_lusol: Use the Stanford LUSOL sparse factorization and solve.\n");CHKERRQ(ierr);
1858 #endif
1859 #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
1860   ierr = (*PetscHelpPrintf)(comm,"  -mat_aij_matlab: Use Matlab engine sparse LU factorization and solve.\n");CHKERRQ(ierr);
1861 #endif
1862   PetscFunctionReturn(0);
1863 }
1864 EXTERN int MatEqual_SeqAIJ(Mat A,Mat B,PetscTruth* flg);
1865 EXTERN int MatFDColoringCreate_SeqAIJ(Mat,ISColoring,MatFDColoring);
1866 EXTERN int MatILUDTFactor_SeqAIJ(Mat,MatILUInfo*,IS,IS,Mat*);
1867 #undef __FUNCT__
1868 #define __FUNCT__ "MatCopy_SeqAIJ"
1869 int MatCopy_SeqAIJ(Mat A,Mat B,MatStructure str)
1870 {
1871   int        ierr;
1872   PetscTruth flg;
1873 
1874   PetscFunctionBegin;
1875   ierr = PetscTypeCompare((PetscObject)B,MATSEQAIJ,&flg);CHKERRQ(ierr);
1876   if (str == SAME_NONZERO_PATTERN && flg) {
1877     Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1878     Mat_SeqAIJ *b = (Mat_SeqAIJ*)B->data;
1879 
1880     if (a->i[A->m]+a->indexshift != b->i[B->m]+a->indexshift) {
1881       SETERRQ(1,"Number of nonzeros in two matrices are different");
1882     }
1883     ierr = PetscMemcpy(b->a,a->a,(a->i[A->m]+a->indexshift)*sizeof(PetscScalar));CHKERRQ(ierr);
1884   } else {
1885     ierr = MatCopy_Basic(A,B,str);CHKERRQ(ierr);
1886   }
1887   PetscFunctionReturn(0);
1888 }
1889 
1890 #undef __FUNCT__
1891 #define __FUNCT__ "MatSetUpPreallocation_SeqAIJ"
1892 int MatSetUpPreallocation_SeqAIJ(Mat A)
1893 {
1894   int        ierr;
1895 
1896   PetscFunctionBegin;
1897   ierr =  MatSeqAIJSetPreallocation(A,PETSC_DEFAULT,0);CHKERRQ(ierr);
1898   PetscFunctionReturn(0);
1899 }
1900 
1901 #undef __FUNCT__
1902 #define __FUNCT__ "MatGetArray_SeqAIJ"
1903 int MatGetArray_SeqAIJ(Mat A,PetscScalar **array)
1904 {
1905   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
1906   PetscFunctionBegin;
1907   *array = a->a;
1908   PetscFunctionReturn(0);
1909 }
1910 
1911 #undef __FUNCT__
1912 #define __FUNCT__ "MatRestoreArray_SeqAIJ"
1913 int MatRestoreArray_SeqAIJ(Mat A,PetscScalar **array)
1914 {
1915   PetscFunctionBegin;
1916   PetscFunctionReturn(0);
1917 }
1918 
1919 #undef __FUNCT__
1920 #define __FUNCT__ "MatFDColoringApply_SeqAIJ"
1921 int MatFDColoringApply_SeqAIJ(Mat J,MatFDColoring coloring,Vec x1,MatStructure *flag,void *sctx)
1922 {
1923   int           (*f)(void *,Vec,Vec,void*) = (int (*)(void *,Vec,Vec,void *))coloring->f;
1924   int           k,ierr,N,start,end,l,row,col,srow,**vscaleforrow,m1,m2;
1925   PetscScalar   dx,mone = -1.0,*y,*xx,*w3_array;
1926   PetscScalar   *vscale_array;
1927   PetscReal     epsilon = coloring->error_rel,umin = coloring->umin;
1928   Vec           w1,w2,w3;
1929   void          *fctx = coloring->fctx;
1930   PetscTruth    flg;
1931 
1932   PetscFunctionBegin;
1933   if (!coloring->w1) {
1934     ierr = VecDuplicate(x1,&coloring->w1);CHKERRQ(ierr);
1935     PetscLogObjectParent(coloring,coloring->w1);
1936     ierr = VecDuplicate(x1,&coloring->w2);CHKERRQ(ierr);
1937     PetscLogObjectParent(coloring,coloring->w2);
1938     ierr = VecDuplicate(x1,&coloring->w3);CHKERRQ(ierr);
1939     PetscLogObjectParent(coloring,coloring->w3);
1940   }
1941   w1 = coloring->w1; w2 = coloring->w2; w3 = coloring->w3;
1942 
1943   ierr = MatSetUnfactored(J);CHKERRQ(ierr);
1944   ierr = PetscOptionsHasName(coloring->prefix,"-mat_fd_coloring_dont_rezero",&flg);CHKERRQ(ierr);
1945   if (flg) {
1946     PetscLogInfo(coloring,"MatFDColoringApply_SeqAIJ: Not calling MatZeroEntries()\n");
1947   } else {
1948     ierr = MatZeroEntries(J);CHKERRQ(ierr);
1949   }
1950 
1951   ierr = VecGetOwnershipRange(x1,&start,&end);CHKERRQ(ierr);
1952   ierr = VecGetSize(x1,&N);CHKERRQ(ierr);
1953 
1954   /*
1955        This is a horrible, horrible, hack. See DMMGComputeJacobian_Multigrid() it inproperly sets
1956      coloring->F for the coarser grids from the finest
1957   */
1958   if (coloring->F) {
1959     ierr = VecGetLocalSize(coloring->F,&m1);CHKERRQ(ierr);
1960     ierr = VecGetLocalSize(w1,&m2);CHKERRQ(ierr);
1961     if (m1 != m2) {
1962       coloring->F = 0;
1963     }
1964   }
1965 
1966   if (coloring->F) {
1967     w1          = coloring->F;
1968     coloring->F = 0;
1969   } else {
1970     ierr = (*f)(sctx,x1,w1,fctx);CHKERRQ(ierr);
1971   }
1972 
1973   /*
1974       Compute all the scale factors and share with other processors
1975   */
1976   ierr = VecGetArray(x1,&xx);CHKERRQ(ierr);xx = xx - start;
1977   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);vscale_array = vscale_array - start;
1978   for (k=0; k<coloring->ncolors; k++) {
1979     /*
1980        Loop over each column associated with color adding the
1981        perturbation to the vector w3.
1982     */
1983     for (l=0; l<coloring->ncolumns[k]; l++) {
1984       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
1985       dx  = xx[col];
1986       if (dx == 0.0) dx = 1.0;
1987 #if !defined(PETSC_USE_COMPLEX)
1988       if (dx < umin && dx >= 0.0)      dx = umin;
1989       else if (dx < 0.0 && dx > -umin) dx = -umin;
1990 #else
1991       if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
1992       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
1993 #endif
1994       dx                *= epsilon;
1995       vscale_array[col] = 1.0/dx;
1996     }
1997   }
1998   vscale_array = vscale_array + start;ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
1999   ierr = VecGhostUpdateBegin(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2000   ierr = VecGhostUpdateEnd(coloring->vscale,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
2001 
2002   /*  ierr = VecView(coloring->vscale,PETSC_VIEWER_STDOUT_WORLD);
2003       ierr = VecView(x1,PETSC_VIEWER_STDOUT_WORLD);*/
2004 
2005   if (coloring->vscaleforrow) vscaleforrow = coloring->vscaleforrow;
2006   else                        vscaleforrow = coloring->columnsforrow;
2007 
2008   ierr = VecGetArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
2009   /*
2010       Loop over each color
2011   */
2012   for (k=0; k<coloring->ncolors; k++) {
2013     coloring->currentcolor = k;
2014     ierr = VecCopy(x1,w3);CHKERRQ(ierr);
2015     ierr = VecGetArray(w3,&w3_array);CHKERRQ(ierr);w3_array = w3_array - start;
2016     /*
2017        Loop over each column associated with color adding the
2018        perturbation to the vector w3.
2019     */
2020     for (l=0; l<coloring->ncolumns[k]; l++) {
2021       col = coloring->columns[k][l];    /* column of the matrix we are probing for */
2022       dx  = xx[col];
2023       if (dx == 0.0) dx = 1.0;
2024 #if !defined(PETSC_USE_COMPLEX)
2025       if (dx < umin && dx >= 0.0)      dx = umin;
2026       else if (dx < 0.0 && dx > -umin) dx = -umin;
2027 #else
2028       if (PetscAbsScalar(dx) < umin && PetscRealPart(dx) >= 0.0)     dx = umin;
2029       else if (PetscRealPart(dx) < 0.0 && PetscAbsScalar(dx) < umin) dx = -umin;
2030 #endif
2031       dx            *= epsilon;
2032       if (!PetscAbsScalar(dx)) SETERRQ(1,"Computed 0 differencing parameter");
2033       w3_array[col] += dx;
2034     }
2035     w3_array = w3_array + start; ierr = VecRestoreArray(w3,&w3_array);CHKERRQ(ierr);
2036 
2037     /*
2038        Evaluate function at x1 + dx (here dx is a vector of perturbations)
2039     */
2040 
2041     ierr = (*f)(sctx,w3,w2,fctx);CHKERRQ(ierr);
2042     ierr = VecAXPY(&mone,w1,w2);CHKERRQ(ierr);
2043 
2044     /*
2045        Loop over rows of vector, putting results into Jacobian matrix
2046     */
2047     ierr = VecGetArray(w2,&y);CHKERRQ(ierr);
2048     for (l=0; l<coloring->nrows[k]; l++) {
2049       row    = coloring->rows[k][l];
2050       col    = coloring->columnsforrow[k][l];
2051       y[row] *= vscale_array[vscaleforrow[k][l]];
2052       srow   = row + start;
2053       ierr   = MatSetValues_SeqAIJ(J,1,&srow,1,&col,y+row,INSERT_VALUES);CHKERRQ(ierr);
2054     }
2055     ierr = VecRestoreArray(w2,&y);CHKERRQ(ierr);
2056   }
2057   coloring->currentcolor = k;
2058   ierr = VecRestoreArray(coloring->vscale,&vscale_array);CHKERRQ(ierr);
2059   xx = xx + start; ierr  = VecRestoreArray(x1,&xx);CHKERRQ(ierr);
2060   ierr  = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2061   ierr  = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2062   PetscFunctionReturn(0);
2063 }
2064 
2065 #include "petscblaslapack.h"
2066 
2067 #undef __FUNCT__
2068 #define __FUNCT__ "MatAXPY_SeqAIJ"
2069 int MatAXPY_SeqAIJ(PetscScalar *a,Mat X,Mat Y,MatStructure str)
2070 {
2071   int        ierr,one=1;
2072   Mat_SeqAIJ *x  = (Mat_SeqAIJ *)X->data,*y = (Mat_SeqAIJ *)Y->data;
2073 
2074   PetscFunctionBegin;
2075   if (str == SAME_NONZERO_PATTERN) {
2076     BLaxpy_(&x->nz,a,x->a,&one,y->a,&one);
2077   } else {
2078     ierr = MatAXPY_Basic(a,X,Y,str);CHKERRQ(ierr);
2079   }
2080   PetscFunctionReturn(0);
2081 }
2082 
2083 
2084 /* -------------------------------------------------------------------*/
2085 static struct _MatOps MatOps_Values = {MatSetValues_SeqAIJ,
2086        MatGetRow_SeqAIJ,
2087        MatRestoreRow_SeqAIJ,
2088        MatMult_SeqAIJ,
2089        MatMultAdd_SeqAIJ,
2090        MatMultTranspose_SeqAIJ,
2091        MatMultTransposeAdd_SeqAIJ,
2092        MatSolve_SeqAIJ,
2093        MatSolveAdd_SeqAIJ,
2094        MatSolveTranspose_SeqAIJ,
2095        MatSolveTransposeAdd_SeqAIJ,
2096        MatLUFactor_SeqAIJ,
2097        0,
2098        MatRelax_SeqAIJ,
2099        MatTranspose_SeqAIJ,
2100        MatGetInfo_SeqAIJ,
2101        MatEqual_SeqAIJ,
2102        MatGetDiagonal_SeqAIJ,
2103        MatDiagonalScale_SeqAIJ,
2104        MatNorm_SeqAIJ,
2105        0,
2106        MatAssemblyEnd_SeqAIJ,
2107        MatCompress_SeqAIJ,
2108        MatSetOption_SeqAIJ,
2109        MatZeroEntries_SeqAIJ,
2110        MatZeroRows_SeqAIJ,
2111        MatLUFactorSymbolic_SeqAIJ,
2112        MatLUFactorNumeric_SeqAIJ,
2113        0,
2114        0,
2115        MatSetUpPreallocation_SeqAIJ,
2116        MatILUFactorSymbolic_SeqAIJ,
2117        0,
2118        MatGetArray_SeqAIJ,
2119        MatRestoreArray_SeqAIJ,
2120        MatDuplicate_SeqAIJ,
2121        0,
2122        0,
2123        MatILUFactor_SeqAIJ,
2124        0,
2125        MatAXPY_SeqAIJ,
2126        MatGetSubMatrices_SeqAIJ,
2127        MatIncreaseOverlap_SeqAIJ,
2128        MatGetValues_SeqAIJ,
2129        MatCopy_SeqAIJ,
2130        MatPrintHelp_SeqAIJ,
2131        MatScale_SeqAIJ,
2132        0,
2133        0,
2134        MatILUDTFactor_SeqAIJ,
2135        MatGetBlockSize_SeqAIJ,
2136        MatGetRowIJ_SeqAIJ,
2137        MatRestoreRowIJ_SeqAIJ,
2138        MatGetColumnIJ_SeqAIJ,
2139        MatRestoreColumnIJ_SeqAIJ,
2140        MatFDColoringCreate_SeqAIJ,
2141        0,
2142        0,
2143        MatPermute_SeqAIJ,
2144        0,
2145        0,
2146        MatDestroy_SeqAIJ,
2147        MatView_SeqAIJ,
2148        MatGetPetscMaps_Petsc,
2149        0,
2150        0,
2151        0,
2152        0,
2153        0,
2154        0,
2155        0,
2156        0,
2157        MatSetColoring_SeqAIJ,
2158        MatSetValuesAdic_SeqAIJ,
2159        MatSetValuesAdifor_SeqAIJ,
2160        MatFDColoringApply_SeqAIJ};
2161 
2162 EXTERN_C_BEGIN
2163 #undef __FUNCT__
2164 #define __FUNCT__ "MatSeqAIJSetColumnIndices_SeqAIJ"
2165 
2166 int MatSeqAIJSetColumnIndices_SeqAIJ(Mat mat,int *indices)
2167 {
2168   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
2169   int        i,nz,n;
2170 
2171   PetscFunctionBegin;
2172 
2173   nz = aij->maxnz;
2174   n  = mat->n;
2175   for (i=0; i<nz; i++) {
2176     aij->j[i] = indices[i];
2177   }
2178   aij->nz = nz;
2179   for (i=0; i<n; i++) {
2180     aij->ilen[i] = aij->imax[i];
2181   }
2182 
2183   PetscFunctionReturn(0);
2184 }
2185 EXTERN_C_END
2186 
2187 #undef __FUNCT__
2188 #define __FUNCT__ "MatSeqAIJSetColumnIndices"
2189 /*@
2190     MatSeqAIJSetColumnIndices - Set the column indices for all the rows
2191        in the matrix.
2192 
2193   Input Parameters:
2194 +  mat - the SeqAIJ matrix
2195 -  indices - the column indices
2196 
2197   Level: advanced
2198 
2199   Notes:
2200     This can be called if you have precomputed the nonzero structure of the
2201   matrix and want to provide it to the matrix object to improve the performance
2202   of the MatSetValues() operation.
2203 
2204     You MUST have set the correct numbers of nonzeros per row in the call to
2205   MatCreateSeqAIJ().
2206 
2207     MUST be called before any calls to MatSetValues();
2208 
2209     The indices should start with zero, not one.
2210 
2211 @*/
2212 int MatSeqAIJSetColumnIndices(Mat mat,int *indices)
2213 {
2214   int ierr,(*f)(Mat,int *);
2215 
2216   PetscFunctionBegin;
2217   PetscValidHeaderSpecific(mat,MAT_COOKIE);
2218   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatSeqAIJSetColumnIndices_C",(void (**)(void))&f);CHKERRQ(ierr);
2219   if (f) {
2220     ierr = (*f)(mat,indices);CHKERRQ(ierr);
2221   } else {
2222     SETERRQ(1,"Wrong type of matrix to set column indices");
2223   }
2224   PetscFunctionReturn(0);
2225 }
2226 
2227 /* ----------------------------------------------------------------------------------------*/
2228 
2229 EXTERN_C_BEGIN
2230 #undef __FUNCT__
2231 #define __FUNCT__ "MatStoreValues_SeqAIJ"
2232 int MatStoreValues_SeqAIJ(Mat mat)
2233 {
2234   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
2235   size_t       nz = aij->i[mat->m]+aij->indexshift,ierr;
2236 
2237   PetscFunctionBegin;
2238   if (aij->nonew != 1) {
2239     SETERRQ(1,"Must call MatSetOption(A,MAT_NO_NEW_NONZERO_LOCATIONS);first");
2240   }
2241 
2242   /* allocate space for values if not already there */
2243   if (!aij->saved_values) {
2244     ierr = PetscMalloc((nz+1)*sizeof(PetscScalar),&aij->saved_values);CHKERRQ(ierr);
2245   }
2246 
2247   /* copy values over */
2248   ierr = PetscMemcpy(aij->saved_values,aij->a,nz*sizeof(PetscScalar));CHKERRQ(ierr);
2249   PetscFunctionReturn(0);
2250 }
2251 EXTERN_C_END
2252 
2253 #undef __FUNCT__
2254 #define __FUNCT__ "MatStoreValues"
2255 /*@
2256     MatStoreValues - Stashes a copy of the matrix values; this allows, for
2257        example, reuse of the linear part of a Jacobian, while recomputing the
2258        nonlinear portion.
2259 
2260    Collect on Mat
2261 
2262   Input Parameters:
2263 .  mat - the matrix (currently on AIJ matrices support this option)
2264 
2265   Level: advanced
2266 
2267   Common Usage, with SNESSolve():
2268 $    Create Jacobian matrix
2269 $    Set linear terms into matrix
2270 $    Apply boundary conditions to matrix, at this time matrix must have
2271 $      final nonzero structure (i.e. setting the nonlinear terms and applying
2272 $      boundary conditions again will not change the nonzero structure
2273 $    ierr = MatSetOption(mat,MAT_NO_NEW_NONZERO_LOCATIONS);
2274 $    ierr = MatStoreValues(mat);
2275 $    Call SNESSetJacobian() with matrix
2276 $    In your Jacobian routine
2277 $      ierr = MatRetrieveValues(mat);
2278 $      Set nonlinear terms in matrix
2279 
2280   Common Usage without SNESSolve(), i.e. when you handle nonlinear solve yourself:
2281 $    // build linear portion of Jacobian
2282 $    ierr = MatSetOption(mat,MAT_NO_NEW_NONZERO_LOCATIONS);
2283 $    ierr = MatStoreValues(mat);
2284 $    loop over nonlinear iterations
2285 $       ierr = MatRetrieveValues(mat);
2286 $       // call MatSetValues(mat,...) to set nonliner portion of Jacobian
2287 $       // call MatAssemblyBegin/End() on matrix
2288 $       Solve linear system with Jacobian
2289 $    endloop
2290 
2291   Notes:
2292     Matrix must already be assemblied before calling this routine
2293     Must set the matrix option MatSetOption(mat,MAT_NO_NEW_NONZERO_LOCATIONS); before
2294     calling this routine.
2295 
2296 .seealso: MatRetrieveValues()
2297 
2298 @*/
2299 int MatStoreValues(Mat mat)
2300 {
2301   int ierr,(*f)(Mat);
2302 
2303   PetscFunctionBegin;
2304   PetscValidHeaderSpecific(mat,MAT_COOKIE);
2305   if (!mat->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
2306   if (mat->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
2307 
2308   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatStoreValues_C",(void (**)(void))&f);CHKERRQ(ierr);
2309   if (f) {
2310     ierr = (*f)(mat);CHKERRQ(ierr);
2311   } else {
2312     SETERRQ(1,"Wrong type of matrix to store values");
2313   }
2314   PetscFunctionReturn(0);
2315 }
2316 
2317 EXTERN_C_BEGIN
2318 #undef __FUNCT__
2319 #define __FUNCT__ "MatRetrieveValues_SeqAIJ"
2320 int MatRetrieveValues_SeqAIJ(Mat mat)
2321 {
2322   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)mat->data;
2323   int        nz = aij->i[mat->m]+aij->indexshift,ierr;
2324 
2325   PetscFunctionBegin;
2326   if (aij->nonew != 1) {
2327     SETERRQ(1,"Must call MatSetOption(A,MAT_NO_NEW_NONZERO_LOCATIONS);first");
2328   }
2329   if (!aij->saved_values) {
2330     SETERRQ(1,"Must call MatStoreValues(A);first");
2331   }
2332 
2333   /* copy values over */
2334   ierr = PetscMemcpy(aij->a,aij->saved_values,nz*sizeof(PetscScalar));CHKERRQ(ierr);
2335   PetscFunctionReturn(0);
2336 }
2337 EXTERN_C_END
2338 
2339 #undef __FUNCT__
2340 #define __FUNCT__ "MatRetrieveValues"
2341 /*@
2342     MatRetrieveValues - Retrieves the copy of the matrix values; this allows, for
2343        example, reuse of the linear part of a Jacobian, while recomputing the
2344        nonlinear portion.
2345 
2346    Collect on Mat
2347 
2348   Input Parameters:
2349 .  mat - the matrix (currently on AIJ matrices support this option)
2350 
2351   Level: advanced
2352 
2353 .seealso: MatStoreValues()
2354 
2355 @*/
2356 int MatRetrieveValues(Mat mat)
2357 {
2358   int ierr,(*f)(Mat);
2359 
2360   PetscFunctionBegin;
2361   PetscValidHeaderSpecific(mat,MAT_COOKIE);
2362   if (!mat->assembled) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
2363   if (mat->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
2364 
2365   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatRetrieveValues_C",(void (**)(void))&f);CHKERRQ(ierr);
2366   if (f) {
2367     ierr = (*f)(mat);CHKERRQ(ierr);
2368   } else {
2369     SETERRQ(1,"Wrong type of matrix to retrieve values");
2370   }
2371   PetscFunctionReturn(0);
2372 }
2373 
2374 /*
2375    This allows SeqAIJ matrices to be passed to the matlab engine
2376 */
2377 #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
2378 #include "engine.h"   /* Matlab include file */
2379 #include "mex.h"      /* Matlab include file */
2380 EXTERN_C_BEGIN
2381 #undef __FUNCT__
2382 #define __FUNCT__ "MatMatlabEnginePut_SeqAIJ"
2383 int MatMatlabEnginePut_SeqAIJ(PetscObject obj,void *engine)
2384 {
2385   int         ierr,i,*ai,*aj;
2386   Mat         B = (Mat)obj;
2387   mxArray     *mat;
2388   Mat_SeqAIJ  *aij = (Mat_SeqAIJ*)B->data;
2389 
2390   PetscFunctionBegin;
2391   mat  = mxCreateSparse(B->n,B->m,aij->nz,mxREAL);
2392   ierr = PetscMemcpy(mxGetPr(mat),aij->a,aij->nz*sizeof(PetscScalar));CHKERRQ(ierr);
2393   /* Matlab stores by column, not row so we pass in the transpose of the matrix */
2394   ierr = PetscMemcpy(mxGetIr(mat),aij->j,aij->nz*sizeof(int));CHKERRQ(ierr);
2395   ierr = PetscMemcpy(mxGetJc(mat),aij->i,(B->m+1)*sizeof(int));CHKERRQ(ierr);
2396 
2397   /* Matlab indices start at 0 for sparse (what a surprise) */
2398   if (aij->indexshift) {
2399     for (i=0; i<B->m+1; i++) {
2400       ai[i]--;
2401     }
2402     for (i=0; i<aij->nz; i++) {
2403       aj[i]--;
2404     }
2405   }
2406   ierr = PetscObjectName(obj);CHKERRQ(ierr);
2407   mxSetName(mat,obj->name);
2408   engPutArray((Engine *)engine,mat);
2409   PetscFunctionReturn(0);
2410 }
2411 EXTERN_C_END
2412 
2413 EXTERN_C_BEGIN
2414 #undef __FUNCT__
2415 #define __FUNCT__ "MatMatlabEngineGet_SeqAIJ"
2416 int MatMatlabEngineGet_SeqAIJ(PetscObject obj,void *engine)
2417 {
2418   int        ierr,ii;
2419   Mat        mat = (Mat)obj;
2420   Mat_SeqAIJ *aij = (Mat_SeqAIJ*)mat->data;
2421   mxArray    *mmat;
2422 
2423   PetscFunctionBegin;
2424   ierr = PetscFree(aij->a);CHKERRQ(ierr);
2425   aij->indexshift = 0;
2426 
2427   mmat = engGetArray((Engine *)engine,obj->name);
2428 
2429   aij->nz           = (mxGetJc(mmat))[mat->m];
2430   ierr              = PetscMalloc(((size_t) aij->nz)*(sizeof(int)+sizeof(PetscScalar))+(mat->m+1)*sizeof(int),&aij->a);CHKERRQ(ierr);
2431   aij->j            = (int*)(aij->a + aij->nz);
2432   aij->i            = aij->j + aij->nz;
2433   aij->singlemalloc = PETSC_TRUE;
2434   aij->freedata     = PETSC_TRUE;
2435 
2436   ierr = PetscMemcpy(aij->a,mxGetPr(mmat),aij->nz*sizeof(PetscScalar));CHKERRQ(ierr);
2437   /* Matlab stores by column, not row so we pass in the transpose of the matrix */
2438   ierr = PetscMemcpy(aij->j,mxGetIr(mmat),aij->nz*sizeof(int));CHKERRQ(ierr);
2439   ierr = PetscMemcpy(aij->i,mxGetJc(mmat),(mat->m+1)*sizeof(int));CHKERRQ(ierr);
2440 
2441   for (ii=0; ii<mat->m; ii++) {
2442     aij->ilen[ii] = aij->imax[ii] = aij->i[ii+1] - aij->i[ii];
2443   }
2444 
2445   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2446   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2447 
2448   PetscFunctionReturn(0);
2449 }
2450 EXTERN_C_END
2451 #endif
2452 
2453 /* --------------------------------------------------------------------------------*/
2454 #undef __FUNCT__
2455 #define __FUNCT__ "MatCreateSeqAIJ"
2456 /*@C
2457    MatCreateSeqAIJ - Creates a sparse matrix in AIJ (compressed row) format
2458    (the default parallel PETSc format).  For good matrix assembly performance
2459    the user should preallocate the matrix storage by setting the parameter nz
2460    (or the array nnz).  By setting these parameters accurately, performance
2461    during matrix assembly can be increased by more than a factor of 50.
2462 
2463    Collective on MPI_Comm
2464 
2465    Input Parameters:
2466 +  comm - MPI communicator, set to PETSC_COMM_SELF
2467 .  m - number of rows
2468 .  n - number of columns
2469 .  nz - number of nonzeros per row (same for all rows)
2470 -  nnz - array containing the number of nonzeros in the various rows
2471          (possibly different for each row) or PETSC_NULL
2472 
2473    Output Parameter:
2474 .  A - the matrix
2475 
2476    Notes:
2477    The AIJ format (also called the Yale sparse matrix format or
2478    compressed row storage), is fully compatible with standard Fortran 77
2479    storage.  That is, the stored row and column indices can begin at
2480    either one (as in Fortran) or zero.  See the users' manual for details.
2481 
2482    Specify the preallocated storage with either nz or nnz (not both).
2483    Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory
2484    allocation.  For large problems you MUST preallocate memory or you
2485    will get TERRIBLE performance, see the users' manual chapter on matrices.
2486 
2487    By default, this format uses inodes (identical nodes) when possible, to
2488    improve numerical efficiency of matrix-vector products and solves. We
2489    search for consecutive rows with the same nonzero structure, thereby
2490    reusing matrix information to achieve increased efficiency.
2491 
2492    Options Database Keys:
2493 +  -mat_aij_no_inode  - Do not use inodes
2494 .  -mat_aij_inode_limit <limit> - Sets inode limit (max limit=5)
2495 -  -mat_aij_oneindex - Internally use indexing starting at 1
2496         rather than 0.  Note that when calling MatSetValues(),
2497         the user still MUST index entries starting at 0!
2498 
2499    Level: intermediate
2500 
2501 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues(), MatSeqAIJSetColumnIndices(), MatCreateSeqAIJWithArrays()
2502 
2503 @*/
2504 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz,Mat *A)
2505 {
2506   int ierr;
2507 
2508   PetscFunctionBegin;
2509   ierr = MatCreate(comm,m,n,m,n,A);CHKERRQ(ierr);
2510   ierr = MatSetType(*A,MATSEQAIJ);CHKERRQ(ierr);
2511   ierr = MatSeqAIJSetPreallocation(*A,nz,nnz);CHKERRQ(ierr);
2512   PetscFunctionReturn(0);
2513 }
2514 
2515 #define SKIP_ALLOCATION -4
2516 
2517 #undef __FUNCT__
2518 #define __FUNCT__ "MatSeqAIJSetPreallocation"
2519 /*@C
2520    MatSeqAIJSetPreallocation - For good matrix assembly performance
2521    the user should preallocate the matrix storage by setting the parameter nz
2522    (or the array nnz).  By setting these parameters accurately, performance
2523    during matrix assembly can be increased by more than a factor of 50.
2524 
2525    Collective on MPI_Comm
2526 
2527    Input Parameters:
2528 +  comm - MPI communicator, set to PETSC_COMM_SELF
2529 .  m - number of rows
2530 .  n - number of columns
2531 .  nz - number of nonzeros per row (same for all rows)
2532 -  nnz - array containing the number of nonzeros in the various rows
2533          (possibly different for each row) or PETSC_NULL
2534 
2535    Output Parameter:
2536 .  A - the matrix
2537 
2538    Notes:
2539    The AIJ format (also called the Yale sparse matrix format or
2540    compressed row storage), is fully compatible with standard Fortran 77
2541    storage.  That is, the stored row and column indices can begin at
2542    either one (as in Fortran) or zero.  See the users' manual for details.
2543 
2544    Specify the preallocated storage with either nz or nnz (not both).
2545    Set nz=PETSC_DEFAULT and nnz=PETSC_NULL for PETSc to control dynamic memory
2546    allocation.  For large problems you MUST preallocate memory or you
2547    will get TERRIBLE performance, see the users' manual chapter on matrices.
2548 
2549    By default, this format uses inodes (identical nodes) when possible, to
2550    improve numerical efficiency of matrix-vector products and solves. We
2551    search for consecutive rows with the same nonzero structure, thereby
2552    reusing matrix information to achieve increased efficiency.
2553 
2554    Options Database Keys:
2555 +  -mat_aij_no_inode  - Do not use inodes
2556 .  -mat_aij_inode_limit <limit> - Sets inode limit (max limit=5)
2557 -  -mat_aij_oneindex - Internally use indexing starting at 1
2558         rather than 0.  Note that when calling MatSetValues(),
2559         the user still MUST index entries starting at 0!
2560 
2561    Level: intermediate
2562 
2563 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues(), MatSeqAIJSetColumnIndices(), MatCreateSeqAIJWithArrays()
2564 
2565 @*/
2566 int MatSeqAIJSetPreallocation(Mat B,int nz,int *nnz)
2567 {
2568   Mat_SeqAIJ *b;
2569   size_t     len = 0;
2570   PetscTruth flg2,skipallocation = PETSC_FALSE;
2571   int        i,ierr;
2572 
2573   PetscFunctionBegin;
2574   ierr = PetscTypeCompare((PetscObject)B,MATSEQAIJ,&flg2);CHKERRQ(ierr);
2575   if (!flg2) PetscFunctionReturn(0);
2576 
2577   if (nz == SKIP_ALLOCATION) {
2578     skipallocation = PETSC_TRUE;
2579     nz             = 0;
2580   }
2581 
2582   if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 5;
2583   if (nz < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"nz cannot be less than 0: value %d",nz);
2584   if (nnz) {
2585     for (i=0; i<B->m; i++) {
2586       if (nnz[i] < 0) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"nnz cannot be less than 0: local row %d value %d",i,nnz[i]);
2587       if (nnz[i] > B->n) SETERRQ3(PETSC_ERR_ARG_OUTOFRANGE,"nnz cannot be greater than row length: local row %d value %d rowlength %d",i,nnz[i],B->n);
2588     }
2589   }
2590 
2591   B->preallocated = PETSC_TRUE;
2592   b = (Mat_SeqAIJ*)B->data;
2593 
2594   ierr = PetscMalloc((B->m+1)*sizeof(int),&b->imax);CHKERRQ(ierr);
2595   if (!nnz) {
2596     if (nz == PETSC_DEFAULT || nz == PETSC_DECIDE) nz = 10;
2597     else if (nz <= 0)        nz = 1;
2598     for (i=0; i<B->m; i++) b->imax[i] = nz;
2599     nz = nz*B->m;
2600   } else {
2601     nz = 0;
2602     for (i=0; i<B->m; i++) {b->imax[i] = nnz[i]; nz += nnz[i];}
2603   }
2604 
2605   if (!skipallocation) {
2606     /* allocate the matrix space */
2607     len             = ((size_t) nz)*(sizeof(int) + sizeof(PetscScalar)) + (B->m+1)*sizeof(int);
2608     ierr            = PetscMalloc(len,&b->a);CHKERRQ(ierr);
2609     b->j            = (int*)(b->a + nz);
2610     ierr            = PetscMemzero(b->j,nz*sizeof(int));CHKERRQ(ierr);
2611     b->i            = b->j + nz;
2612     b->i[0] = -b->indexshift;
2613     for (i=1; i<B->m+1; i++) {
2614       b->i[i] = b->i[i-1] + b->imax[i-1];
2615     }
2616     b->singlemalloc = PETSC_TRUE;
2617     b->freedata     = PETSC_TRUE;
2618   } else {
2619     b->freedata     = PETSC_FALSE;
2620   }
2621 
2622   /* b->ilen will count nonzeros in each row so far. */
2623   ierr = PetscMalloc((B->m+1)*sizeof(int),&b->ilen);CHKERRQ(ierr);
2624   PetscLogObjectMemory(B,len+2*(B->m+1)*sizeof(int)+sizeof(struct _p_Mat)+sizeof(Mat_SeqAIJ));
2625   for (i=0; i<B->m; i++) { b->ilen[i] = 0;}
2626 
2627   b->nz                = 0;
2628   b->maxnz             = nz;
2629   B->info.nz_unneeded  = (double)b->maxnz;
2630   PetscFunctionReturn(0);
2631 }
2632 
2633 EXTERN int RegisterApplyPtAPRoutines_Private(Mat);
2634 
2635 EXTERN_C_BEGIN
2636 #undef __FUNCT__
2637 #define __FUNCT__ "MatCreate_SeqAIJ"
2638 int MatCreate_SeqAIJ(Mat B)
2639 {
2640   Mat_SeqAIJ *b;
2641   int        ierr,size;
2642   PetscTruth flg;
2643 
2644   PetscFunctionBegin;
2645   ierr = MPI_Comm_size(B->comm,&size);CHKERRQ(ierr);
2646   if (size > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Comm must be of size 1");
2647 
2648   B->m = B->M = PetscMax(B->m,B->M);
2649   B->n = B->N = PetscMax(B->n,B->N);
2650 
2651   ierr = PetscNew(Mat_SeqAIJ,&b);CHKERRQ(ierr);
2652   B->data             = (void*)b;
2653   ierr = PetscMemzero(b,sizeof(Mat_SeqAIJ));CHKERRQ(ierr);
2654   ierr = PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
2655   B->factor           = 0;
2656   B->lupivotthreshold = 1.0;
2657   B->mapping          = 0;
2658   ierr = PetscOptionsGetReal(B->prefix,"-mat_lu_pivotthreshold",&B->lupivotthreshold,PETSC_NULL);CHKERRQ(ierr);
2659   ierr = PetscOptionsHasName(B->prefix,"-pc_ilu_preserve_row_sums",&b->ilu_preserve_row_sums);CHKERRQ(ierr);
2660   b->row              = 0;
2661   b->col              = 0;
2662   b->icol             = 0;
2663   b->indexshift       = 0;
2664   b->reallocs         = 0;
2665   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_oneindex",&flg);CHKERRQ(ierr);
2666   if (flg) b->indexshift = -1;
2667 
2668   ierr = PetscMapCreateMPI(B->comm,B->m,B->m,&B->rmap);CHKERRQ(ierr);
2669   ierr = PetscMapCreateMPI(B->comm,B->n,B->n,&B->cmap);CHKERRQ(ierr);
2670 
2671   b->sorted            = PETSC_FALSE;
2672   b->ignorezeroentries = PETSC_FALSE;
2673   b->roworiented       = PETSC_TRUE;
2674   b->nonew             = 0;
2675   b->diag              = 0;
2676   b->solve_work        = 0;
2677   B->spptr             = 0;
2678   b->inode.use         = PETSC_TRUE;
2679   b->inode.node_count  = 0;
2680   b->inode.size        = 0;
2681   b->inode.limit       = 5;
2682   b->inode.max_limit   = 5;
2683   b->saved_values      = 0;
2684   b->idiag             = 0;
2685   b->ssor              = 0;
2686   b->keepzeroedrows    = PETSC_FALSE;
2687 
2688   ierr = PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJ);CHKERRQ(ierr);
2689 
2690 #if defined(PETSC_HAVE_SUPERLU)
2691   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_superlu",&flg);CHKERRQ(ierr);
2692   if (flg) { ierr = MatUseSuperLU_SeqAIJ(B);CHKERRQ(ierr); }
2693 #endif
2694 
2695   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_essl",&flg);CHKERRQ(ierr);
2696   if (flg) { ierr = MatUseEssl_SeqAIJ(B);CHKERRQ(ierr); }
2697   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_lusol",&flg);CHKERRQ(ierr);
2698   if (flg) { ierr = MatUseLUSOL_SeqAIJ(B);CHKERRQ(ierr); }
2699   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_matlab",&flg);CHKERRQ(ierr);
2700   if (flg) {ierr = MatUseMatlab_SeqAIJ(B);CHKERRQ(ierr);}
2701   ierr = PetscOptionsHasName(B->prefix,"-mat_aij_dxml",&flg);CHKERRQ(ierr);
2702   if (flg) {
2703     if (!b->indexshift) SETERRQ(PETSC_ERR_LIB,"need -mat_aij_oneindex with -mat_aij_dxml");
2704     ierr = MatUseDXML_SeqAIJ(B);CHKERRQ(ierr);
2705   }
2706   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSeqAIJSetColumnIndices_C",
2707                                      "MatSeqAIJSetColumnIndices_SeqAIJ",
2708                                      MatSeqAIJSetColumnIndices_SeqAIJ);CHKERRQ(ierr);
2709   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatStoreValues_C",
2710                                      "MatStoreValues_SeqAIJ",
2711                                      MatStoreValues_SeqAIJ);CHKERRQ(ierr);
2712   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatRetrieveValues_C",
2713                                      "MatRetrieveValues_SeqAIJ",
2714                                      MatRetrieveValues_SeqAIJ);CHKERRQ(ierr);
2715 #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
2716   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"PetscMatlabEnginePut_C","MatMatlabEnginePut_SeqAIJ",MatMatlabEnginePut_SeqAIJ);CHKERRQ(ierr);
2717   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"PetscMatlabEngineGet_C","MatMatlabEngineGet_SeqAIJ",MatMatlabEngineGet_SeqAIJ);CHKERRQ(ierr);
2718 #endif
2719   ierr = RegisterApplyPtAPRoutines_Private(B);CHKERRQ(ierr);
2720   PetscFunctionReturn(0);
2721 }
2722 EXTERN_C_END
2723 
2724 #undef __FUNCT__
2725 #define __FUNCT__ "MatDuplicate_SeqAIJ"
2726 int MatDuplicate_SeqAIJ(Mat A,MatDuplicateOption cpvalues,Mat *B)
2727 {
2728   Mat        C;
2729   Mat_SeqAIJ *c,*a = (Mat_SeqAIJ*)A->data;
2730   int        i,m = A->m,shift = a->indexshift,ierr;
2731   size_t     len;
2732 
2733   PetscFunctionBegin;
2734   *B = 0;
2735   ierr = MatCreate(A->comm,A->m,A->n,A->m,A->n,&C);CHKERRQ(ierr);
2736   ierr = MatSetType(C,MATSEQAIJ);CHKERRQ(ierr);
2737   c    = (Mat_SeqAIJ*)C->data;
2738 
2739   C->factor         = A->factor;
2740   c->row            = 0;
2741   c->col            = 0;
2742   c->icol           = 0;
2743   c->indexshift     = shift;
2744   c->keepzeroedrows = a->keepzeroedrows;
2745   C->assembled      = PETSC_TRUE;
2746 
2747   C->M          = A->m;
2748   C->N          = A->n;
2749 
2750   ierr = PetscMalloc((m+1)*sizeof(int),&c->imax);CHKERRQ(ierr);
2751   ierr = PetscMalloc((m+1)*sizeof(int),&c->ilen);CHKERRQ(ierr);
2752   for (i=0; i<m; i++) {
2753     c->imax[i] = a->imax[i];
2754     c->ilen[i] = a->ilen[i];
2755   }
2756 
2757   /* allocate the matrix space */
2758   c->singlemalloc = PETSC_TRUE;
2759   len   = ((size_t) (m+1))*sizeof(int)+(a->i[m])*(sizeof(PetscScalar)+sizeof(int));
2760   ierr  = PetscMalloc(len,&c->a);CHKERRQ(ierr);
2761   c->j  = (int*)(c->a + a->i[m] + shift);
2762   c->i  = c->j + a->i[m] + shift;
2763   ierr = PetscMemcpy(c->i,a->i,(m+1)*sizeof(int));CHKERRQ(ierr);
2764   if (m > 0) {
2765     ierr = PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int));CHKERRQ(ierr);
2766     if (cpvalues == MAT_COPY_VALUES) {
2767       ierr = PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(PetscScalar));CHKERRQ(ierr);
2768     } else {
2769       ierr = PetscMemzero(c->a,(a->i[m]+shift)*sizeof(PetscScalar));CHKERRQ(ierr);
2770     }
2771   }
2772 
2773   PetscLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _p_Mat)+sizeof(Mat_SeqAIJ));
2774   c->sorted      = a->sorted;
2775   c->roworiented = a->roworiented;
2776   c->nonew       = a->nonew;
2777   c->ilu_preserve_row_sums = a->ilu_preserve_row_sums;
2778   c->saved_values = 0;
2779   c->idiag        = 0;
2780   c->ssor         = 0;
2781   c->ignorezeroentries = a->ignorezeroentries;
2782   c->freedata     = PETSC_TRUE;
2783 
2784   if (a->diag) {
2785     ierr = PetscMalloc((m+1)*sizeof(int),&c->diag);CHKERRQ(ierr);
2786     PetscLogObjectMemory(C,(m+1)*sizeof(int));
2787     for (i=0; i<m; i++) {
2788       c->diag[i] = a->diag[i];
2789     }
2790   } else c->diag        = 0;
2791   c->inode.use          = a->inode.use;
2792   c->inode.limit        = a->inode.limit;
2793   c->inode.max_limit    = a->inode.max_limit;
2794   if (a->inode.size){
2795     ierr                = PetscMalloc((m+1)*sizeof(int),&c->inode.size);CHKERRQ(ierr);
2796     c->inode.node_count = a->inode.node_count;
2797     ierr                = PetscMemcpy(c->inode.size,a->inode.size,(m+1)*sizeof(int));CHKERRQ(ierr);
2798   } else {
2799     c->inode.size       = 0;
2800     c->inode.node_count = 0;
2801   }
2802   c->nz                 = a->nz;
2803   c->maxnz              = a->maxnz;
2804   c->solve_work         = 0;
2805   C->spptr              = 0;      /* Dangerous -I'm throwing away a->spptr */
2806   C->preallocated       = PETSC_TRUE;
2807 
2808   *B = C;
2809   ierr = PetscFListDuplicate(A->qlist,&C->qlist);CHKERRQ(ierr);
2810   PetscFunctionReturn(0);
2811 }
2812 
2813 EXTERN_C_BEGIN
2814 #undef __FUNCT__
2815 #define __FUNCT__ "MatLoad_SeqAIJ"
2816 int MatLoad_SeqAIJ(PetscViewer viewer,MatType type,Mat *A)
2817 {
2818   Mat_SeqAIJ   *a;
2819   Mat          B;
2820   int          i,nz,ierr,fd,header[4],size,*rowlengths = 0,M,N,shift;
2821   MPI_Comm     comm;
2822 
2823   PetscFunctionBegin;
2824   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
2825   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
2826   if (size > 1) SETERRQ(PETSC_ERR_ARG_SIZ,"view must have one processor");
2827   ierr = PetscViewerBinaryGetDescriptor(viewer,&fd);CHKERRQ(ierr);
2828   ierr = PetscBinaryRead(fd,header,4,PETSC_INT);CHKERRQ(ierr);
2829   if (header[0] != MAT_FILE_COOKIE) SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"not matrix object in file");
2830   M = header[1]; N = header[2]; nz = header[3];
2831 
2832   if (nz < 0) {
2833     SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"Matrix stored in special format on disk,cannot load as SeqAIJ");
2834   }
2835 
2836   /* read in row lengths */
2837   ierr = PetscMalloc(M*sizeof(int),&rowlengths);CHKERRQ(ierr);
2838   ierr = PetscBinaryRead(fd,rowlengths,M,PETSC_INT);CHKERRQ(ierr);
2839 
2840   /* create our matrix */
2841   ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A);CHKERRQ(ierr);
2842   B = *A;
2843   a = (Mat_SeqAIJ*)B->data;
2844   shift = a->indexshift;
2845 
2846   /* read in column indices and adjust for Fortran indexing*/
2847   ierr = PetscBinaryRead(fd,a->j,nz,PETSC_INT);CHKERRQ(ierr);
2848   if (shift) {
2849     for (i=0; i<nz; i++) {
2850       a->j[i] += 1;
2851     }
2852   }
2853 
2854   /* read in nonzero values */
2855   ierr = PetscBinaryRead(fd,a->a,nz,PETSC_SCALAR);CHKERRQ(ierr);
2856 
2857   /* set matrix "i" values */
2858   a->i[0] = -shift;
2859   for (i=1; i<= M; i++) {
2860     a->i[i]      = a->i[i-1] + rowlengths[i-1];
2861     a->ilen[i-1] = rowlengths[i-1];
2862   }
2863   ierr = PetscFree(rowlengths);CHKERRQ(ierr);
2864 
2865   ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2866   ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2867   PetscFunctionReturn(0);
2868 }
2869 EXTERN_C_END
2870 
2871 #undef __FUNCT__
2872 #define __FUNCT__ "MatEqual_SeqAIJ"
2873 int MatEqual_SeqAIJ(Mat A,Mat B,PetscTruth* flg)
2874 {
2875   Mat_SeqAIJ *a = (Mat_SeqAIJ *)A->data,*b = (Mat_SeqAIJ *)B->data;
2876   int        ierr;
2877   PetscTruth flag;
2878 
2879   PetscFunctionBegin;
2880   ierr = PetscTypeCompare((PetscObject)B,MATSEQAIJ,&flag);CHKERRQ(ierr);
2881   if (!flag) SETERRQ(PETSC_ERR_ARG_INCOMP,"Matrices must be same type");
2882 
2883   /* If the  matrix dimensions are not equal,or no of nonzeros or shift */
2884   if ((A->m != B->m) || (A->n != B->n) ||(a->nz != b->nz)|| (a->indexshift != b->indexshift)) {
2885     *flg = PETSC_FALSE;
2886     PetscFunctionReturn(0);
2887   }
2888 
2889   /* if the a->i are the same */
2890   ierr = PetscMemcmp(a->i,b->i,(A->m+1)*sizeof(int),flg);CHKERRQ(ierr);
2891   if (*flg == PETSC_FALSE) PetscFunctionReturn(0);
2892 
2893   /* if a->j are the same */
2894   ierr = PetscMemcmp(a->j,b->j,(a->nz)*sizeof(int),flg);CHKERRQ(ierr);
2895   if (*flg == PETSC_FALSE) PetscFunctionReturn(0);
2896 
2897   /* if a->a are the same */
2898   ierr = PetscMemcmp(a->a,b->a,(a->nz)*sizeof(PetscScalar),flg);CHKERRQ(ierr);
2899 
2900   PetscFunctionReturn(0);
2901 
2902 }
2903 
2904 #undef __FUNCT__
2905 #define __FUNCT__ "MatCreateSeqAIJWithArrays"
2906 /*@C
2907      MatCreateSeqAIJWithArrays - Creates an sequential AIJ matrix using matrix elements (in CSR format)
2908               provided by the user.
2909 
2910       Coolective on MPI_Comm
2911 
2912    Input Parameters:
2913 +   comm - must be an MPI communicator of size 1
2914 .   m - number of rows
2915 .   n - number of columns
2916 .   i - row indices
2917 .   j - column indices
2918 -   a - matrix values
2919 
2920    Output Parameter:
2921 .   mat - the matrix
2922 
2923    Level: intermediate
2924 
2925    Notes:
2926        The i, j, and a arrays are not copied by this routine, the user must free these arrays
2927     once the matrix is destroyed
2928 
2929        You cannot set new nonzero locations into this matrix, that will generate an error.
2930 
2931        The i and j indices can be either 0- or 1 based
2932 
2933 .seealso: MatCreate(), MatCreateMPIAIJ(), MatCreateSeqAIJ()
2934 
2935 @*/
2936 int MatCreateSeqAIJWithArrays(MPI_Comm comm,int m,int n,int* i,int*j,PetscScalar *a,Mat *mat)
2937 {
2938   int        ierr,ii;
2939   Mat_SeqAIJ *aij;
2940 
2941   PetscFunctionBegin;
2942   ierr = MatCreateSeqAIJ(comm,m,n,SKIP_ALLOCATION,0,mat);CHKERRQ(ierr);
2943   aij  = (Mat_SeqAIJ*)(*mat)->data;
2944 
2945   if (i[0] == 1) {
2946     aij->indexshift = -1;
2947   } else if (i[0]) {
2948     SETERRQ(1,"i (row indices) do not start with 0 or 1");
2949   }
2950   aij->i = i;
2951   aij->j = j;
2952   aij->a = a;
2953   aij->singlemalloc = PETSC_FALSE;
2954   aij->nonew        = -1;             /*this indicates that inserting a new value in the matrix that generates a new nonzero is an error*/
2955   aij->freedata     = PETSC_FALSE;
2956 
2957   for (ii=0; ii<m; ii++) {
2958     aij->ilen[ii] = aij->imax[ii] = i[ii+1] - i[ii];
2959 #if defined(PETSC_USE_BOPT_g)
2960     if (i[ii+1] - i[ii] < 0) SETERRQ2(1,"Negative row length in i (row indices) row = %d length = %d",ii,i[ii+1] - i[ii]);
2961 #endif
2962   }
2963 #if defined(PETSC_USE_BOPT_g)
2964   for (ii=0; ii<aij->i[m]; ii++) {
2965     if (j[ii] < -aij->indexshift) SETERRQ2(1,"Negative column index at location = %d index = %d",ii,j[ii]);
2966     if (j[ii] > n - 1 -aij->indexshift) SETERRQ2(1,"Column index to large at location = %d index = %d",ii,j[ii]);
2967   }
2968 #endif
2969 
2970   /* changes indices to start at 0 */
2971   if (i[0]) {
2972     aij->indexshift = 0;
2973     for (ii=0; ii<m; ii++) {
2974       i[ii]--;
2975     }
2976     for (ii=0; ii<i[m]; ii++) {
2977       j[ii]--;
2978     }
2979   }
2980 
2981   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2982   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2983   PetscFunctionReturn(0);
2984 }
2985 
2986 #undef __FUNCT__
2987 #define __FUNCT__ "MatSetColoring_SeqAIJ"
2988 int MatSetColoring_SeqAIJ(Mat A,ISColoring coloring)
2989 {
2990   int        ierr;
2991   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
2992 
2993   PetscFunctionBegin;
2994   if (coloring->ctype == IS_COLORING_LOCAL) {
2995     ierr        = ISColoringReference(coloring);CHKERRQ(ierr);
2996     a->coloring = coloring;
2997   } else if (coloring->ctype == IS_COLORING_GHOSTED) {
2998     int        *colors,i,*larray;
2999     ISColoring ocoloring;
3000 
3001     /* set coloring for diagonal portion */
3002     ierr = PetscMalloc((A->n+1)*sizeof(int),&larray);CHKERRQ(ierr);
3003     for (i=0; i<A->n; i++) {
3004       larray[i] = i;
3005     }
3006     ierr = ISGlobalToLocalMappingApply(A->mapping,IS_GTOLM_MASK,A->n,larray,PETSC_NULL,larray);CHKERRQ(ierr);
3007     ierr = PetscMalloc((A->n+1)*sizeof(int),&colors);CHKERRQ(ierr);
3008     for (i=0; i<A->n; i++) {
3009       colors[i] = coloring->colors[larray[i]];
3010     }
3011     ierr = PetscFree(larray);CHKERRQ(ierr);
3012     ierr = ISColoringCreate(PETSC_COMM_SELF,A->n,colors,&ocoloring);CHKERRQ(ierr);
3013     a->coloring = ocoloring;
3014   }
3015   PetscFunctionReturn(0);
3016 }
3017 
3018 #if defined(PETSC_HAVE_ADIC) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
3019 EXTERN_C_BEGIN
3020 #include "adic/ad_utils.h"
3021 EXTERN_C_END
3022 
3023 #undef __FUNCT__
3024 #define __FUNCT__ "MatSetValuesAdic_SeqAIJ"
3025 int MatSetValuesAdic_SeqAIJ(Mat A,void *advalues)
3026 {
3027   Mat_SeqAIJ  *a = (Mat_SeqAIJ*)A->data;
3028   int         m = A->m,*ii = a->i,*jj = a->j,nz,i,*color,j,nlen;
3029   PetscScalar *v = a->a,*values;
3030   char        *cadvalues = (char *)advalues;
3031 
3032   PetscFunctionBegin;
3033   if (!a->coloring) SETERRQ(1,"Coloring not set for matrix");
3034   nlen  = PetscADGetDerivTypeSize();
3035   color = a->coloring->colors;
3036   /* loop over rows */
3037   for (i=0; i<m; i++) {
3038     nz = ii[i+1] - ii[i];
3039     /* loop over columns putting computed value into matrix */
3040     values = PetscADGetGradArray(cadvalues);
3041     for (j=0; j<nz; j++) {
3042       *v++ = values[color[*jj++]];
3043     }
3044     cadvalues += nlen; /* jump to next row of derivatives */
3045   }
3046   PetscFunctionReturn(0);
3047 }
3048 
3049 #else
3050 
3051 #undef __FUNCT__
3052 #define __FUNCT__ "MatSetValuesAdic_SeqAIJ"
3053 int MatSetValuesAdic_SeqAIJ(Mat A,void *advalues)
3054 {
3055   PetscFunctionBegin;
3056   SETERRQ(1,"PETSc installed without ADIC");
3057 }
3058 
3059 #endif
3060 
3061 #undef __FUNCT__
3062 #define __FUNCT__ "MatSetValuesAdifor_SeqAIJ"
3063 int MatSetValuesAdifor_SeqAIJ(Mat A,int nl,void *advalues)
3064 {
3065   Mat_SeqAIJ   *a = (Mat_SeqAIJ*)A->data;
3066   int          m = A->m,*ii = a->i,*jj = a->j,nz,i,*color,j;
3067   PetscScalar  *v = a->a,*values = (PetscScalar *)advalues;
3068 
3069   PetscFunctionBegin;
3070   if (!a->coloring) SETERRQ(1,"Coloring not set for matrix");
3071   color = a->coloring->colors;
3072   /* loop over rows */
3073   for (i=0; i<m; i++) {
3074     nz = ii[i+1] - ii[i];
3075     /* loop over columns putting computed value into matrix */
3076     for (j=0; j<nz; j++) {
3077       *v++ = values[color[*jj++]];
3078     }
3079     values += nl; /* jump to next row of derivatives */
3080   }
3081   PetscFunctionReturn(0);
3082 }
3083 
3084