xref: /petsc/src/mat/impls/aij/seq/aij.c (revision 7a2efc394589b136789e5cec3f47c1a804ea8ac0)
1 #ifndef lint
2 static char vcid[] = "$Id: aij.c,v 1.92 1995/09/30 19:28:44 bsmith Exp bsmith $";
3 #endif
4 
5 #include "aij.h"
6 #include "vec/vecimpl.h"
7 #include "inline/spops.h"
8 
9 extern int MatToSymmetricIJ_SeqAIJ(Mat_SeqAIJ*,int**,int**);
10 
11 static int MatGetReordering_SeqAIJ(Mat A,MatOrdering type,IS *rperm, IS *cperm)
12 {
13   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
14   int        ierr, *ia, *ja;
15 
16   if (!a->assembled) SETERRQ(1,"MatGetReordering_SeqAIJ:Not for unassembled matrix");
17 
18   ierr = MatToSymmetricIJ_SeqAIJ( a, &ia, &ja ); CHKERRQ(ierr);
19   ierr = MatGetReordering_IJ(a->n,ia,ja,type,rperm,cperm); CHKERRQ(ierr);
20   PETSCFREE(ia); PETSCFREE(ja);
21   return 0;
22 }
23 
24 #define CHUNKSIZE   10
25 
26 /* This version has row oriented v  */
27 static int MatSetValues_SeqAIJ(Mat A,int m,int *im,int n,int *in,Scalar *v,InsertMode is)
28 {
29   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
30   int        *rp,k,low,high,t,ii,row,nrow,i,col,l,rmax, N, sorted = a->sorted;
31   int        *imax = a->imax, *ai = a->i, *ailen = a->ilen;
32   int        *aj = a->j, nonew = a->nonew;
33   Scalar     *ap,value, *aa = a->a;
34   int        shift = a->indexshift;
35 
36   for ( k=0; k<m; k++ ) { /* loop over added rows */
37     row  = im[k];
38     if (row < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative row");
39     if (row >= a->m) SETERRQ(1,"MatSetValues_SeqAIJ:Row too large");
40     rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
41     rmax = imax[row]; nrow = ailen[row];
42     low = 0;
43     for ( l=0; l<n; l++ ) { /* loop over added columns */
44       if (in[l] < 0) SETERRQ(1,"MatSetValues_SeqAIJ:Negative column");
45       if (in[l] >= a->n) SETERRQ(1,"MatSetValues_SeqAIJ:Column too large");
46       col = in[l] - shift; value = *v++;
47       if (!sorted) low = 0; high = nrow;
48       while (high-low > 5) {
49         t = (low+high)/2;
50         if (rp[t] > col) high = t;
51         else             low  = t;
52       }
53       for ( i=low; i<high; i++ ) {
54         if (rp[i] > col) break;
55         if (rp[i] == col) {
56           if (is == ADD_VALUES) ap[i] += value;
57           else                  ap[i] = value;
58           goto noinsert;
59         }
60       }
61       if (nonew) goto noinsert;
62       if (nrow >= rmax) {
63         /* there is no extra room in row, therefore enlarge */
64         int    new_nz = ai[a->m] + CHUNKSIZE,len,*new_i,*new_j;
65         Scalar *new_a;
66 
67         /* malloc new storage space */
68         len     = new_nz*(sizeof(int)+sizeof(Scalar))+(a->m+1)*sizeof(int);
69         new_a   = (Scalar *) PETSCMALLOC( len ); CHKPTRQ(new_a);
70         new_j   = (int *) (new_a + new_nz);
71         new_i   = new_j + new_nz;
72 
73         /* copy over old data into new slots */
74         for ( ii=0; ii<row+1; ii++ ) {new_i[ii] = ai[ii];}
75         for ( ii=row+1; ii<a->m+1; ii++ ) {new_i[ii] = ai[ii]+CHUNKSIZE;}
76         PetscMemcpy(new_j,aj,(ai[row]+nrow+shift)*sizeof(int));
77         len = (new_nz - CHUNKSIZE - ai[row] - nrow - shift);
78         PetscMemcpy(new_j+ai[row]+shift+nrow+CHUNKSIZE,aj+ai[row]+shift+nrow,
79                                                            len*sizeof(int));
80         PetscMemcpy(new_a,aa,(ai[row]+nrow+shift)*sizeof(Scalar));
81         PetscMemcpy(new_a+ai[row]+shift+nrow+CHUNKSIZE,aa+ai[row]+shift+nrow,
82                                                            len*sizeof(Scalar));
83         /* free up old matrix storage */
84         PETSCFREE(a->a);
85         if (!a->singlemalloc) {PETSCFREE(a->i);PETSCFREE(a->j);}
86         aa = a->a = new_a; ai = a->i = new_i; aj = a->j = new_j;
87         a->singlemalloc = 1;
88 
89         rp   = aj + ai[row] + shift; ap = aa + ai[row] + shift;
90         rmax = imax[row] = imax[row] + CHUNKSIZE;
91         PLogObjectMemory(A,CHUNKSIZE*(sizeof(int) + sizeof(Scalar)));
92         a->maxnz += CHUNKSIZE;
93       }
94       N = nrow++ - 1; a->nz++;
95       /* shift up all the later entries in this row */
96       for ( ii=N; ii>=i; ii-- ) {
97         rp[ii+1] = rp[ii];
98         ap[ii+1] = ap[ii];
99       }
100       rp[i] = col;
101       ap[i] = value;
102       noinsert:;
103       low = i + 1;
104     }
105     ailen[row] = nrow;
106   }
107   return 0;
108 }
109 
110 #include "draw.h"
111 #include "pinclude/pviewer.h"
112 #include "sysio.h"
113 
114 static int MatView_SeqAIJ_Binary(Mat A,Viewer viewer)
115 {
116   Mat_SeqAIJ  *a = (Mat_SeqAIJ *) A->data;
117   int         i,fd,*col_lens,ierr;
118 
119   ierr = ViewerFileGetDescriptor_Private(viewer,&fd); CHKERRQ(ierr);
120 
121   col_lens    = (int *) PETSCMALLOC( (4+a->nz)*sizeof(int) ); CHKPTRQ(col_lens);
122   col_lens[0] = MAT_COOKIE;
123   col_lens[1] = a->m;
124   col_lens[2] = a->n;
125   col_lens[3] = a->nz;
126 
127   /* store lengths of each row and write (including header) to file */
128   for ( i=0; i<a->m; i++ ) {
129     col_lens[4+i] = a->i[i+1] - a->i[i];
130   }
131   ierr = SYWrite(fd,col_lens,4+a->m,SYINT,1); CHKERRQ(ierr);
132   PETSCFREE(col_lens);
133 
134   /* store column indices (zero start index) */
135   if (a->indexshift) {
136     for ( i=0; i<a->nz; i++ ) a->j[i]--;
137   }
138   ierr = SYWrite(fd,a->j,a->nz,SYINT,0); CHKERRQ(ierr);
139   if (a->indexshift) {
140     for ( i=0; i<a->nz; i++ ) a->j[i]++;
141   }
142 
143   /* store nonzero values */
144   ierr = SYWrite(fd,a->a,a->nz,SYSCALAR,0); CHKERRQ(ierr);
145   return 0;
146 }
147 
148 static int MatView_SeqAIJ_ASCII(Mat A,Viewer viewer)
149 {
150   Mat_SeqAIJ  *a = (Mat_SeqAIJ *) A->data;
151   int         ierr, i,j, m = a->m, shift = a->indexshift,format;
152   FILE        *fd;
153   char        *outputname;
154 
155   ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr);
156   ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr);
157   ierr = ViewerFileGetFormat_Private(viewer,&format);
158   if (format == FILE_FORMAT_INFO) {
159     ; /* do nothing for now */
160   }
161   else if (format == FILE_FORMAT_MATLAB) {
162     int nz, nzalloc, mem;
163     MatGetInfo(A,MAT_LOCAL,&nz,&nzalloc,&mem);
164     fprintf(fd,"%% Size = %d %d \n",m,a->n);
165     fprintf(fd,"%% Nonzeros = %d \n",nz);
166     fprintf(fd,"zzz = zeros(%d,3);\n",nz);
167     fprintf(fd,"zzz = [\n");
168 
169     for (i=0; i<m; i++) {
170       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
171 #if defined(PETSC_COMPLEX)
172         fprintf(fd,"%d %d  %18.16e  %18.16e \n",i+1,a->j[j],real(a->a[j]),
173                    imag(a->a[j]));
174 #else
175         fprintf(fd,"%d %d  %18.16e\n", i+1, a->j[j], a->a[j]);
176 #endif
177       }
178     }
179     fprintf(fd,"];\n %s = spconvert(zzz);\n",outputname);
180   }
181   else {
182     for ( i=0; i<m; i++ ) {
183       fprintf(fd,"row %d:",i);
184       for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
185 #if defined(PETSC_COMPLEX)
186         if (imag(a->a[j]) != 0.0) {
187           fprintf(fd," %d %g + %g i",a->j[j]+shift,real(a->a[j]),imag(a->a[j]));
188         }
189         else {
190           fprintf(fd," %d %g ",a->j[j]+shift,real(a->a[j]));
191         }
192 #else
193         fprintf(fd," %d %g ",a->j[j]+shift,a->a[j]);
194 #endif
195       }
196       fprintf(fd,"\n");
197     }
198   }
199   fflush(fd);
200   return 0;
201 }
202 
203 static int MatView_SeqAIJ_Draw(Mat A,Viewer viewer)
204 {
205   Mat_SeqAIJ  *a = (Mat_SeqAIJ *) A->data;
206   int         ierr, i,j, m = a->m, shift = a->indexshift;
207   double      xl,yl,xr,yr,w,h;
208   DrawCtx draw = (DrawCtx) viewer;
209   xr  = a->n; yr = a->m; h = yr/10.0; w = xr/10.0;
210   xr += w;    yr += h;  xl = -w;     yl = -h;
211   ierr = DrawSetCoordinates(draw,xl,yl,xr,yr); CHKERRQ(ierr);
212   /* loop over matrix elements drawing boxes */
213   for ( i=0; i<m; i++ ) {
214     yl = m - i - 1.0; yr = yl + 1.0;
215     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
216       xl = a->j[j] + shift; xr = xl + 1.0;
217       DrawRectangle(draw,xl,yl,xr,yr,DRAW_BLACK,DRAW_BLACK,DRAW_BLACK,DRAW_BLACK);
218     }
219   }
220   DrawFlush(draw);
221   return 0;
222 }
223 
224 static int MatView_SeqAIJ(PetscObject obj,Viewer viewer)
225 {
226   Mat         A = (Mat) obj;
227   Mat_SeqAIJ  *a = (Mat_SeqAIJ*) A->data;
228   PetscObject vobj = (PetscObject) viewer;
229 
230   if (!a->assembled) SETERRQ(1,"MatView_SeqAIJ:Not for unassembled matrix");
231   if (!viewer) {
232     viewer = STDOUT_VIEWER_SELF; vobj = (PetscObject) viewer;
233   }
234   if (vobj->cookie == VIEWER_COOKIE) {
235     if (vobj->type == MATLAB_VIEWER) {
236       return ViewerMatlabPutSparse_Private(viewer,a->m,a->n,a->nz,a->a,a->i,a->j);
237     }
238     else if (vobj->type == ASCII_FILE_VIEWER || vobj->type == ASCII_FILES_VIEWER){
239       return MatView_SeqAIJ_ASCII(A,viewer);
240     }
241     else if (vobj->type == BINARY_FILE_VIEWER) {
242       return MatView_SeqAIJ_Binary(A,viewer);
243     }
244   }
245   else if (vobj->cookie == DRAW_COOKIE) {
246     if (vobj->type == NULLWINDOW) return 0;
247     else return MatView_SeqAIJ_Draw(A,viewer);
248   }
249   return 0;
250 }
251 
252 static int MatAssemblyEnd_SeqAIJ(Mat A,MatAssemblyType mode)
253 {
254   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
255   int        fshift = 0,i,j,*ai = a->i, *aj = a->j, *imax = a->imax;
256   int        m = a->m, *ip, N, *ailen = a->ilen,shift = a->indexshift;
257   Scalar     *aa = a->a, *ap;
258 
259   if (mode == FLUSH_ASSEMBLY) return 0;
260 
261   for ( i=1; i<m; i++ ) {
262     /* move each row back by the amount of empty slots (fshift) before it*/
263     fshift += imax[i-1] - ailen[i-1];
264     if (fshift) {
265       ip = aj + ai[i] + shift; ap = aa + ai[i] + shift;
266       N = ailen[i];
267       for ( j=0; j<N; j++ ) {
268         ip[j-fshift] = ip[j];
269         ap[j-fshift] = ap[j];
270       }
271     }
272     ai[i] = ai[i-1] + ailen[i-1];
273   }
274   if (m) {
275     fshift += imax[m-1] - ailen[m-1];
276     ai[m] = ai[m-1] + ailen[m-1];
277   }
278   /* reset ilen and imax for each row */
279   for ( i=0; i<m; i++ ) {
280     ailen[i] = imax[i] = ai[i+1] - ai[i];
281   }
282   a->nz = ai[m] + shift;
283 
284   /* diagonals may have moved, so kill the diagonal pointers */
285   if (fshift && a->diag) {
286     PETSCFREE(a->diag);
287     PLogObjectMemory(A,-(m+1)*sizeof(int));
288     a->diag = 0;
289   }
290   a->assembled = 1;
291   return 0;
292 }
293 
294 static int MatZeroEntries_SeqAIJ(Mat A)
295 {
296   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
297   PetscZero(a->a,(a->i[a->m]+a->indexshift)*sizeof(Scalar));
298   return 0;
299 }
300 
301 int MatDestroy_SeqAIJ(PetscObject obj)
302 {
303   Mat        A  = (Mat) obj;
304   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
305 #if defined(PETSC_LOG)
306   PLogObjectState(obj,"Rows=%d, Cols=%d, NZ=%d",a->m,a->n,a->nz);
307 #endif
308   PETSCFREE(a->a);
309   if (!a->singlemalloc) { PETSCFREE(a->i); PETSCFREE(a->j);}
310   if (a->diag) PETSCFREE(a->diag);
311   if (a->ilen) PETSCFREE(a->ilen);
312   if (a->imax) PETSCFREE(a->imax);
313   if (a->solve_work) PETSCFREE(a->solve_work);
314   PETSCFREE(a);
315   PLogObjectDestroy(A);
316   PETSCHEADERDESTROY(A);
317   return 0;
318 }
319 
320 static int MatCompress_SeqAIJ(Mat A)
321 {
322   return 0;
323 }
324 
325 static int MatSetOption_SeqAIJ(Mat A,MatOption op)
326 {
327   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
328   if      (op == ROW_ORIENTED)              a->roworiented = 1;
329   else if (op == COLUMN_ORIENTED)           a->roworiented = 0;
330   else if (op == COLUMNS_SORTED)            a->sorted      = 1;
331   /* doesn't care about sorted rows */
332   else if (op == NO_NEW_NONZERO_LOCATIONS)  a->nonew       = 1;
333   else if (op == YES_NEW_NONZERO_LOCATIONS) a->nonew       = 0;
334 
335   if (op == COLUMN_ORIENTED) SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqAIJ:Column input not supported");
336   return 0;
337 }
338 
339 static int MatGetDiagonal_SeqAIJ(Mat A,Vec v)
340 {
341   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
342   int        i,j, n,shift = a->indexshift;
343   Scalar     *x, zero = 0.0;
344 
345   if (!a->assembled) SETERRQ(1,"MatGetDiagonal_SeqAIJ:Not for unassembled matrix");
346   VecSet(&zero,v);
347   VecGetArray(v,&x); VecGetLocalSize(v,&n);
348   if (n != a->m) SETERRQ(1,"MatGetDiagonal_SeqAIJ:Nonconforming matrix and vector");
349   for ( i=0; i<a->m; i++ ) {
350     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
351       if (a->j[j]+shift == i) {
352         x[i] = a->a[j];
353         break;
354       }
355     }
356   }
357   return 0;
358 }
359 
360 /* -------------------------------------------------------*/
361 /* Should check that shapes of vectors and matrices match */
362 /* -------------------------------------------------------*/
363 static int MatMultTrans_SeqAIJ(Mat A,Vec xx,Vec yy)
364 {
365   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
366   Scalar     *x, *y, *v, alpha;
367   int        m = a->m, n, i, *idx, shift = a->indexshift;
368 
369   if (!a->assembled) SETERRQ(1,"MatMultTrans_SeqAIJ:Not for unassembled matrix");
370   VecGetArray(xx,&x); VecGetArray(yy,&y);
371   PetscZero(y,a->n*sizeof(Scalar));
372   y = y + shift; /* shift for Fortran start by 1 indexing */
373   for ( i=0; i<m; i++ ) {
374     idx   = a->j + a->i[i] + shift;
375     v     = a->a + a->i[i] + shift;
376     n     = a->i[i+1] - a->i[i];
377     alpha = x[i];
378     while (n-->0) {y[*idx++] += alpha * *v++;}
379   }
380   PLogFlops(2*a->nz - a->n);
381   return 0;
382 }
383 static int MatMultTransAdd_SeqAIJ(Mat A,Vec xx,Vec zz,Vec yy)
384 {
385   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
386   Scalar     *x, *y, *v, alpha;
387   int        m = a->m, n, i, *idx,shift = a->indexshift;
388 
389   if (!a->assembled) SETERRQ(1,"MatMultTransAdd_SeqAIJ:Not for unassembled matrix");
390   VecGetArray(xx,&x); VecGetArray(yy,&y);
391   if (zz != yy) VecCopy(zz,yy);
392   y = y + shift; /* shift for Fortran start by 1 indexing */
393   for ( i=0; i<m; i++ ) {
394     idx   = a->j + a->i[i] + shift;
395     v     = a->a + a->i[i] + shift;
396     n     = a->i[i+1] - a->i[i];
397     alpha = x[i];
398     while (n-->0) {y[*idx++] += alpha * *v++;}
399   }
400   return 0;
401 }
402 
403 static int MatMult_SeqAIJ(Mat A,Vec xx,Vec yy)
404 {
405   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
406   Scalar     *x, *y, *v, sum;
407   int        m = a->m, n, i, *idx, shift = a->indexshift,*ii;
408 
409   if (!a->assembled) SETERRQ(1,"MatMult_SeqAIJ:Not for unassembled matrix");
410   VecGetArray(xx,&x); VecGetArray(yy,&y);
411   x = x + shift; /* shift for Fortran start by 1 indexing */
412   idx  = a->j;
413   v    = a->a;
414   ii   = a->i;
415 #if defined(PARCH_rs6000)
416 #pragma disjoint (*x,*v,*y)
417 #endif
418   for ( i=0; i<m; i++ ) {
419     n    = ii[1] - ii[0]; ii++;
420     sum  = 0.0;
421     /* SPARSEDENSEDOT(sum,x,v,idx,n);  */
422     /* for ( j=n-1; j>-1; j--) sum += v[j]*x[idx[j]]; */
423     while (n--) sum += *v++ * x[*idx++];
424     y[i] = sum;
425   }
426   PLogFlops(2*a->nz - m);
427   return 0;
428 }
429 
430 static int MatMultAdd_SeqAIJ(Mat A,Vec xx,Vec yy,Vec zz)
431 {
432   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
433   Scalar     *x, *y, *z, *v, sum;
434   int        m = a->m, n, i, *idx, shift = a->indexshift;
435 
436   if (!a->assembled) SETERRQ(1,"MatMultAdd_SeqAIJ:Not for unassembled matrix");
437   VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z);
438   x = x + shift; /* shift for Fortran start by 1 indexing */
439   for ( i=0; i<m; i++ ) {
440     idx  = a->j + a->i[i] + shift;
441     v    = a->a + a->i[i] + shift;
442     n    = a->i[i+1] - a->i[i];
443     sum  = y[i];
444     SPARSEDENSEDOT(sum,x,v,idx,n);
445     z[i] = sum;
446   }
447   PLogFlops(2*a->nz);
448   return 0;
449 }
450 
451 /*
452      Adds diagonal pointers to sparse matrix structure.
453 */
454 
455 int MatMarkDiag_SeqAIJ(Mat A)
456 {
457   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
458   int        i,j, *diag, m = a->m,shift = a->indexshift;
459 
460   if (!a->assembled) SETERRQ(1,"MatMarkDiag_SeqAIJ:unassembled matrix");
461   diag = (int *) PETSCMALLOC( (m+1)*sizeof(int)); CHKPTRQ(diag);
462   PLogObjectMemory(A,(m+1)*sizeof(int));
463   for ( i=0; i<a->m; i++ ) {
464     for ( j=a->i[i]+shift; j<a->i[i+1]+shift; j++ ) {
465       if (a->j[j]+shift == i) {
466         diag[i] = j - shift;
467         break;
468       }
469     }
470   }
471   a->diag = diag;
472   return 0;
473 }
474 
475 static int MatRelax_SeqAIJ(Mat A,Vec bb,double omega,MatSORType flag,
476                            double fshift,int its,Vec xx)
477 {
478   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
479   Scalar     *x, *b, *bs,  d, *xs, sum, *v = a->a,*t,scale,*ts, *xb;
480   int        ierr, *idx, *diag,n = a->n, m = a->m, i;
481   int        shift = a->indexshift;
482 
483   VecGetArray(xx,&x); VecGetArray(bb,&b);
484   if (!a->diag) {if ((ierr = MatMarkDiag_SeqAIJ(A))) return ierr;}
485   diag = a->diag;
486   xs   = x + shift; /* shifted by one for index start of a or a->j*/
487   if (flag == SOR_APPLY_UPPER) {
488    /* apply ( U + D/omega) to the vector */
489     bs = b + shift;
490     for ( i=0; i<m; i++ ) {
491         d    = fshift + a->a[diag[i] + shift];
492         n    = a->i[i+1] - diag[i] - 1;
493         idx  = a->j + diag[i] + (!shift);
494         v    = a->a + diag[i] + (!shift);
495         sum  = b[i]*d/omega;
496         SPARSEDENSEDOT(sum,bs,v,idx,n);
497         x[i] = sum;
498     }
499     return 0;
500   }
501   if (flag == SOR_APPLY_LOWER) {
502     SETERRQ(1,"MatRelax_SeqAIJ:SOR_APPLY_LOWER is not done");
503   }
504   else if (flag & SOR_EISENSTAT) {
505     /* Let  A = L + U + D; where L is lower trianglar,
506     U is upper triangular, E is diagonal; This routine applies
507 
508             (L + E)^{-1} A (U + E)^{-1}
509 
510     to a vector efficiently using Eisenstat's trick. This is for
511     the case of SSOR preconditioner, so E is D/omega where omega
512     is the relaxation factor.
513     */
514     t = (Scalar *) PETSCMALLOC( m*sizeof(Scalar) ); CHKPTRQ(t);
515     scale = (2.0/omega) - 1.0;
516 
517     /*  x = (E + U)^{-1} b */
518     for ( i=m-1; i>=0; i-- ) {
519       d    = fshift + a->a[diag[i] + shift];
520       n    = a->i[i+1] - diag[i] - 1;
521       idx  = a->j + diag[i] + (!shift);
522       v    = a->a + diag[i] + (!shift);
523       sum  = b[i];
524       SPARSEDENSEMDOT(sum,xs,v,idx,n);
525       x[i] = omega*(sum/d);
526     }
527 
528     /*  t = b - (2*E - D)x */
529     v = a->a;
530     for ( i=0; i<m; i++ ) { t[i] = b[i] - scale*(v[*diag++ + shift])*x[i]; }
531 
532     /*  t = (E + L)^{-1}t */
533     ts = t + shift; /* shifted by one for index start of a or a->j*/
534     diag = a->diag;
535     for ( i=0; i<m; i++ ) {
536       d    = fshift + a->a[diag[i]+shift];
537       n    = diag[i] - a->i[i];
538       idx  = a->j + a->i[i] + shift;
539       v    = a->a + a->i[i] + shift;
540       sum  = t[i];
541       SPARSEDENSEMDOT(sum,ts,v,idx,n);
542       t[i] = omega*(sum/d);
543     }
544 
545     /*  x = x + t */
546     for ( i=0; i<m; i++ ) { x[i] += t[i]; }
547     PETSCFREE(t);
548     return 0;
549   }
550   if (flag & SOR_ZERO_INITIAL_GUESS) {
551     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
552       for ( i=0; i<m; i++ ) {
553         d    = fshift + a->a[diag[i]+shift];
554         n    = diag[i] - a->i[i];
555         idx  = a->j + a->i[i] + shift;
556         v    = a->a + a->i[i] + shift;
557         sum  = b[i];
558         SPARSEDENSEMDOT(sum,xs,v,idx,n);
559         x[i] = omega*(sum/d);
560       }
561       xb = x;
562     }
563     else xb = b;
564     if ((flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) &&
565         (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP)) {
566       for ( i=0; i<m; i++ ) {
567         x[i] *= a->a[diag[i]+shift];
568       }
569     }
570     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
571       for ( i=m-1; i>=0; i-- ) {
572         d    = fshift + a->a[diag[i] + shift];
573         n    = a->i[i+1] - diag[i] - 1;
574         idx  = a->j + diag[i] + (!shift);
575         v    = a->a + diag[i] + (!shift);
576         sum  = xb[i];
577         SPARSEDENSEMDOT(sum,xs,v,idx,n);
578         x[i] = omega*(sum/d);
579       }
580     }
581     its--;
582   }
583   while (its--) {
584     if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP){
585       for ( i=0; i<m; i++ ) {
586         d    = fshift + a->a[diag[i]+shift];
587         n    = a->i[i+1] - a->i[i];
588         idx  = a->j + a->i[i] + shift;
589         v    = a->a + a->i[i] + shift;
590         sum  = b[i];
591         SPARSEDENSEMDOT(sum,xs,v,idx,n);
592         x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]);
593       }
594     }
595     if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP){
596       for ( i=m-1; i>=0; i-- ) {
597         d    = fshift + a->a[diag[i] + shift];
598         n    = a->i[i+1] - a->i[i];
599         idx  = a->j + a->i[i] + shift;
600         v    = a->a + a->i[i] + shift;
601         sum  = b[i];
602         SPARSEDENSEMDOT(sum,xs,v,idx,n);
603         x[i] = (1. - omega)*x[i] + omega*(sum/d + x[i]);
604       }
605     }
606   }
607   return 0;
608 }
609 
610 static int MatGetInfo_SeqAIJ(Mat A,MatInfoType flag,int *nz,
611                              int *nzalloc,int *mem)
612 {
613   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
614   *nz      = a->nz;
615   *nzalloc = a->maxnz;
616   *mem     = (int)A->mem;
617   return 0;
618 }
619 
620 extern int MatLUFactorSymbolic_SeqAIJ(Mat,IS,IS,double,Mat*);
621 extern int MatLUFactorNumeric_SeqAIJ(Mat,Mat*);
622 extern int MatLUFactor_SeqAIJ(Mat,IS,IS,double);
623 extern int MatSolve_SeqAIJ(Mat,Vec,Vec);
624 extern int MatSolveAdd_SeqAIJ(Mat,Vec,Vec,Vec);
625 extern int MatSolveTrans_SeqAIJ(Mat,Vec,Vec);
626 extern int MatSolveTransAdd_SeqAIJ(Mat,Vec,Vec,Vec);
627 
628 static int MatZeroRows_SeqAIJ(Mat A,IS is,Scalar *diag)
629 {
630   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
631   int         i,ierr,N, *rows,m = a->m - 1,shift = a->indexshift;
632 
633   ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr);
634   ierr = ISGetIndices(is,&rows); CHKERRQ(ierr);
635   if (diag) {
636     for ( i=0; i<N; i++ ) {
637       if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range");
638       if (a->ilen[rows[i]] > 0) { /* in case row was completely empty */
639         a->ilen[rows[i]] = 1;
640         a->a[a->i[rows[i]]+shift] = *diag;
641         a->j[a->i[rows[i]]+shift] = rows[i]+shift;
642       }
643       else {
644         ierr = MatSetValues_SeqAIJ(A,1,&rows[i],1,&rows[i],diag,INSERT_VALUES);
645         CHKERRQ(ierr);
646       }
647     }
648   }
649   else {
650     for ( i=0; i<N; i++ ) {
651       if (rows[i] < 0 || rows[i] > m) SETERRQ(1,"MatZeroRows_SeqAIJ:row out of range");
652       a->ilen[rows[i]] = 0;
653     }
654   }
655   ISRestoreIndices(is,&rows);
656   ierr = MatAssemblyBegin(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
657   ierr = MatAssemblyEnd(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
658   return 0;
659 }
660 
661 static int MatGetSize_SeqAIJ(Mat A,int *m,int *n)
662 {
663   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
664   *m = a->m; *n = a->n;
665   return 0;
666 }
667 
668 static int MatGetOwnershipRange_SeqAIJ(Mat A,int *m,int *n)
669 {
670   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
671   *m = 0; *n = a->m;
672   return 0;
673 }
674 static int MatGetRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v)
675 {
676   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
677   int        *itmp,i,ierr,shift = a->indexshift;
678 
679   if (row < 0 || row >= a->m) SETERRQ(1,"MatGetRow_SeqAIJ:Row out of range");
680 
681   if (!a->assembled) {
682     ierr = MatAssemblyBegin(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
683     ierr = MatAssemblyEnd(A,FINAL_ASSEMBLY); CHKERRQ(ierr);
684   }
685   *nz = a->i[row+1] - a->i[row];
686   if (v) *v = a->a + a->i[row] + shift;
687   if (idx) {
688     if (*nz) {
689       itmp = a->j + a->i[row] + shift;
690       *idx = (int *) PETSCMALLOC( (*nz)*sizeof(int) ); CHKPTRQ(*idx);
691       for ( i=0; i<(*nz); i++ ) {(*idx)[i] = itmp[i] + shift;}
692     }
693     else *idx = 0;
694   }
695   return 0;
696 }
697 
698 static int MatRestoreRow_SeqAIJ(Mat A,int row,int *nz,int **idx,Scalar **v)
699 {
700   if (idx) {if (*idx) PETSCFREE(*idx);}
701   return 0;
702 }
703 
704 static int MatNorm_SeqAIJ(Mat A,MatNormType type,double *norm)
705 {
706   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
707   Scalar     *v = a->a;
708   double     sum = 0.0;
709   int        i, j,shift = a->indexshift;
710 
711   if (!a->assembled) SETERRQ(1,"MatNorm_SeqAIJ:Not for unassembled matrix");
712   if (type == NORM_FROBENIUS) {
713     for (i=0; i<a->nz; i++ ) {
714 #if defined(PETSC_COMPLEX)
715       sum += real(conj(*v)*(*v)); v++;
716 #else
717       sum += (*v)*(*v); v++;
718 #endif
719     }
720     *norm = sqrt(sum);
721   }
722   else if (type == NORM_1) {
723     double *tmp;
724     int    *jj = a->j;
725     tmp = (double *) PETSCMALLOC( a->n*sizeof(double) ); CHKPTRQ(tmp);
726     PetscZero(tmp,a->n*sizeof(double));
727     *norm = 0.0;
728     for ( j=0; j<a->nz; j++ ) {
729 #if defined(PETSC_COMPLEX)
730         tmp[*jj++ + shift] += abs(*v++);
731 #else
732         tmp[*jj++ + shift] += fabs(*v++);
733 #endif
734     }
735     for ( j=0; j<a->n; j++ ) {
736       if (tmp[j] > *norm) *norm = tmp[j];
737     }
738     PETSCFREE(tmp);
739   }
740   else if (type == NORM_INFINITY) {
741     *norm = 0.0;
742     for ( j=0; j<a->m; j++ ) {
743       v = a->a + a->i[j] + shift;
744       sum = 0.0;
745       for ( i=0; i<a->i[j+1]-a->i[j]; i++ ) {
746 #if defined(PETSC_COMPLEX)
747         sum += abs(*v); v++;
748 #else
749         sum += fabs(*v); v++;
750 #endif
751       }
752       if (sum > *norm) *norm = sum;
753     }
754   }
755   else {
756     SETERRQ(1,"MatNorm_SeqAIJ:No support for two norm yet");
757   }
758   return 0;
759 }
760 
761 static int MatTranspose_SeqAIJ(Mat A,Mat *B)
762 {
763   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
764   Mat        C;
765   int        i, ierr, *aj = a->j, *ai = a->i, m = a->m, len, *col;
766   Scalar     *array = a->a;
767   int        shift = a->indexshift;
768 
769   if (!B && m != a->n) SETERRQ(1,"MatTranspose_SeqAIJ:Not for rectangular mat in place");
770   col = (int *) PETSCMALLOC((1+a->n)*sizeof(int)); CHKPTRQ(col);
771   PetscZero(col,(1+a->n)*sizeof(int));
772   if (shift) {
773     for ( i=0; i<ai[m]-1; i++ ) aj[i] -= 1;
774   }
775   for ( i=0; i<ai[m]+shift; i++ ) col[aj[i]] += 1;
776   ierr = MatCreateSeqAIJ(A->comm,a->n,m,0,col,&C); CHKERRQ(ierr);
777   PETSCFREE(col);
778   for ( i=0; i<m; i++ ) {
779     len = ai[i+1]-ai[i];
780     ierr = MatSetValues(C,len,aj,1,&i,array,INSERT_VALUES); CHKERRQ(ierr);
781     array += len; aj += len;
782   }
783   if (shift) {
784     for ( i=0; i<ai[m]-1; i++ ) aj[i] += 1;
785   }
786 
787   ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
788   ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
789 
790   if (B) {
791     *B = C;
792   } else {
793     /* This isn't really an in-place transpose */
794     PETSCFREE(a->a);
795     if (!a->singlemalloc) {PETSCFREE(a->i); PETSCFREE(a->j);}
796     if (a->diag) PETSCFREE(a->diag);
797     if (a->ilen) PETSCFREE(a->ilen);
798     if (a->imax) PETSCFREE(a->imax);
799     if (a->solve_work) PETSCFREE(a->solve_work);
800     PETSCFREE(a);
801     PetscMemcpy(A,C,sizeof(struct _Mat));
802     PETSCHEADERDESTROY(C);
803   }
804   return 0;
805 }
806 
807 static int MatScale_SeqAIJ(Mat A,Vec ll,Vec rr)
808 {
809   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
810   Scalar     *l,*r,x,*v;
811   int        i,j,m = a->m, n = a->n, M, nz = a->nz, *jj;
812   int        shift = a->indexshift;
813 
814   if (!a->assembled) SETERRQ(1,"MatScale_SeqAIJ:Not for unassembled matrix");
815   if (ll) {
816     VecGetArray(ll,&l); VecGetSize(ll,&m);
817     if (m != a->m) SETERRQ(1,"MatScale_SeqAIJ:Left scaling vector wrong length");
818     v = a->a;
819     for ( i=0; i<m; i++ ) {
820       x = l[i];
821       M = a->i[i+1] - a->i[i];
822       for ( j=0; j<M; j++ ) { (*v++) *= x;}
823     }
824   }
825   if (rr) {
826     VecGetArray(rr,&r); VecGetSize(rr,&n);
827     if (n != a->n) SETERRQ(1,"MatScale_SeqAIJ:Right scaling vector wrong length");
828     v = a->a; jj = a->j;
829     for ( i=0; i<nz; i++ ) {
830       (*v++) *= r[*jj++ + shift];
831     }
832   }
833   return 0;
834 }
835 
836 static int MatGetSubMatrix_SeqAIJ(Mat A,IS isrow,IS iscol,Mat *B)
837 {
838   Mat_SeqAIJ *a = (Mat_SeqAIJ *) A->data;
839   int        nznew, *smap, i, k, kstart, kend, ierr, oldcols = a->n;
840   int        *irow, *icol, nrows, ncols, *cwork, shift = a->indexshift;
841   Scalar     *vwork;
842   Mat        C;
843 
844   if (!a->assembled) SETERRQ(1,"MatGetSubMatrix_SeqAIJ:Not for unassembled matrix");
845   ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr);
846   ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr);
847   ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr);
848   ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr);
849 
850   smap  = (int *) PETSCMALLOC((1+oldcols)*sizeof(int)); CHKPTRQ(smap);
851   cwork = (int *) PETSCMALLOC((1+ncols)*sizeof(int)); CHKPTRQ(cwork);
852   vwork = (Scalar *) PETSCMALLOC((1+ncols)*sizeof(Scalar)); CHKPTRQ(vwork);
853   PetscZero(smap,oldcols*sizeof(int));
854   for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1;
855 
856   /* Create and fill new matrix */
857   ierr = MatCreateSeqAIJ(A->comm,nrows,ncols,0,0,&C);CHKERRQ(ierr);
858   for (i=0; i<nrows; i++) {
859     nznew  = 0;
860     kstart = a->i[irow[i]]+shift;
861     kend   = kstart + a->ilen[irow[i]];
862     for ( k=kstart; k<kend; k++ ) {
863       if (smap[a->j[k]+shift]) {
864         cwork[nznew]   = smap[a->j[k]+shift] - 1;
865         vwork[nznew++] = a->a[k];
866       }
867     }
868     ierr = MatSetValues(C,1,&i,nznew,cwork,vwork,INSERT_VALUES); CHKERRQ(ierr);
869   }
870   ierr = MatAssemblyBegin(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
871   ierr = MatAssemblyEnd(C,FINAL_ASSEMBLY); CHKERRQ(ierr);
872 
873   /* Free work space */
874   PETSCFREE(smap); PETSCFREE(cwork); PETSCFREE(vwork);
875   ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr);
876   ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr);
877   *B = C;
878   return 0;
879 }
880 
881 /* -------------------------------------------------------------------*/
882 extern int MatILUFactorSymbolic_SeqAIJ(Mat,IS,IS,double,int,Mat *);
883 extern int MatConvert_SeqAIJ(Mat,MatType,Mat *);
884 static int MatCopyPrivate_SeqAIJ(Mat,Mat *);
885 
886 static struct _MatOps MatOps = {MatSetValues_SeqAIJ,
887        MatGetRow_SeqAIJ,MatRestoreRow_SeqAIJ,
888        MatMult_SeqAIJ,MatMultAdd_SeqAIJ,
889        MatMultTrans_SeqAIJ,MatMultTransAdd_SeqAIJ,
890        MatSolve_SeqAIJ,MatSolveAdd_SeqAIJ,
891        MatSolveTrans_SeqAIJ,MatSolveTransAdd_SeqAIJ,
892        MatLUFactor_SeqAIJ,0,
893        MatRelax_SeqAIJ,
894        MatTranspose_SeqAIJ,
895        MatGetInfo_SeqAIJ,0,
896        MatGetDiagonal_SeqAIJ,MatScale_SeqAIJ,MatNorm_SeqAIJ,
897        0,MatAssemblyEnd_SeqAIJ,
898        MatCompress_SeqAIJ,
899        MatSetOption_SeqAIJ,MatZeroEntries_SeqAIJ,MatZeroRows_SeqAIJ,
900        MatGetReordering_SeqAIJ,
901        MatLUFactorSymbolic_SeqAIJ,MatLUFactorNumeric_SeqAIJ,0,0,
902        MatGetSize_SeqAIJ,MatGetSize_SeqAIJ,MatGetOwnershipRange_SeqAIJ,
903        MatILUFactorSymbolic_SeqAIJ,0,
904        0,0,MatConvert_SeqAIJ,
905        MatGetSubMatrix_SeqAIJ,0,
906        MatCopyPrivate_SeqAIJ};
907 
908 extern int MatUseSuperLU_SeqAIJ(Mat);
909 extern int MatUseEssl_SeqAIJ(Mat);
910 extern int MatUseDXML_SeqAIJ(Mat);
911 
912 /*@C
913    MatCreateSeqAIJ - Creates a sparse matrix in AIJ format
914    (the default uniprocessor PETSc format).
915 
916    Input Parameters:
917 .  comm - MPI communicator, set to MPI_COMM_SELF
918 .  m - number of rows
919 .  n - number of columns
920 .  nz - number of nonzeros per row (same for all rows)
921 .  nzz - number of nonzeros per row or null (possibly different for each row)
922 
923    Output Parameter:
924 .  A - the matrix
925 
926    Notes:
927    The AIJ format (also called the Yale sparse matrix format or
928    compressed row storage), is fully compatible with standard Fortran 77
929    storage.  That is, the stored row and column indices begin at
930    one, not zero.
931 
932    Specify the preallocated storage with either nz or nnz (not both).
933    Set both nz and nnz to zero for PETSc to control dynamic memory
934    allocation.
935 
936 .keywords: matrix, aij, compressed row, sparse
937 
938 .seealso: MatCreate(), MatCreateMPIAIJ(), MatSetValues()
939 @*/
940 int MatCreateSeqAIJ(MPI_Comm comm,int m,int n,int nz,int *nnz, Mat *A)
941 {
942   Mat        B;
943   Mat_SeqAIJ *b;
944   int        i,len,ierr;
945   *A      = 0;
946   PETSCHEADERCREATE(B,_Mat,MAT_COOKIE,MATSEQAIJ,comm);
947   PLogObjectCreate(B);
948   B->data               = (void *) (b = PETSCNEW(Mat_SeqAIJ)); CHKPTRQ(b);
949   PetscMemcpy(&B->ops,&MatOps,sizeof(struct _MatOps));
950   B->destroy          = MatDestroy_SeqAIJ;
951   B->view             = MatView_SeqAIJ;
952   B->factor           = 0;
953   B->lupivotthreshold = 1.0;
954   OptionsGetDouble(0,"-mat_lu_pivotthreshold",&B->lupivotthreshold);
955   b->row              = 0;
956   b->col              = 0;
957   b->indexshift       = 0;
958   if (OptionsHasName(0,"-mat_aij_oneindex")) b->indexshift = -1;
959 
960   b->m       = m;
961   b->n       = n;
962   b->imax    = (int *) PETSCMALLOC( (m+1)*sizeof(int) ); CHKPTRQ(b->imax);
963   if (!nnz) {
964     if (nz <= 0) nz = 1;
965     for ( i=0; i<m; i++ ) b->imax[i] = nz;
966     nz = nz*m;
967   }
968   else {
969     nz = 0;
970     for ( i=0; i<m; i++ ) {b->imax[i] = nnz[i]; nz += nnz[i];}
971   }
972 
973   /* allocate the matrix space */
974   len     = nz*(sizeof(int) + sizeof(Scalar)) + (b->m+1)*sizeof(int);
975   b->a  = (Scalar *) PETSCMALLOC( len ); CHKPTRQ(b->a);
976   b->j  = (int *) (b->a + nz);
977   PetscZero(b->j,nz*sizeof(int));
978   b->i  = b->j + nz;
979   b->singlemalloc = 1;
980 
981   b->i[0] = -b->indexshift;
982   for (i=1; i<m+1; i++) {
983     b->i[i] = b->i[i-1] + b->imax[i-1];
984   }
985 
986   /* b->ilen will count nonzeros in each row so far. */
987   b->ilen = (int *) PETSCMALLOC((m+1)*sizeof(int));
988   PLogObjectMemory(B,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
989   for ( i=0; i<b->m; i++ ) { b->ilen[i] = 0;}
990 
991   b->nz          = 0;
992   b->maxnz       = nz;
993   b->sorted      = 0;
994   b->roworiented = 1;
995   b->nonew       = 0;
996   b->diag        = 0;
997   b->assembled   = 0;
998   b->solve_work  = 0;
999 
1000   *A = B;
1001   if (OptionsHasName(0,"-mat_aij_superlu")) {
1002     ierr = MatUseSuperLU_SeqAIJ(B); CHKERRQ(ierr);
1003   }
1004   if (OptionsHasName(0,"-mat_aij_essl")) {
1005     ierr = MatUseEssl_SeqAIJ(B); CHKERRQ(ierr);
1006   }
1007   if (OptionsHasName(0,"-mat_aij_dxml")) {
1008     if (!b->indexshift) SETERRQ(1,"MatCreateSeqAIJ:need -mat_aij_oneindex with -mat_aij_dxml");
1009     ierr = MatUseDXML_SeqAIJ(B); CHKERRQ(ierr);
1010   }
1011 
1012   return 0;
1013 }
1014 
1015 static int MatCopyPrivate_SeqAIJ(Mat A,Mat *B)
1016 {
1017   Mat        C;
1018   Mat_SeqAIJ *c,*a = (Mat_SeqAIJ *) A->data;
1019   int        i,len, m = a->m;
1020   int        shift = a->indexshift;
1021   *B      = 0;
1022 
1023   if (!a->assembled) SETERRQ(1,"MatCopyPrivate_SeqAIJ:Cannot copy unassembled matrix");
1024   PETSCHEADERCREATE(C,_Mat,MAT_COOKIE,MATSEQAIJ,A->comm);
1025   PLogObjectCreate(C);
1026   C->data       = (void *) (c = PETSCNEW(Mat_SeqAIJ)); CHKPTRQ(c);
1027   PetscMemcpy(&C->ops,&MatOps,sizeof(struct _MatOps));
1028   C->destroy    = MatDestroy_SeqAIJ;
1029   C->view       = MatView_SeqAIJ;
1030   C->factor     = A->factor;
1031   c->row        = 0;
1032   c->col        = 0;
1033   c->indexshift = shift;
1034 
1035   c->m          = a->m;
1036   c->n          = a->n;
1037 
1038   c->imax       = (int *) PETSCMALLOC((m+1)*sizeof(int)); CHKPTRQ(c->imax);
1039   c->ilen       = (int *) PETSCMALLOC((m+1)*sizeof(int)); CHKPTRQ(c->ilen);
1040   for ( i=0; i<m; i++ ) {
1041     c->imax[i] = a->imax[i];
1042     c->ilen[i] = a->ilen[i];
1043   }
1044 
1045   /* allocate the matrix space */
1046   c->singlemalloc = 1;
1047   len     = (m+1)*sizeof(int)+(a->i[m])*(sizeof(Scalar)+sizeof(int));
1048   c->a  = (Scalar *) PETSCMALLOC( len ); CHKPTRQ(c->a);
1049   c->j  = (int *) (c->a + a->i[m] + shift);
1050   c->i  = c->j + a->i[m] + shift;
1051   PetscMemcpy(c->i,a->i,(m+1)*sizeof(int));
1052   if (m > 0) {
1053     PetscMemcpy(c->j,a->j,(a->i[m]+shift)*sizeof(int));
1054     PetscMemcpy(c->a,a->a,(a->i[m]+shift)*sizeof(Scalar));
1055   }
1056 
1057   PLogObjectMemory(C,len+2*(m+1)*sizeof(int)+sizeof(struct _Mat)+sizeof(Mat_SeqAIJ));
1058   c->sorted      = a->sorted;
1059   c->roworiented = a->roworiented;
1060   c->nonew       = a->nonew;
1061 
1062   if (a->diag) {
1063     c->diag = (int *) PETSCMALLOC( (m+1)*sizeof(int) ); CHKPTRQ(c->diag);
1064     PLogObjectMemory(C,(m+1)*sizeof(int));
1065     for ( i=0; i<m; i++ ) {
1066       c->diag[i] = a->diag[i];
1067     }
1068   }
1069   else c->diag        = 0;
1070   c->assembled        = 1;
1071   c->nz               = a->nz;
1072   c->maxnz            = a->maxnz;
1073   c->solve_work       = 0;
1074   *B = C;
1075   return 0;
1076 }
1077 
1078 int MatLoad_SeqAIJ(Viewer bview,MatType type,Mat *A)
1079 {
1080   Mat_SeqAIJ   *a;
1081   Mat          B;
1082   int          i, nz, ierr, fd, header[4],numtid,*rowlengths = 0,M,N,shift;
1083   PetscObject  vobj = (PetscObject) bview;
1084   MPI_Comm     comm = vobj->comm;
1085 
1086   MPI_Comm_size(comm,&numtid);
1087   if (numtid > 1) SETERRQ(1,"MatLoad_SeqAIJ:view must have one processor");
1088   ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr);
1089   ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr);
1090   if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqAIJ:not matrix object in file");
1091   M = header[1]; N = header[2]; nz = header[3];
1092 
1093   /* read in row lengths */
1094   rowlengths = (int*) PETSCMALLOC( M*sizeof(int) ); CHKPTRQ(rowlengths);
1095   ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr);
1096 
1097   /* create our matrix */
1098   ierr = MatCreateSeqAIJ(comm,M,N,0,rowlengths,A); CHKERRQ(ierr);
1099   B = *A;
1100   a = (Mat_SeqAIJ *) B->data;
1101   shift = a->indexshift;
1102 
1103   /* read in column indices and adjust for Fortran indexing*/
1104   ierr = SYRead(fd,a->j,nz,SYINT); CHKERRQ(ierr);
1105   if (shift) {
1106     for ( i=0; i<nz; i++ ) {
1107       a->j[i] += 1;
1108     }
1109   }
1110 
1111   /* read in nonzero values */
1112   ierr = SYRead(fd,a->a,nz,SYSCALAR); CHKERRQ(ierr);
1113 
1114   /* set matrix "i" values */
1115   a->i[0] = -shift;
1116   for ( i=1; i<= M; i++ ) {
1117     a->i[i]      = a->i[i-1] + rowlengths[i-1];
1118     a->ilen[i-1] = rowlengths[i-1];
1119   }
1120   PETSCFREE(rowlengths);
1121 
1122   ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1123   ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
1124   return 0;
1125 }
1126 
1127 
1128 
1129