Date: 2026-07-30T21:14:28+00:00

Actual source code: taosolver_fg.c

      1: #include <petsc/private/taoimpl.h>

      3: /*@
      4:   TaoSetSolution - Sets the vector holding the initial guess for the solve

      6:   Logically Collective

      8:   Input Parameters:
      9: + tao - the `Tao` context
     10: - x0  - the initial guess

     12:   Level: beginner

     14: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`, `TaoGetSolution()`
     15: @*/
     16: PetscErrorCode TaoSetSolution(Tao tao, Vec x0)
     17: {
     18:   PetscFunctionBegin;
     21:   PetscCall(PetscObjectReference((PetscObject)x0));
     22:   PetscCall(VecDestroy(&tao->solution));
     23:   tao->solution = x0;
     24:   if (x0) PetscCall(TaoTermSetSolutionTemplate(tao->callbacks, x0));
     25:   PetscFunctionReturn(PETSC_SUCCESS);
     26: }

     28: PETSC_INTERN PetscErrorCode TaoTestGradient_Internal(Tao tao, Vec x, Vec g1, PetscViewer viewer, PetscViewer mviewer)
     29: {
     30:   Vec         g2, g3;
     31:   PetscReal   hcnorm, fdnorm, hcmax, fdmax, diffmax, diffnorm;
     32:   PetscScalar dot;

     34:   PetscFunctionBegin;
     35:   PetscCall(VecDuplicate(x, &g2));
     36:   PetscCall(VecDuplicate(x, &g3));

     38:   /* Compute finite difference gradient, assume the gradient is already computed by TaoComputeGradient() and put into g1 */
     39:   PetscCall(TaoDefaultComputeGradient(tao, x, g2, NULL));

     41:   PetscCall(VecNorm(g2, NORM_2, &fdnorm));
     42:   PetscCall(VecNorm(g1, NORM_2, &hcnorm));
     43:   PetscCall(VecNorm(g2, NORM_INFINITY, &fdmax));
     44:   PetscCall(VecNorm(g1, NORM_INFINITY, &hcmax));
     45:   PetscCall(VecDot(g1, g2, &dot));
     46:   PetscCall(VecCopy(g1, g3));
     47:   PetscCall(VecAXPY(g3, -1.0, g2));
     48:   PetscCall(VecNorm(g3, NORM_2, &diffnorm));
     49:   PetscCall(VecNorm(g3, NORM_INFINITY, &diffmax));
     50:   PetscCall(PetscViewerASCIIPrintf(viewer, "  ||Gfd|| %g, ||G|| = %g, angle cosine = (Gfd'G)/||Gfd||||G|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot) / (fdnorm * hcnorm))));
     51:   PetscCall(PetscViewerASCIIPrintf(viewer, "  2-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n", (double)(diffnorm / PetscMax(hcnorm, fdnorm)), (double)diffnorm));
     52:   PetscCall(PetscViewerASCIIPrintf(viewer, "  max-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n", (double)(diffmax / PetscMax(hcmax, fdmax)), (double)diffmax));

     54:   if (mviewer) {
     55:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Hand-coded gradient ----------\n"));
     56:     PetscCall(VecView(g1, mviewer));
     57:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Finite difference gradient ----------\n"));
     58:     PetscCall(VecView(g2, mviewer));
     59:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Hand-coded minus finite-difference gradient ----------\n"));
     60:     PetscCall(VecView(g3, mviewer));
     61:   }
     62:   PetscCall(VecDestroy(&g2));
     63:   PetscCall(VecDestroy(&g3));
     64:   PetscFunctionReturn(PETSC_SUCCESS);
     65: }

     67: /*@
     68:   TaoTestGradient - Compare the user-supplied gradient with a finite-difference approximation, when requested via
     69:   the options database, and print the difference.

     71:   Collective

     73:   Input Parameters:
     74: + tao - the `Tao` context
     75: . x   - the point at which to evaluate the gradient
     76: - g1  - the user-supplied gradient at `x`

     78:   Options Database Keys:
     79: + -tao_test_gradient      - enable the comparison
     80: - -tao_test_gradient_view - display the user-supplied gradient, the finite-difference gradient, and their difference

     82:   Level: intermediate

     84:   Note:
     85:   If `-tao_test_gradient` is not set, this routine returns immediately without performing any work.

     87: .seealso: [](ch_tao), `Tao`, `TaoTestHessian()`, `TaoComputeGradient()`
     88: @*/
     89: PetscErrorCode TaoTestGradient(Tao tao, Vec x, Vec g1)
     90: {
     91:   PetscBool         complete_print = PETSC_FALSE, test = PETSC_FALSE;
     92:   MPI_Comm          comm;
     93:   PetscViewer       viewer, mviewer;
     94:   PetscViewerFormat format;
     95:   PetscInt          tabs;
     96:   static PetscBool  directionsprinted = PETSC_FALSE;

     98:   PetscFunctionBegin;
     99:   PetscObjectOptionsBegin((PetscObject)tao);
    100:   PetscCall(PetscOptionsName("-tao_test_gradient", "Compare hand-coded and finite difference Gradients", "None", &test));
    101:   PetscCall(PetscOptionsViewer("-tao_test_gradient_view", "View difference between hand-coded and finite difference Gradients element entries", "None", &mviewer, &format, &complete_print));
    102:   PetscOptionsEnd();
    103:   if (!test) {
    104:     if (complete_print) PetscCall(PetscViewerDestroy(&mviewer));
    105:     PetscFunctionReturn(PETSC_SUCCESS);
    106:   }

    108:   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));
    109:   PetscCall(PetscViewerASCIIGetStdout(comm, &viewer));
    110:   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
    111:   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
    112:   PetscCall(PetscViewerASCIIPrintf(viewer, "  ---------- Testing Gradient -------------\n"));
    113:   if (!complete_print && !directionsprinted) {
    114:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Run with -tao_test_gradient_view and optionally -tao_test_gradient <threshold> to show difference\n"));
    115:     PetscCall(PetscViewerASCIIPrintf(viewer, "    of hand-coded and finite difference gradient entries greater than <threshold>.\n"));
    116:   }
    117:   if (!directionsprinted) {
    118:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Testing hand-coded Gradient, if (for double precision runs) ||G - Gfd||/||G|| is\n"));
    119:     PetscCall(PetscViewerASCIIPrintf(viewer, "    O(1.e-8), the hand-coded Gradient is probably correct.\n"));
    120:     directionsprinted = PETSC_TRUE;
    121:   }
    122:   if (complete_print) PetscCall(PetscViewerPushFormat(mviewer, format));
    123:   PetscCall(TaoTestGradient_Internal(tao, x, g1, viewer, complete_print ? mviewer : NULL));
    124:   if (complete_print) {
    125:     PetscCall(PetscViewerPopFormat(mviewer));
    126:     PetscCall(PetscViewerDestroy(&mviewer));
    127:   }
    128:   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
    129:   PetscFunctionReturn(PETSC_SUCCESS);
    130: }

    132: /*@
    133:   TaoComputeGradient - Computes the gradient of the objective function

    135:   Collective

    137:   Input Parameters:
    138: + tao - the `Tao` context
    139: - X   - input vector

    141:   Output Parameter:
    142: . G - gradient vector

    144:   Options Database Keys:
    145: + -tao_test_gradient      - compare the user provided gradient with one compute via finite differences to check for errors
    146: - -tao_test_gradient_view - display the user provided gradient, the finite difference gradient and the difference between them to help users detect the location of errors in the user provided gradient

    148:   Level: developer

    150:   Note:
    151:   `TaoComputeGradient()` is typically used within the implementation of the optimization method,
    152:   so most users would not generally call this routine themselves.

    154: .seealso: [](ch_tao), `TaoComputeObjective()`, `TaoComputeObjectiveAndGradient()`, `TaoSetGradient()`
    155: @*/
    156: PetscErrorCode TaoComputeGradient(Tao tao, Vec X, Vec G)
    157: {
    158:   PetscFunctionBegin;
    162:   PetscCheckSameComm(tao, 1, X, 2);
    163:   PetscCheckSameComm(tao, 1, G, 3);
    164:   PetscCall(TaoTermMappingComputeGradient(&tao->objective_term, X, tao->objective_parameters, INSERT_VALUES, G));
    165:   PetscCall(TaoTestGradient(tao, X, G));
    166:   PetscFunctionReturn(PETSC_SUCCESS);
    167: }

    169: /*@
    170:   TaoComputeObjective - Computes the objective function value at a given point

    172:   Collective

    174:   Input Parameters:
    175: + tao - the `Tao` context
    176: - X   - input vector

    178:   Output Parameter:
    179: . f - Objective value at X

    181:   Level: developer

    183:   Note:
    184:   `TaoComputeObjective()` is typically used within the implementation of the optimization algorithm
    185:   so most users would not generally call this routine themselves.

    187: .seealso: [](ch_tao), `Tao`, `TaoComputeGradient()`, `TaoComputeObjectiveAndGradient()`, `TaoSetObjective()`
    188: @*/
    189: PetscErrorCode TaoComputeObjective(Tao tao, Vec X, PetscReal *f)
    190: {
    191:   PetscFunctionBegin;
    194:   PetscAssertPointer(f, 3);
    195:   PetscCheckSameComm(tao, 1, X, 2);
    196:   PetscCall(TaoTermMappingComputeObjective(&tao->objective_term, X, tao->objective_parameters, INSERT_VALUES, f));
    197:   PetscFunctionReturn(PETSC_SUCCESS);
    198: }

    200: /*@
    201:   TaoComputeObjectiveAndGradient - Computes the objective function value at a given point

    203:   Collective

    205:   Input Parameters:
    206: + tao - the `Tao` context
    207: - X   - input vector

    209:   Output Parameters:
    210: + f - Objective value at `X`
    211: - G - Gradient vector at `X`

    213:   Level: developer

    215:   Note:
    216:   `TaoComputeObjectiveAndGradient()` is typically used within the implementation of the optimization algorithm,
    217:   so most users would not generally call this routine themselves.

    219: .seealso: [](ch_tao), `TaoComputeGradient()`, `TaoSetObjective()`
    220: @*/
    221: PetscErrorCode TaoComputeObjectiveAndGradient(Tao tao, Vec X, PetscReal *f, Vec G)
    222: {
    223:   PetscFunctionBegin;
    226:   PetscAssertPointer(f, 3);
    228:   PetscCheckSameComm(tao, 1, X, 2);
    229:   PetscCheckSameComm(tao, 1, G, 4);
    230:   PetscCall(TaoTermMappingComputeObjectiveAndGradient(&tao->objective_term, X, tao->objective_parameters, INSERT_VALUES, f, G));
    231:   PetscCall(TaoTestGradient(tao, X, G));
    232:   PetscFunctionReturn(PETSC_SUCCESS);
    233: }

    235: /*@C
    236:   TaoSetObjective - Sets the function evaluation routine for minimization

    238:   Logically Collective

    240:   Input Parameters:
    241: + tao  - the `Tao` context
    242: . func - the objective function
    243: - ctx  - [optional] user-defined context for private data for the function evaluation
    244:         routine (may be `NULL`)

    246:   Calling sequence of `func`:
    247: + tao - the optimizer
    248: . x   - input vector
    249: . f   - function value
    250: - ctx - [optional] user-defined function context

    252:   Level: beginner

    254: .seealso: [](ch_tao), `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoGetObjective()`
    255: @*/
    256: PetscErrorCode TaoSetObjective(Tao tao, PetscErrorCode (*func)(Tao tao, Vec x, PetscReal *f, PetscCtx ctx), PetscCtx ctx)
    257: {
    258:   PetscFunctionBegin;
    260:   PetscCall(TaoTermCallbacksSetObjective(tao->callbacks, func, ctx));
    261:   PetscFunctionReturn(PETSC_SUCCESS);
    262: }

    264: /*@C
    265:   TaoGetObjective - Gets the function evaluation routine for the function to be minimized

    267:   Not Collective

    269:   Input Parameter:
    270: . tao - the `Tao` context

    272:   Output Parameters:
    273: + func - the objective function
    274: - ctx  - the user-defined context for private data for the function evaluation

    276:   Calling sequence of `func`:
    277: + tao - the optimizer
    278: . x   - input vector
    279: . f   - function value
    280: - ctx - [optional] user-defined function context

    282:   Level: beginner

    284:   Notes:
    285:   In addition to specifying an objective function using callbacks such as
    286:   `TaoSetObjective()` and `TaoSetGradient()`, users can specify
    287:   objective functions with `TaoAddTerm()`.

    289:   `TaoGetObjective()` will always return the callback specified with
    290:   `TaoSetObjective()`, even if the objective function has been changed by
    291:   calling `TaoAddTerm()`.

    293: .seealso: [](ch_tao), `Tao`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjective()`
    294: @*/
    295: PetscErrorCode TaoGetObjective(Tao tao, PetscErrorCode (**func)(Tao tao, Vec x, PetscReal *f, PetscCtx ctx), PetscCtxRt ctx)
    296: {
    297:   PetscFunctionBegin;
    299:   if (func || ctx) PetscCall(TaoTermCallbacksGetObjective(tao->callbacks, func, ctx));
    300:   PetscFunctionReturn(PETSC_SUCCESS);
    301: }

    303: /*@C
    304:   TaoSetResidualRoutine - Sets the residual evaluation routine for least-square applications

    306:   Logically Collective

    308:   Input Parameters:
    309: + tao  - the `Tao` context
    310: . res  - the residual vector
    311: . func - the residual evaluation routine
    312: - ctx  - [optional] user-defined context for private data for the function evaluation
    313:          routine (may be `NULL`)

    315:   Calling sequence of `func`:
    316: + tao - the optimizer
    317: . x   - input vector
    318: . res - function value vector
    319: - ctx - [optional] user-defined function context

    321:   Level: beginner

    323: .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoSetJacobianRoutine()`
    324: @*/
    325: PetscErrorCode TaoSetResidualRoutine(Tao tao, Vec res, PetscErrorCode (*func)(Tao tao, Vec x, Vec res, PetscCtx ctx), PetscCtx ctx)
    326: {
    327:   PetscFunctionBegin;
    330:   PetscCall(PetscObjectReference((PetscObject)res));
    331:   PetscCall(VecDestroy(&tao->ls_res));
    332:   tao->ls_res               = res;
    333:   tao->user_lsresP          = ctx;
    334:   tao->ops->computeresidual = func;
    335:   PetscFunctionReturn(PETSC_SUCCESS);
    336: }

    338: /*@
    339:   TaoSetResidualWeights - Give weights for the residual values. A vector can be used if only diagonal terms are used, otherwise a matrix can be give.

    341:   Collective

    343:   Input Parameters:
    344: + tao     - the `Tao` context
    345: . sigma_v - vector of weights (diagonal terms only)
    346: . n       - the number of weights (if using off-diagonal)
    347: . rows    - index list of rows for `sigma_v`
    348: . cols    - index list of columns for `sigma_v`
    349: - vals    - array of weights

    351:   Level: intermediate

    353:   Notes:
    354:   If this function is not provided, or if `sigma_v` and `vals` are both `NULL`, then the
    355:   identity matrix will be used for weights.

    357:   Either `sigma_v` or `vals` should be `NULL`

    359: .seealso: [](ch_tao), `Tao`, `TaoSetResidualRoutine()`
    360: @*/
    361: PetscErrorCode TaoSetResidualWeights(Tao tao, Vec sigma_v, PetscInt n, PetscInt *rows, PetscInt *cols, PetscReal *vals)
    362: {
    363:   PetscInt i;

    365:   PetscFunctionBegin;
    368:   PetscCall(PetscObjectReference((PetscObject)sigma_v));
    369:   PetscCall(VecDestroy(&tao->res_weights_v));
    370:   tao->res_weights_v = sigma_v;
    371:   if (vals) {
    372:     PetscCall(PetscFree(tao->res_weights_rows));
    373:     PetscCall(PetscFree(tao->res_weights_cols));
    374:     PetscCall(PetscFree(tao->res_weights_w));
    375:     PetscCall(PetscMalloc1(n, &tao->res_weights_rows));
    376:     PetscCall(PetscMalloc1(n, &tao->res_weights_cols));
    377:     PetscCall(PetscMalloc1(n, &tao->res_weights_w));
    378:     tao->res_weights_n = n;
    379:     for (i = 0; i < n; i++) {
    380:       tao->res_weights_rows[i] = rows[i];
    381:       tao->res_weights_cols[i] = cols[i];
    382:       tao->res_weights_w[i]    = vals[i];
    383:     }
    384:   } else {
    385:     tao->res_weights_n    = 0;
    386:     tao->res_weights_rows = NULL;
    387:     tao->res_weights_cols = NULL;
    388:   }
    389:   PetscFunctionReturn(PETSC_SUCCESS);
    390: }

    392: /*@
    393:   TaoComputeResidual - Computes a least-squares residual vector at a given point

    395:   Collective

    397:   Input Parameters:
    398: + tao - the `Tao` context
    399: - X   - input vector

    401:   Output Parameter:
    402: . F - Objective vector at `X`

    404:   Level: advanced

    406:   Notes:
    407:   `TaoComputeResidual()` is typically used within the implementation of the optimization algorithm,
    408:   so most users would not generally call this routine themselves.

    410: .seealso: [](ch_tao), `Tao`, `TaoSetResidualRoutine()`
    411: @*/
    412: PetscErrorCode TaoComputeResidual(Tao tao, Vec X, Vec F)
    413: {
    414:   PetscFunctionBegin;
    418:   PetscCheckSameComm(tao, 1, X, 2);
    419:   PetscCheckSameComm(tao, 1, F, 3);
    420:   PetscCheck(tao->ops->computeresidual, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TaoSetResidualRoutine() has not been called");
    421:   PetscCall(PetscLogEventBegin(TAO_ResidualEval, tao, X, NULL, NULL));
    422:   PetscCallBack("Tao callback least-squares residual", (*tao->ops->computeresidual)(tao, X, F, tao->user_lsresP));
    423:   PetscCall(PetscLogEventEnd(TAO_ResidualEval, tao, X, NULL, NULL));
    424:   tao->nres++;
    425:   PetscCall(PetscInfo(tao, "TAO least-squares residual evaluation.\n"));
    426:   PetscFunctionReturn(PETSC_SUCCESS);
    427: }

    429: /*@C
    430:   TaoSetGradient - Sets the gradient evaluation routine for the function to be optimized

    432:   Logically Collective

    434:   Input Parameters:
    435: + tao  - the `Tao` context
    436: . g    - [optional] the vector to internally hold the gradient computation
    437: . func - the gradient function
    438: - ctx  - [optional] user-defined context for private data for the gradient evaluation
    439:         routine (may be `NULL`)

    441:   Calling sequence of `func`:
    442: + tao - the optimization solver
    443: . x   - input vector
    444: . g   - gradient value (output)
    445: - ctx - [optional] user-defined function context

    447:   Level: beginner

    449: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoGetGradient()`
    450: @*/
    451: PetscErrorCode TaoSetGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao tao, Vec x, Vec g, PetscCtx ctx), PetscCtx ctx)
    452: {
    453:   PetscFunctionBegin;
    455:   if (g) {
    457:     PetscCheckSameComm(tao, 1, g, 2);
    458:     PetscCall(PetscObjectReference((PetscObject)g));
    459:     PetscCall(VecDestroy(&tao->gradient));
    460:     tao->gradient = g;
    461:   }
    462:   PetscCall(TaoTermCallbacksSetGradient(tao->callbacks, func, ctx));
    463:   PetscFunctionReturn(PETSC_SUCCESS);
    464: }

    466: /*@C
    467:   TaoGetGradient - Gets the gradient evaluation routine for the function being optimized

    469:   Not Collective

    471:   Input Parameter:
    472: . tao - the `Tao` context

    474:   Output Parameters:
    475: + g    - the vector to internally hold the gradient computation
    476: . func - the gradient function
    477: - ctx  - user-defined context for private data for the gradient evaluation routine

    479:   Calling sequence of `func`:
    480: + tao - the optimizer
    481: . x   - input vector
    482: . g   - gradient value (output)
    483: - ctx - [optional] user-defined function context

    485:   Level: beginner

    487:   Notes:
    488:   In addition to specifying an objective function using callbacks such as
    489:   `TaoSetObjective()` and `TaoSetGradient()`, users can specify
    490:   objective functions with `TaoAddTerm()`.

    492:   `TaoGetGradient()` will always return the callback specified with
    493:   `TaoSetGradient()`, even if the objective function has been changed by
    494:   calling `TaoAddTerm()`.

    496: .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoSetGradient()`
    497: @*/
    498: PetscErrorCode TaoGetGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao tao, Vec x, Vec g, PetscCtx ctx), PetscCtxRt ctx)
    499: {
    500:   PetscFunctionBegin;
    502:   if (g) *g = tao->gradient;
    503:   if (func || ctx) PetscCall(TaoTermCallbacksGetGradient(tao->callbacks, func, ctx));
    504:   PetscFunctionReturn(PETSC_SUCCESS);
    505: }

    507: /*@C
    508:   TaoSetObjectiveAndGradient - Sets a combined objective function and gradient evaluation routine for the function to be optimized

    510:   Logically Collective

    512:   Input Parameters:
    513: + tao  - the `Tao` context
    514: . g    - [optional] the vector to internally hold the gradient computation
    515: . func - the gradient function
    516: - ctx  - [optional] user-defined context for private data for the gradient evaluation
    517:         routine (may be `NULL`)

    519:   Calling sequence of `func`:
    520: + tao - the optimization object
    521: . x   - input vector
    522: . f   - objective value (output)
    523: . g   - gradient value (output)
    524: - ctx - [optional] user-defined function context

    526:   Level: beginner

    528:   Note:
    529:   For some optimization methods using a combined function can be more efficient.

    531: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetGradient()`, `TaoGetObjectiveAndGradient()`
    532: @*/
    533: PetscErrorCode TaoSetObjectiveAndGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao tao, Vec x, PetscReal *f, Vec g, PetscCtx ctx), PetscCtx ctx)
    534: {
    535:   PetscFunctionBegin;
    537:   if (g) {
    539:     PetscCheckSameComm(tao, 1, g, 2);
    540:     PetscCall(PetscObjectReference((PetscObject)g));
    541:     PetscCall(VecDestroy(&tao->gradient));
    542:     tao->gradient = g;
    543:   }
    544:   PetscCall(TaoTermCallbacksSetObjectiveAndGradient(tao->callbacks, func, ctx));
    545:   PetscFunctionReturn(PETSC_SUCCESS);
    546: }

    548: /*@C
    549:   TaoGetObjectiveAndGradient - Gets the combined objective function and gradient evaluation routine for the function to be optimized

    551:   Not Collective

    553:   Input Parameter:
    554: . tao - the `Tao` context

    556:   Output Parameters:
    557: + g    - the vector to internally hold the gradient computation
    558: . func - the gradient function
    559: - ctx  - user-defined context for private data for the gradient evaluation routine

    561:   Calling sequence of `func`:
    562: + tao - the optimizer
    563: . x   - input vector
    564: . f   - objective value (output)
    565: . g   - gradient value (output)
    566: - ctx - [optional] user-defined function context

    568:   Level: beginner

    570:   Note:
    571:   In addition to specifying an objective function using callbacks such as
    572:   `TaoSetObjectiveAndGradient()`, users can specify
    573:   objective functions with `TaoAddTerm()`.

    575:   `TaoGetObjectiveAndGradient()` will always return the callback specified with
    576:   `TaoSetObjectiveAndGradient()`, even if the objective function has been changed by
    577:   calling `TaoAddTerm()`.

    579: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`
    580: @*/
    581: PetscErrorCode TaoGetObjectiveAndGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao tao, Vec x, PetscReal *f, Vec g, PetscCtx ctx), PetscCtxRt ctx)
    582: {
    583:   PetscFunctionBegin;
    585:   if (g) *g = tao->gradient;
    586:   if (func || ctx) PetscCall(TaoTermCallbacksGetObjectiveAndGradient(tao->callbacks, func, ctx));
    587:   PetscFunctionReturn(PETSC_SUCCESS);
    588: }

    590: /*@
    591:   TaoIsObjectiveDefined - Checks to see if the user has
    592:   declared an objective-only routine.  Useful for determining when
    593:   it is appropriate to call `TaoComputeObjective()` or
    594:   `TaoComputeObjectiveAndGradient()`

    596:   Not Collective

    598:   Input Parameter:
    599: . tao - the `Tao` context

    601:   Output Parameter:
    602: . flg - `PETSC_TRUE` if the `Tao` has this routine `PETSC_FALSE` otherwise

    604:   Level: developer

    606:   Note:
    607:   If the objective of `Tao` has been altered via `TaoAddTerm()`, it will
    608:   return whether the summation of all terms has this routine.

    610: .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoIsGradientDefined()`, `TaoIsObjectiveAndGradientDefined()`
    611: @*/
    612: PetscErrorCode TaoIsObjectiveDefined(Tao tao, PetscBool *flg)
    613: {
    614:   PetscFunctionBegin;
    616:   PetscCall(TaoTermIsObjectiveDefined(tao->objective_term.term, flg));
    617:   PetscFunctionReturn(PETSC_SUCCESS);
    618: }

    620: /*@
    621:   TaoIsGradientDefined - Checks to see if the user has
    622:   declared a gradient-only routine.  Useful for determining when
    623:   it is appropriate to call `TaoComputeGradient()` or
    624:   `TaoComputeObjectiveAndGradient()`

    626:   Not Collective

    628:   Input Parameter:
    629: . tao - the `Tao` context

    631:   Output Parameter:
    632: . flg - `PETSC_TRUE` if the objective `TaoTerm` has this routine, `PETSC_FALSE` otherwise

    634:   Level: developer

    636:   Note:
    637:   If the objective of `Tao` has been altered via `TaoAddTerm()`, it will
    638:   return whether the summation of all terms has this routine.

    640: .seealso: [](ch_tao), `TaoSetGradient()`, `TaoIsObjectiveDefined()`, `TaoIsObjectiveAndGradientDefined()`
    641: @*/
    642: PetscErrorCode TaoIsGradientDefined(Tao tao, PetscBool *flg)
    643: {
    644:   PetscFunctionBegin;
    646:   PetscCall(TaoTermIsGradientDefined(tao->objective_term.term, flg));
    647:   PetscFunctionReturn(PETSC_SUCCESS);
    648: }

    650: /*@
    651:   TaoIsObjectiveAndGradientDefined - Checks to see if the user has
    652:   declared a joint objective/gradient routine.  Useful for determining when
    653:   it is appropriate to call `TaoComputeObjectiveAndGradient()`

    655:   Not Collective

    657:   Input Parameter:
    658: . tao - the `Tao` context

    660:   Output Parameter:
    661: . flg - `PETSC_TRUE` if the objective `TaoTerm` has this routine `PETSC_FALSE` otherwise

    663:   Level: developer

    665:   Note:
    666:   If the objective of `Tao` has been altered via `TaoAddTerm()`, it will
    667:   return whether the summation of all terms has this routine.

    669: .seealso: [](ch_tao), `TaoSetObjectiveAndGradient()`, `TaoIsObjectiveDefined()`, `TaoIsGradientDefined()`
    670: @*/
    671: PetscErrorCode TaoIsObjectiveAndGradientDefined(Tao tao, PetscBool *flg)
    672: {
    673:   PetscFunctionBegin;
    675:   PetscCall(TaoTermIsObjectiveAndGradientDefined(tao->objective_term.term, flg));
    676:   PetscFunctionReturn(PETSC_SUCCESS);
    677: }