Date: 2013-09-02T10:06:31+00:00

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