Actual source code: aijmatlab.c

  1: #define PETSCMAT_DLL

  3: /* 
  4:         Provides an interface for the Matlab engine sparse solver

  6: */
 7:  #include src/mat/impls/aij/seq/aij.h

  9: #include "engine.h"   /* Matlab include file */
 10: #include "mex.h"      /* Matlab include file */

 12: typedef struct {
 13:   PetscErrorCode (*MatDuplicate)(Mat,MatDuplicateOption,Mat*);
 14:   PetscErrorCode (*MatView)(Mat,PetscViewer);
 15:   PetscErrorCode (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*);
 16:   PetscErrorCode (*MatILUDTFactor)(Mat,IS,IS,MatFactorInfo*,Mat*);
 17:   PetscErrorCode (*MatDestroy)(Mat);
 18: } Mat_Matlab;


 24: PetscErrorCode PETSCMAT_DLLEXPORT MatMatlabEnginePut_Matlab(PetscObject obj,void *mengine)
 25: {
 27:   Mat            B = (Mat)obj;
 28:   mxArray        *mat;
 29:   Mat_SeqAIJ     *aij = (Mat_SeqAIJ*)B->data;

 32:   mat  = mxCreateSparse(B->cmap.n,B->rmap.n,aij->nz,mxREAL);
 33:   PetscMemcpy(mxGetPr(mat),aij->a,aij->nz*sizeof(PetscScalar));
 34:   /* Matlab stores by column, not row so we pass in the transpose of the matrix */
 35:   PetscMemcpy(mxGetIr(mat),aij->j,aij->nz*sizeof(int));
 36:   PetscMemcpy(mxGetJc(mat),aij->i,(B->rmap.n+1)*sizeof(int));

 38:   /* Matlab indices start at 0 for sparse (what a surprise) */
 39: 
 40:   PetscObjectName(obj);
 41:   engPutVariable((Engine *)mengine,obj->name,mat);
 42:   return(0);
 43: }

 49: PetscErrorCode PETSCMAT_DLLEXPORT MatMatlabEngineGet_Matlab(PetscObject obj,void *mengine)
 50: {
 52:   int            ii;
 53:   Mat            mat = (Mat)obj;
 54:   Mat_SeqAIJ     *aij = (Mat_SeqAIJ*)mat->data;
 55:   mxArray        *mmat;

 58:   MatSeqXAIJFreeAIJ(aij->singlemalloc,&aij->a,&aij->j,&aij->i);

 60:   mmat = engGetVariable((Engine *)mengine,obj->name);

 62:   aij->nz           = (mxGetJc(mmat))[mat->rmap.n];
 63:   PetscMalloc3(aij->nz,PetscScalar,&aij->a,aij->nz,PetscInt,&aij->j,mat->rmap.n+1,PetscInt,&aij->i);
 64:   aij->singlemalloc = PETSC_TRUE;
 65:   aij->freedata     = PETSC_TRUE;

 67:   PetscMemcpy(aij->a,mxGetPr(mmat),aij->nz*sizeof(PetscScalar));
 68:   /* Matlab stores by column, not row so we pass in the transpose of the matrix */
 69:   PetscMemcpy(aij->j,mxGetIr(mmat),aij->nz*sizeof(int));
 70:   PetscMemcpy(aij->i,mxGetJc(mmat),(mat->rmap.n+1)*sizeof(int));

 72:   for (ii=0; ii<mat->rmap.n; ii++) {
 73:     aij->ilen[ii] = aij->imax[ii] = aij->i[ii+1] - aij->i[ii];
 74:   }

 76:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
 77:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

 79:   return(0);
 80: }

 86: PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_Matlab_SeqAIJ(Mat A,MatType type,MatReuse reuse,Mat *newmat)
 87: {
 89:   Mat            B=*newmat;
 90:   Mat_Matlab    *lu=(Mat_Matlab*)A->spptr;

 93:   if (reuse == MAT_INITIAL_MATRIX) {
 94:     MatDuplicate(A,MAT_COPY_VALUES,&B);
 95:   }
 96:   B->ops->duplicate        = lu->MatDuplicate;
 97:   B->ops->view             = lu->MatView;
 98:   B->ops->lufactorsymbolic = lu->MatLUFactorSymbolic;
 99:   B->ops->iludtfactor      = lu->MatILUDTFactor;
100:   B->ops->destroy          = lu->MatDestroy;
101: 
102:   PetscFree(lu);

104:   PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqaij_matlab_C","",PETSC_NULL);
105:   PetscObjectComposeFunction((PetscObject)B,"MatConvert_matlab_seqaij_C","",PETSC_NULL);
106:   PetscObjectComposeFunction((PetscObject)B,"PetscMatlabEnginePut_C","",PETSC_NULL);
107:   PetscObjectComposeFunction((PetscObject)B,"PetscMatlabEngineGet_C","",PETSC_NULL);

109:   PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJ);
110:   *newmat = B;
111:   return(0);
112: }

117: PetscErrorCode MatDestroy_Matlab(Mat A)
118: {

122:   MatConvert_Matlab_SeqAIJ(A,MATSEQAIJ,MAT_REUSE_MATRIX,&A);
123:   (*A->ops->destroy)(A);
124:   return(0);
125: }

129: PetscErrorCode MatSolve_Matlab(Mat A,Vec b,Vec x)
130: {
132:   const char     *_A,*_b,*_x;

135:   /* make sure objects have names; use default if not */
136:   PetscObjectName((PetscObject)b);
137:   PetscObjectName((PetscObject)x);

139:   PetscObjectGetName((PetscObject)A,&_A);
140:   PetscObjectGetName((PetscObject)b,&_b);
141:   PetscObjectGetName((PetscObject)x,&_x);
142:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)b);
143:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = u%s\\(l%s\\(p%s*%s));",_x,_A,_A,_A,_b);
144:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = 0;",_b);
145:   /* PetscMatlabEnginePrintOutput(PETSC_MATLAB_ENGINE_(A->comm),stdout);  */
146:   PetscMatlabEngineGet(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)x);
147:   return(0);
148: }

152: PetscErrorCode MatLUFactorNumeric_Matlab(Mat A,MatFactorInfo *info,Mat *F)
153: {
155:   size_t         len;
156:   char           *_A,*name;

159:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)A);
160:   _A   = A->name;
161:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"[l_%s,u_%s,p_%s] = lu(%s',%g);",_A,_A,_A,_A,info->dtcol);
162:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = 0;",_A);
163:   PetscStrlen(_A,&len);
164:   PetscMalloc((len+2)*sizeof(char),&name);
165:   sprintf(name,"_%s",_A);
166:   PetscObjectSetName((PetscObject)*F,name);
167:   PetscFree(name);
168:   return(0);
169: }

173: PetscErrorCode MatLUFactorSymbolic_Matlab(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F)
174: {

178:   if (A->cmap.N != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"matrix must be square");
179:   MatCreate(A->comm,F);
180:   MatSetSizes(*F,A->rmap.n,A->cmap.n,A->rmap.n,A->cmap.n);
181:   MatSetType(*F,A->type_name);
182:   MatSeqAIJSetPreallocation(*F,0,PETSC_NULL);
183:   (*F)->ops->solve           = MatSolve_Matlab;
184:   (*F)->ops->lufactornumeric = MatLUFactorNumeric_Matlab;
185:   (*F)->factor               = FACTOR_LU;
186:   return(0);
187: }

189: /* ---------------------------------------------------------------------------------*/
192: PetscErrorCode MatSolve_Matlab_QR(Mat A,Vec b,Vec x)
193: {
195:   const char     *_A,*_b,*_x;

198:   /* make sure objects have names; use default if not */
199:   PetscObjectName((PetscObject)b);
200:   PetscObjectName((PetscObject)x);

202:   PetscObjectGetName((PetscObject)A,&_A);
203:   PetscObjectGetName((PetscObject)b,&_b);
204:   PetscObjectGetName((PetscObject)x,&_x);
205:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)b);
206:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = r%s\\(r%s'\\(%s*%s));",_x,_A,_A,_A+1,_b);
207:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = 0;",_b);
208:   /* PetscMatlabEnginePrintOutput(PETSC_MATLAB_ENGINE_(A->comm),stdout);  */
209:   PetscMatlabEngineGet(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)x);
210:   return(0);
211: }

215: PetscErrorCode MatLUFactorNumeric_Matlab_QR(Mat A,MatFactorInfo *info,Mat *F)
216: {
218:   size_t         len;
219:   char           *_A,*name;

222:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)A);
223:   _A   = A->name;
224:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"r_%s = qr(%s');",_A,_A);
225:   PetscStrlen(_A,&len);
226:   PetscMalloc((len+2)*sizeof(char),&name);
227:   sprintf(name,"_%s",_A);
228:   PetscObjectSetName((PetscObject)*F,name);
229:   PetscFree(name);
230:   return(0);
231: }

235: PetscErrorCode MatLUFactorSymbolic_Matlab_QR(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F)
236: {

240:   if (A->cmap.N != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"matrix must be square");
241:   MatCreate(A->comm,F);
242:   MatSetSizes(*F,A->rmap.n,A->cmap.n,A->rmap.n,A->cmap.n);
243:   MatSetType(*F,A->type_name);
244:   MatSeqAIJSetPreallocation(*F,0,PETSC_NULL);
245:   (*F)->ops->solve           = MatSolve_Matlab_QR;
246:   (*F)->ops->lufactornumeric = MatLUFactorNumeric_Matlab_QR;
247:   (*F)->factor               = FACTOR_LU;
248:   (*F)->assembled            = PETSC_TRUE;  /* required by -ksp_view */

250:   return(0);
251: }

253: /* --------------------------------------------------------------------------------*/
256: PetscErrorCode MatILUDTFactor_Matlab(Mat A,IS isrow,IS iscol,MatFactorInfo *info,Mat *F)
257: {
259:   size_t         len;
260:   char           *_A,*name;

263:   if (info->dt == PETSC_DEFAULT)      info->dt      = .005;
264:   if (info->dtcol == PETSC_DEFAULT)   info->dtcol   = .01;
265:   if (A->cmap.N != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"matrix must be square");
266:   MatCreate(A->comm,F);
267:   MatSetSizes(*F,A->rmap.n,A->cmap.n,A->rmap.n,A->cmap.n);
268:   MatSetType(*F,A->type_name);
269:   MatSeqAIJSetPreallocation(*F,0,PETSC_NULL);
270:   (*F)->ops->solve           = MatSolve_Matlab;
271:   (*F)->factor               = FACTOR_LU;
272:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(A->comm),(PetscObject)A);
273:   _A   = A->name;
274:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"info_%s = struct('droptol',%g,'thresh',%g);",_A,info->dt,info->dtcol);
275:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"[l_%s,u_%s,p_%s] = luinc(%s',info_%s);",_A,_A,_A,_A,_A);
276:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(A->comm),"%s = 0;",_A);

278:   PetscStrlen(_A,&len);
279:   PetscMalloc((len+2)*sizeof(char),&name);
280:   sprintf(name,"_%s",_A);
281:   PetscObjectSetName((PetscObject)*F,name);
282:   PetscFree(name);
283:   return(0);
284: }

288: PetscErrorCode MatFactorInfo_Matlab(Mat A,PetscViewer viewer)
289: {
291: 
293:   PetscViewerASCIIPrintf(viewer,"Matlab run parameters:  -- not written yet!\n");
294:   return(0);
295: }

299: PetscErrorCode MatView_Matlab(Mat A,PetscViewer viewer)
300: {
301:   PetscErrorCode    ierr;
302:   PetscTruth        iascii;
303:   PetscViewerFormat format;
304:   Mat_Matlab        *lu=(Mat_Matlab*)(A->spptr);

307:   (*lu->MatView)(A,viewer);
308:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
309:   if (iascii) {
310:     PetscViewerGetFormat(viewer,&format);
311:     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
312:       MatFactorInfo_Matlab(A,viewer);
313:     }
314:   }
315:   return(0);
316: }

320: PetscErrorCode MatDuplicate_Matlab(Mat A, MatDuplicateOption op, Mat *M)
321: {
323:   Mat_Matlab     *lu=(Mat_Matlab*)A->spptr;

326:   (*lu->MatDuplicate)(A,op,M);
327:   PetscMemcpy((*M)->spptr,lu,sizeof(Mat_Matlab));
328:   return(0);
329: }

334: PetscErrorCode PETSCMAT_DLLEXPORT MatConvert_SeqAIJ_Matlab(Mat A,MatType type,MatReuse reuse,Mat *newmat)
335: {
336:   /* This routine is only called to convert to MATMATLAB */
337:   /* from MATSEQAIJ, so we will ignore 'MatType type'. */
339:   Mat            B=*newmat;
340:   Mat_Matlab     *lu;
341:   PetscTruth     qr;

344:   if (reuse == MAT_INITIAL_MATRIX) {
345:     MatDuplicate(A,MAT_COPY_VALUES,&B);
346:   }

348:   PetscNew(Mat_Matlab,&lu);
349:   lu->MatDuplicate         = A->ops->duplicate;
350:   lu->MatView              = A->ops->view;
351:   lu->MatLUFactorSymbolic  = A->ops->lufactorsymbolic;
352:   lu->MatILUDTFactor       = A->ops->iludtfactor;
353:   lu->MatDestroy           = A->ops->destroy;

355:   B->spptr                 = (void*)lu;
356:   B->ops->duplicate        = MatDuplicate_Matlab;
357:   B->ops->view             = MatView_Matlab;
358:   B->ops->lufactorsymbolic = MatLUFactorSymbolic_Matlab;
359:   B->ops->iludtfactor      = MatILUDTFactor_Matlab;
360:   B->ops->destroy          = MatDestroy_Matlab;

362:   PetscOptionsHasName(A->prefix,"-mat_matlab_qr",&qr);
363:   if (qr) {
364:     B->ops->lufactorsymbolic = MatLUFactorSymbolic_Matlab_QR;
365:     PetscInfo(0,"Using Matlab QR with iterative refinement for LU factorization and solves\n");
366:   } else {
367:     PetscInfo(0,"Using Matlab for LU factorizations and solves.\n");
368:   }
369:   PetscInfo(0,"Using Matlab for ILUDT factorizations and solves.\n");

371:   PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_matlab_C",
372:                                            "MatConvert_SeqAIJ_Matlab",MatConvert_SeqAIJ_Matlab);
373:   PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_matlab_seqaij_C",
374:                                            "MatConvert_Matlab_SeqAIJ",MatConvert_Matlab_SeqAIJ);
375:   PetscObjectComposeFunctionDynamic((PetscObject)B,"PetscMatlabEnginePut_C",
376:                                            "MatMatlabEnginePut_Matlab",MatMatlabEnginePut_Matlab);
377:   PetscObjectComposeFunctionDynamic((PetscObject)B,"PetscMatlabEngineGet_C",
378:                                            "MatMatlabEngineGet_Matlab",MatMatlabEngineGet_Matlab);
379:   PetscObjectChangeTypeName((PetscObject)B,MATMATLAB);
380:   *newmat = B;
381:   return(0);
382: }

385: /*MC
386:   MATMATLAB - MATMATLAB = "matlab" - A matrix type providing direct solvers (LU and QR) and drop tolerance
387:   based ILU factorization (ILUDT) for sequential matrices via the external package Matlab.

389:   If Matlab is instaled (see the manual for
390:   instructions on how to declare the existence of external packages),
391:   a matrix type can be constructed which invokes Matlab solvers.
392:   After calling MatCreate(...,A), simply call MatSetType(A,MATMATLAB).
393:   This matrix type is only supported for double precision real.

395:   This matrix inherits from MATSEQAIJ.  As a result, MatSeqAIJSetPreallocation is 
396:   supported for this matrix type.  One can also call MatConvert for an inplace conversion to or from 
397:   the MATSEQAIJ type without data copy.

399:   Options Database Keys:
400: + -mat_type matlab - sets the matrix type to "matlab" during a call to MatSetFromOptions()
401: - -mat_matlab_qr   - sets the direct solver to be QR instead of LU

403:   Level: beginner

405: .seealso: PCLU
406: M*/

411: PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Matlab(Mat A)
412: {

416:   PetscObjectChangeTypeName((PetscObject)A,MATMATLAB);
417:   MatSetType(A,MATSEQAIJ);
418:   MatConvert_SeqAIJ_Matlab(A,MATMATLAB,MAT_REUSE_MATRIX,&A);
419:   return(0);
420: }