Date: 2023-01-26T12:19:02+00:00

Actual source code: cyclic.c
slepc-3.18.2 2023-01-26
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    SLEPc singular value solver: "cyclic"

     13:    Method: Uses a Hermitian eigensolver for H(A) = [ 0  A ; A^T 0 ]
     14: */

     16: #include <slepc/private/svdimpl.h>
     17: #include "cyclic.h"

     19: static PetscErrorCode MatMult_Cyclic(Mat B,Vec x,Vec y)
     20: {
     21:   SVD_CYCLIC_SHELL  *ctx;
     22:   const PetscScalar *px;
     23:   PetscScalar       *py;
     24:   PetscInt          m;

     26:   MatShellGetContext(B,&ctx);
     27:   MatGetLocalSize(ctx->A,&m,NULL);
     28:   VecGetArrayRead(x,&px);
     29:   VecGetArrayWrite(y,&py);
     30:   VecPlaceArray(ctx->x1,px);
     31:   VecPlaceArray(ctx->x2,px+m);
     32:   VecPlaceArray(ctx->y1,py);
     33:   VecPlaceArray(ctx->y2,py+m);
     34:   MatMult(ctx->A,ctx->x2,ctx->y1);
     35:   MatMult(ctx->AT,ctx->x1,ctx->y2);
     36:   VecResetArray(ctx->x1);
     37:   VecResetArray(ctx->x2);
     38:   VecResetArray(ctx->y1);
     39:   VecResetArray(ctx->y2);
     40:   VecRestoreArrayRead(x,&px);
     41:   VecRestoreArrayWrite(y,&py);
     42:   return 0;
     43: }

     45: static PetscErrorCode MatGetDiagonal_Cyclic(Mat B,Vec diag)
     46: {
     47:   VecSet(diag,0.0);
     48:   return 0;
     49: }

     51: static PetscErrorCode MatDestroy_Cyclic(Mat B)
     52: {
     53:   SVD_CYCLIC_SHELL *ctx;

     55:   MatShellGetContext(B,&ctx);
     56:   VecDestroy(&ctx->x1);
     57:   VecDestroy(&ctx->x2);
     58:   VecDestroy(&ctx->y1);
     59:   VecDestroy(&ctx->y2);
     60:   PetscFree(ctx);
     61:   return 0;
     62: }

     64: /*
     65:    Builds cyclic matrix   C = | 0   A |
     66:                               | AT  0 |
     67: */
     68: static PetscErrorCode SVDCyclicGetCyclicMat(SVD svd,Mat A,Mat AT,Mat *C)
     69: {
     70:   SVD_CYCLIC       *cyclic = (SVD_CYCLIC*)svd->data;
     71:   SVD_CYCLIC_SHELL *ctx;
     72:   PetscInt         i,M,N,m,n,Istart,Iend;
     73:   VecType          vtype;
     74:   Mat              Zm,Zn;
     75: #if defined(PETSC_HAVE_CUDA)
     76:   PetscBool        cuda;
     77: #endif

     79:   MatGetSize(A,&M,&N);
     80:   MatGetLocalSize(A,&m,&n);

     82:   if (cyclic->explicitmatrix) {
     84:     MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
     85:     MatSetSizes(Zm,m,m,M,M);
     86:     MatSetFromOptions(Zm);
     87:     MatSetUp(Zm);
     88:     MatGetOwnershipRange(Zm,&Istart,&Iend);
     89:     for (i=Istart;i<Iend;i++) MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
     90:     MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
     91:     MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
     92:     MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
     93:     MatSetSizes(Zn,n,n,N,N);
     94:     MatSetFromOptions(Zn);
     95:     MatSetUp(Zn);
     96:     MatGetOwnershipRange(Zn,&Istart,&Iend);
     97:     for (i=Istart;i<Iend;i++) MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
     98:     MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
     99:     MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
    100:     MatCreateTile(1.0,Zm,1.0,A,1.0,AT,1.0,Zn,C);
    101:     MatDestroy(&Zm);
    102:     MatDestroy(&Zn);
    103:   } else {
    104:     PetscNew(&ctx);
    105:     ctx->A       = A;
    106:     ctx->AT      = AT;
    107:     ctx->swapped = svd->swapped;
    108:     MatCreateVecsEmpty(A,&ctx->x2,&ctx->x1);
    109:     MatCreateVecsEmpty(A,&ctx->y2,&ctx->y1);
    110:     MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C);
    111:     MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic);
    112:     MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_Cyclic);
    113: #if defined(PETSC_HAVE_CUDA)
    114:     PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&cuda,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,"");
    115:     if (cuda) MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic_CUDA);
    116:     else
    117: #endif
    118:       MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic);
    119:     MatGetVecType(A,&vtype);
    120:     MatSetVecType(*C,vtype);
    121:   }
    122:   return 0;
    123: }

    125: static PetscErrorCode MatMult_ECross(Mat B,Vec x,Vec y)
    126: {
    127:   SVD_CYCLIC_SHELL  *ctx;
    128:   const PetscScalar *px;
    129:   PetscScalar       *py;
    130:   PetscInt          mn,m,n;

    132:   MatShellGetContext(B,&ctx);
    133:   MatGetLocalSize(ctx->A,NULL,&n);
    134:   VecGetLocalSize(y,&mn);
    135:   m = mn-n;
    136:   VecGetArrayRead(x,&px);
    137:   VecGetArrayWrite(y,&py);
    138:   VecPlaceArray(ctx->x1,px);
    139:   VecPlaceArray(ctx->x2,px+m);
    140:   VecPlaceArray(ctx->y1,py);
    141:   VecPlaceArray(ctx->y2,py+m);
    142:   VecCopy(ctx->x1,ctx->y1);
    143:   MatMult(ctx->A,ctx->x2,ctx->w);
    144:   MatMult(ctx->AT,ctx->w,ctx->y2);
    145:   VecResetArray(ctx->x1);
    146:   VecResetArray(ctx->x2);
    147:   VecResetArray(ctx->y1);
    148:   VecResetArray(ctx->y2);
    149:   VecRestoreArrayRead(x,&px);
    150:   VecRestoreArrayWrite(y,&py);
    151:   return 0;
    152: }

    154: static PetscErrorCode MatGetDiagonal_ECross(Mat B,Vec d)
    155: {
    156:   SVD_CYCLIC_SHELL  *ctx;
    157:   PetscScalar       *pd;
    158:   PetscMPIInt       len;
    159:   PetscInt          mn,m,n,N,i,j,start,end,ncols;
    160:   PetscScalar       *work1,*work2,*diag;
    161:   const PetscInt    *cols;
    162:   const PetscScalar *vals;

    164:   MatShellGetContext(B,&ctx);
    165:   MatGetLocalSize(ctx->A,NULL,&n);
    166:   VecGetLocalSize(d,&mn);
    167:   m = mn-n;
    168:   VecGetArrayWrite(d,&pd);
    169:   VecPlaceArray(ctx->y1,pd);
    170:   VecSet(ctx->y1,1.0);
    171:   VecResetArray(ctx->y1);
    172:   VecPlaceArray(ctx->y2,pd+m);
    173:   if (!ctx->diag) {
    174:     /* compute diagonal from rows and store in ctx->diag */
    175:     VecDuplicate(ctx->y2,&ctx->diag);
    176:     MatGetSize(ctx->A,NULL,&N);
    177:     PetscCalloc2(N,&work1,N,&work2);
    178:     if (ctx->swapped) {
    179:       MatGetOwnershipRange(ctx->AT,&start,&end);
    180:       for (i=start;i<end;i++) {
    181:         MatGetRow(ctx->AT,i,&ncols,NULL,&vals);
    182:         for (j=0;j<ncols;j++) work1[i] += vals[j]*vals[j];
    183:         MatRestoreRow(ctx->AT,i,&ncols,NULL,&vals);
    184:       }
    185:     } else {
    186:       MatGetOwnershipRange(ctx->A,&start,&end);
    187:       for (i=start;i<end;i++) {
    188:         MatGetRow(ctx->A,i,&ncols,&cols,&vals);
    189:         for (j=0;j<ncols;j++) work1[cols[j]] += vals[j]*vals[j];
    190:         MatRestoreRow(ctx->A,i,&ncols,&cols,&vals);
    191:       }
    192:     }
    193:     PetscMPIIntCast(N,&len);
    194:     MPIU_Allreduce(work1,work2,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)B));
    195:     VecGetOwnershipRange(ctx->diag,&start,&end);
    196:     VecGetArrayWrite(ctx->diag,&diag);
    197:     for (i=start;i<end;i++) diag[i-start] = work2[i];
    198:     VecRestoreArrayWrite(ctx->diag,&diag);
    199:     PetscFree2(work1,work2);
    200:   }
    201:   VecCopy(ctx->diag,ctx->y2);
    202:   VecResetArray(ctx->y2);
    203:   VecRestoreArrayWrite(d,&pd);
    204:   return 0;
    205: }

    207: static PetscErrorCode MatDestroy_ECross(Mat B)
    208: {
    209:   SVD_CYCLIC_SHELL *ctx;

    211:   MatShellGetContext(B,&ctx);
    212:   VecDestroy(&ctx->x1);
    213:   VecDestroy(&ctx->x2);
    214:   VecDestroy(&ctx->y1);
    215:   VecDestroy(&ctx->y2);
    216:   VecDestroy(&ctx->diag);
    217:   VecDestroy(&ctx->w);
    218:   PetscFree(ctx);
    219:   return 0;
    220: }

    222: /*
    223:    Builds extended cross product matrix   C = | I_m   0  |
    224:                                               |  0  AT*A |
    225:    t is an auxiliary Vec used to take the dimensions of the upper block
    226: */
    227: static PetscErrorCode SVDCyclicGetECrossMat(SVD svd,Mat A,Mat AT,Mat *C,Vec t)
    228: {
    229:   SVD_CYCLIC       *cyclic = (SVD_CYCLIC*)svd->data;
    230:   SVD_CYCLIC_SHELL *ctx;
    231:   PetscInt         i,M,N,m,n,Istart,Iend;
    232:   VecType          vtype;
    233:   Mat              Id,Zm,Zn,ATA;
    234: #if defined(PETSC_HAVE_CUDA)
    235:   PetscBool        cuda;
    236: #endif

    238:   MatGetSize(A,NULL,&N);
    239:   MatGetLocalSize(A,NULL,&n);
    240:   VecGetSize(t,&M);
    241:   VecGetLocalSize(t,&m);

    243:   if (cyclic->explicitmatrix) {
    245:     MatCreateConstantDiagonal(PetscObjectComm((PetscObject)svd),m,m,M,M,1.0,&Id);
    246:     MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
    247:     MatSetSizes(Zm,m,n,M,N);
    248:     MatSetFromOptions(Zm);
    249:     MatSetUp(Zm);
    250:     MatGetOwnershipRange(Zm,&Istart,&Iend);
    251:     for (i=Istart;i<Iend;i++) {
    252:       if (i<N) MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
    253:     }
    254:     MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
    255:     MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
    256:     MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
    257:     MatSetSizes(Zn,n,m,N,M);
    258:     MatSetFromOptions(Zn);
    259:     MatSetUp(Zn);
    260:     MatGetOwnershipRange(Zn,&Istart,&Iend);
    261:     for (i=Istart;i<Iend;i++) {
    262:       if (i<m) MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
    263:     }
    264:     MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
    265:     MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
    266:     MatProductCreate(AT,A,NULL,&ATA);
    267:     MatProductSetType(ATA,MATPRODUCT_AB);
    268:     MatProductSetFromOptions(ATA);
    269:     MatProductSymbolic(ATA);
    270:     MatProductNumeric(ATA);
    271:     MatCreateTile(1.0,Id,1.0,Zm,1.0,Zn,1.0,ATA,C);
    272:     MatDestroy(&Id);
    273:     MatDestroy(&Zm);
    274:     MatDestroy(&Zn);
    275:     MatDestroy(&ATA);
    276:   } else {
    277:     PetscNew(&ctx);
    278:     ctx->A       = A;
    279:     ctx->AT      = AT;
    280:     ctx->swapped = svd->swapped;
    281:     VecDuplicateEmpty(t,&ctx->x1);
    282:     VecDuplicateEmpty(t,&ctx->y1);
    283:     MatCreateVecsEmpty(A,&ctx->x2,NULL);
    284:     MatCreateVecsEmpty(A,&ctx->y2,NULL);
    285:     MatCreateVecs(A,NULL,&ctx->w);
    286:     MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C);
    287:     MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_ECross);
    288:     MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_ECross);
    289: #if defined(PETSC_HAVE_CUDA)
    290:     PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&cuda,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,"");
    291:     if (cuda) MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross_CUDA);
    292:     else
    293: #endif
    294:       MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross);
    295:     MatGetVecType(A,&vtype);
    296:     MatSetVecType(*C,vtype);
    297:   }
    298:   return 0;
    299: }

    301: /* Convergence test relative to the norm of R (used in GSVD only) */
    302: static PetscErrorCode EPSConv_Cyclic(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    303: {
    304:   SVD svd = (SVD)ctx;

    306:   *errest = res/PetscMax(svd->nrma,svd->nrmb);
    307:   return 0;
    308: }

    310: PetscErrorCode SVDSetUp_Cyclic(SVD svd)
    311: {
    312:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
    313:   PetscInt          M,N,m,n,p,k,i,isl,offset,nev,ncv,mpd,maxit;
    314:   PetscReal         tol;
    315:   const PetscScalar *isa,*oa;
    316:   PetscScalar       *va;
    317:   EPSProblemType    ptype;
    318:   PetscBool         trackall,issinv;
    319:   Vec               v,t;
    320:   ST                st;
    321:   Mat               Omega;
    322:   MatType           Atype;

    324:   MatGetSize(svd->A,&M,&N);
    325:   MatGetLocalSize(svd->A,&m,&n);
    326:   if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
    327:   MatDestroy(&cyclic->C);
    328:   MatDestroy(&cyclic->D);
    329:   if (svd->isgeneralized) {
    330:     if (svd->which==SVD_SMALLEST) {  /* alternative pencil */
    331:       MatCreateVecs(svd->B,NULL,&t);
    332:       SVDCyclicGetCyclicMat(svd,svd->B,svd->BT,&cyclic->C);
    333:       SVDCyclicGetECrossMat(svd,svd->A,svd->AT,&cyclic->D,t);
    334:     } else {
    335:       MatCreateVecs(svd->A,NULL,&t);
    336:       SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
    337:       SVDCyclicGetECrossMat(svd,svd->B,svd->BT,&cyclic->D,t);
    338:     }
    339:     VecDestroy(&t);
    340:     EPSSetOperators(cyclic->eps,cyclic->C,cyclic->D);
    341:     EPSGetProblemType(cyclic->eps,&ptype);
    342:     if (!ptype) EPSSetProblemType(cyclic->eps,EPS_GHEP);
    343:   } else if (svd->ishyperbolic) {
    344:     SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
    345:     MatCreateVecs(cyclic->C,&v,NULL);
    346:     VecSet(v,1.0);
    347:     VecGetArrayRead(svd->omega,&oa);
    348:     VecGetArray(v,&va);
    349:     if (svd->swapped) PetscArraycpy(va+m,oa,n);
    350:     else PetscArraycpy(va,oa,m);
    351:     VecRestoreArrayRead(svd->omega,&oa);
    352:     VecRestoreArray(v,&va);
    353:     MatGetType(svd->OP,&Atype);
    354:     MatCreate(PetscObjectComm((PetscObject)svd),&Omega);
    355:     MatSetSizes(Omega,m+n,m+n,M+N,M+N);
    356:     MatSetType(Omega,Atype);
    357:     MatSetUp(Omega);
    358:     MatDiagonalSet(Omega,v,INSERT_VALUES);
    359:     EPSSetOperators(cyclic->eps,cyclic->C,Omega);
    360:     EPSSetProblemType(cyclic->eps,EPS_GHIEP);
    361:     MatDestroy(&Omega);
    362:     VecDestroy(&v);
    363:   } else {
    364:     SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C);
    365:     EPSSetOperators(cyclic->eps,cyclic->C,NULL);
    366:     EPSSetProblemType(cyclic->eps,EPS_HEP);
    367:   }
    368:   if (!cyclic->usereps) {
    369:     if (svd->which == SVD_LARGEST) {
    370:       EPSGetST(cyclic->eps,&st);
    371:       PetscObjectTypeCompare((PetscObject)st,STSINVERT,&issinv);
    372:       if (issinv) EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE);
    373:       else if (svd->ishyperbolic) EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_MAGNITUDE);
    374:       else EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
    375:     } else {
    376:       if (svd->isgeneralized) {  /* computes sigma^{-1} via alternative pencil */
    377:         EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
    378:       } else {
    379:         if (svd->ishyperbolic) EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE);
    380:         else EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL);
    381:         EPSSetTarget(cyclic->eps,0.0);
    382:       }
    383:     }
    384:     EPSGetDimensions(cyclic->eps,&nev,&ncv,&mpd);
    386:     nev = PetscMax(nev,2*svd->nsv);
    387:     if (ncv==PETSC_DEFAULT && svd->ncv!=PETSC_DEFAULT) ncv = PetscMax(3*svd->nsv,svd->ncv);
    388:     if (mpd==PETSC_DEFAULT && svd->mpd!=PETSC_DEFAULT) mpd = svd->mpd;
    389:     EPSSetDimensions(cyclic->eps,nev,ncv,mpd);
    390:     EPSGetTolerances(cyclic->eps,&tol,&maxit);
    391:     if (tol==PETSC_DEFAULT) tol = svd->tol==PETSC_DEFAULT? SLEPC_DEFAULT_TOL/10.0: svd->tol;
    392:     if (maxit==PETSC_DEFAULT && svd->max_it!=PETSC_DEFAULT) maxit = svd->max_it;
    393:     EPSSetTolerances(cyclic->eps,tol,maxit);
    394:     switch (svd->conv) {
    395:     case SVD_CONV_ABS:
    396:       EPSSetConvergenceTest(cyclic->eps,EPS_CONV_ABS);break;
    397:     case SVD_CONV_REL:
    398:       EPSSetConvergenceTest(cyclic->eps,EPS_CONV_REL);break;
    399:     case SVD_CONV_NORM:
    400:       if (svd->isgeneralized) {
    401:         if (!svd->nrma) MatNorm(svd->OP,NORM_INFINITY,&svd->nrma);
    402:         if (!svd->nrmb) MatNorm(svd->OPb,NORM_INFINITY,&svd->nrmb);
    403:         EPSSetConvergenceTestFunction(cyclic->eps,EPSConv_Cyclic,svd,NULL);
    404:       } else {
    405:         EPSSetConvergenceTest(cyclic->eps,EPS_CONV_NORM);break;
    406:       }
    407:       break;
    408:     case SVD_CONV_MAXIT:
    409:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Maxit convergence test not supported in this solver");
    410:     case SVD_CONV_USER:
    411:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined convergence test not supported in this solver");
    412:     }
    413:   }
    414:   SVDCheckUnsupported(svd,SVD_FEATURE_STOPPING);
    415:   /* Transfer the trackall option from svd to eps */
    416:   SVDGetTrackAll(svd,&trackall);
    417:   EPSSetTrackAll(cyclic->eps,trackall);
    418:   /* Transfer the initial subspace from svd to eps */
    419:   if (svd->nini<0 || svd->ninil<0) {
    420:     for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
    421:       MatCreateVecs(cyclic->C,&v,NULL);
    422:       VecGetArrayWrite(v,&va);
    423:       if (svd->isgeneralized) MatGetLocalSize(svd->B,&p,NULL);
    424:       k = (svd->isgeneralized && svd->which==SVD_SMALLEST)? p: m;  /* size of upper block row */
    425:       if (i<-svd->ninil) {
    426:         VecGetArrayRead(svd->ISL[i],&isa);
    427:         if (svd->isgeneralized) {
    428:           VecGetLocalSize(svd->ISL[i],&isl);
    430:           offset = (svd->which==SVD_SMALLEST)? m: 0;
    431:           PetscArraycpy(va,isa+offset,k);
    432:         } else {
    433:           VecGetLocalSize(svd->ISL[i],&isl);
    435:           PetscArraycpy(va,isa,k);
    436:         }
    437:         VecRestoreArrayRead(svd->IS[i],&isa);
    438:       } else PetscArrayzero(&va,k);
    439:       if (i<-svd->nini) {
    440:         VecGetLocalSize(svd->IS[i],&isl);
    442:         VecGetArrayRead(svd->IS[i],&isa);
    443:         PetscArraycpy(va+k,isa,n);
    444:         VecRestoreArrayRead(svd->IS[i],&isa);
    445:       } else PetscArrayzero(va+k,n);
    446:       VecRestoreArrayWrite(v,&va);
    447:       VecDestroy(&svd->IS[i]);
    448:       svd->IS[i] = v;
    449:     }
    450:     svd->nini = PetscMin(svd->nini,svd->ninil);
    451:     EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS);
    452:     SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
    453:     SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL);
    454:   }
    455:   EPSSetUp(cyclic->eps);
    456:   EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd);
    457:   svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
    458:   EPSGetTolerances(cyclic->eps,NULL,&svd->max_it);
    459:   if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;

    461:   svd->leftbasis = PETSC_TRUE;
    462:   SVDAllocateSolution(svd,0);
    463:   return 0;
    464: }

    466: PetscErrorCode SVDCyclicCheckEigenvalue(SVD svd,PetscScalar er,PetscScalar ei,PetscReal *sigma,PetscBool *isreal)
    467: {
    468:   if (svd->ishyperbolic && PetscDefined(USE_COMPLEX) && PetscAbsReal(PetscImaginaryPart(er))>10*PetscAbsReal(PetscRealPart(er))) {
    469:     *sigma = PetscImaginaryPart(er);
    470:     if (isreal) *isreal = PETSC_FALSE;
    471:   } else if (svd->ishyperbolic && !PetscDefined(USE_COMPLEX) && PetscAbsScalar(ei)>10*PetscAbsScalar(er)) {
    472:     *sigma = PetscRealPart(ei);
    473:     if (isreal) *isreal = PETSC_FALSE;
    474:   } else {
    475:     *sigma = PetscRealPart(er);
    476:     if (isreal) *isreal = PETSC_TRUE;
    477:   }
    478:   return 0;
    479: }

    481: PetscErrorCode SVDSolve_Cyclic(SVD svd)
    482: {
    483:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
    484:   PetscInt       i,j,nconv;
    485:   PetscScalar    er,ei;
    486:   PetscReal      sigma;

    488:   EPSSolve(cyclic->eps);
    489:   EPSGetConverged(cyclic->eps,&nconv);
    490:   EPSGetIterationNumber(cyclic->eps,&svd->its);
    491:   EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason);
    492:   for (i=0,j=0;i<nconv;i++) {
    493:     EPSGetEigenvalue(cyclic->eps,i,&er,&ei);
    494:     SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
    495:     if (sigma>0.0) {
    496:       if (svd->isgeneralized && svd->which==SVD_SMALLEST) svd->sigma[j] = 1.0/sigma;
    497:       else svd->sigma[j] = sigma;
    498:       j++;
    499:     }
    500:   }
    501:   svd->nconv = j;
    502:   return 0;
    503: }

    505: static PetscErrorCode SVDComputeVectors_Cyclic_Standard(SVD svd)
    506: {
    507:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
    508:   PetscInt          i,j,m,nconv;
    509:   PetscScalar       er,ei;
    510:   PetscReal         sigma;
    511:   const PetscScalar *px;
    512:   Vec               x,x1,x2;

    514:   MatCreateVecs(cyclic->C,&x,NULL);
    515:   MatGetLocalSize(svd->A,&m,NULL);
    516:   MatCreateVecsEmpty(svd->A,&x2,&x1);
    517:   EPSGetConverged(cyclic->eps,&nconv);
    518:   for (i=0,j=0;i<nconv;i++) {
    519:     EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL);
    520:     SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
    521:     if (sigma<0.0) continue;
    522:     VecGetArrayRead(x,&px);
    523:     VecPlaceArray(x1,px);
    524:     VecPlaceArray(x2,px+m);
    525:     BVInsertVec(svd->U,j,x1);
    526:     BVScaleColumn(svd->U,j,PETSC_SQRT2);
    527:     BVInsertVec(svd->V,j,x2);
    528:     BVScaleColumn(svd->V,j,PETSC_SQRT2);
    529:     VecResetArray(x1);
    530:     VecResetArray(x2);
    531:     VecRestoreArrayRead(x,&px);
    532:     j++;
    533:   }
    534:   VecDestroy(&x);
    535:   VecDestroy(&x1);
    536:   VecDestroy(&x2);
    537:   return 0;
    538: }

    540: static PetscErrorCode SVDComputeVectors_Cyclic_Generalized(SVD svd)
    541: {
    542:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
    543:   PetscInt          i,j,m,p,nconv;
    544:   PetscScalar       *dst,er,ei;
    545:   PetscReal         sigma;
    546:   const PetscScalar *src,*px;
    547:   Vec               u,v,x,x1,x2,uv;

    549:   MatGetLocalSize(svd->A,&m,NULL);
    550:   MatGetLocalSize(svd->B,&p,NULL);
    551:   MatCreateVecs(cyclic->C,&x,NULL);
    552:   if (svd->which==SVD_SMALLEST) MatCreateVecsEmpty(svd->B,&x1,&x2);
    553:   else MatCreateVecsEmpty(svd->A,&x2,&x1);
    554:   MatCreateVecs(svd->A,NULL,&u);
    555:   MatCreateVecs(svd->B,NULL,&v);
    556:   EPSGetConverged(cyclic->eps,&nconv);
    557:   for (i=0,j=0;i<nconv;i++) {
    558:     EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL);
    559:     SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
    560:     if (sigma<0.0) continue;
    561:     if (svd->which==SVD_SMALLEST) {
    562:       /* evec_i = 1/sqrt(2)*[ v_i; w_i ],  w_i = x_i/c_i */
    563:       VecGetArrayRead(x,&px);
    564:       VecPlaceArray(x2,px);
    565:       VecPlaceArray(x1,px+p);
    566:       VecCopy(x2,v);
    567:       VecScale(v,PETSC_SQRT2);  /* v_i = sqrt(2)*evec_i_1 */
    568:       VecScale(x1,PETSC_SQRT2); /* w_i = sqrt(2)*evec_i_2 */
    569:       MatMult(svd->A,x1,u);     /* A*w_i = u_i */
    570:       VecScale(x1,1.0/PetscSqrtScalar(1.0+sigma*sigma));  /* x_i = w_i*c_i */
    571:       BVInsertVec(svd->V,j,x1);
    572:       VecResetArray(x2);
    573:       VecResetArray(x1);
    574:       VecRestoreArrayRead(x,&px);
    575:     } else {
    576:       /* evec_i = 1/sqrt(2)*[ u_i; w_i ],  w_i = x_i/s_i */
    577:       VecGetArrayRead(x,&px);
    578:       VecPlaceArray(x1,px);
    579:       VecPlaceArray(x2,px+m);
    580:       VecCopy(x1,u);
    581:       VecScale(u,PETSC_SQRT2);  /* u_i = sqrt(2)*evec_i_1 */
    582:       VecScale(x2,PETSC_SQRT2); /* w_i = sqrt(2)*evec_i_2 */
    583:       MatMult(svd->B,x2,v);     /* B*w_i = v_i */
    584:       VecScale(x2,1.0/PetscSqrtScalar(1.0+sigma*sigma));  /* x_i = w_i*s_i */
    585:       BVInsertVec(svd->V,j,x2);
    586:       VecResetArray(x1);
    587:       VecResetArray(x2);
    588:       VecRestoreArrayRead(x,&px);
    589:     }
    590:     /* copy [u;v] to U[j] */
    591:     BVGetColumn(svd->U,j,&uv);
    592:     VecGetArrayWrite(uv,&dst);
    593:     VecGetArrayRead(u,&src);
    594:     PetscArraycpy(dst,src,m);
    595:     VecRestoreArrayRead(u,&src);
    596:     VecGetArrayRead(v,&src);
    597:     PetscArraycpy(dst+m,src,p);
    598:     VecRestoreArrayRead(v,&src);
    599:     VecRestoreArrayWrite(uv,&dst);
    600:     BVRestoreColumn(svd->U,j,&uv);
    601:     j++;
    602:   }
    603:   VecDestroy(&x);
    604:   VecDestroy(&x1);
    605:   VecDestroy(&x2);
    606:   VecDestroy(&u);
    607:   VecDestroy(&v);
    608:   return 0;
    609: }

    611: #if defined(PETSC_USE_COMPLEX)
    612: /* VecMaxAbs: returns the entry of x that has max(abs(x(i))), using w as a workspace vector */
    613: static PetscErrorCode VecMaxAbs(Vec x,Vec w,PetscScalar *v)
    614: {
    615:   PetscMPIInt       size,rank,root;
    616:   const PetscScalar *xx;
    617:   const PetscInt    *ranges;
    618:   PetscReal         val;
    619:   PetscInt          p;

    621:   VecCopy(x,w);
    622:   VecAbs(w);
    623:   VecMax(w,&p,&val);
    624:   MPI_Comm_size(PetscObjectComm((PetscObject)x),&size);
    625:   MPI_Comm_rank(PetscObjectComm((PetscObject)x),&rank);
    626:   VecGetOwnershipRanges(x,&ranges);
    627:   for (root=0;root<size;root++) if (p>=ranges[root] && p<ranges[root+1]) break;
    628:   if (rank==root) {
    629:     VecGetArrayRead(x,&xx);
    630:     *v = xx[p-ranges[root]];
    631:     VecRestoreArrayRead(x,&xx);
    632:   }
    633:   MPI_Bcast(v,1,MPIU_SCALAR,root,PetscObjectComm((PetscObject)x));
    634:   return 0;
    635: }
    636: #endif

    638: static PetscErrorCode SVDComputeVectors_Cyclic_Hyperbolic(SVD svd)
    639: {
    640:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
    641:   PetscInt          i,j,m,n,N,nconv;
    642:   PetscScalar       er,ei;
    643:   PetscReal         sigma,nrm;
    644:   PetscBool         isreal;
    645:   const PetscScalar *px;
    646:   Vec               u,x,xi=NULL,x1,x2,x1i=NULL,x2i;
    647:   Mat               Omega;
    648:   MatType           Atype;
    649:   BV                U=NULL,V=NULL;
    650: #if !defined(PETSC_USE_COMPLEX)
    651:   const PetscScalar *pxi;
    652:   PetscReal         nrmr,nrmi;
    653: #else
    654:   PetscScalar       alpha;
    655: #endif

    657:   MatCreateVecs(cyclic->C,&x,svd->ishyperbolic?&xi:NULL);
    658:   MatGetLocalSize(svd->A,&m,NULL);
    659:   MatCreateVecsEmpty(svd->OP,&x2,&x1);
    660: #if defined(PETSC_USE_COMPLEX)
    661:   MatCreateVecs(svd->OP,&x2i,&x1i);
    662: #else
    663:   MatCreateVecsEmpty(svd->OP,&x2i,&x1i);
    664: #endif
    665:   /* set-up Omega-normalization of U */
    666:   U = svd->swapped? svd->V: svd->U;
    667:   V = svd->swapped? svd->U: svd->V;
    668:   MatGetType(svd->A,&Atype);
    669:   BVGetSizes(U,&n,&N,NULL);
    670:   MatCreate(PetscObjectComm((PetscObject)svd),&Omega);
    671:   MatSetSizes(Omega,n,n,N,N);
    672:   MatSetType(Omega,Atype);
    673:   MatSetUp(Omega);
    674:   MatDiagonalSet(Omega,svd->omega,INSERT_VALUES);
    675:   BVSetMatrix(U,Omega,PETSC_TRUE);
    676:   MatDestroy(&Omega);

    678:   EPSGetConverged(cyclic->eps,&nconv);
    679:   for (i=0,j=0;i<nconv;i++) {
    680:     EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,xi);
    681:     SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,&isreal);
    682:     if (sigma<0.0) continue;
    683:     VecGetArrayRead(x,&px);
    684:     if (svd->swapped) {
    685:       VecPlaceArray(x2,px);
    686:       VecPlaceArray(x1,px+m);
    687:     } else {
    688:       VecPlaceArray(x1,px);
    689:       VecPlaceArray(x2,px+n);
    690:     }
    691: #if defined(PETSC_USE_COMPLEX)
    692:     BVInsertVec(U,j,x1);
    693:     BVInsertVec(V,j,x2);
    694:     if (!isreal) {
    695:       VecMaxAbs(x1,x1i,&alpha);
    696:       BVScaleColumn(U,j,PetscAbsScalar(alpha)/alpha);
    697:       BVScaleColumn(V,j,PetscAbsScalar(alpha)/(alpha*PETSC_i));
    698:     }
    699: #else
    700:     VecGetArrayRead(xi,&pxi);
    701:     if (svd->swapped) {
    702:       VecPlaceArray(x2i,pxi);
    703:       VecPlaceArray(x1i,pxi+m);
    704:     } else {
    705:       VecPlaceArray(x1i,pxi);
    706:       VecPlaceArray(x2i,pxi+n);
    707:     }
    708:     VecNorm(x2,NORM_2,&nrmr);
    709:     VecNorm(x2i,NORM_2,&nrmi);
    710:     if (nrmi>nrmr) {
    711:       if (isreal) {
    712:         BVInsertVec(U,j,x1i);
    713:         BVInsertVec(V,j,x2i);
    714:       } else {
    715:         BVInsertVec(U,j,x1);
    716:         BVInsertVec(V,j,x2i);
    717:       }
    718:     } else {
    719:       if (isreal) {
    720:         BVInsertVec(U,j,x1);
    721:         BVInsertVec(V,j,x2);
    722:       } else {
    723:         BVInsertVec(U,j,x1i);
    724:         BVScaleColumn(U,j,-1.0);
    725:         BVInsertVec(V,j,x2);
    726:       }
    727:     }
    728:     VecResetArray(x1i);
    729:     VecResetArray(x2i);
    730:     VecRestoreArrayRead(xi,&pxi);
    731: #endif
    732:     VecResetArray(x1);
    733:     VecResetArray(x2);
    734:     VecRestoreArrayRead(x,&px);
    735:     BVGetColumn(U,j,&u);
    736:     VecPointwiseMult(u,u,svd->omega);
    737:     BVRestoreColumn(U,j,&u);
    738:     BVNormColumn(U,j,NORM_2,&nrm);
    739:     BVScaleColumn(U,j,1.0/PetscAbs(nrm));
    740:     svd->sign[j] = PetscSign(nrm);
    741:     BVNormColumn(V,j,NORM_2,&nrm);
    742:     BVScaleColumn(V,j,1.0/nrm);
    743:     j++;
    744:   }
    745:   VecDestroy(&x);
    746:   VecDestroy(&x1);
    747:   VecDestroy(&x2);
    748:   VecDestroy(&xi);
    749:   VecDestroy(&x1i);
    750:   VecDestroy(&x2i);
    751:   return 0;
    752: }

    754: PetscErrorCode SVDComputeVectors_Cyclic(SVD svd)
    755: {
    756:   switch (svd->problem_type) {
    757:     case SVD_STANDARD:
    758:       SVDComputeVectors_Cyclic_Standard(svd);
    759:       break;
    760:     case SVD_GENERALIZED:
    761:       SVDComputeVectors_Cyclic_Generalized(svd);
    762:       break;
    763:     case SVD_HYPERBOLIC:
    764:       SVDComputeVectors_Cyclic_Hyperbolic(svd);
    765:       break;
    766:     default:
    767:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONG,"Unknown singular value problem type");
    768:   }
    769:   return 0;
    770: }

    772: static PetscErrorCode EPSMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
    773: {
    774:   PetscInt       i,j;
    775:   SVD            svd = (SVD)ctx;
    776:   PetscScalar    er,ei;
    777:   PetscReal      sigma;
    778:   ST             st;

    780:   nconv = 0;
    781:   EPSGetST(eps,&st);
    782:   for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
    783:     er = eigr[i]; ei = eigi[i];
    784:     STBackTransform(st,1,&er,&ei);
    785:     SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL);
    786:     if (sigma>0.0) {
    787:       svd->sigma[j]  = sigma;
    788:       svd->errest[j] = errest[i];
    789:       if (errest[i] && errest[i] < svd->tol) nconv++;
    790:       j++;
    791:     }
    792:   }
    793:   nest = j;
    794:   SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
    795:   return 0;
    796: }

    798: PetscErrorCode SVDSetFromOptions_Cyclic(SVD svd,PetscOptionItems *PetscOptionsObject)
    799: {
    800:   PetscBool      set,val;
    801:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
    802:   ST             st;

    804:   PetscOptionsHeadBegin(PetscOptionsObject,"SVD Cyclic Options");

    806:     PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set);
    807:     if (set) SVDCyclicSetExplicitMatrix(svd,val);

    809:   PetscOptionsHeadEnd();

    811:   if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
    812:   if (!cyclic->explicitmatrix && !cyclic->usereps) {
    813:     /* use as default an ST with shell matrix and Jacobi */
    814:     EPSGetST(cyclic->eps,&st);
    815:     STSetMatMode(st,ST_MATMODE_SHELL);
    816:   }
    817:   EPSSetFromOptions(cyclic->eps);
    818:   return 0;
    819: }

    821: static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmat)
    822: {
    823:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

    825:   if (cyclic->explicitmatrix != explicitmat) {
    826:     cyclic->explicitmatrix = explicitmat;
    827:     svd->state = SVD_STATE_INITIAL;
    828:   }
    829:   return 0;
    830: }

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

    836:    Logically Collective on svd

    838:    Input Parameters:
    839: +  svd         - singular value solver
    840: -  explicitmat - boolean flag indicating if H(A) is built explicitly

    842:    Options Database Key:
    843: .  -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag

    845:    Level: advanced

    847: .seealso: SVDCyclicGetExplicitMatrix()
    848: @*/
    849: PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmat)
    850: {
    853:   PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmat));
    854:   return 0;
    855: }

    857: static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmat)
    858: {
    859:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

    861:   *explicitmat = cyclic->explicitmatrix;
    862:   return 0;
    863: }

    865: /*@
    866:    SVDCyclicGetExplicitMatrix - Returns the flag indicating if H(A) is built explicitly.

    868:    Not Collective

    870:    Input Parameter:
    871: .  svd  - singular value solver

    873:    Output Parameter:
    874: .  explicitmat - the mode flag

    876:    Level: advanced

    878: .seealso: SVDCyclicSetExplicitMatrix()
    879: @*/
    880: PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmat)
    881: {
    884:   PetscUseMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmat));
    885:   return 0;
    886: }

    888: static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
    889: {
    890:   SVD_CYCLIC      *cyclic = (SVD_CYCLIC*)svd->data;

    892:   PetscObjectReference((PetscObject)eps);
    893:   EPSDestroy(&cyclic->eps);
    894:   cyclic->eps     = eps;
    895:   cyclic->usereps = PETSC_TRUE;
    896:   svd->state      = SVD_STATE_INITIAL;
    897:   return 0;
    898: }

    900: /*@
    901:    SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
    902:    singular value solver.

    904:    Collective on svd

    906:    Input Parameters:
    907: +  svd - singular value solver
    908: -  eps - the eigensolver object

    910:    Level: advanced

    912: .seealso: SVDCyclicGetEPS()
    913: @*/
    914: PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
    915: {
    919:   PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
    920:   return 0;
    921: }

    923: static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
    924: {
    925:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    927:   if (!cyclic->eps) {
    928:     EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps);
    929:     PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1);
    930:     EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix);
    931:     EPSAppendOptionsPrefix(cyclic->eps,"svd_cyclic_");
    932:     PetscObjectSetOptions((PetscObject)cyclic->eps,((PetscObject)svd)->options);
    933:     EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
    934:     EPSMonitorSet(cyclic->eps,EPSMonitor_Cyclic,svd,NULL);
    935:   }
    936:   *eps = cyclic->eps;
    937:   return 0;
    938: }

    940: /*@
    941:    SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
    942:    to the singular value solver.

    944:    Not Collective

    946:    Input Parameter:
    947: .  svd - singular value solver

    949:    Output Parameter:
    950: .  eps - the eigensolver object

    952:    Level: advanced

    954: .seealso: SVDCyclicSetEPS()
    955: @*/
    956: PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
    957: {
    960:   PetscUseMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
    961:   return 0;
    962: }

    964: PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
    965: {
    966:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
    967:   PetscBool      isascii;

    969:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    970:   if (isascii) {
    971:     if (!cyclic->eps) SVDCyclicGetEPS(svd,&cyclic->eps);
    972:     PetscViewerASCIIPrintf(viewer,"  %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit");
    973:     PetscViewerASCIIPushTab(viewer);
    974:     EPSView(cyclic->eps,viewer);
    975:     PetscViewerASCIIPopTab(viewer);
    976:   }
    977:   return 0;
    978: }

    980: PetscErrorCode SVDReset_Cyclic(SVD svd)
    981: {
    982:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    984:   EPSReset(cyclic->eps);
    985:   MatDestroy(&cyclic->C);
    986:   MatDestroy(&cyclic->D);
    987:   return 0;
    988: }

    990: PetscErrorCode SVDDestroy_Cyclic(SVD svd)
    991: {
    992:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

    994:   EPSDestroy(&cyclic->eps);
    995:   PetscFree(svd->data);
    996:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL);
    997:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL);
    998:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL);
    999:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL);
    1000:   return 0;
    1001: }

    1003: SLEPC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
    1004: {
    1005:   SVD_CYCLIC     *cyclic;

    1007:   PetscNew(&cyclic);
    1008:   svd->data                = (void*)cyclic;
    1009:   svd->ops->solve          = SVDSolve_Cyclic;
    1010:   svd->ops->solveg         = SVDSolve_Cyclic;
    1011:   svd->ops->solveh         = SVDSolve_Cyclic;
    1012:   svd->ops->setup          = SVDSetUp_Cyclic;
    1013:   svd->ops->setfromoptions = SVDSetFromOptions_Cyclic;
    1014:   svd->ops->destroy        = SVDDestroy_Cyclic;
    1015:   svd->ops->reset          = SVDReset_Cyclic;
    1016:   svd->ops->view           = SVDView_Cyclic;
    1017:   svd->ops->computevectors = SVDComputeVectors_Cyclic;
    1018:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic);
    1019:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic);
    1020:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic);
    1021:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic);
    1022:   return 0;
    1023: }