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 on Tao
8: Input Parameters:
9: + tao - the Tao context
10: - x0 - the initial guess
12: Level: beginner
13: .seealso: TaoCreate(), TaoSolve(), TaoGetSolution()
14: @*/
15: PetscErrorCode TaoSetSolution(Tao tao, Vec x0)
16: {
19: PetscObjectReference((PetscObject)x0);
20: VecDestroy(&tao->solution);
21: tao->solution = x0;
22: return 0;
23: }
25: PetscErrorCode TaoTestGradient(Tao tao,Vec x,Vec g1)
26: {
27: Vec g2,g3;
28: PetscBool complete_print = PETSC_FALSE,test = PETSC_FALSE;
29: PetscReal hcnorm,fdnorm,hcmax,fdmax,diffmax,diffnorm;
30: PetscScalar dot;
31: MPI_Comm comm;
32: PetscViewer viewer,mviewer;
33: PetscViewerFormat format;
34: PetscInt tabs;
35: static PetscBool directionsprinted = PETSC_FALSE;
36: PetscErrorCode ierr;
38: PetscObjectOptionsBegin((PetscObject)tao);
39: PetscOptionsName("-tao_test_gradient","Compare hand-coded and finite difference Gradients","None",&test);
40: PetscOptionsViewer("-tao_test_gradient_view","View difference between hand-coded and finite difference Gradients element entries","None",&mviewer,&format,&complete_print);
41: PetscOptionsEnd();
42: if (!test) {
43: if (complete_print) {
44: PetscViewerDestroy(&mviewer);
45: }
46: return 0;
47: }
49: PetscObjectGetComm((PetscObject)tao,&comm);
50: PetscViewerASCIIGetStdout(comm,&viewer);
51: PetscViewerASCIIGetTab(viewer, &tabs);
52: PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel);
53: PetscViewerASCIIPrintf(viewer," ---------- Testing Gradient -------------\n");
54: if (!complete_print && !directionsprinted) {
55: PetscViewerASCIIPrintf(viewer," Run with -tao_test_gradient_view and optionally -tao_test_gradient <threshold> to show difference\n");
56: PetscViewerASCIIPrintf(viewer," of hand-coded and finite difference gradient entries greater than <threshold>.\n");
57: }
58: if (!directionsprinted) {
59: PetscViewerASCIIPrintf(viewer," Testing hand-coded Gradient, if (for double precision runs) ||G - Gfd||/||G|| is\n");
60: PetscViewerASCIIPrintf(viewer," O(1.e-8), the hand-coded Gradient is probably correct.\n");
61: directionsprinted = PETSC_TRUE;
62: }
63: if (complete_print) {
64: PetscViewerPushFormat(mviewer,format);
65: }
67: VecDuplicate(x,&g2);
68: VecDuplicate(x,&g3);
70: /* Compute finite difference gradient, assume the gradient is already computed by TaoComputeGradient() and put into g1 */
71: TaoDefaultComputeGradient(tao,x,g2,NULL);
73: VecNorm(g2,NORM_2,&fdnorm);
74: VecNorm(g1,NORM_2,&hcnorm);
75: VecNorm(g2,NORM_INFINITY,&fdmax);
76: VecNorm(g1,NORM_INFINITY,&hcmax);
77: VecDot(g1,g2,&dot);
78: VecCopy(g1,g3);
79: VecAXPY(g3,-1.0,g2);
80: VecNorm(g3,NORM_2,&diffnorm);
81: VecNorm(g3,NORM_INFINITY,&diffmax);
82: PetscViewerASCIIPrintf(viewer," ||Gfd|| %g, ||G|| = %g, angle cosine = (Gfd'G)/||Gfd||||G|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot)/(fdnorm*hcnorm)));
83: PetscViewerASCIIPrintf(viewer," 2-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffnorm/PetscMax(hcnorm,fdnorm)),(double)diffnorm);
84: PetscViewerASCIIPrintf(viewer," max-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffmax/PetscMax(hcmax,fdmax)),(double)diffmax);
86: if (complete_print) {
87: PetscViewerASCIIPrintf(viewer," Hand-coded gradient ----------\n");
88: VecView(g1,mviewer);
89: PetscViewerASCIIPrintf(viewer," Finite difference gradient ----------\n");
90: VecView(g2,mviewer);
91: PetscViewerASCIIPrintf(viewer," Hand-coded minus finite-difference gradient ----------\n");
92: VecView(g3,mviewer);
93: }
94: VecDestroy(&g2);
95: VecDestroy(&g3);
97: if (complete_print) {
98: PetscViewerPopFormat(mviewer);
99: PetscViewerDestroy(&mviewer);
100: }
101: PetscViewerASCIISetTab(viewer,tabs);
102: return 0;
103: }
105: /*@
106: TaoComputeGradient - Computes the gradient of the objective function
108: Collective on Tao
110: Input Parameters:
111: + tao - the Tao context
112: - X - input vector
114: Output Parameter:
115: . G - gradient vector
117: Options Database Keys:
118: + -tao_test_gradient - compare the user provided gradient with one compute via finite differences to check for errors
119: - -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
121: Notes:
122: TaoComputeGradient() is typically used within minimization implementations,
123: so most users would not generally call this routine themselves.
125: Level: advanced
127: .seealso: TaoComputeObjective(), TaoComputeObjectiveAndGradient(), TaoSetGradient()
128: @*/
129: PetscErrorCode TaoComputeGradient(Tao tao, Vec X, Vec G)
130: {
131: PetscReal dummy;
138: VecLockReadPush(X);
139: if (tao->ops->computegradient) {
140: PetscLogEventBegin(TAO_GradientEval,tao,X,G,NULL);
141: PetscStackPush("Tao user gradient evaluation routine");
142: (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);
143: PetscStackPop;
144: PetscLogEventEnd(TAO_GradientEval,tao,X,G,NULL);
145: tao->ngrads++;
146: } else if (tao->ops->computeobjectiveandgradient) {
147: PetscLogEventBegin(TAO_ObjGradEval,tao,X,G,NULL);
148: PetscStackPush("Tao user objective/gradient evaluation routine");
149: (*tao->ops->computeobjectiveandgradient)(tao,X,&dummy,G,tao->user_objgradP);
150: PetscStackPop;
151: PetscLogEventEnd(TAO_ObjGradEval,tao,X,G,NULL);
152: tao->nfuncgrads++;
153: } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetGradient() has not been called");
154: VecLockReadPop(X);
156: TaoTestGradient(tao,X,G);
157: return 0;
158: }
160: /*@
161: TaoComputeObjective - Computes the objective function value at a given point
163: Collective on Tao
165: Input Parameters:
166: + tao - the Tao context
167: - X - input vector
169: Output Parameter:
170: . f - Objective value at X
172: Notes:
173: TaoComputeObjective() is typically used within minimization implementations,
174: so most users would not generally call this routine themselves.
176: Level: advanced
178: .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjective()
179: @*/
180: PetscErrorCode TaoComputeObjective(Tao tao, Vec X, PetscReal *f)
181: {
182: Vec temp;
187: VecLockReadPush(X);
188: if (tao->ops->computeobjective) {
189: PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
190: PetscStackPush("Tao user objective evaluation routine");
191: (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);
192: PetscStackPop;
193: PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
194: tao->nfuncs++;
195: } else if (tao->ops->computeobjectiveandgradient) {
196: PetscInfo(tao,"Duplicating variable vector in order to call func/grad routine\n");
197: VecDuplicate(X,&temp);
198: PetscLogEventBegin(TAO_ObjGradEval,tao,X,NULL,NULL);
199: PetscStackPush("Tao user objective/gradient evaluation routine");
200: (*tao->ops->computeobjectiveandgradient)(tao,X,f,temp,tao->user_objgradP);
201: PetscStackPop;
202: PetscLogEventEnd(TAO_ObjGradEval,tao,X,NULL,NULL);
203: VecDestroy(&temp);
204: tao->nfuncgrads++;
205: } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjective() has not been called");
206: PetscInfo(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));
207: VecLockReadPop(X);
208: return 0;
209: }
211: /*@
212: TaoComputeObjectiveAndGradient - Computes the objective function value at a given point
214: Collective on Tao
216: Input Parameters:
217: + tao - the Tao context
218: - X - input vector
220: Output Parameters:
221: + f - Objective value at X
222: - g - Gradient vector at X
224: Notes:
225: TaoComputeObjectiveAndGradient() is typically used within minimization implementations,
226: so most users would not generally call this routine themselves.
228: Level: advanced
230: .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjective()
231: @*/
232: PetscErrorCode TaoComputeObjectiveAndGradient(Tao tao, Vec X, PetscReal *f, Vec G)
233: {
239: VecLockReadPush(X);
240: if (tao->ops->computeobjectiveandgradient) {
241: PetscLogEventBegin(TAO_ObjGradEval,tao,X,G,NULL);
242: if (tao->ops->computegradient == TaoDefaultComputeGradient) {
243: TaoComputeObjective(tao,X,f);
244: TaoDefaultComputeGradient(tao,X,G,NULL);
245: } else {
246: PetscStackPush("Tao user objective/gradient evaluation routine");
247: (*tao->ops->computeobjectiveandgradient)(tao,X,f,G,tao->user_objgradP);
248: PetscStackPop;
249: }
250: PetscLogEventEnd(TAO_ObjGradEval,tao,X,G,NULL);
251: tao->nfuncgrads++;
252: } else if (tao->ops->computeobjective && tao->ops->computegradient) {
253: PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
254: PetscStackPush("Tao user objective evaluation routine");
255: (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);
256: PetscStackPop;
257: PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
258: tao->nfuncs++;
259: PetscLogEventBegin(TAO_GradientEval,tao,X,G,NULL);
260: PetscStackPush("Tao user gradient evaluation routine");
261: (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);
262: PetscStackPop;
263: PetscLogEventEnd(TAO_GradientEval,tao,X,G,NULL);
264: tao->ngrads++;
265: } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjective() or TaoSetGradient() not set");
266: PetscInfo(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));
267: VecLockReadPop(X);
269: TaoTestGradient(tao,X,G);
270: return 0;
271: }
273: /*@C
274: TaoSetObjective - Sets the function evaluation routine for minimization
276: Logically collective on Tao
278: Input Parameters:
279: + tao - the Tao context
280: . func - the objective function
281: - ctx - [optional] user-defined context for private data for the function evaluation
282: routine (may be NULL)
284: Calling sequence of func:
285: $ func (Tao tao, Vec x, PetscReal *f, void *ctx);
287: + x - input vector
288: . f - function value
289: - ctx - [optional] user-defined function context
291: Level: beginner
293: .seealso: TaoSetGradient(), TaoSetHessian(), TaoSetObjectiveAndGradient(), TaoGetObjective()
294: @*/
295: PetscErrorCode TaoSetObjective(Tao tao, PetscErrorCode (*func)(Tao, Vec, PetscReal*,void*),void *ctx)
296: {
298: if (ctx) tao->user_objP = ctx;
299: if (func) tao->ops->computeobjective = func;
300: return 0;
301: }
303: /*@C
304: TaoGetObjective - Gets the function evaluation routine for minimization
306: Not collective
308: Input Parameter:
309: . tao - the Tao context
311: Output Parameters
312: + func - the objective function
313: - ctx - the user-defined context for private data for the function evaluation
315: Calling sequence of func:
316: $ func (Tao tao, Vec x, PetscReal *f, void *ctx);
318: + x - input vector
319: . f - function value
320: - ctx - [optional] user-defined function context
322: Level: beginner
324: .seealso: TaoSetGradient(), TaoSetHessian(), TaoSetObjective()
325: @*/
326: PetscErrorCode TaoGetObjective(Tao tao, PetscErrorCode (**func)(Tao, Vec, PetscReal*,void*),void **ctx)
327: {
329: if (func) *func = tao->ops->computeobjective;
330: if (ctx) *ctx = tao->user_objP;
331: return 0;
332: }
334: /*@C
335: TaoSetResidualRoutine - Sets the residual evaluation routine for least-square applications
337: Logically collective on Tao
339: Input Parameters:
340: + tao - the Tao context
341: . func - the residual evaluation routine
342: - ctx - [optional] user-defined context for private data for the function evaluation
343: routine (may be NULL)
345: Calling sequence of func:
346: $ func (Tao tao, Vec x, Vec f, void *ctx);
348: + x - input vector
349: . f - function value vector
350: - ctx - [optional] user-defined function context
352: Level: beginner
354: .seealso: TaoSetObjective(), TaoSetJacobianRoutine()
355: @*/
356: PetscErrorCode TaoSetResidualRoutine(Tao tao, Vec res, PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
357: {
360: PetscObjectReference((PetscObject)res);
361: if (tao->ls_res) {
362: VecDestroy(&tao->ls_res);
363: }
364: tao->ls_res = res;
365: tao->user_lsresP = ctx;
366: tao->ops->computeresidual = func;
368: return 0;
369: }
371: /*@
372: TaoSetResidualWeights - Give weights for the residual values. A vector can be used if only diagonal terms are used, otherwise a matrix can be give. If this function is not used, or if sigma_v and sigma_w are both NULL, then the default identity matrix will be used for weights.
374: Collective on Tao
376: Input Parameters:
377: + tao - the Tao context
378: . sigma_v - vector of weights (diagonal terms only)
379: . n - the number of weights (if using off-diagonal)
380: . rows - index list of rows for sigma_w
381: . cols - index list of columns for sigma_w
382: - vals - array of weights
384: Note: Either sigma_v or sigma_w (or both) should be NULL
386: Level: intermediate
388: .seealso: TaoSetResidualRoutine()
389: @*/
390: PetscErrorCode TaoSetResidualWeights(Tao tao, Vec sigma_v, PetscInt n, PetscInt *rows, PetscInt *cols, PetscReal *vals)
391: {
392: PetscInt i;
396: PetscObjectReference((PetscObject)sigma_v);
397: VecDestroy(&tao->res_weights_v);
398: tao->res_weights_v = sigma_v;
399: if (vals) {
400: PetscFree(tao->res_weights_rows);
401: PetscFree(tao->res_weights_cols);
402: PetscFree(tao->res_weights_w);
403: PetscMalloc1(n,&tao->res_weights_rows);
404: PetscMalloc1(n,&tao->res_weights_cols);
405: PetscMalloc1(n,&tao->res_weights_w);
406: tao->res_weights_n = n;
407: for (i=0;i<n;i++) {
408: tao->res_weights_rows[i] = rows[i];
409: tao->res_weights_cols[i] = cols[i];
410: tao->res_weights_w[i] = vals[i];
411: }
412: } else {
413: tao->res_weights_n = 0;
414: tao->res_weights_rows = NULL;
415: tao->res_weights_cols = NULL;
416: }
417: return 0;
418: }
420: /*@
421: TaoComputeResidual - Computes a least-squares residual vector at a given point
423: Collective on Tao
425: Input Parameters:
426: + tao - the Tao context
427: - X - input vector
429: Output Parameter:
430: . f - Objective vector at X
432: Notes:
433: TaoComputeResidual() is typically used within minimization implementations,
434: so most users would not generally call this routine themselves.
436: Level: advanced
438: .seealso: TaoSetResidualRoutine()
439: @*/
440: PetscErrorCode TaoComputeResidual(Tao tao, Vec X, Vec F)
441: {
447: if (tao->ops->computeresidual) {
448: PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
449: PetscStackPush("Tao user least-squares residual evaluation routine");
450: (*tao->ops->computeresidual)(tao,X,F,tao->user_lsresP);
451: PetscStackPop;
452: PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
453: tao->nfuncs++;
454: } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetResidualRoutine() has not been called");
455: PetscInfo(tao,"TAO least-squares residual evaluation.\n");
456: return 0;
457: }
459: /*@C
460: TaoSetGradient - Sets the gradient evaluation routine for minimization
462: Logically collective on Tao
464: Input Parameters:
465: + tao - the Tao context
466: . g - [optional] the vector to internally hold the gradient computation
467: . func - the gradient function
468: - ctx - [optional] user-defined context for private data for the gradient evaluation
469: routine (may be NULL)
471: Calling sequence of func:
472: $ func (Tao tao, Vec x, Vec g, void *ctx);
474: + x - input vector
475: . g - gradient value (output)
476: - ctx - [optional] user-defined function context
478: Level: beginner
480: .seealso: TaoSetObjective(), TaoSetHessian(), TaoSetObjectiveAndGradient(), TaoGetGradient()
481: @*/
482: PetscErrorCode TaoSetGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
483: {
485: if (g) {
488: PetscObjectReference((PetscObject)g);
489: VecDestroy(&tao->gradient);
490: tao->gradient = g;
491: }
492: if (func) tao->ops->computegradient = func;
493: if (ctx) tao->user_gradP = ctx;
494: return 0;
495: }
497: /*@C
498: TaoGetGradient - Gets the gradient evaluation routine for minimization
500: Not collective
502: Input Parameter:
503: . tao - the Tao context
505: Output Parameters:
506: + g - the vector to internally hold the gradient computation
507: . func - the gradient function
508: - ctx - user-defined context for private data for the gradient evaluation routine
510: Calling sequence of func:
511: $ func (Tao tao, Vec x, Vec g, void *ctx);
513: + x - input vector
514: . g - gradient value (output)
515: - ctx - [optional] user-defined function context
517: Level: beginner
519: .seealso: TaoSetObjective(), TaoSetHessian(), TaoSetObjectiveAndGradient(), TaoSetGradient()
520: @*/
521: PetscErrorCode TaoGetGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao, Vec, Vec, void*),void **ctx)
522: {
524: if (g) *g = tao->gradient;
525: if (func) *func = tao->ops->computegradient;
526: if (ctx) *ctx = tao->user_gradP;
527: return 0;
528: }
530: /*@C
531: TaoSetObjectiveAndGradient - Sets a combined objective function and gradient evaluation routine for minimization
533: Logically collective on Tao
535: Input Parameters:
536: + tao - the Tao context
537: . g - [optional] the vector to internally hold the gradient computation
538: . func - the gradient function
539: - ctx - [optional] user-defined context for private data for the gradient evaluation
540: routine (may be NULL)
542: Calling sequence of func:
543: $ func (Tao tao, Vec x, PetscReal *f, Vec g, void *ctx);
545: + x - input vector
546: . f - objective value (output)
547: . g - gradient value (output)
548: - ctx - [optional] user-defined function context
550: Level: beginner
552: .seealso: TaoSetObjective(), TaoSetHessian(), TaoSetGradient(), TaoGetObjectiveAndGradient()
553: @*/
554: PetscErrorCode TaoSetObjectiveAndGradient(Tao tao, Vec g, PetscErrorCode (*func)(Tao, Vec, PetscReal*, Vec, void*), void *ctx)
555: {
557: if (g) {
560: PetscObjectReference((PetscObject)g);
561: VecDestroy(&tao->gradient);
562: tao->gradient = g;
563: }
564: if (ctx) tao->user_objgradP = ctx;
565: if (func) tao->ops->computeobjectiveandgradient = func;
566: return 0;
567: }
569: /*@C
570: TaoGetObjectiveAndGradient - Gets a combined objective function and gradient evaluation routine for minimization
572: Not collective
574: Input Parameter:
575: . tao - the Tao context
577: Output Parameters:
578: + g - the vector to internally hold the gradient computation
579: . func - the gradient function
580: - ctx - user-defined context for private data for the gradient evaluation routine
582: Calling sequence of func:
583: $ func (Tao tao, Vec x, PetscReal *f, Vec g, void *ctx);
585: + x - input vector
586: . f - objective value (output)
587: . g - gradient value (output)
588: - ctx - [optional] user-defined function context
590: Level: beginner
592: .seealso: TaoSetObjective(), TaoSetGradient(), TaoSetHessian(), TaoSetObjectiveAndGradient()
593: @*/
594: PetscErrorCode TaoGetObjectiveAndGradient(Tao tao, Vec *g, PetscErrorCode (**func)(Tao, Vec, PetscReal*, Vec, void*), void **ctx)
595: {
597: if (g) *g = tao->gradient;
598: if (func) *func = tao->ops->computeobjectiveandgradient;
599: if (ctx) *ctx = tao->user_objgradP;
600: return 0;
601: }
603: /*@
604: TaoIsObjectiveDefined - Checks to see if the user has
605: declared an objective-only routine. Useful for determining when
606: it is appropriate to call TaoComputeObjective() or
607: TaoComputeObjectiveAndGradient()
609: Not collective
611: Input Parameter:
612: . tao - the Tao context
614: Output Parameter:
615: . flg - PETSC_TRUE if function routine is set by user, PETSC_FALSE otherwise
617: Level: developer
619: .seealso: TaoSetObjective(), TaoIsGradientDefined(), TaoIsObjectiveAndGradientDefined()
620: @*/
621: PetscErrorCode TaoIsObjectiveDefined(Tao tao, PetscBool *flg)
622: {
624: if (tao->ops->computeobjective == NULL) *flg = PETSC_FALSE;
625: else *flg = PETSC_TRUE;
626: return 0;
627: }
629: /*@
630: TaoIsGradientDefined - Checks to see if the user has
631: declared an objective-only routine. Useful for determining when
632: it is appropriate to call TaoComputeGradient() or
633: TaoComputeGradientAndGradient()
635: Not Collective
637: Input Parameter:
638: . tao - the Tao context
640: Output Parameter:
641: . flg - PETSC_TRUE if function routine is set by user, PETSC_FALSE otherwise
643: Level: developer
645: .seealso: TaoSetGradient(), TaoIsObjectiveDefined(), TaoIsObjectiveAndGradientDefined()
646: @*/
647: PetscErrorCode TaoIsGradientDefined(Tao tao, PetscBool *flg)
648: {
650: if (tao->ops->computegradient == NULL) *flg = PETSC_FALSE;
651: else *flg = PETSC_TRUE;
652: return 0;
653: }
655: /*@
656: TaoIsObjectiveAndGradientDefined - Checks to see if the user has
657: declared a joint objective/gradient routine. Useful for determining when
658: it is appropriate to call TaoComputeObjective() or
659: TaoComputeObjectiveAndGradient()
661: Not Collective
663: Input Parameter:
664: . tao - the Tao context
666: Output Parameter:
667: . flg - PETSC_TRUE if function routine is set by user, PETSC_FALSE otherwise
669: Level: developer
671: .seealso: TaoSetObjectiveAndGradient(), TaoIsObjectiveDefined(), TaoIsGradientDefined()
672: @*/
673: PetscErrorCode TaoIsObjectiveAndGradientDefined(Tao tao, PetscBool *flg)
674: {
676: if (tao->ops->computeobjectiveandgradient == NULL) *flg = PETSC_FALSE;
677: else *flg = PETSC_TRUE;
678: return 0;
679: }