xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision 01b716f5d700777802b1c64e79765fb1aa058517)
1 #include <../src/tao/leastsquares/impls/brgn/brgn.h> /*I "petsctao.h" I*/
2 
3 #define BRGN_user               0
4 #define BRGN_l2prox             1
5 #define BRGN_l1dict             2
6 #define BRGNRegTypes            3
7 
8 static const char *BRGN_Table[64] = {"user","l2prox","l1dict"};
9 
10 static PetscErrorCode GNHessianProd(Mat H,Vec in,Vec out)
11 {
12   TAO_BRGN              *gn;
13   PetscErrorCode        ierr;
14 
15   PetscFunctionBegin;
16   ierr = MatShellGetContext(H,&gn);CHKERRQ(ierr);
17   ierr = MatMult(gn->subsolver->ls_jac,in,gn->r_work);CHKERRQ(ierr);
18   ierr = MatMultTranspose(gn->subsolver->ls_jac,gn->r_work,out);CHKERRQ(ierr);
19   switch (gn->reg_type) {
20   case BRGN_user:
21     ierr = MatMult(gn->Hreg,in,gn->x_work);CHKERRQ(ierr);
22     ierr = VecAXPY(out,gn->lambda,gn->x_work);CHKERRQ(ierr);
23     break;
24   case BRGN_l2prox:
25     ierr = VecAXPY(out,gn->lambda,in);CHKERRQ(ierr);
26     break;
27   case BRGN_l1dict:
28     /* out = out + lambda*D'*(diag.*(D*in)) */
29     if (gn->D) {
30       ierr = MatMult(gn->D,in,gn->y);CHKERRQ(ierr);/* y = D*in */
31     } else {
32       ierr = VecCopy(in,gn->y);CHKERRQ(ierr);
33     }
34     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 */
35     if (gn->D) {
36       ierr = MatMultTranspose(gn->D,gn->y_work,gn->x_work);CHKERRQ(ierr); /* x_work = D'*(diag.*(D*in)) */
37     } else {
38       ierr = VecCopy(gn->y_work,gn->x_work);CHKERRQ(ierr);
39     }
40     ierr = VecAXPY(out,gn->lambda,gn->x_work);CHKERRQ(ierr);
41     break;
42   }
43 
44   PetscFunctionReturn(0);
45 }
46 
47 static PetscErrorCode GNObjectiveGradientEval(Tao tao,Vec X,PetscReal *fcn,Vec G,void *ptr)
48 {
49   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
50   PetscInt              K;                    /* dimension of D*X */
51   PetscScalar           yESum;
52   PetscErrorCode        ierr;
53   PetscReal             f_reg;
54 
55   PetscFunctionBegin;
56   /* compute objective *fcn*/
57   /* compute first term 0.5*||ls_res||_2^2 */
58   ierr = TaoComputeResidual(tao,X,tao->ls_res);CHKERRQ(ierr);
59   ierr = VecDot(tao->ls_res,tao->ls_res,fcn);CHKERRQ(ierr);
60   *fcn *= 0.5;
61   /* compute gradient G */
62   ierr = TaoComputeResidualJacobian(tao,X,tao->ls_jac,tao->ls_jac_pre);CHKERRQ(ierr);
63   ierr = MatMultTranspose(tao->ls_jac,tao->ls_res,G);CHKERRQ(ierr);
64   /* add the regularization contribution */
65   switch (gn->reg_type) {
66   case BRGN_user:
67     ierr = (*gn->regularizerobjandgrad)(tao,X,&f_reg,gn->x_work,gn->reg_obj_ctx);CHKERRQ(ierr);
68     *fcn += gn->lambda*f_reg;
69     ierr = VecAXPY(G,gn->lambda,gn->x_work);CHKERRQ(ierr);
70     break;
71   case BRGN_l2prox:
72     /* compute f = f + lambda*0.5*(xk - xkm1)'*(xk - xkm1) */
73     ierr = VecAXPBYPCZ(gn->x_work,1.0,-1.0,0.0,X,gn->x_old);CHKERRQ(ierr);
74     ierr = VecDot(gn->x_work,gn->x_work,&f_reg);CHKERRQ(ierr);
75     *fcn += gn->lambda*0.5*f_reg;
76     /* compute G = G + lambda*(xk - xkm1) */
77     ierr = VecAXPBYPCZ(G,gn->lambda,-gn->lambda,1.0,X,gn->x_old);CHKERRQ(ierr);
78     break;
79   case BRGN_l1dict:
80     /* compute f = f + lambda*sum(sqrt(y.^2+epsilon^2) - epsilon), where y = D*x*/
81     if (gn->D) {
82       ierr = MatMult(gn->D,X,gn->y);CHKERRQ(ierr);/* y = D*x */
83     } else {
84       ierr = VecCopy(X,gn->y);CHKERRQ(ierr);
85     }
86     ierr = VecPointwiseMult(gn->y_work,gn->y,gn->y);CHKERRQ(ierr);
87     ierr = VecShift(gn->y_work,gn->epsilon*gn->epsilon);CHKERRQ(ierr);
88     ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);  /* gn->y_work = sqrt(y.^2+epsilon^2) */
89     ierr = VecSum(gn->y_work,&yESum);CHKERRQ(ierr);CHKERRQ(ierr);
90     ierr = VecGetSize(gn->y,&K);CHKERRQ(ierr);
91     *fcn += gn->lambda*(yESum - K*gn->epsilon);
92     /* compute G = G + lambda*D'*(y./sqrt(y.^2+epsilon^2)),where y = D*x */
93     ierr = VecPointwiseDivide(gn->y_work,gn->y,gn->y_work);CHKERRQ(ierr); /* reuse y_work = y./sqrt(y.^2+epsilon^2) */
94     if (gn->D) {
95       ierr = MatMultTranspose(gn->D,gn->y_work,gn->x_work);CHKERRQ(ierr);
96     } else {
97       ierr = VecCopy(gn->y_work,gn->x_work);CHKERRQ(ierr);
98     }
99     ierr = VecAXPY(G,gn->lambda,gn->x_work);CHKERRQ(ierr);
100     break;
101   }
102   PetscFunctionReturn(0);
103 }
104 
105 static PetscErrorCode GNComputeHessian(Tao tao,Vec X,Mat H,Mat Hpre,void *ptr)
106 {
107   TAO_BRGN              *gn = (TAO_BRGN *)ptr;
108   PetscErrorCode ierr;
109 
110   PetscFunctionBegin;
111   ierr = TaoComputeResidualJacobian(tao,X,tao->ls_jac,tao->ls_jac_pre);CHKERRQ(ierr);
112 
113   switch (gn->reg_type) {
114   case BRGN_user:
115     ierr = (*gn->regularizerhessian)(tao,X,gn->Hreg,gn->reg_hess_ctx);CHKERRQ(ierr);
116     break;
117   case BRGN_l2prox:
118     break;
119   case BRGN_l1dict:
120     /* 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 */
121     if (gn->D) {
122       ierr = MatMult(gn->D,X,gn->y);CHKERRQ(ierr);/* y = D*x */
123     } else {
124       ierr = VecCopy(X,gn->y);CHKERRQ(ierr);
125     }
126     ierr = VecPointwiseMult(gn->y_work,gn->y,gn->y);CHKERRQ(ierr);
127     ierr = VecShift(gn->y_work,gn->epsilon*gn->epsilon);CHKERRQ(ierr);
128     ierr = VecCopy(gn->y_work,gn->diag);CHKERRQ(ierr);                  /* gn->diag = y.^2+epsilon^2 */
129     ierr = VecSqrtAbs(gn->y_work);CHKERRQ(ierr);                        /* gn->y_work = sqrt(y.^2+epsilon^2) */
130     ierr = VecPointwiseMult(gn->diag,gn->y_work,gn->diag);CHKERRQ(ierr);/* gn->diag = sqrt(y.^2+epsilon^2).^3 */
131     ierr = VecReciprocal(gn->diag);CHKERRQ(ierr);
132     ierr = VecScale(gn->diag,gn->epsilon*gn->epsilon);CHKERRQ(ierr);
133     break;
134   }
135 
136   PetscFunctionReturn(0);
137 }
138 
139 static PetscErrorCode GNHookFunction(Tao tao,PetscInt iter)
140 {
141   TAO_BRGN              *gn = (TAO_BRGN *)tao->user_update;
142   PetscErrorCode        ierr;
143 
144   PetscFunctionBegin;
145   /* Update basic tao information from the subsolver */
146   gn->parent->nfuncs = tao->nfuncs;
147   gn->parent->ngrads = tao->ngrads;
148   gn->parent->nfuncgrads = tao->nfuncgrads;
149   gn->parent->nhess = tao->nhess;
150   gn->parent->niter = tao->niter;
151   gn->parent->ksp_its = tao->ksp_its;
152   gn->parent->ksp_tot_its = tao->ksp_tot_its;
153   ierr = TaoGetConvergedReason(tao,&gn->parent->reason);CHKERRQ(ierr);
154   /* Update the solution vectors */
155   if (iter == 0) {
156     ierr = VecSet(gn->x_old,0.0);CHKERRQ(ierr);
157   } else {
158     ierr = VecCopy(tao->solution,gn->x_old);CHKERRQ(ierr);
159     ierr = VecCopy(tao->solution,gn->parent->solution);CHKERRQ(ierr);
160   }
161   /* Update the gradient */
162   ierr = VecCopy(tao->gradient,gn->parent->gradient);CHKERRQ(ierr);
163   /* Call general purpose update function */
164   if (gn->parent->ops->update) {
165     ierr = (*gn->parent->ops->update)(gn->parent,gn->parent->niter);CHKERRQ(ierr);
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 static PetscErrorCode TaoSolve_BRGN(Tao tao)
171 {
172   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
173   PetscErrorCode        ierr;
174 
175   PetscFunctionBegin;
176   ierr = TaoSolve(gn->subsolver);CHKERRQ(ierr);
177   /* Update basic tao information from the subsolver */
178   tao->nfuncs = gn->subsolver->nfuncs;
179   tao->ngrads = gn->subsolver->ngrads;
180   tao->nfuncgrads = gn->subsolver->nfuncgrads;
181   tao->nhess = gn->subsolver->nhess;
182   tao->niter = gn->subsolver->niter;
183   tao->ksp_its = gn->subsolver->ksp_its;
184   tao->ksp_tot_its = gn->subsolver->ksp_tot_its;
185   ierr = TaoGetConvergedReason(gn->subsolver,&tao->reason);CHKERRQ(ierr);
186   /* Update vectors */
187   ierr = VecCopy(gn->subsolver->solution,tao->solution);CHKERRQ(ierr);
188   ierr = VecCopy(gn->subsolver->gradient,tao->gradient);CHKERRQ(ierr);
189   PetscFunctionReturn(0);
190 }
191 
192 static PetscErrorCode TaoSetFromOptions_BRGN(PetscOptionItems *PetscOptionsObject,Tao tao)
193 {
194   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
195   PetscErrorCode        ierr;
196 
197   PetscFunctionBegin;
198   ierr = PetscOptionsHead(PetscOptionsObject,"least-squares problems with regularizer: ||f(x)||^2 + lambda*g(x), g(x) = ||xk-xkm1||^2 or ||Dx||_1 or user defined function.");CHKERRQ(ierr);
199   ierr = PetscOptionsReal("-tao_brgn_lambda","regularizer weight (default 1e-4)","",gn->lambda,&gn->lambda,NULL);CHKERRQ(ierr);
200   ierr = PetscOptionsReal("-tao_brgn_epsilon","L1-norm smooth approximation parameter: ||x||_1 = sum(sqrt(x.^2+epsilon^2)-epsilon) (default 1e-6)","",gn->epsilon,&gn->epsilon,NULL);CHKERRQ(ierr);
201   ierr = PetscOptionsEList("-tao_brgn_regularization_type","regularization type", "",BRGN_Table,BRGNRegTypes,BRGN_Table[gn->reg_type],&gn->reg_type,NULL);CHKERRQ(ierr);
202   ierr = PetscOptionsTail();CHKERRQ(ierr);
203   ierr = TaoSetFromOptions(gn->subsolver);CHKERRQ(ierr);
204   PetscFunctionReturn(0);
205 }
206 
207 static PetscErrorCode TaoView_BRGN(Tao tao,PetscViewer viewer)
208 {
209   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
210   PetscErrorCode        ierr;
211 
212   PetscFunctionBegin;
213   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
214   ierr = TaoView(gn->subsolver,viewer);CHKERRQ(ierr);
215   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
216   PetscFunctionReturn(0);
217 }
218 
219 static PetscErrorCode TaoSetUp_BRGN(Tao tao)
220 {
221   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
222   PetscErrorCode        ierr;
223   PetscBool             is_bnls,is_bntr,is_bntl;
224   PetscInt              i,n,N,K; /* dict has size K*N*/
225 
226   PetscFunctionBegin;
227   if (!tao->ls_res) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ORDER,"TaoSetResidualRoutine() must be called before setup!");
228   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNLS,&is_bnls);CHKERRQ(ierr);
229   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNTR,&is_bntr);CHKERRQ(ierr);
230   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNTL,&is_bntl);CHKERRQ(ierr);
231   if ((is_bnls || is_bntr || is_bntl) && !tao->ls_jac) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ORDER,"TaoSetResidualJacobianRoutine() must be called before setup!");
232   if (!tao->gradient) {
233     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
234   }
235   if (!gn->x_work) {
236     ierr = VecDuplicate(tao->solution,&gn->x_work);CHKERRQ(ierr);
237   }
238   if (!gn->r_work) {
239     ierr = VecDuplicate(tao->ls_res,&gn->r_work);CHKERRQ(ierr);
240   }
241   if (!gn->x_old) {
242     ierr = VecDuplicate(tao->solution,&gn->x_old);CHKERRQ(ierr);
243     ierr = VecSet(gn->x_old,0.0);CHKERRQ(ierr);
244   }
245 
246   if (BRGN_l1dict == gn->reg_type) {
247     if (gn->D) {
248       ierr = MatGetSize(gn->D,&K,&N);CHKERRQ(ierr); /* Shell matrices still must have sizes defined. K = N for identity matrix, K=N-1 or N for gradient matrix */
249     } else {
250       ierr = VecGetSize(tao->solution,&K);CHKERRQ(ierr); /* If user does not setup dict matrix, use identiy matrix, K=N */
251     }
252     if (!gn->y) {
253       ierr = VecCreate(PETSC_COMM_SELF,&gn->y);CHKERRQ(ierr);
254       ierr = VecSetSizes(gn->y,PETSC_DECIDE,K);CHKERRQ(ierr);
255       ierr = VecSetFromOptions(gn->y);CHKERRQ(ierr);
256       ierr = VecSet(gn->y,0.0);CHKERRQ(ierr);
257 
258     }
259     if (!gn->y_work) {
260       ierr = VecDuplicate(gn->y,&gn->y_work);CHKERRQ(ierr);
261     }
262     if (!gn->diag) {
263       ierr = VecDuplicate(gn->y,&gn->diag);CHKERRQ(ierr);
264       ierr = VecSet(gn->diag,0.0);CHKERRQ(ierr);
265     }
266   }
267 
268 
269   if (!tao->setupcalled) {
270     /* Hessian setup */
271     ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr);
272     ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);
273     ierr = MatSetSizes(gn->H,n,n,N,N);CHKERRQ(ierr);
274     ierr = MatSetType(gn->H,MATSHELL);CHKERRQ(ierr);
275     ierr = MatSetUp(gn->H);CHKERRQ(ierr);
276     ierr = MatShellSetOperation(gn->H,MATOP_MULT,(void (*)(void))GNHessianProd);CHKERRQ(ierr);
277     ierr = MatShellSetContext(gn->H,(void*)gn);CHKERRQ(ierr);
278     /* Subsolver setup,include initial vector and dicttionary D */
279     ierr = TaoSetUpdate(gn->subsolver,GNHookFunction,(void*)gn);CHKERRQ(ierr);
280     ierr = TaoSetInitialVector(gn->subsolver,tao->solution);CHKERRQ(ierr);
281     if (tao->bounded) {
282       ierr = TaoSetVariableBounds(gn->subsolver,tao->XL,tao->XU);CHKERRQ(ierr);
283     }
284     ierr = TaoSetResidualRoutine(gn->subsolver,tao->ls_res,tao->ops->computeresidual,tao->user_lsresP);CHKERRQ(ierr);
285     ierr = TaoSetJacobianResidualRoutine(gn->subsolver,tao->ls_jac,tao->ls_jac,tao->ops->computeresidualjacobian,tao->user_lsjacP);CHKERRQ(ierr);
286     ierr = TaoSetObjectiveAndGradientRoutine(gn->subsolver,GNObjectiveGradientEval,(void*)gn);CHKERRQ(ierr);
287     ierr = TaoSetHessianRoutine(gn->subsolver,gn->H,gn->H,GNComputeHessian,(void*)gn);CHKERRQ(ierr);
288     /* Propagate some options down */
289     ierr = TaoSetTolerances(gn->subsolver,tao->gatol,tao->grtol,tao->gttol);CHKERRQ(ierr);
290     ierr = TaoSetMaximumIterations(gn->subsolver,tao->max_it);CHKERRQ(ierr);
291     ierr = TaoSetMaximumFunctionEvaluations(gn->subsolver,tao->max_funcs);CHKERRQ(ierr);
292     for (i=0; i<tao->numbermonitors; ++i) {
293       ierr = TaoSetMonitor(gn->subsolver,tao->monitor[i],tao->monitorcontext[i],tao->monitordestroy[i]);CHKERRQ(ierr);
294       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
295     }
296     ierr = TaoSetUp(gn->subsolver);CHKERRQ(ierr);
297   }
298   PetscFunctionReturn(0);
299 }
300 
301 static PetscErrorCode TaoDestroy_BRGN(Tao tao)
302 {
303   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
304   PetscErrorCode        ierr;
305 
306   PetscFunctionBegin;
307   if (tao->setupcalled) {
308     ierr = VecDestroy(&tao->gradient);CHKERRQ(ierr);
309     ierr = VecDestroy(&gn->x_work);CHKERRQ(ierr);
310     ierr = VecDestroy(&gn->r_work);CHKERRQ(ierr);
311     ierr = VecDestroy(&gn->x_old);CHKERRQ(ierr);
312     ierr = VecDestroy(&gn->diag);CHKERRQ(ierr);
313     ierr = VecDestroy(&gn->y);CHKERRQ(ierr);
314     ierr = VecDestroy(&gn->y_work);CHKERRQ(ierr);
315   }
316   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
317   ierr = MatDestroy(&gn->D);CHKERRQ(ierr);
318   ierr = MatDestroy(&gn->Hreg);CHKERRQ(ierr);
319   ierr = TaoDestroy(&gn->subsolver);CHKERRQ(ierr);
320   gn->parent = NULL;
321   ierr = PetscFree(tao->data);CHKERRQ(ierr);
322   PetscFunctionReturn(0);
323 }
324 
325 /*MC
326   TAOBRGN - Bounded Regularized Gauss-Newton method for solving nonlinear least-squares
327             problems with bound constraints. This algorithm is a thin wrapper around TAOBNTL
328             that constructs the Gauss-Newton problem with the user-provided least-squares
329             residual and Jacobian. The algorithm offers both an L2-norm proximal point ("l2prox")
330             regularizer, and a L1-norm dictionary regularizer ("l1dict"), where we approximate the
331             L1-norm ||x||_1 by sum_i(sqrt(x_i^2+epsilon^2)-epsilon) with a small positive number epsilon.
332             The user can also provide own regularization function.
333 
334   Options Database Keys:
335   + -tao_brgn_lambda              - regularizer weight (default 1e-4)
336   . -tao_brgn_epsilon             - L1-norm smooth approximation parameter: ||x||_1 = sum(sqrt(x.^2+epsilon^2)-epsilon) (default 1e-6)
337   - -tao_brgn_regularization_type - regularization type ("user", "l2prox", "l1dict")
338 
339   Level: beginner
340 M*/
341 PETSC_EXTERN PetscErrorCode TaoCreate_BRGN(Tao tao)
342 {
343   TAO_BRGN       *gn;
344   PetscErrorCode ierr;
345 
346   PetscFunctionBegin;
347   ierr = PetscNewLog(tao,&gn);CHKERRQ(ierr);
348 
349   tao->ops->destroy = TaoDestroy_BRGN;
350   tao->ops->setup = TaoSetUp_BRGN;
351   tao->ops->setfromoptions = TaoSetFromOptions_BRGN;
352   tao->ops->view = TaoView_BRGN;
353   tao->ops->solve = TaoSolve_BRGN;
354 
355   tao->data = (void*)gn;
356   gn->lambda = 1e-4;
357   gn->epsilon = 1e-6;
358   gn->parent = tao;
359 
360   ierr = MatCreate(PetscObjectComm((PetscObject)tao),&gn->H);CHKERRQ(ierr);
361   ierr = MatSetOptionsPrefix(gn->H,"tao_brgn_hessian_");CHKERRQ(ierr);
362 
363   ierr = TaoCreate(PetscObjectComm((PetscObject)tao),&gn->subsolver);CHKERRQ(ierr);
364   ierr = TaoSetType(gn->subsolver,TAOBNLS);CHKERRQ(ierr);
365   ierr = TaoSetOptionsPrefix(gn->subsolver,"tao_brgn_subsolver_");CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 /*@
370   TaoBRGNGetSubsolver - Get the pointer to the subsolver inside BRGN
371 
372   Collective on Tao
373 
374   Level: advanced
375 
376   Input Parameters:
377 +  tao - the Tao solver context
378 -  subsolver - the Tao sub-solver context
379 @*/
380 PetscErrorCode TaoBRGNGetSubsolver(Tao tao,Tao *subsolver)
381 {
382   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
383 
384   PetscFunctionBegin;
385   *subsolver = gn->subsolver;
386   PetscFunctionReturn(0);
387 }
388 
389 /*@
390   TaoBRGNSetRegularizerWeight - Set the regularizer weight for the Gauss-Newton least-squares algorithm
391 
392   Collective on Tao
393 
394   Input Parameters:
395 +  tao - the Tao solver context
396 -  lambda - L1-norm regularizer weight
397 
398   Level: beginner
399 @*/
400 PetscErrorCode TaoBRGNSetRegularizerWeight(Tao tao,PetscReal lambda)
401 {
402   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
403 
404   /* Initialize lambda here */
405 
406   PetscFunctionBegin;
407   gn->lambda = lambda;
408   PetscFunctionReturn(0);
409 }
410 
411 /*@
412   TaoBRGNSetL1SmoothEpsilon - Set the L1-norm smooth approximation parameter for L1-regularized least-squares algorithm
413 
414   Collective on Tao
415 
416   Input Parameters:
417 +  tao - the Tao solver context
418 -  epsilon - L1-norm smooth approximation parameter
419 
420   Level: advanced
421 @*/
422 PetscErrorCode TaoBRGNSetL1SmoothEpsilon(Tao tao,PetscReal epsilon)
423 {
424   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
425 
426   /* Initialize epsilon here */
427 
428   PetscFunctionBegin;
429   gn->epsilon = epsilon;
430   PetscFunctionReturn(0);
431 }
432 
433 /*@
434    TaoBRGNSetDictionaryMatrix - bind the dictionary matrix from user application context to gn->D, for compressed sensing (with least-squares problem)
435 
436    Input Parameters:
437 +  tao  - the Tao context
438 .  dict - the user specified dictionary matrix.  We allow to set a null dictionary, which means identity matrix by default
439 
440     Level: advanced
441 @*/
442 PetscErrorCode TaoBRGNSetDictionaryMatrix(Tao tao,Mat dict)
443 {
444   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
445   PetscErrorCode ierr;
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
448   if (dict) {
449     PetscValidHeaderSpecific(dict,MAT_CLASSID,2);
450     PetscCheckSameComm(tao,1,dict,2);
451     ierr = PetscObjectReference((PetscObject)dict);CHKERRQ(ierr);
452   }
453   ierr = MatDestroy(&gn->D);CHKERRQ(ierr);
454   gn->D = dict;
455   PetscFunctionReturn(0);
456 }
457 
458 /*@C
459    TaoBRGNSetRegularizerObjectiveAndGradientRoutine - Sets the user-defined regularizer call-back
460    function into the algorithm.
461 
462    Input Parameters:
463    + tao - the Tao context
464    . func - function pointer for the regularizer value and gradient evaluation
465    - ctx - user context for the regularizer
466 
467    Level: advanced
468 @*/
469 PetscErrorCode TaoBRGNSetRegularizerObjectiveAndGradientRoutine(Tao tao,PetscErrorCode (*func)(Tao,Vec,PetscReal *,Vec,void*),void *ctx)
470 {
471   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
472 
473   PetscFunctionBegin;
474   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
475   if (ctx) {
476     gn->reg_obj_ctx = ctx;
477   }
478   if (func) {
479     gn->regularizerobjandgrad = func;
480   }
481   PetscFunctionReturn(0);
482 }
483 
484 /*@C
485    TaoBRGNSetRegularizerHessianRoutine - Sets the user-defined regularizer call-back
486    function into the algorithm.
487 
488    Input Parameters:
489    + tao - the Tao context
490    . Hreg - user-created matrix for the Hessian of the regularization term
491    . func - function pointer for the regularizer Hessian evaluation
492    - ctx - user context for the regularizer Hessian
493 
494    Level: advanced
495 @*/
496 PetscErrorCode TaoBRGNSetRegularizerHessianRoutine(Tao tao,Mat Hreg,PetscErrorCode (*func)(Tao,Vec,Mat,void*),void *ctx)
497 {
498   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
503   if (Hreg) {
504     PetscValidHeaderSpecific(Hreg,MAT_CLASSID,2);
505     PetscCheckSameComm(tao,1,Hreg,2);
506   } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONG,"NULL Hessian detected! User must provide valid Hessian for the regularizer.");
507   if (ctx) {
508     gn->reg_hess_ctx = ctx;
509   }
510   if (func) {
511     gn->regularizerhessian = func;
512   }
513   if (Hreg) {
514     ierr = PetscObjectReference((PetscObject)Hreg);CHKERRQ(ierr);
515     ierr = MatDestroy(&gn->Hreg);CHKERRQ(ierr);
516     gn->Hreg = Hreg;
517   }
518   PetscFunctionReturn(0);
519 }