xref: /petsc/src/mat/impls/dense/seq/dense.c (revision 3638b69dbd64ba4780c119c4ea508ad72b54579c)
1 #ifndef lint
2 static char vcid[] = "$Id: dense.c,v 1.89 1996/01/26 04:33:39 bsmith Exp curfman $";
3 #endif
4 /*
5      Defines the basic matrix operations for sequential dense.
6 */
7 
8 #include "dense.h"
9 #include "pinclude/plapack.h"
10 #include "pinclude/pviewer.h"
11 
12 int MatAXPY_SeqDense(Scalar *alpha,Mat X,Mat Y)
13 {
14   Mat_SeqDense *x = (Mat_SeqDense*) X->data,*y = (Mat_SeqDense*) Y->data;
15   int          N = x->m*x->n, one = 1;
16   BLaxpy_( &N, alpha, x->v, &one, y->v, &one );
17   PLogFlops(2*N-1);
18   return 0;
19 }
20 
21 static int MatGetInfo_SeqDense(Mat A,MatInfoType flag,int *nz,int *nzalloc,int *mem)
22 {
23   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
24   int          i,N = mat->m*mat->n,count = 0;
25   Scalar       *v = mat->v;
26   for ( i=0; i<N; i++ ) {if (*v != 0.0) count++; v++;}
27   *nz = count; *nzalloc = N; *mem = (int)A->mem;
28   return 0;
29 }
30 
31 /* ---------------------------------------------------------------*/
32 /* COMMENT: I have chosen to hide column permutation in the pivots,
33    rather than put it in the Mat->col slot.*/
34 static int MatLUFactor_SeqDense(Mat A,IS row,IS col,double f)
35 {
36   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
37   int          info;
38 
39   if (!mat->pivots) {
40     mat->pivots = (int *) PetscMalloc(mat->m*sizeof(int));CHKPTRQ(mat->pivots);
41     PLogObjectMemory(A,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   A->factor = FACTOR_LU;
46   PLogFlops((2*mat->n*mat->n*mat->n)/3);
47   return 0;
48 }
49 static int MatLUFactorSymbolic_SeqDense(Mat A,IS row,IS col,double f,Mat *fact)
50 {
51   return MatConvert(A,MATSAME,fact);
52 }
53 static int MatLUFactorNumeric_SeqDense(Mat A,Mat *fact)
54 {
55   return MatLUFactor(*fact,0,0,1.0);
56 }
57 static int MatCholeskyFactorSymbolic_SeqDense(Mat A,IS row,double f,Mat *fact)
58 {
59   return MatConvert(A,MATSAME,fact);
60 }
61 static int MatCholeskyFactorNumeric_SeqDense(Mat A,Mat *fact)
62 {
63   return MatCholeskyFactor(*fact,0,1.0);
64 }
65 static int MatCholeskyFactor_SeqDense(Mat A,IS perm,double f)
66 {
67   Mat_SeqDense  *mat = (Mat_SeqDense *) A->data;
68   int           info;
69 
70   if (mat->pivots) {
71     PetscFree(mat->pivots);
72     PLogObjectMemory(A,-mat->m*sizeof(int));
73     mat->pivots = 0;
74   }
75   LApotrf_("L",&mat->n,mat->v,&mat->m,&info);
76   if (info) SETERRQ(1,"MatCholeskyFactor_SeqDense:Bad factorization");
77   A->factor = FACTOR_CHOLESKY;
78   PLogFlops((mat->n*mat->n*mat->n)/3);
79   return 0;
80 }
81 
82 static int MatSolve_SeqDense(Mat A,Vec xx,Vec yy)
83 {
84   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
85   int          one = 1, info, ierr;
86   Scalar       *x, *y;
87 
88   ierr = VecGetArray(xx,&x); CHKERRQ(ierr); ierr = VecGetArray(yy,&y); CHKERRQ(ierr);
89   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
90   if (A->factor == FACTOR_LU) {
91     LAgetrs_( "N", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
92   }
93   else if (A->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   PLogFlops(mat->n*mat->n - mat->n);
99   return 0;
100 }
101 static int MatSolveTrans_SeqDense(Mat A,Vec xx,Vec yy)
102 {
103   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
104   int          one = 1, info;
105   Scalar       *x, *y;
106 
107   VecGetArray(xx,&x); VecGetArray(yy,&y);
108   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
109   /* assume if pivots exist then use LU; else Cholesky */
110   if (mat->pivots) {
111     LAgetrs_( "T", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
112   }
113   else {
114     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
115   }
116   if (info) SETERRQ(1,"MatSolveTrans_SeqDense:Bad solve");
117   PLogFlops(mat->n*mat->n - mat->n);
118   return 0;
119 }
120 static int MatSolveAdd_SeqDense(Mat A,Vec xx,Vec zz,Vec yy)
121 {
122   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
123   int          one = 1, info,ierr;
124   Scalar       *x, *y, sone = 1.0;
125   Vec          tmp = 0;
126 
127   VecGetArray(xx,&x); VecGetArray(yy,&y);
128   if (yy == zz) {
129     ierr = VecDuplicate(yy,&tmp); CHKERRQ(ierr);
130     PLogObjectParent(A,tmp);
131     ierr = VecCopy(yy,tmp); CHKERRQ(ierr);
132   }
133   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
134   /* assume if pivots exist then use LU; else Cholesky */
135   if (mat->pivots) {
136     LAgetrs_( "N", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
137   }
138   else {
139     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
140   }
141   if (info) SETERRQ(1,"MatSolveAdd_SeqDense:Bad solve");
142   if (tmp) {VecAXPY(&sone,tmp,yy); VecDestroy(tmp);}
143   else VecAXPY(&sone,zz,yy);
144   PLogFlops(mat->n*mat->n - mat->n);
145   return 0;
146 }
147 
148 static int MatSolveTransAdd_SeqDense(Mat A,Vec xx,Vec zz, Vec yy)
149 {
150   Mat_SeqDense  *mat = (Mat_SeqDense *) A->data;
151   int           one = 1, info,ierr;
152   Scalar        *x, *y, sone = 1.0;
153   Vec           tmp;
154 
155   VecGetArray(xx,&x); VecGetArray(yy,&y);
156   if (yy == zz) {
157     ierr = VecDuplicate(yy,&tmp); CHKERRQ(ierr);
158     PLogObjectParent(A,tmp);
159     ierr = VecCopy(yy,tmp); CHKERRQ(ierr);
160   }
161   PetscMemcpy(y,x,mat->m*sizeof(Scalar));
162   /* assume if pivots exist then use LU; else Cholesky */
163   if (mat->pivots) {
164     LAgetrs_( "T", &mat->m, &one, mat->v, &mat->m, mat->pivots,y, &mat->m, &info );
165   }
166   else {
167     LApotrs_( "L", &mat->m, &one, mat->v, &mat->m,y, &mat->m, &info );
168   }
169   if (info) SETERRQ(1,"MatSolveTransAdd_SeqDense:Bad solve");
170   if (tmp) {VecAXPY(&sone,tmp,yy); VecDestroy(tmp);}
171   else VecAXPY(&sone,zz,yy);
172   PLogFlops(mat->n*mat->n - mat->n);
173   return 0;
174 }
175 /* ------------------------------------------------------------------*/
176 static int MatRelax_SeqDense(Mat A,Vec bb,double omega,MatSORType flag,
177                           double shift,int its,Vec xx)
178 {
179   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
180   Scalar       *x, *b, *v = mat->v, zero = 0.0, xt;
181   int          o = 1,ierr, m = mat->m, i;
182 
183   if (flag & SOR_ZERO_INITIAL_GUESS) {
184     /* this is a hack fix, should have another version without
185        the second BLdot */
186     ierr = VecSet(&zero,xx); CHKERRQ(ierr);
187   }
188   VecGetArray(xx,&x); VecGetArray(bb,&b);
189   while (its--) {
190     if (flag & SOR_FORWARD_SWEEP){
191       for ( i=0; i<m; i++ ) {
192 #if defined(PETSC_COMPLEX)
193         /* cannot use BLAS dot for complex because compiler/linker is
194            not happy about returning a double complex */
195         int    _i;
196         Scalar sum = b[i];
197         for ( _i=0; _i<m; _i++ ) {
198           sum -= conj(v[i+_i*m])*x[_i];
199         }
200         xt = sum;
201 #else
202         xt = b[i]-BLdot_(&m,v+i,&m,x,&o);
203 #endif
204         x[i] = (1. - omega)*x[i] + omega*(xt/(v[i + i*m]+shift) + x[i]);
205       }
206     }
207     if (flag & SOR_BACKWARD_SWEEP) {
208       for ( i=m-1; i>=0; i-- ) {
209 #if defined(PETSC_COMPLEX)
210         /* cannot use BLAS dot for complex because compiler/linker is
211            not happy about returning a double complex */
212         int    _i;
213         Scalar sum = b[i];
214         for ( _i=0; _i<m; _i++ ) {
215           sum -= conj(v[i+_i*m])*x[_i];
216         }
217         xt = sum;
218 #else
219         xt = b[i]-BLdot_(&m,v+i,&m,x,&o);
220 #endif
221         x[i] = (1. - omega)*x[i] + omega*(xt/(v[i + i*m]+shift) + x[i]);
222       }
223     }
224   }
225   return 0;
226 }
227 
228 /* -----------------------------------------------------------------*/
229 static int MatMultTrans_SeqDense(Mat A,Vec xx,Vec yy)
230 {
231   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
232   Scalar       *v = mat->v, *x, *y;
233   int          _One=1;Scalar _DOne=1.0, _DZero=0.0;
234   VecGetArray(xx,&x), VecGetArray(yy,&y);
235   LAgemv_("T",&(mat->m),&(mat->n),&_DOne,v,&(mat->m),x,&_One,&_DZero,y,&_One);
236   PLogFlops(2*mat->m*mat->n - mat->n);
237   return 0;
238 }
239 static int MatMult_SeqDense(Mat A,Vec xx,Vec yy)
240 {
241   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
242   Scalar       *v = mat->v, *x, *y;
243   int          _One=1;Scalar _DOne=1.0, _DZero=0.0;
244   VecGetArray(xx,&x); VecGetArray(yy,&y);
245   LAgemv_( "N", &(mat->m), &(mat->n), &_DOne, v, &(mat->m),x,&_One,&_DZero,y,&_One);
246   PLogFlops(2*mat->m*mat->n - mat->m);
247   return 0;
248 }
249 static int MatMultAdd_SeqDense(Mat A,Vec xx,Vec zz,Vec yy)
250 {
251   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
252   Scalar       *v = mat->v, *x, *y, *z;
253   int          _One=1; Scalar _DOne=1.0;
254   VecGetArray(xx,&x); VecGetArray(yy,&y); VecGetArray(zz,&z);
255   if (zz != yy) PetscMemcpy(y,z,mat->m*sizeof(Scalar));
256   LAgemv_( "N", &(mat->m), &(mat->n),&_DOne,v,&(mat->m),x,&_One,&_DOne,y,&_One);
257   PLogFlops(2*mat->m*mat->n);
258   return 0;
259 }
260 static int MatMultTransAdd_SeqDense(Mat A,Vec xx,Vec zz,Vec yy)
261 {
262   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
263   Scalar       *v = mat->v, *x, *y, *z;
264   int          _One=1;
265   Scalar       _DOne=1.0;
266   VecGetArray(xx,&x); VecGetArray(yy,&y);
267   VecGetArray(zz,&z);
268   if (zz != yy) PetscMemcpy(y,z,mat->m*sizeof(Scalar));
269   LAgemv_( "T", &(mat->m), &(mat->n), &_DOne, v, &(mat->m),x,&_One,&_DOne,y,&_One);
270   PLogFlops(2*mat->m*mat->n);
271   return 0;
272 }
273 
274 /* -----------------------------------------------------------------*/
275 static int MatGetRow_SeqDense(Mat A,int row,int *ncols,int **cols,Scalar **vals)
276 {
277   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
278   Scalar       *v;
279   int          i;
280 
281   *ncols = mat->n;
282   if (cols) {
283     *cols = (int *) PetscMalloc(mat->n*sizeof(int)); CHKPTRQ(*cols);
284     for ( i=0; i<mat->n; i++ ) (*cols)[i] = i;
285   }
286   if (vals) {
287     *vals = (Scalar *) PetscMalloc(mat->n*sizeof(Scalar)); CHKPTRQ(*vals);
288     v = mat->v + row;
289     for ( i=0; i<mat->n; i++ ) {(*vals)[i] = *v; v += mat->m;}
290   }
291   return 0;
292 }
293 static int MatRestoreRow_SeqDense(Mat A,int row,int *ncols,int **cols,Scalar **vals)
294 {
295   if (cols) { PetscFree(*cols); }
296   if (vals) { PetscFree(*vals); }
297   return 0;
298 }
299 /* ----------------------------------------------------------------*/
300 static int MatSetValues_SeqDense(Mat A,int m,int *indexm,int n,
301                                     int *indexn,Scalar *v,InsertMode addv)
302 {
303   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
304   int          i,j;
305 
306   if (!mat->roworiented) {
307     if (addv == INSERT_VALUES) {
308       for ( j=0; j<n; j++ ) {
309         for ( i=0; i<m; i++ ) {
310           mat->v[indexn[j]*mat->m + indexm[i]] = *v++;
311         }
312       }
313     }
314     else {
315       for ( j=0; j<n; j++ ) {
316         for ( i=0; i<m; i++ ) {
317           mat->v[indexn[j]*mat->m + indexm[i]] += *v++;
318         }
319       }
320     }
321   }
322   else {
323     if (addv == INSERT_VALUES) {
324       for ( i=0; i<m; i++ ) {
325         for ( j=0; j<n; j++ ) {
326           mat->v[indexn[j]*mat->m + indexm[i]] = *v++;
327         }
328       }
329     }
330     else {
331       for ( i=0; i<m; i++ ) {
332         for ( j=0; j<n; j++ ) {
333           mat->v[indexn[j]*mat->m + indexm[i]] += *v++;
334         }
335       }
336     }
337   }
338   return 0;
339 }
340 
341 static int MatGetValues_SeqDense(Mat A,int m,int *indexm,int n,int *indexn,Scalar *v)
342 {
343   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
344   int          i, j;
345   Scalar       *vpt = v;
346 
347   /* row-oriented output */
348   for ( i=0; i<m; i++ ) {
349     for ( j=0; j<n; j++ ) {
350       *vpt++ = mat->v[indexn[j]*mat->m + indexm[i]];
351     }
352   }
353   return 0;
354 }
355 
356 /* -----------------------------------------------------------------*/
357 static int MatConvertSameType_SeqDense(Mat A,Mat *newmat,int cpvalues)
358 {
359   Mat_SeqDense *mat = (Mat_SeqDense *) A->data, *l;
360   int          ierr;
361   Mat          newi;
362 
363   ierr = MatCreateSeqDense(A->comm,mat->m,mat->n,PETSC_NULL,&newi); CHKERRQ(ierr);
364   l = (Mat_SeqDense *) newi->data;
365   if (cpvalues == COPY_VALUES) {
366     PetscMemcpy(l->v,mat->v,mat->m*mat->n*sizeof(Scalar));
367   }
368   newi->assembled = PETSC_TRUE;
369   *newmat = newi;
370   return 0;
371 }
372 
373 #include "sysio.h"
374 
375 int MatLoad_SeqDense(Viewer bview,MatType type,Mat *A)
376 {
377   Mat_SeqDense *a;
378   Mat          B;
379   int          *scols, i, j, nz, ierr, fd, header[4], size;
380   int          *rowlengths = 0, M, N, *cols;
381   Scalar       *vals, *svals, *v;
382   PetscObject  vobj = (PetscObject) bview;
383   MPI_Comm     comm = vobj->comm;
384 
385   MPI_Comm_size(comm,&size);
386   if (size > 1) SETERRQ(1,"MatLoad_SeqDense: view must have one processor");
387   ierr = ViewerFileGetDescriptor_Private(bview,&fd); CHKERRQ(ierr);
388   ierr = SYRead(fd,header,4,SYINT); CHKERRQ(ierr);
389   if (header[0] != MAT_COOKIE) SETERRQ(1,"MatLoad_SeqDense:Not matrix object");
390   M = header[1]; N = header[2]; nz = header[3];
391 
392   /* read row lengths */
393   rowlengths = (int*) PetscMalloc( M*sizeof(int) ); CHKPTRQ(rowlengths);
394   ierr = SYRead(fd,rowlengths,M,SYINT); CHKERRQ(ierr);
395 
396   /* create our matrix */
397   ierr = MatCreateSeqDense(comm,M,N,PETSC_NULL,A); CHKERRQ(ierr);
398   B = *A;
399   a = (Mat_SeqDense *) B->data;
400   v = a->v;
401 
402   /* read column indices and nonzeros */
403   cols = scols = (int *) PetscMalloc( nz*sizeof(int) ); CHKPTRQ(cols);
404   ierr = SYRead(fd,cols,nz,SYINT); CHKERRQ(ierr);
405   vals = svals = (Scalar *) PetscMalloc( nz*sizeof(Scalar) ); CHKPTRQ(vals);
406   ierr = SYRead(fd,vals,nz,SYSCALAR); CHKERRQ(ierr);
407 
408   /* insert into matrix */
409   for ( i=0; i<M; i++ ) {
410     for ( j=0; j<rowlengths[i]; j++ ) v[i+M*scols[j]] = svals[j];
411     svals += rowlengths[i]; scols += rowlengths[i];
412   }
413   PetscFree(vals); PetscFree(cols); PetscFree(rowlengths);
414 
415   ierr = MatAssemblyBegin(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
416   ierr = MatAssemblyEnd(B,FINAL_ASSEMBLY); CHKERRQ(ierr);
417   return 0;
418 }
419 
420 #include "pinclude/pviewer.h"
421 #include "sysio.h"
422 
423 static int MatView_SeqDense_ASCII(Mat A,Viewer viewer)
424 {
425   Mat_SeqDense *a = (Mat_SeqDense *) A->data;
426   int          ierr, i, j, format;
427   FILE         *fd;
428   char         *outputname;
429   Scalar       *v;
430 
431   ierr = ViewerFileGetPointer(viewer,&fd); CHKERRQ(ierr);
432   ierr = ViewerFileGetOutputname_Private(viewer,&outputname); CHKERRQ(ierr);
433   ierr = ViewerFileGetFormat_Private(viewer,&format);
434   if (format == FILE_FORMAT_INFO) {
435     ;  /* do nothing for now */
436   }
437   else {
438     for ( i=0; i<a->m; i++ ) {
439       v = a->v + i;
440       for ( j=0; j<a->n; j++ ) {
441 #if defined(PETSC_COMPLEX)
442         fprintf(fd,"%6.4e + %6.4e i ",real(*v),imag(*v)); v += a->m;
443 #else
444         fprintf(fd,"%6.4e ",*v); v += a->m;
445 #endif
446       }
447       fprintf(fd,"\n");
448     }
449   }
450   fflush(fd);
451   return 0;
452 }
453 
454 static int MatView_SeqDense_Binary(Mat A,Viewer viewer)
455 {
456   Mat_SeqDense *a = (Mat_SeqDense *) A->data;
457   int          ict, j, n = a->n, m = a->m, i, fd, *col_lens, ierr, nz = m*n;
458   Scalar       *v, *anonz;
459 
460   ierr = ViewerFileGetDescriptor_Private(viewer,&fd); CHKERRQ(ierr);
461   col_lens = (int *) PetscMalloc( (4+nz)*sizeof(int) ); CHKPTRQ(col_lens);
462   col_lens[0] = MAT_COOKIE;
463   col_lens[1] = m;
464   col_lens[2] = n;
465   col_lens[3] = nz;
466 
467   /* store lengths of each row and write (including header) to file */
468   for ( i=0; i<m; i++ ) col_lens[4+i] = n;
469   ierr = SYWrite(fd,col_lens,4+m,SYINT,1); CHKERRQ(ierr);
470 
471   /* Possibly should write in smaller increments, not whole matrix at once? */
472  /* store column indices (zero start index) */
473   ict = 0;
474   for ( i=0; i<m; i++ ) {
475     for ( j=0; j<n; j++ ) col_lens[ict++] = j;
476   }
477   ierr = SYWrite(fd,col_lens,nz,SYINT,0); CHKERRQ(ierr);
478   PetscFree(col_lens);
479 
480   /* store nonzero values */
481   anonz = (Scalar *) PetscMalloc((nz)*sizeof(Scalar)); CHKPTRQ(anonz);
482   ict = 0;
483   for ( i=0; i<m; i++ ) {
484     v = a->v + i;
485     for ( j=0; j<n; j++ ) {
486       anonz[ict++] = *v; v += a->m;
487     }
488   }
489   ierr = SYWrite(fd,anonz,nz,SYSCALAR,0); CHKERRQ(ierr);
490   PetscFree(anonz);
491   return 0;
492 }
493 
494 static int MatView_SeqDense(PetscObject obj,Viewer viewer)
495 {
496   Mat          A = (Mat) obj;
497   Mat_SeqDense *a = (Mat_SeqDense*) A->data;
498   PetscObject  vobj = (PetscObject) viewer;
499 
500   if (!viewer) {
501     viewer = STDOUT_VIEWER_SELF; vobj = (PetscObject) viewer;
502   }
503   if (vobj->cookie == VIEWER_COOKIE) {
504     if (vobj->type == MATLAB_VIEWER) {
505       return ViewerMatlabPutArray_Private(viewer,a->m,a->n,a->v);
506     }
507     else if (vobj->type == ASCII_FILE_VIEWER || vobj->type == ASCII_FILES_VIEWER) {
508       return MatView_SeqDense_ASCII(A,viewer);
509     }
510     else if (vobj->type == BINARY_FILE_VIEWER) {
511       return MatView_SeqDense_Binary(A,viewer);
512     }
513   }
514   return 0;
515 }
516 
517 static int MatDestroy_SeqDense(PetscObject obj)
518 {
519   Mat          mat = (Mat) obj;
520   Mat_SeqDense *l = (Mat_SeqDense *) mat->data;
521 #if defined(PETSC_LOG)
522   PLogObjectState(obj,"Rows %d Cols %d",l->m,l->n);
523 #endif
524   if (l->pivots) PetscFree(l->pivots);
525   if (!l->user_alloc) PetscFree(l->v);
526   PetscFree(l);
527   PLogObjectDestroy(mat);
528   PetscHeaderDestroy(mat);
529   return 0;
530 }
531 
532 static int MatTranspose_SeqDense(Mat A,Mat *matout)
533 {
534   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
535   int          k, j, m, n;
536   Scalar       *v, tmp;
537 
538   v = mat->v; m = mat->m; n = mat->n;
539   if (matout == PETSC_NULL) { /* in place transpose */
540     if (m != n) SETERRQ(1,"MatTranspose_SeqDense:Supports square matrix only in-place");
541     for ( j=0; j<m; j++ ) {
542       for ( k=0; k<j; k++ ) {
543         tmp = v[j + k*n];
544         v[j + k*n] = v[k + j*n];
545         v[k + j*n] = tmp;
546       }
547     }
548   }
549   else { /* out-of-place transpose */
550     int          ierr;
551     Mat          tmat;
552     Mat_SeqDense *tmatd;
553     Scalar       *v2;
554     ierr = MatCreateSeqDense(A->comm,mat->n,mat->m,PETSC_NULL,&tmat); CHKERRQ(ierr);
555     tmatd = (Mat_SeqDense *) tmat->data;
556     v = mat->v; v2 = tmatd->v;
557     for ( j=0; j<n; j++ ) {
558       for ( k=0; k<m; k++ ) v2[j + k*n] = v[k + j*m];
559     }
560     ierr = MatAssemblyBegin(tmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
561     ierr = MatAssemblyEnd(tmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
562     *matout = tmat;
563   }
564   return 0;
565 }
566 
567 static int MatEqual_SeqDense(Mat A1,Mat A2)
568 {
569   Mat_SeqDense *mat1 = (Mat_SeqDense *) A1->data;
570   Mat_SeqDense *mat2 = (Mat_SeqDense *) A2->data;
571   int          i;
572   Scalar       *v1 = mat1->v, *v2 = mat2->v;
573   if (mat1->m != mat2->m) return 0;
574   if (mat1->n != mat2->n) return 0;
575   for ( i=0; i<mat1->m*mat1->n; i++ ) {
576     if (*v1 != *v2) return 0;
577     v1++; v2++;
578   }
579   return 1;
580 }
581 
582 static int MatGetDiagonal_SeqDense(Mat A,Vec v)
583 {
584   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
585   int          i, n;
586   Scalar       *x;
587   VecGetArray(v,&x); VecGetSize(v,&n);
588   if (n != mat->m) SETERRQ(1,"MatGetDiagonal_SeqDense:Nonconforming mat and vec");
589   for ( i=0; i<mat->m; i++ ) {
590     x[i] = mat->v[i*mat->m + i];
591   }
592   return 0;
593 }
594 
595 static int MatDiagonalScale_SeqDense(Mat A,Vec ll,Vec rr)
596 {
597   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
598   Scalar       *l,*r,x,*v;
599   int          i,j,m = mat->m, n = mat->n;
600 
601   if (ll) {
602     VecGetArray(ll,&l); VecGetSize(ll,&m);
603     if (m != mat->m) SETERRQ(1,"MatDiagonalScale_SeqDense:Left scaling vec wrong size");
604     PLogFlops(n*m);
605     for ( i=0; i<m; i++ ) {
606       x = l[i];
607       v = mat->v + i;
608       for ( j=0; j<n; j++ ) { (*v) *= x; v+= m;}
609     }
610   }
611   if (rr) {
612     VecGetArray(rr,&r); VecGetSize(rr,&n);
613     if (n != mat->n) SETERRQ(1,"MatDiagonalScale_SeqDense:Right scaling vec wrong size");
614     PLogFlops(n*m);
615     for ( i=0; i<n; i++ ) {
616       x = r[i];
617       v = mat->v + i*m;
618       for ( j=0; j<m; j++ ) { (*v++) *= x;}
619     }
620   }
621   return 0;
622 }
623 
624 static int MatNorm_SeqDense(Mat A,NormType type,double *norm)
625 {
626   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
627   Scalar       *v = mat->v;
628   double       sum = 0.0;
629   int          i, j;
630 
631   if (type == NORM_FROBENIUS) {
632     for (i=0; i<mat->n*mat->m; i++ ) {
633 #if defined(PETSC_COMPLEX)
634       sum += real(conj(*v)*(*v)); v++;
635 #else
636       sum += (*v)*(*v); v++;
637 #endif
638     }
639     *norm = sqrt(sum);
640     PLogFlops(2*mat->n*mat->m);
641   }
642   else if (type == NORM_1) {
643     *norm = 0.0;
644     for ( j=0; j<mat->n; j++ ) {
645       sum = 0.0;
646       for ( i=0; i<mat->m; i++ ) {
647         sum += PetscAbsScalar(*v);  v++;
648       }
649       if (sum > *norm) *norm = sum;
650     }
651     PLogFlops(mat->n*mat->m);
652   }
653   else if (type == NORM_INFINITY) {
654     *norm = 0.0;
655     for ( j=0; j<mat->m; j++ ) {
656       v = mat->v + j;
657       sum = 0.0;
658       for ( i=0; i<mat->n; i++ ) {
659         sum += PetscAbsScalar(*v); v += mat->m;
660       }
661       if (sum > *norm) *norm = sum;
662     }
663     PLogFlops(mat->n*mat->m);
664   }
665   else {
666     SETERRQ(1,"MatNorm_SeqDense:No two norm");
667   }
668   return 0;
669 }
670 
671 static int MatSetOption_SeqDense(Mat A,MatOption op)
672 {
673   Mat_SeqDense *aij = (Mat_SeqDense *) A->data;
674 
675   if (op == ROW_ORIENTED)            aij->roworiented = 1;
676   else if (op == COLUMN_ORIENTED)    aij->roworiented = 0;
677   else if (op == ROWS_SORTED ||
678            op == COLUMNS_SORTED ||
679            op == SYMMETRIC_MATRIX ||
680            op == STRUCTURALLY_SYMMETRIC_MATRIX ||
681            op == NO_NEW_NONZERO_LOCATIONS ||
682            op == YES_NEW_NONZERO_LOCATIONS ||
683            op == NO_NEW_DIAGONALS ||
684            op == YES_NEW_DIAGONALS)
685     PLogInfo((PetscObject)A,"Info:MatSetOption_SeqDense:Option ignored\n");
686   else
687     {SETERRQ(PETSC_ERR_SUP,"MatSetOption_SeqDense:unknown option");}
688   return 0;
689 }
690 
691 static int MatZeroEntries_SeqDense(Mat A)
692 {
693   Mat_SeqDense *l = (Mat_SeqDense *) A->data;
694   PetscMemzero(l->v,l->m*l->n*sizeof(Scalar));
695   return 0;
696 }
697 
698 static int MatZeroRows_SeqDense(Mat A,IS is,Scalar *diag)
699 {
700   Mat_SeqDense *l = (Mat_SeqDense *) A->data;
701   int          n = l->n, i, j,ierr,N, *rows;
702   Scalar       *slot;
703 
704   ierr = ISGetLocalSize(is,&N); CHKERRQ(ierr);
705   ierr = ISGetIndices(is,&rows); CHKERRQ(ierr);
706   for ( i=0; i<N; i++ ) {
707     slot = l->v + rows[i];
708     for ( j=0; j<n; j++ ) { *slot = 0.0; slot += n;}
709   }
710   if (diag) {
711     for ( i=0; i<N; i++ ) {
712       slot = l->v + (n+1)*rows[i];
713       *slot = *diag;
714     }
715   }
716   ISRestoreIndices(is,&rows);
717   return 0;
718 }
719 
720 static int MatGetSize_SeqDense(Mat A,int *m,int *n)
721 {
722   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
723   *m = mat->m; *n = mat->n;
724   return 0;
725 }
726 
727 static int MatGetOwnershipRange_SeqDense(Mat A,int *m,int *n)
728 {
729   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
730   *m = 0; *n = mat->m;
731   return 0;
732 }
733 
734 static int MatGetArray_SeqDense(Mat A,Scalar **array)
735 {
736   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
737   *array = mat->v;
738   return 0;
739 }
740 
741 
742 static int MatGetSubMatrixInPlace_SeqDense(Mat A,IS isrow,IS iscol)
743 {
744   SETERRQ(1,"MatGetSubMatrixInPlace_SeqDense:not done");
745 }
746 
747 static int MatGetSubMatrix_SeqDense(Mat A,IS isrow,IS iscol,MatGetSubMatrixCall scall,
748                                     Mat *submat)
749 {
750   Mat_SeqDense *mat = (Mat_SeqDense *) A->data;
751   int          nznew, *smap, i, j, ierr, oldcols = mat->n;
752   int          *irow, *icol, nrows, ncols, *cwork;
753   Scalar       *vwork, *val;
754   Mat          newmat;
755 
756   ierr = ISGetIndices(isrow,&irow); CHKERRQ(ierr);
757   ierr = ISGetIndices(iscol,&icol); CHKERRQ(ierr);
758   ierr = ISGetSize(isrow,&nrows); CHKERRQ(ierr);
759   ierr = ISGetSize(iscol,&ncols); CHKERRQ(ierr);
760 
761   smap = (int *) PetscMalloc(oldcols*sizeof(int)); CHKPTRQ(smap);
762   cwork = (int *) PetscMalloc(ncols*sizeof(int)); CHKPTRQ(cwork);
763   vwork = (Scalar *) PetscMalloc(ncols*sizeof(Scalar)); CHKPTRQ(vwork);
764   PetscMemzero((char*)smap,oldcols*sizeof(int));
765   for ( i=0; i<ncols; i++ ) smap[icol[i]] = i+1;
766 
767   /* Create and fill new matrix */
768   ierr = MatCreateSeqDense(A->comm,nrows,ncols,PETSC_NULL,&newmat); CHKERRQ(ierr);
769   for (i=0; i<nrows; i++) {
770     nznew = 0;
771     val   = mat->v + irow[i];
772     for (j=0; j<oldcols; j++) {
773       if (smap[j]) {
774         cwork[nznew]   = smap[j] - 1;
775         vwork[nznew++] = val[j * mat->m];
776       }
777     }
778     ierr = MatSetValues(newmat,1,&i,nznew,cwork,vwork,INSERT_VALUES);
779            CHKERRQ(ierr);
780   }
781   ierr = MatAssemblyBegin(newmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
782   ierr = MatAssemblyEnd(newmat,FINAL_ASSEMBLY); CHKERRQ(ierr);
783 
784   /* Free work space */
785   PetscFree(smap); PetscFree(cwork); PetscFree(vwork);
786   ierr = ISRestoreIndices(isrow,&irow); CHKERRQ(ierr);
787   ierr = ISRestoreIndices(iscol,&icol); CHKERRQ(ierr);
788   *submat = newmat;
789   return 0;
790 }
791 
792 static int MatCopy_SeqDense(Mat A, Mat B)
793 {
794   Mat_SeqDense *a = (Mat_SeqDense *) A->data, *b = (Mat_SeqDense *)B->data;
795   if (B->type != MATSEQDENSE) return MatCopy_Basic(A,B);
796   if (a->m != b->m || a->n != b->n) SETERRQ(1,"MatCopy_SeqDense:size(B) != size(A)");
797   PetscMemcpy(b->v,a->v,a->m*a->n*sizeof(Scalar));
798   return 0;
799 }
800 
801 /* -------------------------------------------------------------------*/
802 static struct _MatOps MatOps = {MatSetValues_SeqDense,
803        MatGetRow_SeqDense, MatRestoreRow_SeqDense,
804        MatMult_SeqDense, MatMultAdd_SeqDense,
805        MatMultTrans_SeqDense, MatMultTransAdd_SeqDense,
806        MatSolve_SeqDense,MatSolveAdd_SeqDense,
807        MatSolveTrans_SeqDense,MatSolveTransAdd_SeqDense,
808        MatLUFactor_SeqDense,MatCholeskyFactor_SeqDense,
809        MatRelax_SeqDense,
810        MatTranspose_SeqDense,
811        MatGetInfo_SeqDense,MatEqual_SeqDense,
812        MatGetDiagonal_SeqDense,MatDiagonalScale_SeqDense,MatNorm_SeqDense,
813        0,0,
814        0, MatSetOption_SeqDense,MatZeroEntries_SeqDense,MatZeroRows_SeqDense,0,
815        MatLUFactorSymbolic_SeqDense,MatLUFactorNumeric_SeqDense,
816        MatCholeskyFactorSymbolic_SeqDense,MatCholeskyFactorNumeric_SeqDense,
817        MatGetSize_SeqDense,MatGetSize_SeqDense,MatGetOwnershipRange_SeqDense,
818        0,0,MatGetArray_SeqDense,0,0,
819        MatGetSubMatrix_SeqDense,MatGetSubMatrixInPlace_SeqDense,
820        MatConvertSameType_SeqDense,0,0,0,0,
821        MatAXPY_SeqDense,0,0,
822        MatGetValues_SeqDense,
823        MatCopy_SeqDense};
824 
825 /*@C
826    MatCreateSeqDense - Creates a sequential dense matrix that
827    is stored in column major order (the usual Fortran 77 manner). Many
828    of the matrix operations use the BLAS and LAPACK routines.
829 
830    Input Parameters:
831 .  comm - MPI communicator, set to MPI_COMM_SELF
832 .  m - number of rows
833 .  n - number of columns
834 .  data - optional location of matrix data.  Set data=PETSC_NULL for PETSc
835    to control all matrix memory allocation.
836 
837    Output Parameter:
838 .  newmat - the matrix
839 
840   Notes:
841   The data input variable is intended primarily for Fortran programmers
842   who wish to allocate their own matrix memory space.  Most users should
843   set data=PETSC_NULL.
844 
845 .keywords: dense, matrix, LAPACK, BLAS
846 
847 .seealso: MatCreate(), MatSetValues()
848 @*/
849 int MatCreateSeqDense(MPI_Comm comm,int m,int n,Scalar *data,Mat *newmat)
850 {
851   Mat          mat;
852   Mat_SeqDense *l;
853   int          ierr,flg;
854 
855   *newmat        = 0;
856 
857   PetscHeaderCreate(mat,_Mat,MAT_COOKIE,MATSEQDENSE,comm);
858   PLogObjectCreate(mat);
859   l               = (Mat_SeqDense *) PetscMalloc(sizeof(Mat_SeqDense)); CHKPTRQ(l);
860   PetscMemcpy(&mat->ops,&MatOps,sizeof(struct _MatOps));
861   mat->destroy    = MatDestroy_SeqDense;
862   mat->view       = MatView_SeqDense;
863   mat->factor     = 0;
864   PLogObjectMemory(mat,sizeof(struct _Mat));
865   mat->data       = (void *) l;
866 
867   l->m            = m;
868   l->n            = n;
869   l->pivots       = 0;
870   l->roworiented  = 1;
871   if (data == PETSC_NULL) {
872     l->v = (Scalar*) PetscMalloc((m*n+1)*sizeof(Scalar)); CHKPTRQ(l->v);
873     PetscMemzero(l->v,m*n*sizeof(Scalar));
874     l->user_alloc = 0;
875     PLogObjectMemory(mat,n*m*sizeof(Scalar));
876   }
877   else { /* user-allocated storage */
878     l->v = data;
879     l->user_alloc = 1;
880   }
881 
882   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
883   if (flg) {
884     ierr = MatPrintHelp(mat); CHKERRQ(ierr);
885   }
886   *newmat = mat;
887   return 0;
888 }
889 
890 int MatCreate_SeqDense(Mat A,Mat *newmat)
891 {
892   Mat_SeqDense *m = (Mat_SeqDense *) A->data;
893   return MatCreateSeqDense(A->comm,m->m,m->n,PETSC_NULL,newmat);
894 }
895