Actual source code: cyclic.c

slepc-3.7.0 2016-05-16
Report Typos and Errors
  1: /*

  3:    SLEPc singular value solver: "cyclic"

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

  7:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  9:    Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain

 11:    This file is part of SLEPc.

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

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

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

 27: #include <slepc/private/svdimpl.h>                /*I "slepcsvd.h" I*/
 28: #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/

 30: typedef struct {
 31:   PetscBool explicitmatrix;
 32:   EPS       eps;
 33:   Mat       mat;
 34:   Vec       x1,x2,y1,y2;
 35: } SVD_CYCLIC;

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

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

 71: static PetscErrorCode MatGetDiagonal_Cyclic(Mat B,Vec diag)
 72: {

 76:   VecSet(diag,0.0);
 77:   return(0);
 78: }

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

 94:   PetscObjectTypeCompareAny((PetscObject)svd->A,&gpu,MATSEQAIJCUSP,MATMPIAIJCUSP,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,"");
 95:   if (gpu) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Solver not implemented for GPU matrices");
 96:   SVDMatGetSize(svd,&M,&N);
 97:   SVDMatGetLocalSize(svd,&m,&n);
 98:   if (!cyclic->mat) {
 99:     if (cyclic->explicitmatrix) {
100:       if (!svd->AT) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Cannot use explicit cyclic matrix with implicit transpose");
101:       MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
102:       MatSetSizes(Zm,m,m,M,M);
103:       MatSetFromOptions(Zm);
104:       MatSetUp(Zm);
105:       MatGetOwnershipRange(Zm,&Istart,&Iend);
106:       for (i=Istart;i<Iend;i++) {
107:         MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
108:       }
109:       MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
110:       MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
111:       MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
112:       MatSetSizes(Zn,n,n,N,N);
113:       MatSetFromOptions(Zn);
114:       MatSetUp(Zn);
115:       MatGetOwnershipRange(Zn,&Istart,&Iend);
116:       for (i=Istart;i<Iend;i++) {
117:         MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
118:       }
119:       MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
120:       MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
121:       SlepcMatTile(1.0,Zm,1.0,svd->A,1.0,svd->AT,1.0,Zn,&cyclic->mat);
122:       PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->mat);
123:       MatDestroy(&Zm);
124:       MatDestroy(&Zn);
125:     } else {
126:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->x1);
127:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->x2);
128:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->y1);
129:       VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->y2);
130:       PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->x1);
131:       PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->x2);
132:       PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->y1);
133:       PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->y2);
134:       MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,svd,&cyclic->mat);
135:       MatShellSetOperation(cyclic->mat,MATOP_MULT,(void(*)(void))MatMult_Cyclic);
136:       MatShellSetOperation(cyclic->mat,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic);
137:     }
138:     PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->mat);
139:   }

141:   if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
142:   EPSSetOperators(cyclic->eps,cyclic->mat,NULL);
143:   EPSSetProblemType(cyclic->eps,EPS_HEP);
144:   if (svd->which == SVD_LARGEST) {
145:     EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
146:   } else {
147:     EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL);
148:     EPSSetTarget(cyclic->eps,0.0);
149:   }
150:   EPSSetDimensions(cyclic->eps,svd->nsv,svd->ncv?svd->ncv:PETSC_DEFAULT,svd->mpd?svd->mpd:PETSC_DEFAULT);
151:   EPSSetTolerances(cyclic->eps,svd->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL/10.0:svd->tol,svd->max_it?svd->max_it:PETSC_DEFAULT);
152:   switch (svd->conv) {
153:   case SVD_CONV_ABS:
154:     EPSSetConvergenceTest(cyclic->eps,EPS_CONV_ABS);break;
155:   case SVD_CONV_REL:
156:     EPSSetConvergenceTest(cyclic->eps,EPS_CONV_REL);break;
157:   case SVD_CONV_USER:
158:     SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined convergence test not supported in this solver");
159:   }
160:   if (svd->stop!=SVD_STOP_BASIC) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined stopping test not supported in this solver");
161:   /* Transfer the trackall option from svd to eps */
162:   SVDGetTrackAll(svd,&trackall);
163:   EPSSetTrackAll(cyclic->eps,trackall);
164:   /* Transfer the initial subspace from svd to eps */
165:   if (svd->nini<0 || svd->ninil<0) {
166:     for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
167:       MatCreateVecs(cyclic->mat,&v,NULL);
168:       VecGetArray(v,&va);
169:       if (i<-svd->ninil) {
170:         VecGetSize(svd->ISL[i],&isl);
171:         if (isl!=m) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for left initial vector");
172:         VecGetArrayRead(svd->ISL[i],&isa);
173:         PetscMemcpy(va,isa,sizeof(PetscScalar)*m);
174:         VecRestoreArrayRead(svd->IS[i],&isa);
175:       } else {
176:         PetscMemzero(&va,sizeof(PetscScalar)*m);
177:       }
178:       if (i<-svd->nini) {
179:         VecGetSize(svd->IS[i],&isl);
180:         if (isl!=n) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for right initial vector");
181:         VecGetArrayRead(svd->IS[i],&isa);
182:         PetscMemcpy(va+m,isa,sizeof(PetscScalar)*n);
183:         VecRestoreArrayRead(svd->IS[i],&isa);
184:       } else {
185:         PetscMemzero(va+m,sizeof(PetscScalar)*n);
186:       }
187:       VecRestoreArray(v,&va);
188:       VecDestroy(&svd->IS[i]);
189:       svd->IS[i] = v;
190:     }
191:     svd->nini = PetscMin(svd->nini,svd->ninil);
192:     EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS);
193:     SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
194:     SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL);
195:   }
196:   EPSSetUp(cyclic->eps);
197:   EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd);
198:   svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
199:   EPSGetTolerances(cyclic->eps,NULL,&svd->max_it);
200:   if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;

202:   svd->leftbasis = PETSC_TRUE;
203:   SVDAllocateSolution(svd,0);
204:   return(0);
205: }

209: PetscErrorCode SVDSolve_Cyclic(SVD svd)
210: {
211:   PetscErrorCode    ierr;
212:   SVD_CYCLIC        *cyclic = (SVD_CYCLIC*)svd->data;
213:   PetscInt          i,j,M,N,m,n;
214:   PetscScalar       sigma;
215:   const PetscScalar *px;
216:   Vec               x,x1,x2;

219:   EPSSolve(cyclic->eps);
220:   EPSGetConverged(cyclic->eps,&svd->nconv);
221:   EPSGetIterationNumber(cyclic->eps,&svd->its);
222:   EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason);

224:   MatCreateVecs(cyclic->mat,&x,NULL);
225:   SVDMatGetSize(svd,&M,&N);
226:   SVDMatGetLocalSize(svd,&m,&n);
227:   VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&x1);
228:   VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&x2);
229:   for (i=0,j=0;i<svd->nconv;i++) {
230:     EPSGetEigenpair(cyclic->eps,i,&sigma,NULL,x,NULL);
231:     if (PetscRealPart(sigma) > 0.0) {
232:       svd->sigma[j] = PetscRealPart(sigma);
233:       VecGetArrayRead(x,&px);
234:       VecPlaceArray(x1,px);
235:       VecPlaceArray(x2,px+m);
236:       BVInsertVec(svd->U,j,x1);
237:       BVScaleColumn(svd->U,j,1.0/PetscSqrtReal(2.0));
238:       BVInsertVec(svd->V,j,x2);
239:       BVScaleColumn(svd->V,j,1.0/PetscSqrtReal(2.0));
240:       VecResetArray(x1);
241:       VecResetArray(x2);
242:       VecRestoreArrayRead(x,&px);
243:       j++;
244:     }
245:   }
246:   svd->nconv = j;

248:   VecDestroy(&x);
249:   VecDestroy(&x1);
250:   VecDestroy(&x2);
251:   return(0);
252: }

256: static PetscErrorCode EPSMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
257: {
258:   PetscInt       i,j;
259:   SVD            svd = (SVD)ctx;
260:   PetscScalar    er,ei;

264:   nconv = 0;
265:   for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
266:     er = eigr[i]; ei = eigi[i];
267:     STBackTransform(eps->st,1,&er,&ei);
268:     if (PetscRealPart(er) > 0.0) {
269:       svd->sigma[j] = PetscRealPart(er);
270:       svd->errest[j] = errest[i];
271:       if (errest[i] && errest[i] < svd->tol) nconv++;
272:       j++;
273:     }
274:   }
275:   nest = j;
276:   SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
277:   return(0);
278: }

282: PetscErrorCode SVDSetFromOptions_Cyclic(PetscOptionItems *PetscOptionsObject,SVD svd)
283: {
285:   PetscBool      set,val;
286:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
287:   ST             st;

290:   PetscOptionsHead(PetscOptionsObject,"SVD Cyclic Options");
291:   PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set);
292:   if (set) {
293:     SVDCyclicSetExplicitMatrix(svd,val);
294:   }
295:   if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
296:   EPSSetFromOptions(cyclic->eps);
297:   if (!cyclic->explicitmatrix) {
298:     /* use as default an ST with shell matrix and Jacobi */
299:     EPSGetST(cyclic->eps,&st);
300:     STSetMatMode(st,ST_MATMODE_SHELL);
301:   }
302:   PetscOptionsTail();
303:   return(0);
304: }

308: static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmatrix)
309: {
310:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

313:   cyclic->explicitmatrix = explicitmatrix;
314:   return(0);
315: }

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

323:    Logically Collective on SVD

325:    Input Parameters:
326: +  svd      - singular value solver
327: -  explicit - boolean flag indicating if H(A) is built explicitly

329:    Options Database Key:
330: .  -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag

332:    Level: advanced

334: .seealso: SVDCyclicGetExplicitMatrix()
335: @*/
336: PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmatrix)
337: {

343:   PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmatrix));
344:   return(0);
345: }

349: static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmatrix)
350: {
351:   SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;

354:   *explicitmatrix = cyclic->explicitmatrix;
355:   return(0);
356: }

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

363:    Not Collective

365:    Input Parameter:
366: .  svd  - singular value solver

368:    Output Parameter:
369: .  explicit - the mode flag

371:    Level: advanced

373: .seealso: SVDCyclicSetExplicitMatrix()
374: @*/
375: PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmatrix)
376: {

382:   PetscUseMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmatrix));
383:   return(0);
384: }

388: static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
389: {
390:   PetscErrorCode  ierr;
391:   SVD_CYCLIC      *cyclic = (SVD_CYCLIC*)svd->data;

394:   PetscObjectReference((PetscObject)eps);
395:   EPSDestroy(&cyclic->eps);
396:   cyclic->eps = eps;
397:   PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->eps);
398:   svd->state = SVD_STATE_INITIAL;
399:   return(0);
400: }

404: /*@
405:    SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
406:    singular value solver.

408:    Collective on SVD

410:    Input Parameters:
411: +  svd - singular value solver
412: -  eps - the eigensolver object

414:    Level: advanced

416: .seealso: SVDCyclicGetEPS()
417: @*/
418: PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
419: {

426:   PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
427:   return(0);
428: }

432: static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
433: {
435:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

438:   if (!cyclic->eps) {
439:     EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps);
440:     EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix);
441:     EPSAppendOptionsPrefix(cyclic->eps,"svd_cyclic_");
442:     PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1);
443:     PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->eps);
444:     EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
445:     EPSMonitorSet(cyclic->eps,EPSMonitor_Cyclic,svd,NULL);
446:   }
447:   *eps = cyclic->eps;
448:   return(0);
449: }

453: /*@
454:    SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
455:    to the singular value solver.

457:    Not Collective

459:    Input Parameter:
460: .  svd - singular value solver

462:    Output Parameter:
463: .  eps - the eigensolver object

465:    Level: advanced

467: .seealso: SVDCyclicSetEPS()
468: @*/
469: PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
470: {

476:   PetscUseMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
477:   return(0);
478: }

482: PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
483: {
485:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;
486:   PetscBool      isascii;

489:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
490:   if (isascii) {
491:     if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
492:     PetscViewerASCIIPrintf(viewer,"  Cyclic: %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit");
493:     PetscViewerASCIIPushTab(viewer);
494:     EPSView(cyclic->eps,viewer);
495:     PetscViewerASCIIPopTab(viewer);
496:   }
497:   return(0);
498: }

502: PetscErrorCode SVDReset_Cyclic(SVD svd)
503: {
505:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

508:   if (!cyclic->eps) { EPSReset(cyclic->eps); }
509:   MatDestroy(&cyclic->mat);
510:   VecDestroy(&cyclic->x1);
511:   VecDestroy(&cyclic->x2);
512:   VecDestroy(&cyclic->y1);
513:   VecDestroy(&cyclic->y2);
514:   return(0);
515: }

519: PetscErrorCode SVDDestroy_Cyclic(SVD svd)
520: {
522:   SVD_CYCLIC     *cyclic = (SVD_CYCLIC*)svd->data;

525:   EPSDestroy(&cyclic->eps);
526:   PetscFree(svd->data);
527:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL);
528:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL);
529:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL);
530:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL);
531:   return(0);
532: }

536: PETSC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
537: {
539:   SVD_CYCLIC     *cyclic;

542:   PetscNewLog(svd,&cyclic);
543:   svd->data                      = (void*)cyclic;
544:   svd->ops->solve                = SVDSolve_Cyclic;
545:   svd->ops->setup                = SVDSetUp_Cyclic;
546:   svd->ops->setfromoptions       = SVDSetFromOptions_Cyclic;
547:   svd->ops->destroy              = SVDDestroy_Cyclic;
548:   svd->ops->reset                = SVDReset_Cyclic;
549:   svd->ops->view                 = SVDView_Cyclic;
550:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic);
551:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic);
552:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic);
553:   PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic);
554:   return(0);
555: }