xref: /petsc/src/mat/impls/dense/seq/dense.c (revision 48d914877651b9fa76f196ebaf17c108719d05c1)
1 #ifndef lint
2 static char vcid[] = "$Id: dense.c,v 1.60 1995/09/30 19:28:39 bsmith Exp bsmith $";
3 #endif
4 
5 /*
6     Standard Fortran style matrices
7 */
8 #include "petsc.h"
9 #include "pinclude/plapack.h"
10 #include "matimpl.h"
11 #include "math.h"
12 #include "vec/vecimpl.h"
13 #include "pinclude/pviewer.h"
14 
15 typedef struct {
16   Scalar *v;
17   int    roworiented;
18   int    m,n,pad;
19   int    *pivots;   /* pivots in LU factorization */
20 } Mat_SeqDense;
21 
22 static int MatGetInfo_SeqDense(Mat matin,MatInfoType flag,int *nz,int *nzalloc,int *mem)
23 {
24   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
25   int          i,N = mat->m*mat->n,count = 0;
26   Scalar       *v = mat->v;
27   for ( i=0; i<N; i++ ) {if (*v != 0.0) count++; v++;}
28   *nz = count; *nzalloc = N; *mem = (int)matin->mem;
29   return 0;
30 }
31 
32 /* ---------------------------------------------------------------*/
33 /* COMMENT: I have chosen to hide column permutation in the pivots,
34    rather than put it in the Mat->col slot.*/
35 static int MatLUFactor_SeqDense(Mat matin,IS row,IS col,double f)
36 {
37   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
38   int          info;
39   if (!mat->pivots) {
40     mat->pivots = (int *) PETSCMALLOC(mat->m*sizeof(int));CHKPTRQ(mat->pivots);
41     PLogObjectMemory(matin,mat->m*sizeof(int));
42   }
43   LAgetrf_(&mat->m,&mat->n,mat->v,&mat->m,mat->pivots,&info);
44   if (info) SETERRQ(1,"MatLUFactor_SeqDense:Bad LU factorization");
45   matin->factor = FACTOR_LU;
46   return 0;
47 }
48 static int MatLUFactorSymbolic_SeqDense(Mat matin,IS row,IS col,double f,Mat *fact)
49 {
50   int ierr;
51   ierr = MatConvert(matin,MATSAME,fact); CHKERRQ(ierr);
52   return 0;
53 }
54 static int MatLUFactorNumeric_SeqDense(Mat matin,Mat *fact)
55 {
56   return MatLUFactor(*fact,0,0,1.0);
57 }
58 static int MatCholeskyFactorSymbolic_SeqDense(Mat matin,IS row,double f,Mat *fact)
59 {
60   int ierr;
61   ierr = MatConvert(matin,MATSAME,fact); CHKERRQ(ierr);
62   return 0;
63 }
64 static int MatCholeskyFactorNumeric_SeqDense(Mat matin,Mat *fact)
65 {
66   return MatCholeskyFactor(*fact,0,1.0);
67 }
68 static int MatCholeskyFactor_SeqDense(Mat matin,IS perm,double f)
69 {
70   Mat_SeqDense  *mat = (Mat_SeqDense *) matin->data;
71   int           info;
72   if (mat->pivots) {
73     PETSCFREE(mat->pivots);
74     PLogObjectMemory(matin,-mat->m*sizeof(int));
75     mat->pivots = 0;
76   }
77   LApotrf_("L",&mat->n,mat->v,&mat->m,&info);
78   if (info) SETERRQ(1,"MatCholeskyFactor_SeqDense:Bad factorization");
79   matin->factor = FACTOR_CHOLESKY;
80   return 0;
81 }
82 
83 static int MatSolve_SeqDense(Mat matin,Vec xx,Vec yy)
84 {
85   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
86   int          one = 1, info;
87   Scalar       *x, *y;
88   VecGetArray(xx,&x); VecGetArray(yy,&y);
89   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
90   if (matin->factor == FACTOR_LU) {
91     LAgetrs_( "N", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
92   }
93   else if (matin->factor == FACTOR_CHOLESKY){
94     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
95   }
96   else SETERRQ(1,"MatSolve_SeqDense:Matrix must be factored to solve");
97   if (info) SETERRQ(1,"MatSolve_SeqDense:Bad solve");
98   return 0;
99 }
100 static int MatSolveTrans_SeqDense(Mat matin,Vec xx,Vec yy)
101 {
102   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
103   int          one = 1, info;
104   Scalar       *x, *y;
105   VecGetArray(xx,&x); VecGetArray(yy,&y);
106   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
107   /* assume if pivots exist then use LU; else Cholesky */
108   if (mat->pivots) {
109     LAgetrs_( "T", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
110   }
111   else {
112     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
113   }
114   if (info) SETERRQ(1,"MatSolveTrans_SeqDense:Bad solve");
115   return 0;
116 }
117 static int MatSolveAdd_SeqDense(Mat matin,Vec xx,Vec zz,Vec yy)
118 {
119   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
120   int          one = 1, info,ierr;
121   Scalar       *x, *y, sone = 1.0;
122   Vec          tmp = 0;
123   VecGetArray(xx,&x); VecGetArray(yy,&y);
124   if (yy == zz) {
125     ierr = VecDuplicate(yy,&tmp); CHKERRQ(ierr);
126     PLogObjectParent(matin,tmp);
127     ierr = VecCopy(yy,tmp); CHKERRQ(ierr);
128   }
129   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
130   /* assume if pivots exist then use LU; else Cholesky */
131   if (mat->pivots) {
132     LAgetrs_( "N", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
133   }
134   else {
135     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
136   }
137   if (info) SETERRQ(1,"MatSolveAdd_SeqDense:Bad solve");
138   if (tmp) {VecAXPY(&sone,tmp,yy); VecDestroy(tmp);}
139   else VecAXPY(&sone,zz,yy);
140   return 0;
141 }
142 static int MatSolveTransAdd_SeqDense(Mat matin,Vec xx,Vec zz, Vec yy)
143 {
144   Mat_SeqDense  *mat = (Mat_SeqDense *) matin->data;
145   int           one = 1, info,ierr;
146   Scalar        *x, *y, sone = 1.0;
147   Vec           tmp;
148   VecGetArray(xx,&x); VecGetArray(yy,&y);
149   if (yy == zz) {
150     ierr = VecDuplicate(yy,&tmp); CHKERRQ(ierr);
151     PLogObjectParent(matin,tmp);
152     ierr = VecCopy(yy,tmp); CHKERRQ(ierr);
153   }
154   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
155   /* assume if pivots exist then use LU; else Cholesky */
156   if (mat->pivots) {
157     LAgetrs_( "T", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
158   }
159   else {
160     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
161   }
162   if (info) SETERRQ(1,"MatSolveTransAdd_SeqDense:Bad solve");
163   if (tmp) {VecAXPY(&sone,tmp,yy); VecDestroy(tmp);}
164   else VecAXPY(&sone,zz,yy);
165   return 0;
166 }
167 /* ------------------------------------------------------------------*/
168 static int MatRelax_SeqDense(Mat matin,Vec bb,double omega,MatSORType flag,
169                           double shift,int its,Vec xx)
170 {
171   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
172   Scalar       *x, *b, *v = mat->v, zero = 0.0, xt;
173   int          o = 1,ierr, m = mat->m, i;
174 
175   if (flag & SOR_ZERO_INITIAL_GUESS) {
176     /* this is a hack fix, should have another version without
177        the second BLdot */
178     ierr = VecSet(&zero,xx); CHKERRQ(ierr);
179   }
180   VecGetArray(xx,&x); VecGetArray(bb,&b);
181   while (its--) {
182     if (flag & SOR_FORWARD_SWEEP){
183       for ( i=0; i<m; i++ ) {
184 #if defined(PETSC_COMPLEX)
185         /* cannot use BLAS dot for complex because compiler/linker is
186            not happy about returning a double complex */
187         int    _i;
188         Scalar sum = b[i];
189         for ( _i=0; _i<m; _i++ ) {
190           sum -= conj(v[i+_i*m])*x[_i];
191         }
192         xt = sum;
193 #else
194         xt = b[i]-BLdot_(&m,v+i,&m,x,&o);
195 #endif
196         x[i] = (1. - omega)*x[i] + omega*(xt/(v[i + i*m]+shift) + x[i]);
197       }
198     }
199     if (flag & SOR_BACKWARD_SWEEP) {
200       for ( i=m-1; i>=0; i-- ) {
201 #if defined(PETSC_COMPLEX)
202         /* cannot use BLAS dot for complex because compiler/linker is
203            not happy about returning a double complex */
204         int    _i;
205         Scalar sum = b[i];
206         for ( _i=0; _i<m; _i++ ) {
207           sum -= conj(v[i+_i*m])*x[_i];
208         }
209         xt = sum;
210 #else
211         xt = b[i]-BLdot_(&m,v+i,&m,x,&o);
212 #endif
213         x[i] = (1. - omega)*x[i] + omega*(xt/(v[i + i*m]+shift) + x[i]);
214       }
215     }
216   }
217   return 0;
218 }
219 
220 /* -----------------------------------------------------------------*/
221 static int MatMultTrans_SeqDense(Mat matin,Vec xx,Vec yy)
222 {
223   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
224   Scalar       *v = mat->v, *x, *y;
225   int          _One=1;Scalar _DOne=1.0, _DZero=0.0;
226   VecGetArray(xx,&x), VecGetArray(yy,&y);
227   LAgemv_("T",&(mat->m),&(mat->n),&_DOne,v,&(mat->m),x,&_One,&_DZero,y,&_One);
228   return 0;
229 }
230 static int MatMult_SeqDense(Mat matin,Vec xx,Vec yy)
231 {
232   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
233   Scalar       *v = mat->v, *x, *y;
234   int          _One=1;Scalar _DOne=1.0, _DZero=0.0;
235   VecGetArray(xx,&x); VecGetArray(yy,&y);
236   LAgemv_( "N", &(mat->m), &(mat->n), &_DOne, v, &(mat->m),x,&_One,&_DZero,y,&_One);
237   return 0;
238 }
239 static int MatMultAdd_SeqDense(Mat matin,Vec xx,Vec zz,Vec yy)
240 {
241   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
242   Scalar       *v = mat->v, *x, *y, *z;
243   int          _One=1; Scalar _DOne=1.0;
244   VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z);
245   if (zz != yy) PetscMemcpy(y,z,mat->m*sizeof(Scalar));
246   LAgemv_( "N", &(mat->m), &(mat->n),&_DOne,v,&(mat->m),x,&_One,&_DOne,y,&_One);
247   return 0;
248 }
249 static int MatMultTransAdd_SeqDense(Mat matin,Vec xx,Vec zz,Vec yy)
250 {
251   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
252   Scalar       *v = mat->v, *x, *y, *z;
253   int          _One=1;
254   Scalar       _DOne=1.0;
255   VecGetArray(xx,&x); VecGetArray(yy,&y);
256   VecGetArray(zz,&z);
257   if (zz != yy) PetscMemcpy(y,z,mat->m*sizeof(Scalar));
258   LAgemv_( "T", &(mat->m), &(mat->n), &_DOne, v, &(mat->m),x,&_One,&_DOne,y,&_One);
259   return 0;
260 }
261 
262 /* -----------------------------------------------------------------*/
263 static int MatGetRow_SeqDense(Mat matin,int row,int *ncols,int **cols,Scalar **vals)
264 {
265   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
266   Scalar       *v;
267   int          i;
268   *ncols = mat->n;
269   if (cols) {
270     *cols = (int *) PETSCMALLOC(mat->n*sizeof(int)); CHKPTRQ(*cols);
271     for ( i=0; i<mat->n; i++ ) *cols[i] = i;
272   }
273   if (vals) {
274     *vals = (Scalar *) PETSCMALLOC(mat->n*sizeof(Scalar)); CHKPTRQ(*vals);
275     v = mat->v + row;
276     for ( i=0; i<mat->n; i++ ) {*vals[i] = *v; v += mat->m;}
277   }
278   return 0;
279 }
280 static int MatRestoreRow_SeqDense(Mat matin,int row,int *ncols,int **cols,Scalar **vals)
281 {
282   if (cols) { PETSCFREE(*cols); }
283   if (vals) { PETSCFREE(*vals); }
284   return 0;
285 }
286 /* ----------------------------------------------------------------*/
287 static int MatInsert_SeqDense(Mat matin,int m,int *indexm,int n,
288                         int *indexn,Scalar *v,InsertMode addv)
289 {
290   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
291   int          i,j;
292 
293   if (!mat->roworiented) {
294     if (addv == INSERT_VALUES) {
295       for ( j=0; j<n; j++ ) {
296         for ( i=0; i<m; i++ ) {
297           mat->v[indexn[j]*mat->m + indexm[i]] = *v++;
298         }
299       }
300     }
301     else {
302       for ( j=0; j<n; j++ ) {
303         for ( i=0; i<m; i++ ) {
304           mat->v[indexn[j]*mat->m + indexm[i]] += *v++;
305         }
306       }
307     }
308   }
309   else {
310     if (addv == INSERT_VALUES) {
311       for ( i=0; i<m; i++ ) {
312         for ( j=0; j<n; j++ ) {
313           mat->v[indexn[j]*mat->m + indexm[i]] = *v++;
314         }
315       }
316     }
317     else {
318       for ( i=0; i<m; i++ ) {
319         for ( j=0; j<n; j++ ) {
320           mat->v[indexn[j]*mat->m + indexm[i]] += *v++;
321         }
322       }
323     }
324   }
325   return 0;
326 }
327 
328 /* -----------------------------------------------------------------*/
329 static int MatCopyPrivate_SeqDense(Mat matin,Mat *newmat)
330 {
331   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data,*l;
332   int          ierr;
333   Mat          newi;
334 
335   ierr = MatCreateSeqDense(matin->comm,mat->m,mat->n,&newi);CHKERRQ(ierr);
336   l = (Mat_SeqDense *) newi->data;
337   PetscMemcpy(l->v,mat->v,mat->m*mat->n*sizeof(Scalar));
338   *newmat = newi;
339   return 0;
340 }
341 #include "viewer.h"
342 
343 int MatView_SeqDense(PetscObject obj,Viewer ptr)
344 {
345   Mat           matin = (Mat) obj;
346   Mat_SeqDense  *mat = (Mat_SeqDense *) matin->data;
347   Scalar        *v;
348   int           i,j,ierr;
349   PetscObject   vobj = (PetscObject) ptr;
350 
351   if (ptr == 0) {
352     ptr = STDOUT_VIEWER_SELF; vobj = (PetscObject) ptr;
353   }
354   if (vobj->cookie == VIEWER_COOKIE && vobj->type == MATLAB_VIEWER) {
355     return ViewerMatlabPutArray_Private(ptr,mat->m,mat->n,mat->v);
356   }
357   else {
358     FILE *fd;
359     int format;
360     ierr = ViewerFileGetPointer_Private(ptr,&fd); CHKERRQ(ierr);
361     ierr = ViewerFileGetFormat_Private(ptr,&format); CHKERRQ(ierr);
362     if (format == FILE_FORMAT_INFO) {
363       /* do nothing for now */
364     }
365     else {
366       for ( i=0; i<mat->m; i++ ) {
367         v = mat->v + i;
368         for ( j=0; j<mat->n; j++ ) {
369 #if defined(PETSC_COMPLEX)
370           fprintf(fd,"%6.4e + %6.4e i ",real(*v),imag(*v)); v += mat->m;
371 #else
372           fprintf(fd,"%6.4e ",*v); v += mat->m;
373 #endif
374         }
375         fprintf(fd,"\n");
376       }
377     }
378   }
379   return 0;
380 }
381 
382 
383 static int MatDestroy_SeqDense(PetscObject obj)
384 {
385   Mat          mat = (Mat) obj;
386   Mat_SeqDense *l = (Mat_SeqDense *) mat->data;
387 #if defined(PETSC_LOG)
388   PLogObjectState(obj,"Rows %d Cols %d",l->m,l->n);
389 #endif
390   if (l->pivots) PETSCFREE(l->pivots);
391   PETSCFREE(l);
392   PLogObjectDestroy(mat);
393   PETSCHEADERDESTROY(mat);
394   return 0;
395 }
396 
397 static int MatTranspose_SeqDense(Mat matin,Mat *matout)
398 {
399   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
400   int          k, j, m, n;
401   Scalar       *v, tmp;
402 
403   v = mat->v; m = mat->m; n = mat->n;
404   if (!matout) { /* in place transpose */
405     if (m != n) SETERRQ(1,"MatTranspose_SeqDense:Not for rectangular matrix in place");
406     for ( j=0; j<m; j++ ) {
407       for ( k=0; k<j; k++ ) {
408         tmp = v[j + k*n];
409         v[j + k*n] = v[k + j*n];
410         v[k + j*n] = tmp;
411       }
412     }
413   }
414   else { /* out-of-place transpose */
415     int ierr;
416     Mat tmat;
417     Mat_SeqDense *tmatd;
418     Scalar *v2;
419     ierr = MatCreateSeqDense(matin->comm,mat->n,mat->m,&tmat); CHKERRQ(ierr);
420     tmatd = (Mat_SeqDense *) tmat->data;
421     v = mat->v; v2 = tmatd->v;
422     for ( j=0; j<n; j++ ) {
423       for ( k=0; k<m; k++ ) v2[j + k*n] = v[k + j*m];
424     }
425     ierr = MatAssemblyBegin(tmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
426     ierr = MatAssemblyEnd(tmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
427     *matout = tmat;
428   }
429   return 0;
430 }
431 
432 static int MatEqual_SeqDense(Mat matin1,Mat matin2)
433 {
434   Mat_SeqDense *mat1 = (Mat_SeqDense *) matin1->data;
435   Mat_SeqDense *mat2 = (Mat_SeqDense *) matin2->data;
436   int          i;
437   Scalar       *v1 = mat1->v, *v2 = mat2->v;
438   if (mat1->m != mat2->m) return 0;
439   if (mat1->n != mat2->n) return 0;
440   for ( i=0; i<mat1->m*mat1->n; i++ ) {
441     if (*v1 != *v2) return 0;
442     v1++; v2++;
443   }
444   return 1;
445 }
446 
447 static int MatGetDiagonal_SeqDense(Mat matin,Vec v)
448 {
449   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
450   int          i, n;
451   Scalar       *x;
452   VecGetArray(v,&x); VecGetSize(v,&n);
453   if (n != mat->m) SETERRQ(1,"MatGetDiagonal_SeqDense:Nonconforming mat and vec");
454   for ( i=0; i<mat->m; i++ ) {
455     x[i] = mat->v[i*mat->m + i];
456   }
457   return 0;
458 }
459 
460 static int MatScale_SeqDense(Mat matin,Vec ll,Vec rr)
461 {
462   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
463   Scalar       *l,*r,x,*v;
464   int          i,j,m = mat->m, n = mat->n;
465   if (ll) {
466     VecGetArray(ll,&l); VecGetSize(ll,&m);
467     if (m != mat->m) SETERRQ(1,"MatScale_SeqDense:Left scaling vec wrong size");
468     for ( i=0; i<m; i++ ) {
469       x = l[i];
470       v = mat->v + i;
471       for ( j=0; j<n; j++ ) { (*v) *= x; v+= m;}
472     }
473   }
474   if (rr) {
475     VecGetArray(rr,&r); VecGetSize(rr,&n);
476     if (n != mat->n) SETERRQ(1,"MatScale_SeqDense:Right scaling vec wrong size");
477     for ( i=0; i<n; i++ ) {
478       x = r[i];
479       v = mat->v + i*m;
480       for ( j=0; j<m; j++ ) { (*v++) *= x;}
481     }
482   }
483   return 0;
484 }
485 
486 static int MatNorm_SeqDense(Mat matin,MatNormType type,double *norm)
487 {
488   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
489   Scalar       *v = mat->v;
490   double       sum = 0.0;
491   int          i, j;
492   if (type == NORM_FROBENIUS) {
493     for (i=0; i<mat->n*mat->m; i++ ) {
494 #if defined(PETSC_COMPLEX)
495       sum += real(conj(*v)*(*v)); v++;
496 #else
497       sum += (*v)*(*v); v++;
498 #endif
499     }
500     *norm = sqrt(sum);
501   }
502   else if (type == NORM_1) {
503     *norm = 0.0;
504     for ( j=0; j<mat->n; j++ ) {
505       sum = 0.0;
506       for ( i=0; i<mat->m; i++ ) {
507 #if defined(PETSC_COMPLEX)
508         sum += abs(*v++);
509 #else
510         sum += fabs(*v++);
511 #endif
512       }
513       if (sum > *norm) *norm = sum;
514     }
515   }
516   else if (type == NORM_INFINITY) {
517     *norm = 0.0;
518     for ( j=0; j<mat->m; j++ ) {
519       v = mat->v + j;
520       sum = 0.0;
521       for ( i=0; i<mat->n; i++ ) {
522 #if defined(PETSC_COMPLEX)
523         sum += abs(*v); v += mat->m;
524 #else
525         sum += fabs(*v); v += mat->m;
526 #endif
527       }
528       if (sum > *norm) *norm = sum;
529     }
530   }
531   else {
532     SETERRQ(1,"MatNorm_SeqDense:No two norm");
533   }
534   return 0;
535 }
536 
537 static int MatSetOption_SeqDense(Mat aijin,MatOption op)
538 {
539   Mat_SeqDense *aij = (Mat_SeqDense *) aijin->data;
540   if (op == ROW_ORIENTED)            aij->roworiented = 1;
541   else if (op == COLUMN_ORIENTED)    aij->roworiented = 0;
542   /* doesn't care about sorted rows or columns */
543   return 0;
544 }
545 
546 static int MatZeroEntries_SeqDense(Mat A)
547 {
548   Mat_SeqDense *l = (Mat_SeqDense *) A->data;
549   PetscZero(l->v,l->m*l->n*sizeof(Scalar));
550   return 0;
551 }
552 
553 static int MatZeroRows_SeqDense(Mat A,IS is,Scalar *diag)
554 {
555   Mat_SeqDense *l = (Mat_SeqDense *) A->data;
556   int          n = l->n, i, j,ierr,N, *rows;
557   Scalar       *slot;
558   ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr);
559   ierr = ISGetIndices(is,&rows); CHKERRQ(ierr);
560   for ( i=0; i<N; i++ ) {
561     slot = l->v + rows[i];
562     for ( j=0; j<n; j++ ) { *slot = 0.0; slot += n;}
563   }
564   if (diag) {
565     for ( i=0; i<N; i++ ) {
566       slot = l->v + (n+1)*rows[i];
567       *slot = *diag;
568     }
569   }
570   ISRestoreIndices(is,&rows);
571   return 0;
572 }
573 
574 static int MatGetSize_SeqDense(Mat matin,int *m,int *n)
575 {
576   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
577   *m = mat->m; *n = mat->n;
578   return 0;
579 }
580 
581 static int MatGetOwnershipRange_SeqDense(Mat matin,int *m,int *n)
582 {
583   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
584   *m = 0; *n = mat->m;
585   return 0;
586 }
587 
588 static int MatGetArray_SeqDense(Mat matin,Scalar **array)
589 {
590   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
591   *array = mat->v;
592   return 0;
593 }
594 
595 
596 static int MatGetSubMatrixInPlace_SeqDense(Mat matin,IS isrow,IS iscol)
597 {
598   SETERRQ(1,"MatGetSubMatrixInPlace_SeqDense:not done");
599 }
600 
601 static int MatGetSubMatrix_SeqDense(Mat matin,IS isrow,IS iscol,Mat *submat)
602 {
603   Mat_SeqDense *mat = (Mat_SeqDense *) matin->data;
604   int          nznew, *smap, i, j, ierr, oldcols = mat->n;
605   int          *irow, *icol, nrows, ncols, *cwork;
606   Scalar       *vwork, *val;
607   Mat          newmat;
608 
609   ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr);
610   ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr);
611   ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr);
612   ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr);
613 
614   smap = (int *) PETSCMALLOC(oldcols*sizeof(int)); CHKPTRQ(smap);
615   cwork = (int *) PETSCMALLOC(ncols*sizeof(int)); CHKPTRQ(cwork);
616   vwork = (Scalar *) PETSCMALLOC(ncols*sizeof(Scalar)); CHKPTRQ(vwork);
617   PetscZero((char*)smap,oldcols*sizeof(int));
618   for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1;
619 
620   /* Create and fill new matrix */
621   ierr = MatCreateSeqDense(matin->comm,nrows,ncols,&newmat);CHKERRQ(ierr);
622   for (i=0; i<nrows; i++) {
623     nznew = 0;
624     val   = mat->v + irow[i];
625     for (j=0; j<oldcols; j++) {
626       if (smap[j]) {
627         cwork[nznew]   = smap[j] - 1;
628         vwork[nznew++] = val[j * mat->m];
629       }
630     }
631     ierr = MatSetValues(newmat,1,&i,nznew,cwork,vwork,INSERT_VALUES);
632            CHKERRQ(ierr);
633   }
634   ierr = MatAssemblyBegin(newmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
635   ierr = MatAssemblyEnd(newmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
636 
637   /* Free work space */
638   PETSCFREE(smap); PETSCFREE(cwork); PETSCFREE(vwork);
639   ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr);
640   ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr);
641   *submat = newmat;
642   return 0;
643 }
644 
645 /* -------------------------------------------------------------------*/
646 static struct _MatOps MatOps = {MatInsert_SeqDense,
647        MatGetRow_SeqDense, MatRestoreRow_SeqDense,
648        MatMult_SeqDense, MatMultAdd_SeqDense,
649        MatMultTrans_SeqDense, MatMultTransAdd_SeqDense,
650        MatSolve_SeqDense,MatSolveAdd_SeqDense,
651        MatSolveTrans_SeqDense,MatSolveTransAdd_SeqDense,
652        MatLUFactor_SeqDense,MatCholeskyFactor_SeqDense,
653        MatRelax_SeqDense,
654        MatTranspose_SeqDense,
655        MatGetInfo_SeqDense,MatEqual_SeqDense,
656        MatGetDiagonal_SeqDense,MatScale_SeqDense,MatNorm_SeqDense,
657        0,0,
658        0, MatSetOption_SeqDense,MatZeroEntries_SeqDense,MatZeroRows_SeqDense,0,
659        MatLUFactorSymbolic_SeqDense,MatLUFactorNumeric_SeqDense,
660        MatCholeskyFactorSymbolic_SeqDense,MatCholeskyFactorNumeric_SeqDense,
661        MatGetSize_SeqDense,MatGetSize_SeqDense,MatGetOwnershipRange_SeqDense,
662        0,0,MatGetArray_SeqDense,0,0,
663        MatGetSubMatrix_SeqDense,MatGetSubMatrixInPlace_SeqDense,
664        MatCopyPrivate_SeqDense};
665 
666 /*@C
667    MatCreateSeqDense - Creates a sequential dense matrix that
668    is stored in column major order (the usual Fortran 77 manner). Many
669    of the matrix operations use the BLAS and LAPACK routines.
670 
671    Input Parameters:
672 .  comm - MPI communicator, set to MPI_COMM_SELF
673 .  m - number of rows
674 .  n - number of column
675 
676    Output Parameter:
677 .  newmat - the matrix
678 
679 .keywords: dense, matrix, LAPACK, BLAS
680 
681 .seealso: MatCreate(), MatSetValues()
682 @*/
683 int MatCreateSeqDense(MPI_Comm comm,int m,int n,Mat *newmat)
684 {
685   int          size = sizeof(Mat_SeqDense) + m*n*sizeof(Scalar);
686   Mat          mat;
687   Mat_SeqDense *l;
688   *newmat        = 0;
689   PETSCHEADERCREATE(mat,_Mat,MAT_COOKIE,MATSEQDENSE,comm);
690   PLogObjectCreate(mat);
691   l              = (Mat_SeqDense *) PETSCMALLOC(size); CHKPTRQ(l);
692   PetscMemcpy(&mat->ops,&MatOps,sizeof(struct _MatOps));
693   mat->destroy   = MatDestroy_SeqDense;
694   mat->view      = MatView_SeqDense;
695   mat->data      = (void *) l;
696   mat->factor    = 0;
697   PLogObjectMemory(mat,sizeof(struct _Mat) + size);
698 
699   l->m           = m;
700   l->n           = n;
701   l->v           = (Scalar *) (l + 1);
702   l->pivots      = 0;
703   l->roworiented = 1;
704 
705   PetscZero(l->v,m*n*sizeof(Scalar));
706   *newmat = mat;
707   return 0;
708 }
709 
710 int MatCreate_SeqDense(Mat matin,Mat *newmat)
711 {
712   Mat_SeqDense *m = (Mat_SeqDense *) matin->data;
713   return MatCreateSeqDense(matin->comm,m->m,m->n,newmat);
714 }
715