xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision 0d71dc2b6864a86bf8cca4de849a85878788a65c)
1737f463aSAlp Dener #include <../src/tao/leastsquares/impls/brgn/brgn.h>
2737f463aSAlp Dener 
3*0d71dc2bSXiang Huang /* Old code
4737f463aSAlp Dener static PetscErrorCode GNHessianProd(Mat H, Vec in, Vec out)
5737f463aSAlp Dener {
6737f463aSAlp Dener   TAO_BRGN              *gn;
7737f463aSAlp Dener   PetscErrorCode        ierr;
8737f463aSAlp Dener 
9737f463aSAlp Dener   PetscFunctionBegin;
10737f463aSAlp Dener   ierr = MatShellGetContext(H, &gn);CHKERRQ(ierr);
11737f463aSAlp Dener   ierr = MatMult(gn->subsolver->ls_jac, in, gn->r_work);CHKERRQ(ierr);
12737f463aSAlp Dener   ierr = MatMultTranspose(gn->subsolver->ls_jac, gn->r_work, out);CHKERRQ(ierr);
13737f463aSAlp Dener   ierr = VecAXPY(out, gn->lambda, in);CHKERRQ(ierr);
14737f463aSAlp Dener   PetscFunctionReturn(0);
15737f463aSAlp Dener }
16737f463aSAlp Dener 
17737f463aSAlp Dener static PetscErrorCode GNObjectiveGradientEval(Tao tao, Vec X, PetscReal *fcn, Vec G, void *ptr)
18737f463aSAlp Dener {
19737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
20737f463aSAlp Dener   PetscScalar           xnorm2;
21737f463aSAlp Dener   PetscErrorCode        ierr;
22737f463aSAlp Dener 
23737f463aSAlp Dener   PetscFunctionBegin;
24737f463aSAlp Dener   ierr = TaoComputeResidual(tao, X, tao->ls_res);CHKERRQ(ierr);
25737f463aSAlp Dener   ierr = VecDotBegin(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
26e1e80dc8SAlp Dener   ierr = VecAXPBYPCZ(gn->x_work, 1.0, -1.0, 0.0, X, gn->x_old);CHKERRQ(ierr);
27737f463aSAlp Dener   ierr = VecDotBegin(gn->x_work, gn->x_work, &xnorm2);CHKERRQ(ierr);
28737f463aSAlp Dener   ierr = VecDotEnd(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
29737f463aSAlp Dener   ierr = VecDotEnd(gn->x_work, gn->x_work, &xnorm2);CHKERRQ(ierr);
30e1e80dc8SAlp Dener   *fcn = 0.5*(*fcn) + 0.5*gn->lambda*xnorm2;
31737f463aSAlp Dener 
32737f463aSAlp Dener   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
33737f463aSAlp Dener   ierr = MatMultTranspose(tao->ls_jac, tao->ls_res, G);CHKERRQ(ierr);
34e1e80dc8SAlp Dener   ierr = VecAXPBYPCZ(G, gn->lambda, -gn->lambda, 1.0, X, gn->x_old);CHKERRQ(ierr);
35737f463aSAlp Dener   PetscFunctionReturn(0);
36737f463aSAlp Dener }
37*0d71dc2bSXiang Huang */
38*0d71dc2bSXiang Huang 
39*0d71dc2bSXiang Huang static PetscErrorCode GNHessianProd(Mat H, Vec in, Vec out)
40*0d71dc2bSXiang Huang {
41*0d71dc2bSXiang Huang   TAO_BRGN              *gn;
42*0d71dc2bSXiang Huang   PetscInt              N = 3; /* dimension of X hack, to change size 3 to VecGetSize() from Vec X*/
43*0d71dc2bSXiang Huang   PetscScalar           epsilon = 1e-6; /*XH: added epsilon to approximate L1-norm with sqrt(x^2+epsilon^2)-epsilon*/
44*0d71dc2bSXiang Huang   PetscErrorCode        ierr;
45*0d71dc2bSXiang Huang   Vec                   xE, tmp;          /* xE: vector sqrt(x.^2 + epsilon^2) that is reused multiple times */
46*0d71dc2bSXiang Huang 
47*0d71dc2bSXiang Huang   PetscFunctionBegin;
48*0d71dc2bSXiang Huang   /* Allocate vectors */
49*0d71dc2bSXiang Huang 
50*0d71dc2bSXiang Huang   /* XH: Use x_work or r_work instead and do not create new vectors */
51*0d71dc2bSXiang Huang   ierr = VecCreateSeq(MPI_COMM_SELF,N,&xE);CHKERRQ(ierr);
52*0d71dc2bSXiang Huang   ierr = VecCreateSeq(MPI_COMM_SELF,N,&tmp);CHKERRQ(ierr);
53*0d71dc2bSXiang Huang 
54*0d71dc2bSXiang Huang   ierr = MatShellGetContext(H, &gn);CHKERRQ(ierr);
55*0d71dc2bSXiang Huang   ierr = MatMult(gn->subsolver->ls_jac, in, gn->r_work);CHKERRQ(ierr);
56*0d71dc2bSXiang Huang   ierr = MatMultTranspose(gn->subsolver->ls_jac, gn->r_work, out);CHKERRQ(ierr);
57*0d71dc2bSXiang Huang 
58*0d71dc2bSXiang Huang   /* XH: Use the sparse diagonal vector diag that has already been computed.  Code should just be the VecAXPY() */
59*0d71dc2bSXiang Huang 
60*0d71dc2bSXiang Huang   /* out = out +  lambda*epsilon^2*(in./xE.^3) */
61*0d71dc2bSXiang Huang   /* xE = sqrt(x.^2+epsilon^2). Should we reuse code/result of xE from GNObjectiveGradientEval()?*/
62*0d71dc2bSXiang Huang   ierr = VecPointwiseMult(xE, gn->x_old, gn->x_old);CHKERRQ(ierr);  /* hack, todo: change to X, how to add X? */
63*0d71dc2bSXiang Huang   ierr = VecShift(xE, epsilon*epsilon);CHKERRQ(ierr);
64*0d71dc2bSXiang Huang   ierr = VecCopy(xE, tmp);CHKERRQ(ierr);                 /* tmp = xE.^2 */
65*0d71dc2bSXiang Huang   ierr = VecSqrtAbs(xE);CHKERRQ(ierr);
66*0d71dc2bSXiang Huang   ierr = VecPointwiseMult(tmp, tmp, xE);CHKERRQ(ierr);   /* tmp = xE.^3 */
67*0d71dc2bSXiang Huang   ierr = VecPointwiseDivide(tmp, in, tmp);CHKERRQ(ierr); /* tmp = in./xE.^3 */
68*0d71dc2bSXiang Huang   ierr = VecAXPY(out, gn->lambda * epsilon * epsilon, tmp);CHKERRQ(ierr);
69*0d71dc2bSXiang Huang 
70*0d71dc2bSXiang Huang   /* Free PETSc data structures */
71*0d71dc2bSXiang Huang   ierr = VecDestroy(&xE);CHKERRQ(ierr);
72*0d71dc2bSXiang Huang   ierr = VecDestroy(&tmp);CHKERRQ(ierr);
73*0d71dc2bSXiang Huang   PetscFunctionReturn(0);
74*0d71dc2bSXiang Huang }
75*0d71dc2bSXiang Huang 
76*0d71dc2bSXiang Huang static PetscErrorCode GNObjectiveGradientEval(Tao tao, Vec X, PetscReal *fcn, Vec G, void *ptr)
77*0d71dc2bSXiang Huang {
78*0d71dc2bSXiang Huang   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
79*0d71dc2bSXiang Huang   PetscInt              N = 3; /* dimension of X hack, to change size 3 to VecGetSize() from Vec X*/
80*0d71dc2bSXiang Huang   PetscScalar           xESum, epsilon = 1e-6;/* epsilon to approximate L1-norm with sqrt(x^2+epsilon^2)-epsilon*/
81*0d71dc2bSXiang Huang   PetscErrorCode        ierr;
82*0d71dc2bSXiang Huang   Vec                   xE;          /* xE: vector sqrt(x.^2 + epsilon^2) that is reused multiple times */
83*0d71dc2bSXiang Huang 
84*0d71dc2bSXiang Huang   PetscFunctionBegin;
85*0d71dc2bSXiang Huang   /* Allocate vectors */
86*0d71dc2bSXiang Huang 
87*0d71dc2bSXiang Huang   /* XH: Do no create vectors; use x_work or r_work */
88*0d71dc2bSXiang Huang   ierr = VecCreateSeq(MPI_COMM_SELF,N,&xE);CHKERRQ(ierr);
89*0d71dc2bSXiang Huang 
90*0d71dc2bSXiang Huang   ierr = TaoComputeResidual(tao, X, tao->ls_res);CHKERRQ(ierr);
91*0d71dc2bSXiang Huang   ierr = VecDotBegin(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
92*0d71dc2bSXiang Huang   ierr = VecDotEnd(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
93*0d71dc2bSXiang Huang 
94*0d71dc2bSXiang Huang   /* Compute xE = sqrt(x.^2+epsilon^2) */
95*0d71dc2bSXiang Huang 
96*0d71dc2bSXiang Huang   /* XH: Use epsilon from the gn structure */
97*0d71dc2bSXiang Huang   /* XH: Use VecGetSize() rather than N */
98*0d71dc2bSXiang Huang 
99*0d71dc2bSXiang Huang   ierr = VecPointwiseMult(xE, X, X);CHKERRQ(ierr);
100*0d71dc2bSXiang Huang   ierr = VecShift(xE, epsilon*epsilon);CHKERRQ(ierr);
101*0d71dc2bSXiang Huang   ierr = VecSqrtAbs(xE);CHKERRQ(ierr);
102*0d71dc2bSXiang Huang 
103*0d71dc2bSXiang Huang   ierr = VecSum(xE,&xESum);CHKERRQ(ierr);CHKERRQ(ierr);
104*0d71dc2bSXiang Huang   *fcn = 0.5*(*fcn) + gn->lambda*(xESum - N*epsilon);
105*0d71dc2bSXiang Huang 
106*0d71dc2bSXiang Huang   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
107*0d71dc2bSXiang Huang   ierr = MatMultTranspose(tao->ls_jac, tao->ls_res, G);CHKERRQ(ierr);
108*0d71dc2bSXiang Huang   /* G = G + lambda*(X./xE) */
109*0d71dc2bSXiang Huang   ierr = VecPointwiseDivide(xE, X, xE);CHKERRQ(ierr); /* reuse xE = X./xE */
110*0d71dc2bSXiang Huang   ierr = VecAXPY(G, gn->lambda, xE);CHKERRQ(ierr);
111*0d71dc2bSXiang Huang 
112*0d71dc2bSXiang Huang   /* Free PETSc data structures */
113*0d71dc2bSXiang Huang   ierr = VecDestroy(&xE);CHKERRQ(ierr);
114*0d71dc2bSXiang Huang 
115*0d71dc2bSXiang Huang   PetscFunctionReturn(0);
116*0d71dc2bSXiang Huang }
117*0d71dc2bSXiang Huang 
118737f463aSAlp Dener 
119737f463aSAlp Dener static PetscErrorCode GNComputeHessian(Tao tao, Vec X, Mat H, Mat Hpre, void *ptr)
120737f463aSAlp Dener {
121737f463aSAlp Dener   PetscErrorCode ierr;
122737f463aSAlp Dener 
123737f463aSAlp Dener   PetscFunctionBegin;
124e1e80dc8SAlp Dener   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
125*0d71dc2bSXiang Huang 
126*0d71dc2bSXiang Huang   /* XH: Calculate and store diagonal matrix as a vector; diag in the structure */
127e1e80dc8SAlp Dener   PetscFunctionReturn(0);
128e1e80dc8SAlp Dener }
129e1e80dc8SAlp Dener 
130e1e80dc8SAlp Dener static PetscErrorCode GNHookFunction(Tao tao, PetscInt iter)
131e1e80dc8SAlp Dener {
132e1e80dc8SAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->user_update;
133e1e80dc8SAlp Dener   PetscErrorCode        ierr;
134e1e80dc8SAlp Dener 
135e1e80dc8SAlp Dener   PetscFunctionBegin;
136e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
137e1e80dc8SAlp Dener   gn->parent->nfuncs = tao->nfuncs;
138e1e80dc8SAlp Dener   gn->parent->ngrads = tao->ngrads;
139e1e80dc8SAlp Dener   gn->parent->nfuncgrads = tao->nfuncgrads;
140e1e80dc8SAlp Dener   gn->parent->nhess = tao->nhess;
141e1e80dc8SAlp Dener   gn->parent->niter = tao->niter;
142e1e80dc8SAlp Dener   gn->parent->ksp_its = tao->ksp_its;
143e1e80dc8SAlp Dener   gn->parent->ksp_tot_its = tao->ksp_tot_its;
144e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(tao, &gn->parent->reason);CHKERRQ(ierr);
145e1e80dc8SAlp Dener   /* Update the solution vectors */
146e1e80dc8SAlp Dener   if (iter == 0) {
147e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
148e1e80dc8SAlp Dener   } else {
149e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->x_old);CHKERRQ(ierr);
150e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->parent->solution);CHKERRQ(ierr);
151e1e80dc8SAlp Dener   }
152e1e80dc8SAlp Dener   /* Update the gradient */
153e1e80dc8SAlp Dener   ierr = VecCopy(tao->gradient, gn->parent->gradient);CHKERRQ(ierr);
154e1e80dc8SAlp Dener   /* Call general purpose update function */
155e1e80dc8SAlp Dener   if (gn->parent->ops->update) {
156e1e80dc8SAlp Dener     ierr = (*gn->parent->ops->update)(gn->parent, gn->parent->niter);CHKERRQ(ierr);
157737f463aSAlp Dener   }
158737f463aSAlp Dener   PetscFunctionReturn(0);
159737f463aSAlp Dener }
160737f463aSAlp Dener 
161737f463aSAlp Dener static PetscErrorCode TaoSolve_BRGN(Tao tao)
162737f463aSAlp Dener {
163737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
164737f463aSAlp Dener   PetscErrorCode        ierr;
165737f463aSAlp Dener 
166737f463aSAlp Dener   PetscFunctionBegin;
167737f463aSAlp Dener   ierr = TaoSolve(gn->subsolver);CHKERRQ(ierr);
168e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
169e1e80dc8SAlp Dener   tao->nfuncs = gn->subsolver->nfuncs;
170e1e80dc8SAlp Dener   tao->ngrads = gn->subsolver->ngrads;
171e1e80dc8SAlp Dener   tao->nfuncgrads = gn->subsolver->nfuncgrads;
172e1e80dc8SAlp Dener   tao->nhess = gn->subsolver->nhess;
173e1e80dc8SAlp Dener   tao->niter = gn->subsolver->niter;
174e1e80dc8SAlp Dener   tao->ksp_its = gn->subsolver->ksp_its;
175e1e80dc8SAlp Dener   tao->ksp_tot_its = gn->subsolver->ksp_tot_its;
176e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(gn->subsolver, &tao->reason);CHKERRQ(ierr);
177e1e80dc8SAlp Dener   /* Update vectors */
178e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->solution, tao->solution);CHKERRQ(ierr);
179e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->gradient, tao->gradient);CHKERRQ(ierr);
180737f463aSAlp Dener   PetscFunctionReturn(0);
181737f463aSAlp Dener }
182737f463aSAlp Dener 
183737f463aSAlp Dener static PetscErrorCode TaoSetFromOptions_BRGN(PetscOptionItems *PetscOptionsObject,Tao tao)
184737f463aSAlp Dener {
185737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
186737f463aSAlp Dener   PetscErrorCode        ierr;
187737f463aSAlp Dener 
188*0d71dc2bSXiang Huang   /* XH: Read an option to change epsilon in the structure; follow the lambda function below */
189*0d71dc2bSXiang Huang 
190737f463aSAlp Dener   PetscFunctionBegin;
191737f463aSAlp Dener   ierr = PetscOptionsHead(PetscOptionsObject,"Gauss-Newton method for least-squares problems using Tikhonov regularization");CHKERRQ(ierr);
192737f463aSAlp Dener   ierr = PetscOptionsReal("-tao_brgn_lambda", "Tikhonov regularization factor", "", gn->lambda, &gn->lambda, NULL);CHKERRQ(ierr);
193737f463aSAlp Dener   ierr = PetscOptionsTail();CHKERRQ(ierr);
194737f463aSAlp Dener   ierr = TaoSetFromOptions(gn->subsolver);CHKERRQ(ierr);
195737f463aSAlp Dener   PetscFunctionReturn(0);
196737f463aSAlp Dener }
197737f463aSAlp Dener 
198737f463aSAlp Dener static PetscErrorCode TaoView_BRGN(Tao tao, PetscViewer viewer)
199737f463aSAlp Dener {
200737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
201737f463aSAlp Dener   PetscErrorCode        ierr;
202737f463aSAlp Dener 
203737f463aSAlp Dener   PetscFunctionBegin;
204e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
205737f463aSAlp Dener   ierr = TaoView(gn->subsolver, viewer);CHKERRQ(ierr);
206e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
207737f463aSAlp Dener   PetscFunctionReturn(0);
208737f463aSAlp Dener }
209737f463aSAlp Dener 
210737f463aSAlp Dener static PetscErrorCode TaoSetUp_BRGN(Tao tao)
211737f463aSAlp Dener {
212737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
213737f463aSAlp Dener   PetscErrorCode        ierr;
214737f463aSAlp Dener   PetscBool             is_bnls, is_bntr, is_bntl;
215737f463aSAlp Dener   PetscInt              i, nx, Nx;
216737f463aSAlp Dener 
217737f463aSAlp Dener   PetscFunctionBegin;
218737f463aSAlp Dener   if (!tao->ls_res) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualRoutine() must be called before setup!");
219737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNLS, &is_bnls);CHKERRQ(ierr);
220737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTR, &is_bntr);CHKERRQ(ierr);
221737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTL, &is_bntl);CHKERRQ(ierr);
222737f463aSAlp Dener   if ((is_bnls || is_bntr || is_bntl) && !tao->ls_jac) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualJacobianRoutine() must be called before setup!");
223e1e80dc8SAlp Dener   if (!tao->gradient){
224e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &tao->gradient);CHKERRQ(ierr);
225e1e80dc8SAlp Dener   }
226737f463aSAlp Dener   if (!gn->x_work){
227737f463aSAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_work);CHKERRQ(ierr);
228737f463aSAlp Dener   }
229737f463aSAlp Dener   if (!gn->r_work){
230737f463aSAlp Dener     ierr = VecDuplicate(tao->ls_res, &gn->r_work);CHKERRQ(ierr);
231737f463aSAlp Dener   }
232e1e80dc8SAlp Dener   if (!gn->x_old) {
233e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_old);CHKERRQ(ierr);
234e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
235e1e80dc8SAlp Dener   }
236*0d71dc2bSXiang Huang 
237*0d71dc2bSXiang Huang   /* XH: Create diag vector */
238*0d71dc2bSXiang Huang 
239e1e80dc8SAlp Dener   if (!tao->setupcalled) {
240737f463aSAlp Dener     /* Hessian setup */
241737f463aSAlp Dener     ierr = VecGetLocalSize(tao->solution, &nx);CHKERRQ(ierr);
242737f463aSAlp Dener     ierr = VecGetSize(tao->solution, &Nx);CHKERRQ(ierr);
243737f463aSAlp Dener     ierr = MatSetSizes(gn->H, nx, nx, Nx, Nx);CHKERRQ(ierr);
244737f463aSAlp Dener     ierr = MatSetType(gn->H, MATSHELL);CHKERRQ(ierr);
245737f463aSAlp Dener     ierr = MatSetUp(gn->H);CHKERRQ(ierr);
246737f463aSAlp Dener     ierr = MatShellSetOperation(gn->H, MATOP_MULT, (void (*)(void))GNHessianProd);CHKERRQ(ierr);
247737f463aSAlp Dener     ierr = MatShellSetContext(gn->H, (void*)gn);CHKERRQ(ierr);
248737f463aSAlp Dener     /* Subsolver setup */
249e1e80dc8SAlp Dener     ierr = TaoSetUpdate(gn->subsolver, GNHookFunction, (void*)gn);CHKERRQ(ierr);
250737f463aSAlp Dener     ierr = TaoSetInitialVector(gn->subsolver, tao->solution);CHKERRQ(ierr);
251737f463aSAlp Dener     if (tao->bounded) {
252737f463aSAlp Dener       ierr = TaoSetVariableBounds(gn->subsolver, tao->XL, tao->XU);CHKERRQ(ierr);
253737f463aSAlp Dener     }
254737f463aSAlp Dener     ierr = TaoSetResidualRoutine(gn->subsolver, tao->ls_res, tao->ops->computeresidual, tao->user_lsresP);CHKERRQ(ierr);
2554ffbe8acSAlp Dener     ierr = TaoSetJacobianResidualRoutine(gn->subsolver, tao->ls_jac, tao->ls_jac, tao->ops->computeresidualjacobian, tao->user_lsjacP);CHKERRQ(ierr);
256737f463aSAlp Dener     ierr = TaoSetObjectiveAndGradientRoutine(gn->subsolver, GNObjectiveGradientEval, (void*)gn);CHKERRQ(ierr);
257737f463aSAlp Dener     ierr = TaoSetHessianRoutine(gn->subsolver, gn->H, gn->H, GNComputeHessian, (void*)gn);CHKERRQ(ierr);
258e1e80dc8SAlp Dener     /* Propagate some options down */
259e1e80dc8SAlp Dener     ierr = TaoSetTolerances(gn->subsolver, tao->gatol, tao->grtol, tao->gttol);CHKERRQ(ierr);
260e1e80dc8SAlp Dener     ierr = TaoSetMaximumIterations(gn->subsolver, tao->max_it);CHKERRQ(ierr);
261e1e80dc8SAlp Dener     ierr = TaoSetMaximumFunctionEvaluations(gn->subsolver, tao->max_funcs);CHKERRQ(ierr);
262737f463aSAlp Dener     for (i=0; i<tao->numbermonitors; ++i) {
263737f463aSAlp Dener       ierr = TaoSetMonitor(gn->subsolver, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]);CHKERRQ(ierr);
264737f463aSAlp Dener       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
265737f463aSAlp Dener     }
266737f463aSAlp Dener     ierr = TaoSetUp(gn->subsolver);CHKERRQ(ierr);
267e1e80dc8SAlp Dener   }
268737f463aSAlp Dener   PetscFunctionReturn(0);
269737f463aSAlp Dener }
270737f463aSAlp Dener 
271737f463aSAlp Dener static PetscErrorCode TaoDestroy_BRGN(Tao tao)
272737f463aSAlp Dener {
273737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
274737f463aSAlp Dener   PetscErrorCode        ierr;
275737f463aSAlp Dener 
276737f463aSAlp Dener   PetscFunctionBegin;
277737f463aSAlp Dener   if (tao->setupcalled) {
278e1e80dc8SAlp Dener     ierr = VecDestroy(&tao->gradient);CHKERRQ(ierr);
279737f463aSAlp Dener     ierr = VecDestroy(&gn->x_work);CHKERRQ(ierr);
280737f463aSAlp Dener     ierr = VecDestroy(&gn->r_work);CHKERRQ(ierr);
281e1e80dc8SAlp Dener     ierr = VecDestroy(&gn->x_old);CHKERRQ(ierr);
282*0d71dc2bSXiang Huang 
283*0d71dc2bSXiang Huang     /* XH: Destroy diagonal vector */
284737f463aSAlp Dener   }
285737f463aSAlp Dener   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
286737f463aSAlp Dener   ierr = TaoDestroy(&gn->subsolver);CHKERRQ(ierr);
287e1e80dc8SAlp Dener   gn->parent = NULL;
288737f463aSAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
289737f463aSAlp Dener   PetscFunctionReturn(0);
290737f463aSAlp Dener }
291737f463aSAlp Dener 
2923850be85SAlp Dener /*MC
2933850be85SAlp Dener   TAOBRGN - Bounded Regularized Gauss-Newton method for solving nonlinear least-squares
2943850be85SAlp Dener             problems with bound constraints. This algorithm is a thin wrapper around TAOBNTL
2953850be85SAlp Dener             that constructs the Guass-Newton problem with the user-provided least-squares
2963850be85SAlp Dener             residual and Jacobian. The problem is regularized with an L2-norm proximal point
2973850be85SAlp Dener             term.
2983850be85SAlp Dener 
2993850be85SAlp Dener   Options Database Keys:
3003850be85SAlp Dener   + -tao_bqnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
3013850be85SAlp Dener   . -tao_bqnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
3023850be85SAlp Dener   . -tao_bqnk_update_type - trust radius update method ("step", "direction", "interpolation")
3033850be85SAlp Dener   - -tao_bqnk_as_type - active-set estimation method ("none", "bertsekas")
3043850be85SAlp Dener 
3053850be85SAlp Dener   Level: beginner
3063850be85SAlp Dener M*/
307737f463aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BRGN(Tao tao)
308737f463aSAlp Dener {
309737f463aSAlp Dener   TAO_BRGN       *gn;
310737f463aSAlp Dener   PetscErrorCode ierr;
311737f463aSAlp Dener 
312737f463aSAlp Dener   PetscFunctionBegin;
313737f463aSAlp Dener   ierr = PetscNewLog(tao,&gn);CHKERRQ(ierr);
314737f463aSAlp Dener 
315737f463aSAlp Dener   tao->ops->destroy = TaoDestroy_BRGN;
316737f463aSAlp Dener   tao->ops->setup = TaoSetUp_BRGN;
317737f463aSAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BRGN;
318737f463aSAlp Dener   tao->ops->view = TaoView_BRGN;
319737f463aSAlp Dener   tao->ops->solve = TaoSolve_BRGN;
320737f463aSAlp Dener 
321*0d71dc2bSXiang Huang   /* XH: initialize the epsilon */
322*0d71dc2bSXiang Huang 
323737f463aSAlp Dener   tao->data = (void*)gn;
324e1e80dc8SAlp Dener   gn->lambda = 1e-4;
325e1e80dc8SAlp Dener   gn->parent = tao;
326737f463aSAlp Dener 
327737f463aSAlp Dener   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &gn->H);CHKERRQ(ierr);
328737f463aSAlp Dener   ierr = MatSetOptionsPrefix(gn->H, "tao_brgn_hessian_");CHKERRQ(ierr);
329737f463aSAlp Dener 
330737f463aSAlp Dener   ierr = TaoCreate(PetscObjectComm((PetscObject)tao), &gn->subsolver);CHKERRQ(ierr);
331737f463aSAlp Dener   ierr = TaoSetType(gn->subsolver, TAOBNLS);CHKERRQ(ierr);
332737f463aSAlp Dener   ierr = TaoSetOptionsPrefix(gn->subsolver, "tao_brgn_subsolver_");CHKERRQ(ierr);
333e1e80dc8SAlp Dener   PetscFunctionReturn(0);
334e1e80dc8SAlp Dener }
335e1e80dc8SAlp Dener 
336e1e80dc8SAlp Dener /*@C
337e1e80dc8SAlp Dener   TaoBRGNGetSubsolver - Get the pointer to the subsolver inside BRGN
338e1e80dc8SAlp Dener 
339e1e80dc8SAlp Dener   Collective on Tao
340e1e80dc8SAlp Dener 
341e1e80dc8SAlp Dener   Level: developer
342e1e80dc8SAlp Dener 
343e1e80dc8SAlp Dener   Input Parameters:
344e1e80dc8SAlp Dener +  tao - the Tao solver context
345e1e80dc8SAlp Dener -  subsolver - the Tao sub-solver context
346e1e80dc8SAlp Dener @*/
347e1e80dc8SAlp Dener PetscErrorCode TaoBRGNGetSubsolver(Tao tao, Tao *subsolver)
348e1e80dc8SAlp Dener {
349e1e80dc8SAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
350e1e80dc8SAlp Dener 
351e1e80dc8SAlp Dener   PetscFunctionBegin;
352e1e80dc8SAlp Dener   *subsolver = gn->subsolver;
353737f463aSAlp Dener   PetscFunctionReturn(0);
354737f463aSAlp Dener }
355737f463aSAlp Dener 
356737f463aSAlp Dener /*@C
357737f463aSAlp Dener   TaoBRGNSetTikhonovLambda - Set the Tikhonov regularization factor for the Gauss-Newton least-squares algorithm
358737f463aSAlp Dener 
359737f463aSAlp Dener   Collective on Tao
360737f463aSAlp Dener 
361737f463aSAlp Dener   Level: developer
362737f463aSAlp Dener 
363737f463aSAlp Dener   Input Parameters:
364737f463aSAlp Dener +  tao - the Tao solver context
365737f463aSAlp Dener -  lambda - Tikhonov regularization factor
366737f463aSAlp Dener @*/
367737f463aSAlp Dener PetscErrorCode TaoBRGNSetTikhonovLambda(Tao tao, PetscReal lambda)
368737f463aSAlp Dener {
369737f463aSAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
370737f463aSAlp Dener 
371*0d71dc2bSXiang Huang   /* Initialize epsilon here */
372*0d71dc2bSXiang Huang 
373737f463aSAlp Dener   PetscFunctionBegin;
374737f463aSAlp Dener   gn->lambda = lambda;
375737f463aSAlp Dener   PetscFunctionReturn(0);
376737f463aSAlp Dener }
377*0d71dc2bSXiang Huang 
378*0d71dc2bSXiang Huang /* XH: Add a routine to TaoBRGNSetEpsilon; follow the SetTikhonovLambda function including the comment */
379*0d71dc2bSXiang Huang /* XH: Look for BRGNSetTikhonovLambda in the rest of the code; it will appear in a header file somewhere and add TaoBRGNSetEpsilon to that header with the same format */
380*0d71dc2bSXiang Huang /* XH: Need to add a line to the ftn-custom for the TaoBRGNSetEpsilon function */
381