Date: 2022-08-09T09:05:44+00:00

Actual source code: cross.c
slepc-3.17.2 2022-08-09
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    SLEPc singular value solver: "cross"

     13:    Method: Uses a Hermitian eigensolver for A^T*A
     14: */

     16: #include <slepc/private/svdimpl.h>
     17: #include <slepc/private/epsimpl.h>

     19: typedef struct {
     20:   PetscBool explicitmatrix;
     21:   EPS       eps;
     22:   PetscBool usereps;
     23:   Mat       C,D;
     24: } SVD_CROSS;

     26: typedef struct {
     27:   Mat       A,AT;
     28:   Vec       w,diag;
     29:   PetscBool swapped;
     30: } SVD_CROSS_SHELL;

     32: static PetscErrorCode MatMult_Cross(Mat B,Vec x,Vec y)
     33: {
     34:   SVD_CROSS_SHELL *ctx;

     36:   MatShellGetContext(B,&ctx);
     37:   MatMult(ctx->A,x,ctx->w);
     38:   MatMult(ctx->AT,ctx->w,y);
     39:   PetscFunctionReturn(0);
     40: }

     42: static PetscErrorCode MatGetDiagonal_Cross(Mat B,Vec d)
     43: {
     44:   SVD_CROSS_SHELL   *ctx;
     45:   PetscMPIInt       len;
     46:   PetscInt          N,n,i,j,start,end,ncols;
     47:   PetscScalar       *work1,*work2,*diag;
     48:   const PetscInt    *cols;
     49:   const PetscScalar *vals;

     51:   MatShellGetContext(B,&ctx);
     52:   if (!ctx->diag) {
     53:     /* compute diagonal from rows and store in ctx->diag */
     54:     VecDuplicate(d,&ctx->diag);
     55:     MatGetSize(ctx->A,NULL,&N);
     56:     MatGetLocalSize(ctx->A,NULL,&n);
     57:     PetscCalloc2(N,&work1,N,&work2);
     58:     if (ctx->swapped) {
     59:       MatGetOwnershipRange(ctx->AT,&start,&end);
     60:       for (i=start;i<end;i++) {
     61:         MatGetRow(ctx->AT,i,&ncols,NULL,&vals);
     62:         for (j=0;j<ncols;j++) work1[i] += vals[j]*vals[j];
     63:         MatRestoreRow(ctx->AT,i,&ncols,NULL,&vals);
     64:       }
     65:     } else {
     66:       MatGetOwnershipRange(ctx->A,&start,&end);
     67:       for (i=start;i<end;i++) {
     68:         MatGetRow(ctx->A,i,&ncols,&cols,&vals);
     69:         for (j=0;j<ncols;j++) work1[cols[j]] += vals[j]*vals[j];
     70:         MatRestoreRow(ctx->A,i,&ncols,&cols,&vals);
     71:       }
     72:     }
     73:     PetscMPIIntCast(N,&len);
     74:     MPIU_Allreduce(work1,work2,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)B));
     75:     VecGetOwnershipRange(ctx->diag,&start,&end);
     76:     VecGetArrayWrite(ctx->diag,&diag);
     77:     for (i=start;i<end;i++) diag[i-start] = work2[i];
     78:     VecRestoreArrayWrite(ctx->diag,&diag);
     79:     PetscFree2(work1,work2);
     80:   }
     81:   VecCopy(ctx->diag,d);
     82:   PetscFunctionReturn(0);
     83: }

     85: static PetscErrorCode MatDestroy_Cross(Mat B)
     86: {
     87:   SVD_CROSS_SHELL *ctx;

     89:   MatShellGetContext(B,&ctx);
     90:   VecDestroy(&ctx->w);
     91:   VecDestroy(&ctx->diag);
     92:   PetscFree(ctx);
     93:   PetscFunctionReturn(0);
     94: }

     96: static PetscErrorCode SVDCrossGetProductMat(SVD svd,Mat A,Mat AT,Mat *C)
     97: {
     98:   SVD_CROSS       *cross = (SVD_CROSS*)svd->data;
     99:   SVD_CROSS_SHELL *ctx;
    100:   PetscInt        n;
    101:   VecType         vtype;

    103:   if (cross->explicitmatrix) {
    104:     if (svd->expltrans) {  /* explicit transpose */
    105:       MatProductCreate(AT,A,NULL,C);
    106:       MatProductSetType(*C,MATPRODUCT_AB);
    107:     } else {  /* implicit transpose */
    108: #if defined(PETSC_USE_COMPLEX)
    109:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Must use explicit transpose with complex scalars");
    110: #else
    111:       if (!svd->swapped) {
    112:         MatProductCreate(A,A,NULL,C);
    113:         MatProductSetType(*C,MATPRODUCT_AtB);
    114:       } else {
    115:         MatProductCreate(AT,AT,NULL,C);
    116:         MatProductSetType(*C,MATPRODUCT_ABt);
    117:       }
    118: #endif
    119:     }
    120:     MatProductSetFromOptions(*C);
    121:     MatProductSymbolic(*C);
    122:     MatProductNumeric(*C);
    123:   } else {
    124:     PetscNew(&ctx);
    125:     ctx->A       = A;
    126:     ctx->AT      = AT;
    127:     ctx->swapped = svd->swapped;
    128:     MatCreateVecs(A,NULL,&ctx->w);
    129:     PetscLogObjectParent((PetscObject)svd,(PetscObject)ctx->w);
    130:     MatGetLocalSize(A,NULL,&n);
    131:     MatCreateShell(PetscObjectComm((PetscObject)svd),n,n,PETSC_DETERMINE,PETSC_DETERMINE,(void*)ctx,C);
    132:     MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cross);
    133:     MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cross);
    134:     MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_Cross);
    135:     MatGetVecType(A,&vtype);
    136:     MatSetVecType(*C,vtype);
    137:   }
    138:   PetscLogObjectParent((PetscObject)svd,(PetscObject)*C);
    139:   PetscFunctionReturn(0);
    140: }

    142: /* Convergence test relative to the norm of R (used in GSVD only) */
    143: static PetscErrorCode EPSConv_Cross(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
    144: {
    145:   SVD svd = (SVD)ctx;

    147:   *errest = res/PetscMax(svd->nrma,svd->nrmb);
    148:   PetscFunctionReturn(0);
    149: }

    151: PetscErrorCode SVDSetUp_Cross(SVD svd)
    152: {
    153:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    154:   ST             st;
    155:   PetscBool      trackall,issinv;
    156:   EPSProblemType ptype;

    158:   if (!cross->eps) SVDCrossGetEPS(svd,&cross->eps);
    159:   MatDestroy(&cross->C);
    160:   MatDestroy(&cross->D);
    161:   SVDCrossGetProductMat(svd,svd->A,svd->AT,&cross->C);
    162:   if (svd->isgeneralized) {
    163:     SVDCrossGetProductMat(svd,svd->B,svd->BT,&cross->D);
    164:     EPSSetOperators(cross->eps,cross->C,cross->D);
    165:     EPSGetProblemType(cross->eps,&ptype);
    166:     if (!ptype) EPSSetProblemType(cross->eps,EPS_GHEP);
    167:   } else {
    168:     EPSSetOperators(cross->eps,cross->C,NULL);
    169:     EPSSetProblemType(cross->eps,EPS_HEP);
    170:   }
    171:   if (!cross->usereps) {
    172:     EPSGetST(cross->eps,&st);
    173:     if (svd->isgeneralized && svd->which==SVD_SMALLEST) {
    174:       STSetType(st,STSINVERT);
    175:       EPSSetTarget(cross->eps,0.0);
    176:       EPSSetWhichEigenpairs(cross->eps,EPS_TARGET_REAL);
    177:     } else {
    178:       PetscObjectTypeCompare((PetscObject)st,STSINVERT,&issinv);
    179:       if (issinv) EPSSetWhichEigenpairs(cross->eps,EPS_TARGET_MAGNITUDE);
    180:       else EPSSetWhichEigenpairs(cross->eps,svd->which==SVD_LARGEST?EPS_LARGEST_REAL:EPS_SMALLEST_REAL);
    181:     }
    182:     EPSSetDimensions(cross->eps,svd->nsv,svd->ncv,svd->mpd);
    183:     EPSSetTolerances(cross->eps,svd->tol==PETSC_DEFAULT?SLEPC_DEFAULT_TOL/10.0:svd->tol,svd->max_it);
    184:     switch (svd->conv) {
    185:     case SVD_CONV_ABS:
    186:       EPSSetConvergenceTest(cross->eps,EPS_CONV_ABS);break;
    187:     case SVD_CONV_REL:
    188:       EPSSetConvergenceTest(cross->eps,EPS_CONV_REL);break;
    189:     case SVD_CONV_NORM:
    190:       if (svd->isgeneralized) {
    191:         if (!svd->nrma) MatNorm(svd->OP,NORM_INFINITY,&svd->nrma);
    192:         if (!svd->nrmb) MatNorm(svd->OPb,NORM_INFINITY,&svd->nrmb);
    193:         EPSSetConvergenceTestFunction(cross->eps,EPSConv_Cross,svd,NULL);
    194:       } else {
    195:         EPSSetConvergenceTest(cross->eps,EPS_CONV_NORM);break;
    196:       }
    197:       break;
    198:     case SVD_CONV_MAXIT:
    199:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Maxit convergence test not supported in this solver");
    200:     case SVD_CONV_USER:
    201:       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined convergence test not supported in this solver");
    202:     }
    203:   }
    204:   SVDCheckUnsupported(svd,SVD_FEATURE_STOPPING);
    205:   /* Transfer the trackall option from svd to eps */
    206:   SVDGetTrackAll(svd,&trackall);
    207:   EPSSetTrackAll(cross->eps,trackall);
    208:   /* Transfer the initial space from svd to eps */
    209:   if (svd->nini<0) {
    210:     EPSSetInitialSpace(cross->eps,-svd->nini,svd->IS);
    211:     SlepcBasisDestroy_Private(&svd->nini,&svd->IS);
    212:   }
    213:   EPSSetUp(cross->eps);
    214:   EPSGetDimensions(cross->eps,NULL,&svd->ncv,&svd->mpd);
    215:   EPSGetTolerances(cross->eps,NULL,&svd->max_it);
    216:   if (svd->tol==PETSC_DEFAULT) svd->tol = SLEPC_DEFAULT_TOL;

    218:   svd->leftbasis = PETSC_FALSE;
    219:   SVDAllocateSolution(svd,0);
    220:   PetscFunctionReturn(0);
    221: }

    223: PetscErrorCode SVDSolve_Cross(SVD svd)
    224: {
    225:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    226:   PetscInt       i;
    227:   PetscScalar    lambda;
    228:   PetscReal      sigma;

    230:   EPSSolve(cross->eps);
    231:   EPSGetConverged(cross->eps,&svd->nconv);
    232:   EPSGetIterationNumber(cross->eps,&svd->its);
    233:   EPSGetConvergedReason(cross->eps,(EPSConvergedReason*)&svd->reason);
    234:   for (i=0;i<svd->nconv;i++) {
    235:     EPSGetEigenvalue(cross->eps,i,&lambda,NULL);
    236:     sigma = PetscRealPart(lambda);
    238:     if (sigma<0.0) {
    239:       PetscInfo(svd,"Negative eigenvalue computed by EPS: %g, resetting to 0\n",(double)sigma);
    240:       sigma = 0.0;
    241:     }
    242:     svd->sigma[i] = PetscSqrtReal(sigma);
    243:   }
    244:   PetscFunctionReturn(0);
    245: }

    247: PetscErrorCode SVDComputeVectors_Cross(SVD svd)
    248: {
    249:   SVD_CROSS         *cross = (SVD_CROSS*)svd->data;
    250:   PetscInt          i,mloc,ploc;
    251:   Vec               u,v,x,uv;
    252:   PetscScalar       *dst,alpha,lambda;
    253:   const PetscScalar *src;
    254:   PetscReal         nrm;

    256:   if (svd->isgeneralized) {
    257:     MatCreateVecs(svd->A,NULL,&u);
    258:     VecGetLocalSize(u,&mloc);
    259:     MatCreateVecs(svd->B,NULL,&v);
    260:     VecGetLocalSize(v,&ploc);
    261:     for (i=0;i<svd->nconv;i++) {
    262:       BVGetColumn(svd->V,i,&x);
    263:       EPSGetEigenpair(cross->eps,i,&lambda,NULL,x,NULL);
    264:       MatMult(svd->A,x,u);     /* u_i*c_i/alpha = A*x_i */
    265:       VecNormalize(u,NULL);
    266:       MatMult(svd->B,x,v);     /* v_i*s_i/alpha = B*x_i */
    267:       VecNormalize(v,&nrm);    /* ||v||_2 = s_i/alpha   */
    268:       alpha = 1.0/(PetscSqrtReal(1.0+PetscRealPart(lambda))*nrm);    /* alpha=s_i/||v||_2 */
    269:       VecScale(x,alpha);
    270:       BVRestoreColumn(svd->V,i,&x);
    271:       /* copy [u;v] to U[i] */
    272:       BVGetColumn(svd->U,i,&uv);
    273:       VecGetArrayWrite(uv,&dst);
    274:       VecGetArrayRead(u,&src);
    275:       PetscArraycpy(dst,src,mloc);
    276:       VecRestoreArrayRead(u,&src);
    277:       VecGetArrayRead(v,&src);
    278:       PetscArraycpy(dst+mloc,src,ploc);
    279:       VecRestoreArrayRead(v,&src);
    280:       VecRestoreArrayWrite(uv,&dst);
    281:       BVRestoreColumn(svd->U,i,&uv);
    282:     }
    283:     VecDestroy(&v);
    284:     VecDestroy(&u);
    285:   } else {
    286:     for (i=0;i<svd->nconv;i++) {
    287:       BVGetColumn(svd->V,i,&v);
    288:       EPSGetEigenvector(cross->eps,i,v,NULL);
    289:       BVRestoreColumn(svd->V,i,&v);
    290:     }
    291:     SVDComputeVectors_Left(svd);
    292:   }
    293:   PetscFunctionReturn(0);
    294: }

    296: static PetscErrorCode EPSMonitor_Cross(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
    297: {
    298:   PetscInt       i;
    299:   SVD            svd = (SVD)ctx;
    300:   PetscScalar    er,ei;

    302:   for (i=0;i<PetscMin(nest,svd->ncv);i++) {
    303:     er = eigr[i]; ei = eigi[i];
    304:     STBackTransform(eps->st,1,&er,&ei);
    305:     svd->sigma[i] = PetscSqrtReal(PetscAbsReal(PetscRealPart(er)));
    306:     svd->errest[i] = errest[i];
    307:   }
    308:   SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest);
    309:   PetscFunctionReturn(0);
    310: }

    312: PetscErrorCode SVDSetFromOptions_Cross(PetscOptionItems *PetscOptionsObject,SVD svd)
    313: {
    314:   PetscBool      set,val;
    315:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    316:   ST             st;

    318:   PetscOptionsHead(PetscOptionsObject,"SVD Cross Options");

    320:     PetscOptionsBool("-svd_cross_explicitmatrix","Use cross explicit matrix","SVDCrossSetExplicitMatrix",cross->explicitmatrix,&val,&set);
    321:     if (set) SVDCrossSetExplicitMatrix(svd,val);

    323:   PetscOptionsTail();

    325:   if (!cross->eps) SVDCrossGetEPS(svd,&cross->eps);
    326:   if (!cross->explicitmatrix && !cross->usereps) {
    327:     /* use as default an ST with shell matrix and Jacobi */
    328:     EPSGetST(cross->eps,&st);
    329:     STSetMatMode(st,ST_MATMODE_SHELL);
    330:   }
    331:   EPSSetFromOptions(cross->eps);
    332:   PetscFunctionReturn(0);
    333: }

    335: static PetscErrorCode SVDCrossSetExplicitMatrix_Cross(SVD svd,PetscBool explicitmatrix)
    336: {
    337:   SVD_CROSS *cross = (SVD_CROSS*)svd->data;

    339:   if (cross->explicitmatrix != explicitmatrix) {
    340:     cross->explicitmatrix = explicitmatrix;
    341:     svd->state = SVD_STATE_INITIAL;
    342:   }
    343:   PetscFunctionReturn(0);
    344: }

    346: /*@
    347:    SVDCrossSetExplicitMatrix - Indicate if the eigensolver operator A^T*A must
    348:    be computed explicitly.

    350:    Logically Collective on svd

    352:    Input Parameters:
    353: +  svd         - singular value solver
    354: -  explicitmat - boolean flag indicating if A^T*A is built explicitly

    356:    Options Database Key:
    357: .  -svd_cross_explicitmatrix <boolean> - Indicates the boolean flag

    359:    Level: advanced

    361: .seealso: SVDCrossGetExplicitMatrix()
    362: @*/
    363: PetscErrorCode SVDCrossSetExplicitMatrix(SVD svd,PetscBool explicitmat)
    364: {
    367:   PetscTryMethod(svd,"SVDCrossSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmat));
    368:   PetscFunctionReturn(0);
    369: }

    371: static PetscErrorCode SVDCrossGetExplicitMatrix_Cross(SVD svd,PetscBool *explicitmat)
    372: {
    373:   SVD_CROSS *cross = (SVD_CROSS*)svd->data;

    375:   *explicitmat = cross->explicitmatrix;
    376:   PetscFunctionReturn(0);
    377: }

    379: /*@
    380:    SVDCrossGetExplicitMatrix - Returns the flag indicating if A^T*A is built explicitly.

    382:    Not Collective

    384:    Input Parameter:
    385: .  svd  - singular value solver

    387:    Output Parameter:
    388: .  explicitmat - the mode flag

    390:    Level: advanced

    392: .seealso: SVDCrossSetExplicitMatrix()
    393: @*/
    394: PetscErrorCode SVDCrossGetExplicitMatrix(SVD svd,PetscBool *explicitmat)
    395: {
    398:   PetscUseMethod(svd,"SVDCrossGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmat));
    399:   PetscFunctionReturn(0);
    400: }

    402: static PetscErrorCode SVDCrossSetEPS_Cross(SVD svd,EPS eps)
    403: {
    404:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    406:   PetscObjectReference((PetscObject)eps);
    407:   EPSDestroy(&cross->eps);
    408:   cross->eps = eps;
    409:   cross->usereps = PETSC_TRUE;
    410:   PetscLogObjectParent((PetscObject)svd,(PetscObject)cross->eps);
    411:   svd->state = SVD_STATE_INITIAL;
    412:   PetscFunctionReturn(0);
    413: }

    415: /*@
    416:    SVDCrossSetEPS - Associate an eigensolver object (EPS) to the
    417:    singular value solver.

    419:    Collective on svd

    421:    Input Parameters:
    422: +  svd - singular value solver
    423: -  eps - the eigensolver object

    425:    Level: advanced

    427: .seealso: SVDCrossGetEPS()
    428: @*/
    429: PetscErrorCode SVDCrossSetEPS(SVD svd,EPS eps)
    430: {
    434:   PetscTryMethod(svd,"SVDCrossSetEPS_C",(SVD,EPS),(svd,eps));
    435:   PetscFunctionReturn(0);
    436: }

    438: static PetscErrorCode SVDCrossGetEPS_Cross(SVD svd,EPS *eps)
    439: {
    440:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    442:   if (!cross->eps) {
    443:     EPSCreate(PetscObjectComm((PetscObject)svd),&cross->eps);
    444:     PetscObjectIncrementTabLevel((PetscObject)cross->eps,(PetscObject)svd,1);
    445:     EPSSetOptionsPrefix(cross->eps,((PetscObject)svd)->prefix);
    446:     EPSAppendOptionsPrefix(cross->eps,"svd_cross_");
    447:     PetscLogObjectParent((PetscObject)svd,(PetscObject)cross->eps);
    448:     PetscObjectSetOptions((PetscObject)cross->eps,((PetscObject)svd)->options);
    449:     EPSSetWhichEigenpairs(cross->eps,EPS_LARGEST_REAL);
    450:     EPSMonitorSet(cross->eps,EPSMonitor_Cross,svd,NULL);
    451:   }
    452:   *eps = cross->eps;
    453:   PetscFunctionReturn(0);
    454: }

    456: /*@
    457:    SVDCrossGetEPS - Retrieve the eigensolver object (EPS) associated
    458:    to the singular value solver.

    460:    Not Collective

    462:    Input Parameter:
    463: .  svd - singular value solver

    465:    Output Parameter:
    466: .  eps - the eigensolver object

    468:    Level: advanced

    470: .seealso: SVDCrossSetEPS()
    471: @*/
    472: PetscErrorCode SVDCrossGetEPS(SVD svd,EPS *eps)
    473: {
    476:   PetscUseMethod(svd,"SVDCrossGetEPS_C",(SVD,EPS*),(svd,eps));
    477:   PetscFunctionReturn(0);
    478: }

    480: PetscErrorCode SVDView_Cross(SVD svd,PetscViewer viewer)
    481: {
    482:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;
    483:   PetscBool      isascii;

    485:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
    486:   if (isascii) {
    487:     if (!cross->eps) SVDCrossGetEPS(svd,&cross->eps);
    488:     PetscViewerASCIIPrintf(viewer,"  %s matrix\n",cross->explicitmatrix?"explicit":"implicit");
    489:     PetscViewerASCIIPushTab(viewer);
    490:     EPSView(cross->eps,viewer);
    491:     PetscViewerASCIIPopTab(viewer);
    492:   }
    493:   PetscFunctionReturn(0);
    494: }

    496: PetscErrorCode SVDReset_Cross(SVD svd)
    497: {
    498:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    500:   EPSReset(cross->eps);
    501:   MatDestroy(&cross->C);
    502:   MatDestroy(&cross->D);
    503:   PetscFunctionReturn(0);
    504: }

    506: PetscErrorCode SVDDestroy_Cross(SVD svd)
    507: {
    508:   SVD_CROSS      *cross = (SVD_CROSS*)svd->data;

    510:   EPSDestroy(&cross->eps);
    511:   PetscFree(svd->data);
    512:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetEPS_C",NULL);
    513:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetEPS_C",NULL);
    514:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetExplicitMatrix_C",NULL);
    515:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetExplicitMatrix_C",NULL);
    516:   PetscFunctionReturn(0);
    517: }

    519: SLEPC_EXTERN PetscErrorCode SVDCreate_Cross(SVD svd)
    520: {
    521:   SVD_CROSS      *cross;

    523:   PetscNewLog(svd,&cross);
    524:   svd->data = (void*)cross;

    526:   svd->ops->solve          = SVDSolve_Cross;
    527:   svd->ops->solveg         = SVDSolve_Cross;
    528:   svd->ops->setup          = SVDSetUp_Cross;
    529:   svd->ops->setfromoptions = SVDSetFromOptions_Cross;
    530:   svd->ops->destroy        = SVDDestroy_Cross;
    531:   svd->ops->reset          = SVDReset_Cross;
    532:   svd->ops->view           = SVDView_Cross;
    533:   svd->ops->computevectors = SVDComputeVectors_Cross;
    534:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetEPS_C",SVDCrossSetEPS_Cross);
    535:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetEPS_C",SVDCrossGetEPS_Cross);
    536:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossSetExplicitMatrix_C",SVDCrossSetExplicitMatrix_Cross);
    537:   PetscObjectComposeFunction((PetscObject)svd,"SVDCrossGetExplicitMatrix_C",SVDCrossGetExplicitMatrix_Cross);
    538:   PetscFunctionReturn(0);
    539: }