xref: /petsc/src/tao/bound/impls/bncg/bncg.c (revision 691b26d3a7ce3263bd9be9c446af0af2a46feecf)
1ac9112b8SAlp Dener #include <petsctaolinesearch.h>
2ac9112b8SAlp Dener #include <../src/tao/bound/impls/bncg/bncg.h>
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 
28c0f10754SAlp Dener PetscErrorCode TaoBNCGSetRecycleFlag(Tao tao, PetscBool recycle)
29c0f10754SAlp Dener {
30c0f10754SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
31c0f10754SAlp Dener 
32c0f10754SAlp Dener   PetscFunctionBegin;
33c0f10754SAlp Dener   cg->recycle = recycle;
34c0f10754SAlp Dener   PetscFunctionReturn(0);
35c0f10754SAlp Dener }
36c0f10754SAlp Dener 
3761be54a6SAlp Dener PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType)
3861be54a6SAlp Dener {
3961be54a6SAlp Dener   PetscErrorCode               ierr;
4061be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
4161be54a6SAlp Dener 
4261be54a6SAlp Dener   PetscFunctionBegin;
4361be54a6SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
4461be54a6SAlp Dener   if (cg->inactive_idx) {
4561be54a6SAlp Dener     ierr = ISDuplicate(cg->inactive_idx, &cg->inactive_old);CHKERRQ(ierr);
4661be54a6SAlp Dener     ierr = ISCopy(cg->inactive_idx, cg->inactive_old);CHKERRQ(ierr);
4761be54a6SAlp Dener   }
4861be54a6SAlp Dener   switch (asType) {
4961be54a6SAlp Dener   case CG_AS_NONE:
5061be54a6SAlp Dener     ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
5161be54a6SAlp Dener     ierr = VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx);CHKERRQ(ierr);
5261be54a6SAlp Dener     ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
5361be54a6SAlp Dener     ierr = ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx);CHKERRQ(ierr);
5461be54a6SAlp Dener     break;
5561be54a6SAlp Dener 
5661be54a6SAlp Dener   case CG_AS_BERTSEKAS:
5761be54a6SAlp Dener     /* Use gradient descent to estimate the active set */
5861be54a6SAlp Dener     ierr = VecCopy(cg->unprojected_gradient, cg->W);CHKERRQ(ierr);
5961be54a6SAlp Dener     ierr = VecScale(cg->W, -1.0);CHKERRQ(ierr);
6089da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol,
6189da521bSAlp Dener                                    &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx);CHKERRQ(ierr);
62c4b75bccSAlp Dener     break;
6361be54a6SAlp Dener 
6461be54a6SAlp Dener   default:
6561be54a6SAlp Dener     break;
6661be54a6SAlp Dener   }
6761be54a6SAlp Dener   PetscFunctionReturn(0);
6861be54a6SAlp Dener }
6961be54a6SAlp Dener 
70a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step)
7161be54a6SAlp Dener {
7261be54a6SAlp Dener   PetscErrorCode               ierr;
7361be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
7461be54a6SAlp Dener 
7561be54a6SAlp Dener   PetscFunctionBegin;
76a1318120SAlp Dener   switch (asType) {
7761be54a6SAlp Dener   case CG_AS_NONE:
78c4b75bccSAlp Dener     ierr = VecISSet(step, cg->active_idx, 0.0);CHKERRQ(ierr);
7961be54a6SAlp Dener     break;
8061be54a6SAlp Dener 
8161be54a6SAlp Dener   case CG_AS_BERTSEKAS:
82c4b75bccSAlp Dener     ierr = TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step);CHKERRQ(ierr);
8361be54a6SAlp Dener     break;
8461be54a6SAlp Dener 
8561be54a6SAlp Dener   default:
8661be54a6SAlp Dener     break;
8761be54a6SAlp Dener   }
8861be54a6SAlp Dener   PetscFunctionReturn(0);
8961be54a6SAlp Dener }
9061be54a6SAlp Dener 
91ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao)
92ac9112b8SAlp Dener {
93ac9112b8SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
94ac9112b8SAlp Dener   PetscErrorCode               ierr;
95484c7b14SAdam Denchfield   PetscReal                    step=1.0,gnorm,gnorm2, resnorm;
96c4b75bccSAlp Dener   PetscInt                     nDiff;
97ac9112b8SAlp Dener 
98ac9112b8SAlp Dener   PetscFunctionBegin;
99ac9112b8SAlp Dener   /*   Project the current point onto the feasible set */
100ac9112b8SAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
101cd929ea3SAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
102ac9112b8SAlp Dener 
103c8bcdf1eSAdam Denchfield   /* Project the initial point onto the feasible region */
104c8bcdf1eSAdam Denchfield   ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
105484c7b14SAdam Denchfield 
106484c7b14SAdam Denchfield   if (nDiff > 0 || !cg->recycle){
107c0f10754SAlp Dener     ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient);CHKERRQ(ierr);
108484c7b14SAdam Denchfield   }
109ac9112b8SAlp Dener   ierr = VecNorm(cg->unprojected_gradient,NORM_2,&gnorm);CHKERRQ(ierr);
110*691b26d3SBarry Smith   if (PetscIsInfOrNanReal(cg->f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
111ac9112b8SAlp Dener 
11261be54a6SAlp Dener   /* Estimate the active set and compute the projected gradient */
11361be54a6SAlp Dener   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
11461be54a6SAlp Dener 
115ac9112b8SAlp Dener   /* Project the gradient and calculate the norm */
11661be54a6SAlp Dener   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
11761be54a6SAlp Dener   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
118ac9112b8SAlp Dener   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
119ac9112b8SAlp Dener   gnorm2 = gnorm*gnorm;
120ac9112b8SAlp Dener 
121c8bcdf1eSAdam Denchfield   /* Initialize counters */
122e031d6f5SAlp Dener   tao->niter = 0;
12350b47da0SAdam Denchfield   cg->ls_fails = cg->descent_error = 0;
124c8bcdf1eSAdam Denchfield   cg->resets = -1;
125484c7b14SAdam Denchfield   cg->skipped_updates = cg->pure_gd_steps = 0;
126c8bcdf1eSAdam Denchfield   cg->iter_quad = 0;
127c8bcdf1eSAdam Denchfield 
128c8bcdf1eSAdam Denchfield   /* Convergence test at the starting point. */
129ac9112b8SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
130484c7b14SAdam Denchfield 
131484c7b14SAdam Denchfield   ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
132484c7b14SAdam Denchfield   ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
133*691b26d3SBarry Smith   if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
134484c7b14SAdam Denchfield   ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
135484c7b14SAdam Denchfield   ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
136ac9112b8SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
137ac9112b8SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
138484c7b14SAdam Denchfield   /* Calculate initial direction. */
139484c7b14SAdam Denchfield   if (!cg->recycle) {
140484c7b14SAdam Denchfield     /* We are not recycling a solution/history from a past TaoSolve */
141484c7b14SAdam Denchfield     ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
142ac9112b8SAlp Dener   }
143c8bcdf1eSAdam Denchfield   /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */
144c8bcdf1eSAdam Denchfield   while(1) {
145e1e80dc8SAlp Dener     /* Call general purpose update function */
146e1e80dc8SAlp Dener     if (tao->ops->update) {
1478fcddce6SStefano Zampini       ierr = (*tao->ops->update)(tao, tao->niter, tao->user_update);CHKERRQ(ierr);
148e1e80dc8SAlp Dener     }
149c8bcdf1eSAdam Denchfield     ierr = TaoBNCGConductIteration(tao, gnorm);CHKERRQ(ierr);
150c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
151ac9112b8SAlp Dener   }
152ac9112b8SAlp Dener   PetscFunctionReturn(0);
153ac9112b8SAlp Dener }
154ac9112b8SAlp Dener 
155ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao)
156ac9112b8SAlp Dener {
157ac9112b8SAlp Dener   TAO_BNCG         *cg = (TAO_BNCG*)tao->data;
158ac9112b8SAlp Dener   PetscErrorCode ierr;
159ac9112b8SAlp Dener 
160ac9112b8SAlp Dener   PetscFunctionBegin;
161c4b75bccSAlp Dener   if (!tao->gradient) {
162c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
163c4b75bccSAlp Dener   }
164c4b75bccSAlp Dener   if (!tao->stepdirection) {
165c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);
166c4b75bccSAlp Dener   }
167c4b75bccSAlp Dener   if (!cg->W) {
168c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->W);CHKERRQ(ierr);
169c4b75bccSAlp Dener   }
170c4b75bccSAlp Dener   if (!cg->work) {
171c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->work);CHKERRQ(ierr);
172c4b75bccSAlp Dener   }
173c8bcdf1eSAdam Denchfield   if (!cg->sk) {
174c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->sk);CHKERRQ(ierr);
175c8bcdf1eSAdam Denchfield   }
176c8bcdf1eSAdam Denchfield   if (!cg->yk) {
177c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->gradient,&cg->yk);CHKERRQ(ierr);
178c8bcdf1eSAdam Denchfield   }
179c4b75bccSAlp Dener   if (!cg->X_old) {
180c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->X_old);CHKERRQ(ierr);
181c4b75bccSAlp Dener   }
182c4b75bccSAlp Dener   if (!cg->G_old) {
183c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->G_old);CHKERRQ(ierr);
184c8bcdf1eSAdam Denchfield   }
185c8bcdf1eSAdam Denchfield   if (cg->diag_scaling){
186c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->d_work);CHKERRQ(ierr);
187c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->y_work);CHKERRQ(ierr);
18850b47da0SAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->g_work);CHKERRQ(ierr);
189c4b75bccSAlp Dener   }
190c4b75bccSAlp Dener   if (!cg->unprojected_gradient) {
191c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient);CHKERRQ(ierr);
192c4b75bccSAlp Dener   }
193c4b75bccSAlp Dener   if (!cg->unprojected_gradient_old) {
194c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient_old);CHKERRQ(ierr);
195c4b75bccSAlp Dener   }
19650b47da0SAdam Denchfield   ierr = MatLMVMAllocate(cg->B, cg->sk, cg->yk);CHKERRQ(ierr);
197484c7b14SAdam Denchfield   if (cg->pc){
198484c7b14SAdam Denchfield     ierr = MatLMVMSetJ0(cg->B, cg->pc);CHKERRQ(ierr);
199484c7b14SAdam Denchfield   }
200ac9112b8SAlp Dener   PetscFunctionReturn(0);
201ac9112b8SAlp Dener }
202ac9112b8SAlp Dener 
203ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao)
204ac9112b8SAlp Dener {
205ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*) tao->data;
206ac9112b8SAlp Dener   PetscErrorCode ierr;
207ac9112b8SAlp Dener 
208ac9112b8SAlp Dener   PetscFunctionBegin;
209ac9112b8SAlp Dener   if (tao->setupcalled) {
21061be54a6SAlp Dener     ierr = VecDestroy(&cg->W);CHKERRQ(ierr);
211c4b75bccSAlp Dener     ierr = VecDestroy(&cg->work);CHKERRQ(ierr);
212ac9112b8SAlp Dener     ierr = VecDestroy(&cg->X_old);CHKERRQ(ierr);
213ac9112b8SAlp Dener     ierr = VecDestroy(&cg->G_old);CHKERRQ(ierr);
214ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient);CHKERRQ(ierr);
215ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient_old);CHKERRQ(ierr);
21650b47da0SAdam Denchfield     ierr = VecDestroy(&cg->g_work);CHKERRQ(ierr);
21750b47da0SAdam Denchfield     ierr = VecDestroy(&cg->d_work);CHKERRQ(ierr);
21850b47da0SAdam Denchfield     ierr = VecDestroy(&cg->y_work);CHKERRQ(ierr);
21950b47da0SAdam Denchfield     ierr = VecDestroy(&cg->sk);CHKERRQ(ierr);
22050b47da0SAdam Denchfield     ierr = VecDestroy(&cg->yk);CHKERRQ(ierr);
221ac9112b8SAlp Dener   }
222ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_lower);CHKERRQ(ierr);
223ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_upper);CHKERRQ(ierr);
224ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_fixed);CHKERRQ(ierr);
225ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
226ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
227ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
228ca964c49SAlp Dener   ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
22901e1e359SAlp Dener   ierr = MatDestroy(&cg->B);CHKERRQ(ierr);
230484c7b14SAdam Denchfield   if (cg->pc) {
23101e1e359SAlp Dener     ierr = MatDestroy(&cg->pc);CHKERRQ(ierr);
232484c7b14SAdam Denchfield   }
233ac9112b8SAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
234ac9112b8SAlp Dener   PetscFunctionReturn(0);
235ac9112b8SAlp Dener }
236ac9112b8SAlp Dener 
237ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao)
238ac9112b8SAlp Dener {
239ac9112b8SAlp Dener     TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
240ac9112b8SAlp Dener     PetscErrorCode ierr;
241ac9112b8SAlp Dener 
242ac9112b8SAlp Dener     PetscFunctionBegin;
243ac9112b8SAlp Dener     ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
244ac9112b8SAlp Dener     ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr);
245484c7b14SAdam Denchfield     ierr = PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr);
246484c7b14SAdam Denchfield     if (cg->cg_type != CG_SSML_BFGS){
247484c7b14SAdam Denchfield       cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */
248484c7b14SAdam Denchfield     }
249484c7b14SAdam Denchfield     if (CG_GradientDescent == cg->cg_type){
250484c7b14SAdam Denchfield       cg->cg_type = CG_PCGradientDescent;
251484c7b14SAdam Denchfield       /* Set scaling equal to none or, at best, scalar scaling. */
252484c7b14SAdam Denchfield       cg->unscaled_restart = PETSC_TRUE;
253484c7b14SAdam Denchfield       cg->diag_scaling = PETSC_FALSE;
254484c7b14SAdam Denchfield     }
25550b47da0SAdam 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);
25650b47da0SAdam Denchfield 
25750b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL);CHKERRQ(ierr);
25850b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL);CHKERRQ(ierr);
25950b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL);CHKERRQ(ierr);
26050b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL);CHKERRQ(ierr);
26150b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL);CHKERRQ(ierr);
26250b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL);CHKERRQ(ierr);
26350b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL);CHKERRQ(ierr);
264c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL);CHKERRQ(ierr);
265c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL);CHKERRQ(ierr);
266c8bcdf1eSAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL);CHKERRQ(ierr);
26750b47da0SAdam 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);
26850b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL);CHKERRQ(ierr);
26950b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL);CHKERRQ(ierr);
270c8bcdf1eSAdam 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);
27150b47da0SAdam 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);
272484c7b14SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_recycle","enable recycling the existing solution, gradient, and diagonal scaling vector at the start of a new TaoSolve() call","",cg->recycle,&cg->recycle,NULL);CHKERRQ(ierr);
27350b47da0SAdam 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);
274484c7b14SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_no_scaling","Disable all scaling except in restarts","",cg->no_scaling,&cg->no_scaling,NULL);CHKERRQ(ierr);
275484c7b14SAdam Denchfield     if (cg->no_scaling){
276484c7b14SAdam Denchfield       cg->diag_scaling = PETSC_FALSE;
277484c7b14SAdam Denchfield       cg->alpha = -1.0;
278484c7b14SAdam Denchfield     }
279b474139fSKarl Rupp     if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling){ /* Some more default options that appear to be good. */
280484c7b14SAdam Denchfield       cg->neg_xi = PETSC_TRUE;
281484c7b14SAdam Denchfield     }
28250b47da0SAdam 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);
28350b47da0SAdam 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);
28450b47da0SAdam 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);
285484c7b14SAdam 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);
286484c7b14SAdam 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);
28750b47da0SAdam Denchfield 
288ac9112b8SAlp Dener    ierr = PetscOptionsTail();CHKERRQ(ierr);
28950b47da0SAdam Denchfield    ierr = MatSetFromOptions(cg->B);CHKERRQ(ierr);
290ac9112b8SAlp Dener    PetscFunctionReturn(0);
291ac9112b8SAlp Dener }
292ac9112b8SAlp Dener 
293ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer)
294ac9112b8SAlp Dener {
295ac9112b8SAlp Dener   PetscBool      isascii;
296ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
297ac9112b8SAlp Dener   PetscErrorCode ierr;
298ac9112b8SAlp Dener 
299ac9112b8SAlp Dener   PetscFunctionBegin;
300ac9112b8SAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
301ac9112b8SAlp Dener   if (isascii) {
302ac9112b8SAlp Dener     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
303ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type]);CHKERRQ(ierr);
304484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %i\n", cg->skipped_updates);CHKERRQ(ierr);
305484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %i\n", cg->resets);CHKERRQ(ierr);
306484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %i\n", cg->pure_gd_steps);CHKERRQ(ierr);
307484c7b14SAdam Denchfield     ierr = PetscViewerASCIIPrintf(viewer, "Not a descent direction: %i\n", cg->descent_error);CHKERRQ(ierr);
308ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails);CHKERRQ(ierr);
309484c7b14SAdam Denchfield     if (cg->diag_scaling){
310484c7b14SAdam Denchfield       ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
311484c7b14SAdam Denchfield       if (isascii) {
312484c7b14SAdam Denchfield         ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO);CHKERRQ(ierr);
313484c7b14SAdam Denchfield         ierr = MatView(cg->B, viewer);CHKERRQ(ierr);
314484c7b14SAdam Denchfield         ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
315484c7b14SAdam Denchfield       }
316484c7b14SAdam Denchfield     }
317ac9112b8SAlp Dener     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
318ac9112b8SAlp Dener   }
319ac9112b8SAlp Dener   PetscFunctionReturn(0);
320ac9112b8SAlp Dener }
321ac9112b8SAlp Dener 
322c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha)
323c8bcdf1eSAdam Denchfield {
324c8bcdf1eSAdam Denchfield   PetscReal            a, b, c, sig1, sig2;
325c8bcdf1eSAdam Denchfield 
326c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
327c8bcdf1eSAdam Denchfield   *scale = 0.0;
328c8bcdf1eSAdam Denchfield 
32950b47da0SAdam Denchfield   if (1.0 == alpha){
330c8bcdf1eSAdam Denchfield     *scale = yts/yty;
33150b47da0SAdam Denchfield   } else if (0.0 == alpha){
332c8bcdf1eSAdam Denchfield     *scale = sts/yts;
333c8bcdf1eSAdam Denchfield   }
33450b47da0SAdam Denchfield   else if (-1.0 == alpha) *scale = 1.0;
335c8bcdf1eSAdam Denchfield   else {
336c8bcdf1eSAdam Denchfield     a = yty;
337c8bcdf1eSAdam Denchfield     b = yts;
338c8bcdf1eSAdam Denchfield     c = sts;
339c8bcdf1eSAdam Denchfield     a *= alpha;
340c8bcdf1eSAdam Denchfield     b *= -(2.0*alpha - 1.0);
341c8bcdf1eSAdam Denchfield     c *= alpha - 1.0;
342c8bcdf1eSAdam Denchfield     sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
343c8bcdf1eSAdam Denchfield     sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
344c8bcdf1eSAdam Denchfield     /* accept the positive root as the scalar */
345c8bcdf1eSAdam Denchfield     if (sig1 > 0.0) {
346c8bcdf1eSAdam Denchfield       *scale = sig1;
347c8bcdf1eSAdam Denchfield     } else if (sig2 > 0.0) {
348c8bcdf1eSAdam Denchfield       *scale = sig2;
349c8bcdf1eSAdam Denchfield     } else {
350c8bcdf1eSAdam Denchfield       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar");
351c8bcdf1eSAdam Denchfield     }
352c8bcdf1eSAdam Denchfield   }
353c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
354c8bcdf1eSAdam Denchfield }
355c8bcdf1eSAdam Denchfield 
356ac9112b8SAlp Dener /*MC
357ac9112b8SAlp Dener   TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method.
358ac9112b8SAlp Dener 
359ac9112b8SAlp Dener   Options Database Keys:
36050b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled)
361c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance
36261be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula
363c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method
364c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation
365c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation
36650b47da0SAdam 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.
36750b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method
36850b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
36950b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
37050b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method
37150b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method
37250b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method
37350b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method
37450b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True.
37550b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods
37650b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts
37750b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method
378484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps
379484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps
38050b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart
38150b47da0SAdam 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
38250b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations
383484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults.
3843850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions
385ac9112b8SAlp Dener 
386ac9112b8SAlp Dener   Notes:
387ac9112b8SAlp Dener     CG formulas are:
3883850be85SAlp Dener + "gd" - Gradient Descent
3893850be85SAlp Dener . "fr" - Fletcher-Reeves
3903850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak
3913850be85SAlp Dener . "prp" - Polak-Ribiere-Plus
3923850be85SAlp Dener . "hs" - Hestenes-Steifel
3933850be85SAlp Dener . "dy" - Dai-Yuan
3943850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS
3953850be85SAlp Dener . "ssml_dfp"  - Self-Scaling Memoryless DFP
3963850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden
3973850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3)
3983850be85SAlp Dener . "dk" - Dai-Kou (2013)
3993850be85SAlp Dener - "kd" - Kou-Dai (2015)
4009abc5736SPatrick Sanan 
401ac9112b8SAlp Dener   Level: beginner
402ac9112b8SAlp Dener M*/
403ac9112b8SAlp Dener 
404ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao)
405ac9112b8SAlp Dener {
406ac9112b8SAlp Dener   TAO_BNCG       *cg;
407ac9112b8SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
408ac9112b8SAlp Dener   PetscErrorCode ierr;
409ac9112b8SAlp Dener 
410ac9112b8SAlp Dener   PetscFunctionBegin;
411ac9112b8SAlp Dener   tao->ops->setup = TaoSetUp_BNCG;
412ac9112b8SAlp Dener   tao->ops->solve = TaoSolve_BNCG;
413ac9112b8SAlp Dener   tao->ops->view = TaoView_BNCG;
414ac9112b8SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNCG;
415ac9112b8SAlp Dener   tao->ops->destroy = TaoDestroy_BNCG;
416ac9112b8SAlp Dener 
417ac9112b8SAlp Dener   /* Override default settings (unless already changed) */
418ac9112b8SAlp Dener   if (!tao->max_it_changed) tao->max_it = 2000;
419ac9112b8SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
420ac9112b8SAlp Dener 
421ac9112b8SAlp Dener   /*  Note: nondefault values should be used for nonlinear conjugate gradient  */
422ac9112b8SAlp Dener   /*  method.  In particular, gtol should be less that 0.5; the value used in  */
423ac9112b8SAlp Dener   /*  Nocedal and Wright is 0.10.  We use the default values for the  */
424ac9112b8SAlp Dener   /*  linesearch because it seems to work better. */
425ac9112b8SAlp Dener   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr);
426ac9112b8SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr);
427ac9112b8SAlp Dener   ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr);
428ac9112b8SAlp Dener   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr);
429ac9112b8SAlp Dener   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
430ac9112b8SAlp Dener 
431ac9112b8SAlp Dener   ierr = PetscNewLog(tao,&cg);CHKERRQ(ierr);
432ac9112b8SAlp Dener   tao->data = (void*)cg;
433484c7b14SAdam Denchfield   ierr = KSPInitializePackage();CHKERRQ(ierr);
43450b47da0SAdam Denchfield   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &cg->B);CHKERRQ(ierr);
43550b47da0SAdam Denchfield   ierr = PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1);CHKERRQ(ierr);
43650b47da0SAdam Denchfield   ierr = MatSetOptionsPrefix(cg->B, "tao_bncg_");CHKERRQ(ierr);
43750b47da0SAdam Denchfield   ierr = MatSetType(cg->B, MATLMVMDIAGBRDN);CHKERRQ(ierr);
43850b47da0SAdam Denchfield 
439484c7b14SAdam Denchfield   cg->pc = NULL;
440484c7b14SAdam Denchfield 
44150b47da0SAdam Denchfield   cg->dk_eta = 0.5;
44250b47da0SAdam Denchfield   cg->hz_eta = 0.4;
443c8bcdf1eSAdam Denchfield   cg->dynamic_restart = PETSC_FALSE;
444c8bcdf1eSAdam Denchfield   cg->unscaled_restart = PETSC_FALSE;
445484c7b14SAdam Denchfield   cg->no_scaling = PETSC_FALSE;
446484c7b14SAdam Denchfield   cg->delta_min = 1e-7;
447484c7b14SAdam Denchfield   cg->delta_max = 100;
448c8bcdf1eSAdam Denchfield   cg->theta = 1.0;
449c8bcdf1eSAdam Denchfield   cg->hz_theta = 1.0;
450c8bcdf1eSAdam Denchfield   cg->dfp_scale = 1.0;
451c8bcdf1eSAdam Denchfield   cg->bfgs_scale = 1.0;
45250b47da0SAdam Denchfield   cg->zeta = 0.1;
45350b47da0SAdam Denchfield   cg->min_quad = 6;
454c8bcdf1eSAdam Denchfield   cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/
455c8bcdf1eSAdam Denchfield   cg->xi = 1.0;
45650b47da0SAdam Denchfield   cg->neg_xi = PETSC_TRUE;
457c8bcdf1eSAdam Denchfield   cg->spaced_restart = PETSC_FALSE;
458c8bcdf1eSAdam Denchfield   cg->tol_quad = 1e-8;
45961be54a6SAlp Dener   cg->as_step = 0.001;
46061be54a6SAlp Dener   cg->as_tol = 0.001;
46150b47da0SAdam Denchfield   cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/
46261be54a6SAlp Dener   cg->as_type = CG_AS_BERTSEKAS;
463c8bcdf1eSAdam Denchfield   cg->cg_type = CG_SSML_BFGS;
464c0f10754SAlp Dener   cg->recycle = PETSC_FALSE;
465c8bcdf1eSAdam Denchfield   cg->alpha = 1.0;
466c8bcdf1eSAdam Denchfield   cg->diag_scaling = PETSC_TRUE;
467c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
468c8bcdf1eSAdam Denchfield }
469c8bcdf1eSAdam Denchfield 
470c8bcdf1eSAdam Denchfield 
471c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq)
472c8bcdf1eSAdam Denchfield {
473c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
474c8bcdf1eSAdam Denchfield    PetscErrorCode    ierr;
475c8bcdf1eSAdam Denchfield    PetscReal         scaling;
476c8bcdf1eSAdam Denchfield 
477c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
478c8bcdf1eSAdam Denchfield    ++cg->resets;
479c8bcdf1eSAdam Denchfield    scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23);
480484c7b14SAdam Denchfield    scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling));
481484c7b14SAdam Denchfield    if (cg->unscaled_restart) {
482484c7b14SAdam Denchfield      scaling = 1.0;
483484c7b14SAdam Denchfield      ++cg->pure_gd_steps;
484484c7b14SAdam Denchfield    }
485c8bcdf1eSAdam Denchfield    ierr = VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient);CHKERRQ(ierr);
486c8bcdf1eSAdam Denchfield    /* Also want to reset our diagonal scaling with each restart */
487c8bcdf1eSAdam Denchfield    if (cg->diag_scaling) {
48850b47da0SAdam Denchfield      ierr = MatLMVMReset(cg->B, PETSC_FALSE);CHKERRQ(ierr);
489c8bcdf1eSAdam Denchfield    }
490c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
491c8bcdf1eSAdam Denchfield  }
492c8bcdf1eSAdam Denchfield 
493c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold)
494c8bcdf1eSAdam Denchfield {
495c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
496c8bcdf1eSAdam Denchfield    PetscReal         quadinterp;
497c8bcdf1eSAdam Denchfield 
498c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
49950b47da0SAdam Denchfield    if (cg->f < cg->min_quad/10) {
50050b47da0SAdam Denchfield      *dynrestart = PETSC_FALSE;
50150b47da0SAdam Denchfield      PetscFunctionReturn(0);
50250b47da0SAdam Denchfield    } /* just skip this since this strategy doesn't work well for functions near zero */
503484c7b14SAdam Denchfield    quadinterp = 2.0*(cg->f - fold)/(stepsize*(gd + gd_old));
50450b47da0SAdam Denchfield    if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad;
505c8bcdf1eSAdam Denchfield    else {
506c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
507c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_FALSE;
508c8bcdf1eSAdam Denchfield    }
509c8bcdf1eSAdam Denchfield    if (cg->iter_quad >= cg->min_quad) {
510c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
511c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_TRUE;
512c8bcdf1eSAdam Denchfield    }
513c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
514c8bcdf1eSAdam Denchfield  }
515c8bcdf1eSAdam Denchfield 
5168ca2df50S PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback)
51750b47da0SAdam Denchfield {
518c8bcdf1eSAdam Denchfield   TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
519c8bcdf1eSAdam Denchfield   PetscErrorCode    ierr;
52050b47da0SAdam Denchfield   PetscReal         gamma = 1.0, tau_k, beta;
521484c7b14SAdam Denchfield   PetscReal         tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk=1.0, gd;
52250b47da0SAdam Denchfield   PetscReal         gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg;
523c8bcdf1eSAdam Denchfield   PetscInt          dim;
524484c7b14SAdam Denchfield   PetscBool         cg_restart = PETSC_FALSE;
525c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
526c8bcdf1eSAdam Denchfield 
52750b47da0SAdam Denchfield   /* Local curvature check to see if we need to restart */
528484c7b14SAdam Denchfield   if (tao->niter >= 1 || cg->recycle){
529c8bcdf1eSAdam Denchfield     ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
530c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
531c8bcdf1eSAdam Denchfield     ynorm2 = ynorm*ynorm;
532c8bcdf1eSAdam Denchfield     ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
533484c7b14SAdam Denchfield     if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON){
534e2570530SAlp Dener       cg_restart = PETSC_TRUE;
535484c7b14SAdam Denchfield       ++cg->skipped_updates;
536484c7b14SAdam Denchfield     }
53750b47da0SAdam Denchfield     if (cg->spaced_restart) {
53850b47da0SAdam Denchfield       ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
539e2570530SAlp Dener       if (tao->niter % (dim*cg->min_restart_num)) cg_restart = PETSC_TRUE;
54050b47da0SAdam Denchfield     }
54150b47da0SAdam Denchfield   }
54250b47da0SAdam Denchfield   /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */
54350b47da0SAdam Denchfield   if (cg->spaced_restart){
54450b47da0SAdam Denchfield     ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
545e2570530SAlp Dener     if (0 == tao->niter % (6*dim)) cg_restart = PETSC_TRUE;
54650b47da0SAdam Denchfield   }
54750b47da0SAdam Denchfield   /* Compute the diagonal scaling vector if applicable */
54850b47da0SAdam Denchfield   if (cg->diag_scaling) {
54950b47da0SAdam Denchfield     ierr = MatLMVMUpdate(cg->B, tao->solution, tao->gradient);CHKERRQ(ierr);
55050b47da0SAdam Denchfield   }
55150b47da0SAdam Denchfield 
552484c7b14SAdam Denchfield   /* A note on diagonal scaling (to be added to paper):
553484c7b14SAdam Denchfield    For the FR, PR, PRP, and DY methods, the diagonally scaled versions
554484c7b14SAdam Denchfield    must be derived as a preconditioned CG method rather than as
555484c7b14SAdam Denchfield    a Hessian initialization like in the Broyden methods. */
55650b47da0SAdam Denchfield 
557484c7b14SAdam Denchfield   /* In that case, one writes the objective function as
558484c7b14SAdam Denchfield    f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k).
559484c7b14SAdam Denchfield    Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to
560484c7b14SAdam Denchfield    HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the
561484c7b14SAdam Denchfield    same under preconditioning. Note that A is diagonal, such that A^T = A. */
56250b47da0SAdam Denchfield 
563484c7b14SAdam Denchfield   /* This yields questions like what the dot product d_k^T y_k
564484c7b14SAdam Denchfield    should look like. HZ mistakenly treats that as the same under
565484c7b14SAdam Denchfield    preconditioning, but that is not necessarily true. */
56650b47da0SAdam Denchfield 
567484c7b14SAdam Denchfield   /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation,
568484c7b14SAdam 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}),
569484c7b14SAdam 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
570484c7b14SAdam Denchfield    NOT the same if our preconditioning matrix is updated between iterations.
571484c7b14SAdam Denchfield    This same issue is found when considering dot products of the form g_{k+1}^T y_k. */
57250b47da0SAdam Denchfield 
57350b47da0SAdam Denchfield   /* Compute CG step direction */
57450b47da0SAdam Denchfield   if (cg_restart) {
57550b47da0SAdam Denchfield     ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
576484c7b14SAdam Denchfield   } else if (pcgd_fallback) {
577484c7b14SAdam Denchfield     /* Just like preconditioned CG */
578484c7b14SAdam Denchfield     ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
579484c7b14SAdam Denchfield     ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work);CHKERRQ(ierr);
58050b47da0SAdam Denchfield   } else if (ynorm2 > PETSC_MACHINE_EPSILON) {
58150b47da0SAdam Denchfield     switch (cg->cg_type) {
582484c7b14SAdam Denchfield     case CG_PCGradientDescent:
58350b47da0SAdam Denchfield       if (!cg->diag_scaling){
584484c7b14SAdam Denchfield         if (!cg->no_scaling){
58550b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
58650b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
587484c7b14SAdam Denchfield         } else {
588484c7b14SAdam Denchfield           tau_k = 1.0;
589484c7b14SAdam Denchfield           ++cg->pure_gd_steps;
590484c7b14SAdam Denchfield         }
59150b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient);CHKERRQ(ierr);
59250b47da0SAdam Denchfield       } else {
59350b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
59450b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work);CHKERRQ(ierr);
59550b47da0SAdam Denchfield       }
59650b47da0SAdam Denchfield       break;
597484c7b14SAdam Denchfield 
59850b47da0SAdam Denchfield     case CG_HestenesStiefel:
59950b47da0SAdam Denchfield       /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */
60050b47da0SAdam Denchfield       if (!cg->diag_scaling){
60150b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
60250b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
60350b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
60450b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/dk_yk;
60550b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
60650b47da0SAdam Denchfield       } else {
60750b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
60850b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
60950b47da0SAdam Denchfield         beta = gkp1_yk/dk_yk;
61050b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
61150b47da0SAdam Denchfield       }
612c8bcdf1eSAdam Denchfield       break;
613484c7b14SAdam Denchfield 
614c8bcdf1eSAdam Denchfield     case CG_FletcherReeves:
61550b47da0SAdam Denchfield       ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
61650b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
61750b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
61850b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
61950b47da0SAdam Denchfield       ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
62050b47da0SAdam Denchfield       if (!cg->diag_scaling){
62150b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha);CHKERRQ(ierr);
62250b47da0SAdam Denchfield         beta = tau_k*gnorm2/gnorm2_old;
62350b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
62450b47da0SAdam Denchfield       } else {
62550b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Before it's updated */
62650b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
62750b47da0SAdam Denchfield         ierr = VecDot(tao->gradient, cg->g_work, &tmp);CHKERRQ(ierr);
62850b47da0SAdam Denchfield         beta = tmp/gnorm2_old;
62950b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
63050b47da0SAdam Denchfield       }
631c8bcdf1eSAdam Denchfield       break;
632484c7b14SAdam Denchfield 
63350b47da0SAdam Denchfield     case CG_PolakRibierePolyak:
63450b47da0SAdam Denchfield       snorm = step*dnorm;
63550b47da0SAdam Denchfield       if (!cg->diag_scaling){
63650b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
63750b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
63850b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
63950b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
64050b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
64150b47da0SAdam Denchfield       } else {
64250b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr);
64350b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
64450b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
64550b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
64650b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
64750b47da0SAdam Denchfield       }
648c8bcdf1eSAdam Denchfield       break;
649484c7b14SAdam Denchfield 
650c8bcdf1eSAdam Denchfield     case CG_PolakRibierePlus:
65150b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
65250b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
65350b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
65450b47da0SAdam Denchfield       if (!cg->diag_scaling){
65550b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
65650b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
65750b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
65850b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
65950b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
66050b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
66150b47da0SAdam Denchfield       } else {
66250b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Old gtDg */
66350b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
66450b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
66550b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
66650b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
66750b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
66850b47da0SAdam Denchfield       }
669c8bcdf1eSAdam Denchfield       break;
670484c7b14SAdam Denchfield 
671484c7b14SAdam Denchfield     case CG_DaiYuan:
672484c7b14SAdam Denchfield       /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property."
673484c7b14SAdam Denchfield          SIAM Journal on optimization 10, no. 1 (1999): 177-182. */
67450b47da0SAdam Denchfield       if (!cg->diag_scaling){
67550b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, tao->gradient, &gd);CHKERRQ(ierr);
676c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
67750b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha);CHKERRQ(ierr);
67850b47da0SAdam Denchfield         beta = tau_k*gnorm2/(gd - gd_old);
67950b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
68050b47da0SAdam Denchfield       } else {
681484c7b14SAdam Denchfield         ierr = MatMult(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
682484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
68350b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, tao->gradient, &gtDg);CHKERRQ(ierr);
68450b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->G_old, &gd_old);CHKERRQ(ierr);
68550b47da0SAdam Denchfield         ierr = VecDot(cg->d_work, cg->g_work, &dk_yk);CHKERRQ(ierr);
68650b47da0SAdam Denchfield         dk_yk = dk_yk - gd_old;
68750b47da0SAdam Denchfield         beta = gtDg/dk_yk;
688c624ebd3SAlp Dener         ierr = VecScale(cg->d_work, beta);CHKERRQ(ierr);
68950b47da0SAdam Denchfield         ierr = VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work);CHKERRQ(ierr);
69050b47da0SAdam Denchfield       }
691c8bcdf1eSAdam Denchfield       break;
692484c7b14SAdam Denchfield 
693c8bcdf1eSAdam Denchfield     case CG_HagerZhang:
694484c7b14SAdam Denchfield       /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent."
695484c7b14SAdam Denchfield          ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */
696c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
697c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
698c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
69950b47da0SAdam Denchfield       snorm = dnorm*step;
70050b47da0SAdam Denchfield       cg->yts = step*dk_yk;
701c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
702c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
703c8bcdf1eSAdam Denchfield       }
70450b47da0SAdam Denchfield       if (cg->dynamic_restart){
705c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
706c8bcdf1eSAdam Denchfield       } else {
707c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
708c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
709c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
710c8bcdf1eSAdam Denchfield           /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */
711c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
712c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk));
713c8bcdf1eSAdam Denchfield           /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */
71450b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
715c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d */
71650b47da0SAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
717c8bcdf1eSAdam Denchfield         } else {
718c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
719c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
720c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
72150b47da0SAdam Denchfield           /* Apply the diagonal scaling to all my vectors */
72250b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
72350b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
72450b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
725c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
726c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
727c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
728c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
72950b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
730c8bcdf1eSAdam Denchfield           tau_k = -tau_k*gd/(dk_yk*dk_yk);
731c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the dk contribution */
732484c7b14SAdam Denchfield           beta = gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */
733c8bcdf1eSAdam Denchfield           /* From HZ2013, modified to account for diagonal scaling*/
73450b47da0SAdam Denchfield           ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
73550b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
73650b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
737c8bcdf1eSAdam Denchfield           /* Do the update */
738484c7b14SAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
73950b47da0SAdam Denchfield         }
74050b47da0SAdam Denchfield       }
741c8bcdf1eSAdam Denchfield       break;
742484c7b14SAdam Denchfield 
743c8bcdf1eSAdam Denchfield     case CG_DaiKou:
744484c7b14SAdam Denchfield       /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search."
745484c7b14SAdam Denchfield          SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */
746c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
747c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
748c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
74950b47da0SAdam Denchfield       snorm = step*dnorm;
75050b47da0SAdam Denchfield       cg->yts = dk_yk*step;
751c8bcdf1eSAdam Denchfield       if (!cg->diag_scaling){
752c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
75350b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
754c8bcdf1eSAdam Denchfield         /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */
755c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
75650b47da0SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk;
75750b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
758c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*t*d */
759c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
760c8bcdf1eSAdam Denchfield       } else {
761c8bcdf1eSAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
762c8bcdf1eSAdam Denchfield         cg->yty = ynorm2;
763c8bcdf1eSAdam Denchfield         cg->sts = snorm*snorm;
76450b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
76550b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
76650b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
767c8bcdf1eSAdam Denchfield         /* Construct the constant ytDgkp1 */
768c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
76950b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
770c8bcdf1eSAdam Denchfield         tau_k = tau_k*gd/(dk_yk*dk_yk);
771c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
772c8bcdf1eSAdam Denchfield         /* beta is the constant which adds the dk contribution */
773484c7b14SAdam Denchfield         beta = gkp1_yk/dk_yk - step*tmp - tau_k;
774c8bcdf1eSAdam Denchfield         /* Update this for the last term in beta */
775c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->y_work, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
776c8bcdf1eSAdam Denchfield         beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */
77750b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
77850b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
77950b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
780c8bcdf1eSAdam Denchfield         /* Do the update */
781484c7b14SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
78250b47da0SAdam Denchfield       }
783c8bcdf1eSAdam Denchfield       break;
784484c7b14SAdam Denchfield 
785c8bcdf1eSAdam Denchfield     case CG_KouDai:
786484c7b14SAdam Denchfield       /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden–Fletcher–Goldfarb–Shanno method for unconstrained optimization."
787484c7b14SAdam Denchfield          Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */
788c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
789c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
790c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
79150b47da0SAdam Denchfield       snorm = step*dnorm;
79250b47da0SAdam Denchfield       cg->yts = dk_yk*step;
793c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
794c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
795c8bcdf1eSAdam Denchfield       }
79650b47da0SAdam Denchfield       if (cg->dynamic_restart){
797c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
798c8bcdf1eSAdam Denchfield       } else {
799c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
800c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
801c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
802c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
803c8bcdf1eSAdam Denchfield           if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */
804c8bcdf1eSAdam Denchfield           {
805c8bcdf1eSAdam Denchfield             beta = cg->zeta*tau_k*gd/(dnorm*dnorm);
806c8bcdf1eSAdam Denchfield             gamma = 0.0;
807c8bcdf1eSAdam Denchfield           } else {
808c8bcdf1eSAdam Denchfield             if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk;
809484c7b14SAdam Denchfield             /* This seems to be very effective when there's no tau_k scaling.
810484c7b14SAdam Denchfield                This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */
81150b47da0SAdam Denchfield             else {
81250b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
81350b47da0SAdam Denchfield             }
814c8bcdf1eSAdam Denchfield           }
815c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d + t*tmp*yk */
816c8bcdf1eSAdam Denchfield           ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
817c8bcdf1eSAdam Denchfield         } else {
818c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
819c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
820c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
82150b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
82250b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
823c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
824c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1D_yk);CHKERRQ(ierr);
825c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
826c8bcdf1eSAdam Denchfield           gamma = gd/dk_yk;
827c8bcdf1eSAdam Denchfield           /* tau_k = -ytDy/(ytd)^2 * gd */
82850b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
829c8bcdf1eSAdam Denchfield           tau_k = tau_k*gd/(dk_yk*dk_yk);
830c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the d_k contribution */
831c8bcdf1eSAdam Denchfield           beta = gkp1D_yk/dk_yk - step*gamma - tau_k;
832c8bcdf1eSAdam Denchfield           /* Here is the requisite check */
83350b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &tmp);CHKERRQ(ierr);
834c8bcdf1eSAdam Denchfield           if (cg->neg_xi){
835c8bcdf1eSAdam Denchfield             /* modified KD implementation */
836c8bcdf1eSAdam Denchfield             if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk;
83750b47da0SAdam Denchfield             else {
83850b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
83950b47da0SAdam Denchfield             }
840c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)){
841c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
842c8bcdf1eSAdam Denchfield               gamma = 0.0;
843c8bcdf1eSAdam Denchfield             }
844c8bcdf1eSAdam Denchfield           } else { /* original KD 2015 implementation */
845c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)) {
846c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
847c8bcdf1eSAdam Denchfield               gamma = 0.0;
848c8bcdf1eSAdam Denchfield             } else {
849c8bcdf1eSAdam Denchfield               gamma = cg->xi*gd/dk_yk;
850c8bcdf1eSAdam Denchfield             }
851c8bcdf1eSAdam Denchfield           }
852c8bcdf1eSAdam Denchfield           /* Do the update in two steps */
853c8bcdf1eSAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
854c8bcdf1eSAdam Denchfield           ierr = VecAXPY(tao->stepdirection, gamma, cg->y_work);CHKERRQ(ierr);
85550b47da0SAdam Denchfield         }
85650b47da0SAdam Denchfield       }
857c8bcdf1eSAdam Denchfield       break;
858484c7b14SAdam Denchfield 
859484c7b14SAdam Denchfield     case CG_SSML_BFGS:
860484c7b14SAdam Denchfield       /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory."
861484c7b14SAdam Denchfield          Discussion Papers 269 (1977). */
862484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
863484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
864484c7b14SAdam Denchfield       snorm = step*dnorm;
865484c7b14SAdam Denchfield       cg->yts = dk_yk*step;
866484c7b14SAdam Denchfield       cg->yty = ynorm2;
867484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
868484c7b14SAdam Denchfield       if (!cg->diag_scaling){
869484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
870484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
871484c7b14SAdam Denchfield         tmp = gd/dk_yk;
872484c7b14SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp;
873484c7b14SAdam Denchfield         /* d <- -t*g + beta*t*d + t*tmp*yk */
874484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
875484c7b14SAdam Denchfield       } else {
876484c7b14SAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
877484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
878484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
879484c7b14SAdam Denchfield         /* compute scalar gamma */
880484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
881484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
882484c7b14SAdam Denchfield         gamma = gd/dk_yk;
883484c7b14SAdam Denchfield         /* Compute scalar beta */
884484c7b14SAdam Denchfield         beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
885484c7b14SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
886484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
887484c7b14SAdam Denchfield       }
888484c7b14SAdam Denchfield       break;
889484c7b14SAdam Denchfield 
890484c7b14SAdam Denchfield     case CG_SSML_DFP:
891484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
892484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
893484c7b14SAdam Denchfield       snorm = step*dnorm;
894484c7b14SAdam Denchfield       cg->yts = dk_yk*step;
895484c7b14SAdam Denchfield       cg->yty = ynorm2;
896484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
897484c7b14SAdam Denchfield       if (!cg->diag_scaling){
898484c7b14SAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
899484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
900484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
901484c7b14SAdam Denchfield         tau_k = cg->dfp_scale*tau_k;
902484c7b14SAdam Denchfield         tmp = tau_k*gkp1_yk/cg->yty;
903484c7b14SAdam Denchfield         beta = -step*gd/dk_yk;
904484c7b14SAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
905484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
906484c7b14SAdam Denchfield       } else {
907484c7b14SAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */
908484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
909484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
910484c7b14SAdam Denchfield         /* compute scalar gamma */
911484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
912484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
913484c7b14SAdam Denchfield         gamma = (gkp1_yk/tmp);
914484c7b14SAdam Denchfield         /* Compute scalar beta */
915484c7b14SAdam Denchfield         beta = -step*gd/dk_yk;
916484c7b14SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
917484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
918484c7b14SAdam Denchfield       }
919484c7b14SAdam Denchfield       break;
920484c7b14SAdam Denchfield 
921484c7b14SAdam Denchfield     case CG_SSML_BROYDEN:
922484c7b14SAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
923484c7b14SAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
924484c7b14SAdam Denchfield       snorm = step*dnorm;
925484c7b14SAdam Denchfield       cg->yts = step*dk_yk;
926484c7b14SAdam Denchfield       cg->yty = ynorm2;
927484c7b14SAdam Denchfield       cg->sts = snorm*snorm;
928484c7b14SAdam Denchfield       if (!cg->diag_scaling){
929484c7b14SAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
930484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale);CHKERRQ(ierr);
931484c7b14SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale);CHKERRQ(ierr);
932484c7b14SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
933484c7b14SAdam Denchfield         tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp;
934484c7b14SAdam Denchfield         /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0,
935484c7b14SAdam Denchfield            it should reproduce the tau_dfp scaling. Same with dfp_scale.   */
936484c7b14SAdam Denchfield         tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/cg->yty;
937484c7b14SAdam Denchfield         beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
938484c7b14SAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
939484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
940484c7b14SAdam Denchfield       } else {
941484c7b14SAdam Denchfield         /* We have diagonal scaling enabled */
942484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
943484c7b14SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
944484c7b14SAdam Denchfield         /* compute scalar gamma */
945484c7b14SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
946484c7b14SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
947484c7b14SAdam Denchfield         gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp);
948484c7b14SAdam Denchfield         /* Compute scalar beta */
949484c7b14SAdam Denchfield         beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
950484c7b14SAdam Denchfield         /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
951484c7b14SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
952484c7b14SAdam Denchfield       }
953484c7b14SAdam Denchfield       break;
954484c7b14SAdam Denchfield 
955c8bcdf1eSAdam Denchfield     default:
956c8bcdf1eSAdam Denchfield       break;
957484c7b14SAdam Denchfield 
958c8bcdf1eSAdam Denchfield     }
959c8bcdf1eSAdam Denchfield   }
960c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
961c8bcdf1eSAdam Denchfield }
962c8bcdf1eSAdam Denchfield 
963c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm)
964c8bcdf1eSAdam Denchfield {
965c8bcdf1eSAdam Denchfield   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
966c8bcdf1eSAdam Denchfield   PetscErrorCode               ierr;
967c8bcdf1eSAdam Denchfield   TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING;
9688ca2df50S   PetscReal                    step=1.0,gnorm2,gd,dnorm=0.0;
969c8bcdf1eSAdam Denchfield   PetscReal                    gnorm2_old,f_old,resnorm, gnorm_old;
970c624ebd3SAlp Dener   PetscBool                    pcgd_fallback = PETSC_FALSE;
971c8bcdf1eSAdam Denchfield 
972c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
973c8bcdf1eSAdam Denchfield   /* We are now going to perform a line search along the direction. */
974c8bcdf1eSAdam Denchfield   /* Store solution and gradient info before it changes */
975c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr);
976c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr);
977c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr);
978c8bcdf1eSAdam Denchfield 
979c8bcdf1eSAdam Denchfield   gnorm_old = gnorm;
980c8bcdf1eSAdam Denchfield   gnorm2_old = gnorm_old*gnorm_old;
981c8bcdf1eSAdam Denchfield   f_old = cg->f;
982484c7b14SAdam Denchfield   /* Perform bounded line search. If we are recycling a solution from a previous */
983484c7b14SAdam Denchfield   /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */
984484c7b14SAdam Denchfield   if (!(cg->recycle && 0 == tao->niter)){
985484c7b14SAdam Denchfield     /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */
986c8bcdf1eSAdam Denchfield     ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
987c8bcdf1eSAdam Denchfield     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
988c8bcdf1eSAdam Denchfield     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
989c8bcdf1eSAdam Denchfield 
990c8bcdf1eSAdam Denchfield     /*  Check linesearch failure */
991c8bcdf1eSAdam Denchfield     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
992c8bcdf1eSAdam Denchfield       ++cg->ls_fails;
993c624ebd3SAlp Dener       if (cg->cg_type == CG_GradientDescent){
994c8bcdf1eSAdam Denchfield         /* Nothing left to do but fail out of the optimization */
995c8bcdf1eSAdam Denchfield         step = 0.0;
996c8bcdf1eSAdam Denchfield         tao->reason = TAO_DIVERGED_LS_FAILURE;
997c8bcdf1eSAdam Denchfield       } else {
998484c7b14SAdam Denchfield         /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */
999c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr);
1000c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr);
1001c8bcdf1eSAdam Denchfield         ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr);
1002c8bcdf1eSAdam Denchfield         gnorm = gnorm_old;
1003c8bcdf1eSAdam Denchfield         gnorm2 = gnorm2_old;
1004c8bcdf1eSAdam Denchfield         cg->f = f_old;
1005c8bcdf1eSAdam Denchfield 
1006484c7b14SAdam Denchfield         /* Fall back on preconditioned CG (so long as you're not already using it) */
1007484c7b14SAdam Denchfield         if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling){
1008e2570530SAlp Dener           pcgd_fallback = PETSC_TRUE;
10098ca2df50S           ierr = TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback);CHKERRQ(ierr);
1010484c7b14SAdam Denchfield 
101150b47da0SAdam Denchfield           ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1012c8bcdf1eSAdam Denchfield           ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1013c8bcdf1eSAdam Denchfield 
1014c8bcdf1eSAdam Denchfield           ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
1015c8bcdf1eSAdam Denchfield           ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
1016c8bcdf1eSAdam Denchfield           ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
1017c8bcdf1eSAdam Denchfield 
1018484c7b14SAdam Denchfield           pcgd_fallback = PETSC_FALSE;
1019484c7b14SAdam Denchfield           if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1020484c7b14SAdam Denchfield             /* Going to perform a regular gradient descent step. */
1021484c7b14SAdam Denchfield             ++cg->ls_fails;
1022484c7b14SAdam Denchfield             step = 0.0;
1023484c7b14SAdam Denchfield           }
1024484c7b14SAdam Denchfield         }
1025484c7b14SAdam Denchfield         /* Fall back on the scaled gradient step */
1026484c7b14SAdam Denchfield         if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1027484c7b14SAdam Denchfield           ++cg->ls_fails;
1028484c7b14SAdam Denchfield           ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1029484c7b14SAdam Denchfield           ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1030484c7b14SAdam Denchfield           ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
1031484c7b14SAdam Denchfield           ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
1032484c7b14SAdam Denchfield           ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
1033484c7b14SAdam Denchfield         }
1034484c7b14SAdam Denchfield 
1035c8bcdf1eSAdam Denchfield         if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
1036c8bcdf1eSAdam Denchfield           /* Nothing left to do but fail out of the optimization */
103750b47da0SAdam Denchfield           ++cg->ls_fails;
1038c8bcdf1eSAdam Denchfield           step = 0.0;
1039c8bcdf1eSAdam Denchfield           tao->reason = TAO_DIVERGED_LS_FAILURE;
1040484c7b14SAdam Denchfield         } else {
1041484c7b14SAdam Denchfield           /* One of the fallbacks worked. Set them both back equal to false. */
1042484c7b14SAdam Denchfield           pcgd_fallback = PETSC_FALSE;
1043c8bcdf1eSAdam Denchfield         }
1044c8bcdf1eSAdam Denchfield       }
1045c8bcdf1eSAdam Denchfield     }
1046c8bcdf1eSAdam Denchfield     /* Convergence test for line search failure */
1047c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1048c8bcdf1eSAdam Denchfield 
1049c8bcdf1eSAdam Denchfield     /* Standard convergence test */
1050c8bcdf1eSAdam Denchfield     ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
1051c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
1052*691b26d3SBarry Smith     if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
1053c8bcdf1eSAdam Denchfield     ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
1054c8bcdf1eSAdam Denchfield     ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
1055c8bcdf1eSAdam Denchfield     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
1056c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1057484c7b14SAdam Denchfield   }
1058c8bcdf1eSAdam Denchfield   /* Assert we have an updated step and we need at least one more iteration. */
1059c8bcdf1eSAdam Denchfield   /* Calculate the next direction */
1060c8bcdf1eSAdam Denchfield   /* Estimate the active set at the new solution */
1061c8bcdf1eSAdam Denchfield   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
1062c8bcdf1eSAdam Denchfield   /* Compute the projected gradient and its norm */
1063c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
1064c8bcdf1eSAdam Denchfield   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
1065c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
1066c8bcdf1eSAdam Denchfield   gnorm2 = gnorm*gnorm;
1067c8bcdf1eSAdam Denchfield 
1068484c7b14SAdam Denchfield   /* Calculate some quantities used in the StepDirectionUpdate. */
1069c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
1070484c7b14SAdam Denchfield   /* Update the step direction. */
10718ca2df50S   ierr = TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback);CHKERRQ(ierr);
1072484c7b14SAdam Denchfield   ++tao->niter;
1073c8bcdf1eSAdam Denchfield   ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1074c8bcdf1eSAdam Denchfield 
1075c8bcdf1eSAdam Denchfield   if (cg->cg_type != CG_GradientDescent) {
1076c8bcdf1eSAdam Denchfield     /* Figure out which previously active variables became inactive this iteration */
1077c8bcdf1eSAdam Denchfield     ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
1078c8bcdf1eSAdam Denchfield     if (cg->inactive_idx && cg->inactive_old) {
1079c8bcdf1eSAdam Denchfield       ierr = ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives);CHKERRQ(ierr);
1080c8bcdf1eSAdam Denchfield     }
1081c8bcdf1eSAdam Denchfield     /* Selectively reset the CG step those freshly inactive variables */
1082c8bcdf1eSAdam Denchfield     if (cg->new_inactives) {
1083c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1084c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1085c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->inactive_grad, cg->inactive_step);CHKERRQ(ierr);
1086c8bcdf1eSAdam Denchfield       ierr = VecScale(cg->inactive_step, -1.0);CHKERRQ(ierr);
1087c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1088c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1089c8bcdf1eSAdam Denchfield     }
1090c8bcdf1eSAdam Denchfield     /* Verify that this is a descent direction */
1091c8bcdf1eSAdam Denchfield     ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
109250b47da0SAdam Denchfield     ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
109350b47da0SAdam Denchfield     if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) {
1094c8bcdf1eSAdam Denchfield       /* Not a descent direction, so we reset back to projected gradient descent */
109550b47da0SAdam Denchfield       ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1096c8bcdf1eSAdam Denchfield       ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1097c8bcdf1eSAdam Denchfield       ++cg->descent_error;
1098c8bcdf1eSAdam Denchfield     } else {
1099c8bcdf1eSAdam Denchfield     }
1100c8bcdf1eSAdam Denchfield   }
1101ac9112b8SAlp Dener   PetscFunctionReturn(0);
1102ac9112b8SAlp Dener }
1103484c7b14SAdam Denchfield 
1104484c7b14SAdam Denchfield PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0)
1105484c7b14SAdam Denchfield {
1106484c7b14SAdam Denchfield   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
1107484c7b14SAdam Denchfield   PetscErrorCode               ierr;
1108484c7b14SAdam Denchfield 
1109484c7b14SAdam Denchfield   PetscFunctionBegin;
1110484c7b14SAdam Denchfield   ierr = PetscObjectReference((PetscObject)H0);CHKERRQ(ierr);
1111484c7b14SAdam Denchfield   cg->pc = H0;
1112484c7b14SAdam Denchfield   PetscFunctionReturn(0);
1113484c7b14SAdam Denchfield }
1114