xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision 20fe612c600813636c9f603c3d964832e0d810cf)
1737f463aSAlp Dener #include <../src/tao/leastsquares/impls/brgn/brgn.h>
2737f463aSAlp Dener 
30d71dc2bSXiang 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 }
370d71dc2bSXiang Huang */
380d71dc2bSXiang Huang 
390d71dc2bSXiang Huang static PetscErrorCode GNHessianProd(Mat H, Vec in, Vec out)
400d71dc2bSXiang Huang {
410d71dc2bSXiang Huang   TAO_BRGN              *gn;
420d71dc2bSXiang Huang   PetscErrorCode        ierr;
430d71dc2bSXiang Huang 
440d71dc2bSXiang Huang   PetscFunctionBegin;
450d71dc2bSXiang Huang   ierr = MatShellGetContext(H, &gn);CHKERRQ(ierr);
460d71dc2bSXiang Huang   ierr = MatMult(gn->subsolver->ls_jac, in, gn->r_work);CHKERRQ(ierr);
470d71dc2bSXiang Huang   ierr = MatMultTranspose(gn->subsolver->ls_jac, gn->r_work, out);CHKERRQ(ierr);
487cea06e1SXiang Huang   /* out = out + lambda*D'*(diag.*(D*in)) */
497cea06e1SXiang Huang   ierr = MatMult(gn->D, in, gn->y);CHKERRQ(ierr);  /* y = D*in */
507cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->y_work, gn->diag, gn->y);CHKERRQ(ierr);     /* y_work = diag.*(D*in), where diag = epsilon^2 ./ sqrt(x.^2+epsilon^2).^3 */
517cea06e1SXiang Huang   ierr = MatMultTranspose(gn->D, gn->y_work, gn->x_work);CHKERRQ(ierr);   /* x_work = D'*(diag.*(D*in)) */
528ac80d48SXiang Huang   ierr = VecAXPY(out, gn->lambda, gn->x_work);CHKERRQ(ierr);
530d71dc2bSXiang Huang 
540d71dc2bSXiang Huang   PetscFunctionReturn(0);
550d71dc2bSXiang Huang }
560d71dc2bSXiang Huang 
570d71dc2bSXiang Huang static PetscErrorCode GNObjectiveGradientEval(Tao tao, Vec X, PetscReal *fcn, Vec G, void *ptr)
580d71dc2bSXiang Huang {
590d71dc2bSXiang Huang   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
607cea06e1SXiang Huang   PetscInt              Ny;                    /* dimension of D*X */
617cea06e1SXiang Huang   PetscScalar           yESum;
620d71dc2bSXiang Huang   PetscErrorCode        ierr;
630d71dc2bSXiang Huang 
640d71dc2bSXiang Huang   PetscFunctionBegin;
658ac80d48SXiang Huang   /* compute objective */
668ac80d48SXiang Huang   /* compute first term ||ls_res||^2 */
670d71dc2bSXiang Huang   ierr = TaoComputeResidual(tao, X, tao->ls_res);CHKERRQ(ierr);
680d71dc2bSXiang Huang   ierr = VecDotBegin(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
690d71dc2bSXiang Huang   ierr = VecDotEnd(tao->ls_res, tao->ls_res, fcn);CHKERRQ(ierr);
707cea06e1SXiang Huang   /* add the second term lambda*sum(sqrt(y.^2+epsilon^2) - epsilon), where y = D*x*/
717cea06e1SXiang Huang   ierr = MatMult(gn->D, X, gn->y);CHKERRQ(ierr);  /* y = D*x */
727cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->y_work, gn->y, gn->y);CHKERRQ(ierr);
737cea06e1SXiang Huang   ierr = VecShift(gn->y_work, gn->epsilon*gn->epsilon);CHKERRQ(ierr);
747cea06e1SXiang Huang   ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);      /* gn->y_work = sqrt(y.^2+epsilon^2) */
757cea06e1SXiang Huang   ierr = VecSum(gn->y_work, &yESum);CHKERRQ(ierr);CHKERRQ(ierr);
767cea06e1SXiang Huang   ierr = VecGetSize(gn->y, &Ny);CHKERRQ(ierr);
777cea06e1SXiang Huang   *fcn = 0.5*(*fcn) + gn->lambda*(yESum - Ny*gn->epsilon);
780d71dc2bSXiang Huang 
798ac80d48SXiang Huang   /* compute gradient G */
800d71dc2bSXiang Huang   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
810d71dc2bSXiang Huang   ierr = MatMultTranspose(tao->ls_jac, tao->ls_res, G);CHKERRQ(ierr);
827cea06e1SXiang Huang   /* compute G = G + lambda*D'*(y./sqrt(y.^2+epsilon^2)), where y = D*x */
837cea06e1SXiang Huang   ierr = VecPointwiseDivide(gn->y_work, gn->y, gn->y_work);CHKERRQ(ierr); /* reuse y_work = y./sqrt(y.^2+epsilon^2) */
847cea06e1SXiang Huang   ierr = MatMultTranspose(gn->D, gn->y_work, gn->x_work);CHKERRQ(ierr);
858ac80d48SXiang Huang   ierr = VecAXPY(G, gn->lambda, gn->x_work);CHKERRQ(ierr);
860d71dc2bSXiang Huang 
870d71dc2bSXiang Huang   PetscFunctionReturn(0);
880d71dc2bSXiang Huang }
890d71dc2bSXiang Huang 
90737f463aSAlp Dener 
91737f463aSAlp Dener static PetscErrorCode GNComputeHessian(Tao tao, Vec X, Mat H, Mat Hpre, void *ptr)
92737f463aSAlp Dener {
938ac80d48SXiang Huang   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
94737f463aSAlp Dener   PetscErrorCode ierr;
95737f463aSAlp Dener 
96737f463aSAlp Dener   PetscFunctionBegin;
97e1e80dc8SAlp Dener   ierr = TaoComputeResidualJacobian(tao, X, tao->ls_jac, tao->ls_jac_pre);CHKERRQ(ierr);
980d71dc2bSXiang Huang 
997cea06e1SXiang Huang   /* calculate and store diagonal matrix as a vector: diag = epsilon^2 ./ sqrt(x.^2+epsilon^2).^3* --> diag = epsilon^2 ./ sqrt(y.^2+epsilon^2).^3, where y = D*x */
1007cea06e1SXiang Huang   ierr = MatMult(gn->D, X, gn->y);CHKERRQ(ierr);  /* y = D*x */
1017cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->y_work, gn->y, gn->y);CHKERRQ(ierr);
1027cea06e1SXiang Huang   ierr = VecShift(gn->y_work, gn->epsilon*gn->epsilon);CHKERRQ(ierr);
1037cea06e1SXiang Huang   ierr = VecCopy(gn->y_work, gn->diag);CHKERRQ(ierr);                     /* gn->diag = y.^2+epsilon^2 */
1047cea06e1SXiang Huang   ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);                            /* gn->y_work = sqrt(y.^2+epsilon^2) */
1057cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->diag, gn->y_work, gn->diag);CHKERRQ(ierr);  /* gn->diag = sqrt(y.^2+epsilon^2).^3 */
1068ac80d48SXiang Huang   ierr = VecReciprocal(gn->diag);CHKERRQ(ierr);
1078ac80d48SXiang Huang   ierr = VecScale(gn->diag, gn->epsilon*gn->epsilon);CHKERRQ(ierr);
1088ac80d48SXiang Huang 
109e1e80dc8SAlp Dener   PetscFunctionReturn(0);
110e1e80dc8SAlp Dener }
111e1e80dc8SAlp Dener 
112e1e80dc8SAlp Dener static PetscErrorCode GNHookFunction(Tao tao, PetscInt iter)
113e1e80dc8SAlp Dener {
114e1e80dc8SAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->user_update;
115e1e80dc8SAlp Dener   PetscErrorCode        ierr;
116e1e80dc8SAlp Dener 
117e1e80dc8SAlp Dener   PetscFunctionBegin;
118e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
119e1e80dc8SAlp Dener   gn->parent->nfuncs = tao->nfuncs;
120e1e80dc8SAlp Dener   gn->parent->ngrads = tao->ngrads;
121e1e80dc8SAlp Dener   gn->parent->nfuncgrads = tao->nfuncgrads;
122e1e80dc8SAlp Dener   gn->parent->nhess = tao->nhess;
123e1e80dc8SAlp Dener   gn->parent->niter = tao->niter;
124e1e80dc8SAlp Dener   gn->parent->ksp_its = tao->ksp_its;
125e1e80dc8SAlp Dener   gn->parent->ksp_tot_its = tao->ksp_tot_its;
126e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(tao, &gn->parent->reason);CHKERRQ(ierr);
127e1e80dc8SAlp Dener   /* Update the solution vectors */
128e1e80dc8SAlp Dener   if (iter == 0) {
129e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
130e1e80dc8SAlp Dener   } else {
131e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->x_old);CHKERRQ(ierr);
132e1e80dc8SAlp Dener     ierr = VecCopy(tao->solution, gn->parent->solution);CHKERRQ(ierr);
133e1e80dc8SAlp Dener   }
134e1e80dc8SAlp Dener   /* Update the gradient */
135e1e80dc8SAlp Dener   ierr = VecCopy(tao->gradient, gn->parent->gradient);CHKERRQ(ierr);
136e1e80dc8SAlp Dener   /* Call general purpose update function */
137e1e80dc8SAlp Dener   if (gn->parent->ops->update) {
138e1e80dc8SAlp Dener     ierr = (*gn->parent->ops->update)(gn->parent, gn->parent->niter);CHKERRQ(ierr);
139737f463aSAlp Dener   }
140737f463aSAlp Dener   PetscFunctionReturn(0);
141737f463aSAlp Dener }
142737f463aSAlp Dener 
143737f463aSAlp Dener static PetscErrorCode TaoSolve_BRGN(Tao tao)
144737f463aSAlp Dener {
145737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
146737f463aSAlp Dener   PetscErrorCode        ierr;
147737f463aSAlp Dener 
148737f463aSAlp Dener   PetscFunctionBegin;
149737f463aSAlp Dener   ierr = TaoSolve(gn->subsolver);CHKERRQ(ierr);
150e1e80dc8SAlp Dener   /* Update basic tao information from the subsolver */
151e1e80dc8SAlp Dener   tao->nfuncs = gn->subsolver->nfuncs;
152e1e80dc8SAlp Dener   tao->ngrads = gn->subsolver->ngrads;
153e1e80dc8SAlp Dener   tao->nfuncgrads = gn->subsolver->nfuncgrads;
154e1e80dc8SAlp Dener   tao->nhess = gn->subsolver->nhess;
155e1e80dc8SAlp Dener   tao->niter = gn->subsolver->niter;
156e1e80dc8SAlp Dener   tao->ksp_its = gn->subsolver->ksp_its;
157e1e80dc8SAlp Dener   tao->ksp_tot_its = gn->subsolver->ksp_tot_its;
158e1e80dc8SAlp Dener   ierr = TaoGetConvergedReason(gn->subsolver, &tao->reason);CHKERRQ(ierr);
159e1e80dc8SAlp Dener   /* Update vectors */
160e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->solution, tao->solution);CHKERRQ(ierr);
161e1e80dc8SAlp Dener   ierr = VecCopy(gn->subsolver->gradient, tao->gradient);CHKERRQ(ierr);
162737f463aSAlp Dener   PetscFunctionReturn(0);
163737f463aSAlp Dener }
164737f463aSAlp Dener 
165737f463aSAlp Dener static PetscErrorCode TaoSetFromOptions_BRGN(PetscOptionItems *PetscOptionsObject,Tao tao)
166737f463aSAlp Dener {
167737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
168737f463aSAlp Dener   PetscErrorCode        ierr;
169737f463aSAlp Dener 
170737f463aSAlp Dener   PetscFunctionBegin;
1718ac80d48SXiang Huang   /* old Tikhonov regularization code
172737f463aSAlp Dener   ierr = PetscOptionsHead(PetscOptionsObject,"Gauss-Newton method for least-squares problems using Tikhonov regularization");CHKERRQ(ierr);
173737f463aSAlp Dener   ierr = PetscOptionsReal("-tao_brgn_lambda", "Tikhonov regularization factor", "", gn->lambda, &gn->lambda, NULL);CHKERRQ(ierr);
1748ac80d48SXiang Huang   */
1758ac80d48SXiang Huang   ierr = PetscOptionsHead(PetscOptionsObject,"least-squares problems with L1 regularizer: ||f(x)||^2 + lambda*||x||_1. Currently L1-norm is approximated with smooth form");CHKERRQ(ierr);
1768ac80d48SXiang Huang   ierr = PetscOptionsReal("-tao_brgn_lambda", "L1-norm regularizer weight", "", gn->lambda, &gn->lambda, NULL);CHKERRQ(ierr);
1778ac80d48SXiang Huang   ierr = PetscOptionsReal("-tao_brgn_epsilon", "L1-norm smooth approximation parameter: ||x||_1 = sum(sqrt(x.^2+epsilon^2)-epsilon)", "", gn->epsilon, &gn->epsilon, NULL);CHKERRQ(ierr);
178737f463aSAlp Dener   ierr = PetscOptionsTail();CHKERRQ(ierr);
179737f463aSAlp Dener   ierr = TaoSetFromOptions(gn->subsolver);CHKERRQ(ierr);
180737f463aSAlp Dener   PetscFunctionReturn(0);
181737f463aSAlp Dener }
182737f463aSAlp Dener 
183737f463aSAlp Dener static PetscErrorCode TaoView_BRGN(Tao tao, PetscViewer viewer)
184737f463aSAlp Dener {
185737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
186737f463aSAlp Dener   PetscErrorCode        ierr;
187737f463aSAlp Dener 
188737f463aSAlp Dener   PetscFunctionBegin;
189e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
190737f463aSAlp Dener   ierr = TaoView(gn->subsolver, viewer);CHKERRQ(ierr);
191e1e80dc8SAlp Dener   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
192737f463aSAlp Dener   PetscFunctionReturn(0);
193737f463aSAlp Dener }
194737f463aSAlp Dener 
195737f463aSAlp Dener static PetscErrorCode TaoSetUp_BRGN(Tao tao)
196737f463aSAlp Dener {
197737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
198737f463aSAlp Dener   PetscErrorCode        ierr;
199737f463aSAlp Dener   PetscBool             is_bnls, is_bntr, is_bntl;
2007cea06e1SXiang Huang   PetscInt              i, nx, Nx, Ny; /* XH: added Ny  for size of y=D*x*/
2017cea06e1SXiang Huang   PetscScalar           v = 1.0; /* XH: hack to set value of matrix */
202737f463aSAlp Dener 
203737f463aSAlp Dener   PetscFunctionBegin;
204737f463aSAlp Dener   if (!tao->ls_res) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualRoutine() must be called before setup!");
205737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNLS, &is_bnls);CHKERRQ(ierr);
206737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTR, &is_bntr);CHKERRQ(ierr);
207737f463aSAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver, TAOBNTL, &is_bntl);CHKERRQ(ierr);
208737f463aSAlp Dener   if ((is_bnls || is_bntr || is_bntl) && !tao->ls_jac) SETERRQ(PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetResidualJacobianRoutine() must be called before setup!");
209e1e80dc8SAlp Dener   if (!tao->gradient){
210e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &tao->gradient);CHKERRQ(ierr);
211e1e80dc8SAlp Dener   }
212737f463aSAlp Dener   if (!gn->x_work){
213737f463aSAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_work);CHKERRQ(ierr);
214737f463aSAlp Dener   }
215737f463aSAlp Dener   if (!gn->r_work){
216737f463aSAlp Dener     ierr = VecDuplicate(tao->ls_res, &gn->r_work);CHKERRQ(ierr);
217737f463aSAlp Dener   }
218e1e80dc8SAlp Dener   if (!gn->x_old) {
219e1e80dc8SAlp Dener     ierr = VecDuplicate(tao->solution, &gn->x_old);CHKERRQ(ierr);
220e1e80dc8SAlp Dener     ierr = VecSet(gn->x_old, 0.0);CHKERRQ(ierr);
221e1e80dc8SAlp Dener   }
2227cea06e1SXiang Huang 
2237cea06e1SXiang Huang 
2247cea06e1SXiang Huang   /* XH: hack: following works only when D is a squared matrix, to fix dimension of gn->diag/y/y_work, when D is not squared matrix */
2257cea06e1SXiang Huang   ierr = VecGetSize(tao->solution, &Nx);CHKERRQ(ierr);
2267cea06e1SXiang Huang   /* Ny = Nx; */ /* for identity matrix */
2277cea06e1SXiang Huang   Ny = Nx - 1;  /* for gradient matrix */
2287cea06e1SXiang Huang   if (!gn->y){
2297cea06e1SXiang Huang     ierr = VecCreate(PETSC_COMM_SELF,&gn->y);CHKERRQ(ierr);
2307cea06e1SXiang Huang     ierr = VecSetSizes(gn->y,PETSC_DECIDE,Ny);CHKERRQ(ierr);
2317cea06e1SXiang Huang     ierr = VecSetFromOptions(gn->y);CHKERRQ(ierr);
2327cea06e1SXiang Huang     ierr = VecSet(gn->y,0.0);CHKERRQ(ierr);
2337cea06e1SXiang Huang 
2347cea06e1SXiang Huang   }
2357cea06e1SXiang Huang   if (!gn->y_work){
2367cea06e1SXiang Huang     ierr = VecDuplicate(gn->y, &gn->y_work);CHKERRQ(ierr);
2377cea06e1SXiang Huang   }
2388ac80d48SXiang Huang   if (!gn->diag){
2397cea06e1SXiang Huang     ierr = VecDuplicate(gn->y, &gn->diag);CHKERRQ(ierr);
2408ac80d48SXiang Huang     ierr = VecSet(gn->diag, 0.0);CHKERRQ(ierr);
2418ac80d48SXiang Huang   }
2420d71dc2bSXiang Huang 
2437cea06e1SXiang Huang   /* XH: hack: set gn->D as identity/gradient  matrix here for text , how to set D matrix from user data?*/
2447cea06e1SXiang Huang   if (!gn->D){
2457cea06e1SXiang Huang     ierr = MatCreate(PETSC_COMM_SELF,&gn->D);CHKERRQ(ierr);
2467cea06e1SXiang Huang     ierr = MatSetSizes(gn->D,PETSC_DECIDE,PETSC_DECIDE,Ny,Nx);CHKERRQ(ierr);
2477cea06e1SXiang Huang     ierr = MatSetFromOptions(gn->D);CHKERRQ(ierr);
2487cea06e1SXiang Huang     ierr = MatSetUp(gn->D);CHKERRQ(ierr);
2497cea06e1SXiang Huang     /* identity matrix */
2507cea06e1SXiang Huang     /*
2517cea06e1SXiang Huang     for (i=0; i<Ny; i++) {
2527cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&i,&v,INSERT_VALUES);CHKERRQ(ierr);
2537cea06e1SXiang Huang     }
2547cea06e1SXiang Huang     */
2557cea06e1SXiang Huang     /* gradient matrix */
2567cea06e1SXiang Huang     /* [-1, 1, 0,...; 0, -1, 1, 0, ...] */
2577cea06e1SXiang Huang     for (i=0; i<Ny; i++) {
2587cea06e1SXiang Huang         v = 1.0;
2597cea06e1SXiang Huang         nx = i+1;
2607cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&nx,&v,INSERT_VALUES);CHKERRQ(ierr);
2617cea06e1SXiang Huang         v = -1.0;
2627cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&i,&v,INSERT_VALUES);CHKERRQ(ierr);
2637cea06e1SXiang Huang     }
2647cea06e1SXiang Huang     ierr = MatAssemblyBegin(gn->D,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2657cea06e1SXiang Huang     ierr = MatAssemblyEnd(gn->D,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2667cea06e1SXiang Huang   }
2677cea06e1SXiang Huang 
2687cea06e1SXiang Huang   /* XH: debug: check matrix */
2697cea06e1SXiang Huang   PetscPrintf(PETSC_COMM_SELF, "-------- Check D matrix. -------- \n");
2707cea06e1SXiang Huang   ierr = MatView(gn->D,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
271*20fe612cSXiang Huang 
2727cea06e1SXiang Huang 
273e1e80dc8SAlp Dener   if (!tao->setupcalled) {
274737f463aSAlp Dener     /* Hessian setup */
275737f463aSAlp Dener     ierr = VecGetLocalSize(tao->solution, &nx);CHKERRQ(ierr);
276737f463aSAlp Dener     ierr = VecGetSize(tao->solution, &Nx);CHKERRQ(ierr);
277737f463aSAlp Dener     ierr = MatSetSizes(gn->H, nx, nx, Nx, Nx);CHKERRQ(ierr);
278737f463aSAlp Dener     ierr = MatSetType(gn->H, MATSHELL);CHKERRQ(ierr);
279737f463aSAlp Dener     ierr = MatSetUp(gn->H);CHKERRQ(ierr);
280737f463aSAlp Dener     ierr = MatShellSetOperation(gn->H, MATOP_MULT, (void (*)(void))GNHessianProd);CHKERRQ(ierr);
281737f463aSAlp Dener     ierr = MatShellSetContext(gn->H, (void*)gn);CHKERRQ(ierr);
282737f463aSAlp Dener     /* Subsolver setup */
283e1e80dc8SAlp Dener     ierr = TaoSetUpdate(gn->subsolver, GNHookFunction, (void*)gn);CHKERRQ(ierr);
284737f463aSAlp Dener     ierr = TaoSetInitialVector(gn->subsolver, tao->solution);CHKERRQ(ierr);
285737f463aSAlp Dener     if (tao->bounded) {
286737f463aSAlp Dener       ierr = TaoSetVariableBounds(gn->subsolver, tao->XL, tao->XU);CHKERRQ(ierr);
287737f463aSAlp Dener     }
288737f463aSAlp Dener     ierr = TaoSetResidualRoutine(gn->subsolver, tao->ls_res, tao->ops->computeresidual, tao->user_lsresP);CHKERRQ(ierr);
2894ffbe8acSAlp Dener     ierr = TaoSetJacobianResidualRoutine(gn->subsolver, tao->ls_jac, tao->ls_jac, tao->ops->computeresidualjacobian, tao->user_lsjacP);CHKERRQ(ierr);
290737f463aSAlp Dener     ierr = TaoSetObjectiveAndGradientRoutine(gn->subsolver, GNObjectiveGradientEval, (void*)gn);CHKERRQ(ierr);
291737f463aSAlp Dener     ierr = TaoSetHessianRoutine(gn->subsolver, gn->H, gn->H, GNComputeHessian, (void*)gn);CHKERRQ(ierr);
292e1e80dc8SAlp Dener     /* Propagate some options down */
293e1e80dc8SAlp Dener     ierr = TaoSetTolerances(gn->subsolver, tao->gatol, tao->grtol, tao->gttol);CHKERRQ(ierr);
294e1e80dc8SAlp Dener     ierr = TaoSetMaximumIterations(gn->subsolver, tao->max_it);CHKERRQ(ierr);
295e1e80dc8SAlp Dener     ierr = TaoSetMaximumFunctionEvaluations(gn->subsolver, tao->max_funcs);CHKERRQ(ierr);
296737f463aSAlp Dener     for (i=0; i<tao->numbermonitors; ++i) {
297737f463aSAlp Dener       ierr = TaoSetMonitor(gn->subsolver, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]);CHKERRQ(ierr);
298737f463aSAlp Dener       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
299737f463aSAlp Dener     }
300737f463aSAlp Dener     ierr = TaoSetUp(gn->subsolver);CHKERRQ(ierr);
301e1e80dc8SAlp Dener   }
302737f463aSAlp Dener   PetscFunctionReturn(0);
303737f463aSAlp Dener }
304737f463aSAlp Dener 
305737f463aSAlp Dener static PetscErrorCode TaoDestroy_BRGN(Tao tao)
306737f463aSAlp Dener {
307737f463aSAlp Dener   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
308737f463aSAlp Dener   PetscErrorCode        ierr;
309737f463aSAlp Dener 
310737f463aSAlp Dener   PetscFunctionBegin;
311737f463aSAlp Dener   if (tao->setupcalled) {
312e1e80dc8SAlp Dener     ierr = VecDestroy(&tao->gradient);CHKERRQ(ierr);
313737f463aSAlp Dener     ierr = VecDestroy(&gn->x_work);CHKERRQ(ierr);
314737f463aSAlp Dener     ierr = VecDestroy(&gn->r_work);CHKERRQ(ierr);
315e1e80dc8SAlp Dener     ierr = VecDestroy(&gn->x_old);CHKERRQ(ierr);
3168ac80d48SXiang Huang     ierr = VecDestroy(&gn->diag);CHKERRQ(ierr);
3177cea06e1SXiang Huang     ierr = VecDestroy(&gn->y);CHKERRQ(ierr);
3187cea06e1SXiang Huang     ierr = VecDestroy(&gn->y_work);CHKERRQ(ierr);
319737f463aSAlp Dener   }
320737f463aSAlp Dener   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
3217cea06e1SXiang Huang   ierr = MatDestroy(&gn->D);CHKERRQ(ierr);
322737f463aSAlp Dener   ierr = TaoDestroy(&gn->subsolver);CHKERRQ(ierr);
323e1e80dc8SAlp Dener   gn->parent = NULL;
324737f463aSAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
325737f463aSAlp Dener   PetscFunctionReturn(0);
326737f463aSAlp Dener }
327737f463aSAlp Dener 
3283850be85SAlp Dener /*MC
3293850be85SAlp Dener   TAOBRGN - Bounded Regularized Gauss-Newton method for solving nonlinear least-squares
3303850be85SAlp Dener             problems with bound constraints. This algorithm is a thin wrapper around TAOBNTL
3313850be85SAlp Dener             that constructs the Guass-Newton problem with the user-provided least-squares
3323850be85SAlp Dener             residual and Jacobian. The problem is regularized with an L2-norm proximal point
3333850be85SAlp Dener             term.
3343850be85SAlp Dener 
3353850be85SAlp Dener   Options Database Keys:
3363850be85SAlp Dener   + -tao_bqnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
3373850be85SAlp Dener   . -tao_bqnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
3383850be85SAlp Dener   . -tao_bqnk_update_type - trust radius update method ("step", "direction", "interpolation")
3393850be85SAlp Dener   - -tao_bqnk_as_type - active-set estimation method ("none", "bertsekas")
3403850be85SAlp Dener 
3413850be85SAlp Dener   Level: beginner
3423850be85SAlp Dener M*/
343737f463aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BRGN(Tao tao)
344737f463aSAlp Dener {
345737f463aSAlp Dener   TAO_BRGN       *gn;
346737f463aSAlp Dener   PetscErrorCode ierr;
347737f463aSAlp Dener 
348737f463aSAlp Dener   PetscFunctionBegin;
349737f463aSAlp Dener   ierr = PetscNewLog(tao,&gn);CHKERRQ(ierr);
350737f463aSAlp Dener 
351737f463aSAlp Dener   tao->ops->destroy = TaoDestroy_BRGN;
352737f463aSAlp Dener   tao->ops->setup = TaoSetUp_BRGN;
353737f463aSAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BRGN;
354737f463aSAlp Dener   tao->ops->view = TaoView_BRGN;
355737f463aSAlp Dener   tao->ops->solve = TaoSolve_BRGN;
356737f463aSAlp Dener 
357737f463aSAlp Dener   tao->data = (void*)gn;
358e1e80dc8SAlp Dener   gn->lambda = 1e-4;
3598ac80d48SXiang Huang   gn->epsilon = 1e-6;
360e1e80dc8SAlp Dener   gn->parent = tao;
361737f463aSAlp Dener 
362737f463aSAlp Dener   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &gn->H);CHKERRQ(ierr);
363737f463aSAlp Dener   ierr = MatSetOptionsPrefix(gn->H, "tao_brgn_hessian_");CHKERRQ(ierr);
364737f463aSAlp Dener 
365737f463aSAlp Dener   ierr = TaoCreate(PetscObjectComm((PetscObject)tao), &gn->subsolver);CHKERRQ(ierr);
366737f463aSAlp Dener   ierr = TaoSetType(gn->subsolver, TAOBNLS);CHKERRQ(ierr);
367737f463aSAlp Dener   ierr = TaoSetOptionsPrefix(gn->subsolver, "tao_brgn_subsolver_");CHKERRQ(ierr);
368e1e80dc8SAlp Dener   PetscFunctionReturn(0);
369e1e80dc8SAlp Dener }
370e1e80dc8SAlp Dener 
371e1e80dc8SAlp Dener /*@C
372e1e80dc8SAlp Dener   TaoBRGNGetSubsolver - Get the pointer to the subsolver inside BRGN
373e1e80dc8SAlp Dener 
374e1e80dc8SAlp Dener   Collective on Tao
375e1e80dc8SAlp Dener 
376e1e80dc8SAlp Dener   Level: developer
377e1e80dc8SAlp Dener 
378e1e80dc8SAlp Dener   Input Parameters:
379e1e80dc8SAlp Dener +  tao - the Tao solver context
380e1e80dc8SAlp Dener -  subsolver - the Tao sub-solver context
381e1e80dc8SAlp Dener @*/
382e1e80dc8SAlp Dener PetscErrorCode TaoBRGNGetSubsolver(Tao tao, Tao *subsolver)
383e1e80dc8SAlp Dener {
384e1e80dc8SAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
385e1e80dc8SAlp Dener 
386e1e80dc8SAlp Dener   PetscFunctionBegin;
387e1e80dc8SAlp Dener   *subsolver = gn->subsolver;
388737f463aSAlp Dener   PetscFunctionReturn(0);
389737f463aSAlp Dener }
390737f463aSAlp Dener 
391737f463aSAlp Dener /*@C
392737f463aSAlp Dener   TaoBRGNSetTikhonovLambda - Set the Tikhonov regularization factor for the Gauss-Newton least-squares algorithm
393737f463aSAlp Dener 
394737f463aSAlp Dener   Collective on Tao
395737f463aSAlp Dener 
396737f463aSAlp Dener   Level: developer
397737f463aSAlp Dener 
398737f463aSAlp Dener   Input Parameters:
399737f463aSAlp Dener +  tao - the Tao solver context
400737f463aSAlp Dener -  lambda - Tikhonov regularization factor
401737f463aSAlp Dener @*/
402737f463aSAlp Dener PetscErrorCode TaoBRGNSetTikhonovLambda(Tao tao, PetscReal lambda)
403737f463aSAlp Dener {
404737f463aSAlp Dener   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
405737f463aSAlp Dener 
4068ac80d48SXiang Huang   /* Initialize lambda here */
4070d71dc2bSXiang Huang 
408737f463aSAlp Dener   PetscFunctionBegin;
409737f463aSAlp Dener   gn->lambda = lambda;
410737f463aSAlp Dener   PetscFunctionReturn(0);
411737f463aSAlp Dener }
4120d71dc2bSXiang Huang 
4138ac80d48SXiang Huang /*@C
4148ac80d48SXiang Huang   TaoBRGNSetL1SmoothEpsilon - Set the L1-norm smooth approximation parameter for L1-regularized least-squares algorithm
4158ac80d48SXiang Huang 
4168ac80d48SXiang Huang   Collective on Tao
4178ac80d48SXiang Huang 
4188ac80d48SXiang Huang   Level: developer
4198ac80d48SXiang Huang 
4208ac80d48SXiang Huang   Input Parameters:
4218ac80d48SXiang Huang +  tao - the Tao solver context
4228ac80d48SXiang Huang -  epsilon - L1-norm smooth approximation parameter
4238ac80d48SXiang Huang @*/
4248ac80d48SXiang Huang PetscErrorCode TaoBRGNSetL1SmoothEpsilon(Tao tao, PetscReal epsilon)
4258ac80d48SXiang Huang {
4268ac80d48SXiang Huang   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
4278ac80d48SXiang Huang 
4288ac80d48SXiang Huang   /* Initialize epsilon here */
4298ac80d48SXiang Huang 
4308ac80d48SXiang Huang   PetscFunctionBegin;
4318ac80d48SXiang Huang   gn->epsilon = epsilon;
4328ac80d48SXiang Huang   PetscFunctionReturn(0);
4338ac80d48SXiang Huang }
4348ac80d48SXiang Huang /* XH: done TaoBRGNSetL1SmoothEpsilon by copy TaoBRGNSetTikhonovLambda in peststao.h, brgn.c and zbrgnf.c.
4357cea06e1SXiang Huang  maybe change the name of Tikhonov in TaoBRGNSetTikhonovLambda() etc, as lambda is no longer the Tikhonov regularizer weight but the L1 regularizer weight
4367cea06e1SXiang Huang  Maybe change D*x to D(x), and  A*x to A(x) as function handle
4377cea06e1SXiang Huang  Maybe need to also keep y = D*x, to avoid duplicate frequent computation of D*x
4387cea06e1SXiang Huang  */
439