xref: /petsc/src/tao/interface/taosolver_fg.c (revision 1657496c99a8e495416e018d8d3a46dbf89e7c0b)
1 #include <petsc/private/taoimpl.h> /*I "petsctao.h" I*/
2 
3 /*@
4   TaoSetInitialVector - Sets the initial guess for the solve
5 
6   Logically collective on Tao
7 
8   Input Parameters:
9 + tao - the Tao context
10 - x0  - the initial guess
11 
12   Level: beginner
13 .seealso: TaoCreate(), TaoSolve()
14 @*/
15 
16 PetscErrorCode TaoSetInitialVector(Tao tao, Vec x0)
17 {
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
22   if (x0) {
23     PetscValidHeaderSpecific(x0,VEC_CLASSID,2);
24     PetscObjectReference((PetscObject)x0);
25   }
26   ierr = VecDestroy(&tao->solution);CHKERRQ(ierr);
27   tao->solution = x0;
28   PetscFunctionReturn(0);
29 }
30 
31 PetscErrorCode TaoTestGradient(Tao tao,Vec g1)
32 {
33   Vec             x = tao->solution,g2,g3;
34   PetscBool       complete_print = PETSC_FALSE,test = PETSC_FALSE;
35   PetscReal       hcnorm,fdnorm,hcmax,fdmax,diffmax,diffnorm;
36   PetscScalar     dot;
37   MPI_Comm        comm;
38   PetscViewer     viewer;
39   PetscInt        tabs;
40   static PetscBool directionsprinted = PETSC_FALSE;
41   PetscErrorCode ierr;
42 
43   PetscFunctionBegin;
44   ierr = PetscObjectOptionsBegin((PetscObject)tao);CHKERRQ(ierr);
45   ierr = PetscOptionsName("-tao_test_gradient","Compare hand-coded and finite difference Gradients","None",&test);CHKERRQ(ierr);
46   ierr = PetscOptionsBool("-tao_test_gradient_view","View difference between hand-coded and finite difference Gradients element entries","None",complete_print,&complete_print,NULL);CHKERRQ(ierr);
47   ierr = PetscOptionsEnd();CHKERRQ(ierr);
48   if (!test) PetscFunctionReturn(0);
49 
50   ierr = PetscObjectGetComm((PetscObject)tao,&comm);CHKERRQ(ierr);
51   ierr = PetscViewerASCIIGetStdout(comm,&viewer);CHKERRQ(ierr);
52   ierr = PetscViewerASCIIGetTab(viewer, &tabs);CHKERRQ(ierr);
53   ierr = PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel);CHKERRQ(ierr);
54   ierr = PetscViewerASCIIPrintf(viewer,"  ---------- Testing Gradient -------------\n");CHKERRQ(ierr);
55   if (!complete_print && !directionsprinted) {
56     ierr = PetscViewerASCIIPrintf(viewer,"  Run with -tao_test_gradient_view and optionally -tao_test_gradient <threshold> to show difference\n");CHKERRQ(ierr);
57     ierr = PetscViewerASCIIPrintf(viewer,"    of hand-coded and finite difference gradient entries greater than <threshold>.\n");CHKERRQ(ierr);
58   }
59   if (!directionsprinted) {
60     ierr = PetscViewerASCIIPrintf(viewer,"  Testing hand-coded Gradient, if (for double precision runs) ||G - Gfd||_F/||G||_F is\n");CHKERRQ(ierr);
61     ierr = PetscViewerASCIIPrintf(viewer,"    O(1.e-8), the hand-coded Hessian is probably correct.\n");CHKERRQ(ierr);
62     directionsprinted = PETSC_TRUE;
63   }
64 
65   ierr = VecDuplicate(x,&g2);CHKERRQ(ierr);
66   ierr = VecDuplicate(x,&g3);CHKERRQ(ierr);
67 
68   /* Compute finite difference gradient, assume the gradient is already computed by TaoComputeGradient() and put into g1 */
69   ierr = TaoDefaultComputeGradient(tao,x,g2,NULL);CHKERRQ(ierr);
70 
71   ierr = VecNorm(g2,NORM_2,&fdnorm);CHKERRQ(ierr);
72   ierr = VecNorm(g1,NORM_2,&hcnorm);CHKERRQ(ierr);
73   ierr = VecNorm(g2,NORM_INFINITY,&fdmax);CHKERRQ(ierr);
74   ierr = VecNorm(g1,NORM_INFINITY,&hcmax);CHKERRQ(ierr);
75   ierr = VecDot(g1,g2,&dot);CHKERRQ(ierr);
76   ierr = VecCopy(g1,g3);CHKERRQ(ierr);
77   ierr = VecAXPY(g3,-1.0,g2);CHKERRQ(ierr);
78   ierr = VecNorm(g3,NORM_2,&diffnorm);CHKERRQ(ierr);
79   ierr = VecNorm(g3,NORM_INFINITY,&diffmax);CHKERRQ(ierr);
80   ierr = PetscViewerASCIIPrintf(viewer,"  ||Gfd|| %g, ||G|| = %g, angle cosine = (Gfd'G)/||Gfd||||G|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot)/(fdnorm*hcnorm)));CHKERRQ(ierr);
81   ierr = PetscViewerASCIIPrintf(viewer,"  2-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffnorm/PetscMax(hcnorm,fdnorm)),(double)diffnorm);CHKERRQ(ierr);
82   ierr = PetscViewerASCIIPrintf(viewer,"  max-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffmax/PetscMax(hcmax,fdmax)),(double)diffmax);CHKERRQ(ierr);
83 
84   if (complete_print) {
85     ierr = PetscViewerASCIIPrintf(viewer,"  Hand-coded gradient ----------\n");CHKERRQ(ierr);
86     ierr = VecView(g1,viewer);CHKERRQ(ierr);
87     ierr = PetscViewerASCIIPrintf(viewer,"  Finite difference gradient ----------\n");CHKERRQ(ierr);
88     ierr = VecView(g2,viewer);CHKERRQ(ierr);
89     ierr = PetscViewerASCIIPrintf(viewer,"  Hand-coded minus finite-difference gradient ----------\n");CHKERRQ(ierr);
90     ierr = VecView(g3,viewer);CHKERRQ(ierr);
91   }
92   ierr = VecDestroy(&g2);CHKERRQ(ierr);
93   ierr = VecDestroy(&g3);CHKERRQ(ierr);
94   PetscFunctionReturn(0);
95 }
96 
97 /*@
98   TaoComputeGradient - Computes the gradient of the objective function
99 
100   Collective on Tao
101 
102   Input Parameters:
103 + tao - the Tao context
104 - X - input vector
105 
106   Output Parameter:
107 . G - gradient vector
108 
109   Options Database Keys:
110 +    -tao_test_gradient - compare the user provided gradient with one compute via finite differences to check for errors
111 -    -tao_test_gradient_display - 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
112 
113   Notes:
114     TaoComputeGradient() is typically used within minimization implementations,
115   so most users would not generally call this routine themselves.
116 
117   Level: advanced
118 
119 .seealso: TaoComputeObjective(), TaoComputeObjectiveAndGradient(), TaoSetGradientRoutine()
120 @*/
121 PetscErrorCode TaoComputeGradient(Tao tao, Vec X, Vec G)
122 {
123   PetscErrorCode ierr;
124   PetscReal      dummy;
125 
126   PetscFunctionBegin;
127   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
128   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
129   PetscValidHeaderSpecific(G,VEC_CLASSID,2);
130   PetscCheckSameComm(tao,1,X,2);
131   PetscCheckSameComm(tao,1,G,3);
132   ierr = VecLockPush(X);CHKERRQ(ierr);
133   if (tao->ops->computegradient) {
134     ierr = PetscLogEventBegin(Tao_GradientEval,tao,X,G,NULL);CHKERRQ(ierr);
135     PetscStackPush("Tao user gradient evaluation routine");
136     ierr = (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);CHKERRQ(ierr);
137     PetscStackPop;
138     ierr = PetscLogEventEnd(Tao_GradientEval,tao,X,G,NULL);CHKERRQ(ierr);
139     tao->ngrads++;
140   } else if (tao->ops->computeobjectiveandgradient) {
141     ierr = PetscLogEventBegin(Tao_ObjGradientEval,tao,X,G,NULL);CHKERRQ(ierr);
142     PetscStackPush("Tao user objective/gradient evaluation routine");
143     ierr = (*tao->ops->computeobjectiveandgradient)(tao,X,&dummy,G,tao->user_objgradP);CHKERRQ(ierr);
144     PetscStackPop;
145     ierr = PetscLogEventEnd(Tao_ObjGradientEval,tao,X,G,NULL);CHKERRQ(ierr);
146     tao->nfuncgrads++;
147   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"TaoSetGradientRoutine() has not been called");
148   ierr = VecLockPop(X);CHKERRQ(ierr);
149 
150   ierr = TaoTestGradient(tao,G);CHKERRQ(ierr);
151   PetscFunctionReturn(0);
152 }
153 
154 /*@
155   TaoComputeObjective - Computes the objective function value at a given point
156 
157   Collective on Tao
158 
159   Input Parameters:
160 + tao - the Tao context
161 - X - input vector
162 
163   Output Parameter:
164 . f - Objective value at X
165 
166   Notes:
167     TaoComputeObjective() is typically used within minimization implementations,
168   so most users would not generally call this routine themselves.
169 
170   Level: advanced
171 
172 .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjectiveRoutine()
173 @*/
174 PetscErrorCode TaoComputeObjective(Tao tao, Vec X, PetscReal *f)
175 {
176   PetscErrorCode ierr;
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   ierr = VecLockPush(X);CHKERRQ(ierr);
184   if (tao->ops->computeobjective) {
185     ierr = PetscLogEventBegin(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
186     PetscStackPush("Tao user objective evaluation routine");
187     ierr = (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);CHKERRQ(ierr);
188     PetscStackPop;
189     ierr = PetscLogEventEnd(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
190     tao->nfuncs++;
191   } else if (tao->ops->computeobjectiveandgradient) {
192     ierr = PetscInfo(tao,"Duplicating variable vector in order to call func/grad routine\n");CHKERRQ(ierr);
193     ierr = VecDuplicate(X,&temp);CHKERRQ(ierr);
194     ierr = PetscLogEventBegin(Tao_ObjGradientEval,tao,X,NULL,NULL);CHKERRQ(ierr);
195     PetscStackPush("Tao user objective/gradient evaluation routine");
196     ierr = (*tao->ops->computeobjectiveandgradient)(tao,X,f,temp,tao->user_objgradP);CHKERRQ(ierr);
197     PetscStackPop;
198     ierr = PetscLogEventEnd(Tao_ObjGradientEval,tao,X,NULL,NULL);CHKERRQ(ierr);
199     ierr = VecDestroy(&temp);CHKERRQ(ierr);
200     tao->nfuncgrads++;
201   }  else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjectiveRoutine() has not been called");
202   ierr = PetscInfo1(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));CHKERRQ(ierr);
203   ierr = VecLockPop(X);CHKERRQ(ierr);
204   PetscFunctionReturn(0);
205 }
206 
207 /*@
208   TaoComputeObjectiveAndGradient - Computes the objective function value at a given point
209 
210   Collective on Tao
211 
212   Input Parameters:
213 + tao - the Tao context
214 - X - input vector
215 
216   Output Parameter:
217 + f - Objective value at X
218 - g - Gradient vector at X
219 
220   Notes:
221     TaoComputeObjectiveAndGradient() is typically used within minimization implementations,
222   so most users would not generally call this routine themselves.
223 
224   Level: advanced
225 
226 .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjectiveRoutine()
227 @*/
228 PetscErrorCode TaoComputeObjectiveAndGradient(Tao tao, Vec X, PetscReal *f, Vec G)
229 {
230   PetscErrorCode ierr;
231 
232   PetscFunctionBegin;
233   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
234   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
235   PetscValidHeaderSpecific(G,VEC_CLASSID,4);
236   PetscCheckSameComm(tao,1,X,2);
237   PetscCheckSameComm(tao,1,G,4);
238   ierr = VecLockPush(X);CHKERRQ(ierr);
239   if (tao->ops->computeobjectiveandgradient) {
240     ierr = PetscLogEventBegin(Tao_ObjGradientEval,tao,X,G,NULL);CHKERRQ(ierr);
241     if (tao->ops->computegradient == TaoDefaultComputeGradient) {
242       ierr = TaoComputeObjective(tao,X,f);CHKERRQ(ierr);
243       ierr = TaoDefaultComputeGradient(tao,X,G,NULL);CHKERRQ(ierr);
244     } else {
245       PetscStackPush("Tao user objective/gradient evaluation routine");
246       ierr = (*tao->ops->computeobjectiveandgradient)(tao,X,f,G,tao->user_objgradP);CHKERRQ(ierr);
247       PetscStackPop;
248     }
249     ierr = PetscLogEventEnd(Tao_ObjGradientEval,tao,X,G,NULL);CHKERRQ(ierr);
250     tao->nfuncgrads++;
251   } else if (tao->ops->computeobjective && tao->ops->computegradient) {
252     ierr = PetscLogEventBegin(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
253     PetscStackPush("Tao user objective evaluation routine");
254     ierr = (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);CHKERRQ(ierr);
255     PetscStackPop;
256     ierr = PetscLogEventEnd(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
257     tao->nfuncs++;
258     ierr = PetscLogEventBegin(Tao_GradientEval,tao,X,G,NULL);CHKERRQ(ierr);
259     PetscStackPush("Tao user gradient evaluation routine");
260     ierr = (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);CHKERRQ(ierr);
261     PetscStackPop;
262     ierr = PetscLogEventEnd(Tao_GradientEval,tao,X,G,NULL);CHKERRQ(ierr);
263     tao->ngrads++;
264   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjectiveRoutine() or TaoSetGradientRoutine() not set");
265   ierr = PetscInfo1(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));CHKERRQ(ierr);
266   ierr = VecLockPop(X);CHKERRQ(ierr);
267 
268   ierr = TaoTestGradient(tao,G);CHKERRQ(ierr);
269   PetscFunctionReturn(0);
270 }
271 
272 /*@C
273   TaoSetObjectiveRoutine - Sets the function evaluation routine for minimization
274 
275   Logically collective on Tao
276 
277   Input Parameter:
278 + tao - the Tao context
279 . func - the objective function
280 - ctx - [optional] user-defined context for private data for the function evaluation
281         routine (may be NULL)
282 
283   Calling sequence of func:
284 $      func (Tao tao, Vec x, PetscReal *f, void *ctx);
285 
286 + x - input vector
287 . f - function value
288 - ctx - [optional] user-defined function context
289 
290   Level: beginner
291 
292 .seealso: TaoSetGradientRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
293 @*/
294 PetscErrorCode TaoSetObjectiveRoutine(Tao tao, PetscErrorCode (*func)(Tao, Vec, PetscReal*,void*),void *ctx)
295 {
296   PetscFunctionBegin;
297   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
298   tao->user_objP = ctx;
299   tao->ops->computeobjective = func;
300   PetscFunctionReturn(0);
301 }
302 
303 /*@C
304   TaoSetSeparableObjectiveRoutine - Sets the function evaluation routine for least-square applications
305 
306   Logically collective on Tao
307 
308   Input Parameter:
309 + tao - the Tao context
310 . func - the objective function evaluation routine
311 - ctx - [optional] user-defined context for private data for the function evaluation
312         routine (may be NULL)
313 
314   Calling sequence of func:
315 $      func (Tao tao, Vec x, Vec f, void *ctx);
316 
317 + x - input vector
318 . f - function value vector
319 - ctx - [optional] user-defined function context
320 
321   Level: beginner
322 
323 .seealso: TaoSetObjectiveRoutine(), TaoSetJacobianRoutine()
324 @*/
325 PetscErrorCode TaoSetSeparableObjectiveRoutine(Tao tao, Vec sepobj, PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
326 {
327   PetscFunctionBegin;
328   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
329   PetscValidHeaderSpecific(sepobj, VEC_CLASSID,2);
330   tao->user_sepobjP = ctx;
331   tao->sep_objective = sepobj;
332   tao->ops->computeseparableobjective = func;
333   PetscFunctionReturn(0);
334 }
335 
336 /*@
337   TaoSetSeparableObjectiveWeights - Give weights for the separable objective 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.
338 
339   Collective on Tao
340 
341   Input Parameters:
342 + tao - the Tao context
343 . sigma_v - vector of weights (diagonal terms only)
344 . n       - the number of weights (if using off-diagonal)
345 . rows    - index list of rows for sigma_w
346 . cols    - index list of columns for sigma_w
347 - vals - array of weights
348 
349 
350 
351   Note: Either sigma_v or sigma_w (or both) should be NULL
352 
353   Level: intermediate
354 
355 .seealso: TaoSetSeparableObjectiveRoutine()
356 @*/
357 PetscErrorCode TaoSetSeparableObjectiveWeights(Tao tao, Vec sigma_v, PetscInt n, PetscInt *rows, PetscInt *cols, PetscReal *vals)
358 {
359   PetscErrorCode ierr;
360   PetscInt       i;
361   PetscFunctionBegin;
362   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
363   ierr = VecDestroy(&tao->sep_weights_v);CHKERRQ(ierr);
364   tao->sep_weights_v=sigma_v;
365   if (sigma_v) {
366     ierr = PetscObjectReference((PetscObject)sigma_v);CHKERRQ(ierr);
367   }
368   if (vals) {
369     if (tao->sep_weights_n) {
370       ierr = PetscFree(tao->sep_weights_rows);CHKERRQ(ierr);
371       ierr = PetscFree(tao->sep_weights_cols);CHKERRQ(ierr);
372       ierr = PetscFree(tao->sep_weights_w);CHKERRQ(ierr);
373     }
374     ierr = PetscMalloc1(n,&tao->sep_weights_rows);CHKERRQ(ierr);
375     ierr = PetscMalloc1(n,&tao->sep_weights_cols);CHKERRQ(ierr);
376     ierr = PetscMalloc1(n,&tao->sep_weights_w);CHKERRQ(ierr);
377     tao->sep_weights_n=n;
378     for (i=0;i<n;i++) {
379       tao->sep_weights_rows[i]=rows[i];
380       tao->sep_weights_cols[i]=cols[i];
381       tao->sep_weights_w[i]=vals[i];
382     }
383   } else {
384     tao->sep_weights_n=0;
385     tao->sep_weights_rows=0;
386     tao->sep_weights_cols=0;
387   }
388   PetscFunctionReturn(0);
389 }
390 /*@
391   TaoComputeSeparableObjective - Computes a separable objective function vector at a given point (for least-square applications)
392 
393   Collective on Tao
394 
395   Input Parameters:
396 + tao - the Tao context
397 - X - input vector
398 
399   Output Parameter:
400 . f - Objective vector at X
401 
402   Notes:
403     TaoComputeSeparableObjective() is typically used within minimization implementations,
404   so most users would not generally call this routine themselves.
405 
406   Level: advanced
407 
408 .seealso: TaoSetSeparableObjectiveRoutine()
409 @*/
410 PetscErrorCode TaoComputeSeparableObjective(Tao tao, Vec X, Vec F)
411 {
412   PetscErrorCode ierr;
413 
414   PetscFunctionBegin;
415   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
416   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
417   PetscValidHeaderSpecific(F,VEC_CLASSID,3);
418   PetscCheckSameComm(tao,1,X,2);
419   PetscCheckSameComm(tao,1,F,3);
420   if (tao->ops->computeseparableobjective) {
421     ierr = PetscLogEventBegin(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
422     PetscStackPush("Tao user separable objective evaluation routine");
423     ierr = (*tao->ops->computeseparableobjective)(tao,X,F,tao->user_sepobjP);CHKERRQ(ierr);
424     PetscStackPop;
425     ierr = PetscLogEventEnd(Tao_ObjectiveEval,tao,X,NULL,NULL);CHKERRQ(ierr);
426     tao->nfuncs++;
427   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"TaoSetSeparableObjectiveRoutine() has not been called");
428   ierr = PetscInfo(tao,"TAO separable function evaluation.\n");CHKERRQ(ierr);
429   PetscFunctionReturn(0);
430 }
431 
432 /*@C
433   TaoSetGradientRoutine - Sets the gradient evaluation routine for minimization
434 
435   Logically collective on Tao
436 
437   Input Parameter:
438 + tao - the Tao context
439 . func - the gradient function
440 - ctx - [optional] user-defined context for private data for the gradient evaluation
441         routine (may be NULL)
442 
443   Calling sequence of func:
444 $      func (Tao tao, Vec x, Vec g, void *ctx);
445 
446 + x - input vector
447 . g - gradient value (output)
448 - ctx - [optional] user-defined function context
449 
450   Level: beginner
451 
452 .seealso: TaoSetObjectiveRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
453 @*/
454 PetscErrorCode TaoSetGradientRoutine(Tao tao,  PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
455 {
456   PetscFunctionBegin;
457   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
458   tao->user_gradP = ctx;
459   tao->ops->computegradient = func;
460   PetscFunctionReturn(0);
461 }
462 
463 /*@C
464   TaoSetObjectiveAndGradientRoutine - Sets a combined objective function and gradient evaluation routine for minimization
465 
466   Logically collective on Tao
467 
468   Input Parameter:
469 + tao - the Tao context
470 . func - the gradient function
471 - ctx - [optional] user-defined context for private data for the gradient evaluation
472         routine (may be NULL)
473 
474   Calling sequence of func:
475 $      func (Tao tao, Vec x, PetscReal *f, Vec g, void *ctx);
476 
477 + x - input vector
478 . f - objective value (output)
479 . g - gradient value (output)
480 - ctx - [optional] user-defined function context
481 
482   Level: beginner
483 
484 .seealso: TaoSetObjectiveRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
485 @*/
486 PetscErrorCode TaoSetObjectiveAndGradientRoutine(Tao tao, PetscErrorCode (*func)(Tao, Vec, PetscReal *, Vec, void*), void *ctx)
487 {
488   PetscFunctionBegin;
489   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
490   tao->user_objgradP = ctx;
491   tao->ops->computeobjectiveandgradient = func;
492   PetscFunctionReturn(0);
493 }
494 
495 /*@
496   TaoIsObjectiveDefined -- Checks to see if the user has
497   declared an objective-only routine.  Useful for determining when
498   it is appropriate to call TaoComputeObjective() or
499   TaoComputeObjectiveAndGradient()
500 
501   Collective on Tao
502 
503   Input Parameter:
504 + tao - the Tao context
505 - ctx - PETSC_TRUE if objective function routine is set by user,
506         PETSC_FALSE otherwise
507   Level: developer
508 
509 .seealso: TaoSetObjectiveRoutine(), TaoIsGradientDefined(), TaoIsObjectiveAndGradientDefined()
510 @*/
511 PetscErrorCode TaoIsObjectiveDefined(Tao tao, PetscBool *flg)
512 {
513   PetscFunctionBegin;
514   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
515   if (tao->ops->computeobjective == 0) *flg = PETSC_FALSE;
516   else *flg = PETSC_TRUE;
517   PetscFunctionReturn(0);
518 }
519 
520 /*@
521   TaoIsGradientDefined -- Checks to see if the user has
522   declared an objective-only routine.  Useful for determining when
523   it is appropriate to call TaoComputeGradient() or
524   TaoComputeGradientAndGradient()
525 
526   Not Collective
527 
528   Input Parameter:
529 + tao - the Tao context
530 - ctx - PETSC_TRUE if gradient routine is set by user, PETSC_FALSE otherwise
531   Level: developer
532 
533 .seealso: TaoSetGradientRoutine(), TaoIsObjectiveDefined(), TaoIsObjectiveAndGradientDefined()
534 @*/
535 PetscErrorCode TaoIsGradientDefined(Tao tao, PetscBool *flg)
536 {
537   PetscFunctionBegin;
538   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
539   if (tao->ops->computegradient == 0) *flg = PETSC_FALSE;
540   else *flg = PETSC_TRUE;
541   PetscFunctionReturn(0);
542 }
543 
544 /*@
545   TaoIsObjectiveAndGradientDefined -- Checks to see if the user has
546   declared a joint objective/gradient routine.  Useful for determining when
547   it is appropriate to call TaoComputeObjective() or
548   TaoComputeObjectiveAndGradient()
549 
550   Not Collective
551 
552   Input Parameter:
553 + tao - the Tao context
554 - ctx - PETSC_TRUE if objective/gradient routine is set by user, PETSC_FALSE otherwise
555   Level: developer
556 
557 .seealso: TaoSetObjectiveAndGradientRoutine(), TaoIsObjectiveDefined(), TaoIsGradientDefined()
558 @*/
559 PetscErrorCode TaoIsObjectiveAndGradientDefined(Tao tao, PetscBool *flg)
560 {
561   PetscFunctionBegin;
562   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
563   if (tao->ops->computeobjectiveandgradient == 0) *flg = PETSC_FALSE;
564   else *flg = PETSC_TRUE;
565   PetscFunctionReturn(0);
566 }
567