Actual source code: cyclic.c

slepc-3.18.3 2023-03-24
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: }