Date: 2016-03-29T14:57:11+00:00

Actual source code: stsolve.c
slepc-3.6.3 2016-03-29
Report Typos and Errors

      1: /*
      2:     The ST (spectral transformation) interface routines, callable by users.

      4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      6:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

      8:    This file is part of SLEPc.

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

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

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

     24: #include <slepc/private/stimpl.h>            /*I "slepcst.h" I*/

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

     33:    Collective on ST and Vec

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

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

     42:    Level: developer

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

     55:   STCheckMatrices(st,1);
     56:   if (x == y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
     57:   VecLocked(y,3);

     59:   if (!st->setupcalled) { STSetUp(st); }

     61:   if (!st->ops->apply) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have apply");
     62:   VecLockPush(x);
     63:   PetscLogEventBegin(ST_Apply,st,x,y,0);
     64:   if (st->D) { /* with balancing */
     65:     VecPointwiseDivide(st->wb,x,st->D);
     66:     (*st->ops->apply)(st,st->wb,y);
     67:     VecPointwiseMult(y,y,st->D);
     68:   } else {
     69:     (*st->ops->apply)(st,x,y);
     70:   }
     71:   PetscLogEventEnd(ST_Apply,st,x,y,0);
     72:   VecLockPop(x);
     73:   return(0);
     74: }

     78: /*@
     79:    STApplyTranspose - Applies the transpose of the operator to a vector, for
     80:    instance B^T(A - sB)^-T in the case of the shift-and-invert tranformation
     81:    and generalized eigenproblem.

     83:    Collective on ST and Vec

     85:    Input Parameters:
     86: +  st - the spectral transformation context
     87: -  x  - input vector

     89:    Output Parameter:
     90: .  y - output vector

     92:    Level: developer

     94: .seealso: STApply()
     95: @*/
     96: PetscErrorCode STApplyTranspose(ST st,Vec x,Vec y)
     97: {

    105:   STCheckMatrices(st,1);
    106:   if (x == y) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_IDN,"x and y must be different vectors");
    107:   VecLocked(y,3);

    109:   if (!st->setupcalled) { STSetUp(st); }

    111:   if (!st->ops->applytrans) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST does not have applytrans");
    112:   VecLockPush(x);
    113:   PetscLogEventBegin(ST_ApplyTranspose,st,x,y,0);
    114:   if (st->D) { /* with balancing */
    115:     VecPointwiseMult(st->wb,x,st->D);
    116:     (*st->ops->applytrans)(st,st->wb,y);
    117:     VecPointwiseDivide(y,y,st->D);
    118:   } else {
    119:     (*st->ops->applytrans)(st,x,y);
    120:   }
    121:   PetscLogEventEnd(ST_ApplyTranspose,st,x,y,0);
    122:   VecLockPop(x);
    123:   return(0);
    124: }

    128: /*@
    129:    STGetBilinearForm - Returns the matrix used in the bilinear form with a
    130:    generalized problem with semi-definite B.

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

    134:    Input Parameters:
    135: .  st - the spectral transformation context

    137:    Output Parameter:
    138: .  B - output matrix

    140:    Notes:
    141:    The output matrix B must be destroyed after use. It will be NULL in
    142:    case of standard eigenproblems.

    144:    Level: developer
    145: @*/
    146: PetscErrorCode STGetBilinearForm(ST st,Mat *B)
    147: {

    154:   STCheckMatrices(st,1);
    155:   (*st->ops->getbilinearform)(st,B);
    156:   return(0);
    157: }

    161: PetscErrorCode STGetBilinearForm_Default(ST st,Mat *B)
    162: {

    166:   if (st->nmat==1) *B = NULL;
    167:   else {
    168:     *B = st->A[1];
    169:     PetscObjectReference((PetscObject)*B);
    170:   }
    171:   return(0);
    172: }

    176: /*@
    177:    STComputeExplicitOperator - Computes the explicit operator associated
    178:    to the eigenvalue problem with the specified spectral transformation.

    180:    Collective on ST

    182:    Input Parameter:
    183: .  st - the spectral transform context

    185:    Output Parameter:
    186: .  mat - the explicit operator

    188:    Notes:
    189:    This routine builds a matrix containing the explicit operator. For
    190:    example, in generalized problems with shift-and-invert spectral
    191:    transformation the result would be matrix (A - s B)^-1 B.

    193:    This computation is done by applying the operator to columns of the
    194:    identity matrix. This is analogous to MatComputeExplicitOperator().

    196:    Level: advanced

    198: .seealso: STApply()
    199: @*/
    200: PetscErrorCode STComputeExplicitOperator(ST st,Mat *mat)
    201: {
    202:   PetscErrorCode    ierr;
    203:   Vec               in,out;
    204:   PetscInt          i,M,m,*rows,start,end;
    205:   const PetscScalar *array;
    206:   PetscScalar       one = 1.0;
    207:   PetscMPIInt       size;

    212:   STCheckMatrices(st,1);
    213:   if (st->nmat>2) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_ARG_WRONGSTATE,"Can only be used with 1 or 2 matrices");
    214:   MPI_Comm_size(PetscObjectComm((PetscObject)st),&size);

    216:   MatCreateVecs(st->A[0],&in,&out);
    217:   VecGetSize(out,&M);
    218:   VecGetLocalSize(out,&m);
    219:   VecSetOption(in,VEC_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE);
    220:   VecGetOwnershipRange(out,&start,&end);
    221:   PetscMalloc1(m,&rows);
    222:   for (i=0;i<m;i++) rows[i] = start + i;

    224:   MatCreate(PetscObjectComm((PetscObject)st),mat);
    225:   MatSetSizes(*mat,m,m,M,M);
    226:   if (size == 1) {
    227:     MatSetType(*mat,MATSEQDENSE);
    228:     MatSeqDenseSetPreallocation(*mat,NULL);
    229:   } else {
    230:     MatSetType(*mat,MATMPIAIJ);
    231:     MatMPIAIJSetPreallocation(*mat,m,NULL,M-m,NULL);
    232:   }

    234:   for (i=0;i<M;i++) {
    235:     VecSet(in,0.0);
    236:     VecSetValues(in,1,&i,&one,INSERT_VALUES);
    237:     VecAssemblyBegin(in);
    238:     VecAssemblyEnd(in);

    240:     STApply(st,in,out);

    242:     VecGetArrayRead(out,&array);
    243:     MatSetValues(*mat,m,rows,1,&i,array,INSERT_VALUES);
    244:     VecRestoreArrayRead(out,&array);
    245:   }
    246:   PetscFree(rows);
    247:   VecDestroy(&in);
    248:   VecDestroy(&out);
    249:   MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
    250:   MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
    251:   return(0);
    252: }

    256: /*@
    257:    STSetUp - Prepares for the use of a spectral transformation.

    259:    Collective on ST

    261:    Input Parameter:
    262: .  st - the spectral transformation context

    264:    Level: advanced

    266: .seealso: STCreate(), STApply(), STDestroy()
    267: @*/
    268: PetscErrorCode STSetUp(ST st)
    269: {
    270:   PetscInt       i,n,k;

    275:   STCheckMatrices(st,1);
    276:   if (st->setupcalled) return(0);
    277:   PetscInfo(st,"Setting up new ST\n");
    278:   PetscLogEventBegin(ST_SetUp,st,0,0,0);
    279:   if (!((PetscObject)st)->type_name) {
    280:     STSetType(st,STSHIFT);
    281:   }
    282:   if (!st->T) {
    283:     PetscMalloc(PetscMax(2,st->nmat)*sizeof(Mat),&st->T);
    284:     PetscLogObjectMemory((PetscObject)st,PetscMax(2,st->nmat)*sizeof(Mat));
    285:     for (i=0;i<PetscMax(2,st->nmat);i++) st->T[i] = NULL;
    286:   } else {
    287:     for (i=0;i<PetscMax(2,st->nmat);i++) {
    288:       MatDestroy(&st->T[i]);
    289:     }
    290:   }
    291:   MatDestroy(&st->P);
    292:   if (!st->w) {
    293:     MatCreateVecs(st->A[0],&st->w,NULL);
    294:     PetscLogObjectParent((PetscObject)st,(PetscObject)st->w);
    295:   }
    296:   if (st->D) {
    297:     MatGetLocalSize(st->A[0],NULL,&n);
    298:     VecGetLocalSize(st->D,&k);
    299:     if (n != k) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %D (should be %D)",k,n);
    300:     if (!st->wb) {
    301:       VecDuplicate(st->D,&st->wb);
    302:       PetscLogObjectParent((PetscObject)st,(PetscObject)st->wb);
    303:     }
    304:   }
    305:   if (st->ops->setup) { (*st->ops->setup)(st); }
    306:   st->setupcalled = 1;
    307:   PetscLogEventEnd(ST_SetUp,st,0,0,0);
    308:   return(0);
    309: }

    313: /*
    314:    Computes coefficients for the transformed polynomial,
    315:    and stores the result in argument S.

    317:    alpha - value of the parameter of the transformed polynomial
    318:    beta - value of the previous shift (only used in inplace mode)
    319:    k - number of A matrices involved in the computation
    320:    coeffs - coefficients of the expansion
    321:    initial - true if this is the first time (only relevant for shell mode)
    322: */
    323: PetscErrorCode STMatMAXPY_Private(ST st,PetscScalar alpha,PetscScalar beta,PetscInt k,PetscScalar *coeffs,PetscBool initial,Mat *S)
    324: {
    326:   PetscInt       *matIdx=NULL,nmat,i,ini=-1;
    327:   PetscScalar    t=1.0,ta,gamma;
    328:   PetscBool      nz=PETSC_FALSE;

    331:   nmat = st->nmat-k;
    332:   switch (st->shift_matrix) {
    333:   case ST_MATMODE_INPLACE:
    334:     if (st->nmat>2) SETERRQ(PetscObjectComm((PetscObject)st),PETSC_ERR_SUP,"ST_MATMODE_INPLACE not supported for polynomial eigenproblems");
    335:     if (initial) {
    336:       PetscObjectReference((PetscObject)st->A[0]);
    337:       *S = st->A[0];
    338:       gamma = alpha;
    339:     } else gamma = alpha-beta;
    340:     if (gamma != 0.0) {
    341:       if (st->nmat>1) {
    342:         MatAXPY(*S,gamma,st->A[1],st->str);
    343:       } else {
    344:         MatShift(*S,gamma);
    345:       }
    346:     }
    347:     break;
    348:   case ST_MATMODE_SHELL:
    349:     if (initial) {
    350:       if (st->nmat>2) {
    351:         PetscMalloc(nmat*sizeof(PetscInt),&matIdx);
    352:         for (i=0;i<nmat;i++) matIdx[i] = k+i;
    353:       }
    354:       STMatShellCreate(st,alpha,nmat,matIdx,coeffs,S);
    355:       PetscLogObjectParent((PetscObject)st,(PetscObject)*S);
    356:       if (st->nmat>2) { PetscFree(matIdx); }
    357:     } else {
    358:       STMatShellShift(*S,alpha);
    359:     }
    360:     break;
    361:   case ST_MATMODE_COPY:
    362:     if (coeffs) {
    363:       for (i=0;i<nmat && ini==-1;i++) {
    364:         if (coeffs[i]!=0.0) ini = i;
    365:         else t *= alpha;
    366:       }
    367:       if (coeffs[ini] != 1.0) nz = PETSC_TRUE;
    368:       for (i=ini+1;i<nmat&&!nz;i++) if (coeffs[i]!=0.0) nz = PETSC_TRUE;
    369:     } else { nz = PETSC_TRUE; ini = 0; }
    370:     if ((alpha == 0.0 || !nz) && t==1.0) {
    371:       MatDestroy(S);
    372:       PetscObjectReference((PetscObject)st->A[k+ini]);
    373:       *S = st->A[k+ini];
    374:     } else {
    375:       if (*S && *S!=st->A[k+ini]) {
    376:         MatCopy(st->A[k+ini],*S,DIFFERENT_NONZERO_PATTERN);
    377:       } else {
    378:         MatDestroy(S);
    379:         MatDuplicate(st->A[k+ini],MAT_COPY_VALUES,S);
    380:         PetscLogObjectParent((PetscObject)st,(PetscObject)*S);
    381:       }
    382:       if (coeffs && coeffs[ini]!=1.0) {
    383:         MatScale(*S,coeffs[ini]);
    384:       }
    385:       for (i=ini+k+1;i<PetscMax(2,st->nmat);i++) {
    386:         t *= alpha;
    387:         ta = t;
    388:         if (coeffs) ta *= coeffs[i-k];
    389:         if (ta!=0.0) {
    390:           if (st->nmat>1) {
    391:             MatAXPY(*S,ta,st->A[i],st->str);
    392:           } else {
    393:             MatShift(*S,ta);
    394:           }
    395:         }
    396:       }
    397:     }
    398:   }
    399:   STMatSetHermitian(st,*S);
    400:   return(0);
    401: }

    405: /*
    406:    Computes the values of the coefficients required by STMatMAXPY_Private
    407:    for the case of monomial basis.
    408: */
    409: PetscErrorCode STCoeffs_Monomial(ST st, PetscScalar *coeffs)
    410: {
    411:   PetscInt  k,i,ini,inip;

    414:   /* Compute binomial coefficients */
    415:   ini = (st->nmat*(st->nmat-1))/2;
    416:   for (i=0;i<st->nmat;i++) coeffs[ini+i]=1.0;
    417:   for (k=st->nmat-1;k>=1;k--) {
    418:     inip = ini+1;
    419:     ini = (k*(k-1))/2;
    420:     coeffs[ini] = 1.0;
    421:     for (i=1;i<k;i++) coeffs[ini+i] = coeffs[ini+i-1]+coeffs[inip+i-1];
    422:   }
    423:   return(0);
    424: }

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

    432:    Collective on ST

    434:    Input Parameters:
    435: .  st  - the spectral transformation context

    437:    Level: developer

    439: .seealso: EPSSolve()
    440: @*/
    441: PetscErrorCode STPostSolve(ST st)
    442: {

    448:   if (st->ops->postsolve) {
    449:     (*st->ops->postsolve)(st);
    450:   }
    451:   return(0);
    452: }

    456: /*@
    457:    STBackTransform - Back-transformation phase, intended for
    458:    spectral transformations which require to transform the computed
    459:    eigenvalues back to the original eigenvalue problem.

    461:    Not Collective

    463:    Input Parameters:
    464:    st   - the spectral transformation context
    465:    eigr - real part of a computed eigenvalue
    466:    eigi - imaginary part of a computed eigenvalue

    468:    Level: developer
    469: @*/
    470: PetscErrorCode STBackTransform(ST st,PetscInt n,PetscScalar* eigr,PetscScalar* eigi)
    471: {

    477:   if (st->ops->backtransform) {
    478:     (*st->ops->backtransform)(st,n,eigr,eigi);
    479:   }
    480:   return(0);
    481: }

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

    488:    Collective on ST

    490:    Input Parameters:
    491: +  st     - the spectral transformation context
    492: .  sigma  - the shift
    493: -  coeffs - the coefficients (may be NULL)

    495:    Note:
    496:    This function is not intended to be called by end users, but by SLEPc
    497:    solvers that use ST. It builds matrix st->P as follows, then calls KSPSetUp().
    498: .vb
    499:     If (coeffs):  st->P = Sum_{i=0:nmat-1} coeffs[i]*sigma^i*A_i.
    500:     else          st->P = Sum_{i=0:nmat-1} sigma^i*A_i
    501: .ve

    503:    Level: developer

    505: .seealso: STMatSolve()
    506: @*/
    507: PetscErrorCode STMatSetUp(ST st,PetscScalar sigma,PetscScalar *coeffs)
    508: {
    510:   PetscBool      flg;

    515:   STCheckMatrices(st,1);

    517:   PetscLogEventBegin(ST_MatSetUp,st,0,0,0);
    518:   STMatMAXPY_Private(st,sigma,0.0,0,coeffs,PETSC_TRUE,&st->P);
    519:   if (!st->ksp) { STGetKSP(st,&st->ksp); }
    520:   STCheckFactorPackage(st);
    521:   KSPSetOperators(st->ksp,st->P,st->P);
    522:   PetscObjectTypeCompare((PetscObject)st,STPRECOND,&flg);
    523:   if (!flg) {
    524:     KSPSetErrorIfNotConverged(st->ksp,PETSC_TRUE);
    525:   }
    526:   KSPSetUp(st->ksp);
    527:   PetscLogEventEnd(ST_MatSetUp,st,0,0,0);
    528:   return(0);
    529: }