Actual source code: taosolver_fg.c

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

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

  6:   Logically Collective

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

 12:   Level: beginner

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

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

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

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

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

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

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

 71:   Collective

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

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

 82:   Level: intermediate

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

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

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

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

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

135:   Collective

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

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

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

148:   Level: developer

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

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

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

172:   Collective

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

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

181:   Level: developer

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

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

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

203:   Collective

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

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

213:   Level: developer

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

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

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

238:   Logically Collective

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

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

252:   Level: beginner

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

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

267:   Not Collective

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

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

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

282:   Level: beginner

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

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

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

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

306:   Logically Collective

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

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

321:   Level: beginner

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

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

341:   Collective

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

351:   Level: intermediate

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

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

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

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

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

395:   Collective

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

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

404:   Level: advanced

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

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

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

432:   Logically Collective

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

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

447:   Level: beginner

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

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

469:   Not Collective

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

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

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

485:   Level: beginner

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

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

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

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

510:   Logically Collective

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

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

526:   Level: beginner

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

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

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

551:   Not Collective

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

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

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

568:   Level: beginner

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

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

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

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

596:   Not Collective

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

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

604:   Level: developer

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

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

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

626:   Not Collective

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

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

634:   Level: developer

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

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

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

655:   Not Collective

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

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

663:   Level: developer

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

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