xref: /petsc/src/tao/bound/impls/bncg/bncg.c (revision 50b47da0f1ee44d44f7d7183a5d0083a5c160eaf)
1ac9112b8SAlp Dener #include <petsctaolinesearch.h>
2ac9112b8SAlp Dener #include <../src/tao/bound/impls/bncg/bncg.h>
3*50b47da0SAdam Denchfield #include <petscksp.h>
4ac9112b8SAlp Dener 
5c8bcdf1eSAdam Denchfield #define CG_GradientDescent      0
6c8bcdf1eSAdam Denchfield #define CG_HestenesStiefel      1
7c8bcdf1eSAdam Denchfield #define CG_FletcherReeves       2
8*50b47da0SAdam 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
17*50b47da0SAdam Denchfield #define CG_Types                12
18ac9112b8SAlp Dener 
19*50b47da0SAdam Denchfield static const char *CG_Table[64] = {"gd", "hs", "fr", "pr", "prp", "dy", "hz", "dk", "kd", "ssml_bfgs", "ssml_dfp", "ssml_brdn"};
20ac9112b8SAlp Dener 
2161be54a6SAlp Dener #define CG_AS_NONE       0
2261be54a6SAlp Dener #define CG_AS_BERTSEKAS  1
2361be54a6SAlp Dener #define CG_AS_SIZE       2
24ac9112b8SAlp Dener 
2561be54a6SAlp Dener static const char *CG_AS_TYPE[64] = {"none", "bertsekas"};
26ac9112b8SAlp Dener 
27c0f10754SAlp Dener PetscErrorCode TaoBNCGSetRecycleFlag(Tao tao, PetscBool recycle)
28c0f10754SAlp Dener {
29c0f10754SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
30c0f10754SAlp Dener 
31c0f10754SAlp Dener   PetscFunctionBegin;
32c0f10754SAlp Dener   cg->recycle = recycle;
33c0f10754SAlp Dener   PetscFunctionReturn(0);
34c0f10754SAlp Dener }
35c0f10754SAlp Dener 
3661be54a6SAlp Dener PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType)
3761be54a6SAlp Dener {
3861be54a6SAlp Dener   PetscErrorCode               ierr;
3961be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
4061be54a6SAlp Dener 
4161be54a6SAlp Dener   PetscFunctionBegin;
4261be54a6SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
4361be54a6SAlp Dener   if (cg->inactive_idx) {
4461be54a6SAlp Dener     ierr = ISDuplicate(cg->inactive_idx, &cg->inactive_old);CHKERRQ(ierr);
4561be54a6SAlp Dener     ierr = ISCopy(cg->inactive_idx, cg->inactive_old);CHKERRQ(ierr);
4661be54a6SAlp Dener   }
4761be54a6SAlp Dener   switch (asType) {
4861be54a6SAlp Dener   case CG_AS_NONE:
4961be54a6SAlp Dener     ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
5061be54a6SAlp Dener     ierr = VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx);CHKERRQ(ierr);
5161be54a6SAlp Dener     ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
5261be54a6SAlp Dener     ierr = ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx);CHKERRQ(ierr);
5361be54a6SAlp Dener     break;
5461be54a6SAlp Dener 
5561be54a6SAlp Dener   case CG_AS_BERTSEKAS:
5661be54a6SAlp Dener     /* Use gradient descent to estimate the active set */
5761be54a6SAlp Dener     ierr = VecCopy(cg->unprojected_gradient, cg->W);CHKERRQ(ierr);
5861be54a6SAlp Dener     ierr = VecScale(cg->W, -1.0);CHKERRQ(ierr);
5989da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol,
6089da521bSAlp Dener                                    &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx);CHKERRQ(ierr);
61c4b75bccSAlp Dener     break;
6261be54a6SAlp Dener 
6361be54a6SAlp Dener   default:
6461be54a6SAlp Dener     break;
6561be54a6SAlp Dener   }
6661be54a6SAlp Dener   PetscFunctionReturn(0);
6761be54a6SAlp Dener }
6861be54a6SAlp Dener 
69a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step)
7061be54a6SAlp Dener {
7161be54a6SAlp Dener   PetscErrorCode               ierr;
7261be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
7361be54a6SAlp Dener 
7461be54a6SAlp Dener   PetscFunctionBegin;
75a1318120SAlp Dener   switch (asType) {
7661be54a6SAlp Dener   case CG_AS_NONE:
77c4b75bccSAlp Dener     ierr = VecISSet(step, cg->active_idx, 0.0);CHKERRQ(ierr);
7861be54a6SAlp Dener     break;
7961be54a6SAlp Dener 
8061be54a6SAlp Dener   case CG_AS_BERTSEKAS:
81c4b75bccSAlp Dener     ierr = TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step);CHKERRQ(ierr);
8261be54a6SAlp Dener     break;
8361be54a6SAlp Dener 
8461be54a6SAlp Dener   default:
8561be54a6SAlp Dener     break;
8661be54a6SAlp Dener   }
8761be54a6SAlp Dener   PetscFunctionReturn(0);
8861be54a6SAlp Dener }
8961be54a6SAlp Dener 
90ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao)
91ac9112b8SAlp Dener {
92ac9112b8SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
93ac9112b8SAlp Dener   PetscErrorCode               ierr;
94c8bcdf1eSAdam Denchfield   PetscReal                    step=1.0,gnorm,gnorm2;
95c4b75bccSAlp Dener   PetscInt                     nDiff;
96ac9112b8SAlp Dener 
97ac9112b8SAlp Dener   PetscFunctionBegin;
98ac9112b8SAlp Dener   /*   Project the current point onto the feasible set */
99ac9112b8SAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
100cd929ea3SAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
101ac9112b8SAlp Dener 
102c8bcdf1eSAdam Denchfield   /* Project the initial point onto the feasible region */
103c8bcdf1eSAdam Denchfield   ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
104c0f10754SAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient);CHKERRQ(ierr);
105ac9112b8SAlp Dener   ierr = VecNorm(cg->unprojected_gradient,NORM_2,&gnorm);CHKERRQ(ierr);
106c0f10754SAlp Dener   if (PetscIsInfOrNanReal(cg->f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
107ac9112b8SAlp Dener 
10861be54a6SAlp Dener   /* Estimate the active set and compute the projected gradient */
10961be54a6SAlp Dener   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
11061be54a6SAlp Dener 
111ac9112b8SAlp Dener   /* Project the gradient and calculate the norm */
11261be54a6SAlp Dener   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
11361be54a6SAlp Dener   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
114ac9112b8SAlp Dener   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
115ac9112b8SAlp Dener   gnorm2 = gnorm*gnorm;
116ac9112b8SAlp Dener 
117c8bcdf1eSAdam Denchfield   /* Initialize counters */
118e031d6f5SAlp Dener   tao->niter = 0;
119*50b47da0SAdam Denchfield   cg->ls_fails = cg->descent_error = 0;
120c8bcdf1eSAdam Denchfield   cg->resets = -1;
121c8bcdf1eSAdam Denchfield   cg->iter_quad = 0;
122c8bcdf1eSAdam Denchfield 
123c8bcdf1eSAdam Denchfield   /* Convergence test at the starting point. */
124ac9112b8SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
125c8bcdf1eSAdam Denchfield   ierr = TaoLogConvergenceHistory(tao, cg->f, gnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
126c8bcdf1eSAdam Denchfield   ierr = TaoMonitor(tao, tao->niter, cg->f, gnorm, 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);
129ac9112b8SAlp Dener 
130c8bcdf1eSAdam Denchfield   /* Assert that we have not converged.  Calculate initial direction. */
131c8bcdf1eSAdam Denchfield   /* This is where recycling goes.  The outcome of this code must be */
132c8bcdf1eSAdam Denchfield   /* the direction that we will use. */
133c8bcdf1eSAdam Denchfield   if (cg->recycle) {
134ac9112b8SAlp Dener   }
135c8bcdf1eSAdam Denchfield   /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems.  */
136*50b47da0SAdam Denchfield   ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
137ac9112b8SAlp Dener 
138c8bcdf1eSAdam Denchfield   while(1) {
139c8bcdf1eSAdam Denchfield     ierr = TaoBNCGConductIteration(tao, gnorm);CHKERRQ(ierr);
140*50b47da0SAdam Denchfield     /* Steffenson is currently an experimental (broken) feature. Do not use. */
141*50b47da0SAdam Denchfield     if (cg->use_steffenson) {
142*50b47da0SAdam Denchfield       ierr = TaoBNCGSteffensonAcceleration(tao);CHKERRQ(ierr);
143*50b47da0SAdam Denchfield     }
144c8bcdf1eSAdam Denchfield     if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
145ac9112b8SAlp Dener   }
146ac9112b8SAlp Dener   PetscFunctionReturn(0);
147ac9112b8SAlp Dener }
148ac9112b8SAlp Dener 
149ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao)
150ac9112b8SAlp Dener {
151ac9112b8SAlp Dener   TAO_BNCG         *cg = (TAO_BNCG*)tao->data;
152ac9112b8SAlp Dener   PetscErrorCode ierr;
153ac9112b8SAlp Dener 
154ac9112b8SAlp Dener   PetscFunctionBegin;
155c4b75bccSAlp Dener   if (!tao->gradient) {
156c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
157c4b75bccSAlp Dener   }
158c4b75bccSAlp Dener   if (!tao->stepdirection) {
159c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);
160c4b75bccSAlp Dener   }
161c4b75bccSAlp Dener   if (!cg->W) {
162c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->W);CHKERRQ(ierr);
163c4b75bccSAlp Dener   }
164c4b75bccSAlp Dener   if (!cg->work) {
165c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->work);CHKERRQ(ierr);
166c4b75bccSAlp Dener   }
167c8bcdf1eSAdam Denchfield   if (!cg->sk) {
168c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->sk);CHKERRQ(ierr);
169c8bcdf1eSAdam Denchfield   }
170c8bcdf1eSAdam Denchfield   if (!cg->yk) {
171c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->gradient,&cg->yk);CHKERRQ(ierr);
172c8bcdf1eSAdam Denchfield   }
173c4b75bccSAlp Dener   if (!cg->X_old) {
174c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->X_old);CHKERRQ(ierr);
175c4b75bccSAlp Dener   }
176c4b75bccSAlp Dener   if (!cg->G_old) {
177c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->G_old);CHKERRQ(ierr);
178c8bcdf1eSAdam Denchfield   }
179c8bcdf1eSAdam Denchfield   if (cg->use_steffenson){
180*50b47da0SAdam Denchfield     if (!cg->steffnm1) {
181*50b47da0SAdam Denchfield       ierr = VecDuplicate(tao->solution, &cg->steffnm1);CHKERRQ(ierr);
182*50b47da0SAdam Denchfield     }
183*50b47da0SAdam Denchfield     if (!cg->steffn) {
184*50b47da0SAdam Denchfield       ierr = VecDuplicate(tao->solution, &cg->steffn);CHKERRQ(ierr);
185*50b47da0SAdam Denchfield     }
186*50b47da0SAdam Denchfield     if (!cg->steffnp1) {
187*50b47da0SAdam Denchfield       ierr = VecDuplicate(tao->solution, &cg->steffnp1);CHKERRQ(ierr);
188*50b47da0SAdam Denchfield     }
189*50b47da0SAdam Denchfield     if (!cg->steffva) {
190*50b47da0SAdam Denchfield       ierr = VecDuplicate(tao->solution, &cg->steffva);CHKERRQ(ierr);
191*50b47da0SAdam Denchfield     }
192*50b47da0SAdam Denchfield     if (!cg->steffvatmp) {
193*50b47da0SAdam Denchfield       ierr = VecDuplicate(tao->solution, &cg->steffvatmp);CHKERRQ(ierr);
194*50b47da0SAdam Denchfield     }
195c8bcdf1eSAdam Denchfield   }
196c8bcdf1eSAdam Denchfield   if (cg->diag_scaling){
197c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->d_work);CHKERRQ(ierr);
198c8bcdf1eSAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->y_work);CHKERRQ(ierr);
199*50b47da0SAdam Denchfield     ierr = VecDuplicate(tao->solution,&cg->g_work);CHKERRQ(ierr);
200c4b75bccSAlp Dener   }
201c4b75bccSAlp Dener   if (!cg->unprojected_gradient) {
202c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient);CHKERRQ(ierr);
203c4b75bccSAlp Dener   }
204c4b75bccSAlp Dener   if (!cg->unprojected_gradient_old) {
205c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient_old);CHKERRQ(ierr);
206c4b75bccSAlp Dener   }
207*50b47da0SAdam Denchfield 
208*50b47da0SAdam Denchfield   ierr = MatLMVMAllocate(cg->B, cg->sk, cg->yk);CHKERRQ(ierr);
209ac9112b8SAlp Dener   PetscFunctionReturn(0);
210ac9112b8SAlp Dener }
211ac9112b8SAlp Dener 
212ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao)
213ac9112b8SAlp Dener {
214ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*) tao->data;
215ac9112b8SAlp Dener   PetscErrorCode ierr;
216ac9112b8SAlp Dener 
217ac9112b8SAlp Dener   PetscFunctionBegin;
218ac9112b8SAlp Dener   if (tao->setupcalled) {
21961be54a6SAlp Dener     ierr = VecDestroy(&cg->W);CHKERRQ(ierr);
220c4b75bccSAlp Dener     ierr = VecDestroy(&cg->work);CHKERRQ(ierr);
221ac9112b8SAlp Dener     ierr = VecDestroy(&cg->X_old);CHKERRQ(ierr);
222ac9112b8SAlp Dener     ierr = VecDestroy(&cg->G_old);CHKERRQ(ierr);
223ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient);CHKERRQ(ierr);
224ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient_old);CHKERRQ(ierr);
225*50b47da0SAdam Denchfield     ierr = VecDestroy(&cg->g_work);CHKERRQ(ierr);
226*50b47da0SAdam Denchfield     ierr = VecDestroy(&cg->d_work);CHKERRQ(ierr);
227*50b47da0SAdam Denchfield     ierr = VecDestroy(&cg->y_work);CHKERRQ(ierr);
228*50b47da0SAdam Denchfield     ierr = VecDestroy(&cg->sk);CHKERRQ(ierr);
229*50b47da0SAdam Denchfield     ierr = VecDestroy(&cg->yk);CHKERRQ(ierr);
230*50b47da0SAdam Denchfield     ierr = MatDestroy(&cg->B);CHKERRQ(ierr);
231ac9112b8SAlp Dener   }
232ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_lower);CHKERRQ(ierr);
233ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_upper);CHKERRQ(ierr);
234ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_fixed);CHKERRQ(ierr);
235ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
236ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
237ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
238ca964c49SAlp Dener   ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
239*50b47da0SAdam Denchfield 
240ac9112b8SAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
241ac9112b8SAlp Dener   PetscFunctionReturn(0);
242ac9112b8SAlp Dener }
243ac9112b8SAlp Dener 
244ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao)
245ac9112b8SAlp Dener {
246ac9112b8SAlp Dener     TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
247ac9112b8SAlp Dener     PetscErrorCode ierr;
248ac9112b8SAlp Dener 
249ac9112b8SAlp Dener     PetscFunctionBegin;
250ac9112b8SAlp Dener     ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
251ac9112b8SAlp Dener     ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr);
252*50b47da0SAdam Denchfield     ierr = PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CG_Types, CG_Table[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr);
253*50b47da0SAdam 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);
254*50b47da0SAdam Denchfield 
255*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL);CHKERRQ(ierr);
256*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL);CHKERRQ(ierr);
257*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL);CHKERRQ(ierr);
258*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL);CHKERRQ(ierr);
259*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL);CHKERRQ(ierr);
260*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL);CHKERRQ(ierr);
261*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL);CHKERRQ(ierr);
262c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL);CHKERRQ(ierr);
263c8bcdf1eSAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL);CHKERRQ(ierr);
264c8bcdf1eSAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL);CHKERRQ(ierr);
265*50b47da0SAdam 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);
266*50b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL);CHKERRQ(ierr);
267*50b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_use_steffenson","(developer - incomplete, do not use) use vector-Steffenson acceleration","",cg->use_steffenson,&cg->use_steffenson,NULL);CHKERRQ(ierr);
268*50b47da0SAdam Denchfield     ierr = PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL);CHKERRQ(ierr);
269c8bcdf1eSAdam 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);
270*50b47da0SAdam 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);
271*50b47da0SAdam Denchfield     ierr = PetscOptionsBool("-tao_bncg_recycle","(developer) enable recycling the existing solution and gradient at the start of a new solve","",cg->recycle,&cg->recycle,NULL);CHKERRQ(ierr);
272*50b47da0SAdam 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);
273*50b47da0SAdam 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);
274*50b47da0SAdam 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);
275*50b47da0SAdam 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);
276*50b47da0SAdam Denchfield 
277ac9112b8SAlp Dener    ierr = PetscOptionsTail();CHKERRQ(ierr);
278*50b47da0SAdam 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);
293ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Resets: %i\n", cg->resets);CHKERRQ(ierr);
294*50b47da0SAdam Denchfield 
295ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  Not a descent dir.: %i\n", cg->descent_error);CHKERRQ(ierr);
296ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails);CHKERRQ(ierr);
297ac9112b8SAlp Dener     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
298ac9112b8SAlp Dener   }
299ac9112b8SAlp Dener   PetscFunctionReturn(0);
300ac9112b8SAlp Dener }
301ac9112b8SAlp Dener 
302c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha)
303c8bcdf1eSAdam Denchfield {
304c8bcdf1eSAdam Denchfield   PetscReal            a, b, c, sig1, sig2;
305c8bcdf1eSAdam Denchfield 
306c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
307c8bcdf1eSAdam Denchfield   *scale = 0.0;
308c8bcdf1eSAdam Denchfield 
309*50b47da0SAdam Denchfield   if (1.0 == alpha){
310c8bcdf1eSAdam Denchfield     *scale = yts/yty;
311*50b47da0SAdam Denchfield   } else if (0.0 == alpha){
312c8bcdf1eSAdam Denchfield     *scale = sts/yts;
313c8bcdf1eSAdam Denchfield   }
314*50b47da0SAdam Denchfield   else if (-1.0 == alpha) *scale = 1.0;
315c8bcdf1eSAdam Denchfield   else {
316c8bcdf1eSAdam Denchfield     a = yty;
317c8bcdf1eSAdam Denchfield     b = yts;
318c8bcdf1eSAdam Denchfield     c = sts;
319c8bcdf1eSAdam Denchfield     a *= alpha;
320c8bcdf1eSAdam Denchfield     b *= -(2.0*alpha - 1.0);
321c8bcdf1eSAdam Denchfield     c *= alpha - 1.0;
322c8bcdf1eSAdam Denchfield     sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
323c8bcdf1eSAdam Denchfield     sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a);
324c8bcdf1eSAdam Denchfield     /* accept the positive root as the scalar */
325c8bcdf1eSAdam Denchfield     if (sig1 > 0.0) {
326c8bcdf1eSAdam Denchfield       *scale = sig1;
327c8bcdf1eSAdam Denchfield     } else if (sig2 > 0.0) {
328c8bcdf1eSAdam Denchfield       *scale = sig2;
329c8bcdf1eSAdam Denchfield     } else {
330c8bcdf1eSAdam Denchfield       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar");
331c8bcdf1eSAdam Denchfield     }
332c8bcdf1eSAdam Denchfield   }
333c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
334c8bcdf1eSAdam Denchfield }
335c8bcdf1eSAdam Denchfield 
336ac9112b8SAlp Dener /*MC
337ac9112b8SAlp Dener      TAOBNCG -   Bound-constrained Nonlinear Conjugate Gradient method.
338ac9112b8SAlp Dener 
339ac9112b8SAlp Dener    Options Database Keys:
340*50b47da0SAdam Denchfield +      -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled)
341c4b75bccSAlp Dener .      -tao_bncg_eta <r> - restart tolerance
34261be54a6SAlp Dener .      -tao_bncg_type <taocg_type> - cg formula
343c4b75bccSAlp Dener .      -tao_bncg_as_type <none,bertsekas> - active set estimation method
344c4b75bccSAlp Dener .      -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation
345c4b75bccSAlp Dener .      -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation
346*50b47da0SAdam 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.
347*50b47da0SAdam Denchfield .      -tao_bncg_theta <r> - convex combination parameter for the Broyden method
348*50b47da0SAdam Denchfield .      -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
349*50b47da0SAdam Denchfield .      -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods
350*50b47da0SAdam Denchfield .      -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method
351*50b47da0SAdam Denchfield .      -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method
352*50b47da0SAdam Denchfield .      -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method
353*50b47da0SAdam Denchfield .      -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method
354*50b47da0SAdam Denchfield .      -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True.
355*50b47da0SAdam Denchfield .      -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods
356*50b47da0SAdam Denchfield .      -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts
357*50b47da0SAdam Denchfield .      -tao_bncg_use_steffenson <b> (not implemented) - use Steffenson acceleration
358*50b47da0SAdam Denchfield .      -tao_bncg_zeta <r> - Scaling parameter in the KD method
359*50b47da0SAdam Denchfield .      -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart
360*50b47da0SAdam 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
361*50b47da0SAdam Denchfield .      -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations
362*50b47da0SAdam Denchfield .      -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions
363ac9112b8SAlp Dener 
364ac9112b8SAlp Dener   Notes:
365ac9112b8SAlp Dener      CG formulas are:
366*50b47da0SAdam Denchfield          "gd" - Gradient Descent
367ac9112b8SAlp Dener          "fr" - Fletcher-Reeves
368*50b47da0SAdam Denchfield          "pr" - Polak-Ribiere-Polyak
369ac9112b8SAlp Dener          "prp" - Polak-Ribiere-Plus
370ac9112b8SAlp Dener          "hs" - Hestenes-Steifel
371ac9112b8SAlp Dener          "dy" - Dai-Yuan
372*50b47da0SAdam Denchfield          "ssml_bfgs" - Self-Scaling Memoryless BFGS
373*50b47da0SAdam Denchfield          "ssml_dfp"  - Self-Scaling Memoryless DFP
374*50b47da0SAdam Denchfield          "ssml_brdn" - Self-Scaling Memoryless Broyden
375*50b47da0SAdam Denchfield          "hz" - Hager-Zhang (CG_DESCENT 5.3)
376*50b47da0SAdam Denchfield          "dk" - Dai-Kou (2013)
377*50b47da0SAdam Denchfield          "kd" - Kou-Dai (2015)
378ac9112b8SAlp Dener   Level: beginner
379ac9112b8SAlp Dener M*/
380ac9112b8SAlp Dener 
381ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao)
382ac9112b8SAlp Dener {
383ac9112b8SAlp Dener   TAO_BNCG       *cg;
384ac9112b8SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
385ac9112b8SAlp Dener   PetscErrorCode ierr;
386ac9112b8SAlp Dener 
387ac9112b8SAlp Dener   PetscFunctionBegin;
388ac9112b8SAlp Dener   tao->ops->setup = TaoSetUp_BNCG;
389ac9112b8SAlp Dener   tao->ops->solve = TaoSolve_BNCG;
390ac9112b8SAlp Dener   tao->ops->view = TaoView_BNCG;
391ac9112b8SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNCG;
392ac9112b8SAlp Dener   tao->ops->destroy = TaoDestroy_BNCG;
393ac9112b8SAlp Dener 
394ac9112b8SAlp Dener   /* Override default settings (unless already changed) */
395ac9112b8SAlp Dener   if (!tao->max_it_changed) tao->max_it = 2000;
396ac9112b8SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
397ac9112b8SAlp Dener 
398ac9112b8SAlp Dener   /*  Note: nondefault values should be used for nonlinear conjugate gradient  */
399ac9112b8SAlp Dener   /*  method.  In particular, gtol should be less that 0.5; the value used in  */
400ac9112b8SAlp Dener   /*  Nocedal and Wright is 0.10.  We use the default values for the  */
401ac9112b8SAlp Dener   /*  linesearch because it seems to work better. */
402ac9112b8SAlp Dener   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr);
403ac9112b8SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr);
404ac9112b8SAlp Dener   ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr);
405ac9112b8SAlp Dener   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr);
406ac9112b8SAlp Dener   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
407ac9112b8SAlp Dener 
408ac9112b8SAlp Dener   ierr = PetscNewLog(tao,&cg);CHKERRQ(ierr);
409ac9112b8SAlp Dener   tao->data = (void*)cg;
410c8bcdf1eSAdam Denchfield 
411*50b47da0SAdam Denchfield   ierr = MatCreate(PetscObjectComm((PetscObject)tao), &cg->B);CHKERRQ(ierr);
412*50b47da0SAdam Denchfield   ierr = PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1);CHKERRQ(ierr);
413*50b47da0SAdam Denchfield   ierr = MatSetOptionsPrefix(cg->B, "tao_bncg_");CHKERRQ(ierr);
414*50b47da0SAdam Denchfield   ierr = MatSetType(cg->B, MATLMVMDIAGBRDN);CHKERRQ(ierr);
415*50b47da0SAdam Denchfield 
416*50b47da0SAdam Denchfield   cg->dk_eta = 0.5;
417*50b47da0SAdam Denchfield   cg->hz_eta = 0.4;
418c8bcdf1eSAdam Denchfield   cg->dynamic_restart = PETSC_FALSE;
419c8bcdf1eSAdam Denchfield   cg->unscaled_restart = PETSC_FALSE;
420c8bcdf1eSAdam Denchfield   cg->theta = 1.0;
421c8bcdf1eSAdam Denchfield   cg->hz_theta = 1.0;
422c8bcdf1eSAdam Denchfield   cg->dfp_scale = 1.0;
423c8bcdf1eSAdam Denchfield   cg->bfgs_scale = 1.0;
424*50b47da0SAdam Denchfield   cg->zeta = 0.1;
425*50b47da0SAdam Denchfield   cg->min_quad = 6;
426*50b47da0SAdam Denchfield   cg->use_steffenson = PETSC_FALSE;
427c8bcdf1eSAdam Denchfield   cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/
428c8bcdf1eSAdam Denchfield   cg->xi = 1.0;
429*50b47da0SAdam Denchfield   cg->neg_xi = PETSC_TRUE;
430c8bcdf1eSAdam Denchfield   cg->spaced_restart = PETSC_FALSE;
431c8bcdf1eSAdam Denchfield   cg->tol_quad = 1e-8;
43261be54a6SAlp Dener   cg->as_step = 0.001;
43361be54a6SAlp Dener   cg->as_tol = 0.001;
434*50b47da0SAdam Denchfield   cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/
43561be54a6SAlp Dener   cg->as_type = CG_AS_BERTSEKAS;
436c8bcdf1eSAdam Denchfield   cg->cg_type = CG_SSML_BFGS;
437c0f10754SAlp Dener   cg->recycle = PETSC_FALSE;
438c8bcdf1eSAdam Denchfield   cg->alpha = 1.0;
439c8bcdf1eSAdam Denchfield   cg->diag_scaling = PETSC_TRUE;
440c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
441c8bcdf1eSAdam Denchfield }
442c8bcdf1eSAdam Denchfield 
443c8bcdf1eSAdam Denchfield 
444c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq)
445c8bcdf1eSAdam Denchfield {
446c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
447c8bcdf1eSAdam Denchfield    PetscErrorCode    ierr;
448c8bcdf1eSAdam Denchfield    PetscReal         scaling;
449c8bcdf1eSAdam Denchfield 
450c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
451c8bcdf1eSAdam Denchfield    ++cg->resets;
452c8bcdf1eSAdam Denchfield    scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23);
453c8bcdf1eSAdam Denchfield    scaling = PetscMin(100.0, PetscMax(1e-7, scaling));
454c8bcdf1eSAdam Denchfield    if (cg->unscaled_restart) scaling = 1.0;
455c8bcdf1eSAdam Denchfield    ierr = VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient);CHKERRQ(ierr);
456c8bcdf1eSAdam Denchfield    /* Also want to reset our diagonal scaling with each restart */
457c8bcdf1eSAdam Denchfield    if (cg->diag_scaling) {
458*50b47da0SAdam Denchfield      ierr = MatLMVMReset(cg->B, PETSC_FALSE);CHKERRQ(ierr);
459c8bcdf1eSAdam Denchfield    }
460c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
461c8bcdf1eSAdam Denchfield  }
462c8bcdf1eSAdam Denchfield 
463c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold)
464c8bcdf1eSAdam Denchfield {
465c8bcdf1eSAdam Denchfield    TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
466c8bcdf1eSAdam Denchfield    PetscReal         quadinterp;
467c8bcdf1eSAdam Denchfield 
468c8bcdf1eSAdam Denchfield    PetscFunctionBegin;
469*50b47da0SAdam Denchfield    if (cg->f < cg->min_quad/10) {
470*50b47da0SAdam Denchfield      *dynrestart = PETSC_FALSE;
471*50b47da0SAdam Denchfield      PetscFunctionReturn(0);
472*50b47da0SAdam Denchfield    } /* just skip this since this strategy doesn't work well for functions near zero */
473c8bcdf1eSAdam Denchfield    quadinterp = 2*(cg->f - fold)/(stepsize*(gd + gd_old));
474*50b47da0SAdam Denchfield    if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad;
475c8bcdf1eSAdam Denchfield    else {
476c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
477c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_FALSE;
478c8bcdf1eSAdam Denchfield    }
479c8bcdf1eSAdam Denchfield    if (cg->iter_quad >= cg->min_quad) {
480c8bcdf1eSAdam Denchfield      cg->iter_quad = 0;
481c8bcdf1eSAdam Denchfield      *dynrestart = PETSC_TRUE;
482c8bcdf1eSAdam Denchfield    }
483c8bcdf1eSAdam Denchfield    PetscFunctionReturn(0);
484c8bcdf1eSAdam Denchfield  }
485c8bcdf1eSAdam Denchfield 
486*50b47da0SAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscBool cg_restart, PetscReal dnorm, PetscReal ginner)
487*50b47da0SAdam Denchfield {
488c8bcdf1eSAdam Denchfield   TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
489c8bcdf1eSAdam Denchfield   PetscErrorCode    ierr;
490*50b47da0SAdam Denchfield   PetscReal         gamma = 1.0, tau_k, beta;
491*50b47da0SAdam Denchfield   PetscReal         tmp = 1.0, ynorm, ynorm2, snorm = 1.0, dk_yk=1.0, gd;
492*50b47da0SAdam Denchfield   PetscReal         gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg;
493c8bcdf1eSAdam Denchfield   PetscInt          dim;
494c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
495c8bcdf1eSAdam Denchfield 
496*50b47da0SAdam Denchfield   /* Local curvature check to see if we need to restart */
497*50b47da0SAdam Denchfield   if (tao->niter >= 1){
498c8bcdf1eSAdam Denchfield     ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
499c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
500c8bcdf1eSAdam Denchfield     ynorm2 = ynorm*ynorm;
501c8bcdf1eSAdam Denchfield     ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
502*50b47da0SAdam Denchfield     if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON) cg_restart = 1;
503*50b47da0SAdam Denchfield     if (cg->spaced_restart) {
504*50b47da0SAdam Denchfield       ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
505*50b47da0SAdam Denchfield       if (tao->niter % (dim*cg->min_restart_num)) cg_restart = 1;
506*50b47da0SAdam Denchfield     }
507*50b47da0SAdam Denchfield   }
508*50b47da0SAdam Denchfield   /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */
509*50b47da0SAdam Denchfield   if (cg->spaced_restart){
510*50b47da0SAdam Denchfield     ierr = VecGetSize(tao->gradient, &dim);CHKERRQ(ierr);
511*50b47da0SAdam Denchfield     if (0 == tao->niter % (6*dim)) cg_restart = 1;
512*50b47da0SAdam Denchfield   }
513*50b47da0SAdam Denchfield   /* Compute the diagonal scaling vector if applicable */
514*50b47da0SAdam Denchfield   if (cg->diag_scaling) {
515*50b47da0SAdam Denchfield     ierr = MatLMVMUpdate(cg->B, tao->solution, tao->gradient);CHKERRQ(ierr);
516*50b47da0SAdam Denchfield   }
517*50b47da0SAdam Denchfield 
518*50b47da0SAdam Denchfield   /* A note on diagonal scaling (to be added to paper): For the FR, PR, PRP, and DY methods, the diagonally scaled versions must be derived as a preconditioned CG method rather than as a Hessian initialization like in the Broyden methods. */
519*50b47da0SAdam Denchfield 
520*50b47da0SAdam Denchfield   /* In that case, one writes the objective function as f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the same under preconditioning. Note that A is diagonal, such that A^T = A. */
521*50b47da0SAdam Denchfield 
522*50b47da0SAdam Denchfield   /* This yields questions like what the dot product d_k^T y_k should look like. HZ mistakenly treats that as the same under preconditioning, but that is not necessarily true. */
523*50b47da0SAdam Denchfield 
524*50b47da0SAdam Denchfield   /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 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}), 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 NOT the same if our preconditioning matrix is updated between iterations. This same issue is found when considering dot products of the form g_{k+1}^T y_k. */
525*50b47da0SAdam Denchfield 
526*50b47da0SAdam Denchfield   /* As of now, for PR, PRP, and DY, the above considerations have not been fully taken into account, explaining their poorer performance. FR is implemented correctly, and yields some marginal improvement on performance. Working on the rest now. */
527*50b47da0SAdam Denchfield 
528*50b47da0SAdam Denchfield   /* Compute CG step direction */
529*50b47da0SAdam Denchfield   if (cg_restart) {
530*50b47da0SAdam Denchfield     ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
531*50b47da0SAdam Denchfield   } else if (ynorm2 > PETSC_MACHINE_EPSILON) {
532*50b47da0SAdam Denchfield     switch (cg->cg_type) {
533*50b47da0SAdam Denchfield     case CG_GradientDescent:
534*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
535*50b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
536*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
537*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient);CHKERRQ(ierr);
538*50b47da0SAdam Denchfield       } else {
539*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
540*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work);CHKERRQ(ierr);
541*50b47da0SAdam Denchfield       }
542*50b47da0SAdam Denchfield       break;
543*50b47da0SAdam Denchfield     case CG_HestenesStiefel:
544*50b47da0SAdam Denchfield       /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */
545*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
546*50b47da0SAdam Denchfield         cg->sts = step*step*dnorm*dnorm;
547*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
548*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
549*50b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/dk_yk;
550*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
551*50b47da0SAdam Denchfield       } else {
552*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
553*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
554*50b47da0SAdam Denchfield         beta = gkp1_yk/dk_yk;
555*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
556*50b47da0SAdam Denchfield       }
557c8bcdf1eSAdam Denchfield       break;
558c8bcdf1eSAdam Denchfield     case CG_FletcherReeves:
559*50b47da0SAdam Denchfield       ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
560*50b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
561*50b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
562*50b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
563*50b47da0SAdam Denchfield       ierr = VecDot(cg->yk, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
564*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
565*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha);CHKERRQ(ierr);
566*50b47da0SAdam Denchfield         beta = tau_k*gnorm2/gnorm2_old;
567*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
568*50b47da0SAdam Denchfield       } else {
569*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Before it's updated */
570*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
571*50b47da0SAdam Denchfield         ierr = VecDot(tao->gradient, cg->g_work, &tmp);CHKERRQ(ierr);
572*50b47da0SAdam Denchfield         beta = tmp/gnorm2_old;
573*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
574*50b47da0SAdam Denchfield       }
575c8bcdf1eSAdam Denchfield       break;
576*50b47da0SAdam Denchfield     case CG_PolakRibierePolyak:
577*50b47da0SAdam Denchfield       snorm = step*dnorm;
578*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
579*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
580*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
581*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
582*50b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
583*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
584*50b47da0SAdam Denchfield       } else {
585*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr);
586*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
587*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
588*50b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
589*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
590*50b47da0SAdam Denchfield       }
591c8bcdf1eSAdam Denchfield       break;
592c8bcdf1eSAdam Denchfield     case CG_PolakRibierePlus:
593*50b47da0SAdam Denchfield       ierr = VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient);CHKERRQ(ierr);
594*50b47da0SAdam Denchfield       ierr = VecNorm(cg->yk, NORM_2, &ynorm);CHKERRQ(ierr);
595*50b47da0SAdam Denchfield       ynorm2 = ynorm*ynorm;
596*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
597*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
598*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
599*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
600*50b47da0SAdam Denchfield         beta = tau_k*gkp1_yk/gnorm2_old;
601*50b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
602*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
603*50b47da0SAdam Denchfield       } else {
604*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->g_work, &gnorm2_old);CHKERRQ(ierr); /* Old gtDg */
605*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
606*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
607*50b47da0SAdam Denchfield         beta = gkp1_yk/gnorm2_old;
608*50b47da0SAdam Denchfield         beta = PetscMax(beta, 0.0);
609*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
610*50b47da0SAdam Denchfield       }
611c8bcdf1eSAdam Denchfield       break;
612*50b47da0SAdam Denchfield     case CG_DaiYuan: /* TODO: suspect this is broken in the diag part - test4 */
613*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
614*50b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, tao->gradient, &gd);CHKERRQ(ierr);
615c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
616*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha);CHKERRQ(ierr);
617*50b47da0SAdam Denchfield         beta = tau_k*gnorm2/(gd - gd_old);
618*50b47da0SAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
619*50b47da0SAdam Denchfield       } else {
620*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
621*50b47da0SAdam Denchfield         ierr = MatMult(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
622*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, tao->gradient, &gtDg);CHKERRQ(ierr);
623*50b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->G_old, &gd_old);CHKERRQ(ierr);
624*50b47da0SAdam Denchfield         ierr = VecDot(cg->d_work, cg->g_work, &dk_yk);CHKERRQ(ierr);
625*50b47da0SAdam Denchfield         dk_yk = dk_yk - gd_old;
626*50b47da0SAdam Denchfield         beta = gtDg/dk_yk;
627*50b47da0SAdam Denchfield         ierr = VecScale(cg->d_work, beta);
628*50b47da0SAdam Denchfield         ierr = VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work);CHKERRQ(ierr);
629*50b47da0SAdam Denchfield       }
630c8bcdf1eSAdam Denchfield       break;
631c8bcdf1eSAdam Denchfield     case CG_SSML_BFGS:
632c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
633c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
634*50b47da0SAdam Denchfield       snorm = step*dnorm;
635*50b47da0SAdam Denchfield       cg->yts = dk_yk*step;
636c8bcdf1eSAdam Denchfield       cg->yty = ynorm2;
637c8bcdf1eSAdam Denchfield       cg->sts = snorm*snorm;
638c8bcdf1eSAdam Denchfield       if (!cg->diag_scaling){
639c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
640*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
641c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
642*50b47da0SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp;
643c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*t*d + t*tmp*yk */
644c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
645c8bcdf1eSAdam Denchfield       } else {
646c8bcdf1eSAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
647*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
648*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
649*50b47da0SAdam Denchfield         /* compute scalar gamma */
650*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
651*50b47da0SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
652*50b47da0SAdam Denchfield         gamma = gd/dk_yk;
653*50b47da0SAdam Denchfield         /* Compute scalar beta */
654*50b47da0SAdam Denchfield         beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
655*50b47da0SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
656*50b47da0SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
657*50b47da0SAdam Denchfield       }
658c8bcdf1eSAdam Denchfield       break;
659c8bcdf1eSAdam Denchfield     case CG_SSML_DFP:
660c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
661c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
662*50b47da0SAdam Denchfield       snorm = step*dnorm;
663*50b47da0SAdam Denchfield       cg->yts = dk_yk*step;
664*50b47da0SAdam Denchfield       cg->yty = ynorm2;
665*50b47da0SAdam Denchfield       cg->sts = snorm*snorm;
666*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
667*50b47da0SAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
668*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha);CHKERRQ(ierr);
669c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
670*50b47da0SAdam Denchfield         tau_k = cg->dfp_scale*tau_k;
671c8bcdf1eSAdam Denchfield         tmp = tau_k*gkp1_yk/ynorm2;
672c8bcdf1eSAdam Denchfield         beta = -step*gd/dk_yk;
673c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
674c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
675*50b47da0SAdam Denchfield       } else {
676*50b47da0SAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */
677*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
678*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
679*50b47da0SAdam Denchfield         /* compute scalar gamma */
680*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
681*50b47da0SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
682*50b47da0SAdam Denchfield         gamma = (gkp1_yk/tmp);
683*50b47da0SAdam Denchfield         /* Compute scalar beta */
684*50b47da0SAdam Denchfield         beta = -step*gd/dk_yk;
685*50b47da0SAdam Denchfield         /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
686*50b47da0SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
687c8bcdf1eSAdam Denchfield       }
688c8bcdf1eSAdam Denchfield       break;
689c8bcdf1eSAdam Denchfield     case CG_SSML_BROYDEN:
690c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
691c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
692*50b47da0SAdam Denchfield       snorm = step*dnorm;
693*50b47da0SAdam Denchfield       cg->yts = step*dk_yk;
694*50b47da0SAdam Denchfield       cg->yty = ynorm2;
695*50b47da0SAdam Denchfield       cg->sts = snorm*snorm;
696*50b47da0SAdam Denchfield       if (!cg->diag_scaling){
697c8bcdf1eSAdam Denchfield         /* Instead of a regular convex combination, we will solve a quadratic formula. */
698*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale);CHKERRQ(ierr);
699*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale);CHKERRQ(ierr);
700*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
701c8bcdf1eSAdam Denchfield         tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp;
702c8bcdf1eSAdam Denchfield         /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, it should reproduce the tau_dfp scaling. Same with dfp_scale.   */
703c8bcdf1eSAdam Denchfield         tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/ynorm2;
704c8bcdf1eSAdam Denchfield         beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
705c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*d + tmp*yk */
706c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
707*50b47da0SAdam Denchfield       } else {
708*50b47da0SAdam Denchfield         /* We have diagonal scaling enabled */
709*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
710*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
711*50b47da0SAdam Denchfield         /* compute scalar gamma */
712*50b47da0SAdam Denchfield         ierr = VecDot(cg->g_work, cg->yk, &gkp1_yk);CHKERRQ(ierr);
713*50b47da0SAdam Denchfield         ierr = VecDot(cg->y_work, cg->yk, &tmp);CHKERRQ(ierr);
714*50b47da0SAdam Denchfield         gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp);
715*50b47da0SAdam Denchfield         /* Compute scalar beta */
716*50b47da0SAdam Denchfield         beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk;
717*50b47da0SAdam Denchfield         /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */
718*50b47da0SAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work);CHKERRQ(ierr);
719c8bcdf1eSAdam Denchfield       }
720c8bcdf1eSAdam Denchfield       break;
721c8bcdf1eSAdam Denchfield     case CG_HagerZhang:
722*50b47da0SAdam Denchfield       /* Their 2006 paper. Comes from deleting the y_k term from SSML_BFGS, introducing a theta parameter, and using a cutoff for beta. See DK 2013 pg. 315 for a review of CG_DESCENT 5.3. One can use the dynamic restart strategy they implement, but it doesn't work well for us. */
723c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
724c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
725c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
726*50b47da0SAdam Denchfield       snorm = dnorm*step;
727*50b47da0SAdam Denchfield       cg->yts = step*dk_yk;
728c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
729c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
730c8bcdf1eSAdam Denchfield       }
731*50b47da0SAdam Denchfield       if (cg->dynamic_restart){
732c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
733c8bcdf1eSAdam Denchfield       } else {
734c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
735c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
736c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
737c8bcdf1eSAdam Denchfield           /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */
738c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
739c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk));
740c8bcdf1eSAdam Denchfield           /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */
741*50b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
742c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d */
743*50b47da0SAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient);CHKERRQ(ierr);
744c8bcdf1eSAdam Denchfield         } else {
745c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
746c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
747c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
748*50b47da0SAdam Denchfield           /* Apply the diagonal scaling to all my vectors */
749*50b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
750*50b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
751*50b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
752c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
753c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
754c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
755c8bcdf1eSAdam Denchfield           tmp = gd/dk_yk;
756c8bcdf1eSAdam Denchfield           /* tau_bfgs can be a parameter we tune via command line in future versions. For now, just setting to one. May instead put this inside the ComputeDiagonalScaling function... */
757c8bcdf1eSAdam Denchfield           cg->tau_bfgs = 1.0;
758*50b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
759c8bcdf1eSAdam Denchfield           tau_k = -tau_k*gd/(dk_yk*dk_yk);
760c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the dk contribution */
761c8bcdf1eSAdam Denchfield           beta = cg->tau_bfgs*gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */
762c8bcdf1eSAdam Denchfield           /* From HZ2013, modified to account for diagonal scaling*/
763*50b47da0SAdam Denchfield           ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
764*50b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
765*50b47da0SAdam Denchfield           beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
766c8bcdf1eSAdam Denchfield           /* Do the update */
767c8bcdf1eSAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -cg->tau_bfgs, beta, cg->g_work);CHKERRQ(ierr);
768*50b47da0SAdam Denchfield         }
769*50b47da0SAdam Denchfield       }
770c8bcdf1eSAdam Denchfield       break;
771c8bcdf1eSAdam Denchfield     case CG_DaiKou:
772c8bcdf1eSAdam Denchfield       /* 2013 paper.  */
773c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
774c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
775c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
776*50b47da0SAdam Denchfield       snorm = step*dnorm;
777*50b47da0SAdam Denchfield       cg->yts = dk_yk*step;
778c8bcdf1eSAdam Denchfield       if (!cg->diag_scaling){
779c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
780*50b47da0SAdam Denchfield         ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
781c8bcdf1eSAdam Denchfield         /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */
782c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
783*50b47da0SAdam Denchfield         beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk;
784*50b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm));
785c8bcdf1eSAdam Denchfield         /* d <- -t*g + beta*t*d */
786c8bcdf1eSAdam Denchfield         ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
787c8bcdf1eSAdam Denchfield       } else {
788c8bcdf1eSAdam Denchfield         /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
789c8bcdf1eSAdam Denchfield         cg->yty = ynorm2;
790c8bcdf1eSAdam Denchfield         cg->sts = snorm*snorm;
791*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
792*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
793*50b47da0SAdam Denchfield         ierr = MatSolve(cg->B, tao->stepdirection, cg->d_work);CHKERRQ(ierr);
794c8bcdf1eSAdam Denchfield         /* Construct the constant ytDgkp1 */
795c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->yk, cg->g_work, &gkp1_yk);CHKERRQ(ierr);
796c8bcdf1eSAdam Denchfield         /* tau_bfgs can be a parameter we tune via command line in future versions. For now, just setting to one. May instead put this inside the ComputeDiagonalScaling function... */
797c8bcdf1eSAdam Denchfield         cg->tau_bfgs = 1.0;
798*50b47da0SAdam Denchfield         ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
799c8bcdf1eSAdam Denchfield         tau_k = tau_k*gd/(dk_yk*dk_yk);
800c8bcdf1eSAdam Denchfield         tmp = gd/dk_yk;
801c8bcdf1eSAdam Denchfield         /* beta is the constant which adds the dk contribution */
802c8bcdf1eSAdam Denchfield         beta = cg->tau_bfgs*gkp1_yk/dk_yk - step*tmp - tau_k;
803c8bcdf1eSAdam Denchfield         /* Update this for the last term in beta */
804c8bcdf1eSAdam Denchfield         ierr = VecDot(cg->y_work, tao->stepdirection, &dk_yk);CHKERRQ(ierr);
805c8bcdf1eSAdam Denchfield         beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */
806*50b47da0SAdam Denchfield         ierr = VecDot(tao->stepdirection, cg->g_work, &gd);CHKERRQ(ierr);
807*50b47da0SAdam Denchfield         ierr = VecDot(cg->G_old, cg->d_work, &gd_old);CHKERRQ(ierr);
808*50b47da0SAdam Denchfield         beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm));
809c8bcdf1eSAdam Denchfield         /* Do the update */
810c8bcdf1eSAdam Denchfield         ierr = VecAXPBY(tao->stepdirection, -cg->tau_bfgs, beta, cg->g_work);CHKERRQ(ierr);
811*50b47da0SAdam Denchfield       }
812c8bcdf1eSAdam Denchfield       break;
813c8bcdf1eSAdam Denchfield     case CG_KouDai:
814c8bcdf1eSAdam Denchfield       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
815c8bcdf1eSAdam Denchfield       ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
816c8bcdf1eSAdam Denchfield       ierr = VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution);CHKERRQ(ierr);
817*50b47da0SAdam Denchfield       snorm = step*dnorm;
818*50b47da0SAdam Denchfield       cg->yts = dk_yk*step;
819c8bcdf1eSAdam Denchfield       if (cg->use_dynamic_restart){
820c8bcdf1eSAdam Denchfield         ierr = TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold);CHKERRQ(ierr);
821c8bcdf1eSAdam Denchfield       }
822*50b47da0SAdam Denchfield       if (cg->dynamic_restart){
823c8bcdf1eSAdam Denchfield         ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
824c8bcdf1eSAdam Denchfield       } else {
825c8bcdf1eSAdam Denchfield         if (!cg->diag_scaling){
826c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, tao->gradient, &gkp1_yk);CHKERRQ(ierr);
827c8bcdf1eSAdam Denchfield           ierr = TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha);CHKERRQ(ierr);
828c8bcdf1eSAdam Denchfield           beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk;
829c8bcdf1eSAdam Denchfield           if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */
830c8bcdf1eSAdam Denchfield           {
831c8bcdf1eSAdam Denchfield             beta = cg->zeta*tau_k*gd/(dnorm*dnorm);
832c8bcdf1eSAdam Denchfield             gamma = 0.0;
833c8bcdf1eSAdam Denchfield           } else {
834c8bcdf1eSAdam Denchfield             if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk;
835*50b47da0SAdam Denchfield             /* This seems to be very effective when there's no tau_k scaling. This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */
836*50b47da0SAdam Denchfield             else {
837*50b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
838*50b47da0SAdam Denchfield             }
839c8bcdf1eSAdam Denchfield           }
840c8bcdf1eSAdam Denchfield           /* d <- -t*g + beta*t*d + t*tmp*yk */
841c8bcdf1eSAdam Denchfield           ierr = VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk);CHKERRQ(ierr);
842c8bcdf1eSAdam Denchfield         } else {
843c8bcdf1eSAdam Denchfield           /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */
844c8bcdf1eSAdam Denchfield           cg->yty = ynorm2;
845c8bcdf1eSAdam Denchfield           cg->sts = snorm*snorm;
846*50b47da0SAdam Denchfield           ierr = MatSolve(cg->B, tao->gradient, cg->g_work);CHKERRQ(ierr);
847*50b47da0SAdam Denchfield           ierr = MatSolve(cg->B, cg->yk, cg->y_work);CHKERRQ(ierr);
848c8bcdf1eSAdam Denchfield           /* Construct the constant ytDgkp1 */
849c8bcdf1eSAdam Denchfield           ierr = VecDot(cg->yk, cg->g_work, &gkp1D_yk);CHKERRQ(ierr);
850c8bcdf1eSAdam Denchfield           /* Construct the constant for scaling Dkyk in the update */
851c8bcdf1eSAdam Denchfield           gamma = gd/dk_yk;
852c8bcdf1eSAdam Denchfield           /* tau_k = -ytDy/(ytd)^2 * gd */
853*50b47da0SAdam Denchfield           ierr = VecDot(cg->yk, cg->y_work, &tau_k);CHKERRQ(ierr);
854c8bcdf1eSAdam Denchfield           tau_k = tau_k*gd/(dk_yk*dk_yk);
855c8bcdf1eSAdam Denchfield           /* beta is the constant which adds the d_k contribution */
856c8bcdf1eSAdam Denchfield           beta = gkp1D_yk/dk_yk - step*gamma - tau_k;
857c8bcdf1eSAdam Denchfield           /* Here is the requisite check */
858*50b47da0SAdam Denchfield           ierr = VecDot(tao->stepdirection, cg->g_work, &tmp);CHKERRQ(ierr);
859c8bcdf1eSAdam Denchfield           if (cg->neg_xi){
860c8bcdf1eSAdam Denchfield             /* modified KD implementation */
861c8bcdf1eSAdam Denchfield             if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk;
862*50b47da0SAdam Denchfield             else {
863*50b47da0SAdam Denchfield               gamma = cg->xi*gd/dk_yk;
864*50b47da0SAdam Denchfield             }
865c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)){
866c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
867c8bcdf1eSAdam Denchfield               gamma = 0.0;
868c8bcdf1eSAdam Denchfield             }
869c8bcdf1eSAdam Denchfield           } else { /* original KD 2015 implementation */
870c8bcdf1eSAdam Denchfield             if (beta < cg->zeta*tmp/(dnorm*dnorm)) {
871c8bcdf1eSAdam Denchfield               beta = cg->zeta*tmp/(dnorm*dnorm);
872c8bcdf1eSAdam Denchfield               gamma = 0.0;
873c8bcdf1eSAdam Denchfield             } else {
874c8bcdf1eSAdam Denchfield               gamma = cg->xi*gd/dk_yk;
875c8bcdf1eSAdam Denchfield             }
876c8bcdf1eSAdam Denchfield           }
877c8bcdf1eSAdam Denchfield           /* Do the update in two steps */
878c8bcdf1eSAdam Denchfield           ierr = VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work);CHKERRQ(ierr);
879c8bcdf1eSAdam Denchfield           ierr = VecAXPY(tao->stepdirection, gamma, cg->y_work);CHKERRQ(ierr);
880*50b47da0SAdam Denchfield         }
881*50b47da0SAdam Denchfield       }
882c8bcdf1eSAdam Denchfield       break;
883c8bcdf1eSAdam Denchfield     default:
884c8bcdf1eSAdam Denchfield       beta = 0.0;
885c8bcdf1eSAdam Denchfield       break;
886c8bcdf1eSAdam Denchfield     }
887c8bcdf1eSAdam Denchfield   }
888*50b47da0SAdam Denchfield   cg_restart = 0; /* Will check in next iteration */
889c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
890c8bcdf1eSAdam Denchfield }
891c8bcdf1eSAdam Denchfield 
892*50b47da0SAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGSteffensonAcceleration(Tao tao)
893*50b47da0SAdam Denchfield {
894*50b47da0SAdam Denchfield   /* Steffenson is currently an experimental (broken) feature. Do not use. */
895c8bcdf1eSAdam Denchfield   TAO_BNCG          *cg = (TAO_BNCG*)tao->data;
896c8bcdf1eSAdam Denchfield   PetscErrorCode    ierr;
897c8bcdf1eSAdam Denchfield   PetscReal         mag1, mag2;
898c8bcdf1eSAdam Denchfield   PetscReal         resnorm;
899c8bcdf1eSAdam Denchfield   PetscReal         steff_f;
900c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
901c8bcdf1eSAdam Denchfield   if (tao->niter > 2 && tao->niter % 2 == 0){
902c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->steffnp1, cg->steffnm1);CHKERRQ(ierr); /* X_np1 to X_nm1 since it's been two iterations*/
903c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->X_old, cg->steffn);CHKERRQ(ierr); /* Get X_n */
904c8bcdf1eSAdam Denchfield     ierr = VecCopy(tao->solution, cg->steffnp1);CHKERRQ(ierr);
905c8bcdf1eSAdam Denchfield 
906c8bcdf1eSAdam Denchfield     /* Begin step 4 */
907c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->steffnm1, cg->W);CHKERRQ(ierr);
908c8bcdf1eSAdam Denchfield     ierr = VecAXPBY(cg->W, 1.0, -1.0, cg->steffn);CHKERRQ(ierr);
909*50b47da0SAdam Denchfield     ierr = VecDot(cg->W, cg->W, &mag1);CHKERRQ(ierr);
910c8bcdf1eSAdam Denchfield     ierr = VecAXPBYPCZ(cg->W, -1.0, 1.0, -1.0, cg->steffn, cg->steffnp1);CHKERRQ(ierr);
911*50b47da0SAdam Denchfield     ierr = VecDot(cg->W, cg->W, &mag2);CHKERRQ(ierr);
912c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->steffnm1, cg->steffva);CHKERRQ(ierr);
913c8bcdf1eSAdam Denchfield     ierr = VecAXPY(cg->steffva, -mag1/mag2, cg->W);CHKERRQ(ierr);
914c8bcdf1eSAdam Denchfield 
915c8bcdf1eSAdam Denchfield     ierr = TaoComputeObjectiveAndGradient(tao, cg->steffva, &steff_f, cg->g_work);CHKERRQ(ierr);
916c8bcdf1eSAdam Denchfield 
917c8bcdf1eSAdam Denchfield     /* Check if the accelerated point has converged*/
918c8bcdf1eSAdam Denchfield     ierr = VecFischer(cg->steffva, cg->g_work, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
919c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
920c8bcdf1eSAdam Denchfield     if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
921c8bcdf1eSAdam Denchfield     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
922*50b47da0SAdam Denchfield     ierr = PetscPrintf(PETSC_COMM_SELF, "va f: %20.19e\t va gnorm: %20.19e\n", steff_f, resnorm);CHKERRQ(ierr);
923c8bcdf1eSAdam Denchfield 
924*50b47da0SAdam Denchfield   } else if (2 == tao->niter){
925c8bcdf1eSAdam Denchfield     ierr = VecCopy(tao->solution, cg->steffnp1);CHKERRQ(ierr);
926c8bcdf1eSAdam Denchfield     mag1 = cg->sts; /* = |x1 - x0|^2 */
927c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->steffnm1, cg->steffvatmp);CHKERRQ(ierr);
928*50b47da0SAdam Denchfield     ierr = VecAXPBYPCZ(cg->steffva, 1.0, -1.0, 0.0, cg->steffnp1, cg->steffn);CHKERRQ(ierr);
929*50b47da0SAdam Denchfield     ierr = VecAXPBYPCZ(cg->steffva, 1.0, -1.0, 1.0, cg->steffnm1, cg->steffn);CHKERRQ(ierr);
930c8bcdf1eSAdam Denchfield     ierr = VecNorm(cg->steffva, NORM_2, &mag2);CHKERRQ(ierr);
931c8bcdf1eSAdam Denchfield     mag2 = mag2*mag2;
932c8bcdf1eSAdam Denchfield     ierr = VecAXPBY(cg->steffva, 1.0, -mag1/mag2, cg->steffvatmp);CHKERRQ(ierr);
933c8bcdf1eSAdam Denchfield     // finished step 2
934*50b47da0SAdam Denchfield   } else if (1 == tao->niter){
935c8bcdf1eSAdam Denchfield     ierr = VecCopy(cg->X_old, cg->steffnm1);CHKERRQ(ierr);
936c8bcdf1eSAdam Denchfield     ierr = VecCopy(tao->solution, cg->steffn);CHKERRQ(ierr);
937c8bcdf1eSAdam Denchfield   }
938c8bcdf1eSAdam Denchfield   /* Now have step 2 done of method */
939c8bcdf1eSAdam Denchfield   PetscFunctionReturn(0);
940c8bcdf1eSAdam Denchfield }
941c8bcdf1eSAdam Denchfield 
942c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm)
943c8bcdf1eSAdam Denchfield {
944c8bcdf1eSAdam Denchfield   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
945c8bcdf1eSAdam Denchfield   PetscErrorCode               ierr;
946c8bcdf1eSAdam Denchfield   TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING;
947c8bcdf1eSAdam Denchfield   PetscReal                    step=1.0,gnorm2,gd,ginner,dnorm;
948c8bcdf1eSAdam Denchfield   PetscReal                    gnorm2_old,f_old,resnorm, gnorm_old;
949c8bcdf1eSAdam Denchfield   PetscBool                    cg_restart, gd_fallback = PETSC_FALSE;
950c8bcdf1eSAdam Denchfield 
951c8bcdf1eSAdam Denchfield   PetscFunctionBegin;
952c8bcdf1eSAdam Denchfield   /* We are now going to perform a line search along the direction.  */
953c8bcdf1eSAdam Denchfield   ++tao->niter;
954c8bcdf1eSAdam Denchfield 
955c8bcdf1eSAdam Denchfield   /* Store solution and gradient info before it changes */
956c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr);
957c8bcdf1eSAdam Denchfield   ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr);
958c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr);
959c8bcdf1eSAdam Denchfield 
960c8bcdf1eSAdam Denchfield   gnorm_old = gnorm;
961c8bcdf1eSAdam Denchfield   gnorm2_old = gnorm_old*gnorm_old;
962c8bcdf1eSAdam Denchfield   f_old = cg->f;
963c8bcdf1eSAdam Denchfield   /* Perform bounded line search */
964c8bcdf1eSAdam Denchfield   ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
965c8bcdf1eSAdam Denchfield   ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
966c8bcdf1eSAdam Denchfield   ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
967c8bcdf1eSAdam Denchfield 
968c8bcdf1eSAdam Denchfield   /*  Check linesearch failure */
969c8bcdf1eSAdam Denchfield   if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
970c8bcdf1eSAdam Denchfield     ++cg->ls_fails;
971c8bcdf1eSAdam Denchfield 
972c8bcdf1eSAdam Denchfield     if (cg->cg_type == CG_GradientDescent || gd_fallback){
973c8bcdf1eSAdam Denchfield       /* Nothing left to do but fail out of the optimization */
974c8bcdf1eSAdam Denchfield       step = 0.0;
975c8bcdf1eSAdam Denchfield       tao->reason = TAO_DIVERGED_LS_FAILURE;
976c8bcdf1eSAdam Denchfield     } else {
977c8bcdf1eSAdam Denchfield       /* Restore previous point */
978c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr);
979c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr);
980c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr);
981c8bcdf1eSAdam Denchfield 
982c8bcdf1eSAdam Denchfield       gnorm = gnorm_old;
983c8bcdf1eSAdam Denchfield       gnorm2 = gnorm2_old;
984c8bcdf1eSAdam Denchfield       cg->f = f_old;
985c8bcdf1eSAdam Denchfield 
986c8bcdf1eSAdam Denchfield       /* Fall back on the scaled gradient step */
987*50b47da0SAdam Denchfield       ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
988c8bcdf1eSAdam Denchfield       ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
989c8bcdf1eSAdam Denchfield 
990c8bcdf1eSAdam Denchfield       ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
991c8bcdf1eSAdam Denchfield       ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
992c8bcdf1eSAdam Denchfield       ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
993c8bcdf1eSAdam Denchfield 
994c8bcdf1eSAdam Denchfield       if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
995c8bcdf1eSAdam Denchfield         /* Nothing left to do but fail out of the optimization */
996*50b47da0SAdam Denchfield         ++cg->ls_fails;
997c8bcdf1eSAdam Denchfield         step = 0.0;
998c8bcdf1eSAdam Denchfield         tao->reason = TAO_DIVERGED_LS_FAILURE;
999c8bcdf1eSAdam Denchfield       }
1000c8bcdf1eSAdam Denchfield     }
1001c8bcdf1eSAdam Denchfield   }
1002c8bcdf1eSAdam Denchfield   /* Convergence test for line search failure */
1003c8bcdf1eSAdam Denchfield   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1004c8bcdf1eSAdam Denchfield 
1005c8bcdf1eSAdam Denchfield   /* Standard convergence test */
1006c8bcdf1eSAdam Denchfield   /* Make sure convergence test is the same. */
1007c8bcdf1eSAdam Denchfield   ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
1008c8bcdf1eSAdam Denchfield   ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
1009c8bcdf1eSAdam Denchfield   if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
1010c8bcdf1eSAdam Denchfield   ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
1011c8bcdf1eSAdam Denchfield   ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
1012c8bcdf1eSAdam Denchfield   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
1013c8bcdf1eSAdam Denchfield   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
1014c8bcdf1eSAdam Denchfield 
1015c8bcdf1eSAdam Denchfield   /* Assert we have an updated step and we need at least one more iteration. */
1016c8bcdf1eSAdam Denchfield   /* Calculate the next direction */
1017c8bcdf1eSAdam Denchfield   /* Estimate the active set at the new solution */
1018c8bcdf1eSAdam Denchfield   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
1019c8bcdf1eSAdam Denchfield   /* Compute the projected gradient and its norm */
1020c8bcdf1eSAdam Denchfield   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
1021c8bcdf1eSAdam Denchfield   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
1022c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
1023c8bcdf1eSAdam Denchfield   gnorm2 = gnorm*gnorm;
1024c8bcdf1eSAdam Denchfield 
1025c8bcdf1eSAdam Denchfield   /* Check restart conditions for using steepest descent */
1026*50b47da0SAdam Denchfield   cg_restart = 0;
1027c8bcdf1eSAdam Denchfield   ierr = VecDot(tao->gradient, cg->G_old, &ginner);CHKERRQ(ierr);
1028c8bcdf1eSAdam Denchfield   ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
1029c8bcdf1eSAdam Denchfield 
1030c8bcdf1eSAdam Denchfield   ierr = TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, cg_restart, dnorm, ginner);CHKERRQ(ierr);
1031c8bcdf1eSAdam Denchfield 
1032c8bcdf1eSAdam Denchfield   ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1033c8bcdf1eSAdam Denchfield 
1034c8bcdf1eSAdam Denchfield   if (cg->cg_type != CG_GradientDescent) {
1035c8bcdf1eSAdam Denchfield     /* Figure out which previously active variables became inactive this iteration */
1036c8bcdf1eSAdam Denchfield     ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
1037c8bcdf1eSAdam Denchfield     if (cg->inactive_idx && cg->inactive_old) {
1038c8bcdf1eSAdam Denchfield       ierr = ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives);CHKERRQ(ierr);
1039c8bcdf1eSAdam Denchfield     }
1040c8bcdf1eSAdam Denchfield     /* Selectively reset the CG step those freshly inactive variables */
1041c8bcdf1eSAdam Denchfield     if (cg->new_inactives) {
1042c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1043c8bcdf1eSAdam Denchfield       ierr = VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1044c8bcdf1eSAdam Denchfield       ierr = VecCopy(cg->inactive_grad, cg->inactive_step);CHKERRQ(ierr);
1045c8bcdf1eSAdam Denchfield       ierr = VecScale(cg->inactive_step, -1.0);CHKERRQ(ierr);
1046c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
1047c8bcdf1eSAdam Denchfield       ierr = VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
1048c8bcdf1eSAdam Denchfield     }
1049c8bcdf1eSAdam Denchfield 
1050c8bcdf1eSAdam Denchfield     /* Verify that this is a descent direction */
1051c8bcdf1eSAdam Denchfield     ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
1052*50b47da0SAdam Denchfield     ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
1053*50b47da0SAdam Denchfield     if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) {
1054c8bcdf1eSAdam Denchfield       /* Not a descent direction, so we reset back to projected gradient descent */
1055*50b47da0SAdam Denchfield       PetscPrintf(PETSC_COMM_SELF, "gtd/(dtd) is small or positive: %20.19e\n", gd/(dnorm*dnorm));
1056*50b47da0SAdam Denchfield       ierr = TaoBNCGResetUpdate(tao, gnorm2);CHKERRQ(ierr);
1057c8bcdf1eSAdam Denchfield       ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
1058c8bcdf1eSAdam Denchfield       ++cg->descent_error;
1059c8bcdf1eSAdam Denchfield       gd_fallback = PETSC_TRUE;
1060c8bcdf1eSAdam Denchfield     } else {
1061c8bcdf1eSAdam Denchfield       gd_fallback = PETSC_FALSE;
1062c8bcdf1eSAdam Denchfield     }
1063c8bcdf1eSAdam Denchfield   }
1064ac9112b8SAlp Dener   PetscFunctionReturn(0);
1065ac9112b8SAlp Dener }
1066