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 *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 all the parameters in `tao` to their default value (when `TaoCreate()` was called) if they
 76:   currently contain default values. Default values are the parameter values when the object's type is set.

 78:   Collective

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

 83:   Level: developer

 85:   Developer Note:
 86:   This is called by all the `TaoCreate_XXX()` routines.

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

106: /*@
107:   TaoCreate - Creates a Tao solver

109:   Collective

111:   Input Parameter:
112: . comm - MPI communicator

114:   Output Parameter:
115: . newtao - the new `Tao` context

117:   Options Database Key:
118: . -tao_type - select which method Tao should use

120:   Level: beginner

122: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoDestroy()`, `TaoSetFromOptions()`, `TaoSetType()`
123: @*/
124: PetscErrorCode TaoCreate(MPI_Comm comm, Tao *newtao)
125: {
126:   Tao tao;

128:   PetscFunctionBegin;
129:   PetscAssertPointer(newtao, 2);
130:   PetscCall(TaoInitializePackage());
131:   PetscCall(TaoLineSearchInitializePackage());

133:   PetscCall(PetscHeaderCreate(tao, TAO_CLASSID, "Tao", "Optimization solver", "Tao", comm, TaoDestroy, TaoView));
134:   tao->ops->convergencetest = TaoDefaultConvergenceTest;

136:   tao->hist_reset = PETSC_TRUE;
137:   tao->term_set   = PETSC_FALSE;

139:   PetscCall(TaoTermCreateCallbacks(tao, &tao->callbacks));
140:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
141:   PetscCall(TaoTermMappingSetData(&tao->objective_term, NULL, 1.0, tao->callbacks, NULL));
142:   PetscCall(TaoResetStatistics(tao));
143:   *newtao = tao;
144:   PetscFunctionReturn(PETSC_SUCCESS);
145: }

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

150:   Collective

152:   Input Parameter:
153: . tao - the `Tao` context

155:   Level: beginner

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

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

163: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSetObjective()`, `TaoSetGradient()`, `TaoSetHessian()`, `TaoGetConvergedReason()`, `TaoSetUp()`
164:  @*/
165: PetscErrorCode TaoSolve(Tao tao)
166: {
167:   static PetscBool set = PETSC_FALSE;

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

184:   PetscCall(PetscLogEventBegin(TAO_Solve, tao, 0, 0, 0));
185:   PetscTryTypeMethod(tao, solve);
186:   PetscCall(PetscLogEventEnd(TAO_Solve, tao, 0, 0, 0));

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

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

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

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

215: /*@
216:   TaoSetUp - Sets up the internal data structures for the later use
217:   of a Tao solver

219:   Collective

221:   Input Parameter:
222: . tao - the `Tao` context

224:   Level: advanced

226:   Note:
227:   The user will not need to explicitly call `TaoSetUp()`, as it will
228:   automatically be called in `TaoSolve()`.  However, if the user
229:   desires to call it explicitly, it should come after `TaoCreate()`
230:   and any TaoSetSomething() routines, but before `TaoSolve()`.

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

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

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

265:   Collective

267:   Input Parameter:
268: . tao - the `Tao` context

270:   Level: beginner

272: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
273: @*/
274: PetscErrorCode TaoDestroy(Tao *tao)
275: {
276:   PetscFunctionBegin;
277:   if (!*tao) PetscFunctionReturn(PETSC_SUCCESS);
279:   if (--((PetscObject)*tao)->refct > 0) {
280:     *tao = NULL;
281:     PetscFunctionReturn(PETSC_SUCCESS);
282:   }

284:   PetscTryTypeMethod(*tao, destroy);
285:   PetscCall(TaoTermMappingReset(&(*tao)->objective_term));
286:   PetscCall(VecDestroy(&(*tao)->objective_parameters));
287:   PetscCall(TaoTermDestroy(&(*tao)->callbacks));
288:   PetscCall(DMDestroy(&(*tao)->dm));
289:   PetscCall(KSPDestroy(&(*tao)->ksp));
290:   PetscCall(SNESDestroy(&(*tao)->snes_ewdummy));
291:   PetscCall(TaoLineSearchDestroy(&(*tao)->linesearch));

293:   if ((*tao)->ops->convergencedestroy) {
294:     PetscCall((*(*tao)->ops->convergencedestroy)((*tao)->cnvP));
295:     PetscCall(MatDestroy(&(*tao)->jacobian_state_inv));
296:   }
297:   PetscCall(VecDestroy(&(*tao)->solution));
298:   PetscCall(VecDestroy(&(*tao)->gradient));
299:   PetscCall(VecDestroy(&(*tao)->ls_res));

301:   if ((*tao)->gradient_norm) {
302:     PetscCall(PetscObjectDereference((PetscObject)(*tao)->gradient_norm));
303:     PetscCall(VecDestroy(&(*tao)->gradient_norm_tmp));
304:   }

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

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

347:   Logically Collective

349:   Input Parameters:
350: + tao  - Tao context
351: - flag - `PETSC_TRUE` or `PETSC_FALSE`

353:   Level: advanced

355:   Note:
356:   See `SNESKSPSetUseEW()` for customization details.

358: .seealso: [](ch_tao), `Tao`, `SNESKSPSetUseEW()`
359: @*/
360: PetscErrorCode TaoKSPSetUseEW(Tao tao, PetscBool flag)
361: {
362:   PetscFunctionBegin;
365:   tao->ksp_ewconv = flag;
366:   PetscFunctionReturn(PETSC_SUCCESS);
367: }

369: /*@C
370:   TaoMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

372:   Collective

374:   Input Parameters:
375: + tao     - `Tao` object you wish to monitor
376: . name    - the monitor type one is seeking
377: . help    - message indicating what monitoring is done
378: . manual  - manual page for the monitor
379: - monitor - the monitor function, this must use a `PetscViewerFormat` as its context

381:   Level: developer

383: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
384:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
385:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
386:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
387:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
388:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
389:           `PetscOptionsFList()`, `PetscOptionsEList()`
390: @*/
391: PetscErrorCode TaoMonitorSetFromOptions(Tao tao, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(Tao, PetscViewerAndFormat *))
392: {
393:   PetscViewer       viewer;
394:   PetscViewerFormat format;
395:   PetscBool         flg;

397:   PetscFunctionBegin;
398:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)tao), ((PetscObject)tao)->options, ((PetscObject)tao)->prefix, name, &viewer, &format, &flg));
399:   if (flg) {
400:     PetscViewerAndFormat *vf;
401:     char                  interval_key[1024];

403:     PetscCall(PetscSNPrintf(interval_key, sizeof interval_key, "%s_interval", name));
404:     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
405:     vf->view_interval = 1;
406:     PetscCall(PetscOptionsGetInt(((PetscObject)tao)->options, ((PetscObject)tao)->prefix, interval_key, &vf->view_interval, NULL));

408:     PetscCall(PetscViewerDestroy(&viewer));
409:     PetscCall(TaoMonitorSet(tao, (PetscErrorCode (*)(Tao, PetscCtx))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
410:   }
411:   PetscFunctionReturn(PETSC_SUCCESS);
412: }

414: /*@
415:   TaoSetFromOptions - Sets various Tao parameters from the options database

417:   Collective

419:   Input Parameter:
420: . tao - the `Tao` solver context

422:   Options Database Keys:
423: + -tao_type type               - The algorithm that Tao uses (lmvm, nls, etc.). See `TAOType`
424: . -tao_gatol gatol             - absolute error tolerance for ||gradient||
425: . -tao_grtol grtol             - relative error tolerance for ||gradient||
426: . -tao_gttol gttol             - reduction of ||gradient|| relative to initial gradient
427: . -tao_max_it max              - sets maximum number of iterations
428: . -tao_max_funcs max           - sets maximum number of function evaluations
429: . -tao_fmin fmin               - stop if function value reaches fmin
430: . -tao_steptol tol             - stop if trust region radius less than `tol`
431: . -tao_trust0 radius           - initial trust region radius
432: . -tao_view_solution           - view the solution at the end of the optimization process
433: . -tao_monitor                 - prints function value and residual norm at each iteration
434: . -tao_monitor_short           - same as `-tao_monitor`, but truncates very small values
435: . -tao_monitor_constraint_norm - prints objective value, gradient, and constraint norm at each iteration
436: . -tao_monitor_globalization   - prints information about the globalization at each iteration
437: . -tao_monitor_solution        - prints solution vector at each iteration
438: . -tao_monitor_ls_residual     - prints least-squares residual vector at each iteration
439: . -tao_monitor_step            - prints step vector at each iteration
440: . -tao_monitor_gradient        - prints gradient vector at each iteration
441: . -tao_monitor_solution_draw   - graphically view solution vector at each iteration
442: . -tao_monitor_step_draw       - graphically view step vector at each iteration
443: . -tao_monitor_gradient_draw   - graphically view gradient at each iteration
444: . -tao_monitor_cancel          - cancels all monitors (except those set with command line)
445: . -tao_fd_gradient             - use gradient computed with finite differences
446: . -tao_fd_hessian              - use hessian computed with finite differences
447: . -tao_mf_hessian              - use matrix-free Hessian computed with finite differences. No `TaoTerm` support
448: . -tao_view                    - prints information about the Tao after solving
449: . -tao_converged_reason        - prints the reason Tao stopped iterating
450: - -tao_add_terms               - takes a comma-separated list of up to 16 options prefixes, a `TaoTerm` will be created for each and added to the objective function

452:   Level: beginner

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

458:   The `-tao_add_terms` option accepts at most 16 prefixes.

460: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
461: @*/
462: PetscErrorCode TaoSetFromOptions(Tao tao)
463: {
464:   TaoType   default_type = TAOLMVM;
465:   char      type[256];
466:   PetscBool flg, found;
467:   MPI_Comm  comm;
468:   PetscReal catol, crtol, gatol, grtol, gttol;

470:   PetscFunctionBegin;
472:   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));

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

476:   PetscObjectOptionsBegin((PetscObject)tao);
477:   /* Check for type from options */
478:   PetscCall(PetscOptionsFList("-tao_type", "Tao Solver type", "TaoSetType", TaoList, default_type, type, 256, &flg));
479:   if (flg) PetscCall(TaoSetType(tao, type));
480:   else if (!((PetscObject)tao)->type_name) PetscCall(TaoSetType(tao, default_type));

482:   /* Tao solvers do not set the prefix, set it here if not yet done
483:      We do it after SetType since solver may have been changed */
484:   if (tao->linesearch) {
485:     const char *prefix;
486:     PetscCall(TaoLineSearchGetOptionsPrefix(tao->linesearch, &prefix));
487:     if (!prefix) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, ((PetscObject)tao)->prefix));
488:   }

490:   catol = tao->catol;
491:   crtol = tao->crtol;
492:   PetscCall(PetscOptionsReal("-tao_catol", "Stop if constraints violations within", "TaoSetConstraintTolerances", tao->catol, &catol, NULL));
493:   PetscCall(PetscOptionsReal("-tao_crtol", "Stop if relative constraint violations within", "TaoSetConstraintTolerances", tao->crtol, &crtol, NULL));
494:   PetscCall(TaoSetConstraintTolerances(tao, catol, crtol));

496:   gatol = tao->gatol;
497:   grtol = tao->grtol;
498:   gttol = tao->gttol;
499:   PetscCall(PetscOptionsReal("-tao_gatol", "Stop if norm of gradient less than", "TaoSetTolerances", tao->gatol, &gatol, NULL));
500:   PetscCall(PetscOptionsReal("-tao_grtol", "Stop if norm of gradient divided by the function value is less than", "TaoSetTolerances", tao->grtol, &grtol, NULL));
501:   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));
502:   PetscCall(TaoSetTolerances(tao, gatol, grtol, gttol));

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

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

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

515:   PetscCall(PetscOptionsDeprecated("-tao_solution_monitor", "-tao_monitor_solution", "3.21", NULL));
516:   PetscCall(PetscOptionsDeprecated("-tao_gradient_monitor", "-tao_monitor_gradient", "3.21", NULL));
517:   PetscCall(PetscOptionsDeprecated("-tao_stepdirection_monitor", "-tao_monitor_step", "3.21", NULL));
518:   PetscCall(PetscOptionsDeprecated("-tao_residual_monitor", "-tao_monitor_residual", "3.21", NULL));
519:   PetscCall(PetscOptionsDeprecated("-tao_smonitor", "-tao_monitor_short", "3.21", NULL));
520:   PetscCall(PetscOptionsDeprecated("-tao_cmonitor", "-tao_monitor_constraint_norm", "3.21", NULL));
521:   PetscCall(PetscOptionsDeprecated("-tao_gmonitor", "-tao_monitor_globalization", "3.21", NULL));
522:   PetscCall(PetscOptionsDeprecated("-tao_draw_solution", "-tao_monitor_solution_draw", "3.21", NULL));
523:   PetscCall(PetscOptionsDeprecated("-tao_draw_gradient", "-tao_monitor_gradient_draw", "3.21", NULL));
524:   PetscCall(PetscOptionsDeprecated("-tao_draw_step", "-tao_monitor_step_draw", "3.21", NULL));

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

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

531:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_step", "View step vector after each iteration", "TaoMonitorStep", TaoMonitorStep));
532:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_residual", "View least-squares residual vector after each iteration", "TaoMonitorResidual", TaoMonitorResidual));
533:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor", "Use the default convergence monitor", "TaoMonitorDefault", TaoMonitorDefault));
534:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_globalization", "Use the convergence monitor with extra globalization info", "TaoMonitorGlobalization", TaoMonitorGlobalization));
535:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_short", "Use the short convergence monitor", "TaoMonitorDefaultShort", TaoMonitorDefaultShort));
536:   PetscCall(TaoMonitorSetFromOptions(tao, "-tao_monitor_constraint_norm", "Use the default convergence monitor with constraint norm", "TaoMonitorConstraintNorm", TaoMonitorConstraintNorm));

538:   flg = PETSC_FALSE;
539:   PetscCall(PetscOptionsDeprecated("-tao_cancelmonitors", "-tao_monitor_cancel", "3.21", NULL));
540:   PetscCall(PetscOptionsBool("-tao_monitor_cancel", "cancel all monitors and call any registered destroy routines", "TaoMonitorCancel", flg, &flg, NULL));
541:   if (flg) PetscCall(TaoMonitorCancel(tao));

543:   flg = PETSC_FALSE;
544:   PetscCall(PetscOptionsBool("-tao_monitor_solution_draw", "Plot solution vector at each iteration", "TaoMonitorSet", flg, &flg, NULL));
545:   if (flg) {
546:     TaoMonitorDrawCtx drawctx;
547:     PetscInt          howoften = 1;
548:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
549:     PetscCall(TaoMonitorSet(tao, TaoMonitorSolutionDraw, drawctx, (PetscCtxDestroyFn *)TaoMonitorDrawCtxDestroy));
550:   }

552:   flg = PETSC_FALSE;
553:   PetscCall(PetscOptionsBool("-tao_monitor_step_draw", "Plots step at each iteration", "TaoMonitorSet", flg, &flg, NULL));
554:   if (flg) PetscCall(TaoMonitorSet(tao, TaoMonitorStepDraw, NULL, NULL));

556:   flg = PETSC_FALSE;
557:   PetscCall(PetscOptionsBool("-tao_monitor_gradient_draw", "plots gradient at each iteration", "TaoMonitorSet", flg, &flg, NULL));
558:   if (flg) {
559:     TaoMonitorDrawCtx drawctx;
560:     PetscInt          howoften = 1;
561:     PetscCall(TaoMonitorDrawCtxCreate(PetscObjectComm((PetscObject)tao), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, howoften, &drawctx));
562:     PetscCall(TaoMonitorSet(tao, TaoMonitorGradientDraw, drawctx, (PetscCtxDestroyFn *)TaoMonitorDrawCtxDestroy));
563:   }

565:   flg = PETSC_FALSE;
566:   PetscCall(PetscOptionsBool("-tao_fd_gradient", "compute gradient using finite differences", "TaoDefaultComputeGradient", flg, &flg, NULL));
567:   if (flg) PetscCall(TaoTermComputeGradientSetUseFD(tao->objective_term.term, PETSC_TRUE));
568:   flg = PETSC_FALSE;
569:   PetscCall(PetscOptionsBool("-tao_fd_hessian", "compute Hessian using finite differences", "TaoDefaultComputeHessian", flg, &flg, NULL));
570:   if (flg) {
571:     Mat H;

573:     PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &H));
574:     PetscCall(MatSetType(H, MATAIJ));
575:     PetscCall(MatSetOption(H, MAT_SYMMETRIC, PETSC_TRUE));
576:     PetscCall(MatSetOption(H, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
577:     PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessian, NULL));
578:     PetscCall(TaoTermComputeHessianSetUseFD(tao->objective_term.term, PETSC_TRUE));
579:     PetscCall(MatDestroy(&H));
580:   }
581:   flg = PETSC_FALSE;
582:   PetscCall(PetscOptionsBool("-tao_mf_hessian", "compute matrix-free Hessian using finite differences", "TaoDefaultComputeHessianMFFD", flg, &flg, NULL));
583:   if (flg) {
584:     PetscBool is_callback;
585:     Mat       H;

587:     // Check that tao has only one TaoTerm with type TAOTERMCALLBACK
588:     PetscCall(PetscObjectTypeCompare((PetscObject)tao->objective_term.term, TAOTERMCALLBACKS, &is_callback));
589:     if (is_callback) {
590:       // Create Hessian via TaoTermCreateHessianMFFD
591:       PetscCall(TaoTermCreateHessianMFFD(tao->objective_term.term, &H));
592:       PetscCall(TaoSetHessian(tao, H, H, TaoDefaultComputeHessianMFFD, NULL));
593:       PetscCall(MatDestroy(&H));
594:     } else {
595:       PetscCall(PetscInfo(tao, "-tao_mf_hessian only works when Tao has a single TAOTERMCALLBACK term. Ignoring.\n"));
596:     }
597:   }
598:   PetscCall(PetscOptionsBool("-tao_recycle_history", "enable recycling/re-using information from the previous TaoSolve() call for some algorithms", "TaoSetRecycleHistory", flg, &flg, &found));
599:   if (found) PetscCall(TaoSetRecycleHistory(tao, flg));
600:   PetscCall(PetscOptionsEnum("-tao_subset_type", "subset type", "", TaoSubSetTypes, (PetscEnum)tao->subset_type, (PetscEnum *)&tao->subset_type, NULL));

602:   if (tao->ksp) {
603:     PetscCall(PetscOptionsBool("-tao_ksp_ew", "Use Eisentat-Walker linear system convergence test", "TaoKSPSetUseEW", tao->ksp_ewconv, &tao->ksp_ewconv, NULL));
604:     PetscCall(TaoKSPSetUseEW(tao, tao->ksp_ewconv));
605:   }

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

609:   {
610:     char    *term_prefixes[16];
611:     PetscInt n_terms = PETSC_STATIC_ARRAY_LENGTH(term_prefixes);

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

618:       PetscCall(TaoTermDuplicate(tao->objective_term.term, TAOTERM_DUPLICATE_SIZEONLY, &term));
619:       PetscCall(TaoGetOptionsPrefix(tao, &prefix));
620:       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)term, prefix));
621:       PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)term, term_prefixes[i]));
622:       PetscCall(TaoTermSetFromOptions(term));
623:       PetscCall(TaoAddTerm(tao, term_prefixes[i], 1.0, term, NULL, NULL));
624:       PetscCall(TaoTermDestroy(&term));
625:       PetscCall(PetscFree(term_prefixes[i]));
626:     }
627:   }

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

631:   PetscTryTypeMethod(tao, setfromoptions, PetscOptionsObject);

633:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
634:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tao, PetscOptionsObject));
635:   PetscOptionsEnd();

637:   if (tao->linesearch) PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
638:   PetscFunctionReturn(PETSC_SUCCESS);
639: }

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

644:   Collective

646:   Input Parameters:
647: + A    - the  `Tao` context
648: . obj  - Optional object that provides the prefix for the options database
649: - name - command line option

651:   Options Database Key:
652: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments

654:   Level: intermediate

656: .seealso: [](ch_tao), `Tao`, `TaoView`, `PetscObjectViewFromOptions()`, `TaoCreate()`
657: @*/
658: PetscErrorCode TaoViewFromOptions(Tao A, PetscObject obj, const char name[])
659: {
660:   PetscFunctionBegin;
662:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
663:   PetscFunctionReturn(PETSC_SUCCESS);
664: }

666: /*@
667:   TaoView - Prints information about the `Tao` object

669:   Collective

671:   Input Parameters:
672: + tao    - the `Tao` context
673: - viewer - visualization context

675:   Options Database Key:
676: . -tao_view - Calls `TaoView()` at the end of `TaoSolve()`

678:   Level: beginner

680:   Notes:
681:   The available visualization contexts include
682: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
683: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
684:   output where only the first processor opens
685:   the file.  All other processors send their
686:   data to the first processor to print.

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

691: .seealso: [](ch_tao), `Tao`, `PetscViewerASCIIOpen()`
692: @*/
693: PetscErrorCode TaoView(Tao tao, PetscViewer viewer)
694: {
695:   PetscBool isascii, isstring;
696:   TaoType   type;

698:   PetscFunctionBegin;
700:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(((PetscObject)tao)->comm, &viewer));
702:   PetscCheckSameComm(tao, 1, viewer, 2);

704:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
705:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
706:   if (isascii) {
707:     PetscViewerFormat format;

709:     PetscCall(PetscViewerGetFormat(viewer, &format));
710:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tao, viewer));

712:     PetscCall(PetscViewerASCIIPushTab(viewer));
713:     PetscTryTypeMethod(tao, view, viewer);
714:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
715:       PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
716:       PetscCall(PetscViewerASCIIPushTab(viewer));
717:       PetscCall(PetscViewerASCIIPrintf(viewer, "Scale (tao_objective_scale): %g\n", (double)tao->objective_term.scale));
718:       PetscCall(PetscViewerASCIIPrintf(viewer, "Function:\n"));
719:       PetscCall(PetscViewerASCIIPushTab(viewer));
720:       PetscCall(TaoTermView(tao->objective_term.term, viewer));
721:       PetscCall(PetscViewerASCIIPopTab(viewer));
722:       if (tao->objective_term.map) {
723:         PetscCall(PetscViewerASCIIPrintf(viewer, "Map:\n"));
724:         PetscCall(PetscViewerASCIIPushTab(viewer));
725:         PetscCall(MatView(tao->objective_term.map, viewer));
726:         PetscCall(PetscViewerASCIIPopTab(viewer));
727:       } else PetscCall(PetscViewerASCIIPrintf(viewer, "Map: unmapped\n"));
728:       PetscCall(PetscViewerASCIIPopTab(viewer));
729:     } else if (tao->num_terms > 0 || tao->term_set) {
730:       if (tao->objective_term.scale == 1.0 && tao->objective_term.map == NULL) {
731:         PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
732:         PetscCall(PetscViewerASCIIPushTab(viewer));
733:         PetscCall(TaoTermView(tao->objective_term.term, viewer));
734:         PetscCall(PetscViewerASCIIPopTab(viewer));
735:       } else {
736:         PetscCall(PetscViewerASCIIPrintf(viewer, "Objective function:\n"));
737:         PetscCall(PetscViewerASCIIPushTab(viewer));
738:         if (tao->objective_term.scale != 1.0) PetscCall(PetscViewerASCIIPrintf(viewer, "Scale: %g\n", (double)tao->objective_term.scale));
739:         PetscCall(PetscViewerASCIIPrintf(viewer, "Function:\n"));
740:         PetscCall(PetscViewerASCIIPushTab(viewer));
741:         PetscCall(TaoTermView(tao->objective_term.term, viewer));
742:         PetscCall(PetscViewerASCIIPopTab(viewer));
743:         if (tao->objective_term.map) {
744:           PetscCall(PetscViewerASCIIPrintf(viewer, "Map:\n"));
745:           PetscCall(PetscViewerASCIIPushTab(viewer));
746:           PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO));
747:           PetscCall(MatView(tao->objective_term.map, viewer));
748:           PetscCall(PetscViewerPopFormat(viewer));
749:           PetscCall(PetscViewerASCIIPopTab(viewer));
750:         }
751:         PetscCall(PetscViewerASCIIPopTab(viewer));
752:       }
753:     }
754:     if (tao->linesearch) PetscCall(TaoLineSearchView(tao->linesearch, viewer));
755:     if (tao->ksp) {
756:       PetscCall(KSPView(tao->ksp, viewer));
757:       PetscCall(PetscViewerASCIIPrintf(viewer, "total KSP iterations: %" PetscInt_FMT "\n", tao->ksp_tot_its));
758:     }

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

762:     PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: gatol=%g,", (double)tao->gatol));
763:     PetscCall(PetscViewerASCIIPrintf(viewer, " grtol=%g,", (double)tao->grtol));
764:     PetscCall(PetscViewerASCIIPrintf(viewer, " steptol=%g,", (double)tao->steptol));
765:     PetscCall(PetscViewerASCIIPrintf(viewer, " gttol=%g\n", (double)tao->gttol));
766:     PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Function/Gradient:=%g\n", (double)tao->residual));

768:     if (tao->constrained) {
769:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances:"));
770:       PetscCall(PetscViewerASCIIPrintf(viewer, " catol=%g,", (double)tao->catol));
771:       PetscCall(PetscViewerASCIIPrintf(viewer, " crtol=%g\n", (double)tao->crtol));
772:       PetscCall(PetscViewerASCIIPrintf(viewer, "Residual in Constraints:=%g\n", (double)tao->cnorm));
773:     }

775:     if (tao->trust < tao->steptol) {
776:       PetscCall(PetscViewerASCIIPrintf(viewer, "convergence tolerances: steptol=%g\n", (double)tao->steptol));
777:       PetscCall(PetscViewerASCIIPrintf(viewer, "Final trust region radius:=%g\n", (double)tao->trust));
778:     }

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

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

786:     if (tao->objective_term.term->nobj > 0) {
787:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function evaluations=%" PetscInt_FMT ",", tao->objective_term.term->nobj));
788:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
789:       else PetscCall(PetscViewerASCIIPrintf(viewer, "               (max: %" PetscInt_FMT ")\n", tao->max_funcs));
790:     }
791:     if (tao->objective_term.term->ngrad > 0) {
792:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of gradient evaluations=%" PetscInt_FMT ",", tao->objective_term.term->ngrad));
793:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: unlimited)\n"));
794:       else PetscCall(PetscViewerASCIIPrintf(viewer, "                (max: %" PetscInt_FMT ")\n", tao->max_funcs));
795:     }
796:     if (tao->objective_term.term->nobjgrad > 0) {
797:       PetscCall(PetscViewerASCIIPrintf(viewer, "total number of function/gradient evaluations=%" PetscInt_FMT ",", tao->objective_term.term->nobjgrad));
798:       if (tao->max_funcs == PETSC_UNLIMITED) PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: unlimited)\n"));
799:       else PetscCall(PetscViewerASCIIPrintf(viewer, "    (max: %" PetscInt_FMT ")\n", tao->max_funcs));
800:     }
801:     if (tao->nres > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of residual evaluations=%" PetscInt_FMT "\n", tao->nres));
802:     if (tao->objective_term.term->nhess > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Hessian evaluations=%" PetscInt_FMT "\n", tao->objective_term.term->nhess));
803:     if (tao->nconstraints > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of constraint function evaluations=%" PetscInt_FMT "\n", tao->nconstraints));
804:     if (tao->njac > 0) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of Jacobian evaluations=%" PetscInt_FMT "\n", tao->njac));

806:     if (tao->reason > 0) {
807:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solution converged: "));
808:       switch (tao->reason) {
809:       case TAO_CONVERGED_GATOL:
810:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)|| <= gatol\n"));
811:         break;
812:       case TAO_CONVERGED_GRTOL:
813:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/|f(X)| <= grtol\n"));
814:         break;
815:       case TAO_CONVERGED_GTTOL:
816:         PetscCall(PetscViewerASCIIPrintf(viewer, " ||g(X)||/||g(X0)|| <= gttol\n"));
817:         break;
818:       case TAO_CONVERGED_STEPTOL:
819:         PetscCall(PetscViewerASCIIPrintf(viewer, " Steptol -- step size small\n"));
820:         break;
821:       case TAO_CONVERGED_MINF:
822:         PetscCall(PetscViewerASCIIPrintf(viewer, " Minf --  f < fmin\n"));
823:         break;
824:       case TAO_CONVERGED_USER:
825:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
826:         break;
827:       default:
828:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
829:         break;
830:       }
831:     } else if (tao->reason == TAO_CONTINUE_ITERATING) {
832:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver never run\n"));
833:     } else {
834:       PetscCall(PetscViewerASCIIPrintf(viewer, "Solver failed: "));
835:       switch (tao->reason) {
836:       case TAO_DIVERGED_MAXITS:
837:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Iterations\n"));
838:         break;
839:       case TAO_DIVERGED_NAN:
840:         PetscCall(PetscViewerASCIIPrintf(viewer, " NAN or infinity encountered\n"));
841:         break;
842:       case TAO_DIVERGED_MAXFCN:
843:         PetscCall(PetscViewerASCIIPrintf(viewer, " Maximum Function Evaluations\n"));
844:         break;
845:       case TAO_DIVERGED_LS_FAILURE:
846:         PetscCall(PetscViewerASCIIPrintf(viewer, " Line Search Failure\n"));
847:         break;
848:       case TAO_DIVERGED_TR_REDUCTION:
849:         PetscCall(PetscViewerASCIIPrintf(viewer, " Trust Region too small\n"));
850:         break;
851:       case TAO_DIVERGED_USER:
852:         PetscCall(PetscViewerASCIIPrintf(viewer, " User Terminated\n"));
853:         break;
854:       default:
855:         PetscCall(PetscViewerASCIIPrintf(viewer, " %d\n", tao->reason));
856:         break;
857:       }
858:     }
859:     PetscCall(PetscViewerASCIIPopTab(viewer));
860:   } else if (isstring) {
861:     PetscCall(TaoGetType(tao, &type));
862:     PetscCall(PetscViewerStringSPrintf(viewer, " %-3.3s", type));
863:   }
864:   PetscFunctionReturn(PETSC_SUCCESS);
865: }

867: /*@
868:   TaoSetRecycleHistory - Sets the boolean flag to enable/disable re-using
869:   iterate information from the previous `TaoSolve()`. This feature is disabled by
870:   default.

872:   Logically Collective

874:   Input Parameters:
875: + tao     - the `Tao` context
876: - recycle - boolean flag

878:   Options Database Key:
879: . -tao_recycle_history (true|false) - reuse the history

881:   Level: intermediate

883:   Notes:
884:   For conjugate gradient methods (`TAOBNCG`), this re-uses the latest search direction
885:   from the previous `TaoSolve()` call when computing the first search direction in a
886:   new solution. By default, CG methods set the first search direction to the
887:   negative gradient.

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

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

896: .seealso: [](ch_tao), `Tao`, `TaoGetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
897: @*/
898: PetscErrorCode TaoSetRecycleHistory(Tao tao, PetscBool recycle)
899: {
900:   PetscFunctionBegin;
903:   tao->recycle = recycle;
904:   PetscFunctionReturn(PETSC_SUCCESS);
905: }

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

911:   Logically Collective

913:   Input Parameter:
914: . tao - the `Tao` context

916:   Output Parameter:
917: . recycle - boolean flag

919:   Level: intermediate

921: .seealso: [](ch_tao), `Tao`, `TaoSetRecycleHistory()`, `TAOBNCG`, `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTR`, `TAOBQNKTL`
922: @*/
923: PetscErrorCode TaoGetRecycleHistory(Tao tao, PetscBool *recycle)
924: {
925:   PetscFunctionBegin;
927:   PetscAssertPointer(recycle, 2);
928:   *recycle = tao->recycle;
929:   PetscFunctionReturn(PETSC_SUCCESS);
930: }

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

935:   Logically Collective

937:   Input Parameters:
938: + tao   - the `Tao` context
939: . gatol - stop if norm of gradient is less than this
940: . grtol - stop if relative norm of gradient is less than this
941: - gttol - stop if norm of gradient is reduced by this factor

943:   Options Database Keys:
944: + -tao_gatol gatol - Sets gatol
945: . -tao_grtol grtol - Sets grtol
946: - -tao_gttol gttol - Sets gttol

948:   Stopping Criteria\:
949: .vb
950:   ||g(X)||                            <= gatol
951:   ||g(X)|| / |f(X)|                   <= grtol
952:   ||g(X)|| / ||g(X0)||                <= gttol
953: .ve

955:   Level: beginner

957:   Notes:
958:   Use `PETSC_CURRENT` to leave one or more tolerances unchanged.

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

962:   Fortran Note:
963:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

965: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`
966: @*/
967: PetscErrorCode TaoSetTolerances(Tao tao, PetscReal gatol, PetscReal grtol, PetscReal gttol)
968: {
969:   PetscFunctionBegin;

975:   if (gatol == (PetscReal)PETSC_DETERMINE) {
976:     tao->gatol = tao->default_gatol;
977:   } else if (gatol != (PetscReal)PETSC_CURRENT) {
978:     PetscCheck(gatol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gatol not allowed");
979:     tao->gatol = gatol;
980:   }

982:   if (grtol == (PetscReal)PETSC_DETERMINE) {
983:     tao->grtol = tao->default_grtol;
984:   } else if (grtol != (PetscReal)PETSC_CURRENT) {
985:     PetscCheck(grtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative grtol not allowed");
986:     tao->grtol = grtol;
987:   }

989:   if (gttol == (PetscReal)PETSC_DETERMINE) {
990:     tao->gttol = tao->default_gttol;
991:   } else if (gttol != (PetscReal)PETSC_CURRENT) {
992:     PetscCheck(gttol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative gttol not allowed");
993:     tao->gttol = gttol;
994:   }
995:   PetscFunctionReturn(PETSC_SUCCESS);
996: }

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

1001:   Logically Collective

1003:   Input Parameters:
1004: + tao   - the `Tao` context
1005: . catol - absolute constraint tolerance, constraint norm must be less than `catol` for used for `gatol` convergence criteria
1006: - crtol - relative constraint tolerance, constraint norm must be less than `crtol` for used for `gatol`, `gttol` convergence criteria

1008:   Options Database Keys:
1009: + -tao_catol catol - Sets catol
1010: - -tao_crtol crtol - Sets crtol

1012:   Level: intermediate

1014:   Notes:
1015:   Use `PETSC_CURRENT` to leave one or tolerance unchanged.

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

1019:   Fortran Note:
1020:   Use `PETSC_CURRENT_REAL` or `PETSC_DETERMINE_REAL`

1022: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`, `TaoGetConstraintTolerances()`, `TaoSetTolerances()`
1023: @*/
1024: PetscErrorCode TaoSetConstraintTolerances(Tao tao, PetscReal catol, PetscReal crtol)
1025: {
1026:   PetscFunctionBegin;

1031:   if (catol == (PetscReal)PETSC_DETERMINE) {
1032:     tao->catol = tao->default_catol;
1033:   } else if (catol != (PetscReal)PETSC_CURRENT) {
1034:     PetscCheck(catol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative catol not allowed");
1035:     tao->catol = catol;
1036:   }

1038:   if (crtol == (PetscReal)PETSC_DETERMINE) {
1039:     tao->crtol = tao->default_crtol;
1040:   } else if (crtol != (PetscReal)PETSC_CURRENT) {
1041:     PetscCheck(crtol >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Negative crtol not allowed");
1042:     tao->crtol = crtol;
1043:   }
1044:   PetscFunctionReturn(PETSC_SUCCESS);
1045: }

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

1050:   Not Collective

1052:   Input Parameter:
1053: . tao - the `Tao` context

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

1059:   Level: intermediate

1061: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoGetTolerances()`, `TaoSetTolerances()`, `TaoSetConstraintTolerances()`
1062: @*/
1063: PetscErrorCode TaoGetConstraintTolerances(Tao tao, PetscReal *catol, PetscReal *crtol)
1064: {
1065:   PetscFunctionBegin;
1067:   if (catol) *catol = tao->catol;
1068:   if (crtol) *crtol = tao->crtol;
1069:   PetscFunctionReturn(PETSC_SUCCESS);
1070: }

1072: /*@
1073:   TaoSetFunctionLowerBound - Sets a bound on the solution objective value.
1074:   When an approximate solution with an objective value below this number
1075:   has been found, the solver will terminate.

1077:   Logically Collective

1079:   Input Parameters:
1080: + tao  - the Tao solver context
1081: - fmin - the tolerance

1083:   Options Database Key:
1084: . -tao_fmin fmin - sets the minimum function value

1086:   Level: intermediate

1088: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetTolerances()`
1089: @*/
1090: PetscErrorCode TaoSetFunctionLowerBound(Tao tao, PetscReal fmin)
1091: {
1092:   PetscFunctionBegin;
1095:   tao->fmin = fmin;
1096:   PetscFunctionReturn(PETSC_SUCCESS);
1097: }

1099: /*@
1100:   TaoGetFunctionLowerBound - Gets the bound on the solution objective value.
1101:   When an approximate solution with an objective value below this number
1102:   has been found, the solver will terminate.

1104:   Not Collective

1106:   Input Parameter:
1107: . tao - the `Tao` solver context

1109:   Output Parameter:
1110: . fmin - the minimum function value

1112:   Level: intermediate

1114: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetFunctionLowerBound()`
1115: @*/
1116: PetscErrorCode TaoGetFunctionLowerBound(Tao tao, PetscReal *fmin)
1117: {
1118:   PetscFunctionBegin;
1120:   PetscAssertPointer(fmin, 2);
1121:   *fmin = tao->fmin;
1122:   PetscFunctionReturn(PETSC_SUCCESS);
1123: }

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

1128:   Logically Collective

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

1134:   Options Database Key:
1135: . -tao_max_funcs nfcn - sets the maximum number of function evaluations

1137:   Level: intermediate

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

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

1145: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumIterations()`
1146: @*/
1147: PetscErrorCode TaoSetMaximumFunctionEvaluations(Tao tao, PetscInt nfcn)
1148: {
1149:   PetscFunctionBegin;
1152:   if (nfcn == PETSC_DETERMINE) {
1153:     tao->max_funcs = tao->default_max_funcs;
1154:   } else if (nfcn == PETSC_UNLIMITED || nfcn < 0) {
1155:     tao->max_funcs = PETSC_UNLIMITED;
1156:   } else {
1157:     PetscCheck(nfcn >= 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of function evaluations  must be positive");
1158:     tao->max_funcs = nfcn;
1159:   }
1160:   PetscFunctionReturn(PETSC_SUCCESS);
1161: }

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

1166:   Logically Collective

1168:   Input Parameter:
1169: . tao - the `Tao` solver context

1171:   Output Parameter:
1172: . nfcn - the maximum number of function evaluations

1174:   Level: intermediate

1176: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
1177: @*/
1178: PetscErrorCode TaoGetMaximumFunctionEvaluations(Tao tao, PetscInt *nfcn)
1179: {
1180:   PetscFunctionBegin;
1182:   PetscAssertPointer(nfcn, 2);
1183:   *nfcn = tao->max_funcs;
1184:   PetscFunctionReturn(PETSC_SUCCESS);
1185: }

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

1190:   Not Collective

1192:   Input Parameter:
1193: . tao - the `Tao` solver context

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

1198:   Level: intermediate

1200: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumFunctionEvaluations()`, `TaoGetMaximumFunctionEvaluations()`, `TaoGetMaximumIterations()`
1201: @*/
1202: PetscErrorCode TaoGetCurrentFunctionEvaluations(Tao tao, PetscInt *nfuncs)
1203: {
1204:   PetscFunctionBegin;
1206:   PetscAssertPointer(nfuncs, 2);
1207:   *nfuncs = PetscMax(tao->objective_term.term->nobj, tao->objective_term.term->nobjgrad);
1208:   PetscFunctionReturn(PETSC_SUCCESS);
1209: }

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

1214:   Logically Collective

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

1220:   Options Database Key:
1221: . -tao_max_it its - sets the maximum number of iterations

1223:   Level: intermediate

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

1228:   Developer Note:
1229:   Also accepts the deprecated negative values to indicate no limit

1231: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoSetMaximumFunctionEvaluations()`
1232: @*/
1233: PetscErrorCode TaoSetMaximumIterations(Tao tao, PetscInt maxits)
1234: {
1235:   PetscFunctionBegin;
1238:   if (maxits == PETSC_DETERMINE) {
1239:     tao->max_it = tao->default_max_it;
1240:   } else if (maxits == PETSC_UNLIMITED) {
1241:     tao->max_it = PETSC_INT_MAX;
1242:   } else {
1243:     PetscCheck(maxits > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations must be positive");
1244:     tao->max_it = maxits;
1245:   }
1246:   PetscFunctionReturn(PETSC_SUCCESS);
1247: }

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

1252:   Not Collective

1254:   Input Parameter:
1255: . tao - the `Tao` solver context

1257:   Output Parameter:
1258: . maxits - the maximum number of iterates

1260:   Level: intermediate

1262: .seealso: [](ch_tao), `Tao`, `TaoSetMaximumIterations()`, `TaoGetMaximumFunctionEvaluations()`
1263: @*/
1264: PetscErrorCode TaoGetMaximumIterations(Tao tao, PetscInt *maxits)
1265: {
1266:   PetscFunctionBegin;
1268:   PetscAssertPointer(maxits, 2);
1269:   *maxits = tao->max_it;
1270:   PetscFunctionReturn(PETSC_SUCCESS);
1271: }

1273: /*@
1274:   TaoSetInitialTrustRegionRadius - Sets the initial trust region radius.

1276:   Logically Collective

1278:   Input Parameters:
1279: + tao    - a `Tao` optimization solver
1280: - radius - the trust region radius

1282:   Options Database Key:
1283: . -tao_trust0 radius - sets initial trust region radius

1285:   Level: intermediate

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

1290: .seealso: [](ch_tao), `Tao`, `TaoGetTrustRegionRadius()`, `TaoSetTrustRegionTolerance()`, `TAONTR`
1291: @*/
1292: PetscErrorCode TaoSetInitialTrustRegionRadius(Tao tao, PetscReal radius)
1293: {
1294:   PetscFunctionBegin;
1297:   if (radius == PETSC_DETERMINE) {
1298:     tao->trust0 = tao->default_trust0;
1299:   } else {
1300:     PetscCheck(radius > 0, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_OUTOFRANGE, "Radius must be positive");
1301:     tao->trust0 = radius;
1302:   }
1303:   PetscFunctionReturn(PETSC_SUCCESS);
1304: }

1306: /*@
1307:   TaoGetInitialTrustRegionRadius - Gets the initial trust region radius.

1309:   Not Collective

1311:   Input Parameter:
1312: . tao - a `Tao` optimization solver

1314:   Output Parameter:
1315: . radius - the trust region radius

1317:   Level: intermediate

1319: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetCurrentTrustRegionRadius()`, `TAONTR`
1320: @*/
1321: PetscErrorCode TaoGetInitialTrustRegionRadius(Tao tao, PetscReal *radius)
1322: {
1323:   PetscFunctionBegin;
1325:   PetscAssertPointer(radius, 2);
1326:   *radius = tao->trust0;
1327:   PetscFunctionReturn(PETSC_SUCCESS);
1328: }

1330: /*@
1331:   TaoGetCurrentTrustRegionRadius - Gets the current trust region radius.

1333:   Not Collective

1335:   Input Parameter:
1336: . tao - a `Tao` optimization solver

1338:   Output Parameter:
1339: . radius - the trust region radius

1341:   Level: intermediate

1343: .seealso: [](ch_tao), `Tao`, `TaoSetInitialTrustRegionRadius()`, `TaoGetInitialTrustRegionRadius()`, `TAONTR`
1344: @*/
1345: PetscErrorCode TaoGetCurrentTrustRegionRadius(Tao tao, PetscReal *radius)
1346: {
1347:   PetscFunctionBegin;
1349:   PetscAssertPointer(radius, 2);
1350:   *radius = tao->trust;
1351:   PetscFunctionReturn(PETSC_SUCCESS);
1352: }

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

1357:   Not Collective

1359:   Input Parameter:
1360: . tao - the `Tao` context

1362:   Output Parameters:
1363: + gatol - stop if norm of gradient is less than this
1364: . grtol - stop if relative norm of gradient is less than this
1365: - gttol - stop if norm of gradient is reduced by a this factor

1367:   Level: intermediate

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

1372: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`
1373: @*/
1374: PetscErrorCode TaoGetTolerances(Tao tao, PetscReal *gatol, PetscReal *grtol, PetscReal *gttol)
1375: {
1376:   PetscFunctionBegin;
1378:   if (gatol) *gatol = tao->gatol;
1379:   if (grtol) *grtol = tao->grtol;
1380:   if (gttol) *gttol = tao->gttol;
1381:   PetscFunctionReturn(PETSC_SUCCESS);
1382: }

1384: /*@
1385:   TaoGetKSP - Gets the linear solver used by the optimization solver.

1387:   Not Collective

1389:   Input Parameter:
1390: . tao - the `Tao` solver

1392:   Output Parameter:
1393: . ksp - the `KSP` linear solver used in the optimization solver

1395:   Level: intermediate

1397: .seealso: [](ch_tao), `Tao`, `KSP`
1398: @*/
1399: PetscErrorCode TaoGetKSP(Tao tao, KSP *ksp)
1400: {
1401:   PetscFunctionBegin;
1403:   PetscAssertPointer(ksp, 2);
1404:   *ksp = tao->ksp;
1405:   PetscFunctionReturn(PETSC_SUCCESS);
1406: }

1408: /*@
1409:   TaoGetLinearSolveIterations - Gets the total number of linear iterations
1410:   used by the `Tao` solver

1412:   Not Collective

1414:   Input Parameter:
1415: . tao - the `Tao` context

1417:   Output Parameter:
1418: . lits - number of linear iterations

1420:   Level: intermediate

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

1425: .seealso: [](ch_tao), `Tao`, `TaoGetKSP()`
1426: @*/
1427: PetscErrorCode TaoGetLinearSolveIterations(Tao tao, PetscInt *lits)
1428: {
1429:   PetscFunctionBegin;
1431:   PetscAssertPointer(lits, 2);
1432:   *lits = tao->ksp_tot_its;
1433:   PetscFunctionReturn(PETSC_SUCCESS);
1434: }

1436: /*@
1437:   TaoGetLineSearch - Gets the line search used by the optimization solver.

1439:   Not Collective

1441:   Input Parameter:
1442: . tao - the `Tao` solver

1444:   Output Parameter:
1445: . ls - the line search used in the optimization solver

1447:   Level: intermediate

1449: .seealso: [](ch_tao), `Tao`, `TaoLineSearch`, `TaoLineSearchType`
1450: @*/
1451: PetscErrorCode TaoGetLineSearch(Tao tao, TaoLineSearch *ls)
1452: {
1453:   PetscFunctionBegin;
1455:   PetscAssertPointer(ls, 2);
1456:   *ls = tao->linesearch;
1457:   PetscFunctionReturn(PETSC_SUCCESS);
1458: }

1460: /*@
1461:   TaoAddLineSearchCounts - Adds the number of function evaluations spent
1462:   in the line search to the running total.

1464:   Input Parameters:
1465: . tao - the `Tao` solver

1467:   Level: developer

1469: .seealso: [](ch_tao), `Tao`, `TaoGetLineSearch()`, `TaoLineSearchApply()`
1470: @*/
1471: PetscErrorCode TaoAddLineSearchCounts(Tao tao)
1472: {
1473:   PetscBool flg;
1474:   PetscInt  nfeval, ngeval, nfgeval;

1476:   PetscFunctionBegin;
1478:   if (tao->linesearch) {
1479:     PetscCall(TaoLineSearchIsUsingTaoRoutines(tao->linesearch, &flg));
1480:     if (!flg) {
1481:       PetscCall(TaoLineSearchGetNumberFunctionEvaluations(tao->linesearch, &nfeval, &ngeval, &nfgeval));
1482:       tao->objective_term.term->nobj += nfeval;
1483:       tao->objective_term.term->ngrad += ngeval;
1484:       tao->objective_term.term->nobjgrad += nfgeval;
1485:     }
1486:   }
1487:   PetscFunctionReturn(PETSC_SUCCESS);
1488: }

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

1493:   Not Collective

1495:   Input Parameter:
1496: . tao - the `Tao` context

1498:   Output Parameter:
1499: . X - the current solution

1501:   Level: intermediate

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

1506: .seealso: [](ch_tao), `Tao`, `TaoSetSolution()`, `TaoSolve()`
1507: @*/
1508: PetscErrorCode TaoGetSolution(Tao tao, Vec *X)
1509: {
1510:   PetscFunctionBegin;
1512:   PetscAssertPointer(X, 2);
1513:   *X = tao->solution;
1514:   PetscFunctionReturn(PETSC_SUCCESS);
1515: }

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

1522:   Collective

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

1527:   Level: developer

1529:   Note:
1530:   This function does not reset the statistics of internal `TaoTerm`

1532: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoSolve()`
1533: @*/
1534: PetscErrorCode TaoResetStatistics(Tao tao)
1535: {
1536:   PetscFunctionBegin;
1538:   tao->niter        = 0;
1539:   tao->nres         = 0;
1540:   tao->njac         = 0;
1541:   tao->nconstraints = 0;
1542:   tao->ksp_its      = 0;
1543:   tao->ksp_tot_its  = 0;
1544:   tao->reason       = TAO_CONTINUE_ITERATING;
1545:   tao->residual     = 0.0;
1546:   tao->cnorm        = 0.0;
1547:   tao->step         = 0.0;
1548:   tao->lsflag       = PETSC_FALSE;
1549:   if (tao->hist_reset) tao->hist_len = 0;
1550:   PetscFunctionReturn(PETSC_SUCCESS);
1551: }

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

1558:   Logically Collective

1560:   Input Parameters:
1561: + tao  - The `Tao` solver
1562: . func - The function
1563: - ctx  - The update function context

1565:   Calling sequence of `func`:
1566: + tao - The optimizer context
1567: . it  - The current iteration index
1568: - ctx - The update context

1570:   Level: advanced

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

1576: .seealso: [](ch_tao), `Tao`, `TaoSolve()`
1577: @*/
1578: PetscErrorCode TaoSetUpdate(Tao tao, PetscErrorCode (*func)(Tao tao, PetscInt it, PetscCtx ctx), PetscCtx ctx)
1579: {
1580:   PetscFunctionBegin;
1582:   tao->ops->update = func;
1583:   tao->user_update = ctx;
1584:   PetscFunctionReturn(PETSC_SUCCESS);
1585: }

1587: /*@C
1588:   TaoSetConvergenceTest - Sets the function that is to be used to test
1589:   for convergence of the iterative minimization solution.  The new convergence
1590:   testing routine will replace Tao's default convergence test.

1592:   Logically Collective

1594:   Input Parameters:
1595: + tao  - the `Tao` object
1596: . conv - the routine to test for convergence
1597: - ctx  - [optional] context for private data for the convergence routine (may be `NULL`)

1599:   Calling sequence of `conv`:
1600: + tao - the `Tao` object
1601: - ctx - [optional] convergence context

1603:   Level: advanced

1605:   Note:
1606:   The new convergence testing routine should call `TaoSetConvergedReason()`.

1608: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergedReason()`, `TaoGetSolutionStatus()`, `TaoGetTolerances()`, `TaoMonitorSet()`
1609: @*/
1610: PetscErrorCode TaoSetConvergenceTest(Tao tao, PetscErrorCode (*conv)(Tao tao, PetscCtx ctx), PetscCtx ctx)
1611: {
1612:   PetscFunctionBegin;
1614:   tao->ops->convergencetest = conv;
1615:   tao->cnvP                 = ctx;
1616:   PetscFunctionReturn(PETSC_SUCCESS);
1617: }

1619: /*@C
1620:   TaoMonitorSet - Sets an additional function that is to be used at every
1621:   iteration of the solver to display the iteration's
1622:   progress.

1624:   Logically Collective

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

1632:   Calling sequence of `func`:
1633: + tao - the `Tao` solver context
1634: - ctx - [optional] monitoring context

1636:   Level: intermediate

1638:   Notes:
1639:   See `TaoSetFromOptions()` for a monitoring options.

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

1645:   Fortran Notes:
1646:   Only one monitor function may be set

1648: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoMonitorDefault()`, `TaoMonitorCancel()`, `TaoView()`, `PetscCtxDestroyFn`
1649: @*/
1650: PetscErrorCode TaoMonitorSet(Tao tao, PetscErrorCode (*func)(Tao tao, PetscCtx ctx), PetscCtx ctx, PetscCtxDestroyFn *dest)
1651: {
1652:   PetscFunctionBegin;
1654:   PetscCheck(tao->numbermonitors < MAXTAOMONITORS, PetscObjectComm((PetscObject)tao), PETSC_ERR_SUP, "Cannot attach another monitor -- max=%d", MAXTAOMONITORS);
1655:   for (PetscInt i = 0; i < tao->numbermonitors; i++) {
1656:     PetscBool identical;

1658:     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)func, ctx, dest, (PetscErrorCode (*)(void))(PetscVoidFn *)tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i], &identical));
1659:     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
1660:   }
1661:   tao->monitor[tao->numbermonitors]        = func;
1662:   tao->monitorcontext[tao->numbermonitors] = ctx;
1663:   tao->monitordestroy[tao->numbermonitors] = dest;
1664:   ++tao->numbermonitors;
1665:   PetscFunctionReturn(PETSC_SUCCESS);
1666: }

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

1671:   Logically Collective

1673:   Input Parameter:
1674: . tao - the `Tao` solver context

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

1681:   Level: advanced

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

1686: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1687: @*/
1688: PetscErrorCode TaoMonitorCancel(Tao tao)
1689: {
1690:   PetscFunctionBegin;
1692:   for (PetscInt i = 0; i < tao->numbermonitors; i++) {
1693:     if (tao->monitordestroy[i]) PetscCall((*tao->monitordestroy[i])(&tao->monitorcontext[i]));
1694:   }
1695:   tao->numbermonitors = 0;
1696:   PetscFunctionReturn(PETSC_SUCCESS);
1697: }

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

1702:   Collective

1704:   Input Parameters:
1705: + tao - the `Tao` context
1706: - vf  - `PetscViewerAndFormat` context

1708:   Options Database Key:
1709: . -tao_monitor - turn on default monitoring

1711:   Level: advanced

1713:   Note:
1714:   This monitor prints the function value and gradient
1715:   norm at each iteration.

1717: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
1718: @*/
1719: PetscErrorCode TaoMonitorDefault(Tao tao, PetscViewerAndFormat *vf)
1720: {
1721:   PetscViewer viewer = vf->viewer;
1722:   PetscBool   isascii;
1723:   PetscInt    tabs;

1725:   PetscFunctionBegin;
1727:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);

1729:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1730:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1731:   if (isascii) {
1732:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));

1734:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1735:     if (tao->niter == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
1736:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
1737:       tao->header_printed = PETSC_TRUE;
1738:     }
1739:     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", tao->niter));
1740:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)tao->fc));
1741:     if (tao->residual >= PETSC_INFINITY) {
1742:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: infinity \n"));
1743:     } else {
1744:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g \n", (double)tao->residual));
1745:     }
1746:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1747:   }
1748:   PetscCall(PetscViewerPopFormat(viewer));
1749:   PetscFunctionReturn(PETSC_SUCCESS);
1750: }

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

1755:   Collective

1757:   Input Parameters:
1758: + tao - the `Tao` context
1759: - vf  - `PetscViewerAndFormat` context

1761:   Options Database Key:
1762: . -tao_monitor_globalization - turn on monitoring with globalization information

1764:   Level: advanced

1766:   Note:
1767:   This monitor prints the function value and gradient norm at each
1768:   iteration, as well as the step size and trust radius. Note that the
1769:   step size and trust radius may be the same for some algorithms.

1771: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
1772: @*/
1773: PetscErrorCode TaoMonitorGlobalization(Tao tao, PetscViewerAndFormat *vf)
1774: {
1775:   PetscViewer viewer = vf->viewer;
1776:   PetscBool   isascii;
1777:   PetscInt    tabs;

1779:   PetscFunctionBegin;
1781:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);

1783:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1784:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1785:   if (isascii) {
1786:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
1787:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1788:     if (tao->niter == 0 && ((PetscObject)tao)->prefix && !tao->header_printed) {
1789:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Iteration information for %s solve.\n", ((PetscObject)tao)->prefix));
1790:       tao->header_printed = PETSC_TRUE;
1791:     }
1792:     PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " TAO,", tao->niter));
1793:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Function value: %g,", (double)tao->fc));
1794:     if (tao->residual >= PETSC_INFINITY) {
1795:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: Inf,"));
1796:     } else {
1797:       PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g,", (double)tao->residual));
1798:     }
1799:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Step: %g,  Trust: %g\n", (double)tao->step, (double)tao->trust));
1800:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1801:   }
1802:   PetscCall(PetscViewerPopFormat(viewer));
1803:   PetscFunctionReturn(PETSC_SUCCESS);
1804: }

1806: /*@
1807:   TaoMonitorDefaultShort - Routine for monitoring progress of `TaoSolve()` that displays fewer digits than `TaoMonitorDefault()`

1809:   Collective

1811:   Input Parameters:
1812: + tao - the `Tao` context
1813: - vf  - `PetscViewerAndFormat` context

1815:   Options Database Key:
1816: . -tao_monitor_short - turn on default short monitoring

1818:   Level: advanced

1820:   Note:
1821:   Same as `TaoMonitorDefault()` except
1822:   it prints fewer digits of the residual as the residual gets smaller.
1823:   This is because the later digits are meaningless and are often
1824:   different on different machines; by using this routine different
1825:   machines will usually generate the same output.

1827: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1828: @*/
1829: PetscErrorCode TaoMonitorDefaultShort(Tao tao, PetscViewerAndFormat *vf)
1830: {
1831:   PetscViewer viewer = vf->viewer;
1832:   PetscBool   isascii;
1833:   PetscInt    tabs;
1834:   PetscReal   gnorm;

1836:   PetscFunctionBegin;
1838:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);

1840:   gnorm = tao->residual;
1841:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1842:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1843:   if (isascii) {
1844:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
1845:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1846:     PetscCall(PetscViewerASCIIPrintf(viewer, "iter = %3" PetscInt_FMT ",", tao->niter));
1847:     PetscCall(PetscViewerASCIIPrintf(viewer, " Function value %g,", (double)tao->fc));
1848:     if (gnorm >= PETSC_INFINITY) {
1849:       PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: infinity \n"));
1850:     } else if (gnorm > 1.e-6) {
1851:       PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: %g \n", (double)gnorm));
1852:     } else if (gnorm > 1.e-11) {
1853:       PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: < 1.0e-6 \n"));
1854:     } else {
1855:       PetscCall(PetscViewerASCIIPrintf(viewer, " Residual: < 1.0e-11 \n"));
1856:     }
1857:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1858:   }
1859:   PetscCall(PetscViewerPopFormat(viewer));
1860:   PetscFunctionReturn(PETSC_SUCCESS);
1861: }

1863: /*@
1864:   TaoMonitorConstraintNorm - same as `TaoMonitorDefault()` except
1865:   it prints the norm of the constraint function.

1867:   Collective

1869:   Input Parameters:
1870: + tao - the `Tao` context
1871: - vf  - `PetscViewerAndFormat` context

1873:   Options Database Key:
1874: . -tao_monitor_constraint_norm - monitor the constraints

1876:   Level: advanced

1878: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefault()`, `TaoMonitorSet()`
1879: @*/
1880: PetscErrorCode TaoMonitorConstraintNorm(Tao tao, PetscViewerAndFormat *vf)
1881: {
1882:   PetscViewer viewer = vf->viewer;
1883:   PetscBool   isascii;
1884:   PetscInt    tabs;

1886:   PetscFunctionBegin;
1888:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);

1890:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1891:   PetscCall(PetscViewerPushFormat(viewer, vf->format));
1892:   if (isascii) {
1893:     PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
1894:     PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel));
1895:     PetscCall(PetscViewerASCIIPrintf(viewer, "iter = %" PetscInt_FMT ",", tao->niter));
1896:     PetscCall(PetscViewerASCIIPrintf(viewer, " Function value: %g,", (double)tao->fc));
1897:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Residual: %g ", (double)tao->residual));
1898:     PetscCall(PetscViewerASCIIPrintf(viewer, "  Constraint: %g \n", (double)tao->cnorm));
1899:     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1900:   }
1901:   PetscCall(PetscViewerPopFormat(viewer));
1902:   PetscFunctionReturn(PETSC_SUCCESS);
1903: }

1905: /*@C
1906:   TaoMonitorSolution - Views the solution at each iteration of `TaoSolve()`

1908:   Collective

1910:   Input Parameters:
1911: + tao - the `Tao` context
1912: - vf  - `PetscViewerAndFormat` context

1914:   Options Database Key:
1915: . -tao_monitor_solution - view the solution

1917:   Level: advanced

1919: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
1920: @*/
1921: PetscErrorCode TaoMonitorSolution(Tao tao, PetscViewerAndFormat *vf)
1922: {
1923:   PetscFunctionBegin;
1925:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);
1926:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1927:   PetscCall(VecView(tao->solution, vf->viewer));
1928:   PetscCall(PetscViewerPopFormat(vf->viewer));
1929:   PetscFunctionReturn(PETSC_SUCCESS);
1930: }

1932: /*@C
1933:   TaoMonitorGradient - Views the gradient at each iteration of `TaoSolve()`

1935:   Collective

1937:   Input Parameters:
1938: + tao - the `Tao` context
1939: - vf  - `PetscViewerAndFormat` context

1941:   Options Database Key:
1942: . -tao_monitor_gradient - view the gradient at each iteration

1944:   Level: advanced

1946: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
1947: @*/
1948: PetscErrorCode TaoMonitorGradient(Tao tao, PetscViewerAndFormat *vf)
1949: {
1950:   PetscFunctionBegin;
1952:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);
1953:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1954:   PetscCall(VecView(tao->gradient, vf->viewer));
1955:   PetscCall(PetscViewerPopFormat(vf->viewer));
1956:   PetscFunctionReturn(PETSC_SUCCESS);
1957: }

1959: /*@C
1960:   TaoMonitorStep - Views the step-direction at each iteration of `TaoSolve()`

1962:   Collective

1964:   Input Parameters:
1965: + tao - the `Tao` context
1966: - vf  - `PetscViewerAndFormat` context

1968:   Options Database Key:
1969: . -tao_monitor_step - view the step vector at each iteration

1971:   Level: advanced

1973: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
1974: @*/
1975: PetscErrorCode TaoMonitorStep(Tao tao, PetscViewerAndFormat *vf)
1976: {
1977:   PetscFunctionBegin;
1979:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);
1980:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
1981:   PetscCall(VecView(tao->stepdirection, vf->viewer));
1982:   PetscCall(PetscViewerPopFormat(vf->viewer));
1983:   PetscFunctionReturn(PETSC_SUCCESS);
1984: }

1986: /*@C
1987:   TaoMonitorSolutionDraw - Plots the solution at each iteration of `TaoSolve()`

1989:   Collective

1991:   Input Parameters:
1992: + tao - the `Tao` context
1993: - ctx - `TaoMonitorDraw` context

1995:   Options Database Key:
1996: . -tao_monitor_solution_draw - draw the solution at each iteration

1998:   Level: advanced

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

2004: .seealso: [](ch_tao), `Tao`, `TaoMonitorSolution()`, `TaoMonitorSet()`, `TaoMonitorGradientDraw()`, `TaoMonitorDrawCtxCreate()`,
2005:           `TaoMonitorDrawCtxDestroy()`
2006: @*/
2007: PetscErrorCode TaoMonitorSolutionDraw(Tao tao, PetscCtx ctx)
2008: {
2009:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

2011:   PetscFunctionBegin;
2013:   if (!(((ictx->howoften > 0) && (!(tao->niter % ictx->howoften))) || ((ictx->howoften == -1) && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
2014:   PetscCall(VecView(tao->solution, ictx->viewer));
2015:   PetscFunctionReturn(PETSC_SUCCESS);
2016: }

2018: /*@C
2019:   TaoMonitorGradientDraw - Plots the gradient at each iteration of `TaoSolve()`

2021:   Collective

2023:   Input Parameters:
2024: + tao - the `Tao` context
2025: - ctx - `PetscViewer` context

2027:   Options Database Key:
2028: . -tao_monitor_gradient_draw - draw the gradient at each iteration

2030:   Level: advanced

2032: .seealso: [](ch_tao), `Tao`, `TaoMonitorGradient()`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw()`
2033: @*/
2034: PetscErrorCode TaoMonitorGradientDraw(Tao tao, PetscCtx ctx)
2035: {
2036:   TaoMonitorDrawCtx ictx = (TaoMonitorDrawCtx)ctx;

2038:   PetscFunctionBegin;
2040:   if (!(((ictx->howoften > 0) && (!(tao->niter % ictx->howoften))) || ((ictx->howoften == -1) && tao->reason))) PetscFunctionReturn(PETSC_SUCCESS);
2041:   PetscCall(VecView(tao->gradient, ictx->viewer));
2042:   PetscFunctionReturn(PETSC_SUCCESS);
2043: }

2045: /*@C
2046:   TaoMonitorStepDraw - Plots the step direction at each iteration of `TaoSolve()`

2048:   Collective

2050:   Input Parameters:
2051: + tao - the `Tao` context
2052: - ctx - the `PetscViewer` context

2054:   Options Database Key:
2055: . -tao_monitor_step_draw - draw the step direction at each iteration

2057:   Level: advanced

2059: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorSolutionDraw`
2060: @*/
2061: PetscErrorCode TaoMonitorStepDraw(Tao tao, PetscCtx ctx)
2062: {
2063:   PetscViewer viewer = (PetscViewer)ctx;

2065:   PetscFunctionBegin;
2068:   PetscCall(VecView(tao->stepdirection, viewer));
2069:   PetscFunctionReturn(PETSC_SUCCESS);
2070: }

2072: /*@C
2073:   TaoMonitorResidual - Views the least-squares residual at each iteration of `TaoSolve()`

2075:   Collective

2077:   Input Parameters:
2078: + tao - the `Tao` context
2079: - vf  - `PetscViewerAndFormat` context

2081:   Options Database Key:
2082: . -tao_monitor_ls_residual - view the residual at each iteration

2084:   Level: advanced

2086: .seealso: [](ch_tao), `Tao`, `TaoMonitorDefaultShort()`, `TaoMonitorSet()`
2087: @*/
2088: PetscErrorCode TaoMonitorResidual(Tao tao, PetscViewerAndFormat *vf)
2089: {
2090:   PetscFunctionBegin;
2092:   if (vf->view_interval > 0 && tao->niter % vf->view_interval) PetscFunctionReturn(PETSC_SUCCESS);
2093:   PetscCall(PetscViewerPushFormat(vf->viewer, vf->format));
2094:   PetscCall(VecView(tao->ls_res, vf->viewer));
2095:   PetscCall(PetscViewerPopFormat(vf->viewer));
2096:   PetscFunctionReturn(PETSC_SUCCESS);
2097: }

2099: /*@
2100:   TaoDefaultConvergenceTest - Determines whether the solver should continue iterating
2101:   or terminate.

2103:   Collective

2105:   Input Parameters:
2106: + tao   - the `Tao` context
2107: - dummy - unused dummy context

2109:   Level: developer

2111:   Notes:
2112:   This routine checks the residual in the optimality conditions, the
2113:   relative residual in the optimity conditions, the number of function
2114:   evaluations, and the function value to test convergence.  Some
2115:   solvers may use different convergence routines.

2117: .seealso: [](ch_tao), `Tao`, `TaoSetTolerances()`, `TaoGetConvergedReason()`, `TaoSetConvergedReason()`
2118: @*/
2119: PetscErrorCode TaoDefaultConvergenceTest(Tao tao, void *dummy)
2120: {
2121:   PetscInt           niter     = tao->niter, nfuncs;
2122:   PetscInt           max_funcs = tao->max_funcs;
2123:   PetscReal          gnorm = tao->residual, gnorm0 = tao->gnorm0;
2124:   PetscReal          f = tao->fc, steptol = tao->steptol, trradius = tao->step;
2125:   PetscReal          gatol = tao->gatol, grtol = tao->grtol, gttol = tao->gttol;
2126:   PetscReal          catol = tao->catol, crtol = tao->crtol;
2127:   PetscReal          fmin = tao->fmin, cnorm = tao->cnorm;
2128:   TaoConvergedReason reason = tao->reason;

2130:   PetscFunctionBegin;
2132:   if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);

2134:   PetscCall(TaoGetCurrentFunctionEvaluations(tao, &nfuncs));
2135:   if (PetscIsInfOrNanReal(f)) {
2136:     PetscCall(PetscInfo(tao, "Failed to converged, function value is infinity or NaN\n"));
2137:     reason = TAO_DIVERGED_NAN;
2138:   } else if (f <= fmin && cnorm <= catol) {
2139:     PetscCall(PetscInfo(tao, "Converged due to function value %g < minimum function value %g\n", (double)f, (double)fmin));
2140:     reason = TAO_CONVERGED_MINF;
2141:   } else if (gnorm <= gatol && cnorm <= catol) {
2142:     PetscCall(PetscInfo(tao, "Converged due to residual norm ||g(X)||=%g < %g\n", (double)gnorm, (double)gatol));
2143:     reason = TAO_CONVERGED_GATOL;
2144:   } else if (f != 0 && PetscAbsReal(gnorm / f) <= grtol && cnorm <= crtol) {
2145:     PetscCall(PetscInfo(tao, "Converged due to residual ||g(X)||/|f(X)| =%g < %g\n", (double)(gnorm / f), (double)grtol));
2146:     reason = TAO_CONVERGED_GRTOL;
2147:   } else if (gnorm0 != 0 && ((gttol == 0 && gnorm == 0) || gnorm / gnorm0 < gttol) && cnorm <= crtol) {
2148:     PetscCall(PetscInfo(tao, "Converged due to relative residual norm ||g(X)||/||g(X0)|| = %g < %g\n", (double)(gnorm / gnorm0), (double)gttol));
2149:     reason = TAO_CONVERGED_GTTOL;
2150:   } else if (max_funcs != PETSC_UNLIMITED && nfuncs > max_funcs) {
2151:     PetscCall(PetscInfo(tao, "Exceeded maximum number of function evaluations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", nfuncs, max_funcs));
2152:     reason = TAO_DIVERGED_MAXFCN;
2153:   } else if (tao->lsflag != 0) {
2154:     PetscCall(PetscInfo(tao, "Tao Line Search failure.\n"));
2155:     reason = TAO_DIVERGED_LS_FAILURE;
2156:   } else if (trradius < steptol && niter > 0) {
2157:     PetscCall(PetscInfo(tao, "Trust region/step size too small: %g < %g\n", (double)trradius, (double)steptol));
2158:     reason = TAO_CONVERGED_STEPTOL;
2159:   } else if (niter >= tao->max_it) {
2160:     PetscCall(PetscInfo(tao, "Exceeded maximum number of iterations: %" PetscInt_FMT " > %" PetscInt_FMT "\n", niter, tao->max_it));
2161:     reason = TAO_DIVERGED_MAXITS;
2162:   } else {
2163:     reason = TAO_CONTINUE_ITERATING;
2164:   }
2165:   tao->reason = reason;
2166:   PetscFunctionReturn(PETSC_SUCCESS);
2167: }

2169: /*@
2170:   TaoSetOptionsPrefix - Sets the prefix used for searching for all
2171:   Tao options in the database.

2173:   Logically Collective

2175:   Input Parameters:
2176: + tao - the `Tao` context
2177: - p   - the prefix string to prepend to all Tao option requests

2179:   Level: advanced

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

2185:   For example, to distinguish between the runtime options for two
2186:   different Tao solvers, one could call
2187: .vb
2188:       TaoSetOptionsPrefix(tao1,"sys1_")
2189:       TaoSetOptionsPrefix(tao2,"sys2_")
2190: .ve

2192:   This would enable use of different options for each system, such as
2193: .vb
2194:       -sys1_tao_method blmvm -sys1_tao_grtol 1.e-3
2195:       -sys2_tao_method lmvm  -sys2_tao_grtol 1.e-4
2196: .ve

2198: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoAppendOptionsPrefix()`, `TaoGetOptionsPrefix()`
2199: @*/
2200: PetscErrorCode TaoSetOptionsPrefix(Tao tao, const char p[])
2201: {
2202:   PetscFunctionBegin;
2204:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao, p));
2205:   if (tao->linesearch) PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, p));
2206:   if (tao->ksp) PetscCall(KSPSetOptionsPrefix(tao->ksp, p));
2207:   if (tao->callbacks) {
2208:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, p));
2209:     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
2210:   }
2211:   PetscFunctionReturn(PETSC_SUCCESS);
2212: }

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

2217:   Logically Collective

2219:   Input Parameters:
2220: + tao - the `Tao` solver context
2221: - p   - the prefix string to prepend to all `Tao` option requests

2223:   Level: advanced

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

2229: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoGetOptionsPrefix()`
2230: @*/
2231: PetscErrorCode TaoAppendOptionsPrefix(Tao tao, const char p[])
2232: {
2233:   PetscFunctionBegin;
2235:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao, p));
2236:   if (tao->linesearch) PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->linesearch, p));
2237:   if (tao->ksp) PetscCall(KSPAppendOptionsPrefix(tao->ksp, p));
2238:   if (tao->callbacks) {
2239:     const char *prefix;

2241:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao, &prefix));
2242:     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tao->callbacks, prefix));
2243:     PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)tao->callbacks, "callbacks_"));
2244:   }
2245:   PetscFunctionReturn(PETSC_SUCCESS);
2246: }

2248: /*@
2249:   TaoGetOptionsPrefix - Gets the prefix used for searching for all
2250:   Tao options in the database

2252:   Not Collective

2254:   Input Parameter:
2255: . tao - the `Tao` context

2257:   Output Parameter:
2258: . p - pointer to the prefix string used is returned

2260:   Level: advanced

2262: .seealso: [](ch_tao), `Tao`, `TaoSetFromOptions()`, `TaoSetOptionsPrefix()`, `TaoAppendOptionsPrefix()`
2263: @*/
2264: PetscErrorCode TaoGetOptionsPrefix(Tao tao, const char *p[])
2265: {
2266:   PetscFunctionBegin;
2268:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)tao, p));
2269:   PetscFunctionReturn(PETSC_SUCCESS);
2270: }

2272: /*@
2273:   TaoSetType - Sets the `TaoType` for the minimization solver.

2275:   Collective

2277:   Input Parameters:
2278: + tao  - the `Tao` solver context
2279: - type - a known method

2281:   Options Database Key:
2282: . -tao_type type - Sets the method; see `TaoType`

2284:   Level: intermediate

2286:   Note:
2287:   Calling this function resets the convergence test to `TaoDefaultConvergenceTest()`.
2288:   If a custom convergence test has been set with `TaoSetConvergenceTest()`, it must
2289:   be set again after calling `TaoSetType()`.

2291: .seealso: [](ch_tao), `Tao`, `TaoCreate()`, `TaoGetType()`, `TaoType`
2292: @*/
2293: PetscErrorCode TaoSetType(Tao tao, TaoType type)
2294: {
2295:   PetscErrorCode (*create_xxx)(Tao);
2296:   PetscBool issame;

2298:   PetscFunctionBegin;

2301:   PetscCall(PetscObjectTypeCompare((PetscObject)tao, type, &issame));
2302:   if (issame) PetscFunctionReturn(PETSC_SUCCESS);

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

2307:   /* Destroy the existing solver information */
2308:   PetscTryTypeMethod(tao, destroy);
2309:   PetscCall(KSPDestroy(&tao->ksp));
2310:   PetscCall(TaoLineSearchDestroy(&tao->linesearch));

2312:   /* Reinitialize type-specific function pointers in TaoOps structure */
2313:   tao->ops->setup           = NULL;
2314:   tao->ops->computedual     = NULL;
2315:   tao->ops->solve           = NULL;
2316:   tao->ops->view            = NULL;
2317:   tao->ops->setfromoptions  = NULL;
2318:   tao->ops->destroy         = NULL;
2319:   tao->ops->convergencetest = TaoDefaultConvergenceTest;

2321:   tao->setupcalled           = PETSC_FALSE;
2322:   tao->uses_gradient         = PETSC_FALSE;
2323:   tao->uses_hessian_matrices = PETSC_FALSE;

2325:   PetscCall((*create_xxx)(tao));
2326:   PetscCall(PetscObjectChangeTypeName((PetscObject)tao, type));
2327:   PetscFunctionReturn(PETSC_SUCCESS);
2328: }

2330: /*@C
2331:   TaoRegister - Adds a method to the Tao package for minimization.

2333:   Not Collective, No Fortran Support

2335:   Input Parameters:
2336: + sname - name of a new user-defined solver
2337: - func  - routine to create `TaoType` specific method context

2339:   Calling sequence of `func`:
2340: . tao - the `Tao` object to be created

2342:   Example Usage:
2343: .vb
2344:    TaoRegister("my_solver", MySolverCreate);
2345: .ve

2347:   Then, your solver can be chosen with the procedural interface via
2348: .vb
2349:   TaoSetType(tao, "my_solver")
2350: .ve
2351:   or at runtime via the option
2352: .vb
2353:   -tao_type my_solver
2354: .ve

2356:   Level: advanced

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

2361: .seealso: [](ch_tao), `Tao`, `TaoSetType()`, `TaoRegisterAll()`, `TaoRegisterDestroy()`
2362: @*/
2363: PetscErrorCode TaoRegister(const char sname[], PetscErrorCode (*func)(Tao tao))
2364: {
2365:   PetscFunctionBegin;
2366:   PetscCall(TaoInitializePackage());
2367:   PetscCall(PetscFunctionListAdd(&TaoList, sname, func));
2368:   PetscFunctionReturn(PETSC_SUCCESS);
2369: }

2371: /*@C
2372:   TaoRegisterDestroy - Frees the list of minimization solvers that were
2373:   registered by `TaoRegister()`.

2375:   Not Collective

2377:   Level: advanced

2379: .seealso: [](ch_tao), `Tao`, `TaoRegisterAll()`, `TaoRegister()`
2380: @*/
2381: PetscErrorCode TaoRegisterDestroy(void)
2382: {
2383:   PetscFunctionBegin;
2384:   PetscCall(PetscFunctionListDestroy(&TaoList));
2385:   TaoRegisterAllCalled = PETSC_FALSE;
2386:   PetscFunctionReturn(PETSC_SUCCESS);
2387: }

2389: /*@
2390:   TaoGetIterationNumber - Gets the number of `TaoSolve()` iterations completed
2391:   at this time.

2393:   Not Collective

2395:   Input Parameter:
2396: . tao - the `Tao` context

2398:   Output Parameter:
2399: . iter - iteration number

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

2404:   Level: intermediate

2406: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetResidualNorm()`, `TaoGetObjective()`
2407: @*/
2408: PetscErrorCode TaoGetIterationNumber(Tao tao, PetscInt *iter)
2409: {
2410:   PetscFunctionBegin;
2412:   PetscAssertPointer(iter, 2);
2413:   *iter = tao->niter;
2414:   PetscFunctionReturn(PETSC_SUCCESS);
2415: }

2417: /*@
2418:   TaoGetResidualNorm - Gets the current value of the norm of the residual (gradient)
2419:   at this time.

2421:   Not Collective

2423:   Input Parameter:
2424: . tao - the `Tao` context

2426:   Output Parameter:
2427: . value - the current value

2429:   Level: intermediate

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

2435: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`, `TaoGetIterationNumber()`, `TaoGetObjective()`
2436: @*/
2437: PetscErrorCode TaoGetResidualNorm(Tao tao, PetscReal *value)
2438: {
2439:   PetscFunctionBegin;
2441:   PetscAssertPointer(value, 2);
2442:   *value = tao->residual;
2443:   PetscFunctionReturn(PETSC_SUCCESS);
2444: }

2446: /*@
2447:   TaoSetIterationNumber - Sets the current iteration number.

2449:   Logically Collective

2451:   Input Parameters:
2452: + tao  - the `Tao` context
2453: - iter - iteration number

2455:   Level: developer

2457: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2458: @*/
2459: PetscErrorCode TaoSetIterationNumber(Tao tao, PetscInt iter)
2460: {
2461:   PetscFunctionBegin;
2464:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
2465:   tao->niter = iter;
2466:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
2467:   PetscFunctionReturn(PETSC_SUCCESS);
2468: }

2470: /*@
2471:   TaoGetTotalIterationNumber - Gets the total number of `TaoSolve()` iterations
2472:   completed. This number keeps accumulating if multiple solves
2473:   are called with the `Tao` object.

2475:   Not Collective

2477:   Input Parameter:
2478: . tao - the `Tao` context

2480:   Output Parameter:
2481: . iter - number of iterations

2483:   Level: intermediate

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

2489: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2490: @*/
2491: PetscErrorCode TaoGetTotalIterationNumber(Tao tao, PetscInt *iter)
2492: {
2493:   PetscFunctionBegin;
2495:   PetscAssertPointer(iter, 2);
2496:   *iter = tao->ntotalits;
2497:   PetscFunctionReturn(PETSC_SUCCESS);
2498: }

2500: /*@
2501:   TaoSetTotalIterationNumber - Sets the current total iteration number.

2503:   Logically Collective

2505:   Input Parameters:
2506: + tao  - the `Tao` context
2507: - iter - the iteration number

2509:   Level: developer

2511: .seealso: [](ch_tao), `Tao`, `TaoGetLinearSolveIterations()`
2512: @*/
2513: PetscErrorCode TaoSetTotalIterationNumber(Tao tao, PetscInt iter)
2514: {
2515:   PetscFunctionBegin;
2518:   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)tao));
2519:   tao->ntotalits = iter;
2520:   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)tao));
2521:   PetscFunctionReturn(PETSC_SUCCESS);
2522: }

2524: /*@
2525:   TaoSetConvergedReason - Sets the termination flag on a `Tao` object

2527:   Logically Collective

2529:   Input Parameters:
2530: + tao    - the `Tao` context
2531: - reason - the `TaoConvergedReason`

2533:   Level: intermediate

2535: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`
2536: @*/
2537: PetscErrorCode TaoSetConvergedReason(Tao tao, TaoConvergedReason reason)
2538: {
2539:   PetscFunctionBegin;
2542:   tao->reason = reason;
2543:   PetscFunctionReturn(PETSC_SUCCESS);
2544: }

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

2549:   Not Collective

2551:   Input Parameter:
2552: . tao - the `Tao` solver context

2554:   Output Parameter:
2555: . reason - value of `TaoConvergedReason`

2557:   Level: intermediate

2559: .seealso: [](ch_tao), `Tao`, `TaoConvergedReason`, `TaoSetConvergenceTest()`, `TaoSetTolerances()`
2560: @*/
2561: PetscErrorCode TaoGetConvergedReason(Tao tao, TaoConvergedReason *reason)
2562: {
2563:   PetscFunctionBegin;
2565:   PetscAssertPointer(reason, 2);
2566:   *reason = tao->reason;
2567:   PetscFunctionReturn(PETSC_SUCCESS);
2568: }

2570: /*@
2571:   TaoGetSolutionStatus - Get the current iterate, objective value,
2572:   residual, infeasibility, and termination from a `Tao` object

2574:   Not Collective

2576:   Input Parameter:
2577: . tao - the `Tao` context

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

2587:   Level: intermediate

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

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

2594: .seealso: [](ch_tao), `TaoMonitor()`, `TaoGetConvergedReason()`
2595: @*/
2596: PetscErrorCode TaoGetSolutionStatus(Tao tao, PetscInt *its, PetscReal *f, PetscReal *gnorm, PetscReal *cnorm, PetscReal *xdiff, TaoConvergedReason *reason)
2597: {
2598:   PetscFunctionBegin;
2600:   if (its) *its = tao->niter;
2601:   if (f) *f = tao->fc;
2602:   if (gnorm) *gnorm = tao->residual;
2603:   if (cnorm) *cnorm = tao->cnorm;
2604:   if (reason) *reason = tao->reason;
2605:   if (xdiff) *xdiff = tao->step;
2606:   PetscFunctionReturn(PETSC_SUCCESS);
2607: }

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

2612:   Not Collective

2614:   Input Parameter:
2615: . tao - the `Tao` solver context

2617:   Output Parameter:
2618: . type - the `TaoType`

2620:   Level: intermediate

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

2625: .seealso: [](ch_tao), `Tao`, `TaoType`, `TaoSetType()`, `PetscObjectTypeCompare()`, `PetscObjectTypeCompareAny()`
2626: @*/
2627: PetscErrorCode TaoGetType(Tao tao, TaoType *type)
2628: {
2629:   PetscFunctionBegin;
2631:   PetscAssertPointer(type, 2);
2632:   *type = ((PetscObject)tao)->type_name;
2633:   PetscFunctionReturn(PETSC_SUCCESS);
2634: }

2636: /*@C
2637:   TaoMonitor - Monitor the solver and the current solution.  This
2638:   routine will record the iteration number and residual statistics,
2639:   and call any monitors specified by the user.

2641:   Input Parameters:
2642: + tao        - the `Tao` context
2643: . its        - the current iterate number (>=0)
2644: . f          - the current objective function value
2645: . res        - the gradient norm, square root of the duality gap, or other measure indicating distance from optimality.  This measure will be recorded and
2646:           used for some termination tests.
2647: . cnorm      - the infeasibility of the current solution with regard to the constraints.
2648: - steplength - multiple of the step direction added to the previous iterate.

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

2653:   Level: developer

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

2675: /*@
2676:   TaoSetConvergenceHistory - Sets the array used to hold the convergence history.

2678:   Logically Collective

2680:   Input Parameters:
2681: + tao   - the `Tao` solver context
2682: . obj   - array to hold objective value history
2683: . resid - array to hold residual history
2684: . cnorm - array to hold constraint violation history
2685: . lits  - integer array holds the number of linear iterations for each Tao iteration
2686: . na    - size of `obj`, `resid`, and `cnorm`
2687: - reset - `PETSC_TRUE` indicates each new minimization resets the history counter to zero,
2688:            else it continues storing new values for new minimizations after the old ones

2690:   Level: intermediate

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

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

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

2705: .seealso: [](ch_tao), `TaoGetConvergenceHistory()`
2706: @*/
2707: PetscErrorCode TaoSetConvergenceHistory(Tao tao, PetscReal obj[], PetscReal resid[], PetscReal cnorm[], PetscInt lits[], PetscInt na, PetscBool reset)
2708: {
2709:   PetscFunctionBegin;
2711:   if (obj) PetscAssertPointer(obj, 2);
2712:   if (resid) PetscAssertPointer(resid, 3);
2713:   if (cnorm) PetscAssertPointer(cnorm, 4);
2714:   if (lits) PetscAssertPointer(lits, 5);

2716:   if (na == PETSC_DECIDE || na == PETSC_CURRENT) na = 1000;
2717:   if (!obj && !resid && !cnorm && !lits) {
2718:     PetscCall(PetscCalloc4(na, &obj, na, &resid, na, &cnorm, na, &lits));
2719:     tao->hist_malloc = PETSC_TRUE;
2720:   }

2722:   tao->hist_obj   = obj;
2723:   tao->hist_resid = resid;
2724:   tao->hist_cnorm = cnorm;
2725:   tao->hist_lits  = lits;
2726:   tao->hist_max   = na;
2727:   tao->hist_reset = reset;
2728:   tao->hist_len   = 0;
2729:   PetscFunctionReturn(PETSC_SUCCESS);
2730: }

2732: /*@C
2733:   TaoGetConvergenceHistory - Gets the arrays used that hold the convergence history.

2735:   Collective

2737:   Input Parameter:
2738: . tao - the `Tao` context

2740:   Output Parameters:
2741: + obj   - array used to hold objective value history
2742: . resid - array used to hold residual history
2743: . cnorm - array used to hold constraint violation history
2744: . lits  - integer array used to hold linear solver iteration count
2745: - nhist - size of `obj`, `resid`, `cnorm`, and `lits`

2747:   Level: advanced

2749:   Notes:
2750:   This routine must be preceded by calls to `TaoSetConvergenceHistory()`
2751:   and `TaoSolve()`, otherwise it returns useless information.

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

2757:   Fortran Notes:
2758:   The calling sequence is
2759: .vb
2760:    call TaoGetConvergenceHistory(Tao tao, PetscInt nhist, PetscErrorCode ierr)
2761: .ve
2762:   In other words this gets the current number of entries in the history. Access the history through the array you passed to `TaoSetConvergenceHistory()`

2764: .seealso: [](ch_tao), `Tao`, `TaoSolve()`, `TaoSetConvergenceHistory()`
2765: @*/
2766: PetscErrorCode TaoGetConvergenceHistory(Tao tao, PetscReal **obj, PetscReal **resid, PetscReal **cnorm, PetscInt **lits, PetscInt *nhist)
2767: {
2768:   PetscFunctionBegin;
2770:   if (obj) *obj = tao->hist_obj;
2771:   if (cnorm) *cnorm = tao->hist_cnorm;
2772:   if (resid) *resid = tao->hist_resid;
2773:   if (lits) *lits = tao->hist_lits;
2774:   if (nhist) *nhist = tao->hist_len;
2775:   PetscFunctionReturn(PETSC_SUCCESS);
2776: }

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

2782:   Logically Collective

2784:   Input Parameters:
2785: + tao - the `Tao` context
2786: - ctx - the user context

2788:   Level: intermediate

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

2795: .seealso: [](ch_tao), `Tao`, `TaoGetApplicationContext()`
2796: @*/
2797: PetscErrorCode TaoSetApplicationContext(Tao tao, PetscCtx ctx)
2798: {
2799:   PetscFunctionBegin;
2801:   tao->ctx = ctx;
2802:   PetscFunctionReturn(PETSC_SUCCESS);
2803: }

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

2808:   Not Collective

2810:   Input Parameter:
2811: . tao - the `Tao` context

2813:   Output Parameter:
2814: . ctx - a pointer to the user context

2816:   Level: intermediate

2818:   Fortran Note:
2819:   This only works when the context is a Fortran derived type or a `PetscObject`. Define `ctx` with
2820: .vb
2821:   type(tUsertype), pointer :: ctx
2822: .ve

2824: .seealso: [](ch_tao), `Tao`, `TaoSetApplicationContext()`
2825: @*/
2826: PetscErrorCode TaoGetApplicationContext(Tao tao, PetscCtxRt ctx)
2827: {
2828:   PetscFunctionBegin;
2830:   PetscAssertPointer(ctx, 2);
2831:   *(void **)ctx = tao->ctx;
2832:   PetscFunctionReturn(PETSC_SUCCESS);
2833: }

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

2838:   Collective

2840:   Input Parameters:
2841: + tao - the `Tao` context
2842: - M   - matrix that defines the norm

2844:   Level: beginner

2846: .seealso: [](ch_tao), `Tao`, `TaoGetGradientNorm()`, `TaoGradientNorm()`
2847: @*/
2848: PetscErrorCode TaoSetGradientNorm(Tao tao, Mat M)
2849: {
2850:   PetscFunctionBegin;
2853:   PetscCall(PetscObjectReference((PetscObject)M));
2854:   PetscCall(MatDestroy(&tao->gradient_norm));
2855:   PetscCall(VecDestroy(&tao->gradient_norm_tmp));
2856:   tao->gradient_norm = M;
2857:   PetscCall(MatCreateVecs(M, NULL, &tao->gradient_norm_tmp));
2858:   PetscFunctionReturn(PETSC_SUCCESS);
2859: }

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

2864:   Not Collective

2866:   Input Parameter:
2867: . tao - the `Tao` context

2869:   Output Parameter:
2870: . M - gradient norm

2872:   Level: beginner

2874: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGradientNorm()`
2875: @*/
2876: PetscErrorCode TaoGetGradientNorm(Tao tao, Mat *M)
2877: {
2878:   PetscFunctionBegin;
2880:   PetscAssertPointer(M, 2);
2881:   *M = tao->gradient_norm;
2882:   PetscFunctionReturn(PETSC_SUCCESS);
2883: }

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

2888:   Collective

2890:   Input Parameters:
2891: + tao      - the `Tao` context
2892: . gradient - the gradient
2893: - type     - the norm type

2895:   Output Parameter:
2896: . gnorm - the gradient norm

2898:   Level: advanced

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

2903:   Developer Notes:
2904:   Should be named `TaoComputeGradientNorm()`.

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

2909: .seealso: [](ch_tao), `Tao`, `TaoSetGradientNorm()`, `TaoGetGradientNorm()`
2910: @*/
2911: PetscErrorCode TaoGradientNorm(Tao tao, Vec gradient, NormType type, PetscReal *gnorm)
2912: {
2913:   PetscFunctionBegin;
2917:   PetscAssertPointer(gnorm, 4);
2918:   if (tao->gradient_norm) {
2919:     PetscScalar gnorms;

2921:     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.");
2922:     PetscCall(MatMult(tao->gradient_norm, gradient, tao->gradient_norm_tmp));
2923:     PetscCall(VecDot(gradient, tao->gradient_norm_tmp, &gnorms));
2924:     *gnorm = PetscRealPart(PetscSqrtScalar(gnorms));
2925:   } else {
2926:     PetscCall(VecNorm(gradient, type, gnorm));
2927:   }
2928:   PetscFunctionReturn(PETSC_SUCCESS);
2929: }

2931: /*@C
2932:   TaoMonitorDrawCtxCreate - Creates the monitor context for `TaoMonitorSolutionDraw()`

2934:   Collective

2936:   Input Parameters:
2937: + comm     - the communicator to share the context
2938: . host     - the name of the X Windows host that will display the monitor
2939: . label    - the label to put at the top of the display window
2940: . x        - the horizontal coordinate of the lower left corner of the window to open
2941: . y        - the vertical coordinate of the lower left corner of the window to open
2942: . m        - the width of the window
2943: . n        - the height of the window
2944: - howoften - how many `Tao` iterations between displaying the monitor information

2946:   Output Parameter:
2947: . ctx - the monitor context

2949:   Options Database Keys:
2950: + -tao_monitor_solution_draw - use `TaoMonitorSolutionDraw()` to monitor the solution
2951: - -tao_draw_solution_initial - show initial guess as well as current solution

2953:   Level: intermediate

2955:   Note:
2956:   The context this creates, along with `TaoMonitorSolutionDraw()`, and `TaoMonitorDrawCtxDestroy()`
2957:   are passed to `TaoMonitorSet()`.

2959: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorDrawCtx()`
2960: @*/
2961: PetscErrorCode TaoMonitorDrawCtxCreate(MPI_Comm comm, const char host[], const char label[], int x, int y, int m, int n, PetscInt howoften, TaoMonitorDrawCtx *ctx)
2962: {
2963:   PetscFunctionBegin;
2964:   PetscCall(PetscNew(ctx));
2965:   PetscCall(PetscViewerDrawOpen(comm, host, label, x, y, m, n, &(*ctx)->viewer));
2966:   PetscCall(PetscViewerSetFromOptions((*ctx)->viewer));
2967:   (*ctx)->howoften = howoften;
2968:   PetscFunctionReturn(PETSC_SUCCESS);
2969: }

2971: /*@C
2972:   TaoMonitorDrawCtxDestroy - Destroys the monitor context for `TaoMonitorSolutionDraw()`

2974:   Collective

2976:   Input Parameter:
2977: . ictx - the monitor context

2979:   Level: intermediate

2981:   Note:
2982:   This is passed to `TaoMonitorSet()` as the final argument, along with `TaoMonitorSolutionDraw()`, and the context
2983:   obtained with `TaoMonitorDrawCtxCreate()`.

2985: .seealso: [](ch_tao), `Tao`, `TaoMonitorSet()`, `TaoMonitorDefault()`, `VecView()`, `TaoMonitorSolutionDraw()`
2986: @*/
2987: PetscErrorCode TaoMonitorDrawCtxDestroy(TaoMonitorDrawCtx *ictx)
2988: {
2989:   PetscFunctionBegin;
2990:   PetscCall(PetscViewerDestroy(&(*ictx)->viewer));
2991:   PetscCall(PetscFree(*ictx));
2992:   PetscFunctionReturn(PETSC_SUCCESS);
2993: }

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

3000:   Not collective

3002:   Input Parameter:
3003: . tao - a `Tao` context

3005:   Output Parameters:
3006: + scale  - the scale of the term
3007: . term   - a `TaoTerm` for the real-valued function defining the objective
3008: . params - the vector of parameters for `term`, or `NULL` if no parameters were specified for `term`
3009: - map    - a map from the solution space of `tao` to the solution space of `term`, if `NULL` then the map is the identity

3011:   Level: intermediate

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

3018:   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.

3020: .seealso: [](ch_tao), `Tao`, `TaoTerm`, `TAOTERMSUM`, `TaoAddTerm()`
3021: @*/
3022: PetscErrorCode TaoGetTerm(Tao tao, PetscReal *scale, TaoTerm *term, Vec *params, Mat *map)
3023: {
3024:   PetscFunctionBegin;
3026:   if (scale) PetscAssertPointer(scale, 2);
3027:   if (term) PetscAssertPointer(term, 3);
3028:   if (params) PetscAssertPointer(params, 4);
3029:   if (map) PetscAssertPointer(map, 5);
3030:   PetscCall(TaoTermMappingGetData(&tao->objective_term, NULL, scale, term, map));
3031:   if (params) *params = tao->objective_parameters;
3032:   PetscFunctionReturn(PETSC_SUCCESS);
3033: }

3035: /*@
3036:   TaoAddTerm - Add a `term` to the objective function. If `Tao` is empty,
3037:   `term` will be the objective of `Tao`.

3039:   Collective

3041:   Input Parameters:
3042: + tao    - a `Tao` solver context
3043: . 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.)
3044: . scale  - scaling coefficient for the new term
3045: . term   - the real-valued function defining the new term
3046: . params - (optional) parameters for the new term.  It is up to each implementation of `TaoTerm` to determine how it behaves when parameters are omitted.
3047: - map    - (optional) a map from the `tao` solution space to the `term` solution space; if `NULL` the map is assumed to be the identity

3049:   Level: beginner

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

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

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

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

3071: .seealso: [](ch_tao), `Tao`, `TaoTerm`, `TAOTERMSUM`, `TaoGetTerm()`
3072: @*/
3073: PetscErrorCode TaoAddTerm(Tao tao, const char prefix[], PetscReal scale, TaoTerm term, Vec params, Mat map)
3074: {
3075:   PetscBool is_sum, is_callback;
3076:   PetscInt  num_old_terms;
3077:   Vec      *vec_list = NULL;

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

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

3124:     PetscCall(TaoTermDuplicate(tao->objective_term.term, TAOTERM_DUPLICATE_SIZEONLY, &old_sum));
3125:     if (tao->objective_term.map) {
3126:       VecType     map_vectype;
3127:       VecType     param_vectype;
3128:       PetscLayout cmap, param_layout;

3130:       PetscCall(MatGetVecType(tao->objective_term.map, &map_vectype));
3131:       PetscCall(MatGetLayouts(tao->objective_term.map, NULL, &cmap));
3132:       PetscCall(TaoTermGetParametersVecType(old_sum, &param_vectype));
3133:       PetscCall(TaoTermGetParametersLayout(old_sum, &param_layout));

3135:       PetscCall(TaoTermSetSolutionVecType(old_sum, map_vectype));
3136:       PetscCall(TaoTermSetParametersVecType(old_sum, param_vectype));
3137:       PetscCall(TaoTermSetSolutionLayout(old_sum, cmap));
3138:       PetscCall(TaoTermSetParametersLayout(old_sum, param_layout));
3139:     }

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

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

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

3185:   Logically Collective

3187:   Input Parameters:
3188: + tao - the nonlinear solver context
3189: - dm  - the `DM`, cannot be `NULL`

3191:   Level: intermediate

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

3198: .seealso: [](ch_snes), `DM`, `TAO`, `TaoGetDM()`, `SNESSetDM()`, `SNESGetDM()`, `KSPSetDM()`, `KSPGetDM()`
3199: @*/
3200: PetscErrorCode TaoSetDM(Tao tao, DM dm)
3201: {
3202:   KSP ksp;

3204:   PetscFunctionBegin;
3207:   PetscCall(PetscObjectReference((PetscObject)dm));
3208:   PetscCall(DMDestroy(&tao->dm));
3209:   tao->dm = dm;

3211:   PetscCall(TaoGetKSP(tao, &ksp));
3212:   if (ksp) {
3213:     PetscCall(KSPSetDM(ksp, dm));
3214:     PetscCall(KSPSetDMActive(ksp, KSP_DMACTIVE_ALL, PETSC_FALSE));
3215:   }
3216:   PetscFunctionReturn(PETSC_SUCCESS);
3217: }

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

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

3224:   Input Parameter:
3225: . tao - the `TAO` context

3227:   Output Parameter:
3228: . dm - the `DM`

3230:   Level: intermediate

3232: .seealso: [](ch_snes), `DM`, `TAO`, `TaoSetDM()`, `SNESSetDM()`, `SNESGetDM()`, `KSPSetDM()`, `KSPGetDM()`
3233: @*/
3234: PetscErrorCode TaoGetDM(Tao tao, DM *dm)
3235: {
3236:   PetscFunctionBegin;
3238:   PetscAssertPointer(dm, 2);
3239:   if (!tao->dm) PetscCall(DMShellCreate(PetscObjectComm((PetscObject)tao), &tao->dm));
3240:   *dm = tao->dm;
3241:   PetscFunctionReturn(PETSC_SUCCESS);
3242: }