Actual source code: fnrational.c

      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:    Rational function  r(x) = p(x)/q(x), where p(x) and q(x) are polynomials
     12: */

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

     16: typedef struct {
     17:   PetscScalar *pcoeff;    /* numerator coefficients */
     18:   PetscInt    np;         /* length of array pcoeff, p(x) has degree np-1 */
     19:   PetscScalar *qcoeff;    /* denominator coefficients */
     20:   PetscInt    nq;         /* length of array qcoeff, q(x) has degree nq-1 */
     21: } FN_RATIONAL;

     23: static PetscErrorCode FNEvaluateFunction_Rational(FN fn,PetscScalar x,PetscScalar *y)
     24: {
     25:   FN_RATIONAL *ctx = (FN_RATIONAL*)fn->data;
     26:   PetscInt    i;
     27:   PetscScalar p,q;

     29:   PetscFunctionBegin;
     30:   if (!ctx->np) p = 1.0;
     31:   else {
     32:     p = ctx->pcoeff[0];
     33:     for (i=1;i<ctx->np;i++)
     34:       p = ctx->pcoeff[i]+x*p;
     35:   }
     36:   if (!ctx->nq) *y = p;
     37:   else {
     38:     q = ctx->qcoeff[0];
     39:     for (i=1;i<ctx->nq;i++)
     40:       q = ctx->qcoeff[i]+x*q;
     41:     PetscCheck(q!=0.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Function not defined in the requested value");
     42:     *y = p/q;
     43:   }
     44:   PetscFunctionReturn(PETSC_SUCCESS);
     45: }

     47: /*
     48:    Horner evaluation of P=p(A)
     49:    d = degree of polynomial;   coeff = coefficients of polynomial;    W = workspace
     50: */
     51: static PetscErrorCode EvaluatePoly(Mat A,Mat P,Mat W,PetscInt d,PetscScalar *coeff)
     52: {
     53:   PetscInt j;

     55:   PetscFunctionBegin;
     56:   PetscCall(MatZeroEntries(P));
     57:   if (!d) PetscCall(MatShift(P,1.0));
     58:   else {
     59:     PetscCall(MatShift(P,coeff[0]));
     60:     for (j=1;j<d;j++) {
     61:       PetscCall(MatMatMult(P,A,MAT_REUSE_MATRIX,PETSC_DEFAULT,&W));
     62:       PetscCall(MatCopy(W,P,SAME_NONZERO_PATTERN));
     63:       PetscCall(MatShift(P,coeff[j]));
     64:     }
     65:   }
     66:   PetscFunctionReturn(PETSC_SUCCESS);
     67: }

     69: static PetscErrorCode FNEvaluateFunctionMat_Rational(FN fn,Mat A,Mat B)
     70: {
     71:   FN_RATIONAL *ctx = (FN_RATIONAL*)fn->data;
     72:   Mat         P,Q,W,F;
     73:   PetscBool   iscuda;

     75:   PetscFunctionBegin;
     76:   if (A==B) PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&P));
     77:   else P = B;
     78:   PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&W));

     80:   PetscCall(EvaluatePoly(A,P,W,ctx->np,ctx->pcoeff));
     81:   if (ctx->nq) {
     82:     PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&Q));
     83:     PetscCall(EvaluatePoly(A,Q,W,ctx->nq,ctx->qcoeff));
     84:     PetscCall(PetscObjectTypeCompare((PetscObject)A,MATSEQDENSECUDA,&iscuda));
     85:     PetscCall(MatGetFactor(Q,iscuda?MATSOLVERCUDA:MATSOLVERPETSC,MAT_FACTOR_LU,&F));
     86:     PetscCall(MatLUFactorSymbolic(F,Q,NULL,NULL,NULL));
     87:     PetscCall(MatLUFactorNumeric(F,Q,NULL));
     88:     PetscCall(MatMatSolve(F,P,P));
     89:     PetscCall(MatDestroy(&F));
     90:     PetscCall(MatDestroy(&Q));
     91:   }

     93:   if (A==B) {
     94:     PetscCall(MatCopy(P,B,SAME_NONZERO_PATTERN));
     95:     PetscCall(MatDestroy(&P));
     96:   }
     97:   PetscCall(MatDestroy(&W));
     98:   PetscFunctionReturn(PETSC_SUCCESS);
     99: }

    101: static PetscErrorCode FNEvaluateFunctionMatVec_Rational(FN fn,Mat A,Vec v)
    102: {
    103:   FN_RATIONAL *ctx = (FN_RATIONAL*)fn->data;
    104:   Mat         P,Q,W,F;
    105:   Vec         b;
    106:   PetscBool   iscuda;

    108:   PetscFunctionBegin;
    109:   PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&P));
    110:   PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&W));

    112:   PetscCall(EvaluatePoly(A,P,W,ctx->np,ctx->pcoeff));
    113:   if (ctx->nq) {
    114:     PetscCall(MatDuplicate(A,MAT_DO_NOT_COPY_VALUES,&Q));
    115:     PetscCall(EvaluatePoly(A,Q,W,ctx->nq,ctx->qcoeff));
    116:     PetscCall(PetscObjectTypeCompare((PetscObject)A,MATSEQDENSECUDA,&iscuda));
    117:     PetscCall(MatGetFactor(Q,iscuda?MATSOLVERCUDA:MATSOLVERPETSC,MAT_FACTOR_LU,&F));
    118:     PetscCall(MatLUFactorSymbolic(F,Q,NULL,NULL,NULL));
    119:     PetscCall(MatLUFactorNumeric(F,Q,NULL));
    120:     PetscCall(MatCreateVecs(P,&b,NULL));
    121:     PetscCall(MatGetColumnVector(P,b,0));
    122:     PetscCall(MatSolve(F,b,v));
    123:     PetscCall(VecDestroy(&b));
    124:     PetscCall(MatDestroy(&F));
    125:     PetscCall(MatDestroy(&Q));
    126:   } else PetscCall(MatGetColumnVector(P,v,0));

    128:   PetscCall(MatDestroy(&P));
    129:   PetscCall(MatDestroy(&W));
    130:   PetscFunctionReturn(PETSC_SUCCESS);
    131: }

    133: static PetscErrorCode FNEvaluateDerivative_Rational(FN fn,PetscScalar x,PetscScalar *yp)
    134: {
    135:   FN_RATIONAL *ctx = (FN_RATIONAL*)fn->data;
    136:   PetscInt    i;
    137:   PetscScalar p,q,pp,qp;

    139:   PetscFunctionBegin;
    140:   if (!ctx->np) {
    141:     p = 1.0;
    142:     pp = 0.0;
    143:   } else {
    144:     p = ctx->pcoeff[0];
    145:     pp = 0.0;
    146:     for (i=1;i<ctx->np;i++) {
    147:       pp = p+x*pp;
    148:       p = ctx->pcoeff[i]+x*p;
    149:     }
    150:   }
    151:   if (!ctx->nq) *yp = pp;
    152:   else {
    153:     q = ctx->qcoeff[0];
    154:     qp = 0.0;
    155:     for (i=1;i<ctx->nq;i++) {
    156:       qp = q+x*qp;
    157:       q = ctx->qcoeff[i]+x*q;
    158:     }
    159:     PetscCheck(q!=0.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Derivative not defined in the requested value");
    160:     *yp = (pp*q-p*qp)/(q*q);
    161:   }
    162:   PetscFunctionReturn(PETSC_SUCCESS);
    163: }

    165: static PetscErrorCode FNView_Rational(FN fn,PetscViewer viewer)
    166: {
    167:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;
    168:   PetscBool      isascii;
    169:   PetscInt       i;
    170:   char           str[50];

    172:   PetscFunctionBegin;
    173:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    174:   if (isascii) {
    175:     if (fn->alpha!=(PetscScalar)1.0 || fn->beta!=(PetscScalar)1.0) {
    176:       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),fn->alpha,PETSC_FALSE));
    177:       PetscCall(PetscViewerASCIIPrintf(viewer,"  scale factors: alpha=%s,",str));
    178:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
    179:       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),fn->beta,PETSC_FALSE));
    180:       PetscCall(PetscViewerASCIIPrintf(viewer," beta=%s\n",str));
    181:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
    182:     }
    183:     if (!ctx->nq) {
    184:       if (!ctx->np) PetscCall(PetscViewerASCIIPrintf(viewer,"  constant: 1.0\n"));
    185:       else if (ctx->np==1) {
    186:         PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->pcoeff[0],PETSC_FALSE));
    187:         PetscCall(PetscViewerASCIIPrintf(viewer,"  constant: %s\n",str));
    188:       } else {
    189:         PetscCall(PetscViewerASCIIPrintf(viewer,"  polynomial: "));
    190:         PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
    191:         for (i=0;i<ctx->np-1;i++) {
    192:           PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->pcoeff[i],PETSC_TRUE));
    193:           PetscCall(PetscViewerASCIIPrintf(viewer,"%s*x^%1" PetscInt_FMT,str,ctx->np-i-1));
    194:         }
    195:         PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->pcoeff[ctx->np-1],PETSC_TRUE));
    196:         PetscCall(PetscViewerASCIIPrintf(viewer,"%s\n",str));
    197:         PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
    198:       }
    199:     } else if (!ctx->np) {
    200:       PetscCall(PetscViewerASCIIPrintf(viewer,"  inverse polynomial: 1 / ("));
    201:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
    202:       for (i=0;i<ctx->nq-1;i++) {
    203:         PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->qcoeff[i],PETSC_TRUE));
    204:         PetscCall(PetscViewerASCIIPrintf(viewer,"%s*x^%1" PetscInt_FMT,str,ctx->nq-i-1));
    205:       }
    206:       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->qcoeff[ctx->nq-1],PETSC_TRUE));
    207:       PetscCall(PetscViewerASCIIPrintf(viewer,"%s)\n",str));
    208:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
    209:     } else {
    210:       PetscCall(PetscViewerASCIIPrintf(viewer,"  rational function: ("));
    211:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
    212:       for (i=0;i<ctx->np-1;i++) {
    213:         PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->pcoeff[i],PETSC_TRUE));
    214:         PetscCall(PetscViewerASCIIPrintf(viewer,"%s*x^%1" PetscInt_FMT,str,ctx->np-i-1));
    215:       }
    216:       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->pcoeff[ctx->np-1],PETSC_TRUE));
    217:       PetscCall(PetscViewerASCIIPrintf(viewer,"%s) / (",str));
    218:       for (i=0;i<ctx->nq-1;i++) {
    219:         PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->qcoeff[i],PETSC_TRUE));
    220:         PetscCall(PetscViewerASCIIPrintf(viewer,"%s*x^%1" PetscInt_FMT,str,ctx->nq-i-1));
    221:       }
    222:       PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->qcoeff[ctx->nq-1],PETSC_TRUE));
    223:       PetscCall(PetscViewerASCIIPrintf(viewer,"%s)\n",str));
    224:       PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
    225:     }
    226:   }
    227:   PetscFunctionReturn(PETSC_SUCCESS);
    228: }

    230: static PetscErrorCode FNRationalSetNumerator_Rational(FN fn,PetscInt np,PetscScalar *pcoeff)
    231: {
    232:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;
    233:   PetscInt       i;

    235:   PetscFunctionBegin;
    236:   PetscCheck(np>=0,PetscObjectComm((PetscObject)fn),PETSC_ERR_ARG_OUTOFRANGE,"Argument np cannot be negative");
    237:   ctx->np = np;
    238:   PetscCall(PetscFree(ctx->pcoeff));
    239:   if (np) {
    240:     PetscCall(PetscMalloc1(np,&ctx->pcoeff));
    241:     for (i=0;i<np;i++) ctx->pcoeff[i] = pcoeff[i];
    242:   }
    243:   PetscFunctionReturn(PETSC_SUCCESS);
    244: }

    246: /*@
    247:    FNRationalSetNumerator - Sets the parameters defining the numerator of the
    248:    rational function.

    250:    Logically Collective

    252:    Input Parameters:
    253: +  fn     - the math function context
    254: .  np     - number of coefficients
    255: -  pcoeff - coefficients (array of scalar values)

    257:    Notes:
    258:    Let the rational function be $f(x) = p(x)/q(x)$, where $p(x)$ and $q(x)$ are
    259:    polynomials. This function provides the coefficients of the numerator $p(x)$.
    260:    Hence, $p(x)$ is of degree `np-1`. If `np` is zero, or this function is not
    261:    called, then the numerator is assumed to be $p(x)=1$.

    263:    In polynomials, high order coefficients are stored in the first positions
    264:    of the array, e.g., to represent $x^2-3$ use `{1,0,-3}`.

    266:    Level: intermediate

    268: .seealso: [](sec:fn), `FNRATIONAL`, `FNRationalSetDenominator()`, `FNRationalGetNumerator()`
    269: @*/
    270: PetscErrorCode FNRationalSetNumerator(FN fn,PetscInt np,PetscScalar pcoeff[])
    271: {
    272:   PetscFunctionBegin;
    275:   if (np) PetscAssertPointer(pcoeff,3);
    276:   PetscTryMethod(fn,"FNRationalSetNumerator_C",(FN,PetscInt,PetscScalar*),(fn,np,pcoeff));
    277:   PetscFunctionReturn(PETSC_SUCCESS);
    278: }

    280: static PetscErrorCode FNRationalGetNumerator_Rational(FN fn,PetscInt *np,PetscScalar *pcoeff[])
    281: {
    282:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;
    283:   PetscInt       i;

    285:   PetscFunctionBegin;
    286:   if (np) *np = ctx->np;
    287:   if (pcoeff) {
    288:     if (!ctx->np) *pcoeff = NULL;
    289:     else {
    290:       PetscCall(PetscMalloc1(ctx->np,pcoeff));
    291:       for (i=0;i<ctx->np;i++) (*pcoeff)[i] = ctx->pcoeff[i];
    292:     }
    293:   }
    294:   PetscFunctionReturn(PETSC_SUCCESS);
    295: }

    297: /*@C
    298:    FNRationalGetNumerator - Gets the parameters that define the numerator of the
    299:    rational function.

    301:    Not Collective

    303:    Input Parameter:
    304: .  fn     - the math function context

    306:    Output Parameters:
    307: +  np     - number of coefficients
    308: -  pcoeff - coefficients (array of scalar values, length `np`)

    310:    Notes:
    311:    The values passed by user with `FNRationalSetNumerator()` are returned (or
    312:    `NULL` pointers otherwise).
    313:    The `pcoeff` array should be freed by the user when no longer needed.

    315:    Level: intermediate

    317: .seealso: [](sec:fn), `FNRATIONAL`, `FNRationalSetNumerator()`
    318: @*/
    319: PetscErrorCode FNRationalGetNumerator(FN fn,PetscInt *np,PetscScalar *pcoeff[]) PeNS
    320: {
    321:   PetscFunctionBegin;
    323:   PetscUseMethod(fn,"FNRationalGetNumerator_C",(FN,PetscInt*,PetscScalar**),(fn,np,pcoeff));
    324:   PetscFunctionReturn(PETSC_SUCCESS);
    325: }

    327: static PetscErrorCode FNRationalSetDenominator_Rational(FN fn,PetscInt nq,PetscScalar *qcoeff)
    328: {
    329:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;
    330:   PetscInt       i;

    332:   PetscFunctionBegin;
    333:   PetscCheck(nq>=0,PetscObjectComm((PetscObject)fn),PETSC_ERR_ARG_OUTOFRANGE,"Argument nq cannot be negative");
    334:   ctx->nq = nq;
    335:   PetscCall(PetscFree(ctx->qcoeff));
    336:   if (nq) {
    337:     PetscCall(PetscMalloc1(nq,&ctx->qcoeff));
    338:     for (i=0;i<nq;i++) ctx->qcoeff[i] = qcoeff[i];
    339:   }
    340:   PetscFunctionReturn(PETSC_SUCCESS);
    341: }

    343: /*@
    344:    FNRationalSetDenominator - Sets the parameters defining the denominator of the
    345:    rational function.

    347:    Logically Collective

    349:    Input Parameters:
    350: +  fn     - the math function context
    351: .  nq     - number of coefficients
    352: -  qcoeff - coefficients (array of scalar values)

    354:    Notes:
    355:    Let the rational function be $f(x) = p(x)/q(x)$, where $p(x)$ and $q(x)$ are
    356:    polynomials. This function provides the coefficients of the denominator $q(x)$.
    357:    Hence, $q(x)$ is of degree `nq-1`. If `nq` is zero, or this function is not
    358:    called, then the function is assumed to be polynomial, $f(x) = p(x)$.

    360:    In polynomials, high order coefficients are stored in the first positions
    361:    of the array, e.g., to represent $x^2-3$ use `{1,0,-3}`.

    363:    Level: intermediate

    365: .seealso: [](sec:fn), `FNRATIONAL`, `FNRationalSetNumerator()`, `FNRationalGetDenominator()`
    366: @*/
    367: PetscErrorCode FNRationalSetDenominator(FN fn,PetscInt nq,PetscScalar qcoeff[])
    368: {
    369:   PetscFunctionBegin;
    372:   if (nq) PetscAssertPointer(qcoeff,3);
    373:   PetscTryMethod(fn,"FNRationalSetDenominator_C",(FN,PetscInt,PetscScalar*),(fn,nq,qcoeff));
    374:   PetscFunctionReturn(PETSC_SUCCESS);
    375: }

    377: static PetscErrorCode FNRationalGetDenominator_Rational(FN fn,PetscInt *nq,PetscScalar *qcoeff[])
    378: {
    379:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;
    380:   PetscInt       i;

    382:   PetscFunctionBegin;
    383:   if (nq) *nq = ctx->nq;
    384:   if (qcoeff) {
    385:     if (!ctx->nq) *qcoeff = NULL;
    386:     else {
    387:       PetscCall(PetscMalloc1(ctx->nq,qcoeff));
    388:       for (i=0;i<ctx->nq;i++) (*qcoeff)[i] = ctx->qcoeff[i];
    389:     }
    390:   }
    391:   PetscFunctionReturn(PETSC_SUCCESS);
    392: }

    394: /*@C
    395:    FNRationalGetDenominator - Gets the parameters that define the denominator of the
    396:    rational function.

    398:    Not Collective

    400:    Input Parameter:
    401: .  fn     - the math function context

    403:    Output Parameters:
    404: +  nq     - number of coefficients
    405: -  qcoeff - coefficients (array of scalar values, length `nq`)

    407:    Notes:
    408:    The values passed by user with `FNRationalSetDenominator()` are returned (or a
    409:    `NULL` pointer otherwise).
    410:    The `qcoeff` array should be freed by the user when no longer needed.

    412:    Level: intermediate

    414: .seealso: [](sec:fn), `FNRATIONAL`, `FNRationalSetDenominator()`
    415: @*/
    416: PetscErrorCode FNRationalGetDenominator(FN fn,PetscInt *nq,PetscScalar *qcoeff[]) PeNS
    417: {
    418:   PetscFunctionBegin;
    420:   PetscUseMethod(fn,"FNRationalGetDenominator_C",(FN,PetscInt*,PetscScalar**),(fn,nq,qcoeff));
    421:   PetscFunctionReturn(PETSC_SUCCESS);
    422: }

    424: static PetscErrorCode FNSetFromOptions_Rational(FN fn,PetscOptionItems PetscOptionsObject)
    425: {
    426: #define PARMAX 10
    427:   PetscScalar    array[PARMAX];
    428:   PetscInt       i,k;
    429:   PetscBool      flg;

    431:   PetscFunctionBegin;
    432:   PetscOptionsHeadBegin(PetscOptionsObject,"FN Rational Options");

    434:     k = PARMAX;
    435:     for (i=0;i<k;i++) array[i] = 0;
    436:     PetscCall(PetscOptionsScalarArray("-fn_rational_numerator","Numerator coefficients (one or more scalar values separated with a comma without spaces)","FNRationalSetNumerator",array,&k,&flg));
    437:     if (flg) PetscCall(FNRationalSetNumerator(fn,k,array));

    439:     k = PARMAX;
    440:     for (i=0;i<k;i++) array[i] = 0;
    441:     PetscCall(PetscOptionsScalarArray("-fn_rational_denominator","Denominator coefficients (one or more scalar values separated with a comma without spaces)","FNRationalSetDenominator",array,&k,&flg));
    442:     if (flg) PetscCall(FNRationalSetDenominator(fn,k,array));

    444:   PetscOptionsHeadEnd();
    445:   PetscFunctionReturn(PETSC_SUCCESS);
    446: }

    448: static PetscErrorCode FNDuplicate_Rational(FN fn,MPI_Comm comm,FN *newfn)
    449: {
    450:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data,*ctx2 = (FN_RATIONAL*)(*newfn)->data;
    451:   PetscInt       i;

    453:   PetscFunctionBegin;
    454:   ctx2->np = ctx->np;
    455:   if (ctx->np) {
    456:     PetscCall(PetscMalloc1(ctx->np,&ctx2->pcoeff));
    457:     for (i=0;i<ctx->np;i++) ctx2->pcoeff[i] = ctx->pcoeff[i];
    458:   }
    459:   ctx2->nq = ctx->nq;
    460:   if (ctx->nq) {
    461:     PetscCall(PetscMalloc1(ctx->nq,&ctx2->qcoeff));
    462:     for (i=0;i<ctx->nq;i++) ctx2->qcoeff[i] = ctx->qcoeff[i];
    463:   }
    464:   PetscFunctionReturn(PETSC_SUCCESS);
    465: }

    467: static PetscErrorCode FNDestroy_Rational(FN fn)
    468: {
    469:   FN_RATIONAL    *ctx = (FN_RATIONAL*)fn->data;

    471:   PetscFunctionBegin;
    472:   PetscCall(PetscFree(ctx->pcoeff));
    473:   PetscCall(PetscFree(ctx->qcoeff));
    474:   PetscCall(PetscFree(fn->data));
    475:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalSetNumerator_C",NULL));
    476:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalGetNumerator_C",NULL));
    477:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalSetDenominator_C",NULL));
    478:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalGetDenominator_C",NULL));
    479:   PetscFunctionReturn(PETSC_SUCCESS);
    480: }

    482: /*MC
    483:    FNRATIONAL - FNRATIONAL = "rational" - A rational function $f(x)=p(x)/q(x)$,
    484:    where the coefficients of the $p(x)$ and $q(x)$ polynomials are specified with
    485:    `FNRationalSetNumerator()` and `FNRationalSetDenominator()`, respectively.

    487:    Level: beginner

    489:    Notes:
    490:    The function will behave as a polynomial if only the numerator is given.

    492:    When working with matrix functions, the rational function should rather be
    493:    interpreted as $f(x)=q(x)^{-1}p(x)$.

    495: .seealso: [](sec:fn), `FN`, `FNType`, `FNSetType()`, `FNRationalSetNumerator()`, `FNRationalSetDenominator()`
    496: M*/

    498: SLEPC_EXTERN PetscErrorCode FNCreate_Rational(FN fn)
    499: {
    500:   FN_RATIONAL    *ctx;

    502:   PetscFunctionBegin;
    503:   PetscCall(PetscNew(&ctx));
    504:   fn->data = (void*)ctx;

    506:   fn->ops->evaluatefunction          = FNEvaluateFunction_Rational;
    507:   fn->ops->evaluatederivative        = FNEvaluateDerivative_Rational;
    508:   fn->ops->evaluatefunctionmat[0]    = FNEvaluateFunctionMat_Rational;
    509:   fn->ops->evaluatefunctionmatvec[0] = FNEvaluateFunctionMatVec_Rational;
    510: #if defined(PETSC_HAVE_CUDA)
    511:   fn->ops->evaluatefunctionmatcuda[0]    = FNEvaluateFunctionMat_Rational;
    512:   fn->ops->evaluatefunctionmatveccuda[0] = FNEvaluateFunctionMatVec_Rational;
    513: #endif
    514:   fn->ops->setfromoptions            = FNSetFromOptions_Rational;
    515:   fn->ops->view                      = FNView_Rational;
    516:   fn->ops->duplicate                 = FNDuplicate_Rational;
    517:   fn->ops->destroy                   = FNDestroy_Rational;
    518:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalSetNumerator_C",FNRationalSetNumerator_Rational));
    519:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalGetNumerator_C",FNRationalGetNumerator_Rational));
    520:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalSetDenominator_C",FNRationalSetDenominator_Rational));
    521:   PetscCall(PetscObjectComposeFunction((PetscObject)fn,"FNRationalGetDenominator_C",FNRationalGetDenominator_Rational));
    522:   PetscFunctionReturn(PETSC_SUCCESS);
    523: }