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 PetscErrorCode ierr; 3161be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 3261be54a6SAlp Dener 3361be54a6SAlp Dener PetscFunctionBegin; 34*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 3561be54a6SAlp Dener if (cg->inactive_idx) { 36*9566063dSJacob Faibussowitsch PetscCall(ISDuplicate(cg->inactive_idx, &cg->inactive_old)); 37*9566063dSJacob Faibussowitsch PetscCall(ISCopy(cg->inactive_idx, cg->inactive_old)); 3861be54a6SAlp Dener } 3961be54a6SAlp Dener switch (asType) { 4061be54a6SAlp Dener case CG_AS_NONE: 41*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 42*9566063dSJacob Faibussowitsch PetscCall(VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx)); 43*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 44*9566063dSJacob Faibussowitsch PetscCall(ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx)); 4561be54a6SAlp Dener break; 4661be54a6SAlp Dener 4761be54a6SAlp Dener case CG_AS_BERTSEKAS: 4861be54a6SAlp Dener /* Use gradient descent to estimate the active set */ 49*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->W)); 50*9566063dSJacob Faibussowitsch PetscCall(VecScale(cg->W, -1.0)); 5189da521bSAlp Dener ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol, 52*9566063dSJacob Faibussowitsch &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx);PetscCall(ierr); 53c4b75bccSAlp Dener break; 5461be54a6SAlp Dener 5561be54a6SAlp Dener default: 5661be54a6SAlp Dener break; 5761be54a6SAlp Dener } 5861be54a6SAlp Dener PetscFunctionReturn(0); 5961be54a6SAlp Dener } 6061be54a6SAlp Dener 61a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step) 6261be54a6SAlp Dener { 6361be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 6461be54a6SAlp Dener 6561be54a6SAlp Dener PetscFunctionBegin; 66a1318120SAlp Dener switch (asType) { 6761be54a6SAlp Dener case CG_AS_NONE: 68*9566063dSJacob Faibussowitsch PetscCall(VecISSet(step, cg->active_idx, 0.0)); 6961be54a6SAlp Dener break; 7061be54a6SAlp Dener 7161be54a6SAlp Dener case CG_AS_BERTSEKAS: 72*9566063dSJacob Faibussowitsch PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step)); 7361be54a6SAlp Dener break; 7461be54a6SAlp Dener 7561be54a6SAlp Dener default: 7661be54a6SAlp Dener break; 7761be54a6SAlp Dener } 7861be54a6SAlp Dener PetscFunctionReturn(0); 7961be54a6SAlp Dener } 8061be54a6SAlp Dener 81ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao) 82ac9112b8SAlp Dener { 83ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 84484c7b14SAdam Denchfield PetscReal step=1.0,gnorm,gnorm2, resnorm; 85c4b75bccSAlp Dener PetscInt nDiff; 86ac9112b8SAlp Dener 87ac9112b8SAlp Dener PetscFunctionBegin; 88ac9112b8SAlp Dener /* Project the current point onto the feasible set */ 89*9566063dSJacob Faibussowitsch PetscCall(TaoComputeVariableBounds(tao)); 90*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU)); 91ac9112b8SAlp Dener 92c8bcdf1eSAdam Denchfield /* Project the initial point onto the feasible region */ 93*9566063dSJacob Faibussowitsch PetscCall(TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution)); 94484c7b14SAdam Denchfield 95414d97d3SAlp Dener if (nDiff > 0 || !tao->recycle) { 96*9566063dSJacob Faibussowitsch PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 97484c7b14SAdam Denchfield } 98*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->unprojected_gradient,NORM_2,&gnorm)); 993c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(cg->f) && !PetscIsInfOrNanReal(gnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 100ac9112b8SAlp Dener 10161be54a6SAlp Dener /* Estimate the active set and compute the projected gradient */ 102*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 10361be54a6SAlp Dener 104ac9112b8SAlp Dener /* Project the gradient and calculate the norm */ 105*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 106*9566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 107*9566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient,NORM_2,&gnorm)); 108ac9112b8SAlp Dener gnorm2 = gnorm*gnorm; 109ac9112b8SAlp Dener 110c8bcdf1eSAdam Denchfield /* Initialize counters */ 111e031d6f5SAlp Dener tao->niter = 0; 11250b47da0SAdam Denchfield cg->ls_fails = cg->descent_error = 0; 113c8bcdf1eSAdam Denchfield cg->resets = -1; 114484c7b14SAdam Denchfield cg->skipped_updates = cg->pure_gd_steps = 0; 115c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 116c8bcdf1eSAdam Denchfield 117c8bcdf1eSAdam Denchfield /* Convergence test at the starting point. */ 118ac9112b8SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 119484c7b14SAdam Denchfield 120*9566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 121*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 1223c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 123*9566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 124*9566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 125*9566063dSJacob Faibussowitsch PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP)); 126ac9112b8SAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 127484c7b14SAdam Denchfield /* Calculate initial direction. */ 128414d97d3SAlp Dener if (!tao->recycle) { 129484c7b14SAdam Denchfield /* We are not recycling a solution/history from a past TaoSolve */ 130*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 131ac9112b8SAlp Dener } 132c8bcdf1eSAdam Denchfield /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */ 133c8bcdf1eSAdam Denchfield while (1) { 134e1e80dc8SAlp Dener /* Call general purpose update function */ 135e1e80dc8SAlp Dener if (tao->ops->update) { 136*9566063dSJacob Faibussowitsch PetscCall((*tao->ops->update)(tao, tao->niter, tao->user_update)); 137e1e80dc8SAlp Dener } 138*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGConductIteration(tao, gnorm)); 139c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 140ac9112b8SAlp Dener } 141ac9112b8SAlp Dener } 142ac9112b8SAlp Dener 143ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao) 144ac9112b8SAlp Dener { 145ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 146ac9112b8SAlp Dener 147ac9112b8SAlp Dener PetscFunctionBegin; 148c4b75bccSAlp Dener if (!tao->gradient) { 149*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->gradient)); 150c4b75bccSAlp Dener } 151c4b75bccSAlp Dener if (!tao->stepdirection) { 152*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&tao->stepdirection)); 153c4b75bccSAlp Dener } 154c4b75bccSAlp Dener if (!cg->W) { 155*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->W)); 156c4b75bccSAlp Dener } 157c4b75bccSAlp Dener if (!cg->work) { 158*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->work)); 159c4b75bccSAlp Dener } 160c8bcdf1eSAdam Denchfield if (!cg->sk) { 161*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->sk)); 162c8bcdf1eSAdam Denchfield } 163c8bcdf1eSAdam Denchfield if (!cg->yk) { 164*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->yk)); 165c8bcdf1eSAdam Denchfield } 166c4b75bccSAlp Dener if (!cg->X_old) { 167*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->X_old)); 168c4b75bccSAlp Dener } 169c4b75bccSAlp Dener if (!cg->G_old) { 170*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->G_old)); 171c8bcdf1eSAdam Denchfield } 172c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 173*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->d_work)); 174*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->y_work)); 175*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution,&cg->g_work)); 176c4b75bccSAlp Dener } 177c4b75bccSAlp Dener if (!cg->unprojected_gradient) { 178*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient)); 179c4b75bccSAlp Dener } 180c4b75bccSAlp Dener if (!cg->unprojected_gradient_old) { 181*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->gradient,&cg->unprojected_gradient_old)); 182c4b75bccSAlp Dener } 183*9566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(cg->B, cg->sk, cg->yk)); 184484c7b14SAdam Denchfield if (cg->pc) { 185*9566063dSJacob Faibussowitsch PetscCall(MatLMVMSetJ0(cg->B, cg->pc)); 186484c7b14SAdam Denchfield } 187ac9112b8SAlp Dener PetscFunctionReturn(0); 188ac9112b8SAlp Dener } 189ac9112b8SAlp Dener 190ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao) 191ac9112b8SAlp Dener { 192ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*) tao->data; 193ac9112b8SAlp Dener 194ac9112b8SAlp Dener PetscFunctionBegin; 195ac9112b8SAlp Dener if (tao->setupcalled) { 196*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->W)); 197*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->work)); 198*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->X_old)); 199*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->G_old)); 200*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient)); 201*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient_old)); 202*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->g_work)); 203*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->d_work)); 204*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->y_work)); 205*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->sk)); 206*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->yk)); 207ac9112b8SAlp Dener } 208*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_lower)); 209*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_upper)); 210*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_fixed)); 211*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 212*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 213*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 214*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 215*9566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->B)); 216484c7b14SAdam Denchfield if (cg->pc) { 217*9566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->pc)); 218484c7b14SAdam Denchfield } 219*9566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 220ac9112b8SAlp Dener PetscFunctionReturn(0); 221ac9112b8SAlp Dener } 222ac9112b8SAlp Dener 223ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao) 224ac9112b8SAlp Dener { 225ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 226ac9112b8SAlp Dener 227ac9112b8SAlp Dener PetscFunctionBegin; 228*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization")); 229*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type,NULL)); 2308ebe3e4eSStefano Zampini if (cg->cg_type != CG_SSML_BFGS) cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */ 231484c7b14SAdam Denchfield if (CG_GradientDescent == cg->cg_type) { 232484c7b14SAdam Denchfield cg->cg_type = CG_PCGradientDescent; 233484c7b14SAdam Denchfield /* Set scaling equal to none or, at best, scalar scaling. */ 234484c7b14SAdam Denchfield cg->unscaled_restart = PETSC_TRUE; 235484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 236484c7b14SAdam Denchfield } 237*9566063dSJacob 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)); 238*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_eta","(developer) cutoff tolerance for HZ", "", cg->hz_eta,&cg->hz_eta,NULL)); 239*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_eps","(developer) cutoff value for restarts", "", cg->epsilon,&cg->epsilon,NULL)); 240*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dk_eta","(developer) cutoff tolerance for DK", "", cg->dk_eta,&cg->dk_eta,NULL)); 241*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_xi","(developer) Parameter in the KD method", "", cg->xi,&cg->xi,NULL)); 242*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL)); 243*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL)); 244*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_alpha","(developer) parameter for the scalar scaling","",cg->alpha,&cg->alpha,NULL)); 245*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL)); 246*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL)); 247*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_diag_scaling","Enable diagonal Broyden-like preconditioning","",cg->diag_scaling,&cg->diag_scaling,NULL)); 248*9566063dSJacob 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)); 249*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_unscaled_restart","(developer) use unscaled gradient restarts","",cg->unscaled_restart,&cg->unscaled_restart,NULL)); 250*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL)); 251*9566063dSJacob 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)); 252*9566063dSJacob 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)); 253*9566063dSJacob 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)); 254*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_no_scaling","Disable all scaling except in restarts","",cg->no_scaling,&cg->no_scaling,NULL)); 255484c7b14SAdam Denchfield if (cg->no_scaling) { 256484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 257484c7b14SAdam Denchfield cg->alpha = -1.0; 258484c7b14SAdam Denchfield } 259b474139fSKarl Rupp if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling) { /* Some more default options that appear to be good. */ 260484c7b14SAdam Denchfield cg->neg_xi = PETSC_TRUE; 261484c7b14SAdam Denchfield } 262*9566063dSJacob 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)); 263*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables","",cg->as_tol,&cg->as_tol,NULL)); 264*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables","",cg->as_step,&cg->as_step,NULL)); 265*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts","",cg->delta_min,&cg->delta_min,NULL)); 266*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts","",cg->delta_max,&cg->delta_max,NULL)); 26750b47da0SAdam Denchfield 268*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsTail()); 269*9566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(cg->B, ((PetscObject)tao)->prefix)); 270*9566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(cg->B, "tao_bncg_")); 271*9566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(cg->B)); 272ac9112b8SAlp Dener PetscFunctionReturn(0); 273ac9112b8SAlp Dener } 274ac9112b8SAlp Dener 275ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 276ac9112b8SAlp Dener { 277ac9112b8SAlp Dener PetscBool isascii; 278ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG*)tao->data; 279ac9112b8SAlp Dener 280ac9112b8SAlp Dener PetscFunctionBegin; 281*9566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 282ac9112b8SAlp Dener if (isascii) { 283*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 284*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type])); 285*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %i\n", cg->skipped_updates)); 286*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %i\n", cg->resets)); 287*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %i\n", cg->pure_gd_steps)); 288*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not a descent direction: %i\n", cg->descent_error)); 289*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails)); 290484c7b14SAdam Denchfield if (cg->diag_scaling) { 291*9566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii)); 292484c7b14SAdam Denchfield if (isascii) { 293*9566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 294*9566063dSJacob Faibussowitsch PetscCall(MatView(cg->B, viewer)); 295*9566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 296484c7b14SAdam Denchfield } 297484c7b14SAdam Denchfield } 298*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 299ac9112b8SAlp Dener } 300ac9112b8SAlp Dener PetscFunctionReturn(0); 301ac9112b8SAlp Dener } 302ac9112b8SAlp Dener 303c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha) 304c8bcdf1eSAdam Denchfield { 305c8bcdf1eSAdam Denchfield PetscReal a, b, c, sig1, sig2; 306c8bcdf1eSAdam Denchfield 307c8bcdf1eSAdam Denchfield PetscFunctionBegin; 308c8bcdf1eSAdam Denchfield *scale = 0.0; 3098ebe3e4eSStefano Zampini if (1.0 == alpha) *scale = yts/yty; 3108ebe3e4eSStefano Zampini else if (0.0 == alpha) *scale = sts/yts; 31150b47da0SAdam Denchfield else if (-1.0 == alpha) *scale = 1.0; 312c8bcdf1eSAdam Denchfield else { 313c8bcdf1eSAdam Denchfield a = yty; 314c8bcdf1eSAdam Denchfield b = yts; 315c8bcdf1eSAdam Denchfield c = sts; 316c8bcdf1eSAdam Denchfield a *= alpha; 317c8bcdf1eSAdam Denchfield b *= -(2.0*alpha - 1.0); 318c8bcdf1eSAdam Denchfield c *= alpha - 1.0; 319c8bcdf1eSAdam Denchfield sig1 = (-b + PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 320c8bcdf1eSAdam Denchfield sig2 = (-b - PetscSqrtReal(b*b - 4.0*a*c))/(2.0*a); 321c8bcdf1eSAdam Denchfield /* accept the positive root as the scalar */ 3228ebe3e4eSStefano Zampini if (sig1 > 0.0) *scale = sig1; 3238ebe3e4eSStefano Zampini else if (sig2 > 0.0) *scale = sig2; 3248ebe3e4eSStefano Zampini else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar"); 325c8bcdf1eSAdam Denchfield } 326c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 327c8bcdf1eSAdam Denchfield } 328c8bcdf1eSAdam Denchfield 329ac9112b8SAlp Dener /*MC 330ac9112b8SAlp Dener TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 331ac9112b8SAlp Dener 332ac9112b8SAlp Dener Options Database Keys: 33350b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled) 334c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance 33561be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula 336c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method 337c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation 338c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation 33950b47da0SAdam 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. 34050b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method 34150b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34250b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 34350b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method 34450b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method 34550b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method 34650b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method 34750b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True. 34850b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods 34950b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts 35050b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method 351484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps 352484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps 35350b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart 35450b47da0SAdam 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 35550b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations 356484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults. 3573850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions 358ac9112b8SAlp Dener 359ac9112b8SAlp Dener Notes: 360ac9112b8SAlp Dener CG formulas are: 3613850be85SAlp Dener + "gd" - Gradient Descent 3623850be85SAlp Dener . "fr" - Fletcher-Reeves 3633850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak 3643850be85SAlp Dener . "prp" - Polak-Ribiere-Plus 3653850be85SAlp Dener . "hs" - Hestenes-Steifel 3663850be85SAlp Dener . "dy" - Dai-Yuan 3673850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS 3683850be85SAlp Dener . "ssml_dfp" - Self-Scaling Memoryless DFP 3693850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden 3703850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3) 3713850be85SAlp Dener . "dk" - Dai-Kou (2013) 3723850be85SAlp Dener - "kd" - Kou-Dai (2015) 3739abc5736SPatrick Sanan 374ac9112b8SAlp Dener Level: beginner 375ac9112b8SAlp Dener M*/ 376ac9112b8SAlp Dener 377ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 378ac9112b8SAlp Dener { 379ac9112b8SAlp Dener TAO_BNCG *cg; 380ac9112b8SAlp Dener const char *morethuente_type = TAOLINESEARCHMT; 381ac9112b8SAlp Dener 382ac9112b8SAlp Dener PetscFunctionBegin; 383ac9112b8SAlp Dener tao->ops->setup = TaoSetUp_BNCG; 384ac9112b8SAlp Dener tao->ops->solve = TaoSolve_BNCG; 385ac9112b8SAlp Dener tao->ops->view = TaoView_BNCG; 386ac9112b8SAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 387ac9112b8SAlp Dener tao->ops->destroy = TaoDestroy_BNCG; 388ac9112b8SAlp Dener 389ac9112b8SAlp Dener /* Override default settings (unless already changed) */ 390ac9112b8SAlp Dener if (!tao->max_it_changed) tao->max_it = 2000; 391ac9112b8SAlp Dener if (!tao->max_funcs_changed) tao->max_funcs = 4000; 392ac9112b8SAlp Dener 393ac9112b8SAlp Dener /* Note: nondefault values should be used for nonlinear conjugate gradient */ 394ac9112b8SAlp Dener /* method. In particular, gtol should be less that 0.5; the value used in */ 395ac9112b8SAlp Dener /* Nocedal and Wright is 0.10. We use the default values for the */ 396ac9112b8SAlp Dener /* linesearch because it seems to work better. */ 397*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch)); 398*9566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1)); 399*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type)); 400*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao)); 401ac9112b8SAlp Dener 402*9566063dSJacob Faibussowitsch PetscCall(PetscNewLog(tao,&cg)); 403ac9112b8SAlp Dener tao->data = (void*)cg; 404*9566063dSJacob Faibussowitsch PetscCall(KSPInitializePackage()); 405*9566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &cg->B)); 406*9566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1)); 407*9566063dSJacob Faibussowitsch PetscCall(MatSetType(cg->B, MATLMVMDIAGBROYDEN)); 40850b47da0SAdam Denchfield 409484c7b14SAdam Denchfield cg->pc = NULL; 410484c7b14SAdam Denchfield 41150b47da0SAdam Denchfield cg->dk_eta = 0.5; 41250b47da0SAdam Denchfield cg->hz_eta = 0.4; 413c8bcdf1eSAdam Denchfield cg->dynamic_restart = PETSC_FALSE; 414c8bcdf1eSAdam Denchfield cg->unscaled_restart = PETSC_FALSE; 415484c7b14SAdam Denchfield cg->no_scaling = PETSC_FALSE; 416484c7b14SAdam Denchfield cg->delta_min = 1e-7; 417484c7b14SAdam Denchfield cg->delta_max = 100; 418c8bcdf1eSAdam Denchfield cg->theta = 1.0; 419c8bcdf1eSAdam Denchfield cg->hz_theta = 1.0; 420c8bcdf1eSAdam Denchfield cg->dfp_scale = 1.0; 421c8bcdf1eSAdam Denchfield cg->bfgs_scale = 1.0; 42250b47da0SAdam Denchfield cg->zeta = 0.1; 42350b47da0SAdam Denchfield cg->min_quad = 6; 424c8bcdf1eSAdam Denchfield cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/ 425c8bcdf1eSAdam Denchfield cg->xi = 1.0; 42650b47da0SAdam Denchfield cg->neg_xi = PETSC_TRUE; 427c8bcdf1eSAdam Denchfield cg->spaced_restart = PETSC_FALSE; 428c8bcdf1eSAdam Denchfield cg->tol_quad = 1e-8; 42961be54a6SAlp Dener cg->as_step = 0.001; 43061be54a6SAlp Dener cg->as_tol = 0.001; 43150b47da0SAdam Denchfield cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0); /* Just a little tighter*/ 43261be54a6SAlp Dener cg->as_type = CG_AS_BERTSEKAS; 433c8bcdf1eSAdam Denchfield cg->cg_type = CG_SSML_BFGS; 434c8bcdf1eSAdam Denchfield cg->alpha = 1.0; 435c8bcdf1eSAdam Denchfield cg->diag_scaling = PETSC_TRUE; 436c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 437c8bcdf1eSAdam Denchfield } 438c8bcdf1eSAdam Denchfield 439c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq) 440c8bcdf1eSAdam Denchfield { 441c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 442c8bcdf1eSAdam Denchfield PetscReal scaling; 443c8bcdf1eSAdam Denchfield 444c8bcdf1eSAdam Denchfield PetscFunctionBegin; 445c8bcdf1eSAdam Denchfield ++cg->resets; 446c8bcdf1eSAdam Denchfield scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23); 447484c7b14SAdam Denchfield scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling)); 448484c7b14SAdam Denchfield if (cg->unscaled_restart) { 449484c7b14SAdam Denchfield scaling = 1.0; 450484c7b14SAdam Denchfield ++cg->pure_gd_steps; 451484c7b14SAdam Denchfield } 452*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient)); 453c8bcdf1eSAdam Denchfield /* Also want to reset our diagonal scaling with each restart */ 454c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 455*9566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(cg->B, PETSC_FALSE)); 456c8bcdf1eSAdam Denchfield } 457c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 458c8bcdf1eSAdam Denchfield } 459c8bcdf1eSAdam Denchfield 460c8bcdf1eSAdam Denchfield PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold) 461c8bcdf1eSAdam Denchfield { 462c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 463c8bcdf1eSAdam Denchfield PetscReal quadinterp; 464c8bcdf1eSAdam Denchfield 465c8bcdf1eSAdam Denchfield PetscFunctionBegin; 46650b47da0SAdam Denchfield if (cg->f < cg->min_quad/10) { 46750b47da0SAdam Denchfield *dynrestart = PETSC_FALSE; 46850b47da0SAdam Denchfield PetscFunctionReturn(0); 46950b47da0SAdam Denchfield } /* just skip this since this strategy doesn't work well for functions near zero */ 470484c7b14SAdam Denchfield quadinterp = 2.0*(cg->f - fold)/(stepsize*(gd + gd_old)); 47150b47da0SAdam Denchfield if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad; 472c8bcdf1eSAdam Denchfield else { 473c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 474c8bcdf1eSAdam Denchfield *dynrestart = PETSC_FALSE; 475c8bcdf1eSAdam Denchfield } 476c8bcdf1eSAdam Denchfield if (cg->iter_quad >= cg->min_quad) { 477c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 478c8bcdf1eSAdam Denchfield *dynrestart = PETSC_TRUE; 479c8bcdf1eSAdam Denchfield } 480c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 481c8bcdf1eSAdam Denchfield } 482c8bcdf1eSAdam Denchfield 4838ca2df50S PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback) 48450b47da0SAdam Denchfield { 485c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 48650b47da0SAdam Denchfield PetscReal gamma = 1.0, tau_k, beta; 487484c7b14SAdam Denchfield PetscReal tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk=1.0, gd; 48850b47da0SAdam Denchfield PetscReal gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg; 489c8bcdf1eSAdam Denchfield PetscInt dim; 490484c7b14SAdam Denchfield PetscBool cg_restart = PETSC_FALSE; 491c8bcdf1eSAdam Denchfield PetscFunctionBegin; 492c8bcdf1eSAdam Denchfield 49350b47da0SAdam Denchfield /* Local curvature check to see if we need to restart */ 494414d97d3SAlp Dener if (tao->niter >= 1 || tao->recycle) { 495*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 496*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 497c8bcdf1eSAdam Denchfield ynorm2 = ynorm*ynorm; 498*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 499484c7b14SAdam Denchfield if (step*dnorm < PETSC_MACHINE_EPSILON || step*dk_yk < PETSC_MACHINE_EPSILON) { 500e2570530SAlp Dener cg_restart = PETSC_TRUE; 501484c7b14SAdam Denchfield ++cg->skipped_updates; 502484c7b14SAdam Denchfield } 50350b47da0SAdam Denchfield if (cg->spaced_restart) { 504*9566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 505e2570530SAlp Dener if (tao->niter % (dim*cg->min_restart_num)) cg_restart = PETSC_TRUE; 50650b47da0SAdam Denchfield } 50750b47da0SAdam Denchfield } 50850b47da0SAdam Denchfield /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */ 50950b47da0SAdam Denchfield if (cg->spaced_restart) { 510*9566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 511e2570530SAlp Dener if (0 == tao->niter % (6*dim)) cg_restart = PETSC_TRUE; 51250b47da0SAdam Denchfield } 51350b47da0SAdam Denchfield /* Compute the diagonal scaling vector if applicable */ 51450b47da0SAdam Denchfield if (cg->diag_scaling) { 515*9566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(cg->B, tao->solution, tao->gradient)); 51650b47da0SAdam Denchfield } 51750b47da0SAdam Denchfield 518484c7b14SAdam Denchfield /* A note on diagonal scaling (to be added to paper): 519484c7b14SAdam Denchfield For the FR, PR, PRP, and DY methods, the diagonally scaled versions 520484c7b14SAdam Denchfield must be derived as a preconditioned CG method rather than as 521484c7b14SAdam Denchfield a Hessian initialization like in the Broyden methods. */ 52250b47da0SAdam Denchfield 523484c7b14SAdam Denchfield /* In that case, one writes the objective function as 524484c7b14SAdam Denchfield f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). 525484c7b14SAdam Denchfield Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to 526484c7b14SAdam Denchfield HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the 527484c7b14SAdam Denchfield same under preconditioning. Note that A is diagonal, such that A^T = A. */ 52850b47da0SAdam Denchfield 529484c7b14SAdam Denchfield /* This yields questions like what the dot product d_k^T y_k 530484c7b14SAdam Denchfield should look like. HZ mistakenly treats that as the same under 531484c7b14SAdam Denchfield preconditioning, but that is not necessarily true. */ 53250b47da0SAdam Denchfield 533484c7b14SAdam Denchfield /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 534484c7b14SAdam 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}), 535484c7b14SAdam 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 536484c7b14SAdam Denchfield NOT the same if our preconditioning matrix is updated between iterations. 537484c7b14SAdam Denchfield This same issue is found when considering dot products of the form g_{k+1}^T y_k. */ 53850b47da0SAdam Denchfield 53950b47da0SAdam Denchfield /* Compute CG step direction */ 54050b47da0SAdam Denchfield if (cg_restart) { 541*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 542484c7b14SAdam Denchfield } else if (pcgd_fallback) { 543484c7b14SAdam Denchfield /* Just like preconditioned CG */ 544*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 545*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 54650b47da0SAdam Denchfield } else if (ynorm2 > PETSC_MACHINE_EPSILON) { 54750b47da0SAdam Denchfield switch (cg->cg_type) { 548484c7b14SAdam Denchfield case CG_PCGradientDescent: 54950b47da0SAdam Denchfield if (!cg->diag_scaling) { 550484c7b14SAdam Denchfield if (!cg->no_scaling) { 55150b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 552*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 553484c7b14SAdam Denchfield } else { 554484c7b14SAdam Denchfield tau_k = 1.0; 555484c7b14SAdam Denchfield ++cg->pure_gd_steps; 556484c7b14SAdam Denchfield } 557*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient)); 55850b47da0SAdam Denchfield } else { 559*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 560*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 56150b47da0SAdam Denchfield } 56250b47da0SAdam Denchfield break; 563484c7b14SAdam Denchfield 56450b47da0SAdam Denchfield case CG_HestenesStiefel: 56550b47da0SAdam Denchfield /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */ 56650b47da0SAdam Denchfield if (!cg->diag_scaling) { 56750b47da0SAdam Denchfield cg->sts = step*step*dnorm*dnorm; 568*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 569*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->sts, &tau_k, cg->alpha)); 57050b47da0SAdam Denchfield beta = tau_k*gkp1_yk/dk_yk; 571*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 57250b47da0SAdam Denchfield } else { 573*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 574*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 57550b47da0SAdam Denchfield beta = gkp1_yk/dk_yk; 576*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 57750b47da0SAdam Denchfield } 578c8bcdf1eSAdam Denchfield break; 579484c7b14SAdam Denchfield 580c8bcdf1eSAdam Denchfield case CG_FletcherReeves: 581*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 582*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 583*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 58450b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 585*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 58650b47da0SAdam Denchfield if (!cg->diag_scaling) { 587*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, step*step*dnorm*dnorm, &tau_k, cg->alpha)); 58850b47da0SAdam Denchfield beta = tau_k*gnorm2/gnorm2_old; 589*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 59050b47da0SAdam Denchfield } else { 591*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Before it's updated */ 592*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 593*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, cg->g_work, &tmp)); 59450b47da0SAdam Denchfield beta = tmp/gnorm2_old; 595*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 59650b47da0SAdam Denchfield } 597c8bcdf1eSAdam Denchfield break; 598484c7b14SAdam Denchfield 59950b47da0SAdam Denchfield case CG_PolakRibierePolyak: 60050b47da0SAdam Denchfield snorm = step*dnorm; 60150b47da0SAdam Denchfield if (!cg->diag_scaling) { 602*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 603*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 604*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 60550b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 606*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 60750b47da0SAdam Denchfield } else { 608*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); 609*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 610*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 61150b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 612*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 61350b47da0SAdam Denchfield } 614c8bcdf1eSAdam Denchfield break; 615484c7b14SAdam Denchfield 616c8bcdf1eSAdam Denchfield case CG_PolakRibierePlus: 617*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 618*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 61950b47da0SAdam Denchfield ynorm2 = ynorm*ynorm; 62050b47da0SAdam Denchfield if (!cg->diag_scaling) { 621*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 622*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 623*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, snorm*snorm, &tau_k, cg->alpha)); 62450b47da0SAdam Denchfield beta = tau_k*gkp1_yk/gnorm2_old; 62550b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 626*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 62750b47da0SAdam Denchfield } else { 628*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Old gtDg */ 629*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 630*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 63150b47da0SAdam Denchfield beta = gkp1_yk/gnorm2_old; 63250b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 633*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 63450b47da0SAdam Denchfield } 635c8bcdf1eSAdam Denchfield break; 636484c7b14SAdam Denchfield 637484c7b14SAdam Denchfield case CG_DaiYuan: 638484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property." 639484c7b14SAdam Denchfield SIAM Journal on optimization 10, no. 1 (1999): 177-182. */ 64050b47da0SAdam Denchfield if (!cg->diag_scaling) { 641*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, tao->gradient, &gd)); 642*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 643*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step*dk_yk, cg->yts, &tau_k, cg->alpha)); 64450b47da0SAdam Denchfield beta = tau_k*gnorm2/(gd - gd_old); 645*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 64650b47da0SAdam Denchfield } else { 647*9566063dSJacob Faibussowitsch PetscCall(MatMult(cg->B, tao->stepdirection, cg->d_work)); 648*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 649*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, tao->gradient, >Dg)); 650*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->G_old, &gd_old)); 651*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->d_work, cg->g_work, &dk_yk)); 65250b47da0SAdam Denchfield dk_yk = dk_yk - gd_old; 65350b47da0SAdam Denchfield beta = gtDg/dk_yk; 654*9566063dSJacob Faibussowitsch PetscCall(VecScale(cg->d_work, beta)); 655*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work)); 65650b47da0SAdam Denchfield } 657c8bcdf1eSAdam Denchfield break; 658484c7b14SAdam Denchfield 659c8bcdf1eSAdam Denchfield case CG_HagerZhang: 660484c7b14SAdam Denchfield /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent." 661484c7b14SAdam Denchfield ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */ 662*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 663*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 664*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 66550b47da0SAdam Denchfield snorm = dnorm*step; 66650b47da0SAdam Denchfield cg->yts = step*dk_yk; 667c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 668*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 669c8bcdf1eSAdam Denchfield } 67050b47da0SAdam Denchfield if (cg->dynamic_restart) { 671*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 672c8bcdf1eSAdam Denchfield } else { 673c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 674*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 675*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 676c8bcdf1eSAdam Denchfield /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */ 677c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 678c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)); 679c8bcdf1eSAdam Denchfield /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */ 68050b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 681c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 682*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 683c8bcdf1eSAdam Denchfield } else { 684c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 685c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 686c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 68750b47da0SAdam Denchfield /* Apply the diagonal scaling to all my vectors */ 688*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 689*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 690*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 691c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 692*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 693c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 694c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 695*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 696c8bcdf1eSAdam Denchfield tau_k = -tau_k*gd/(dk_yk*dk_yk); 697c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 698484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk + cg->hz_theta*tau_k; /* HZ; (1.15) from DK 2013 */ 699c8bcdf1eSAdam Denchfield /* From HZ2013, modified to account for diagonal scaling*/ 700*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 701*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 70250b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 703c8bcdf1eSAdam Denchfield /* Do the update */ 704*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 70550b47da0SAdam Denchfield } 70650b47da0SAdam Denchfield } 707c8bcdf1eSAdam Denchfield break; 708484c7b14SAdam Denchfield 709c8bcdf1eSAdam Denchfield case CG_DaiKou: 710484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search." 711484c7b14SAdam Denchfield SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */ 712*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 713*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 714*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 71550b47da0SAdam Denchfield snorm = step*dnorm; 71650b47da0SAdam Denchfield cg->yts = dk_yk*step; 717c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 718*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 719*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 720c8bcdf1eSAdam Denchfield /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */ 721c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 72250b47da0SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk) + gd/(dnorm*dnorm)) - step*gd/dk_yk; 72350b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*tau_k*gd_old/(dnorm*dnorm)), cg->dk_eta*tau_k*gd/(dnorm*dnorm)); 724c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 725*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk)); 726c8bcdf1eSAdam Denchfield } else { 727c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 728c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 729c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 730*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 731*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 732*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 733c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 734*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 735*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 736c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 737c8bcdf1eSAdam Denchfield tmp = gd/dk_yk; 738c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 739484c7b14SAdam Denchfield beta = gkp1_yk/dk_yk - step*tmp - tau_k; 740c8bcdf1eSAdam Denchfield /* Update this for the last term in beta */ 741*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, tao->stepdirection, &dk_yk)); 742c8bcdf1eSAdam Denchfield beta += tmp*dk_yk/(dnorm*dnorm); /* projection of y_work onto dk */ 743*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 744*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 74550b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta*gd_old/(dnorm*dnorm)), cg->dk_eta*gd/(dnorm*dnorm)); 746c8bcdf1eSAdam Denchfield /* Do the update */ 747*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 74850b47da0SAdam Denchfield } 749c8bcdf1eSAdam Denchfield break; 750484c7b14SAdam Denchfield 751c8bcdf1eSAdam Denchfield case CG_KouDai: 752110fc3b0SBarry Smith /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization." 753484c7b14SAdam Denchfield Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */ 754*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 755*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 756*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 75750b47da0SAdam Denchfield snorm = step*dnorm; 75850b47da0SAdam Denchfield cg->yts = dk_yk*step; 759c8bcdf1eSAdam Denchfield if (cg->use_dynamic_restart) { 760*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 761c8bcdf1eSAdam Denchfield } 76250b47da0SAdam Denchfield if (cg->dynamic_restart) { 763*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 764c8bcdf1eSAdam Denchfield } else { 765c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 766*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 767*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm*snorm, &tau_k, cg->alpha)); 768c8bcdf1eSAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - ynorm2*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 769c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tau_k*gd/(dnorm*dnorm)) /* 0.1 is KD's zeta parameter */ 770c8bcdf1eSAdam Denchfield { 771c8bcdf1eSAdam Denchfield beta = cg->zeta*tau_k*gd/(dnorm*dnorm); 772c8bcdf1eSAdam Denchfield gamma = 0.0; 773c8bcdf1eSAdam Denchfield } else { 774c8bcdf1eSAdam Denchfield if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0*gd/dk_yk; 775484c7b14SAdam Denchfield /* This seems to be very effective when there's no tau_k scaling. 776484c7b14SAdam Denchfield This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */ 77750b47da0SAdam Denchfield else { 77850b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 77950b47da0SAdam Denchfield } 780c8bcdf1eSAdam Denchfield } 781c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 782*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma*tau_k, beta, tao->gradient, cg->yk)); 783c8bcdf1eSAdam Denchfield } else { 784c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 785c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 786c8bcdf1eSAdam Denchfield cg->sts = snorm*snorm; 787*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 788*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 789c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 790*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1D_yk)); 791c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 792c8bcdf1eSAdam Denchfield gamma = gd/dk_yk; 793c8bcdf1eSAdam Denchfield /* tau_k = -ytDy/(ytd)^2 * gd */ 794*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 795c8bcdf1eSAdam Denchfield tau_k = tau_k*gd/(dk_yk*dk_yk); 796c8bcdf1eSAdam Denchfield /* beta is the constant which adds the d_k contribution */ 797c8bcdf1eSAdam Denchfield beta = gkp1D_yk/dk_yk - step*gamma - tau_k; 798c8bcdf1eSAdam Denchfield /* Here is the requisite check */ 799*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &tmp)); 800c8bcdf1eSAdam Denchfield if (cg->neg_xi) { 801c8bcdf1eSAdam Denchfield /* modified KD implementation */ 802c8bcdf1eSAdam Denchfield if (gkp1D_yk/dk_yk < 0) gamma = -1.0*gd/dk_yk; 80350b47da0SAdam Denchfield else { 80450b47da0SAdam Denchfield gamma = cg->xi*gd/dk_yk; 80550b47da0SAdam Denchfield } 806c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 807c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 808c8bcdf1eSAdam Denchfield gamma = 0.0; 809c8bcdf1eSAdam Denchfield } 810c8bcdf1eSAdam Denchfield } else { /* original KD 2015 implementation */ 811c8bcdf1eSAdam Denchfield if (beta < cg->zeta*tmp/(dnorm*dnorm)) { 812c8bcdf1eSAdam Denchfield beta = cg->zeta*tmp/(dnorm*dnorm); 813c8bcdf1eSAdam Denchfield gamma = 0.0; 814c8bcdf1eSAdam Denchfield } else { 815c8bcdf1eSAdam Denchfield gamma = cg->xi*gd/dk_yk; 816c8bcdf1eSAdam Denchfield } 817c8bcdf1eSAdam Denchfield } 818c8bcdf1eSAdam Denchfield /* Do the update in two steps */ 819*9566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 820*9566063dSJacob Faibussowitsch PetscCall(VecAXPY(tao->stepdirection, gamma, cg->y_work)); 82150b47da0SAdam Denchfield } 82250b47da0SAdam Denchfield } 823c8bcdf1eSAdam Denchfield break; 824484c7b14SAdam Denchfield 825484c7b14SAdam Denchfield case CG_SSML_BFGS: 826484c7b14SAdam Denchfield /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory." 827484c7b14SAdam Denchfield Discussion Papers 269 (1977). */ 828*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 829*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 830484c7b14SAdam Denchfield snorm = step*dnorm; 831484c7b14SAdam Denchfield cg->yts = dk_yk*step; 832484c7b14SAdam Denchfield cg->yty = ynorm2; 833484c7b14SAdam Denchfield cg->sts = snorm*snorm; 834484c7b14SAdam Denchfield if (!cg->diag_scaling) { 835*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 836*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 837484c7b14SAdam Denchfield tmp = gd/dk_yk; 838484c7b14SAdam Denchfield beta = tau_k*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*tmp; 839484c7b14SAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 840*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp*tau_k, beta, tao->gradient, cg->yk)); 841484c7b14SAdam Denchfield } else { 842484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 843*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 844*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 845484c7b14SAdam Denchfield /* compute scalar gamma */ 846*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 847*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 848484c7b14SAdam Denchfield gamma = gd/dk_yk; 849484c7b14SAdam Denchfield /* Compute scalar beta */ 850484c7b14SAdam Denchfield beta = (gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 851484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 852*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 853484c7b14SAdam Denchfield } 854484c7b14SAdam Denchfield break; 855484c7b14SAdam Denchfield 856484c7b14SAdam Denchfield case CG_SSML_DFP: 857*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 858*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 859484c7b14SAdam Denchfield snorm = step*dnorm; 860484c7b14SAdam Denchfield cg->yts = dk_yk*step; 861484c7b14SAdam Denchfield cg->yty = ynorm2; 862484c7b14SAdam Denchfield cg->sts = snorm*snorm; 863484c7b14SAdam Denchfield if (!cg->diag_scaling) { 864484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 865*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 866*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 867484c7b14SAdam Denchfield tau_k = cg->dfp_scale*tau_k; 868484c7b14SAdam Denchfield tmp = tau_k*gkp1_yk/cg->yty; 869484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 870484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 871*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 872484c7b14SAdam Denchfield } else { 873484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */ 874*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 875*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 876484c7b14SAdam Denchfield /* compute scalar gamma */ 877*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 878*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 879484c7b14SAdam Denchfield gamma = (gkp1_yk/tmp); 880484c7b14SAdam Denchfield /* Compute scalar beta */ 881484c7b14SAdam Denchfield beta = -step*gd/dk_yk; 882484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 883*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 884484c7b14SAdam Denchfield } 885484c7b14SAdam Denchfield break; 886484c7b14SAdam Denchfield 887484c7b14SAdam Denchfield case CG_SSML_BROYDEN: 888*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 889*9566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 890484c7b14SAdam Denchfield snorm = step*dnorm; 891484c7b14SAdam Denchfield cg->yts = step*dk_yk; 892484c7b14SAdam Denchfield cg->yty = ynorm2; 893484c7b14SAdam Denchfield cg->sts = snorm*snorm; 894484c7b14SAdam Denchfield if (!cg->diag_scaling) { 895484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 896*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_bfgs, cg->bfgs_scale)); 897*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step*dk_yk, snorm*snorm, &tau_dfp, cg->dfp_scale)); 898*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 899484c7b14SAdam Denchfield tau_k = cg->theta*tau_bfgs + (1.0-cg->theta)*tau_dfp; 900484c7b14SAdam Denchfield /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, 901484c7b14SAdam Denchfield it should reproduce the tau_dfp scaling. Same with dfp_scale. */ 902484c7b14SAdam Denchfield tmp = cg->theta*tau_bfgs*gd/dk_yk + (1-cg->theta)*tau_dfp*gkp1_yk/cg->yty; 903484c7b14SAdam Denchfield beta = cg->theta*tau_bfgs*(gkp1_yk/dk_yk - cg->yty*gd/(dk_yk*dk_yk)) - step*gd/dk_yk; 904484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 905*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 906484c7b14SAdam Denchfield } else { 907484c7b14SAdam Denchfield /* We have diagonal scaling enabled */ 908*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 909*9566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 910484c7b14SAdam Denchfield /* compute scalar gamma */ 911*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 912*9566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 913484c7b14SAdam Denchfield gamma = cg->theta*gd/dk_yk + (1-cg->theta)*(gkp1_yk/tmp); 914484c7b14SAdam Denchfield /* Compute scalar beta */ 915484c7b14SAdam Denchfield beta = cg->theta*(gkp1_yk/dk_yk - gd*tmp/(dk_yk*dk_yk)) - step*gd/dk_yk; 916484c7b14SAdam Denchfield /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 917*9566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 918484c7b14SAdam Denchfield } 919484c7b14SAdam Denchfield break; 920484c7b14SAdam Denchfield 921c8bcdf1eSAdam Denchfield default: 922c8bcdf1eSAdam Denchfield break; 923484c7b14SAdam Denchfield 924c8bcdf1eSAdam Denchfield } 925c8bcdf1eSAdam Denchfield } 926c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 927c8bcdf1eSAdam Denchfield } 928c8bcdf1eSAdam Denchfield 929c8bcdf1eSAdam Denchfield PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm) 930c8bcdf1eSAdam Denchfield { 931c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 932c8bcdf1eSAdam Denchfield TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 9338ca2df50S PetscReal step=1.0,gnorm2,gd,dnorm=0.0; 934c8bcdf1eSAdam Denchfield PetscReal gnorm2_old,f_old,resnorm, gnorm_old; 935c624ebd3SAlp Dener PetscBool pcgd_fallback = PETSC_FALSE; 936c8bcdf1eSAdam Denchfield 937c8bcdf1eSAdam Denchfield PetscFunctionBegin; 938c8bcdf1eSAdam Denchfield /* We are now going to perform a line search along the direction. */ 939c8bcdf1eSAdam Denchfield /* Store solution and gradient info before it changes */ 940*9566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, cg->X_old)); 941*9566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->gradient, cg->G_old)); 942*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old)); 943c8bcdf1eSAdam Denchfield 944c8bcdf1eSAdam Denchfield gnorm_old = gnorm; 945c8bcdf1eSAdam Denchfield gnorm2_old = gnorm_old*gnorm_old; 946c8bcdf1eSAdam Denchfield f_old = cg->f; 947484c7b14SAdam Denchfield /* Perform bounded line search. If we are recycling a solution from a previous */ 948484c7b14SAdam Denchfield /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */ 949414d97d3SAlp Dener if (!(tao->recycle && 0 == tao->niter)) { 950484c7b14SAdam Denchfield /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */ 951*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 952*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 953*9566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 954c8bcdf1eSAdam Denchfield 955c8bcdf1eSAdam Denchfield /* Check linesearch failure */ 956c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 957c8bcdf1eSAdam Denchfield ++cg->ls_fails; 958c624ebd3SAlp Dener if (cg->cg_type == CG_GradientDescent) { 959c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 960c8bcdf1eSAdam Denchfield step = 0.0; 961c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 962c8bcdf1eSAdam Denchfield } else { 963484c7b14SAdam Denchfield /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */ 964*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->X_old, tao->solution)); 965*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->G_old, tao->gradient)); 966*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient)); 967c8bcdf1eSAdam Denchfield gnorm = gnorm_old; 968c8bcdf1eSAdam Denchfield gnorm2 = gnorm2_old; 969c8bcdf1eSAdam Denchfield cg->f = f_old; 970c8bcdf1eSAdam Denchfield 971484c7b14SAdam Denchfield /* Fall back on preconditioned CG (so long as you're not already using it) */ 972484c7b14SAdam Denchfield if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling) { 973e2570530SAlp Dener pcgd_fallback = PETSC_TRUE; 974*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 975484c7b14SAdam Denchfield 976*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 977*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 978c8bcdf1eSAdam Denchfield 979*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 980*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 981*9566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 982c8bcdf1eSAdam Denchfield 983484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 984484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 985484c7b14SAdam Denchfield /* Going to perform a regular gradient descent step. */ 986484c7b14SAdam Denchfield ++cg->ls_fails; 987484c7b14SAdam Denchfield step = 0.0; 988484c7b14SAdam Denchfield } 989484c7b14SAdam Denchfield } 990484c7b14SAdam Denchfield /* Fall back on the scaled gradient step */ 991484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 992484c7b14SAdam Denchfield ++cg->ls_fails; 993*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 994*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 995*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 996*9566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 997*9566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 998484c7b14SAdam Denchfield } 999484c7b14SAdam Denchfield 1000c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 1001c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 100250b47da0SAdam Denchfield ++cg->ls_fails; 1003c8bcdf1eSAdam Denchfield step = 0.0; 1004c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 1005484c7b14SAdam Denchfield } else { 1006484c7b14SAdam Denchfield /* One of the fallbacks worked. Set them both back equal to false. */ 1007484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 1008c8bcdf1eSAdam Denchfield } 1009c8bcdf1eSAdam Denchfield } 1010c8bcdf1eSAdam Denchfield } 1011c8bcdf1eSAdam Denchfield /* Convergence test for line search failure */ 1012c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1013c8bcdf1eSAdam Denchfield 1014c8bcdf1eSAdam Denchfield /* Standard convergence test */ 1015*9566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 1016*9566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 10173c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 1018*9566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 1019*9566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 1020*9566063dSJacob Faibussowitsch PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP)); 1021c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 1022484c7b14SAdam Denchfield } 1023c8bcdf1eSAdam Denchfield /* Assert we have an updated step and we need at least one more iteration. */ 1024c8bcdf1eSAdam Denchfield /* Calculate the next direction */ 1025c8bcdf1eSAdam Denchfield /* Estimate the active set at the new solution */ 1026*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 1027c8bcdf1eSAdam Denchfield /* Compute the projected gradient and its norm */ 1028*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 1029*9566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 1030*9566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient,NORM_2,&gnorm)); 1031c8bcdf1eSAdam Denchfield gnorm2 = gnorm*gnorm; 1032c8bcdf1eSAdam Denchfield 1033484c7b14SAdam Denchfield /* Calculate some quantities used in the StepDirectionUpdate. */ 1034*9566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 1035484c7b14SAdam Denchfield /* Update the step direction. */ 1036*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 1037484c7b14SAdam Denchfield ++tao->niter; 1038*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1039c8bcdf1eSAdam Denchfield 1040c8bcdf1eSAdam Denchfield if (cg->cg_type != CG_GradientDescent) { 1041c8bcdf1eSAdam Denchfield /* Figure out which previously active variables became inactive this iteration */ 1042*9566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 1043c8bcdf1eSAdam Denchfield if (cg->inactive_idx && cg->inactive_old) { 1044*9566063dSJacob Faibussowitsch PetscCall(ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives)); 1045c8bcdf1eSAdam Denchfield } 1046c8bcdf1eSAdam Denchfield /* Selectively reset the CG step those freshly inactive variables */ 1047c8bcdf1eSAdam Denchfield if (cg->new_inactives) { 1048*9566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 1049*9566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 1050*9566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->inactive_grad, cg->inactive_step)); 1051*9566063dSJacob Faibussowitsch PetscCall(VecScale(cg->inactive_step, -1.0)); 1052*9566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 1053*9566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 1054c8bcdf1eSAdam Denchfield } 1055c8bcdf1eSAdam Denchfield /* Verify that this is a descent direction */ 1056*9566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 1057*9566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 105850b47da0SAdam Denchfield if (PetscIsInfOrNanReal(gd) || (gd/(dnorm*dnorm) <= -1e10 || gd/(dnorm*dnorm) >= -1e-10)) { 1059c8bcdf1eSAdam Denchfield /* Not a descent direction, so we reset back to projected gradient descent */ 1060*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 1061*9566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1062c8bcdf1eSAdam Denchfield ++cg->descent_error; 1063c8bcdf1eSAdam Denchfield } else { 1064c8bcdf1eSAdam Denchfield } 1065c8bcdf1eSAdam Denchfield } 1066ac9112b8SAlp Dener PetscFunctionReturn(0); 1067ac9112b8SAlp Dener } 1068484c7b14SAdam Denchfield 1069484c7b14SAdam Denchfield PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0) 1070484c7b14SAdam Denchfield { 1071484c7b14SAdam Denchfield TAO_BNCG *cg = (TAO_BNCG*)tao->data; 1072484c7b14SAdam Denchfield 1073484c7b14SAdam Denchfield PetscFunctionBegin; 1074*9566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)H0)); 1075484c7b14SAdam Denchfield cg->pc = H0; 1076484c7b14SAdam Denchfield PetscFunctionReturn(0); 1077484c7b14SAdam Denchfield } 1078