xref: /petsc/src/mat/impls/transpose/transm.c (revision 6718818e67c4802797f2feae43fc3d52878b6955)
185e3dda7SBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/matimpl.h>          /*I "petscmat.h" I*/
385e3dda7SBarry Smith 
485e3dda7SBarry Smith typedef struct {
585e3dda7SBarry Smith   Mat A;
685e3dda7SBarry Smith } Mat_Transpose;
785e3dda7SBarry Smith 
885e3dda7SBarry Smith PetscErrorCode MatMult_Transpose(Mat N,Vec x,Vec y)
985e3dda7SBarry Smith {
1085e3dda7SBarry Smith   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
1185e3dda7SBarry Smith   PetscErrorCode ierr;
1285e3dda7SBarry Smith 
1385e3dda7SBarry Smith   PetscFunctionBegin;
1485e3dda7SBarry Smith   ierr = MatMultTranspose(Na->A,x,y);CHKERRQ(ierr);
1585e3dda7SBarry Smith   PetscFunctionReturn(0);
1685e3dda7SBarry Smith }
1785e3dda7SBarry Smith 
1885e3dda7SBarry Smith PetscErrorCode MatMultAdd_Transpose(Mat N,Vec v1,Vec v2,Vec v3)
1985e3dda7SBarry Smith {
2085e3dda7SBarry Smith   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
2185e3dda7SBarry Smith   PetscErrorCode ierr;
2285e3dda7SBarry Smith 
2385e3dda7SBarry Smith   PetscFunctionBegin;
2485e3dda7SBarry Smith   ierr = MatMultTransposeAdd(Na->A,v1,v2,v3);CHKERRQ(ierr);
2585e3dda7SBarry Smith   PetscFunctionReturn(0);
2685e3dda7SBarry Smith }
2785e3dda7SBarry Smith 
2847a9afc9SBarry Smith PetscErrorCode MatMultTranspose_Transpose(Mat N,Vec x,Vec y)
2947a9afc9SBarry Smith {
3047a9afc9SBarry Smith   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
3147a9afc9SBarry Smith   PetscErrorCode ierr;
3247a9afc9SBarry Smith 
3347a9afc9SBarry Smith   PetscFunctionBegin;
3447a9afc9SBarry Smith   ierr = MatMult(Na->A,x,y);CHKERRQ(ierr);
3547a9afc9SBarry Smith   PetscFunctionReturn(0);
3647a9afc9SBarry Smith }
3747a9afc9SBarry Smith 
3847a9afc9SBarry Smith PetscErrorCode MatMultTransposeAdd_Transpose(Mat N,Vec v1,Vec v2,Vec v3)
3947a9afc9SBarry Smith {
4047a9afc9SBarry Smith   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
4147a9afc9SBarry Smith   PetscErrorCode ierr;
4247a9afc9SBarry Smith 
4347a9afc9SBarry Smith   PetscFunctionBegin;
4447a9afc9SBarry Smith   ierr = MatMultAdd(Na->A,v1,v2,v3);CHKERRQ(ierr);
4547a9afc9SBarry Smith   PetscFunctionReturn(0);
4647a9afc9SBarry Smith }
4747a9afc9SBarry Smith 
4885e3dda7SBarry Smith PetscErrorCode MatDestroy_Transpose(Mat N)
4985e3dda7SBarry Smith {
5085e3dda7SBarry Smith   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
5185e3dda7SBarry Smith   PetscErrorCode ierr;
5285e3dda7SBarry Smith 
5385e3dda7SBarry Smith   PetscFunctionBegin;
546bf464f9SBarry Smith   ierr = MatDestroy(&Na->A);CHKERRQ(ierr);
558060fb66Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)N,"MatTransposeGetMat_C",NULL);CHKERRQ(ierr);
56*6718818eSStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)N,"MatProductSetFromOptions_anytype_C",NULL);CHKERRQ(ierr);
57bf0cc555SLisandro Dalcin   ierr = PetscFree(N->data);CHKERRQ(ierr);
5885e3dda7SBarry Smith   PetscFunctionReturn(0);
5985e3dda7SBarry Smith }
6085e3dda7SBarry Smith 
61d0de2241SAndrew Spott PetscErrorCode MatDuplicate_Transpose(Mat N, MatDuplicateOption op, Mat* m)
62d0de2241SAndrew Spott {
63d0de2241SAndrew Spott   Mat_Transpose  *Na = (Mat_Transpose*)N->data;
64d0de2241SAndrew Spott   PetscErrorCode ierr;
65d0de2241SAndrew Spott 
66d0de2241SAndrew Spott   PetscFunctionBegin;
67d0de2241SAndrew Spott   if (op == MAT_COPY_VALUES) {
68d0de2241SAndrew Spott     ierr = MatTranspose(Na->A,MAT_INITIAL_MATRIX,m);CHKERRQ(ierr);
69d0de2241SAndrew Spott   } else if (op == MAT_DO_NOT_COPY_VALUES) {
70d0de2241SAndrew Spott     ierr = MatDuplicate(Na->A,MAT_DO_NOT_COPY_VALUES,m);CHKERRQ(ierr);
71c837ededSStefano Zampini     ierr = MatTranspose(*m,MAT_INPLACE_MATRIX,m);CHKERRQ(ierr);
72fb41c00aSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)N),PETSC_ERR_SUP,"MAT_SHARE_NONZERO_PATTERN not supported for this matrix type");
73d0de2241SAndrew Spott   PetscFunctionReturn(0);
74d0de2241SAndrew Spott }
75d0de2241SAndrew Spott 
76d9b48344SStefano Zampini PetscErrorCode MatCreateVecs_Transpose(Mat A,Vec *r, Vec *l)
77d9b48344SStefano Zampini {
78d9b48344SStefano Zampini   Mat_Transpose  *Aa = (Mat_Transpose*)A->data;
79d9b48344SStefano Zampini   PetscErrorCode ierr;
80d9b48344SStefano Zampini 
81d9b48344SStefano Zampini   PetscFunctionBegin;
82d9b48344SStefano Zampini   ierr = MatCreateVecs(Aa->A,l,r);CHKERRQ(ierr);
83d9b48344SStefano Zampini   PetscFunctionReturn(0);
84d9b48344SStefano Zampini }
85d9b48344SStefano Zampini 
866171f1c8SPierre Jolivet PetscErrorCode MatAXPY_Transpose(Mat Y,PetscScalar a,Mat X,MatStructure str)
876171f1c8SPierre Jolivet {
886171f1c8SPierre Jolivet   Mat_Transpose  *Ya = (Mat_Transpose*)Y->data;
896171f1c8SPierre Jolivet   Mat_Transpose  *Xa = (Mat_Transpose*)X->data;
906171f1c8SPierre Jolivet   Mat              M = Ya->A;
916171f1c8SPierre Jolivet   Mat              N = Xa->A;
926171f1c8SPierre Jolivet   PetscErrorCode ierr;
936171f1c8SPierre Jolivet 
946171f1c8SPierre Jolivet   PetscFunctionBegin;
956171f1c8SPierre Jolivet   ierr = MatAXPY(M,a,N,str);CHKERRQ(ierr);
966171f1c8SPierre Jolivet   PetscFunctionReturn(0);
976171f1c8SPierre Jolivet }
986171f1c8SPierre Jolivet 
9952c5f739Sprj- PetscErrorCode MatHasOperation_Transpose(Mat mat,MatOperation op,PetscBool *has)
10052c5f739Sprj- {
10152c5f739Sprj-   Mat_Transpose  *X = (Mat_Transpose*)mat->data;
10252c5f739Sprj-   PetscErrorCode ierr;
10352c5f739Sprj-   PetscFunctionBegin;
10452c5f739Sprj- 
10552c5f739Sprj-   *has = PETSC_FALSE;
1063c6db4c4SPierre Jolivet   if (op == MATOP_MULT) {
1073c6db4c4SPierre Jolivet     ierr = MatHasOperation(X->A,MATOP_MULT_TRANSPOSE,has);CHKERRQ(ierr);
1083c6db4c4SPierre Jolivet   } else if (op == MATOP_MULT_TRANSPOSE) {
1093c6db4c4SPierre Jolivet     ierr = MatHasOperation(X->A,MATOP_MULT,has);CHKERRQ(ierr);
1103c6db4c4SPierre Jolivet   } else if (op == MATOP_MULT_ADD) {
1113c6db4c4SPierre Jolivet     ierr = MatHasOperation(X->A,MATOP_MULT_TRANSPOSE_ADD,has);CHKERRQ(ierr);
1123c6db4c4SPierre Jolivet   } else if (op == MATOP_MULT_TRANSPOSE_ADD) {
1133c6db4c4SPierre Jolivet     ierr = MatHasOperation(X->A,MATOP_MULT_ADD,has);CHKERRQ(ierr);
1143c6db4c4SPierre Jolivet   } else if (((void**)mat->ops)[op]) *has = PETSC_TRUE;
11552c5f739Sprj-   PetscFunctionReturn(0);
11652c5f739Sprj- }
11752c5f739Sprj- 
118*6718818eSStefano Zampini /* used by hermitian transpose */
119*6718818eSStefano Zampini PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Transpose(Mat D)
120*6718818eSStefano Zampini {
121*6718818eSStefano Zampini   Mat            A,B,C,Ain,Bin,Cin;
122*6718818eSStefano Zampini   PetscBool      Aistrans,Bistrans,Cistrans;
123*6718818eSStefano Zampini   PetscInt       Atrans,Btrans,Ctrans;
124*6718818eSStefano Zampini   MatProductType ptype;
125*6718818eSStefano Zampini   PetscErrorCode ierr;
126*6718818eSStefano Zampini 
127*6718818eSStefano Zampini   PetscFunctionBegin;
128*6718818eSStefano Zampini   MatCheckProduct(D,1);
129*6718818eSStefano Zampini   A = D->product->A;
130*6718818eSStefano Zampini   B = D->product->B;
131*6718818eSStefano Zampini   C = D->product->C;
132*6718818eSStefano Zampini   ierr = PetscObjectTypeCompare((PetscObject)A,MATTRANSPOSEMAT,&Aistrans);CHKERRQ(ierr);
133*6718818eSStefano Zampini   ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&Bistrans);CHKERRQ(ierr);
134*6718818eSStefano Zampini   ierr = PetscObjectTypeCompare((PetscObject)C,MATTRANSPOSEMAT,&Cistrans);CHKERRQ(ierr);
135*6718818eSStefano Zampini   if (!Aistrans && !Bistrans && !Cistrans) SETERRQ(PetscObjectComm((PetscObject)D),PETSC_ERR_PLIB,"This should not happen");
136*6718818eSStefano Zampini   Atrans = 0;
137*6718818eSStefano Zampini   Ain    = A;
138*6718818eSStefano Zampini   while (Aistrans) {
139*6718818eSStefano Zampini     Atrans++;
140*6718818eSStefano Zampini     ierr = MatTransposeGetMat(Ain,&Ain);CHKERRQ(ierr);
141*6718818eSStefano Zampini     ierr = PetscObjectTypeCompare((PetscObject)Ain,MATTRANSPOSEMAT,&Aistrans);CHKERRQ(ierr);
142*6718818eSStefano Zampini   }
143*6718818eSStefano Zampini   Btrans = 0;
144*6718818eSStefano Zampini   Bin    = B;
145*6718818eSStefano Zampini   while (Bistrans) {
146*6718818eSStefano Zampini     Btrans++;
147*6718818eSStefano Zampini     ierr = MatTransposeGetMat(Bin,&Bin);CHKERRQ(ierr);
148*6718818eSStefano Zampini     ierr = PetscObjectTypeCompare((PetscObject)Bin,MATTRANSPOSEMAT,&Bistrans);CHKERRQ(ierr);
149*6718818eSStefano Zampini   }
150*6718818eSStefano Zampini   Ctrans = 0;
151*6718818eSStefano Zampini   Cin    = C;
152*6718818eSStefano Zampini   while (Cistrans) {
153*6718818eSStefano Zampini     Ctrans++;
154*6718818eSStefano Zampini     ierr = MatTransposeGetMat(Cin,&Cin);CHKERRQ(ierr);
155*6718818eSStefano Zampini     ierr = PetscObjectTypeCompare((PetscObject)Cin,MATTRANSPOSEMAT,&Cistrans);CHKERRQ(ierr);
156*6718818eSStefano Zampini   }
157*6718818eSStefano Zampini   Atrans = Atrans%2;
158*6718818eSStefano Zampini   Btrans = Btrans%2;
159*6718818eSStefano Zampini   Ctrans = Ctrans%2;
160*6718818eSStefano Zampini   ptype = D->product->type; /* same product type by default */
161*6718818eSStefano Zampini   if (Ain->symmetric) Atrans = 0;
162*6718818eSStefano Zampini   if (Bin->symmetric) Btrans = 0;
163*6718818eSStefano Zampini   if (Cin && Cin->symmetric) Ctrans = 0;
164*6718818eSStefano Zampini 
165*6718818eSStefano Zampini   if (Atrans || Btrans || Ctrans) {
166*6718818eSStefano Zampini     ptype = MATPRODUCT_UNSPECIFIED;
167*6718818eSStefano Zampini     switch (D->product->type) {
168*6718818eSStefano Zampini     case MATPRODUCT_AB:
169*6718818eSStefano Zampini       if (Atrans && Btrans) { /* At * Bt we do not have support for this */
170*6718818eSStefano Zampini         /* TODO custom implementation ? */
171*6718818eSStefano Zampini       } else if (Atrans) { /* At * B */
172*6718818eSStefano Zampini         ptype = MATPRODUCT_AtB;
173*6718818eSStefano Zampini       } else { /* A * Bt */
174*6718818eSStefano Zampini         ptype = MATPRODUCT_ABt;
175*6718818eSStefano Zampini       }
176*6718818eSStefano Zampini       break;
177*6718818eSStefano Zampini     case MATPRODUCT_AtB:
178*6718818eSStefano Zampini       if (Atrans && Btrans) { /* A * Bt */
179*6718818eSStefano Zampini         ptype = MATPRODUCT_ABt;
180*6718818eSStefano Zampini       } else if (Atrans) { /* A * B */
181*6718818eSStefano Zampini         ptype = MATPRODUCT_AB;
182*6718818eSStefano Zampini       } else { /* At * Bt we do not have support for this */
183*6718818eSStefano Zampini         /* TODO custom implementation ? */
184*6718818eSStefano Zampini       }
185*6718818eSStefano Zampini       break;
186*6718818eSStefano Zampini     case MATPRODUCT_ABt:
187*6718818eSStefano Zampini       if (Atrans && Btrans) { /* At * B */
188*6718818eSStefano Zampini         ptype = MATPRODUCT_AtB;
189*6718818eSStefano Zampini       } else if (Atrans) { /* At * Bt we do not have support for this */
190*6718818eSStefano Zampini         /* TODO custom implementation ? */
191*6718818eSStefano Zampini       } else {  /* A * B */
192*6718818eSStefano Zampini         ptype = MATPRODUCT_AB;
193*6718818eSStefano Zampini       }
194*6718818eSStefano Zampini       break;
195*6718818eSStefano Zampini     case MATPRODUCT_PtAP:
196*6718818eSStefano Zampini       if (Atrans) { /* PtAtP */
197*6718818eSStefano Zampini         /* TODO custom implementation ? */
198*6718818eSStefano Zampini       } else { /* RARt */
199*6718818eSStefano Zampini         ptype = MATPRODUCT_RARt;
200*6718818eSStefano Zampini       }
201*6718818eSStefano Zampini       break;
202*6718818eSStefano Zampini     case MATPRODUCT_RARt:
203*6718818eSStefano Zampini       if (Atrans) { /* RAtRt */
204*6718818eSStefano Zampini         /* TODO custom implementation ? */
205*6718818eSStefano Zampini       } else { /* PtAP */
206*6718818eSStefano Zampini         ptype = MATPRODUCT_PtAP;
207*6718818eSStefano Zampini       }
208*6718818eSStefano Zampini       break;
209*6718818eSStefano Zampini     case MATPRODUCT_ABC:
210*6718818eSStefano Zampini       /* TODO custom implementation ? */
211*6718818eSStefano Zampini       break;
212*6718818eSStefano Zampini     default: SETERRQ1(PetscObjectComm((PetscObject)D),PETSC_ERR_SUP,"ProductType %s is not supported",MatProductTypes[D->product->type]);
213*6718818eSStefano Zampini     }
214*6718818eSStefano Zampini   }
215*6718818eSStefano Zampini   ierr = MatProductReplaceMats(Ain,Bin,Cin,D);CHKERRQ(ierr);
216*6718818eSStefano Zampini   ierr = MatProductSetType(D,ptype);CHKERRQ(ierr);
217*6718818eSStefano Zampini   ierr = MatProductSetFromOptions(D);CHKERRQ(ierr);
218*6718818eSStefano Zampini   PetscFunctionReturn(0);
219*6718818eSStefano Zampini }
220*6718818eSStefano Zampini 
2218060fb66Sstefano_zampini PetscErrorCode MatTransposeGetMat_Transpose(Mat A,Mat *M)
2228060fb66Sstefano_zampini {
2238060fb66Sstefano_zampini   Mat_Transpose  *Aa = (Mat_Transpose*)A->data;
2248060fb66Sstefano_zampini 
2258060fb66Sstefano_zampini   PetscFunctionBegin;
2268060fb66Sstefano_zampini   *M = Aa->A;
2278060fb66Sstefano_zampini   PetscFunctionReturn(0);
2288060fb66Sstefano_zampini }
2298060fb66Sstefano_zampini 
2308060fb66Sstefano_zampini /*@
23106511a5cSPierre Jolivet       MatTransposeGetMat - Gets the Mat object stored inside a MATTRANSPOSEMAT
2328060fb66Sstefano_zampini 
2338060fb66Sstefano_zampini    Logically collective on Mat
2348060fb66Sstefano_zampini 
2358060fb66Sstefano_zampini    Input Parameter:
2368060fb66Sstefano_zampini .   A  - the MATTRANSPOSE matrix
2378060fb66Sstefano_zampini 
2388060fb66Sstefano_zampini    Output Parameter:
2398060fb66Sstefano_zampini .   M - the matrix object stored inside A
2408060fb66Sstefano_zampini 
2418060fb66Sstefano_zampini    Level: intermediate
2428060fb66Sstefano_zampini 
2438060fb66Sstefano_zampini .seealso: MatCreateTranspose()
2448060fb66Sstefano_zampini 
2458060fb66Sstefano_zampini @*/
2468060fb66Sstefano_zampini PetscErrorCode MatTransposeGetMat(Mat A,Mat *M)
2478060fb66Sstefano_zampini {
2488060fb66Sstefano_zampini   PetscErrorCode ierr;
2498060fb66Sstefano_zampini 
2508060fb66Sstefano_zampini   PetscFunctionBegin;
2518060fb66Sstefano_zampini   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
2528060fb66Sstefano_zampini   PetscValidType(A,1);
2538060fb66Sstefano_zampini   PetscValidPointer(M,2);
2548060fb66Sstefano_zampini   ierr = PetscUseMethod(A,"MatTransposeGetMat_C",(Mat,Mat*),(A,M));CHKERRQ(ierr);
2558060fb66Sstefano_zampini   PetscFunctionReturn(0);
2568060fb66Sstefano_zampini }
257d0de2241SAndrew Spott 
25885e3dda7SBarry Smith /*@
25985e3dda7SBarry Smith       MatCreateTranspose - Creates a new matrix object that behaves like A'
26085e3dda7SBarry Smith 
26185e3dda7SBarry Smith    Collective on Mat
26285e3dda7SBarry Smith 
26385e3dda7SBarry Smith    Input Parameter:
26485e3dda7SBarry Smith .   A  - the (possibly rectangular) matrix
26585e3dda7SBarry Smith 
26685e3dda7SBarry Smith    Output Parameter:
26785e3dda7SBarry Smith .   N - the matrix that represents A'
26885e3dda7SBarry Smith 
26985e3dda7SBarry Smith    Level: intermediate
27085e3dda7SBarry Smith 
27195452b02SPatrick Sanan    Notes:
27295452b02SPatrick Sanan     The transpose A' is NOT actually formed! Rather the new matrix
27385e3dda7SBarry Smith           object performs the matrix-vector product by using the MatMultTranspose() on
27485e3dda7SBarry Smith           the original matrix
27585e3dda7SBarry Smith 
27685e3dda7SBarry Smith .seealso: MatCreateNormal(), MatMult(), MatMultTranspose(), MatCreate()
27785e3dda7SBarry Smith 
27885e3dda7SBarry Smith @*/
2797087cfbeSBarry Smith PetscErrorCode  MatCreateTranspose(Mat A,Mat *N)
28085e3dda7SBarry Smith {
28185e3dda7SBarry Smith   PetscErrorCode ierr;
28285e3dda7SBarry Smith   PetscInt       m,n;
28385e3dda7SBarry Smith   Mat_Transpose  *Na;
28485e3dda7SBarry Smith 
28585e3dda7SBarry Smith   PetscFunctionBegin;
28685e3dda7SBarry Smith   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
287ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)A),N);CHKERRQ(ierr);
28885e3dda7SBarry Smith   ierr = MatSetSizes(*N,n,m,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
289d97d01c0SJed Brown   ierr = PetscLayoutSetUp((*N)->rmap);CHKERRQ(ierr);
290d97d01c0SJed Brown   ierr = PetscLayoutSetUp((*N)->cmap);CHKERRQ(ierr);
291557cca28SSatish Balay   ierr = PetscObjectChangeTypeName((PetscObject)*N,MATTRANSPOSEMAT);CHKERRQ(ierr);
29285e3dda7SBarry Smith 
293b00a9115SJed Brown   ierr       = PetscNewLog(*N,&Na);CHKERRQ(ierr);
29485e3dda7SBarry Smith   (*N)->data = (void*) Na;
29585e3dda7SBarry Smith   ierr       = PetscObjectReference((PetscObject)A);CHKERRQ(ierr);
29685e3dda7SBarry Smith   Na->A      = A;
29785e3dda7SBarry Smith 
29885e3dda7SBarry Smith   (*N)->ops->destroy               = MatDestroy_Transpose;
29985e3dda7SBarry Smith   (*N)->ops->mult                  = MatMult_Transpose;
3006d12b599SJed Brown   (*N)->ops->multadd               = MatMultAdd_Transpose;
30147a9afc9SBarry Smith   (*N)->ops->multtranspose         = MatMultTranspose_Transpose;
30247a9afc9SBarry Smith   (*N)->ops->multtransposeadd      = MatMultTransposeAdd_Transpose;
303d0de2241SAndrew Spott   (*N)->ops->duplicate             = MatDuplicate_Transpose;
304d9b48344SStefano Zampini   (*N)->ops->getvecs               = MatCreateVecs_Transpose;
3056171f1c8SPierre Jolivet   (*N)->ops->axpy                  = MatAXPY_Transpose;
30652c5f739Sprj-   (*N)->ops->hasoperation          = MatHasOperation_Transpose;
307*6718818eSStefano Zampini   (*N)->ops->productsetfromoptions = MatProductSetFromOptions_Transpose;
30885e3dda7SBarry Smith   (*N)->assembled                  = PETSC_TRUE;
30985e3dda7SBarry Smith 
3108060fb66Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)(*N),"MatTransposeGetMat_C",MatTransposeGetMat_Transpose);CHKERRQ(ierr);
311*6718818eSStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)(*N),"MatProductSetFromOptions_anytype_C",MatProductSetFromOptions_Transpose);CHKERRQ(ierr);
31233d57670SJed Brown   ierr = MatSetBlockSizes(*N,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs));CHKERRQ(ierr);
313037c98a2SJed Brown   ierr = MatSetUp(*N);CHKERRQ(ierr);
31485e3dda7SBarry Smith   PetscFunctionReturn(0);
31585e3dda7SBarry Smith }
316