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-2010, Universidad Politecnica de Valencia, Spain
8: This file is part of SLEPc.
9:
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 private/svdimpl.h
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:
37: . -svd_view - print information about the solver used
39: Level: beginner
41: .seealso: SVDCreate(), SVDSetUp(), SVDDestroy()
42: @*/
43: PetscErrorCode SVDSolve(SVD svd)
44: {
46: PetscTruth flg;
47: PetscInt i,*workperm;
48: char filename[PETSC_MAX_PATH_LEN];
49: PetscViewer viewer;
54: if (!svd->setupcalled) { SVDSetUp(svd); }
55: svd->its = 0;
56: svd->matvecs = 0;
57: svd->nconv = 0;
58: svd->reason = SVD_CONVERGED_ITERATING;
59: IPResetOperationCounters(svd->ip);
60: for (i=0;i<svd->ncv;i++) svd->sigma[i]=svd->errest[i]=0.0;
61: SVDMonitor(svd,svd->its,svd->nconv,svd->sigma,svd->errest,svd->ncv);
63: PetscLogEventBegin(SVD_Solve,svd,0,0,0);
64: (*svd->ops->solve)(svd);
65: PetscLogEventEnd(SVD_Solve,svd,0,0,0);
67: /* sort singular triplets */
68: if (svd->which == SVD_SMALLEST) {
69: for (i=0;i<svd->nconv;i++) svd->perm[i] = i;
70: PetscSortRealWithPermutation(svd->nconv,svd->sigma,svd->perm);
71: } else {
72: PetscMalloc(sizeof(PetscInt)*svd->nconv,&workperm);
73: for (i=0;i<svd->nconv;i++) workperm[i] = i;
74: PetscSortRealWithPermutation(svd->nconv,svd->sigma,workperm);
75: for (i=0;i<svd->nconv;i++) svd->perm[i] = workperm[svd->nconv-i-1];
76: PetscFree(workperm);
77: }
79: PetscOptionsGetString(((PetscObject)svd)->prefix,"-svd_view",filename,PETSC_MAX_PATH_LEN,&flg);
80: if (flg && !PetscPreLoadingOn) {
81: PetscViewerASCIIOpen(((PetscObject)svd)->comm,filename,&viewer);
82: SVDView(svd,viewer);
83: PetscViewerDestroy(viewer);
84: }
86: /* Remove the initial subspace */
87: svd->nini = 0;
89: return(0);
90: }
94: /*@
95: SVDGetIterationNumber - Gets the current iteration number. If the
96: call to SVDSolve() is complete, then it returns the number of iterations
97: carried out by the solution method.
98:
99: Not Collective
101: Input Parameter:
102: . svd - the singular value solver context
104: Output Parameter:
105: . its - number of iterations
107: Level: intermediate
109: Notes:
110: During the i-th iteration this call returns i-1. If SVDSolve() is
111: complete, then parameter "its" contains either the iteration number at
112: which convergence was successfully reached, or failure was detected.
113: Call SVDGetConvergedReason() to determine if the solver converged or
114: failed and why.
116: @*/
117: PetscErrorCode SVDGetIterationNumber(SVD svd,PetscInt *its)
118: {
122: *its = svd->its;
123: return(0);
124: }
128: /*@C
129: SVDGetConvergedReason - Gets the reason why the SVDSolve() iteration was
130: stopped.
132: Not Collective
134: Input Parameter:
135: . svd - the singular value solver context
137: Output Parameter:
138: . reason - negative value indicates diverged, positive value converged
139: (see SVDConvergedReason)
141: Possible values for reason:
142: + SVD_CONVERGED_TOL - converged up to tolerance
143: . SVD_DIVERGED_ITS - required more than its to reach convergence
144: - SVD_DIVERGED_BREAKDOWN - generic breakdown in method
146: Level: intermediate
148: Notes: Can only be called after the call to SVDSolve() is complete.
150: .seealso: SVDSetTolerances(), SVDSolve(), SVDConvergedReason
151: @*/
152: PetscErrorCode SVDGetConvergedReason(SVD svd,SVDConvergedReason *reason)
153: {
157: *reason = svd->reason;
158: return(0);
159: }
163: /*@
164: SVDGetConverged - Gets the number of converged singular values.
166: Not Collective
168: Input Parameter:
169: . svd - the singular value solver context
170:
171: Output Parameter:
172: . nconv - number of converged singular values
174: Note:
175: This function should be called after SVDSolve() has finished.
177: Level: beginner
179: @*/
180: PetscErrorCode SVDGetConverged(SVD svd,PetscInt *nconv)
181: {
185: if (svd->reason == SVD_CONVERGED_ITERATING) {
186: SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "SVDSolve must be called first");
187: }
188: *nconv = svd->nconv;
189: return(0);
190: }
194: /*@
195: SVDGetSingularTriplet - Gets the i-th triplet of the singular value decomposition
196: as computed by SVDSolve(). The solution consists in the singular value and its left
197: and right singular vectors.
199: Not Collective
201: Input Parameters:
202: + svd - singular value solver context
203: - i - index of the solution
205: Output Parameters:
206: + sigma - singular value
207: . u - left singular vector
208: - v - right singular vector
210: Note:
211: The index i should be a value between 0 and nconv-1 (see SVDGetConverged()).
212: Both U or V can be PETSC_NULL if singular vectors are not required.
214: Level: beginner
216: .seealso: SVDSolve(), SVDGetConverged()
217: @*/
218: PetscErrorCode SVDGetSingularTriplet(SVD svd, PetscInt i, PetscReal *sigma, Vec u, Vec v)
219: {
221: PetscReal norm;
222: PetscInt j,nloc,M,N;
223: PetscScalar *pU;
224: Vec w;
229: if (svd->reason == SVD_CONVERGED_ITERATING) {
230: SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "SVDSolve must be called first");
231: }
232: if (i<0 || i>=svd->nconv) {
233: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Argument 2 out of range");
234: }
235: *sigma = svd->sigma[svd->perm[i]];
236: MatGetSize(svd->OP,&M,&N);
237: if (M<N) { w = u; u = v; v = w; }
238: if (u) {
240: if (!svd->U) {
241: PetscMalloc(sizeof(Vec)*svd->ncv,&svd->U);
242: SVDMatGetLocalSize(svd,&nloc,PETSC_NULL);
243: PetscMalloc(svd->ncv*nloc*sizeof(PetscScalar),&pU);
244: for (j=0;j<svd->ncv;j++) {
245: VecCreateMPIWithArray(((PetscObject)svd)->comm,nloc,PETSC_DECIDE,pU+j*nloc,&svd->U[j]);
246: }
247: for (j=0;j<svd->nconv;j++) {
248: SVDMatMult(svd,PETSC_FALSE,svd->V[j],svd->U[j]);
249: IPOrthogonalize(svd->ip,0,PETSC_NULL,j,PETSC_NULL,svd->U,svd->U[j],PETSC_NULL,&norm,PETSC_NULL);
250: VecScale(svd->U[j],1.0/norm);
251: }
252: }
253: VecCopy(svd->U[svd->perm[i]],u);
254: }
255: if (v) {
257: VecCopy(svd->V[svd->perm[i]],v);
258: }
259: return(0);
260: }
264: /*@
265: SVDComputeResidualNorms - Computes the norms of the residual vectors associated with
266: the i-th computed singular triplet.
268: Collective on SVD
270: Input Parameters:
271: + svd - the singular value solver context
272: - i - the solution index
274: Output Parameters:
275: + norm1 - the norm ||A*v-sigma*u||_2 where sigma is the
276: singular value, u and v are the left and right singular vectors.
277: - norm2 - the norm ||A^T*u-sigma*v||_2 with the same sigma, u and v
279: Note:
280: The index i should be a value between 0 and nconv-1 (see SVDGetConverged()).
281: Both output parameters can be PETSC_NULL on input if not needed.
283: Level: beginner
285: .seealso: SVDSolve(), SVDGetConverged(), SVDComputeRelativeError()
286: @*/
287: PetscErrorCode SVDComputeResidualNorms(SVD svd, PetscInt i, PetscReal *norm1, PetscReal *norm2)
288: {
290: Vec u,v,x = PETSC_NULL,y = PETSC_NULL;
291: PetscReal sigma;
292: PetscInt M,N;
296: if (svd->reason == SVD_CONVERGED_ITERATING) {
297: SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "SVDSolve must be called first");
298: }
299: if (i<0 || i>=svd->nconv) {
300: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE, "Argument 2 out of range");
301: }
302:
303: MatGetVecs(svd->OP,&v,&u);
304: SVDGetSingularTriplet(svd,i,&sigma,u,v);
305: if (norm1) {
306: VecDuplicate(u,&x);
307: MatMult(svd->OP,v,x);
308: VecAXPY(x,-sigma,u);
309: VecNorm(x,NORM_2,norm1);
310: }
311: if (norm2) {
312: VecDuplicate(v,&y);
313: if (svd->A && svd->AT) {
314: MatGetSize(svd->OP,&M,&N);
315: if (M<N) {
316: MatMult(svd->A,u,y);
317: } else {
318: MatMult(svd->AT,u,y);
319: }
320: } else {
321: MatMultTranspose(svd->OP,u,y);
322: }
323: VecAXPY(y,-sigma,v);
324: VecNorm(y,NORM_2,norm2);
325: }
327: VecDestroy(v);
328: VecDestroy(u);
329: if (x) { VecDestroy(x); }
330: if (y) { VecDestroy(y); }
331: return(0);
332: }
336: /*@
337: SVDComputeRelativeError - Computes the relative error bound associated
338: with the i-th singular triplet.
340: Collective on SVD
342: Input Parameter:
343: + svd - the singular value solver context
344: - i - the solution index
346: Output Parameter:
347: . error - the relative error bound, computed as sqrt(n1^2+n2^2)/sigma
348: where n1 = ||A*v-sigma*u||_2 , n2 = ||A^T*u-sigma*v||_2 , sigma is the singular value,
349: u and v are the left and right singular vectors.
350: If sigma is too small the relative error is computed as sqrt(n1^2+n2^2).
352: Level: beginner
354: .seealso: SVDSolve(), SVDComputeResidualNorms()
355: @*/
356: PetscErrorCode SVDComputeRelativeError(SVD svd,PetscInt i,PetscReal *error)
357: {
359: PetscReal sigma,norm1,norm2;
364: SVDGetSingularTriplet(svd,i,&sigma,PETSC_NULL,PETSC_NULL);
365: SVDComputeResidualNorms(svd,i,&norm1,&norm2);
366: *error = sqrt(norm1*norm1+norm2*norm2);
367: if (sigma>*error) *error /= sigma;
368: return(0);
369: }
373: /*@
374: SVDGetOperationCounters - Gets the total number of matrix vector and dot
375: products used by the SVD object during the last SVDSolve() call.
377: Not Collective
379: Input Parameter:
380: . svd - SVD context
382: Output Parameter:
383: + matvecs - number of matrix vector product operations
384: - dots - number of dot product operations
386: Notes:
387: These counters are reset to zero at each successive call to SVDSolve().
389: Level: intermediate
391: @*/
392: PetscErrorCode SVDGetOperationCounters(SVD svd,PetscInt* matvecs,PetscInt* dots)
393: {
395:
398: if (matvecs) *matvecs = svd->matvecs;
399: if (dots) {
400: IPGetOperationCounters(svd->ip,dots);
401: }
402: return(0);
403: }