Date: 2021-02-01T14:41:50+00:00

Actual source code: stsolve.c
slepc-3.14.2 2021-02-01
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-2020, 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: {

     21:   if (st->M && st->P) {
     22:     MatMult(st->M,x,st->work[0]);
     23:     STMatSolve(st,st->work[0],y);
     24:   } else if (st->M) {
     25:     MatMult(st->M,x,y);
     26:   } else {
     27:     STMatSolve(st,x,y);
     28:   }
     29:   return(0);
     30: }

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

     37:    Collective on st

     39:    Input Parameters:
     40: +  st - the spectral transformation context
     41: -  x  - input vector

     43:    Output Parameter:
     44: .  y - output vector

     46:    Level: developer

     48: .seealso: STApplyTranspose(), STApplyHermitianTranspose()
     49: @*/
     50: PetscErrorCode STApply(ST st,Vec x,Vec y)
     51: {
     53:   Mat            Op;

     60:   STCheckMatrices(st,1);
     61:   if (x == y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     62:   VecSetErrorIfLocked(y,3);
     63:   if (!st->ops->apply) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have apply");
     64:   STGetOperator_Private(st,&Op);
     65:   MatMult(Op,x,y);
     66:   return(0);
     67: }

     69: PetscErrorCode STApplyMat_Generic(ST st,Mat B,Mat C)
     70: {
     72:   Mat            work;

     75:   if (st->M && st->P) {
     76:     MatMatMult(st->M,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&work);
     77:     STMatMatSolve(st,work,C);
     78:     MatDestroy(&work);
     79:   } else if (st->M) {
     80:     MatMatMult(st->M,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&C);
     81:   } else {
     82:     STMatMatSolve(st,B,C);
     83:   }
     84:   return(0);
     85: }

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

     92:    Collective on st

     94:    Input Parameters:
     95: +  st - the spectral transformation context
     96: -  X  - input matrix

     98:    Output Parameter:
     99: .  y - output matrix

    101:    Level: developer

    103: .seealso: STApply()
    104: @*/
    105: PetscErrorCode STApplyMat(ST st,Mat X,Mat Y)
    106: {

    114:   STCheckMatrices(st,1);
    115:   if (X == Y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"X and Y must be different matrices");
    116:   if (!st->ops->applymat) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have applymat");
    117:   (*st->ops->applymat)(st,X,Y);
    118:   return(0);
    119: }

    121: PetscErrorCode STApplyTranspose_Generic(ST st,Vec x,Vec y)
    122: {

    126:   if (st->M && st->P) {
    127:     STMatSolveTranspose(st,x,st->work[0]);
    128:     MatMultTranspose(st->M,st->work[0],y);
    129:   } else if (st->M) {
    130:     MatMultTranspose(st->M,x,y);
    131:   } else {
    132:     STMatSolveTranspose(st,x,y);
    133:   }
    134:   return(0);
    135: }

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

    142:    Collective on st

    144:    Input Parameters:
    145: +  st - the spectral transformation context
    146: -  x  - input vector

    148:    Output Parameter:
    149: .  y - output vector

    151:    Level: developer

    153: .seealso: STApply(), STApplyHermitianTranspose()
    154: @*/
    155: PetscErrorCode STApplyTranspose(ST st,Vec x,Vec y)
    156: {
    158:   Mat            Op;

    165:   STCheckMatrices(st,1);
    166:   if (x == y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    167:   VecSetErrorIfLocked(y,3);
    168:   if (!st->ops->applytrans) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have applytrans");
    169:   STGetOperator_Private(st,&Op);
    170:   MatMultTranspose(Op,x,y);
    171:   return(0);
    172: }

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

    179:    Collective on st

    181:    Input Parameters:
    182: +  st - the spectral transformation context
    183: -  x  - input vector

    185:    Output Parameter:
    186: .  y - output vector

    188:    Note:
    189:    Currently implemented via STApplyTranspose() with appropriate conjugation.

    191:    Level: developer

    193: .seealso: STApply(), STApplyTranspose()
    194: @*/
    195: PetscErrorCode STApplyHermitianTranspose(ST st,Vec x,Vec y)
    196: {
    198:   Mat            Op;

    205:   STCheckMatrices(st,1);
    206:   if (x == y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    207:   VecSetErrorIfLocked(y,3);
    208:   if (!st->ops->applytrans) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have applytrans");
    209:   STGetOperator_Private(st,&Op);
    210:   MatMultHermitianTranspose(Op,x,y);
    211:   return(0);
    212: }

    214: /*@
    215:    STGetBilinearForm - Returns the matrix used in the bilinear form with a
    216:    generalized problem with semi-definite B.

    218:    Not collective, though a parallel Mat may be returned

    220:    Input Parameters:
    221: .  st - the spectral transformation context

    223:    Output Parameter:
    224: .  B - output matrix

    226:    Notes:
    227:    The output matrix B must be destroyed after use. It will be NULL in
    228:    case of standard eigenproblems.

    230:    Level: developer
    231: @*/
    232: PetscErrorCode STGetBilinearForm(ST st,Mat *B)
    233: {

    240:   STCheckMatrices(st,1);
    241:   (*st->ops->getbilinearform)(st,B);
    242:   return(0);
    243: }

    245: PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
    246: {

    250:   if (st->nmat==1) *B = NULL;
    251:   else {
    252:     *B = st->A[1];
    253:     PetscObjectReference((PetscObject)*B);
    254:   }
    255:   return(0);
    256: }

    258: static PetscErrorCode MatMult_STOperator(Mat Op,Vec x,Vec y)
    259: {
    261:   ST             st;

    264:   MatShellGetContext(Op,(void**)&st);
    265:   STSetUp(st);
    266:   PetscLogEventBegin(ST_Apply,st,x,y,0);
    267:   if (st->D) { /* with balancing */
    268:     VecPointwiseDivide(st->wb,x,st->D);
    269:     (*st->ops->apply)(st,st->wb,y);
    270:     VecPointwiseMult(y,y,st->D);
    271:   } else {
    272:     (*st->ops->apply)(st,x,y);
    273:   }
    274:   PetscLogEventEnd(ST_Apply,st,x,y,0);
    275:   return(0);
    276: }

    278: static PetscErrorCode MatMultTranspose_STOperator(Mat Op,Vec x,Vec y)
    279: {
    281:   ST             st;

    284:   MatShellGetContext(Op,(void**)&st);
    285:   STSetUp(st);
    286:   PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0);
    287:   if (st->D) { /* with balancing */
    288:     VecPointwiseMult(st->wb,x,st->D);
    289:     (*st->ops->applytrans)(st,st->wb,y);
    290:     VecPointwiseDivide(y,y,st->D);
    291:   } else {
    292:     (*st->ops->applytrans)(st,x,y);
    293:   }
    294:   PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0);
    295:   return(0);
    296: }

    298: #if defined(PETSC_USE_COMPLEX)
    299: static PetscErrorCode MatMultHermitianTranspose_STOperator(Mat Op,Vec x,Vec y)
    300: {
    302:   ST             st;

    305:   MatShellGetContext(Op,(void**)&st);
    306:   STSetUp(st);
    307:   PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0);
    308:   if (!st->wht) {
    309:     MatCreateVecs(st->A[0],&st->wht,NULL);
    310:     PetscLogObjectParent((PetscObject)st,(PetscObject)st->wht);
    311:   }
    312:   VecCopy(x,st->wht);
    313:   VecConjugate(st->wht);
    314:   if (st->D) { /* with balancing */
    315:     VecPointwiseMult(st->wb,st->wht,st->D);
    316:     (*st->ops->applytrans)(st,st->wb,y);
    317:     VecPointwiseDivide(y,y,st->D);
    318:   } else {
    319:     (*st->ops->applytrans)(st,st->wht,y);
    320:   }
    321:   VecConjugate(y);
    322:   PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0);
    323:   return(0);
    324: }
    325: #endif

    327: static PetscErrorCode MatMatMult_STOperator(Mat Op,Mat B,Mat C,void *ctx)
    328: {
    330:   ST             st;

    333:   MatShellGetContext(Op,(void**)&st);
    334:   STSetUp(st);
    335:   PetscLogEventBegin(ST_Apply,st,B,C,0);
    336:   STApplyMat_Generic(st,B,C);
    337:   PetscLogEventEnd(ST_Apply,st,B,C,0);
    338:   return(0);
    339: }

    341: PetscErrorCode STGetOperator_Private(ST st,Mat *Op)
    342: {
    344:   PetscInt       m,n,M,N;
    345:   Vec            v;
    346:   VecType        vtype;

    349:   if (!st->Op) {
    350:     if (Op) *Op = NULL;
    351:     /* create the shell matrix */
    352:     MatGetLocalSize(st->A[0],&m,&n);
    353:     MatGetSize(st->A[0],&M,&N);
    354:     MatCreateShell(PetscObjectComm((PetscObject)st),m,n,M,N,st,&st->Op);
    355:     MatShellSetOperation(st->Op,MATOP_MULT,(void(*)(void))MatMult_STOperator);
    356:     MatShellSetOperation(st->Op,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator);
    357: #if defined(PETSC_USE_COMPLEX)
    358:     MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultHermitianTranspose_STOperator);
    359: #else
    360:     MatShellSetOperation(st->Op,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultTranspose_STOperator);
    361: #endif
    362:     if (!st->D && st->ops->apply==STApply_Generic) {
    363:       MatShellSetMatProductOperation(st->Op,MATPRODUCT_AB,NULL,MatMatMult_STOperator,NULL,MATDENSE,MATDENSE);
    364:     }
    365:     /* make sure the shell matrix generates a vector of the same type as the problem matrices */
    366:     MatCreateVecs(st->A[0],&v,NULL);
    367:     VecGetType(v,&vtype);
    368:     MatShellSetVecType(st->Op,vtype);
    369:     VecDestroy(&v);
    370:     /* build the operator matrices */
    371:     STComputeOperator(st);
    372:   }
    373:   if (Op) *Op = st->Op;
    374:   return(0);
    375: }

    377: /*@
    378:    STGetOperator - Returns a shell matrix that represents the operator of the
    379:    spectral transformation.

    381:    Collective on st

    383:    Input Parameter:
    384: .  st - the spectral transformation context

    386:    Output Parameter:
    387: .  Op - operator matrix

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

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

    396: .vb
    397:       Op = D*inv(K)*M*inv(D)
    398: .ve

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

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

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

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

    419:    Level: advanced

    421: .seealso: STApply(), STApplyTranspose(), STSetBalanceMatrix(), STShellSetApply(),
    422:           STGetKSP(), STSetShift(), STRestoreOperator(), STSetMatrices()
    423: @*/
    424: PetscErrorCode STGetOperator(ST st,Mat *Op)
    425: {

    431:   STCheckMatrices(st,1);
    432:   STCheckNotSeized(st,1);
    433:   if (st->nmat>2) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"The operator is not defined in polynomial eigenproblems");
    434:   STGetOperator_Private(st,Op);
    435:   if (Op) st->opseized = PETSC_TRUE;
    436:   return(0);
    437: }

    439: /*@
    440:    STRestoreOperator - Restore the previously seized operator matrix.

    442:    Collective on st

    444:    Input Parameters:
    445: +  st - the spectral transformation context
    446: -  Op - operator matrix

    448:    Notes:
    449:    The arguments must match the corresponding call to STGetOperator().

    451:    Level: advanced

    453: .seealso: STGetOperator()
    454: @*/
    455: PetscErrorCode STRestoreOperator(ST st,Mat *Op)
    456: {
    461:   if (!st->opseized) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Must be called after STGetOperator()");
    462:   *Op = NULL;
    463:   st->opseized = PETSC_FALSE;
    464:   return(0);
    465: }

    467: /*
    468:    STComputeOperator - Computes the matrices that constitute the operator

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

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

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

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

    484:    STSHELL does not compute anything here, but sets the flag as if it was ready.
    485: */
    486: PetscErrorCode STComputeOperator(ST st)
    487: {
    489:   PC             pc;

    494:   if (!st->opready && st->ops->computeoperator) {
    495:     PetscInfo(st,"Building the operator matrices\n");
    496:     STCheckMatrices(st,1);
    497:     if (!st->T) {
    498:       PetscCalloc1(PetscMax(2,st->nmat),&st->T);
    499:       PetscLogObjectMemory((PetscObject)st,PetscMax(2,st->nmat)*sizeof(Mat));
    500:     }
    501:     PetscLogEventBegin(ST_ComputeOperator,st,0,0,0);
    502:     (*st->ops->computeoperator)(st);
    503:     PetscLogEventEnd(ST_ComputeOperator,st,0,0,0);
    504:     if (st->usesksp) {
    505:       if (!st->ksp) { STGetKSP(st,&st->ksp); }
    506:       if (st->P) {
    507:         STSetDefaultKSP(st);
    508:         STCheckFactorPackage(st);
    509:         KSPSetOperators(st->ksp,st->P,st->P);
    510:       } else {
    511:         /* STPRECOND defaults to PCNONE if st->P is empty */
    512:         KSPGetPC(st->ksp,&pc);
    513:         PCSetType(pc,PCNONE);
    514:       }
    515:     }
    516:   }
    517:   st->opready = PETSC_TRUE;
    518:   return(0);
    519: }

    521: /*@
    522:    STSetUp - Prepares for the use of a spectral transformation.

    524:    Collective on st

    526:    Input Parameter:
    527: .  st - the spectral transformation context

    529:    Level: advanced

    531: .seealso: STCreate(), STApply(), STDestroy()
    532: @*/
    533: PetscErrorCode STSetUp(ST st)
    534: {
    535:   PetscInt       i,n,k;

    541:   STCheckMatrices(st,1);
    542:   switch (st->state) {
    543:     case ST_STATE_INITIAL:
    544:       PetscInfo(st,"Setting up new ST\n");
    545:       if (!((PetscObject)st)->type_name) {
    546:         STSetType(st,STSHIFT);
    547:       }
    548:       break;
    549:     case ST_STATE_SETUP:
    550:       return(0);
    551:     case ST_STATE_UPDATED:
    552:       PetscInfo(st,"Setting up updated ST\n");
    553:       break;
    554:   }
    555:   PetscLogEventBegin(ST_SetUp,st,0,0,0);
    556:   if (st->state!=ST_STATE_UPDATED) {
    557:     if (!(st->nmat<3 && st->opready)) {
    558:       if (st->T) {
    559:         for (i=0;i<PetscMax(2,st->nmat);i++) {
    560:           MatDestroy(&st->T[i]);
    561:         }
    562:       }
    563:       MatDestroy(&st->P);
    564:     }
    565:   }
    566:   if (st->D) {
    567:     MatGetLocalSize(st->A[0],NULL,&n);
    568:     VecGetLocalSize(st->D,&k);
    569:     if (n != k) SETERRQ2(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %D (should be %D)",k,n);
    570:     if (!st->wb) {
    571:       VecDuplicate(st->D,&st->wb);
    572:       PetscLogObjectParent((PetscObject)st,(PetscObject)st->wb);
    573:     }
    574:   }
    575:   if (st->nmat<3 && st->transform) {
    576:     STComputeOperator(st);
    577:   } else {
    578:     if (!st->T) {
    579:       PetscCalloc1(PetscMax(2,st->nmat),&st->T);
    580:       PetscLogObjectMemory((PetscObject)st,PetscMax(2,st->nmat)*sizeof(Mat));
    581:     }
    582:   }
    583:   if (st->ops->setup) { (*st->ops->setup)(st); }
    584:   st->state = ST_STATE_SETUP;
    585:   PetscLogEventEnd(ST_SetUp,st,0,0,0);
    586:   return(0);
    587: }

    589: /*
    590:    Computes coefficients for the transformed polynomial,
    591:    and stores the result in argument S.

    593:    alpha - value of the parameter of the transformed polynomial
    594:    beta - value of the previous shift (only used in inplace mode)
    595:    k - index of first matrix included in the computation
    596:    coeffs - coefficients of the expansion
    597:    initial - true if this is the first time (only relevant for shell mode)
    598: */
    599: PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,Mat *S)
    600: {
    602:   PetscInt       *matIdx=NULL,nmat,i,ini=-1;
    603:   PetscScalar    t=1.0,ta,gamma;
    604:   PetscBool      nz=PETSC_FALSE;

    607:   nmat = st->nmat-k;
    608:   switch (st->matmode) {
    609:   case ST_MATMODE_INPLACE:
    610:     if (st->nmat>2) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
    611:     if (initial) {
    612:       PetscObjectReference((PetscObject)st->A[0]);
    613:       *S = st->A[0];
    614:       gamma = alpha;
    615:     } else gamma = alpha-beta;
    616:     if (gamma != 0.0) {
    617:       if (st->nmat>1) {
    618:         MatAXPY(*S,gamma,st->A[1],st->str);
    619:       } else {
    620:         MatShift(*S,gamma);
    621:       }
    622:     }
    623:     break;
    624:   case ST_MATMODE_SHELL:
    625:     if (initial) {
    626:       if (st->nmat>2) {
    627:         PetscMalloc1(nmat,&matIdx);
    628:         for (i=0;i<nmat;i++) matIdx[i] = k+i;
    629:       }
    630:       STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S);
    631:       PetscLogObjectParent((PetscObject)st,(PetscObject)*S);
    632:       if (st->nmat>2) { PetscFree(matIdx); }
    633:     } else {
    634:       STMatShellShift(*S,alpha);
    635:     }
    636:     break;
    637:   case ST_MATMODE_COPY:
    638:     if (coeffs) {
    639:       for (i=0;i<nmat && ini==-1;i++) {
    640:         if (coeffs[i]!=0.0) ini = i;
    641:         else t *= alpha;
    642:       }
    643:       if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
    644:       for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
    645:     } else { nz = PETSC_TRUE; ini = 0; }
    646:     if ((alpha == 0.0 || !nz) && t==1.0) {
    647:       PetscObjectReference((PetscObject)st->A[k+ini]);
    648:       MatDestroy(S);
    649:       *S = st->A[k+ini];
    650:     } else {
    651:       if (*S && *S!=st->A[k+ini]) {
    652:         MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);
    653:         MatCopy(st->A[k+ini],*S,DIFFERENT_NONZERO_PATTERN);
    654:       } else {
    655:         MatDestroy(S);
    656:         MatDuplicate(st->A[k+ini],MAT_COPY_VALUES,S);
    657:         MatSetOption(*S,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE);
    658:         PetscLogObjectParent((PetscObject)st,(PetscObject)*S);
    659:       }
    660:       if (coeffs && coeffs[ini]!=1.0) {
    661:         MatScale(*S,coeffs[ini]);
    662:       }
    663:       for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
    664:         t *= alpha;
    665:         ta = t;
    666:         if (coeffs) ta *= coeffs[i-k];
    667:         if (ta!=0.0) {
    668:           if (st->nmat>1) {
    669:             MatAXPY(*S,ta,st->A[i],st->str);
    670:           } else {
    671:             MatShift(*S,ta);
    672:           }
    673:         }
    674:       }
    675:     }
    676:   }
    677:   MatSetOption(*S,MAT_SYMMETRIC,st->asymm);
    678:   MatSetOption(*S,MAT_HERMITIAN,(PetscImaginaryPart(st->sigma)==0.0)?st->aherm:PETSC_FALSE);
    679:   return(0);
    680: }

    682: /*
    683:    Computes the values of the coefficients required by STMatMAXPY_Private
    684:    for the case of monomial basis.
    685: */
    686: PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
    687: {
    688:   PetscInt  k,i,ini,inip;

    691:   /* Compute binomial coefficients */
    692:   ini = (st->nmat*(st->nmat-1))/2;
    693:   for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
    694:   for (k=st->nmat-1;k>=1;k--) {
    695:     inip = ini+1;
    696:     ini = (k*(k-1))/2;
    697:     coeffs[ini] = 1.0;
    698:     for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
    699:   }
    700:   return(0);
    701: }

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

    707:    Collective on st

    709:    Input Parameters:
    710: .  st  - the spectral transformation context

    712:    Level: developer

    714: .seealso: EPSSolve()
    715: @*/
    716: PetscErrorCode STPostSolve(ST st)
    717: {

    723:   if (st->ops->postsolve) {
    724:     (*st->ops->postsolve)(st);
    725:   }
    726:   return(0);
    727: }

    729: /*@
    730:    STBackTransform - Back-transformation phase, intended for
    731:    spectral transformations which require to transform the computed
    732:    eigenvalues back to the original eigenvalue problem.

    734:    Not Collective

    736:    Input Parameters:
    737: +  st   - the spectral transformation context
    738:    eigr - real part of a computed eigenvalue
    739: -  eigi - imaginary part of a computed eigenvalue

    741:    Level: developer

    743: .seealso: STIsInjective()
    744: @*/
    745: PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar* eigr,PetscScalar* eigi)
    746: {

    752:   if (st->ops->backtransform) {
    753:     (*st->ops->backtransform)(st,n,eigr,eigi);
    754:   }
    755:   return(0);
    756: }

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

    763:    Not collective

    765:    Input Parameter:
    766: .  st   - the spectral transformation context

    768:    Output Parameter:
    769: .  is - the answer

    771:    Level: developer

    773: .seealso: STBackTransform()
    774: @*/
    775: PetscErrorCode STIsInjective(ST st,PetscBool* is)
    776: {
    778:   PetscBool      shell;

    785:   PetscObjectTypeCompare((PetscObject)st,STSHELL,&shell);
    786:   if (shell) {
    787:     STIsInjective_Shell(st,is);
    788:   } else *is = st->ops->backtransform? PETSC_TRUE: PETSC_FALSE;
    789:   return(0);
    790: }

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

    795:    Collective on st

    797:    Input Parameters:
    798: +  st     - the spectral transformation context
    799: .  sigma  - the shift
    800: -  coeffs - the coefficients (may be NULL)

    802:    Note:
    803:    This function is not intended to be called by end users, but by SLEPc
    804:    solvers that use ST. It builds matrix st->P as follows, then calls KSPSetUp().
    805: .vb
    806:     If (coeffs):  st->P = Sum_{i=0:nmat-1} coeffs[i]*sigma^i*A_i.
    807:     else          st->P = Sum_{i=0:nmat-1} sigma^i*A_i
    808: .ve

    810:    Level: developer

    812: .seealso: STMatSolve()
    813: @*/
    814: PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar *coeffs)
    815: {

    821:   STCheckMatrices(st,1);

    823:   PetscLogEventBegin(ST_MatSetUp,st,0,0,0);
    824:   STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,&st->P);
    825:   if (!st->ksp) { STGetKSP(st,&st->ksp); }
    826:   STCheckFactorPackage(st);
    827:   KSPSetOperators(st->ksp,st->P,st->P);
    828:   KSPSetUp(st->ksp);
    829:   PetscLogEventEnd(ST_MatSetUp,st,0,0,0);
    830:   return(0);
    831: }

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

    836:    Collective on st

    838:    Input Parameters:
    839: +  st - the spectral transformation context
    840: -  nw - number of work vectors to allocate

    842:    Developers Note:
    843:    This is SLEPC_EXTERN because it may be required by shell STs.

    845:    Level: developer
    846: @*/
    847: PetscErrorCode STSetWorkVecs(ST st,PetscInt nw)
    848: {
    850:   PetscInt       i;

    855:   if (nw <= 0) SETERRQ1(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_OUTOFRANGE,"nw must be > 0: nw = %D",nw);
    856:   if (st->nwork < nw) {
    857:     VecDestroyVecs(st->nwork,&st->work);
    858:     st->nwork = nw;
    859:     PetscMalloc1(nw,&st->work);
    860:     for (i=0;i<nw;i++) { STMatCreateVecs(st,&st->work[i],NULL); }
    861:     PetscLogObjectParents(st,nw,st->work);
    862:   }
    863:   return(0);
    864: }