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

Actual source code: cross.c

      1: /*

      3:    SLEPc singular value solver: "cross"

      5:    Method: Uses a Hermitian eigensolver for A^T*A

      7:    Last update: Jun 2007

      9:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     10:    SLEPc - Scalable Library for Eigenvalue Problem Computations
     11:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

     13:    This file is part of SLEPc.

     15:    SLEPc is free software: you can redistribute it and/or modify it under  the
     16:    terms of version 3 of the GNU Lesser General Public License as published by
     17:    the Free Software Foundation.

     19:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     20:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     21:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     22:    more details.

     24:    You  should have received a copy of the GNU Lesser General  Public  License
     25:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     26:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     27: */

     29: #include <slepc-private/svdimpl.h>                /*I "slepcsvd.h" I*/
     30: #include <slepc-private/epsimpl.h>                /*I "slepceps.h" I*/

     32: typedef struct {
     33:   EPS       eps;
     34:   PetscBool setfromoptionscalled;
     35:   Mat       mat;
     36:   Vec       w,diag;
     37: } SVD_CROSS;

     41: static PetscErrorCode MatMult_Cross(Mat B,Vec x,Vec y)
     42: {
     44:   SVD            svd;
     45:   SVD_CROSS      *cross;

     48:   MatShellGetContext(B,(void**)&svd);
     49:   cross = (SVD_CROSS*)svd->data;
     50:   SVDMatMult(svd,PETSC_FALSE,x,cross->w);
     51:   SVDMatMult(svd,PETSC_TRUE,cross->w,y);
     52:   return(0);
     53: }

     57: static PetscErrorCode MatGetDiagonal_Cross(Mat B,Vec d)
     58: {
     59:   PetscErrorCode    ierr;
     60:   SVD               svd;
     61:   SVD_CROSS         *cross;
     62:   PetscInt          N,n,i,j,start,end,ncols;
     63:   PetscScalar       *work1,*work2,*diag;
     64:   const PetscInt    *cols;
     65:   const PetscScalar *vals;

     68:   MatShellGetContext(B,(void**)&svd);
     69:   cross = (SVD_CROSS*)svd->data;
     70:   if (!cross->diag) {
     71:     /* compute diagonal from rows and store in cross->diag */
     72:     VecDuplicate(d,&cross->diag);
     73:     SVDMatGetSize(svd,NULL,&N);
     74:     SVDMatGetLocalSize(svd,NULL,&n);
     75:     PetscMalloc(sizeof(PetscScalar)*N,&work1);
     76:     PetscMalloc(sizeof(PetscScalar)*N,&work2);
     77:     for (i=0;i<n;i++) work1[i] = work2[i] = 0.0;
     78:     if (svd->AT) {
     79:       MatGetOwnershipRange(svd->AT,&start,&end);
     80:       for (i=start;i<end;i++) {
     81:         MatGetRow(svd->AT,i,&ncols,NULL,&vals);
     82:         for (j=0;j<ncols;j++)
     83:           work1[i] += vals[j]*vals[j];
     84:         MatRestoreRow(svd->AT,i,&ncols,NULL,&vals);
     85:       }
     86:     } else {
     87:       MatGetOwnershipRange(svd->A,&start,&end);
     88:       for (i=start;i<end;i++) {
     89:         MatGetRow(svd->A,i,&ncols,&cols,&vals);
     90:         for (j=0;j<ncols;j++)
     91:           work1[cols[j]] += vals[j]*vals[j];
     92:         MatRestoreRow(svd->A,i,&ncols,&cols,&vals);
     93:       }
     94:     }
     95:     MPI_Allreduce(work1,work2,N,MPIU_SCALAR,MPI_SUM,PetscObjectComm((PetscObject)svd));
     96:     VecGetOwnershipRange(cross->diag,&start,&end);
     97:     VecGetArray(cross->diag,&diag);
     98:     for (i=start;i<end;i++)
     99:       diag[i-start] = work2[i];
    100:     VecRestoreArray(cross->diag,&diag);
    101:     PetscFree(work1);
    102:     PetscFree(work2);
    103:   }
    104:   VecCopy(cross->diag,d);
    105:   return(0);
    106: }

    110: PetscErrorCode SVDSetUp_Cross(SVD svd)
    111: {
    113:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    114:   PetscInt       n,i;
    115:   PetscBool      trackall;

    118:   if (!cross->mat) {
    119:     SVDMatGetLocalSize(svd,NULL,&n);
    120:     MatCreateShell(PetscObjectComm((PetscObject)svd),n,n,PETSC_DETERMINE,PETSC_DETERMINE,svd,&cross->mat);
    121:     MatShellSetOperation(cross->mat,MATOP_MULT,(void(*)(void))MatMult_Cross);
    122:     MatShellSetOperation(cross->mat,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cross);
    123:     SVDMatGetVecs(svd,NULL,&cross->w);
    124:     PetscLogObjectParent(svd,cross->mat);
    125:     PetscLogObjectParent(svd,cross->w);
    126:   }

    128:   if (!cross->eps) { SVDCrossGetEPS(svd,&cross->eps); }
    129:   EPSSetOperators(cross->eps,cross->mat,NULL);
    130:   EPSSetProblemType(cross->eps,EPS_HEP);
    131:   EPSSetWhichEigenpairs(cross->eps,svd->which == SVD_LARGEST ? EPS_LARGEST_REAL : EPS_SMALLEST_REAL);
    132:   EPSSetDimensions(cross->eps,svd->nsv,svd->ncv,svd->mpd);
    133:   EPSSetTolerances(cross->eps,svd->tol,svd->max_it);
    134:   /* Transfer the trackall option from svd to eps */
    135:   SVDGetTrackAll(svd,&trackall);
    136:   EPSSetTrackAll(cross->eps,trackall);
    137:   if (cross->setfromoptionscalled) {
    138:     EPSSetFromOptions(cross->eps);
    139:     cross->setfromoptionscalled = PETSC_FALSE;
    140:   }
    141:   EPSSetUp(cross->eps);
    142:   EPSGetDimensions(cross->eps,NULL,&svd->ncv,&svd->mpd);
    143:   EPSGetTolerances(cross->eps,&svd->tol,&svd->max_it);
    144:   /* Transfer the initial space from svd to eps */
    145:   if (svd->nini < 0) {
    146:     EPSSetInitialSpace(cross->eps,-svd->nini,svd->IS);
    147:     for (i=0;i<-svd->nini;i++) {
    148:       VecDestroy(&svd->IS[i]);
    149:     }
    150:     PetscFree(svd->IS);
    151:     svd->nini = 0;
    152:   }
    153:   return(0);
    154: }

    158: PetscErrorCode SVDSolve_Cross(SVD svd)
    159: {
    161:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    162:   PetscInt       i;
    163:   PetscScalar    sigma;

    166:   EPSSolve(cross->eps);
    167:   EPSGetConverged(cross->eps,&svd->nconv);
    168:   EPSGetIterationNumber(cross->eps,&svd->its);
    169:   EPSGetConvergedReason(cross->eps,(EPSConvergedReason*)&svd->reason);
    170:   for (i=0;i<svd->nconv;i++) {
    171:     EPSGetEigenpair(cross->eps,i,&sigma,NULL,svd->V[i],NULL);
    172:     if (PetscRealPart(sigma)<0.0) SETERRQ(PetscObjectComm((PetscObject)svd),1,"Negative eigenvalue computed by EPS");
    173:     svd->sigma[i] = PetscSqrtReal(PetscRealPart(sigma));
    174:   }
    175:   return(0);
    176: }

    180: static PetscErrorCode SVDMonitor_Cross(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
    181: {
    182:   PetscInt       i;
    183:   SVD            svd = (SVD)ctx;
    184:   PetscScalar    er,ei;

    188:   for (i=0;i<PetscMin(nest,svd->ncv);i++) {
    189:     er = eigr[i]; ei = eigi[i];
    190:     STBackTransform(eps->st,1,&er,&ei);
    191:     svd->sigma[i] = PetscSqrtReal(PetscRealPart(er));
    192:     svd->errest[i] = errest[i];
    193:   }
    194:   SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
    195:   return(0);
    196: }

    200: PetscErrorCode SVDSetFromOptions_Cross(SVD svd)
    201: {
    202:   SVD_CROSS *cross = (SVD_CROSS*)svd->data;

    205:   cross->setfromoptionscalled = PETSC_TRUE;
    206:   return(0);
    207: }

    211: static PetscErrorCode SVDCrossSetEPS_Cross(SVD svd,EPS eps)
    212: {
    214:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    217:   PetscObjectReference((PetscObject)eps);
    218:   EPSDestroy(&cross->eps);
    219:   cross->eps = eps;
    220:   PetscLogObjectParent(svd,cross->eps);
    221:   svd->setupcalled = 0;
    222:   return(0);
    223: }

    227: /*@
    228:    SVDCrossSetEPS - Associate an eigensolver object (EPS) to the
    229:    singular value solver.

    231:    Collective on SVD

    233:    Input Parameters:
    234: +  svd - singular value solver
    235: -  eps - the eigensolver object

    237:    Level: advanced

    239: .seealso: SVDCrossGetEPS()
    240: @*/
    241: PetscErrorCode SVDCrossSetEPS(SVD svd,EPS eps)
    242: {

    249:   PetscTryMethod(svd,"SVDCrossSetEPS_C",(SVD,EPS),(svd,eps));
    250:   return(0);
    251: }

    255: static PetscErrorCode SVDCrossGetEPS_Cross(SVD svd,EPS *eps)
    256: {
    257:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    258:   ST             st;

    262:   if (!cross->eps) {
    263:     EPSCreate(PetscObjectComm((PetscObject)svd),&cross->eps);
    264:     EPSSetOptionsPrefix(cross->eps,((PetscObject)svd)->prefix);
    265:     EPSAppendOptionsPrefix(cross->eps,"svd_");
    266:     PetscObjectIncrementTabLevel((PetscObject)cross->eps,(PetscObject)svd,1);
    267:     PetscLogObjectParent(svd,cross->eps);
    268:     if (!svd->ip) { SVDGetIP(svd,&svd->ip); }
    269:     EPSSetIP(cross->eps,svd->ip);
    270:     EPSSetWhichEigenpairs(cross->eps,EPS_LARGEST_REAL);
    271:     EPSMonitorSet(cross->eps,SVDMonitor_Cross,svd,NULL);
    272:     EPSGetST(cross->eps,&st);
    273:     STSetMatMode(st,ST_MATMODE_SHELL);
    274:   }
    275:   *eps = cross->eps;
    276:   return(0);
    277: }

    281: /*@
    282:    SVDCrossGetEPS - Retrieve the eigensolver object (EPS) associated
    283:    to the singular value solver.

    285:    Not Collective

    287:    Input Parameter:
    288: .  svd - singular value solver

    290:    Output Parameter:
    291: .  eps - the eigensolver object

    293:    Level: advanced

    295: .seealso: SVDCrossSetEPS()
    296: @*/
    297: PetscErrorCode SVDCrossGetEPS(SVD svd,EPS *eps)
    298: {

    304:   PetscTryMethod(svd,"SVDCrossGetEPS_C",(SVD,EPS*),(svd,eps));
    305:   return(0);
    306: }

    310: PetscErrorCode SVDView_Cross(SVD svd,PetscViewer viewer)
    311: {
    313:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    316:   if (!cross->eps) { SVDCrossGetEPS(svd,&cross->eps); }
    317:   PetscViewerASCIIPushTab(viewer);
    318:   EPSView(cross->eps,viewer);
    319:   PetscViewerASCIIPopTab(viewer);
    320:   return(0);
    321: }

    325: PetscErrorCode SVDReset_Cross(SVD svd)
    326: {
    328:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    331:   if (cross->eps) { EPSReset(cross->eps); }
    332:   MatDestroy(&cross->mat);
    333:   VecDestroy(&cross->w);
    334:   VecDestroy(&cross->diag);
    335:   return(0);
    336: }

    340: PetscErrorCode SVDDestroy_Cross(SVD svd)
    341: {
    343:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    346:   EPSDestroy(&cross->eps);
    347:   PetscFree(svd->data);
    348:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetEPS_C",NULL);
    349:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetEPS_C",NULL);
    350:   return(0);
    351: }

    355: PETSC_EXTERN PetscErrorCode SVDCreate_Cross(SVD svd)
    356: {
    358:   SVD_CROSS      *cross;

    361:   PetscNewLog(svd,SVD_CROSS,&cross);
    362:   svd->data                = (void*)cross;
    363:   svd->ops->solve          = SVDSolve_Cross;
    364:   svd->ops->setup          = SVDSetUp_Cross;
    365:   svd->ops->setfromoptions = SVDSetFromOptions_Cross;
    366:   svd->ops->destroy        = SVDDestroy_Cross;
    367:   svd->ops->reset          = SVDReset_Cross;
    368:   svd->ops->view           = SVDView_Cross;
    369:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetEPS_C",SVDCrossSetEPS_Cross);
    370:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetEPS_C",SVDCrossGetEPS_Cross);
    371:   return(0);
    372: }