xref: /petsc/src/tao/leastsquares/impls/brgn/brgn.c (revision a3c390cf90def66a8111e1ecee6db1297494c92c)
1 #include <../src/tao/leastsquares/impls/brgn/brgn.h>
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)^T(xk - xkm1) */
73     ierr = VecAXPBYPCZ(gn->x_work,1.0,-1.0,0.0,X,gn->x_old);CHKERRQ(ierr); /*TODO: no need to use VecAXPBYPCZ for x - xkm1 */
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","",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)","",gn->epsilon,&gn->epsilon,NULL);CHKERRQ(ierr);
201   ierr = PetscOptionsEList("-tao_brgn_reg_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   /*PetscScalar           v; */ /* XH: hack to set value of matrix */
226 
227   PetscFunctionBegin;
228   if (!tao->ls_res) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ORDER,"TaoSetResidualRoutine() must be called before setup!");
229   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNLS,&is_bnls);CHKERRQ(ierr);
230   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNTR,&is_bntr);CHKERRQ(ierr);
231   ierr = PetscObjectTypeCompare((PetscObject)gn->subsolver,TAOBNTL,&is_bntl);CHKERRQ(ierr);
232   if ((is_bnls || is_bntr || is_bntl) && !tao->ls_jac) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ORDER,"TaoSetResidualJacobianRoutine() must be called before setup!");
233   if (!tao->gradient){
234     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
235   }
236   if (!gn->x_work){
237     ierr = VecDuplicate(tao->solution,&gn->x_work);CHKERRQ(ierr);
238   }
239   if (!gn->r_work){
240     ierr = VecDuplicate(tao->ls_res,&gn->r_work);CHKERRQ(ierr);
241   }
242   if (!gn->x_old) {
243     ierr = VecDuplicate(tao->solution,&gn->x_old);CHKERRQ(ierr);
244     ierr = VecSet(gn->x_old,0.0);CHKERRQ(ierr);
245   }
246 
247   /*ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);*/
248   /* TODO: Safeguard against NULL matrix */
249   /*if (!gn->D)*/
250   ierr = MatGetSize(gn->D,&K,&N);CHKERRQ(ierr); /* Shell matrices still must have sizes defined */
251    /* K = N for identity matrix, K=N-1 or N for gradient matrix */
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   /* XH: debug: check matrix */
268 #if 0
269   ierr = PetscPrintf(PETSC_COMM_SELF,"-------- Check D matrix: -------- \n"); CHKERRQ(ierr);
270   ierr = MatView(gn->D,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
271 #endif
272 
273   if (!tao->setupcalled) {
274     /* Hessian setup */
275     ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr);
276     ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);
277     ierr = MatSetSizes(gn->H,n,n,N,N);CHKERRQ(ierr);
278     ierr = MatSetType(gn->H,MATSHELL);CHKERRQ(ierr);
279     ierr = MatSetUp(gn->H);CHKERRQ(ierr);
280     ierr = MatShellSetOperation(gn->H,MATOP_MULT,(void (*)(void))GNHessianProd);CHKERRQ(ierr);
281     ierr = MatShellSetContext(gn->H,(void*)gn);CHKERRQ(ierr);
282     /* Subsolver setup,include initial vector and dicttionary D */
283     ierr = TaoSetUpdate(gn->subsolver,GNHookFunction,(void*)gn);CHKERRQ(ierr);
284     ierr = TaoSetInitialVector(gn->subsolver,tao->solution);CHKERRQ(ierr);
285     if (tao->bounded) {
286       ierr = TaoSetVariableBounds(gn->subsolver,tao->XL,tao->XU);CHKERRQ(ierr);
287     }
288     ierr = TaoSetResidualRoutine(gn->subsolver,tao->ls_res,tao->ops->computeresidual,tao->user_lsresP);CHKERRQ(ierr);
289     ierr = TaoSetJacobianResidualRoutine(gn->subsolver,tao->ls_jac,tao->ls_jac,tao->ops->computeresidualjacobian,tao->user_lsjacP);CHKERRQ(ierr);
290     ierr = TaoSetObjectiveAndGradientRoutine(gn->subsolver,GNObjectiveGradientEval,(void*)gn);CHKERRQ(ierr);
291     ierr = TaoSetHessianRoutine(gn->subsolver,gn->H,gn->H,GNComputeHessian,(void*)gn);CHKERRQ(ierr);
292     /* Propagate some options down */
293     ierr = TaoSetTolerances(gn->subsolver,tao->gatol,tao->grtol,tao->gttol);CHKERRQ(ierr);
294     ierr = TaoSetMaximumIterations(gn->subsolver,tao->max_it);CHKERRQ(ierr);
295     ierr = TaoSetMaximumFunctionEvaluations(gn->subsolver,tao->max_funcs);CHKERRQ(ierr);
296     for (i=0; i<tao->numbermonitors; ++i) {
297       ierr = TaoSetMonitor(gn->subsolver,tao->monitor[i],tao->monitorcontext[i],tao->monitordestroy[i]);CHKERRQ(ierr);
298       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
299     }
300     ierr = TaoSetUp(gn->subsolver);CHKERRQ(ierr);
301   }
302   PetscFunctionReturn(0);
303 }
304 
305 static PetscErrorCode TaoDestroy_BRGN(Tao tao)
306 {
307   TAO_BRGN              *gn = (TAO_BRGN *)tao->data;
308   PetscErrorCode        ierr;
309 
310   PetscFunctionBegin;
311   if (tao->setupcalled) {
312     ierr = VecDestroy(&tao->gradient);CHKERRQ(ierr);
313     ierr = VecDestroy(&gn->x_work);CHKERRQ(ierr);
314     ierr = VecDestroy(&gn->r_work);CHKERRQ(ierr);
315     ierr = VecDestroy(&gn->x_old);CHKERRQ(ierr);
316     ierr = VecDestroy(&gn->diag);CHKERRQ(ierr);
317     ierr = VecDestroy(&gn->y);CHKERRQ(ierr);
318     ierr = VecDestroy(&gn->y_work);CHKERRQ(ierr);
319   }
320   ierr = MatDestroy(&gn->H);CHKERRQ(ierr);
321   ierr = MatDestroy(&gn->D);CHKERRQ(ierr);
322   ierr = TaoDestroy(&gn->subsolver);CHKERRQ(ierr);
323   gn->parent = NULL;
324   ierr = PetscFree(tao->data);CHKERRQ(ierr);
325   PetscFunctionReturn(0);
326 }
327 
328 /*MC
329   TAOBRGN - Bounded Regularized Gauss-Newton method for solving nonlinear least-squares
330             problems with bound constraints. This algorithm is a thin wrapper around TAOBNTL
331             that constructs the Guass-Newton problem with the user-provided least-squares
332             residual and Jacobian. The problem is regularized with an L2-norm proximal point
333             term.
334 
335   Options Database Keys:
336   + -tao_bqnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
337   . -tao_bqnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
338   . -tao_bqnk_update_type - trust radius update method ("step", "direction", "interpolation")
339   - -tao_bqnk_as_type - active-set estimation method ("none", "bertsekas")
340 
341   Level: beginner
342 M*/
343 PETSC_EXTERN PetscErrorCode TaoCreate_BRGN(Tao tao)
344 {
345   TAO_BRGN       *gn;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   ierr = PetscNewLog(tao,&gn);CHKERRQ(ierr);
350 
351   tao->ops->destroy = TaoDestroy_BRGN;
352   tao->ops->setup = TaoSetUp_BRGN;
353   tao->ops->setfromoptions = TaoSetFromOptions_BRGN;
354   tao->ops->view = TaoView_BRGN;
355   tao->ops->solve = TaoSolve_BRGN;
356 
357   tao->data = (void*)gn;
358   gn->lambda = 1e-4;
359   gn->epsilon = 1e-6;
360   gn->parent = tao;
361 
362   ierr = MatCreate(PetscObjectComm((PetscObject)tao),&gn->H);CHKERRQ(ierr);
363   ierr = MatSetOptionsPrefix(gn->H,"tao_brgn_hessian_");CHKERRQ(ierr);
364 
365   ierr = TaoCreate(PetscObjectComm((PetscObject)tao),&gn->subsolver);CHKERRQ(ierr);
366   ierr = TaoSetType(gn->subsolver,TAOBNLS);CHKERRQ(ierr);
367   ierr = TaoSetOptionsPrefix(gn->subsolver,"tao_brgn_subsolver_");CHKERRQ(ierr);
368   PetscFunctionReturn(0);
369 }
370 
371 /*@C
372   TaoBRGNGetSubsolver - Get the pointer to the subsolver inside BRGN
373 
374   Collective on Tao
375 
376   Level: developer
377 
378   Input Parameters:
379 +  tao - the Tao solver context
380 -  subsolver - the Tao sub-solver context
381 @*/
382 PetscErrorCode TaoBRGNGetSubsolver(Tao tao,Tao *subsolver)
383 {
384   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
385 
386   PetscFunctionBegin;
387   *subsolver = gn->subsolver;
388   PetscFunctionReturn(0);
389 }
390 
391 /*@C
392   TaoBRGNSetL1RegularizerWeight - Set the L1-norm regularizer weight for the Gauss-Newton least-squares algorithm
393 
394   Collective on Tao
395 
396   Level: developer
397 
398   Input Parameters:
399 +  tao - the Tao solver context
400 -  lambda - L1-norm regularizer weight
401 @*/
402 PetscErrorCode TaoBRGNSetRegularizerWeight(Tao tao,PetscReal lambda)
403 {
404   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
405 
406   /* Initialize lambda here */
407 
408   PetscFunctionBegin;
409   gn->lambda = lambda;
410   PetscFunctionReturn(0);
411 }
412 
413 /*@C
414   TaoBRGNSetL1SmoothEpsilon - Set the L1-norm smooth approximation parameter for L1-regularized least-squares algorithm
415 
416   Collective on Tao
417 
418   Level: developer
419 
420   Input Parameters:
421 +  tao - the Tao solver context
422 -  epsilon - L1-norm smooth approximation parameter
423 @*/
424 PetscErrorCode TaoBRGNSetL1SmoothEpsilon(Tao tao,PetscReal epsilon)
425 {
426   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
427 
428   /* Initialize epsilon here */
429 
430   PetscFunctionBegin;
431   gn->epsilon = epsilon;
432   PetscFunctionReturn(0);
433 }
434 
435 /*@C
436    TaoBRGNSetDictionaryMatrix - bind the dictionary matrix from user application context to gn->D, for compressed sensing (with least-squares problem)
437 
438    Input Parameters:
439 +  tao  - the Tao context
440 .  dict - the user specified dictionary matrix
441 
442     Level: developer
443 @*/
444 PetscErrorCode TaoBRGNSetDictionaryMatrix(Tao tao,Mat dict)
445 {
446   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
447   PetscErrorCode ierr;
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
450   if (dict) {
451     PetscValidHeaderSpecific(dict,MAT_CLASSID,2);
452     PetscCheckSameComm(tao,1,dict,2);
453     ierr = PetscObjectReference((PetscObject)dict);CHKERRQ(ierr);
454   }
455   ierr = MatDestroy(&gn->D);CHKERRQ(ierr);
456   gn->D = dict;  /* We allow to set a null dictionary, which means we just use default identity matrix? */
457   PetscFunctionReturn(0);
458 }
459 
460 /*@C
461 @*/
462 PetscErrorCode TaoBRGNSetRegularizerObjectiveAndGradientRoutine(Tao tao,PetscErrorCode (*func)(Tao, Vec, PetscReal *, Vec, void*),void *ctx)
463 {
464   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
465 
466   PetscFunctionBegin;
467   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
468   if (ctx) {
469     gn->reg_obj_ctx = ctx;
470   }
471   if (func) {
472     gn->regularizerobjandgrad = func;
473   }
474   PetscFunctionReturn(0);
475 }
476 
477 /*@C
478 @*/
479 PetscErrorCode TaoBRGNSetRegularizerHessianRoutine(Tao tao,Mat Hreg,PetscErrorCode (*func)(Tao, Vec, Mat, void*),void *ctx)
480 {
481   TAO_BRGN       *gn = (TAO_BRGN *)tao->data;
482   PetscErrorCode ierr;
483 
484   PetscFunctionBegin;
485   PetscValidHeaderSpecific(tao,TAO_CLASSID,1);
486   if (Hreg) {
487     PetscValidHeaderSpecific(Hreg,MAT_CLASSID,2);
488     PetscCheckSameComm(tao,1,Hreg,2);
489   } else {
490     SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONG,"NULL Hessian detected! User must provide valid Hessian for the regularizer.");
491   }
492   if (ctx) {
493     gn->reg_hess_ctx = ctx;
494   }
495   if (func) {
496     gn->regularizerhessian = func;
497   }
498   if (Hreg) {
499     ierr = PetscObjectReference((PetscObject)Hreg);CHKERRQ(ierr);
500     ierr = MatDestroy(&gn->Hreg);CHKERRQ(ierr);
501     gn->Hreg = Hreg;
502   }
503   PetscFunctionReturn(0);
504 }