Date: 2023-09-05T10:19:16+00:00

Actual source code: stsolve.c
slepc-3.19.2 2023-09-05
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:    ST interface routines, callable by users
     12: */

     14: #include <slepc/private/stimpl.h>

     16: PetscErrorCode STApply_Generic(ST st,Vec x,Vec y)
     17: {
     18:   PetscFunctionBegin;
     19:   if (st->M && st->P) {
     20:     PetscCall(MatMult(st->M,x,st->work[0]));
     21:     PetscCall(STMatSolve(st,st->work[0],y));
     22:   } else if (st->M) PetscCall(MatMult(st->M,x,y));
     23:   else PetscCall(STMatSolve(st,x,y));
     24:   PetscFunctionReturn(PETSC_SUCCESS);
     25: }

     27: /*@
     28:    STApply - Applies the spectral transformation operator to a vector, for
     29:    instance (A - sB)^-1 B in the case of the shift-and-invert transformation
     30:    and generalized eigenproblem.

     32:    Collective

     34:    Input Parameters:
     35: +  st - the spectral transformation context
     36: -  x  - input vector

     38:    Output Parameter:
     39: .  y - output vector

     41:    Level: developer

     43: .seealso: STApplyTranspose(), STApplyHermitianTranspose()
     44: @*/
     45: PetscErrorCode STApply(ST st,Vec x,Vec y)
     46: {
     47:   Mat            Op;

     49:   PetscFunctionBegin;
     54:   STCheckMatrices(st,1);
     55:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     56:   PetscCall(VecSetErrorIfLocked(y,3));
     57:   PetscCall(STGetOperator_Private(st,&Op));
     58:   PetscCall(MatMult(Op,x,y));
     59:   PetscFunctionReturn(PETSC_SUCCESS);
     60: }

     62: PetscErrorCode STApplyMat_Generic(ST st,Mat B,Mat C)
     63: {
     64:   Mat            work;

     66:   PetscFunctionBegin;
     67:   if (st->M && st->P) {
     68:     PetscCall(MatMatMult(st->M,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&work));
     69:     PetscCall(STMatMatSolve(st,work,C));
     70:     PetscCall(MatDestroy(&work));
     71:   } else if (st->M) PetscCall(MatMatMult(st->M,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&C));
     72:   else PetscCall(STMatMatSolve(st,B,C));
     73:   PetscFunctionReturn(PETSC_SUCCESS);
     74: }

     76: /*@
     77:    STApplyMat - Applies the spectral transformation operator to a matrix, for
     78:    instance (A - sB)^-1 B in the case of the shift-and-invert transformation
     79:    and generalized eigenproblem.

     81:    Collective

     83:    Input Parameters:
     84: +  st - the spectral transformation context
     85: -  X  - input matrix

     87:    Output Parameter:
     88: .  Y - output matrix

     90:    Level: developer

     92: .seealso: STApply()
     93: @*/
     94: PetscErrorCode STApplyMat(ST st,Mat X,Mat Y)
     95: {
     96:   PetscFunctionBegin;
    101:   STCheckMatrices(st,1);
    102:   PetscCheck(X!=Y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"X and Y must be different matrices");
    103:   PetscUseTypeMethod(st,applymat,X,Y);
    104:   PetscFunctionReturn(PETSC_SUCCESS);
    105: }

    107: PetscErrorCode STApplyTranspose_Generic(ST st,Vec x,Vec y)
    108: {
    109:   PetscFunctionBegin;
    110:   if (st->M && st->P) {
    111:     PetscCall(STMatSolveTranspose(st,x,st->work[0]));
    112:     PetscCall(MatMultTranspose(st->M,st->work[0],y));
    113:   } else if (st->M) PetscCall(MatMultTranspose(st->M,x,y));
    114:   else PetscCall(STMatSolveTranspose(st,x,y));
    115:   PetscFunctionReturn(PETSC_SUCCESS);
    116: }

    118: /*@
    119:    STApplyTranspose - Applies the transpose of the operator to a vector, for
    120:    instance B^T(A - sB)^-T in the case of the shift-and-invert transformation
    121:    and generalized eigenproblem.

    123:    Collective

    125:    Input Parameters:
    126: +  st - the spectral transformation context
    127: -  x  - input vector

    129:    Output Parameter:
    130: .  y - output vector

    132:    Level: developer

    134: .seealso: STApply(), STApplyHermitianTranspose()
    135: @*/
    136: PetscErrorCode STApplyTranspose(ST st,Vec x,Vec y)
    137: {
    138:   Mat            Op;

    140:   PetscFunctionBegin;
    145:   STCheckMatrices(st,1);
    146:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    147:   PetscCall(VecSetErrorIfLocked(y,3));
    148:   PetscCall(STGetOperator_Private(st,&Op));
    149:   PetscCall(MatMultTranspose(Op,x,y));
    150:   PetscFunctionReturn(PETSC_SUCCESS);
    151: }

    153: /*@
    154:    STApplyHermitianTranspose - Applies the hermitian-transpose of the operator
    155:    to a vector, for instance B^H(A - sB)^-H in the case of the shift-and-invert
    156:    transformation and generalized eigenproblem.

    158:    Collective

    160:    Input Parameters:
    161: +  st - the spectral transformation context
    162: -  x  - input vector

    164:    Output Parameter:
    165: .  y - output vector

    167:    Note:
    168:    Currently implemented via STApplyTranspose() with appropriate conjugation.

    170:    Level: developer

    172: .seealso: STApply(), STApplyTranspose()
    173: @*/
    174: PetscErrorCode STApplyHermitianTranspose(ST st,Vec x,Vec y)
    175: {
    176:   Mat            Op;

    178:   PetscFunctionBegin;
    183:   STCheckMatrices(st,1);
    184:   PetscCheck(x!=y,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    185:   PetscCall(VecSetErrorIfLocked(y,3));
    186:   PetscCall(STGetOperator_Private(st,&Op));
    187:   PetscCall(MatMultHermitianTranspose(Op,x,y));
    188:   PetscFunctionReturn(PETSC_SUCCESS);
    189: }

    191: /*@
    192:    STGetBilinearForm - Returns the matrix used in the bilinear form with a
    193:    generalized problem with semi-definite B.

    195:    Logically Collective

    197:    Input Parameters:
    198: .  st - the spectral transformation context

    200:    Output Parameter:
    201: .  B - output matrix

    203:    Notes:
    204:    The output matrix B must be destroyed after use. It will be NULL in
    205:    case of standard eigenproblems.

    207:    Level: developer

    209: .seealso: BVSetMatrix()
    210: @*/
    211: PetscErrorCode STGetBilinearForm(ST st,Mat *B)
    212: {
    213:   PetscFunctionBegin;
    217:   STCheckMatrices(st,1);
    218:   PetscUseTypeMethod(st,getbilinearform,B);
    219:   PetscFunctionReturn(PETSC_SUCCESS);
    220: }

    222: PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
    223: {
    224:   PetscFunctionBegin;
    225:   if (st->nmat==1) *B = NULL;
    226:   else {
    227:     *B = st->A[1];
    228:     PetscCall(PetscObjectReference((PetscObject)*B));
    229:   }
    230:   PetscFunctionReturn(PETSC_SUCCESS);
    231: }

    233: static PetscErrorCode MatMult_STOperator(Mat Op,Vec x,Vec y)
    234: {
    235:   ST             st;

    237:   PetscFunctionBegin;
    238:   PetscCall(MatShellGetContext(Op,&st));
    239:   PetscCall(STSetUp(st));
    240:   PetscCall(PetscLogEventBegin(ST_Apply,st,x,y,0));
    241:   if (st->D) { /* with balancing */
    242:     PetscCall(VecPointwiseDivide(st->wb,x,st->D));
    243:     PetscUseTypeMethod(st,apply,st->wb,y);
    244:     PetscCall(VecPointwiseMult(y,y,st->D));
    245:   } else PetscUseTypeMethod(st,apply,x,y);
    246:   PetscCall(PetscLogEventEnd(ST_Apply,st,x,y,0));
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: static PetscErrorCode MatMultTranspose_STOperator(Mat Op,Vec x,Vec y)
    251: {
    252:   ST             st;

    254:   PetscFunctionBegin;
    255:   PetscCall(MatShellGetContext(Op,&st));
    256:   PetscCall(STSetUp(st));
    257:   PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
    258:   if (st->D) { /* with balancing */
    259:     PetscCall(VecPointwiseMult(st->wb,x,st->D));
    260:     PetscUseTypeMethod(st,applytrans,st->wb,y);
    261:     PetscCall(VecPointwiseDivide(y,y,st->D));
    262:   } else PetscUseTypeMethod(st,applytrans,x,y);
    263:   PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
    264:   PetscFunctionReturn(PETSC_SUCCESS);
    265: }

    267: #if defined(PETSC_USE_COMPLEX)
    268: static PetscErrorCode MatMultHermitianTranspose_STOperator(Mat Op,Vec x,Vec y)
    269: {
    270:   ST             st;

    272:   PetscFunctionBegin;
    273:   PetscCall(MatShellGetContext(Op,&st));
    274:   PetscCall(STSetUp(st));
    275:   PetscCall(PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0));
    276:   if (!st->wht) PetscCall(MatCreateVecs(st->A[0],&st->wht,NULL));
    277:   PetscCall(VecCopy(x,st->wht));
    278:   PetscCall(VecConjugate(st->wht));
    279:   if (st->D) { /* with balancing */
    280:     PetscCall(VecPointwiseMult(st->wb,st->wht,st->D));
    281:     PetscUseTypeMethod(st,applytrans,st->wb,y);
    282:     PetscCall(VecPointwiseDivide(y,y,st->D));
    283:   } else PetscUseTypeMethod(st,applytrans,st->wht,y);
    284:   PetscCall(VecConjugate(y));
    285:   PetscCall(PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0));
    286:   PetscFunctionReturn(PETSC_SUCCESS);
    287: }
    288: #endif

    290: static PetscErrorCode MatMatMult_STOperator(Mat Op,Mat B,Mat C,void *ctx)
    291: {
    292:   ST             st;

    294:   PetscFunctionBegin;
    295:   PetscCall(MatShellGetContext(Op,&st));
    296:   PetscCall(STSetUp(st));
    297:   PetscCall(PetscLogEventBegin(ST_Apply,st,B,C,0));
    298:   PetscCall(STApplyMat_Generic(st,B,C));
    299:   PetscCall(PetscLogEventEnd(ST_Apply,st,B,C,0));
    300:   PetscFunctionReturn(PETSC_SUCCESS);
    301: }

    303: PetscErrorCode STGetOperator_Private(ST st,Mat *Op)
    304: {
    305:   PetscInt       m,n,M,N;
    306:   Vec            v;
    307:   VecType        vtype;

    309:   PetscFunctionBegin;
    310:   if (!st->Op) {
    311:     if (Op) *Op = NULL;
    312:     /* create the shell matrix */
    313:     PetscCall(MatGetLocalSize(st->A[0],&m,&n));
    314:     PetscCall(MatGetSize(st->A[0],&M,&N));
    315:     PetscCall(MatCreateShell(PetscObjectComm((PetscObject)st),m,n,M,N,st,&st->Op));
    316:     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT,(void(*)(void))MatMult_STOperator));
    317:     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
    318: #if defined(PETSC_USE_COMPLEX)
    319:     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultHermitianTranspose_STOperator));
    320: #else
    321:     PetscCall(MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator));
    322: #endif
    323:     if (!st->D && st->ops->apply==STApply_Generic) {
    324:       PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSE,MATDENSE));
    325:       PetscCall(MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSECUDA,MATDENSECUDA));
    326:     }
    327:     /* make sure the shell matrix generates a vector of the same type as the problem matrices */
    328:     PetscCall(MatCreateVecs(st->A[0],&v,NULL));
    329:     PetscCall(VecGetType(v,&vtype));
    330:     PetscCall(MatShellSetVecType(st->Op,vtype));
    331:     PetscCall(VecDestroy(&v));
    332:     /* build the operator matrices */
    333:     PetscCall(STComputeOperator(st));
    334:   }
    335:   if (Op) *Op = st->Op;
    336:   PetscFunctionReturn(PETSC_SUCCESS);
    337: }

    339: /*@
    340:    STGetOperator - Returns a shell matrix that represents the operator of the
    341:    spectral transformation.

    343:    Collective

    345:    Input Parameter:
    346: .  st - the spectral transformation context

    348:    Output Parameter:
    349: .  Op - operator matrix

    351:    Notes:
    352:    The operator is defined in linear eigenproblems only, not in polynomial ones,
    353:    so the call will fail if more than 2 matrices were passed in STSetMatrices().

    355:    The returned shell matrix is essentially a wrapper to the STApply() and
    356:    STApplyTranspose() operations. The operator can often be expressed as

    358: $     Op = D*inv(K)*M*inv(D)

    360:    where D is the balancing matrix, and M and K are two matrices corresponding
    361:    to the numerator and denominator for spectral transformations that represent
    362:    a rational matrix function. In the case of STSHELL, the inner part inv(K)*M
    363:    is replaced by the user-provided operation from STShellSetApply().

    365:    The preconditioner matrix K typically depends on the value of the shift, and
    366:    its inverse is handled via an internal KSP object. Normal usage does not
    367:    require explicitly calling STGetOperator(), but it can be used to force the
    368:    creation of K and M, and then K is passed to the KSP. This is useful for
    369:    setting options associated with the PCFactor (to set MUMPS options, for instance).

    371:    The returned matrix must NOT be destroyed by the user. Instead, when no
    372:    longer needed it must be returned with STRestoreOperator(). In particular,
    373:    this is required before modifying the ST matrices or the shift.

    375:    A NULL pointer can be passed in Op in case the matrix is not required but we
    376:    want to force its creation. In this case, STRestoreOperator() should not be
    377:    called.

    379:    Level: advanced

    381: .seealso: STApply(), STApplyTranspose(), STSetBalanceMatrix(), STShellSetApply(),
    382:           STGetKSP(), STSetShift(), STRestoreOperator(), STSetMatrices()
    383: @*/
    384: PetscErrorCode STGetOperator(ST st,Mat *Op)
    385: {
    386:   PetscFunctionBegin;
    389:   STCheckMatrices(st,1);
    390:   STCheckNotSeized(st,1);
    391:   PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"The operator is not defined in polynomial eigenproblems");
    392:   PetscCall(STGetOperator_Private(st,Op));
    393:   if (Op) st->opseized = PETSC_TRUE;
    394:   PetscFunctionReturn(PETSC_SUCCESS);
    395: }

    397: /*@
    398:    STRestoreOperator - Restore the previously seized operator matrix.

    400:    Logically Collective

    402:    Input Parameters:
    403: +  st - the spectral transformation context
    404: -  Op - operator matrix

    406:    Notes:
    407:    The arguments must match the corresponding call to STGetOperator().

    409:    Level: advanced

    411: .seealso: STGetOperator()
    412: @*/
    413: PetscErrorCode STRestoreOperator(ST st,Mat *Op)
    414: {
    415:   PetscFunctionBegin;
    419:   PetscCheck(st->opseized,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must be called after STGetOperator()");
    420:   *Op = NULL;
    421:   st->opseized = PETSC_FALSE;
    422:   PetscFunctionReturn(PETSC_SUCCESS);
    423: }

    425: /*
    426:    STComputeOperator - Computes the matrices that constitute the operator

    428:       Op = D*inv(K)*M*inv(D).

    430:    K and M are computed here (D is user-provided) from the system matrices
    431:    and the shift sigma (whenever these are changed, this function recomputes
    432:    K and M). This is used only in linear eigenproblems (nmat<3).

    434:    K is the "preconditioner matrix": it is the denominator in rational operators,
    435:    e.g. (A-sigma*B) in shift-and-invert. In non-rational transformations such
    436:    as STFILTER, K=NULL which means identity. After computing K, it is passed to
    437:    the internal KSP object via KSPSetOperators.

    439:    M is the numerator in rational operators. If unused it is set to NULL (e.g.
    440:    in STPRECOND).

    442:    STSHELL does not compute anything here, but sets the flag as if it was ready.
    443: */
    444: PetscErrorCode STComputeOperator(ST st)
    445: {
    446:   PC             pc;

    448:   PetscFunctionBegin;
    451:   if (!st->opready && st->ops->computeoperator) {
    452:     PetscCall(PetscInfo(st,"Building the operator matrices\n"));
    453:     STCheckMatrices(st,1);
    454:     if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
    455:     PetscCall(PetscLogEventBegin(ST_ComputeOperator,st,0,0,0));
    456:     PetscUseTypeMethod(st,computeoperator);
    457:     PetscCall(PetscLogEventEnd(ST_ComputeOperator,st,0,0,0));
    458:     if (st->usesksp) {
    459:       if (!st->ksp) PetscCall(STGetKSP(st,&st->ksp));
    460:       if (st->P) {
    461:         PetscCall(STSetDefaultKSP(st));
    462:         PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
    463:       } else {
    464:         /* STPRECOND defaults to PCNONE if st->P is empty */
    465:         PetscCall(KSPGetPC(st->ksp,&pc));
    466:         PetscCall(PCSetType(pc,PCNONE));
    467:       }
    468:     }
    469:   }
    470:   st->opready = PETSC_TRUE;
    471:   PetscFunctionReturn(PETSC_SUCCESS);
    472: }

    474: /*@
    475:    STSetUp - Prepares for the use of a spectral transformation.

    477:    Collective

    479:    Input Parameter:
    480: .  st - the spectral transformation context

    482:    Level: advanced

    484: .seealso: STCreate(), STApply(), STDestroy()
    485: @*/
    486: PetscErrorCode STSetUp(ST st)
    487: {
    488:   PetscInt       i,n,k;

    490:   PetscFunctionBegin;
    493:   STCheckMatrices(st,1);
    494:   switch (st->state) {
    495:     case ST_STATE_INITIAL:
    496:       PetscCall(PetscInfo(st,"Setting up new ST\n"));
    497:       if (!((PetscObject)st)->type_name) PetscCall(STSetType(st,STSHIFT));
    498:       break;
    499:     case ST_STATE_SETUP:
    500:       PetscFunctionReturn(PETSC_SUCCESS);
    501:     case ST_STATE_UPDATED:
    502:       PetscCall(PetscInfo(st,"Setting up updated ST\n"));
    503:       break;
    504:   }
    505:   PetscCall(PetscLogEventBegin(ST_SetUp,st,0,0,0));
    506:   if (st->state!=ST_STATE_UPDATED) {
    507:     if (!(st->nmat<3 && st->opready)) {
    508:       if (st->T) {
    509:         for (i=0;i<PetscMax(2,st->nmat);i++) PetscCall(MatDestroy(&st->T[i]));
    510:       }
    511:       PetscCall(MatDestroy(&st->P));
    512:     }
    513:   }
    514:   if (st->D) {
    515:     PetscCall(MatGetLocalSize(st->A[0],NULL,&n));
    516:     PetscCall(VecGetLocalSize(st->D,&k));
    517:     PetscCheck(n==k,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %" PetscInt_FMT " (should be %" PetscInt_FMT ")",k,n);
    518:     if (!st->wb) PetscCall(VecDuplicate(st->D,&st->wb));
    519:   }
    520:   if (st->nmat<3 && st->transform) PetscCall(STComputeOperator(st));
    521:   else {
    522:     if (!st->T) PetscCall(PetscCalloc1(PetscMax(2,st->nmat),&st->T));
    523:   }
    524:   PetscTryTypeMethod(st,setup);
    525:   st->state = ST_STATE_SETUP;
    526:   PetscCall(PetscLogEventEnd(ST_SetUp,st,0,0,0));
    527:   PetscFunctionReturn(PETSC_SUCCESS);
    528: }

    530: /*
    531:    Computes coefficients for the transformed polynomial,
    532:    and stores the result in argument S.

    534:    alpha - value of the parameter of the transformed polynomial
    535:    beta - value of the previous shift (only used in inplace mode)
    536:    k - index of first matrix included in the computation
    537:    coeffs - coefficients of the expansion
    538:    initial - true if this is the first time
    539:    precond - whether the preconditioner matrix must be computed
    540: */
    541: PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,PetscBool precond,Mat *S)
    542: {
    543:   PetscInt       *matIdx=NULL,nmat,i,ini=-1;
    544:   PetscScalar    t=1.0,ta,gamma;
    545:   PetscBool      nz=PETSC_FALSE;
    546:   Mat            *A=precond?st->Psplit:st->A;
    547:   MatStructure   str=precond?st->strp:st->str;

    549:   PetscFunctionBegin;
    550:   nmat = st->nmat-k;
    551:   switch (st->matmode) {
    552:   case ST_MATMODE_INPLACE:
    553:     PetscCheck(st->nmat<=2,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
    554:     PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for split preconditioner");
    555:     if (initial) {
    556:       PetscCall(PetscObjectReference((PetscObject)A[0]));
    557:       *S = A[0];
    558:       gamma = alpha;
    559:     } else gamma = alpha-beta;
    560:     if (gamma != 0.0) {
    561:       if (st->nmat>1) PetscCall(MatAXPY(*S,gamma,A[1],str));
    562:       else PetscCall(MatShift(*S,gamma));
    563:     }
    564:     break;
    565:   case ST_MATMODE_SHELL:
    566:     PetscCheck(!precond,PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_SHELL not supported for split preconditioner");
    567:     if (initial) {
    568:       if (st->nmat>2) {
    569:         PetscCall(PetscMalloc1(nmat,&matIdx));
    570:         for (i=0;i<nmat;i++) matIdx[i] = k+i;
    571:       }
    572:       PetscCall(STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S));
    573:       if (st->nmat>2) PetscCall(PetscFree(matIdx));
    574:     } else PetscCall(STMatShellShift(*S,alpha));
    575:     break;
    576:   case ST_MATMODE_COPY:
    577:     if (coeffs) {
    578:       for (i=0;i<nmat && ini==-1;i++) {
    579:         if (coeffs[i]!=0.0) ini = i;
    580:         else t *= alpha;
    581:       }
    582:       if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
    583:       for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
    584:     } else { nz = PETSC_TRUE; ini = 0; }
    585:     if ((alpha == 0.0 || !nz) && t==1.0) {
    586:       PetscCall(PetscObjectReference((PetscObject)A[k+ini]));
    587:       PetscCall(MatDestroy(S));
    588:       *S = A[k+ini];
    589:     } else {
    590:       if (*S && *S!=A[k+ini]) {
    591:         PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
    592:         PetscCall(MatCopy(A[k+ini],*S,DIFFERENT_NONZERO_PATTERN));
    593:       } else {
    594:         PetscCall(MatDestroy(S));
    595:         PetscCall(MatDuplicate(A[k+ini],MAT_COPY_VALUES,S));
    596:         PetscCall(MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE));
    597:       }
    598:       if (coeffs && coeffs[ini]!=1.0) PetscCall(MatScale(*S,coeffs[ini]));
    599:       for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
    600:         t *= alpha;
    601:         ta = t;
    602:         if (coeffs) ta *= coeffs[i-k];
    603:         if (ta!=0.0) {
    604:           if (st->nmat>1) PetscCall(MatAXPY(*S,ta,A[i],str));
    605:           else PetscCall(MatShift(*S,ta));
    606:         }
    607:       }
    608:     }
    609:   }
    610:   PetscCall(MatSetOption(*S,MAT_SYMMETRIC,st->asymm));
    611:   PetscCall(MatSetOption(*S,MAT_HERMITIAN,(PetscImaginaryPart(st->sigma)==0.0)?st->aherm:PETSC_FALSE));
    612:   PetscFunctionReturn(PETSC_SUCCESS);
    613: }

    615: /*
    616:    Computes the values of the coefficients required by STMatMAXPY_Private
    617:    for the case of monomial basis.
    618: */
    619: PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
    620: {
    621:   PetscInt  k,i,ini,inip;

    623:   PetscFunctionBegin;
    624:   /* Compute binomial coefficients */
    625:   ini = (st->nmat*(st->nmat-1))/2;
    626:   for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
    627:   for (k=st->nmat-1;k>=1;k--) {
    628:     inip = ini+1;
    629:     ini = (k*(k-1))/2;
    630:     coeffs[ini] = 1.0;
    631:     for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
    632:   }
    633:   PetscFunctionReturn(PETSC_SUCCESS);
    634: }

    636: /*@
    637:    STPostSolve - Optional post-solve phase, intended for any actions that must
    638:    be performed on the ST object after the eigensolver has finished.

    640:    Collective

    642:    Input Parameters:
    643: .  st  - the spectral transformation context

    645:    Level: developer

    647: .seealso: EPSSolve()
    648: @*/
    649: PetscErrorCode STPostSolve(ST st)
    650: {
    651:   PetscFunctionBegin;
    654:   PetscTryTypeMethod(st,postsolve);
    655:   PetscFunctionReturn(PETSC_SUCCESS);
    656: }

    658: /*@
    659:    STBackTransform - Back-transformation phase, intended for
    660:    spectral transformations which require to transform the computed
    661:    eigenvalues back to the original eigenvalue problem.

    663:    Not Collective

    665:    Input Parameters:
    666: +  st   - the spectral transformation context
    667: .  n    - number of eigenvalues
    668: .  eigr - real part of a computed eigenvalues
    669: -  eigi - imaginary part of a computed eigenvalues

    671:    Level: developer

    673: .seealso: STIsInjective()
    674: @*/
    675: PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar* eigr,PetscScalar* eigi)
    676: {
    677:   PetscFunctionBegin;
    680:   PetscTryTypeMethod(st,backtransform,n,eigr,eigi);
    681:   PetscFunctionReturn(PETSC_SUCCESS);
    682: }

    684: /*@
    685:    STIsInjective - Ask if this spectral transformation is injective or not
    686:    (that is, if it corresponds to a one-to-one mapping). If not, then it
    687:    does not make sense to call STBackTransform().

    689:    Not Collective

    691:    Input Parameter:
    692: .  st   - the spectral transformation context

    694:    Output Parameter:
    695: .  is - the answer

    697:    Level: developer

    699: .seealso: STBackTransform()
    700: @*/
    701: PetscErrorCode STIsInjective(ST st,PetscBool* is)
    702: {
    703:   PetscBool      shell;

    705:   PetscFunctionBegin;

    710:   PetscCall(PetscObjectTypeCompare((PetscObject)st,STSHELL,&shell));
    711:   if (shell) PetscCall(STIsInjective_Shell(st,is));
    712:   else *is = st->ops->backtransform? PETSC_TRUE: PETSC_FALSE;
    713:   PetscFunctionReturn(PETSC_SUCCESS);
    714: }

    716: /*@
    717:    STMatSetUp - Build the preconditioner matrix used in STMatSolve().

    719:    Collective

    721:    Input Parameters:
    722: +  st     - the spectral transformation context
    723: .  sigma  - the shift
    724: -  coeffs - the coefficients (may be NULL)

    726:    Note:
    727:    This function is not intended to be called by end users, but by SLEPc
    728:    solvers that use ST. It builds matrix st->P as follows, then calls KSPSetUp().
    729: .vb
    730:     If (coeffs)  st->P = Sum_{i=0..nmat-1} coeffs[i]*sigma^i*A_i
    731:     else         st->P = Sum_{i=0..nmat-1} sigma^i*A_i
    732: .ve

    734:    Level: developer

    736: .seealso: STMatSolve()
    737: @*/
    738: PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar *coeffs)
    739: {
    740:   PetscFunctionBegin;
    743:   STCheckMatrices(st,1);

    745:   PetscCall(PetscLogEventBegin(ST_MatSetUp,st,0,0,0));
    746:   PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_FALSE,&st->P));
    747:   if (st->Psplit) PetscCall(STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,PETSC_TRUE,&st->Pmat));
    748:   PetscCall(ST_KSPSetOperators(st,st->P,st->Pmat?st->Pmat:st->P));
    749:   PetscCall(KSPSetUp(st->ksp));
    750:   PetscCall(PetscLogEventEnd(ST_MatSetUp,st,0,0,0));
    751:   PetscFunctionReturn(PETSC_SUCCESS);
    752: }

    754: /*@
    755:    STSetWorkVecs - Sets a number of work vectors into the ST object.

    757:    Collective

    759:    Input Parameters:
    760: +  st - the spectral transformation context
    761: -  nw - number of work vectors to allocate

    763:    Developer Notes:
    764:    This is SLEPC_EXTERN because it may be required by shell STs.

    766:    Level: developer

    768: .seealso: STMatCreateVecs()
    769: @*/
    770: PetscErrorCode STSetWorkVecs(ST st,PetscInt nw)
    771: {
    772:   PetscInt       i;

    774:   PetscFunctionBegin;
    777:   PetscCheck(nw>0,PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"nw must be > 0: nw = %" PetscInt_FMT,nw);
    778:   if (st->nwork < nw) {
    779:     PetscCall(VecDestroyVecs(st->nwork,&st->work));
    780:     st->nwork = nw;
    781:     PetscCall(PetscMalloc1(nw,&st->work));
    782:     for (i=0;i<nw;i++) PetscCall(STMatCreateVecs(st,&st->work[i],NULL));
    783:   }
    784:   PetscFunctionReturn(PETSC_SUCCESS);
    785: }