Date: 2026-03-31T13:23:03+00:00

Actual source code: linear.c

      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:    Explicit linearization for polynomial eigenproblems
     12: */

     14: #include <slepc/private/pepimpl.h>
     15: #include "linear.h"

     17: static PetscErrorCode MatMult_Linear_Shift(Mat M,Vec x,Vec y)
     18: {
     19:   PEP_LINEAR        *ctx;
     20:   PEP               pep;
     21:   const PetscScalar *px;
     22:   PetscScalar       *py,a,sigma=0.0;
     23:   PetscInt          nmat,deg,i,m;
     24:   Vec               x1,x2,x3,y1,aux;
     25:   PetscReal         *ca,*cb,*cg;
     26:   PetscBool         flg;

     28:   PetscFunctionBegin;
     29:   PetscCall(MatShellGetContext(M,&ctx));
     30:   pep = ctx->pep;
     31:   PetscCall(STGetTransform(pep->st,&flg));
     32:   if (!flg) PetscCall(STGetShift(pep->st,&sigma));
     33:   nmat = pep->nmat;
     34:   deg = nmat-1;
     35:   m = pep->nloc;
     36:   ca = pep->pbc;
     37:   cb = pep->pbc+nmat;
     38:   cg = pep->pbc+2*nmat;
     39:   x1=ctx->w[0];x2=ctx->w[1];x3=ctx->w[2];y1=ctx->w[3];aux=ctx->w[4];

     41:   PetscCall(VecSet(y,0.0));
     42:   PetscCall(VecGetArrayRead(x,&px));
     43:   PetscCall(VecGetArray(y,&py));
     44:   a = 1.0;

     46:   /* first block */
     47:   PetscCall(VecPlaceArray(x2,px));
     48:   PetscCall(VecPlaceArray(x3,px+m));
     49:   PetscCall(VecPlaceArray(y1,py));
     50:   PetscCall(VecAXPY(y1,cb[0]-sigma,x2));
     51:   PetscCall(VecAXPY(y1,ca[0],x3));
     52:   PetscCall(VecResetArray(x2));
     53:   PetscCall(VecResetArray(x3));
     54:   PetscCall(VecResetArray(y1));

     56:   /* inner blocks */
     57:   for (i=1;i<deg-1;i++) {
     58:     PetscCall(VecPlaceArray(x1,px+(i-1)*m));
     59:     PetscCall(VecPlaceArray(x2,px+i*m));
     60:     PetscCall(VecPlaceArray(x3,px+(i+1)*m));
     61:     PetscCall(VecPlaceArray(y1,py+i*m));
     62:     PetscCall(VecAXPY(y1,cg[i],x1));
     63:     PetscCall(VecAXPY(y1,cb[i]-sigma,x2));
     64:     PetscCall(VecAXPY(y1,ca[i],x3));
     65:     PetscCall(VecResetArray(x1));
     66:     PetscCall(VecResetArray(x2));
     67:     PetscCall(VecResetArray(x3));
     68:     PetscCall(VecResetArray(y1));
     69:   }

     71:   /* last block */
     72:   PetscCall(VecPlaceArray(y1,py+(deg-1)*m));
     73:   for (i=0;i<deg;i++) {
     74:     PetscCall(VecPlaceArray(x1,px+i*m));
     75:     PetscCall(STMatMult(pep->st,i,x1,aux));
     76:     PetscCall(VecAXPY(y1,a,aux));
     77:     PetscCall(VecResetArray(x1));
     78:     a *= pep->sfactor;
     79:   }
     80:   PetscCall(VecCopy(y1,aux));
     81:   PetscCall(STMatSolve(pep->st,aux,y1));
     82:   PetscCall(VecScale(y1,-ca[deg-1]/a));
     83:   PetscCall(VecPlaceArray(x1,px+(deg-2)*m));
     84:   PetscCall(VecPlaceArray(x2,px+(deg-1)*m));
     85:   PetscCall(VecAXPY(y1,cg[deg-1],x1));
     86:   PetscCall(VecAXPY(y1,cb[deg-1]-sigma,x2));
     87:   PetscCall(VecResetArray(x1));
     88:   PetscCall(VecResetArray(x2));
     89:   PetscCall(VecResetArray(y1));

     91:   PetscCall(VecRestoreArrayRead(x,&px));
     92:   PetscCall(VecRestoreArray(y,&py));
     93:   PetscFunctionReturn(PETSC_SUCCESS);
     94: }

     96: static PetscErrorCode MatMult_Linear_Sinvert(Mat M,Vec x,Vec y)
     97: {
     98:   PEP_LINEAR        *ctx;
     99:   PEP               pep;
    100:   const PetscScalar *px;
    101:   PetscScalar       *py,a,sigma,t=1.0,tp=0.0,tt;
    102:   PetscInt          nmat,deg,i,m;
    103:   Vec               x1,y1,y2,y3,aux,aux2;
    104:   PetscReal         *ca,*cb,*cg;

    106:   PetscFunctionBegin;
    107:   PetscCall(MatShellGetContext(M,&ctx));
    108:   pep = ctx->pep;
    109:   nmat = pep->nmat;
    110:   deg = nmat-1;
    111:   m = pep->nloc;
    112:   ca = pep->pbc;
    113:   cb = pep->pbc+nmat;
    114:   cg = pep->pbc+2*nmat;
    115:   x1=ctx->w[0];y1=ctx->w[1];y2=ctx->w[2];y3=ctx->w[3];aux=ctx->w[4];aux2=ctx->w[5];
    116:   PetscCall(EPSGetTarget(ctx->eps,&sigma));
    117:   PetscCall(VecSet(y,0.0));
    118:   PetscCall(VecGetArrayRead(x,&px));
    119:   PetscCall(VecGetArray(y,&py));
    120:   a = pep->sfactor;

    122:   /* first block */
    123:   PetscCall(VecPlaceArray(x1,px));
    124:   PetscCall(VecPlaceArray(y1,py+m));
    125:   PetscCall(VecCopy(x1,y1));
    126:   PetscCall(VecScale(y1,1.0/ca[0]));
    127:   PetscCall(VecResetArray(x1));
    128:   PetscCall(VecResetArray(y1));

    130:   /* second block */
    131:   if (deg>2) {
    132:     PetscCall(VecPlaceArray(x1,px+m));
    133:     PetscCall(VecPlaceArray(y1,py+m));
    134:     PetscCall(VecPlaceArray(y2,py+2*m));
    135:     PetscCall(VecCopy(x1,y2));
    136:     PetscCall(VecAXPY(y2,sigma-cb[1],y1));
    137:     PetscCall(VecScale(y2,1.0/ca[1]));
    138:     PetscCall(VecResetArray(x1));
    139:     PetscCall(VecResetArray(y1));
    140:     PetscCall(VecResetArray(y2));
    141:   }

    143:   /* inner blocks */
    144:   for (i=2;i<deg-1;i++) {
    145:     PetscCall(VecPlaceArray(x1,px+i*m));
    146:     PetscCall(VecPlaceArray(y1,py+(i-1)*m));
    147:     PetscCall(VecPlaceArray(y2,py+i*m));
    148:     PetscCall(VecPlaceArray(y3,py+(i+1)*m));
    149:     PetscCall(VecCopy(x1,y3));
    150:     PetscCall(VecAXPY(y3,sigma-cb[i],y2));
    151:     PetscCall(VecAXPY(y3,-cg[i],y1));
    152:     PetscCall(VecScale(y3,1.0/ca[i]));
    153:     PetscCall(VecResetArray(x1));
    154:     PetscCall(VecResetArray(y1));
    155:     PetscCall(VecResetArray(y2));
    156:     PetscCall(VecResetArray(y3));
    157:   }

    159:   /* last block */
    160:   PetscCall(VecPlaceArray(y1,py));
    161:   for (i=0;i<deg-2;i++) {
    162:     PetscCall(VecPlaceArray(y2,py+(i+1)*m));
    163:     PetscCall(STMatMult(pep->st,i+1,y2,aux));
    164:     PetscCall(VecAXPY(y1,a,aux));
    165:     PetscCall(VecResetArray(y2));
    166:     a *= pep->sfactor;
    167:   }
    168:   i = deg-2;
    169:   PetscCall(VecPlaceArray(y2,py+(i+1)*m));
    170:   PetscCall(VecPlaceArray(y3,py+i*m));
    171:   PetscCall(VecCopy(y2,aux2));
    172:   PetscCall(VecAXPY(aux2,cg[i+1]/ca[i+1],y3));
    173:   PetscCall(STMatMult(pep->st,i+1,aux2,aux));
    174:   PetscCall(VecAXPY(y1,a,aux));
    175:   PetscCall(VecResetArray(y2));
    176:   PetscCall(VecResetArray(y3));
    177:   a *= pep->sfactor;
    178:   i = deg-1;
    179:   PetscCall(VecPlaceArray(x1,px+i*m));
    180:   PetscCall(VecPlaceArray(y3,py+i*m));
    181:   PetscCall(VecCopy(x1,aux2));
    182:   PetscCall(VecAXPY(aux2,sigma-cb[i],y3));
    183:   PetscCall(VecScale(aux2,1.0/ca[i]));
    184:   PetscCall(STMatMult(pep->st,i+1,aux2,aux));
    185:   PetscCall(VecAXPY(y1,a,aux));
    186:   PetscCall(VecResetArray(x1));
    187:   PetscCall(VecResetArray(y3));

    189:   PetscCall(VecCopy(y1,aux));
    190:   PetscCall(STMatSolve(pep->st,aux,y1));
    191:   PetscCall(VecScale(y1,-1.0));

    193:   /* final update */
    194:   for (i=1;i<deg;i++) {
    195:     PetscCall(VecPlaceArray(y2,py+i*m));
    196:     tt = t;
    197:     t = ((sigma-cb[i-1])*t-cg[i-1]*tp)/ca[i-1]; /* i-th basis polynomial */
    198:     tp = tt;
    199:     PetscCall(VecAXPY(y2,t,y1));
    200:     PetscCall(VecResetArray(y2));
    201:   }
    202:   PetscCall(VecResetArray(y1));

    204:   PetscCall(VecRestoreArrayRead(x,&px));
    205:   PetscCall(VecRestoreArray(y,&py));
    206:   PetscFunctionReturn(PETSC_SUCCESS);
    207: }

    209: static PetscErrorCode BackTransform_Linear(ST st,PetscInt n,PetscScalar *eigr,PetscScalar *eigi)
    210: {
    211:   PEP_LINEAR     *ctx;
    212:   ST             stctx;

    214:   PetscFunctionBegin;
    215:   PetscCall(STShellGetContext(st,&ctx));
    216:   PetscCall(PEPGetST(ctx->pep,&stctx));
    217:   PetscCall(STBackTransform(stctx,n,eigr,eigi));
    218:   PetscFunctionReturn(PETSC_SUCCESS);
    219: }

    221: /*
    222:    Dummy backtransform operation
    223:  */
    224: static PetscErrorCode BackTransform_Skip(ST st,PetscInt n,PetscScalar *eigr,PetscScalar *eigi)
    225: {
    226:   PetscFunctionBegin;
    227:   PetscFunctionReturn(PETSC_SUCCESS);
    228: }

    230: static PetscErrorCode Apply_Linear(ST st,Vec x,Vec y)
    231: {
    232:   PEP_LINEAR     *ctx;

    234:   PetscFunctionBegin;
    235:   PetscCall(STShellGetContext(st,&ctx));
    236:   PetscCall(MatMult(ctx->A,x,y));
    237:   PetscFunctionReturn(PETSC_SUCCESS);
    238: }

    240: static PetscErrorCode PEPSetUp_Linear(PEP pep)
    241: {
    242:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;
    243:   ST             st;
    244:   PetscInt       i=0,deg=pep->nmat-1;
    245:   EPSWhich       which = EPS_LARGEST_MAGNITUDE;
    246:   EPSProblemType ptype;
    247:   PetscBool      trackall,istrivial,transf,sinv,ks;
    248:   PetscScalar    sigma,*epsarray,*peparray;
    249:   Vec            veps,w=NULL;
    250:   /* function tables */
    251:   PetscErrorCode (*fcreate[][2])(MPI_Comm,PEP_LINEAR*,Mat*) = {
    252:     { MatCreateExplicit_Linear_NA, MatCreateExplicit_Linear_NB },
    253:     { MatCreateExplicit_Linear_SA, MatCreateExplicit_Linear_SB },
    254:     { MatCreateExplicit_Linear_HA, MatCreateExplicit_Linear_HB },
    255:   };

    257:   PetscFunctionBegin;
    258:   PEPCheckShiftSinvert(pep);
    259:   PEPCheckUnsupported(pep,PEP_FEATURE_STOPPING);
    260:   PEPCheckIgnored(pep,PEP_FEATURE_CONVERGENCE);
    261:   PetscCall(STGetTransform(pep->st,&transf));
    262:   PetscCall(PetscObjectTypeCompare((PetscObject)pep->st,STSINVERT,&sinv));
    263:   if (!pep->which) PetscCall(PEPSetWhichEigenpairs_Default(pep));
    264:   PetscCheck(pep->which!=PEP_ALL,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"This solver does not support computing all eigenvalues");
    265:   PetscCall(STSetUp(pep->st));
    266:   if (!ctx->eps) PetscCall(PEPLinearGetEPS(pep,&ctx->eps));
    267:   PetscCall(EPSGetST(ctx->eps,&st));
    268:   if (!transf && !ctx->usereps) PetscCall(EPSSetTarget(ctx->eps,pep->target));
    269:   if (sinv && !transf && !ctx->usereps) PetscCall(STSetDefaultShift(st,pep->target));
    270:   /* compute scale factor if not set by user */
    271:   PetscCall(PEPComputeScaleFactor(pep));

    273:   if (ctx->explicitmatrix) {
    274:     PEPCheckQuadraticCondition(pep,PETSC_TRUE," (with explicit matrix)");
    275:     PEPCheckUnsupportedCondition(pep,PEP_FEATURE_NONMONOMIAL,PETSC_TRUE," (with explicit matrix)");
    276:     PetscCheck(!transf,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Explicit matrix option is not implemented with st-transform flag active");
    277:     PetscCheck(pep->scale!=PEP_SCALE_DIAGONAL && pep->scale!=PEP_SCALE_BOTH,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Diagonal scaling not allowed in PEPLINEAR with explicit matrices");
    278:     if (sinv && !transf) PetscCall(STSetType(st,STSINVERT));
    279:     PetscCall(RGPushScale(pep->rg,1.0/pep->sfactor));
    280:     PetscCall(STGetMatrixTransformed(pep->st,0,&ctx->K));
    281:     PetscCall(STGetMatrixTransformed(pep->st,1,&ctx->C));
    282:     PetscCall(STGetMatrixTransformed(pep->st,2,&ctx->M));
    283:     ctx->sfactor = pep->sfactor;
    284:     ctx->dsfactor = pep->dsfactor;

    286:     PetscCall(MatDestroy(&ctx->A));
    287:     PetscCall(MatDestroy(&ctx->B));
    288:     PetscCall(VecDestroy(&ctx->w[0]));
    289:     PetscCall(VecDestroy(&ctx->w[1]));
    290:     PetscCall(VecDestroy(&ctx->w[2]));
    291:     PetscCall(VecDestroy(&ctx->w[3]));

    293:     switch (pep->problem_type) {
    294:       case PEP_GENERAL:    i = 0; break;
    295:       case PEP_HERMITIAN:
    296:       case PEP_HYPERBOLIC: i = 1; break;
    297:       case PEP_GYROSCOPIC: i = 2; break;
    298:     }

    300:     PetscCall((*fcreate[i][0])(PetscObjectComm((PetscObject)pep),ctx,&ctx->A));
    301:     PetscCall((*fcreate[i][1])(PetscObjectComm((PetscObject)pep),ctx,&ctx->B));

    303:   } else {   /* implicit matrix */
    304:     PetscCheck(pep->problem_type==PEP_GENERAL,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Must use the explicit matrix option if problem type is not general");
    305:     if (!((PetscObject)ctx->eps)->type_name) PetscCall(EPSSetType(ctx->eps,EPSKRYLOVSCHUR));
    306:     else {
    307:       PetscCall(PetscObjectTypeCompare((PetscObject)ctx->eps,EPSKRYLOVSCHUR,&ks));
    308:       PetscCheck(ks,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Implicit matrix option only implemented for Krylov-Schur");
    309:     }
    310:     PetscCheck(ctx->alpha==1.0 && ctx->beta==0.0,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Implicit matrix option does not support setting alpha,beta parameters of the linearization");
    311:     PetscCall(STSetType(st,STSHELL));
    312:     PetscCall(STShellSetContext(st,ctx));
    313:     if (!transf) PetscCall(STShellSetBackTransform(st,BackTransform_Linear));
    314:     else PetscCall(STShellSetBackTransform(st,BackTransform_Skip));
    315:     PetscCall(MatCreateVecsEmpty(pep->A[0],&ctx->w[0],&ctx->w[1]));
    316:     PetscCall(MatCreateVecsEmpty(pep->A[0],&ctx->w[2],&ctx->w[3]));
    317:     PetscCall(MatCreateVecs(pep->A[0],&ctx->w[4],&ctx->w[5]));
    318:     PetscCall(MatCreateShell(PetscObjectComm((PetscObject)pep),deg*pep->nloc,deg*pep->nloc,deg*pep->n,deg*pep->n,ctx,&ctx->A));
    319:     if (sinv && !transf) PetscCall(MatShellSetOperation(ctx->A,MATOP_MULT,(PetscErrorCodeFn*)MatMult_Linear_Sinvert));
    320:     else PetscCall(MatShellSetOperation(ctx->A,MATOP_MULT,(PetscErrorCodeFn*)MatMult_Linear_Shift));
    321:     PetscCall(STShellSetApply(st,Apply_Linear));
    322:     ctx->pep = pep;

    324:     PetscCall(PEPBasisCoefficients(pep,pep->pbc));
    325:     if (!transf) {
    326:       PetscCall(PetscMalloc1(pep->nmat,&pep->solvematcoeffs));
    327:       if (sinv) PetscCall(PEPEvaluateBasis(pep,pep->target,0,pep->solvematcoeffs,NULL));
    328:       else {
    329:         for (i=0;i<deg;i++) pep->solvematcoeffs[i] = 0.0;
    330:         pep->solvematcoeffs[deg] = 1.0;
    331:       }
    332:       PetscCall(STScaleShift(pep->st,1.0/pep->sfactor));
    333:       PetscCall(RGPushScale(pep->rg,1.0/pep->sfactor));
    334:     }
    335:     if (pep->sfactor!=1.0) {
    336:       for (i=0;i<pep->nmat;i++) {
    337:         pep->pbc[pep->nmat+i] /= pep->sfactor;
    338:         pep->pbc[2*pep->nmat+i] /= pep->sfactor*pep->sfactor;
    339:       }
    340:     }
    341:   }

    343:   PetscCall(EPSSetOperators(ctx->eps,ctx->A,ctx->B));
    344:   PetscCall(EPSGetProblemType(ctx->eps,&ptype));
    345:   if (!ptype) {
    346:     if (ctx->explicitmatrix) PetscCall(EPSSetProblemType(ctx->eps,EPS_GNHEP));
    347:     else PetscCall(EPSSetProblemType(ctx->eps,EPS_NHEP));
    348:   }
    349:   if (!ctx->usereps) {
    350:     if (transf) which = EPS_LARGEST_MAGNITUDE;
    351:     else {
    352:       switch (pep->which) {
    353:         case PEP_LARGEST_MAGNITUDE:  which = EPS_LARGEST_MAGNITUDE; break;
    354:         case PEP_SMALLEST_MAGNITUDE: which = EPS_SMALLEST_MAGNITUDE; break;
    355:         case PEP_LARGEST_REAL:       which = EPS_LARGEST_REAL; break;
    356:         case PEP_SMALLEST_REAL:      which = EPS_SMALLEST_REAL; break;
    357:         case PEP_LARGEST_IMAGINARY:  which = EPS_LARGEST_IMAGINARY; break;
    358:         case PEP_SMALLEST_IMAGINARY: which = EPS_SMALLEST_IMAGINARY; break;
    359:         case PEP_TARGET_MAGNITUDE:   which = EPS_TARGET_MAGNITUDE; break;
    360:         case PEP_TARGET_REAL:        which = EPS_TARGET_REAL; break;
    361:         case PEP_TARGET_IMAGINARY:   which = EPS_TARGET_IMAGINARY; break;
    362:         case PEP_ALL:                which = EPS_ALL; break;
    363:         case PEP_WHICH_USER:         which = EPS_WHICH_USER;
    364:           PetscCall(EPSSetEigenvalueComparison(ctx->eps,pep->sc->comparison,pep->sc->comparisonctx));
    365:           break;
    366:       }
    367:     }
    368:     PetscCall(EPSSetWhichEigenpairs(ctx->eps,which));

    370:     PetscCall(EPSSetDimensions(ctx->eps,pep->nev,pep->ncv,pep->mpd));
    371:     PetscCall(EPSSetTolerances(ctx->eps,SlepcDefaultTol(pep->tol),pep->max_it));
    372:   }
    373:   PetscCall(RGIsTrivial(pep->rg,&istrivial));
    374:   if (!istrivial) {
    375:     PetscCheck(!transf,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"PEPLINEAR does not support a nontrivial region with st-transform");
    376:     PetscCall(EPSSetRG(ctx->eps,pep->rg));
    377:   }
    378:   /* Transfer the trackall option from pep to eps */
    379:   PetscCall(PEPGetTrackAll(pep,&trackall));
    380:   PetscCall(EPSSetTrackAll(ctx->eps,trackall));

    382:   /* temporary change of target */
    383:   if (pep->sfactor!=1.0) {
    384:     PetscCall(EPSGetTarget(ctx->eps,&sigma));
    385:     PetscCall(EPSSetTarget(ctx->eps,sigma/pep->sfactor));
    386:   }

    388:   /* process initial vector */
    389:   if (pep->nini<0) {
    390:     PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)ctx->eps),deg*pep->nloc,deg*pep->n,&veps));
    391:     PetscCall(VecGetArray(veps,&epsarray));
    392:     for (i=0;i<deg;i++) {
    393:       if (i<-pep->nini) {
    394:         PetscCall(VecGetArray(pep->IS[i],&peparray));
    395:         PetscCall(PetscArraycpy(epsarray+i*pep->nloc,peparray,pep->nloc));
    396:         PetscCall(VecRestoreArray(pep->IS[i],&peparray));
    397:       } else {
    398:         if (!w) PetscCall(VecDuplicate(pep->IS[0],&w));
    399:         PetscCall(VecSetRandom(w,NULL));
    400:         PetscCall(VecGetArray(w,&peparray));
    401:         PetscCall(PetscArraycpy(epsarray+i*pep->nloc,peparray,pep->nloc));
    402:         PetscCall(VecRestoreArray(w,&peparray));
    403:       }
    404:     }
    405:     PetscCall(VecRestoreArray(veps,&epsarray));
    406:     PetscCall(EPSSetInitialSpace(ctx->eps,1,&veps));
    407:     PetscCall(VecDestroy(&veps));
    408:     PetscCall(VecDestroy(&w));
    409:     PetscCall(SlepcBasisDestroy_Private(&pep->nini,&pep->IS));
    410:   }

    412:   PetscCall(EPSSetUp(ctx->eps));
    413:   PetscCall(EPSGetDimensions(ctx->eps,NULL,&pep->ncv,&pep->mpd));
    414:   PetscCall(EPSGetTolerances(ctx->eps,NULL,&pep->max_it));
    415:   PetscCall(PEPAllocateSolution(pep,0));
    416:   PetscFunctionReturn(PETSC_SUCCESS);
    417: }

    419: /*
    420:    PEPLinearExtract_Residual - Auxiliary routine that copies the solution of the
    421:    linear eigenproblem to the PEP object. The eigenvector of the generalized
    422:    problem is supposed to be
    423:                                z = [  x  ]
    424:                                    [ l*x ]
    425:    The eigenvector is taken from z(1:n) or z(n+1:2*n) depending on the explicitly
    426:    computed residual norm.
    427:    Finally, x is normalized so that ||x||_2 = 1.
    428: */
    429: static PetscErrorCode PEPLinearExtract_Residual(PEP pep,EPS eps)
    430: {
    431:   PetscInt          i,k;
    432:   const PetscScalar *px;
    433:   PetscScalar       *er=pep->eigr,*ei=pep->eigi;
    434:   PetscReal         rn1,rn2;
    435:   Vec               xr,xi=NULL,wr;
    436:   Mat               A;
    437: #if !defined(PETSC_USE_COMPLEX)
    438:   Vec               wi;
    439:   const PetscScalar *py;
    440: #endif

    442:   PetscFunctionBegin;
    443: #if defined(PETSC_USE_COMPLEX)
    444:   PetscCall(PEPSetWorkVecs(pep,2));
    445: #else
    446:   PetscCall(PEPSetWorkVecs(pep,4));
    447: #endif
    448:   PetscCall(EPSGetOperators(eps,&A,NULL));
    449:   PetscCall(MatCreateVecs(A,&xr,NULL));
    450:   PetscCall(MatCreateVecsEmpty(pep->A[0],&wr,NULL));
    451: #if !defined(PETSC_USE_COMPLEX)
    452:   PetscCall(VecDuplicate(xr,&xi));
    453:   PetscCall(VecDuplicateEmpty(wr,&wi));
    454: #endif
    455:   for (i=0;i<pep->nconv;i++) {
    456:     PetscCall(EPSGetEigenpair(eps,i,NULL,NULL,xr,xi));
    457: #if !defined(PETSC_USE_COMPLEX)
    458:     if (ei[i]!=0.0) {   /* complex conjugate pair */
    459:       PetscCall(VecGetArrayRead(xr,&px));
    460:       PetscCall(VecGetArrayRead(xi,&py));
    461:       PetscCall(VecPlaceArray(wr,px));
    462:       PetscCall(VecPlaceArray(wi,py));
    463:       PetscCall(VecNormalizeComplex(wr,wi,PETSC_TRUE,NULL));
    464:       PetscCall(PEPComputeResidualNorm_Private(pep,er[i],ei[i],wr,wi,pep->work,&rn1));
    465:       PetscCall(BVInsertVec(pep->V,i,wr));
    466:       PetscCall(BVInsertVec(pep->V,i+1,wi));
    467:       for (k=1;k<pep->nmat-1;k++) {
    468:         PetscCall(VecResetArray(wr));
    469:         PetscCall(VecResetArray(wi));
    470:         PetscCall(VecPlaceArray(wr,px+k*pep->nloc));
    471:         PetscCall(VecPlaceArray(wi,py+k*pep->nloc));
    472:         PetscCall(VecNormalizeComplex(wr,wi,PETSC_TRUE,NULL));
    473:         PetscCall(PEPComputeResidualNorm_Private(pep,er[i],ei[i],wr,wi,pep->work,&rn2));
    474:         if (rn1>rn2) {
    475:           PetscCall(BVInsertVec(pep->V,i,wr));
    476:           PetscCall(BVInsertVec(pep->V,i+1,wi));
    477:           rn1 = rn2;
    478:         }
    479:       }
    480:       PetscCall(VecResetArray(wr));
    481:       PetscCall(VecResetArray(wi));
    482:       PetscCall(VecRestoreArrayRead(xr,&px));
    483:       PetscCall(VecRestoreArrayRead(xi,&py));
    484:       i++;
    485:     } else   /* real eigenvalue */
    486: #endif
    487:     {
    488:       PetscCall(VecGetArrayRead(xr,&px));
    489:       PetscCall(VecPlaceArray(wr,px));
    490:       PetscCall(VecNormalizeComplex(wr,NULL,PETSC_FALSE,NULL));
    491:       PetscCall(PEPComputeResidualNorm_Private(pep,er[i],ei[i],wr,NULL,pep->work,&rn1));
    492:       PetscCall(BVInsertVec(pep->V,i,wr));
    493:       for (k=1;k<pep->nmat-1;k++) {
    494:         PetscCall(VecResetArray(wr));
    495:         PetscCall(VecPlaceArray(wr,px+k*pep->nloc));
    496:         PetscCall(VecNormalizeComplex(wr,NULL,PETSC_FALSE,NULL));
    497:         PetscCall(PEPComputeResidualNorm_Private(pep,er[i],ei[i],wr,NULL,pep->work,&rn2));
    498:         if (rn1>rn2) {
    499:           PetscCall(BVInsertVec(pep->V,i,wr));
    500:           rn1 = rn2;
    501:         }
    502:       }
    503:       PetscCall(VecResetArray(wr));
    504:       PetscCall(VecRestoreArrayRead(xr,&px));
    505:     }
    506:   }
    507:   PetscCall(VecDestroy(&wr));
    508:   PetscCall(VecDestroy(&xr));
    509: #if !defined(PETSC_USE_COMPLEX)
    510:   PetscCall(VecDestroy(&wi));
    511:   PetscCall(VecDestroy(&xi));
    512: #endif
    513:   PetscFunctionReturn(PETSC_SUCCESS);
    514: }

    516: /*
    517:    PEPLinearExtract_None - Same as PEPLinearExtract_Norm but always takes
    518:    the first block.
    519: */
    520: static PetscErrorCode PEPLinearExtract_None(PEP pep,EPS eps)
    521: {
    522:   PetscInt          i;
    523:   const PetscScalar *px;
    524:   Mat               A;
    525:   Vec               xr,xi=NULL,w;
    526: #if !defined(PETSC_USE_COMPLEX)
    527:   PetscScalar       *ei=pep->eigi;
    528: #endif

    530:   PetscFunctionBegin;
    531:   PetscCall(EPSGetOperators(eps,&A,NULL));
    532:   PetscCall(MatCreateVecs(A,&xr,NULL));
    533: #if !defined(PETSC_USE_COMPLEX)
    534:   PetscCall(VecDuplicate(xr,&xi));
    535: #endif
    536:   PetscCall(MatCreateVecsEmpty(pep->A[0],&w,NULL));
    537:   for (i=0;i<pep->nconv;i++) {
    538:     PetscCall(EPSGetEigenvector(eps,i,xr,xi));
    539: #if !defined(PETSC_USE_COMPLEX)
    540:     if (ei[i]!=0.0) {   /* complex conjugate pair */
    541:       PetscCall(VecGetArrayRead(xr,&px));
    542:       PetscCall(VecPlaceArray(w,px));
    543:       PetscCall(BVInsertVec(pep->V,i,w));
    544:       PetscCall(VecResetArray(w));
    545:       PetscCall(VecRestoreArrayRead(xr,&px));
    546:       PetscCall(VecGetArrayRead(xi,&px));
    547:       PetscCall(VecPlaceArray(w,px));
    548:       PetscCall(BVInsertVec(pep->V,i+1,w));
    549:       PetscCall(VecResetArray(w));
    550:       PetscCall(VecRestoreArrayRead(xi,&px));
    551:       i++;
    552:     } else   /* real eigenvalue */
    553: #endif
    554:     {
    555:       PetscCall(VecGetArrayRead(xr,&px));
    556:       PetscCall(VecPlaceArray(w,px));
    557:       PetscCall(BVInsertVec(pep->V,i,w));
    558:       PetscCall(VecResetArray(w));
    559:       PetscCall(VecRestoreArrayRead(xr,&px));
    560:     }
    561:   }
    562:   PetscCall(VecDestroy(&w));
    563:   PetscCall(VecDestroy(&xr));
    564: #if !defined(PETSC_USE_COMPLEX)
    565:   PetscCall(VecDestroy(&xi));
    566: #endif
    567:   PetscFunctionReturn(PETSC_SUCCESS);
    568: }

    570: /*
    571:    PEPLinearExtract_Norm - Auxiliary routine that copies the solution of the
    572:    linear eigenproblem to the PEP object. The eigenvector of the generalized
    573:    problem is supposed to be
    574:                                z = [  x  ]
    575:                                    [ l*x ]
    576:    If |l|<1.0, the eigenvector is taken from z(1:n), otherwise from z(n+1:2*n).
    577:    Finally, x is normalized so that ||x||_2 = 1.
    578: */
    579: static PetscErrorCode PEPLinearExtract_Norm(PEP pep,EPS eps)
    580: {
    581:   PetscInt          i,offset;
    582:   const PetscScalar *px;
    583:   PetscScalar       *er=pep->eigr;
    584:   Mat               A;
    585:   Vec               xr,xi=NULL,w;
    586: #if !defined(PETSC_USE_COMPLEX)
    587:   PetscScalar       *ei=pep->eigi;
    588: #endif

    590:   PetscFunctionBegin;
    591:   PetscCall(EPSGetOperators(eps,&A,NULL));
    592:   PetscCall(MatCreateVecs(A,&xr,NULL));
    593: #if !defined(PETSC_USE_COMPLEX)
    594:   PetscCall(VecDuplicate(xr,&xi));
    595: #endif
    596:   PetscCall(MatCreateVecsEmpty(pep->A[0],&w,NULL));
    597:   for (i=0;i<pep->nconv;i++) {
    598:     PetscCall(EPSGetEigenpair(eps,i,NULL,NULL,xr,xi));
    599:     if (SlepcAbsEigenvalue(er[i],ei[i])>1.0) offset = (pep->nmat-2)*pep->nloc;
    600:     else offset = 0;
    601: #if !defined(PETSC_USE_COMPLEX)
    602:     if (ei[i]!=0.0) {   /* complex conjugate pair */
    603:       PetscCall(VecGetArrayRead(xr,&px));
    604:       PetscCall(VecPlaceArray(w,px+offset));
    605:       PetscCall(BVInsertVec(pep->V,i,w));
    606:       PetscCall(VecResetArray(w));
    607:       PetscCall(VecRestoreArrayRead(xr,&px));
    608:       PetscCall(VecGetArrayRead(xi,&px));
    609:       PetscCall(VecPlaceArray(w,px+offset));
    610:       PetscCall(BVInsertVec(pep->V,i+1,w));
    611:       PetscCall(VecResetArray(w));
    612:       PetscCall(VecRestoreArrayRead(xi,&px));
    613:       i++;
    614:     } else /* real eigenvalue */
    615: #endif
    616:     {
    617:       PetscCall(VecGetArrayRead(xr,&px));
    618:       PetscCall(VecPlaceArray(w,px+offset));
    619:       PetscCall(BVInsertVec(pep->V,i,w));
    620:       PetscCall(VecResetArray(w));
    621:       PetscCall(VecRestoreArrayRead(xr,&px));
    622:     }
    623:   }
    624:   PetscCall(VecDestroy(&w));
    625:   PetscCall(VecDestroy(&xr));
    626: #if !defined(PETSC_USE_COMPLEX)
    627:   PetscCall(VecDestroy(&xi));
    628: #endif
    629:   PetscFunctionReturn(PETSC_SUCCESS);
    630: }

    632: static PetscErrorCode PEPExtractVectors_Linear(PEP pep)
    633: {
    634:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    636:   PetscFunctionBegin;
    637:   switch (pep->extract) {
    638:   case PEP_EXTRACT_NONE:
    639:     PetscCall(PEPLinearExtract_None(pep,ctx->eps));
    640:     break;
    641:   case PEP_EXTRACT_NORM:
    642:     PetscCall(PEPLinearExtract_Norm(pep,ctx->eps));
    643:     break;
    644:   case PEP_EXTRACT_RESIDUAL:
    645:     PetscCall(PEPLinearExtract_Residual(pep,ctx->eps));
    646:     break;
    647:   case PEP_EXTRACT_STRUCTURED:
    648:     SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Extraction not implemented in this solver");
    649:   }
    650:   PetscFunctionReturn(PETSC_SUCCESS);
    651: }

    653: static PetscErrorCode PEPSolve_Linear(PEP pep)
    654: {
    655:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;
    656:   PetscScalar    sigma;
    657:   PetscBool      flg;
    658:   PetscInt       i;

    660:   PetscFunctionBegin;
    661:   PetscCall(EPSSolve(ctx->eps));
    662:   PetscCall(EPSGetConverged(ctx->eps,&pep->nconv));
    663:   PetscCall(EPSGetIterationNumber(ctx->eps,&pep->its));
    664:   PetscCall(EPSGetConvergedReason(ctx->eps,(EPSConvergedReason*)&pep->reason));

    666:   /* recover eigenvalues */
    667:   for (i=0;i<pep->nconv;i++) {
    668:     PetscCall(EPSGetEigenpair(ctx->eps,i,&pep->eigr[i],&pep->eigi[i],NULL,NULL));
    669:     pep->eigr[i] *= pep->sfactor;
    670:     pep->eigi[i] *= pep->sfactor;
    671:   }

    673:   /* restore target */
    674:   PetscCall(EPSGetTarget(ctx->eps,&sigma));
    675:   PetscCall(EPSSetTarget(ctx->eps,sigma*pep->sfactor));

    677:   PetscCall(STGetTransform(pep->st,&flg));
    678:   if (flg) PetscTryTypeMethod(pep,backtransform);
    679:   if (pep->sfactor!=1.0) {
    680:     /* Restore original values */
    681:     for (i=0;i<pep->nmat;i++) {
    682:       pep->pbc[pep->nmat+i] *= pep->sfactor;
    683:       pep->pbc[2*pep->nmat+i] *= pep->sfactor*pep->sfactor;
    684:     }
    685:     if (!flg && !ctx->explicitmatrix) PetscCall(STScaleShift(pep->st,pep->sfactor));
    686:   }
    687:   if (ctx->explicitmatrix || !flg) PetscCall(RGPopScale(pep->rg));
    688:   PetscFunctionReturn(PETSC_SUCCESS);
    689: }

    691: static PetscErrorCode EPSMonitor_Linear(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
    692: {
    693:   PEP            pep = (PEP)ctx;

    695:   PetscFunctionBegin;
    696:   PetscCall(PEPMonitor(pep,its,nconv,eigr,eigi,errest,nest));
    697:   PetscFunctionReturn(PETSC_SUCCESS);
    698: }

    700: static PetscErrorCode PEPSetFromOptions_Linear(PEP pep,PetscOptionItems PetscOptionsObject)
    701: {
    702:   PetscBool      set,val;
    703:   PetscInt       k;
    704:   PetscReal      array[2]={0,0};
    705:   PetscBool      flg;
    706:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    708:   PetscFunctionBegin;
    709:   PetscOptionsHeadBegin(PetscOptionsObject,"PEP Linear Options");

    711:     k = 2;
    712:     PetscCall(PetscOptionsRealArray("-pep_linear_linearization","Parameters of the linearization","PEPLinearSetLinearization",array,&k,&flg));
    713:     if (flg) PetscCall(PEPLinearSetLinearization(pep,array[0],array[1]));

    715:     PetscCall(PetscOptionsBool("-pep_linear_explicitmatrix","Use explicit matrix in linearization","PEPLinearSetExplicitMatrix",ctx->explicitmatrix,&val,&set));
    716:     if (set) PetscCall(PEPLinearSetExplicitMatrix(pep,val));

    718:   PetscOptionsHeadEnd();

    720:   if (!ctx->eps) PetscCall(PEPLinearGetEPS(pep,&ctx->eps));
    721:   PetscCall(EPSSetFromOptions(ctx->eps));
    722:   PetscFunctionReturn(PETSC_SUCCESS);
    723: }

    725: static PetscErrorCode PEPLinearSetLinearization_Linear(PEP pep,PetscReal alpha,PetscReal beta)
    726: {
    727:   PEP_LINEAR *ctx = (PEP_LINEAR*)pep->data;

    729:   PetscFunctionBegin;
    730:   PetscCheck(beta!=0.0 || alpha!=0.0,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"Parameters alpha and beta cannot be zero simultaneously");
    731:   ctx->alpha = alpha;
    732:   ctx->beta  = beta;
    733:   PetscFunctionReturn(PETSC_SUCCESS);
    734: }

    736: /*@
    737:    PEPLinearSetLinearization - Set the coefficients that define
    738:    the linearization of a quadratic eigenproblem.

    740:    Logically Collective

    742:    Input Parameters:
    743: +  pep   - the polynomial eigensolver context
    744: .  alpha - first parameter of the linearization
    745: -  beta  - second parameter of the linearization

    747:    Options Database Key:
    748: .  -pep_linear_linearization alpha,beta - sets the coefficients

    750:    Notes:
    751:    See section [](#sec:linearization) for the general expressions of
    752:    the linearizations. Note that the expressions are different depending
    753:    on `PEPProblemType`.

    755:    Cannot pass zero for both `alpha` and `beta`. The default values are
    756:    `alpha`=1 and `beta`=0.

    758:    Level: advanced

    760: .seealso: [](ch:pep), [](#sec:linearization), `PEPLINEAR`, `PEPProblemType`, `PEPLinearGetLinearization()`
    761: @*/
    762: PetscErrorCode PEPLinearSetLinearization(PEP pep,PetscReal alpha,PetscReal beta)
    763: {
    764:   PetscFunctionBegin;
    768:   PetscTryMethod(pep,"PEPLinearSetLinearization_C",(PEP,PetscReal,PetscReal),(pep,alpha,beta));
    769:   PetscFunctionReturn(PETSC_SUCCESS);
    770: }

    772: static PetscErrorCode PEPLinearGetLinearization_Linear(PEP pep,PetscReal *alpha,PetscReal *beta)
    773: {
    774:   PEP_LINEAR *ctx = (PEP_LINEAR*)pep->data;

    776:   PetscFunctionBegin;
    777:   if (alpha) *alpha = ctx->alpha;
    778:   if (beta)  *beta  = ctx->beta;
    779:   PetscFunctionReturn(PETSC_SUCCESS);
    780: }

    782: /*@
    783:    PEPLinearGetLinearization - Returns the coefficients that define
    784:    the linearization of a quadratic eigenproblem.

    786:    Not Collective

    788:    Input Parameter:
    789: .  pep  - the polynomial eigensolver context

    791:    Output Parameters:
    792: +  alpha - the first parameter of the linearization
    793: -  beta  - the second parameter of the linearization

    795:    Level: advanced

    797: .seealso: [](ch:pep), `PEPLINEAR`, `PEPLinearSetLinearization()`
    798: @*/
    799: PetscErrorCode PEPLinearGetLinearization(PEP pep,PetscReal *alpha,PetscReal *beta)
    800: {
    801:   PetscFunctionBegin;
    803:   PetscUseMethod(pep,"PEPLinearGetLinearization_C",(PEP,PetscReal*,PetscReal*),(pep,alpha,beta));
    804:   PetscFunctionReturn(PETSC_SUCCESS);
    805: }

    807: static PetscErrorCode PEPLinearSetExplicitMatrix_Linear(PEP pep,PetscBool explicitmatrix)
    808: {
    809:   PEP_LINEAR *ctx = (PEP_LINEAR*)pep->data;

    811:   PetscFunctionBegin;
    812:   if (ctx->explicitmatrix != explicitmatrix) {
    813:     ctx->explicitmatrix = explicitmatrix;
    814:     pep->state = PEP_STATE_INITIAL;
    815:   }
    816:   PetscFunctionReturn(PETSC_SUCCESS);
    817: }

    819: /*@
    820:    PEPLinearSetExplicitMatrix - Indicate if the matrices $A$ and $B$ for the
    821:    linearization of the problem must be built explicitly.

    823:    Logically Collective

    825:    Input Parameters:
    826: +  pep         - the polynomial eigensolver context
    827: -  explicitmat - boolean flag indicating if the matrices are built explicitly

    829:    Options Database Key:
    830: .  -pep_linear_explicitmatrix (true|false) - set the boolean flag

    832:    Level: advanced

    834: .seealso: [](ch:pep), `PEPLINEAR`, `PEPLinearGetExplicitMatrix()`
    835: @*/
    836: PetscErrorCode PEPLinearSetExplicitMatrix(PEP pep,PetscBool explicitmat)
    837: {
    838:   PetscFunctionBegin;
    841:   PetscTryMethod(pep,"PEPLinearSetExplicitMatrix_C",(PEP,PetscBool),(pep,explicitmat));
    842:   PetscFunctionReturn(PETSC_SUCCESS);
    843: }

    845: static PetscErrorCode PEPLinearGetExplicitMatrix_Linear(PEP pep,PetscBool *explicitmat)
    846: {
    847:   PEP_LINEAR *ctx = (PEP_LINEAR*)pep->data;

    849:   PetscFunctionBegin;
    850:   *explicitmat = ctx->explicitmatrix;
    851:   PetscFunctionReturn(PETSC_SUCCESS);
    852: }

    854: /*@
    855:    PEPLinearGetExplicitMatrix - Returns the flag indicating if the matrices
    856:    $A$ and $B$ for the linearization are built explicitly.

    858:    Not Collective

    860:    Input Parameter:
    861: .  pep  - the polynomial eigensolver context

    863:    Output Parameter:
    864: .  explicitmat - the mode flag

    866:    Level: advanced

    868: .seealso: [](ch:pep), `PEPLINEAR`, `PEPLinearSetExplicitMatrix()`
    869: @*/
    870: PetscErrorCode PEPLinearGetExplicitMatrix(PEP pep,PetscBool *explicitmat)
    871: {
    872:   PetscFunctionBegin;
    874:   PetscAssertPointer(explicitmat,2);
    875:   PetscUseMethod(pep,"PEPLinearGetExplicitMatrix_C",(PEP,PetscBool*),(pep,explicitmat));
    876:   PetscFunctionReturn(PETSC_SUCCESS);
    877: }

    879: static PetscErrorCode PEPLinearSetEPS_Linear(PEP pep,EPS eps)
    880: {
    881:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    883:   PetscFunctionBegin;
    884:   PetscCall(PetscObjectReference((PetscObject)eps));
    885:   PetscCall(EPSDestroy(&ctx->eps));
    886:   ctx->eps     = eps;
    887:   ctx->usereps = PETSC_TRUE;
    888:   pep->state   = PEP_STATE_INITIAL;
    889:   PetscFunctionReturn(PETSC_SUCCESS);
    890: }

    892: /*@
    893:    PEPLinearSetEPS - Associate a linear eigensolver object (`EPS`) to the
    894:    polynomial eigenvalue solver.

    896:    Collective

    898:    Input Parameters:
    899: +  pep - the polynomial eigensolver context
    900: -  eps - the linear eigensolver context

    902:    Level: advanced

    904: .seealso: [](ch:pep), `PEPLINEAR`, `PEPLinearGetEPS()`
    905: @*/
    906: PetscErrorCode PEPLinearSetEPS(PEP pep,EPS eps)
    907: {
    908:   PetscFunctionBegin;
    911:   PetscCheckSameComm(pep,1,eps,2);
    912:   PetscTryMethod(pep,"PEPLinearSetEPS_C",(PEP,EPS),(pep,eps));
    913:   PetscFunctionReturn(PETSC_SUCCESS);
    914: }

    916: static PetscErrorCode PEPLinearGetEPS_Linear(PEP pep,EPS *eps)
    917: {
    918:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    920:   PetscFunctionBegin;
    921:   if (!ctx->eps) {
    922:     PetscCall(EPSCreate(PetscObjectComm((PetscObject)pep),&ctx->eps));
    923:     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->eps,(PetscObject)pep,1));
    924:     PetscCall(EPSSetOptionsPrefix(ctx->eps,((PetscObject)pep)->prefix));
    925:     PetscCall(EPSAppendOptionsPrefix(ctx->eps,"pep_linear_"));
    926:     PetscCall(PetscObjectSetOptions((PetscObject)ctx->eps,((PetscObject)pep)->options));
    927:     PetscCall(EPSMonitorSet(ctx->eps,EPSMonitor_Linear,pep,NULL));
    928:   }
    929:   *eps = ctx->eps;
    930:   PetscFunctionReturn(PETSC_SUCCESS);
    931: }

    933: /*@
    934:    PEPLinearGetEPS - Retrieve the linear eigensolver object (`EPS`) associated
    935:    to the polynomial eigenvalue solver.

    937:    Collective

    939:    Input Parameter:
    940: .  pep - the polynomial eigensolver context

    942:    Output Parameter:
    943: .  eps - the linear eigensolver context

    945:    Level: advanced

    947: .seealso: [](ch:pep), `PEPLINEAR`, `PEPLinearSetEPS()`
    948: @*/
    949: PetscErrorCode PEPLinearGetEPS(PEP pep,EPS *eps)
    950: {
    951:   PetscFunctionBegin;
    953:   PetscAssertPointer(eps,2);
    954:   PetscUseMethod(pep,"PEPLinearGetEPS_C",(PEP,EPS*),(pep,eps));
    955:   PetscFunctionReturn(PETSC_SUCCESS);
    956: }

    958: static PetscErrorCode PEPView_Linear(PEP pep,PetscViewer viewer)
    959: {
    960:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;
    961:   PetscBool      isascii;

    963:   PetscFunctionBegin;
    964:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    965:   if (isascii) {
    966:     if (!ctx->eps) PetscCall(PEPLinearGetEPS(pep,&ctx->eps));
    967:     PetscCall(PetscViewerASCIIPrintf(viewer,"  %s matrices\n",ctx->explicitmatrix? "explicit": "implicit"));
    968:     PetscCall(PetscViewerASCIIPrintf(viewer,"  linearization parameters: alpha=%g beta=%g\n",(double)ctx->alpha,(double)ctx->beta));
    969:     PetscCall(PetscViewerASCIIPushTab(viewer));
    970:     PetscCall(EPSView(ctx->eps,viewer));
    971:     PetscCall(PetscViewerASCIIPopTab(viewer));
    972:   }
    973:   PetscFunctionReturn(PETSC_SUCCESS);
    974: }

    976: static PetscErrorCode PEPReset_Linear(PEP pep)
    977: {
    978:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    980:   PetscFunctionBegin;
    981:   if (!ctx->eps) PetscCall(EPSReset(ctx->eps));
    982:   PetscCall(MatDestroy(&ctx->A));
    983:   PetscCall(MatDestroy(&ctx->B));
    984:   PetscCall(VecDestroy(&ctx->w[0]));
    985:   PetscCall(VecDestroy(&ctx->w[1]));
    986:   PetscCall(VecDestroy(&ctx->w[2]));
    987:   PetscCall(VecDestroy(&ctx->w[3]));
    988:   PetscCall(VecDestroy(&ctx->w[4]));
    989:   PetscCall(VecDestroy(&ctx->w[5]));
    990:   PetscFunctionReturn(PETSC_SUCCESS);
    991: }

    993: static PetscErrorCode PEPDestroy_Linear(PEP pep)
    994: {
    995:   PEP_LINEAR     *ctx = (PEP_LINEAR*)pep->data;

    997:   PetscFunctionBegin;
    998:   PetscCall(EPSDestroy(&ctx->eps));
    999:   PetscCall(PetscFree(pep->data));
    1000:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetLinearization_C",NULL));
    1001:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetLinearization_C",NULL));
    1002:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetEPS_C",NULL));
    1003:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetEPS_C",NULL));
    1004:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetExplicitMatrix_C",NULL));
    1005:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetExplicitMatrix_C",NULL));
    1006:   PetscFunctionReturn(PETSC_SUCCESS);
    1007: }

    1009: /*MC
    1010:    PEPLINEAR - PEPLINEAR = "linear" - A linearization-based solver that
    1011:    uses `EPS` to solve the resulting linear eigenproblem.

    1013:    Notes:
    1014:    A linear eigenvalue problem is obtained by linearization, as described
    1015:    in section [](#sec:linearization), where the linearization parameters
    1016:    can be set via `PEPLinearSetLinearization()`. Note that the linearization
    1017:    is done differently depending on `PEPProblemType`. Then the matrices of
    1018:    the linearization are passed to an `EPS` object. Use `PEPLinearGetEPS()`
    1019:    to configure this solver.

    1021:    By default, the matrices of the linearization are handled implicitly via
    1022:    shell matrices, but this can be changed with `PEPLinearSetExplicitMatrix()`.

    1024:    Level: beginner

    1026: .seealso: [](ch:pep), [](#sec:linearization), `PEP`, `PEPType`, `PEPProblemType`, `PEPSetType()`, `PEPLinearSetLinearization()`, `PEPLinearGetEPS()`, `PEPLinearSetExplicitMatrix()`
    1027: M*/
    1028: SLEPC_EXTERN PetscErrorCode PEPCreate_Linear(PEP pep)
    1029: {
    1030:   PEP_LINEAR     *ctx;

    1032:   PetscFunctionBegin;
    1033:   PetscCall(PetscNew(&ctx));
    1034:   pep->data = (void*)ctx;

    1036:   pep->lineariz       = PETSC_TRUE;
    1037:   ctx->explicitmatrix = PETSC_FALSE;
    1038:   ctx->alpha          = 1.0;
    1039:   ctx->beta           = 0.0;

    1041:   pep->ops->solve          = PEPSolve_Linear;
    1042:   pep->ops->setup          = PEPSetUp_Linear;
    1043:   pep->ops->setfromoptions = PEPSetFromOptions_Linear;
    1044:   pep->ops->destroy        = PEPDestroy_Linear;
    1045:   pep->ops->reset          = PEPReset_Linear;
    1046:   pep->ops->view           = PEPView_Linear;
    1047:   pep->ops->backtransform  = PEPBackTransform_Default;
    1048:   pep->ops->computevectors = PEPComputeVectors_Default;
    1049:   pep->ops->extractvectors = PEPExtractVectors_Linear;

    1051:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetLinearization_C",PEPLinearSetLinearization_Linear));
    1052:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetLinearization_C",PEPLinearGetLinearization_Linear));
    1053:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetEPS_C",PEPLinearSetEPS_Linear));
    1054:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetEPS_C",PEPLinearGetEPS_Linear));
    1055:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearSetExplicitMatrix_C",PEPLinearSetExplicitMatrix_Linear));
    1056:   PetscCall(PetscObjectComposeFunction((PetscObject)pep,"PEPLinearGetExplicitMatrix_C",PEPLinearGetExplicitMatrix_Linear));
    1057:   PetscFunctionReturn(PETSC_SUCCESS);
    1058: }