xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision 3850be85d423de4139c8d950c0ca17adc39e763f)
1737f463aSAlp Dener #include <../src/tao/leastsquares/impls/brgn/brgn.h>
2737f463aSAlp Dener 
3737f463aSAlp Dener static PetscErrorCode GNHessianProd(Mat H, Vec in, Vec out)
4737f463aSAlp Dener {
5737f463aSAlp Dener   TAO_BRGN              *gn;
6737f463aSAlp Dener   PetscErrorCode        ierr;
7737f463aSAlp Dener 
8737f463aSAlp Dener   PetscFunctionBegin;
9737f463aSAlp Dener   ierr = MatShellGetContext(H, &gn);CHKERRQ(ierr);
10737f463aSAlp Dener   ierr = MatMult(gn->subsolver->ls_jac, in, gn->r_work);CHKERRQ(ierr);
11737f463aSAlp Dener   ierr = MatMultTranspose(gn->subsolver->ls_jac, gn->r_work, out);CHKERRQ(ierr);
12737f463aSAlp Dener   ierr = VecAXPY(out, gn->lambda, in);CHKERRQ(ierr);
13737f463aSAlp Dener   PetscFunctionReturn(0);
14737f463aSAlp Dener }
15737f463aSAlp Dener 
16737f463aSAlp Dener static PetscErrorCode GNObjectiveGradientEval(Tao tao, Vec X, PetscReal *fcn, Vec G, void *ptr)
17737f463aSAlp Dener {
18737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
19737f463aSAlp Dener   PetscScalar           xnorm2;
20737f463aSAlp Dener   PetscErrorCode        ierr;
21737f463aSAlp Dener 
22737f463aSAlp Dener   PetscFunctionBegin;
23737f463aSAlp Dener   ierr = TaoComputeResidual(tao, X, tao->ls_res);CHKERRQ(ierr);
24737f463aSAlp Dener   ierr = VecDotBegin(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
25e1e80dc8SAlp Dener   ierr = VecAXPBYPCZ(gn->x_work, 1.0, -1.0, 0.0, X, gn->x_old);CHKERRQ(ierr);
26737f463aSAlp Dener   ierr = VecDotBegin(gn->x_work, gn->x_work, &xnorm2);CHKERRQ(ierr);
27737f463aSAlp Dener   ierr = VecDotEnd(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
28737f463aSAlp Dener   ierr = VecDotEnd(gn->x_work, gn->x_work, &xnorm2);CHKERRQ(ierr);
29e1e80dc8SAlp Dener   *fcn = 0.5*(*fcn) + 0.5*gn->lambda*xnorm2;
30737f463aSAlp Dener 
31737f463aSAlp Dener   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
32737f463aSAlp Dener   ierr = MatMultTranspose(tao->ls_jac, tao->ls_res, G);CHKERRQ(ierr);
33e1e80dc8SAlp Dener   ierr = VecAXPBYPCZ(G, gn->lambda, -gn->lambda, 1.0, X, gn->x_old);CHKERRQ(ierr);
34737f463aSAlp Dener   PetscFunctionReturn(0);
35737f463aSAlp Dener }
36737f463aSAlp Dener 
37737f463aSAlp Dener static PetscErrorCode GNComputeHessian(Tao tao, Vec X, Mat H, Mat Hpre, void *ptr)
38737f463aSAlp Dener {
39737f463aSAlp Dener   PetscErrorCode ierr;
40737f463aSAlp Dener 
41737f463aSAlp Dener   PetscFunctionBegin;
42e1e80dc8SAlp Dener   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
43e1e80dc8SAlp Dener   PetscFunctionReturn(0);
44e1e80dc8SAlp Dener }
45e1e80dc8SAlp Dener 
46e1e80dc8SAlp Dener static PetscErrorCode GNHookFunction(Tao tao, PetscInt iter)
47e1e80dc8SAlp Dener {
48e1e80dc8SAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->user_update;
49e1e80dc8SAlp Dener   PetscErrorCode        ierr;
50e1e80dc8SAlp Dener 
51e1e80dc8SAlp Dener   PetscFunctionBegin;
52e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
53e1e80dc8SAlp Dener   gn->parent->nfuncs = tao->nfuncs;
54e1e80dc8SAlp Dener   gn->parent->ngrads = tao->ngrads;
55e1e80dc8SAlp Dener   gn->parent->nfuncgrads = tao->nfuncgrads;
56e1e80dc8SAlp Dener   gn->parent->nhess = tao->nhess;
57e1e80dc8SAlp Dener   gn->parent->niter = tao->niter;
58e1e80dc8SAlp Dener   gn->parent->ksp_its = tao->ksp_its;
59e1e80dc8SAlp Dener   gn->parent->ksp_tot_its = tao->ksp_tot_its;
60e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(tao, &gn->parent->reason);CHKERRQ(ierr);
61e1e80dc8SAlp Dener   /* Update the solution vectors */
62e1e80dc8SAlp Dener   if (iter == 0) {
63e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
64e1e80dc8SAlp Dener   } else {
65e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->x_old);CHKERRQ(ierr);
66e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->parent->solution);CHKERRQ(ierr);
67e1e80dc8SAlp Dener   }
68e1e80dc8SAlp Dener   /* Update the gradient */
69e1e80dc8SAlp Dener   ierr = VecCopy(tao->gradient, gn->parent->gradient);CHKERRQ(ierr);
70e1e80dc8SAlp Dener   /* Call general purpose update function */
71e1e80dc8SAlp Dener   if (gn->parent->ops->update) {
72e1e80dc8SAlp Dener     ierr = (*gn->parent->ops->update)(gn->parent, gn->parent->niter);CHKERRQ(ierr);
73737f463aSAlp Dener   }
74737f463aSAlp Dener   PetscFunctionReturn(0);
75737f463aSAlp Dener }
76737f463aSAlp Dener 
77737f463aSAlp Dener static PetscErrorCode TaoSolve_BRGN(Tao tao)
78737f463aSAlp Dener {
79737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
80737f463aSAlp Dener   PetscErrorCode        ierr;
81737f463aSAlp Dener 
82737f463aSAlp Dener   PetscFunctionBegin;
83737f463aSAlp Dener   ierr = TaoSolve(gn->subsolver);CHKERRQ(ierr);
84e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
85e1e80dc8SAlp Dener   tao->nfuncs = gn->subsolver->nfuncs;
86e1e80dc8SAlp Dener   tao->ngrads = gn->subsolver->ngrads;
87e1e80dc8SAlp Dener   tao->nfuncgrads = gn->subsolver->nfuncgrads;
88e1e80dc8SAlp Dener   tao->nhess = gn->subsolver->nhess;
89e1e80dc8SAlp Dener   tao->niter = gn->subsolver->niter;
90e1e80dc8SAlp Dener   tao->ksp_its = gn->subsolver->ksp_its;
91e1e80dc8SAlp Dener   tao->ksp_tot_its = gn->subsolver->ksp_tot_its;
92e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(gn->subsolver, &tao->reason);CHKERRQ(ierr);
93e1e80dc8SAlp Dener   /* Update vectors */
94e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->solution, tao->solution);CHKERRQ(ierr);
95e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->gradient, tao->gradient);CHKERRQ(ierr);
96737f463aSAlp Dener   PetscFunctionReturn(0);
97737f463aSAlp Dener }
98737f463aSAlp Dener 
99737f463aSAlp Dener static PetscErrorCode TaoSetFromOptions_BRGN(PetscOptionItems *PetscOptionsObject,Tao tao)
100737f463aSAlp Dener {
101737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
102737f463aSAlp Dener   PetscErrorCode        ierr;
103737f463aSAlp Dener 
104737f463aSAlp Dener   PetscFunctionBegin;
105737f463aSAlp Dener   ierr = PetscOptionsHead(PetscOptionsObject,"Gauss-Newton method for least-squares problems using Tikhonov regularization");CHKERRQ(ierr);
106737f463aSAlp Dener   ierr = PetscOptionsReal("-tao_brgn_lambda", "Tikhonov regularization factor", "", gn->lambda, &gn->lambda, NULL);CHKERRQ(ierr);
107737f463aSAlp Dener   ierr = PetscOptionsTail();CHKERRQ(ierr);
108737f463aSAlp Dener   ierr = TaoSetFromOptions(gn->subsolver);CHKERRQ(ierr);
109737f463aSAlp Dener   PetscFunctionReturn(0);
110737f463aSAlp Dener }
111737f463aSAlp Dener 
112737f463aSAlp Dener static PetscErrorCode TaoView_BRGN(Tao tao, PetscViewer viewer)
113737f463aSAlp Dener {
114737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
115737f463aSAlp Dener   PetscErrorCode        ierr;
116737f463aSAlp Dener 
117737f463aSAlp Dener   PetscFunctionBegin;
118e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
119737f463aSAlp Dener   ierr = TaoView(gn->subsolver, viewer);CHKERRQ(ierr);
120e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
121737f463aSAlp Dener   PetscFunctionReturn(0);
122737f463aSAlp Dener }
123737f463aSAlp Dener 
124737f463aSAlp Dener static PetscErrorCode TaoSetUp_BRGN(Tao tao)
125737f463aSAlp Dener {
126737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
127737f463aSAlp Dener   PetscErrorCode        ierr;
128737f463aSAlp Dener   PetscBool             is_bnls, is_bntr, is_bntl;
129737f463aSAlp Dener   PetscInt              i, nx, Nx;
130737f463aSAlp Dener 
131737f463aSAlp Dener   PetscFunctionBegin;
132737f463aSAlp Dener   if (!tao->ls_res) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualRoutine() must be called before setup!");
133737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNLS, &is_bnls);CHKERRQ(ierr);
134737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTR, &is_bntr);CHKERRQ(ierr);
135737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTL, &is_bntl);CHKERRQ(ierr);
136737f463aSAlp Dener   if ((is_bnls || is_bntr || is_bntl) && !tao->ls_jac) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualJacobianRoutine() must be called before setup!");
137e1e80dc8SAlp Dener   if (!tao->gradient){
138e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &tao->gradient);CHKERRQ(ierr);
139e1e80dc8SAlp Dener   }
140737f463aSAlp Dener   if (!gn->x_work){
141737f463aSAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_work);CHKERRQ(ierr);
142737f463aSAlp Dener   }
143737f463aSAlp Dener   if (!gn->r_work){
144737f463aSAlp Dener     ierr = VecDuplicate(tao->ls_res, &gn->r_work);CHKERRQ(ierr);
145737f463aSAlp Dener   }
146e1e80dc8SAlp Dener   if (!gn->x_old) {
147e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_old);CHKERRQ(ierr);
148e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
149e1e80dc8SAlp Dener   }
150e1e80dc8SAlp Dener   if (!tao->setupcalled) {
151737f463aSAlp Dener     /* Hessian setup */
152737f463aSAlp Dener     ierr = VecGetLocalSize(tao->solution, &nx);CHKERRQ(ierr);
153737f463aSAlp Dener     ierr = VecGetSize(tao->solution, &Nx);CHKERRQ(ierr);
154737f463aSAlp Dener     ierr = MatSetSizes(gn->H, nx, nx, Nx, Nx);CHKERRQ(ierr);
155737f463aSAlp Dener     ierr = MatSetType(gn->H, MATSHELL);CHKERRQ(ierr);
156737f463aSAlp Dener     ierr = MatSetUp(gn->H);CHKERRQ(ierr);
157737f463aSAlp Dener     ierr = MatShellSetOperation(gn->H, MATOP_MULT, (void (*)(void))GNHessianProd);CHKERRQ(ierr);
158737f463aSAlp Dener     ierr = MatShellSetContext(gn->H, (void*)gn);CHKERRQ(ierr);
159737f463aSAlp Dener     /* Subsolver setup */
160e1e80dc8SAlp Dener     ierr = TaoSetUpdate(gn->subsolver, GNHookFunction, (void*)gn);CHKERRQ(ierr);
161737f463aSAlp Dener     ierr = TaoSetInitialVector(gn->subsolver, tao->solution);CHKERRQ(ierr);
162737f463aSAlp Dener     if (tao->bounded) {
163737f463aSAlp Dener       ierr = TaoSetVariableBounds(gn->subsolver, tao->XL, tao->XU);CHKERRQ(ierr);
164737f463aSAlp Dener     }
165737f463aSAlp Dener     ierr = TaoSetResidualRoutine(gn->subsolver, tao->ls_res, tao->ops->computeresidual, tao->user_lsresP);CHKERRQ(ierr);
1664ffbe8acSAlp Dener     ierr = TaoSetJacobianResidualRoutine(gn->subsolver, tao->ls_jac, tao->ls_jac, tao->ops->computeresidualjacobian, tao->user_lsjacP);CHKERRQ(ierr);
167737f463aSAlp Dener     ierr = TaoSetObjectiveAndGradientRoutine(gn->subsolver, GNObjectiveGradientEval, (void*)gn);CHKERRQ(ierr);
168737f463aSAlp Dener     ierr = TaoSetHessianRoutine(gn->subsolver, gn->H, gn->H, GNComputeHessian, (void*)gn);CHKERRQ(ierr);
169e1e80dc8SAlp Dener     /* Propagate some options down */
170e1e80dc8SAlp Dener     ierr = TaoSetTolerances(gn->subsolver, tao->gatol, tao->grtol, tao->gttol);CHKERRQ(ierr);
171e1e80dc8SAlp Dener     ierr = TaoSetMaximumIterations(gn->subsolver, tao->max_it);CHKERRQ(ierr);
172e1e80dc8SAlp Dener     ierr = TaoSetMaximumFunctionEvaluations(gn->subsolver, tao->max_funcs);CHKERRQ(ierr);
173737f463aSAlp Dener     for (i=0; i<tao->numbermonitors; ++i) {
174737f463aSAlp Dener       ierr = TaoSetMonitor(gn->subsolver, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]);CHKERRQ(ierr);
175737f463aSAlp Dener       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
176737f463aSAlp Dener     }
177737f463aSAlp Dener     ierr = TaoSetUp(gn->subsolver);CHKERRQ(ierr);
178e1e80dc8SAlp Dener   }
179737f463aSAlp Dener   PetscFunctionReturn(0);
180737f463aSAlp Dener }
181737f463aSAlp Dener 
182737f463aSAlp Dener static PetscErrorCode TaoDestroy_BRGN(Tao tao)
183737f463aSAlp Dener {
184737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
185737f463aSAlp Dener   PetscErrorCode        ierr;
186737f463aSAlp Dener 
187737f463aSAlp Dener   PetscFunctionBegin;
188737f463aSAlp Dener   if (tao->setupcalled) {
189e1e80dc8SAlp Dener     ierr = VecDestroy(&tao->gradient);CHKERRQ(ierr);
190737f463aSAlp Dener     ierr = VecDestroy(&gn->x_work);CHKERRQ(ierr);
191737f463aSAlp Dener     ierr = VecDestroy(&gn->r_work);CHKERRQ(ierr);
192e1e80dc8SAlp Dener     ierr = VecDestroy(&gn->x_old);CHKERRQ(ierr);
193737f463aSAlp Dener   }
194737f463aSAlp Dener   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
195737f463aSAlp Dener   ierr = TaoDestroy(&gn->subsolver);CHKERRQ(ierr);
196e1e80dc8SAlp Dener   gn->parent = NULL;
197737f463aSAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
198737f463aSAlp Dener   PetscFunctionReturn(0);
199737f463aSAlp Dener }
200737f463aSAlp Dener 
201*3850be85SAlp Dener /*MC
202*3850be85SAlp Dener   TAOBRGN - Bounded Regularized Gauss-Newton method for solving nonlinear least-squares
203*3850be85SAlp Dener             problems with bound constraints. This algorithm is a thin wrapper around TAOBNTL
204*3850be85SAlp Dener             that constructs the Guass-Newton problem with the user-provided least-squares
205*3850be85SAlp Dener             residual and Jacobian. The problem is regularized with an L2-norm proximal point
206*3850be85SAlp Dener             term.
207*3850be85SAlp Dener 
208*3850be85SAlp Dener   Options Database Keys:
209*3850be85SAlp Dener   + -tao_bqnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
210*3850be85SAlp Dener   . -tao_bqnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
211*3850be85SAlp Dener   . -tao_bqnk_update_type - trust radius update method ("step", "direction", "interpolation")
212*3850be85SAlp Dener   - -tao_bqnk_as_type - active-set estimation method ("none", "bertsekas")
213*3850be85SAlp Dener 
214*3850be85SAlp Dener   Level: beginner
215*3850be85SAlp Dener M*/
216737f463aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BRGN(Tao tao)
217737f463aSAlp Dener {
218737f463aSAlp Dener   TAO_BRGN       *gn;
219737f463aSAlp Dener   PetscErrorCode ierr;
220737f463aSAlp Dener 
221737f463aSAlp Dener   PetscFunctionBegin;
222737f463aSAlp Dener   ierr = PetscNewLog(tao,&gn);CHKERRQ(ierr);
223737f463aSAlp Dener 
224737f463aSAlp Dener   tao->ops->destroy = TaoDestroy_BRGN;
225737f463aSAlp Dener   tao->ops->setup = TaoSetUp_BRGN;
226737f463aSAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BRGN;
227737f463aSAlp Dener   tao->ops->view = TaoView_BRGN;
228737f463aSAlp Dener   tao->ops->solve = TaoSolve_BRGN;
229737f463aSAlp Dener 
230737f463aSAlp Dener   tao->data = (void*)gn;
231e1e80dc8SAlp Dener   gn->lambda = 1e-4;
232e1e80dc8SAlp Dener   gn->parent = tao;
233737f463aSAlp Dener 
234737f463aSAlp Dener   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &gn->H);CHKERRQ(ierr);
235737f463aSAlp Dener   ierr = MatSetOptionsPrefix(gn->H, "tao_brgn_hessian_");CHKERRQ(ierr);
236737f463aSAlp Dener 
237737f463aSAlp Dener   ierr = TaoCreate(PetscObjectComm((PetscObject)tao), &gn->subsolver);CHKERRQ(ierr);
238737f463aSAlp Dener   ierr = TaoSetType(gn->subsolver, TAOBNLS);CHKERRQ(ierr);
239737f463aSAlp Dener   ierr = TaoSetOptionsPrefix(gn->subsolver, "tao_brgn_subsolver_");CHKERRQ(ierr);
240e1e80dc8SAlp Dener   PetscFunctionReturn(0);
241e1e80dc8SAlp Dener }
242e1e80dc8SAlp Dener 
243e1e80dc8SAlp Dener /*@C
244e1e80dc8SAlp Dener   TaoBRGNGetSubsolver - Get the pointer to the subsolver inside BRGN
245e1e80dc8SAlp Dener 
246e1e80dc8SAlp Dener   Collective on Tao
247e1e80dc8SAlp Dener 
248e1e80dc8SAlp Dener   Level: developer
249e1e80dc8SAlp Dener 
250e1e80dc8SAlp Dener   Input Parameters:
251e1e80dc8SAlp Dener +  tao - the Tao solver context
252e1e80dc8SAlp Dener -  subsolver - the Tao sub-solver context
253e1e80dc8SAlp Dener @*/
254e1e80dc8SAlp Dener PetscErrorCode TaoBRGNGetSubsolver(Tao tao, Tao *subsolver)
255e1e80dc8SAlp Dener {
256e1e80dc8SAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
257e1e80dc8SAlp Dener 
258e1e80dc8SAlp Dener   PetscFunctionBegin;
259e1e80dc8SAlp Dener   *subsolver = gn->subsolver;
260737f463aSAlp Dener   PetscFunctionReturn(0);
261737f463aSAlp Dener }
262737f463aSAlp Dener 
263737f463aSAlp Dener /*@C
264737f463aSAlp Dener   TaoBRGNSetTikhonovLambda - Set the Tikhonov regularization factor for the Gauss-Newton least-squares algorithm
265737f463aSAlp Dener 
266737f463aSAlp Dener   Collective on Tao
267737f463aSAlp Dener 
268737f463aSAlp Dener   Level: developer
269737f463aSAlp Dener 
270737f463aSAlp Dener   Input Parameters:
271737f463aSAlp Dener +  tao - the Tao solver context
272737f463aSAlp Dener -  lambda - Tikhonov regularization factor
273737f463aSAlp Dener @*/
274737f463aSAlp Dener PetscErrorCode TaoBRGNSetTikhonovLambda(Tao tao, PetscReal lambda)
275737f463aSAlp Dener {
276737f463aSAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
277737f463aSAlp Dener 
278737f463aSAlp Dener   PetscFunctionBegin;
279737f463aSAlp Dener   gn->lambda = lambda;
280737f463aSAlp Dener   PetscFunctionReturn(0);
281737f463aSAlp Dener }
282