Actual source code: stsolve.c

slepc-3.19.0 2023-03-31
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: }