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: }