Actual source code: taosolver.c

  1: #include <petsc/private/taoimpl.h>
  2: #include <petsc/private/snesimpl.h>
  3: #include <petsc/private/kspimpl.h>
  4: #include <petscdmshell.h>

  6: PetscBool         TaoRegisterAllCalled = PETSC_FALSE;
  7: PetscFunctionList TaoList              = NULL;

  9: PetscClassId TAO_CLASSID = 0;

 11: PetscLogEvent TAO_Solve;
 12: PetscLogEvent TAO_ResidualEval;
 13: PetscLogEvent TAO_JacobianEval;
 14: PetscLogEvent TAO_ConstraintsEval;

 16: const char *const TaoSubsetTypes[] = {"subvec", "mask", "matrixfree", "TaoSubsetType", "TAO_SUBSET_", NULL};

 18: struct _n_TaoMonitorDrawCtx {
 19:   PetscViewer viewer;
 20:   PetscInt    howoften; /* when > 0 uses iteration % howoften, when negative only final solution plotted */
 21: };

 23: static PetscErrorCode KSPPreSolve_TAOEW_Private(KSP ksp, Vec b, Vec x, PetscCtx ctx)
 24: {
 25:   Tao  tao          = (Tao)ctx;
 26:   SNES snes_ewdummy = tao->snes_ewdummy;

 28:   PetscFunctionBegin;
 29:   if (!snes_ewdummy) PetscFunctionReturn(PETSC_SUCCESS);
 30:   /* populate snes_ewdummy struct values used in KSPPreSolve_SNESEW */
 31:   snes_ewdummy->vec_func = b;
 32:   snes_ewdummy->rtol     = tao->gttol;
 33:   snes_ewdummy->iter     = tao->niter;
 34:   PetscCall(VecNorm(b, NORM_2, &snes_ewdummy->norm));
 35:   PetscCall(KSPPreSolve_SNESEW(ksp, b, x, snes_ewdummy));
 36:   snes_ewdummy->vec_func = NULL;
 37:   PetscFunctionReturn(PETSC_SUCCESS);
 38: }

 40: static PetscErrorCode KSPPostSolve_TAOEW_Private(KSP ksp, Vec b, Vec x, PetscCtx ctx)
 41: {
 42:   Tao  tao          = (Tao)ctx;
 43:   SNES snes_ewdummy = tao->snes_ewdummy;

 45:   PetscFunctionBegin;
 46:   if (!snes_ewdummy) PetscFunctionReturn(PETSC_SUCCESS);
 47:   PetscCall(KSPPostSolve_SNESEW(ksp, b, x, snes_ewdummy));
 48:   PetscFunctionReturn(PETSC_SUCCESS);
 49: }

 51: static PetscErrorCode TaoSetUpEW_Private(Tao tao)
 52: {
 53:   SNESKSPEW  *kctx;
 54:   const char *ewprefix;

 56:   PetscFunctionBegin;
 57:   if (!tao->ksp) PetscFunctionReturn(PETSC_SUCCESS);
 58:   if (tao->ksp_ewconv) {
 59:     if (!tao->snes_ewdummy) PetscCall(SNESCreate(PetscObjectComm((PetscObject)tao), &tao->snes_ewdummy));
 60:     tao->snes_ewdummy->ksp_ewconv = PETSC_TRUE;

 62:     tao->ksp->presolve_ew  = KSPPreSolve_TAOEW_Private;
 63:     tao->ksp->prectx_ew    = tao;
 64:     tao->ksp->postsolve_ew = KSPPostSolve_TAOEW_Private;
 65:     tao->ksp->postctx_ew   = tao;

 67:     PetscCall(KSPGetOptionsPrefix(tao->ksp, &ewprefix));
 68:     kctx = (SNESKSPEW *)tao->snes_ewdummy->kspconvctx;
 69:     PetscCall(SNESEWSetFromOptions_Private(kctx, PETSC_FALSE, PetscObjectComm((PetscObject)tao), ewprefix));
 70:   } else PetscCall(SNESDestroy(&tao->snes_ewdummy));
 71:   PetscFunctionReturn(PETSC_SUCCESS);
 72: }

 74: /*@
 75:   TaoParametersInitialize - Sets the base defaults for parameters in `tao`, updating a parameter's current value when it matches its previously recorded default.

 77:   Logically collective

 79:   Input Parameter:
 80: . tao - the `Tao` object

 82:   Level: developer

 84:   Notes:

 86:   The base defaults are the non-type-specific values established when the `Tao` is created. A `TaoType` constructor may subsequently replace them with type-specific defaults.

 88:   Developer Notes:

 90:   `TaoCreate()` calls this routine to establish the base defaults. `TaoSetType()` calls it before constructing a new `TaoType`, so the recorded defaults associated with the previous type are replaced before the new type installs its own defaults.

 92:   Default tracking is based on value equality, not on whether a setter was called. Consequently, an explicitly assigned value that equals the recorded default may be updated when the type changes.

 94: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoDestroy()`, `PetscObjectParameterSetDefault()`
 95: @*/
 96: PetscErrorCode TaoParametersInitialize(Tao tao)
 97: {
 98:   PetscObjectParameterSetDefault(tao, max_it, 10000);
 99:   PetscObjectParameterSetDefault(tao, max_funcs, PETSC_UNLIMITED);
100:   PetscObjectParameterSetDefault(tao, gatol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
101:   PetscObjectParameterSetDefault(tao, grtol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
102:   PetscObjectParameterSetDefault(tao, crtol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
103:   PetscObjectParameterSetDefault(tao, catol, PetscDefined(USE_REAL_SINGLE) ? 1e-5 : 1e-8);
104:   PetscObjectParameterSetDefault(tao, gttol, 0.0);
105:   PetscObjectParameterSetDefault(tao, steptol, 0.0);
106:   PetscObjectParameterSetDefault(tao, fmin, PETSC_NINFINITY);
107:   PetscObjectParameterSetDefault(tao, trust0, PETSC_INFINITY);
108:   return PETSC_SUCCESS;
109: }

111: /*@
112:   TaoCreate - Creates a Tao solver

114:   Collective

116:   Input Parameter:
117: . comm - MPI communicator

119:   Output Parameter:
120: . newtao - the new `Tao` context

122:   Options Database Key:
123: . -tao_type - select which method Tao should use

125:   Level: beginner

127: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoDestroy()`, `TaoSetFromOptions()`, `TaoSetType()`
128: @*/
129: PetscErrorCode TaoCreate(MPI_Comm comm, Tao *newtao)
130: {
131:   Tao tao;

133:   PetscFunctionBegin;
134:   PetscAssertPointer(newtao, 2);
135:   PetscCall(TaoInitializePackage());
136:   PetscCall(TaoLineSearchInitializePackage());

138:   PetscCall(PetscHeaderCreate(tao, TAO_CLASSID, "Tao", "Optimization solver", "Tao", comm, TaoDestroy, TaoView));
139:   PetscCall(TaoParametersInitialize(tao));
140:   tao->hist_reset = PETSC_TRUE;

142:   tao->ops->convergencetest = TaoDefaultConvergenceTest;

144:   PetscCall(TaoTermCreateCallbacks(tao, &tao->callbacks));
145:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
146:   PetscCall(TaoTermMappingSetData(&tao->objective_term, NULL, 1.0, tao->callbacks, NULL));
147:   PetscCall(TaoResetStatistics(tao));
148:   *newtao = tao;
149:   PetscFunctionReturn(PETSC_SUCCESS);
150: }

152: /*@
153:   TaoSolve - Solves an optimization problem min F(x) s.t. l <= x <= u

155:   Collective

157:   Input Parameter:
158: . tao - the `Tao` context

160:   Level: beginner

162:   Notes:
163:   The user must set up the `Tao` object  with calls to `TaoSetSolution()`, `TaoSetObjective()`, `TaoSetGradient()`, and (if using 2nd order method) `TaoSetHessian()`.

165:   You should call `TaoGetConvergedReason()` or run with `-tao_converged_reason` to determine if the optimization algorithm actually succeeded or
166:   why it failed.

168: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSetObjective()`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoGetConvergedReason()`, `TaoSetUp()`
169:  @*/
170: PetscErrorCode TaoSolve(Tao tao)
171: {
172:   static PetscBool set = PETSC_FALSE;

174:   PetscFunctionBegin;
176:   PetscCall(PetscCitationsRegister("@TechReport{tao-user-ref,\n"
177:                                    "title   = {Toolkit for Advanced Optimization (TAO) Users Manual},\n"
178:                                    "author  = {Todd Munson and Jason Sarich and Stefan Wild and Steve Benson and Lois Curfman McInnes},\n"
179:                                    "Institution = {Argonne National Laboratory},\n"
180:                                    "Year   = 2014,\n"
181:                                    "Number = {ANL/MCS-TM-322 - Revision 3.5},\n"
182:                                    "url    = {https://www.mcs.anl.gov/research/projects/tao/}\n}\n",
183:                                    &set));
184:   tao->header_printed = PETSC_FALSE;
185:   PetscCall(TaoSetUp(tao));
186:   PetscCall(TaoResetStatistics(tao));
187:   if (tao->linesearch) PetscCall(TaoLineSearchReset(tao->linesearch));

189:   PetscCall(PetscLogEventBegin(TAO_Solve, tao, 0, 0, 0));
190:   PetscTryTypeMethod(tao, solve);
191:   PetscCall(PetscLogEventEnd(TAO_Solve, tao, 0, 0, 0));

193:   PetscCall(VecViewFromOptions(tao->solution, (PetscObject)tao, "-tao_view_solution"));

195:   tao->ntotalits += tao->niter;

197:   if (tao->printreason) {
198:     PetscViewer viewer = PETSC_VIEWER_STDOUT_(((PetscObject)tao)->comm);

200:     PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)tao)->tablevel));
201:     if (tao->reason > 0) {
202:       if (((PetscObject)tao)->prefix) {
203:         PetscCall(PetscViewerASCIIPrintf(viewer, "TAO %s solve converged due to %s iterations %" PetscInt_FMT "\n", ((PetscObject)tao)->prefix, TaoConvergedReasons[tao->reason], tao->niter));
204:       } else {
205:         PetscCall(PetscViewerASCIIPrintf(viewer, "TAO solve converged due to %s iterations %" PetscInt_FMT "\n", TaoConvergedReasons[tao->reason], tao->niter));
206:       }
207:     } else {
208:       if (((PetscObject)tao)->prefix) {
209:         PetscCall(PetscViewerASCIIPrintf(viewer, "TAO %s solve did not converge due to %s iteration %" PetscInt_FMT "\n", ((PetscObject)tao)->prefix, TaoConvergedReasons[tao->reason], tao->niter));
210:       } else {
211:         PetscCall(PetscViewerASCIIPrintf(viewer, "TAO solve did not converge due to %s iteration %" PetscInt_FMT "\n", TaoConvergedReasons[tao->reason], tao->niter));
212:       }
213:     }
214:     PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)tao)->tablevel));
215:   }
216:   PetscCall(TaoViewFromOptions(tao, NULL, "-tao_view"));
217:   PetscFunctionReturn(PETSC_SUCCESS);
218: }

220: /*@
221:   TaoSetUp - Sets up the internal data structures for the later use
222:   of a Tao solver

224:   Collective

226:   Input Parameter:
227: . tao - the `Tao` context

229:   Level: advanced

231:   Note:
232:   The user will not need to explicitly call `TaoSetUp()`, as it will
233:   automatically be called in `TaoSolve()`.  However, if the user
234:   desires to call it explicitly, it should come after `TaoCreate()`
235:   and any TaoSetSomething() routines, but before `TaoSolve()`.

237: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
238: @*/
239: PetscErrorCode TaoSetUp(Tao tao)
240: {
241:   PetscFunctionBegin;
243:   if (tao->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
244:   PetscCall(TaoSetUpEW_Private(tao));
245:   PetscCall(TaoTermMappingSetUp(&tao->objective_term));
246:   if (!tao->solution) PetscCall(TaoTermMappingCreateSolutionVec(&tao->objective_term, &tao->solution));
247:   PetscCheck(tao->solution, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Must call TaoSetSolution()");
248:   if (tao->uses_gradient && !tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
249:   if (tao->uses_hessian_matrices) {
250:     // TaoSetHessian has been called, but as terms have been added,
251:     // subterms' Hessian and PtAP routines, if needed, have to be created
252:     // TODO Function to set TAOTERMSUM's Hessian.
253:     if (!tao->hessian) {
254:       PetscBool is_defined;

256:       // TAOTERMSUM's Hessian will follow layout and type of first term's Hessian
257:       PetscCall(TaoTermIsCreateHessianMatricesDefined(tao->objective_term.term, &is_defined));
258:       if (is_defined) PetscCall(TaoTermMappingCreateHessianMatrices(&tao->objective_term, &tao->hessian, &tao->hessian_pre));
259:     }
260:     PetscCheck(tao->hessian, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Must call TaoSetHessian()");
261:   }
262:   PetscTryTypeMethod(tao, setup);
263:   tao->setupcalled = PETSC_TRUE;
264:   PetscFunctionReturn(PETSC_SUCCESS);
265: }

267: /*@
268:   TaoDestroy - Destroys the `Tao` context that was created with `TaoCreate()`

270:   Collective

272:   Input Parameter:
273: . tao - the `Tao` context

275:   Level: beginner

277: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
278: @*/
279: PetscErrorCode TaoDestroy(Tao *tao)
280: {
281:   PetscFunctionBegin;
282:   if (!*tao) PetscFunctionReturn(PETSC_SUCCESS);
284:   if (--((PetscObject)*tao)->refct > 0) {
285:     *tao = NULL;
286:     PetscFunctionReturn(PETSC_SUCCESS);
287:   }

289:   PetscTryTypeMethod(*tao, destroy);
290:   PetscCall(TaoTermMappingReset(&(*tao)->objective_term));
291:   PetscCall(VecDestroy(&(*tao)->objective_parameters));
292:   PetscCall(TaoTermDestroy(&(*tao)->callbacks));
293:   PetscCall(DMDestroy(&(*tao)->dm));
294:   PetscCall(KSPDestroy(&(*tao)->ksp));
295:   PetscCall(SNESDestroy(&(*tao)->snes_ewdummy));
296:   PetscCall(TaoLineSearchDestroy(&(*tao)->linesearch));

298:   if ((*tao)->ops->convergencedestroy) {
299:     PetscCall((*(*tao)->ops->convergencedestroy)((*tao)->cnvP));
300:     PetscCall(MatDestroy(&(*tao)->jacobian_state_inv));
301:   }
302:   PetscCall(VecDestroy(&(*tao)->solution));
303:   PetscCall(VecDestroy(&(*tao)->gradient));
304:   PetscCall(VecDestroy(&(*tao)->ls_res));

306:   if ((*tao)->gradient_norm) {
307:     PetscCall(PetscObjectDereference((PetscObject)(*tao)->gradient_norm));
308:     PetscCall(VecDestroy(&(*tao)->gradient_norm_tmp));
309:   }

311:   PetscCall(VecDestroy(&(*tao)->XL));
312:   PetscCall(VecDestroy(&(*tao)->XU));
313:   PetscCall(VecDestroy(&(*tao)->IL));
314:   PetscCall(VecDestroy(&(*tao)->IU));
315:   PetscCall(VecDestroy(&(*tao)->DE));
316:   PetscCall(VecDestroy(&(*tao)->DI));
317:   PetscCall(VecDestroy(&(*tao)->constraints));
318:   PetscCall(VecDestroy(&(*tao)->constraints_equality));
319:   PetscCall(VecDestroy(&(*tao)->constraints_inequality));
320:   PetscCall(VecDestroy(&(*tao)->stepdirection));
321:   PetscCall(MatDestroy(&(*tao)->hessian_pre));
322:   PetscCall(MatDestroy(&(*tao)->hessian));
323:   PetscCall(MatDestroy(&(*tao)->ls_jac));
324:   PetscCall(MatDestroy(&(*tao)->ls_jac_pre));
325:   PetscCall(MatDestroy(&(*tao)->jacobian_pre));
326:   PetscCall(MatDestroy(&(*tao)->jacobian));
327:   PetscCall(MatDestroy(&(*tao)->jacobian_state_pre));
328:   PetscCall(MatDestroy(&(*tao)->jacobian_state));
329:   PetscCall(MatDestroy(&(*tao)->jacobian_state_inv));
330:   PetscCall(MatDestroy(&(*tao)->jacobian_design));
331:   PetscCall(MatDestroy(&(*tao)->jacobian_equality));
332:   PetscCall(MatDestroy(&(*tao)->jacobian_equality_pre));
333:   PetscCall(MatDestroy(&(*tao)->jacobian_inequality));
334:   PetscCall(MatDestroy(&(*tao)->jacobian_inequality_pre));
335:   PetscCall(ISDestroy(&(*tao)->state_is));
336:   PetscCall(ISDestroy(&(*tao)->design_is));
337:   PetscCall(VecDestroy(&(*tao)->res_weights_v));
338:   PetscCall(TaoMonitorCancel(*tao));
339:   if ((*tao)->hist_malloc) PetscCall(PetscFree4((*tao)->hist_obj, (*tao)->hist_resid, (*tao)->hist_cnorm, (*tao)->hist_lits));
340:   if ((*tao)->res_weights_n) {
341:     PetscCall(PetscFree((*tao)->res_weights_rows));
342:     PetscCall(PetscFree((*tao)->res_weights_cols));
343:     PetscCall(PetscFree((*tao)->res_weights_w));
344:   }
345:   PetscCall(PetscHeaderDestroy(tao));
346:   PetscFunctionReturn(PETSC_SUCCESS);
347: }

349: /*@
350:   TaoKSPSetUseEW - Sets `SNES` to use Eisenstat-Walker method {cite}`ew96` for computing relative tolerance for linear solvers.

352:   Logically Collective

354:   Input Parameters:
355: + tao  - Tao context
356: - flag - `PETSC_TRUE` or `PETSC_FALSE`

358:   Options Database Key:
359: . -tao_ksp_ew (true|false) - use Eisenstat-Walker linear system convergence test

361:   Level: advanced

363:   Note:
364:   See `SNESKSPSetUseEW()` for customization details.

366: .seealso: [](ch_tao), `Tao`, `SNESKSPSetUseEW()`
367: @*/
368: PetscErrorCode TaoKSPSetUseEW(Tao tao, PetscBool flag)
369: {
370:   PetscFunctionBegin;
373:   tao->ksp_ewconv = flag;
374:   PetscFunctionReturn(PETSC_SUCCESS);
375: }

377: /*@
378:   TaoMonitorSetFromOptions - Sets a monitor function, viewer, and viewer format based on the viewer specification in the options database

380:   Collective

382:   Input Parameters:
383: + tao     - `Tao` object you wish to monitor
384: . name    - the monitor type one is seeking
385: . help    - message indicating what monitoring is done
386: . manual  - manual page for the monitor
387: - monitor - the monitor function, this must use a `PetscViewerFormat` as its context

389:   Options Database Key:
390: . -name_interval interval - sets the interval of `Tao` iterations to monitor, by default this is 1.

392:   Level: developer

394:   Note:
395:   See `PetscOptionsCreateViewer()` for details on the viewer specification, for example, `-tao_monitor ascii:myfile::append`

397: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
398:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
399:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
400:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
401:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
402:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
403:           `PetscOptionsFList()`, `PetscOptionsEList()`
404: @*/
405: PetscErrorCode TaoMonitorSetFromOptions(Tao tao, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(Tao, PetscViewerAndFormat *))
406: {
407:   PetscViewer       viewer;
408:   PetscViewerFormat format;
409:   PetscBool         flg;

411:   PetscFunctionBegin;
412:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)tao), ((PetscObject)tao)->options, ((PetscObject)tao)->prefix, name, &viewer, &format, &flg));
413:   if (flg) {
414:     PetscViewerAndFormat *vf;
415:     char                  interval_key[1024];

417:     PetscCall(PetscSNPrintf(interval_key, sizeof(interval_key), "%s_interval", name));
418:     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
419:     vf->view_interval = 1;
420:     PetscCall(PetscOptionsGetInt(((PetscObject)tao)->options, ((PetscObject)tao)->prefix, interval_key, &vf->view_interval, NULL));

422:     PetscCall(PetscViewerDestroy(&viewer));
423:     PetscCall(TaoMonitorSet(tao, (PetscErrorCode (*)(Tao, PetscCtx))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
424:   }
425:   PetscFunctionReturn(PETSC_SUCCESS);
426: }

428: /*@
429:   TaoSetFromOptions - Sets various Tao parameters from the options database

431:   Collective

433:   Input Parameter:
434: . tao - the `Tao` solver context

436:   Options Database Keys:
437: + -tao_type type                                    - The algorithm that `tao` will use (lmvm, nls, etc.). See `TaoType`
438: . -tao_gatol gatol                                  - absolute error tolerance for ||gradient||
439: . -tao_grtol grtol                                  - relative error tolerance for ||gradient||
440: . -tao_gttol gttol                                  - reduction of ||gradient|| relative to initial gradient
441: . -tao_max_it max                                   - sets maximum number of iterations
442: . -tao_max_funcs max                                - sets maximum number of function evaluations
443: . -tao_fmin fmin                                    - stop if function value reaches `fmin`
444: . -tao_steptol tol                                  - stop if the trust region radius becomes less than `tol`
445: . -tao_trust0 radius                                - initial trust region radius
446: . -tao_monitor viewer_specification                 - prints function value and residual norm at each iteration
447: . -tao_monitor_constraint_norm viewer_specification - prints objective value, gradient, and constraint norm at each iteration
448: . -tao_monitor_globalization viewer_specification   - prints information about the globalization at each iteration
449: . -tao_monitor_solution viewer_specification        - prints solution vector at each iteration
450: . -tao_monitor_residual viewer_specification        - view the least-squares residual at each iteration
451: . -tao_monitor_step viewer_specification            - prints step vector at each iteration
452: . -tao_monitor_gradient viewer_specification        - prints gradient vector at each iteration
453: . -tao_monitor_solution_draw (true|false)           - use `TaoMonitorSolutionDraw()` to draw the solution at each iteration
454: . -tao_monitor_gradient_draw (true|false)           - use `TaoMonitorGradientDraw()` to draw the gradient at each iteration
455: . -tao_monitor_step_draw (true|false)               - use `TaoMonitorStepDraw()` to draw the solution step at each iteration
456: . -tao_monitor_cancel (true|false)                  - cancels all monitors (except those set from the command line)
457: . -tao_fd_gradient (true|false)                     - use gradient computed with finite differences
458: . -tao_fd_hessian (true|false)                      - use Hessian computed with finite differences
459: . -tao_mf_hessian (true|false)                      - use matrix-free Hessian computed with finite differences. No `TaoTerm` support
460: . -tao_view viewer_specification                    - displays information about `tao` at the end of `TaoSolve()`
461: . -tao_view_solution viewer_specification           - view the solution at the end of the optimization process
462: . -tao_converged_reason (true|false)                - displays the reason `tao` stopped iterating
463: . -tao_add_terms prefix1,prefix2,...                - takes a comma-separated list of up to 16 options prefixes, a `TaoTerm` will be created for each and added to the objective function
464: . -tao_recycle_history (true|false)                 - reuse the history from previous `TaoSolve()`, for some algorithms. See `TaoSetRecycleHistory()`
465: . -tao_subset_type (subvec|mask|matrixfree)         - strategies for handling active-sets, see `TaoSubsetType`
466: - -tao_ksp_ew (true|false)                          - use Eisenstat-Walker linear system convergence test, see `TaoKSPSetUseEW()`

468:   Level: beginner

470:   Notes:
471:   See `PetscOptionsCreateViewer()` for the format of `viewer_specification`

473:   To see all options, run your program with the `-help` option or consult the
474:   user's manual. Should be called after `TaoCreate()` but before `TaoSolve()`.

476: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`, `TaoSetRecycleHistory()`, `PetscOptionsCreateViewer()`, `TaoSubsetType`, `TaoKSPSetUseEW()`
477: @*/
478: PetscErrorCode TaoSetFromOptions(Tao tao)
479: {
480:   TaoType   default_type = TAOLMVM;
481:   char      type[256];
482:   PetscBool flg, found;
483:   MPI_Comm  comm;
484:   PetscReal catol, crtol, gatol, grtol, gttol;

486:   PetscFunctionBegin;
488:   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));

490:   if (((PetscObject)tao)->type_name) default_type = ((PetscObject)tao)->type_name;

492:   PetscObjectOptionsBegin((PetscObject)tao);
493:   /* Check for type from options */
494:   PetscCall(PetscOptionsFList("-tao_type", "Tao Solver type", "TaoSetType", TaoList, default_type, type, sizeof(type), &flg));
495:   if (flg) PetscCall(TaoSetType(tao, type));
496:   else if (!((PetscObject)tao)->type_name) PetscCall(TaoSetType(tao, default_type));

498:   /* Tao solvers do not set the prefix, set it here if not yet done
499:      We do it after SetType since solver may have been changed */
500:   if (tao->linesearch) {
501:     const char *prefix;
502:     PetscCall(TaoLineSearchGetOptionsPrefix(tao->linesearch, &prefix));
503:     if (!prefix) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, ((PetscObject)tao)->prefix));
504:   }

506:   catol = tao->catol;
507:   crtol = tao->crtol;
508:   PetscCall(PetscOptionsReal("-tao_catol", "Stop if constraints violations within", "TaoSetConstraintTolerances", tao->catol, &catol, NULL));
509:   PetscCall(PetscOptionsReal("-tao_crtol", "Stop if relative constraint violations within", "TaoSetConstraintTolerances", tao->crtol, &crtol, NULL));
510:   PetscCall(TaoSetConstraintTolerances(tao, catol, crtol));

512:   gatol = tao->gatol;
513:   grtol = tao->grtol;
514:   gttol = tao->gttol;
515:   PetscCall(PetscOptionsReal("-tao_gatol", "Stop if norm of gradient less than", "TaoSetTolerances", tao->gatol, &gatol, NULL));
516:   PetscCall(PetscOptionsReal("-tao_grtol", "Stop if norm of gradient divided by the function value is less than", "TaoSetTolerances", tao->grtol, &grtol, NULL));
517:   PetscCall(PetscOptionsReal("-tao_gttol", "Stop if the norm of the gradient is less than the norm of the initial gradient times tol", "TaoSetTolerances", tao->gttol, &gttol, NULL));
518:   PetscCall(TaoSetTolerances(tao, gatol, grtol, gttol));

520:   PetscCall(PetscOptionsInt("-tao_max_it", "Stop if iteration number exceeds", "TaoSetMaximumIterations", tao->max_it, &tao->max_it, &flg));
521:   if (flg) PetscCall(TaoSetMaximumIterations(tao, tao->max_it));

523:   PetscCall(PetscOptionsInt("-tao_max_funcs", "Stop if number of function evaluations exceeds", "TaoSetMaximumFunctionEvaluations", tao->max_funcs, &tao->max_funcs, &flg));
524:   if (flg) PetscCall(TaoSetMaximumFunctionEvaluations(tao, tao->max_funcs));

526:   PetscCall(PetscOptionsReal("-tao_fmin", "Stop if function less than", "TaoSetFunctionLowerBound", tao->fmin, &tao->fmin, NULL));
527:   PetscCall(PetscOptionsBoundedReal("-tao_steptol", "Stop if step size or trust region radius less than", "", tao->steptol, &tao->steptol, NULL, 0));
528:   PetscCall(PetscOptionsReal("-tao_trust0", "Initial trust region radius", "TaoSetInitialTrustRegionRadius", tao->trust0, &tao->trust0, &flg));
529:   if (flg) PetscCall(TaoSetInitialTrustRegionRadius(tao, tao->trust0));

531:   PetscCall(PetscOptionsDeprecated("-tao_solution_monitor", "-tao_monitor_solution", "3.21", NULL));
532:   PetscCall(PetscOptionsDeprecated("-tao_gradient_monitor", "-tao_monitor_gradient", "3.21", NULL));
533:   PetscCall(PetscOptionsDeprecated("-tao_stepdirection_monitor", "-tao_monitor_step", "3.21", NULL));
534:   PetscCall(PetscOptionsDeprecated("-tao_residual_monitor", "-tao_monitor_residual", "3.21", NULL));
535:   PetscCall(PetscOptionsDeprecated("-tao_smonitor", "-tao_monitor", "3.21", NULL));
536:   PetscCall(PetscOptionsDeprecated("-tao_monitor_short", "-tao_monitor", "3.26", NULL));
537:   PetscCall(PetscOptionsDeprecated("-tao_monitor_short_interval", "-tao_monitor_interval", "3.26", NULL));
538:   PetscCall(PetscOptionsDeprecated("-tao_cmonitor", "-tao_monitor_constraint_norm", "3.21", NULL));
539:   PetscCall(PetscOptionsDeprecated("-tao_gmonitor", "-tao_monitor_globalization", "3.21", NULL));
540:   PetscCall(PetscOptionsDeprecated("-tao_draw_solution", "-tao_monitor_solution_draw", "3.21", NULL));
541:   PetscCall(PetscOptionsDeprecated("-tao_draw_gradient", "-tao_monitor_gradient_draw", "3.21", NULL));
542:   PetscCall(PetscOptionsDeprecated("-tao_draw_step", "-tao_monitor_step_draw", "3.21", NULL));

544:   PetscCall(PetscOptionsBool("-tao_converged_reason", "Print reason for Tao converged", "TaoSolve", tao->printreason, &tao->printreason, NULL));

546:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_solution", "View solution vector after each iteration", "TaoMonitorSolution", TaoMonitorSolution));
547:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_gradient", "View gradient vector for each iteration", "TaoMonitorGradient", TaoMonitorGradient));

549:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_step", "View step vector after each iteration", "TaoMonitorStep", TaoMonitorStep));
550:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_residual", "View least-squares residual vector after each iteration", "TaoMonitorResidual", TaoMonitorResidual));
551:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor", "Use the default convergence monitor", "TaoMonitorDefault", TaoMonitorDefault));
552:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_globalization", "Use the convergence monitor with extra globalization info", "TaoMonitorGlobalization", TaoMonitorGlobalization));
553:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_constraint_norm", "Use the default convergence monitor with constraint norm", "TaoMonitorConstraintNorm", TaoMonitorConstraintNorm));

555:   flg = PETSC_FALSE;
556:   PetscCall(PetscOptionsDeprecated("-tao_cancelmonitors", "-tao_monitor_cancel", "3.21", NULL));
557:   PetscCall(PetscOptionsBool("-tao_monitor_cancel", "cancel all monitors and call any registered destroy routines", "TaoMonitorCancel", flg, &flg, NULL));
558:   if (flg) PetscCall(TaoMonitorCancel(tao));

560:   flg = PETSC_FALSE;
561:   PetscCall(PetscOptionsBool("-tao_monitor_solution_draw", "Plot solution vector at each iteration", "TaoMonitorSet", flg, &flg, NULL));
562:   if (flg) {
563:     TaoMonitorDrawCtx drawctx;
564:     PetscInt          howoften = 1;
565:     PetscCall(PetscOptionsInt("-tao_monitor_solution_draw_interval", "Only draw every interval iterations, and the final value", "TaoMonitorSet", howoften, &howoften, NULL));
566:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
567:     PetscCall(TaoMonitorSet(tao, TaoMonitorSolutionDraw, drawctx, (PetscCtxDestroyFn *)TaoMonitorDrawCtxDestroy));
568:   }

570:   flg = PETSC_FALSE;
571:   PetscCall(PetscOptionsBool("-tao_monitor_step_draw", "Plots step at each iteration", "TaoMonitorSet", flg, &flg, NULL));
572:   if (flg) {
573:     TaoMonitorDrawCtx drawctx;
574:     PetscInt          howoften = 1;
575:     PetscCall(PetscOptionsInt("-tao_monitor_step_draw_interval", "Only draw every interval iterations, and the final value", "TaoMonitorSet", howoften, &howoften, NULL));
576:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
577:     PetscCall(TaoMonitorSet(tao, TaoMonitorStepDraw, drawctx, (PetscCtxDestroyFn *)TaoMonitorDrawCtxDestroy));
578:   }

580:   flg = PETSC_FALSE;
581:   PetscCall(PetscOptionsBool("-tao_monitor_gradient_draw", "plots gradient at each iteration", "TaoMonitorSet", flg, &flg, NULL));
582:   if (flg) {
583:     TaoMonitorDrawCtx drawctx;
584:     PetscInt          howoften = 1;
585:     PetscCall(PetscOptionsInt("-tao_monitor_gradient_draw_interval", "Only draw every interval iterations, and the final value", "TaoMonitorSet", howoften, &howoften, NULL));
586:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
587:     PetscCall(TaoMonitorSet(tao, TaoMonitorGradientDraw, drawctx, (PetscCtxDestroyFn *)TaoMonitorDrawCtxDestroy));
588:   }

590:   flg = PETSC_FALSE;
591:   PetscCall(PetscOptionsBool("-tao_fd_gradient", "compute gradient using finite differences", "TaoDefaultComputeGradient", flg, &flg, NULL));
592:   if (flg) PetscCall(TaoTermComputeGradientSetUseFD(tao->objective_term.term, PETSC_TRUE));
593:   flg = PETSC_FALSE;
594:   PetscCall(PetscOptionsBool("-tao_fd_hessian", "compute Hessian using finite differences", "TaoDefaultComputeHessian", flg, &flg, NULL));
595:   if (flg) {
596:     Mat H;

598:     PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &H));
599:     PetscCall(MatSetType(H, MATAIJ));
600:     PetscCall(MatSetOption(H, MAT_SYMMETRIC, PETSC_TRUE));
601:     PetscCall(MatSetOption(H, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
602:     PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessian, NULL));
603:     PetscCall(TaoTermComputeHessianSetUseFD(tao->objective_term.term, PETSC_TRUE));
604:     PetscCall(MatDestroy(&H));
605:   }
606:   flg = PETSC_FALSE;
607:   PetscCall(PetscOptionsBool("-tao_mf_hessian", "compute matrix-free Hessian using finite differences", "TaoDefaultComputeHessianMFFD", flg, &flg, NULL));
608:   if (flg) {
609:     PetscBool is_callback;
610:     Mat       H;

612:     // Check that tao has only one TaoTerm with type TAOTERMCALLBACK
613:     PetscCall(PetscObjectTypeCompare((PetscObject)tao->objective_term.term, TAOTERMCALLBACKS, &is_callback));
614:     if (is_callback) {
615:       // Create Hessian via TaoTermCreateHessianMFFD
616:       PetscCall(TaoTermCreateHessianMFFD(tao->objective_term.term, &H));
617:       PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessianMFFD, NULL));
618:       PetscCall(MatDestroy(&H));
619:     } else {
620:       PetscCall(PetscInfo(tao, "-tao_mf_hessian only works when Tao has a single TAOTERMCALLBACK term. Ignoring.\n"));
621:     }
622:   }
623:   PetscCall(PetscOptionsBool("-tao_recycle_history", "enable recycling/re-using information from the previous TaoSolve() call for some algorithms", "TaoSetRecycleHistory", flg, &flg, &found));
624:   if (found) PetscCall(TaoSetRecycleHistory(tao, flg));
625:   PetscCall(PetscOptionsEnum("-tao_subset_type", "subset type", "", TaoSubsetTypes, (PetscEnum)tao->subset_type, (PetscEnum *)&tao->subset_type, NULL));

627:   if (tao->ksp) {
628:     PetscCall(PetscOptionsBool("-tao_ksp_ew", "Use Eisentat-Walker linear system convergence test", "TaoKSPSetUseEW", tao->ksp_ewconv, &tao->ksp_ewconv, NULL));
629:     PetscCall(TaoKSPSetUseEW(tao, tao->ksp_ewconv));
630:   }

632:   PetscCall(TaoTermSetFromOptions(tao->callbacks));

634:   {
635:     char    *term_prefixes[16];
636:     PetscInt n_terms = PETSC_STATIC_ARRAY_LENGTH(term_prefixes);

638:     PetscCall(PetscOptionsStringArray("-tao_add_terms", "a list of prefixes for terms to add to the Tao objective function", "TaoAddTerm", term_prefixes, &n_terms, NULL));
639:     for (PetscInt i = 0; i < n_terms; i++) {
640:       TaoTerm     term;
641:       const char *prefix;

643:       PetscCall(TaoTermDuplicate(tao->objective_term.term, TAOTERM_DUPLICATE_SIZEONLY, &term));
644:       PetscCall(TaoGetOptionsPrefix(tao, &prefix));
645:       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)term, prefix));
646:       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)term, term_prefixes[i]));
647:       PetscCall(TaoTermSetFromOptions(term));
648:       PetscCall(TaoAddTerm(tao, term_prefixes[i], 1.0, term, NULL, NULL));
649:       PetscCall(TaoTermDestroy(&term));
650:       PetscCall(PetscFree(term_prefixes[i]));
651:     }
652:   }

654:   if (tao->objective_term.term != tao->callbacks) PetscCall(TaoTermSetFromOptions(tao->objective_term.term));

656:   PetscTryTypeMethod(tao, setfromoptions, PetscOptionsObject);

658:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
659:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tao, PetscOptionsObject));
660:   PetscOptionsEnd();

662:   if (tao->linesearch) PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
663:   PetscFunctionReturn(PETSC_SUCCESS);
664: }

666: /*@
667:   TaoViewFromOptions - View a `Tao` object based on values in the options database

669:   Collective

671:   Input Parameters:
672: + A    - the  `Tao` context
673: . obj  - optional object that provides the prefix for the options database, pass `NULL` to use the options prefix of `A`
674: - name - command line option

676:   Options Database Key:
677: . -name viewer_specification - See `PetscOptionsCreateViewer()` for the values of `viewer_specification`

679:   Level: intermediate

681:   Note:
682:   This checks the options database, creates the viewer on-the-fly, uses it and then destroys it. Hence it should not be called in heavily used routines,
683:   rather `PetscOptionsCreateViewer()` should be used to construct the viewer once which can then be utilized in the heavily used routine.

685: .seealso: [](ch_tao), `Tao`, `TaoView()`, `PetscObjectViewFromOptions()`, `TaoCreate()`, `PetscOptionsCreateViewer()`
686: @*/
687: PetscErrorCode TaoViewFromOptions(Tao A, PetscObject obj, const char name[])
688: {
689:   PetscFunctionBegin;
691:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
692:   PetscFunctionReturn(PETSC_SUCCESS);
693: }

695: /*@
696:   TaoView - Displays information about the `Tao` object

698:   Collective

700:   Input Parameters:
701: + tao    - the `Tao` context
702: - viewer - visualization context

704:   Options Database Key:
705: . -tao_view viewer_specification - Calls `TaoView()` at the end of `TaoSolve()`. See `PetscOptionsCreateViewer()` for the format of `viewer_specification`.

707:   Level: beginner

709:   Notes:
710:   The available visualization contexts include
711: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
712: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
713:   output where only the first processor opens
714:   the file.  All other processors send their
715:   data to the first processor to print.

717:   To view all the `TaoTerm` inside of `Tao`, use `PETSC_VIEWER_ASCII_INFO_DETAIL`,
718:   or pass `-tao_view ::ascii_info_detail` flag

720: .seealso: [](ch_tao), `Tao`, `PetscViewerASCIIOpen()`, `PetscOptionsCreateViewer()`
721: @*/
722: PetscErrorCode TaoView(Tao tao, PetscViewer viewer)
723: {
724:   PetscBool isascii, isstring;
725:   TaoType   type;

727:   PetscFunctionBegin;
729:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(((PetscObject)tao)->comm, &viewer));
731:   PetscCheckSameComm(tao, 1, viewer, 2);

733:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
734:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
735:   if (isascii) {
736:     PetscViewerFormat format;

738:     PetscCall(PetscViewerGetFormat(viewer, &format));
739:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tao, viewer));

741:     PetscCall(PetscViewerASCIIPushTab(viewer));
742:     PetscTryTypeMethod(tao, view, viewer);
743:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
744:       PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
745:       PetscCall(PetscViewerASCIIPushTab(viewer));
746:       PetscCall(PetscViewerASCIIPrintf(viewer, "Scale (tao_objective_scale): %g\n", (double)tao->objective_term.scale));
747:       PetscCall(PetscViewerASCIIPrintf(viewer, "Function:\n"));
748:       PetscCall(PetscViewerASCIIPushTab(viewer));
749:       PetscCall(TaoTermView(tao->objective_term.term, viewer));
750:       PetscCall(PetscViewerASCIIPopTab(viewer));
751:       if (tao->objective_term.map) {
752:         PetscCall(PetscViewerASCIIPrintf(viewer, "Map:\n"));
753:         PetscCall(PetscViewerASCIIPushTab(viewer));
754:         PetscCall(MatView(tao->objective_term.map, viewer));
755:         PetscCall(PetscViewerASCIIPopTab(viewer));
756:       } else PetscCall(PetscViewerASCIIPrintf(viewer, "Map: unmapped\n"));
757:       PetscCall(PetscViewerASCIIPopTab(viewer));
758:     } else if (tao->num_terms > 0 || tao->term_set) {
759:       if (tao->objective_term.scale == 1.0 && tao->objective_term.map == NULL) {
760:         PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
761:         PetscCall(PetscViewerASCIIPushTab(viewer));
762:         PetscCall(TaoTermView(tao->objective_term.term, viewer));
763:         PetscCall(PetscViewerASCIIPopTab(viewer));
764:       } else {
765:         PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
766:         PetscCall(PetscViewerASCIIPushTab(viewer));
767:         if (tao->objective_term.scale != 1.0) PetscCall(PetscViewerASCIIPrintf(viewer, "Scale: %g\n", (double)tao->objective_term.scale));
768:         PetscCall(PetscViewerASCIIPrintf(viewer, "Function:\n"));
769:         PetscCall(PetscViewerASCIIPushTab(viewer));
770:         PetscCall(TaoTermView(tao->objective_term.term, viewer));
771:         PetscCall(PetscViewerASCIIPopTab(viewer));
772:         if (tao->objective_term.map) {
773:           PetscCall(PetscViewerASCIIPrintf(viewer, "Map:\n"));
774:           PetscCall(PetscViewerASCIIPushTab(viewer));
775:           PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO));
776:           PetscCall(MatView(tao->objective_term.map, viewer));
777:           PetscCall(PetscViewerPopFormat(viewer));
778:           PetscCall(PetscViewerASCIIPopTab(viewer));
779:         }
780:         PetscCall(PetscViewerASCIIPopTab(viewer));
781:       }
782:     }
783:     if (tao->linesearch) PetscCall(TaoLineSearchView(tao->linesearch, viewer));
784:     if (tao->ksp) {
785:       PetscCall(KSPView(tao->ksp, viewer));
786:       PetscCall(PetscViewerASCIIPrintf(viewer, "total KSP iterations: %" PetscInt_FMT "\n", tao->ksp_tot_its));
787:     }

789:     if (tao->XL || tao->XU) PetscCall(PetscViewerASCIIPrintf(viewer, "Active Set subset type: %s\n", TaoSubsetTypes[tao->subset_type]));

791:     PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: gatol=%g,", (double)tao->gatol));
792:     PetscCall(PetscViewerASCIIPrintf(viewer, " grtol=%g,", (double)tao->grtol));
793:     PetscCall(PetscViewerASCIIPrintf(viewer, " steptol=%g,", (double)tao->steptol));
794:     PetscCall(PetscViewerASCIIPrintf(viewer, " gttol=%g\n", (double)tao->gttol));
795:     PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Function/Gradient:=%g\n", (double)tao->residual));

797:     if (tao->constrained) {
798:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances:"));
799:       PetscCall(PetscViewerASCIIPrintf(viewer, " catol=%g,", (double)tao->catol));
800:       PetscCall(PetscViewerASCIIPrintf(viewer, " crtol=%g\n", (double)tao->crtol));
801:       PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Constraints:=%g\n", (double)tao->cnorm));
802:     }

804:     if (tao->trust < tao->steptol) {
805:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: steptol=%g\n", (double)tao->steptol));
806:       PetscCall(PetscViewerASCIIPrintf(viewer, "Final trust region radius:=%g\n", (double)tao->trust));
807:     }

809:     if (tao->fmin > -1.e25) PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: function minimum=%g\n", (double)tao->fmin));
810:     PetscCall(PetscViewerASCIIPrintf(viewer, "Objective value=%g\n", (double)tao->fc));

812:     PetscCall(PetscViewerASCIIPrintf(viewer, "total number of iterations=%" PetscInt_FMT ",          ", tao->niter));
813:     PetscCall(PetscViewerASCIIPrintf(viewer, "              (max: %" PetscInt_FMT ")\n", tao->max_it));

815:     if (tao->objective_term.term->nobj > 0) {
816:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function evaluations=%" PetscInt_FMT ",", tao->objective_term.term->nobj));
817:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
818:       else PetscCall(PetscViewerASCIIPrintf(viewer, "               (max: %" PetscInt_FMT ")\n", tao->max_funcs));
819:     }
820:     if (tao->objective_term.term->ngrad > 0) {
821:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of gradient evaluations=%" PetscInt_FMT ",", tao->objective_term.term->ngrad));
822:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
823:       else PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: %" PetscInt_FMT ")\n", tao->max_funcs));
824:     }
825:     if (tao->objective_term.term->nobjgrad > 0) {
826:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function/gradient evaluations=%" PetscInt_FMT ",", tao->objective_term.term->nobjgrad));
827:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: unlimited)\n"));
828:       else PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: %" PetscInt_FMT ")\n", tao->max_funcs));
829:     }
830:     if (tao->nres > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of residual evaluations=%" PetscInt_FMT "\n", tao->nres));
831:     if (tao->objective_term.term->nhess > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Hessian evaluations=%" PetscInt_FMT "\n", tao->objective_term.term->nhess));
832:     if (tao->nconstraints > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of constraint function evaluations=%" PetscInt_FMT "\n", tao->nconstraints));
833:     if (tao->njac > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Jacobian evaluations=%" PetscInt_FMT "\n", tao->njac));

835:     if (tao->reason > 0) {
836:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solution converged: "));
837:       switch (tao->reason) {
838:       case TAO_CONVERGED_GATOL:
839:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)|| <= gatol\n"));
840:         break;
841:       case TAO_CONVERGED_GRTOL:
842:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/|f(X)| <= grtol\n"));
843:         break;
844:       case TAO_CONVERGED_GTTOL:
845:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/||g(X0)|| <= gttol\n"));
846:         break;
847:       case TAO_CONVERGED_STEPTOL:
848:         PetscCall(PetscViewerASCIIPrintf(viewer, " Steptol -- step size small\n"));
849:         break;
850:       case TAO_CONVERGED_MINF:
851:         PetscCall(PetscViewerASCIIPrintf(viewer, " Minf --  f < fmin\n"));
852:         break;
853:       case TAO_CONVERGED_USER:
854:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
855:         break;
856:       default:
857:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
858:         break;
859:       }
860:     } else if (tao->reason == TAO_CONTINUE_ITERATING) {
861:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver never run\n"));
862:     } else {
863:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver failed: "));
864:       switch (tao->reason) {
865:       case TAO_DIVERGED_MAXITS:
866:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Iterations\n"));
867:         break;
868:       case TAO_DIVERGED_NAN:
869:         PetscCall(PetscViewerASCIIPrintf(viewer, " NaN or infinity encountered\n"));
870:         break;
871:       case TAO_DIVERGED_MAXFCN:
872:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Function Evaluations\n"));
873:         break;
874:       case TAO_DIVERGED_LS_FAILURE:
875:         PetscCall(PetscViewerASCIIPrintf(viewer, " Line Search Failure\n"));
876:         break;
877:       case TAO_DIVERGED_TR_REDUCTION:
878:         PetscCall(PetscViewerASCIIPrintf(viewer, " Trust Region too small\n"));
879:         break;
880:       case TAO_DIVERGED_USER:
881:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
882:         break;
883:       default:
884:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
885:         break;
886:       }
887:     }
888:     PetscCall(PetscViewerASCIIPopTab(viewer));
889:   } else if (isstring) {
890:     PetscCall(TaoGetType(tao, &type));
891:     PetscCall(PetscViewerStringSPrintf(viewer, " %-3.3s", type));
892:   }
893:   PetscFunctionReturn(PETSC_SUCCESS);
894: }

896: /*@
897:   TaoSetRecycleHistory - Sets the boolean flag to enable/disable re-using
898:   iterate information from the previous `TaoSolve()`. This feature is disabled by
899:   default.

901:   Logically Collective

903:   Input Parameters:
904: + tao     - the `Tao` context
905: - recycle - boolean flag

907:   Options Database Key:
908: . -tao_recycle_history (true|false) - reuse the history

910:   Level: intermediate

912:   Notes:
913:   For conjugate gradient methods (`TAOBNCG`), this re-uses the latest search direction
914:   from the previous `TaoSolve()` call when computing the first search direction in a
915:   new solution. By default, CG methods set the first search direction to the
916:   negative gradient.

918:   For quasi-Newton family of methods (`TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`), this re-uses
919:   the accumulated quasi-Newton Hessian approximation from the previous `TaoSolve()`
920:   call. By default, QN family of methods reset the initial Hessian approximation to
921:   the identity matrix.

923:   For any other algorithm, this setting has no effect.

925: .seealso: [](ch_tao), `Tao`, `TaoGetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
926: @*/
927: PetscErrorCode TaoSetRecycleHistory(Tao tao, PetscBool recycle)
928: {
929:   PetscFunctionBegin;
932:   tao->recycle = recycle;
933:   PetscFunctionReturn(PETSC_SUCCESS);
934: }

936: /*@
937:   TaoGetRecycleHistory - Retrieve the boolean flag for re-using iterate information
938:   from the previous `TaoSolve()`. This feature is disabled by default.

940:   Logically Collective

942:   Input Parameter:
943: . tao - the `Tao` context

945:   Output Parameter:
946: . recycle - boolean flag

948:   Level: intermediate

950: .seealso: [](ch_tao), `Tao`, `TaoSetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
951: @*/
952: PetscErrorCode TaoGetRecycleHistory(Tao tao, PetscBool *recycle)
953: {
954:   PetscFunctionBegin;
956:   PetscAssertPointer(recycle, 2);
957:   *recycle = tao->recycle;
958:   PetscFunctionReturn(PETSC_SUCCESS);
959: }

961: /*@
962:   TaoSetTolerances - Sets parameters used in `TaoSolve()` convergence tests

964:   Logically Collective

966:   Input Parameters:
967: + tao   - the `Tao` context
968: . gatol - stop if norm of gradient is less than this
969: . grtol - stop if relative norm of gradient is less than this
970: - gttol - stop if norm of gradient is reduced by this factor

972:   Options Database Keys:
973: + -tao_gatol gatol - Sets gatol
974: . -tao_grtol grtol - Sets grtol
975: - -tao_gttol gttol - Sets gttol

977:   Stopping Criteria\:
978: .vb
979:   ||g(X)||                            <= gatol
980:   ||g(X)|| / |f(X)|                   <= grtol
981:   ||g(X)|| / ||g(X0)||                <= gttol
982: .ve

984:   Level: beginner

986:   Notes:
987:   Use `PETSC_CURRENT` to leave one or more tolerances unchanged.

989:   Use `PETSC_DETERMINE` to set one or more tolerances to their values when the `tao`object's type was set

991:   Fortran Note:
992:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

994: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`
995: @*/
996: PetscErrorCode TaoSetTolerances(Tao tao, PetscReal gatol, PetscReal grtol, PetscReal gttol)
997: {
998:   PetscFunctionBegin;

1004:   if (gatol == (PetscReal)PETSC_DETERMINE) {
1005:     tao->gatol = tao->default_gatol;
1006:   } else if (gatol != (PetscReal)PETSC_CURRENT) {
1007:     PetscCheck(gatol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gatol not allowed");
1008:     tao->gatol = gatol;
1009:   }

1011:   if (grtol == (PetscReal)PETSC_DETERMINE) {
1012:     tao->grtol = tao->default_grtol;
1013:   } else if (grtol != (PetscReal)PETSC_CURRENT) {
1014:     PetscCheck(grtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative grtol not allowed");
1015:     tao->grtol = grtol;
1016:   }

1018:   if (gttol == (PetscReal)PETSC_DETERMINE) {
1019:     tao->gttol = tao->default_gttol;
1020:   } else if (gttol != (PetscReal)PETSC_CURRENT) {
1021:     PetscCheck(gttol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gttol not allowed");
1022:     tao->gttol = gttol;
1023:   }
1024:   PetscFunctionReturn(PETSC_SUCCESS);
1025: }

1027: /*@
1028:   TaoSetConstraintTolerances - Sets constraint tolerance parameters used in `TaoSolve()` convergence tests

1030:   Logically Collective

1032:   Input Parameters:
1033: + tao   - the `Tao` context
1034: . catol - absolute constraint tolerance, constraint norm must be less than `catol` for used for `gatol` convergence criteria
1035: - crtol - relative constraint tolerance, constraint norm must be less than `crtol` for used for `gatol`, `gttol` convergence criteria

1037:   Options Database Keys:
1038: + -tao_catol catol - Sets catol
1039: - -tao_crtol crtol - Sets crtol

1041:   Level: intermediate

1043:   Notes:
1044:   Use `PETSC_CURRENT` to leave one or tolerance unchanged.

1046:   Use `PETSC_DETERMINE` to set one or more tolerances to their values when the `tao` object's type was set

1048:   Fortran Note:
1049:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

1051: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`, `TaoGetConstraintTolerances()`, `TaoSetTolerances()`
1052: @*/
1053: PetscErrorCode TaoSetConstraintTolerances(Tao tao, PetscReal catol, PetscReal crtol)
1054: {
1055:   PetscFunctionBegin;

1060:   if (catol == (PetscReal)PETSC_DETERMINE) {
1061:     tao->catol = tao->default_catol;
1062:   } else if (catol != (PetscReal)PETSC_CURRENT) {
1063:     PetscCheck(catol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative catol not allowed");
1064:     tao->catol = catol;
1065:   }

1067:   if (crtol == (PetscReal)PETSC_DETERMINE) {
1068:     tao->crtol = tao->default_crtol;
1069:   } else if (crtol != (PetscReal)PETSC_CURRENT) {
1070:     PetscCheck(crtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative crtol not allowed");
1071:     tao->crtol = crtol;
1072:   }
1073:   PetscFunctionReturn(PETSC_SUCCESS);
1074: }

1076: /*@
1077:   TaoGetConstraintTolerances - Gets constraint tolerance parameters used in `TaoSolve()` convergence tests

1079:   Not Collective

1081:   Input Parameter:
1082: . tao - the `Tao` context

1084:   Output Parameters:
1085: + catol - absolute constraint tolerance, constraint norm must be less than `catol` for used for `gatol` convergence criteria
1086: - crtol - relative constraint tolerance, constraint norm must be less than `crtol` for used for `gatol`, `gttol` convergence criteria

1088:   Level: intermediate

1090: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`, `TaoSetTolerances()`, `TaoSetConstraintTolerances()`
1091: @*/
1092: PetscErrorCode TaoGetConstraintTolerances(Tao tao, PetscReal *catol, PetscReal *crtol)
1093: {
1094:   PetscFunctionBegin;
1096:   if (catol) *catol = tao->catol;
1097:   if (crtol) *crtol = tao->crtol;
1098:   PetscFunctionReturn(PETSC_SUCCESS);
1099: }

1101: /*@
1102:   TaoSetFunctionLowerBound - Sets a bound on the solution objective value.
1103:   When an approximate solution with an objective value below this number
1104:   has been found, the solver will terminate.

1106:   Logically Collective

1108:   Input Parameters:
1109: + tao  - the Tao solver context
1110: - fmin - the tolerance

1112:   Options Database Key:
1113: . -tao_fmin fmin - sets the minimum function value

1115:   Level: intermediate

1117: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetTolerances()`
1118: @*/
1119: PetscErrorCode TaoSetFunctionLowerBound(Tao tao, PetscReal fmin)
1120: {
1121:   PetscFunctionBegin;
1124:   tao->fmin = fmin;
1125:   PetscFunctionReturn(PETSC_SUCCESS);
1126: }

1128: /*@
1129:   TaoGetFunctionLowerBound - Gets the bound on the solution objective value.
1130:   When an approximate solution with an objective value below this number
1131:   has been found, the solver will terminate.

1133:   Not Collective

1135:   Input Parameter:
1136: . tao - the `Tao` solver context

1138:   Output Parameter:
1139: . fmin - the minimum function value

1141:   Level: intermediate

1143: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetFunctionLowerBound()`
1144: @*/
1145: PetscErrorCode TaoGetFunctionLowerBound(Tao tao, PetscReal *fmin)
1146: {
1147:   PetscFunctionBegin;
1149:   PetscAssertPointer(fmin, 2);
1150:   *fmin = tao->fmin;
1151:   PetscFunctionReturn(PETSC_SUCCESS);
1152: }

1154: /*@
1155:   TaoSetMaximumFunctionEvaluations - Sets a maximum number of function evaluations allowed for a `TaoSolve()`.

1157:   Logically Collective

1159:   Input Parameters:
1160: + tao  - the `Tao` solver context
1161: - nfcn - the maximum number of function evaluations (>=0), use `PETSC_UNLIMITED` to have no bound

1163:   Options Database Key:
1164: . -tao_max_funcs nfcn - sets the maximum number of function evaluations

1166:   Level: intermediate

1168:   Note:
1169:   Use `PETSC_DETERMINE` to use the default maximum number of function evaluations that was set when the object type was set.

1171:   Developer Note:
1172:   Deprecated support for an unlimited number of function evaluations by passing a negative value.

1174: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumIterations()`
1175: @*/
1176: PetscErrorCode TaoSetMaximumFunctionEvaluations(Tao tao, PetscInt nfcn)
1177: {
1178:   PetscFunctionBegin;
1181:   if (nfcn == PETSC_DETERMINE) {
1182:     tao->max_funcs = tao->default_max_funcs;
1183:   } else if (nfcn == PETSC_UNLIMITED || nfcn < 0) {
1184:     tao->max_funcs = PETSC_UNLIMITED;
1185:   } else {
1186:     PetscCheck(nfcn >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of function evaluations  must be positive");
1187:     tao->max_funcs = nfcn;
1188:   }
1189:   PetscFunctionReturn(PETSC_SUCCESS);
1190: }

1192: /*@
1193:   TaoGetMaximumFunctionEvaluations - Gets a maximum number of function evaluations allowed for a `TaoSolve()`

1195:   Logically Collective

1197:   Input Parameter:
1198: . tao - the `Tao` solver context

1200:   Output Parameter:
1201: . nfcn - the maximum number of function evaluations

1203:   Level: intermediate

1205: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
1206: @*/
1207: PetscErrorCode TaoGetMaximumFunctionEvaluations(Tao tao, PetscInt *nfcn)
1208: {
1209:   PetscFunctionBegin;
1211:   PetscAssertPointer(nfcn, 2);
1212:   *nfcn = tao->max_funcs;
1213:   PetscFunctionReturn(PETSC_SUCCESS);
1214: }

1216: /*@
1217:   TaoGetCurrentFunctionEvaluations - Get current number of function evaluations used by a `Tao` object

1219:   Not Collective

1221:   Input Parameter:
1222: . tao - the `Tao` solver context

1224:   Output Parameter:
1225: . nfuncs - the current number of function evaluations (maximum between gradient and function evaluations)

1227:   Level: intermediate

1229: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
1230: @*/
1231: PetscErrorCode TaoGetCurrentFunctionEvaluations(Tao tao, PetscInt *nfuncs)
1232: {
1233:   PetscFunctionBegin;
1235:   PetscAssertPointer(nfuncs, 2);
1236:   *nfuncs = PetscMax(tao->objective_term.term->nobj, tao->objective_term.term->nobjgrad);
1237:   PetscFunctionReturn(PETSC_SUCCESS);
1238: }

1240: /*@
1241:   TaoSetMaximumIterations - Sets a maximum number of iterates to be used in `TaoSolve()`

1243:   Logically Collective

1245:   Input Parameters:
1246: + tao    - the `Tao` solver context
1247: - maxits - the maximum number of iterates (>=0), use `PETSC_UNLIMITED` to have no bound

1249:   Options Database Key:
1250: . -tao_max_it its - sets the maximum number of iterations

1252:   Level: intermediate

1254:   Note:
1255:   Use `PETSC_DETERMINE` to use the default maximum number of iterations that was set when the object's type was set.

1257:   Developer Note:
1258:   Also accepts the deprecated negative values to indicate no limit

1260: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumFunctionEvaluations()`
1261: @*/
1262: PetscErrorCode TaoSetMaximumIterations(Tao tao, PetscInt maxits)
1263: {
1264:   PetscFunctionBegin;
1267:   if (maxits == PETSC_DETERMINE) {
1268:     tao->max_it = tao->default_max_it;
1269:   } else if (maxits == PETSC_UNLIMITED) {
1270:     tao->max_it = PETSC_INT_MAX;
1271:   } else {
1272:     PetscCheck(maxits > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations must be positive");
1273:     tao->max_it = maxits;
1274:   }
1275:   PetscFunctionReturn(PETSC_SUCCESS);
1276: }

1278: /*@
1279:   TaoGetMaximumIterations - Gets a maximum number of iterates that will be used

1281:   Not Collective

1283:   Input Parameter:
1284: . tao - the `Tao` solver context

1286:   Output Parameter:
1287: . maxits - the maximum number of iterates

1289:   Level: intermediate

1291: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumIterations()`, `TaoGetMaximumFunctionEvaluations()`
1292: @*/
1293: PetscErrorCode TaoGetMaximumIterations(Tao tao, PetscInt *maxits)
1294: {
1295:   PetscFunctionBegin;
1297:   PetscAssertPointer(maxits, 2);
1298:   *maxits = tao->max_it;
1299:   PetscFunctionReturn(PETSC_SUCCESS);
1300: }

1302: /*@
1303:   TaoSetInitialTrustRegionRadius - Sets the initial trust region radius.

1305:   Logically Collective

1307:   Input Parameters:
1308: + tao    - a `Tao` optimization solver
1309: - radius - the trust region radius

1311:   Options Database Key:
1312: . -tao_trust0 radius - sets initial trust region radius

1314:   Level: intermediate

1316:   Note:
1317:   Use `PETSC_DETERMINE` to use the default radius that was set when the object's type was set.

1319: .seealso: [](ch_tao), `Tao`, `TaoGetTrustRegionRadius()`, `TaoSetTrustRegionTolerance()`, `TAONTR`
1320: @*/
1321: PetscErrorCode TaoSetInitialTrustRegionRadius(Tao tao, PetscReal radius)
1322: {
1323:   PetscFunctionBegin;
1326:   if (radius == PETSC_DETERMINE) {
1327:     tao->trust0 = tao->default_trust0;
1328:   } else {
1329:     PetscCheck(radius > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Radius must be positive");
1330:     tao->trust0 = radius;
1331:   }
1332:   PetscFunctionReturn(PETSC_SUCCESS);
1333: }

1335: /*@
1336:   TaoGetInitialTrustRegionRadius - Gets the initial trust region radius.

1338:   Not Collective

1340:   Input Parameter:
1341: . tao - a `Tao` optimization solver

1343:   Output Parameter:
1344: . radius - the trust region radius

1346:   Level: intermediate

1348: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetCurrentTrustRegionRadius()`, `TAONTR`
1349: @*/
1350: PetscErrorCode TaoGetInitialTrustRegionRadius(Tao tao, PetscReal *radius)
1351: {
1352:   PetscFunctionBegin;
1354:   PetscAssertPointer(radius, 2);
1355:   *radius = tao->trust0;
1356:   PetscFunctionReturn(PETSC_SUCCESS);
1357: }

1359: /*@
1360:   TaoGetCurrentTrustRegionRadius - Gets the current trust region radius.

1362:   Not Collective

1364:   Input Parameter:
1365: . tao - a `Tao` optimization solver

1367:   Output Parameter:
1368: . radius - the trust region radius

1370:   Level: intermediate

1372: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetInitialTrustRegionRadius()`, `TAONTR`
1373: @*/
1374: PetscErrorCode TaoGetCurrentTrustRegionRadius(Tao tao, PetscReal *radius)
1375: {
1376:   PetscFunctionBegin;
1378:   PetscAssertPointer(radius, 2);
1379:   *radius = tao->trust;
1380:   PetscFunctionReturn(PETSC_SUCCESS);
1381: }

1383: /*@
1384:   TaoGetTolerances - gets the current values of some tolerances used for the convergence testing of `TaoSolve()`

1386:   Not Collective

1388:   Input Parameter:
1389: . tao - the `Tao` context

1391:   Output Parameters:
1392: + gatol - stop if norm of gradient is less than this
1393: . grtol - stop if relative norm of gradient is less than this
1394: - gttol - stop if norm of gradient is reduced by a this factor

1396:   Level: intermediate

1398:   Note:
1399:   `NULL` can be used as an argument if not all tolerances values are needed

1401: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`
1402: @*/
1403: PetscErrorCode TaoGetTolerances(Tao tao, PetscReal *gatol, PetscReal *grtol, PetscReal *gttol)
1404: {
1405:   PetscFunctionBegin;
1407:   if (gatol) *gatol = tao->gatol;
1408:   if (grtol) *grtol = tao->grtol;
1409:   if (gttol) *gttol = tao->gttol;
1410:   PetscFunctionReturn(PETSC_SUCCESS);
1411: }

1413: /*@
1414:   TaoGetKSP - Gets the linear solver used by the optimization solver.

1416:   Not Collective

1418:   Input Parameter:
1419: . tao - the `Tao` solver

1421:   Output Parameter:
1422: . ksp - the `KSP` linear solver used in the optimization solver

1424:   Level: intermediate

1426: .seealso: [](ch_tao), `Tao`, `KSP`
1427: @*/
1428: PetscErrorCode TaoGetKSP(Tao tao, KSP *ksp)
1429: {
1430:   PetscFunctionBegin;
1432:   PetscAssertPointer(ksp, 2);
1433:   *ksp = tao->ksp;
1434:   PetscFunctionReturn(PETSC_SUCCESS);
1435: }

1437: /*@
1438:   TaoGetLinearSolveIterations - Gets the total number of linear iterations
1439:   used by the `Tao` solver

1441:   Not Collective

1443:   Input Parameter:
1444: . tao - the `Tao` context

1446:   Output Parameter:
1447: . lits - number of linear iterations

1449:   Level: intermediate

1451:   Note:
1452:   This counter is reset to zero for each successive call to `TaoSolve()`

1454: .seealso: [](ch_tao), `Tao`, `TaoGetKSP()`
1455: @*/
1456: PetscErrorCode TaoGetLinearSolveIterations(Tao tao, PetscInt *lits)
1457: {
1458:   PetscFunctionBegin;
1460:   PetscAssertPointer(lits, 2);
1461:   *lits = tao->ksp_tot_its;
1462:   PetscFunctionReturn(PETSC_SUCCESS);
1463: }

1465: /*@
1466:   TaoGetLineSearch - Gets the line search used by the optimization solver.

1468:   Not Collective

1470:   Input Parameter:
1471: . tao - the `Tao` solver

1473:   Output Parameter:
1474: . ls - the line search used in the optimization solver

1476:   Level: intermediate

1478: .seealso: [](ch_tao), `Tao`, `TaoLineSearch`, `TaoLineSearchType`
1479: @*/
1480: PetscErrorCode TaoGetLineSearch(Tao tao, TaoLineSearch *ls)
1481: {
1482:   PetscFunctionBegin;
1484:   PetscAssertPointer(ls, 2);
1485:   *ls = tao->linesearch;
1486:   PetscFunctionReturn(PETSC_SUCCESS);
1487: }

1489: /*@
1490:   TaoAddLineSearchCounts - Adds the number of function evaluations spent
1491:   in the line search to the running total.

1493:   Input Parameters:
1494: . tao - the `Tao` solver

1496:   Level: developer

1498: .seealso: [](ch_tao), `Tao`, `TaoGetLineSearch()`, `TaoLineSearchApply()`
1499: @*/
1500: PetscErrorCode TaoAddLineSearchCounts(Tao tao)
1501: {
1502:   PetscBool flg;
1503:   PetscInt  nfeval, ngeval, nfgeval;

1505:   PetscFunctionBegin;
1507:   if (tao->linesearch) {
1508:     PetscCall(TaoLineSearchIsUsingTaoRoutines(tao->linesearch, &flg));
1509:     if (!flg) {
1510:       PetscCall(TaoLineSearchGetNumberFunctionEvaluations(tao->linesearch, &nfeval, &ngeval, &nfgeval));
1511:       tao->objective_term.term->nobj += nfeval;
1512:       tao->objective_term.term->ngrad += ngeval;
1513:       tao->objective_term.term->nobjgrad += nfgeval;
1514:     }
1515:   }
1516:   PetscFunctionReturn(PETSC_SUCCESS);
1517: }

1519: /*@
1520:   TaoGetSolution - Returns the vector with the current solution from the `Tao` object

1522:   Not Collective

1524:   Input Parameter:
1525: . tao - the `Tao` context

1527:   Output Parameter:
1528: . X - the current solution

1530:   Level: intermediate

1532:   Note:
1533:   The returned vector will be the same object that was passed into `TaoSetSolution()`

1535: .seealso: [](ch_tao), `Tao`, `TaoSetSolution()`, `TaoSolve()`
1536: @*/
1537: PetscErrorCode TaoGetSolution(Tao tao, Vec *X)
1538: {
1539:   PetscFunctionBegin;
1541:   PetscAssertPointer(X, 2);
1542:   *X = tao->solution;
1543:   PetscFunctionReturn(PETSC_SUCCESS);
1544: }

1546: /*@
1547:   TaoResetStatistics - Initialize the statistics collected by the `Tao` object.
1548:   These statistics include the iteration number, residual norms, and convergence status.
1549:   This routine gets called before solving each optimization problem.

1551:   Collective

1553:   Input Parameter:
1554: . tao - the `Tao` context

1556:   Level: developer

1558:   Note:
1559:   This function does not reset the statistics of internal `TaoTerm`

1561: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
1562: @*/
1563: PetscErrorCode TaoResetStatistics(Tao tao)
1564: {
1565:   PetscFunctionBegin;
1567:   tao->niter        = 0;
1568:   tao->nres         = 0;
1569:   tao->njac         = 0;
1570:   tao->nconstraints = 0;
1571:   tao->ksp_its      = 0;
1572:   tao->ksp_tot_its  = 0;
1573:   tao->reason       = TAO_CONTINUE_ITERATING;
1574:   tao->residual     = 0.0;
1575:   tao->cnorm        = 0.0;
1576:   tao->step         = 0.0;
1577:   tao->lsflag       = PETSC_FALSE;
1578:   if (tao->hist_reset) tao->hist_len = 0;
1579:   PetscFunctionReturn(PETSC_SUCCESS);
1580: }

1582: /*@
1583:   TaoSetUpdate - Sets the general-purpose update function called
1584:   at the beginning of every iteration of the optimization algorithm. Called after the new solution and the gradient
1585:   is determined, but before the Hessian is computed (if applicable).

1587:   Logically Collective

1589:   Input Parameters:
1590: + tao  - The `Tao` solver
1591: . func - The function
1592: - ctx  - The update function context

1594:   Calling sequence of `func`:
1595: + tao - The optimizer context
1596: . it  - The current iteration index
1597: - ctx - The update context

1599:   Level: advanced

1601:   Notes:
1602:   Users can modify the gradient direction or any other vector associated to the specific solver used.
1603:   The objective function value is always recomputed after a call to the update hook.

1605: .seealso: [](ch_tao), `Tao`, `TaoSolve()`
1606: @*/
1607: PetscErrorCode TaoSetUpdate(Tao tao, PetscErrorCode (*func)(Tao tao, PetscInt it, PetscCtx ctx), PetscCtx ctx)
1608: {
1609:   PetscFunctionBegin;
1611:   tao->ops->update = func;
1612:   tao->user_update = ctx;
1613:   PetscFunctionReturn(PETSC_SUCCESS);
1614: }

1616: /*@
1617:   TaoSetConvergenceTest - Sets the function that is to be used to test
1618:   for convergence of the iterative minimization solution.  The new convergence
1619:   testing routine will replace Tao's default convergence test.

1621:   Logically Collective

1623:   Input Parameters:
1624: + tao  - the `Tao` object
1625: . conv - the routine to test for convergence
1626: - ctx  - [optional] context for private data for the convergence routine (may be `NULL`)

1628:   Calling sequence of `conv`:
1629: + tao - the `Tao` object
1630: - ctx - [optional] convergence context

1632:   Level: advanced

1634:   Note:
1635:   The new convergence testing routine should call `TaoSetConvergedReason()`.

1637: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergedReason()`, `TaoGetSolutionStatus()`, `TaoGetTolerances()`, `TaoMonitorSet()`
1638: @*/
1639: PetscErrorCode TaoSetConvergenceTest(Tao tao, PetscErrorCode (*conv)(Tao tao, PetscCtx ctx), PetscCtx ctx)
1640: {
1641:   PetscFunctionBegin;
1643:   tao->ops->convergencetest = conv;
1644:   tao->cnvP                 = ctx;
1645:   PetscFunctionReturn(PETSC_SUCCESS);
1646: }

1648: /*@
1649:   TaoMonitorSet - Sets an additional function that is to be used at every
1650:   iteration of the solver to display the iteration's
1651:   progress.

1653:   Logically Collective

1655:   Input Parameters:
1656: + tao  - the `Tao` solver context
1657: . func - monitoring routine
1658: . ctx  - [optional] user-defined context for private data for the monitor routine (may be `NULL`)
1659: - dest - [optional] function to destroy the context when the `Tao` is destroyed, see `PetscCtxDestroyFn` for the calling sequence

1661:   Calling sequence of `func`:
1662: + tao - the `Tao` solver context
1663: - ctx - [optional] monitoring context

1665:   Level: intermediate

1667:   Notes:
1668:   See `TaoSetFromOptions()` for a monitoring options.

1670:   Several different monitoring routines may be set by calling
1671:   `TaoMonitorSet()` multiple times; all will be called in the
1672:   order in which they were set.

1674:   Fortran Notes:
1675:   Only one monitor function may be set

1677: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoMonitorDefault()`, `TaoMonitorCancel()`, `TaoView()`, `PetscCtxDestroyFn`
1678: @*/
1679: PetscErrorCode TaoMonitorSet(Tao tao, PetscErrorCode (*func)(Tao tao, PetscCtx ctx), PetscCtx ctx, PetscCtxDestroyFn *dest)
1680: {
1681:   PetscFunctionBegin;
1683:   PetscCheck(tao->numbermonitors < MAXTAOMONITORS, PetscObjectComm((PetscObject)tao), PETSC_ERR_SUP, "Cannot attach another monitor -- max=%d", MAXTAOMONITORS);
1684:   for (PetscInt i = 0; i < tao->numbermonitors; i++) {
1685:     PetscBool identical;

1687:     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)func, ctx, dest, (PetscErrorCode (*)(void))(PetscVoidFn *)tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i], &identical));
1688:     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
1689:   }
1690:   tao->monitor[tao->numbermonitors]        = func;
1691:   tao->monitorcontext[tao->numbermonitors] = ctx;
1692:   tao->monitordestroy[tao->numbermonitors] = dest;
1693:   ++tao->numbermonitors;
1694:   PetscFunctionReturn(PETSC_SUCCESS);
1695: }

1697: /*@
1698:   TaoMonitorCancel - Clears all the monitor functions for a `Tao` object.

1700:   Logically Collective

1702:   Input Parameter:
1703: . tao - the `Tao` solver context

1705:   Options Database Key:
1706: . -tao_monitor_cancel - cancels all monitors that have been hardwired
1707:     into a code by calls to `TaoMonitorSet()`, but does not cancel those
1708:     set via the options database

1710:   Level: advanced

1712:   Note:
1713:   There is no way to clear one specific monitor from a `Tao` object.

1715: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1716: @*/
1717: PetscErrorCode TaoMonitorCancel(Tao tao)
1718: {
1719:   PetscFunctionBegin;
1721:   for (PetscInt i = 0; i < tao->numbermonitors; i++) {
1722:     if (tao->monitordestroy[i]) PetscCall((*tao->monitordestroy[i])(&tao->monitorcontext[i]));
1723:   }
1724:   tao->numbermonitors = 0;
1725:   PetscFunctionReturn(PETSC_SUCCESS);
1726: }

1728: /*@
1729:   TaoMonitorDefault - Default routine for monitoring progress of `TaoSolve()`

1731:   Collective

1733:   Input Parameters:
1734: + tao - the `Tao` context
1735: - vf  - `PetscViewerAndFormat` context

1737:   Options Database Keys:
1738: + -tao_monitor [ascii][:filename] - monitor function and residual norms at each iteration, only ASCII viewers supported
1739: - -tao_monitor_interval interval  - only monitor function and residual norms every `interval` iterations, and the last iteration

1741:   Level: advanced

1743:   Note:
1744:   This monitor prints the function value and gradient
1745:   norm at each iteration.

1747: .seealso: [](ch_tao), `Tao`, `TaoMonitorGlobalization()`, `TaoMonitorSet()`
1748: @*/
1749: PetscErrorCode TaoMonitorDefault(Tao tao, PetscViewerAndFormat *vf)
1750: {
1751:   PetscViewer viewer = vf->viewer;
1752:   PetscBool   isascii;
1753:   PetscInt    tabs;

1755:   PetscFunctionBegin;
1757:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);

1759:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1760:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1761:   if (isascii) {
1762:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));

1764:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1765:     if (tao->niter == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
1766:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
1767:       tao->header_printed = PETSC_TRUE;
1768:     }
1769:     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", tao->niter));
1770:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)tao->fc));
1771:     if (tao->residual >= PETSC_INFINITY) {
1772:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: infinity \n"));
1773:     } else {
1774:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g \n", (double)tao->residual));
1775:     }
1776:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1777:   }
1778:   PetscCall(PetscViewerPopFormat(viewer));
1779:   PetscFunctionReturn(PETSC_SUCCESS);
1780: }

1782: /*@
1783:   TaoMonitorGlobalization - Default routine for monitoring progress of `TaoSolve()` with extra detail on the globalization method.

1785:   Collective

1787:   Input Parameters:
1788: + tao - the `Tao` context
1789: - vf  - `PetscViewerAndFormat` context

1791:   Options Database Keys:
1792: + -tao_monitor_globalization [ascii][:filename] - monitor globalization information at each iteration, only ASCII viewers are supported
1793: - -tao_monitor_globalization_interval interval  - only monitor globalization information every `interval` iterations, and the last iteration

1795:   Level: advanced

1797:   Note:
1798:   This monitor prints the function value and gradient norm at each
1799:   iteration, as well as the step size and trust radius. Note that the
1800:   step size and trust radius may be the same for some algorithms.

1802: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1803: @*/
1804: PetscErrorCode TaoMonitorGlobalization(Tao tao, PetscViewerAndFormat *vf)
1805: {
1806:   PetscViewer viewer = vf->viewer;
1807:   PetscBool   isascii;
1808:   PetscInt    tabs;

1810:   PetscFunctionBegin;
1812:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);

1814:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1815:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1816:   if (isascii) {
1817:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
1818:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1819:     if (tao->niter == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
1820:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
1821:       tao->header_printed = PETSC_TRUE;
1822:     }
1823:     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", tao->niter));
1824:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)tao->fc));
1825:     if (tao->residual >= PETSC_INFINITY) {
1826:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: Inf,"));
1827:     } else {
1828:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g,", (double)tao->residual));
1829:     }
1830:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Step: %g,  Trust: %g\n", (double)tao->step, (double)tao->trust));
1831:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1832:   }
1833:   PetscCall(PetscViewerPopFormat(viewer));
1834:   PetscFunctionReturn(PETSC_SUCCESS);
1835: }

1837: /*@
1838:   TaoMonitorConstraintNorm - same as `TaoMonitorDefault()` except
1839:   it prints the norm of the constraint function.

1841:   Collective

1843:   Input Parameters:
1844: + tao - the `Tao` context
1845: - vf  - `PetscViewerAndFormat` context

1847:   Options Database Keys:
1848: + -tao_monitor_constraint_norm [ascii][:filename] - monitor the constraints at each iteration, only ASCII viewers are supported
1849: - -tao_monitor_constraint_norm_interval interval  - only monitor the constraints every `interval` iterations, and the last iteration

1851:   Level: advanced

1853: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1854: @*/
1855: PetscErrorCode TaoMonitorConstraintNorm(Tao tao, PetscViewerAndFormat *vf)
1856: {
1857:   PetscViewer viewer = vf->viewer;
1858:   PetscBool   isascii;
1859:   PetscInt    tabs;

1861:   PetscFunctionBegin;
1863:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);

1865:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1866:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1867:   if (isascii) {
1868:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
1869:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1870:     PetscCall(PetscViewerASCIIPrintf(viewer, "iter = %" PetscInt_FMT ",", tao->niter));
1871:     PetscCall(PetscViewerASCIIPrintf(viewer, " Function value: %g,", (double)tao->fc));
1872:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g ", (double)tao->residual));
1873:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Constraint: %g \n", (double)tao->cnorm));
1874:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1875:   }
1876:   PetscCall(PetscViewerPopFormat(viewer));
1877:   PetscFunctionReturn(PETSC_SUCCESS);
1878: }

1880: /*@
1881:   TaoMonitorSolution - Views the solution at each iteration of `TaoSolve()`

1883:   Collective

1885:   Input Parameters:
1886: + tao - the `Tao` context
1887: - vf  - `PetscViewerAndFormat` context

1889:   Options Database Keys:
1890: + -tao_monitor_solution viewer_specification - view the solution vector at each iteration, see `PetscOptionsCreateViewer()` for `viewer_specification` details
1891: - -tao_monitor_solution_interval interval    - only view the solution every `interval` iterations, and the last iteration

1893:   Level: advanced

1895: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1896: @*/
1897: PetscErrorCode TaoMonitorSolution(Tao tao, PetscViewerAndFormat *vf)
1898: {
1899:   PetscFunctionBegin;
1901:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);
1902:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1903:   PetscCall(VecView(tao->solution, vf->viewer));
1904:   PetscCall(PetscViewerPopFormat(vf->viewer));
1905:   PetscFunctionReturn(PETSC_SUCCESS);
1906: }

1908: /*@
1909:   TaoMonitorGradient - Views the gradient at each iteration of `TaoSolve()`

1911:   Collective

1913:   Input Parameters:
1914: + tao - the `Tao` context
1915: - vf  - `PetscViewerAndFormat` context

1917:   Options Database Keys:
1918: + -tao_monitor_gradient viewer_specification - view the gradient at each iteration, see `PetscOptionsCreateViewer()` for `viewer_specification` details
1919: - -tao_monitor_gradient_interval interval    - only view the gradient every `interval` iterations, and the last iteration

1921:   Level: advanced

1923: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1924: @*/
1925: PetscErrorCode TaoMonitorGradient(Tao tao, PetscViewerAndFormat *vf)
1926: {
1927:   PetscFunctionBegin;
1929:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);
1930:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1931:   PetscCall(VecView(tao->gradient, vf->viewer));
1932:   PetscCall(PetscViewerPopFormat(vf->viewer));
1933:   PetscFunctionReturn(PETSC_SUCCESS);
1934: }

1936: /*@
1937:   TaoMonitorStep - Views the step-direction at each iteration of `TaoSolve()`

1939:   Collective

1941:   Input Parameters:
1942: + tao - the `Tao` context
1943: - vf  - `PetscViewerAndFormat` context

1945:   Options Database Keys:
1946: + -tao_monitor_step viewer_specification - view the step vector at each iteration, see `PetscOptionsCreateViewer()` for `viewer_specification` details
1947: - -tao_monitor_step_interval interval    - only view the step vector every `interval` iterations, and the last iteration

1949:   Level: advanced

1951: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1952: @*/
1953: PetscErrorCode TaoMonitorStep(Tao tao, PetscViewerAndFormat *vf)
1954: {
1955:   PetscFunctionBegin;
1957:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);
1958:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1959:   PetscCall(VecView(tao->stepdirection, vf->viewer));
1960:   PetscCall(PetscViewerPopFormat(vf->viewer));
1961:   PetscFunctionReturn(PETSC_SUCCESS);
1962: }

1964: /*@
1965:   TaoMonitorSolutionDraw - Plots the solution at each iteration of `TaoSolve()`

1967:   Collective

1969:   Input Parameters:
1970: + tao - the `Tao` context
1971: - ctx - `TaoMonitorDrawCtx` context

1973:   Options Database Keys:
1974: + -tao_monitor_solution_draw (true|false)      - draw the solution at each iteration
1975: - -tao_monitor_solution_draw_interval interval - only draw the solution every `interval` iterations and final value, or only final value if negative

1977:   Level: advanced

1979:   Note:
1980:   The context created by `TaoMonitorDrawCtxCreate()`, along with `TaoMonitorSolutionDraw()`, and `TaoMonitorDrawCtxDestroy()`
1981:   are passed to `TaoMonitorSet()` to monitor the solution graphically.

1983: .seealso: [](ch_tao), `Tao`, `TaoMonitorSolution()`, `TaoMonitorSet()`, `TaoMonitorGradientDraw()`, `TaoMonitorDrawCtxCreate()`,
1984:           `TaoMonitorDrawCtxDestroy()`
1985: @*/
1986: PetscErrorCode TaoMonitorSolutionDraw(Tao tao, PetscCtx ctx)
1987: {
1988:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

1990:   PetscFunctionBegin;
1992:   if (!((ictx->howoften > 0 && !((tao->niter % ictx->howoften) && !tao->reason)) || (ictx->howoften < 0 && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
1993:   PetscCall(VecView(tao->solution, ictx->viewer));
1994:   PetscFunctionReturn(PETSC_SUCCESS);
1995: }

1997: /*@
1998:   TaoMonitorGradientDraw - Plots the gradient at each iteration of `TaoSolve()`

2000:   Collective

2002:   Input Parameters:
2003: + tao - the `Tao` context
2004: - ctx - `TaoMonitorDrawCtx` context

2006:   Options Database Keys:
2007: + -tao_monitor_gradient_draw (true|false)      - draw the gradient at each iteration
2008: - -tao_monitor_gradient_draw_interval interval - only draw the gradient every `interval` iterations and final value, or only final value if negative

2010:   Level: advanced

2012: .seealso: [](ch_tao), `Tao`, `TaoMonitorGradient()`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw()`
2013: @*/
2014: PetscErrorCode TaoMonitorGradientDraw(Tao tao, PetscCtx ctx)
2015: {
2016:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

2018:   PetscFunctionBegin;
2020:   if (!((ictx->howoften > 0 && !((tao->niter % ictx->howoften) && !tao->reason)) || (ictx->howoften < 0 && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
2021:   PetscCall(VecView(tao->gradient, ictx->viewer));
2022:   PetscFunctionReturn(PETSC_SUCCESS);
2023: }

2025: /*@
2026:   TaoMonitorStepDraw - Plots the step direction at each iteration of `TaoSolve()`

2028:   Collective

2030:   Input Parameters:
2031: + tao - the `Tao` context
2032: - ctx - the `TaoMonitorDrawCtx` context

2034:   Options Database Keys:
2035: + -tao_monitor_step_draw (true|false)      - draw the step direction at each iteration
2036: - -tao_monitor_step_draw_interval interval - only draw the step direction every `interval` iterations and final value, or only final value if negative

2038:   Level: advanced

2040: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw`
2041: @*/
2042: PetscErrorCode TaoMonitorStepDraw(Tao tao, PetscCtx ctx)
2043: {
2044:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

2046:   PetscFunctionBegin;
2048:   if (!((ictx->howoften > 0 && !((tao->niter % ictx->howoften) && !tao->reason)) || (ictx->howoften < 0 && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
2049:   PetscCall(VecView(tao->stepdirection, ictx->viewer));
2050:   PetscFunctionReturn(PETSC_SUCCESS);
2051: }

2053: /*@
2054:   TaoMonitorResidual - Views the least-squares residual at each iteration of `TaoSolve()`

2056:   Collective

2058:   Input Parameters:
2059: + tao - the `Tao` context
2060: - vf  - `PetscViewerAndFormat` context

2062:   Options Database Keys:
2063: + -tao_monitor_residual viewer_specification - view the least-squares residual at each iteration, see `PetscOptionsCreateViewer()` for `viewer_specification` details
2064: - -tao_monitor_residual_interval interval    - only monitor the residual every `interval` iterations and final value, or only final value if negative

2066:   Level: advanced

2068: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
2069: @*/
2070: PetscErrorCode TaoMonitorResidual(Tao tao, PetscViewerAndFormat *vf)
2071: {
2072:   PetscFunctionBegin;
2074:   if (vf->view_interval > 0 && tao->niter % vf->view_interval && !tao->reason) PetscFunctionReturn(PETSC_SUCCESS);
2075:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
2076:   PetscCall(VecView(tao->ls_res, vf->viewer));
2077:   PetscCall(PetscViewerPopFormat(vf->viewer));
2078:   PetscFunctionReturn(PETSC_SUCCESS);
2079: }

2081: /*@
2082:   TaoDefaultConvergenceTest - Determines whether the solver should continue iterating
2083:   or terminate.

2085:   Collective

2087:   Input Parameters:
2088: + tao   - the `Tao` context
2089: - dummy - unused dummy context

2091:   Level: developer

2093:   Notes:
2094:   This routine checks the residual in the optimality conditions, the
2095:   relative residual in the optimity conditions, the number of function
2096:   evaluations, and the function value to test convergence.  Some
2097:   solvers may use different convergence routines.

2099: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoGetConvergedReason()`, `TaoSetConvergedReason()`
2100: @*/
2101: PetscErrorCode TaoDefaultConvergenceTest(Tao tao, void *dummy)
2102: {
2103:   PetscInt           niter     = tao->niter, nfuncs;
2104:   PetscInt           max_funcs = tao->max_funcs;
2105:   PetscReal          gnorm = tao->residual, gnorm0 = tao->gnorm0;
2106:   PetscReal          f = tao->fc, steptol = tao->steptol, trradius = tao->step;
2107:   PetscReal          gatol = tao->gatol, grtol = tao->grtol, gttol = tao->gttol;
2108:   PetscReal          catol = tao->catol, crtol = tao->crtol;
2109:   PetscReal          fmin = tao->fmin, cnorm = tao->cnorm;
2110:   TaoConvergedReason reason = tao->reason;

2112:   PetscFunctionBegin;
2114:   if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);

2116:   PetscCall(TaoGetCurrentFunctionEvaluations(tao, &nfuncs));
2117:   if (PetscIsInfOrNanReal(f)) {
2118:     PetscCall(PetscInfo(tao, "Failed to converged, function value is infinity or NaN\n"));
2119:     reason = TAO_DIVERGED_NAN;
2120:   } else if (f <= fmin && cnorm <= catol) {
2121:     PetscCall(PetscInfo(tao, "Converged due to function value %g < minimum function value %g\n", (double)f, (double)fmin));
2122:     reason = TAO_CONVERGED_MINF;
2123:   } else if (gnorm <= gatol && cnorm <= catol) {
2124:     PetscCall(PetscInfo(tao, "Converged due to residual norm ||g(X)||=%g < %g\n", (double)gnorm, (double)gatol));
2125:     reason = TAO_CONVERGED_GATOL;
2126:   } else if (f != 0 && PetscAbsReal(gnorm / f) <= grtol && cnorm <= crtol) {
2127:     PetscCall(PetscInfo(tao, "Converged due to residual ||g(X)||/|f(X)| =%g < %g\n", (double)(gnorm / f), (double)grtol));
2128:     reason = TAO_CONVERGED_GRTOL;
2129:   } else if (gnorm0 != 0 && ((gttol == 0 && gnorm == 0) || gnorm / gnorm0 < gttol) && cnorm <= crtol) {
2130:     PetscCall(PetscInfo(tao, "Converged due to relative residual norm ||g(X)||/||g(X0)|| = %g < %g\n", (double)(gnorm / gnorm0), (double)gttol));
2131:     reason = TAO_CONVERGED_GTTOL;
2132:   } else if (max_funcs != PETSC_UNLIMITED && nfuncs > max_funcs) {
2133:     PetscCall(PetscInfo(tao, "Exceeded maximum number of function evaluations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", nfuncs, max_funcs));
2134:     reason = TAO_DIVERGED_MAXFCN;
2135:   } else if (tao->lsflag != 0) {
2136:     PetscCall(PetscInfo(tao, "Tao Line Search failure.\n"));
2137:     reason = TAO_DIVERGED_LS_FAILURE;
2138:   } else if (trradius < steptol && niter > 0) {
2139:     PetscCall(PetscInfo(tao, "Trust region/step size too small: %g < %g\n", (double)trradius, (double)steptol));
2140:     reason = TAO_CONVERGED_STEPTOL;
2141:   } else if (niter >= tao->max_it) {
2142:     PetscCall(PetscInfo(tao, "Exceeded maximum number of iterations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", niter, tao->max_it));
2143:     reason = TAO_DIVERGED_MAXITS;
2144:   } else {
2145:     reason = TAO_CONTINUE_ITERATING;
2146:   }
2147:   tao->reason = reason;
2148:   PetscFunctionReturn(PETSC_SUCCESS);
2149: }

2151: /*@
2152:   TaoSetOptionsPrefix - Sets the prefix used for searching for all
2153:   Tao options in the database.

2155:   Logically Collective

2157:   Input Parameters:
2158: + tao - the `Tao` context
2159: - p   - the prefix string to prepend to all Tao option requests

2161:   Level: advanced

2163:   Notes:
2164:   A hyphen (-) must NOT be given at the beginning of the prefix name.
2165:   The first character of all runtime options is AUTOMATICALLY the hyphen.

2167:   For example, to distinguish between the runtime options for two
2168:   different Tao solvers, one could call
2169: .vb
2170:       TaoSetOptionsPrefix(tao1,"sys1_")
2171:       TaoSetOptionsPrefix(tao2,"sys2_")
2172: .ve

2174:   This would enable use of different options for each system, such as
2175: .vb
2176:       -sys1_tao_method blmvm -sys1_tao_grtol 1.e-3
2177:       -sys2_tao_method lmvm  -sys2_tao_grtol 1.e-4
2178: .ve

2180: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoAppendOptionsPrefix()`, `TaoGetOptionsPrefix()`
2181: @*/
2182: PetscErrorCode TaoSetOptionsPrefix(Tao tao, const char p[])
2183: {
2184:   PetscFunctionBegin;
2186:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao, p));
2187:   if (tao->linesearch) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, p));
2188:   if (tao->ksp) PetscCall(KSPSetOptionsPrefix(tao->ksp, p));
2189:   if (tao->callbacks) {
2190:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, p));
2191:     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
2192:   }
2193:   PetscFunctionReturn(PETSC_SUCCESS);
2194: }

2196: /*@
2197:   TaoAppendOptionsPrefix - Appends to the prefix used for searching for all Tao options in the database.

2199:   Logically Collective

2201:   Input Parameters:
2202: + tao - the `Tao` solver context
2203: - p   - the prefix string to prepend to all `Tao` option requests

2205:   Level: advanced

2207:   Note:
2208:   A hyphen (-) must NOT be given at the beginning of the prefix name.
2209:   The first character of all runtime options is automatically the hyphen.

2211: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoGetOptionsPrefix()`
2212: @*/
2213: PetscErrorCode TaoAppendOptionsPrefix(Tao tao, const char p[])
2214: {
2215:   PetscFunctionBegin;
2217:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao, p));
2218:   if (tao->linesearch) PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->linesearch, p));
2219:   if (tao->ksp) PetscCall(KSPAppendOptionsPrefix(tao->ksp, p));
2220:   if (tao->callbacks) {
2221:     const char *prefix;

2223:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao, &prefix));
2224:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, prefix));
2225:     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
2226:   }
2227:   PetscFunctionReturn(PETSC_SUCCESS);
2228: }

2230: /*@
2231:   TaoGetOptionsPrefix - Gets the prefix used for searching for all
2232:   Tao options in the database

2234:   Not Collective

2236:   Input Parameter:
2237: . tao - the `Tao` context

2239:   Output Parameter:
2240: . p - pointer to the prefix string used is returned

2242:   Level: advanced

2244: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoAppendOptionsPrefix()`
2245: @*/
2246: PetscErrorCode TaoGetOptionsPrefix(Tao tao, const char *p[])
2247: {
2248:   PetscFunctionBegin;
2250:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao, p));
2251:   PetscFunctionReturn(PETSC_SUCCESS);
2252: }

2254: /*@
2255:   TaoSetType - Sets the `TaoType` for the minimization solver.

2257:   Collective

2259:   Input Parameters:
2260: + tao  - the `Tao` solver context
2261: - type - a known method

2263:   Options Database Key:
2264: . -tao_type type - Sets the method; see `TaoType`

2266:   Level: intermediate

2268:   Note:
2269:   Calling this function resets the convergence test to `TaoDefaultConvergenceTest()`.
2270:   If a custom convergence test has been set with `TaoSetConvergenceTest()`, it must
2271:   be set again after calling `TaoSetType()`.

2273: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoGetType()`, `TaoType`
2274: @*/
2275: PetscErrorCode TaoSetType(Tao tao, TaoType type)
2276: {
2277:   PetscErrorCode (*create_xxx)(Tao);
2278:   PetscBool issame;

2280:   PetscFunctionBegin;

2283:   PetscCall(PetscObjectTypeCompare((PetscObject)tao, type, &issame));
2284:   if (issame) PetscFunctionReturn(PETSC_SUCCESS);

2286:   PetscCall(PetscFunctionListFind(TaoList, type, &create_xxx));
2287:   PetscCheck(create_xxx, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested Tao type %s", type);

2289:   /* Destroy the existing solver information */
2290:   PetscTryTypeMethod(tao, destroy);
2291:   PetscCall(KSPDestroy(&tao->ksp));
2292:   PetscCall(TaoLineSearchDestroy(&tao->linesearch));

2294:   /* Reinitialize type-specific function pointers in TaoOps structure */
2295:   tao->ops->setup           = NULL;
2296:   tao->ops->computedual     = NULL;
2297:   tao->ops->solve           = NULL;
2298:   tao->ops->view            = NULL;
2299:   tao->ops->setfromoptions  = NULL;
2300:   tao->ops->destroy         = NULL;
2301:   tao->ops->convergencetest = TaoDefaultConvergenceTest;

2303:   tao->setupcalled           = PETSC_FALSE;
2304:   tao->uses_gradient         = PETSC_FALSE;
2305:   tao->uses_hessian_matrices = PETSC_FALSE;

2307:   PetscCall(TaoParametersInitialize(tao));

2309:   PetscCall((*create_xxx)(tao));
2310:   PetscCall(PetscObjectChangeTypeName((PetscObject)tao, type));
2311:   PetscFunctionReturn(PETSC_SUCCESS);
2312: }

2314: /*@
2315:   TaoRegister - Adds a method to the Tao package for minimization.

2317:   Not Collective, No Fortran Support

2319:   Input Parameters:
2320: + sname - name of a new user-defined solver
2321: - func  - routine to create `TaoType` specific method context

2323:   Calling sequence of `func`:
2324: . tao - the `Tao` object to be created

2326:   Example Usage:
2327: .vb
2328:    TaoRegister("my_solver", MySolverCreate);
2329: .ve

2331:   Then, your solver can be chosen with the procedural interface via
2332: .vb
2333:   TaoSetType(tao, "my_solver")
2334: .ve
2335:   or at runtime via the option
2336: .vb
2337:   -tao_type my_solver
2338: .ve

2340:   Level: advanced

2342:   Note:
2343:   `TaoRegister()` may be called multiple times to add several user-defined solvers.

2345: .seealso: [](ch_tao), `Tao`, `TaoSetType()`, `TaoRegisterAll()`, `TaoRegisterDestroy()`
2346: @*/
2347: PetscErrorCode TaoRegister(const char sname[], PetscErrorCode (*func)(Tao tao))
2348: {
2349:   PetscFunctionBegin;
2350:   PetscCall(TaoInitializePackage());
2351:   PetscCall(PetscFunctionListAdd(&TaoList, sname, func));
2352:   PetscFunctionReturn(PETSC_SUCCESS);
2353: }

2355: /*@
2356:   TaoRegisterDestroy - Frees the list of minimization solvers that were
2357:   registered by `TaoRegister()`.

2359:   Not Collective

2361:   Level: advanced

2363: .seealso: [](ch_tao), `Tao`, `TaoRegisterAll()`, `TaoRegister()`
2364: @*/
2365: PetscErrorCode TaoRegisterDestroy(void)
2366: {
2367:   PetscFunctionBegin;
2368:   PetscCall(PetscFunctionListDestroy(&TaoList));
2369:   TaoRegisterAllCalled = PETSC_FALSE;
2370:   PetscFunctionReturn(PETSC_SUCCESS);
2371: }

2373: /*@
2374:   TaoGetIterationNumber - Gets the number of `TaoSolve()` iterations completed
2375:   at this time.

2377:   Not Collective

2379:   Input Parameter:
2380: . tao - the `Tao` context

2382:   Output Parameter:
2383: . iter - iteration number

2385:   Notes:
2386:   For example, during the computation of iteration 2 this would return 1.

2388:   Level: intermediate

2390: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetResidualNorm()`, `TaoGetObjective()`
2391: @*/
2392: PetscErrorCode TaoGetIterationNumber(Tao tao, PetscInt *iter)
2393: {
2394:   PetscFunctionBegin;
2396:   PetscAssertPointer(iter, 2);
2397:   *iter = tao->niter;
2398:   PetscFunctionReturn(PETSC_SUCCESS);
2399: }

2401: /*@
2402:   TaoGetResidualNorm - Gets the current value of the norm of the residual (gradient)
2403:   at this time.

2405:   Not Collective

2407:   Input Parameter:
2408: . tao - the `Tao` context

2410:   Output Parameter:
2411: . value - the current value

2413:   Level: intermediate

2415:   Developer Notes:
2416:   This is the 2-norm of the residual, we cannot use `TaoGetGradientNorm()` because that has
2417:   a different meaning. For some reason `Tao` sometimes calls the gradient the residual.

2419: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetIterationNumber()`, `TaoGetObjective()`
2420: @*/
2421: PetscErrorCode TaoGetResidualNorm(Tao tao, PetscReal *value)
2422: {
2423:   PetscFunctionBegin;
2425:   PetscAssertPointer(value, 2);
2426:   *value = tao->residual;
2427:   PetscFunctionReturn(PETSC_SUCCESS);
2428: }

2430: /*@
2431:   TaoSetIterationNumber - Sets the current iteration number.

2433:   Logically Collective

2435:   Input Parameters:
2436: + tao  - the `Tao` context
2437: - iter - iteration number

2439:   Level: developer

2441: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2442: @*/
2443: PetscErrorCode TaoSetIterationNumber(Tao tao, PetscInt iter)
2444: {
2445:   PetscFunctionBegin;
2448:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
2449:   tao->niter = iter;
2450:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
2451:   PetscFunctionReturn(PETSC_SUCCESS);
2452: }

2454: /*@
2455:   TaoGetTotalIterationNumber - Gets the total number of `TaoSolve()` iterations
2456:   completed. This number keeps accumulating if multiple solves
2457:   are called with the `Tao` object.

2459:   Not Collective

2461:   Input Parameter:
2462: . tao - the `Tao` context

2464:   Output Parameter:
2465: . iter - number of iterations

2467:   Level: intermediate

2469:   Note:
2470:   The total iteration count is updated after each solve, if there is a current
2471:   `TaoSolve()` in progress then those iterations are not included in the count

2473: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2474: @*/
2475: PetscErrorCode TaoGetTotalIterationNumber(Tao tao, PetscInt *iter)
2476: {
2477:   PetscFunctionBegin;
2479:   PetscAssertPointer(iter, 2);
2480:   *iter = tao->ntotalits;
2481:   PetscFunctionReturn(PETSC_SUCCESS);
2482: }

2484: /*@
2485:   TaoSetTotalIterationNumber - Sets the current total iteration number.

2487:   Logically Collective

2489:   Input Parameters:
2490: + tao  - the `Tao` context
2491: - iter - the iteration number

2493:   Level: developer

2495: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2496: @*/
2497: PetscErrorCode TaoSetTotalIterationNumber(Tao tao, PetscInt iter)
2498: {
2499:   PetscFunctionBegin;
2502:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
2503:   tao->ntotalits = iter;
2504:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
2505:   PetscFunctionReturn(PETSC_SUCCESS);
2506: }

2508: /*@
2509:   TaoSetConvergedReason - Sets the termination flag on a `Tao` object

2511:   Logically Collective

2513:   Input Parameters:
2514: + tao    - the `Tao` context
2515: - reason - the `TaoConvergedReason`

2517:   Level: intermediate

2519: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`
2520: @*/
2521: PetscErrorCode TaoSetConvergedReason(Tao tao, TaoConvergedReason reason)
2522: {
2523:   PetscFunctionBegin;
2526:   tao->reason = reason;
2527:   PetscFunctionReturn(PETSC_SUCCESS);
2528: }

2530: /*@
2531:   TaoGetConvergedReason - Gets the reason the `TaoSolve()` was stopped.

2533:   Not Collective

2535:   Input Parameter:
2536: . tao - the `Tao` solver context

2538:   Output Parameter:
2539: . reason - value of `TaoConvergedReason`

2541:   Level: intermediate

2543: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetConvergenceTest()`, `TaoSetTolerances()`, `TaoGetConvergedReasonString()`
2544: @*/
2545: PetscErrorCode TaoGetConvergedReason(Tao tao, TaoConvergedReason *reason)
2546: {
2547:   PetscFunctionBegin;
2549:   PetscAssertPointer(reason, 2);
2550:   *reason = tao->reason;
2551:   PetscFunctionReturn(PETSC_SUCCESS);
2552: }

2554: /*@
2555:   TaoGetConvergedReasonString - Return a human readable string for a `TaoConvergedReason`

2557:   Not Collective

2559:   Input Parameter:
2560: . tao - the `Tao` solver context

2562:   Output Parameter:
2563: . strreason - a human readable string that describes the `Tao` converged reason

2565:   Level: beginner

2567: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetConvergedReason()`
2568: @*/
2569: PetscErrorCode TaoGetConvergedReasonString(Tao tao, const char *strreason[])
2570: {
2571:   PetscFunctionBegin;
2573:   PetscAssertPointer(strreason, 2);
2574:   *strreason = TaoConvergedReasons[tao->reason];
2575:   PetscFunctionReturn(PETSC_SUCCESS);
2576: }

2578: /*@
2579:   TaoGetSolutionStatus - Get the current iterate, objective value,
2580:   residual, infeasibility, and termination from a `Tao` object

2582:   Not Collective

2584:   Input Parameter:
2585: . tao - the `Tao` context

2587:   Output Parameters:
2588: + its    - the current iterate number (>=0)
2589: . f      - the current function value
2590: . gnorm  - the square of the gradient norm, duality gap, or other measure indicating distance from optimality.
2591: . cnorm  - the infeasibility of the current solution with regard to the constraints.
2592: . xdiff  - the step length or trust region radius of the most recent iterate.
2593: - reason - The termination reason, which can equal `TAO_CONTINUE_ITERATING`

2595:   Level: intermediate

2597:   Notes:
2598:   Tao returns the values set by the solvers in the routine `TaoMonitor()`.

2600:   If any of the output arguments are set to `NULL`, no corresponding value will be returned.

2602: .seealso: [](ch_tao), `TaoMonitor()`, `TaoGetConvergedReason()`
2603: @*/
2604: PetscErrorCode TaoGetSolutionStatus(Tao tao, PetscInt *its, PetscReal *f, PetscReal *gnorm, PetscReal *cnorm, PetscReal *xdiff, TaoConvergedReason *reason)
2605: {
2606:   PetscFunctionBegin;
2608:   if (its) *its = tao->niter;
2609:   if (f) *f = tao->fc;
2610:   if (gnorm) *gnorm = tao->residual;
2611:   if (cnorm) *cnorm = tao->cnorm;
2612:   if (reason) *reason = tao->reason;
2613:   if (xdiff) *xdiff = tao->step;
2614:   PetscFunctionReturn(PETSC_SUCCESS);
2615: }

2617: /*@
2618:   TaoGetType - Gets the current `TaoType` being used in the `Tao` object

2620:   Not Collective

2622:   Input Parameter:
2623: . tao - the `Tao` solver context

2625:   Output Parameter:
2626: . type - the `TaoType`

2628:   Level: intermediate

2630:   Note:
2631:   `type` should not be retained for later use as it will be an invalid pointer if the `TaoType` of `tao` is changed.

2633: .seealso: [](ch_tao), `Tao`, `TaoType`, `TaoSetType()`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`
2634: @*/
2635: PetscErrorCode TaoGetType(Tao tao, TaoType *type)
2636: {
2637:   PetscFunctionBegin;
2639:   PetscAssertPointer(type, 2);
2640:   *type = ((PetscObject)tao)->type_name;
2641:   PetscFunctionReturn(PETSC_SUCCESS);
2642: }

2644: /*@
2645:   TaoMonitor - Monitor the solver and the current solution.  This
2646:   routine will record the iteration number and residual statistics,
2647:   and call any monitors specified by the user.

2649:   Input Parameters:
2650: + tao        - the `Tao` context
2651: . its        - the current iterate number (>=0)
2652: . f          - the current objective function value
2653: . res        - the gradient norm, square root of the duality gap, or other measure indicating distance from optimality.  This measure will be recorded and
2654:           used for some termination tests.
2655: . cnorm      - the infeasibility of the current solution with regard to the constraints.
2656: - steplength - multiple of the step direction added to the previous iterate.

2658:   Options Database Key:
2659: . -tao_monitor - Use the default monitor, which prints statistics to standard output

2661:   Level: developer

2663: .seealso: [](ch_tao), `Tao`, `TaoGetConvergedReason()`, `TaoMonitorDefault()`, `TaoMonitorSet()`
2664: @*/
2665: PetscErrorCode TaoMonitor(Tao tao, PetscInt its, PetscReal f, PetscReal res, PetscReal cnorm, PetscReal steplength)
2666: {
2667:   PetscFunctionBegin;
2669:   tao->fc       = f;
2670:   tao->residual = res;
2671:   tao->cnorm    = cnorm;
2672:   tao->step     = steplength;
2673:   if (!its) {
2674:     tao->cnorm0 = cnorm;
2675:     tao->gnorm0 = res;
2676:   }
2677:   PetscCall(VecLockReadPush(tao->solution));
2678:   for (PetscInt i = 0; i < tao->numbermonitors; i++) PetscCall((*tao->monitor[i])(tao, tao->monitorcontext[i]));
2679:   PetscCall(VecLockReadPop(tao->solution));
2680:   PetscFunctionReturn(PETSC_SUCCESS);
2681: }

2683: /*@
2684:   TaoSetConvergenceHistory - Sets the array used to hold the convergence history.

2686:   Logically Collective

2688:   Input Parameters:
2689: + tao   - the `Tao` solver context
2690: . obj   - array to hold objective value history
2691: . resid - array to hold residual history
2692: . cnorm - array to hold constraint violation history
2693: . lits  - integer array holds the number of linear iterations for each Tao iteration
2694: . na    - size of `obj`, `resid`, and `cnorm`
2695: - reset - `PETSC_TRUE` indicates each new minimization resets the history counter to zero,
2696:            else it continues storing new values for new minimizations after the old ones

2698:   Level: intermediate

2700:   Notes:
2701:   If set, `Tao` will fill the given arrays with the indicated
2702:   information at each iteration.  If 'obj','resid','cnorm','lits' are
2703:   *all* `NULL` then space (using size `na`, or 1000 if `na` is `PETSC_DECIDE`) is allocated for the history.
2704:   If not all are `NULL`, then only the non-`NULL` information categories
2705:   will be stored, the others will be ignored.

2707:   Any convergence information after iteration number 'na' will not be stored.

2709:   This routine is useful, e.g., when running a code for purposes
2710:   of accurate performance monitoring, when no I/O should be done
2711:   during the section of code that is being timed.

2713: .seealso: [](ch_tao), `TaoGetConvergenceHistory()`
2714: @*/
2715: PetscErrorCode TaoSetConvergenceHistory(Tao tao, PetscReal obj[], PetscReal resid[], PetscReal cnorm[], PetscInt lits[], PetscInt na, PetscBool reset)
2716: {
2717:   PetscFunctionBegin;
2719:   if (obj) PetscAssertPointer(obj, 2);
2720:   if (resid) PetscAssertPointer(resid, 3);
2721:   if (cnorm) PetscAssertPointer(cnorm, 4);
2722:   if (lits) PetscAssertPointer(lits, 5);

2724:   if (na == PETSC_DECIDE || na == PETSC_CURRENT) na = 1000;
2725:   if (!obj && !resid && !cnorm && !lits) {
2726:     PetscCall(PetscCalloc4(na, &obj, na, &resid, na, &cnorm, na, &lits));
2727:     tao->hist_malloc = PETSC_TRUE;
2728:   }

2730:   tao->hist_obj   = obj;
2731:   tao->hist_resid = resid;
2732:   tao->hist_cnorm = cnorm;
2733:   tao->hist_lits  = lits;
2734:   tao->hist_max   = na;
2735:   tao->hist_reset = reset;
2736:   tao->hist_len   = 0;
2737:   PetscFunctionReturn(PETSC_SUCCESS);
2738: }

2740: /*@
2741:   TaoGetConvergenceHistory - Gets the arrays used that hold the convergence history.

2743:   Collective

2745:   Input Parameter:
2746: . tao - the `Tao` context

2748:   Output Parameters:
2749: + obj   - array used to hold objective value history
2750: . resid - array used to hold residual history
2751: . cnorm - array used to hold constraint violation history
2752: . lits  - integer array used to hold linear solver iteration count
2753: - nhist - size of `obj`, `resid`, `cnorm`, and `lits`

2755:   Level: advanced

2757:   Notes:
2758:   This routine must be preceded by calls to `TaoSetConvergenceHistory()`
2759:   and `TaoSolve()`, otherwise it returns useless information.

2761:   This routine is useful, e.g., when running a code for purposes
2762:   of accurate performance monitoring, when no I/O should be done
2763:   during the section of code that is being timed.

2765:   Fortran Notes:
2766:   The calling sequence is
2767: .vb
2768:    call TaoGetConvergenceHistory(Tao tao, PetscInt nhist, PetscErrorCode ierr)
2769: .ve
2770:   In other words this gets the current number of entries in the history. Access the history through the array you passed to `TaoSetConvergenceHistory()`

2772: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergenceHistory()`
2773: @*/
2774: PetscErrorCode TaoGetConvergenceHistory(Tao tao, PetscReal **obj, PetscReal **resid, PetscReal **cnorm, PetscInt **lits, PetscInt *nhist)
2775: {
2776:   PetscFunctionBegin;
2778:   if (obj) *obj = tao->hist_obj;
2779:   if (cnorm) *cnorm = tao->hist_cnorm;
2780:   if (resid) *resid = tao->hist_resid;
2781:   if (lits) *lits = tao->hist_lits;
2782:   if (nhist) *nhist = tao->hist_len;
2783:   PetscFunctionReturn(PETSC_SUCCESS);
2784: }

2786: /*@
2787:   TaoSetApplicationContext - Sets the optional user-defined context for a `Tao` solver that can be accessed later, for example in the
2788:   `Tao` callback functions with `TaoGetApplicationContext()`

2790:   Logically Collective

2792:   Input Parameters:
2793: + tao - the `Tao` context
2794: - ctx - the application context

2796:   Level: intermediate

2798:   Fortran Note:
2799:   This only works when `ctx` is a Fortran derived type (it cannot be a `PetscObject`), we recommend writing a Fortran interface definition for this
2800:   function that tells the Fortran compiler the derived data type that is passed in as the `ctx` argument. See `TaoGetApplicationContext()` for
2801:   an example.

2803: .seealso: [](ch_tao), `Tao`, `TaoGetApplicationContext()`
2804: @*/
2805: PetscErrorCode TaoSetApplicationContext(Tao tao, PetscCtx ctx)
2806: {
2807:   PetscFunctionBegin;
2809:   tao->ctx = ctx;
2810:   PetscFunctionReturn(PETSC_SUCCESS);
2811: }

2813: /*@
2814:   TaoGetApplicationContext - Gets the user-defined context for a `Tao` solver provided with `TaoSetApplicationContext()`

2816:   Not Collective

2818:   Input Parameter:
2819: . tao - the `Tao` context

2821:   Output Parameter:
2822: . ctx - a pointer to the application context

2824:   Level: intermediate

2826:   Fortran Note:
2827:   This only works when the context is a Fortran derived type or a `PetscObject`. Define `ctx` with
2828: .vb
2829:   type(tUsertype), pointer :: ctx
2830: .ve

2832: .seealso: [](ch_tao), `Tao`, `TaoSetApplicationContext()`
2833: @*/
2834: PetscErrorCode TaoGetApplicationContext(Tao tao, PetscCtxRt ctx)
2835: {
2836:   PetscFunctionBegin;
2838:   PetscAssertPointer(ctx, 2);
2839:   *(void **)ctx = tao->ctx;
2840:   PetscFunctionReturn(PETSC_SUCCESS);
2841: }

2843: /*@
2844:   TaoSetGradientNorm - Sets the matrix used to define the norm that measures the size of the gradient in some of the `Tao` algorithms

2846:   Collective

2848:   Input Parameters:
2849: + tao - the `Tao` context
2850: - M   - matrix that defines the norm

2852:   Level: beginner

2854: .seealso: [](ch_tao), `Tao`, `TaoGetGradientNorm()`, `TaoGradientNorm()`
2855: @*/
2856: PetscErrorCode TaoSetGradientNorm(Tao tao, Mat M)
2857: {
2858:   PetscFunctionBegin;
2861:   PetscCall(PetscObjectReference((PetscObject)M));
2862:   PetscCall(MatDestroy(&tao->gradient_norm));
2863:   PetscCall(VecDestroy(&tao->gradient_norm_tmp));
2864:   tao->gradient_norm = M;
2865:   PetscCall(MatCreateVecs(M, NULL, &tao->gradient_norm_tmp));
2866:   PetscFunctionReturn(PETSC_SUCCESS);
2867: }

2869: /*@
2870:   TaoGetGradientNorm - Returns the matrix used to define the norm used for measuring the size of the gradient in some of the `Tao` algorithms

2872:   Not Collective

2874:   Input Parameter:
2875: . tao - the `Tao` context

2877:   Output Parameter:
2878: . M - gradient norm

2880:   Level: beginner

2882: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGradientNorm()`
2883: @*/
2884: PetscErrorCode TaoGetGradientNorm(Tao tao, Mat *M)
2885: {
2886:   PetscFunctionBegin;
2888:   PetscAssertPointer(M, 2);
2889:   *M = tao->gradient_norm;
2890:   PetscFunctionReturn(PETSC_SUCCESS);
2891: }

2893: /*@
2894:   TaoGradientNorm - Compute the norm using the `NormType`, the user has selected

2896:   Collective

2898:   Input Parameters:
2899: + tao      - the `Tao` context
2900: . gradient - the gradient
2901: - type     - the norm type

2903:   Output Parameter:
2904: . gnorm - the gradient norm

2906:   Level: advanced

2908:   Note:
2909:   If `TaoSetGradientNorm()` has been set and `type` is `NORM_2` then the norm provided with `TaoSetGradientNorm()` is used.

2911:   Developer Notes:
2912:   Should be named `TaoComputeGradientNorm()`.

2914:   The usage is a bit confusing, with `TaoSetGradientNorm()` plus `NORM_2` resulting in the computation of the user provided
2915:   norm, perhaps a refactorization is in order.

2917: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGetGradientNorm()`
2918: @*/
2919: PetscErrorCode TaoGradientNorm(Tao tao, Vec gradient, NormType type, PetscReal *gnorm)
2920: {
2921:   PetscFunctionBegin;
2925:   PetscAssertPointer(gnorm, 4);
2926:   if (tao->gradient_norm) {
2927:     PetscScalar gnorms;

2929:     PetscCheck(type == NORM_2, PetscObjectComm((PetscObject)gradient), PETSC_ERR_ARG_WRONG, "Norm type must be NORM_2 if an inner product for the gradient norm is set.");
2930:     PetscCall(MatMult(tao->gradient_norm, gradient, tao->gradient_norm_tmp));
2931:     PetscCall(VecDot(gradient, tao->gradient_norm_tmp, &gnorms));
2932:     *gnorm = PetscRealPart(PetscSqrtScalar(gnorms));
2933:   } else {
2934:     PetscCall(VecNorm(gradient, type, gnorm));
2935:   }
2936:   PetscFunctionReturn(PETSC_SUCCESS);
2937: }

2939: /*@
2940:   TaoMonitorDrawCtxCreate - Creates the monitor context for `TaoMonitorSolutionDraw()`

2942:   Collective

2944:   Input Parameters:
2945: + comm     - the communicator to share the context
2946: . host     - the name of the X Windows host that will display the monitor
2947: . label    - the label to put at the top of the display window
2948: . x        - the horizontal coordinate of the lower left corner of the window to open
2949: . y        - the vertical coordinate of the lower left corner of the window to open
2950: . m        - the width of the window
2951: . n        - the height of the window
2952: - howoften - how many `Tao` iterations between displaying the monitor information

2954:   Output Parameter:
2955: . ctx - the monitor context

2957:   Options Database Key:
2958: . -tao_monitor_solution_draw (true|false) - use `TaoMonitorSolutionDraw()` to monitor the solution

2960:   Level: intermediate

2962:   Note:
2963:   The context this creates, along with `TaoMonitorSolutionDraw()`, and `TaoMonitorDrawCtxDestroy()`
2964:   are passed to `TaoMonitorSet()`.

2966: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorDrawCtx()`
2967: @*/
2968: PetscErrorCode TaoMonitorDrawCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TaoMonitorDrawCtx *ctx)
2969: {
2970:   PetscFunctionBegin;
2971:   PetscCall(PetscNew(ctx));
2972:   PetscCall(PetscViewerDrawOpen(comm, host, label, x, y, m, n, &(*ctx)->viewer));
2973:   PetscCall(PetscViewerSetFromOptions((*ctx)->viewer));
2974:   (*ctx)->howoften = howoften;
2975:   PetscFunctionReturn(PETSC_SUCCESS);
2976: }

2978: /*@
2979:   TaoMonitorDrawCtxDestroy - Destroys the monitor context for `TaoMonitorSolutionDraw()`

2981:   Collective

2983:   Input Parameter:
2984: . ictx - the monitor context

2986:   Level: intermediate

2988:   Note:
2989:   This is passed to `TaoMonitorSet()` as the final argument, along with `TaoMonitorSolutionDraw()`, and the context
2990:   obtained with `TaoMonitorDrawCtxCreate()`.

2992: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorSolutionDraw()`
2993: @*/
2994: PetscErrorCode TaoMonitorDrawCtxDestroy(TaoMonitorDrawCtx *ictx)
2995: {
2996:   PetscFunctionBegin;
2997:   PetscCall(PetscViewerDestroy(&(*ictx)->viewer));
2998:   PetscCall(PetscFree(*ictx));
2999:   PetscFunctionReturn(PETSC_SUCCESS);
3000: }

3002: /*@
3003:   TaoGetTerm - Get the entire objective function of the `Tao` as a
3004:   single `TaoTerm` in the form $\alpha f(Ax; p)$, where $\alpha$ is a scaling
3005:   coefficient, $f$ is a `TaoTerm`, $A$ is an (optional) map and $p$ are the parameters of $f$.

3007:   Not collective

3009:   Input Parameter:
3010: . tao - a `Tao` context

3012:   Output Parameters:
3013: + scale  - the scale of the term
3014: . term   - a `TaoTerm` for the real-valued function defining the objective
3015: . params - the vector of parameters for `term`, or `NULL` if no parameters were specified for `term`
3016: - map    - a map from the solution space of `tao` to the solution space of `term`, if `NULL` then the map is the identity

3018:   Level: intermediate

3020:   Notes:
3021:   If the objective function was defined by providing function callbacks directly to `Tao` (for example, with `TaoSetObjectiveAndGradient()`), then
3022:   `TaoGetTerm` will return a `TaoTerm` with the type `TAOTERMCALLBACKS` that encapsulates
3023:   those functions.

3025:   If multiple `TaoTerms` were provided to `Tao` via, for example, `TaoAddTerm()`, or in combination with giving functions directly to `Tao`, then the type `TAOTERMSUM` is returned.

3027: .seealso: [](ch_tao), `Tao`, `TaoTerm`, `TAOTERMSUM`, `TaoAddTerm()`
3028: @*/
3029: PetscErrorCode TaoGetTerm(Tao tao, PetscReal *scale, TaoTerm *term, Vec *params, Mat *map)
3030: {
3031:   PetscFunctionBegin;
3033:   if (scale) PetscAssertPointer(scale, 2);
3034:   if (term) PetscAssertPointer(term, 3);
3035:   if (params) PetscAssertPointer(params, 4);
3036:   if (map) PetscAssertPointer(map, 5);
3037:   PetscCall(TaoTermMappingGetData(&tao->objective_term, NULL, scale, term, map));
3038:   if (params) *params = tao->objective_parameters;
3039:   PetscFunctionReturn(PETSC_SUCCESS);
3040: }

3042: /*@
3043:   TaoAddTerm - Add a `term` to the objective function. If `Tao` is empty,
3044:   `term` will be the objective of `Tao`.

3046:   Collective

3048:   Input Parameters:
3049: + tao    - a `Tao` solver context
3050: . prefix - the prefix used for configuring the new term (if `NULL`, the index of the term will be used as a prefix, e.g. "0_", "1_", etc.)
3051: . scale  - scaling coefficient for the new term
3052: . term   - the real-valued function defining the new term
3053: . params - (optional) parameters for the new term.  It is up to each implementation of `TaoTerm` to determine how it behaves when parameters are omitted.
3054: - map    - (optional) a map from the `tao` solution space to the `term` solution space; if `NULL` the map is assumed to be the identity

3056:   Level: beginner

3058:   Notes:
3059:   If the objective function was $f(x)$, after calling `TaoAddTerm()` it becomes
3060:   $f(x) + \alpha g(Ax; p)$, where $\alpha$ is the `scale`, $g$ is the `term`, $A$ is the
3061:   (optional) `map`, and $p$ are the (optional) `params` of $g$.

3063:   The `map` $A$ transforms the `Tao` solution vector into the term's solution space.
3064:   For example, if the `Tao` solution vector is $x \in \mathbb{R}^n$ and the mapping
3065:   matrix is $A \in \mathbb{R}^{m \times n}$, then the term evaluates $g(Ax; p)$ with
3066:   $Ax \in \mathbb{R}^m$. The term's solution space is therefore $\mathbb{R}^m$. If the map is
3067:   `NULL`, the identity is used and the term's solution space must match the `Tao` solution space.
3068:   `Tao` automatically applies the chain rule for gradients ($A^T \nabla g$) and Hessians
3069:   ($A^T \nabla^2 g \, A$) with respect to $x$.

3071:   The `params` $p$ are fixed data that are not optimized over. Some `TaoTermType`s
3072:   require the parameter space to be related to the term's solution space (e.g., the same
3073:   size); when a mapping matrix $A$ is used, the parameter space may depend on either the row
3074:   or column space of $A$.  See the documentation for each `TaoTermType`.

3076:   Currently, `TaoAddTerm()` does not support bounded Newton solvers (`TAOBNK`,`TAOBNLS`,`TAOBNTL`,`TAOBNTR`,and `TAOBQNK`)

3078: .seealso: [](ch_tao), `Tao`, `TaoTerm`, `TAOTERMSUM`, `TaoGetTerm()`
3079: @*/
3080: PetscErrorCode TaoAddTerm(Tao tao, const char prefix[], PetscReal scale, TaoTerm term, Vec params, Mat map)
3081: {
3082:   PetscBool is_sum, is_callback;
3083:   PetscInt  num_old_terms;
3084:   Vec      *vec_list = NULL;

3086:   PetscFunctionBegin;
3088:   if (prefix) PetscAssertPointer(prefix, 2);
3091:   PetscCheckSameComm(tao, 1, term, 4);
3092:   if (params) {
3094:     PetscCheckSameComm(tao, 1, params, 5);
3095:   }
3096:   if (map) {
3098:     PetscCheckSameComm(tao, 1, map, 6);
3099:   }
3100:   // If user is using TaoAddTerm, before setting any terms or callbacks,
3101:   // then tao->objective_term.term is empty callback, which we want to remove.
3102:   PetscCall(PetscObjectTypeCompare((PetscObject)tao->objective_term.term, TAOTERMCALLBACKS, &is_callback));
3103:   PetscCall(PetscObjectTypeCompare((PetscObject)term, TAOTERMSUM, &is_sum));
3104:   PetscCheck(!is_sum, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "TaoAddTerm does not support adding TAOTERMSUM");
3105:   if (is_callback) {
3106:     PetscBool is_obj, is_objgrad, is_grad;

3108:     PetscCall(TaoTermIsObjectiveDefined(tao->objective_term.term, &is_obj));
3109:     PetscCall(TaoTermIsObjectiveAndGradientDefined(tao->objective_term.term, &is_objgrad));
3110:     PetscCall(TaoTermIsGradientDefined(tao->objective_term.term, &is_grad));
3111:     // Empty callback term
3112:     if (!(is_obj || is_objgrad || is_grad)) {
3113:       PetscCall(TaoTermMappingSetData(&tao->objective_term, NULL, scale, term, map));
3114:       PetscCall(PetscObjectReference((PetscObject)params));
3115:       PetscCall(VecDestroy(&tao->objective_parameters));
3116:       // Empty callback term. Destroy hessians, as they are not needed
3117:       PetscCall(MatDestroy(&tao->hessian));
3118:       PetscCall(MatDestroy(&tao->hessian_pre));
3119:       tao->objective_parameters = params;
3120:       tao->term_set             = PETSC_TRUE;
3121:       PetscFunctionReturn(PETSC_SUCCESS);
3122:     }
3123:   }
3124:   PetscCall(PetscObjectTypeCompare((PetscObject)tao->objective_term.term, TAOTERMSUM, &is_sum));
3125:   // One TaoTerm has been set. Create TAOTERMSUM to store that, and the new one
3126:   if (!is_sum) {
3127:     TaoTerm     old_sum;
3128:     const char *tao_prefix;
3129:     const char *term_prefix;

3131:     PetscCall(TaoTermDuplicate(tao->objective_term.term, TAOTERM_DUPLICATE_SIZEONLY, &old_sum));
3132:     if (tao->objective_term.map) {
3133:       VecType     map_vectype;
3134:       VecType     param_vectype;
3135:       PetscLayout cmap, param_layout;

3137:       PetscCall(MatGetVecType(tao->objective_term.map, &map_vectype));
3138:       PetscCall(MatGetLayouts(tao->objective_term.map, NULL, &cmap));
3139:       PetscCall(TaoTermGetParametersVecType(old_sum, &param_vectype));
3140:       PetscCall(TaoTermGetParametersLayout(old_sum, &param_layout));

3142:       PetscCall(TaoTermSetSolutionVecType(old_sum, map_vectype));
3143:       PetscCall(TaoTermSetParametersVecType(old_sum, param_vectype));
3144:       PetscCall(TaoTermSetSolutionLayout(old_sum, cmap));
3145:       PetscCall(TaoTermSetParametersLayout(old_sum, param_layout));
3146:     }

3148:     PetscCall(TaoTermSetType(old_sum, TAOTERMSUM));
3149:     PetscCall(TaoGetOptionsPrefix(tao, &tao_prefix));
3150:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)old_sum, tao_prefix));
3151:     PetscCall(TaoTermSumSetNumberTerms(old_sum, 1));
3152:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao->objective_term.term, &term_prefix));
3153:     PetscCall(TaoTermSumSetTerm(old_sum, 0, term_prefix, tao->objective_term.scale, tao->objective_term.term, tao->objective_term.map));
3154:     PetscCall(TaoTermSumSetTermHessianMatrices(old_sum, 0, NULL, NULL, tao->hessian, tao->hessian_pre));
3155:     PetscCall(MatDestroy(&tao->hessian));
3156:     PetscCall(MatDestroy(&tao->hessian_pre));
3157:     PetscCall(TaoTermMappingReset(&tao->objective_term));
3158:     PetscCall(TaoTermMappingSetData(&tao->objective_term, NULL, 1.0, old_sum, NULL));
3159:     if (tao->objective_parameters) {
3160:       // convert the parameters to a VECNEST
3161:       Vec subvecs[1];

3163:       subvecs[0]                = tao->objective_parameters;
3164:       tao->objective_parameters = NULL;
3165:       PetscCall(TaoTermSumParametersPack(old_sum, subvecs, &tao->objective_parameters));
3166:       PetscCall(VecDestroy(&subvecs[0]));
3167:     }
3168:     PetscCall(TaoTermDestroy(&old_sum));
3169:     tao->num_terms = 1;
3170:   }
3171:   PetscCall(TaoTermSumGetNumberTerms(tao->objective_term.term, &num_old_terms));
3172:   if (tao->objective_parameters || params) {
3173:     PetscCall(PetscCalloc1(num_old_terms + 1, &vec_list));
3174:     if (tao->objective_parameters) PetscCall(TaoTermSumParametersUnpack(tao->objective_term.term, &tao->objective_parameters, vec_list));
3175:     PetscCall(PetscObjectReference((PetscObject)params));
3176:     vec_list[num_old_terms] = params;
3177:   }
3178:   PetscCall(TaoTermSumAddTerm(tao->objective_term.term, prefix, scale, term, map, NULL));
3179:   tao->num_terms++;
3180:   if (vec_list) {
3181:     PetscInt num_terms = num_old_terms + 1;
3182:     PetscCall(TaoTermSumParametersPack(tao->objective_term.term, vec_list, &tao->objective_parameters));
3183:     for (PetscInt i = 0; i < num_terms; i++) PetscCall(VecDestroy(&vec_list[i]));
3184:     PetscCall(PetscFree(vec_list));
3185:   }
3186:   PetscFunctionReturn(PETSC_SUCCESS);
3187: }

3189: /*@
3190:   TaoSetDM - Sets the `DM` that may be used by some `TAO` solvers or their underlying solvers and preconditioners

3192:   Logically Collective

3194:   Input Parameters:
3195: + tao - the nonlinear solver context
3196: - dm  - the `DM`, cannot be `NULL`

3198:   Level: intermediate

3200:   Note:
3201:   A `DM` can only be used for solving one problem at a time because information about the problem is stored on the `DM`,
3202:   even when not using interfaces like `DMSNESSetFunction()`.  Use `DMClone()` to get a distinct `DM` when solving different
3203:   problems using the same function space.

3205: .seealso: [](ch_snes), `DM`, `TAO`, `TaoGetDM()`, `SNESSetDM()`, `SNESGetDM()`, `KSPSetDM()`, `KSPGetDM()`
3206: @*/
3207: PetscErrorCode TaoSetDM(Tao tao, DM dm)
3208: {
3209:   KSP ksp;

3211:   PetscFunctionBegin;
3214:   PetscCall(PetscObjectReference((PetscObject)dm));
3215:   PetscCall(DMDestroy(&tao->dm));
3216:   tao->dm = dm;

3218:   PetscCall(TaoGetKSP(tao, &ksp));
3219:   if (ksp) {
3220:     PetscCall(KSPSetDM(ksp, dm));
3221:     PetscCall(KSPSetDMActive(ksp, KSP_DMACTIVE_ALL, PETSC_FALSE));
3222:   }
3223:   PetscFunctionReturn(PETSC_SUCCESS);
3224: }

3226: /*@
3227:   TaoGetDM - Gets the `DM` that may be used by some `TAO` solvers or their underlying solvers and preconditioners

3229:   Not Collective but `dm` obtained is parallel on `tao`

3231:   Input Parameter:
3232: . tao - the `TAO` context

3234:   Output Parameter:
3235: . dm - the `DM`

3237:   Level: intermediate

3239: .seealso: [](ch_snes), `DM`, `TAO`, `TaoSetDM()`, `SNESSetDM()`, `SNESGetDM()`, `KSPSetDM()`, `KSPGetDM()`
3240: @*/
3241: PetscErrorCode TaoGetDM(Tao tao, DM *dm)
3242: {
3243:   PetscFunctionBegin;
3245:   PetscAssertPointer(dm, 2);
3246:   if (!tao->dm) PetscCall(DMShellCreate(PetscObjectComm((PetscObject)tao), &tao->dm));
3247:   *dm = tao->dm;
3248:   PetscFunctionReturn(PETSC_SUCCESS);
3249: }