Actual source code: svdsolve.c
1: /*
2: SVD routines related to the solution process.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
10: SLEPc is free software: you can redistribute it and/or modify it under the
11: terms of version 3 of the GNU Lesser General Public License as published by
12: the Free Software Foundation.
14: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
15: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17: more details.
19: You should have received a copy of the GNU Lesser General Public License
20: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
21: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22: */
24: #include <slepc-private/svdimpl.h> /*I "slepcsvd.h" I*/
28: /*@
29: SVDSolve - Solves the singular value problem.
31: Collective on SVD
33: Input Parameter:
34: . svd - singular value solver context obtained from SVDCreate()
36: Options Database Keys:
37: + -svd_view - print information about the solver used
38: - -svd_view_mat binary - save the matrix to the default binary viewer
40: Level: beginner
42: .seealso: SVDCreate(), SVDSetUp(), SVDDestroy()
43: @*/
44: PetscErrorCode SVDSolve(SVD svd)
45: {
46: PetscErrorCode ierr;
47: PetscBool flg;
48: PetscInt i,*workperm;
49: PetscViewer viewer;
50: PetscViewerFormat format;
51: PetscErrorCode (*which_func)(PetscScalar,PetscScalar,PetscScalar,PetscScalar,PetscInt*,void*);
55: PetscLogEventBegin(SVD_Solve,svd,0,0,0);
57: /* call setup */
58: SVDSetUp(svd);
59: svd->its = 0;
60: svd->nconv = 0;
61: for (i=0;i<svd->ncv;i++) {
62: svd->sigma[i] = 0.0;
63: svd->errest[i] = 0.0;
64: }
65: SVDMonitor(svd,svd->its,svd->nconv,svd->sigma,svd->errest,svd->ncv);
67: which_func = (svd->which==SVD_LARGEST)? SlepcCompareLargestReal: SlepcCompareSmallestReal;
68: DSSetEigenvalueComparison(svd->ds,which_func,NULL);
70: (*svd->ops->solve)(svd);
72: /* sort singular triplets */
73: if (svd->which == SVD_SMALLEST) {
74: for (i=0;i<svd->nconv;i++) svd->perm[i] = i;
75: PetscSortRealWithPermutation(svd->nconv,svd->sigma,svd->perm);
76: } else {
77: PetscMalloc(sizeof(PetscInt)*svd->nconv,&workperm);
78: for (i=0;i<svd->nconv;i++) workperm[i] = i;
79: PetscSortRealWithPermutation(svd->nconv,svd->sigma,workperm);
80: for (i=0;i<svd->nconv;i++) svd->perm[i] = workperm[svd->nconv-i-1];
81: PetscFree(workperm);
82: }
84: PetscLogEventEnd(SVD_Solve,svd,0,0,0);
86: /* various viewers */
87: MatViewFromOptions(svd->OP,((PetscObject)svd)->prefix,"-svd_view_mat");
89: PetscOptionsGetViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->prefix,"-svd_view",&viewer,&format,&flg);
90: if (flg && !PetscPreLoadingOn) {
91: PetscViewerPushFormat(viewer,format);
92: SVDView(svd,viewer);
93: PetscViewerPopFormat(viewer);
94: PetscViewerDestroy(&viewer);
95: }
97: /* Remove the initial subspace */
98: svd->nini = 0;
99: return(0);
100: }
104: /*@
105: SVDGetIterationNumber - Gets the current iteration number. If the
106: call to SVDSolve() is complete, then it returns the number of iterations
107: carried out by the solution method.
109: Not Collective
111: Input Parameter:
112: . svd - the singular value solver context
114: Output Parameter:
115: . its - number of iterations
117: Level: intermediate
119: Notes:
120: During the i-th iteration this call returns i-1. If SVDSolve() is
121: complete, then parameter "its" contains either the iteration number at
122: which convergence was successfully reached, or failure was detected.
123: Call SVDGetConvergedReason() to determine if the solver converged or
124: failed and why.
126: @*/
127: PetscErrorCode SVDGetIterationNumber(SVD svd,PetscInt *its)
128: {
132: *its = svd->its;
133: return(0);
134: }
138: /*@C
139: SVDGetConvergedReason - Gets the reason why the SVDSolve() iteration was
140: stopped.
142: Not Collective
144: Input Parameter:
145: . svd - the singular value solver context
147: Output Parameter:
148: . reason - negative value indicates diverged, positive value converged
149: (see SVDConvergedReason)
151: Possible values for reason:
152: + SVD_CONVERGED_TOL - converged up to tolerance
153: . SVD_DIVERGED_ITS - required more than its to reach convergence
154: - SVD_DIVERGED_BREAKDOWN - generic breakdown in method
156: Level: intermediate
158: Notes: Can only be called after the call to SVDSolve() is complete.
160: .seealso: SVDSetTolerances(), SVDSolve(), SVDConvergedReason
161: @*/
162: PetscErrorCode SVDGetConvergedReason(SVD svd,SVDConvergedReason *reason)
163: {
167: *reason = svd->reason;
168: return(0);
169: }
173: /*@
174: SVDGetConverged - Gets the number of converged singular values.
176: Not Collective
178: Input Parameter:
179: . svd - the singular value solver context
181: Output Parameter:
182: . nconv - number of converged singular values
184: Note:
185: This function should be called after SVDSolve() has finished.
187: Level: beginner
189: @*/
190: PetscErrorCode SVDGetConverged(SVD svd,PetscInt *nconv)
191: {
195: *nconv = svd->nconv;
196: return(0);
197: }
201: /*@
202: SVDGetSingularTriplet - Gets the i-th triplet of the singular value decomposition
203: as computed by SVDSolve(). The solution consists in the singular value and its left
204: and right singular vectors.
206: Not Collective, but vectors are shared by all processors that share the SVD
208: Input Parameters:
209: + svd - singular value solver context
210: - i - index of the solution
212: Output Parameters:
213: + sigma - singular value
214: . u - left singular vector
215: - v - right singular vector
217: Note:
218: The index i should be a value between 0 and nconv-1 (see SVDGetConverged()).
219: Both U or V can be NULL if singular vectors are not required.
221: Level: beginner
223: .seealso: SVDSolve(), SVDGetConverged()
224: @*/
225: PetscErrorCode SVDGetSingularTriplet(SVD svd,PetscInt i,PetscReal *sigma,Vec u,Vec v)
226: {
228: PetscReal norm;
229: PetscInt j,M,N;
230: Vec w;
236: if (svd->reason == SVD_CONVERGED_ITERATING) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONGSTATE,"SVDSolve must be called first");
237: if (i<0 || i>=svd->nconv) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
238: *sigma = svd->sigma[svd->perm[i]];
239: MatGetSize(svd->OP,&M,&N);
240: if (M<N) { w = u; u = v; v = w; }
241: if (u) {
242: if (!svd->U) {
243: VecDuplicateVecs(svd->tl,svd->ncv,&svd->U);
244: PetscLogObjectParents(svd,svd->ncv,svd->U);
245: for (j=0;j<svd->nconv;j++) {
246: SVDMatMult(svd,PETSC_FALSE,svd->V[j],svd->U[j]);
247: IPOrthogonalize(svd->ip,0,NULL,j,NULL,svd->U,svd->U[j],NULL,&norm,NULL);
248: VecScale(svd->U[j],1.0/norm);
249: }
250: }
251: VecCopy(svd->U[svd->perm[i]],u);
252: }
253: if (v) {
254: VecCopy(svd->V[svd->perm[i]],v);
255: }
256: return(0);
257: }
261: /*@
262: SVDComputeResidualNorms - Computes the norms of the residual vectors associated with
263: the i-th computed singular triplet.
265: Collective on SVD
267: Input Parameters:
268: + svd - the singular value solver context
269: - i - the solution index
271: Output Parameters:
272: + norm1 - the norm ||A*v-sigma*u||_2 where sigma is the
273: singular value, u and v are the left and right singular vectors.
274: - norm2 - the norm ||A^T*u-sigma*v||_2 with the same sigma, u and v
276: Note:
277: The index i should be a value between 0 and nconv-1 (see SVDGetConverged()).
278: Both output parameters can be NULL on input if not needed.
280: Level: beginner
282: .seealso: SVDSolve(), SVDGetConverged(), SVDComputeRelativeError()
283: @*/
284: PetscErrorCode SVDComputeResidualNorms(SVD svd,PetscInt i,PetscReal *norm1,PetscReal *norm2)
285: {
287: Vec u,v,x = NULL,y = NULL;
288: PetscReal sigma;
289: PetscInt M,N;
294: if (svd->reason == SVD_CONVERGED_ITERATING) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONGSTATE,"SVDSolve must be called first");
295: if (i<0 || i>=svd->nconv) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
297: MatGetVecs(svd->OP,&v,&u);
298: SVDGetSingularTriplet(svd,i,&sigma,u,v);
299: if (norm1) {
300: VecDuplicate(u,&x);
301: MatMult(svd->OP,v,x);
302: VecAXPY(x,-sigma,u);
303: VecNorm(x,NORM_2,norm1);
304: }
305: if (norm2) {
306: VecDuplicate(v,&y);
307: if (svd->A && svd->AT) {
308: MatGetSize(svd->OP,&M,&N);
309: if (M<N) {
310: MatMult(svd->A,u,y);
311: } else {
312: MatMult(svd->AT,u,y);
313: }
314: } else {
315: #if defined(PETSC_USE_COMPLEX)
316: MatMultHermitianTranspose(svd->OP,u,y);
317: #else
318: MatMultTranspose(svd->OP,u,y);
319: #endif
320: }
321: VecAXPY(y,-sigma,v);
322: VecNorm(y,NORM_2,norm2);
323: }
325: VecDestroy(&v);
326: VecDestroy(&u);
327: VecDestroy(&x);
328: VecDestroy(&y);
329: return(0);
330: }
334: /*@
335: SVDComputeRelativeError - Computes the relative error bound associated
336: with the i-th singular triplet.
338: Collective on SVD
340: Input Parameter:
341: + svd - the singular value solver context
342: - i - the solution index
344: Output Parameter:
345: . error - the relative error bound, computed as sqrt(n1^2+n2^2)/sigma
346: where n1 = ||A*v-sigma*u||_2 , n2 = ||A^T*u-sigma*v||_2 , sigma is the singular value,
347: u and v are the left and right singular vectors.
348: If sigma is too small the relative error is computed as sqrt(n1^2+n2^2).
350: Level: beginner
352: .seealso: SVDSolve(), SVDComputeResidualNorms()
353: @*/
354: PetscErrorCode SVDComputeRelativeError(SVD svd,PetscInt i,PetscReal *error)
355: {
357: PetscReal sigma,norm1,norm2;
363: SVDGetSingularTriplet(svd,i,&sigma,NULL,NULL);
364: SVDComputeResidualNorms(svd,i,&norm1,&norm2);
365: *error = PetscSqrtReal(norm1*norm1+norm2*norm2);
366: if (sigma>*error) *error /= sigma;
367: return(0);
368: }
372: /*@
373: SVDGetOperationCounters - Gets the total number of matrix vector and dot
374: products used by the SVD object during the last SVDSolve() call.
376: Not Collective
378: Input Parameter:
379: . svd - SVD context
381: Output Parameter:
382: + matvecs - number of matrix vector product operations
383: - dots - number of dot product operations
385: Notes:
386: These counters are reset to zero at each successive call to SVDSolve().
388: Level: intermediate
390: @*/
391: PetscErrorCode SVDGetOperationCounters(SVD svd,PetscInt* matvecs,PetscInt* dots)
392: {
397: if (matvecs) *matvecs = svd->matvecs;
398: if (dots) {
399: if (!svd->ip) { SVDGetIP(svd,&svd->ip); }
400: IPGetOperationCounters(svd->ip,dots);
401: }
402: return(0);
403: }