Date: 2017-05-17T08:25:04+00:00

Actual source code: stsolve.c
slepc-3.7.4 2017-05-17
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-2016, 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 transformation
     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->state!=ST_STATE_SETUP) { 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 transformation
     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->state!=ST_STATE_SETUP) { 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->state==ST_STATE_SETUP) 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:     PetscMalloc1(PetscMax(2,st->nmat),&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 if (st->state!=ST_STATE_UPDATED) {
    287:     for (i=0;i<PetscMax(2,st->nmat);i++) {
    288:       MatDestroy(&st->T[i]);
    289:     }
    290:   }
    291:   if (st->state!=ST_STATE_UPDATED) { MatDestroy(&st->P); }
    292:   if (st->D) {
    293:     MatGetLocalSize(st->A[0],NULL,&n);
    294:     VecGetLocalSize(st->D,&k);
    295:     if (n != k) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Balance matrix has wrong dimension %D (should be %D)",k,n);
    296:     if (!st->wb) {
    297:       VecDuplicate(st->D,&st->wb);
    298:       PetscLogObjectParent((PetscObject)st,(PetscObject)st->wb);
    299:     }
    300:   }
    301:   if (st->ops->setup) { (*st->ops->setup)(st); }
    302:   st->state = ST_STATE_SETUP;
    303:   PetscLogEventEnd(ST_SetUp,st,0,0,0);
    304:   return(0);
    305: }

    309: /*
    310:    Computes coefficients for the transformed polynomial,
    311:    and stores the result in argument S.

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

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

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

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

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

    430:    Collective on ST

    432:    Input Parameters:
    433: .  st  - the spectral transformation context

    435:    Level: developer

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

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

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

    459:    Not Collective

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

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

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

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

    486:    Collective on ST

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

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

    501:    Level: developer

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

    513:   STCheckMatrices(st,1);

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