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

Actual source code: taoterm.c

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

      4: PetscClassId TAOTERM_CLASSID;

      6: PetscLogEvent TAOTERM_ObjectiveEval;
      7: PetscLogEvent TAOTERM_GradientEval;
      8: PetscLogEvent TAOTERM_ObjGradEval;
      9: PetscLogEvent TAOTERM_HessianEval;

     11: const char *const TaoTermParametersModes[] = {"optional", "none", "required", "TaoTermParametersMode", "TAOTERM_PARAMETERS_", NULL};

     13: /*@
     14:   TaoTermDestroy - Destroy a `TaoTerm`.

     16:   Collective

     18:   Input Parameter:
     19: . term - a `TaoTerm`

     21:   Level: beginner

     23: .seealso: [](sec_tao_term),
     24:           `TaoTerm`,
     25:           `TaoTermCreate()`,
     26:           `TaoTermSetType()`,
     27:           `TaoTermSetFromOptions()`,
     28:           `TaoTermSetUp()`,
     29:           `TaoTermView()`
     30: @*/
     31: PetscErrorCode TaoTermDestroy(TaoTerm *term)
     32: {
     33:   PetscFunctionBegin;
     34:   if (!*term) PetscFunctionReturn(PETSC_SUCCESS);
     36:   if (--((PetscObject)*term)->refct > 0) {
     37:     *term = NULL;
     38:     PetscFunctionReturn(PETSC_SUCCESS);
     39:   }

     41:   PetscTryTypeMethod(*term, destroy);
     42:   PetscCall(PetscFree((*term)->H_mattype));
     43:   PetscCall(PetscFree((*term)->Hpre_mattype));
     44:   PetscCall(MatDestroy(&(*term)->solution_factory));
     45:   PetscCall(MatDestroy(&(*term)->parameters_factory));
     46:   PetscCall(MatDestroy(&(*term)->parameters_factory_orig));
     47:   PetscCall(PetscHeaderDestroy(term));
     48:   PetscFunctionReturn(PETSC_SUCCESS);
     49: }

     51: /*@
     52:   TaoTermView - View a description of a `TaoTerm`.

     54:   Collective

     56:   Input Parameters:
     57: + term   - a `TaoTerm`
     58: - viewer - a `PetscViewer`

     60:   Level: beginner

     62: .seealso: [](sec_tao_term),
     63:           `TaoTerm`,
     64:           `TaoTermCreate()`,
     65:           `TaoTermSetType()`,
     66:           `TaoTermSetFromOptions()`,
     67:           `TaoTermSetUp()`,
     68:           `TaoTermDestroy()`,
     69:           `PetscViewer`
     70: @*/
     71: PetscErrorCode TaoTermView(TaoTerm term, PetscViewer viewer)
     72: {
     73:   PetscBool iascii;

     75:   PetscFunctionBegin;
     77:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)term), &viewer));
     79:   PetscCheckSameComm(term, 1, viewer, 2);

     81:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
     82:   if (iascii) {
     83:     const char       *solution_vec_type;
     84:     PetscInt          N;
     85:     PetscViewerFormat format;

     87:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)term, viewer));
     88:     PetscCall(PetscViewerGetFormat(viewer, &format));
     89:     PetscCall(PetscViewerASCIIPushTab(viewer));
     90:     PetscCall(MatGetVecType(term->solution_factory, &solution_vec_type));
     91:     PetscCall(MatGetSize(term->solution_factory, &N, NULL));
     92:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
     93:       if (N < 0) PetscCall(PetscViewerASCIIPrintf(viewer, "solution vector space: not set up yet [VecType %s (tao_term_solution_vec_type)]\n", solution_vec_type));
     94:       else PetscCall(PetscViewerASCIIPrintf(viewer, "solution vector space: N = %" PetscInt_FMT " [VecType %s (tao_term_solution_vec_type)]\n", N, solution_vec_type));
     95:     } else {
     96:       if (N < 0) PetscCall(PetscViewerASCIIPrintf(viewer, "solution vector space: not set up yet\n"));
     97:       else PetscCall(PetscViewerASCIIPrintf(viewer, "solution vector space: N = %" PetscInt_FMT "\n", N));
     98:     }
     99:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL && term->parameters_mode == TAOTERM_PARAMETERS_NONE) {
    100:       PetscCall(PetscViewerASCIIPrintf(viewer, "parameter vector space: (none)\n"));
    101:     } else if (term->parameters_mode != TAOTERM_PARAMETERS_NONE) {
    102:       const char *parameters_vec_type;
    103:       PetscInt    K;

    105:       PetscCall(MatGetVecType(term->parameters_factory, &parameters_vec_type));
    106:       PetscCall(MatGetSize(term->parameters_factory, &K, NULL));
    107:       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    108:         if (K < 0) PetscCall(PetscViewerASCIIPrintf(viewer, "parameter vector space: (%s) not set up yet [VecType %s (tao_term_parameters_vec_type)]\n", TaoTermParametersModes[term->parameters_mode], parameters_vec_type));
    109:         else PetscCall(PetscViewerASCIIPrintf(viewer, "parameter vector space: (%s) K = %" PetscInt_FMT " [VecType %s (tao_term_parameters_vec_type)]\n", TaoTermParametersModes[term->parameters_mode], K, parameters_vec_type));
    110:       } else {
    111:         if (K < 0) PetscCall(PetscViewerASCIIPrintf(viewer, "parameter vector space:%s not set up yet\n", term->parameters_mode == TAOTERM_PARAMETERS_OPTIONAL ? " (optional)" : ""));
    112:         else PetscCall(PetscViewerASCIIPrintf(viewer, "parameter vector space:%s K = %" PetscInt_FMT "\n", term->parameters_mode == TAOTERM_PARAMETERS_OPTIONAL ? " (optional)" : "", K));
    113:       }
    114:     }
    115:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    116:       PetscBool3 is_fdpossible;

    118:       PetscCall(TaoTermIsComputeHessianFDPossible(term, &is_fdpossible));
    119:       if (is_fdpossible == PETSC_BOOL3_FALSE) {
    120:         if (term->fd_hessian) PetscCall(PetscViewerASCIIPrintf(viewer, "Finite differences for Hessian computation was requested, but ignored.\n"));
    121:         if (term->ops->createhessianmatrices == TaoTermCreateHessianMatricesDefault) {
    122:           PetscCall(PetscViewerASCIIPrintf(viewer, "default Hessian MatType (tao_term_hessian_mat_type): %s\n", term->H_mattype ? term->H_mattype : "(undefined)"));
    123:           if (!term->Hpre_is_H) PetscCall(PetscViewerASCIIPrintf(viewer, "default Hessian preconditioning MatType (tao_term_hessian_pre_mat_type): %s\n", term->Hpre_mattype ? term->Hpre_mattype : "(undefined)"));
    124:         } else {
    125:           PetscCall(PetscViewerASCIIPrintf(viewer, "Hessian MatType (tao_term_hessian_mat_type): %s\n", term->H_mattype ? term->H_mattype : "(undefined)"));
    126:           if (!term->Hpre_is_H) PetscCall(PetscViewerASCIIPrintf(viewer, "Hessian preconditioning MatType (tao_term_hessian_pre_mat_type): %s\n", term->Hpre_mattype ? term->Hpre_mattype : "(undefined)"));
    127:         }
    128:       } else {
    129:         if (term->fd_hessian) PetscCall(PetscViewerASCIIPrintf(viewer, "Using finite differences for Hessian computation\n"));
    130:         else if (term->ops->createhessianmatrices == TaoTermCreateHessianMatricesDefault) {
    131:           PetscCall(PetscViewerASCIIPrintf(viewer, "default Hessian MatType (tao_term_hessian_mat_type): %s\n", term->H_mattype ? term->H_mattype : "(undefined)"));
    132:           if (!term->Hpre_is_H) PetscCall(PetscViewerASCIIPrintf(viewer, "default Hessian preconditioning MatType (tao_term_hessian_pre_mat_type): %s\n", term->Hpre_mattype ? term->Hpre_mattype : "(undefined)"));
    133:         } else {
    134:           PetscBool is_h_mffd    = PETSC_FALSE;
    135:           PetscBool is_hpre_mffd = PETSC_FALSE;

    137:           if (term->H_mattype) PetscCall(PetscStrcmp(term->H_mattype, MATMFFD, &is_h_mffd));
    138:           if (term->Hpre_mattype) PetscCall(PetscStrcmp(term->Hpre_mattype, MATMFFD, &is_hpre_mffd));

    140:           PetscCall(PetscViewerASCIIPrintf(viewer, "Hessian MatType (tao_term_hessian_mat_type): %s\n", term->H_mattype ? term->H_mattype : "(undefined)"));
    141:           if (is_h_mffd) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of gradient evaluations used by MFFD=%" PetscInt_FMT "\n", term->ngrad_mffd));
    142:           if (!term->Hpre_is_H) PetscCall(PetscViewerASCIIPrintf(viewer, "Hessian preconditioning MatType (tao_term_hessian_pre_mat_type): %s\n", term->Hpre_mattype ? term->Hpre_mattype : "(undefined)"));
    143:         }
    144:       }
    145:     }
    146:     PetscTryTypeMethod(term, view, viewer);
    147:     if (term->nobj > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function evaluations=%" PetscInt_FMT "\n", term->nobj));
    148:     if (term->ngrad > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of gradient evaluations=%" PetscInt_FMT "\n", term->ngrad));
    149:     if (term->nobjgrad > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function/gradient evaluations=%" PetscInt_FMT "\n", term->nobjgrad));
    150:     if (term->nhess > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Hessian evaluations=%" PetscInt_FMT "\n", term->nhess));
    151:     PetscCall(PetscViewerASCIIPopTab(viewer));
    152:   }
    153:   PetscFunctionReturn(PETSC_SUCCESS);
    154: }

    156: /*@
    157:   TaoTermSetUp - Set up a `TaoTerm`.

    159:   Collective

    161:   Input Parameter:
    162: . term - a `TaoTerm`

    164:   Level: intermediate

    166: .seealso: [](sec_tao_term),
    167:           `TaoTerm`,
    168:           `TaoTermCreate()`,
    169:           `TaoTermSetType()`,
    170:           `TaoTermSetFromOptions()`,
    171:           `TaoTermView()`,
    172:           `TaoTermDestroy()`
    173: @*/
    174: PetscErrorCode TaoTermSetUp(TaoTerm term)
    175: {
    176:   PetscInt N;

    178:   PetscFunctionBegin;
    180:   if (term->setup_called) PetscFunctionReturn(PETSC_SUCCESS);
    181:   term->setup_called = PETSC_TRUE;
    182:   PetscTryTypeMethod(term, setup);
    183:   PetscCall(MatGetSize(term->solution_factory, &N, NULL));
    184:   if (N < 0) {
    185:     PetscBool is_shell;
    186:     Vec       sol_template;

    188:     PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMSHELL, &is_shell));
    189:     if (is_shell)
    190:       PetscCheck(term->ops->createsolutionvec, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm solution space not known. You should have called TaoTermSetSolutionSizes(), TaoTermSetSolutionTemplate(), TaoTermSetSolutionLayout(), or TaoTermShellSetCreateSolutionVec()");
    191:     else
    192:       PetscCheck(term->ops->createsolutionvec, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm solution space not known. You should have called TaoTermSetSolutionSizes(), TaoTermSetSolutionTemplate(), or TaoTermSetSolutionLayout()");

    194:     PetscCall(TaoTermCreateSolutionVec(term, &sol_template));
    195:     PetscCall(TaoTermSetSolutionTemplate(term, sol_template));
    196:     PetscCall(VecDestroy(&sol_template));
    197:   }
    198:   PetscCall(MatSetUp(term->solution_factory));
    199:   if (term->parameters_mode != TAOTERM_PARAMETERS_NONE) {
    200:     PetscInt K;

    202:     PetscCall(MatGetSize(term->parameters_factory, &K, NULL));
    203:     if (K < 0) {
    204:       PetscBool is_shell;
    205:       Vec       params_template;

    207:       PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMSHELL, &is_shell));
    208:       if (is_shell)
    209:         PetscCheck(term->ops->createparametersvec, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm parameters space not known. You should have called TaoTermSetParametersSizes(), TaoTermSetParametersTemplate(), TaoTermSetParametersLayout(), or TaoTermShellSetCreateParametersVec()");
    210:       else
    211:         PetscCheck(term->ops->createparametersvec, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm parameters space not known. You should have called TaoTermSetParametersSizes(), TaoTermSetParametersTemplate(), or TaoTermSetParametersLayout()");

    213:       PetscCall(TaoTermCreateParametersVec(term, &params_template));
    214:       PetscCall(TaoTermSetParametersTemplate(term, params_template));
    215:       PetscCall(VecDestroy(&params_template));
    216:     }
    217:     PetscCall(MatSetUp(term->parameters_factory));
    218:   }
    219:   PetscFunctionReturn(PETSC_SUCCESS);
    220: }

    222: /*@
    223:   TaoTermSetFromOptions - Configure a `TaoTerm` from the PETSc options database

    225:   Collective

    227:   Input Parameter:
    228: . term - a `TaoTerm`

    230:   Options Database Keys:
    231: + -tao_term_type <type>                              - l1, halfl2squared; see `TaoTermType` for a complete list
    232: . -tao_term_solution_vec_type <type>                 - the type of vector to use for the solution, see `VecType` for a complete list of vector types
    233: . -tao_term_parameters_vec_type <type>               - the type of vector to use for the parameters, see `VecType` for a complete list of vector types
    234: . -tao_term_parameters_mode <optional,none,required> - `TAOTERM_PARAMETERS_OPTIONAL`, `TAOTERM_PARAMETERS_NONE`, `TAOTERM_PARAMETERS_REQUIRED`
    235: . -tao_term_hessian_pre_is_hessian <bool>            - Whether `TaoTermCreateHessianMatricesDefault()` should make a separate preconditioning matrix
    236: . -tao_term_hessian_mat_type <type>                  - `MatType` for Hessian matrix created by `TaoTermCreateHessianMatricesDefault()`
    237: . -tao_term_hessian_pre_mat_type <type>              - `MatType` for approximate Hessian matrix used to construct the preconditioner created by `TaoTermCreateHessianMatricesDefault()`
    238: . -tao_term_fd_delta <real>                          - Increment for finite difference derivative approximations in `TaoTermComputeGradientFD()`
    239: . -tao_term_gradient_use_fd <bool>                   - Use finite differences in `TaoTermComputeGradient()`, overriding other user-provided or built-in routines
    240: - -tao_term_hessian_use_fd <bool>                    - Use finite differences in `TaoTermComputeHessian()`, overriding other user-provided or built-in routines

    242:   Level: beginner

    244: .seealso: [](sec_tao_term),
    245:           `TaoTerm`,
    246:           `TaoTermCreate()`,
    247:           `TaoTermSetType()`,
    248:           `TaoTermSetUp()`,
    249:           `TaoTermView()`,
    250:           `TaoTermDestroy()`
    251: @*/
    252: PetscErrorCode TaoTermSetFromOptions(TaoTerm term)
    253: {
    254:   const char *deft = TAOTERMSHELL;
    255:   PetscBool   flg;
    256:   char        typeName[256];
    257:   VecType     sol_type, params_type;
    258:   PetscBool   opt;
    259:   PetscBool   grad_use_fd;
    260:   PetscBool   hess_use_fd;

    262:   PetscFunctionBegin;
    264:   if (((PetscObject)term)->type_name) deft = ((PetscObject)term)->type_name;
    265:   PetscObjectOptionsBegin((PetscObject)term);
    266:   PetscCall(PetscOptionsFList("-tao_term_type", "TaoTerm type", "TaoTermType", TaoTermList, deft, typeName, 256, &flg));
    267:   if (flg) PetscCall(TaoTermSetType(term, typeName));
    268:   else PetscCall(TaoTermSetType(term, deft));
    269:   PetscCall(TaoTermGetSolutionVecType(term, &sol_type));
    270:   PetscCall(TaoTermGetParametersVecType(term, &params_type));
    271:   PetscCall(PetscOptionsFList("-tao_term_solution_vec_type", "Solution vector type", "TaoTermSetSolutionVecType", VecList, sol_type, typeName, 256, &opt));
    272:   if (opt) PetscCall(TaoTermSetSolutionVecType(term, typeName));
    273:   PetscCall(PetscOptionsFList("-tao_term_parameters_vec_type", "Parameters vector type", "TaoTermSetParametersVecType", VecList, params_type, typeName, 256, &opt));
    274:   if (opt) PetscCall(TaoTermSetParametersVecType(term, typeName));
    275:   PetscCall(PetscOptionsEnum("-tao_term_parameters_mode", "Parameters requirement type", "TaoTermSetParametersMode", TaoTermParametersModes, (PetscEnum)term->parameters_mode, (PetscEnum *)&term->parameters_mode, NULL));
    276:   PetscCall(PetscOptionsBool("-tao_term_hessian_pre_is_hessian", "If the Hessian and its preconditioning matrix should be the same", "TaoTermSetCreateHessianMode", term->Hpre_is_H, &term->Hpre_is_H, NULL));

    278:   deft = MATAIJ;
    279:   if (term->H_mattype) deft = term->H_mattype;
    280:   PetscCall(PetscOptionsFList("-tao_term_hessian_mat_type", "Hessian mat type", "TaoTermSetCreateHessianMode", MatList, deft, typeName, 256, &opt));
    281:   if (opt) {
    282:     PetscBool is_mffd, is_shell, is_callbacks;
    283:     PetscCall(PetscStrcmp(typeName, MATMFFD, &is_mffd));
    284:     if (is_mffd) {
    285:       PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMSHELL, &is_shell));
    286:       PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMCALLBACKS, &is_callbacks));
    287:       if (is_shell || is_callbacks) {
    288:         PetscCall(PetscFree(term->H_mattype));
    289:         PetscCall(PetscStrallocpy(typeName, (char **)&term->H_mattype));
    290:       } else {
    291:         PetscCall(PetscInfo(term, "%s: TaoTerm Hessian MatType MFFD requested but TaoTerm type is neither SHELL nor CALLBACKS. Ignoring.\n", ((PetscObject)term)->prefix));
    292:       }
    293:     } else {
    294:       PetscCall(PetscFree(term->H_mattype));
    295:       PetscCall(PetscStrallocpy(typeName, (char **)&term->H_mattype));
    296:     }
    297:   }

    299:   deft = MATAIJ;
    300:   if (term->Hpre_mattype) deft = term->Hpre_mattype;
    301:   PetscCall(PetscOptionsFList("-tao_term_hessian_pre_mat_type", "Hessian preconditioning mat type", "TaoTermSetCreateHessianMode", MatList, deft, typeName, 256, &opt));
    302:   if (opt) {
    303:     PetscCall(PetscFree(term->Hpre_mattype));
    304:     PetscCall(PetscStrallocpy(typeName, (char **)&term->Hpre_mattype));
    305:   }

    307:   if (term->Hpre_is_H) {
    308:     PetscBool mattypes_same;

    310:     PetscCall(PetscStrcmp(term->H_mattype, term->Hpre_mattype, &mattypes_same));
    311:     if (!mattypes_same) {
    312:       PetscCall(PetscInfo(term, "%s: Hpre_is_H, but H_mattype and Hpre_mattype are different. Setting Hpre_mattype to be same as H_mattype\n", ((PetscObject)term)->prefix));
    313:       PetscCall(PetscFree(term->Hpre_mattype));
    314:       PetscCall(PetscStrallocpy(term->H_mattype, (char **)&term->Hpre_mattype));
    315:     }
    316:   }

    318:   PetscCall(PetscOptionsBoundedReal("-tao_term_fd_delta", "Finite difference increment", "TaoTermSetFDDelta", term->fd_delta, &term->fd_delta, NULL, PETSC_SMALL));
    319:   PetscCall(PetscInfo(term, "%s: Finite difference delta set to %g\n", ((PetscObject)term)->prefix, (double)term->fd_delta));

    321:   grad_use_fd = term->fd_gradient;
    322:   PetscCall(PetscOptionsBool("-tao_term_gradient_use_fd", "Use finite differences in TaoTermComputeGradient()", "TaoTermComputeGradientSetUseFD", grad_use_fd, &grad_use_fd, NULL));
    323:   PetscCall(TaoTermComputeGradientSetUseFD(term, grad_use_fd));

    325:   hess_use_fd = term->fd_hessian;
    326:   PetscCall(PetscOptionsBool("-tao_term_hessian_use_fd", "Use finite differences in TaoTermComputeHessian()", "TaoTermComputeHessianSetUseFD", hess_use_fd, &hess_use_fd, NULL));
    327:   PetscCall(TaoTermComputeHessianSetUseFD(term, hess_use_fd));

    329:   PetscTryTypeMethod(term, setfromoptions, PetscOptionsObject);
    330:   PetscOptionsEnd();
    331:   PetscFunctionReturn(PETSC_SUCCESS);
    332: }

    334: /*@
    335:   TaoTermSetType - Set the type of a `TaoTerm`

    337:   Collective

    339:   Input Parameters:
    340: + term - a `TaoTerm`
    341: - type - a `TaoTermType`

    343:   Options Database Keys:
    344: . -tao_term_type <type> - l1, halfl2squared, `TaoTermType` for complete list

    346:   Level: beginner

    348:   Notes:
    349:   Use `TaoTermCreateShell()` to define a custom term using your own function definition

    351:   New types of `TaoTerm` can be created with `TaoTermRegister()`

    353: .seealso: [](sec_tao_term),
    354:           `TaoTerm`,
    355:           `TaoTermType`,
    356:           `TaoTermCreate()`,
    357:           `TaoTermGetType()`,
    358:           `TaoTermSetFromOptions()`,
    359:           `TaoTermSetUp()`,
    360:           `TaoTermView()`,
    361:           `TaoTermDestroy()`
    362: @*/
    363: PetscErrorCode TaoTermSetType(TaoTerm term, TaoTermType type)
    364: {
    365:   PetscErrorCode (*create)(TaoTerm);
    366:   PetscBool issame;

    368:   PetscFunctionBegin;

    371:   PetscCall(PetscObjectTypeCompare((PetscObject)term, type, &issame));
    372:   if (issame) PetscFunctionReturn(PETSC_SUCCESS);

    374:   PetscCall(PetscFunctionListFind(TaoTermList, type, (void (**)(void))&create));
    375:   PetscCheck(create, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested TaoTerm type %s", type);

    377:   /* Destroy the existing term information */
    378:   PetscTryTypeMethod(term, destroy);
    379:   term->setup_called = PETSC_FALSE;
    380:   PetscCall(PetscMemzero(term->ops, sizeof(struct _TaoTermOps)));

    382:   PetscCall((*create)(term));
    383:   PetscCall(PetscObjectChangeTypeName((PetscObject)term, type));
    384:   PetscFunctionReturn(PETSC_SUCCESS);
    385: }

    387: /*@
    388:   TaoTermGetType - Get the type of a `TaoTerm`

    390:   Not collective

    392:   Input Parameter:
    393: . term - a `TaoTerm`

    395:   Output Parameter:
    396: . type - the `TaoTermType`

    398:   Level: beginner

    400: .seealso: [](sec_tao_term),
    401:           `TaoTerm`,
    402:           `TaoTermType`,
    403:           `TaoTermCreate()`,
    404:           `TaoTermSetType()`,
    405:           `TaoTermSetFromOptions()`,
    406:           `TaoTermSetUp()`,
    407:           `TaoTermView()`,
    408:           `TaoTermDestroy()`
    409: @*/
    410: PetscErrorCode TaoTermGetType(TaoTerm term, TaoTermType *type)
    411: {
    412:   PetscFunctionBegin;
    414:   PetscAssertPointer(type, 2);
    415:   *type = ((PetscObject)term)->type_name;
    416:   PetscFunctionReturn(PETSC_SUCCESS);
    417: }

    419: /*@
    420:   TaoTermCreate - Create a TaoTerm to use in defining the function `Tao` is to optimize

    422:   Collective

    424:   Input Parameter:
    425: . comm - communicator for MPI processes that compute the term

    427:   Output Parameter:
    428: . term - a new `TaoTerm`

    430:   Level: beginner

    432: .seealso: [](sec_tao_term),
    433:           `TaoTerm`,
    434:           `TaoTermSetType()`,
    435:           `TaoAddTerm()`,
    436:           `TaoTermSetFromOptions()`,
    437:           `TaoTermSetUp()`,
    438:           `TaoTermView()`,
    439:           `TaoTermDestroy()`
    440: @*/
    441: PetscErrorCode TaoTermCreate(MPI_Comm comm, TaoTerm *term)
    442: {
    443:   TaoTerm     _term;
    444:   PetscLayout zero_layout, rlayout, clayout;

    446:   PetscFunctionBegin;
    447:   PetscAssertPointer(term, 2);
    448:   PetscCall(TaoInitializePackage());
    449:   PetscCall(PetscHeaderCreate(_term, TAOTERM_CLASSID, "TaoTerm", "Objective function term", "Tao", comm, TaoTermDestroy, TaoTermView));
    450:   PetscCall(MatCreate(comm, &_term->solution_factory));
    451:   PetscCall(MatSetType(_term->solution_factory, MATDUMMY));
    452:   PetscCall(MatCreate(comm, &_term->parameters_factory));
    453:   PetscCall(MatSetType(_term->parameters_factory, MATDUMMY));
    454:   PetscCall(PetscObjectReference((PetscObject)_term->parameters_factory));
    455:   _term->parameters_factory_orig = _term->parameters_factory;
    456:   PetscCall(PetscLayoutCreateFromSizes(comm, 0, 0, 1, &zero_layout));
    457:   PetscCall(MatGetLayouts(_term->solution_factory, &rlayout, &clayout));
    458:   PetscCall(MatSetLayouts(_term->solution_factory, rlayout, zero_layout));
    459:   PetscCall(MatGetLayouts(_term->parameters_factory, &rlayout, &clayout));
    460:   PetscCall(MatSetLayouts(_term->parameters_factory, rlayout, zero_layout));
    461:   PetscCall(PetscLayoutDestroy(&zero_layout));
    462:   _term->ngrad_mffd   = 0;
    463:   _term->nobj         = 0;
    464:   _term->ngrad        = 0;
    465:   _term->nobjgrad     = 0;
    466:   _term->nhess        = 0;
    467:   _term->Hpre_is_H    = PETSC_TRUE;
    468:   _term->fd_delta     = 0.5 * PETSC_SQRT_MACHINE_EPSILON;
    469:   _term->H_mattype    = NULL;
    470:   _term->Hpre_mattype = NULL;
    471:   *term               = _term;
    472:   PetscFunctionReturn(PETSC_SUCCESS);
    473: }

    475: /*@
    476:   TaoTermComputeObjective - Evaluate a `TaoTerm` for a given solution vector and parameter vector

    478:   Collective

    480:   Input Parameters:
    481: + term   - a `TaoTerm` representing a parametric function $f(x; p)$
    482: . x      - the solution variable $x$ in $f(x; p)$
    483: - params - the parameters $p$ in $f(x; p)$ (may be `NULL` if the term is not parametric)

    485:   Output Parameter:
    486: . value - the value of $f(x; p)$

    488:   Level: developer

    490: .seealso: [](sec_tao_term),
    491:           `TaoTerm`,
    492:           `TaoTermComputeGradient()`,
    493:           `TaoTermComputeObjectiveAndGradient()`,
    494:           `TaoTermComputeHessian()`,
    495:           `TaoTermShellSetObjective()`
    496: @*/
    497: PetscErrorCode TaoTermComputeObjective(TaoTerm term, Vec x, Vec params, PetscReal *value)
    498: {
    499:   PetscBool obj, objgrad;

    501:   PetscFunctionBegin;
    504:   PetscCheckSameComm(term, 1, x, 2);
    505:   PetscAssertPointer(value, 4);
    506:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_NONE || params == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters passed to a TaoTerm with TAOTERM_PARAMETERS_NONE");
    507:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_REQUIRED || params, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters required but not provided for a TaoTerm with TAOTERM_PARAMETERS_REQUIRED");
    508:   if (params) {
    510:     PetscCheckSameComm(term, 1, params, 3);
    511:     PetscCall(VecLockReadPush(params));
    512:   }
    513:   PetscCall(VecLockReadPush(x));
    514:   PetscCall(TaoTermIsObjectiveDefined(term, &obj));
    515:   PetscCall(TaoTermIsObjectiveAndGradientDefined(term, &objgrad));
    516:   if (obj) {
    517:     PetscCall(PetscLogEventBegin(TAOTERM_ObjectiveEval, term, NULL, NULL, NULL));
    518:     PetscUseTypeMethod(term, objective, x, params, value);
    519:     PetscCall(PetscLogEventEnd(TAOTERM_ObjectiveEval, term, NULL, NULL, NULL));
    520:     term->nobj++;
    521:   } else if (objgrad) {
    522:     Vec temp;

    524:     PetscCall(PetscInfo(term, "%s: Duplicating solution vector in order to call objective/gradient routine\n", ((PetscObject)term)->prefix));
    525:     PetscCall(VecDuplicate(x, &temp));
    526:     PetscCall(PetscLogEventBegin(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    527:     PetscUseTypeMethod(term, objectiveandgradient, x, params, value, temp);
    528:     PetscCall(PetscLogEventEnd(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    529:     PetscCall(VecDestroy(&temp));
    530:     term->nobjgrad++;
    531:   } else SETERRQ(PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm does not have an objective function");
    532:   if (params) PetscCall(VecLockReadPop(params));
    533:   PetscCall(VecLockReadPop(x));
    534:   PetscCall(PetscInfo(term, "%s: TaoTerm value: %20.19e\n", ((PetscObject)term)->prefix, (double)(*value)));
    535:   PetscFunctionReturn(PETSC_SUCCESS);
    536: }

    538: /*@
    539:   TaoTermComputeGradient - Evaluate the gradient of a `TaoTerm` for a given solution vector and parameter vector

    541:   Collective

    543:   Input Parameters:
    544: + term   - a `TaoTerm` representing a parametric function $f(x; p)$
    545: . x      - the solution variable $x$ in $f(x; p)$
    546: - params - the parameters $p$ in $f(x; p)$ (may be NULL if the term is not parametric)

    548:   Output Parameter:
    549: . g - the value of $\nabla_x f(x; p)$

    551:   Level: developer

    553: .seealso: [](sec_tao_term),
    554:           `TaoTerm`,
    555:           `TaoTermComputeObjective()`,
    556:           `TaoTermComputeObjectiveAndGradient()`,
    557:           `TaoTermComputeHessian()`,
    558:           `TaoTermShellSetGradient()`
    559: @*/
    560: PetscErrorCode TaoTermComputeGradient(TaoTerm term, Vec x, Vec params, Vec g)
    561: {
    562:   PetscBool objgrad, grad;

    564:   PetscFunctionBegin;
    568:   PetscCheckSameComm(term, 1, x, 2);
    569:   PetscCheckSameComm(term, 1, g, 4);
    570:   VecCheckSameSize(x, 2, g, 4);
    571:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_NONE || params == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters passed to a TaoTerm with TAOTERM_PARAMETERS_NONE");
    572:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_REQUIRED || params, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters required but not provided for a TaoTerm with TAOTERM_PARAMETERS_REQUIRED");
    573:   if (params) {
    575:     PetscCheckSameComm(term, 1, params, 3);
    576:     PetscCall(VecLockReadPush(params));
    577:   }
    578:   PetscCall(VecLockReadPush(x));
    579:   PetscCall(TaoTermIsGradientDefined(term, &grad));
    580:   PetscCall(TaoTermIsObjectiveAndGradientDefined(term, &objgrad));
    581:   if (term->fd_gradient) {
    582:     PetscCall(PetscLogEventBegin(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    583:     PetscCall(TaoTermComputeGradientFD(term, x, params, g));
    584:     PetscCall(PetscLogEventEnd(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    585:     term->ngrad++;
    586:   } else if (grad) {
    587:     PetscCall(PetscLogEventBegin(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    588:     PetscUseTypeMethod(term, gradient, x, params, g);
    589:     PetscCall(PetscLogEventEnd(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    590:     term->ngrad++;
    591:   } else if (objgrad) {
    592:     PetscReal value;

    594:     PetscCall(PetscLogEventBegin(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    595:     PetscUseTypeMethod(term, objectiveandgradient, x, params, &value, g);
    596:     PetscCall(PetscLogEventEnd(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    597:     term->nobjgrad++;
    598:   } else SETERRQ(PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm does not have a gradient function");
    599:   if (params) PetscCall(VecLockReadPop(params));
    600:   PetscCall(VecLockReadPop(x));
    601:   PetscFunctionReturn(PETSC_SUCCESS);
    602: }

    604: /*@
    605:   TaoTermComputeObjectiveAndGradient - Evaluate both the value and gradient of
    606:   a `TaoTerm` for a given set of solution vector and parameter vector

    608:   Collective

    610:   Input Parameters:
    611: + term   - a `TaoTerm` representing a parametric function $f(x; p)$
    612: . x      - the solution variable $x$ in $f(x; p)$
    613: - params - the parameters $p$ in $f(x; p)$ (may be NULL if the term is not parametric)

    615:   Output Parameters:
    616: + value - the value of $f(x; p)$
    617: - g     - the value of $\nabla_x f(x; p)$

    619:   Level: developer

    621: .seealso: [](sec_tao_term),
    622:           `TaoTerm`,
    623:           `TaoTermComputeObjective()`,
    624:           `TaoTermComputeGradient()`,
    625:           `TaoTermComputeHessian()`,
    626:           `TaoTermShellSetObjectiveAndGradient()`
    627: @*/
    628: PetscErrorCode TaoTermComputeObjectiveAndGradient(TaoTerm term, Vec x, Vec params, PetscReal *value, Vec g)
    629: {
    630:   PetscBool objgrad, obj, grad;

    632:   PetscFunctionBegin;
    636:   PetscAssertPointer(value, 4);
    637:   PetscCheckSameComm(term, 1, x, 2);
    638:   PetscCheckSameComm(term, 1, g, 5);
    639:   VecCheckSameSize(x, 2, g, 5);
    640:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_NONE || params == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters passed to a TaoTerm with TAOTERM_PARAMETERS_NONE");
    641:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_REQUIRED || params, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters required but not provided for a TaoTerm with TAOTERM_PARAMETERS_REQUIRED");
    642:   if (params) {
    644:     PetscCheckSameComm(term, 1, params, 3);
    645:     PetscCall(VecLockReadPush(params));
    646:   }
    647:   PetscCall(VecLockReadPush(x));
    648:   PetscCall(TaoTermIsObjectiveDefined(term, &obj));
    649:   PetscCall(TaoTermIsGradientDefined(term, &grad));
    650:   PetscCall(TaoTermIsObjectiveAndGradientDefined(term, &objgrad));
    651:   if (term->fd_gradient) {
    652:     PetscCall(TaoTermComputeObjective(term, x, params, value));
    653:     PetscCall(PetscLogEventBegin(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    654:     PetscCall(TaoTermComputeGradientFD(term, x, params, g));
    655:     PetscCall(PetscLogEventEnd(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    656:     term->ngrad++;
    657:   } else if (objgrad) {
    658:     PetscCall(PetscLogEventBegin(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    659:     PetscUseTypeMethod(term, objectiveandgradient, x, params, value, g);
    660:     PetscCall(PetscLogEventEnd(TAOTERM_ObjGradEval, term, NULL, NULL, NULL));
    661:     term->nobjgrad++;
    662:   } else if (obj && grad) {
    663:     PetscCall(PetscLogEventBegin(TAOTERM_ObjectiveEval, term, NULL, NULL, NULL));
    664:     PetscUseTypeMethod(term, objective, x, params, value);
    665:     PetscCall(PetscLogEventEnd(TAOTERM_ObjectiveEval, term, NULL, NULL, NULL));
    666:     term->nobj++;
    667:     PetscCall(PetscLogEventBegin(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    668:     PetscUseTypeMethod(term, gradient, x, params, g);
    669:     PetscCall(PetscLogEventEnd(TAOTERM_GradientEval, term, NULL, NULL, NULL));
    670:     term->ngrad++;
    671:   } else SETERRQ(PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm does not have objective and gradient function");
    672:   if (params) PetscCall(VecLockReadPop(params));
    673:   PetscCall(VecLockReadPop(x));
    674:   PetscCall(PetscInfo(term, "%s: TaoTerm value: %20.19e\n", ((PetscObject)term)->prefix, (double)(*value)));
    675:   PetscFunctionReturn(PETSC_SUCCESS);
    676: }

    678: /*@
    679:   TaoTermComputeHessian - Evaluate the Hessian of a `TaoTerm`
    680:   (with respect to the solution variables) for a given solution vector and parameter vector

    682:   Collective

    684:   Input Parameters:
    685: + term   - a `TaoTerm` representing a parametric function $f(x; p)$
    686: . x      - the solution variable $x$ in $f(x; p)$
    687: - params - the parameters $p$ in $f(x; p)$ (may be `NULL` if the term is not parametric)

    689:   Output Parameters:
    690: + H    - Hessian matrix $\nabla_x^2 f(x;p)$
    691: - Hpre - an (approximate) Hessian from which the preconditioner will be constructed, often the same as `H`

    693:   Level: developer

    695:   Note:
    696:   If there is no separate matrix from which to construct the preconditioner, then `TaoTermComputeHessian(term, x, params, H, NULL)`
    697:   and `TaoTermComputeHessian(term, x, params, H, H)` are equivalent.

    699: .seealso: [](sec_tao_term),
    700:           `TaoTerm`,
    701:           `TaoTermComputeObjective()`,
    702:           `TaoTermComputeGradient()`,
    703:           `TaoTermComputeObjectiveAndGradient()`,
    704:           `TaoTermShellSetHessian()`
    705: @*/
    706: PetscErrorCode TaoTermComputeHessian(TaoTerm term, Vec x, Vec params, Mat H, Mat Hpre)
    707: {
    708:   PetscBool  is_mffd       = PETSC_FALSE;
    709:   PetscBool3 is_fdpossible = PETSC_BOOL3_UNKNOWN;

    711:   PetscFunctionBegin;
    714:   PetscCheckSameComm(term, 1, x, 2);
    715:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_NONE || params == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters passed to a TaoTerm with TAOTERM_PARAMETERS_NONE");
    716:   PetscCheck(term->parameters_mode != TAOTERM_PARAMETERS_REQUIRED || params, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Parameters required but not provided for a TaoTerm with TAOTERM_PARAMETERS_REQUIRED");
    717:   if (params) {
    719:     PetscCheckSameComm(term, 1, params, 3);
    720:     PetscCall(VecLockReadPush(params));
    721:   }
    722:   PetscCall(VecLockReadPush(x));
    723:   if (H) {
    725:     PetscCheckSameComm(term, 1, H, 4);
    726:   }
    727:   if (Hpre) {
    729:     PetscCheckSameComm(term, 1, Hpre, 5);
    730:   }
    731:   if (H) PetscCall(PetscObjectTypeCompare((PetscObject)H, MATMFFD, &is_mffd));
    732:   PetscCall(TaoTermIsComputeHessianFDPossible(term, &is_fdpossible));
    733:   PetscCall(PetscLogEventBegin(TAOTERM_HessianEval, term, NULL, NULL, NULL));
    734:   if (is_fdpossible == PETSC_BOOL3_FALSE) {
    735:     PetscUseTypeMethod(term, hessian, x, params, H, Hpre);
    736:   } else if (term->fd_hessian) {
    737:     if (is_fdpossible == PETSC_BOOL3_UNKNOWN) PetscCall(PetscInfo(term, "%s: Whether TaoTermComputeHessianFD is possible is unknown. Trying anyway.\n", ((PetscObject)term)->prefix));
    738:     PetscCall(TaoTermComputeHessianFD(term, x, params, H, Hpre));
    739:   } else if (is_mffd) {
    740:     if (is_fdpossible == PETSC_BOOL3_UNKNOWN) PetscCall(PetscInfo(term, "%s: Whether TaoTermComputeHessianMFFD is possible is unknown. Trying anyway.\n", ((PetscObject)term)->prefix));
    741:     PetscCall(TaoTermComputeHessianMFFD(term, x, params, H, Hpre));
    742:   } else {
    743:     if (term->ops->hessian) PetscUseTypeMethod(term, hessian, x, params, H, Hpre);
    744:     else
    745:       SETERRQ(PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONGSTATE, "TaoTerm does not have TaoTermComputeHessian routine, and cannot use finite differences for Hessian computation. Either set Hessian MatType to MATMFFD, or call TaoTermComputeHessianSetUseFD()");
    746:   }
    747:   PetscCall(PetscLogEventEnd(TAOTERM_HessianEval, term, NULL, NULL, NULL));
    748:   term->nhess++;
    749:   if (params) PetscCall(VecLockReadPop(params));
    750:   PetscCall(VecLockReadPop(x));
    751:   PetscFunctionReturn(PETSC_SUCCESS);
    752: }

    754: /*@
    755:   TaoTermIsComputeHessianFDPossible - Whether this term can compute Hessian with finite differences
    756:   with either `-tao_term_hessian_use_fd`, `TaoTermComputeHessianSetUseFD()`, or `MATMFFD`.

    758:   Not collective

    760:   Input Parameter:
    761: . term - a `TaoTerm`

    763:   Output Parameter:
    764: . is_fdpossible - whether Hessian computation with finite differences is possible

    766:   Level: developer

    768: .seealso: [](sec_tao_term),
    769:           `TaoTerm`,
    770:           `TaoTermComputeObjective()`,
    771:           `TaoTermShellSetObjective()`,
    772:           `TaoTermIsGradientDefined()`,
    773:           `TaoTermIsObjectiveAndGradientDefined()`,
    774:           `TaoTermIsHessianDefined()`
    775: @*/
    776: PetscErrorCode TaoTermIsComputeHessianFDPossible(TaoTerm term, PetscBool3 *is_fdpossible)
    777: {
    778:   PetscFunctionBegin;
    780:   PetscAssertPointer(is_fdpossible, 2);
    781:   if (term->ops->iscomputehessianfdpossible) PetscUseTypeMethod(term, iscomputehessianfdpossible, is_fdpossible);
    782:   else *is_fdpossible = PETSC_BOOL3_UNKNOWN;
    783:   PetscFunctionReturn(PETSC_SUCCESS);
    784: }

    786: /*@
    787:   TaoTermIsObjectiveDefined - Whether a standalone objective operation is defined for this `TaoTerm`

    789:   Not collective

    791:   Input Parameter:
    792: . term - a `TaoTerm`

    794:   Output Parameter:
    795: . is_defined - whether the objective is defined

    797:   Note:
    798:   This function strictly checks whether a dedicated objective operation is defined. It does not check whether the
    799:   objective could be computed via other operations (e.g., an objective-and-gradient callback). `TaoTermComputeObjective()`
    800:   may still succeed even if this function returns `PETSC_FALSE`, by falling back to `TaoTermComputeObjectiveAndGradient()`.

    802:   Level: developer

    804: .seealso: [](sec_tao_term),
    805:           `TaoTerm`,
    806:           `TaoTermComputeObjective()`,
    807:           `TaoTermShellSetObjective()`,
    808:           `TaoTermIsGradientDefined()`,
    809:           `TaoTermIsObjectiveAndGradientDefined()`,
    810:           `TaoTermIsHessianDefined()`
    811: @*/
    812: PetscErrorCode TaoTermIsObjectiveDefined(TaoTerm term, PetscBool *is_defined)
    813: {
    814:   PetscFunctionBegin;
    816:   PetscAssertPointer(is_defined, 2);
    817:   if (term->ops->isobjectivedefined) PetscUseTypeMethod(term, isobjectivedefined, is_defined);
    818:   else *is_defined = (term->ops->objective != NULL) ? PETSC_TRUE : PETSC_FALSE;
    819:   PetscFunctionReturn(PETSC_SUCCESS);
    820: }

    822: /*@
    823:   TaoTermIsGradientDefined - Whether a standalone gradient operation is defined for this `TaoTerm`

    825:   Not collective

    827:   Input Parameter:
    828: . term - a `TaoTerm`

    830:   Output Parameter:
    831: . is_defined - whether the gradient is defined

    833:   Note:
    834:   This function strictly checks whether a dedicated gradient operation is defined. It does not check whether the
    835:   gradient could be computed via other operations (e.g., an objective-and-gradient callback or finite differences).
    836:   `TaoTermComputeGradient()` may still succeed even if this function returns `PETSC_FALSE`, by falling back to
    837:   `TaoTermComputeObjectiveAndGradient()` or finite-difference approximation.

    839:   Level: developer

    841: .seealso: [](sec_tao_term),
    842:           `TaoTerm`,
    843:           `TaoTermComputeGradient()`,
    844:           `TaoTermShellSetGradient()`,
    845:           `TaoTermIsObjectiveDefined()`,
    846:           `TaoTermIsObjectiveAndGradientDefined()`,
    847:           `TaoTermIsHessianDefined()`
    848: @*/
    849: PetscErrorCode TaoTermIsGradientDefined(TaoTerm term, PetscBool *is_defined)
    850: {
    851:   PetscFunctionBegin;
    853:   PetscAssertPointer(is_defined, 2);
    854:   if (term->ops->isgradientdefined) PetscUseTypeMethod(term, isgradientdefined, is_defined);
    855:   else *is_defined = (term->ops->gradient != NULL) ? PETSC_TRUE : PETSC_FALSE;
    856:   PetscFunctionReturn(PETSC_SUCCESS);
    857: }

    859: /*@
    860:   TaoTermIsObjectiveAndGradientDefined - Whether a combined objective-and-gradient operation is defined for this `TaoTerm`

    862:   Not collective

    864:   Input Parameter:
    865: . term - a `TaoTerm`

    867:   Output Parameter:
    868: . is_defined - whether the objective/gradient is defined

    870:   Note:
    871:   This function strictly checks whether a dedicated combined objective-and-gradient operation is defined. It does not
    872:   check whether the objective and gradient could be computed via separate objective and gradient operations.
    873:   `TaoTermComputeObjectiveAndGradient()` may still succeed even if this function returns `PETSC_FALSE`, by falling back
    874:   to separate `TaoTermComputeObjective()` and `TaoTermComputeGradient()` calls.

    876:   Level: developer

    878: .seealso: [](sec_tao_term),
    879:           `TaoTerm`,
    880:           `TaoTermComputeObjectiveAndGradient()`,
    881:           `TaoTermShellSetObjectiveAndGradient()`,
    882:           `TaoTermIsObjectiveDefined()`,
    883:           `TaoTermIsGradientDefined()`,
    884:           `TaoTermIsHessianDefined()`
    885: @*/
    886: PetscErrorCode TaoTermIsObjectiveAndGradientDefined(TaoTerm term, PetscBool *is_defined)
    887: {
    888:   PetscFunctionBegin;
    890:   PetscAssertPointer(is_defined, 2);
    891:   if (term->ops->isobjectiveandgradientdefined) PetscUseTypeMethod(term, isobjectiveandgradientdefined, is_defined);
    892:   else *is_defined = (term->ops->objectiveandgradient != NULL) ? PETSC_TRUE : PETSC_FALSE;
    893:   PetscFunctionReturn(PETSC_SUCCESS);
    894: }

    896: /*@
    897:   TaoTermIsHessianDefined - Whether a Hessian operation is defined for this `TaoTerm`

    899:   Not collective

    901:   Input Parameter:
    902: . term - a `TaoTerm`

    904:   Output Parameter:
    905: . is_defined - whether the Hessian is defined

    907:   Note:
    908:   This function strictly checks whether a dedicated Hessian operation is defined. It does not check whether the
    909:   Hessian could be computed via finite differences. `TaoTermComputeHessian()` may still succeed even if this function
    910:   returns `PETSC_FALSE`, if finite-difference Hessian computation has been enabled.

    912:   Level: developer

    914: .seealso: [](sec_tao_term),
    915:           `TaoTerm`,
    916:           `TaoTermComputeHessian()`,
    917:           `TaoTermShellSetHessian()`,
    918:           `TaoTermIsObjectiveDefined()`,
    919:           `TaoTermIsGradientDefined()`,
    920:           `TaoTermIsObjectiveAndGradientDefined()`
    921: @*/
    922: PetscErrorCode TaoTermIsHessianDefined(TaoTerm term, PetscBool *is_defined)
    923: {
    924:   PetscFunctionBegin;
    926:   PetscAssertPointer(is_defined, 2);
    927:   if (term->ops->ishessiandefined) PetscUseTypeMethod(term, ishessiandefined, is_defined);
    928:   else *is_defined = (term->ops->hessian != NULL) ? PETSC_TRUE : PETSC_FALSE;
    929:   PetscFunctionReturn(PETSC_SUCCESS);
    930: }

    932: /*@
    933:   TaoTermIsCreateHessianMatricesDefined - Whether this term can call `TaoTermCreateHessianMatrices()`.

    935:   Not collective

    937:   Input Parameter:
    938: . term - a `TaoTerm`

    940:   Output Parameter:
    941: . is_defined - whether the term can create new Hessian matrices

    943:   Level: developer

    945: .seealso: [](sec_tao_term),
    946:           `TaoTerm`,
    947:           `TaoTermCreateHessianMatrices()`,
    948:           `TaoTermShellSetCreateHessianMatrices()`,
    949:           `TaoTermIsObjectiveDefined()`,
    950:           `TaoTermIsGradientDefined()`,
    951:           `TaoTermIsObjectiveAndGradientDefined()`,
    952:           `TaoTermIsHessianDefined()`
    953: @*/
    954: PetscErrorCode TaoTermIsCreateHessianMatricesDefined(TaoTerm term, PetscBool *is_defined)
    955: {
    956:   PetscFunctionBegin;
    958:   PetscAssertPointer(is_defined, 2);
    959:   if (term->ops->iscreatehessianmatricesdefined) PetscUseTypeMethod(term, iscreatehessianmatricesdefined, is_defined);
    960:   else *is_defined = (term->ops->createhessianmatrices != NULL) ? PETSC_TRUE : PETSC_FALSE;
    961:   PetscFunctionReturn(PETSC_SUCCESS);
    962: }

    964: /*@
    965:   TaoTermSetSolutionSizes - Set the sizes describing the layout of the solution vector space of a `TaoTerm`.

    967:   Logically collective

    969:   Input Parameters:
    970: + term - a `TaoTerm`
    971: . n    - the size of a solution vector on the current MPI process (or `PETSC_DECIDE`)
    972: . N    - the global size of a solution vector (or `PETSC_DECIDE`)
    973: - bs   - the block size of a solution vector (must be >= 1)

    975:   Level: beginner

    977:   Notes:
    978:   The "solution space" of a `TaoTerm` is the vector space of the optimization variable $x$ in
    979:   $f(x; p)$. This is distinct from the "parameter space" (the space of the fixed data $p$, set
    980:   with `TaoTermSetParametersSizes()`). Some `TaoTermType`s require the solution and parameter
    981:   spaces to be related (e.g., have the same size); see the documentation for each type.

    983:   When a mapping matrix $A$ is used to add a term to a `Tao` via `TaoAddTerm()`, the mapping
    984:   transforms the `Tao` solution vector into this term's solution space.  For example, if the
    985:   `Tao` solution vector is $x \in \mathbb{R}^n$ and the mapping matrix is $A \in \mathbb{R}^{m \times n}$,
    986:   then the term evaluates $f(Ax; p)$ with $Ax \in \mathbb{R}^m$.  The term's solution space is
    987:   therefore $\mathbb{R}^m$, and `TaoTermView()` will report $N = m$ for this term.

    989:   Alternatively, one may use `TaoTermSetSolutionLayout()` or `TaoTermSetSolutionTemplate()` to define the vector sizes.

    991: .seealso: [](sec_tao_term),
    992:           `TaoTerm`,
    993:           `TaoTermGetSolutionSizes()`,
    994:           `TaoTermSetSolutionTemplate()`,
    995:           `TaoTermGetSolutionVecType()`,
    996:           `TaoTermSetSolutionVecType()`,
    997:           `TaoTermGetSolutionLayout()`,
    998:           `TaoTermSetSolutionLayout()`,
    999:           `TaoTermCreateSolutionVec()`
    1000: @*/
    1001: PetscErrorCode TaoTermSetSolutionSizes(TaoTerm term, PetscInt n, PetscInt N, PetscInt bs)
    1002: {
    1003:   PetscLayout layout;

    1005:   PetscFunctionBegin;
    1007:   PetscCall(MatGetLayouts(term->solution_factory, &layout, NULL));
    1008:   PetscCall(PetscLayoutSetLocalSize(layout, n));
    1009:   PetscCall(PetscLayoutSetSize(layout, N));
    1010:   PetscCall(PetscLayoutSetBlockSize(layout, bs));
    1011:   PetscFunctionReturn(PETSC_SUCCESS);
    1012: }

    1014: /*@
    1015:   TaoTermGetSolutionSizes - Get the sizes describing the layout of the solution vector space of a `TaoTerm`.

    1017:   Not collective

    1019:   Input Parameter:
    1020: . term - a `TaoTerm`

    1022:   Output Parameters:
    1023: + n  - (optional) the size of a solution vector on the current MPI process
    1024: . N  - (optional) the global size of a solution vector
    1025: - bs - (optional) the block size of a solution vector

    1027:   Level: beginner

    1029: .seealso: [](sec_tao_term),
    1030:           `TaoTerm`,
    1031:           `TaoTermSetSolutionSizes()`,
    1032:           `TaoTermSetSolutionTemplate()`,
    1033:           `TaoTermGetSolutionVecType()`,
    1034:           `TaoTermSetSolutionVecType()`,
    1035:           `TaoTermGetSolutionLayout()`,
    1036:           `TaoTermSetSolutionLayout()`,
    1037:           `TaoTermCreateSolutionVec()`
    1038: @*/
    1039: PetscErrorCode TaoTermGetSolutionSizes(TaoTerm term, PetscInt *n, PetscInt *N, PetscInt *bs)
    1040: {
    1041:   PetscFunctionBegin;
    1043:   if (n) PetscCall(MatGetLocalSize(term->solution_factory, n, NULL));
    1044:   if (N) PetscCall(MatGetSize(term->solution_factory, N, NULL));
    1045:   if (bs) PetscCall(MatGetBlockSizes(term->solution_factory, bs, NULL));
    1046:   PetscFunctionReturn(PETSC_SUCCESS);
    1047: }

    1049: /*@
    1050:   TaoTermSetParametersSizes - Set the sizes describing the layout of the parameter vector space of a `TaoTerm`.

    1052:   Logically collective

    1054:   Input Parameters:
    1055: + term - a `TaoTerm`
    1056: . k    - the size of a parameter vector on the current MPI process (or `PETSC_DECIDE`)
    1057: . K    - the global size of a parameter vector (or `PETSC_DECIDE`)
    1058: - bs   - the block size of a parameter vector (must be >= 1)

    1060:   Level: beginner

    1062:   Notes:
    1063:   The "parameter space" of a `TaoTerm` is the vector space of the fixed data $p$ in $f(x; p)$.
    1064:   Parameters are not optimized over. This is distinct from the "solution space" (set with
    1065:   `TaoTermSetSolutionSizes()`), which is the space of the optimization variable $x$.
    1066:   Some `TaoTermType`s require the solution and parameter spaces to be related (e.g., have the same size);
    1067:   see the documentation for each type.

    1069:   Alternatively, one may use `TaoTermSetParametersLayout()` or `TaoTermSetParametersTemplate()` to define the vector sizes.

    1071: .seealso: [](sec_tao_term),
    1072:           `TaoTerm`,
    1073:           `TaoTermGetParametersSizes()`,
    1074:           `TaoTermSetParametersTemplate()`,
    1075:           `TaoTermGetParametersVecType()`,
    1076:           `TaoTermSetParametersVecType()`,
    1077:           `TaoTermGetParametersLayout()`,
    1078:           `TaoTermSetParametersLayout()`,
    1079:           `TaoTermCreateParametersVec()`
    1080: @*/
    1081: PetscErrorCode TaoTermSetParametersSizes(TaoTerm term, PetscInt k, PetscInt K, PetscInt bs)
    1082: {
    1083:   PetscLayout layout;

    1085:   PetscFunctionBegin;
    1087:   PetscCall(MatGetLayouts(term->parameters_factory, &layout, NULL));
    1088:   PetscCall(PetscLayoutSetLocalSize(layout, k));
    1089:   PetscCall(PetscLayoutSetSize(layout, K));
    1090:   PetscCall(PetscLayoutSetBlockSize(layout, bs));
    1091:   PetscFunctionReturn(PETSC_SUCCESS);
    1092: }

    1094: /*@
    1095:   TaoTermGetParametersSizes - Get the sizes describing the layout of the parameter vector space of a `TaoTerm`.

    1097:   Not collective

    1099:   Input Parameter:
    1100: . term - a `TaoTerm`

    1102:   Output Parameters:
    1103: + k  - (optional) the size of a parameter vector on the current MPI process
    1104: . K  - (optional) the global size of a parameter vector
    1105: - bs - (optional) the block size of a parameter vector

    1107:   Level: beginner

    1109: .seealso: [](sec_tao_term),
    1110:           `TaoTerm`,
    1111:           `TaoTermSetParametersSizes()`,
    1112:           `TaoTermSetParametersTemplate()`,
    1113:           `TaoTermGetParametersVecType()`,
    1114:           `TaoTermSetParametersVecType()`,
    1115:           `TaoTermGetParametersLayout()`,
    1116:           `TaoTermSetParametersLayout()`,
    1117:           `TaoTermCreateParametersVec()`
    1118: @*/
    1119: PetscErrorCode TaoTermGetParametersSizes(TaoTerm term, PetscInt *k, PetscInt *K, PetscInt *bs)
    1120: {
    1121:   PetscFunctionBegin;
    1123:   if (k) PetscCall(MatGetLocalSize(term->parameters_factory, k, NULL));
    1124:   if (K) PetscCall(MatGetSize(term->parameters_factory, K, NULL));
    1125:   if (bs) PetscCall(MatGetBlockSizes(term->parameters_factory, bs, NULL));
    1126:   PetscFunctionReturn(PETSC_SUCCESS);
    1127: }

    1129: /*@
    1130:   TaoTermSetParametersLayout - Set the layout describing the parameter vector of `TaoTerm`.

    1132:   Collective

    1134:   Input Parameters:
    1135: + term              - a `TaoTerm`
    1136: - parameters_layout - the `PetscLayout` for the parameter space

    1138:   Level: intermediate

    1140:   Notes:
    1141:   The "parameter space" of a `TaoTerm` is the vector space of the fixed data $p$ in $f(x; p)$.
    1142:   Parameters are not optimized over. This is distinct from the "solution space" (set with
    1143:   `TaoTermSetSolutionSizes()`), which is the space of the optimization variable $x$.
    1144:   Some `TaoTermType`s require the solution and parameter spaces to be related (e.g., have the same size);
    1145:   see the documentation for each type.

    1147:   Alternatively, one may use `TaoTermSetParametersSizes()` or `TaoTermSetParametersTemplate()` to define the vector sizes.

    1149: .seealso: [](sec_tao_term),
    1150:           `TaoTerm`,
    1151:           `TaoTermGetParametersVecType()`,
    1152:           `TaoTermSetParametersVecType()`,
    1153:           `TaoTermGetParametersLayout()`,
    1154:           `TaoTermSetSolutionTemplate()`,
    1155:           `TaoTermSetParametersTemplate()`,
    1156:           `TaoTermCreateParametersVec()`
    1157: @*/
    1158: PetscErrorCode TaoTermSetParametersLayout(TaoTerm term, PetscLayout parameters_layout)
    1159: {
    1160:   PetscLayout rlayout, clayout;

    1162:   PetscFunctionBegin;
    1164:   PetscCall(MatGetLayouts(term->parameters_factory, &rlayout, &clayout));
    1165:   PetscCall(MatSetLayouts(term->parameters_factory, parameters_layout, clayout));
    1166:   PetscFunctionReturn(PETSC_SUCCESS);
    1167: }

    1169: /*@
    1170:   TaoTermGetParametersLayout - Get the layouts describing the parameter vectors of a `TaoTerm`.

    1172:   Not collective

    1174:   Input Parameter:
    1175: . term - a `TaoTerm`

    1177:   Output Parameter:
    1178: . parameters_layout - the `PetscLayout` for the parameter space

    1180:   Level: intermediate

    1182: .seealso: [](sec_tao_term),
    1183:           `TaoTerm`,
    1184:           `TaoTermGetParametersVecType()`,
    1185:           `TaoTermSetParametersVecType()`,
    1186:           `TaoTermSetParametersLayout()`,
    1187:           `TaoTermSetSolutionTemplate()`,
    1188:           `TaoTermSetParametersTemplate()`,
    1189:           `TaoTermCreateParametersVec()`
    1190: @*/
    1191: PetscErrorCode TaoTermGetParametersLayout(TaoTerm term, PetscLayout *parameters_layout)
    1192: {
    1193:   PetscFunctionBegin;
    1195:   PetscAssertPointer(parameters_layout, 2);
    1196:   PetscCall(MatGetLayouts(term->parameters_factory, parameters_layout, NULL));
    1197:   PetscFunctionReturn(PETSC_SUCCESS);
    1198: }

    1200: /*@
    1201:   TaoTermSetSolutionLayout - Set the layout describing the solution vector of `TaoTerm`.

    1203:   Collective

    1205:   Input Parameters:
    1206: + term            - a `TaoTerm`
    1207: - solution_layout - the `PetscLayout` for the solution space

    1209:   Level: intermediate

    1211:   Notes:
    1212:   The "solution space" of a `TaoTerm` is the vector space of the optimization variable $x$ in
    1213:   $f(x; p)$. This is distinct from the "parameter space" (the space of the fixed data $p$, set
    1214:   with `TaoTermSetParametersSizes()`). Some `TaoTermType`s require the solution and parameter
    1215:   spaces to be related (e.g., have the same size); see the documentation for each type.

    1217:   When a mapping matrix $A$ is used to add a term to a `Tao` via `TaoAddTerm()`, the mapping
    1218:   transforms the `Tao` solution vector into this term's solution space.  For example, if the
    1219:   `Tao` solution vector is $x \in \mathbb{R}^n$ and the mapping matrix is $A \in \mathbb{R}^{m \times n}$,
    1220:   then the term evaluates $f(Ax; p)$ with $Ax \in \mathbb{R}^m$.  The term's solution space is
    1221:   therefore $\mathbb{R}^m$, and `TaoTermView()` will report $N = m$ for this term.

    1223:   Alternatively, one may use `TaoTermSetSolutionSizes()` or `TaoTermSetSolutionTemplate()` to define the vector sizes.

    1225: .seealso: [](sec_tao_term),
    1226:           `TaoTerm`,
    1227:           `TaoTermGetSolutionVecType()`,
    1228:           `TaoTermSetSolutionVecType()`,
    1229:           `TaoTermGetSolutionLayout()`,
    1230:           `TaoTermSetSolutionTemplate()`,
    1231:           `TaoTermSetParametersTemplate()`,
    1232:           `TaoTermCreateSolutionVec()`
    1233: @*/
    1234: PetscErrorCode TaoTermSetSolutionLayout(TaoTerm term, PetscLayout solution_layout)
    1235: {
    1236:   PetscLayout rlayout, clayout;

    1238:   PetscFunctionBegin;
    1240:   PetscCall(MatGetLayouts(term->solution_factory, &rlayout, &clayout));
    1241:   PetscCall(MatSetLayouts(term->solution_factory, solution_layout, clayout));
    1242:   PetscFunctionReturn(PETSC_SUCCESS);
    1243: }

    1245: /*@
    1246:   TaoTermGetSolutionLayout - Get the layouts describing the solution vectors of a `TaoTerm`.

    1248:   Not collective

    1250:   Input Parameter:
    1251: . term - a `TaoTerm`

    1253:   Output Parameter:
    1254: . solution_layout - the `PetscLayout` for the solution space

    1256:   Level: intermediate

    1258: .seealso: [](sec_tao_term),
    1259:           `TaoTerm`,
    1260:           `TaoTermGetSolutionVecType()`,
    1261:           `TaoTermSetSolutionVecType()`,
    1262:           `TaoTermSetSolutionLayout()`,
    1263:           `TaoTermSetSolutionTemplate()`,
    1264:           `TaoTermSetParametersTemplate()`,
    1265:           `TaoTermCreateSolutionVec()`
    1266: @*/
    1267: PetscErrorCode TaoTermGetSolutionLayout(TaoTerm term, PetscLayout *solution_layout)
    1268: {
    1269:   PetscFunctionBegin;
    1271:   PetscAssertPointer(solution_layout, 2);
    1272:   PetscCall(MatGetLayouts(term->solution_factory, solution_layout, NULL));
    1273:   PetscFunctionReturn(PETSC_SUCCESS);
    1274: }

    1276: /*@
    1277:   TaoTermSetSolutionTemplate - Set the solution vector space to match a template vector

    1279:   Collective

    1281:   Input Parameters:
    1282: + term         - a `TaoTerm`
    1283: - sol_template - a vector with the desired size, layout, and `VecType` of solution vectors for `TaoTerm`

    1285:   Level: intermediate

    1287:   Notes:
    1288:   The "solution space" of a `TaoTerm` is the vector space of the optimization variable $x$ in
    1289:   $f(x; p)$. This is distinct from the "parameter space" (the space of the fixed data $p$, set
    1290:   with `TaoTermSetParametersSizes()`). Some `TaoTermType`s require the solution and parameter
    1291:   spaces to be related (e.g., have the same size); see the documentation for each type.

    1293:   When a mapping matrix $A$ is used to add a term to a `Tao` via `TaoAddTerm()`, the mapping
    1294:   transforms the `Tao` solution vector into this term's solution space.  For example, if the
    1295:   `Tao` solution vector is $x \in \mathbb{R}^n$ and the mapping matrix is $A \in \mathbb{R}^{m \times n}$,
    1296:   then the term evaluates $f(Ax; p)$ with $Ax \in \mathbb{R}^m$.  The term's solution space is
    1297:   therefore $\mathbb{R}^m$, and `TaoTermView()` will report $N = m$ for this term.

    1299:   Alternatively, one may use `TaoTermSetSolutionSizes()` or `TaoTermSetSolutionLayout()` to define the vector sizes.

    1301: .seealso: [](sec_tao_term),
    1302:           `TaoTerm`,
    1303:           `TaoTermGetSolutionVecType()`,
    1304:           `TaoTermSetSolutionVecType()`,
    1305:           `TaoTermSetParametersTemplate()`,
    1306:           `TaoTermGetSolutionLayout()`,
    1307:           `TaoTermSetSolutionLayout()`,
    1308:           `TaoTermCreateSolutionVec()`
    1309: @*/
    1310: PetscErrorCode TaoTermSetSolutionTemplate(TaoTerm term, Vec sol_template)
    1311: {
    1312:   PetscLayout layout, clayout;
    1313:   VecType     vec_type;

    1315:   PetscFunctionBegin;
    1318:   PetscCheckSameComm(term, 1, sol_template, 2);
    1319:   PetscCall(VecGetType(sol_template, &vec_type));
    1320:   PetscCall(VecGetLayout(sol_template, &layout));
    1321:   PetscCall(MatGetLayouts(term->solution_factory, NULL, &clayout));
    1322:   PetscCall(MatSetLayouts(term->solution_factory, layout, clayout));
    1323:   PetscCall(MatSetVecType(term->solution_factory, vec_type));
    1324:   PetscFunctionReturn(PETSC_SUCCESS);
    1325: }

    1327: /*@
    1328:   TaoTermSetParametersTemplate - Set the parameter vector space to match a template vector

    1330:   Collective

    1332:   Input Parameters:
    1333: + term            - a `TaoTerm`
    1334: - params_template - a vector with the desired size, layout, and `VecType` of parameter vectors for `TaoTerm`

    1336:   Level: intermediate

    1338:   Notes:
    1339:   The "parameter space" of a `TaoTerm` is the vector space of the fixed data $p$ in $f(x; p)$.
    1340:   Parameters are not optimized over. This is distinct from the "solution space" (set with
    1341:   `TaoTermSetSolutionSizes()`), which is the space of the optimization variable $x$.
    1342:   Some `TaoTermType`s require the solution and parameter spaces to be related (e.g., have the same size);
    1343:   see the documentation for each type.

    1345:   Alternatively, one may use `TaoTermSetParametersSizes()` or `TaoTermSetParametersLayout()` to define the vector sizes.

    1347: .seealso: [](sec_tao_term),
    1348:           `TaoTerm`,
    1349:           `TaoTermGetParametersVecType()`,
    1350:           `TaoTermSetParametersVecType()`,
    1351:           `TaoTermSetSolutionTemplate()`,
    1352:           `TaoTermGetParametersLayout()`,
    1353:           `TaoTermSetParametersLayout()`,
    1354:           `TaoTermCreateSolutionVec()`
    1355: @*/
    1356: PetscErrorCode TaoTermSetParametersTemplate(TaoTerm term, Vec params_template)
    1357: {
    1358:   PetscLayout layout, clayout;
    1359:   VecType     vec_type;

    1361:   PetscFunctionBegin;
    1364:   PetscCheckSameComm(term, 1, params_template, 2);
    1365:   PetscCall(VecGetType(params_template, &vec_type));
    1366:   PetscCall(VecGetLayout(params_template, &layout));
    1367:   PetscCall(MatGetLayouts(term->parameters_factory, NULL, &clayout));
    1368:   PetscCall(MatSetLayouts(term->parameters_factory, layout, clayout));
    1369:   PetscCall(MatSetVecType(term->parameters_factory, vec_type));
    1370:   PetscFunctionReturn(PETSC_SUCCESS);
    1371: }

    1373: /*@
    1374:   TaoTermSetSolutionVecType - Set the vector types of the solution vector of a `TaoTerm`

    1376:   Logically collective

    1378:   Input Parameters:
    1379: + term          - a `TaoTerm`
    1380: - solution_type - the `VecType` for the solution space

    1382:   Options Database Keys:
    1383: . -tao_term_solution_vec_type <type> - `VecType` for complete list of vector types

    1385:   Level: advanced

    1387: .seealso: [](sec_tao_term),
    1388:           `TaoTerm`,
    1389:           `TaoTermGetSolutionVecType()`,
    1390:           `TaoTermSetSolutionLayout()`,
    1391:           `TaoTermGetSolutionLayout()`,
    1392:           `TaoTermSetSolutionTemplate()`,
    1393:           `TaoTermSetParametersTemplate()`,
    1394:           `TaoTermCreateSolutionVec()`
    1395: @*/
    1396: PetscErrorCode TaoTermSetSolutionVecType(TaoTerm term, VecType solution_type)
    1397: {
    1398:   PetscFunctionBegin;
    1400:   if (solution_type) PetscCall(MatSetVecType(term->solution_factory, solution_type));
    1401:   PetscFunctionReturn(PETSC_SUCCESS);
    1402: }

    1404: /*@
    1405:   TaoTermSetParametersVecType - Set the vector types of the parameters vector of a `TaoTerm`

    1407:   Logically collective

    1409:   Input Parameters:
    1410: + term            - a `TaoTerm`
    1411: - parameters_type - the `VecType` for the parameters space

    1413:   Options Database Keys:
    1414: . -tao_term_parameters_vec_type <type> - `VecType` for complete list of vector types

    1416:   Level: advanced

    1418: .seealso: [](sec_tao_term),
    1419:           `TaoTerm`,
    1420:           `TaoTermGetParametersVecType()`,
    1421:           `TaoTermSetParametersLayout()`,
    1422:           `TaoTermGetParametersLayout()`,
    1423:           `TaoTermSetParametersTemplate()`,
    1424:           `TaoTermCreateParametersVec()`
    1425: @*/
    1426: PetscErrorCode TaoTermSetParametersVecType(TaoTerm term, VecType parameters_type)
    1427: {
    1428:   PetscFunctionBegin;
    1430:   if (parameters_type) PetscCall(MatSetVecType(term->parameters_factory, parameters_type));
    1431:   PetscFunctionReturn(PETSC_SUCCESS);
    1432: }

    1434: /*@
    1435:   TaoTermGetSolutionVecType - Get the vector types of the solution vector of a `TaoTerm`

    1437:   Not collective

    1439:   Input Parameter:
    1440: . term - a `TaoTerm`

    1442:   Output Parameter:
    1443: . solution_type - the `VecType` for the solution space

    1445:   Level: advanced

    1447: .seealso: [](sec_tao_term),
    1448:           `TaoTerm`,
    1449:           `TaoTermSetSolutionVecType()`,
    1450:           `TaoTermGetSolutionLayout()`,
    1451:           `TaoTermSetSolutionLayout()`,
    1452:           `TaoTermSetSolutionTemplate()`,
    1453:           `TaoTermSetParametersTemplate()`,
    1454:           `TaoTermCreateSolutionVec()`
    1455: @*/
    1456: PetscErrorCode TaoTermGetSolutionVecType(TaoTerm term, VecType *solution_type)
    1457: {
    1458:   PetscFunctionBegin;
    1460:   PetscAssertPointer(solution_type, 2);
    1461:   PetscCall(MatGetVecType(term->solution_factory, solution_type));
    1462:   PetscFunctionReturn(PETSC_SUCCESS);
    1463: }

    1465: /*@
    1466:   TaoTermGetParametersVecType - Get the vector types of the parameter vector of a `TaoTerm`

    1468:   Not collective

    1470:   Input Parameter:
    1471: . term - a `TaoTerm`

    1473:   Output Parameter:
    1474: . parameters_type - the `VecType` for the parameter space

    1476:   Level: advanced

    1478: .seealso: [](sec_tao_term),
    1479:           `TaoTerm`,
    1480:           `TaoTermSetParametersVecType()`,
    1481:           `TaoTermGetParametersLayout()`,
    1482:           `TaoTermSetParametersLayout()`,
    1483:           `TaoTermSetSolutionTemplate()`,
    1484:           `TaoTermSetParametersTemplate()`,
    1485:           `TaoTermCreateParametersVec()`
    1486: @*/
    1487: PetscErrorCode TaoTermGetParametersVecType(TaoTerm term, VecType *parameters_type)
    1488: {
    1489:   PetscFunctionBegin;
    1491:   PetscAssertPointer(parameters_type, 2);
    1492:   PetscCall(MatGetVecType(term->parameters_factory, parameters_type));
    1493:   PetscFunctionReturn(PETSC_SUCCESS);
    1494: }

    1496: /*@
    1497:   TaoTermCreateSolutionVec - Create a solution vector for a `TaoTerm`

    1499:   Collective

    1501:   Input Parameter:
    1502: . term - a `TaoTerm`

    1504:   Output Parameter:
    1505: . solution - a compatible solution vector for `term`

    1507:   Level: advanced

    1509:   Note:
    1510:   Before a `TaoTerm` can create a solution vector, you must do one of the following\:

    1512:   * Call `TaoTermSetSolutionSizes()` to describe the size and parallel layout of a solution vector.
    1513:   * Call `TaoTermSetSolutionLayout()` to directly set `PetscLayout`s for the solution vector.
    1514:   * Call `TaoTermSetSolutionTemplate()` to set the solution vector spaces to match existing `Vec`.
    1515:   * If the `TaoTerm` is a `TAOTERMSHELL`, you can call `TaoTermShellSetCreateSolutionVec()` to use
    1516:   your own code for creating vectors.

    1518:   You can also call `TaoTermSetSolutionVecType()` to set the type of vector created (e.g. `VECCUDA`).

    1520: .seealso: [](sec_tao_term),
    1521:           `TaoTerm`,
    1522:           `TaoTermShellSetCreateSolutionVec()`,
    1523:           `TaoTermGetSolutionSizes()`,
    1524:           `TaoTermSetSolutionSizes()`,
    1525:           `TaoTermSetSolutionTemplate()`,
    1526:           `TaoTermGetSolutionVecType()`,
    1527:           `TaoTermSetSolutionVecType()`,
    1528:           `TaoTermGetSolutionLayout()`,
    1529:           `TaoTermSetSolutionLayout()`,
    1530:           `TaoTermCreateHessianMatrices()`
    1531: @*/
    1532: PetscErrorCode TaoTermCreateSolutionVec(TaoTerm term, Vec *solution)
    1533: {
    1534:   PetscFunctionBegin;
    1536:   PetscAssertPointer(solution, 2);
    1537:   if (term->ops->createsolutionvec) {
    1538:     PetscUseTypeMethod(term, createsolutionvec, solution);
    1539:   } else {
    1540:     PetscCall(MatCreateVecs(term->solution_factory, NULL, solution));
    1541:   }
    1542:   PetscFunctionReturn(PETSC_SUCCESS);
    1543: }

    1545: /*@
    1546:   TaoTermCreateParametersVec - Create a parameter vector for a `TaoTerm`

    1548:   Collective

    1550:   Input Parameter:
    1551: . term - a `TaoTerm`

    1553:   Output Parameter:
    1554: . parameters - a compatible parameter vector for `term`

    1556:   Level: advanced

    1558:   Notes:
    1559:   Before a `TaoTerm` can create a parameter vector, you must do one of the following\:

    1561:   * Call `TaoTermSetParametersSizes()` to describe the size and parallel layout of a parameters vector.
    1562:   * Call `TaoTermSetParametersLayout()` to directly set `PetscLayout`s for the parameters vector.
    1563:   * Call `TaoTermSetParametersTemplate()` to set the parameters vector spaces to match existing `Vec`.
    1564:   * If the `TaoTerm` is a `TAOTERMSHELL`, you can call `TaoTermShellSetCreateParametersVec()` to use your
    1565:   own code for creating vectors.

    1567:   You can also call `TaoTermSetParametersVecType()` to set the type of vector created (e.g. `VECCUDA`).

    1569: .seealso: [](sec_tao_term),
    1570:           `TaoTerm`,
    1571:           `TaoTermShellSetCreateParametersVec()`,
    1572:           `TaoTermGetParametersSizes()`,
    1573:           `TaoTermSetParametersSizes()`,
    1574:           `TaoTermSetParametersTemplate()`,
    1575:           `TaoTermGetParametersVecType()`,
    1576:           `TaoTermSetParametersVecType()`,
    1577:           `TaoTermGetParametersLayout()`,
    1578:           `TaoTermSetParametersLayout()`,
    1579:           `TaoTermCreateHessianMatrices()`
    1580: @*/
    1581: PetscErrorCode TaoTermCreateParametersVec(TaoTerm term, Vec *parameters)
    1582: {
    1583:   PetscFunctionBegin;
    1585:   PetscAssertPointer(parameters, 2);
    1586:   if (term->ops->createparametersvec) {
    1587:     PetscUseTypeMethod(term, createparametersvec, parameters);
    1588:   } else {
    1589:     PetscCall(MatCreateVecs(term->parameters_factory, NULL, parameters));
    1590:   }
    1591:   PetscFunctionReturn(PETSC_SUCCESS);
    1592: }

    1594: /*@
    1595:   TaoTermCreateHessianMatrices - Create the matrices that can be inputs to `TaoTermComputeHessian()`

    1597:   Collective

    1599:   Input Parameter:
    1600: . term - a `TaoTerm`

    1602:   Output Parameters:
    1603: + H    - (optional) a matrix that can store the Hessian computed in `TaoTermComputeHessian()`
    1604: - Hpre - (optional) a matrix from which a preconditioner can be computed in `TaoTermComputeHessian()`

    1606:   Level: advanced

    1608:   Note:
    1609:   Before Hessian matrices can be created, the size of the solution vector space
    1610:   must be set (see the ways this can be done in `TaoTermCreateSolutionVec()`).  If the
    1611:   term is a `TAOTERMSHELL`, `TaoTermShellSetCreateHessianMatrices()` must be
    1612:   called.  Most `TaoTerm`s use `TaoTermCreateHessianMatricesDefault()` to create
    1613:   their Hessian matrices: the behavior of that function can be controlled by
    1614:   `TaoTermSetCreateHessianMode()`.

    1616: .seealso: [](sec_tao_term),
    1617:           `TaoTerm`,
    1618:           `TaoTermComputeHessian()`,
    1619:           `TaoTermShellSetCreateHessianMatrices()`,
    1620:           `TaoTermCreateSolutionVec()`,
    1621:           `TaoTermCreateHessianMatricesDefault()`,
    1622:           `TaoTermGetCreateHessianMode()`,
    1623:           `TaoTermSetCreateHessianMode()`,
    1624:           `TaoTermIsCreateHessianMatricesDefined()`
    1625: @*/
    1626: PetscErrorCode TaoTermCreateHessianMatrices(TaoTerm term, Mat *H, Mat *Hpre)
    1627: {
    1628:   PetscFunctionBegin;
    1630:   if (H) PetscAssertPointer(H, 2);
    1631:   if (Hpre) PetscAssertPointer(Hpre, 3);
    1632:   PetscUseTypeMethod(term, createhessianmatrices, H, Hpre);
    1633:   PetscFunctionReturn(PETSC_SUCCESS);
    1634: }

    1636: /*@
    1637:   TaoTermCreateHessianMatricesDefault - Default routine for creating Hessian matrices that can be used by many `TaoTerm` implementations

    1639:   Collective

    1641:   Input Parameter:
    1642: . term - a `TaoTerm`

    1644:   Output Parameters:
    1645: + H    - (optional) a matrix that can store the Hessian computed in `TaoTermComputeHessian()`
    1646: - Hpre - (optional) a matrix from which a preconditioner can be computed in `TaoTermComputeHessian()`

    1648:   Level: developer

    1650:   Developer Note:
    1651:   The behavior of this routine is determined by `TaoTermSetCreateHessianMode()`.
    1652:   If `Hpre_is_H`, then the same matrix will be returned for `H` and `Hpre`,
    1653:   otherwise they will be separate matrices, with the matrix types `H_mattype` and `Hpre_mattype`.
    1654:   If either type is `MATMFFD`, then it will create a shell matrix with `TaoTermCreateHessianMFFD()`.

    1656: .seealso: [](sec_tao_term),
    1657:           `TaoTerm`,
    1658:           `TaoTermComputeHessian()`,
    1659:           `TaoTermCreateHessianMatrices()`,
    1660:           `TaoTermGetCreateHessianMode()`,
    1661:           `TaoTermSetCreateHessianMode()`
    1662: @*/
    1663: PetscErrorCode TaoTermCreateHessianMatricesDefault(TaoTerm term, Mat *H, Mat *Hpre)
    1664: {
    1665:   PetscBool Hpre_is_H;
    1666:   MatType   H_mattype;
    1667:   MatType   Hpre_mattype;

    1669:   PetscFunctionBegin;
    1671:   PetscCall(TaoTermGetCreateHessianMode(term, &Hpre_is_H, &H_mattype, &Hpre_mattype));

    1673:   if (H || (Hpre && Hpre_is_H)) PetscCall(TaoTermCreateHessianMatricesDefault_H_Internal(term, H, Hpre, Hpre_is_H, H_mattype));
    1674:   if (Hpre && !Hpre_is_H) PetscCall(TaoTermCreateHessianMatricesDefault_Hpre_Internal(term, H, Hpre, Hpre_is_H, Hpre_mattype));
    1675:   PetscFunctionReturn(PETSC_SUCCESS);
    1676: }

    1678: /*@
    1679:   TaoTermSetCreateHessianMode - Determine the behavior of `TaoTermCreateHessianMatricesDefault()`.

    1681:   Logically collective

    1683:   Input Parameters:
    1684: + term         - a `TaoTerm`
    1685: . Hpre_is_H    - should `TaoTermCreateHessianMatricesDefault()` make one matrix for `H` and `Hpre`?
    1686: . H_mattype    - the `MatType` to create for `H`
    1687: - Hpre_mattype - the `MatType` to create for `Hpre`

    1689:   Options Database Keys:
    1690: + -tao_term_hessian_pre_is_hessian <bool> - Whether `TaoTermCreateHessianMatrices()` should make a separate matrix for constructing the preconditioner
    1691: . -tao_term_hessian_mat_type <type>       - `MatType` for Hessian matrix created by `TaoTermCreateHessianMatrices()`
    1692: - -tao_term_hessian_pre_mat_type <type>   - `MatType` for matrix from which a preconditioner can be created by `TaoTermCreateHessianMatrices()`

    1694:   Level: developer

    1696: .seealso: [](sec_tao_term),
    1697:           `TaoTerm`,
    1698:           `TaoTermComputeHessian()`,
    1699:           `TaoTermCreateHessianMatrices()`,
    1700:           `TaoTermCreateHessianMatricesDefault()`,
    1701:           `TaoTermGetCreateHessianMode()`
    1702: @*/
    1703: PetscErrorCode TaoTermSetCreateHessianMode(TaoTerm term, PetscBool Hpre_is_H, MatType H_mattype, MatType Hpre_mattype)
    1704: {
    1705:   PetscBool is_hsame, is_hpresame;

    1707:   PetscFunctionBegin;
    1709:   term->Hpre_is_H = Hpre_is_H;
    1710:   PetscCall(PetscStrcmp(term->H_mattype, H_mattype, &is_hsame));
    1711:   PetscCall(PetscStrcmp(term->Hpre_mattype, Hpre_mattype, &is_hpresame));
    1712:   if (!is_hsame) {
    1713:     PetscCall(PetscFree(term->H_mattype));
    1714:     if (H_mattype) PetscCall(PetscStrallocpy(H_mattype, (char **)&term->H_mattype));
    1715:   }
    1716:   if (!is_hpresame) {
    1717:     PetscCall(PetscFree(term->Hpre_mattype));
    1718:     if (Hpre_mattype) PetscCall(PetscStrallocpy(Hpre_mattype, (char **)&term->Hpre_mattype));
    1719:   }
    1720:   PetscFunctionReturn(PETSC_SUCCESS);
    1721: }

    1723: /*@
    1724:   TaoTermGetCreateHessianMode - Get the behavior of `TaoTermCreateHessianMatricesDefault()`.

    1726:   Not collective

    1728:   Input Parameter:
    1729: . term - a `TaoTerm`

    1731:   Output Parameters:
    1732: + Hpre_is_H    - (optional) should `TaoTermCreateHessianMatricesDefault()` make one matrix for `H` and `Hpre`?
    1733: . H_mattype    - (optional) the `MatType` to create for `H`
    1734: - Hpre_mattype - (optional) the `MatType` to create for `Hpre`

    1736:   Level: developer

    1738: .seealso: [](sec_tao_term),
    1739:           `TaoTerm`,
    1740:           `TaoTermComputeHessian()`,
    1741:           `TaoTermCreateHessianMatrices()`,
    1742:           `TaoTermCreateHessianMatricesDefault()`,
    1743:           `TaoTermSetCreateHessianMode()`
    1744: @*/
    1745: PetscErrorCode TaoTermGetCreateHessianMode(TaoTerm term, PetscBool *Hpre_is_H, MatType *H_mattype, MatType *Hpre_mattype)
    1746: {
    1747:   PetscFunctionBegin;
    1749:   if (Hpre_is_H) *Hpre_is_H = term->Hpre_is_H;
    1750:   if (H_mattype) *H_mattype = term->fd_hessian ? MATAIJ : term->H_mattype;
    1751:   if (Hpre_mattype) *Hpre_mattype = term->fd_hessian ? MATAIJ : term->Hpre_mattype;
    1752:   PetscFunctionReturn(PETSC_SUCCESS);
    1753: }

    1755: /*@
    1756:   TaoTermDuplicate - Duplicate a `TaoTerm`

    1758:   Collective

    1760:   Input Parameters:
    1761: + term - a `TaoTerm`
    1762: - opt  - `TAOTERM_DUPLICATE_SIZEONLY` or `TAOTERM_DUPLICATE_TYPE`

    1764:   Output Parameter:
    1765: . newterm - the duplicate `TaoTerm`

    1767:   Notes:
    1768:   This function duplicates the solution space layout and vector type, but does not duplicate
    1769:   parameters-related configuration such as the parameters layout, `TaoTermParametersMode`,
    1770:   Hessian matrix types, or finite-difference settings. These must be set separately on the
    1771:   new `TaoTerm` if needed.

    1773:   If `TAOTERM_DUPLICATE_SIZEONLY` is used, then the duplicated term must have proper `TaoTermType`
    1774:   set with `TaoTermSetType()`.

    1776:   Level: intermediate

    1778: .seealso: [](sec_tao_term),
    1779:           `TaoTerm`,
    1780:           `TaoTermDuplicateOption`
    1781: @*/
    1782: PetscErrorCode TaoTermDuplicate(TaoTerm term, TaoTermDuplicateOption opt, TaoTerm *newterm)
    1783: {
    1784:   VecType     solution_vec_type;
    1785:   PetscLayout rlayout, clayout;
    1786:   PetscBool   is_shell;

    1788:   PetscFunctionBegin;
    1790:   PetscAssertPointer(newterm, 3);
    1791:   PetscCall(TaoTermCreate(PetscObjectComm((PetscObject)term), newterm));
    1792:   PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMSHELL, &is_shell));
    1793:   // Check if createsolutionvec is available first (for TaoTermShell)
    1794:   if (is_shell && term->ops->createsolutionvec) {
    1795:     Vec sol_template;

    1797:     PetscCall(TaoTermCreateSolutionVec(term, &sol_template));
    1798:     PetscCall(TaoTermSetSolutionTemplate(*newterm, sol_template));
    1799:     PetscCall(VecDestroy(&sol_template));
    1800:   } else {
    1801:     PetscCall(MatGetVecType(term->solution_factory, &solution_vec_type));
    1802:     PetscCall(MatGetLayouts(term->solution_factory, &rlayout, &clayout));
    1803:     PetscCall(MatSetVecType((*newterm)->solution_factory, solution_vec_type));
    1804:     PetscCall(MatSetLayouts((*newterm)->solution_factory, rlayout, clayout));
    1805:   }
    1806:   if (opt == TAOTERM_DUPLICATE_TYPE) {
    1807:     TaoTermType type;

    1809:     PetscCall(TaoTermGetType(term, &type));
    1810:     PetscCall(TaoTermSetType(*newterm, type));
    1811:   }
    1812:   PetscFunctionReturn(PETSC_SUCCESS);
    1813: }

    1815: /*@
    1816:   TaoTermSetParametersMode - Sets the way a `TaoTerm` can accept parameters

    1818:   Logically collective

    1820:   Input Parameters:
    1821: + term            - a `TaoTerm`
    1822: - parameters_mode - `TAOTERM_PARAMETERS_OPTIONAL`, `TAOTERM_PARAMETERS_NONE`, `TAOTERM_PARAMETERS_REQUIRED`

    1824:   Options Database Keys:
    1825: . -tao_term_parameters_mode <optional,none,required> - `TAOTERM_PARAMETERS_OPTIONAL`, `TAOTERM_PARAMETERS_NONE`, `TAOTERM_PARAMETERS_REQUIRED`

    1827:   Level: advanced

    1829: .seealso: [](sec_tao_term),
    1830:           `TaoTerm`,
    1831:           `TaoTermParametersMode`,
    1832:           `TaoTermGetParametersMode()`
    1833: @*/
    1834: PetscErrorCode TaoTermSetParametersMode(TaoTerm term, TaoTermParametersMode parameters_mode)
    1835: {
    1836:   PetscFunctionBegin;
    1839:   term->parameters_mode = parameters_mode;
    1840:   PetscFunctionReturn(PETSC_SUCCESS);
    1841: }

    1843: /*@
    1844:   TaoTermGetParametersMode - Gets the way a `TaoTerm` can accept parameters

    1846:   Not collective

    1848:   Input Parameter:
    1849: . term - a `TaoTerm`

    1851:   Output Parameter:
    1852: . parameters_mode - `TAOTERM_PARAMETERS_OPTIONAL`, `TAOTERM_PARAMETERS_NONE`, `TAOTERM_PARAMETERS_REQUIRED`

    1854:   Level: intermediate

    1856: .seealso: [](sec_tao_term),
    1857:           `TaoTerm`,
    1858:           `TaoTermParametersMode`,
    1859:           `TaoTermSetParametersMode()`
    1860: @*/
    1861: PetscErrorCode TaoTermGetParametersMode(TaoTerm term, TaoTermParametersMode *parameters_mode)
    1862: {
    1863:   PetscFunctionBegin;
    1865:   PetscAssertPointer(parameters_mode, 2);
    1866:   *parameters_mode = term->parameters_mode;
    1867:   PetscFunctionReturn(PETSC_SUCCESS);
    1868: }

    1870: /*@
    1871:   TaoTermGetFDDelta - Get the increment used for finite difference derivative approximations in methods like `TaoTermComputeGradientFD()`

    1873:   Not collective

    1875:   Input Parameter:
    1876: . term - a `TaoTerm`

    1878:   Output Parameter:
    1879: . delta - the finite difference increment

    1881:   Options Database Key:
    1882: . -tao_term_fd_delta <delta> - the above increment

    1884:   Level: advanced

    1886: .seealso: [](sec_tao_term),
    1887:           `TaoTerm`,
    1888:           `TaoTermSetFDDelta()`,
    1889:           `TaoTermComputeGradientFD()`,
    1890:           `TaoTermComputeGradientSetUseFD()`,
    1891:           `TaoTermComputeGradientGetUseFD()`
    1892: @*/
    1893: PetscErrorCode TaoTermGetFDDelta(TaoTerm term, PetscReal *delta)
    1894: {
    1895:   PetscFunctionBegin;
    1897:   PetscAssertPointer(delta, 2);
    1898:   *delta = term->fd_delta;
    1899:   PetscFunctionReturn(PETSC_SUCCESS);
    1900: }

    1902: /*@
    1903:   TaoTermSetFDDelta - Set the increment used for finite difference derivative approximations in methods like `TaoTermComputeGradientFD()`

    1905:   Logically collective

    1907:   Input Parameters:
    1908: + term  - a `TaoTerm`
    1909: - delta - the finite difference increment

    1911:   Options Database Key:
    1912: . -tao_term_fd_delta <delta> - the above increment

    1914:   Level: advanced

    1916: .seealso: [](sec_tao_term),
    1917:           `TaoTerm`,
    1918:           `TaoTermGetFDDelta()`,
    1919:           `TaoTermComputeGradientFD()`,
    1920:           `TaoTermComputeGradientSetUseFD()`,
    1921:           `TaoTermComputeGradientGetUseFD()`,
    1922:           `TaoTermComputeHessianFD()`,
    1923:           `TaoTermComputeHessianSetUseFD()`,
    1924:           `TaoTermComputeHessianGetUseFD()`
    1925: @*/
    1926: PetscErrorCode TaoTermSetFDDelta(TaoTerm term, PetscReal delta)
    1927: {
    1928:   PetscFunctionBegin;
    1931:   PetscCheck(delta > 0.0, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_OUTOFRANGE, "finite difference increment must be positive");
    1932:   term->fd_delta = delta;
    1933:   PetscFunctionReturn(PETSC_SUCCESS);
    1934: }

    1936: /*@
    1937:   TaoTermComputeGradientSetUseFD - Set whether to use finite differences instead of the user-provided or built-in gradient method in `TaoTermComputeGradient()`.

    1939:   Logically collective

    1941:   Input Parameters:
    1942: + term   - a `TaoTerm`
    1943: - use_fd - `PETSC_TRUE` to use finite differences, `PETSC_FALSE` to use the user-provided or built-in gradient method

    1945:   Options Database Keys:
    1946: . -tao_term_gradient_use_fd <bool> - use finite differences for gradient computation

    1948:   Level: advanced

    1950: .seealso: [](sec_tao_term),
    1951:           `TaoTerm`,
    1952:           `TaoTermGetFDDelta()`,
    1953:           `TaoTermSetFDDelta()`,
    1954:           `TaoTermComputeGradientFD()`,
    1955:           `TaoTermComputeGradientGetUseFD()`,
    1956:           `TaoTermComputeHessianFD()`,
    1957:           `TaoTermComputeHessianSetUseFD()`,
    1958:           `TaoTermComputeHessianGetUseFD()`
    1959: @*/
    1960: PetscErrorCode TaoTermComputeGradientSetUseFD(TaoTerm term, PetscBool use_fd)
    1961: {
    1962:   PetscFunctionBegin;
    1965:   term->fd_gradient = use_fd;
    1966:   PetscFunctionReturn(PETSC_SUCCESS);
    1967: }

    1969: /*@
    1970:   TaoTermComputeGradientGetUseFD - Get whether finite differences are used in `TaoTermComputeGradient()`.

    1972:   Not collective

    1974:   Input Parameter:
    1975: . term - a `TaoTerm`

    1977:   Output Parameter:
    1978: . use_fd - `PETSC_TRUE` if finite differences are used

    1980:   Level: advanced

    1982: .seealso: [](sec_tao_term),
    1983:           `TaoTerm`,
    1984:           `TaoTermGetFDDelta()`,
    1985:           `TaoTermSetFDDelta()`,
    1986:           `TaoTermComputeGradientFD()`,
    1987:           `TaoTermComputeGradientSetUseFD()`,
    1988:           `TaoTermComputeHessianFD()`,
    1989:           `TaoTermComputeHessianSetUseFD()`,
    1990:           `TaoTermComputeHessianGetUseFD()`
    1991: @*/
    1992: PetscErrorCode TaoTermComputeGradientGetUseFD(TaoTerm term, PetscBool *use_fd)
    1993: {
    1994:   PetscFunctionBegin;
    1996:   PetscAssertPointer(use_fd, 2);
    1997:   *use_fd = term->fd_gradient;
    1998:   PetscFunctionReturn(PETSC_SUCCESS);
    1999: }

    2001: /*@
    2002:   TaoTermComputeHessianSetUseFD - Set whether to use finite differences instead of the user-provided or built-in methods in `TaoTermComputeHessian()`.

    2004:   Logically collective

    2006:   Input Parameters:
    2007: + term   - a `TaoTerm`
    2008: - use_fd - `PETSC_TRUE` to use finite differences, `PETSC_FALSE` to use the user-provided or built-in Hessian method

    2010:   Options Database Keys:
    2011: . -tao_term_hessian_use_fd <bool> - use finite differences for Hessian computation

    2013:   Level: advanced

    2015: .seealso: [](sec_tao_term),
    2016:           `TaoTerm`,
    2017:           `TaoTermGetFDDelta()`,
    2018:           `TaoTermSetFDDelta()`,
    2019:           `TaoTermComputeGradientFD()`,
    2020:           `TaoTermComputeGradientSetUseFD()`,
    2021:           `TaoTermComputeGradientGetUseFD()`,
    2022:           `TaoTermComputeHessianFD()`,
    2023:           `TaoTermComputeHessianGetUseFD()`
    2024: @*/
    2025: PetscErrorCode TaoTermComputeHessianSetUseFD(TaoTerm term, PetscBool use_fd)
    2026: {
    2027:   PetscFunctionBegin;
    2030:   term->fd_hessian = use_fd;
    2031:   PetscFunctionReturn(PETSC_SUCCESS);
    2032: }

    2034: /*@
    2035:   TaoTermComputeHessianGetUseFD - Get whether finite differences are used in `TaoTermComputeHessian()`.

    2037:   Not collective

    2039:   Input Parameter:
    2040: . term - a `TaoTerm`

    2042:   Output Parameter:
    2043: . use_fd - `PETSC_TRUE` if finite differences are used

    2045:   Level: advanced

    2047: .seealso: [](sec_tao_term),
    2048:           `TaoTerm`,
    2049:           `TaoTermGetFDDelta()`,
    2050:           `TaoTermSetFDDelta()`,
    2051:           `TaoTermComputeGradientFD()`,
    2052:           `TaoTermComputeGradientSetUseFD()`,
    2053:           `TaoTermComputeGradientGetUseFD()`,
    2054:           `TaoTermComputeHessianFD()`,
    2055:           `TaoTermComputeHessianSetUseFD()`
    2056: @*/
    2057: PetscErrorCode TaoTermComputeHessianGetUseFD(TaoTerm term, PetscBool *use_fd)
    2058: {
    2059:   PetscFunctionBegin;
    2061:   PetscAssertPointer(use_fd, 2);
    2062:   *use_fd = term->fd_hessian;
    2063:   PetscFunctionReturn(PETSC_SUCCESS);
    2064: }