Date: 2013-09-02T10:06:39+00:00

Actual source code: cyclic.c

      1: /*

      3:    SLEPc singular value solver: "cyclic"

      5:    Method: Uses a Hermitian eigensolver for H(A) = [ 0  A ; A^T 0 ]

      7:    Last update: Jun 2007

      9:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     10:    SLEPc - Scalable Library for Eigenvalue Problem Computations
     11:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

     13:    This file is part of SLEPc.

     15:    SLEPc is free software: you can redistribute it and/or modify it under  the
     16:    terms of version 3 of the GNU Lesser General Public License as published by
     17:    the Free Software Foundation.

     19:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     20:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     21:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     22:    more details.

     24:    You  should have received a copy of the GNU Lesser General  Public  License
     25:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     26:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     27: */

     29: #include <slepc-private/svdimpl.h>                /*I "slepcsvd.h" I*/
     30: #include <slepc-private/epsimpl.h>                /*I "slepceps.h" I*/

     32: typedef struct {
     33:   PetscBool explicitmatrix;
     34:   EPS       eps;
     35:   PetscBool setfromoptionscalled;
     36:   Mat       mat;
     37:   Vec       x1,x2,y1,y2;
     38: } SVD_CYCLIC;

     42: static PetscErrorCode MatMult_Cyclic(Mat B,Vec x,Vec y)
     43: {
     44:   PetscErrorCode    ierr;
     45:   SVD               svd;
     46:   SVD_CYCLIC        *cyclic;
     47:   const PetscScalar *px;
     48:   PetscScalar       *py;
     49:   PetscInt          m;

     52:   MatShellGetContext(B,(void**)&svd);
     53:   cyclic = (SVD_CYCLIC*)svd->data;
     54:   SVDMatGetLocalSize(svd,&m,NULL);
     55:   VecGetArrayRead(x,&px);
     56:   VecGetArray(y,&py);
     57:   VecPlaceArray(cyclic->x1,px);
     58:   VecPlaceArray(cyclic->x2,px+m);
     59:   VecPlaceArray(cyclic->y1,py);
     60:   VecPlaceArray(cyclic->y2,py+m);
     61:   SVDMatMult(svd,PETSC_FALSE,cyclic->x2,cyclic->y1);
     62:   SVDMatMult(svd,PETSC_TRUE,cyclic->x1,cyclic->y2);
     63:   VecResetArray(cyclic->x1);
     64:   VecResetArray(cyclic->x2);
     65:   VecResetArray(cyclic->y1);
     66:   VecResetArray(cyclic->y2);
     67:   VecRestoreArrayRead(x,&px);
     68:   VecRestoreArray(y,&py);
     69:   return(0);
     70: }

     74: static PetscErrorCode MatGetDiagonal_Cyclic(Mat B,Vec diag)
     75: {

     79:   VecSet(diag,0.0);
     80:   return(0);
     81: }

     85: PetscErrorCode SVDSetUp_Cyclic(SVD svd)
     86: {
     87:   PetscErrorCode    ierr;
     88:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
     89:   PetscInt          M,N,m,n,i,isl;
     90:   const PetscScalar *isa;
     91:   PetscScalar       *va;
     92:   PetscBool         trackall;
     93:   Vec               v;
     94:   Mat               Zm,Zn;

     97:   SVDMatGetSize(svd,&M,&N);
     98:   SVDMatGetLocalSize(svd,&m,&n);
     99:   if (!cyclic->mat) {
    100:     if (cyclic->explicitmatrix) {
    101:       if (!svd->AT) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Cannot use explicit cyclic matrix with implicit transpose");
    102:       MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
    103:       MatSetSizes(Zm,m,m,M,M);
    104:       MatSetFromOptions(Zm);
    105:       MatSetUp(Zm);
    106:       MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
    107:       MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
    108:       MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
    109:       MatSetSizes(Zn,n,n,N,N);
    110:       MatSetFromOptions(Zn);
    111:       MatSetUp(Zn);
    112:       MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
    113:       MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
    114:       SlepcMatTile(0.0,Zm,1.0,svd->A,1.0,svd->AT,0.0,Zn,&cyclic->mat);
    115:       PetscLogObjectParent(svd,cyclic->mat);
    116:       MatDestroy(&Zm);
    117:       MatDestroy(&Zn);
    118:     } else {
    119:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->x1);
    120:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->x2);
    121:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->y1);
    122:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->y2);
    123:       PetscLogObjectParent(svd,cyclic->x1);
    124:       PetscLogObjectParent(svd,cyclic->x2);
    125:       PetscLogObjectParent(svd,cyclic->y1);
    126:       PetscLogObjectParent(svd,cyclic->y2);
    127:       MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,svd,&cyclic->mat);
    128:       MatShellSetOperation(cyclic->mat,MATOP_MULT,(void(*)(void))MatMult_Cyclic);
    129:       MatShellSetOperation(cyclic->mat,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic);
    130:     }
    131:     PetscLogObjectParent(svd,cyclic->mat);
    132:   }

    134:   if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
    135:   EPSSetOperators(cyclic->eps,cyclic->mat,NULL);
    136:   EPSSetProblemType(cyclic->eps,EPS_HEP);
    137:   if (svd->which == SVD_LARGEST) {
    138:     EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
    139:   } else {
    140:     EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL);
    141:     EPSSetTarget(cyclic->eps,0.0);
    142:   }
    143:   EPSSetDimensions(cyclic->eps,svd->nsv,svd->ncv,svd->mpd);
    144:   EPSSetTolerances(cyclic->eps,svd->tol,svd->max_it);
    145:   /* Transfer the trackall option from svd to eps */
    146:   SVDGetTrackAll(svd,&trackall);
    147:   EPSSetTrackAll(cyclic->eps,trackall);
    148:   /* Transfer the initial subspace from svd to eps */
    149:   if (svd->nini<0 || svd->ninil<0) {
    150:     for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
    151:       MatGetVecs(cyclic->mat,&v,NULL);
    152:       VecGetArray(v,&va);
    153:       if (i<-svd->ninil) {
    154:         VecGetSize(svd->ISL[i],&isl);
    155:         if (isl!=m) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for left initial vector");
    156:         VecGetArrayRead(svd->ISL[i],&isa);
    157:         PetscMemcpy(va,isa,sizeof(PetscScalar)*m);
    158:         VecRestoreArrayRead(svd->IS[i],&isa);
    159:       } else {
    160:         PetscMemzero(&va,sizeof(PetscScalar)*m);
    161:       }
    162:       if (i<-svd->nini) {
    163:         VecGetSize(svd->IS[i],&isl);
    164:         if (isl!=n) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for right initial vector");
    165:         VecGetArrayRead(svd->IS[i],&isa);
    166:         PetscMemcpy(va+m,isa,sizeof(PetscScalar)*n);
    167:         VecRestoreArrayRead(svd->IS[i],&isa);
    168:       } else {
    169:         PetscMemzero(va+m,sizeof(PetscScalar)*n);
    170:       }
    171:       VecRestoreArray(v,&va);
    172:       VecDestroy(&svd->IS[i]);
    173:       svd->IS[i] = v;
    174:     }
    175:     svd->nini = PetscMin(svd->nini,svd->ninil);
    176:     EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS);
    177:     SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
    178:     SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL);
    179:   }
    180:   if (cyclic->setfromoptionscalled) {
    181:     EPSSetFromOptions(cyclic->eps);
    182:     cyclic->setfromoptionscalled = PETSC_FALSE;
    183:   }
    184:   EPSSetUp(cyclic->eps);
    185:   EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd);
    186:   svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
    187:   EPSGetTolerances(cyclic->eps,&svd->tol,&svd->max_it);

    189:   if (svd->ncv != svd->n) {
    190:     VecDestroyVecs(svd->n,&svd->U);
    191:     VecDuplicateVecs(svd->tl,svd->ncv,&svd->U);
    192:     PetscLogObjectParents(svd,svd->ncv,svd->U);
    193:   }
    194:   return(0);
    195: }

    199: PetscErrorCode SVDSolve_Cyclic(SVD svd)
    200: {
    201:   PetscErrorCode    ierr;
    202:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
    203:   PetscInt          i,j,M,N,m,n;
    204:   PetscScalar       sigma;
    205:   const PetscScalar *px;
    206:   Vec               x,x1,x2;

    209:   EPSSolve(cyclic->eps);
    210:   EPSGetConverged(cyclic->eps,&svd->nconv);
    211:   EPSGetIterationNumber(cyclic->eps,&svd->its);
    212:   EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason);

    214:   MatGetVecs(cyclic->mat,&x,NULL);
    215:   SVDMatGetSize(svd,&M,&N);
    216:   SVDMatGetLocalSize(svd,&m,&n);
    217:   VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&x1);
    218:   VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&x2);
    219:   for (i=0,j=0;i<svd->nconv;i++) {
    220:     EPSGetEigenpair(cyclic->eps,i,&sigma,NULL,x,NULL);
    221:     if (PetscRealPart(sigma) > 0.0) {
    222:       svd->sigma[j] = PetscRealPart(sigma);
    223:       VecGetArrayRead(x,&px);
    224:       VecPlaceArray(x1,px);
    225:       VecPlaceArray(x2,px+m);
    226:       VecCopy(x1,svd->U[j]);
    227:       VecScale(svd->U[j],1.0/PetscSqrtReal(2.0));
    228:       VecCopy(x2,svd->V[j]);
    229:       VecScale(svd->V[j],1.0/PetscSqrtReal(2.0));
    230:       VecResetArray(x1);
    231:       VecResetArray(x2);
    232:       VecRestoreArrayRead(x,&px);
    233:       j++;
    234:     }
    235:   }
    236:   svd->nconv = j;

    238:   VecDestroy(&x);
    239:   VecDestroy(&x1);
    240:   VecDestroy(&x2);
    241:   return(0);
    242: }

    246: static PetscErrorCode SVDMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
    247: {
    248:   PetscInt       i,j;
    249:   SVD            svd = (SVD)ctx;
    250:   PetscScalar    er,ei;

    254:   nconv = 0;
    255:   for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
    256:     er = eigr[i]; ei = eigi[i];
    257:     STBackTransform(eps->st,1,&er,&ei);
    258:     if (PetscRealPart(er) > 0.0) {
    259:       svd->sigma[j] = PetscRealPart(er);
    260:       svd->errest[j] = errest[i];
    261:       if (errest[i] < svd->tol) nconv++;
    262:       j++;
    263:     }
    264:   }
    265:   nest = j;
    266:   SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
    267:   return(0);
    268: }

    272: PetscErrorCode SVDSetFromOptions_Cyclic(SVD svd)
    273: {
    275:   PetscBool      set,val;
    276:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
    277:   ST             st;

    280:   cyclic->setfromoptionscalled = PETSC_TRUE;
    281:   PetscOptionsHead("SVD Cyclic Options");
    282:   PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set);
    283:   if (set) {
    284:     SVDCyclicSetExplicitMatrix(svd,val);
    285:   }
    286:   if (!cyclic->explicitmatrix) {
    287:     /* use as default an ST with shell matrix and Jacobi */
    288:     if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
    289:     EPSGetST(cyclic->eps,&st);
    290:     STSetMatMode(st,ST_MATMODE_SHELL);
    291:   }
    292:   PetscOptionsTail();
    293:   return(0);
    294: }

    298: static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmatrix)
    299: {
    300:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

    303:   cyclic->explicitmatrix = explicitmatrix;
    304:   return(0);
    305: }

    309: /*@
    310:    SVDCyclicSetExplicitMatrix - Indicate if the eigensolver operator
    311:    H(A) = [ 0  A ; A^T 0 ] must be computed explicitly.

    313:    Logically Collective on SVD

    315:    Input Parameters:
    316: +  svd      - singular value solver
    317: -  explicit - boolean flag indicating if H(A) is built explicitly

    319:    Options Database Key:
    320: .  -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag

    322:    Level: advanced

    324: .seealso: SVDCyclicGetExplicitMatrix()
    325: @*/
    326: PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmatrix)
    327: {

    333:   PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmatrix));
    334:   return(0);
    335: }

    339: static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmatrix)
    340: {
    341:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

    344:   *explicitmatrix = cyclic->explicitmatrix;
    345:   return(0);
    346: }

    350: /*@
    351:    SVDCyclicGetExplicitMatrix - Returns the flag indicating if H(A) is built explicitly

    353:    Not Collective

    355:    Input Parameter:
    356: .  svd  - singular value solver

    358:    Output Parameter:
    359: .  explicit - the mode flag

    361:    Level: advanced

    363: .seealso: SVDCyclicSetExplicitMatrix()
    364: @*/
    365: PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmatrix)
    366: {

    372:   PetscTryMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmatrix));
    373:   return(0);
    374: }

    378: static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
    379: {
    380:   PetscErrorCode  ierr;
    381:   SVD_CYCLIC      *cyclic = (SVD_CYCLIC*)svd->data;

    384:   PetscObjectReference((PetscObject)eps);
    385:   EPSDestroy(&cyclic->eps);
    386:   cyclic->eps = eps;
    387:   PetscLogObjectParent(svd,cyclic->eps);
    388:   svd->setupcalled = 0;
    389:   return(0);
    390: }

    394: /*@
    395:    SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
    396:    singular value solver.

    398:    Collective on SVD

    400:    Input Parameters:
    401: +  svd - singular value solver
    402: -  eps - the eigensolver object

    404:    Level: advanced

    406: .seealso: SVDCyclicGetEPS()
    407: @*/
    408: PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
    409: {

    416:   PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
    417:   return(0);
    418: }

    422: static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
    423: {
    425:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    428:   if (!cyclic->eps) {
    429:     EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps);
    430:     EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix);
    431:     EPSAppendOptionsPrefix(cyclic->eps,"svd_");
    432:     PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1);
    433:     PetscLogObjectParent(svd,cyclic->eps);
    434:     if (!svd->ip) { SVDGetIP(svd,&svd->ip); }
    435:     EPSSetIP(cyclic->eps,svd->ip);
    436:     EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
    437:     EPSMonitorSet(cyclic->eps,SVDMonitor_Cyclic,svd,NULL);
    438:   }
    439:   *eps = cyclic->eps;
    440:   return(0);
    441: }

    445: /*@
    446:    SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
    447:    to the singular value solver.

    449:    Not Collective

    451:    Input Parameter:
    452: .  svd - singular value solver

    454:    Output Parameter:
    455: .  eps - the eigensolver object

    457:    Level: advanced

    459: .seealso: SVDCyclicSetEPS()
    460: @*/
    461: PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
    462: {

    468:   PetscTryMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
    469:   return(0);
    470: }

    474: PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
    475: {
    477:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    480:   if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
    481:   PetscViewerASCIIPrintf(viewer,"  Cyclic: %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit");
    482:   PetscViewerASCIIPushTab(viewer);
    483:   EPSView(cyclic->eps,viewer);
    484:   PetscViewerASCIIPopTab(viewer);
    485:   return(0);
    486: }

    490: PetscErrorCode SVDReset_Cyclic(SVD svd)
    491: {
    493:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    496:   if (!cyclic->eps) { EPSReset(cyclic->eps); }
    497:   MatDestroy(&cyclic->mat);
    498:   VecDestroy(&cyclic->x1);
    499:   VecDestroy(&cyclic->x2);
    500:   VecDestroy(&cyclic->y1);
    501:   VecDestroy(&cyclic->y2);
    502:   return(0);
    503: }

    507: PetscErrorCode SVDDestroy_Cyclic(SVD svd)
    508: {
    510:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    513:   EPSDestroy(&cyclic->eps);
    514:   PetscFree(svd->data);
    515:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL);
    516:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL);
    517:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL);
    518:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL);
    519:   return(0);
    520: }

    524: PETSC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
    525: {
    527:   SVD_CYCLIC     *cyclic;

    530:   PetscNewLog(svd,SVD_CYCLIC,&cyclic);
    531:   svd->data                      = (void*)cyclic;
    532:   svd->ops->solve                = SVDSolve_Cyclic;
    533:   svd->ops->setup                = SVDSetUp_Cyclic;
    534:   svd->ops->setfromoptions       = SVDSetFromOptions_Cyclic;
    535:   svd->ops->destroy              = SVDDestroy_Cyclic;
    536:   svd->ops->reset                = SVDReset_Cyclic;
    537:   svd->ops->view                 = SVDView_Cyclic;
    538:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic);
    539:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic);
    540:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic);
    541:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic);
    542:   return(0);
    543: }