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