Actual source code: cyclic.c
slepc-3.6.1 2015-09-03
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-2015, 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;
90: Vec v;
91: Mat Zm,Zn;
94: SVDMatGetSize(svd,&M,&N);
95: SVDMatGetLocalSize(svd,&m,&n);
96: if (!cyclic->mat) {
97: if (cyclic->explicitmatrix) {
98: if (!svd->AT) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Cannot use explicit cyclic matrix with implicit transpose");
99: MatCreate(PetscObjectComm((PetscObject)svd),&Zm);
100: MatSetSizes(Zm,m,m,M,M);
101: MatSetFromOptions(Zm);
102: MatSetUp(Zm);
103: MatGetOwnershipRange(Zm,&Istart,&Iend);
104: for (i=Istart;i<Iend;i++) {
105: MatSetValue(Zm,i,i,0.0,INSERT_VALUES);
106: }
107: MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY);
108: MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY);
109: MatCreate(PetscObjectComm((PetscObject)svd),&Zn);
110: MatSetSizes(Zn,n,n,N,N);
111: MatSetFromOptions(Zn);
112: MatSetUp(Zn);
113: MatGetOwnershipRange(Zn,&Istart,&Iend);
114: for (i=Istart;i<Iend;i++) {
115: MatSetValue(Zn,i,i,0.0,INSERT_VALUES);
116: }
117: MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY);
118: MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY);
119: SlepcMatTile(1.0,Zm,1.0,svd->A,1.0,svd->AT,1.0,Zn,&cyclic->mat);
120: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->mat);
121: MatDestroy(&Zm);
122: MatDestroy(&Zn);
123: } else {
124: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->x1);
125: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->x2);
126: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&cyclic->y1);
127: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&cyclic->y2);
128: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->x1);
129: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->x2);
130: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->y1);
131: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->y2);
132: MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,svd,&cyclic->mat);
133: MatShellSetOperation(cyclic->mat,MATOP_MULT,(void(*)(void))MatMult_Cyclic);
134: MatShellSetOperation(cyclic->mat,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic);
135: }
136: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->mat);
137: }
139: if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
140: EPSSetOperators(cyclic->eps,cyclic->mat,NULL);
141: EPSSetProblemType(cyclic->eps,EPS_HEP);
142: if (svd->which == SVD_LARGEST) {
143: EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
144: } else {
145: EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL);
146: EPSSetTarget(cyclic->eps,0.0);
147: }
148: EPSSetDimensions(cyclic->eps,svd->nsv,svd->ncv?svd->ncv:PETSC_DEFAULT,svd->mpd?svd->mpd:PETSC_DEFAULT);
149: EPSSetTolerances(cyclic->eps,svd->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL/10.0:svd->tol,svd->max_it?svd->max_it:PETSC_DEFAULT);
150: /* Transfer the trackall option from svd to eps */
151: SVDGetTrackAll(svd,&trackall);
152: EPSSetTrackAll(cyclic->eps,trackall);
153: /* Transfer the initial subspace from svd to eps */
154: if (svd->nini<0 || svd->ninil<0) {
155: for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
156: MatCreateVecs(cyclic->mat,&v,NULL);
157: VecGetArray(v,&va);
158: if (i<-svd->ninil) {
159: VecGetSize(svd->ISL[i],&isl);
160: if (isl!=m) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for left initial vector");
161: VecGetArrayRead(svd->ISL[i],&isa);
162: PetscMemcpy(va,isa,sizeof(PetscScalar)*m);
163: VecRestoreArrayRead(svd->IS[i],&isa);
164: } else {
165: PetscMemzero(&va,sizeof(PetscScalar)*m);
166: }
167: if (i<-svd->nini) {
168: VecGetSize(svd->IS[i],&isl);
169: if (isl!=n) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for right initial vector");
170: VecGetArrayRead(svd->IS[i],&isa);
171: PetscMemcpy(va+m,isa,sizeof(PetscScalar)*n);
172: VecRestoreArrayRead(svd->IS[i],&isa);
173: } else {
174: PetscMemzero(va+m,sizeof(PetscScalar)*n);
175: }
176: VecRestoreArray(v,&va);
177: VecDestroy(&svd->IS[i]);
178: svd->IS[i] = v;
179: }
180: svd->nini = PetscMin(svd->nini,svd->ninil);
181: EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS);
182: SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
183: SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL);
184: }
185: EPSSetUp(cyclic->eps);
186: EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd);
187: svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
188: EPSGetTolerances(cyclic->eps,NULL,&svd->max_it);
189: if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;
191: svd->leftbasis = PETSC_TRUE;
192: SVDAllocateSolution(svd,0);
193: return(0);
194: }
198: PetscErrorCode SVDSolve_Cyclic(SVD svd)
199: {
200: PetscErrorCode ierr;
201: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
202: PetscInt i,j,M,N,m,n;
203: PetscScalar sigma;
204: const PetscScalar *px;
205: Vec x,x1,x2;
208: EPSSolve(cyclic->eps);
209: EPSGetConverged(cyclic->eps,&svd->nconv);
210: EPSGetIterationNumber(cyclic->eps,&svd->its);
211: EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason);
213: MatCreateVecs(cyclic->mat,&x,NULL);
214: SVDMatGetSize(svd,&M,&N);
215: SVDMatGetLocalSize(svd,&m,&n);
216: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,m,M,NULL,&x1);
217: VecCreateMPIWithArray(PetscObjectComm((PetscObject)svd),1,n,N,NULL,&x2);
218: for (i=0,j=0;i<svd->nconv;i++) {
219: EPSGetEigenpair(cyclic->eps,i,&sigma,NULL,x,NULL);
220: if (PetscRealPart(sigma) > 0.0) {
221: svd->sigma[j] = PetscRealPart(sigma);
222: VecGetArrayRead(x,&px);
223: VecPlaceArray(x1,px);
224: VecPlaceArray(x2,px+m);
225: BVInsertVec(svd->U,j,x1);
226: BVScaleColumn(svd->U,j,1.0/PetscSqrtReal(2.0));
227: BVInsertVec(svd->V,j,x2);
228: BVScaleColumn(svd->V,j,1.0/PetscSqrtReal(2.0));
229: VecResetArray(x1);
230: VecResetArray(x2);
231: VecRestoreArrayRead(x,&px);
232: j++;
233: }
234: }
235: svd->nconv = j;
237: VecDestroy(&x);
238: VecDestroy(&x1);
239: VecDestroy(&x2);
240: return(0);
241: }
245: static PetscErrorCode SVDMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
246: {
247: PetscInt i,j;
248: SVD svd = (SVD)ctx;
249: PetscScalar er,ei;
253: nconv = 0;
254: for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
255: er = eigr[i]; ei = eigi[i];
256: STBackTransform(eps->st,1,&er,&ei);
257: if (PetscRealPart(er) > 0.0) {
258: svd->sigma[j] = PetscRealPart(er);
259: svd->errest[j] = errest[i];
260: if (errest[i] < svd->tol) nconv++;
261: j++;
262: }
263: }
264: nest = j;
265: SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
266: return(0);
267: }
271: PetscErrorCode SVDSetFromOptions_Cyclic(PetscOptions *PetscOptionsObject,SVD svd)
272: {
274: PetscBool set,val;
275: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
276: ST st;
279: PetscOptionsHead(PetscOptionsObject,"SVD Cyclic Options");
280: PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set);
281: if (set) {
282: SVDCyclicSetExplicitMatrix(svd,val);
283: }
284: if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
285: EPSSetFromOptions(cyclic->eps);
286: if (!cyclic->explicitmatrix) {
287: /* use as default an ST with shell matrix and Jacobi */
288: EPSGetST(cyclic->eps,&st);
289: STSetMatMode(st,ST_MATMODE_SHELL);
290: }
291: PetscOptionsTail();
292: return(0);
293: }
297: static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmatrix)
298: {
299: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
302: cyclic->explicitmatrix = explicitmatrix;
303: return(0);
304: }
308: /*@
309: SVDCyclicSetExplicitMatrix - Indicate if the eigensolver operator
310: H(A) = [ 0 A ; A^T 0 ] must be computed explicitly.
312: Logically Collective on SVD
314: Input Parameters:
315: + svd - singular value solver
316: - explicit - boolean flag indicating if H(A) is built explicitly
318: Options Database Key:
319: . -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag
321: Level: advanced
323: .seealso: SVDCyclicGetExplicitMatrix()
324: @*/
325: PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmatrix)
326: {
332: PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmatrix));
333: return(0);
334: }
338: static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmatrix)
339: {
340: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
343: *explicitmatrix = cyclic->explicitmatrix;
344: return(0);
345: }
349: /*@
350: SVDCyclicGetExplicitMatrix - Returns the flag indicating if H(A) is built explicitly
352: Not Collective
354: Input Parameter:
355: . svd - singular value solver
357: Output Parameter:
358: . explicit - the mode flag
360: Level: advanced
362: .seealso: SVDCyclicSetExplicitMatrix()
363: @*/
364: PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmatrix)
365: {
371: PetscTryMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmatrix));
372: return(0);
373: }
377: static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
378: {
379: PetscErrorCode ierr;
380: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
383: PetscObjectReference((PetscObject)eps);
384: EPSDestroy(&cyclic->eps);
385: cyclic->eps = eps;
386: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->eps);
387: svd->state = SVD_STATE_INITIAL;
388: return(0);
389: }
393: /*@
394: SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
395: singular value solver.
397: Collective on SVD
399: Input Parameters:
400: + svd - singular value solver
401: - eps - the eigensolver object
403: Level: advanced
405: .seealso: SVDCyclicGetEPS()
406: @*/
407: PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
408: {
415: PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
416: return(0);
417: }
421: static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
422: {
424: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
427: if (!cyclic->eps) {
428: EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps);
429: EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix);
430: EPSAppendOptionsPrefix(cyclic->eps,"svd_");
431: PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1);
432: PetscLogObjectParent((PetscObject)svd,(PetscObject)cyclic->eps);
433: EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL);
434: EPSMonitorSet(cyclic->eps,SVDMonitor_Cyclic,svd,NULL);
435: }
436: *eps = cyclic->eps;
437: return(0);
438: }
442: /*@
443: SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
444: to the singular value solver.
446: Not Collective
448: Input Parameter:
449: . svd - singular value solver
451: Output Parameter:
452: . eps - the eigensolver object
454: Level: advanced
456: .seealso: SVDCyclicSetEPS()
457: @*/
458: PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
459: {
465: PetscTryMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
466: return(0);
467: }
471: PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
472: {
474: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
477: if (!cyclic->eps) { SVDCyclicGetEPS(svd,&cyclic->eps); }
478: PetscViewerASCIIPrintf(viewer," Cyclic: %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit");
479: PetscViewerASCIIPushTab(viewer);
480: EPSView(cyclic->eps,viewer);
481: PetscViewerASCIIPopTab(viewer);
482: return(0);
483: }
487: PetscErrorCode SVDReset_Cyclic(SVD svd)
488: {
490: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
493: if (!cyclic->eps) { EPSReset(cyclic->eps); }
494: MatDestroy(&cyclic->mat);
495: VecDestroy(&cyclic->x1);
496: VecDestroy(&cyclic->x2);
497: VecDestroy(&cyclic->y1);
498: VecDestroy(&cyclic->y2);
499: return(0);
500: }
504: PetscErrorCode SVDDestroy_Cyclic(SVD svd)
505: {
507: SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
510: EPSDestroy(&cyclic->eps);
511: PetscFree(svd->data);
512: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL);
513: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL);
514: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL);
515: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL);
516: return(0);
517: }
521: PETSC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
522: {
524: SVD_CYCLIC *cyclic;
527: PetscNewLog(svd,&cyclic);
528: svd->data = (void*)cyclic;
529: svd->ops->solve = SVDSolve_Cyclic;
530: svd->ops->setup = SVDSetUp_Cyclic;
531: svd->ops->setfromoptions = SVDSetFromOptions_Cyclic;
532: svd->ops->destroy = SVDDestroy_Cyclic;
533: svd->ops->reset = SVDReset_Cyclic;
534: svd->ops->view = SVDView_Cyclic;
535: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic);
536: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic);
537: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic);
538: PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic);
539: return(0);
540: }