Actual source code: rosenbrock1_taoterm.c

  1: /*  Include "petsctao.h" so we can use TAO solvers.  */
  2: #include <petsctao.h>
  3: #include "rosenbrock1.h" // defines AppCtx, AppCtxFormFunctionGradient(), and AppCtxFormHessian()

  5: static char help[] = "This example demonstrates use of the TaoTerm\n\
  6: interface for defining problems in the Tao library.  This example\n\
  7: should be compared to rosenbrock1.c, which uses the callback interface\n\
  8: to define the Rosenbrock function.\n";

 10: static PetscErrorCode FormFunctionGradient(TaoTerm, Vec, Vec, PetscReal *, Vec);
 11: static PetscErrorCode FormHessian(TaoTerm, Vec, Vec, Mat, Mat);
 12: static PetscErrorCode CreateSolutionVec(TaoTerm, Vec *);

 14: static PetscErrorCode CtxDestroy(PetscCtxRt ctx)
 15: {
 16:   PetscFunctionBeginUser;
 17:   PetscFunctionReturn(PETSC_SUCCESS);
 18: }

 20: int main(int argc, char **argv)
 21: {
 22:   TaoTerm     objective;
 23:   Tao         tao;  /* Tao solver context */
 24:   PetscMPIInt size; /* number of processes running */
 25:   AppCtx      user; /* user-defined application context */
 26:   MPI_Comm    comm;
 27:   PetscBool   test_gradient_fd_check = PETSC_FALSE; /* test that FD delta is preserved */
 28:   PetscReal   fd_delta_set           = 1.e-6;

 30:   /* Initialize TAO and PETSc */
 31:   PetscFunctionBeginUser;
 32:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
 33:   comm = PETSC_COMM_WORLD;
 34:   PetscCallMPI(MPI_Comm_size(comm, &size));
 35:   PetscCheck(size == 1, comm, PETSC_ERR_WRONG_MPI_SIZE, "Incorrect number of processors");

 37:   PetscOptionsBegin(comm, "", help, "none");
 38:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_gradient_fd_check", &test_gradient_fd_check, NULL));
 39:   PetscOptionsEnd();
 40:   /* Initialize problem parameters */
 41:   PetscCall(AppCtxInitialize(comm, &user));

 43:   /* Define the objective function */
 44:   PetscCall(TaoTermCreateShell(comm, &user, CtxDestroy, &objective));
 45:   PetscCall(TaoTermSetParametersMode(objective, TAOTERM_PARAMETERS_NONE));
 46:   PetscCall(TaoTermShellSetCreateSolutionVec(objective, CreateSolutionVec));
 47:   PetscCall(TaoTermShellSetObjectiveAndGradient(objective, FormFunctionGradient));
 48:   PetscCall(TaoTermShellSetCreateHessianMatrices(objective, TaoTermCreateHessianMatricesDefault));
 49:   if (user.jacobi_pc) PetscCall(TaoTermSetCreateHessianMode(objective, PETSC_FALSE, MATBAIJ, MATBAIJ));
 50:   else PetscCall(TaoTermSetCreateHessianMode(objective, PETSC_TRUE /* H == Hpre */, MATBAIJ, NULL));
 51:   PetscCall(TaoTermShellSetHessian(objective, FormHessian));

 53:   /* Create TAO solver with desired solution method */
 54:   PetscCall(TaoCreate(PETSC_COMM_SELF, &tao));
 55:   PetscCall(TaoSetType(tao, TAOLMVM));

 57:   if (user.use_fd) {
 58:     PetscCall(TaoTermSetFDDelta(objective, 7.e-9));
 59:     PetscCall(TaoTermComputeGradientSetUseFD(objective, PETSC_TRUE));
 60:     PetscCall(TaoTermComputeHessianSetUseFD(objective, PETSC_TRUE));
 61:   }
 62:   /* Set routines for function, gradient, hessian evaluation */
 63:   PetscCall(TaoAddTerm(tao, NULL, 1.0, objective, NULL, NULL));

 65:   /* Check for TAO command line options */
 66:   PetscCall(TaoSetFromOptions(tao));

 68:   /* Set FD delta for testing if requested (after options processing) */
 69:   if (test_gradient_fd_check) PetscCall(TaoTermSetFDDelta(objective, fd_delta_set));

 71:   /* SOLVE THE APPLICATION */
 72:   PetscCall(TaoSolve(tao));

 74:   /* Check that FD delta is preserved if testing */
 75:   if (test_gradient_fd_check) {
 76:     PetscReal fd_delta_get;

 78:     PetscCall(TaoTermGetFDDelta(objective, &fd_delta_get));
 79:     PetscCheck(PetscAbsReal(fd_delta_get - 1.e-6) < 1.e-15, comm, PETSC_ERR_PLIB, "FD delta changed: set %g, got %g", (double)fd_delta_set, (double)fd_delta_get);
 80:   }

 82:   /* Clean up */
 83:   PetscCall(AppCtxFinalize(&user, tao));
 84:   PetscCall(TaoDestroy(&tao));
 85:   PetscCall(TaoTermDestroy(&objective));

 87:   PetscCall(PetscFinalize());
 88:   return 0;
 89: }

 91: /*
 92:   FormFunctionGradient - Evaluates the function, f(X), and gradient, G(X).

 94:   Input Parameters:
 95: + term              - the `TaoTerm` for the objective function
 96: . X                 - input vector
 97: - parameters_unused - optional vector of parameters that this rosenbrock function does not use

 99:   Output Parameters:
100: + f - function value
101: - G - vector containing the newly evaluated gradient

103:   Note:
104:   Some optimization methods ask for the function and the gradient evaluation
105:   at the same time.  Evaluating both at once may be more efficient that
106:   evaluating each separately.
107: */
108: static PetscErrorCode FormFunctionGradient(TaoTerm term, Vec X, Vec parameters_unused, PetscReal *f, Vec G)
109: {
110:   AppCtx *user;

112:   PetscFunctionBeginUser;
113:   PetscCheck(parameters_unused == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Rosenbrock function does not take a parameter vector");
114:   PetscCall(TaoTermShellGetContext(term, &user));
115:   PetscCall(AppCtxFormFunctionGradient(user, X, f, G));
116:   PetscFunctionReturn(PETSC_SUCCESS);
117: }

119: /*
120:   FormHessian - Evaluates Hessian matrix.

122:   Input Parameters:
123: + tao    - the Tao context
124: . x      - input vector
125: . params - optional vector of parameters that this rosenbrock function does not use
126: - ptr    - optional user-defined context, as set by TaoSetHessian()

128:   Output Parameters:
129: + H    - Hessian matrix
130: - Hpre - Preconditioning matrix

132:   Note:  Providing the Hessian may not be necessary.  Only some solvers
133:   require this matrix.
134: */
135: static PetscErrorCode FormHessian(TaoTerm term, Vec X, Vec params, Mat H, Mat Hpre)
136: {
137:   AppCtx *user;

139:   PetscFunctionBeginUser;
140:   PetscCheck(params == NULL, PetscObjectComm((PetscObject)term), PETSC_ERR_ARG_WRONG, "Rosenbrock function does not take a parameter vector");
141:   PetscCall(TaoTermShellGetContext(term, &user));
142:   if (H) PetscCall(AppCtxFormHessian(user, X, H));
143:   if (Hpre && Hpre != H) {
144:     if (user->jacobi_pc) {
145:       Vec v;

147:       PetscCall(VecDuplicate(X, &v));
148:       PetscCall(MatGetDiagonal(H, v));
149:       PetscCall(MatZeroEntries(Hpre));
150:       PetscCall(MatDiagonalSet(Hpre, v, INSERT_VALUES));
151:       PetscCall(VecDestroy(&v));
152:     } else {
153:       if (H) PetscCall(MatCopy(H, Hpre, SAME_NONZERO_PATTERN));
154:       else PetscCall(AppCtxFormHessian(user, X, Hpre));
155:     }
156:   }
157:   PetscFunctionReturn(PETSC_SUCCESS);
158: }

160: static PetscErrorCode CreateSolutionVec(TaoTerm term, Vec *solution)
161: {
162:   AppCtx *user;

164:   PetscFunctionBeginUser;
165:   PetscCall(TaoTermShellGetContext(term, &user));
166:   PetscCall(AppCtxCreateSolution(user, solution));
167:   PetscFunctionReturn(PETSC_SUCCESS);
168: }

170: /*TEST

172:    build:
173:      requires: !complex !single !quad !defined(PETSC_USE_64BIT_INDICES) !__float128

175:    test:
176:      output_file: output/rosenbrock1_1.out
177:      args: -tao_monitor_short -tao_type nls -tao_gatol 1.e-4

179:    test:
180:      suffix: test_gradient
181:      args: -tao_monitor_short -tao_type nls -tao_gatol 1.e-4 -tao_test_gradient -tao_fd_delta 1.e-6 -n 4 -chained -tao_term_hessian_mat_type aij -alpha 49.0

183:    test:
184:      suffix: test_gradient_fd_check
185:      args: -tao_monitor_short -tao_type nls -tao_gatol 1.e-4 -tao_test_gradient
186:      args: -n 4 -chained -tao_term_hessian_mat_type aij -alpha 49.0 -test_gradient_fd_check 1

188:    test:
189:      suffix: fd_grad
190:      args: -tao_monitor_short -tao_type nls -tao_term_gradient_use_fd

192:    test:
193:      suffix: fd_hess
194:      args: -tao_monitor_short -tao_type nls -tao_term_hessian_use_fd

196:    test:
197:      suffix: fd_hess_diffpre
198:      args: -tao_monitor_short -tao_type nls -tao_term_hessian_use_fd -tao_term_hessian_pre_is_hessian 0

200:    test:
201:      suffix: use_fd
202:      args: -tao_monitor_short -tao_type nls -use_fd

204:    test:
205:      suffix: test_fd_hess
206:      args: -tao_type nls -tao_fd_hessian -tao_view -tao_monitor_short

208:    test:
209:      suffix: test_mf_hessian
210:      args: -tao_type nls -tao_term_hessian_mat_type mffd -tao_monitor_short -tao_view

212:    test:
213:      suffix: add_term
214:      args: -tao_type nls -tao_add_terms extra_ -extra_tao_term_type halfl2squared -tao_view ::ascii_info_detail

216:    test:
217:      suffix: separate_hessians
218:      requires: !single
219:      args: -tao_monitor_short -tao_type nls -tao_gatol 1.e-4 -tao_term_hessian_pre_is_hessian 0 -tao_term_hessian_mat_type aij -tao_term_hessian_pre_mat_type sbaij -tao_view

221: TEST*/