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)); 135e1e80dc8SAlp Dener } 1369566063dSJacob Faibussowitsch PetscCall(TaoBNCGConductIteration(tao, gnorm)); 137c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 138ac9112b8SAlp Dener } 139ac9112b8SAlp Dener } 140ac9112b8SAlp Dener 141ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao) 142ac9112b8SAlp Dener { 143ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 144ac9112b8SAlp Dener 145ac9112b8SAlp Dener PetscFunctionBegin; 146c4b75bccSAlp Dener if (!tao->gradient) { 1479566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->gradient)); 148c4b75bccSAlp Dener } 149c4b75bccSAlp Dener if (!tao->stepdirection) { 1509566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->stepdirection)); 151c4b75bccSAlp Dener } 152c4b75bccSAlp Dener if (!cg->W) { 1539566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->W)); 154c4b75bccSAlp Dener } 155c4b75bccSAlp Dener if (!cg->work) { 1569566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->work)); 157c4b75bccSAlp Dener } 158c8bcdf1eSAdam Denchfield if (!cg->sk) { 1599566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->sk)); 160c8bcdf1eSAdam Denchfield } 161c8bcdf1eSAdam Denchfield if (!cg->yk) { 1629566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->yk)); 163c8bcdf1eSAdam Denchfield } 164c4b75bccSAlp Dener if (!cg->X_old) { 1659566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->X_old)); 166c4b75bccSAlp Dener } 167c4b75bccSAlp Dener if (!cg->G_old) { 1689566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->G_old)); 169c8bcdf1eSAdam Denchfield } 170c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 1719566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->d_work)); 1729566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->y_work)); 1739566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->g_work)); 174c4b75bccSAlp Dener } 175c4b75bccSAlp Dener if (!cg->unprojected_gradient) { 1769566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient)); 177c4b75bccSAlp Dener } 178c4b75bccSAlp Dener if (!cg->unprojected_gradient_old) { 1799566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient_old)); 180c4b75bccSAlp Dener } 1819566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(cg->B, cg->sk, cg->yk)); 182484c7b14SAdam Denchfield if (cg->pc) { 1839566063dSJacob Faibussowitsch PetscCall(MatLMVMSetJ0(cg->B, cg->pc)); 184484c7b14SAdam Denchfield } 185ac9112b8SAlp Dener PetscFunctionReturn(0); 186ac9112b8SAlp Dener } 187ac9112b8SAlp Dener 188ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao) 189ac9112b8SAlp Dener { 190ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*) tao->data; 191ac9112b8SAlp Dener 192ac9112b8SAlp Dener PetscFunctionBegin; 193ac9112b8SAlp Dener if (tao->setupcalled) { 1949566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->W)); 1959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->work)); 1969566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->X_old)); 1979566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->G_old)); 1989566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient)); 1999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient_old)); 2009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->g_work)); 2019566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->d_work)); 2029566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->y_work)); 2039566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->sk)); 2049566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->yk)); 205ac9112b8SAlp Dener } 2069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_lower)); 2079566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_upper)); 2089566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_fixed)); 2099566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 2109566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 2119566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 2129566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 2139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->B)); 214484c7b14SAdam Denchfield if (cg->pc) { 2159566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->pc)); 216484c7b14SAdam Denchfield } 2179566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 218ac9112b8SAlp Dener PetscFunctionReturn(0); 219ac9112b8SAlp Dener } 220ac9112b8SAlp Dener 221ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao) 222ac9112b8SAlp Dener { 223ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 224ac9112b8SAlp Dener 225ac9112b8SAlp Dener PetscFunctionBegin; 226d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization"); 2279566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type,NULL)); 2288ebe3e4eSStefano Zampini if (cg->cg_type != CG_SSML_BFGS) cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */ 229484c7b14SAdam Denchfield if (CG_GradientDescent == cg->cg_type) { 230484c7b14SAdam Denchfield cg->cg_type = CG_PCGradientDescent; 231484c7b14SAdam Denchfield /* Set scaling equal to none or, at best, scalar scaling. */ 232484c7b14SAdam Denchfield cg->unscaled_restart = PETSC_TRUE; 233484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 234484c7b14SAdam Denchfield } 2359566063dSJacob 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)); 2369566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL)); 2379566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL)); 2389566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL)); 2399566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL)); 2409566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL)); 2419566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL)); 2429566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL)); 2439566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL)); 2449566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL)); 2459566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL)); 2469566063dSJacob 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)); 2479566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL)); 2489566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL)); 2499566063dSJacob 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)); 2509566063dSJacob 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)); 2519566063dSJacob 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)); 2529566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_no_scaling","Disable all scaling except in restarts","",cg->no_scaling,&cg->no_scaling,NULL)); 253484c7b14SAdam Denchfield if (cg->no_scaling) { 254484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 255484c7b14SAdam Denchfield cg->alpha = -1.0; 256484c7b14SAdam Denchfield } 257b474139fSKarl Rupp if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling) { /* Some more default options that appear to be good. */ 258484c7b14SAdam Denchfield cg->neg_xi = PETSC_TRUE; 259484c7b14SAdam Denchfield } 2609566063dSJacob 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)); 2619566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables","",cg->as_tol,&cg->as_tol,NULL)); 2629566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables","",cg->as_step,&cg->as_step,NULL)); 2639566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts","",cg->delta_min,&cg->delta_min,NULL)); 2649566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts","",cg->delta_max,&cg->delta_max,NULL)); 26550b47da0SAdam Denchfield 266d0609cedSBarry Smith PetscOptionsHeadEnd(); 2679566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(cg->B, ((PetscObject)tao)->prefix)); 2689566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(cg->B, "tao_bncg_")); 2699566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(cg->B)); 270ac9112b8SAlp Dener PetscFunctionReturn(0); 271ac9112b8SAlp Dener } 272ac9112b8SAlp Dener 273ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 274ac9112b8SAlp Dener { 275ac9112b8SAlp Dener PetscBool isascii; 276ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 277ac9112b8SAlp Dener 278ac9112b8SAlp Dener PetscFunctionBegin; 2799566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 280ac9112b8SAlp Dener if (isascii) { 2819566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 2829566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type])); 283*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %" PetscInt_FMT "\n", cg->skipped_updates)); 284*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", cg->resets)); 285*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %" PetscInt_FMT "\n", cg->pure_gd_steps)); 286*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not a descent direction: %" PetscInt_FMT "\n", cg->descent_error)); 287*63a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Line search fails: %" PetscInt_FMT "\n", cg->ls_fails)); 288484c7b14SAdam Denchfield if (cg->diag_scaling) { 2899566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii)); 290484c7b14SAdam Denchfield if (isascii) { 2919566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 2929566063dSJacob Faibussowitsch PetscCall(MatView(cg->B, viewer)); 2939566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 294484c7b14SAdam Denchfield } 295484c7b14SAdam Denchfield } 2969566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 297ac9112b8SAlp Dener } 298ac9112b8SAlp Dener PetscFunctionReturn(0); 299ac9112b8SAlp Dener } 300ac9112b8SAlp Dener 301c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha) 302c8bcdf1eSAdam Denchfield { 303c8bcdf1eSAdam Denchfield PetscReal a, b, c, sig1, sig2; 304c8bcdf1eSAdam Denchfield 305c8bcdf1eSAdam Denchfield PetscFunctionBegin; 306c8bcdf1eSAdam Denchfield *scale = 0.0; 3078ebe3e4eSStefano Zampini if (1.0 == alpha) *scale = yts/yty; 3088ebe3e4eSStefano Zampini else if (0.0 == alpha) *scale = sts/yts; 30950b47da0SAdam Denchfield else if (-1.0 == alpha) *scale = 1.0; 310c8bcdf1eSAdam Denchfield else { 311c8bcdf1eSAdam Denchfield a = yty; 312c8bcdf1eSAdam Denchfield b = yts; 313c8bcdf1eSAdam Denchfield c = sts; 314c8bcdf1eSAdam Denchfield a *= alpha; 315c8bcdf1eSAdam Denchfield b *= -(2.0*alpha - 1.0); 316c8bcdf1eSAdam Denchfield c *= alpha - 1.0; 317c8bcdf1eSAdam Denchfield sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 318c8bcdf1eSAdam Denchfield sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 319c8bcdf1eSAdam Denchfield /* accept the positive root as the scalar */ 3208ebe3e4eSStefano Zampini if (sig1 > 0.0) *scale = sig1; 3218ebe3e4eSStefano Zampini else if (sig2 > 0.0) *scale = sig2; 3228ebe3e4eSStefano Zampini else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar"); 323c8bcdf1eSAdam Denchfield } 324c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 325c8bcdf1eSAdam Denchfield } 326c8bcdf1eSAdam Denchfield 327ac9112b8SAlp Dener /*MC 328ac9112b8SAlp Dener TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 329ac9112b8SAlp Dener 330ac9112b8SAlp Dener Options Database Keys: 33150b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled) 332c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance 33361be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula 334c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method 335c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation 336c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation 33750b47da0SAdam 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. 33850b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method 33950b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34050b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34150b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method 34250b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method 34350b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method 34450b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method 34550b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True. 34650b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods 34750b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts 34850b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method 349484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps 350484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps 35150b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart 35250b47da0SAdam 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 35350b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations 354484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults. 3553850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions 356ac9112b8SAlp Dener 357ac9112b8SAlp Dener Notes: 358ac9112b8SAlp Dener CG formulas are: 3593850be85SAlp Dener + "gd" - Gradient Descent 3603850be85SAlp Dener . "fr" - Fletcher-Reeves 3613850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak 3623850be85SAlp Dener . "prp" - Polak-Ribiere-Plus 3633850be85SAlp Dener . "hs" - Hestenes-Steifel 3643850be85SAlp Dener . "dy" - Dai-Yuan 3653850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS 3663850be85SAlp Dener . "ssml_dfp" - Self-Scaling Memoryless DFP 3673850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden 3683850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3) 3693850be85SAlp Dener . "dk" - Dai-Kou (2013) 3703850be85SAlp Dener - "kd" - Kou-Dai (2015) 3719abc5736SPatrick Sanan 372ac9112b8SAlp Dener Level: beginner 373ac9112b8SAlp Dener M*/ 374ac9112b8SAlp Dener 375ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 376ac9112b8SAlp Dener { 377ac9112b8SAlp Dener TAO_BNCG *cg; 378ac9112b8SAlp Dener const char *morethuente_type = TAOLINESEARCHMT; 379ac9112b8SAlp Dener 380ac9112b8SAlp Dener PetscFunctionBegin; 381ac9112b8SAlp Dener tao->ops->setup = TaoSetUp_BNCG; 382ac9112b8SAlp Dener tao->ops->solve = TaoSolve_BNCG; 383ac9112b8SAlp Dener tao->ops->view = TaoView_BNCG; 384ac9112b8SAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 385ac9112b8SAlp Dener tao->ops->destroy = TaoDestroy_BNCG; 386ac9112b8SAlp Dener 387ac9112b8SAlp Dener /* Override default settings (unless already changed) */ 388ac9112b8SAlp Dener if (!tao->max_it_changed) tao->max_it = 2000; 389ac9112b8SAlp Dener if (!tao->max_funcs_changed) tao->max_funcs = 4000; 390ac9112b8SAlp Dener 391ac9112b8SAlp Dener /* Note: nondefault values should be used for nonlinear conjugate gradient */ 392ac9112b8SAlp Dener /* method. In particular, gtol should be less that 0.5; the value used in */ 393ac9112b8SAlp Dener /* Nocedal and Wright is 0.10. We use the default values for the */ 394ac9112b8SAlp Dener /* linesearch because it seems to work better. */ 3959566063dSJacob Faibussowitsch PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch)); 3969566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1)); 3979566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type)); 3989566063dSJacob Faibussowitsch PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao)); 399ac9112b8SAlp Dener 4009566063dSJacob Faibussowitsch PetscCall(PetscNewLog(tao,&cg)); 401ac9112b8SAlp Dener tao->data = (void*)cg; 4029566063dSJacob Faibussowitsch PetscCall(KSPInitializePackage()); 4039566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &cg->B)); 4049566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1)); 4059566063dSJacob Faibussowitsch PetscCall(MatSetType(cg->B, MATLMVMDIAGBROYDEN)); 40650b47da0SAdam Denchfield 407484c7b14SAdam Denchfield cg->pc = NULL; 408484c7b14SAdam Denchfield 40950b47da0SAdam Denchfield cg->dk_eta = 0.5; 41050b47da0SAdam Denchfield cg->hz_eta = 0.4; 411c8bcdf1eSAdam Denchfield cg->dynamic_restart = PETSC_FALSE; 412c8bcdf1eSAdam Denchfield cg->unscaled_restart = PETSC_FALSE; 413484c7b14SAdam Denchfield cg->no_scaling = PETSC_FALSE; 414484c7b14SAdam Denchfield cg->delta_min = 1e-7; 415484c7b14SAdam Denchfield cg->delta_max = 100; 416c8bcdf1eSAdam Denchfield cg->theta = 1.0; 417c8bcdf1eSAdam Denchfield cg->hz_theta = 1.0; 418c8bcdf1eSAdam Denchfield cg->dfp_scale = 1.0; 419c8bcdf1eSAdam Denchfield cg->bfgs_scale = 1.0; 42050b47da0SAdam Denchfield cg->zeta = 0.1; 42150b47da0SAdam Denchfield cg->min_quad = 6; 422c8bcdf1eSAdam Denchfield cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/ 423c8bcdf1eSAdam Denchfield cg->xi = 1.0; 42450b47da0SAdam Denchfield cg->neg_xi = PETSC_TRUE; 425c8bcdf1eSAdam Denchfield cg->spaced_restart = PETSC_FALSE; 426c8bcdf1eSAdam Denchfield cg->tol_quad = 1e-8; 42761be54a6SAlp Dener cg->as_step = 0.001; 42861be54a6SAlp Dener cg->as_tol = 0.001; 42950b47da0SAdam Denchfield cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/ 43061be54a6SAlp Dener cg->as_type = CG_AS_BERTSEKAS; 431c8bcdf1eSAdam Denchfield cg->cg_type = CG_SSML_BFGS; 432c8bcdf1eSAdam Denchfield cg->alpha = 1.0; 433c8bcdf1eSAdam Denchfield cg->diag_scaling = PETSC_TRUE; 434c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 435c8bcdf1eSAdam Denchfield } 436c8bcdf1eSAdam Denchfield 437c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq) 438c8bcdf1eSAdam Denchfield { 439c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 440c8bcdf1eSAdam Denchfield PetscReal scaling; 441c8bcdf1eSAdam Denchfield 442c8bcdf1eSAdam Denchfield PetscFunctionBegin; 443c8bcdf1eSAdam Denchfield ++cg->resets; 444c8bcdf1eSAdam Denchfield scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23); 445484c7b14SAdam Denchfield scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling)); 446484c7b14SAdam Denchfield if (cg->unscaled_restart) { 447484c7b14SAdam Denchfield scaling = 1.0; 448484c7b14SAdam Denchfield ++cg->pure_gd_steps; 449484c7b14SAdam Denchfield } 4509566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient)); 451c8bcdf1eSAdam Denchfield /* Also want to reset our diagonal scaling with each restart */ 452c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 4539566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(cg->B, PETSC_FALSE)); 454c8bcdf1eSAdam Denchfield } 455c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 456c8bcdf1eSAdam Denchfield } 457c8bcdf1eSAdam Denchfield 458c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold) 459c8bcdf1eSAdam Denchfield { 460c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 461c8bcdf1eSAdam Denchfield PetscReal quadinterp; 462c8bcdf1eSAdam Denchfield 463c8bcdf1eSAdam Denchfield PetscFunctionBegin; 46450b47da0SAdam Denchfield if (cg->f < cg->min_quad/10) { 46550b47da0SAdam Denchfield *dynrestart = PETSC_FALSE; 46650b47da0SAdam Denchfield PetscFunctionReturn(0); 46750b47da0SAdam Denchfield } /* just skip this since this strategy doesn't work well for functions near zero */ 468484c7b14SAdam Denchfield quadinterp = 2.0*(cg->f - fold)/(stepsize*(gd + gd_old)); 46950b47da0SAdam Denchfield if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad; 470c8bcdf1eSAdam Denchfield else { 471c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 472c8bcdf1eSAdam Denchfield *dynrestart = PETSC_FALSE; 473c8bcdf1eSAdam Denchfield } 474c8bcdf1eSAdam Denchfield if (cg->iter_quad >= cg->min_quad) { 475c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 476c8bcdf1eSAdam Denchfield *dynrestart = PETSC_TRUE; 477c8bcdf1eSAdam Denchfield } 478c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 479c8bcdf1eSAdam Denchfield } 480c8bcdf1eSAdam Denchfield 4818ca2df50S PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback) 48250b47da0SAdam Denchfield { 483c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 48450b47da0SAdam Denchfield PetscReal gamma = 1.0, tau_k, beta; 485484c7b14SAdam Denchfield PetscReal tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk=1.0, gd; 48650b47da0SAdam Denchfield PetscReal gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg; 487c8bcdf1eSAdam Denchfield PetscInt dim; 488484c7b14SAdam Denchfield PetscBool cg_restart = PETSC_FALSE; 489c8bcdf1eSAdam Denchfield PetscFunctionBegin; 490c8bcdf1eSAdam Denchfield 49150b47da0SAdam Denchfield /* Local curvature check to see if we need to restart */ 492414d97d3SAlp Dener if (tao->niter >= 1 || tao->recycle) { 4939566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 4949566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 495c8bcdf1eSAdam Denchfield ynorm2 = ynorm*ynorm; 4969566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 497484c7b14SAdam Denchfield if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON) { 498e2570530SAlp Dener cg_restart = PETSC_TRUE; 499484c7b14SAdam Denchfield ++cg->skipped_updates; 500484c7b14SAdam Denchfield } 50150b47da0SAdam Denchfield if (cg->spaced_restart) { 5029566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 503e2570530SAlp Dener if (tao->niter % (dim*cg->min_restart_num)) cg_restart = PETSC_TRUE; 50450b47da0SAdam Denchfield } 50550b47da0SAdam Denchfield } 50650b47da0SAdam Denchfield /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */ 50750b47da0SAdam Denchfield if (cg->spaced_restart) { 5089566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 509e2570530SAlp Dener if (0 == tao->niter % (6*dim)) cg_restart = PETSC_TRUE; 51050b47da0SAdam Denchfield } 51150b47da0SAdam Denchfield /* Compute the diagonal scaling vector if applicable */ 51250b47da0SAdam Denchfield if (cg->diag_scaling) { 5139566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(cg->B, tao->solution, tao->gradient)); 51450b47da0SAdam Denchfield } 51550b47da0SAdam Denchfield 516484c7b14SAdam Denchfield /* A note on diagonal scaling (to be added to paper): 517484c7b14SAdam Denchfield For the FR, PR, PRP, and DY methods, the diagonally scaled versions 518484c7b14SAdam Denchfield must be derived as a preconditioned CG method rather than as 519484c7b14SAdam Denchfield a Hessian initialization like in the Broyden methods. */ 52050b47da0SAdam Denchfield 521484c7b14SAdam Denchfield /* In that case, one writes the objective function as 522484c7b14SAdam Denchfield f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). 523484c7b14SAdam Denchfield Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to 524484c7b14SAdam Denchfield HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the 525484c7b14SAdam Denchfield same under preconditioning. Note that A is diagonal, such that A^T = A. */ 52650b47da0SAdam Denchfield 527484c7b14SAdam Denchfield /* This yields questions like what the dot product d_k^T y_k 528484c7b14SAdam Denchfield should look like. HZ mistakenly treats that as the same under 529484c7b14SAdam Denchfield preconditioning, but that is not necessarily true. */ 53050b47da0SAdam Denchfield 531484c7b14SAdam Denchfield /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 532484c7b14SAdam 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}), 533484c7b14SAdam 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 534484c7b14SAdam Denchfield NOT the same if our preconditioning matrix is updated between iterations. 535484c7b14SAdam Denchfield This same issue is found when considering dot products of the form g_{k+1}^T y_k. */ 53650b47da0SAdam Denchfield 53750b47da0SAdam Denchfield /* Compute CG step direction */ 53850b47da0SAdam Denchfield if (cg_restart) { 5399566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 540484c7b14SAdam Denchfield } else if (pcgd_fallback) { 541484c7b14SAdam Denchfield /* Just like preconditioned CG */ 5429566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5439566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 54450b47da0SAdam Denchfield } else if (ynorm2 > PETSC_MACHINE_EPSILON) { 54550b47da0SAdam Denchfield switch (cg->cg_type) { 546484c7b14SAdam Denchfield case CG_PCGradientDescent: 54750b47da0SAdam Denchfield if (!cg->diag_scaling) { 548484c7b14SAdam Denchfield if (!cg->no_scaling) { 54950b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 5509566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 551484c7b14SAdam Denchfield } else { 552484c7b14SAdam Denchfield tau_k = 1.0; 553484c7b14SAdam Denchfield ++cg->pure_gd_steps; 554484c7b14SAdam Denchfield } 5559566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient)); 55650b47da0SAdam Denchfield } else { 5579566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5589566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 55950b47da0SAdam Denchfield } 56050b47da0SAdam Denchfield break; 561484c7b14SAdam Denchfield 56250b47da0SAdam Denchfield case CG_HestenesStiefel: 56350b47da0SAdam Denchfield /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */ 56450b47da0SAdam Denchfield if (!cg->diag_scaling) { 56550b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 5669566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5679566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 56850b47da0SAdam Denchfield beta = tau_k*gkp1_yk/dk_yk; 5699566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 57050b47da0SAdam Denchfield } else { 5719566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5729566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 57350b47da0SAdam Denchfield beta = gkp1_yk/dk_yk; 5749566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 57550b47da0SAdam Denchfield } 576c8bcdf1eSAdam Denchfield break; 577484c7b14SAdam Denchfield 578c8bcdf1eSAdam Denchfield case CG_FletcherReeves: 5799566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5809566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5819566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 58250b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 5839566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 58450b47da0SAdam Denchfield if (!cg->diag_scaling) { 5859566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha)); 58650b47da0SAdam Denchfield beta = tau_k*gnorm2/gnorm2_old; 5879566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 58850b47da0SAdam Denchfield } else { 5899566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Before it's updated */ 5909566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5919566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, cg->g_work, &tmp)); 59250b47da0SAdam Denchfield beta = tmp/gnorm2_old; 5939566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 59450b47da0SAdam Denchfield } 595c8bcdf1eSAdam Denchfield break; 596484c7b14SAdam Denchfield 59750b47da0SAdam Denchfield case CG_PolakRibierePolyak: 59850b47da0SAdam Denchfield snorm = step*dnorm; 59950b47da0SAdam Denchfield if (!cg->diag_scaling) { 6009566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 6019566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6029566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 60350b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 6049566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 60550b47da0SAdam Denchfield } else { 6069566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); 6079566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6089566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 60950b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 6109566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 61150b47da0SAdam Denchfield } 612c8bcdf1eSAdam Denchfield break; 613484c7b14SAdam Denchfield 614c8bcdf1eSAdam Denchfield case CG_PolakRibierePlus: 6159566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 6169566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 61750b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 61850b47da0SAdam Denchfield if (!cg->diag_scaling) { 6199566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 6209566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6219566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 62250b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 62350b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 6249566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 62550b47da0SAdam Denchfield } else { 6269566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Old gtDg */ 6279566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6289566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 62950b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 63050b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 6319566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 63250b47da0SAdam Denchfield } 633c8bcdf1eSAdam Denchfield break; 634484c7b14SAdam Denchfield 635484c7b14SAdam Denchfield case CG_DaiYuan: 636484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property." 637484c7b14SAdam Denchfield SIAM Journal on optimization 10, no. 1 (1999): 177-182. */ 63850b47da0SAdam Denchfield if (!cg->diag_scaling) { 6399566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, tao->gradient, &gd)); 6409566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6419566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha)); 64250b47da0SAdam Denchfield beta = tau_k*gnorm2/(gd - gd_old); 6439566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 64450b47da0SAdam Denchfield } else { 6459566063dSJacob Faibussowitsch PetscCall(MatMult(cg->B, tao->stepdirection, cg->d_work)); 6469566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6479566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, tao->gradient, >Dg)); 6489566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->G_old, &gd_old)); 6499566063dSJacob Faibussowitsch PetscCall(VecDot(cg->d_work, cg->g_work, &dk_yk)); 65050b47da0SAdam Denchfield dk_yk = dk_yk - gd_old; 65150b47da0SAdam Denchfield beta = gtDg/dk_yk; 6529566063dSJacob Faibussowitsch PetscCall(VecScale(cg->d_work, beta)); 6539566063dSJacob Faibussowitsch PetscCall(VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work)); 65450b47da0SAdam Denchfield } 655c8bcdf1eSAdam Denchfield break; 656484c7b14SAdam Denchfield 657c8bcdf1eSAdam Denchfield case CG_HagerZhang: 658484c7b14SAdam Denchfield /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent." 659484c7b14SAdam Denchfield ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */ 6609566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6619566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6629566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 66350b47da0SAdam Denchfield snorm = dnorm*step; 66450b47da0SAdam Denchfield cg->yts = step*dk_yk; 665c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 6669566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 667c8bcdf1eSAdam Denchfield } 66850b47da0SAdam Denchfield if (cg->dynamic_restart) { 6699566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 670c8bcdf1eSAdam Denchfield } else { 671c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6729566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6739566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 674c8bcdf1eSAdam Denchfield /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */ 675c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 676c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)); 677c8bcdf1eSAdam Denchfield /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */ 67850b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 679c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6809566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 681c8bcdf1eSAdam Denchfield } else { 682c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 683c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 684c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 68550b47da0SAdam Denchfield /* Apply the diagonal scaling to all my vectors */ 6869566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6879566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6889566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 689c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 6909566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 691c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 692c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 6939566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 694c8bcdf1eSAdam Denchfield tau_k = -tau_k*gd/(dk_yk*dk_yk); 695c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 696484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */ 697c8bcdf1eSAdam Denchfield /* From HZ2013, modified to account for diagonal scaling*/ 6989566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 6999566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 70050b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 701c8bcdf1eSAdam Denchfield /* Do the update */ 7029566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 70350b47da0SAdam Denchfield } 70450b47da0SAdam Denchfield } 705c8bcdf1eSAdam Denchfield break; 706484c7b14SAdam Denchfield 707c8bcdf1eSAdam Denchfield case CG_DaiKou: 708484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search." 709484c7b14SAdam Denchfield SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */ 7109566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7119566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7129566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 71350b47da0SAdam Denchfield snorm = step*dnorm; 71450b47da0SAdam Denchfield cg->yts = dk_yk*step; 715c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7169566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7179566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 718c8bcdf1eSAdam Denchfield /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */ 719c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 72050b47da0SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk; 72150b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 722c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 7239566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk)); 724c8bcdf1eSAdam Denchfield } else { 725c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 726c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 727c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 7289566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7299566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 7309566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 731c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7329566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 7339566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 734c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 735c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 736c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 737484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk - step*tmp - tau_k; 738c8bcdf1eSAdam Denchfield /* Update this for the last term in beta */ 7399566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, tao->stepdirection, &dk_yk)); 740c8bcdf1eSAdam Denchfield beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */ 7419566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 7429566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 74350b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 744c8bcdf1eSAdam Denchfield /* Do the update */ 7459566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 74650b47da0SAdam Denchfield } 747c8bcdf1eSAdam Denchfield break; 748484c7b14SAdam Denchfield 749c8bcdf1eSAdam Denchfield case CG_KouDai: 750110fc3b0SBarry Smith /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization." 751484c7b14SAdam Denchfield Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */ 7529566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7539566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7549566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 75550b47da0SAdam Denchfield snorm = step*dnorm; 75650b47da0SAdam Denchfield cg->yts = dk_yk*step; 757c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 7589566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 759c8bcdf1eSAdam Denchfield } 76050b47da0SAdam Denchfield if (cg->dynamic_restart) { 7619566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 762c8bcdf1eSAdam Denchfield } else { 763c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7649566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7659566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 766c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 767c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */ 768c8bcdf1eSAdam Denchfield { 769c8bcdf1eSAdam Denchfield beta = cg->zeta*tau_k*gd/(dnorm*dnorm); 770c8bcdf1eSAdam Denchfield gamma = 0.0; 771c8bcdf1eSAdam Denchfield } else { 772c8bcdf1eSAdam Denchfield if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk; 773484c7b14SAdam Denchfield /* This seems to be very effective when there's no tau_k scaling. 774484c7b14SAdam Denchfield This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */ 77550b47da0SAdam Denchfield else { 77650b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 77750b47da0SAdam Denchfield } 778c8bcdf1eSAdam Denchfield } 779c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7809566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk)); 781c8bcdf1eSAdam Denchfield } else { 782c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 783c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 784c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 7859566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7869566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 787c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7889566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1D_yk)); 789c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 790c8bcdf1eSAdam Denchfield gamma = gd/dk_yk; 791c8bcdf1eSAdam Denchfield /* tau_k = -ytDy/(ytd)^2 * gd */ 7929566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 793c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 794c8bcdf1eSAdam Denchfield /* beta is the constant which adds the d_k contribution */ 795c8bcdf1eSAdam Denchfield beta = gkp1D_yk/dk_yk - step*gamma - tau_k; 796c8bcdf1eSAdam Denchfield /* Here is the requisite check */ 7979566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &tmp)); 798c8bcdf1eSAdam Denchfield if (cg->neg_xi) { 799c8bcdf1eSAdam Denchfield /* modified KD implementation */ 800c8bcdf1eSAdam Denchfield if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk; 80150b47da0SAdam Denchfield else { 80250b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 80350b47da0SAdam Denchfield } 804c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 805c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 806c8bcdf1eSAdam Denchfield gamma = 0.0; 807c8bcdf1eSAdam Denchfield } 808c8bcdf1eSAdam Denchfield } else { /* original KD 2015 implementation */ 809c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 810c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 811c8bcdf1eSAdam Denchfield gamma = 0.0; 812c8bcdf1eSAdam Denchfield } else { 813c8bcdf1eSAdam Denchfield gamma = cg->xi*gd/dk_yk; 814c8bcdf1eSAdam Denchfield } 815c8bcdf1eSAdam Denchfield } 816c8bcdf1eSAdam Denchfield /* Do the update in two steps */ 8179566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 8189566063dSJacob Faibussowitsch PetscCall(VecAXPY(tao->stepdirection, gamma, cg->y_work)); 81950b47da0SAdam Denchfield } 82050b47da0SAdam Denchfield } 821c8bcdf1eSAdam Denchfield break; 822484c7b14SAdam Denchfield 823484c7b14SAdam Denchfield case CG_SSML_BFGS: 824484c7b14SAdam Denchfield /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory." 825484c7b14SAdam Denchfield Discussion Papers 269 (1977). */ 8269566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8279566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 828484c7b14SAdam Denchfield snorm = step*dnorm; 829484c7b14SAdam Denchfield cg->yts = dk_yk*step; 830484c7b14SAdam Denchfield cg->yty = ynorm2; 831484c7b14SAdam Denchfield cg->sts = snorm*snorm; 832484c7b14SAdam Denchfield if (!cg->diag_scaling) { 8339566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 8349566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 835484c7b14SAdam Denchfield tmp = gd/dk_yk; 836484c7b14SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp; 837484c7b14SAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 8389566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk)); 839484c7b14SAdam Denchfield } else { 840484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 8419566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8429566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 843484c7b14SAdam Denchfield /* compute scalar gamma */ 8449566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8459566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 846484c7b14SAdam Denchfield gamma = gd/dk_yk; 847484c7b14SAdam Denchfield /* Compute scalar beta */ 848484c7b14SAdam Denchfield beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 849484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8509566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 851484c7b14SAdam Denchfield } 852484c7b14SAdam Denchfield break; 853484c7b14SAdam Denchfield 854484c7b14SAdam Denchfield case CG_SSML_DFP: 8559566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8569566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 857484c7b14SAdam Denchfield snorm = step*dnorm; 858484c7b14SAdam Denchfield cg->yts = dk_yk*step; 859484c7b14SAdam Denchfield cg->yty = ynorm2; 860484c7b14SAdam Denchfield cg->sts = snorm*snorm; 861484c7b14SAdam Denchfield if (!cg->diag_scaling) { 862484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8639566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 8649566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 865484c7b14SAdam Denchfield tau_k = cg->dfp_scale*tau_k; 866484c7b14SAdam Denchfield tmp = tau_k*gkp1_yk/cg->yty; 867484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 868484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8699566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 870484c7b14SAdam Denchfield } else { 871484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */ 8729566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8739566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 874484c7b14SAdam Denchfield /* compute scalar gamma */ 8759566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8769566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 877484c7b14SAdam Denchfield gamma = (gkp1_yk/tmp); 878484c7b14SAdam Denchfield /* Compute scalar beta */ 879484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 880484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8819566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 882484c7b14SAdam Denchfield } 883484c7b14SAdam Denchfield break; 884484c7b14SAdam Denchfield 885484c7b14SAdam Denchfield case CG_SSML_BROYDEN: 8869566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8879566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 888484c7b14SAdam Denchfield snorm = step*dnorm; 889484c7b14SAdam Denchfield cg->yts = step*dk_yk; 890484c7b14SAdam Denchfield cg->yty = ynorm2; 891484c7b14SAdam Denchfield cg->sts = snorm*snorm; 892484c7b14SAdam Denchfield if (!cg->diag_scaling) { 893484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8949566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale)); 8959566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale)); 8969566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 897484c7b14SAdam Denchfield tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp; 898484c7b14SAdam Denchfield /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, 899484c7b14SAdam Denchfield it should reproduce the tau_dfp scaling. Same with dfp_scale. */ 900484c7b14SAdam Denchfield tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/cg->yty; 901484c7b14SAdam Denchfield beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 902484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 9039566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 904484c7b14SAdam Denchfield } else { 905484c7b14SAdam Denchfield /* We have diagonal scaling enabled */ 9069566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 9079566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 908484c7b14SAdam Denchfield /* compute scalar gamma */ 9099566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 9109566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 911484c7b14SAdam Denchfield gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp); 912484c7b14SAdam Denchfield /* Compute scalar beta */ 913484c7b14SAdam Denchfield beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 914484c7b14SAdam Denchfield /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 9159566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 916484c7b14SAdam Denchfield } 917484c7b14SAdam Denchfield break; 918484c7b14SAdam Denchfield 919c8bcdf1eSAdam Denchfield default: 920c8bcdf1eSAdam Denchfield break; 921484c7b14SAdam Denchfield 922c8bcdf1eSAdam Denchfield } 923c8bcdf1eSAdam Denchfield } 924c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 925c8bcdf1eSAdam Denchfield } 926c8bcdf1eSAdam Denchfield 927c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm) 928c8bcdf1eSAdam Denchfield { 929c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 930c8bcdf1eSAdam Denchfield TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 9318ca2df50S PetscReal step=1.0,gnorm2,gd,dnorm=0.0; 932c8bcdf1eSAdam Denchfield PetscReal gnorm2_old,f_old,resnorm, gnorm_old; 933c624ebd3SAlp Dener PetscBool pcgd_fallback = PETSC_FALSE; 934c8bcdf1eSAdam Denchfield 935c8bcdf1eSAdam Denchfield PetscFunctionBegin; 936c8bcdf1eSAdam Denchfield /* We are now going to perform a line search along the direction. */ 937c8bcdf1eSAdam Denchfield /* Store solution and gradient info before it changes */ 9389566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, cg->X_old)); 9399566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->gradient, cg->G_old)); 9409566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old)); 941c8bcdf1eSAdam Denchfield 942c8bcdf1eSAdam Denchfield gnorm_old = gnorm; 943c8bcdf1eSAdam Denchfield gnorm2_old = gnorm_old*gnorm_old; 944c8bcdf1eSAdam Denchfield f_old = cg->f; 945484c7b14SAdam Denchfield /* Perform bounded line search. If we are recycling a solution from a previous */ 946484c7b14SAdam Denchfield /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */ 947414d97d3SAlp Dener if (!(tao->recycle && 0 == tao->niter)) { 948484c7b14SAdam Denchfield /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */ 9499566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9509566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9519566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 952c8bcdf1eSAdam Denchfield 953c8bcdf1eSAdam Denchfield /* Check linesearch failure */ 954c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 955c8bcdf1eSAdam Denchfield ++cg->ls_fails; 956c624ebd3SAlp Dener if (cg->cg_type == CG_GradientDescent) { 957c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 958c8bcdf1eSAdam Denchfield step = 0.0; 959c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 960c8bcdf1eSAdam Denchfield } else { 961484c7b14SAdam Denchfield /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */ 9629566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->X_old, tao->solution)); 9639566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->G_old, tao->gradient)); 9649566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient)); 965c8bcdf1eSAdam Denchfield gnorm = gnorm_old; 966c8bcdf1eSAdam Denchfield gnorm2 = gnorm2_old; 967c8bcdf1eSAdam Denchfield cg->f = f_old; 968c8bcdf1eSAdam Denchfield 969484c7b14SAdam Denchfield /* Fall back on preconditioned CG (so long as you're not already using it) */ 970484c7b14SAdam Denchfield if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling) { 971e2570530SAlp Dener pcgd_fallback = PETSC_TRUE; 9729566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 973484c7b14SAdam Denchfield 9749566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9759566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 976c8bcdf1eSAdam Denchfield 9779566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9789566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9799566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 980c8bcdf1eSAdam Denchfield 981484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 982484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 983484c7b14SAdam Denchfield /* Going to perform a regular gradient descent step. */ 984484c7b14SAdam Denchfield ++cg->ls_fails; 985484c7b14SAdam Denchfield step = 0.0; 986484c7b14SAdam Denchfield } 987484c7b14SAdam Denchfield } 988484c7b14SAdam Denchfield /* Fall back on the scaled gradient step */ 989484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 990484c7b14SAdam Denchfield ++cg->ls_fails; 9919566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9929566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 9939566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9949566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9959566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 996484c7b14SAdam Denchfield } 997484c7b14SAdam Denchfield 998c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 999c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 100050b47da0SAdam Denchfield ++cg->ls_fails; 1001c8bcdf1eSAdam Denchfield step = 0.0; 1002c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 1003484c7b14SAdam Denchfield } else { 1004484c7b14SAdam Denchfield /* One of the fallbacks worked. Set them both back equal to false. */ 1005484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 1006c8bcdf1eSAdam Denchfield } 1007c8bcdf1eSAdam Denchfield } 1008c8bcdf1eSAdam Denchfield } 1009c8bcdf1eSAdam Denchfield /* Convergence test for line search failure */ 1010c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1011c8bcdf1eSAdam Denchfield 1012c8bcdf1eSAdam Denchfield /* Standard convergence test */ 10139566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 10149566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 10153c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 10169566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 10179566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 10189566063dSJacob Faibussowitsch PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP)); 1019c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1020484c7b14SAdam Denchfield } 1021c8bcdf1eSAdam Denchfield /* Assert we have an updated step and we need at least one more iteration. */ 1022c8bcdf1eSAdam Denchfield /* Calculate the next direction */ 1023c8bcdf1eSAdam Denchfield /* Estimate the active set at the new solution */ 10249566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 1025c8bcdf1eSAdam Denchfield /* Compute the projected gradient and its norm */ 10269566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 10279566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 10289566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient,NORM_2,&gnorm)); 1029c8bcdf1eSAdam Denchfield gnorm2 = gnorm*gnorm; 1030c8bcdf1eSAdam Denchfield 1031484c7b14SAdam Denchfield /* Calculate some quantities used in the StepDirectionUpdate. */ 10329566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 1033484c7b14SAdam Denchfield /* Update the step direction. */ 10349566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 1035484c7b14SAdam Denchfield ++tao->niter; 10369566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1037c8bcdf1eSAdam Denchfield 1038c8bcdf1eSAdam Denchfield if (cg->cg_type != CG_GradientDescent) { 1039c8bcdf1eSAdam Denchfield /* Figure out which previously active variables became inactive this iteration */ 10409566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 1041c8bcdf1eSAdam Denchfield if (cg->inactive_idx && cg->inactive_old) { 10429566063dSJacob Faibussowitsch PetscCall(ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives)); 1043c8bcdf1eSAdam Denchfield } 1044c8bcdf1eSAdam Denchfield /* Selectively reset the CG step those freshly inactive variables */ 1045c8bcdf1eSAdam Denchfield if (cg->new_inactives) { 10469566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10479566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 10489566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->inactive_grad, cg->inactive_step)); 10499566063dSJacob Faibussowitsch PetscCall(VecScale(cg->inactive_step, -1.0)); 10509566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10519566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 1052c8bcdf1eSAdam Denchfield } 1053c8bcdf1eSAdam Denchfield /* Verify that this is a descent direction */ 10549566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 10559566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 105650b47da0SAdam Denchfield if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) { 1057c8bcdf1eSAdam Denchfield /* Not a descent direction, so we reset back to projected gradient descent */ 10589566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 10599566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1060c8bcdf1eSAdam Denchfield ++cg->descent_error; 1061c8bcdf1eSAdam Denchfield } else { 1062c8bcdf1eSAdam Denchfield } 1063c8bcdf1eSAdam Denchfield } 1064ac9112b8SAlp Dener PetscFunctionReturn(0); 1065ac9112b8SAlp Dener } 1066484c7b14SAdam Denchfield 1067484c7b14SAdam Denchfield PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0) 1068484c7b14SAdam Denchfield { 1069484c7b14SAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 1070484c7b14SAdam Denchfield 1071484c7b14SAdam Denchfield PetscFunctionBegin; 10729566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)H0)); 1073484c7b14SAdam Denchfield cg->pc = H0; 1074484c7b14SAdam Denchfield PetscFunctionReturn(0); 1075484c7b14SAdam Denchfield } 1076