xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision 7cea06e17344f68ea9d5d5c2ae263aead5001856)
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);
48*7cea06e1SXiang Huang   /* out = out + lambda*D'*(diag.*(D*in)) */
49*7cea06e1SXiang Huang   ierr = MatMult(gn->D, in, gn->y);CHKERRQ(ierr);  /* y = D*in */
50*7cea06e1SXiang 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 */
51*7cea06e1SXiang 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;
60*7cea06e1SXiang Huang   PetscInt              Ny;                    /* dimension of D*X */
61*7cea06e1SXiang 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);
70*7cea06e1SXiang Huang   /* add the second term lambda*sum(sqrt(y.^2+epsilon^2) - epsilon), where y = D*x*/
71*7cea06e1SXiang Huang   ierr = MatMult(gn->D, X, gn->y);CHKERRQ(ierr);  /* y = D*x */
72*7cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->y_work, gn->y, gn->y);CHKERRQ(ierr);
73*7cea06e1SXiang Huang   ierr = VecShift(gn->y_work, gn->epsilon*gn->epsilon);CHKERRQ(ierr);
74*7cea06e1SXiang Huang   ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);      /* gn->y_work = sqrt(y.^2+epsilon^2) */
75*7cea06e1SXiang Huang   ierr = VecSum(gn->y_work, &yESum);CHKERRQ(ierr);CHKERRQ(ierr);
76*7cea06e1SXiang Huang   ierr = VecGetSize(gn->y, &Ny);CHKERRQ(ierr);
77*7cea06e1SXiang 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);
82*7cea06e1SXiang Huang   /* compute G = G + lambda*D'*(y./sqrt(y.^2+epsilon^2)), where y = D*x */
83*7cea06e1SXiang Huang   ierr = VecPointwiseDivide(gn->y_work, gn->y, gn->y_work);CHKERRQ(ierr); /* reuse y_work = y./sqrt(y.^2+epsilon^2) */
84*7cea06e1SXiang 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 
99*7cea06e1SXiang 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 */
100*7cea06e1SXiang Huang   ierr = MatMult(gn->D, X, gn->y);CHKERRQ(ierr);  /* y = D*x */
101*7cea06e1SXiang Huang   ierr = VecPointwiseMult(gn->y_work, gn->y, gn->y);CHKERRQ(ierr);
102*7cea06e1SXiang Huang   ierr = VecShift(gn->y_work, gn->epsilon*gn->epsilon);CHKERRQ(ierr);
103*7cea06e1SXiang Huang   ierr = VecCopy(gn->y_work, gn->diag);CHKERRQ(ierr);                     /* gn->diag = y.^2+epsilon^2 */
104*7cea06e1SXiang Huang   ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);                            /* gn->y_work = sqrt(y.^2+epsilon^2) */
105*7cea06e1SXiang 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;
200*7cea06e1SXiang Huang   PetscInt              i, nx, Nx, Ny; /* XH: added Ny  for size of y=D*x*/
201*7cea06e1SXiang 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   }
222*7cea06e1SXiang Huang 
223*7cea06e1SXiang Huang 
224*7cea06e1SXiang 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 */
225*7cea06e1SXiang Huang   ierr = VecGetSize(tao->solution, &Nx);CHKERRQ(ierr);
226*7cea06e1SXiang Huang   /* Ny = Nx; */ /* for identity matrix */
227*7cea06e1SXiang Huang   Ny = Nx - 1;  /* for gradient matrix */
228*7cea06e1SXiang Huang   if (!gn->y){
229*7cea06e1SXiang Huang     ierr = VecCreate(PETSC_COMM_SELF,&gn->y);CHKERRQ(ierr);
230*7cea06e1SXiang Huang     ierr = VecSetSizes(gn->y,PETSC_DECIDE,Ny);CHKERRQ(ierr);
231*7cea06e1SXiang Huang     ierr = VecSetFromOptions(gn->y);CHKERRQ(ierr);
232*7cea06e1SXiang Huang     ierr = VecSet(gn->y,0.0);CHKERRQ(ierr);
233*7cea06e1SXiang Huang 
234*7cea06e1SXiang Huang   }
235*7cea06e1SXiang Huang   if (!gn->y_work){
236*7cea06e1SXiang Huang     ierr = VecDuplicate(gn->y, &gn->y_work);CHKERRQ(ierr);
237*7cea06e1SXiang Huang   }
2388ac80d48SXiang Huang   if (!gn->diag){
239*7cea06e1SXiang Huang     ierr = VecDuplicate(gn->y, &gn->diag);CHKERRQ(ierr);
2408ac80d48SXiang Huang     ierr = VecSet(gn->diag, 0.0);CHKERRQ(ierr);
2418ac80d48SXiang Huang   }
2420d71dc2bSXiang Huang 
243*7cea06e1SXiang Huang   /* XH: hack: set gn->D as identity/gradient  matrix here for text , how to set D matrix from user data?*/
244*7cea06e1SXiang Huang   if (!gn->D){
245*7cea06e1SXiang Huang     ierr = MatCreate(PETSC_COMM_SELF,&gn->D);CHKERRQ(ierr);
246*7cea06e1SXiang Huang     ierr = MatSetSizes(gn->D,PETSC_DECIDE,PETSC_DECIDE,Ny,Nx);CHKERRQ(ierr);
247*7cea06e1SXiang Huang     ierr = MatSetFromOptions(gn->D);CHKERRQ(ierr);
248*7cea06e1SXiang Huang     ierr = MatSetUp(gn->D);CHKERRQ(ierr);
249*7cea06e1SXiang Huang     /* identity matrix */
250*7cea06e1SXiang Huang     /*
251*7cea06e1SXiang Huang     for (i=0; i<Ny; i++) {
252*7cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&i,&v,INSERT_VALUES);CHKERRQ(ierr);
253*7cea06e1SXiang Huang     }
254*7cea06e1SXiang Huang     */
255*7cea06e1SXiang Huang     /* gradient matrix */
256*7cea06e1SXiang Huang     /* [-1, 1, 0,...; 0, -1, 1, 0, ...] */
257*7cea06e1SXiang Huang     for (i=0; i<Ny; i++) {
258*7cea06e1SXiang Huang         v = 1.0;
259*7cea06e1SXiang Huang         nx = i+1;
260*7cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&nx,&v,INSERT_VALUES);CHKERRQ(ierr);
261*7cea06e1SXiang Huang         v = -1.0;
262*7cea06e1SXiang Huang         ierr = MatSetValues(gn->D,1,&i,1,&i,&v,INSERT_VALUES);CHKERRQ(ierr);
263*7cea06e1SXiang Huang     }
264*7cea06e1SXiang Huang     ierr = MatAssemblyBegin(gn->D,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
265*7cea06e1SXiang Huang     ierr = MatAssemblyEnd(gn->D,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
266*7cea06e1SXiang Huang   }
267*7cea06e1SXiang Huang 
268*7cea06e1SXiang Huang   /* XH: debug: check matrix */
269*7cea06e1SXiang Huang   PetscPrintf(PETSC_COMM_SELF, "-------- Check D matrix. -------- \n");
270*7cea06e1SXiang Huang   ierr = MatView(gn->D,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
271*7cea06e1SXiang Huang   getchar();
272*7cea06e1SXiang 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);
317*7cea06e1SXiang Huang     ierr = VecDestroy(&gn->y);CHKERRQ(ierr);
318*7cea06e1SXiang Huang     ierr = VecDestroy(&gn->y_work);CHKERRQ(ierr);
319737f463aSAlp Dener   }
320737f463aSAlp Dener   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
321*7cea06e1SXiang 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.
435*7cea06e1SXiang Huang  maybe change the name of Tikhonov in TaoBRGNSetTikhonovLambda() etc, as lambda is no longer the Tikhonov regularizer weight but the L1 regularizer weight
436*7cea06e1SXiang Huang  Maybe change D*x to D(x), and  A*x to A(x) as function handle
437*7cea06e1SXiang Huang  Maybe need to also keep y = D*x, to avoid duplicate frequent computation of D*x
438*7cea06e1SXiang Huang  */
439