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: }