xref: /petsc/src/tao/interface/taosolver_fg.c (revision a4e35b1925eceef64945ea472b84f2bf06a67b5e)
1 #include <petsc/private/taoimpl.h> /*I "petsctao.h" I*/
2 
3 /*@
4   TaoSetSolution - Sets the vector holding the initial guess for the solve
5 
6   Logically Collective
7 
8   Input Parameters:
9 + tao - the `Tao` context
10 - x0  - the initial guess
11 
12   Level: beginner
13 
14 .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`, `TaoGetSolution()`
15 @*/
16 PetscErrorCode TaoSetSolution(Tao tao, Vec x0)
17 {
18   PetscFunctionBegin;
19   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
20   if (x0) PetscValidHeaderSpecific(x0, VEC_CLASSID, 2);
21   PetscCall(PetscObjectReference((PetscObject)x0));
22   PetscCall(VecDestroy(&tao->solution));
23   tao->solution = x0;
24   PetscFunctionReturn(PETSC_SUCCESS);
25 }
26 
27 PetscErrorCode TaoTestGradient(Tao tao, Vec x, Vec g1)
28 {
29   Vec               g2, g3;
30   PetscBool         complete_print = PETSC_FALSE, test = PETSC_FALSE;
31   PetscReal         hcnorm, fdnorm, hcmax, fdmax, diffmax, diffnorm;
32   PetscScalar       dot;
33   MPI_Comm          comm;
34   PetscViewer       viewer, mviewer;
35   PetscViewerFormat format;
36   PetscInt          tabs;
37   static PetscBool  directionsprinted = PETSC_FALSE;
38 
39   PetscFunctionBegin;
40   PetscObjectOptionsBegin((PetscObject)tao);
41   PetscCall(PetscOptionsName("-tao_test_gradient", "Compare hand-coded and finite difference Gradients", "None", &test));
42   PetscCall(PetscOptionsViewer("-tao_test_gradient_view", "View difference between hand-coded and finite difference Gradients element entries", "None", &mviewer, &format, &complete_print));
43   PetscOptionsEnd();
44   if (!test) {
45     if (complete_print) PetscCall(PetscViewerDestroy(&mviewer));
46     PetscFunctionReturn(PETSC_SUCCESS);
47   }
48 
49   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));
50   PetscCall(PetscViewerASCIIGetStdout(comm, &viewer));
51   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
52   PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
53   PetscCall(PetscViewerASCIIPrintf(viewer, "  ---------- Testing Gradient -------------\n"));
54   if (!complete_print && !directionsprinted) {
55     PetscCall(PetscViewerASCIIPrintf(viewer, "  Run with -tao_test_gradient_view and optionally -tao_test_gradient <threshold> to show difference\n"));
56     PetscCall(PetscViewerASCIIPrintf(viewer, "    of hand-coded and finite difference gradient entries greater than <threshold>.\n"));
57   }
58   if (!directionsprinted) {
59     PetscCall(PetscViewerASCIIPrintf(viewer, "  Testing hand-coded Gradient, if (for double precision runs) ||G - Gfd||/||G|| is\n"));
60     PetscCall(PetscViewerASCIIPrintf(viewer, "    O(1.e-8), the hand-coded Gradient is probably correct.\n"));
61     directionsprinted = PETSC_TRUE;
62   }
63   if (complete_print) PetscCall(PetscViewerPushFormat(mviewer, format));
64 
65   PetscCall(VecDuplicate(x, &g2));
66   PetscCall(VecDuplicate(x, &g3));
67 
68   /* Compute finite difference gradient, assume the gradient is already computed by TaoComputeGradient() and put into g1 */
69   PetscCall(TaoDefaultComputeGradient(tao, x, g2, NULL));
70 
71   PetscCall(VecNorm(g2, NORM_2, &fdnorm));
72   PetscCall(VecNorm(g1, NORM_2, &hcnorm));
73   PetscCall(VecNorm(g2, NORM_INFINITY, &fdmax));
74   PetscCall(VecNorm(g1, NORM_INFINITY, &hcmax));
75   PetscCall(VecDot(g1, g2, &dot));
76   PetscCall(VecCopy(g1, g3));
77   PetscCall(VecAXPY(g3, -1.0, g2));
78   PetscCall(VecNorm(g3, NORM_2, &diffnorm));
79   PetscCall(VecNorm(g3, NORM_INFINITY, &diffmax));
80   PetscCall(PetscViewerASCIIPrintf(viewer, "  ||Gfd|| %g, ||G|| = %g, angle cosine = (Gfd'G)/||Gfd||||G|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot) / (fdnorm * hcnorm))));
81   PetscCall(PetscViewerASCIIPrintf(viewer, "  2-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n", (double)(diffnorm / PetscMax(hcnorm, fdnorm)), (double)diffnorm));
82   PetscCall(PetscViewerASCIIPrintf(viewer, "  max-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n", (double)(diffmax / PetscMax(hcmax, fdmax)), (double)diffmax));
83 
84   if (complete_print) {
85     PetscCall(PetscViewerASCIIPrintf(viewer, "  Hand-coded gradient ----------\n"));
86     PetscCall(VecView(g1, mviewer));
87     PetscCall(PetscViewerASCIIPrintf(viewer, "  Finite difference gradient ----------\n"));
88     PetscCall(VecView(g2, mviewer));
89     PetscCall(PetscViewerASCIIPrintf(viewer, "  Hand-coded minus finite-difference gradient ----------\n"));
90     PetscCall(VecView(g3, mviewer));
91   }
92   PetscCall(VecDestroy(&g2));
93   PetscCall(VecDestroy(&g3));
94 
95   if (complete_print) {
96     PetscCall(PetscViewerPopFormat(mviewer));
97     PetscCall(PetscViewerDestroy(&mviewer));
98   }
99   PetscCall(PetscViewerASCIISetTab(viewer, tabs));
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 /*@
104   TaoComputeGradient - Computes the gradient of the objective function
105 
106   Collective
107 
108   Input Parameters:
109 + tao - the `Tao` context
110 - X   - input vector
111 
112   Output Parameter:
113 . G - gradient vector
114 
115   Options Database Keys:
116 + -tao_test_gradient      - compare the user provided gradient with one compute via finite differences to check for errors
117 - -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
118 
119   Level: developer
120 
121   Note:
122   `TaoComputeGradient()` is typically used within the implementation of the optimization method,
123   so most users would not generally call this routine themselves.
124 
125 .seealso: [](ch_tao), `TaoComputeObjective()`, `TaoComputeObjectiveAndGradient()`, `TaoSetGradient()`
126 @*/
127 PetscErrorCode TaoComputeGradient(Tao tao, Vec X, Vec G)
128 {
129   PetscReal dummy;
130 
131   PetscFunctionBegin;
132   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
133   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
134   PetscValidHeaderSpecific(G, VEC_CLASSID, 3);
135   PetscCheckSameComm(tao, 1, X, 2);
136   PetscCheckSameComm(tao, 1, G, 3);
137   PetscCall(VecLockReadPush(X));
138   if (tao->ops->computegradient) {
139     PetscCall(PetscLogEventBegin(TAO_GradientEval, tao, X, G, NULL));
140     PetscCallBack("Tao callback gradient", (*tao->ops->computegradient)(tao, X, G, tao->user_gradP));
141     PetscCall(PetscLogEventEnd(TAO_GradientEval, tao, X, G, NULL));
142     tao->ngrads++;
143   } else if (tao->ops->computeobjectiveandgradient) {
144     PetscCall(PetscLogEventBegin(TAO_ObjGradEval, tao, X, G, NULL));
145     PetscCallBack("Tao callback objective/gradient", (*tao->ops->computeobjectiveandgradient)(tao, X, &dummy, G, tao->user_objgradP));
146     PetscCall(PetscLogEventEnd(TAO_ObjGradEval, tao, X, G, NULL));
147     tao->nfuncgrads++;
148   } else SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TaoSetGradient() has not been called");
149   PetscCall(VecLockReadPop(X));
150 
151   PetscCall(TaoTestGradient(tao, X, G));
152   PetscFunctionReturn(PETSC_SUCCESS);
153 }
154 
155 /*@
156   TaoComputeObjective - Computes the objective function value at a given point
157 
158   Collective
159 
160   Input Parameters:
161 + tao - the `Tao` context
162 - X   - input vector
163 
164   Output Parameter:
165 . f - Objective value at X
166 
167   Level: developer
168 
169   Note:
170   `TaoComputeObjective()` is typically used within the implementation of the optimization algorithm
171   so most users would not generally call this routine themselves.
172 
173 .seealso: [](ch_tao), `Tao`, `TaoComputeGradient()`, `TaoComputeObjectiveAndGradient()`, `TaoSetObjective()`
174 @*/
175 PetscErrorCode TaoComputeObjective(Tao tao, Vec X, PetscReal *f)
176 {
177   Vec temp;
178 
179   PetscFunctionBegin;
180   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
181   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
182   PetscCheckSameComm(tao, 1, X, 2);
183   PetscCall(VecLockReadPush(X));
184   if (tao->ops->computeobjective) {
185     PetscCall(PetscLogEventBegin(TAO_ObjectiveEval, tao, X, NULL, NULL));
186     PetscCallBack("Tao callback objective", (*tao->ops->computeobjective)(tao, X, f, tao->user_objP));
187     PetscCall(PetscLogEventEnd(TAO_ObjectiveEval, tao, X, NULL, NULL));
188     tao->nfuncs++;
189   } else if (tao->ops->computeobjectiveandgradient) {
190     PetscCall(PetscInfo(tao, "Duplicating variable vector in order to call func/grad routine\n"));
191     PetscCall(VecDuplicate(X, &temp));
192     PetscCall(PetscLogEventBegin(TAO_ObjGradEval, tao, X, NULL, NULL));
193     PetscCallBack("Tao callback objective/gradient", (*tao->ops->computeobjectiveandgradient)(tao, X, f, temp, tao->user_objgradP));
194     PetscCall(PetscLogEventEnd(TAO_ObjGradEval, tao, X, NULL, NULL));
195     PetscCall(VecDestroy(&temp));
196     tao->nfuncgrads++;
197   } else SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TaoSetObjective() has not been called");
198   PetscCall(PetscInfo(tao, "TAO Function evaluation: %20.19e\n", (double)(*f)));
199   PetscCall(VecLockReadPop(X));
200   PetscFunctionReturn(PETSC_SUCCESS);
201 }
202 
203 /*@
204   TaoComputeObjectiveAndGradient - Computes the objective function value at a given point
205 
206   Collective
207 
208   Input Parameters:
209 + tao - the `Tao` context
210 - X   - input vector
211 
212   Output Parameters:
213 + f - Objective value at `X`
214 - G - Gradient vector at `X`
215 
216   Level: developer
217 
218   Note:
219   `TaoComputeObjectiveAndGradient()` is typically used within the implementation of the optimization algorithm,
220   so most users would not generally call this routine themselves.
221 
222 .seealso: [](ch_tao), `TaoComputeGradient()`, `TaoSetObjective()`
223 @*/
224 PetscErrorCode TaoComputeObjectiveAndGradient(Tao tao, Vec X, PetscReal *f, Vec G)
225 {
226   PetscFunctionBegin;
227   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
228   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
229   PetscValidHeaderSpecific(G, VEC_CLASSID, 4);
230   PetscCheckSameComm(tao, 1, X, 2);
231   PetscCheckSameComm(tao, 1, G, 4);
232   PetscCall(VecLockReadPush(X));
233   if (tao->ops->computeobjectiveandgradient) {
234     PetscCall(PetscLogEventBegin(TAO_ObjGradEval, tao, X, G, NULL));
235     if (tao->ops->computegradient == TaoDefaultComputeGradient) {
236       PetscCall(TaoComputeObjective(tao, X, f));
237       PetscCall(TaoDefaultComputeGradient(tao, X, G, NULL));
238     } else PetscCallBack("Tao callback objective/gradient", (*tao->ops->computeobjectiveandgradient)(tao, X, f, G, tao->user_objgradP));
239     PetscCall(PetscLogEventEnd(TAO_ObjGradEval, tao, X, G, NULL));
240     tao->nfuncgrads++;
241   } else if (tao->ops->computeobjective && tao->ops->computegradient) {
242     PetscCall(PetscLogEventBegin(TAO_ObjectiveEval, tao, X, NULL, NULL));
243     PetscCallBack("Tao callback objective", (*tao->ops->computeobjective)(tao, X, f, tao->user_objP));
244     PetscCall(PetscLogEventEnd(TAO_ObjectiveEval, tao, X, NULL, NULL));
245     tao->nfuncs++;
246     PetscCall(PetscLogEventBegin(TAO_GradientEval, tao, X, G, NULL));
247     PetscCallBack("Tao callback gradient", (*tao->ops->computegradient)(tao, X, G, tao->user_gradP));
248     PetscCall(PetscLogEventEnd(TAO_GradientEval, tao, X, G, NULL));
249     tao->ngrads++;
250   } else SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TaoSetObjective() or TaoSetGradient() not set");
251   PetscCall(PetscInfo(tao, "TAO Function evaluation: %20.19e\n", (double)(*f)));
252   PetscCall(VecLockReadPop(X));
253 
254   PetscCall(TaoTestGradient(tao, X, G));
255   PetscFunctionReturn(PETSC_SUCCESS);
256 }
257 
258 /*@C
259   TaoSetObjective - Sets the function evaluation routine for minimization
260 
261   Logically Collective
262 
263   Input Parameters:
264 + tao  - the `Tao` context
265 . func - the objective function
266 - ctx  - [optional] user-defined context for private data for the function evaluation
267         routine (may be `NULL`)
268 
269   Calling sequence of `func`:
270 + tao - the optimizer
271 . x   - input vector
272 . f   - function value
273 - ctx - [optional] user-defined function context
274 
275   Level: beginner
276 
277 .seealso: [](ch_tao), `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoGetObjective()`
278 @*/
279 PetscErrorCode TaoSetObjective(Tao tao, PetscErrorCode (*func)(Tao tao, Vec x, PetscReal *f, void *ctx), void *ctx)
280 {
281   PetscFunctionBegin;
282   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
283   if (ctx) tao->user_objP = ctx;
284   if (func) tao->ops->computeobjective = func;
285   PetscFunctionReturn(PETSC_SUCCESS);
286 }
287 
288 /*@C
289   TaoGetObjective - Gets the function evaluation routine for the function to be minimized
290 
291   Not Collective
292 
293   Input Parameter:
294 . tao - the `Tao` context
295 
296   Output Parameters:
297 + func - the objective function
298 - ctx  - the user-defined context for private data for the function evaluation
299 
300   Calling sequence of `func`:
301 + tao - the optimizer
302 . x   - input vector
303 . f   - function value
304 - ctx - [optional] user-defined function context
305 
306   Level: beginner
307 
308 .seealso: [](ch_tao), `Tao`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjective()`
309 @*/
310 PetscErrorCode TaoGetObjective(Tao tao, PetscErrorCode (**func)(Tao tao, Vec x, PetscReal *f, void *ctx), void **ctx)
311 {
312   PetscFunctionBegin;
313   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
314   if (func) *func = tao->ops->computeobjective;
315   if (ctx) *ctx = tao->user_objP;
316   PetscFunctionReturn(PETSC_SUCCESS);
317 }
318 
319 /*@C
320   TaoSetResidualRoutine - Sets the residual evaluation routine for least-square applications
321 
322   Logically Collective
323 
324   Input Parameters:
325 + tao  - the `Tao` context
326 . res  - the residual vector
327 . func - the residual evaluation routine
328 - ctx  - [optional] user-defined context for private data for the function evaluation
329          routine (may be `NULL`)
330 
331   Calling sequence of `func`:
332 + tao - the optimizer
333 . x   - input vector
334 . res - function value vector
335 - ctx - [optional] user-defined function context
336 
337   Level: beginner
338 
339 .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoSetJacobianRoutine()`
340 @*/
341 PetscErrorCode TaoSetResidualRoutine(Tao tao, Vec res, PetscErrorCode (*func)(Tao tao, Vec x, Vec res, void *ctx), void *ctx)
342 {
343   PetscFunctionBegin;
344   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
345   PetscValidHeaderSpecific(res, VEC_CLASSID, 2);
346   PetscCall(PetscObjectReference((PetscObject)res));
347   if (tao->ls_res) PetscCall(VecDestroy(&tao->ls_res));
348   tao->ls_res               = res;
349   tao->user_lsresP          = ctx;
350   tao->ops->computeresidual = func;
351 
352   PetscFunctionReturn(PETSC_SUCCESS);
353 }
354 
355 /*@
356   TaoSetResidualWeights - Give weights for the residual values. A vector can be used if only diagonal terms are used, otherwise a matrix can be give.
357 
358   Collective
359 
360   Input Parameters:
361 + tao     - the `Tao` context
362 . sigma_v - vector of weights (diagonal terms only)
363 . n       - the number of weights (if using off-diagonal)
364 . rows    - index list of rows for `sigma_v`
365 . cols    - index list of columns for `sigma_v`
366 - vals    - array of weights
367 
368   Level: intermediate
369 
370   Notes:
371   If this function is not provided, or if `sigma_v` and `vals` are both `NULL`, then the
372   identity matrix will be used for weights.
373 
374   Either `sigma_v` or `vals` should be `NULL`
375 
376 .seealso: [](ch_tao), `Tao`, `TaoSetResidualRoutine()`
377 @*/
378 PetscErrorCode TaoSetResidualWeights(Tao tao, Vec sigma_v, PetscInt n, PetscInt *rows, PetscInt *cols, PetscReal *vals)
379 {
380   PetscInt i;
381 
382   PetscFunctionBegin;
383   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
384   if (sigma_v) PetscValidHeaderSpecific(sigma_v, VEC_CLASSID, 2);
385   PetscCall(PetscObjectReference((PetscObject)sigma_v));
386   PetscCall(VecDestroy(&tao->res_weights_v));
387   tao->res_weights_v = sigma_v;
388   if (vals) {
389     PetscCall(PetscFree(tao->res_weights_rows));
390     PetscCall(PetscFree(tao->res_weights_cols));
391     PetscCall(PetscFree(tao->res_weights_w));
392     PetscCall(PetscMalloc1(n, &tao->res_weights_rows));
393     PetscCall(PetscMalloc1(n, &tao->res_weights_cols));
394     PetscCall(PetscMalloc1(n, &tao->res_weights_w));
395     tao->res_weights_n = n;
396     for (i = 0; i < n; i++) {
397       tao->res_weights_rows[i] = rows[i];
398       tao->res_weights_cols[i] = cols[i];
399       tao->res_weights_w[i]    = vals[i];
400     }
401   } else {
402     tao->res_weights_n    = 0;
403     tao->res_weights_rows = NULL;
404     tao->res_weights_cols = NULL;
405   }
406   PetscFunctionReturn(PETSC_SUCCESS);
407 }
408 
409 /*@
410   TaoComputeResidual - Computes a least-squares residual vector at a given point
411 
412   Collective
413 
414   Input Parameters:
415 + tao - the `Tao` context
416 - X   - input vector
417 
418   Output Parameter:
419 . F - Objective vector at `X`
420 
421   Level: advanced
422 
423   Notes:
424   `TaoComputeResidual()` is typically used within the implementation of the optimization algorithm,
425   so most users would not generally call this routine themselves.
426 
427 .seealso: [](ch_tao), `Tao`, `TaoSetResidualRoutine()`
428 @*/
429 PetscErrorCode TaoComputeResidual(Tao tao, Vec X, Vec F)
430 {
431   PetscFunctionBegin;
432   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
433   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
434   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
435   PetscCheckSameComm(tao, 1, X, 2);
436   PetscCheckSameComm(tao, 1, F, 3);
437   if (tao->ops->computeresidual) {
438     PetscCall(PetscLogEventBegin(TAO_ObjectiveEval, tao, X, NULL, NULL));
439     PetscCallBack("Tao callback least-squares residual", (*tao->ops->computeresidual)(tao, X, F, tao->user_lsresP));
440     PetscCall(PetscLogEventEnd(TAO_ObjectiveEval, tao, X, NULL, NULL));
441     tao->nfuncs++;
442   } else SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TaoSetResidualRoutine() has not been called");
443   PetscCall(PetscInfo(tao, "TAO least-squares residual evaluation.\n"));
444   PetscFunctionReturn(PETSC_SUCCESS);
445 }
446 
447 /*@C
448   TaoSetGradient - Sets the gradient evaluation routine for the function to be optimized
449 
450   Logically Collective
451 
452   Input Parameters:
453 + tao  - the `Tao` context
454 . g    - [optional] the vector to internally hold the gradient computation
455 . func - the gradient function
456 - ctx  - [optional] user-defined context for private data for the gradient evaluation
457         routine (may be `NULL`)
458 
459   Calling sequence of `func`:
460 + tao - the optimization solver
461 . x   - input vector
462 . g   - gradient value (output)
463 - ctx - [optional] user-defined function context
464 
465   Level: beginner
466 
467 .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoGetGradient()`
468 @*/
469 PetscErrorCode TaoSetGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao tao, Vec x, Vec g, void *ctx), void *ctx)
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
473   if (g) {
474     PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
475     PetscCheckSameComm(tao, 1, g, 2);
476     PetscCall(PetscObjectReference((PetscObject)g));
477     PetscCall(VecDestroy(&tao->gradient));
478     tao->gradient = g;
479   }
480   if (func) tao->ops->computegradient = func;
481   if (ctx) tao->user_gradP = ctx;
482   PetscFunctionReturn(PETSC_SUCCESS);
483 }
484 
485 /*@C
486   TaoGetGradient - Gets the gradient evaluation routine for the function being optimized
487 
488   Not Collective
489 
490   Input Parameter:
491 . tao - the `Tao` context
492 
493   Output Parameters:
494 + g    - the vector to internally hold the gradient computation
495 . func - the gradient function
496 - ctx  - user-defined context for private data for the gradient evaluation routine
497 
498   Calling sequence of `func`:
499 + tao - the optimizer
500 . x   - input vector
501 . g   - gradient value (output)
502 - ctx - [optional] user-defined function context
503 
504   Level: beginner
505 
506 .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`, `TaoSetGradient()`
507 @*/
508 PetscErrorCode TaoGetGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao tao, Vec x, Vec g, void *ctx), void **ctx)
509 {
510   PetscFunctionBegin;
511   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
512   if (g) *g = tao->gradient;
513   if (func) *func = tao->ops->computegradient;
514   if (ctx) *ctx = tao->user_gradP;
515   PetscFunctionReturn(PETSC_SUCCESS);
516 }
517 
518 /*@C
519   TaoSetObjectiveAndGradient - Sets a combined objective function and gradient evaluation routine for the function to be optimized
520 
521   Logically Collective
522 
523   Input Parameters:
524 + tao  - the `Tao` context
525 . g    - [optional] the vector to internally hold the gradient computation
526 . func - the gradient function
527 - ctx  - [optional] user-defined context for private data for the gradient evaluation
528         routine (may be `NULL`)
529 
530   Calling sequence of `func`:
531 + tao - the optimization object
532 . x   - input vector
533 . f   - objective value (output)
534 . g   - gradient value (output)
535 - ctx - [optional] user-defined function context
536 
537   Level: beginner
538 
539   Note:
540   For some optimization methods using a combined function can be more eifficient.
541 
542 .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetHessian()`, `TaoSetGradient()`, `TaoGetObjectiveAndGradient()`
543 @*/
544 PetscErrorCode TaoSetObjectiveAndGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao tao, Vec x, PetscReal *f, Vec g, void *ctx), void *ctx)
545 {
546   PetscFunctionBegin;
547   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
548   if (g) {
549     PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
550     PetscCheckSameComm(tao, 1, g, 2);
551     PetscCall(PetscObjectReference((PetscObject)g));
552     PetscCall(VecDestroy(&tao->gradient));
553     tao->gradient = g;
554   }
555   if (ctx) tao->user_objgradP = ctx;
556   if (func) tao->ops->computeobjectiveandgradient = func;
557   PetscFunctionReturn(PETSC_SUCCESS);
558 }
559 
560 /*@C
561   TaoGetObjectiveAndGradient - Gets the combined objective function and gradient evaluation routine for the function to be optimized
562 
563   Not Collective
564 
565   Input Parameter:
566 . tao - the `Tao` context
567 
568   Output Parameters:
569 + g    - the vector to internally hold the gradient computation
570 . func - the gradient function
571 - ctx  - user-defined context for private data for the gradient evaluation routine
572 
573   Calling sequence of `func`:
574 + tao - the optimizer
575 . x   - input vector
576 . f   - objective value (output)
577 . g   - gradient value (output)
578 - ctx - [optional] user-defined function context
579 
580   Level: beginner
581 
582 .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetObjective()`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoSetObjectiveAndGradient()`
583 @*/
584 PetscErrorCode TaoGetObjectiveAndGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao tao, Vec x, PetscReal *f, Vec g, void *ctx), void **ctx)
585 {
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
588   if (g) *g = tao->gradient;
589   if (func) *func = tao->ops->computeobjectiveandgradient;
590   if (ctx) *ctx = tao->user_objgradP;
591   PetscFunctionReturn(PETSC_SUCCESS);
592 }
593 
594 /*@
595   TaoIsObjectiveDefined - Checks to see if the user has
596   declared an objective-only routine.  Useful for determining when
597   it is appropriate to call `TaoComputeObjective()` or
598   `TaoComputeObjectiveAndGradient()`
599 
600   Not Collective
601 
602   Input Parameter:
603 . tao - the `Tao` context
604 
605   Output Parameter:
606 . flg - `PETSC_TRUE` if function routine is set by user, `PETSC_FALSE` otherwise
607 
608   Level: developer
609 
610 .seealso: [](ch_tao), `Tao`, `TaoSetObjective()`, `TaoIsGradientDefined()`, `TaoIsObjectiveAndGradientDefined()`
611 @*/
612 PetscErrorCode TaoIsObjectiveDefined(Tao tao, PetscBool *flg)
613 {
614   PetscFunctionBegin;
615   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
616   if (tao->ops->computeobjective == NULL) *flg = PETSC_FALSE;
617   else *flg = PETSC_TRUE;
618   PetscFunctionReturn(PETSC_SUCCESS);
619 }
620 
621 /*@
622   TaoIsGradientDefined - Checks to see if the user has
623   declared an objective-only routine.  Useful for determining when
624   it is appropriate to call `TaoComputeGradient()` or
625   `TaoComputeGradientAndGradient()`
626 
627   Not Collective
628 
629   Input Parameter:
630 . tao - the `Tao` context
631 
632   Output Parameter:
633 . flg - `PETSC_TRUE` if function routine is set by user, `PETSC_FALSE` otherwise
634 
635   Level: developer
636 
637 .seealso: [](ch_tao), `TaoSetGradient()`, `TaoIsObjectiveDefined()`, `TaoIsObjectiveAndGradientDefined()`
638 @*/
639 PetscErrorCode TaoIsGradientDefined(Tao tao, PetscBool *flg)
640 {
641   PetscFunctionBegin;
642   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
643   if (tao->ops->computegradient == NULL) *flg = PETSC_FALSE;
644   else *flg = PETSC_TRUE;
645   PetscFunctionReturn(PETSC_SUCCESS);
646 }
647 
648 /*@
649   TaoIsObjectiveAndGradientDefined - Checks to see if the user has
650   declared a joint objective/gradient routine.  Useful for determining when
651   it is appropriate to call `TaoComputeObjective()` or
652   `TaoComputeObjectiveAndGradient()`
653 
654   Not Collective
655 
656   Input Parameter:
657 . tao - the `Tao` context
658 
659   Output Parameter:
660 . flg - `PETSC_TRUE` if function routine is set by user, `PETSC_FALSE` otherwise
661 
662   Level: developer
663 
664 .seealso: [](ch_tao), `TaoSetObjectiveAndGradient()`, `TaoIsObjectiveDefined()`, `TaoIsGradientDefined()`
665 @*/
666 PetscErrorCode TaoIsObjectiveAndGradientDefined(Tao tao, PetscBool *flg)
667 {
668   PetscFunctionBegin;
669   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
670   if (tao->ops->computeobjectiveandgradient == NULL) *flg = PETSC_FALSE;
671   else *flg = PETSC_TRUE;
672   PetscFunctionReturn(PETSC_SUCCESS);
673 }
674