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 28*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType) 29*d71ae5a4SJacob Faibussowitsch { 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)); 509371c9d4SSatish Balay PetscCall(TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol, &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx)); 51c4b75bccSAlp Dener break; 52*d71ae5a4SJacob Faibussowitsch default: 53*d71ae5a4SJacob Faibussowitsch break; 5461be54a6SAlp Dener } 5561be54a6SAlp Dener PetscFunctionReturn(0); 5661be54a6SAlp Dener } 5761be54a6SAlp Dener 58*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step) 59*d71ae5a4SJacob Faibussowitsch { 6061be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 6161be54a6SAlp Dener 6261be54a6SAlp Dener PetscFunctionBegin; 63a1318120SAlp Dener switch (asType) { 64*d71ae5a4SJacob Faibussowitsch case CG_AS_NONE: 65*d71ae5a4SJacob Faibussowitsch PetscCall(VecISSet(step, cg->active_idx, 0.0)); 66*d71ae5a4SJacob Faibussowitsch break; 6761be54a6SAlp Dener 68*d71ae5a4SJacob Faibussowitsch case CG_AS_BERTSEKAS: 69*d71ae5a4SJacob Faibussowitsch PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step)); 70*d71ae5a4SJacob Faibussowitsch break; 7161be54a6SAlp Dener 72*d71ae5a4SJacob Faibussowitsch default: 73*d71ae5a4SJacob Faibussowitsch break; 7461be54a6SAlp Dener } 7561be54a6SAlp Dener PetscFunctionReturn(0); 7661be54a6SAlp Dener } 7761be54a6SAlp Dener 78*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_BNCG(Tao tao) 79*d71ae5a4SJacob Faibussowitsch { 80ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 81484c7b14SAdam Denchfield PetscReal step = 1.0, gnorm, gnorm2, resnorm; 82c4b75bccSAlp Dener PetscInt nDiff; 83ac9112b8SAlp Dener 84ac9112b8SAlp Dener PetscFunctionBegin; 85ac9112b8SAlp Dener /* Project the current point onto the feasible set */ 869566063dSJacob Faibussowitsch PetscCall(TaoComputeVariableBounds(tao)); 879566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch, tao->XL, tao->XU)); 88ac9112b8SAlp Dener 89c8bcdf1eSAdam Denchfield /* Project the initial point onto the feasible region */ 909566063dSJacob Faibussowitsch PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution)); 91484c7b14SAdam Denchfield 9248a46eb9SPierre Jolivet if (nDiff > 0 || !tao->recycle) PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 939566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->unprojected_gradient, NORM_2, &gnorm)); 943c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(cg->f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 95ac9112b8SAlp Dener 9661be54a6SAlp Dener /* Estimate the active set and compute the projected gradient */ 979566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 9861be54a6SAlp Dener 99ac9112b8SAlp Dener /* Project the gradient and calculate the norm */ 1009566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 1019566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 1029566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient, NORM_2, &gnorm)); 103ac9112b8SAlp Dener gnorm2 = gnorm * gnorm; 104ac9112b8SAlp Dener 105c8bcdf1eSAdam Denchfield /* Initialize counters */ 106e031d6f5SAlp Dener tao->niter = 0; 10750b47da0SAdam Denchfield cg->ls_fails = cg->descent_error = 0; 108c8bcdf1eSAdam Denchfield cg->resets = -1; 109484c7b14SAdam Denchfield cg->skipped_updates = cg->pure_gd_steps = 0; 110c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 111c8bcdf1eSAdam Denchfield 112c8bcdf1eSAdam Denchfield /* Convergence test at the starting point. */ 113ac9112b8SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 114484c7b14SAdam Denchfield 1159566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 1169566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 1173c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 1189566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 1199566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 120dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 121ac9112b8SAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 122484c7b14SAdam Denchfield /* Calculate initial direction. */ 123414d97d3SAlp Dener if (!tao->recycle) { 124484c7b14SAdam Denchfield /* We are not recycling a solution/history from a past TaoSolve */ 1259566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 126ac9112b8SAlp Dener } 127c8bcdf1eSAdam Denchfield /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */ 128c8bcdf1eSAdam Denchfield while (1) { 129e1e80dc8SAlp Dener /* Call general purpose update function */ 130e1e80dc8SAlp Dener if (tao->ops->update) { 131dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, update, tao->niter, tao->user_update); 1327494f0b1SStefano Zampini PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 133e1e80dc8SAlp Dener } 1349566063dSJacob Faibussowitsch PetscCall(TaoBNCGConductIteration(tao, gnorm)); 135c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 136ac9112b8SAlp Dener } 137ac9112b8SAlp Dener } 138ac9112b8SAlp Dener 139*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_BNCG(Tao tao) 140*d71ae5a4SJacob Faibussowitsch { 141ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 142ac9112b8SAlp Dener 143ac9112b8SAlp Dener PetscFunctionBegin; 14448a46eb9SPierre Jolivet if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient)); 14548a46eb9SPierre Jolivet if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection)); 14648a46eb9SPierre Jolivet if (!cg->W) PetscCall(VecDuplicate(tao->solution, &cg->W)); 14748a46eb9SPierre Jolivet if (!cg->work) PetscCall(VecDuplicate(tao->solution, &cg->work)); 14848a46eb9SPierre Jolivet if (!cg->sk) PetscCall(VecDuplicate(tao->solution, &cg->sk)); 14948a46eb9SPierre Jolivet if (!cg->yk) PetscCall(VecDuplicate(tao->gradient, &cg->yk)); 15048a46eb9SPierre Jolivet if (!cg->X_old) PetscCall(VecDuplicate(tao->solution, &cg->X_old)); 15148a46eb9SPierre Jolivet if (!cg->G_old) PetscCall(VecDuplicate(tao->gradient, &cg->G_old)); 152c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 1539566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->d_work)); 1549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->y_work)); 1559566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->g_work)); 156c4b75bccSAlp Dener } 15748a46eb9SPierre Jolivet if (!cg->unprojected_gradient) PetscCall(VecDuplicate(tao->gradient, &cg->unprojected_gradient)); 15848a46eb9SPierre Jolivet if (!cg->unprojected_gradient_old) PetscCall(VecDuplicate(tao->gradient, &cg->unprojected_gradient_old)); 1599566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(cg->B, cg->sk, cg->yk)); 1601baa6e33SBarry Smith if (cg->pc) PetscCall(MatLMVMSetJ0(cg->B, cg->pc)); 161ac9112b8SAlp Dener PetscFunctionReturn(0); 162ac9112b8SAlp Dener } 163ac9112b8SAlp Dener 164*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_BNCG(Tao tao) 165*d71ae5a4SJacob Faibussowitsch { 166ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 167ac9112b8SAlp Dener 168ac9112b8SAlp Dener PetscFunctionBegin; 169ac9112b8SAlp Dener if (tao->setupcalled) { 1709566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->W)); 1719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->work)); 1729566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->X_old)); 1739566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->G_old)); 1749566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient)); 1759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient_old)); 1769566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->g_work)); 1779566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->d_work)); 1789566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->y_work)); 1799566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->sk)); 1809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->yk)); 181ac9112b8SAlp Dener } 1829566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_lower)); 1839566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_upper)); 1849566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_fixed)); 1859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 1869566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 1879566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 1889566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 1899566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->B)); 19048a46eb9SPierre Jolivet if (cg->pc) PetscCall(MatDestroy(&cg->pc)); 1919566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 192ac9112b8SAlp Dener PetscFunctionReturn(0); 193ac9112b8SAlp Dener } 194ac9112b8SAlp Dener 195*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_BNCG(Tao tao, PetscOptionItems *PetscOptionsObject) 196*d71ae5a4SJacob Faibussowitsch { 197ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 198ac9112b8SAlp Dener 199ac9112b8SAlp Dener PetscFunctionBegin; 200d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Nonlinear Conjugate Gradient method for unconstrained optimization"); 2019566063dSJacob Faibussowitsch PetscCall(PetscOptionsEList("-tao_bncg_type", "cg formula", "", CG_Table, CGTypes, CG_Table[cg->cg_type], &cg->cg_type, NULL)); 2028ebe3e4eSStefano Zampini if (cg->cg_type != CG_SSML_BFGS) cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */ 203484c7b14SAdam Denchfield if (CG_GradientDescent == cg->cg_type) { 204484c7b14SAdam Denchfield cg->cg_type = CG_PCGradientDescent; 205484c7b14SAdam Denchfield /* Set scaling equal to none or, at best, scalar scaling. */ 206484c7b14SAdam Denchfield cg->unscaled_restart = PETSC_TRUE; 207484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 208484c7b14SAdam Denchfield } 2099566063dSJacob 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)); 2109566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_eta", "(developer) cutoff tolerance for HZ", "", cg->hz_eta, &cg->hz_eta, NULL)); 2119566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_eps", "(developer) cutoff value for restarts", "", cg->epsilon, &cg->epsilon, NULL)); 2129566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dk_eta", "(developer) cutoff tolerance for DK", "", cg->dk_eta, &cg->dk_eta, NULL)); 2139566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_xi", "(developer) Parameter in the KD method", "", cg->xi, &cg->xi, NULL)); 2149566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL)); 2159566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL)); 2169566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_alpha", "(developer) parameter for the scalar scaling", "", cg->alpha, &cg->alpha, NULL)); 2179566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL)); 2189566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL)); 2199566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_diag_scaling", "Enable diagonal Broyden-like preconditioning", "", cg->diag_scaling, &cg->diag_scaling, NULL)); 2209566063dSJacob 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)); 2219566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_unscaled_restart", "(developer) use unscaled gradient restarts", "", cg->unscaled_restart, &cg->unscaled_restart, NULL)); 2229566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL)); 2239566063dSJacob 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)); 2249566063dSJacob 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)); 2259566063dSJacob 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)); 2269566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_no_scaling", "Disable all scaling except in restarts", "", cg->no_scaling, &cg->no_scaling, NULL)); 227484c7b14SAdam Denchfield if (cg->no_scaling) { 228484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 229484c7b14SAdam Denchfield cg->alpha = -1.0; 230484c7b14SAdam Denchfield } 231b474139fSKarl Rupp if (cg->alpha == -1.0 && cg->cg_type == CG_KouDai && !cg->diag_scaling) { /* Some more default options that appear to be good. */ 232484c7b14SAdam Denchfield cg->neg_xi = PETSC_TRUE; 233484c7b14SAdam Denchfield } 2349566063dSJacob 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)); 2359566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", cg->as_tol, &cg->as_tol, NULL)); 2369566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables", "", cg->as_step, &cg->as_step, NULL)); 2379566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts", "", cg->delta_min, &cg->delta_min, NULL)); 2389566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts", "", cg->delta_max, &cg->delta_max, NULL)); 23950b47da0SAdam Denchfield 240d0609cedSBarry Smith PetscOptionsHeadEnd(); 2419566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(cg->B, ((PetscObject)tao)->prefix)); 2429566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(cg->B, "tao_bncg_")); 2439566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(cg->B)); 244ac9112b8SAlp Dener PetscFunctionReturn(0); 245ac9112b8SAlp Dener } 246ac9112b8SAlp Dener 247*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 248*d71ae5a4SJacob Faibussowitsch { 249ac9112b8SAlp Dener PetscBool isascii; 250ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 251ac9112b8SAlp Dener 252ac9112b8SAlp Dener PetscFunctionBegin; 2539566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 254ac9112b8SAlp Dener if (isascii) { 2559566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 2569566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type])); 25763a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %" PetscInt_FMT "\n", cg->skipped_updates)); 25863a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", cg->resets)); 25963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %" PetscInt_FMT "\n", cg->pure_gd_steps)); 26063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not a descent direction: %" PetscInt_FMT "\n", cg->descent_error)); 26163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Line search fails: %" PetscInt_FMT "\n", cg->ls_fails)); 262484c7b14SAdam Denchfield if (cg->diag_scaling) { 2639566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 264484c7b14SAdam Denchfield if (isascii) { 2659566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 2669566063dSJacob Faibussowitsch PetscCall(MatView(cg->B, viewer)); 2679566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 268484c7b14SAdam Denchfield } 269484c7b14SAdam Denchfield } 2709566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 271ac9112b8SAlp Dener } 272ac9112b8SAlp Dener PetscFunctionReturn(0); 273ac9112b8SAlp Dener } 274ac9112b8SAlp Dener 275*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha) 276*d71ae5a4SJacob Faibussowitsch { 277c8bcdf1eSAdam Denchfield PetscReal a, b, c, sig1, sig2; 278c8bcdf1eSAdam Denchfield 279c8bcdf1eSAdam Denchfield PetscFunctionBegin; 280c8bcdf1eSAdam Denchfield *scale = 0.0; 2818ebe3e4eSStefano Zampini if (1.0 == alpha) *scale = yts / yty; 2828ebe3e4eSStefano Zampini else if (0.0 == alpha) *scale = sts / yts; 28350b47da0SAdam Denchfield else if (-1.0 == alpha) *scale = 1.0; 284c8bcdf1eSAdam Denchfield else { 285c8bcdf1eSAdam Denchfield a = yty; 286c8bcdf1eSAdam Denchfield b = yts; 287c8bcdf1eSAdam Denchfield c = sts; 288c8bcdf1eSAdam Denchfield a *= alpha; 289c8bcdf1eSAdam Denchfield b *= -(2.0 * alpha - 1.0); 290c8bcdf1eSAdam Denchfield c *= alpha - 1.0; 291c8bcdf1eSAdam Denchfield sig1 = (-b + PetscSqrtReal(b * b - 4.0 * a * c)) / (2.0 * a); 292c8bcdf1eSAdam Denchfield sig2 = (-b - PetscSqrtReal(b * b - 4.0 * a * c)) / (2.0 * a); 293c8bcdf1eSAdam Denchfield /* accept the positive root as the scalar */ 2948ebe3e4eSStefano Zampini if (sig1 > 0.0) *scale = sig1; 2958ebe3e4eSStefano Zampini else if (sig2 > 0.0) *scale = sig2; 2968ebe3e4eSStefano Zampini else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar"); 297c8bcdf1eSAdam Denchfield } 298c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 299c8bcdf1eSAdam Denchfield } 300c8bcdf1eSAdam Denchfield 301ac9112b8SAlp Dener /*MC 302ac9112b8SAlp Dener TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 303ac9112b8SAlp Dener 304ac9112b8SAlp Dener Options Database Keys: 30550b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled) 306c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance 30761be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula 308c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method 309c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation 310c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation 31150b47da0SAdam 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. 31250b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method 31350b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 31450b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 31550b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method 31650b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method 31750b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method 31850b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method 31950b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True. 32050b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods 32150b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts 32250b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method 323484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps 324484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps 32550b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart 32650b47da0SAdam 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 32750b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations 328484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults. 3293850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions 330ac9112b8SAlp Dener 331ac9112b8SAlp Dener Notes: 332ac9112b8SAlp Dener CG formulas are: 3333850be85SAlp Dener + "gd" - Gradient Descent 3343850be85SAlp Dener . "fr" - Fletcher-Reeves 3353850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak 3363850be85SAlp Dener . "prp" - Polak-Ribiere-Plus 3373850be85SAlp Dener . "hs" - Hestenes-Steifel 3383850be85SAlp Dener . "dy" - Dai-Yuan 3393850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS 3403850be85SAlp Dener . "ssml_dfp" - Self-Scaling Memoryless DFP 3413850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden 3423850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3) 3433850be85SAlp Dener . "dk" - Dai-Kou (2013) 3443850be85SAlp Dener - "kd" - Kou-Dai (2015) 3459abc5736SPatrick Sanan 346ac9112b8SAlp Dener Level: beginner 347ac9112b8SAlp Dener M*/ 348ac9112b8SAlp Dener 349*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 350*d71ae5a4SJacob Faibussowitsch { 351ac9112b8SAlp Dener TAO_BNCG *cg; 352ac9112b8SAlp Dener const char *morethuente_type = TAOLINESEARCHMT; 353ac9112b8SAlp Dener 354ac9112b8SAlp Dener PetscFunctionBegin; 355ac9112b8SAlp Dener tao->ops->setup = TaoSetUp_BNCG; 356ac9112b8SAlp Dener tao->ops->solve = TaoSolve_BNCG; 357ac9112b8SAlp Dener tao->ops->view = TaoView_BNCG; 358ac9112b8SAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 359ac9112b8SAlp Dener tao->ops->destroy = TaoDestroy_BNCG; 360ac9112b8SAlp Dener 361ac9112b8SAlp Dener /* Override default settings (unless already changed) */ 362ac9112b8SAlp Dener if (!tao->max_it_changed) tao->max_it = 2000; 363ac9112b8SAlp Dener if (!tao->max_funcs_changed) tao->max_funcs = 4000; 364ac9112b8SAlp Dener 365ac9112b8SAlp Dener /* Note: nondefault values should be used for nonlinear conjugate gradient */ 366ac9112b8SAlp Dener /* method. In particular, gtol should be less that 0.5; the value used in */ 367ac9112b8SAlp Dener /* Nocedal and Wright is 0.10. We use the default values for the */ 368ac9112b8SAlp Dener /* linesearch because it seems to work better. */ 3699566063dSJacob Faibussowitsch PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch)); 3709566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1)); 3719566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type)); 3729566063dSJacob Faibussowitsch PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao)); 373ac9112b8SAlp Dener 3744dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&cg)); 375ac9112b8SAlp Dener tao->data = (void *)cg; 3769566063dSJacob Faibussowitsch PetscCall(KSPInitializePackage()); 3779566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &cg->B)); 3789566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1)); 3799566063dSJacob Faibussowitsch PetscCall(MatSetType(cg->B, MATLMVMDIAGBROYDEN)); 38050b47da0SAdam Denchfield 381484c7b14SAdam Denchfield cg->pc = NULL; 382484c7b14SAdam Denchfield 38350b47da0SAdam Denchfield cg->dk_eta = 0.5; 38450b47da0SAdam Denchfield cg->hz_eta = 0.4; 385c8bcdf1eSAdam Denchfield cg->dynamic_restart = PETSC_FALSE; 386c8bcdf1eSAdam Denchfield cg->unscaled_restart = PETSC_FALSE; 387484c7b14SAdam Denchfield cg->no_scaling = PETSC_FALSE; 388484c7b14SAdam Denchfield cg->delta_min = 1e-7; 389484c7b14SAdam Denchfield cg->delta_max = 100; 390c8bcdf1eSAdam Denchfield cg->theta = 1.0; 391c8bcdf1eSAdam Denchfield cg->hz_theta = 1.0; 392c8bcdf1eSAdam Denchfield cg->dfp_scale = 1.0; 393c8bcdf1eSAdam Denchfield cg->bfgs_scale = 1.0; 39450b47da0SAdam Denchfield cg->zeta = 0.1; 39550b47da0SAdam Denchfield cg->min_quad = 6; 396c8bcdf1eSAdam Denchfield cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/ 397c8bcdf1eSAdam Denchfield cg->xi = 1.0; 39850b47da0SAdam Denchfield cg->neg_xi = PETSC_TRUE; 399c8bcdf1eSAdam Denchfield cg->spaced_restart = PETSC_FALSE; 400c8bcdf1eSAdam Denchfield cg->tol_quad = 1e-8; 40161be54a6SAlp Dener cg->as_step = 0.001; 40261be54a6SAlp Dener cg->as_tol = 0.001; 40350b47da0SAdam Denchfield cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0 / 3.0); /* Just a little tighter*/ 40461be54a6SAlp Dener cg->as_type = CG_AS_BERTSEKAS; 405c8bcdf1eSAdam Denchfield cg->cg_type = CG_SSML_BFGS; 406c8bcdf1eSAdam Denchfield cg->alpha = 1.0; 407c8bcdf1eSAdam Denchfield cg->diag_scaling = PETSC_TRUE; 408c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 409c8bcdf1eSAdam Denchfield } 410c8bcdf1eSAdam Denchfield 411*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq) 412*d71ae5a4SJacob Faibussowitsch { 413c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 414c8bcdf1eSAdam Denchfield PetscReal scaling; 415c8bcdf1eSAdam Denchfield 416c8bcdf1eSAdam Denchfield PetscFunctionBegin; 417c8bcdf1eSAdam Denchfield ++cg->resets; 418c8bcdf1eSAdam Denchfield scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23); 419484c7b14SAdam Denchfield scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling)); 420484c7b14SAdam Denchfield if (cg->unscaled_restart) { 421484c7b14SAdam Denchfield scaling = 1.0; 422484c7b14SAdam Denchfield ++cg->pure_gd_steps; 423484c7b14SAdam Denchfield } 4249566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient)); 425c8bcdf1eSAdam Denchfield /* Also want to reset our diagonal scaling with each restart */ 4261baa6e33SBarry Smith if (cg->diag_scaling) PetscCall(MatLMVMReset(cg->B, PETSC_FALSE)); 427c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 428c8bcdf1eSAdam Denchfield } 429c8bcdf1eSAdam Denchfield 430*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold) 431*d71ae5a4SJacob Faibussowitsch { 432c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 433c8bcdf1eSAdam Denchfield PetscReal quadinterp; 434c8bcdf1eSAdam Denchfield 435c8bcdf1eSAdam Denchfield PetscFunctionBegin; 43650b47da0SAdam Denchfield if (cg->f < cg->min_quad / 10) { 43750b47da0SAdam Denchfield *dynrestart = PETSC_FALSE; 43850b47da0SAdam Denchfield PetscFunctionReturn(0); 43950b47da0SAdam Denchfield } /* just skip this since this strategy doesn't work well for functions near zero */ 440484c7b14SAdam Denchfield quadinterp = 2.0 * (cg->f - fold) / (stepsize * (gd + gd_old)); 44150b47da0SAdam Denchfield if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad; 442c8bcdf1eSAdam Denchfield else { 443c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 444c8bcdf1eSAdam Denchfield *dynrestart = PETSC_FALSE; 445c8bcdf1eSAdam Denchfield } 446c8bcdf1eSAdam Denchfield if (cg->iter_quad >= cg->min_quad) { 447c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 448c8bcdf1eSAdam Denchfield *dynrestart = PETSC_TRUE; 449c8bcdf1eSAdam Denchfield } 450c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 451c8bcdf1eSAdam Denchfield } 452c8bcdf1eSAdam Denchfield 453*d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback) 454*d71ae5a4SJacob Faibussowitsch { 455c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 45650b47da0SAdam Denchfield PetscReal gamma = 1.0, tau_k, beta; 457484c7b14SAdam Denchfield PetscReal tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk = 1.0, gd; 45850b47da0SAdam Denchfield PetscReal gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg; 459c8bcdf1eSAdam Denchfield PetscInt dim; 460484c7b14SAdam Denchfield PetscBool cg_restart = PETSC_FALSE; 461c8bcdf1eSAdam Denchfield PetscFunctionBegin; 462c8bcdf1eSAdam Denchfield 46350b47da0SAdam Denchfield /* Local curvature check to see if we need to restart */ 464414d97d3SAlp Dener if (tao->niter >= 1 || tao->recycle) { 4659566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 4669566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 467c8bcdf1eSAdam Denchfield ynorm2 = ynorm * ynorm; 4689566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 469484c7b14SAdam Denchfield if (step * dnorm < PETSC_MACHINE_EPSILON || step * dk_yk < PETSC_MACHINE_EPSILON) { 470e2570530SAlp Dener cg_restart = PETSC_TRUE; 471484c7b14SAdam Denchfield ++cg->skipped_updates; 472484c7b14SAdam Denchfield } 47350b47da0SAdam Denchfield if (cg->spaced_restart) { 4749566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 475e2570530SAlp Dener if (tao->niter % (dim * cg->min_restart_num)) cg_restart = PETSC_TRUE; 47650b47da0SAdam Denchfield } 47750b47da0SAdam Denchfield } 47850b47da0SAdam Denchfield /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */ 47950b47da0SAdam Denchfield if (cg->spaced_restart) { 4809566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 481e2570530SAlp Dener if (0 == tao->niter % (6 * dim)) cg_restart = PETSC_TRUE; 48250b47da0SAdam Denchfield } 48350b47da0SAdam Denchfield /* Compute the diagonal scaling vector if applicable */ 4841baa6e33SBarry Smith if (cg->diag_scaling) PetscCall(MatLMVMUpdate(cg->B, tao->solution, tao->gradient)); 48550b47da0SAdam Denchfield 486484c7b14SAdam Denchfield /* A note on diagonal scaling (to be added to paper): 487484c7b14SAdam Denchfield For the FR, PR, PRP, and DY methods, the diagonally scaled versions 488484c7b14SAdam Denchfield must be derived as a preconditioned CG method rather than as 489484c7b14SAdam Denchfield a Hessian initialization like in the Broyden methods. */ 49050b47da0SAdam Denchfield 491484c7b14SAdam Denchfield /* In that case, one writes the objective function as 492484c7b14SAdam Denchfield f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). 493484c7b14SAdam Denchfield Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to 494484c7b14SAdam Denchfield HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the 495484c7b14SAdam Denchfield same under preconditioning. Note that A is diagonal, such that A^T = A. */ 49650b47da0SAdam Denchfield 497484c7b14SAdam Denchfield /* This yields questions like what the dot product d_k^T y_k 498484c7b14SAdam Denchfield should look like. HZ mistakenly treats that as the same under 499484c7b14SAdam Denchfield preconditioning, but that is not necessarily true. */ 50050b47da0SAdam Denchfield 501484c7b14SAdam Denchfield /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 502484c7b14SAdam 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}), 503484c7b14SAdam 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 504484c7b14SAdam Denchfield NOT the same if our preconditioning matrix is updated between iterations. 505484c7b14SAdam Denchfield This same issue is found when considering dot products of the form g_{k+1}^T y_k. */ 50650b47da0SAdam Denchfield 50750b47da0SAdam Denchfield /* Compute CG step direction */ 50850b47da0SAdam Denchfield if (cg_restart) { 5099566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 510484c7b14SAdam Denchfield } else if (pcgd_fallback) { 511484c7b14SAdam Denchfield /* Just like preconditioned CG */ 5129566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5139566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 51450b47da0SAdam Denchfield } else if (ynorm2 > PETSC_MACHINE_EPSILON) { 51550b47da0SAdam Denchfield switch (cg->cg_type) { 516484c7b14SAdam Denchfield case CG_PCGradientDescent: 51750b47da0SAdam Denchfield if (!cg->diag_scaling) { 518484c7b14SAdam Denchfield if (!cg->no_scaling) { 51950b47da0SAdam Denchfield cg->sts = step * step * dnorm * dnorm; 5209566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->sts, &tau_k, cg->alpha)); 521484c7b14SAdam Denchfield } else { 522484c7b14SAdam Denchfield tau_k = 1.0; 523484c7b14SAdam Denchfield ++cg->pure_gd_steps; 524484c7b14SAdam Denchfield } 5259566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient)); 52650b47da0SAdam Denchfield } else { 5279566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5289566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 52950b47da0SAdam Denchfield } 53050b47da0SAdam Denchfield break; 531484c7b14SAdam Denchfield 53250b47da0SAdam Denchfield case CG_HestenesStiefel: 53350b47da0SAdam Denchfield /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */ 53450b47da0SAdam Denchfield if (!cg->diag_scaling) { 53550b47da0SAdam Denchfield cg->sts = step * step * dnorm * dnorm; 5369566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5379566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->sts, &tau_k, cg->alpha)); 53850b47da0SAdam Denchfield beta = tau_k * gkp1_yk / dk_yk; 5399566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 54050b47da0SAdam Denchfield } else { 5419566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5429566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 54350b47da0SAdam Denchfield beta = gkp1_yk / dk_yk; 5449566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 54550b47da0SAdam Denchfield } 546c8bcdf1eSAdam Denchfield break; 547484c7b14SAdam Denchfield 548c8bcdf1eSAdam Denchfield case CG_FletcherReeves: 5499566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5509566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5519566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 55250b47da0SAdam Denchfield ynorm2 = ynorm * ynorm; 5539566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 55450b47da0SAdam Denchfield if (!cg->diag_scaling) { 5559566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, step * step * dnorm * dnorm, &tau_k, cg->alpha)); 55650b47da0SAdam Denchfield beta = tau_k * gnorm2 / gnorm2_old; 5579566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 55850b47da0SAdam Denchfield } else { 5599566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Before it's updated */ 5609566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5619566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, cg->g_work, &tmp)); 56250b47da0SAdam Denchfield beta = tmp / gnorm2_old; 5639566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 56450b47da0SAdam Denchfield } 565c8bcdf1eSAdam Denchfield break; 566484c7b14SAdam Denchfield 56750b47da0SAdam Denchfield case CG_PolakRibierePolyak: 56850b47da0SAdam Denchfield snorm = step * dnorm; 56950b47da0SAdam Denchfield if (!cg->diag_scaling) { 5709566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5719566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5729566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, snorm * snorm, &tau_k, cg->alpha)); 57350b47da0SAdam Denchfield beta = tau_k * gkp1_yk / gnorm2_old; 5749566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 57550b47da0SAdam Denchfield } else { 5769566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); 5779566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5789566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 57950b47da0SAdam Denchfield beta = gkp1_yk / gnorm2_old; 5809566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 58150b47da0SAdam Denchfield } 582c8bcdf1eSAdam Denchfield break; 583484c7b14SAdam Denchfield 584c8bcdf1eSAdam Denchfield case CG_PolakRibierePlus: 5859566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5869566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 58750b47da0SAdam Denchfield ynorm2 = ynorm * ynorm; 58850b47da0SAdam Denchfield if (!cg->diag_scaling) { 5899566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5909566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5919566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, snorm * snorm, &tau_k, cg->alpha)); 59250b47da0SAdam Denchfield beta = tau_k * gkp1_yk / gnorm2_old; 59350b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 5949566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 59550b47da0SAdam Denchfield } else { 5969566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Old gtDg */ 5979566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5989566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 59950b47da0SAdam Denchfield beta = gkp1_yk / gnorm2_old; 60050b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 6019566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 60250b47da0SAdam Denchfield } 603c8bcdf1eSAdam Denchfield break; 604484c7b14SAdam Denchfield 605484c7b14SAdam Denchfield case CG_DaiYuan: 606484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property." 607484c7b14SAdam Denchfield SIAM Journal on optimization 10, no. 1 (1999): 177-182. */ 60850b47da0SAdam Denchfield if (!cg->diag_scaling) { 6099566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, tao->gradient, &gd)); 6109566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6119566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->yts, &tau_k, cg->alpha)); 61250b47da0SAdam Denchfield beta = tau_k * gnorm2 / (gd - gd_old); 6139566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 61450b47da0SAdam Denchfield } else { 6159566063dSJacob Faibussowitsch PetscCall(MatMult(cg->B, tao->stepdirection, cg->d_work)); 6169566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6179566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, tao->gradient, >Dg)); 6189566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->G_old, &gd_old)); 6199566063dSJacob Faibussowitsch PetscCall(VecDot(cg->d_work, cg->g_work, &dk_yk)); 62050b47da0SAdam Denchfield dk_yk = dk_yk - gd_old; 62150b47da0SAdam Denchfield beta = gtDg / dk_yk; 6229566063dSJacob Faibussowitsch PetscCall(VecScale(cg->d_work, beta)); 6239566063dSJacob Faibussowitsch PetscCall(VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work)); 62450b47da0SAdam Denchfield } 625c8bcdf1eSAdam Denchfield break; 626484c7b14SAdam Denchfield 627c8bcdf1eSAdam Denchfield case CG_HagerZhang: 628484c7b14SAdam Denchfield /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent." 629484c7b14SAdam Denchfield ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */ 6309566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6319566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6329566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 63350b47da0SAdam Denchfield snorm = dnorm * step; 63450b47da0SAdam Denchfield cg->yts = step * dk_yk; 63548a46eb9SPierre Jolivet if (cg->use_dynamic_restart) PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 63650b47da0SAdam Denchfield if (cg->dynamic_restart) { 6379566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 638c8bcdf1eSAdam Denchfield } else { 639c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6409566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6419566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 642c8bcdf1eSAdam Denchfield /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */ 643c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 644c8bcdf1eSAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk)); 645c8bcdf1eSAdam Denchfield /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */ 64650b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * tau_k * gd_old / (dnorm * dnorm)), cg->dk_eta * tau_k * gd / (dnorm * dnorm)); 647c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6489566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 649c8bcdf1eSAdam Denchfield } else { 650c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 651c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 652c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 65350b47da0SAdam Denchfield /* Apply the diagonal scaling to all my vectors */ 6549566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6559566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6569566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 657c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 6589566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 659c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 660c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 6619566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 662c8bcdf1eSAdam Denchfield tau_k = -tau_k * gd / (dk_yk * dk_yk); 663c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 664484c7b14SAdam Denchfield beta = gkp1_yk / dk_yk + cg->hz_theta * tau_k; /* HZ; (1.15) from DK 2013 */ 665c8bcdf1eSAdam Denchfield /* From HZ2013, modified to account for diagonal scaling*/ 6669566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 6679566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 66850b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * gd_old / (dnorm * dnorm)), cg->dk_eta * gd / (dnorm * dnorm)); 669c8bcdf1eSAdam Denchfield /* Do the update */ 6709566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 67150b47da0SAdam Denchfield } 67250b47da0SAdam Denchfield } 673c8bcdf1eSAdam Denchfield break; 674484c7b14SAdam Denchfield 675c8bcdf1eSAdam Denchfield case CG_DaiKou: 676484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search." 677484c7b14SAdam Denchfield SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */ 6789566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6799566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6809566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 68150b47da0SAdam Denchfield snorm = step * dnorm; 68250b47da0SAdam Denchfield cg->yts = dk_yk * step; 683c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6849566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6859566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 686c8bcdf1eSAdam Denchfield /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */ 687c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 68850b47da0SAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk) + gd / (dnorm * dnorm)) - step * gd / dk_yk; 68950b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * tau_k * gd_old / (dnorm * dnorm)), cg->dk_eta * tau_k * gd / (dnorm * dnorm)); 690c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6919566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk)); 692c8bcdf1eSAdam Denchfield } else { 693c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 694c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 695c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 6969566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6979566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6989566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 699c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7009566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 7019566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 702c8bcdf1eSAdam Denchfield tau_k = tau_k * gd / (dk_yk * dk_yk); 703c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 704c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 705484c7b14SAdam Denchfield beta = gkp1_yk / dk_yk - step * tmp - tau_k; 706c8bcdf1eSAdam Denchfield /* Update this for the last term in beta */ 7079566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, tao->stepdirection, &dk_yk)); 708c8bcdf1eSAdam Denchfield beta += tmp * dk_yk / (dnorm * dnorm); /* projection of y_work onto dk */ 7099566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 7109566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 71150b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * gd_old / (dnorm * dnorm)), cg->dk_eta * gd / (dnorm * dnorm)); 712c8bcdf1eSAdam Denchfield /* Do the update */ 7139566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 71450b47da0SAdam Denchfield } 715c8bcdf1eSAdam Denchfield break; 716484c7b14SAdam Denchfield 717c8bcdf1eSAdam Denchfield case CG_KouDai: 718110fc3b0SBarry Smith /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization." 719484c7b14SAdam Denchfield Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */ 7209566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7219566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7229566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 72350b47da0SAdam Denchfield snorm = step * dnorm; 72450b47da0SAdam Denchfield cg->yts = dk_yk * step; 72548a46eb9SPierre Jolivet if (cg->use_dynamic_restart) PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 72650b47da0SAdam Denchfield if (cg->dynamic_restart) { 7279566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 728c8bcdf1eSAdam Denchfield } else { 729c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7309566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7319566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 732c8bcdf1eSAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk)) - step * gd / dk_yk; 733c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tau_k * gd / (dnorm * dnorm)) /* 0.1 is KD's zeta parameter */ 734c8bcdf1eSAdam Denchfield { 735c8bcdf1eSAdam Denchfield beta = cg->zeta * tau_k * gd / (dnorm * dnorm); 736c8bcdf1eSAdam Denchfield gamma = 0.0; 737c8bcdf1eSAdam Denchfield } else { 738c8bcdf1eSAdam Denchfield if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0 * gd / dk_yk; 739484c7b14SAdam Denchfield /* This seems to be very effective when there's no tau_k scaling. 740484c7b14SAdam Denchfield This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */ 741ad540459SPierre Jolivet else gamma = cg->xi * gd / dk_yk; 742c8bcdf1eSAdam Denchfield } 743c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7449566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma * tau_k, beta, tao->gradient, cg->yk)); 745c8bcdf1eSAdam Denchfield } else { 746c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 747c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 748c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 7499566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7509566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 751c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7529566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1D_yk)); 753c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 754c8bcdf1eSAdam Denchfield gamma = gd / dk_yk; 755c8bcdf1eSAdam Denchfield /* tau_k = -ytDy/(ytd)^2 * gd */ 7569566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 757c8bcdf1eSAdam Denchfield tau_k = tau_k * gd / (dk_yk * dk_yk); 758c8bcdf1eSAdam Denchfield /* beta is the constant which adds the d_k contribution */ 759c8bcdf1eSAdam Denchfield beta = gkp1D_yk / dk_yk - step * gamma - tau_k; 760c8bcdf1eSAdam Denchfield /* Here is the requisite check */ 7619566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &tmp)); 762c8bcdf1eSAdam Denchfield if (cg->neg_xi) { 763c8bcdf1eSAdam Denchfield /* modified KD implementation */ 764c8bcdf1eSAdam Denchfield if (gkp1D_yk / dk_yk < 0) gamma = -1.0 * gd / dk_yk; 765ad540459SPierre Jolivet else gamma = cg->xi * gd / dk_yk; 766c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tmp / (dnorm * dnorm)) { 767c8bcdf1eSAdam Denchfield beta = cg->zeta * tmp / (dnorm * dnorm); 768c8bcdf1eSAdam Denchfield gamma = 0.0; 769c8bcdf1eSAdam Denchfield } 770c8bcdf1eSAdam Denchfield } else { /* original KD 2015 implementation */ 771c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tmp / (dnorm * dnorm)) { 772c8bcdf1eSAdam Denchfield beta = cg->zeta * tmp / (dnorm * dnorm); 773c8bcdf1eSAdam Denchfield gamma = 0.0; 774ad540459SPierre Jolivet } else gamma = cg->xi * gd / dk_yk; 775c8bcdf1eSAdam Denchfield } 776c8bcdf1eSAdam Denchfield /* Do the update in two steps */ 7779566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 7789566063dSJacob Faibussowitsch PetscCall(VecAXPY(tao->stepdirection, gamma, cg->y_work)); 77950b47da0SAdam Denchfield } 78050b47da0SAdam Denchfield } 781c8bcdf1eSAdam Denchfield break; 782484c7b14SAdam Denchfield 783484c7b14SAdam Denchfield case CG_SSML_BFGS: 784484c7b14SAdam Denchfield /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory." 785484c7b14SAdam Denchfield Discussion Papers 269 (1977). */ 7869566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7879566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 788484c7b14SAdam Denchfield snorm = step * dnorm; 789484c7b14SAdam Denchfield cg->yts = dk_yk * step; 790484c7b14SAdam Denchfield cg->yty = ynorm2; 791484c7b14SAdam Denchfield cg->sts = snorm * snorm; 792484c7b14SAdam Denchfield if (!cg->diag_scaling) { 7939566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7949566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 795484c7b14SAdam Denchfield tmp = gd / dk_yk; 796484c7b14SAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - cg->yty * gd / (dk_yk * dk_yk)) - step * tmp; 797484c7b14SAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7989566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp * tau_k, beta, tao->gradient, cg->yk)); 799484c7b14SAdam Denchfield } else { 800484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 8019566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8029566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 803484c7b14SAdam Denchfield /* compute scalar gamma */ 8049566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8059566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 806484c7b14SAdam Denchfield gamma = gd / dk_yk; 807484c7b14SAdam Denchfield /* Compute scalar beta */ 808484c7b14SAdam Denchfield beta = (gkp1_yk / dk_yk - gd * tmp / (dk_yk * dk_yk)) - step * gd / dk_yk; 809484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8109566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 811484c7b14SAdam Denchfield } 812484c7b14SAdam Denchfield break; 813484c7b14SAdam Denchfield 814484c7b14SAdam Denchfield case CG_SSML_DFP: 8159566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8169566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 817484c7b14SAdam Denchfield snorm = step * dnorm; 818484c7b14SAdam Denchfield cg->yts = dk_yk * step; 819484c7b14SAdam Denchfield cg->yty = ynorm2; 820484c7b14SAdam Denchfield cg->sts = snorm * snorm; 821484c7b14SAdam Denchfield if (!cg->diag_scaling) { 822484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8239566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 8249566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 825484c7b14SAdam Denchfield tau_k = cg->dfp_scale * tau_k; 826484c7b14SAdam Denchfield tmp = tau_k * gkp1_yk / cg->yty; 827484c7b14SAdam Denchfield beta = -step * gd / dk_yk; 828484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8299566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 830484c7b14SAdam Denchfield } else { 831484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */ 8329566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8339566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 834484c7b14SAdam Denchfield /* compute scalar gamma */ 8359566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8369566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 837484c7b14SAdam Denchfield gamma = (gkp1_yk / tmp); 838484c7b14SAdam Denchfield /* Compute scalar beta */ 839484c7b14SAdam Denchfield beta = -step * gd / dk_yk; 840484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8419566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 842484c7b14SAdam Denchfield } 843484c7b14SAdam Denchfield break; 844484c7b14SAdam Denchfield 845484c7b14SAdam Denchfield case CG_SSML_BROYDEN: 8469566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8479566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 848484c7b14SAdam Denchfield snorm = step * dnorm; 849484c7b14SAdam Denchfield cg->yts = step * dk_yk; 850484c7b14SAdam Denchfield cg->yty = ynorm2; 851484c7b14SAdam Denchfield cg->sts = snorm * snorm; 852484c7b14SAdam Denchfield if (!cg->diag_scaling) { 853484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8549566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step * dk_yk, snorm * snorm, &tau_bfgs, cg->bfgs_scale)); 8559566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step * dk_yk, snorm * snorm, &tau_dfp, cg->dfp_scale)); 8569566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 857484c7b14SAdam Denchfield tau_k = cg->theta * tau_bfgs + (1.0 - cg->theta) * tau_dfp; 858484c7b14SAdam Denchfield /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, 859484c7b14SAdam Denchfield it should reproduce the tau_dfp scaling. Same with dfp_scale. */ 860484c7b14SAdam Denchfield tmp = cg->theta * tau_bfgs * gd / dk_yk + (1 - cg->theta) * tau_dfp * gkp1_yk / cg->yty; 861484c7b14SAdam Denchfield beta = cg->theta * tau_bfgs * (gkp1_yk / dk_yk - cg->yty * gd / (dk_yk * dk_yk)) - step * gd / dk_yk; 862484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8639566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 864484c7b14SAdam Denchfield } else { 865484c7b14SAdam Denchfield /* We have diagonal scaling enabled */ 8669566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8679566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 868484c7b14SAdam Denchfield /* compute scalar gamma */ 8699566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8709566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 871484c7b14SAdam Denchfield gamma = cg->theta * gd / dk_yk + (1 - cg->theta) * (gkp1_yk / tmp); 872484c7b14SAdam Denchfield /* Compute scalar beta */ 873484c7b14SAdam Denchfield beta = cg->theta * (gkp1_yk / dk_yk - gd * tmp / (dk_yk * dk_yk)) - step * gd / dk_yk; 874484c7b14SAdam Denchfield /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8759566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 876484c7b14SAdam Denchfield } 877484c7b14SAdam Denchfield break; 878484c7b14SAdam Denchfield 879*d71ae5a4SJacob Faibussowitsch default: 880*d71ae5a4SJacob Faibussowitsch break; 881c8bcdf1eSAdam Denchfield } 882c8bcdf1eSAdam Denchfield } 883c8bcdf1eSAdam Denchfield PetscFunctionReturn(0); 884c8bcdf1eSAdam Denchfield } 885c8bcdf1eSAdam Denchfield 886*d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm) 887*d71ae5a4SJacob Faibussowitsch { 888c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 889c8bcdf1eSAdam Denchfield TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 8908ca2df50S PetscReal step = 1.0, gnorm2, gd, dnorm = 0.0; 891c8bcdf1eSAdam Denchfield PetscReal gnorm2_old, f_old, resnorm, gnorm_old; 892c624ebd3SAlp Dener PetscBool pcgd_fallback = PETSC_FALSE; 893c8bcdf1eSAdam Denchfield 894c8bcdf1eSAdam Denchfield PetscFunctionBegin; 895c8bcdf1eSAdam Denchfield /* We are now going to perform a line search along the direction. */ 896c8bcdf1eSAdam Denchfield /* Store solution and gradient info before it changes */ 8979566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, cg->X_old)); 8989566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->gradient, cg->G_old)); 8999566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old)); 900c8bcdf1eSAdam Denchfield 901c8bcdf1eSAdam Denchfield gnorm_old = gnorm; 902c8bcdf1eSAdam Denchfield gnorm2_old = gnorm_old * gnorm_old; 903c8bcdf1eSAdam Denchfield f_old = cg->f; 904484c7b14SAdam Denchfield /* Perform bounded line search. If we are recycling a solution from a previous */ 905484c7b14SAdam Denchfield /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */ 906414d97d3SAlp Dener if (!(tao->recycle && 0 == tao->niter)) { 907484c7b14SAdam Denchfield /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */ 9089566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9099566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9109566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 911c8bcdf1eSAdam Denchfield 912c8bcdf1eSAdam Denchfield /* Check linesearch failure */ 913c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 914c8bcdf1eSAdam Denchfield ++cg->ls_fails; 915c624ebd3SAlp Dener if (cg->cg_type == CG_GradientDescent) { 916c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 917c8bcdf1eSAdam Denchfield step = 0.0; 918c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 919c8bcdf1eSAdam Denchfield } else { 920484c7b14SAdam Denchfield /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */ 9219566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->X_old, tao->solution)); 9229566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->G_old, tao->gradient)); 9239566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient)); 924c8bcdf1eSAdam Denchfield gnorm = gnorm_old; 925c8bcdf1eSAdam Denchfield gnorm2 = gnorm2_old; 926c8bcdf1eSAdam Denchfield cg->f = f_old; 927c8bcdf1eSAdam Denchfield 928484c7b14SAdam Denchfield /* Fall back on preconditioned CG (so long as you're not already using it) */ 929484c7b14SAdam Denchfield if (cg->cg_type != CG_PCGradientDescent && cg->diag_scaling) { 930e2570530SAlp Dener pcgd_fallback = PETSC_TRUE; 9319566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 932484c7b14SAdam Denchfield 9339566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9349566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 935c8bcdf1eSAdam Denchfield 9369566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9379566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9389566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 939c8bcdf1eSAdam Denchfield 940484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 941484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 942484c7b14SAdam Denchfield /* Going to perform a regular gradient descent step. */ 943484c7b14SAdam Denchfield ++cg->ls_fails; 944484c7b14SAdam Denchfield step = 0.0; 945484c7b14SAdam Denchfield } 946484c7b14SAdam Denchfield } 947484c7b14SAdam Denchfield /* Fall back on the scaled gradient step */ 948484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 949484c7b14SAdam Denchfield ++cg->ls_fails; 9509566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9519566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 9529566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9539566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9549566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 955484c7b14SAdam Denchfield } 956484c7b14SAdam Denchfield 957c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 958c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 95950b47da0SAdam Denchfield ++cg->ls_fails; 960c8bcdf1eSAdam Denchfield step = 0.0; 961c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 962484c7b14SAdam Denchfield } else { 963484c7b14SAdam Denchfield /* One of the fallbacks worked. Set them both back equal to false. */ 964484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 965c8bcdf1eSAdam Denchfield } 966c8bcdf1eSAdam Denchfield } 967c8bcdf1eSAdam Denchfield } 968c8bcdf1eSAdam Denchfield /* Convergence test for line search failure */ 969c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 970c8bcdf1eSAdam Denchfield 971c8bcdf1eSAdam Denchfield /* Standard convergence test */ 9729566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 9739566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 9743c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 9759566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 9769566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 977dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 978c8bcdf1eSAdam Denchfield if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 979484c7b14SAdam Denchfield } 980c8bcdf1eSAdam Denchfield /* Assert we have an updated step and we need at least one more iteration. */ 981c8bcdf1eSAdam Denchfield /* Calculate the next direction */ 982c8bcdf1eSAdam Denchfield /* Estimate the active set at the new solution */ 9839566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 984c8bcdf1eSAdam Denchfield /* Compute the projected gradient and its norm */ 9859566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 9869566063dSJacob Faibussowitsch PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 9879566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient, NORM_2, &gnorm)); 988c8bcdf1eSAdam Denchfield gnorm2 = gnorm * gnorm; 989c8bcdf1eSAdam Denchfield 990484c7b14SAdam Denchfield /* Calculate some quantities used in the StepDirectionUpdate. */ 9919566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 992484c7b14SAdam Denchfield /* Update the step direction. */ 9939566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 994484c7b14SAdam Denchfield ++tao->niter; 9959566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 996c8bcdf1eSAdam Denchfield 997c8bcdf1eSAdam Denchfield if (cg->cg_type != CG_GradientDescent) { 998c8bcdf1eSAdam Denchfield /* Figure out which previously active variables became inactive this iteration */ 9999566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 100048a46eb9SPierre Jolivet if (cg->inactive_idx && cg->inactive_old) PetscCall(ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives)); 1001c8bcdf1eSAdam Denchfield /* Selectively reset the CG step those freshly inactive variables */ 1002c8bcdf1eSAdam Denchfield if (cg->new_inactives) { 10039566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10049566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 10059566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->inactive_grad, cg->inactive_step)); 10069566063dSJacob Faibussowitsch PetscCall(VecScale(cg->inactive_step, -1.0)); 10079566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 10089566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 1009c8bcdf1eSAdam Denchfield } 1010c8bcdf1eSAdam Denchfield /* Verify that this is a descent direction */ 10119566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 10129566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 101350b47da0SAdam Denchfield if (PetscIsInfOrNanReal(gd) || (gd / (dnorm * dnorm) <= -1e10 || gd / (dnorm * dnorm) >= -1e-10)) { 1014c8bcdf1eSAdam Denchfield /* Not a descent direction, so we reset back to projected gradient descent */ 10159566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 10169566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 1017c8bcdf1eSAdam Denchfield ++cg->descent_error; 1018c8bcdf1eSAdam Denchfield } else { 1019c8bcdf1eSAdam Denchfield } 1020c8bcdf1eSAdam Denchfield } 1021ac9112b8SAlp Dener PetscFunctionReturn(0); 1022ac9112b8SAlp Dener } 1023484c7b14SAdam Denchfield 1024*d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0) 1025*d71ae5a4SJacob Faibussowitsch { 1026484c7b14SAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 1027484c7b14SAdam Denchfield 1028484c7b14SAdam Denchfield PetscFunctionBegin; 10299566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)H0)); 1030484c7b14SAdam Denchfield cg->pc = H0; 1031484c7b14SAdam Denchfield PetscFunctionReturn(0); 1032484c7b14SAdam Denchfield } 1033