1ac9112b8SAlp Dener #include <petsctaolinesearch.h> 2414d97d3SAlp Dener #include <../src/tao/bound/impls/bncg/bncg.h> /*I "petsctao.h" I*/ 350b47da0SAdam Denchfield #include <petscksp.h> 4ac9112b8SAlp Dener 5c8bcdf1eSAdam Denchfield #define CG_GradientDescent 0 6c8bcdf1eSAdam Denchfield #define CG_HestenesStiefel 1 7c8bcdf1eSAdam Denchfield #define CG_FletcherReeves 2 850b47da0SAdam Denchfield #define CG_PolakRibierePolyak 3 9c8bcdf1eSAdam Denchfield #define CG_PolakRibierePlus 4 10c8bcdf1eSAdam Denchfield #define CG_DaiYuan 5 11c8bcdf1eSAdam Denchfield #define CG_HagerZhang 6 12c8bcdf1eSAdam Denchfield #define CG_DaiKou 7 13c8bcdf1eSAdam Denchfield #define CG_KouDai 8 14c8bcdf1eSAdam Denchfield #define CG_SSML_BFGS 9 15c8bcdf1eSAdam Denchfield #define CG_SSML_DFP 10 16c8bcdf1eSAdam Denchfield #define CG_SSML_BROYDEN 11 17484c7b14SAdam Denchfield #define CG_PCGradientDescent 12 18484c7b14SAdam Denchfield #define CGTypes 13 19ac9112b8SAlp Dener 20484c7b14SAdam Denchfield static const char *CG_Table[64] = {"gd", "hs", "fr", "pr", "prp", "dy", "hz", "dk", "kd", "ssml_bfgs", "ssml_dfp", "ssml_brdn", "pcgd"}; 21ac9112b8SAlp Dener 2261be54a6SAlp Dener #define CG_AS_NONE 0 2361be54a6SAlp Dener #define CG_AS_BERTSEKAS 1 2461be54a6SAlp Dener #define CG_AS_SIZE 2 25ac9112b8SAlp Dener 2661be54a6SAlp Dener static const char *CG_AS_TYPE[64] = {"none", "bertsekas"}; 27ac9112b8SAlp Dener 2861be54a6SAlp Dener PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType) 2961be54a6SAlp Dener { 3061be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 3161be54a6SAlp Dener 3261be54a6SAlp Dener PetscFunctionBegin; 339566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 3461be54a6SAlp Dener if (cg->inactive_idx) { 359566063dSJacob Faibussowitsch PetscCall(ISDuplicate(cg->inactive_idx, &cg->inactive_old)); 369566063dSJacob Faibussowitsch PetscCall(ISCopy(cg->inactive_idx, cg->inactive_old)); 3761be54a6SAlp Dener } 3861be54a6SAlp Dener switch (asType) { 3961be54a6SAlp Dener case CG_AS_NONE: 409566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 419566063dSJacob Faibussowitsch PetscCall(VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx)); 429566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 439566063dSJacob Faibussowitsch PetscCall(ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx)); 4461be54a6SAlp Dener break; 4561be54a6SAlp Dener 4661be54a6SAlp Dener case CG_AS_BERTSEKAS: 4761be54a6SAlp Dener /* Use gradient descent to estimate the active set */ 489566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->W)); 499566063dSJacob Faibussowitsch PetscCall(VecScale(cg->W, -1.0)); 50d0609cedSBarry Smith PetscCall(TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol, 51d0609cedSBarry Smith &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx)); 52c4b75bccSAlp Dener break; 5361be54a6SAlp Dener default: 5461be54a6SAlp Dener break; 5561be54a6SAlp Dener } 5661be54a6SAlp Dener PetscFunctionReturn(0); 5761be54a6SAlp Dener } 5861be54a6SAlp Dener 59a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step) 6061be54a6SAlp Dener { 6161be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 6261be54a6SAlp Dener 6361be54a6SAlp Dener PetscFunctionBegin; 64a1318120SAlp Dener switch (asType) { 6561be54a6SAlp Dener case CG_AS_NONE: 669566063dSJacob Faibussowitsch PetscCall(VecISSet(step, cg->active_idx, 0.0)); 6761be54a6SAlp Dener break; 6861be54a6SAlp Dener 6961be54a6SAlp Dener case CG_AS_BERTSEKAS: 709566063dSJacob Faibussowitsch PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step)); 7161be54a6SAlp Dener break; 7261be54a6SAlp Dener 7361be54a6SAlp Dener default: 7461be54a6SAlp Dener break; 7561be54a6SAlp Dener } 7661be54a6SAlp Dener PetscFunctionReturn(0); 7761be54a6SAlp Dener } 7861be54a6SAlp Dener 79ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao) 80ac9112b8SAlp Dener { 81ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 82484c7b14SAdam Denchfield PetscReal step=1.0,gnorm,gnorm2, resnorm; 83c4b75bccSAlp Dener PetscInt nDiff; 84ac9112b8SAlp Dener 85ac9112b8SAlp Dener PetscFunctionBegin; 86ac9112b8SAlp Dener /* Project the current point onto the feasible set */ 879566063dSJacob Faibussowitsch PetscCall(TaoComputeVariableBounds(tao)); 889566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU)); 89ac9112b8SAlp Dener 90c8bcdf1eSAdam Denchfield /* Project the initial point onto the feasible region */ 919566063dSJacob Faibussowitsch PetscCall(TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution)); 92484c7b14SAdam Denchfield 93414d97d3SAlp Dener if (nDiff > 0 || !tao->recycle) { 949566063dSJacob Faibussowitsch PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 95484c7b14SAdam Denchfield } 969566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->unprojected_gradient,NORM_2,&gnorm)); 973c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(cg->f) && !PetscIsInfOrNanReal(gnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 98ac9112b8SAlp Dener 9961be54a6SAlp Dener /* Estimate the active set and compute the projected gradient */ 1009566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 10161be54a6SAlp Dener 102ac9112b8SAlp Dener /* Project the gradient and calculate the norm */ 1039566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 1049566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 1059566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient,NORM_2,&gnorm)); 106ac9112b8SAlp Dener gnorm2 = gnorm*gnorm; 107ac9112b8SAlp Dener 108c8bcdf1eSAdam Denchfield /* Initialize counters */ 109e031d6f5SAlp Dener tao->niter = 0; 11050b47da0SAdam Denchfield cg->ls_fails = cg->descent_error = 0; 111c8bcdf1eSAdam Denchfield cg->resets = -1; 112484c7b14SAdam Denchfield cg->skipped_updates = cg->pure_gd_steps = 0; 113c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 114c8bcdf1eSAdam Denchfield 115c8bcdf1eSAdam Denchfield /* Convergence test at the starting point. */ 116ac9112b8SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 117484c7b14SAdam Denchfield 1189566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 1199566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 1203c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 1219566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 1229566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 1239566063dSJacob Faibussowitsch PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP)); 124ac9112b8SAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 125484c7b14SAdam Denchfield /* Calculate initial direction. */ 126414d97d3SAlp Dener if (!tao->recycle) { 127484c7b14SAdam Denchfield /* We are not recycling a solution/history from a past TaoSolve */ 1289566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 129ac9112b8SAlp Dener } 130c8bcdf1eSAdam Denchfield /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */ 131c8bcdf1eSAdam Denchfield while (1) { 132e1e80dc8SAlp Dener /* Call general purpose update function */ 133e1e80dc8SAlp Dener if (tao->ops->update) { 1349566063dSJacob Faibussowitsch PetscCall((*tao->ops->update)(tao, tao->niter, tao->user_update)); 135*7494f0b1SStefano Zampini PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 136e1e80dc8SAlp Dener } 1379566063dSJacob Faibussowitsch PetscCall(TaoBNCGConductIteration(tao, gnorm)); 138c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 139ac9112b8SAlp Dener } 140ac9112b8SAlp Dener } 141ac9112b8SAlp Dener 142ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao) 143ac9112b8SAlp Dener { 144ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 145ac9112b8SAlp Dener 146ac9112b8SAlp Dener PetscFunctionBegin; 147c4b75bccSAlp Dener if (!tao->gradient) { 1489566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->gradient)); 149c4b75bccSAlp Dener } 150c4b75bccSAlp Dener if (!tao->stepdirection) { 1519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->stepdirection)); 152c4b75bccSAlp Dener } 153c4b75bccSAlp Dener if (!cg->W) { 1549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->W)); 155c4b75bccSAlp Dener } 156c4b75bccSAlp Dener if (!cg->work) { 1579566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->work)); 158c4b75bccSAlp Dener } 159c8bcdf1eSAdam Denchfield if (!cg->sk) { 1609566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->sk)); 161c8bcdf1eSAdam Denchfield } 162c8bcdf1eSAdam Denchfield if (!cg->yk) { 1639566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->yk)); 164c8bcdf1eSAdam Denchfield } 165c4b75bccSAlp Dener if (!cg->X_old) { 1669566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->X_old)); 167c4b75bccSAlp Dener } 168c4b75bccSAlp Dener if (!cg->G_old) { 1699566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->G_old)); 170c8bcdf1eSAdam Denchfield } 171c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 1729566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->d_work)); 1739566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->y_work)); 1749566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->g_work)); 175c4b75bccSAlp Dener } 176c4b75bccSAlp Dener if (!cg->unprojected_gradient) { 1779566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient)); 178c4b75bccSAlp Dener } 179c4b75bccSAlp Dener if (!cg->unprojected_gradient_old) { 1809566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient_old)); 181c4b75bccSAlp Dener } 1829566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(cg->B, cg->sk, cg->yk)); 183484c7b14SAdam Denchfield if (cg->pc) { 1849566063dSJacob Faibussowitsch PetscCall(MatLMVMSetJ0(cg->B, cg->pc)); 185484c7b14SAdam Denchfield } 186ac9112b8SAlp Dener PetscFunctionReturn(0); 187ac9112b8SAlp Dener } 188ac9112b8SAlp Dener 189ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao) 190ac9112b8SAlp Dener { 191ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*) tao->data; 192ac9112b8SAlp Dener 193ac9112b8SAlp Dener PetscFunctionBegin; 194ac9112b8SAlp Dener if (tao->setupcalled) { 1959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->W)); 1969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->work)); 1979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->X_old)); 1989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->G_old)); 1999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient)); 2009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient_old)); 2019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->g_work)); 2029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->d_work)); 2039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->y_work)); 2049566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->sk)); 2059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->yk)); 206ac9112b8SAlp Dener } 2079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_lower)); 2089566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_upper)); 2099566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_fixed)); 2109566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 2119566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 2129566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 2139566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 2149566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->B)); 215484c7b14SAdam Denchfield if (cg->pc) { 2169566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->pc)); 217484c7b14SAdam Denchfield } 2189566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 219ac9112b8SAlp Dener PetscFunctionReturn(0); 220ac9112b8SAlp Dener } 221ac9112b8SAlp Dener 222ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao) 223ac9112b8SAlp Dener { 224ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 225ac9112b8SAlp Dener 226ac9112b8SAlp Dener PetscFunctionBegin; 227d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization"); 2289566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type,NULL)); 2298ebe3e4eSStefano Zampini if (cg->cg_type != CG_SSML_BFGS) cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */ 230484c7b14SAdam Denchfield if (CG_GradientDescent == cg->cg_type) { 231484c7b14SAdam Denchfield cg->cg_type = CG_PCGradientDescent; 232484c7b14SAdam Denchfield /* Set scaling equal to none or, at best, scalar scaling. */ 233484c7b14SAdam Denchfield cg->unscaled_restart = PETSC_TRUE; 234484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 235484c7b14SAdam Denchfield } 2369566063dSJacob Faibussowitsch PetscCall(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)); 2379566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL)); 2389566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL)); 2399566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL)); 2409566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL)); 2419566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL)); 2429566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL)); 2439566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL)); 2449566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL)); 2459566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL)); 2469566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL)); 2479566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_dynamic_restart","(developer) use dynamic restarts as in HZ, DK, KD","",cg->use_dynamic_restart,&cg->use_dynamic_restart,NULL)); 2489566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL)); 2499566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL)); 2509566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-tao_bncg_min_quad", "(developer) Number of iterations with approximate quadratic behavior needed for restart", "", cg->min_quad, &cg->min_quad, NULL)); 2519566063dSJacob Faibussowitsch PetscCall(PetscOptionsInt("-tao_bncg_min_restart_num", "(developer) Number of iterations between restarts (times dimension)", "", cg->min_restart_num, &cg->min_restart_num, NULL)); 2529566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_spaced_restart","(developer) Enable regular steepest descent restarting every fixed number of iterations","",cg->spaced_restart,&cg->spaced_restart,NULL)); 2539566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_no_scaling","Disable all scaling except in restarts","",cg->no_scaling,&cg->no_scaling,NULL)); 254484c7b14SAdam Denchfield if (cg->no_scaling) { 255484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 256484c7b14SAdam Denchfield cg->alpha = -1.0; 257484c7b14SAdam Denchfield } 258b474139fSKarl Rupp if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling) { /* Some more default options that appear to be good. */ 259484c7b14SAdam Denchfield cg->neg_xi = PETSC_TRUE; 260484c7b14SAdam Denchfield } 2619566063dSJacob Faibussowitsch PetscCall(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)); 2629566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables","",cg->as_tol,&cg->as_tol,NULL)); 2639566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables","",cg->as_step,&cg->as_step,NULL)); 2649566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts","",cg->delta_min,&cg->delta_min,NULL)); 2659566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts","",cg->delta_max,&cg->delta_max,NULL)); 26650b47da0SAdam Denchfield 267d0609cedSBarry Smith PetscOptionsHeadEnd(); 2689566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(cg->B, ((PetscObject)tao)->prefix)); 2699566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(cg->B, "tao_bncg_")); 2709566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(cg->B)); 271ac9112b8SAlp Dener PetscFunctionReturn(0); 272ac9112b8SAlp Dener } 273ac9112b8SAlp Dener 274ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 275ac9112b8SAlp Dener { 276ac9112b8SAlp Dener PetscBool isascii; 277ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 278ac9112b8SAlp Dener 279ac9112b8SAlp Dener PetscFunctionBegin; 2809566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 281ac9112b8SAlp Dener if (isascii) { 2829566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 2839566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type])); 28463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %" PetscInt_FMT "\n", cg->skipped_updates)); 28563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", cg->resets)); 28663a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %" PetscInt_FMT "\n", cg->pure_gd_steps)); 28763a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not a descent direction: %" PetscInt_FMT "\n", cg->descent_error)); 28863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Line search fails: %" PetscInt_FMT "\n", cg->ls_fails)); 289484c7b14SAdam Denchfield if (cg->diag_scaling) { 2909566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii)); 291484c7b14SAdam Denchfield if (isascii) { 2929566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 2939566063dSJacob Faibussowitsch PetscCall(MatView(cg->B, viewer)); 2949566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 295484c7b14SAdam Denchfield } 296484c7b14SAdam Denchfield } 2979566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 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; 3088ebe3e4eSStefano Zampini if (1.0 == alpha) *scale = yts/yty; 3098ebe3e4eSStefano Zampini else if (0.0 == alpha) *scale = sts/yts; 31050b47da0SAdam Denchfield else if (-1.0 == alpha) *scale = 1.0; 311c8bcdf1eSAdam Denchfield else { 312c8bcdf1eSAdam Denchfield a = yty; 313c8bcdf1eSAdam Denchfield b = yts; 314c8bcdf1eSAdam Denchfield c = sts; 315c8bcdf1eSAdam Denchfield a *= alpha; 316c8bcdf1eSAdam Denchfield b *= -(2.0*alpha - 1.0); 317c8bcdf1eSAdam Denchfield c *= alpha - 1.0; 318c8bcdf1eSAdam Denchfield sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 319c8bcdf1eSAdam Denchfield sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 320c8bcdf1eSAdam Denchfield /* accept the positive root as the scalar */ 3218ebe3e4eSStefano Zampini if (sig1 > 0.0) *scale = sig1; 3228ebe3e4eSStefano Zampini else if (sig2 > 0.0) *scale = sig2; 3238ebe3e4eSStefano Zampini else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar"); 324c8bcdf1eSAdam Denchfield } 325c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 326c8bcdf1eSAdam Denchfield } 327c8bcdf1eSAdam Denchfield 328ac9112b8SAlp Dener /*MC 329ac9112b8SAlp Dener TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 330ac9112b8SAlp Dener 331ac9112b8SAlp Dener Options Database Keys: 33250b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled) 333c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance 33461be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula 335c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method 336c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation 337c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation 33850b47da0SAdam 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. 33950b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method 34050b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34150b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34250b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method 34350b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method 34450b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method 34550b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method 34650b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True. 34750b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods 34850b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts 34950b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method 350484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps 351484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps 35250b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart 35350b47da0SAdam 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 35450b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations 355484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults. 3563850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions 357ac9112b8SAlp Dener 358ac9112b8SAlp Dener Notes: 359ac9112b8SAlp Dener CG formulas are: 3603850be85SAlp Dener + "gd" - Gradient Descent 3613850be85SAlp Dener . "fr" - Fletcher-Reeves 3623850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak 3633850be85SAlp Dener . "prp" - Polak-Ribiere-Plus 3643850be85SAlp Dener . "hs" - Hestenes-Steifel 3653850be85SAlp Dener . "dy" - Dai-Yuan 3663850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS 3673850be85SAlp Dener . "ssml_dfp" - Self-Scaling Memoryless DFP 3683850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden 3693850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3) 3703850be85SAlp Dener . "dk" - Dai-Kou (2013) 3713850be85SAlp Dener - "kd" - Kou-Dai (2015) 3729abc5736SPatrick Sanan 373ac9112b8SAlp Dener Level: beginner 374ac9112b8SAlp Dener M*/ 375ac9112b8SAlp Dener 376ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 377ac9112b8SAlp Dener { 378ac9112b8SAlp Dener TAO_BNCG *cg; 379ac9112b8SAlp Dener const char *morethuente_type = TAOLINESEARCHMT; 380ac9112b8SAlp Dener 381ac9112b8SAlp Dener PetscFunctionBegin; 382ac9112b8SAlp Dener tao->ops->setup = TaoSetUp_BNCG; 383ac9112b8SAlp Dener tao->ops->solve = TaoSolve_BNCG; 384ac9112b8SAlp Dener tao->ops->view = TaoView_BNCG; 385ac9112b8SAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 386ac9112b8SAlp Dener tao->ops->destroy = TaoDestroy_BNCG; 387ac9112b8SAlp Dener 388ac9112b8SAlp Dener /* Override default settings (unless already changed) */ 389ac9112b8SAlp Dener if (!tao->max_it_changed) tao->max_it = 2000; 390ac9112b8SAlp Dener if (!tao->max_funcs_changed) tao->max_funcs = 4000; 391ac9112b8SAlp Dener 392ac9112b8SAlp Dener /* Note: nondefault values should be used for nonlinear conjugate gradient */ 393ac9112b8SAlp Dener /* method. In particular, gtol should be less that 0.5; the value used in */ 394ac9112b8SAlp Dener /* Nocedal and Wright is 0.10. We use the default values for the */ 395ac9112b8SAlp Dener /* linesearch because it seems to work better. */ 3969566063dSJacob Faibussowitsch PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch)); 3979566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1)); 3989566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type)); 3999566063dSJacob Faibussowitsch PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao)); 400ac9112b8SAlp Dener 4019566063dSJacob Faibussowitsch PetscCall(PetscNewLog(tao,&cg)); 402ac9112b8SAlp Dener tao->data = (void*)cg; 4039566063dSJacob Faibussowitsch PetscCall(KSPInitializePackage()); 4049566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &cg->B)); 4059566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1)); 4069566063dSJacob Faibussowitsch PetscCall(MatSetType(cg->B, MATLMVMDIAGBROYDEN)); 40750b47da0SAdam Denchfield 408484c7b14SAdam Denchfield cg->pc = NULL; 409484c7b14SAdam Denchfield 41050b47da0SAdam Denchfield cg->dk_eta = 0.5; 41150b47da0SAdam Denchfield cg->hz_eta = 0.4; 412c8bcdf1eSAdam Denchfield cg->dynamic_restart = PETSC_FALSE; 413c8bcdf1eSAdam Denchfield cg->unscaled_restart = PETSC_FALSE; 414484c7b14SAdam Denchfield cg->no_scaling = PETSC_FALSE; 415484c7b14SAdam Denchfield cg->delta_min = 1e-7; 416484c7b14SAdam Denchfield cg->delta_max = 100; 417c8bcdf1eSAdam Denchfield cg->theta = 1.0; 418c8bcdf1eSAdam Denchfield cg->hz_theta = 1.0; 419c8bcdf1eSAdam Denchfield cg->dfp_scale = 1.0; 420c8bcdf1eSAdam Denchfield cg->bfgs_scale = 1.0; 42150b47da0SAdam Denchfield cg->zeta = 0.1; 42250b47da0SAdam Denchfield cg->min_quad = 6; 423c8bcdf1eSAdam Denchfield cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/ 424c8bcdf1eSAdam Denchfield cg->xi = 1.0; 42550b47da0SAdam Denchfield cg->neg_xi = PETSC_TRUE; 426c8bcdf1eSAdam Denchfield cg->spaced_restart = PETSC_FALSE; 427c8bcdf1eSAdam Denchfield cg->tol_quad = 1e-8; 42861be54a6SAlp Dener cg->as_step = 0.001; 42961be54a6SAlp Dener cg->as_tol = 0.001; 43050b47da0SAdam Denchfield cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/ 43161be54a6SAlp Dener cg->as_type = CG_AS_BERTSEKAS; 432c8bcdf1eSAdam Denchfield cg->cg_type = CG_SSML_BFGS; 433c8bcdf1eSAdam Denchfield cg->alpha = 1.0; 434c8bcdf1eSAdam Denchfield cg->diag_scaling = PETSC_TRUE; 435c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 436c8bcdf1eSAdam Denchfield } 437c8bcdf1eSAdam Denchfield 438c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq) 439c8bcdf1eSAdam Denchfield { 440c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 441c8bcdf1eSAdam Denchfield PetscReal scaling; 442c8bcdf1eSAdam Denchfield 443c8bcdf1eSAdam Denchfield PetscFunctionBegin; 444c8bcdf1eSAdam Denchfield ++cg->resets; 445c8bcdf1eSAdam Denchfield scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23); 446484c7b14SAdam Denchfield scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling)); 447484c7b14SAdam Denchfield if (cg->unscaled_restart) { 448484c7b14SAdam Denchfield scaling = 1.0; 449484c7b14SAdam Denchfield ++cg->pure_gd_steps; 450484c7b14SAdam Denchfield } 4519566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient)); 452c8bcdf1eSAdam Denchfield /* Also want to reset our diagonal scaling with each restart */ 453c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 4549566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(cg->B, PETSC_FALSE)); 455c8bcdf1eSAdam Denchfield } 456c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 457c8bcdf1eSAdam Denchfield } 458c8bcdf1eSAdam Denchfield 459c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold) 460c8bcdf1eSAdam Denchfield { 461c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 462c8bcdf1eSAdam Denchfield PetscReal quadinterp; 463c8bcdf1eSAdam Denchfield 464c8bcdf1eSAdam Denchfield PetscFunctionBegin; 46550b47da0SAdam Denchfield if (cg->f < cg->min_quad/10) { 46650b47da0SAdam Denchfield *dynrestart = PETSC_FALSE; 46750b47da0SAdam Denchfield PetscFunctionReturn(0); 46850b47da0SAdam Denchfield } /* just skip this since this strategy doesn't work well for functions near zero */ 469484c7b14SAdam Denchfield quadinterp = 2.0*(cg->f - fold)/(stepsize*(gd + gd_old)); 47050b47da0SAdam Denchfield if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad; 471c8bcdf1eSAdam Denchfield else { 472c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 473c8bcdf1eSAdam Denchfield *dynrestart = PETSC_FALSE; 474c8bcdf1eSAdam Denchfield } 475c8bcdf1eSAdam Denchfield if (cg->iter_quad >= cg->min_quad) { 476c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 477c8bcdf1eSAdam Denchfield *dynrestart = PETSC_TRUE; 478c8bcdf1eSAdam Denchfield } 479c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 480c8bcdf1eSAdam Denchfield } 481c8bcdf1eSAdam Denchfield 4828ca2df50S PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback) 48350b47da0SAdam Denchfield { 484c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 48550b47da0SAdam Denchfield PetscReal gamma = 1.0, tau_k, beta; 486484c7b14SAdam Denchfield PetscReal tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk=1.0, gd; 48750b47da0SAdam Denchfield PetscReal gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg; 488c8bcdf1eSAdam Denchfield PetscInt dim; 489484c7b14SAdam Denchfield PetscBool cg_restart = PETSC_FALSE; 490c8bcdf1eSAdam Denchfield PetscFunctionBegin; 491c8bcdf1eSAdam Denchfield 49250b47da0SAdam Denchfield /* Local curvature check to see if we need to restart */ 493414d97d3SAlp Dener if (tao->niter >= 1 || tao->recycle) { 4949566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 4959566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 496c8bcdf1eSAdam Denchfield ynorm2 = ynorm*ynorm; 4979566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 498484c7b14SAdam Denchfield if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON) { 499e2570530SAlp Dener cg_restart = PETSC_TRUE; 500484c7b14SAdam Denchfield ++cg->skipped_updates; 501484c7b14SAdam Denchfield } 50250b47da0SAdam Denchfield if (cg->spaced_restart) { 5039566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 504e2570530SAlp Dener if (tao->niter % (dim*cg->min_restart_num)) cg_restart = PETSC_TRUE; 50550b47da0SAdam Denchfield } 50650b47da0SAdam Denchfield } 50750b47da0SAdam Denchfield /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */ 50850b47da0SAdam Denchfield if (cg->spaced_restart) { 5099566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 510e2570530SAlp Dener if (0 == tao->niter % (6*dim)) cg_restart = PETSC_TRUE; 51150b47da0SAdam Denchfield } 51250b47da0SAdam Denchfield /* Compute the diagonal scaling vector if applicable */ 51350b47da0SAdam Denchfield if (cg->diag_scaling) { 5149566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(cg->B, tao->solution, tao->gradient)); 51550b47da0SAdam Denchfield } 51650b47da0SAdam Denchfield 517484c7b14SAdam Denchfield /* A note on diagonal scaling (to be added to paper): 518484c7b14SAdam Denchfield For the FR, PR, PRP, and DY methods, the diagonally scaled versions 519484c7b14SAdam Denchfield must be derived as a preconditioned CG method rather than as 520484c7b14SAdam Denchfield a Hessian initialization like in the Broyden methods. */ 52150b47da0SAdam Denchfield 522484c7b14SAdam Denchfield /* In that case, one writes the objective function as 523484c7b14SAdam Denchfield f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). 524484c7b14SAdam Denchfield Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to 525484c7b14SAdam Denchfield HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the 526484c7b14SAdam Denchfield same under preconditioning. Note that A is diagonal, such that A^T = A. */ 52750b47da0SAdam Denchfield 528484c7b14SAdam Denchfield /* This yields questions like what the dot product d_k^T y_k 529484c7b14SAdam Denchfield should look like. HZ mistakenly treats that as the same under 530484c7b14SAdam Denchfield preconditioning, but that is not necessarily true. */ 53150b47da0SAdam Denchfield 532484c7b14SAdam Denchfield /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 533484c7b14SAdam 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}), 534484c7b14SAdam 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 535484c7b14SAdam Denchfield NOT the same if our preconditioning matrix is updated between iterations. 536484c7b14SAdam Denchfield This same issue is found when considering dot products of the form g_{k+1}^T y_k. */ 53750b47da0SAdam Denchfield 53850b47da0SAdam Denchfield /* Compute CG step direction */ 53950b47da0SAdam Denchfield if (cg_restart) { 5409566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 541484c7b14SAdam Denchfield } else if (pcgd_fallback) { 542484c7b14SAdam Denchfield /* Just like preconditioned CG */ 5439566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5449566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 54550b47da0SAdam Denchfield } else if (ynorm2 > PETSC_MACHINE_EPSILON) { 54650b47da0SAdam Denchfield switch (cg->cg_type) { 547484c7b14SAdam Denchfield case CG_PCGradientDescent: 54850b47da0SAdam Denchfield if (!cg->diag_scaling) { 549484c7b14SAdam Denchfield if (!cg->no_scaling) { 55050b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 5519566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 552484c7b14SAdam Denchfield } else { 553484c7b14SAdam Denchfield tau_k = 1.0; 554484c7b14SAdam Denchfield ++cg->pure_gd_steps; 555484c7b14SAdam Denchfield } 5569566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient)); 55750b47da0SAdam Denchfield } else { 5589566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5599566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 56050b47da0SAdam Denchfield } 56150b47da0SAdam Denchfield break; 562484c7b14SAdam Denchfield 56350b47da0SAdam Denchfield case CG_HestenesStiefel: 56450b47da0SAdam Denchfield /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */ 56550b47da0SAdam Denchfield if (!cg->diag_scaling) { 56650b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 5679566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5689566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 56950b47da0SAdam Denchfield beta = tau_k*gkp1_yk/dk_yk; 5709566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 57150b47da0SAdam Denchfield } else { 5729566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5739566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 57450b47da0SAdam Denchfield beta = gkp1_yk/dk_yk; 5759566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 57650b47da0SAdam Denchfield } 577c8bcdf1eSAdam Denchfield break; 578484c7b14SAdam Denchfield 579c8bcdf1eSAdam Denchfield case CG_FletcherReeves: 5809566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5819566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5829566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 58350b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 5849566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 58550b47da0SAdam Denchfield if (!cg->diag_scaling) { 5869566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha)); 58750b47da0SAdam Denchfield beta = tau_k*gnorm2/gnorm2_old; 5889566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 58950b47da0SAdam Denchfield } else { 5909566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Before it's updated */ 5919566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5929566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, cg->g_work, &tmp)); 59350b47da0SAdam Denchfield beta = tmp/gnorm2_old; 5949566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 59550b47da0SAdam Denchfield } 596c8bcdf1eSAdam Denchfield break; 597484c7b14SAdam Denchfield 59850b47da0SAdam Denchfield case CG_PolakRibierePolyak: 59950b47da0SAdam Denchfield snorm = step*dnorm; 60050b47da0SAdam Denchfield if (!cg->diag_scaling) { 6019566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 6029566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6039566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 60450b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 6059566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 60650b47da0SAdam Denchfield } else { 6079566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); 6089566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6099566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 61050b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 6119566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 61250b47da0SAdam Denchfield } 613c8bcdf1eSAdam Denchfield break; 614484c7b14SAdam Denchfield 615c8bcdf1eSAdam Denchfield case CG_PolakRibierePlus: 6169566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 6179566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 61850b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 61950b47da0SAdam Denchfield if (!cg->diag_scaling) { 6209566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 6219566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6229566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 62350b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 62450b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 6259566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 62650b47da0SAdam Denchfield } else { 6279566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Old gtDg */ 6289566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6299566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 63050b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 63150b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 6329566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 63350b47da0SAdam Denchfield } 634c8bcdf1eSAdam Denchfield break; 635484c7b14SAdam Denchfield 636484c7b14SAdam Denchfield case CG_DaiYuan: 637484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property." 638484c7b14SAdam Denchfield SIAM Journal on optimization 10, no. 1 (1999): 177-182. */ 63950b47da0SAdam Denchfield if (!cg->diag_scaling) { 6409566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, tao->gradient, &gd)); 6419566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6429566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha)); 64350b47da0SAdam Denchfield beta = tau_k*gnorm2/(gd - gd_old); 6449566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 64550b47da0SAdam Denchfield } else { 6469566063dSJacob Faibussowitsch PetscCall(MatMult(cg->B, tao->stepdirection, cg->d_work)); 6479566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6489566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, tao->gradient, >Dg)); 6499566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->G_old, &gd_old)); 6509566063dSJacob Faibussowitsch PetscCall(VecDot(cg->d_work, cg->g_work, &dk_yk)); 65150b47da0SAdam Denchfield dk_yk = dk_yk - gd_old; 65250b47da0SAdam Denchfield beta = gtDg/dk_yk; 6539566063dSJacob Faibussowitsch PetscCall(VecScale(cg->d_work, beta)); 6549566063dSJacob Faibussowitsch PetscCall(VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work)); 65550b47da0SAdam Denchfield } 656c8bcdf1eSAdam Denchfield break; 657484c7b14SAdam Denchfield 658c8bcdf1eSAdam Denchfield case CG_HagerZhang: 659484c7b14SAdam Denchfield /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent." 660484c7b14SAdam Denchfield ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */ 6619566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6629566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6639566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 66450b47da0SAdam Denchfield snorm = dnorm*step; 66550b47da0SAdam Denchfield cg->yts = step*dk_yk; 666c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 6679566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 668c8bcdf1eSAdam Denchfield } 66950b47da0SAdam Denchfield if (cg->dynamic_restart) { 6709566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 671c8bcdf1eSAdam Denchfield } else { 672c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6739566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6749566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 675c8bcdf1eSAdam Denchfield /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */ 676c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 677c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)); 678c8bcdf1eSAdam Denchfield /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */ 67950b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 680c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6819566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 682c8bcdf1eSAdam Denchfield } else { 683c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 684c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 685c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 68650b47da0SAdam Denchfield /* Apply the diagonal scaling to all my vectors */ 6879566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6889566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6899566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 690c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 6919566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 692c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 693c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 6949566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 695c8bcdf1eSAdam Denchfield tau_k = -tau_k*gd/(dk_yk*dk_yk); 696c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 697484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */ 698c8bcdf1eSAdam Denchfield /* From HZ2013, modified to account for diagonal scaling*/ 6999566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 7009566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 70150b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 702c8bcdf1eSAdam Denchfield /* Do the update */ 7039566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 70450b47da0SAdam Denchfield } 70550b47da0SAdam Denchfield } 706c8bcdf1eSAdam Denchfield break; 707484c7b14SAdam Denchfield 708c8bcdf1eSAdam Denchfield case CG_DaiKou: 709484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search." 710484c7b14SAdam Denchfield SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */ 7119566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7129566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7139566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 71450b47da0SAdam Denchfield snorm = step*dnorm; 71550b47da0SAdam Denchfield cg->yts = dk_yk*step; 716c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7179566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7189566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 719c8bcdf1eSAdam Denchfield /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */ 720c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 72150b47da0SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk; 72250b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 723c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 7249566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk)); 725c8bcdf1eSAdam Denchfield } else { 726c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 727c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 728c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 7299566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7309566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 7319566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 732c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7339566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 7349566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 735c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 736c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 737c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 738484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk - step*tmp - tau_k; 739c8bcdf1eSAdam Denchfield /* Update this for the last term in beta */ 7409566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, tao->stepdirection, &dk_yk)); 741c8bcdf1eSAdam Denchfield beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */ 7429566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 7439566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 74450b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 745c8bcdf1eSAdam Denchfield /* Do the update */ 7469566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 74750b47da0SAdam Denchfield } 748c8bcdf1eSAdam Denchfield break; 749484c7b14SAdam Denchfield 750c8bcdf1eSAdam Denchfield case CG_KouDai: 751110fc3b0SBarry Smith /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization." 752484c7b14SAdam Denchfield Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */ 7539566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7549566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7559566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 75650b47da0SAdam Denchfield snorm = step*dnorm; 75750b47da0SAdam Denchfield cg->yts = dk_yk*step; 758c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 7599566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 760c8bcdf1eSAdam Denchfield } 76150b47da0SAdam Denchfield if (cg->dynamic_restart) { 7629566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 763c8bcdf1eSAdam Denchfield } else { 764c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7659566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7669566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 767c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 768c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */ 769c8bcdf1eSAdam Denchfield { 770c8bcdf1eSAdam Denchfield beta = cg->zeta*tau_k*gd/(dnorm*dnorm); 771c8bcdf1eSAdam Denchfield gamma = 0.0; 772c8bcdf1eSAdam Denchfield } else { 773c8bcdf1eSAdam Denchfield if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk; 774484c7b14SAdam Denchfield /* This seems to be very effective when there's no tau_k scaling. 775484c7b14SAdam Denchfield This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */ 77650b47da0SAdam Denchfield else { 77750b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 77850b47da0SAdam Denchfield } 779c8bcdf1eSAdam Denchfield } 780c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7819566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk)); 782c8bcdf1eSAdam Denchfield } else { 783c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 784c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 785c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 7869566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7879566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 788c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7899566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1D_yk)); 790c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 791c8bcdf1eSAdam Denchfield gamma = gd/dk_yk; 792c8bcdf1eSAdam Denchfield /* tau_k = -ytDy/(ytd)^2 * gd */ 7939566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 794c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 795c8bcdf1eSAdam Denchfield /* beta is the constant which adds the d_k contribution */ 796c8bcdf1eSAdam Denchfield beta = gkp1D_yk/dk_yk - step*gamma - tau_k; 797c8bcdf1eSAdam Denchfield /* Here is the requisite check */ 7989566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &tmp)); 799c8bcdf1eSAdam Denchfield if (cg->neg_xi) { 800c8bcdf1eSAdam Denchfield /* modified KD implementation */ 801c8bcdf1eSAdam Denchfield if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk; 80250b47da0SAdam Denchfield else { 80350b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 80450b47da0SAdam Denchfield } 805c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 806c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 807c8bcdf1eSAdam Denchfield gamma = 0.0; 808c8bcdf1eSAdam Denchfield } 809c8bcdf1eSAdam Denchfield } else { /* original KD 2015 implementation */ 810c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 811c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 812c8bcdf1eSAdam Denchfield gamma = 0.0; 813c8bcdf1eSAdam Denchfield } else { 814c8bcdf1eSAdam Denchfield gamma = cg->xi*gd/dk_yk; 815c8bcdf1eSAdam Denchfield } 816c8bcdf1eSAdam Denchfield } 817c8bcdf1eSAdam Denchfield /* Do the update in two steps */ 8189566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 8199566063dSJacob Faibussowitsch PetscCall(VecAXPY(tao->stepdirection, gamma, cg->y_work)); 82050b47da0SAdam Denchfield } 82150b47da0SAdam Denchfield } 822c8bcdf1eSAdam Denchfield break; 823484c7b14SAdam Denchfield 824484c7b14SAdam Denchfield case CG_SSML_BFGS: 825484c7b14SAdam Denchfield /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory." 826484c7b14SAdam Denchfield Discussion Papers 269 (1977). */ 8279566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8289566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 829484c7b14SAdam Denchfield snorm = step*dnorm; 830484c7b14SAdam Denchfield cg->yts = dk_yk*step; 831484c7b14SAdam Denchfield cg->yty = ynorm2; 832484c7b14SAdam Denchfield cg->sts = snorm*snorm; 833484c7b14SAdam Denchfield if (!cg->diag_scaling) { 8349566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 8359566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 836484c7b14SAdam Denchfield tmp = gd/dk_yk; 837484c7b14SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp; 838484c7b14SAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 8399566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk)); 840484c7b14SAdam Denchfield } else { 841484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 8429566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8439566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 844484c7b14SAdam Denchfield /* compute scalar gamma */ 8459566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8469566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 847484c7b14SAdam Denchfield gamma = gd/dk_yk; 848484c7b14SAdam Denchfield /* Compute scalar beta */ 849484c7b14SAdam Denchfield beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 850484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8519566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 852484c7b14SAdam Denchfield } 853484c7b14SAdam Denchfield break; 854484c7b14SAdam Denchfield 855484c7b14SAdam Denchfield case CG_SSML_DFP: 8569566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8579566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 858484c7b14SAdam Denchfield snorm = step*dnorm; 859484c7b14SAdam Denchfield cg->yts = dk_yk*step; 860484c7b14SAdam Denchfield cg->yty = ynorm2; 861484c7b14SAdam Denchfield cg->sts = snorm*snorm; 862484c7b14SAdam Denchfield if (!cg->diag_scaling) { 863484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8649566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 8659566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 866484c7b14SAdam Denchfield tau_k = cg->dfp_scale*tau_k; 867484c7b14SAdam Denchfield tmp = tau_k*gkp1_yk/cg->yty; 868484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 869484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8709566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 871484c7b14SAdam Denchfield } else { 872484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */ 8739566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8749566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 875484c7b14SAdam Denchfield /* compute scalar gamma */ 8769566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8779566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 878484c7b14SAdam Denchfield gamma = (gkp1_yk/tmp); 879484c7b14SAdam Denchfield /* Compute scalar beta */ 880484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 881484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8829566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 883484c7b14SAdam Denchfield } 884484c7b14SAdam Denchfield break; 885484c7b14SAdam Denchfield 886484c7b14SAdam Denchfield case CG_SSML_BROYDEN: 8879566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8889566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 889484c7b14SAdam Denchfield snorm = step*dnorm; 890484c7b14SAdam Denchfield cg->yts = step*dk_yk; 891484c7b14SAdam Denchfield cg->yty = ynorm2; 892484c7b14SAdam Denchfield cg->sts = snorm*snorm; 893484c7b14SAdam Denchfield if (!cg->diag_scaling) { 894484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8959566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale)); 8969566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale)); 8979566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 898484c7b14SAdam Denchfield tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp; 899484c7b14SAdam Denchfield /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, 900484c7b14SAdam Denchfield it should reproduce the tau_dfp scaling. Same with dfp_scale. */ 901484c7b14SAdam Denchfield tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/cg->yty; 902484c7b14SAdam Denchfield beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 903484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 9049566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 905484c7b14SAdam Denchfield } else { 906484c7b14SAdam Denchfield /* We have diagonal scaling enabled */ 9079566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 9089566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 909484c7b14SAdam Denchfield /* compute scalar gamma */ 9109566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 9119566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 912484c7b14SAdam Denchfield gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp); 913484c7b14SAdam Denchfield /* Compute scalar beta */ 914484c7b14SAdam Denchfield beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 915484c7b14SAdam Denchfield /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 9169566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 917484c7b14SAdam Denchfield } 918484c7b14SAdam Denchfield break; 919484c7b14SAdam Denchfield 920c8bcdf1eSAdam Denchfield default: 921c8bcdf1eSAdam Denchfield break; 922484c7b14SAdam Denchfield 923c8bcdf1eSAdam Denchfield } 924c8bcdf1eSAdam Denchfield } 925c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 926c8bcdf1eSAdam Denchfield } 927c8bcdf1eSAdam Denchfield 928c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm) 929c8bcdf1eSAdam Denchfield { 930c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 931c8bcdf1eSAdam Denchfield TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 9328ca2df50S PetscReal step=1.0,gnorm2,gd,dnorm=0.0; 933c8bcdf1eSAdam Denchfield PetscReal gnorm2_old,f_old,resnorm, gnorm_old; 934c624ebd3SAlp Dener PetscBool pcgd_fallback = PETSC_FALSE; 935c8bcdf1eSAdam Denchfield 936c8bcdf1eSAdam Denchfield PetscFunctionBegin; 937c8bcdf1eSAdam Denchfield /* We are now going to perform a line search along the direction. */ 938c8bcdf1eSAdam Denchfield /* Store solution and gradient info before it changes */ 9399566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, cg->X_old)); 9409566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->gradient, cg->G_old)); 9419566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old)); 942c8bcdf1eSAdam Denchfield 943c8bcdf1eSAdam Denchfield gnorm_old = gnorm; 944c8bcdf1eSAdam Denchfield gnorm2_old = gnorm_old*gnorm_old; 945c8bcdf1eSAdam Denchfield f_old = cg->f; 946484c7b14SAdam Denchfield /* Perform bounded line search. If we are recycling a solution from a previous */ 947484c7b14SAdam Denchfield /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */ 948414d97d3SAlp Dener if (!(tao->recycle && 0 == tao->niter)) { 949484c7b14SAdam Denchfield /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */ 9509566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9519566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9529566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 953c8bcdf1eSAdam Denchfield 954c8bcdf1eSAdam Denchfield /* Check linesearch failure */ 955c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 956c8bcdf1eSAdam Denchfield ++cg->ls_fails; 957c624ebd3SAlp Dener if (cg->cg_type == CG_GradientDescent) { 958c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 959c8bcdf1eSAdam Denchfield step = 0.0; 960c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 961c8bcdf1eSAdam Denchfield } else { 962484c7b14SAdam Denchfield /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */ 9639566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->X_old, tao->solution)); 9649566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->G_old, tao->gradient)); 9659566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient)); 966c8bcdf1eSAdam Denchfield gnorm = gnorm_old; 967c8bcdf1eSAdam Denchfield gnorm2 = gnorm2_old; 968c8bcdf1eSAdam Denchfield cg->f = f_old; 969c8bcdf1eSAdam Denchfield 970484c7b14SAdam Denchfield /* Fall back on preconditioned CG (so long as you're not already using it) */ 971484c7b14SAdam Denchfield if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling) { 972e2570530SAlp Dener pcgd_fallback = PETSC_TRUE; 9739566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 974484c7b14SAdam Denchfield 9759566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9769566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 977c8bcdf1eSAdam Denchfield 9789566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9799566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9809566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 981c8bcdf1eSAdam Denchfield 982484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 983484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 984484c7b14SAdam Denchfield /* Going to perform a regular gradient descent step. */ 985484c7b14SAdam Denchfield ++cg->ls_fails; 986484c7b14SAdam Denchfield step = 0.0; 987484c7b14SAdam Denchfield } 988484c7b14SAdam Denchfield } 989484c7b14SAdam Denchfield /* Fall back on the scaled gradient step */ 990484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 991484c7b14SAdam Denchfield ++cg->ls_fails; 9929566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9939566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 9949566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9959566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9969566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 997484c7b14SAdam Denchfield } 998484c7b14SAdam Denchfield 999c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 1000c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 100150b47da0SAdam Denchfield ++cg->ls_fails; 1002c8bcdf1eSAdam Denchfield step = 0.0; 1003c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 1004484c7b14SAdam Denchfield } else { 1005484c7b14SAdam Denchfield /* One of the fallbacks worked. Set them both back equal to false. */ 1006484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 1007c8bcdf1eSAdam Denchfield } 1008c8bcdf1eSAdam Denchfield } 1009c8bcdf1eSAdam Denchfield } 1010c8bcdf1eSAdam Denchfield /* Convergence test for line search failure */ 1011c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1012c8bcdf1eSAdam Denchfield 1013c8bcdf1eSAdam Denchfield /* Standard convergence test */ 10149566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 10159566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 10163c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 10179566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 10189566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 10199566063dSJacob Faibussowitsch PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP)); 1020c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1021484c7b14SAdam Denchfield } 1022c8bcdf1eSAdam Denchfield /* Assert we have an updated step and we need at least one more iteration. */ 1023c8bcdf1eSAdam Denchfield /* Calculate the next direction */ 1024c8bcdf1eSAdam Denchfield /* Estimate the active set at the new solution */ 10259566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 1026c8bcdf1eSAdam Denchfield /* Compute the projected gradient and its norm */ 10279566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 10289566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 10299566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient,NORM_2,&gnorm)); 1030c8bcdf1eSAdam Denchfield gnorm2 = gnorm*gnorm; 1031c8bcdf1eSAdam Denchfield 1032484c7b14SAdam Denchfield /* Calculate some quantities used in the StepDirectionUpdate. */ 10339566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 1034484c7b14SAdam Denchfield /* Update the step direction. */ 10359566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 1036484c7b14SAdam Denchfield ++tao->niter; 10379566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1038c8bcdf1eSAdam Denchfield 1039c8bcdf1eSAdam Denchfield if (cg->cg_type != CG_GradientDescent) { 1040c8bcdf1eSAdam Denchfield /* Figure out which previously active variables became inactive this iteration */ 10419566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 1042c8bcdf1eSAdam Denchfield if (cg->inactive_idx && cg->inactive_old) { 10439566063dSJacob Faibussowitsch PetscCall(ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives)); 1044c8bcdf1eSAdam Denchfield } 1045c8bcdf1eSAdam Denchfield /* Selectively reset the CG step those freshly inactive variables */ 1046c8bcdf1eSAdam Denchfield if (cg->new_inactives) { 10479566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10489566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 10499566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->inactive_grad, cg->inactive_step)); 10509566063dSJacob Faibussowitsch PetscCall(VecScale(cg->inactive_step, -1.0)); 10519566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10529566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 1053c8bcdf1eSAdam Denchfield } 1054c8bcdf1eSAdam Denchfield /* Verify that this is a descent direction */ 10559566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 10569566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 105750b47da0SAdam Denchfield if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) { 1058c8bcdf1eSAdam Denchfield /* Not a descent direction, so we reset back to projected gradient descent */ 10599566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 10609566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1061c8bcdf1eSAdam Denchfield ++cg->descent_error; 1062c8bcdf1eSAdam Denchfield } else { 1063c8bcdf1eSAdam Denchfield } 1064c8bcdf1eSAdam Denchfield } 1065ac9112b8SAlp Dener PetscFunctionReturn(0); 1066ac9112b8SAlp Dener } 1067484c7b14SAdam Denchfield 1068484c7b14SAdam Denchfield PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0) 1069484c7b14SAdam Denchfield { 1070484c7b14SAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 1071484c7b14SAdam Denchfield 1072484c7b14SAdam Denchfield PetscFunctionBegin; 10739566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)H0)); 1074484c7b14SAdam Denchfield cg->pc = H0; 1075484c7b14SAdam Denchfield PetscFunctionReturn(0); 1076484c7b14SAdam Denchfield } 1077