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 5d6e07cdcSHong Zhang const char *const TaoBNCGTypes[] = {"gd", "pcgd", "hs", "fr", "prp", "prp_plus", "dy", "hz", "dk", "kd", "ssml_bfgs", "ssml_dfp", "ssml_brdn", "TAOBNCGType", "TAO_BNCG_", NULL}; 6ac9112b8SAlp Dener 761be54a6SAlp Dener #define CG_AS_NONE 0 861be54a6SAlp Dener #define CG_AS_BERTSEKAS 1 961be54a6SAlp Dener #define CG_AS_SIZE 2 10ac9112b8SAlp Dener 1161be54a6SAlp Dener static const char *CG_AS_TYPE[64] = {"none", "bertsekas"}; 12ac9112b8SAlp Dener 13d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType) 14d71ae5a4SJacob Faibussowitsch { 1561be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 1661be54a6SAlp Dener 1761be54a6SAlp Dener PetscFunctionBegin; 189566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 1961be54a6SAlp Dener if (cg->inactive_idx) { 209566063dSJacob Faibussowitsch PetscCall(ISDuplicate(cg->inactive_idx, &cg->inactive_old)); 219566063dSJacob Faibussowitsch PetscCall(ISCopy(cg->inactive_idx, cg->inactive_old)); 2261be54a6SAlp Dener } 2361be54a6SAlp Dener switch (asType) { 2461be54a6SAlp Dener case CG_AS_NONE: 259566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 269566063dSJacob Faibussowitsch PetscCall(VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx)); 279566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 289566063dSJacob Faibussowitsch PetscCall(ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx)); 2961be54a6SAlp Dener break; 3061be54a6SAlp Dener case CG_AS_BERTSEKAS: 3161be54a6SAlp Dener /* Use gradient descent to estimate the active set */ 329566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->W)); 339566063dSJacob Faibussowitsch PetscCall(VecScale(cg->W, -1.0)); 349371c9d4SSatish 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)); 35c4b75bccSAlp Dener break; 36d71ae5a4SJacob Faibussowitsch default: 37d71ae5a4SJacob Faibussowitsch break; 3861be54a6SAlp Dener } 393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4061be54a6SAlp Dener } 4161be54a6SAlp Dener 42d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step) 43d71ae5a4SJacob Faibussowitsch { 4461be54a6SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 4561be54a6SAlp Dener 4661be54a6SAlp Dener PetscFunctionBegin; 47a1318120SAlp Dener switch (asType) { 48d71ae5a4SJacob Faibussowitsch case CG_AS_NONE: 49976ed0a4SStefano Zampini if (cg->active_idx) PetscCall(VecISSet(step, cg->active_idx, 0.0)); 50d71ae5a4SJacob Faibussowitsch break; 51d71ae5a4SJacob Faibussowitsch case CG_AS_BERTSEKAS: 52d71ae5a4SJacob Faibussowitsch PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step)); 53d71ae5a4SJacob Faibussowitsch break; 54d71ae5a4SJacob Faibussowitsch default: 55d71ae5a4SJacob Faibussowitsch break; 5661be54a6SAlp Dener } 573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5861be54a6SAlp Dener } 5961be54a6SAlp Dener 60d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_BNCG(Tao tao) 61d71ae5a4SJacob Faibussowitsch { 62ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 63484c7b14SAdam Denchfield PetscReal step = 1.0, gnorm, gnorm2, resnorm; 64c4b75bccSAlp Dener PetscInt nDiff; 65ac9112b8SAlp Dener 66ac9112b8SAlp Dener PetscFunctionBegin; 67ac9112b8SAlp Dener /* Project the current point onto the feasible set */ 689566063dSJacob Faibussowitsch PetscCall(TaoComputeVariableBounds(tao)); 699566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch, tao->XL, tao->XU)); 70ac9112b8SAlp Dener 71c8bcdf1eSAdam Denchfield /* Project the initial point onto the feasible region */ 729566063dSJacob Faibussowitsch PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution)); 73484c7b14SAdam Denchfield 7448a46eb9SPierre Jolivet if (nDiff > 0 || !tao->recycle) PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 759566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->unprojected_gradient, NORM_2, &gnorm)); 763c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(cg->f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 77ac9112b8SAlp Dener 7861be54a6SAlp Dener /* Estimate the active set and compute the projected gradient */ 799566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 8061be54a6SAlp Dener 81ac9112b8SAlp Dener /* Project the gradient and calculate the norm */ 829566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 83976ed0a4SStefano Zampini if (cg->active_idx) PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 849566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient, NORM_2, &gnorm)); 85ac9112b8SAlp Dener gnorm2 = gnorm * gnorm; 86ac9112b8SAlp Dener 87c8bcdf1eSAdam Denchfield /* Initialize counters */ 88e031d6f5SAlp Dener tao->niter = 0; 8950b47da0SAdam Denchfield cg->ls_fails = cg->descent_error = 0; 90c8bcdf1eSAdam Denchfield cg->resets = -1; 91484c7b14SAdam Denchfield cg->skipped_updates = cg->pure_gd_steps = 0; 92c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 93c8bcdf1eSAdam Denchfield 94c8bcdf1eSAdam Denchfield /* Convergence test at the starting point. */ 95ac9112b8SAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 96484c7b14SAdam Denchfield 979566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 989566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 993c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 1009566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 1019566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 102dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 1033ba16761SJacob Faibussowitsch if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS); 104484c7b14SAdam Denchfield /* Calculate initial direction. */ 105414d97d3SAlp Dener if (!tao->recycle) { 106484c7b14SAdam Denchfield /* We are not recycling a solution/history from a past TaoSolve */ 1079566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 108ac9112b8SAlp Dener } 109c8bcdf1eSAdam Denchfield /* Initial gradient descent step. Scaling by 1.0 also does a decent job for some problems. */ 110c8bcdf1eSAdam Denchfield while (1) { 111e1e80dc8SAlp Dener /* Call general purpose update function */ 112e1e80dc8SAlp Dener if (tao->ops->update) { 113dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, update, tao->niter, tao->user_update); 1147494f0b1SStefano Zampini PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient)); 115e1e80dc8SAlp Dener } 1169566063dSJacob Faibussowitsch PetscCall(TaoBNCGConductIteration(tao, gnorm)); 1173ba16761SJacob Faibussowitsch if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS); 118ac9112b8SAlp Dener } 119ac9112b8SAlp Dener } 120ac9112b8SAlp Dener 121d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_BNCG(Tao tao) 122d71ae5a4SJacob Faibussowitsch { 123ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 124ac9112b8SAlp Dener 125ac9112b8SAlp Dener PetscFunctionBegin; 12648a46eb9SPierre Jolivet if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient)); 12748a46eb9SPierre Jolivet if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection)); 12848a46eb9SPierre Jolivet if (!cg->W) PetscCall(VecDuplicate(tao->solution, &cg->W)); 12948a46eb9SPierre Jolivet if (!cg->work) PetscCall(VecDuplicate(tao->solution, &cg->work)); 13048a46eb9SPierre Jolivet if (!cg->sk) PetscCall(VecDuplicate(tao->solution, &cg->sk)); 13148a46eb9SPierre Jolivet if (!cg->yk) PetscCall(VecDuplicate(tao->gradient, &cg->yk)); 13248a46eb9SPierre Jolivet if (!cg->X_old) PetscCall(VecDuplicate(tao->solution, &cg->X_old)); 13348a46eb9SPierre Jolivet if (!cg->G_old) PetscCall(VecDuplicate(tao->gradient, &cg->G_old)); 134c8bcdf1eSAdam Denchfield if (cg->diag_scaling) { 1359566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->d_work)); 1369566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->y_work)); 1379566063dSJacob Faibussowitsch PetscCall(VecDuplicate(tao->solution, &cg->g_work)); 138c4b75bccSAlp Dener } 13948a46eb9SPierre Jolivet if (!cg->unprojected_gradient) PetscCall(VecDuplicate(tao->gradient, &cg->unprojected_gradient)); 14048a46eb9SPierre Jolivet if (!cg->unprojected_gradient_old) PetscCall(VecDuplicate(tao->gradient, &cg->unprojected_gradient_old)); 1419566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(cg->B, cg->sk, cg->yk)); 1421baa6e33SBarry Smith if (cg->pc) PetscCall(MatLMVMSetJ0(cg->B, cg->pc)); 1433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 144ac9112b8SAlp Dener } 145ac9112b8SAlp Dener 146d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_BNCG(Tao tao) 147d71ae5a4SJacob Faibussowitsch { 148ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 149ac9112b8SAlp Dener 150ac9112b8SAlp Dener PetscFunctionBegin; 151ac9112b8SAlp Dener if (tao->setupcalled) { 1529566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->W)); 1539566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->work)); 1549566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->X_old)); 1559566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->G_old)); 1569566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient)); 1579566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->unprojected_gradient_old)); 1589566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->g_work)); 1599566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->d_work)); 1609566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->y_work)); 1619566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->sk)); 1629566063dSJacob Faibussowitsch PetscCall(VecDestroy(&cg->yk)); 163ac9112b8SAlp Dener } 1649566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_lower)); 1659566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_upper)); 1669566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_fixed)); 1679566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->active_idx)); 1689566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_idx)); 1699566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->inactive_old)); 1709566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 1719566063dSJacob Faibussowitsch PetscCall(MatDestroy(&cg->B)); 17248a46eb9SPierre Jolivet if (cg->pc) PetscCall(MatDestroy(&cg->pc)); 1739566063dSJacob Faibussowitsch PetscCall(PetscFree(tao->data)); 1743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 175ac9112b8SAlp Dener } 176ac9112b8SAlp Dener 177d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_BNCG(Tao tao, PetscOptionItems *PetscOptionsObject) 178d71ae5a4SJacob Faibussowitsch { 179ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 180ac9112b8SAlp Dener 181ac9112b8SAlp Dener PetscFunctionBegin; 182d0609cedSBarry Smith PetscOptionsHeadBegin(PetscOptionsObject, "Nonlinear Conjugate Gradient method for unconstrained optimization"); 183d6e07cdcSHong Zhang PetscCall(PetscOptionsEnum("-tao_bncg_type", "CG update formula", "TaoBNCGTypes", TaoBNCGTypes, (PetscEnum)cg->cg_type, (PetscEnum *)&cg->cg_type, NULL)); 184d6e07cdcSHong Zhang if (cg->cg_type != TAO_BNCG_SSML_BFGS) cg->alpha = -1.0; /* Setting defaults for non-BFGS methods. User can change it below. */ 185d6e07cdcSHong Zhang if (TAO_BNCG_GD == cg->cg_type) { 186d6e07cdcSHong Zhang cg->cg_type = TAO_BNCG_PCGD; 187484c7b14SAdam Denchfield /* Set scaling equal to none or, at best, scalar scaling. */ 188484c7b14SAdam Denchfield cg->unscaled_restart = PETSC_TRUE; 189484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 190484c7b14SAdam Denchfield } 1919566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_eta", "(developer) cutoff tolerance for HZ", "", cg->hz_eta, &cg->hz_eta, NULL)); 1929566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_eps", "(developer) cutoff value for restarts", "", cg->epsilon, &cg->epsilon, NULL)); 1939566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dk_eta", "(developer) cutoff tolerance for DK", "", cg->dk_eta, &cg->dk_eta, NULL)); 1949566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_xi", "(developer) Parameter in the KD method", "", cg->xi, &cg->xi, NULL)); 1959566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_theta", "(developer) update parameter for the Broyden method", "", cg->theta, &cg->theta, NULL)); 1969566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_hz_theta", "(developer) parameter for the HZ (2006) method", "", cg->hz_theta, &cg->hz_theta, NULL)); 1979566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_alpha", "(developer) parameter for the scalar scaling", "", cg->alpha, &cg->alpha, NULL)); 1989566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_bfgs_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->bfgs_scale, &cg->bfgs_scale, NULL)); 1999566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_dfp_scale", "(developer) update parameter for bfgs/brdn CG methods", "", cg->dfp_scale, &cg->dfp_scale, NULL)); 2009566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_diag_scaling", "Enable diagonal Broyden-like preconditioning", "", cg->diag_scaling, &cg->diag_scaling, NULL)); 2019566063dSJacob 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)); 2029566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_unscaled_restart", "(developer) use unscaled gradient restarts", "", cg->unscaled_restart, &cg->unscaled_restart, NULL)); 2039566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_zeta", "(developer) Free parameter for the Kou-Dai method", "", cg->zeta, &cg->zeta, NULL)); 2049566063dSJacob 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)); 2059566063dSJacob 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)); 2069566063dSJacob 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)); 2079566063dSJacob Faibussowitsch PetscCall(PetscOptionsBool("-tao_bncg_no_scaling", "Disable all scaling except in restarts", "", cg->no_scaling, &cg->no_scaling, NULL)); 208484c7b14SAdam Denchfield if (cg->no_scaling) { 209484c7b14SAdam Denchfield cg->diag_scaling = PETSC_FALSE; 210484c7b14SAdam Denchfield cg->alpha = -1.0; 211484c7b14SAdam Denchfield } 212d6e07cdcSHong Zhang if (cg->alpha == -1.0 && cg->cg_type == TAO_BNCG_KD && !cg->diag_scaling) { /* Some more default options that appear to be good. */ 213484c7b14SAdam Denchfield cg->neg_xi = PETSC_TRUE; 214484c7b14SAdam Denchfield } 2159566063dSJacob 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)); 216d6e07cdcSHong Zhang PetscCall(PetscOptionsEList("-tao_bncg_as_type", "active set estimation method", "", CG_AS_TYPE, CG_AS_SIZE, CG_AS_TYPE[cg->as_type], &cg->as_type, NULL)); 2179566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", cg->as_tol, &cg->as_tol, NULL)); 2189566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_as_step", "(developer) step length used when estimating actively bounded variables", "", cg->as_step, &cg->as_step, NULL)); 2199566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_min", "(developer) minimum scaling factor used for scaled gradient restarts", "", cg->delta_min, &cg->delta_min, NULL)); 2209566063dSJacob Faibussowitsch PetscCall(PetscOptionsReal("-tao_bncg_delta_max", "(developer) maximum scaling factor used for scaled gradient restarts", "", cg->delta_max, &cg->delta_max, NULL)); 22150b47da0SAdam Denchfield 222d0609cedSBarry Smith PetscOptionsHeadEnd(); 2239566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(cg->B, ((PetscObject)tao)->prefix)); 2249566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(cg->B, "tao_bncg_")); 2259566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(cg->B)); 2263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 227ac9112b8SAlp Dener } 228ac9112b8SAlp Dener 229d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 230d71ae5a4SJacob Faibussowitsch { 231ac9112b8SAlp Dener PetscBool isascii; 232ac9112b8SAlp Dener TAO_BNCG *cg = (TAO_BNCG *)tao->data; 233ac9112b8SAlp Dener 234ac9112b8SAlp Dener PetscFunctionBegin; 2359566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 236ac9112b8SAlp Dener if (isascii) { 2379566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 238d6e07cdcSHong Zhang PetscCall(PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", TaoBNCGTypes[cg->cg_type])); 23963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Skipped Stepdirection Updates: %" PetscInt_FMT "\n", cg->skipped_updates)); 24063a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", cg->resets)); 24163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Pure gradient steps: %" PetscInt_FMT "\n", cg->pure_gd_steps)); 24263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Not a descent direction: %" PetscInt_FMT "\n", cg->descent_error)); 24363a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Line search fails: %" PetscInt_FMT "\n", cg->ls_fails)); 244484c7b14SAdam Denchfield if (cg->diag_scaling) { 2459566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 246484c7b14SAdam Denchfield if (isascii) { 2479566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 2489566063dSJacob Faibussowitsch PetscCall(MatView(cg->B, viewer)); 2499566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 250484c7b14SAdam Denchfield } 251484c7b14SAdam Denchfield } 2529566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 253ac9112b8SAlp Dener } 2543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 255ac9112b8SAlp Dener } 256ac9112b8SAlp Dener 257d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGComputeScalarScaling(PetscReal yty, PetscReal yts, PetscReal sts, PetscReal *scale, PetscReal alpha) 258d71ae5a4SJacob Faibussowitsch { 259c8bcdf1eSAdam Denchfield PetscReal a, b, c, sig1, sig2; 260c8bcdf1eSAdam Denchfield 261c8bcdf1eSAdam Denchfield PetscFunctionBegin; 262c8bcdf1eSAdam Denchfield *scale = 0.0; 2638ebe3e4eSStefano Zampini if (1.0 == alpha) *scale = yts / yty; 2648ebe3e4eSStefano Zampini else if (0.0 == alpha) *scale = sts / yts; 26550b47da0SAdam Denchfield else if (-1.0 == alpha) *scale = 1.0; 266c8bcdf1eSAdam Denchfield else { 267c8bcdf1eSAdam Denchfield a = yty; 268c8bcdf1eSAdam Denchfield b = yts; 269c8bcdf1eSAdam Denchfield c = sts; 270c8bcdf1eSAdam Denchfield a *= alpha; 271c8bcdf1eSAdam Denchfield b *= -(2.0 * alpha - 1.0); 272c8bcdf1eSAdam Denchfield c *= alpha - 1.0; 273c8bcdf1eSAdam Denchfield sig1 = (-b + PetscSqrtReal(b * b - 4.0 * a * c)) / (2.0 * a); 274c8bcdf1eSAdam Denchfield sig2 = (-b - PetscSqrtReal(b * b - 4.0 * a * c)) / (2.0 * a); 275c8bcdf1eSAdam Denchfield /* accept the positive root as the scalar */ 2768ebe3e4eSStefano Zampini if (sig1 > 0.0) *scale = sig1; 2778ebe3e4eSStefano Zampini else if (sig2 > 0.0) *scale = sig2; 2788ebe3e4eSStefano Zampini else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Cannot find positive scalar"); 279c8bcdf1eSAdam Denchfield } 2803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 281c8bcdf1eSAdam Denchfield } 282c8bcdf1eSAdam Denchfield 283ac9112b8SAlp Dener /*MC 284ac9112b8SAlp Dener TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 285ac9112b8SAlp Dener 286ac9112b8SAlp Dener Options Database Keys: 28750b47da0SAdam Denchfield + -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls (currently disabled) 288c4b75bccSAlp Dener . -tao_bncg_eta <r> - restart tolerance 28961be54a6SAlp Dener . -tao_bncg_type <taocg_type> - cg formula 290c4b75bccSAlp Dener . -tao_bncg_as_type <none,bertsekas> - active set estimation method 291c4b75bccSAlp Dener . -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation 292c4b75bccSAlp Dener . -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation 29350b47da0SAdam 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. 29450b47da0SAdam Denchfield . -tao_bncg_theta <r> - convex combination parameter for the Broyden method 29550b47da0SAdam Denchfield . -tao_bncg_hz_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 29650b47da0SAdam Denchfield . -tao_bncg_dk_eta <r> - cutoff tolerance for the beta term in the HZ, DK methods 29750b47da0SAdam Denchfield . -tao_bncg_xi <r> - Multiplicative constant of the gamma term in the KD method 29850b47da0SAdam Denchfield . -tao_bncg_hz_theta <r> - Multiplicative constant of the theta term for the HZ method 29950b47da0SAdam Denchfield . -tao_bncg_bfgs_scale <r> - Scaling parameter of the bfgs contribution to the scalar Broyden method 30050b47da0SAdam Denchfield . -tao_bncg_dfp_scale <r> - Scaling parameter of the dfp contribution to the scalar Broyden method 30150b47da0SAdam Denchfield . -tao_bncg_diag_scaling <b> - Whether or not to use diagonal initialization/preconditioning for the CG methods. Default True. 30250b47da0SAdam Denchfield . -tao_bncg_dynamic_restart <b> - use dynamic restart strategy in the HZ, DK, KD methods 30350b47da0SAdam Denchfield . -tao_bncg_unscaled_restart <b> - whether or not to scale the gradient when doing gradient descent restarts 30450b47da0SAdam Denchfield . -tao_bncg_zeta <r> - Scaling parameter in the KD method 305484c7b14SAdam Denchfield . -tao_bncg_delta_min <r> - Minimum bound for rescaling during restarted gradient descent steps 306484c7b14SAdam Denchfield . -tao_bncg_delta_max <r> - Maximum bound for rescaling during restarted gradient descent steps 30750b47da0SAdam Denchfield . -tao_bncg_min_quad <i> - Number of quadratic-like steps in a row necessary to do a dynamic restart 30850b47da0SAdam 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 30950b47da0SAdam Denchfield . -tao_bncg_spaced_restart <b> - whether or not to do gradient descent steps every x*n iterations 310484c7b14SAdam Denchfield . -tao_bncg_no_scaling <b> - If true, eliminates all scaling, including defaults. 3113850be85SAlp Dener - -tao_bncg_neg_xi <b> - Whether or not to use negative xi in the KD method under certain conditions 312ac9112b8SAlp Dener 313ac9112b8SAlp Dener Notes: 314ac9112b8SAlp Dener CG formulas are: 3153850be85SAlp Dener + "gd" - Gradient Descent 3163850be85SAlp Dener . "fr" - Fletcher-Reeves 3173850be85SAlp Dener . "pr" - Polak-Ribiere-Polyak 3183850be85SAlp Dener . "prp" - Polak-Ribiere-Plus 3193850be85SAlp Dener . "hs" - Hestenes-Steifel 3203850be85SAlp Dener . "dy" - Dai-Yuan 3213850be85SAlp Dener . "ssml_bfgs" - Self-Scaling Memoryless BFGS 3223850be85SAlp Dener . "ssml_dfp" - Self-Scaling Memoryless DFP 3233850be85SAlp Dener . "ssml_brdn" - Self-Scaling Memoryless Broyden 3243850be85SAlp Dener . "hz" - Hager-Zhang (CG_DESCENT 5.3) 3253850be85SAlp Dener . "dk" - Dai-Kou (2013) 3263850be85SAlp Dener - "kd" - Kou-Dai (2015) 3279abc5736SPatrick Sanan 328ac9112b8SAlp Dener Level: beginner 329ac9112b8SAlp Dener M*/ 330ac9112b8SAlp Dener 331d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 332d71ae5a4SJacob Faibussowitsch { 333ac9112b8SAlp Dener TAO_BNCG *cg; 334ac9112b8SAlp Dener const char *morethuente_type = TAOLINESEARCHMT; 335ac9112b8SAlp Dener 336ac9112b8SAlp Dener PetscFunctionBegin; 337ac9112b8SAlp Dener tao->ops->setup = TaoSetUp_BNCG; 338ac9112b8SAlp Dener tao->ops->solve = TaoSolve_BNCG; 339ac9112b8SAlp Dener tao->ops->view = TaoView_BNCG; 340ac9112b8SAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 341ac9112b8SAlp Dener tao->ops->destroy = TaoDestroy_BNCG; 342ac9112b8SAlp Dener 343ac9112b8SAlp Dener /* Override default settings (unless already changed) */ 344ac9112b8SAlp Dener if (!tao->max_it_changed) tao->max_it = 2000; 345ac9112b8SAlp Dener if (!tao->max_funcs_changed) tao->max_funcs = 4000; 346ac9112b8SAlp Dener 347ac9112b8SAlp Dener /* Note: nondefault values should be used for nonlinear conjugate gradient */ 348ac9112b8SAlp Dener /* method. In particular, gtol should be less that 0.5; the value used in */ 349ac9112b8SAlp Dener /* Nocedal and Wright is 0.10. We use the default values for the */ 350ac9112b8SAlp Dener /* linesearch because it seems to work better. */ 3519566063dSJacob Faibussowitsch PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch)); 3529566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1)); 3539566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type)); 3549566063dSJacob Faibussowitsch PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao)); 355ac9112b8SAlp Dener 3564dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&cg)); 357ac9112b8SAlp Dener tao->data = (void *)cg; 3589566063dSJacob Faibussowitsch PetscCall(KSPInitializePackage()); 3599566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &cg->B)); 3609566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)cg->B, (PetscObject)tao, 1)); 3619566063dSJacob Faibussowitsch PetscCall(MatSetType(cg->B, MATLMVMDIAGBROYDEN)); 36250b47da0SAdam Denchfield 363484c7b14SAdam Denchfield cg->pc = NULL; 364484c7b14SAdam Denchfield 36550b47da0SAdam Denchfield cg->dk_eta = 0.5; 36650b47da0SAdam Denchfield cg->hz_eta = 0.4; 367c8bcdf1eSAdam Denchfield cg->dynamic_restart = PETSC_FALSE; 368c8bcdf1eSAdam Denchfield cg->unscaled_restart = PETSC_FALSE; 369484c7b14SAdam Denchfield cg->no_scaling = PETSC_FALSE; 370484c7b14SAdam Denchfield cg->delta_min = 1e-7; 371484c7b14SAdam Denchfield cg->delta_max = 100; 372c8bcdf1eSAdam Denchfield cg->theta = 1.0; 373c8bcdf1eSAdam Denchfield cg->hz_theta = 1.0; 374c8bcdf1eSAdam Denchfield cg->dfp_scale = 1.0; 375c8bcdf1eSAdam Denchfield cg->bfgs_scale = 1.0; 37650b47da0SAdam Denchfield cg->zeta = 0.1; 37750b47da0SAdam Denchfield cg->min_quad = 6; 378c8bcdf1eSAdam Denchfield cg->min_restart_num = 6; /* As in CG_DESCENT and KD2015*/ 379c8bcdf1eSAdam Denchfield cg->xi = 1.0; 38050b47da0SAdam Denchfield cg->neg_xi = PETSC_TRUE; 381c8bcdf1eSAdam Denchfield cg->spaced_restart = PETSC_FALSE; 382c8bcdf1eSAdam Denchfield cg->tol_quad = 1e-8; 38361be54a6SAlp Dener cg->as_step = 0.001; 38461be54a6SAlp Dener cg->as_tol = 0.001; 38550b47da0SAdam Denchfield cg->eps_23 = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0 / 3.0); /* Just a little tighter*/ 38661be54a6SAlp Dener cg->as_type = CG_AS_BERTSEKAS; 387d6e07cdcSHong Zhang cg->cg_type = TAO_BNCG_SSML_BFGS; 388c8bcdf1eSAdam Denchfield cg->alpha = 1.0; 389c8bcdf1eSAdam Denchfield cg->diag_scaling = PETSC_TRUE; 3903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 391c8bcdf1eSAdam Denchfield } 392c8bcdf1eSAdam Denchfield 393d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGResetUpdate(Tao tao, PetscReal gnormsq) 394d71ae5a4SJacob Faibussowitsch { 395c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 396c8bcdf1eSAdam Denchfield PetscReal scaling; 397c8bcdf1eSAdam Denchfield 398c8bcdf1eSAdam Denchfield PetscFunctionBegin; 399c8bcdf1eSAdam Denchfield ++cg->resets; 400c8bcdf1eSAdam Denchfield scaling = 2.0 * PetscMax(1.0, PetscAbsScalar(cg->f)) / PetscMax(gnormsq, cg->eps_23); 401484c7b14SAdam Denchfield scaling = PetscMin(cg->delta_max, PetscMax(cg->delta_min, scaling)); 402484c7b14SAdam Denchfield if (cg->unscaled_restart) { 403484c7b14SAdam Denchfield scaling = 1.0; 404484c7b14SAdam Denchfield ++cg->pure_gd_steps; 405484c7b14SAdam Denchfield } 4069566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -scaling, 0.0, tao->gradient)); 407c8bcdf1eSAdam Denchfield /* Also want to reset our diagonal scaling with each restart */ 4081baa6e33SBarry Smith if (cg->diag_scaling) PetscCall(MatLMVMReset(cg->B, PETSC_FALSE)); 4093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 410c8bcdf1eSAdam Denchfield } 411c8bcdf1eSAdam Denchfield 412d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNCGCheckDynamicRestart(Tao tao, PetscReal stepsize, PetscReal gd, PetscReal gd_old, PetscBool *dynrestart, PetscReal fold) 413d71ae5a4SJacob Faibussowitsch { 414c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 415c8bcdf1eSAdam Denchfield PetscReal quadinterp; 416c8bcdf1eSAdam Denchfield 417c8bcdf1eSAdam Denchfield PetscFunctionBegin; 41850b47da0SAdam Denchfield if (cg->f < cg->min_quad / 10) { 41950b47da0SAdam Denchfield *dynrestart = PETSC_FALSE; 4203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 42150b47da0SAdam Denchfield } /* just skip this since this strategy doesn't work well for functions near zero */ 422484c7b14SAdam Denchfield quadinterp = 2.0 * (cg->f - fold) / (stepsize * (gd + gd_old)); 42350b47da0SAdam Denchfield if (PetscAbs(quadinterp - 1.0) < cg->tol_quad) ++cg->iter_quad; 424c8bcdf1eSAdam Denchfield else { 425c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 426c8bcdf1eSAdam Denchfield *dynrestart = PETSC_FALSE; 427c8bcdf1eSAdam Denchfield } 428c8bcdf1eSAdam Denchfield if (cg->iter_quad >= cg->min_quad) { 429c8bcdf1eSAdam Denchfield cg->iter_quad = 0; 430c8bcdf1eSAdam Denchfield *dynrestart = PETSC_TRUE; 431c8bcdf1eSAdam Denchfield } 4323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 433c8bcdf1eSAdam Denchfield } 434c8bcdf1eSAdam Denchfield 435d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode TaoBNCGStepDirectionUpdate(Tao tao, PetscReal gnorm2, PetscReal step, PetscReal fold, PetscReal gnorm2_old, PetscReal dnorm, PetscBool pcgd_fallback) 436d71ae5a4SJacob Faibussowitsch { 437c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 43850b47da0SAdam Denchfield PetscReal gamma = 1.0, tau_k, beta; 439484c7b14SAdam Denchfield PetscReal tmp = 1.0, ynorm, ynorm2 = 1.0, snorm = 1.0, dk_yk = 1.0, gd; 44050b47da0SAdam Denchfield PetscReal gkp1_yk, gd_old, tau_bfgs, tau_dfp, gkp1D_yk, gtDg; 441c8bcdf1eSAdam Denchfield PetscInt dim; 442484c7b14SAdam Denchfield PetscBool cg_restart = PETSC_FALSE; 443c8bcdf1eSAdam Denchfield 444*4d86920dSPierre Jolivet PetscFunctionBegin; 44550b47da0SAdam Denchfield /* Local curvature check to see if we need to restart */ 446414d97d3SAlp Dener if (tao->niter >= 1 || tao->recycle) { 4479566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 4489566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 449c8bcdf1eSAdam Denchfield ynorm2 = ynorm * ynorm; 4509566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 451484c7b14SAdam Denchfield if (step * dnorm < PETSC_MACHINE_EPSILON || step * dk_yk < PETSC_MACHINE_EPSILON) { 452e2570530SAlp Dener cg_restart = PETSC_TRUE; 453484c7b14SAdam Denchfield ++cg->skipped_updates; 454484c7b14SAdam Denchfield } 45550b47da0SAdam Denchfield if (cg->spaced_restart) { 4569566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 457e2570530SAlp Dener if (tao->niter % (dim * cg->min_restart_num)) cg_restart = PETSC_TRUE; 45850b47da0SAdam Denchfield } 45950b47da0SAdam Denchfield } 46050b47da0SAdam Denchfield /* If the user wants regular restarts, do it every 6n iterations, where n=dimension */ 46150b47da0SAdam Denchfield if (cg->spaced_restart) { 4629566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->gradient, &dim)); 463e2570530SAlp Dener if (0 == tao->niter % (6 * dim)) cg_restart = PETSC_TRUE; 46450b47da0SAdam Denchfield } 46550b47da0SAdam Denchfield /* Compute the diagonal scaling vector if applicable */ 4661baa6e33SBarry Smith if (cg->diag_scaling) PetscCall(MatLMVMUpdate(cg->B, tao->solution, tao->gradient)); 46750b47da0SAdam Denchfield 468484c7b14SAdam Denchfield /* A note on diagonal scaling (to be added to paper): 469484c7b14SAdam Denchfield For the FR, PR, PRP, and DY methods, the diagonally scaled versions 470484c7b14SAdam Denchfield must be derived as a preconditioned CG method rather than as 471484c7b14SAdam Denchfield a Hessian initialization like in the Broyden methods. */ 47250b47da0SAdam Denchfield 473484c7b14SAdam Denchfield /* In that case, one writes the objective function as 474484c7b14SAdam Denchfield f(x) \equiv f(Ay). Gradient evaluations yield g(x_k) = A g(Ay_k) = A g(x_k). 475484c7b14SAdam Denchfield Furthermore, the direction d_k \equiv (x_k - x_{k-1})/step according to 476484c7b14SAdam Denchfield HZ (2006) becomes A^{-1} d_k, such that d_k^T g_k remains the 477484c7b14SAdam Denchfield same under preconditioning. Note that A is diagonal, such that A^T = A. */ 47850b47da0SAdam Denchfield 479484c7b14SAdam Denchfield /* This yields questions like what the dot product d_k^T y_k 480484c7b14SAdam Denchfield should look like. HZ mistakenly treats that as the same under 481484c7b14SAdam Denchfield preconditioning, but that is not necessarily true. */ 48250b47da0SAdam Denchfield 483484c7b14SAdam Denchfield /* Observe y_k \equiv g_k - g_{k-1}, and under the P.C. transformation, 484484c7b14SAdam 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}), 485484c7b14SAdam 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 486484c7b14SAdam Denchfield NOT the same if our preconditioning matrix is updated between iterations. 487484c7b14SAdam Denchfield This same issue is found when considering dot products of the form g_{k+1}^T y_k. */ 48850b47da0SAdam Denchfield 48950b47da0SAdam Denchfield /* Compute CG step direction */ 49050b47da0SAdam Denchfield if (cg_restart) { 4919566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 492484c7b14SAdam Denchfield } else if (pcgd_fallback) { 493484c7b14SAdam Denchfield /* Just like preconditioned CG */ 4949566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 4959566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 49650b47da0SAdam Denchfield } else if (ynorm2 > PETSC_MACHINE_EPSILON) { 49750b47da0SAdam Denchfield switch (cg->cg_type) { 498d6e07cdcSHong Zhang case TAO_BNCG_PCGD: 49950b47da0SAdam Denchfield if (!cg->diag_scaling) { 500484c7b14SAdam Denchfield if (!cg->no_scaling) { 50150b47da0SAdam Denchfield cg->sts = step * step * dnorm * dnorm; 5029566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->sts, &tau_k, cg->alpha)); 503484c7b14SAdam Denchfield } else { 504484c7b14SAdam Denchfield tau_k = 1.0; 505484c7b14SAdam Denchfield ++cg->pure_gd_steps; 506484c7b14SAdam Denchfield } 5079566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, 0.0, tao->gradient)); 50850b47da0SAdam Denchfield } else { 5099566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5109566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, 0.0, cg->g_work)); 51150b47da0SAdam Denchfield } 51250b47da0SAdam Denchfield break; 513484c7b14SAdam Denchfield 514d6e07cdcSHong Zhang case TAO_BNCG_HS: 51550b47da0SAdam Denchfield /* Classic Hestenes-Stiefel method, modified with scalar and diagonal preconditioning. */ 51650b47da0SAdam Denchfield if (!cg->diag_scaling) { 51750b47da0SAdam Denchfield cg->sts = step * step * dnorm * dnorm; 5189566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5199566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->sts, &tau_k, cg->alpha)); 52050b47da0SAdam Denchfield beta = tau_k * gkp1_yk / dk_yk; 5219566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 52250b47da0SAdam Denchfield } else { 5239566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5249566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 52550b47da0SAdam Denchfield beta = gkp1_yk / dk_yk; 5269566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 52750b47da0SAdam Denchfield } 528c8bcdf1eSAdam Denchfield break; 529484c7b14SAdam Denchfield 530d6e07cdcSHong Zhang case TAO_BNCG_FR: 5319566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5329566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5339566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 53450b47da0SAdam Denchfield ynorm2 = ynorm * ynorm; 5359566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->stepdirection, &dk_yk)); 53650b47da0SAdam Denchfield if (!cg->diag_scaling) { 5379566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, step * step * dnorm * dnorm, &tau_k, cg->alpha)); 53850b47da0SAdam Denchfield beta = tau_k * gnorm2 / gnorm2_old; 5399566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 54050b47da0SAdam Denchfield } else { 5419566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Before it's updated */ 5429566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5439566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, cg->g_work, &tmp)); 54450b47da0SAdam Denchfield beta = tmp / gnorm2_old; 5459566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 54650b47da0SAdam Denchfield } 547c8bcdf1eSAdam Denchfield break; 548484c7b14SAdam Denchfield 549d6e07cdcSHong Zhang case TAO_BNCG_PRP: 55050b47da0SAdam Denchfield snorm = step * dnorm; 55150b47da0SAdam Denchfield if (!cg->diag_scaling) { 5529566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5539566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5549566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, snorm * snorm, &tau_k, cg->alpha)); 55550b47da0SAdam Denchfield beta = tau_k * gkp1_yk / gnorm2_old; 5569566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 55750b47da0SAdam Denchfield } else { 5589566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); 5599566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5609566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 56150b47da0SAdam Denchfield beta = gkp1_yk / gnorm2_old; 5629566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 56350b47da0SAdam Denchfield } 564c8bcdf1eSAdam Denchfield break; 565484c7b14SAdam Denchfield 566d6e07cdcSHong Zhang case TAO_BNCG_PRP_PLUS: 5679566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->yk, -1.0, cg->G_old, tao->gradient)); 5689566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->yk, NORM_2, &ynorm)); 56950b47da0SAdam Denchfield ynorm2 = ynorm * ynorm; 57050b47da0SAdam Denchfield if (!cg->diag_scaling) { 5719566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->G_old, &gnorm2_old)); 5729566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 5739566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, snorm * snorm, &tau_k, cg->alpha)); 57450b47da0SAdam Denchfield beta = tau_k * gkp1_yk / gnorm2_old; 57550b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 5769566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 57750b47da0SAdam Denchfield } else { 5789566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->g_work, &gnorm2_old)); /* Old gtDg */ 5799566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5809566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 58150b47da0SAdam Denchfield beta = gkp1_yk / gnorm2_old; 58250b47da0SAdam Denchfield beta = PetscMax(beta, 0.0); 5839566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 58450b47da0SAdam Denchfield } 585c8bcdf1eSAdam Denchfield break; 586484c7b14SAdam Denchfield 587d6e07cdcSHong Zhang case TAO_BNCG_DY: 588484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Yaxiang Yuan. "A nonlinear conjugate gradient method with a strong global convergence property." 589484c7b14SAdam Denchfield SIAM Journal on optimization 10, no. 1 (1999): 177-182. */ 59050b47da0SAdam Denchfield if (!cg->diag_scaling) { 5919566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, tao->gradient, &gd)); 5929566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 5939566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, step * dk_yk, cg->yts, &tau_k, cg->alpha)); 59450b47da0SAdam Denchfield beta = tau_k * gnorm2 / (gd - gd_old); 5959566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 59650b47da0SAdam Denchfield } else { 5979566063dSJacob Faibussowitsch PetscCall(MatMult(cg->B, tao->stepdirection, cg->d_work)); 5989566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 5999566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, tao->gradient, >Dg)); 6009566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->G_old, &gd_old)); 6019566063dSJacob Faibussowitsch PetscCall(VecDot(cg->d_work, cg->g_work, &dk_yk)); 60250b47da0SAdam Denchfield dk_yk = dk_yk - gd_old; 60350b47da0SAdam Denchfield beta = gtDg / dk_yk; 6049566063dSJacob Faibussowitsch PetscCall(VecScale(cg->d_work, beta)); 6059566063dSJacob Faibussowitsch PetscCall(VecWAXPY(tao->stepdirection, -1.0, cg->g_work, cg->d_work)); 60650b47da0SAdam Denchfield } 607c8bcdf1eSAdam Denchfield break; 608484c7b14SAdam Denchfield 609d6e07cdcSHong Zhang case TAO_BNCG_HZ: 610484c7b14SAdam Denchfield /* Hager, William W., and Hongchao Zhang. "Algorithm 851: CG_DESCENT, a conjugate gradient method with guaranteed descent." 611484c7b14SAdam Denchfield ACM Transactions on Mathematical Software (TOMS) 32, no. 1 (2006): 113-137. */ 6129566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6139566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6149566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 61550b47da0SAdam Denchfield snorm = dnorm * step; 61650b47da0SAdam Denchfield cg->yts = step * dk_yk; 61748a46eb9SPierre Jolivet if (cg->use_dynamic_restart) PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 61850b47da0SAdam Denchfield if (cg->dynamic_restart) { 6199566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 620c8bcdf1eSAdam Denchfield } else { 621c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6229566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6239566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 624c8bcdf1eSAdam Denchfield /* Supplying cg->alpha = -1.0 will give the CG_DESCENT 5.3 special case of tau_k = 1.0 */ 625c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 626c8bcdf1eSAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk)); 627c8bcdf1eSAdam Denchfield /* Bound beta as in CG_DESCENT 5.3, as implemented, with the third comparison from DK 2013 */ 62850b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * tau_k * gd_old / (dnorm * dnorm)), cg->dk_eta * tau_k * gd / (dnorm * dnorm)); 629c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6309566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -tau_k, beta, tao->gradient)); 631c8bcdf1eSAdam Denchfield } else { 632c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 633c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 634c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 63550b47da0SAdam Denchfield /* Apply the diagonal scaling to all my vectors */ 6369566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6379566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6389566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 639c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 6409566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 641c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 642c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 6439566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 644c8bcdf1eSAdam Denchfield tau_k = -tau_k * gd / (dk_yk * dk_yk); 645c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 646484c7b14SAdam Denchfield beta = gkp1_yk / dk_yk + cg->hz_theta * tau_k; /* HZ; (1.15) from DK 2013 */ 647c8bcdf1eSAdam Denchfield /* From HZ2013, modified to account for diagonal scaling*/ 6489566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 6499566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 65050b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * gd_old / (dnorm * dnorm)), cg->dk_eta * gd / (dnorm * dnorm)); 651c8bcdf1eSAdam Denchfield /* Do the update */ 6529566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 65350b47da0SAdam Denchfield } 65450b47da0SAdam Denchfield } 655c8bcdf1eSAdam Denchfield break; 656484c7b14SAdam Denchfield 657d6e07cdcSHong Zhang case TAO_BNCG_DK: 658484c7b14SAdam Denchfield /* Dai, Yu-Hong, and Cai-Xia Kou. "A nonlinear conjugate gradient algorithm with an optimal property and an improved Wolfe line search." 659484c7b14SAdam Denchfield SIAM Journal on Optimization 23, no. 1 (2013): 296-320. */ 6609566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 6619566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 6629566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 66350b47da0SAdam Denchfield snorm = step * dnorm; 66450b47da0SAdam Denchfield cg->yts = dk_yk * step; 665c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 6669566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 6679566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 668c8bcdf1eSAdam Denchfield /* Use cg->alpha = -1.0 to get tau_k = 1.0 as in CG_DESCENT 5.3 */ 669c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 67050b47da0SAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk) + gd / (dnorm * dnorm)) - step * gd / dk_yk; 67150b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * tau_k * gd_old / (dnorm * dnorm)), cg->dk_eta * tau_k * gd / (dnorm * dnorm)); 672c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d */ 6739566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, 0.0, beta, tao->gradient, cg->yk)); 674c8bcdf1eSAdam Denchfield } else { 675c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 676c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 677c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 6789566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 6799566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 6809566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->stepdirection, cg->d_work)); 681c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 6829566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1_yk)); 6839566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 684c8bcdf1eSAdam Denchfield tau_k = tau_k * gd / (dk_yk * dk_yk); 685c8bcdf1eSAdam Denchfield tmp = gd / dk_yk; 686c8bcdf1eSAdam Denchfield /* beta is the constant which adds the dk contribution */ 687484c7b14SAdam Denchfield beta = gkp1_yk / dk_yk - step * tmp - tau_k; 688c8bcdf1eSAdam Denchfield /* Update this for the last term in beta */ 6899566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, tao->stepdirection, &dk_yk)); 690c8bcdf1eSAdam Denchfield beta += tmp * dk_yk / (dnorm * dnorm); /* projection of y_work onto dk */ 6919566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &gd)); 6929566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, cg->d_work, &gd_old)); 69350b47da0SAdam Denchfield beta = PetscMax(PetscMax(beta, cg->hz_eta * gd_old / (dnorm * dnorm)), cg->dk_eta * gd / (dnorm * dnorm)); 694c8bcdf1eSAdam Denchfield /* Do the update */ 6959566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 69650b47da0SAdam Denchfield } 697c8bcdf1eSAdam Denchfield break; 698484c7b14SAdam Denchfield 699d6e07cdcSHong Zhang case TAO_BNCG_KD: 700110fc3b0SBarry Smith /* Kou, Cai-Xia, and Yu-Hong Dai. "A modified self-scaling memoryless Broyden-Fletcher-Goldfarb-Shanno method for unconstrained optimization." 701484c7b14SAdam Denchfield Journal of Optimization Theory and Applications 165, no. 1 (2015): 209-224. */ 7029566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7039566063dSJacob Faibussowitsch PetscCall(VecDot(cg->G_old, tao->stepdirection, &gd_old)); 7049566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 70550b47da0SAdam Denchfield snorm = step * dnorm; 70650b47da0SAdam Denchfield cg->yts = dk_yk * step; 70748a46eb9SPierre Jolivet if (cg->use_dynamic_restart) PetscCall(TaoBNCGCheckDynamicRestart(tao, step, gd, gd_old, &cg->dynamic_restart, fold)); 70850b47da0SAdam Denchfield if (cg->dynamic_restart) { 7099566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 710c8bcdf1eSAdam Denchfield } else { 711c8bcdf1eSAdam Denchfield if (!cg->diag_scaling) { 7129566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7139566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(ynorm2, cg->yts, snorm * snorm, &tau_k, cg->alpha)); 714c8bcdf1eSAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - ynorm2 * gd / (dk_yk * dk_yk)) - step * gd / dk_yk; 715c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tau_k * gd / (dnorm * dnorm)) /* 0.1 is KD's zeta parameter */ 716c8bcdf1eSAdam Denchfield { 717c8bcdf1eSAdam Denchfield beta = cg->zeta * tau_k * gd / (dnorm * dnorm); 718c8bcdf1eSAdam Denchfield gamma = 0.0; 719c8bcdf1eSAdam Denchfield } else { 720c8bcdf1eSAdam Denchfield if (gkp1_yk < 0 && cg->neg_xi) gamma = -1.0 * gd / dk_yk; 721484c7b14SAdam Denchfield /* This seems to be very effective when there's no tau_k scaling. 722484c7b14SAdam Denchfield This guarantees a large descent step every iteration, going through DK 2015 Lemma 3.1's proof but allowing for negative xi */ 723ad540459SPierre Jolivet else gamma = cg->xi * gd / dk_yk; 724c8bcdf1eSAdam Denchfield } 725c8bcdf1eSAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7269566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, gamma * tau_k, beta, tao->gradient, cg->yk)); 727c8bcdf1eSAdam Denchfield } else { 728c8bcdf1eSAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 729c8bcdf1eSAdam Denchfield cg->yty = ynorm2; 730c8bcdf1eSAdam Denchfield cg->sts = snorm * snorm; 7319566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7329566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 733c8bcdf1eSAdam Denchfield /* Construct the constant ytDgkp1 */ 7349566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->g_work, &gkp1D_yk)); 735c8bcdf1eSAdam Denchfield /* Construct the constant for scaling Dkyk in the update */ 736c8bcdf1eSAdam Denchfield gamma = gd / dk_yk; 737c8bcdf1eSAdam Denchfield /* tau_k = -ytDy/(ytd)^2 * gd */ 7389566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, cg->y_work, &tau_k)); 739c8bcdf1eSAdam Denchfield tau_k = tau_k * gd / (dk_yk * dk_yk); 740c8bcdf1eSAdam Denchfield /* beta is the constant which adds the d_k contribution */ 741c8bcdf1eSAdam Denchfield beta = gkp1D_yk / dk_yk - step * gamma - tau_k; 742c8bcdf1eSAdam Denchfield /* Here is the requisite check */ 7439566063dSJacob Faibussowitsch PetscCall(VecDot(tao->stepdirection, cg->g_work, &tmp)); 744c8bcdf1eSAdam Denchfield if (cg->neg_xi) { 745c8bcdf1eSAdam Denchfield /* modified KD implementation */ 746c8bcdf1eSAdam Denchfield if (gkp1D_yk / dk_yk < 0) gamma = -1.0 * gd / dk_yk; 747ad540459SPierre Jolivet else gamma = cg->xi * gd / dk_yk; 748c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tmp / (dnorm * dnorm)) { 749c8bcdf1eSAdam Denchfield beta = cg->zeta * tmp / (dnorm * dnorm); 750c8bcdf1eSAdam Denchfield gamma = 0.0; 751c8bcdf1eSAdam Denchfield } 752c8bcdf1eSAdam Denchfield } else { /* original KD 2015 implementation */ 753c8bcdf1eSAdam Denchfield if (beta < cg->zeta * tmp / (dnorm * dnorm)) { 754c8bcdf1eSAdam Denchfield beta = cg->zeta * tmp / (dnorm * dnorm); 755c8bcdf1eSAdam Denchfield gamma = 0.0; 756ad540459SPierre Jolivet } else gamma = cg->xi * gd / dk_yk; 757c8bcdf1eSAdam Denchfield } 758c8bcdf1eSAdam Denchfield /* Do the update in two steps */ 7599566063dSJacob Faibussowitsch PetscCall(VecAXPBY(tao->stepdirection, -1.0, beta, cg->g_work)); 7609566063dSJacob Faibussowitsch PetscCall(VecAXPY(tao->stepdirection, gamma, cg->y_work)); 76150b47da0SAdam Denchfield } 76250b47da0SAdam Denchfield } 763c8bcdf1eSAdam Denchfield break; 764484c7b14SAdam Denchfield 765d6e07cdcSHong Zhang case TAO_BNCG_SSML_BFGS: 766484c7b14SAdam Denchfield /* Perry, J. M. "A class of conjugate gradient algorithms with a two-step variable-metric memory." 767484c7b14SAdam Denchfield Discussion Papers 269 (1977). */ 7689566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7699566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 770484c7b14SAdam Denchfield snorm = step * dnorm; 771484c7b14SAdam Denchfield cg->yts = dk_yk * step; 772484c7b14SAdam Denchfield cg->yty = ynorm2; 773484c7b14SAdam Denchfield cg->sts = snorm * snorm; 774484c7b14SAdam Denchfield if (!cg->diag_scaling) { 7759566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 7769566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 777484c7b14SAdam Denchfield tmp = gd / dk_yk; 778484c7b14SAdam Denchfield beta = tau_k * (gkp1_yk / dk_yk - cg->yty * gd / (dk_yk * dk_yk)) - step * tmp; 779484c7b14SAdam Denchfield /* d <- -t*g + beta*t*d + t*tmp*yk */ 7809566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp * tau_k, beta, tao->gradient, cg->yk)); 781484c7b14SAdam Denchfield } else { 782484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless BFGS step */ 7839566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 7849566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 785484c7b14SAdam Denchfield /* compute scalar gamma */ 7869566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 7879566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 788484c7b14SAdam Denchfield gamma = gd / dk_yk; 789484c7b14SAdam Denchfield /* Compute scalar beta */ 790484c7b14SAdam Denchfield beta = (gkp1_yk / dk_yk - gd * tmp / (dk_yk * dk_yk)) - step * gd / dk_yk; 791484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 7929566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 793484c7b14SAdam Denchfield } 794484c7b14SAdam Denchfield break; 795484c7b14SAdam Denchfield 796d6e07cdcSHong Zhang case TAO_BNCG_SSML_DFP: 7979566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 7989566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 799484c7b14SAdam Denchfield snorm = step * dnorm; 800484c7b14SAdam Denchfield cg->yts = dk_yk * step; 801484c7b14SAdam Denchfield cg->yty = ynorm2; 802484c7b14SAdam Denchfield cg->sts = snorm * snorm; 803484c7b14SAdam Denchfield if (!cg->diag_scaling) { 804484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8059566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, cg->yts, cg->sts, &tau_k, cg->alpha)); 8069566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 807484c7b14SAdam Denchfield tau_k = cg->dfp_scale * tau_k; 808484c7b14SAdam Denchfield tmp = tau_k * gkp1_yk / cg->yty; 809484c7b14SAdam Denchfield beta = -step * gd / dk_yk; 810484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8119566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 812484c7b14SAdam Denchfield } else { 813484c7b14SAdam Denchfield /* We have diagonal scaling enabled and are taking a diagonally-scaled memoryless DFP step */ 8149566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8159566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 816484c7b14SAdam Denchfield /* compute scalar gamma */ 8179566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8189566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 819484c7b14SAdam Denchfield gamma = (gkp1_yk / tmp); 820484c7b14SAdam Denchfield /* Compute scalar beta */ 821484c7b14SAdam Denchfield beta = -step * gd / dk_yk; 822484c7b14SAdam Denchfield /* Compute stepdirection d_kp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8239566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 824484c7b14SAdam Denchfield } 825484c7b14SAdam Denchfield break; 826484c7b14SAdam Denchfield 827d6e07cdcSHong Zhang case TAO_BNCG_SSML_BRDN: 8289566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 8299566063dSJacob Faibussowitsch PetscCall(VecWAXPY(cg->sk, -1.0, cg->X_old, tao->solution)); 830484c7b14SAdam Denchfield snorm = step * dnorm; 831484c7b14SAdam Denchfield cg->yts = step * dk_yk; 832484c7b14SAdam Denchfield cg->yty = ynorm2; 833484c7b14SAdam Denchfield cg->sts = snorm * snorm; 834484c7b14SAdam Denchfield if (!cg->diag_scaling) { 835484c7b14SAdam Denchfield /* Instead of a regular convex combination, we will solve a quadratic formula. */ 8369566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step * dk_yk, snorm * snorm, &tau_bfgs, cg->bfgs_scale)); 8379566063dSJacob Faibussowitsch PetscCall(TaoBNCGComputeScalarScaling(cg->yty, step * dk_yk, snorm * snorm, &tau_dfp, cg->dfp_scale)); 8389566063dSJacob Faibussowitsch PetscCall(VecDot(cg->yk, tao->gradient, &gkp1_yk)); 839484c7b14SAdam Denchfield tau_k = cg->theta * tau_bfgs + (1.0 - cg->theta) * tau_dfp; 840484c7b14SAdam Denchfield /* If bfgs_scale = 1.0, it should reproduce the bfgs tau_bfgs. If bfgs_scale = 0.0, 841484c7b14SAdam Denchfield it should reproduce the tau_dfp scaling. Same with dfp_scale. */ 842484c7b14SAdam Denchfield tmp = cg->theta * tau_bfgs * gd / dk_yk + (1 - cg->theta) * tau_dfp * gkp1_yk / cg->yty; 843484c7b14SAdam Denchfield beta = cg->theta * tau_bfgs * (gkp1_yk / dk_yk - cg->yty * gd / (dk_yk * dk_yk)) - step * gd / dk_yk; 844484c7b14SAdam Denchfield /* d <- -t*g + beta*d + tmp*yk */ 8459566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -tau_k, tmp, beta, tao->gradient, cg->yk)); 846484c7b14SAdam Denchfield } else { 847484c7b14SAdam Denchfield /* We have diagonal scaling enabled */ 8489566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, tao->gradient, cg->g_work)); 8499566063dSJacob Faibussowitsch PetscCall(MatSolve(cg->B, cg->yk, cg->y_work)); 850484c7b14SAdam Denchfield /* compute scalar gamma */ 8519566063dSJacob Faibussowitsch PetscCall(VecDot(cg->g_work, cg->yk, &gkp1_yk)); 8529566063dSJacob Faibussowitsch PetscCall(VecDot(cg->y_work, cg->yk, &tmp)); 853484c7b14SAdam Denchfield gamma = cg->theta * gd / dk_yk + (1 - cg->theta) * (gkp1_yk / tmp); 854484c7b14SAdam Denchfield /* Compute scalar beta */ 855484c7b14SAdam Denchfield beta = cg->theta * (gkp1_yk / dk_yk - gd * tmp / (dk_yk * dk_yk)) - step * gd / dk_yk; 856484c7b14SAdam Denchfield /* Compute stepdirection dkp1 = gamma*Dkyk + beta*dk - Dkgkp1 */ 8579566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(tao->stepdirection, -1.0, gamma, beta, cg->g_work, cg->y_work)); 858484c7b14SAdam Denchfield } 859484c7b14SAdam Denchfield break; 860484c7b14SAdam Denchfield 861d71ae5a4SJacob Faibussowitsch default: 862d71ae5a4SJacob Faibussowitsch break; 863c8bcdf1eSAdam Denchfield } 864c8bcdf1eSAdam Denchfield } 8653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 866c8bcdf1eSAdam Denchfield } 867c8bcdf1eSAdam Denchfield 868d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode TaoBNCGConductIteration(Tao tao, PetscReal gnorm) 869d71ae5a4SJacob Faibussowitsch { 870c8bcdf1eSAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 871c8bcdf1eSAdam Denchfield TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 8728ca2df50S PetscReal step = 1.0, gnorm2, gd, dnorm = 0.0; 873c8bcdf1eSAdam Denchfield PetscReal gnorm2_old, f_old, resnorm, gnorm_old; 874c624ebd3SAlp Dener PetscBool pcgd_fallback = PETSC_FALSE; 875c8bcdf1eSAdam Denchfield 876c8bcdf1eSAdam Denchfield PetscFunctionBegin; 877c8bcdf1eSAdam Denchfield /* We are now going to perform a line search along the direction. */ 878c8bcdf1eSAdam Denchfield /* Store solution and gradient info before it changes */ 8799566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->solution, cg->X_old)); 8809566063dSJacob Faibussowitsch PetscCall(VecCopy(tao->gradient, cg->G_old)); 8819566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old)); 882c8bcdf1eSAdam Denchfield 883c8bcdf1eSAdam Denchfield gnorm_old = gnorm; 884c8bcdf1eSAdam Denchfield gnorm2_old = gnorm_old * gnorm_old; 885c8bcdf1eSAdam Denchfield f_old = cg->f; 886484c7b14SAdam Denchfield /* Perform bounded line search. If we are recycling a solution from a previous */ 887484c7b14SAdam Denchfield /* TaoSolve, then we want to immediately skip to calculating a new direction rather than performing a linesearch */ 888414d97d3SAlp Dener if (!(tao->recycle && 0 == tao->niter)) { 889484c7b14SAdam Denchfield /* Above logic: the below code happens every iteration, except for the first iteration of a recycled TaoSolve */ 8909566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 8919566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 8929566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 893c8bcdf1eSAdam Denchfield 894c8bcdf1eSAdam Denchfield /* Check linesearch failure */ 895c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 896c8bcdf1eSAdam Denchfield ++cg->ls_fails; 897d6e07cdcSHong Zhang if (cg->cg_type == TAO_BNCG_GD) { 898c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 899c8bcdf1eSAdam Denchfield step = 0.0; 900c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 901c8bcdf1eSAdam Denchfield } else { 902484c7b14SAdam Denchfield /* Restore previous point, perform preconditioned GD and regular GD steps at the last good point */ 9039566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->X_old, tao->solution)); 9049566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->G_old, tao->gradient)); 9059566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient)); 906c8bcdf1eSAdam Denchfield gnorm = gnorm_old; 907c8bcdf1eSAdam Denchfield gnorm2 = gnorm2_old; 908c8bcdf1eSAdam Denchfield cg->f = f_old; 909c8bcdf1eSAdam Denchfield 910484c7b14SAdam Denchfield /* Fall back on preconditioned CG (so long as you're not already using it) */ 911d6e07cdcSHong Zhang if (cg->cg_type != TAO_BNCG_PCGD && cg->diag_scaling) { 912e2570530SAlp Dener pcgd_fallback = PETSC_TRUE; 9139566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 914484c7b14SAdam Denchfield 9159566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9169566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 917c8bcdf1eSAdam Denchfield 9189566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9199566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9209566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 921c8bcdf1eSAdam Denchfield 922484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 923484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 924484c7b14SAdam Denchfield /* Going to perform a regular gradient descent step. */ 925484c7b14SAdam Denchfield ++cg->ls_fails; 926484c7b14SAdam Denchfield step = 0.0; 927484c7b14SAdam Denchfield } 928484c7b14SAdam Denchfield } 929484c7b14SAdam Denchfield /* Fall back on the scaled gradient step */ 930484c7b14SAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 931484c7b14SAdam Denchfield ++cg->ls_fails; 9329566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9339566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 9349566063dSJacob Faibussowitsch PetscCall(TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0)); 9359566063dSJacob Faibussowitsch PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status)); 9369566063dSJacob Faibussowitsch PetscCall(TaoAddLineSearchCounts(tao)); 937484c7b14SAdam Denchfield } 938484c7b14SAdam Denchfield 939c8bcdf1eSAdam Denchfield if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 940c8bcdf1eSAdam Denchfield /* Nothing left to do but fail out of the optimization */ 94150b47da0SAdam Denchfield ++cg->ls_fails; 942c8bcdf1eSAdam Denchfield step = 0.0; 943c8bcdf1eSAdam Denchfield tao->reason = TAO_DIVERGED_LS_FAILURE; 944484c7b14SAdam Denchfield } else { 945484c7b14SAdam Denchfield /* One of the fallbacks worked. Set them both back equal to false. */ 946484c7b14SAdam Denchfield pcgd_fallback = PETSC_FALSE; 947c8bcdf1eSAdam Denchfield } 948c8bcdf1eSAdam Denchfield } 949c8bcdf1eSAdam Denchfield } 950c8bcdf1eSAdam Denchfield /* Convergence test for line search failure */ 9513ba16761SJacob Faibussowitsch if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS); 952c8bcdf1eSAdam Denchfield 953c8bcdf1eSAdam Denchfield /* Standard convergence test */ 9549566063dSJacob Faibussowitsch PetscCall(VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W)); 9559566063dSJacob Faibussowitsch PetscCall(VecNorm(cg->W, NORM_2, &resnorm)); 9563c859ba3SBarry Smith PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN"); 9579566063dSJacob Faibussowitsch PetscCall(TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its)); 9589566063dSJacob Faibussowitsch PetscCall(TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step)); 959dbbe0bcdSBarry Smith PetscUseTypeMethod(tao, convergencetest, tao->cnvP); 9603ba16761SJacob Faibussowitsch if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS); 961484c7b14SAdam Denchfield } 962c8bcdf1eSAdam Denchfield /* Assert we have an updated step and we need at least one more iteration. */ 963c8bcdf1eSAdam Denchfield /* Calculate the next direction */ 964c8bcdf1eSAdam Denchfield /* Estimate the active set at the new solution */ 9659566063dSJacob Faibussowitsch PetscCall(TaoBNCGEstimateActiveSet(tao, cg->as_type)); 966c8bcdf1eSAdam Denchfield /* Compute the projected gradient and its norm */ 9679566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->unprojected_gradient, tao->gradient)); 968976ed0a4SStefano Zampini if (cg->active_idx) PetscCall(VecISSet(tao->gradient, cg->active_idx, 0.0)); 9699566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->gradient, NORM_2, &gnorm)); 970c8bcdf1eSAdam Denchfield gnorm2 = gnorm * gnorm; 971c8bcdf1eSAdam Denchfield 972484c7b14SAdam Denchfield /* Calculate some quantities used in the StepDirectionUpdate. */ 9739566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 974484c7b14SAdam Denchfield /* Update the step direction. */ 9759566063dSJacob Faibussowitsch PetscCall(TaoBNCGStepDirectionUpdate(tao, gnorm2, step, f_old, gnorm2_old, dnorm, pcgd_fallback)); 976484c7b14SAdam Denchfield ++tao->niter; 9779566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 978c8bcdf1eSAdam Denchfield 979d6e07cdcSHong Zhang if (cg->cg_type != TAO_BNCG_GD) { 980c8bcdf1eSAdam Denchfield /* Figure out which previously active variables became inactive this iteration */ 9819566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cg->new_inactives)); 98248a46eb9SPierre Jolivet if (cg->inactive_idx && cg->inactive_old) PetscCall(ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives)); 983c8bcdf1eSAdam Denchfield /* Selectively reset the CG step those freshly inactive variables */ 984c8bcdf1eSAdam Denchfield if (cg->new_inactives) { 9859566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 9869566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 9879566063dSJacob Faibussowitsch PetscCall(VecCopy(cg->inactive_grad, cg->inactive_step)); 9889566063dSJacob Faibussowitsch PetscCall(VecScale(cg->inactive_step, -1.0)); 9899566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step)); 9909566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad)); 991c8bcdf1eSAdam Denchfield } 992c8bcdf1eSAdam Denchfield /* Verify that this is a descent direction */ 9939566063dSJacob Faibussowitsch PetscCall(VecDot(tao->gradient, tao->stepdirection, &gd)); 9949566063dSJacob Faibussowitsch PetscCall(VecNorm(tao->stepdirection, NORM_2, &dnorm)); 99550b47da0SAdam Denchfield if (PetscIsInfOrNanReal(gd) || (gd / (dnorm * dnorm) <= -1e10 || gd / (dnorm * dnorm) >= -1e-10)) { 996c8bcdf1eSAdam Denchfield /* Not a descent direction, so we reset back to projected gradient descent */ 9979566063dSJacob Faibussowitsch PetscCall(TaoBNCGResetUpdate(tao, gnorm2)); 9989566063dSJacob Faibussowitsch PetscCall(TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection)); 999c8bcdf1eSAdam Denchfield ++cg->descent_error; 1000c8bcdf1eSAdam Denchfield } else { 1001c8bcdf1eSAdam Denchfield } 1002c8bcdf1eSAdam Denchfield } 10033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1004ac9112b8SAlp Dener } 1005484c7b14SAdam Denchfield 1006d6e07cdcSHong Zhang PETSC_INTERN PetscErrorCode TaoBNCGSetH0(Tao tao, Mat H0) 1007d71ae5a4SJacob Faibussowitsch { 1008484c7b14SAdam Denchfield TAO_BNCG *cg = (TAO_BNCG *)tao->data; 1009d6e07cdcSHong Zhang PetscBool same; 1010484c7b14SAdam Denchfield 1011484c7b14SAdam Denchfield PetscFunctionBegin; 1012d6e07cdcSHong Zhang PetscCall(PetscObjectTypeCompare((PetscObject)tao, TAOBNCG, &same)); 1013d6e07cdcSHong Zhang if (same) { 10149566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)H0)); 1015484c7b14SAdam Denchfield cg->pc = H0; 1016d6e07cdcSHong Zhang } 1017d6e07cdcSHong Zhang PetscFunctionReturn(PETSC_SUCCESS); 1018d6e07cdcSHong Zhang } 1019d6e07cdcSHong Zhang 1020d6e07cdcSHong Zhang /*@ 1021d6e07cdcSHong Zhang TaoBNCGGetType - Return the type for the `TAOBNCG` solver 1022d6e07cdcSHong Zhang 1023d6e07cdcSHong Zhang Input Parameter: 1024d6e07cdcSHong Zhang . tao - the `Tao` solver context 1025d6e07cdcSHong Zhang 1026d6e07cdcSHong Zhang Output Parameter: 1027d6e07cdcSHong Zhang . type - `TAOBNCG` type 1028d6e07cdcSHong Zhang 1029d6e07cdcSHong Zhang Level: advanced 1030d6e07cdcSHong Zhang 1031d6e07cdcSHong Zhang .seealso: `Tao`, `TAOBNCG`, `TaoBNCGSetType()`, `TaoBNCGType` 1032d6e07cdcSHong Zhang @*/ 1033d6e07cdcSHong Zhang PetscErrorCode TaoBNCGGetType(Tao tao, TaoBNCGType *type) 1034d6e07cdcSHong Zhang { 1035d6e07cdcSHong Zhang TAO_BNCG *cg = (TAO_BNCG *)tao->data; 1036d6e07cdcSHong Zhang PetscBool same; 1037d6e07cdcSHong Zhang 1038d6e07cdcSHong Zhang PetscFunctionBegin; 1039d6e07cdcSHong Zhang PetscCall(PetscObjectTypeCompare((PetscObject)tao, TAOBNCG, &same)); 1040d6e07cdcSHong Zhang PetscCheck(same, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "TAO solver is not BNCG type"); 1041d6e07cdcSHong Zhang *type = cg->cg_type; 1042d6e07cdcSHong Zhang PetscFunctionReturn(PETSC_SUCCESS); 1043d6e07cdcSHong Zhang } 1044d6e07cdcSHong Zhang 1045d6e07cdcSHong Zhang /*@ 1046d6e07cdcSHong Zhang TaoBNCGSetType - Set the type for the `TAOBNCG` solver 1047d6e07cdcSHong Zhang 1048d6e07cdcSHong Zhang Input Parameters: 1049d6e07cdcSHong Zhang + tao - the `Tao` solver context 1050d6e07cdcSHong Zhang - type - `TAOBNCG` type 1051d6e07cdcSHong Zhang 1052d6e07cdcSHong Zhang Level: advanced 1053d6e07cdcSHong Zhang 1054d6e07cdcSHong Zhang .seealso: `Tao`, `TAOBNCG`, `TaoBNCGGetType()`, `TaoBNCGType` 1055d6e07cdcSHong Zhang @*/ 1056d6e07cdcSHong Zhang PetscErrorCode TaoBNCGSetType(Tao tao, TaoBNCGType type) 1057d6e07cdcSHong Zhang { 1058d6e07cdcSHong Zhang TAO_BNCG *cg = (TAO_BNCG *)tao->data; 1059d6e07cdcSHong Zhang PetscBool same; 1060d6e07cdcSHong Zhang 1061d6e07cdcSHong Zhang PetscFunctionBegin; 1062d6e07cdcSHong Zhang PetscCall(PetscObjectTypeCompare((PetscObject)tao, TAOBNCG, &same)); 1063d6e07cdcSHong Zhang if (same) cg->cg_type = type; 10643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1065484c7b14SAdam Denchfield } 1066