xref: /petsc/src/tao/bound/impls/bncg/bncg.c (revision 414d97d33157b14bf619cafd0d5a004382ae017e)
1ac9112b8SAlp Dener #include <petsctaolinesearch.h>
2*414d97d3SAlp Dener #include <../src/tao/bound/impls/bncg/bncg.h> /*I "petsctao.h" I*/
350b47da0SAdam Denchfield #include <petscksp.h>
4ac9112b8SAlp Dener 
5c8bcdf1eSAdam Denchfield #define CG_GradientDescent      0
6c8bcdf1eSAdam Denchfield #define CG_HestenesStiefel      1
7c8bcdf1eSAdam Denchfield #define CG_FletcherReeves       2
850b47da0SAdam Denchfield #define CG_PolakRibierePolyak   3
9c8bcdf1eSAdam Denchfield #define CG_PolakRibierePlus     4
10c8bcdf1eSAdam Denchfield #define CG_DaiYuan              5
11c8bcdf1eSAdam Denchfield #define CG_HagerZhang           6
12c8bcdf1eSAdam Denchfield #define CG_DaiKou               7
13c8bcdf1eSAdam Denchfield #define CG_KouDai               8
14c8bcdf1eSAdam Denchfield #define CG_SSML_BFGS            9
15c8bcdf1eSAdam Denchfield #define CG_SSML_DFP             10
16c8bcdf1eSAdam Denchfield #define CG_SSML_BROYDEN         11
17484c7b14SAdam Denchfield #define CG_PCGradientDescent    12
18484c7b14SAdam Denchfield #define CGTypes                 13
19ac9112b8SAlp Dener 
20484c7b14SAdam Denchfield static const char *CG_Table[64] = {"gd", "hs", "fr", "pr", "prp", "dy", "hz", "dk", "kd", "ssml_bfgs", "ssml_dfp", "ssml_brdn", "pcgd"};
21ac9112b8SAlp Dener 
2261be54a6SAlp Dener #define CG_AS_NONE       0
2361be54a6SAlp Dener #define CG_AS_BERTSEKAS  1
2461be54a6SAlp Dener #define CG_AS_SIZE       2
25ac9112b8SAlp Dener 
2661be54a6SAlp Dener static const char *CG_AS_TYPE[64] = {"none", "bertsekas"};
27ac9112b8SAlp Dener 
2861be54a6SAlp Dener PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType)
2961be54a6SAlp Dener {
3061be54a6SAlp Dener   PetscErrorCode               ierr;
3161be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
3261be54a6SAlp Dener 
3361be54a6SAlp Dener   PetscFunctionBegin;
3461be54a6SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
3561be54a6SAlp Dener   if (cg->inactive_idx) {
3661be54a6SAlp Dener     ierr = ISDuplicate(cg->inactive_idx, &cg->inactive_old);CHKERRQ(ierr);
3761be54a6SAlp Dener     ierr = ISCopy(cg->inactive_idx, cg->inactive_old);CHKERRQ(ierr);
3861be54a6SAlp Dener   }
3961be54a6SAlp Dener   switch (asType) {
4061be54a6SAlp Dener   case CG_AS_NONE:
4161be54a6SAlp Dener     ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
4261be54a6SAlp Dener     ierr = VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx);CHKERRQ(ierr);
4361be54a6SAlp Dener     ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
4461be54a6SAlp Dener     ierr = ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx);CHKERRQ(ierr);
4561be54a6SAlp Dener     break;
4661be54a6SAlp Dener 
4761be54a6SAlp Dener   case CG_AS_BERTSEKAS:
4861be54a6SAlp Dener     /* Use gradient descent to estimate the active set */
4961be54a6SAlp Dener     ierr = VecCopy(cg->unprojected_gradient, cg->W);CHKERRQ(ierr);
5061be54a6SAlp Dener     ierr = VecScale(cg->W, -1.0);CHKERRQ(ierr);
5189da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol,
5289da521bSAlp Dener                                    &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx);CHKERRQ(ierr);
53c4b75bccSAlp Dener     break;
5461be54a6SAlp Dener 
5561be54a6SAlp Dener   default:
5661be54a6SAlp Dener     break;
5761be54a6SAlp Dener   }
5861be54a6SAlp Dener   PetscFunctionReturn(0);
5961be54a6SAlp Dener }
6061be54a6SAlp Dener 
61a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step)
6261be54a6SAlp Dener {
6361be54a6SAlp Dener   PetscErrorCode               ierr;
6461be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
6561be54a6SAlp Dener 
6661be54a6SAlp Dener   PetscFunctionBegin;
67a1318120SAlp Dener   switch (asType) {
6861be54a6SAlp Dener   case CG_AS_NONE:
69c4b75bccSAlp Dener     ierr = VecISSet(step, cg->active_idx, 0.0);CHKERRQ(ierr);
7061be54a6SAlp Dener     break;
7161be54a6SAlp Dener 
7261be54a6SAlp Dener   case CG_AS_BERTSEKAS:
73c4b75bccSAlp Dener     ierr = TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step);CHKERRQ(ierr);
7461be54a6SAlp Dener     break;
7561be54a6SAlp Dener 
7661be54a6SAlp Dener   default:
7761be54a6SAlp Dener     break;
7861be54a6SAlp Dener   }
7961be54a6SAlp Dener   PetscFunctionReturn(0);
8061be54a6SAlp Dener }
8161be54a6SAlp Dener 
82ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao)
83ac9112b8SAlp Dener {
84ac9112b8SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
85ac9112b8SAlp Dener   PetscErrorCode               ierr;
86484c7b14SAdam Denchfield   PetscReal                    step=1.0,gnorm,gnorm2, resnorm;
87c4b75bccSAlp Dener   PetscInt                     nDiff;
88ac9112b8SAlp Dener 
89ac9112b8SAlp Dener   PetscFunctionBegin;
90ac9112b8SAlp Dener   /*   Project the current point onto the feasible set */
91ac9112b8SAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
92cd929ea3SAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
93ac9112b8SAlp Dener 
94c8bcdf1eSAdam Denchfield   /* Project the initial point onto the feasible region */
95c8bcdf1eSAdam Denchfield   ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
96484c7b14SAdam Denchfield 
97*414d97d3SAlp Dener   if (nDiff > 0 || !tao->recycle){
98c0f10754SAlp Dener     ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient);CHKERRQ(ierr);
99484c7b14SAdam Denchfield   }
100ac9112b8SAlp Dener   ierr = VecNorm(cg->unprojected_gradient,NORM_2,&gnorm);CHKERRQ(ierr);
101691b26d3SBarry Smith   if (PetscIsInfOrNanReal(cg->f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
102ac9112b8SAlp Dener 
10361be54a6SAlp Dener   /* Estimate the active set and compute the projected gradient */
10461be54a6SAlp Dener   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
10561be54a6SAlp Dener 
106ac9112b8SAlp Dener   /* Project the gradient and calculate the norm */
10761be54a6SAlp Dener   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
10861be54a6SAlp Dener   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
109ac9112b8SAlp Dener   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
110ac9112b8SAlp Dener   gnorm2 = gnorm*gnorm;
111ac9112b8SAlp Dener 
112c8bcdf1eSAdam Denchfield   /* Initialize counters */
113e031d6f5SAlp Dener   tao->niter = 0;
11450b47da0SAdam Denchfield   cg->ls_fails = cg->descent_error = 0;
115c8bcdf1eSAdam Denchfield   cg->resets = -1;
116484c7b14SAdam Denchfield   cg->skipped_updates = cg->pure_gd_steps = 0;
117c8bcdf1eSAdam Denchfield   cg->iter_quad = 0;
118c8bcdf1eSAdam Denchfield 
119c8bcdf1eSAdam Denchfield   /* Convergence test at the starting point. */
120ac9112b8SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
121484c7b14SAdam Denchfield 
122484c7b14SAdam Denchfield   ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
123484c7b14SAdam Denchfield   ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
124691b26d3SBarry Smith   if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
125484c7b14SAdam Denchfield   ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
126484c7b14SAdam Denchfield   ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
127ac9112b8SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
128ac9112b8SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
129484c7b14SAdam Denchfield   /* Calculate initial direction. */
130*414d97d3SAlp Dener   if (!tao->recycle) {
131484c7b14SAdam Denchfield     /* We are not recycling a solution/history from a past TaoSolve */
132484c7b14SAdam Denchfield     ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
133ac9112b8SAlp Dener   }
134c8bcdf1eSAdam Denchfield   /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */
135c8bcdf1eSAdam Denchfield   while (1) {
136e1e80dc8SAlp Dener     /* Call general purpose update function */
137e1e80dc8SAlp Dener     if (tao->ops->update) {
1388fcddce6SStefano Zampini       ierr = (*tao->ops->update)(tao, tao->niter, tao->user_update);CHKERRQ(ierr);
139e1e80dc8SAlp Dener     }
140c8bcdf1eSAdam Denchfield     ierr = TaoBNCGConductIteration(tao, gnorm);CHKERRQ(ierr);
141c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
142ac9112b8SAlp Dener   }
143ac9112b8SAlp Dener }
144ac9112b8SAlp Dener 
145ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao)
146ac9112b8SAlp Dener {
147ac9112b8SAlp Dener   TAO_BNCG         *cg = (TAO_BNCG*)tao->data;
148ac9112b8SAlp Dener   PetscErrorCode ierr;
149ac9112b8SAlp Dener 
150ac9112b8SAlp Dener   PetscFunctionBegin;
151c4b75bccSAlp Dener   if (!tao->gradient) {
152c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
153c4b75bccSAlp Dener   }
154c4b75bccSAlp Dener   if (!tao->stepdirection) {
155c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);
156c4b75bccSAlp Dener   }
157c4b75bccSAlp Dener   if (!cg->W) {
158c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->W);CHKERRQ(ierr);
159c4b75bccSAlp Dener   }
160c4b75bccSAlp Dener   if (!cg->work) {
161c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->work);CHKERRQ(ierr);
162c4b75bccSAlp Dener   }
163c8bcdf1eSAdam Denchfield   if (!cg->sk) {
164c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->sk);CHKERRQ(ierr);
165c8bcdf1eSAdam Denchfield   }
166c8bcdf1eSAdam Denchfield   if (!cg->yk) {
167c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->gradient,&cg->yk);CHKERRQ(ierr);
168c8bcdf1eSAdam Denchfield   }
169c4b75bccSAlp Dener   if (!cg->X_old) {
170c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->X_old);CHKERRQ(ierr);
171c4b75bccSAlp Dener   }
172c4b75bccSAlp Dener   if (!cg->G_old) {
173c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->G_old);CHKERRQ(ierr);
174c8bcdf1eSAdam Denchfield   }
175c8bcdf1eSAdam Denchfield   if (cg->diag_scaling){
176c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->d_work);CHKERRQ(ierr);
177c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->y_work);CHKERRQ(ierr);
17850b47da0SAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->g_work);CHKERRQ(ierr);
179c4b75bccSAlp Dener   }
180c4b75bccSAlp Dener   if (!cg->unprojected_gradient) {
181c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient);CHKERRQ(ierr);
182c4b75bccSAlp Dener   }
183c4b75bccSAlp Dener   if (!cg->unprojected_gradient_old) {
184c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient_old);CHKERRQ(ierr);
185c4b75bccSAlp Dener   }
18650b47da0SAdam Denchfield   ierr = MatLMVMAllocate(cg->B, cg->sk, cg->yk);CHKERRQ(ierr);
187484c7b14SAdam Denchfield   if (cg->pc){
188484c7b14SAdam Denchfield     ierr = MatLMVMSetJ0(cg->B, cg->pc);CHKERRQ(ierr);
189484c7b14SAdam Denchfield   }
190ac9112b8SAlp Dener   PetscFunctionReturn(0);
191ac9112b8SAlp Dener }
192ac9112b8SAlp Dener 
193ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao)
194ac9112b8SAlp Dener {
195ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*) tao->data;
196ac9112b8SAlp Dener   PetscErrorCode ierr;
197ac9112b8SAlp Dener 
198ac9112b8SAlp Dener   PetscFunctionBegin;
199ac9112b8SAlp Dener   if (tao->setupcalled) {
20061be54a6SAlp Dener     ierr = VecDestroy(&cg->W);CHKERRQ(ierr);
201c4b75bccSAlp Dener     ierr = VecDestroy(&cg->work);CHKERRQ(ierr);
202ac9112b8SAlp Dener     ierr = VecDestroy(&cg->X_old);CHKERRQ(ierr);
203ac9112b8SAlp Dener     ierr = VecDestroy(&cg->G_old);CHKERRQ(ierr);
204ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient);CHKERRQ(ierr);
205ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient_old);CHKERRQ(ierr);
20650b47da0SAdam Denchfield     ierr = VecDestroy(&cg->g_work);CHKERRQ(ierr);
20750b47da0SAdam Denchfield     ierr = VecDestroy(&cg->d_work);CHKERRQ(ierr);
20850b47da0SAdam Denchfield     ierr = VecDestroy(&cg->y_work);CHKERRQ(ierr);
20950b47da0SAdam Denchfield     ierr = VecDestroy(&cg->sk);CHKERRQ(ierr);
21050b47da0SAdam Denchfield     ierr = VecDestroy(&cg->yk);CHKERRQ(ierr);
211ac9112b8SAlp Dener   }
212ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_lower);CHKERRQ(ierr);
213ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_upper);CHKERRQ(ierr);
214ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_fixed);CHKERRQ(ierr);
215ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
216ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
217ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
218ca964c49SAlp Dener   ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
21901e1e359SAlp Dener   ierr = MatDestroy(&cg->B);CHKERRQ(ierr);
220484c7b14SAdam Denchfield   if (cg->pc) {
22101e1e359SAlp Dener     ierr = MatDestroy(&cg->pc);CHKERRQ(ierr);
222484c7b14SAdam Denchfield   }
223ac9112b8SAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
224ac9112b8SAlp Dener   PetscFunctionReturn(0);
225ac9112b8SAlp Dener }
226ac9112b8SAlp Dener 
227ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao)
228ac9112b8SAlp Dener {
229ac9112b8SAlp Dener     TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
230ac9112b8SAlp Dener     PetscErrorCode ierr;
231ac9112b8SAlp Dener 
232ac9112b8SAlp Dener     PetscFunctionBegin;
233ac9112b8SAlp Dener     ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
234ac9112b8SAlp Dener     ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr);
235484c7b14SAdam Denchfield     ierr = PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr);
236484c7b14SAdam Denchfield     if (cg->cg_type != CG_SSML_BFGS){
237484c7b14SAdam Denchfield       cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */
238484c7b14SAdam Denchfield     }
239484c7b14SAdam Denchfield     if (CG_GradientDescent == cg->cg_type){
240484c7b14SAdam Denchfield       cg->cg_type = CG_PCGradientDescent;
241484c7b14SAdam Denchfield       /* Set scaling equal to none or, at best, scalar scaling. */
242484c7b14SAdam Denchfield       cg->unscaled_restart = PETSC_TRUE;
243484c7b14SAdam Denchfield       cg->diag_scaling = PETSC_FALSE;
244484c7b14SAdam Denchfield     }
24550b47da0SAdam Denchfield     ierr = PetscOptionsEList("-tao_bncg_as_type","active set estimation method", "", CG_AS_TYPE, CG_AS_SIZE, CG_AS_TYPE[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr);
24650b47da0SAdam Denchfield 
24750b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL);CHKERRQ(ierr);
24850b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL);CHKERRQ(ierr);
24950b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL);CHKERRQ(ierr);
25050b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL);CHKERRQ(ierr);
25150b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL);CHKERRQ(ierr);
25250b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL);CHKERRQ(ierr);
25350b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL);CHKERRQ(ierr);
254c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL);CHKERRQ(ierr);
255c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL);CHKERRQ(ierr);
256c8bcdf1eSAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL);CHKERRQ(ierr);
25750b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_dynamic_restart","(developer) use dynamic restarts as in HZ, DK, KD","",cg->use_dynamic_restart,&cg->use_dynamic_restart,NULL);CHKERRQ(ierr);
25850b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL);CHKERRQ(ierr);
25950b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL);CHKERRQ(ierr);
260c8bcdf1eSAdam Denchfield     ierr = PetscOptionsInt("-tao_bncg_min_quad", "(developer) Number of iterations with approximate quadratic behavior needed for restart", "", cg->min_quad, &cg->min_quad, NULL);CHKERRQ(ierr);
26150b47da0SAdam Denchfield     ierr = PetscOptionsInt("-tao_bncg_min_restart_num", "(developer) Number of iterations between restarts (times dimension)", "", cg->min_restart_num, &cg->min_restart_num, NULL);CHKERRQ(ierr);
26250b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_spaced_restart","(developer) Enable regular steepest descent restarting every fixed number of iterations","",cg->spaced_restart,&cg->spaced_restart,NULL);CHKERRQ(ierr);
263484c7b14SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_no_scaling","Disable all scaling except in restarts","",cg->no_scaling,&cg->no_scaling,NULL);CHKERRQ(ierr);
264484c7b14SAdam Denchfield     if (cg->no_scaling){
265484c7b14SAdam Denchfield       cg->diag_scaling = PETSC_FALSE;
266484c7b14SAdam Denchfield       cg->alpha = -1.0;
267484c7b14SAdam Denchfield     }
268b474139fSKarl Rupp     if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling){ /* Some more default options that appear to be good. */
269484c7b14SAdam Denchfield       cg->neg_xi = PETSC_TRUE;
270484c7b14SAdam Denchfield     }
27150b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_neg_xi","(developer) Use negative xi when it might be a smaller descent direction than necessary","",cg->neg_xi,&cg->neg_xi,NULL);CHKERRQ(ierr);
27250b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables","",cg->as_tol,&cg->as_tol,NULL);CHKERRQ(ierr);
27350b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables","",cg->as_step,&cg->as_step,NULL);CHKERRQ(ierr);
274484c7b14SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts","",cg->delta_min,&cg->delta_min,NULL);CHKERRQ(ierr);
275484c7b14SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts","",cg->delta_max,&cg->delta_max,NULL);CHKERRQ(ierr);
27650b47da0SAdam Denchfield 
277ac9112b8SAlp Dener    ierr = PetscOptionsTail();CHKERRQ(ierr);
27850b47da0SAdam Denchfield    ierr = MatSetFromOptions(cg->B);CHKERRQ(ierr);
279ac9112b8SAlp Dener    PetscFunctionReturn(0);
280ac9112b8SAlp Dener }
281ac9112b8SAlp Dener 
282ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer)
283ac9112b8SAlp Dener {
284ac9112b8SAlp Dener   PetscBool      isascii;
285ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
286ac9112b8SAlp Dener   PetscErrorCode ierr;
287ac9112b8SAlp Dener 
288ac9112b8SAlp Dener   PetscFunctionBegin;
289ac9112b8SAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
290ac9112b8SAlp Dener   if (isascii) {
291ac9112b8SAlp Dener     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
292ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type]);CHKERRQ(ierr);
293484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %i\n", cg->skipped_updates);CHKERRQ(ierr);
294484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %i\n", cg->resets);CHKERRQ(ierr);
295484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %i\n", cg->pure_gd_steps);CHKERRQ(ierr);
296484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Not a descent direction: %i\n", cg->descent_error);CHKERRQ(ierr);
297ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails);CHKERRQ(ierr);
298484c7b14SAdam Denchfield     if (cg->diag_scaling){
299484c7b14SAdam Denchfield       ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
300484c7b14SAdam Denchfield       if (isascii) {
301484c7b14SAdam Denchfield         ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO);CHKERRQ(ierr);
302484c7b14SAdam Denchfield         ierr = MatView(cg->B, viewer);CHKERRQ(ierr);
303484c7b14SAdam Denchfield         ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
304484c7b14SAdam Denchfield       }
305484c7b14SAdam Denchfield     }
306ac9112b8SAlp Dener     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
307ac9112b8SAlp Dener   }
308ac9112b8SAlp Dener   PetscFunctionReturn(0);
309ac9112b8SAlp Dener }
310ac9112b8SAlp Dener 
311c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha)
312c8bcdf1eSAdam Denchfield {
313c8bcdf1eSAdam Denchfield   PetscReal            a, b, c, sig1, sig2;
314c8bcdf1eSAdam Denchfield 
315c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
316c8bcdf1eSAdam Denchfield   *scale = 0.0;
317c8bcdf1eSAdam Denchfield 
31850b47da0SAdam Denchfield   if (1.0 == alpha){
319c8bcdf1eSAdam Denchfield     *scale = yts/yty;
32050b47da0SAdam Denchfield   } else if (0.0 == alpha){
321c8bcdf1eSAdam Denchfield     *scale = sts/yts;
322c8bcdf1eSAdam Denchfield   }
32350b47da0SAdam Denchfield   else if (-1.0 == alpha) *scale = 1.0;
324c8bcdf1eSAdam Denchfield   else {
325c8bcdf1eSAdam Denchfield     a = yty;
326c8bcdf1eSAdam Denchfield     b = yts;
327c8bcdf1eSAdam Denchfield     c = sts;
328c8bcdf1eSAdam Denchfield     a *= alpha;
329c8bcdf1eSAdam Denchfield     b *= -(2.0*alpha - 1.0);
330c8bcdf1eSAdam Denchfield     c *= alpha - 1.0;
331c8bcdf1eSAdam Denchfield     sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
332c8bcdf1eSAdam Denchfield     sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
333c8bcdf1eSAdam Denchfield     /* accept the positive root as the scalar */
334c8bcdf1eSAdam Denchfield     if (sig1 > 0.0) {
335c8bcdf1eSAdam Denchfield       *scale = sig1;
336c8bcdf1eSAdam Denchfield     } else if (sig2 > 0.0) {
337c8bcdf1eSAdam Denchfield       *scale = sig2;
338c8bcdf1eSAdam Denchfield     } else {
339c8bcdf1eSAdam Denchfield       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar");
340c8bcdf1eSAdam Denchfield     }
341c8bcdf1eSAdam Denchfield   }
342c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
343c8bcdf1eSAdam Denchfield }
344c8bcdf1eSAdam Denchfield 
345ac9112b8SAlp Dener /*MC
346ac9112b8SAlp Dener   TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method.
347ac9112b8SAlp Dener 
348ac9112b8SAlp Dener   Options Database Keys:
34950b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled)
350c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance
35161be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula
352c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method
353c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation
354c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation
35550b47da0SAdam Denchfield . -tao_bncg_eps <r> - cutoff used for determining whether or not we restart based on steplength each iteration, as well as determining whether or not we continue using the last stepdirection. Defaults to machine precision.
35650b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method
35750b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
35850b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
35950b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method
36050b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method
36150b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method
36250b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method
36350b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True.
36450b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods
36550b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts
36650b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method
367484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps
368484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps
36950b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart
37050b47da0SAdam Denchfield . -tao_bncg_min_restart_num <i> - This number, x, makes sure there is a gradient descent step every x*n iterations, where n is the dimension of the problem
37150b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations
372484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults.
3733850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions
374ac9112b8SAlp Dener 
375ac9112b8SAlp Dener   Notes:
376ac9112b8SAlp Dener     CG formulas are:
3773850be85SAlp Dener + "gd" - Gradient Descent
3783850be85SAlp Dener . "fr" - Fletcher-Reeves
3793850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak
3803850be85SAlp Dener . "prp" - Polak-Ribiere-Plus
3813850be85SAlp Dener . "hs" - Hestenes-Steifel
3823850be85SAlp Dener . "dy" - Dai-Yuan
3833850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS
3843850be85SAlp Dener . "ssml_dfp"  - Self-Scaling Memoryless DFP
3853850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden
3863850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3)
3873850be85SAlp Dener . "dk" - Dai-Kou (2013)
3883850be85SAlp Dener - "kd" - Kou-Dai (2015)
3899abc5736SPatrick Sanan 
390ac9112b8SAlp Dener   Level: beginner
391ac9112b8SAlp Dener M*/
392ac9112b8SAlp Dener 
393ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao)
394ac9112b8SAlp Dener {
395ac9112b8SAlp Dener   TAO_BNCG       *cg;
396ac9112b8SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
397ac9112b8SAlp Dener   PetscErrorCode ierr;
398ac9112b8SAlp Dener 
399ac9112b8SAlp Dener   PetscFunctionBegin;
400ac9112b8SAlp Dener   tao->ops->setup = TaoSetUp_BNCG;
401ac9112b8SAlp Dener   tao->ops->solve = TaoSolve_BNCG;
402ac9112b8SAlp Dener   tao->ops->view = TaoView_BNCG;
403ac9112b8SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNCG;
404ac9112b8SAlp Dener   tao->ops->destroy = TaoDestroy_BNCG;
405ac9112b8SAlp Dener 
406ac9112b8SAlp Dener   /* Override default settings (unless already changed) */
407ac9112b8SAlp Dener   if (!tao->max_it_changed) tao->max_it = 2000;
408ac9112b8SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
409ac9112b8SAlp Dener 
410ac9112b8SAlp Dener   /*  Note: nondefault values should be used for nonlinear conjugate gradient  */
411ac9112b8SAlp Dener   /*  method.  In particular, gtol should be less that 0.5; the value used in  */
412ac9112b8SAlp Dener   /*  Nocedal and Wright is 0.10.  We use the default values for the  */
413ac9112b8SAlp Dener   /*  linesearch because it seems to work better. */
414ac9112b8SAlp Dener   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr);
415ac9112b8SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr);
416ac9112b8SAlp Dener   ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr);
417ac9112b8SAlp Dener   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr);
418ac9112b8SAlp Dener   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
419ac9112b8SAlp Dener 
420ac9112b8SAlp Dener   ierr = PetscNewLog(tao,&cg);CHKERRQ(ierr);
421ac9112b8SAlp Dener   tao->data = (void*)cg;
422484c7b14SAdam Denchfield   ierr = KSPInitializePackage();CHKERRQ(ierr);
42350b47da0SAdam Denchfield   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &cg->B);CHKERRQ(ierr);
42450b47da0SAdam Denchfield   ierr = PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1);CHKERRQ(ierr);
42550b47da0SAdam Denchfield   ierr = MatSetOptionsPrefix(cg->B, "tao_bncg_");CHKERRQ(ierr);
426864588a7SAlp Dener   ierr = MatSetType(cg->B, MATLMVMDIAGBROYDEN);CHKERRQ(ierr);
42750b47da0SAdam Denchfield 
428484c7b14SAdam Denchfield   cg->pc = NULL;
429484c7b14SAdam Denchfield 
43050b47da0SAdam Denchfield   cg->dk_eta = 0.5;
43150b47da0SAdam Denchfield   cg->hz_eta = 0.4;
432c8bcdf1eSAdam Denchfield   cg->dynamic_restart = PETSC_FALSE;
433c8bcdf1eSAdam Denchfield   cg->unscaled_restart = PETSC_FALSE;
434484c7b14SAdam Denchfield   cg->no_scaling = PETSC_FALSE;
435484c7b14SAdam Denchfield   cg->delta_min = 1e-7;
436484c7b14SAdam Denchfield   cg->delta_max = 100;
437c8bcdf1eSAdam Denchfield   cg->theta = 1.0;
438c8bcdf1eSAdam Denchfield   cg->hz_theta = 1.0;
439c8bcdf1eSAdam Denchfield   cg->dfp_scale = 1.0;
440c8bcdf1eSAdam Denchfield   cg->bfgs_scale = 1.0;
44150b47da0SAdam Denchfield   cg->zeta = 0.1;
44250b47da0SAdam Denchfield   cg->min_quad = 6;
443c8bcdf1eSAdam Denchfield   cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/
444c8bcdf1eSAdam Denchfield   cg->xi = 1.0;
44550b47da0SAdam Denchfield   cg->neg_xi = PETSC_TRUE;
446c8bcdf1eSAdam Denchfield   cg->spaced_restart = PETSC_FALSE;
447c8bcdf1eSAdam Denchfield   cg->tol_quad = 1e-8;
44861be54a6SAlp Dener   cg->as_step = 0.001;
44961be54a6SAlp Dener   cg->as_tol = 0.001;
45050b47da0SAdam Denchfield   cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/
45161be54a6SAlp Dener   cg->as_type = CG_AS_BERTSEKAS;
452c8bcdf1eSAdam Denchfield   cg->cg_type = CG_SSML_BFGS;
453c8bcdf1eSAdam Denchfield   cg->alpha = 1.0;
454c8bcdf1eSAdam Denchfield   cg->diag_scaling = PETSC_TRUE;
455c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
456c8bcdf1eSAdam Denchfield }
457c8bcdf1eSAdam Denchfield 
458c8bcdf1eSAdam Denchfield 
459c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq)
460c8bcdf1eSAdam Denchfield {
461c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
462c8bcdf1eSAdam Denchfield    PetscErrorCode    ierr;
463c8bcdf1eSAdam Denchfield    PetscReal         scaling;
464c8bcdf1eSAdam Denchfield 
465c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
466c8bcdf1eSAdam Denchfield    ++cg->resets;
467c8bcdf1eSAdam Denchfield    scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23);
468484c7b14SAdam Denchfield    scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling));
469484c7b14SAdam Denchfield    if (cg->unscaled_restart) {
470484c7b14SAdam Denchfield      scaling = 1.0;
471484c7b14SAdam Denchfield      ++cg->pure_gd_steps;
472484c7b14SAdam Denchfield    }
473c8bcdf1eSAdam Denchfield    ierr = VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient);CHKERRQ(ierr);
474c8bcdf1eSAdam Denchfield    /* Also want to reset our diagonal scaling with each restart */
475c8bcdf1eSAdam Denchfield    if (cg->diag_scaling) {
47650b47da0SAdam Denchfield      ierr = MatLMVMReset(cg->B, PETSC_FALSE);CHKERRQ(ierr);
477c8bcdf1eSAdam Denchfield    }
478c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
479c8bcdf1eSAdam Denchfield  }
480c8bcdf1eSAdam Denchfield 
481c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold)
482c8bcdf1eSAdam Denchfield {
483c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
484c8bcdf1eSAdam Denchfield    PetscReal         quadinterp;
485c8bcdf1eSAdam Denchfield 
486c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
48750b47da0SAdam Denchfield    if (cg->f < cg->min_quad/10) {
48850b47da0SAdam Denchfield      *dynrestart = PETSC_FALSE;
48950b47da0SAdam Denchfield      PetscFunctionReturn(0);
49050b47da0SAdam Denchfield    } /* just skip this since this strategy doesn't work well for functions near zero */
491484c7b14SAdam Denchfield    quadinterp = 2.0*(cg->f - fold)/(stepsize*(gd + gd_old));
49250b47da0SAdam Denchfield    if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad;
493c8bcdf1eSAdam Denchfield    else {
494c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
495c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_FALSE;
496c8bcdf1eSAdam Denchfield    }
497c8bcdf1eSAdam Denchfield    if (cg->iter_quad >= cg->min_quad) {
498c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
499c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_TRUE;
500c8bcdf1eSAdam Denchfield    }
501c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
502c8bcdf1eSAdam Denchfield  }
503c8bcdf1eSAdam Denchfield 
5048ca2df50S PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback)
50550b47da0SAdam Denchfield {
506c8bcdf1eSAdam Denchfield   TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
507c8bcdf1eSAdam Denchfield   PetscErrorCode    ierr;
50850b47da0SAdam Denchfield   PetscReal         gamma = 1.0, tau_k, beta;
509484c7b14SAdam Denchfield   PetscReal         tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk=1.0, gd;
51050b47da0SAdam Denchfield   PetscReal         gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg;
511c8bcdf1eSAdam Denchfield   PetscInt          dim;
512484c7b14SAdam Denchfield   PetscBool         cg_restart = PETSC_FALSE;
513c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
514c8bcdf1eSAdam Denchfield 
51550b47da0SAdam Denchfield   /* Local curvature check to see if we need to restart */
516*414d97d3SAlp Dener   if (tao->niter >= 1 || tao->recycle){
517c8bcdf1eSAdam Denchfield     ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
518c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
519c8bcdf1eSAdam Denchfield     ynorm2 = ynorm*ynorm;
520c8bcdf1eSAdam Denchfield     ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
521484c7b14SAdam Denchfield     if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON){
522e2570530SAlp Dener       cg_restart = PETSC_TRUE;
523484c7b14SAdam Denchfield       ++cg->skipped_updates;
524484c7b14SAdam Denchfield     }
52550b47da0SAdam Denchfield     if (cg->spaced_restart) {
52650b47da0SAdam Denchfield       ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
527e2570530SAlp Dener       if (tao->niter % (dim*cg->min_restart_num)) cg_restart = PETSC_TRUE;
52850b47da0SAdam Denchfield     }
52950b47da0SAdam Denchfield   }
53050b47da0SAdam Denchfield   /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */
53150b47da0SAdam Denchfield   if (cg->spaced_restart){
53250b47da0SAdam Denchfield     ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
533e2570530SAlp Dener     if (0 == tao->niter % (6*dim)) cg_restart = PETSC_TRUE;
53450b47da0SAdam Denchfield   }
53550b47da0SAdam Denchfield   /* Compute the diagonal scaling vector if applicable */
53650b47da0SAdam Denchfield   if (cg->diag_scaling) {
53750b47da0SAdam Denchfield     ierr = MatLMVMUpdate(cg->B, tao->solution, tao->gradient);CHKERRQ(ierr);
53850b47da0SAdam Denchfield   }
53950b47da0SAdam Denchfield 
540484c7b14SAdam Denchfield   /* A note on diagonal scaling (to be added to paper):
541484c7b14SAdam Denchfield    For the FR, PR, PRP, and DY methods, the diagonally scaled versions
542484c7b14SAdam Denchfield    must be derived as a preconditioned CG method rather than as
543484c7b14SAdam Denchfield    a Hessian initialization like in the Broyden methods. */
54450b47da0SAdam Denchfield 
545484c7b14SAdam Denchfield   /* In that case, one writes the objective function as
546484c7b14SAdam Denchfield    f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k).
547484c7b14SAdam Denchfield    Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to
548484c7b14SAdam Denchfield    HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the
549484c7b14SAdam Denchfield    same under preconditioning. Note that A is diagonal, such that A^T = A. */
55050b47da0SAdam Denchfield 
551484c7b14SAdam Denchfield   /* This yields questions like what the dot product d_k^T y_k
552484c7b14SAdam Denchfield    should look like. HZ mistakenly treats that as the same under
553484c7b14SAdam Denchfield    preconditioning, but that is not necessarily true. */
55450b47da0SAdam Denchfield 
555484c7b14SAdam Denchfield   /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation,
556484c7b14SAdam Denchfield    we get d_k^T y_k = (d_k^T A_k^{-T} A_k g_k - d_k^T A_k^{-T} A_{k-1} g_{k-1}),
557484c7b14SAdam Denchfield    yielding d_k^T y_k = d_k^T g_k - d_k^T (A_k^{-T} A_{k-1} g_{k-1}), which is
558484c7b14SAdam Denchfield    NOT the same if our preconditioning matrix is updated between iterations.
559484c7b14SAdam Denchfield    This same issue is found when considering dot products of the form g_{k+1}^T y_k. */
56050b47da0SAdam Denchfield 
56150b47da0SAdam Denchfield   /* Compute CG step direction */
56250b47da0SAdam Denchfield   if (cg_restart) {
56350b47da0SAdam Denchfield     ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
564484c7b14SAdam Denchfield   } else if (pcgd_fallback) {
565484c7b14SAdam Denchfield     /* Just like preconditioned CG */
566484c7b14SAdam Denchfield     ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
567484c7b14SAdam Denchfield     ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work);CHKERRQ(ierr);
56850b47da0SAdam Denchfield   } else if (ynorm2 > PETSC_MACHINE_EPSILON) {
56950b47da0SAdam Denchfield     switch (cg->cg_type) {
570484c7b14SAdam Denchfield     case CG_PCGradientDescent:
57150b47da0SAdam Denchfield       if (!cg->diag_scaling){
572484c7b14SAdam Denchfield         if (!cg->no_scaling){
57350b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
57450b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
575484c7b14SAdam Denchfield         } else {
576484c7b14SAdam Denchfield           tau_k = 1.0;
577484c7b14SAdam Denchfield           ++cg->pure_gd_steps;
578484c7b14SAdam Denchfield         }
57950b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient);CHKERRQ(ierr);
58050b47da0SAdam Denchfield       } else {
58150b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
58250b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work);CHKERRQ(ierr);
58350b47da0SAdam Denchfield       }
58450b47da0SAdam Denchfield       break;
585484c7b14SAdam Denchfield 
58650b47da0SAdam Denchfield     case CG_HestenesStiefel:
58750b47da0SAdam Denchfield       /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */
58850b47da0SAdam Denchfield       if (!cg->diag_scaling){
58950b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
59050b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
59150b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
59250b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/dk_yk;
59350b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
59450b47da0SAdam Denchfield       } else {
59550b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
59650b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
59750b47da0SAdam Denchfield         beta = gkp1_yk/dk_yk;
59850b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
59950b47da0SAdam Denchfield       }
600c8bcdf1eSAdam Denchfield       break;
601484c7b14SAdam Denchfield 
602c8bcdf1eSAdam Denchfield     case CG_FletcherReeves:
60350b47da0SAdam Denchfield       ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
60450b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
60550b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
60650b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
60750b47da0SAdam Denchfield       ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
60850b47da0SAdam Denchfield       if (!cg->diag_scaling){
60950b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha);CHKERRQ(ierr);
61050b47da0SAdam Denchfield         beta = tau_k*gnorm2/gnorm2_old;
61150b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
61250b47da0SAdam Denchfield       } else {
61350b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Before it's updated */
61450b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
61550b47da0SAdam Denchfield         ierr = VecDot(tao->gradient, cg->g_work, &tmp);CHKERRQ(ierr);
61650b47da0SAdam Denchfield         beta = tmp/gnorm2_old;
61750b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
61850b47da0SAdam Denchfield       }
619c8bcdf1eSAdam Denchfield       break;
620484c7b14SAdam Denchfield 
62150b47da0SAdam Denchfield     case CG_PolakRibierePolyak:
62250b47da0SAdam Denchfield       snorm = step*dnorm;
62350b47da0SAdam Denchfield       if (!cg->diag_scaling){
62450b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
62550b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
62650b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
62750b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
62850b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
62950b47da0SAdam Denchfield       } else {
63050b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr);
63150b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
63250b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
63350b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
63450b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
63550b47da0SAdam Denchfield       }
636c8bcdf1eSAdam Denchfield       break;
637484c7b14SAdam Denchfield 
638c8bcdf1eSAdam Denchfield     case CG_PolakRibierePlus:
63950b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
64050b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
64150b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
64250b47da0SAdam Denchfield       if (!cg->diag_scaling){
64350b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
64450b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
64550b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
64650b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
64750b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
64850b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
64950b47da0SAdam Denchfield       } else {
65050b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Old gtDg */
65150b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
65250b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
65350b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
65450b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
65550b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
65650b47da0SAdam Denchfield       }
657c8bcdf1eSAdam Denchfield       break;
658484c7b14SAdam Denchfield 
659484c7b14SAdam Denchfield     case CG_DaiYuan:
660484c7b14SAdam Denchfield       /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property."
661484c7b14SAdam Denchfield          SIAM Journal on optimization 10, no. 1 (1999): 177-182. */
66250b47da0SAdam Denchfield       if (!cg->diag_scaling){
66350b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, tao->gradient, &gd);CHKERRQ(ierr);
664c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
66550b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha);CHKERRQ(ierr);
66650b47da0SAdam Denchfield         beta = tau_k*gnorm2/(gd - gd_old);
66750b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
66850b47da0SAdam Denchfield       } else {
669484c7b14SAdam Denchfield         ierr = MatMult(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
670484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
67150b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, tao->gradient, &gtDg);CHKERRQ(ierr);
67250b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->G_old, &gd_old);CHKERRQ(ierr);
67350b47da0SAdam Denchfield         ierr = VecDot(cg->d_work, cg->g_work, &dk_yk);CHKERRQ(ierr);
67450b47da0SAdam Denchfield         dk_yk = dk_yk - gd_old;
67550b47da0SAdam Denchfield         beta = gtDg/dk_yk;
676c624ebd3SAlp Dener         ierr = VecScale(cg->d_work, beta);CHKERRQ(ierr);
67750b47da0SAdam Denchfield         ierr = VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work);CHKERRQ(ierr);
67850b47da0SAdam Denchfield       }
679c8bcdf1eSAdam Denchfield       break;
680484c7b14SAdam Denchfield 
681c8bcdf1eSAdam Denchfield     case CG_HagerZhang:
682484c7b14SAdam Denchfield       /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent."
683484c7b14SAdam Denchfield          ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */
684c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
685c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
686c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
68750b47da0SAdam Denchfield       snorm = dnorm*step;
68850b47da0SAdam Denchfield       cg->yts = step*dk_yk;
689c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
690c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
691c8bcdf1eSAdam Denchfield       }
69250b47da0SAdam Denchfield       if (cg->dynamic_restart){
693c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
694c8bcdf1eSAdam Denchfield       } else {
695c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
696c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
697c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
698c8bcdf1eSAdam Denchfield           /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */
699c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
700c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk));
701c8bcdf1eSAdam Denchfield           /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */
70250b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
703c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d */
70450b47da0SAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
705c8bcdf1eSAdam Denchfield         } else {
706c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
707c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
708c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
70950b47da0SAdam Denchfield           /* Apply the diagonal scaling to all my vectors */
71050b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
71150b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
71250b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
713c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
714c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
715c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
716c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
71750b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
718c8bcdf1eSAdam Denchfield           tau_k = -tau_k*gd/(dk_yk*dk_yk);
719c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the dk contribution */
720484c7b14SAdam Denchfield           beta = gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */
721c8bcdf1eSAdam Denchfield           /* From HZ2013, modified to account for diagonal scaling*/
72250b47da0SAdam Denchfield           ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
72350b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
72450b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
725c8bcdf1eSAdam Denchfield           /* Do the update */
726484c7b14SAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
72750b47da0SAdam Denchfield         }
72850b47da0SAdam Denchfield       }
729c8bcdf1eSAdam Denchfield       break;
730484c7b14SAdam Denchfield 
731c8bcdf1eSAdam Denchfield     case CG_DaiKou:
732484c7b14SAdam Denchfield       /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search."
733484c7b14SAdam Denchfield          SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */
734c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
735c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
736c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
73750b47da0SAdam Denchfield       snorm = step*dnorm;
73850b47da0SAdam Denchfield       cg->yts = dk_yk*step;
739c8bcdf1eSAdam Denchfield       if (!cg->diag_scaling){
740c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
74150b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
742c8bcdf1eSAdam Denchfield         /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */
743c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
74450b47da0SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk;
74550b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
746c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*t*d */
747c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
748c8bcdf1eSAdam Denchfield       } else {
749c8bcdf1eSAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
750c8bcdf1eSAdam Denchfield         cg->yty = ynorm2;
751c8bcdf1eSAdam Denchfield         cg->sts = snorm*snorm;
75250b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
75350b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
75450b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
755c8bcdf1eSAdam Denchfield         /* Construct the constant ytDgkp1 */
756c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
75750b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
758c8bcdf1eSAdam Denchfield         tau_k = tau_k*gd/(dk_yk*dk_yk);
759c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
760c8bcdf1eSAdam Denchfield         /* beta is the constant which adds the dk contribution */
761484c7b14SAdam Denchfield         beta = gkp1_yk/dk_yk - step*tmp - tau_k;
762c8bcdf1eSAdam Denchfield         /* Update this for the last term in beta */
763c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->y_work, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
764c8bcdf1eSAdam Denchfield         beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */
76550b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
76650b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
76750b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
768c8bcdf1eSAdam Denchfield         /* Do the update */
769484c7b14SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
77050b47da0SAdam Denchfield       }
771c8bcdf1eSAdam Denchfield       break;
772484c7b14SAdam Denchfield 
773c8bcdf1eSAdam Denchfield     case CG_KouDai:
774110fc3b0SBarry Smith       /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization."
775484c7b14SAdam Denchfield          Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */
776c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
777c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
778c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
77950b47da0SAdam Denchfield       snorm = step*dnorm;
78050b47da0SAdam Denchfield       cg->yts = dk_yk*step;
781c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
782c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
783c8bcdf1eSAdam Denchfield       }
78450b47da0SAdam Denchfield       if (cg->dynamic_restart){
785c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
786c8bcdf1eSAdam Denchfield       } else {
787c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
788c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
789c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
790c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
791c8bcdf1eSAdam Denchfield           if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */
792c8bcdf1eSAdam Denchfield           {
793c8bcdf1eSAdam Denchfield             beta = cg->zeta*tau_k*gd/(dnorm*dnorm);
794c8bcdf1eSAdam Denchfield             gamma = 0.0;
795c8bcdf1eSAdam Denchfield           } else {
796c8bcdf1eSAdam Denchfield             if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk;
797484c7b14SAdam Denchfield             /* This seems to be very effective when there's no tau_k scaling.
798484c7b14SAdam Denchfield                This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */
79950b47da0SAdam Denchfield             else {
80050b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
80150b47da0SAdam Denchfield             }
802c8bcdf1eSAdam Denchfield           }
803c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d + t*tmp*yk */
804c8bcdf1eSAdam Denchfield           ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
805c8bcdf1eSAdam Denchfield         } else {
806c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
807c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
808c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
80950b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
81050b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
811c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
812c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1D_yk);CHKERRQ(ierr);
813c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
814c8bcdf1eSAdam Denchfield           gamma = gd/dk_yk;
815c8bcdf1eSAdam Denchfield           /* tau_k = -ytDy/(ytd)^2 * gd */
81650b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
817c8bcdf1eSAdam Denchfield           tau_k = tau_k*gd/(dk_yk*dk_yk);
818c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the d_k contribution */
819c8bcdf1eSAdam Denchfield           beta = gkp1D_yk/dk_yk - step*gamma - tau_k;
820c8bcdf1eSAdam Denchfield           /* Here is the requisite check */
82150b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &tmp);CHKERRQ(ierr);
822c8bcdf1eSAdam Denchfield           if (cg->neg_xi){
823c8bcdf1eSAdam Denchfield             /* modified KD implementation */
824c8bcdf1eSAdam Denchfield             if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk;
82550b47da0SAdam Denchfield             else {
82650b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
82750b47da0SAdam Denchfield             }
828c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)){
829c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
830c8bcdf1eSAdam Denchfield               gamma = 0.0;
831c8bcdf1eSAdam Denchfield             }
832c8bcdf1eSAdam Denchfield           } else { /* original KD 2015 implementation */
833c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)) {
834c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
835c8bcdf1eSAdam Denchfield               gamma = 0.0;
836c8bcdf1eSAdam Denchfield             } else {
837c8bcdf1eSAdam Denchfield               gamma = cg->xi*gd/dk_yk;
838c8bcdf1eSAdam Denchfield             }
839c8bcdf1eSAdam Denchfield           }
840c8bcdf1eSAdam Denchfield           /* Do the update in two steps */
841c8bcdf1eSAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
842c8bcdf1eSAdam Denchfield           ierr = VecAXPY(tao->stepdirection, gamma, cg->y_work);CHKERRQ(ierr);
84350b47da0SAdam Denchfield         }
84450b47da0SAdam Denchfield       }
845c8bcdf1eSAdam Denchfield       break;
846484c7b14SAdam Denchfield 
847484c7b14SAdam Denchfield     case CG_SSML_BFGS:
848484c7b14SAdam Denchfield       /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory."
849484c7b14SAdam Denchfield          Discussion Papers 269 (1977). */
850484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
851484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
852484c7b14SAdam Denchfield       snorm = step*dnorm;
853484c7b14SAdam Denchfield       cg->yts = dk_yk*step;
854484c7b14SAdam Denchfield       cg->yty = ynorm2;
855484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
856484c7b14SAdam Denchfield       if (!cg->diag_scaling){
857484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
858484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
859484c7b14SAdam Denchfield         tmp = gd/dk_yk;
860484c7b14SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp;
861484c7b14SAdam Denchfield         /* d <- -t*g + beta*t*d + t*tmp*yk */
862484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
863484c7b14SAdam Denchfield       } else {
864484c7b14SAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
865484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
866484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
867484c7b14SAdam Denchfield         /* compute scalar gamma */
868484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
869484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
870484c7b14SAdam Denchfield         gamma = gd/dk_yk;
871484c7b14SAdam Denchfield         /* Compute scalar beta */
872484c7b14SAdam Denchfield         beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
873484c7b14SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
874484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
875484c7b14SAdam Denchfield       }
876484c7b14SAdam Denchfield       break;
877484c7b14SAdam Denchfield 
878484c7b14SAdam Denchfield     case CG_SSML_DFP:
879484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
880484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
881484c7b14SAdam Denchfield       snorm = step*dnorm;
882484c7b14SAdam Denchfield       cg->yts = dk_yk*step;
883484c7b14SAdam Denchfield       cg->yty = ynorm2;
884484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
885484c7b14SAdam Denchfield       if (!cg->diag_scaling){
886484c7b14SAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
887484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
888484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
889484c7b14SAdam Denchfield         tau_k = cg->dfp_scale*tau_k;
890484c7b14SAdam Denchfield         tmp = tau_k*gkp1_yk/cg->yty;
891484c7b14SAdam Denchfield         beta = -step*gd/dk_yk;
892484c7b14SAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
893484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
894484c7b14SAdam Denchfield       } else {
895484c7b14SAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */
896484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
897484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
898484c7b14SAdam Denchfield         /* compute scalar gamma */
899484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
900484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
901484c7b14SAdam Denchfield         gamma = (gkp1_yk/tmp);
902484c7b14SAdam Denchfield         /* Compute scalar beta */
903484c7b14SAdam Denchfield         beta = -step*gd/dk_yk;
904484c7b14SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
905484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
906484c7b14SAdam Denchfield       }
907484c7b14SAdam Denchfield       break;
908484c7b14SAdam Denchfield 
909484c7b14SAdam Denchfield     case CG_SSML_BROYDEN:
910484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
911484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
912484c7b14SAdam Denchfield       snorm = step*dnorm;
913484c7b14SAdam Denchfield       cg->yts = step*dk_yk;
914484c7b14SAdam Denchfield       cg->yty = ynorm2;
915484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
916484c7b14SAdam Denchfield       if (!cg->diag_scaling){
917484c7b14SAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
918484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale);CHKERRQ(ierr);
919484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale);CHKERRQ(ierr);
920484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
921484c7b14SAdam Denchfield         tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp;
922484c7b14SAdam Denchfield         /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0,
923484c7b14SAdam Denchfield            it should reproduce the tau_dfp scaling. Same with dfp_scale.   */
924484c7b14SAdam Denchfield         tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/cg->yty;
925484c7b14SAdam Denchfield         beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
926484c7b14SAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
927484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
928484c7b14SAdam Denchfield       } else {
929484c7b14SAdam Denchfield         /* We have diagonal scaling enabled */
930484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
931484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
932484c7b14SAdam Denchfield         /* compute scalar gamma */
933484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
934484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
935484c7b14SAdam Denchfield         gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp);
936484c7b14SAdam Denchfield         /* Compute scalar beta */
937484c7b14SAdam Denchfield         beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
938484c7b14SAdam Denchfield         /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
939484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
940484c7b14SAdam Denchfield       }
941484c7b14SAdam Denchfield       break;
942484c7b14SAdam Denchfield 
943c8bcdf1eSAdam Denchfield     default:
944c8bcdf1eSAdam Denchfield       break;
945484c7b14SAdam Denchfield 
946c8bcdf1eSAdam Denchfield     }
947c8bcdf1eSAdam Denchfield   }
948c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
949c8bcdf1eSAdam Denchfield }
950c8bcdf1eSAdam Denchfield 
951c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm)
952c8bcdf1eSAdam Denchfield {
953c8bcdf1eSAdam Denchfield   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
954c8bcdf1eSAdam Denchfield   PetscErrorCode               ierr;
955c8bcdf1eSAdam Denchfield   TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING;
9568ca2df50S   PetscReal                    step=1.0,gnorm2,gd,dnorm=0.0;
957c8bcdf1eSAdam Denchfield   PetscReal                    gnorm2_old,f_old,resnorm, gnorm_old;
958c624ebd3SAlp Dener   PetscBool                    pcgd_fallback = PETSC_FALSE;
959c8bcdf1eSAdam Denchfield 
960c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
961c8bcdf1eSAdam Denchfield   /* We are now going to perform a line search along the direction. */
962c8bcdf1eSAdam Denchfield   /* Store solution and gradient info before it changes */
963c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr);
964c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr);
965c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr);
966c8bcdf1eSAdam Denchfield 
967c8bcdf1eSAdam Denchfield   gnorm_old = gnorm;
968c8bcdf1eSAdam Denchfield   gnorm2_old = gnorm_old*gnorm_old;
969c8bcdf1eSAdam Denchfield   f_old = cg->f;
970484c7b14SAdam Denchfield   /* Perform bounded line search. If we are recycling a solution from a previous */
971484c7b14SAdam Denchfield   /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */
972*414d97d3SAlp Dener   if (!(tao->recycle && 0 == tao->niter)){
973484c7b14SAdam Denchfield     /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */
974c8bcdf1eSAdam Denchfield     ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
975c8bcdf1eSAdam Denchfield     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
976c8bcdf1eSAdam Denchfield     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
977c8bcdf1eSAdam Denchfield 
978c8bcdf1eSAdam Denchfield     /*  Check linesearch failure */
979c8bcdf1eSAdam Denchfield     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
980c8bcdf1eSAdam Denchfield       ++cg->ls_fails;
981c624ebd3SAlp Dener       if (cg->cg_type == CG_GradientDescent){
982c8bcdf1eSAdam Denchfield         /* Nothing left to do but fail out of the optimization */
983c8bcdf1eSAdam Denchfield         step = 0.0;
984c8bcdf1eSAdam Denchfield         tao->reason = TAO_DIVERGED_LS_FAILURE;
985c8bcdf1eSAdam Denchfield       } else {
986484c7b14SAdam Denchfield         /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */
987c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr);
988c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr);
989c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr);
990c8bcdf1eSAdam Denchfield         gnorm = gnorm_old;
991c8bcdf1eSAdam Denchfield         gnorm2 = gnorm2_old;
992c8bcdf1eSAdam Denchfield         cg->f = f_old;
993c8bcdf1eSAdam Denchfield 
994484c7b14SAdam Denchfield         /* Fall back on preconditioned CG (so long as you're not already using it) */
995484c7b14SAdam Denchfield         if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling){
996e2570530SAlp Dener           pcgd_fallback = PETSC_TRUE;
9978ca2df50S           ierr = TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback);CHKERRQ(ierr);
998484c7b14SAdam Denchfield 
99950b47da0SAdam Denchfield           ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1000c8bcdf1eSAdam Denchfield           ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1001c8bcdf1eSAdam Denchfield 
1002c8bcdf1eSAdam Denchfield           ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
1003c8bcdf1eSAdam Denchfield           ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
1004c8bcdf1eSAdam Denchfield           ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
1005c8bcdf1eSAdam Denchfield 
1006484c7b14SAdam Denchfield           pcgd_fallback = PETSC_FALSE;
1007484c7b14SAdam Denchfield           if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1008484c7b14SAdam Denchfield             /* Going to perform a regular gradient descent step. */
1009484c7b14SAdam Denchfield             ++cg->ls_fails;
1010484c7b14SAdam Denchfield             step = 0.0;
1011484c7b14SAdam Denchfield           }
1012484c7b14SAdam Denchfield         }
1013484c7b14SAdam Denchfield         /* Fall back on the scaled gradient step */
1014484c7b14SAdam Denchfield         if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1015484c7b14SAdam Denchfield           ++cg->ls_fails;
1016484c7b14SAdam Denchfield           ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1017484c7b14SAdam Denchfield           ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1018484c7b14SAdam Denchfield           ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
1019484c7b14SAdam Denchfield           ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
1020484c7b14SAdam Denchfield           ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
1021484c7b14SAdam Denchfield         }
1022484c7b14SAdam Denchfield 
1023c8bcdf1eSAdam Denchfield         if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1024c8bcdf1eSAdam Denchfield           /* Nothing left to do but fail out of the optimization */
102550b47da0SAdam Denchfield           ++cg->ls_fails;
1026c8bcdf1eSAdam Denchfield           step = 0.0;
1027c8bcdf1eSAdam Denchfield           tao->reason = TAO_DIVERGED_LS_FAILURE;
1028484c7b14SAdam Denchfield         } else {
1029484c7b14SAdam Denchfield           /* One of the fallbacks worked. Set them both back equal to false. */
1030484c7b14SAdam Denchfield           pcgd_fallback = PETSC_FALSE;
1031c8bcdf1eSAdam Denchfield         }
1032c8bcdf1eSAdam Denchfield       }
1033c8bcdf1eSAdam Denchfield     }
1034c8bcdf1eSAdam Denchfield     /* Convergence test for line search failure */
1035c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1036c8bcdf1eSAdam Denchfield 
1037c8bcdf1eSAdam Denchfield     /* Standard convergence test */
1038c8bcdf1eSAdam Denchfield     ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
1039c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
1040691b26d3SBarry Smith     if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
1041c8bcdf1eSAdam Denchfield     ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
1042c8bcdf1eSAdam Denchfield     ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
1043c8bcdf1eSAdam Denchfield     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
1044c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1045484c7b14SAdam Denchfield   }
1046c8bcdf1eSAdam Denchfield   /* Assert we have an updated step and we need at least one more iteration. */
1047c8bcdf1eSAdam Denchfield   /* Calculate the next direction */
1048c8bcdf1eSAdam Denchfield   /* Estimate the active set at the new solution */
1049c8bcdf1eSAdam Denchfield   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
1050c8bcdf1eSAdam Denchfield   /* Compute the projected gradient and its norm */
1051c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
1052c8bcdf1eSAdam Denchfield   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
1053c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
1054c8bcdf1eSAdam Denchfield   gnorm2 = gnorm*gnorm;
1055c8bcdf1eSAdam Denchfield 
1056484c7b14SAdam Denchfield   /* Calculate some quantities used in the StepDirectionUpdate. */
1057c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
1058484c7b14SAdam Denchfield   /* Update the step direction. */
10598ca2df50S   ierr = TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback);CHKERRQ(ierr);
1060484c7b14SAdam Denchfield   ++tao->niter;
1061c8bcdf1eSAdam Denchfield   ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1062c8bcdf1eSAdam Denchfield 
1063c8bcdf1eSAdam Denchfield   if (cg->cg_type != CG_GradientDescent) {
1064c8bcdf1eSAdam Denchfield     /* Figure out which previously active variables became inactive this iteration */
1065c8bcdf1eSAdam Denchfield     ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
1066c8bcdf1eSAdam Denchfield     if (cg->inactive_idx && cg->inactive_old) {
1067c8bcdf1eSAdam Denchfield       ierr = ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives);CHKERRQ(ierr);
1068c8bcdf1eSAdam Denchfield     }
1069c8bcdf1eSAdam Denchfield     /* Selectively reset the CG step those freshly inactive variables */
1070c8bcdf1eSAdam Denchfield     if (cg->new_inactives) {
1071c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1072c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1073c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->inactive_grad, cg->inactive_step);CHKERRQ(ierr);
1074c8bcdf1eSAdam Denchfield       ierr = VecScale(cg->inactive_step, -1.0);CHKERRQ(ierr);
1075c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1076c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1077c8bcdf1eSAdam Denchfield     }
1078c8bcdf1eSAdam Denchfield     /* Verify that this is a descent direction */
1079c8bcdf1eSAdam Denchfield     ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
108050b47da0SAdam Denchfield     ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
108150b47da0SAdam Denchfield     if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) {
1082c8bcdf1eSAdam Denchfield       /* Not a descent direction, so we reset back to projected gradient descent */
108350b47da0SAdam Denchfield       ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1084c8bcdf1eSAdam Denchfield       ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1085c8bcdf1eSAdam Denchfield       ++cg->descent_error;
1086c8bcdf1eSAdam Denchfield     } else {
1087c8bcdf1eSAdam Denchfield     }
1088c8bcdf1eSAdam Denchfield   }
1089ac9112b8SAlp Dener   PetscFunctionReturn(0);
1090ac9112b8SAlp Dener }
1091484c7b14SAdam Denchfield 
1092484c7b14SAdam Denchfield PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0)
1093484c7b14SAdam Denchfield {
1094484c7b14SAdam Denchfield   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
1095484c7b14SAdam Denchfield   PetscErrorCode               ierr;
1096484c7b14SAdam Denchfield 
1097484c7b14SAdam Denchfield   PetscFunctionBegin;
1098484c7b14SAdam Denchfield   ierr = PetscObjectReference((PetscObject)H0);CHKERRQ(ierr);
1099484c7b14SAdam Denchfield   cg->pc = H0;
1100484c7b14SAdam Denchfield   PetscFunctionReturn(0);
1101484c7b14SAdam Denchfield }
1102