xref: /petsc/src/tao/bound/impls/bnk/bnk.c (revision 4a221d5978a6d86d172efe6a78940aca257e68d3)
1eb910715SAlp Dener #include <petsctaolinesearch.h>
2eb910715SAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
3eb910715SAlp Dener #include <petscksp.h>
4eb910715SAlp Dener 
570a3f44bSAlp Dener static const char *BNK_INIT[64]   = {"constant", "direction", "interpolation"};
670a3f44bSAlp Dener static const char *BNK_UPDATE[64] = {"step", "reduction", "interpolation"};
770a3f44bSAlp Dener static const char *BNK_AS[64]     = {"none", "bertsekas"};
870a3f44bSAlp Dener 
9b3e6a353SBarry Smith /* Extracts from the full Hessian the part associated with the current bnk->inactive_idx and set the PCLMVM preconditioner */
10e031d6f5SAlp Dener 
11b3e6a353SBarry Smith static PetscErrorCode TaoBNKComputeSubHessian(Tao tao)
12b3e6a353SBarry Smith {
13b3e6a353SBarry Smith   TAO_BNK *bnk = (TAO_BNK *)tao->data;
14b3e6a353SBarry Smith 
15b3e6a353SBarry Smith   PetscFunctionBegin;
16b3e6a353SBarry Smith   PetscCall(MatDestroy(&bnk->Hpre_inactive));
17b3e6a353SBarry Smith   PetscCall(MatDestroy(&bnk->H_inactive));
18b3e6a353SBarry Smith   if (bnk->active_idx) {
19b3e6a353SBarry Smith     PetscCall(MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive));
20b3e6a353SBarry Smith     if (tao->hessian == tao->hessian_pre) {
21b3e6a353SBarry Smith       PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive));
22b3e6a353SBarry Smith       bnk->Hpre_inactive = bnk->H_inactive;
23b3e6a353SBarry Smith     } else {
24b3e6a353SBarry Smith       PetscCall(MatCreateSubMatrix(tao->hessian_pre, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->Hpre_inactive));
25b3e6a353SBarry Smith     }
26b3e6a353SBarry Smith     if (bnk->bfgs_pre) PetscCall(PCLMVMSetIS(bnk->bfgs_pre, bnk->inactive_idx));
27b3e6a353SBarry Smith   } else {
28b3e6a353SBarry Smith     PetscCall(PetscObjectReference((PetscObject)tao->hessian));
29b3e6a353SBarry Smith     bnk->H_inactive = tao->hessian;
30b3e6a353SBarry Smith     PetscCall(PetscObjectReference((PetscObject)tao->hessian_pre));
31b3e6a353SBarry Smith     bnk->Hpre_inactive = tao->hessian_pre;
32b3e6a353SBarry Smith     if (bnk->bfgs_pre) PetscCall(PCLMVMClearIS(bnk->bfgs_pre));
33b3e6a353SBarry Smith   }
343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35b3e6a353SBarry Smith }
36b3e6a353SBarry Smith 
37b3e6a353SBarry Smith /* Initializes the KSP solver, the BFGS preconditioner, and the initial trust radius estimation */
38df278d8fSAlp Dener 
39d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKInitialize(Tao tao, PetscInt initType, PetscBool *needH)
40d71ae5a4SJacob Faibussowitsch {
41eb910715SAlp Dener   TAO_BNK          *bnk = (TAO_BNK *)tao->data;
42eb910715SAlp Dener   PC                pc;
4389da521bSAlp Dener   PetscReal         f_min, ftrial, prered, actred, kappa, sigma, resnorm;
44eb910715SAlp Dener   PetscReal         tau, tau_1, tau_2, tau_max, tau_min, max_radius;
450ad3a497SAlp Dener   PetscBool         is_bfgs, is_jacobi, is_symmetric, sym_set;
46c4b75bccSAlp Dener   PetscInt          n, N, nDiff;
47eb910715SAlp Dener   PetscInt          i_max = 5;
48eb910715SAlp Dener   PetscInt          j_max = 1;
49eb910715SAlp Dener   PetscInt          i, j;
502e6e4ca1SStefano Zampini   PetscVoidFunction kspTR;
51eb910715SAlp Dener 
52eb910715SAlp Dener   PetscFunctionBegin;
5328017e9fSAlp Dener   /* Project the current point onto the feasible set */
549566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
559566063dSJacob Faibussowitsch   PetscCall(TaoSetVariableBounds(bnk->bncg, tao->XL, tao->XU));
561baa6e33SBarry Smith   if (tao->bounded) PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch, tao->XL, tao->XU));
5728017e9fSAlp Dener 
5828017e9fSAlp Dener   /* Project the initial point onto the feasible region */
599566063dSJacob Faibussowitsch   PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
6028017e9fSAlp Dener 
6128017e9fSAlp Dener   /* Check convergence criteria */
629566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient));
639566063dSJacob Faibussowitsch   PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
649566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
659566063dSJacob Faibussowitsch   PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
669566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
6728017e9fSAlp Dener 
68c0f10754SAlp Dener   /* Test the initial point for convergence */
699566063dSJacob Faibussowitsch   PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
709566063dSJacob Faibussowitsch   PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
713c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(bnk->f) && !PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
729566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its));
739566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, 1.0));
74dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
753ba16761SJacob Faibussowitsch   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);
76c0f10754SAlp Dener 
77e031d6f5SAlp Dener   /* Reset KSP stopping reason counters */
78eb910715SAlp Dener   bnk->ksp_atol = 0;
79eb910715SAlp Dener   bnk->ksp_rtol = 0;
80eb910715SAlp Dener   bnk->ksp_dtol = 0;
81eb910715SAlp Dener   bnk->ksp_ctol = 0;
82eb910715SAlp Dener   bnk->ksp_negc = 0;
83eb910715SAlp Dener   bnk->ksp_iter = 0;
84eb910715SAlp Dener   bnk->ksp_othr = 0;
85eb910715SAlp Dener 
86e031d6f5SAlp Dener   /* Reset accepted step type counters */
87e031d6f5SAlp Dener   bnk->tot_cg_its = 0;
88e031d6f5SAlp Dener   bnk->newt       = 0;
89e031d6f5SAlp Dener   bnk->bfgs       = 0;
90e031d6f5SAlp Dener   bnk->sgrad      = 0;
91e031d6f5SAlp Dener   bnk->grad       = 0;
92e031d6f5SAlp Dener 
93fed79b8eSAlp Dener   /* Initialize the Hessian perturbation */
94fed79b8eSAlp Dener   bnk->pert = bnk->sval;
95fed79b8eSAlp Dener 
96937a31a1SAlp Dener   /* Reset initial steplength to zero (this helps BNCG reset its direction internally) */
979566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
98937a31a1SAlp Dener 
99e031d6f5SAlp Dener   /* Allocate the vectors needed for the BFGS approximation */
1009566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
1019566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &is_bfgs));
1029566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCJACOBI, &is_jacobi));
103b9ac7092SAlp Dener   if (is_bfgs) {
104b9ac7092SAlp Dener     bnk->bfgs_pre = pc;
1059566063dSJacob Faibussowitsch     PetscCall(PCLMVMGetMatLMVM(bnk->bfgs_pre, &bnk->M));
1069566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tao->solution, &n));
1079566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tao->solution, &N));
1089566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(bnk->M, n, n, N, N));
1099566063dSJacob Faibussowitsch     PetscCall(MatLMVMAllocate(bnk->M, tao->solution, bnk->unprojected_gradient));
1109566063dSJacob Faibussowitsch     PetscCall(MatIsSymmetricKnown(bnk->M, &sym_set, &is_symmetric));
1113c859ba3SBarry Smith     PetscCheck(sym_set && is_symmetric, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix in the LMVM preconditioner must be symmetric.");
1121baa6e33SBarry Smith   } else if (is_jacobi) PetscCall(PCJacobiSetUseAbs(pc, PETSC_TRUE));
113e031d6f5SAlp Dener 
114e031d6f5SAlp Dener   /* Prepare the min/max vectors for safeguarding diagonal scales */
1159566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_min, bnk->dmin));
1169566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_max, bnk->dmax));
117eb910715SAlp Dener 
118eb910715SAlp Dener   /* Initialize trust-region radius.  The initialization is only performed
119eb910715SAlp Dener      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
120c0f10754SAlp Dener   *needH = PETSC_TRUE;
1219566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp, "KSPCGSetRadius_C", &kspTR));
1222e6e4ca1SStefano Zampini   if (kspTR) {
12362675beeSAlp Dener     switch (initType) {
124eb910715SAlp Dener     case BNK_INIT_CONSTANT:
125eb910715SAlp Dener       /* Use the initial radius specified */
126c0f10754SAlp Dener       tao->trust = tao->trust0;
127eb910715SAlp Dener       break;
128eb910715SAlp Dener 
129eb910715SAlp Dener     case BNK_INIT_INTERPOLATION:
130c0f10754SAlp Dener       /* Use interpolation based on the initial Hessian */
131eb910715SAlp Dener       max_radius = 0.0;
13208752603SAlp Dener       tao->trust = tao->trust0;
133eb910715SAlp Dener       for (j = 0; j < j_max; ++j) {
1340a4511e9SAlp Dener         f_min = bnk->f;
135eb910715SAlp Dener         sigma = 0.0;
136eb910715SAlp Dener 
137c0f10754SAlp Dener         if (*needH) {
13862602cfbSAlp Dener           /* Compute the Hessian at the new step, and extract the inactive subsystem */
1399566063dSJacob Faibussowitsch           PetscCall((*bnk->computehessian)(tao));
1409566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, BNK_AS_NONE));
141b3e6a353SBarry Smith           PetscCall(TaoBNKComputeSubHessian(tao));
142c0f10754SAlp Dener           *needH = PETSC_FALSE;
143eb910715SAlp Dener         }
144eb910715SAlp Dener 
145eb910715SAlp Dener         for (i = 0; i < i_max; ++i) {
14662602cfbSAlp Dener           /* Take a steepest descent step and snap it to bounds */
1479566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
1489566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution, -tao->trust / bnk->gnorm, tao->gradient));
1499566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
15089da521bSAlp Dener           /* Compute the step we actually accepted */
1519566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->W));
1529566063dSJacob Faibussowitsch           PetscCall(VecAXPY(bnk->W, -1.0, bnk->Xold));
15362602cfbSAlp Dener           /* Compute the objective at the trial */
1549566063dSJacob Faibussowitsch           PetscCall(TaoComputeObjective(tao, tao->solution, &ftrial));
1553c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(bnk->f), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
1569566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->Xold, tao->solution));
157eb910715SAlp Dener           if (PetscIsInfOrNanReal(ftrial)) {
158eb910715SAlp Dener             tau = bnk->gamma1_i;
159eb910715SAlp Dener           } else {
1600a4511e9SAlp Dener             if (ftrial < f_min) {
1610a4511e9SAlp Dener               f_min = ftrial;
162eb910715SAlp Dener               sigma = -tao->trust / bnk->gnorm;
163eb910715SAlp Dener             }
16408752603SAlp Dener 
165770b7498SAlp Dener             /* Compute the predicted and actual reduction */
16689da521bSAlp Dener             if (bnk->active_idx) {
1679566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
1689566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1692ab2a32cSAlp Dener             } else {
17008752603SAlp Dener               bnk->X_inactive    = bnk->W;
17108752603SAlp Dener               bnk->inactive_work = bnk->Xwork;
1722ab2a32cSAlp Dener             }
1739566063dSJacob Faibussowitsch             PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
1749566063dSJacob Faibussowitsch             PetscCall(VecDot(bnk->X_inactive, bnk->inactive_work, &prered));
17589da521bSAlp Dener             if (bnk->active_idx) {
1769566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
1779566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1782ab2a32cSAlp Dener             }
179eb910715SAlp Dener             prered = tao->trust * (bnk->gnorm - 0.5 * tao->trust * prered / (bnk->gnorm * bnk->gnorm));
180eb910715SAlp Dener             actred = bnk->f - ftrial;
1813105154fSTodd Munson             if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
182eb910715SAlp Dener               kappa = 1.0;
1833105154fSTodd Munson             } else {
184eb910715SAlp Dener               kappa = actred / prered;
185eb910715SAlp Dener             }
186eb910715SAlp Dener 
187eb910715SAlp Dener             tau_1   = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust + (1.0 - bnk->theta_i) * prered - actred);
188eb910715SAlp Dener             tau_2   = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust - (1.0 + bnk->theta_i) * prered + actred);
189eb910715SAlp Dener             tau_min = PetscMin(tau_1, tau_2);
190eb910715SAlp Dener             tau_max = PetscMax(tau_1, tau_2);
191eb910715SAlp Dener 
19218cfbf8eSSatish Balay             if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu1_i) {
193eb910715SAlp Dener               /*  Great agreement */
194eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
195eb910715SAlp Dener 
196eb910715SAlp Dener               if (tau_max < 1.0) {
197eb910715SAlp Dener                 tau = bnk->gamma3_i;
1983105154fSTodd Munson               } else if (tau_max > bnk->gamma4_i) {
199eb910715SAlp Dener                 tau = bnk->gamma4_i;
2003105154fSTodd Munson               } else {
201eb910715SAlp Dener                 tau = tau_max;
202eb910715SAlp Dener               }
20318cfbf8eSSatish Balay             } else if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu2_i) {
204eb910715SAlp Dener               /*  Good agreement */
205eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
206eb910715SAlp Dener 
207eb910715SAlp Dener               if (tau_max < bnk->gamma2_i) {
208eb910715SAlp Dener                 tau = bnk->gamma2_i;
209eb910715SAlp Dener               } else if (tau_max > bnk->gamma3_i) {
210eb910715SAlp Dener                 tau = bnk->gamma3_i;
211eb910715SAlp Dener               } else {
212eb910715SAlp Dener                 tau = tau_max;
213eb910715SAlp Dener               }
2148f8a4e06SAlp Dener             } else {
215eb910715SAlp Dener               /*  Not good agreement */
216eb910715SAlp Dener               if (tau_min > 1.0) {
217eb910715SAlp Dener                 tau = bnk->gamma2_i;
218eb910715SAlp Dener               } else if (tau_max < bnk->gamma1_i) {
219eb910715SAlp Dener                 tau = bnk->gamma1_i;
220eb910715SAlp Dener               } else if ((tau_min < bnk->gamma1_i) && (tau_max >= 1.0)) {
221eb910715SAlp Dener                 tau = bnk->gamma1_i;
2223105154fSTodd Munson               } else if ((tau_1 >= bnk->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
223eb910715SAlp Dener                 tau = tau_1;
2243105154fSTodd Munson               } else if ((tau_2 >= bnk->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
225eb910715SAlp Dener                 tau = tau_2;
226eb910715SAlp Dener               } else {
227eb910715SAlp Dener                 tau = tau_max;
228eb910715SAlp Dener               }
229eb910715SAlp Dener             }
230eb910715SAlp Dener           }
231eb910715SAlp Dener           tao->trust = tau * tao->trust;
232eb910715SAlp Dener         }
233eb910715SAlp Dener 
2340a4511e9SAlp Dener         if (f_min < bnk->f) {
235937a31a1SAlp Dener           /* We accidentally found a solution better than the initial, so accept it */
2360a4511e9SAlp Dener           bnk->f = f_min;
2379566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
2389566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution, sigma, tao->gradient));
2399566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
2409566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, tao->stepdirection));
2419566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->stepdirection, -1.0, bnk->Xold));
2429566063dSJacob Faibussowitsch           PetscCall(TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient));
2439566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
2449566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
2459566063dSJacob Faibussowitsch           PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
246937a31a1SAlp Dener           /* Compute gradient at the new iterate and flip switch to compute the Hessian later */
2479566063dSJacob Faibussowitsch           PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
248c0f10754SAlp Dener           *needH = PETSC_TRUE;
249937a31a1SAlp Dener           /* Test the new step for convergence */
2509566063dSJacob Faibussowitsch           PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
2519566063dSJacob Faibussowitsch           PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
2523c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
2539566063dSJacob Faibussowitsch           PetscCall(TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its));
2549566063dSJacob Faibussowitsch           PetscCall(TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, 1.0));
255dbbe0bcdSBarry Smith           PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
2563ba16761SJacob Faibussowitsch           if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);
257937a31a1SAlp Dener           /* active BNCG recycling early because we have a stepdirection computed */
2589566063dSJacob Faibussowitsch           PetscCall(TaoSetRecycleHistory(bnk->bncg, PETSC_TRUE));
259eb910715SAlp Dener         }
260eb910715SAlp Dener       }
261eb910715SAlp Dener       tao->trust = PetscMax(tao->trust, max_radius);
262e031d6f5SAlp Dener 
263e031d6f5SAlp Dener       /* Ensure that the trust radius is within the limits */
264e031d6f5SAlp Dener       tao->trust = PetscMax(tao->trust, bnk->min_radius);
265e031d6f5SAlp Dener       tao->trust = PetscMin(tao->trust, bnk->max_radius);
266eb910715SAlp Dener       break;
267eb910715SAlp Dener 
268eb910715SAlp Dener     default:
269eb910715SAlp Dener       /* Norm of the first direction will initialize radius */
270eb910715SAlp Dener       tao->trust = 0.0;
271eb910715SAlp Dener       break;
272eb910715SAlp Dener     }
273eb910715SAlp Dener   }
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
275eb910715SAlp Dener }
276eb910715SAlp Dener 
277df278d8fSAlp Dener /*------------------------------------------------------------*/
278df278d8fSAlp Dener 
279b3e6a353SBarry Smith /* Computes the exact Hessian and extracts its subHessian */
28062675beeSAlp Dener 
281d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKComputeHessian(Tao tao)
282d71ae5a4SJacob Faibussowitsch {
28362675beeSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
28462675beeSAlp Dener 
28562675beeSAlp Dener   PetscFunctionBegin;
28662675beeSAlp Dener   /* Compute the Hessian */
2879566063dSJacob Faibussowitsch   PetscCall(TaoComputeHessian(tao, tao->solution, tao->hessian, tao->hessian_pre));
28862675beeSAlp Dener   /* Add a correction to the BFGS preconditioner */
2891baa6e33SBarry Smith   if (bnk->M) PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
290e0ed867bSAlp Dener   /* Prepare the reduced sub-matrices for the inactive set */
291b3e6a353SBarry Smith   PetscCall(TaoBNKComputeSubHessian(tao));
2923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29362675beeSAlp Dener }
29462675beeSAlp Dener 
29562675beeSAlp Dener /*------------------------------------------------------------*/
29662675beeSAlp Dener 
2972f75a4aaSAlp Dener /* Routine for estimating the active set */
2982f75a4aaSAlp Dener 
299d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKEstimateActiveSet(Tao tao, PetscInt asType)
300d71ae5a4SJacob Faibussowitsch {
3012f75a4aaSAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
302f4db9bf7SStefano Zampini   PetscBool hessComputed, diagExists, hadactive;
3032f75a4aaSAlp Dener 
3042f75a4aaSAlp Dener   PetscFunctionBegin;
305f4db9bf7SStefano Zampini   hadactive = bnk->active_idx ? PETSC_TRUE : PETSC_FALSE;
30608752603SAlp Dener   switch (asType) {
3072f75a4aaSAlp Dener   case BNK_AS_NONE:
3089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->inactive_idx));
3099566063dSJacob Faibussowitsch     PetscCall(VecWhichInactive(tao->XL, tao->solution, bnk->unprojected_gradient, tao->XU, PETSC_TRUE, &bnk->inactive_idx));
3109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->active_idx));
3119566063dSJacob Faibussowitsch     PetscCall(ISComplementVec(bnk->inactive_idx, tao->solution, &bnk->active_idx));
3122f75a4aaSAlp Dener     break;
3132f75a4aaSAlp Dener 
3142f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
3152f75a4aaSAlp Dener     /* Compute the trial step vector with which we will estimate the active set at the next iteration */
316b9ac7092SAlp Dener     if (bnk->M) {
3172f75a4aaSAlp Dener       /* If the BFGS preconditioner matrix is available, we will construct a trial step with it */
3189566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, bnk->W));
3192f75a4aaSAlp Dener     } else {
320fc5ca067SStefano Zampini       hessComputed = diagExists = PETSC_FALSE;
32148a46eb9SPierre Jolivet       if (tao->hessian) PetscCall(MatAssembled(tao->hessian, &hessComputed));
32248a46eb9SPierre Jolivet       if (hessComputed) PetscCall(MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &diagExists));
323fc5ca067SStefano Zampini       if (diagExists) {
3249b6ef848SAlp Dener         /* BFGS preconditioner doesn't exist so let's invert the absolute diagonal of the Hessian instead onto the gradient */
3259566063dSJacob Faibussowitsch         PetscCall(MatGetDiagonal(tao->hessian, bnk->Xwork));
3269566063dSJacob Faibussowitsch         PetscCall(VecAbs(bnk->Xwork));
3279566063dSJacob Faibussowitsch         PetscCall(VecMedian(bnk->Diag_min, bnk->Xwork, bnk->Diag_max, bnk->Xwork));
3289566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(bnk->Xwork));
3299566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(bnk->W, bnk->Xwork, bnk->unprojected_gradient));
33061be54a6SAlp Dener       } else {
331c4b75bccSAlp Dener         /* If the Hessian or its diagonal does not exist, we will simply use gradient step */
3329566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, bnk->W));
33361be54a6SAlp Dener       }
3342f75a4aaSAlp Dener     }
3359566063dSJacob Faibussowitsch     PetscCall(VecScale(bnk->W, -1.0));
3369371c9d4SSatish Balay     PetscCall(TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, bnk->unprojected_gradient, bnk->W, bnk->Xwork, bnk->as_step, &bnk->as_tol, &bnk->active_lower, &bnk->active_upper, &bnk->active_fixed, &bnk->active_idx, &bnk->inactive_idx));
337c4b75bccSAlp Dener     break;
3382f75a4aaSAlp Dener 
339d71ae5a4SJacob Faibussowitsch   default:
340d71ae5a4SJacob Faibussowitsch     break;
3412f75a4aaSAlp Dener   }
342f4db9bf7SStefano Zampini   bnk->resetksp = (PetscBool)(bnk->active_idx || hadactive); /* inactive Hessian size may have changed, need to reset operators */
3433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3442f75a4aaSAlp Dener }
3452f75a4aaSAlp Dener 
3462f75a4aaSAlp Dener /*------------------------------------------------------------*/
3472f75a4aaSAlp Dener 
3482f75a4aaSAlp Dener /* Routine for bounding the step direction */
3492f75a4aaSAlp Dener 
350d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKBoundStep(Tao tao, PetscInt asType, Vec step)
351d71ae5a4SJacob Faibussowitsch {
3522f75a4aaSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
3532f75a4aaSAlp Dener 
3542f75a4aaSAlp Dener   PetscFunctionBegin;
355a1318120SAlp Dener   switch (asType) {
356d71ae5a4SJacob Faibussowitsch   case BNK_AS_NONE:
357d71ae5a4SJacob Faibussowitsch     PetscCall(VecISSet(step, bnk->active_idx, 0.0));
358d71ae5a4SJacob Faibussowitsch     break;
3592f75a4aaSAlp Dener 
360d71ae5a4SJacob Faibussowitsch   case BNK_AS_BERTSEKAS:
361d71ae5a4SJacob Faibussowitsch     PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, bnk->active_lower, bnk->active_upper, bnk->active_fixed, 1.0, step));
362d71ae5a4SJacob Faibussowitsch     break;
3632f75a4aaSAlp Dener 
364d71ae5a4SJacob Faibussowitsch   default:
365d71ae5a4SJacob Faibussowitsch     break;
3662f75a4aaSAlp Dener   }
3673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3682f75a4aaSAlp Dener }
3692f75a4aaSAlp Dener 
370e031d6f5SAlp Dener /*------------------------------------------------------------*/
371e031d6f5SAlp Dener 
372e031d6f5SAlp Dener /* Routine for taking a finite number of BNCG iterations to
373e031d6f5SAlp Dener    accelerate Newton convergence.
374e031d6f5SAlp Dener 
375e031d6f5SAlp Dener    In practice, this approach simply trades off Hessian evaluations
376e031d6f5SAlp Dener    for more gradient evaluations.
377e031d6f5SAlp Dener */
378e031d6f5SAlp Dener 
379d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKTakeCGSteps(Tao tao, PetscBool *terminate)
380d71ae5a4SJacob Faibussowitsch {
381c0f10754SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
382c0f10754SAlp Dener 
383c0f10754SAlp Dener   PetscFunctionBegin;
384c0f10754SAlp Dener   *terminate = PETSC_FALSE;
385c0f10754SAlp Dener   if (bnk->max_cg_its > 0) {
386c4b75bccSAlp Dener     /* Copy the current function value (important vectors are already shared) */
387c0f10754SAlp Dener     bnk->bncg_ctx->f = bnk->f;
388c0f10754SAlp Dener     /* Take some small finite number of BNCG iterations */
3899566063dSJacob Faibussowitsch     PetscCall(TaoSolve(bnk->bncg));
390c0f10754SAlp Dener     /* Add the number of gradient and function evaluations to the total */
391c0f10754SAlp Dener     tao->nfuncs += bnk->bncg->nfuncs;
392c0f10754SAlp Dener     tao->nfuncgrads += bnk->bncg->nfuncgrads;
393c0f10754SAlp Dener     tao->ngrads += bnk->bncg->ngrads;
394c0f10754SAlp Dener     tao->nhess += bnk->bncg->nhess;
395e031d6f5SAlp Dener     bnk->tot_cg_its += bnk->bncg->niter;
396c4b75bccSAlp Dener     /* Extract the BNCG function value out and save it into BNK */
397c0f10754SAlp Dener     bnk->f = bnk->bncg_ctx->f;
398c0f10754SAlp Dener     if (bnk->bncg->reason == TAO_CONVERGED_GATOL || bnk->bncg->reason == TAO_CONVERGED_GRTOL || bnk->bncg->reason == TAO_CONVERGED_GTTOL || bnk->bncg->reason == TAO_CONVERGED_MINF) {
399c0f10754SAlp Dener       *terminate = PETSC_TRUE;
40061be54a6SAlp Dener     } else {
4019566063dSJacob Faibussowitsch       PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
402c0f10754SAlp Dener     }
403c0f10754SAlp Dener   }
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
405c0f10754SAlp Dener }
406c0f10754SAlp Dener 
4072f75a4aaSAlp Dener /*------------------------------------------------------------*/
4082f75a4aaSAlp Dener 
409c0f10754SAlp Dener /* Routine for computing the Newton step. */
410df278d8fSAlp Dener 
411d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKComputeStep(Tao tao, PetscBool shift, KSPConvergedReason *ksp_reason, PetscInt *step_type)
412d71ae5a4SJacob Faibussowitsch {
413eb910715SAlp Dener   TAO_BNK          *bnk         = (TAO_BNK *)tao->data;
414eb910715SAlp Dener   PetscInt          bfgsUpdates = 0;
415eb910715SAlp Dener   PetscInt          kspits;
416bddd1ffdSAlp Dener   PetscBool         is_lmvm;
4172e6e4ca1SStefano Zampini   PetscVoidFunction kspTR;
418eb910715SAlp Dener 
419eb910715SAlp Dener   PetscFunctionBegin;
42089da521bSAlp Dener   /* If there are no inactive variables left, save some computation and return an adjusted zero step
42189da521bSAlp Dener      that has (l-x) and (u-x) for lower and upper bounded variables. */
42289da521bSAlp Dener   if (!bnk->inactive_idx) {
4239566063dSJacob Faibussowitsch     PetscCall(VecSet(tao->stepdirection, 0.0));
4249566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
4253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
42689da521bSAlp Dener   }
42789da521bSAlp Dener 
42862675beeSAlp Dener   /* Shift the reduced Hessian matrix */
429e831869dSStefano Zampini   if (shift && bnk->pert > 0) {
4309566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)tao->hessian, MATLMVM, &is_lmvm));
431f7bf01afSAlp Dener     if (is_lmvm) {
4329566063dSJacob Faibussowitsch       PetscCall(MatShift(tao->hessian, bnk->pert));
433f7bf01afSAlp Dener     } else {
4349566063dSJacob Faibussowitsch       PetscCall(MatShift(bnk->H_inactive, bnk->pert));
43548a46eb9SPierre Jolivet       if (bnk->H_inactive != bnk->Hpre_inactive) PetscCall(MatShift(bnk->Hpre_inactive, bnk->pert));
43662675beeSAlp Dener     }
437f7bf01afSAlp Dener   }
43862675beeSAlp Dener 
439eb910715SAlp Dener   /* Solve the Newton system of equations */
440937a31a1SAlp Dener   tao->ksp_its = 0;
4419566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
442f4db9bf7SStefano Zampini   if (bnk->resetksp) {
4439566063dSJacob Faibussowitsch     PetscCall(KSPReset(tao->ksp));
4449566063dSJacob Faibussowitsch     PetscCall(KSPResetFromOptions(tao->ksp));
445f4db9bf7SStefano Zampini     bnk->resetksp = PETSC_FALSE;
446f4db9bf7SStefano Zampini   }
4479566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(tao->ksp, bnk->H_inactive, bnk->Hpre_inactive));
4489566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, bnk->Gwork));
44989da521bSAlp Dener   if (bnk->active_idx) {
4509566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
4519566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
4525e9b73cbSAlp Dener   } else {
4535e9b73cbSAlp Dener     bnk->G_inactive = bnk->unprojected_gradient;
4545e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
45528017e9fSAlp Dener   }
4569566063dSJacob Faibussowitsch   PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
4579566063dSJacob Faibussowitsch   PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
4589566063dSJacob Faibussowitsch   PetscCall(KSPGetIterationNumber(tao->ksp, &kspits));
459eb910715SAlp Dener   tao->ksp_its += kspits;
460eb910715SAlp Dener   tao->ksp_tot_its += kspits;
461f4db9bf7SStefano Zampini   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp, "KSPCGGetNormD_C", &kspTR));
462f4db9bf7SStefano Zampini   if (kspTR) {
4639566063dSJacob Faibussowitsch     PetscCall(KSPCGGetNormD(tao->ksp, &bnk->dnorm));
464eb910715SAlp Dener 
465eb910715SAlp Dener     if (0.0 == tao->trust) {
466eb910715SAlp Dener       /* Radius was uninitialized; use the norm of the direction */
467080d2917SAlp Dener       if (bnk->dnorm > 0.0) {
468080d2917SAlp Dener         tao->trust = bnk->dnorm;
469eb910715SAlp Dener 
470eb910715SAlp Dener         /* Modify the radius if it is too large or small */
471eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
472eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
473eb910715SAlp Dener       } else {
474eb910715SAlp Dener         /* The direction was bad; set radius to default value and re-solve
475eb910715SAlp Dener            the trust-region subproblem to get a direction */
476eb910715SAlp Dener         tao->trust = tao->trust0;
477eb910715SAlp Dener 
478eb910715SAlp Dener         /* Modify the radius if it is too large or small */
479eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
480eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
481eb910715SAlp Dener 
4829566063dSJacob Faibussowitsch         PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
4839566063dSJacob Faibussowitsch         PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
4849566063dSJacob Faibussowitsch         PetscCall(KSPGetIterationNumber(tao->ksp, &kspits));
485eb910715SAlp Dener         tao->ksp_its += kspits;
486eb910715SAlp Dener         tao->ksp_tot_its += kspits;
4879566063dSJacob Faibussowitsch         PetscCall(KSPCGGetNormD(tao->ksp, &bnk->dnorm));
488eb910715SAlp Dener 
4893c859ba3SBarry Smith         PetscCheck(bnk->dnorm != 0.0, PetscObjectComm((PetscObject)tao), PETSC_ERR_PLIB, "Initial direction zero");
490eb910715SAlp Dener       }
491eb910715SAlp Dener     }
492eb910715SAlp Dener   }
4935e9b73cbSAlp Dener   /* Restore sub vectors back */
49489da521bSAlp Dener   if (bnk->active_idx) {
4959566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
4969566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
4975e9b73cbSAlp Dener   }
498770b7498SAlp Dener   /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
4999566063dSJacob Faibussowitsch   PetscCall(VecScale(tao->stepdirection, -1.0));
5009566063dSJacob Faibussowitsch   PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
501770b7498SAlp Dener 
502770b7498SAlp Dener   /* Record convergence reasons */
5039566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(tao->ksp, ksp_reason));
504e465cd6fSAlp Dener   if (KSP_CONVERGED_ATOL == *ksp_reason) {
505770b7498SAlp Dener     ++bnk->ksp_atol;
506e465cd6fSAlp Dener   } else if (KSP_CONVERGED_RTOL == *ksp_reason) {
507770b7498SAlp Dener     ++bnk->ksp_rtol;
508*4a221d59SStefano Zampini   } else if (KSP_CONVERGED_STEP_LENGTH == *ksp_reason) {
509770b7498SAlp Dener     ++bnk->ksp_ctol;
510*4a221d59SStefano Zampini   } else if (KSP_CONVERGED_NEG_CURVE == *ksp_reason) {
511770b7498SAlp Dener     ++bnk->ksp_negc;
512e465cd6fSAlp Dener   } else if (KSP_DIVERGED_DTOL == *ksp_reason) {
513770b7498SAlp Dener     ++bnk->ksp_dtol;
514e465cd6fSAlp Dener   } else if (KSP_DIVERGED_ITS == *ksp_reason) {
515770b7498SAlp Dener     ++bnk->ksp_iter;
516770b7498SAlp Dener   } else {
517770b7498SAlp Dener     ++bnk->ksp_othr;
518770b7498SAlp Dener   }
519fed79b8eSAlp Dener 
520fed79b8eSAlp Dener   /* Make sure the BFGS preconditioner is healthy */
521b9ac7092SAlp Dener   if (bnk->M) {
5229566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
523b2d8c577SAlp Dener     if ((KSP_DIVERGED_INDEFINITE_PC == *ksp_reason) && (bfgsUpdates > 0)) {
524fed79b8eSAlp Dener       /* Preconditioner is numerically indefinite; reset the approximation. */
5259566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
5269566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
527eb910715SAlp Dener     }
528fed79b8eSAlp Dener   }
5296b591159SAlp Dener   *step_type = BNK_NEWTON;
5303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
531e465cd6fSAlp Dener }
532eb910715SAlp Dener 
53362675beeSAlp Dener /*------------------------------------------------------------*/
53462675beeSAlp Dener 
5355e9b73cbSAlp Dener /* Routine for recomputing the predicted reduction for a given step vector */
5365e9b73cbSAlp Dener 
537d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKRecomputePred(Tao tao, Vec S, PetscReal *prered)
538d71ae5a4SJacob Faibussowitsch {
5395e9b73cbSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
5405e9b73cbSAlp Dener 
5415e9b73cbSAlp Dener   PetscFunctionBegin;
5425e9b73cbSAlp Dener   /* Extract subvectors associated with the inactive set */
54389da521bSAlp Dener   if (bnk->active_idx) {
5449566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
5459566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
5469566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5475e9b73cbSAlp Dener   } else {
5485e9b73cbSAlp Dener     bnk->X_inactive    = tao->stepdirection;
5495e9b73cbSAlp Dener     bnk->inactive_work = bnk->Xwork;
5505e9b73cbSAlp Dener     bnk->G_inactive    = bnk->Gwork;
5515e9b73cbSAlp Dener   }
5525e9b73cbSAlp Dener   /* Recompute the predicted decrease based on the quadratic model */
5539566063dSJacob Faibussowitsch   PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
5549566063dSJacob Faibussowitsch   PetscCall(VecAYPX(bnk->inactive_work, -0.5, bnk->G_inactive));
5559566063dSJacob Faibussowitsch   PetscCall(VecDot(bnk->inactive_work, bnk->X_inactive, prered));
5565e9b73cbSAlp Dener   /* Restore the sub vectors */
55789da521bSAlp Dener   if (bnk->active_idx) {
5589566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
5599566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
5609566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5615e9b73cbSAlp Dener   }
5623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5635e9b73cbSAlp Dener }
5645e9b73cbSAlp Dener 
5655e9b73cbSAlp Dener /*------------------------------------------------------------*/
5665e9b73cbSAlp Dener 
56762675beeSAlp Dener /* Routine for ensuring that the Newton step is a descent direction.
56862675beeSAlp Dener 
56962675beeSAlp Dener    The step direction falls back onto BFGS, scaled gradient and gradient steps
57062675beeSAlp Dener    in the event that the Newton step fails the test.
57162675beeSAlp Dener */
57262675beeSAlp Dener 
573d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKSafeguardStep(Tao tao, KSPConvergedReason ksp_reason, PetscInt *stepType)
574d71ae5a4SJacob Faibussowitsch {
575e465cd6fSAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
576b2d8c577SAlp Dener   PetscReal gdx, e_min;
577e465cd6fSAlp Dener   PetscInt  bfgsUpdates;
578e465cd6fSAlp Dener 
579e465cd6fSAlp Dener   PetscFunctionBegin;
5806b591159SAlp Dener   switch (*stepType) {
5816b591159SAlp Dener   case BNK_NEWTON:
5829566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
583eb910715SAlp Dener     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
584eb910715SAlp Dener       /* Newton step is not descent or direction produced Inf or NaN
585eb910715SAlp Dener         Update the perturbation for next time */
586eb910715SAlp Dener       if (bnk->pert <= 0.0) {
5872e6e4ca1SStefano Zampini         PetscBool is_gltr;
5882e6e4ca1SStefano Zampini 
589eb910715SAlp Dener         /* Initialize the perturbation */
590eb910715SAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
5919566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
5922e6e4ca1SStefano Zampini         if (is_gltr) {
5939566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
594eb910715SAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
595eb910715SAlp Dener         }
596eb910715SAlp Dener       } else {
597eb910715SAlp Dener         /* Increase the perturbation */
598eb910715SAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
599eb910715SAlp Dener       }
600eb910715SAlp Dener 
6010ad3a497SAlp Dener       if (!bnk->M) {
602eb910715SAlp Dener         /* We don't have the bfgs matrix around and updated
603eb910715SAlp Dener           Must use gradient direction in this case */
6049566063dSJacob Faibussowitsch         PetscCall(VecCopy(tao->gradient, tao->stepdirection));
605eb910715SAlp Dener         *stepType = BNK_GRADIENT;
606eb910715SAlp Dener       } else {
607eb910715SAlp Dener         /* Attempt to use the BFGS direction */
6089566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
609eb910715SAlp Dener 
6108d5ead36SAlp Dener         /* Check for success (descent direction)
6118d5ead36SAlp Dener           NOTE: Negative gdx here means not a descent direction because
6128d5ead36SAlp Dener           the fall-back step is missing a negative sign. */
6139566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
6143105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
615eb910715SAlp Dener           /* BFGS direction is not descent or direction produced not a number
616eb910715SAlp Dener             We can assert bfgsUpdates > 1 in this case because
617eb910715SAlp Dener             the first solve produces the scaled gradient direction,
618eb910715SAlp Dener             which is guaranteed to be descent */
619eb910715SAlp Dener 
620eb910715SAlp Dener           /* Use steepest descent direction (scaled) */
6219566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
6229566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
6239566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
624eb910715SAlp Dener 
625eb910715SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
626eb910715SAlp Dener         } else {
6279566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
628eb910715SAlp Dener           if (1 == bfgsUpdates) {
629eb910715SAlp Dener             /* The first BFGS direction is always the scaled gradient */
630eb910715SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
631eb910715SAlp Dener           } else {
632eb910715SAlp Dener             *stepType = BNK_BFGS;
633eb910715SAlp Dener           }
634eb910715SAlp Dener         }
635eb910715SAlp Dener       }
6368d5ead36SAlp Dener       /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
6379566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection, -1.0));
6389566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
639eb910715SAlp Dener     } else {
640eb910715SAlp Dener       /* Computed Newton step is descent */
641eb910715SAlp Dener       switch (ksp_reason) {
642eb910715SAlp Dener       case KSP_DIVERGED_NANORINF:
643eb910715SAlp Dener       case KSP_DIVERGED_BREAKDOWN:
644eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_MAT:
645eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_PC:
646*4a221d59SStefano Zampini       case KSP_CONVERGED_NEG_CURVE:
647eb910715SAlp Dener         /* Matrix or preconditioner is indefinite; increase perturbation */
648eb910715SAlp Dener         if (bnk->pert <= 0.0) {
6492e6e4ca1SStefano Zampini           PetscBool is_gltr;
6502e6e4ca1SStefano Zampini 
651eb910715SAlp Dener           /* Initialize the perturbation */
652eb910715SAlp Dener           bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
6539566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
6542e6e4ca1SStefano Zampini           if (is_gltr) {
6559566063dSJacob Faibussowitsch             PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
656eb910715SAlp Dener             bnk->pert = PetscMax(bnk->pert, -e_min);
657eb910715SAlp Dener           }
658eb910715SAlp Dener         } else {
659eb910715SAlp Dener           /* Increase the perturbation */
660eb910715SAlp Dener           bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
661eb910715SAlp Dener         }
662eb910715SAlp Dener         break;
663eb910715SAlp Dener 
664eb910715SAlp Dener       default:
665eb910715SAlp Dener         /* Newton step computation is good; decrease perturbation */
666eb910715SAlp Dener         bnk->pert = PetscMin(bnk->psfac * bnk->pert, bnk->pmsfac * bnk->gnorm);
667ad540459SPierre Jolivet         if (bnk->pert < bnk->pmin) bnk->pert = 0.0;
668eb910715SAlp Dener         break;
669eb910715SAlp Dener       }
670fed79b8eSAlp Dener       *stepType = BNK_NEWTON;
671eb910715SAlp Dener     }
6726b591159SAlp Dener     break;
6736b591159SAlp Dener 
6746b591159SAlp Dener   case BNK_BFGS:
6756b591159SAlp Dener     /* Check for success (descent direction) */
6769566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
6776b591159SAlp Dener     if (gdx >= 0 || PetscIsInfOrNanReal(gdx)) {
6786b591159SAlp Dener       /* Step is not descent or solve was not successful
6796b591159SAlp Dener          Use steepest descent direction (scaled) */
6809566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
6819566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
6829566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, tao->gradient, tao->stepdirection));
6839566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection, -1.0));
6849566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
6856b591159SAlp Dener       *stepType = BNK_SCALED_GRADIENT;
6866b591159SAlp Dener     } else {
6876b591159SAlp Dener       *stepType = BNK_BFGS;
6886b591159SAlp Dener     }
6896b591159SAlp Dener     break;
6906b591159SAlp Dener 
691d71ae5a4SJacob Faibussowitsch   case BNK_SCALED_GRADIENT:
692d71ae5a4SJacob Faibussowitsch     break;
6936b591159SAlp Dener 
694d71ae5a4SJacob Faibussowitsch   default:
695d71ae5a4SJacob Faibussowitsch     break;
6966b591159SAlp Dener   }
6976b591159SAlp Dener 
6983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
699eb910715SAlp Dener }
700eb910715SAlp Dener 
701df278d8fSAlp Dener /*------------------------------------------------------------*/
702df278d8fSAlp Dener 
703df278d8fSAlp Dener /* Routine for performing a bound-projected More-Thuente line search.
704df278d8fSAlp Dener 
705df278d8fSAlp Dener   Includes fallbacks to BFGS, scaled gradient, and unscaled gradient steps if the
706df278d8fSAlp Dener   Newton step does not produce a valid step length.
707df278d8fSAlp Dener */
708df278d8fSAlp Dener 
709d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKPerformLineSearch(Tao tao, PetscInt *stepType, PetscReal *steplen, TaoLineSearchConvergedReason *reason)
710d71ae5a4SJacob Faibussowitsch {
711c14b763aSAlp Dener   TAO_BNK                     *bnk = (TAO_BNK *)tao->data;
712c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
713b2d8c577SAlp Dener   PetscReal                    e_min, gdx;
714c14b763aSAlp Dener   PetscInt                     bfgsUpdates;
715c14b763aSAlp Dener 
716c14b763aSAlp Dener   PetscFunctionBegin;
717c14b763aSAlp Dener   /* Perform the linesearch */
7189566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
7199566063dSJacob Faibussowitsch   PetscCall(TaoAddLineSearchCounts(tao));
720c14b763aSAlp Dener 
721b2d8c577SAlp Dener   while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && *stepType != BNK_SCALED_GRADIENT && *stepType != BNK_GRADIENT) {
722c14b763aSAlp Dener     /* Linesearch failed, revert solution */
723c14b763aSAlp Dener     bnk->f = bnk->fold;
7249566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->Xold, tao->solution));
7259566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient));
726c14b763aSAlp Dener 
727937a31a1SAlp Dener     switch (*stepType) {
728c14b763aSAlp Dener     case BNK_NEWTON:
7298d5ead36SAlp Dener       /* Failed to obtain acceptable iterate with Newton step
730c14b763aSAlp Dener          Update the perturbation for next time */
731c14b763aSAlp Dener       if (bnk->pert <= 0.0) {
7322e6e4ca1SStefano Zampini         PetscBool is_gltr;
7332e6e4ca1SStefano Zampini 
734c14b763aSAlp Dener         /* Initialize the perturbation */
735c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
7369566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
7372e6e4ca1SStefano Zampini         if (is_gltr) {
7389566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
739c14b763aSAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
740c14b763aSAlp Dener         }
741c14b763aSAlp Dener       } else {
742c14b763aSAlp Dener         /* Increase the perturbation */
743c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
744c14b763aSAlp Dener       }
745c14b763aSAlp Dener 
7460ad3a497SAlp Dener       if (!bnk->M) {
747c14b763aSAlp Dener         /* We don't have the bfgs matrix around and being updated
748c14b763aSAlp Dener            Must use gradient direction in this case */
7499566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, tao->stepdirection));
750937a31a1SAlp Dener         *stepType = BNK_GRADIENT;
751c14b763aSAlp Dener       } else {
752c14b763aSAlp Dener         /* Attempt to use the BFGS direction */
7539566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
7548d5ead36SAlp Dener         /* Check for success (descent direction)
7558d5ead36SAlp Dener            NOTE: Negative gdx means not a descent direction because the step here is missing a negative sign. */
7569566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
7573105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
758c14b763aSAlp Dener           /* BFGS direction is not descent or direction produced not a number
759c14b763aSAlp Dener              We can assert bfgsUpdates > 1 in this case
760c14b763aSAlp Dener              Use steepest descent direction (scaled) */
7619566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
7629566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
7639566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
764c14b763aSAlp Dener 
765c14b763aSAlp Dener           bfgsUpdates = 1;
766937a31a1SAlp Dener           *stepType   = BNK_SCALED_GRADIENT;
767c14b763aSAlp Dener         } else {
7689566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
769c14b763aSAlp Dener           if (1 == bfgsUpdates) {
770c14b763aSAlp Dener             /* The first BFGS direction is always the scaled gradient */
771937a31a1SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
772c14b763aSAlp Dener           } else {
773937a31a1SAlp Dener             *stepType = BNK_BFGS;
774c14b763aSAlp Dener           }
775c14b763aSAlp Dener         }
776c14b763aSAlp Dener       }
777c14b763aSAlp Dener       break;
778c14b763aSAlp Dener 
779c14b763aSAlp Dener     case BNK_BFGS:
780c14b763aSAlp Dener       /* Can only enter if pc_type == BNK_PC_BFGS
781c14b763aSAlp Dener          Failed to obtain acceptable iterate with BFGS step
782c14b763aSAlp Dener          Attempt to use the scaled gradient direction */
7839566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
7849566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
7859566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
786c14b763aSAlp Dener 
787c14b763aSAlp Dener       bfgsUpdates = 1;
788937a31a1SAlp Dener       *stepType   = BNK_SCALED_GRADIENT;
789c14b763aSAlp Dener       break;
790c14b763aSAlp Dener     }
7918d5ead36SAlp Dener     /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
7929566063dSJacob Faibussowitsch     PetscCall(VecScale(tao->stepdirection, -1.0));
7939566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
794c14b763aSAlp Dener 
7958d5ead36SAlp Dener     /* Perform one last line search with the fall-back step */
7969566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
7979566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
798c14b763aSAlp Dener   }
799c14b763aSAlp Dener   *reason = ls_reason;
8003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
801c14b763aSAlp Dener }
802c14b763aSAlp Dener 
803df278d8fSAlp Dener /*------------------------------------------------------------*/
804df278d8fSAlp Dener 
805df278d8fSAlp Dener /* Routine for updating the trust radius.
806df278d8fSAlp Dener 
807df278d8fSAlp Dener   Function features three different update methods:
808df278d8fSAlp Dener   1) Line-search step length based
809df278d8fSAlp Dener   2) Predicted decrease on the CG quadratic model
810df278d8fSAlp Dener   3) Interpolation
811df278d8fSAlp Dener */
812df278d8fSAlp Dener 
813d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKUpdateTrustRadius(Tao tao, PetscReal prered, PetscReal actred, PetscInt updateType, PetscInt stepType, PetscBool *accept)
814d71ae5a4SJacob Faibussowitsch {
815080d2917SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
816080d2917SAlp Dener 
817b1c2d0e3SAlp Dener   PetscReal step, kappa;
818080d2917SAlp Dener   PetscReal gdx, tau_1, tau_2, tau_min, tau_max;
819080d2917SAlp Dener 
820080d2917SAlp Dener   PetscFunctionBegin;
821080d2917SAlp Dener   /* Update trust region radius */
822080d2917SAlp Dener   *accept = PETSC_FALSE;
82328017e9fSAlp Dener   switch (updateType) {
824080d2917SAlp Dener   case BNK_UPDATE_STEP:
825c14b763aSAlp Dener     *accept = PETSC_TRUE; /* always accept here because line search succeeded */
826080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
8279566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchGetStepLength(tao->linesearch, &step));
828080d2917SAlp Dener       if (step < bnk->nu1) {
829080d2917SAlp Dener         /* Very bad step taken; reduce radius */
830080d2917SAlp Dener         tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
831080d2917SAlp Dener       } else if (step < bnk->nu2) {
832080d2917SAlp Dener         /* Reasonably bad step taken; reduce radius */
833080d2917SAlp Dener         tao->trust = bnk->omega2 * PetscMin(bnk->dnorm, tao->trust);
834080d2917SAlp Dener       } else if (step < bnk->nu3) {
835080d2917SAlp Dener         /*  Reasonable step was taken; leave radius alone */
836080d2917SAlp Dener         if (bnk->omega3 < 1.0) {
837080d2917SAlp Dener           tao->trust = bnk->omega3 * PetscMin(bnk->dnorm, tao->trust);
838080d2917SAlp Dener         } else if (bnk->omega3 > 1.0) {
839080d2917SAlp Dener           tao->trust = PetscMax(bnk->omega3 * bnk->dnorm, tao->trust);
840080d2917SAlp Dener         }
841080d2917SAlp Dener       } else if (step < bnk->nu4) {
842080d2917SAlp Dener         /*  Full step taken; increase the radius */
843080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega4 * bnk->dnorm, tao->trust);
844080d2917SAlp Dener       } else {
845080d2917SAlp Dener         /*  More than full step taken; increase the radius */
846080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega5 * bnk->dnorm, tao->trust);
847080d2917SAlp Dener       }
848080d2917SAlp Dener     } else {
849080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
850080d2917SAlp Dener       tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
851080d2917SAlp Dener     }
852080d2917SAlp Dener     break;
853080d2917SAlp Dener 
854080d2917SAlp Dener   case BNK_UPDATE_REDUCTION:
855080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
856e0ed867bSAlp Dener       if ((prered < 0.0) || PetscIsInfOrNanReal(prered)) {
857fed79b8eSAlp Dener         /* The predicted reduction has the wrong sign.  This cannot
858fed79b8eSAlp Dener            happen in infinite precision arithmetic.  Step should
859fed79b8eSAlp Dener            be rejected! */
860080d2917SAlp Dener         tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8613105154fSTodd Munson       } else {
862b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
863080d2917SAlp Dener           tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
864080d2917SAlp Dener         } else {
8653105154fSTodd Munson           if ((PetscAbsScalar(actred) <= PetscMax(1.0, PetscAbsScalar(bnk->f)) * bnk->epsilon) && (PetscAbsScalar(prered) <= PetscMax(1.0, PetscAbsScalar(bnk->f)) * bnk->epsilon)) {
866080d2917SAlp Dener             kappa = 1.0;
8673105154fSTodd Munson           } else {
868080d2917SAlp Dener             kappa = actred / prered;
869080d2917SAlp Dener           }
870fed79b8eSAlp Dener           /* Accept or reject the step and update radius */
871080d2917SAlp Dener           if (kappa < bnk->eta1) {
872fed79b8eSAlp Dener             /* Reject the step */
873080d2917SAlp Dener             tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8743105154fSTodd Munson           } else {
875fed79b8eSAlp Dener             /* Accept the step */
876c133c014SAlp Dener             *accept = PETSC_TRUE;
877c133c014SAlp Dener             /* Update the trust region radius only if the computed step is at the trust radius boundary */
8788d5ead36SAlp Dener             if (bnk->dnorm == tao->trust) {
879080d2917SAlp Dener               if (kappa < bnk->eta2) {
880080d2917SAlp Dener                 /* Marginal bad step */
881c133c014SAlp Dener                 tao->trust = bnk->alpha2 * tao->trust;
8823105154fSTodd Munson               } else if (kappa < bnk->eta3) {
883fed79b8eSAlp Dener                 /* Reasonable step */
884fed79b8eSAlp Dener                 tao->trust = bnk->alpha3 * tao->trust;
8853105154fSTodd Munson               } else if (kappa < bnk->eta4) {
886080d2917SAlp Dener                 /* Good step */
887c133c014SAlp Dener                 tao->trust = bnk->alpha4 * tao->trust;
8883105154fSTodd Munson               } else {
889080d2917SAlp Dener                 /* Very good step */
890c133c014SAlp Dener                 tao->trust = bnk->alpha5 * tao->trust;
891080d2917SAlp Dener               }
892c133c014SAlp Dener             }
893080d2917SAlp Dener           }
894080d2917SAlp Dener         }
895080d2917SAlp Dener       }
896080d2917SAlp Dener     } else {
897080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
898080d2917SAlp Dener       tao->trust = bnk->alpha1 * PetscMin(bnk->dnorm, tao->trust);
899080d2917SAlp Dener     }
900080d2917SAlp Dener     break;
901080d2917SAlp Dener 
902080d2917SAlp Dener   default:
903080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
904b1c2d0e3SAlp Dener       if (prered < 0.0) {
905080d2917SAlp Dener         /*  The predicted reduction has the wrong sign.  This cannot */
906080d2917SAlp Dener         /*  happen in infinite precision arithmetic.  Step should */
907080d2917SAlp Dener         /*  be rejected! */
908080d2917SAlp Dener         tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
909080d2917SAlp Dener       } else {
910b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
911080d2917SAlp Dener           tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
912080d2917SAlp Dener         } else {
913080d2917SAlp Dener           if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
914080d2917SAlp Dener             kappa = 1.0;
915080d2917SAlp Dener           } else {
916080d2917SAlp Dener             kappa = actred / prered;
917080d2917SAlp Dener           }
918080d2917SAlp Dener 
9199566063dSJacob Faibussowitsch           PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
920080d2917SAlp Dener           tau_1   = bnk->theta * gdx / (bnk->theta * gdx - (1.0 - bnk->theta) * prered + actred);
921080d2917SAlp Dener           tau_2   = bnk->theta * gdx / (bnk->theta * gdx + (1.0 + bnk->theta) * prered - actred);
922080d2917SAlp Dener           tau_min = PetscMin(tau_1, tau_2);
923080d2917SAlp Dener           tau_max = PetscMax(tau_1, tau_2);
924080d2917SAlp Dener 
925080d2917SAlp Dener           if (kappa >= 1.0 - bnk->mu1) {
926080d2917SAlp Dener             /*  Great agreement */
927080d2917SAlp Dener             *accept = PETSC_TRUE;
928080d2917SAlp Dener             if (tau_max < 1.0) {
929080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
930080d2917SAlp Dener             } else if (tau_max > bnk->gamma4) {
931080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma4 * bnk->dnorm);
932080d2917SAlp Dener             } else {
933080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
934080d2917SAlp Dener             }
935080d2917SAlp Dener           } else if (kappa >= 1.0 - bnk->mu2) {
936080d2917SAlp Dener             /*  Good agreement */
937080d2917SAlp Dener             *accept = PETSC_TRUE;
938080d2917SAlp Dener             if (tau_max < bnk->gamma2) {
939080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
940080d2917SAlp Dener             } else if (tau_max > bnk->gamma3) {
941080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
942080d2917SAlp Dener             } else if (tau_max < 1.0) {
943080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
944080d2917SAlp Dener             } else {
945080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
946080d2917SAlp Dener             }
947080d2917SAlp Dener           } else {
948080d2917SAlp Dener             /*  Not good agreement */
949080d2917SAlp Dener             if (tau_min > 1.0) {
950080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
951080d2917SAlp Dener             } else if (tau_max < bnk->gamma1) {
952080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
953080d2917SAlp Dener             } else if ((tau_min < bnk->gamma1) && (tau_max >= 1.0)) {
954080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
955080d2917SAlp Dener             } else if ((tau_1 >= bnk->gamma1) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1) || (tau_2 >= 1.0))) {
956080d2917SAlp Dener               tao->trust = tau_1 * PetscMin(tao->trust, bnk->dnorm);
957080d2917SAlp Dener             } else if ((tau_2 >= bnk->gamma1) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1) || (tau_2 >= 1.0))) {
958080d2917SAlp Dener               tao->trust = tau_2 * PetscMin(tao->trust, bnk->dnorm);
959080d2917SAlp Dener             } else {
960080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
961080d2917SAlp Dener             }
962080d2917SAlp Dener           }
963080d2917SAlp Dener         }
964080d2917SAlp Dener       }
965080d2917SAlp Dener     } else {
966080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
967080d2917SAlp Dener       tao->trust = bnk->gamma1 * PetscMin(bnk->dnorm, tao->trust);
968080d2917SAlp Dener     }
96928017e9fSAlp Dener     break;
970080d2917SAlp Dener   }
971c133c014SAlp Dener   /* Make sure the radius does not violate min and max settings */
972c133c014SAlp Dener   tao->trust = PetscMin(tao->trust, bnk->max_radius);
973fed79b8eSAlp Dener   tao->trust = PetscMax(tao->trust, bnk->min_radius);
9743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
975080d2917SAlp Dener }
976080d2917SAlp Dener 
977eb910715SAlp Dener /* ---------------------------------------------------------- */
978df278d8fSAlp Dener 
979d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKAddStepCounts(Tao tao, PetscInt stepType)
980d71ae5a4SJacob Faibussowitsch {
98162675beeSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
98262675beeSAlp Dener 
98362675beeSAlp Dener   PetscFunctionBegin;
98462675beeSAlp Dener   switch (stepType) {
985d71ae5a4SJacob Faibussowitsch   case BNK_NEWTON:
986d71ae5a4SJacob Faibussowitsch     ++bnk->newt;
987d71ae5a4SJacob Faibussowitsch     break;
988d71ae5a4SJacob Faibussowitsch   case BNK_BFGS:
989d71ae5a4SJacob Faibussowitsch     ++bnk->bfgs;
990d71ae5a4SJacob Faibussowitsch     break;
991d71ae5a4SJacob Faibussowitsch   case BNK_SCALED_GRADIENT:
992d71ae5a4SJacob Faibussowitsch     ++bnk->sgrad;
993d71ae5a4SJacob Faibussowitsch     break;
994d71ae5a4SJacob Faibussowitsch   case BNK_GRADIENT:
995d71ae5a4SJacob Faibussowitsch     ++bnk->grad;
996d71ae5a4SJacob Faibussowitsch     break;
997d71ae5a4SJacob Faibussowitsch   default:
998d71ae5a4SJacob Faibussowitsch     break;
99962675beeSAlp Dener   }
10003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100162675beeSAlp Dener }
100262675beeSAlp Dener 
100362675beeSAlp Dener /* ---------------------------------------------------------- */
100462675beeSAlp Dener 
1005d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetUp_BNK(Tao tao)
1006d71ae5a4SJacob Faibussowitsch {
1007eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1008e031d6f5SAlp Dener   PetscInt i;
1009eb910715SAlp Dener 
1010eb910715SAlp Dener   PetscFunctionBegin;
101148a46eb9SPierre Jolivet   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
101248a46eb9SPierre Jolivet   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
101348a46eb9SPierre Jolivet   if (!bnk->W) PetscCall(VecDuplicate(tao->solution, &bnk->W));
101448a46eb9SPierre Jolivet   if (!bnk->Xold) PetscCall(VecDuplicate(tao->solution, &bnk->Xold));
101548a46eb9SPierre Jolivet   if (!bnk->Gold) PetscCall(VecDuplicate(tao->solution, &bnk->Gold));
101648a46eb9SPierre Jolivet   if (!bnk->Xwork) PetscCall(VecDuplicate(tao->solution, &bnk->Xwork));
101748a46eb9SPierre Jolivet   if (!bnk->Gwork) PetscCall(VecDuplicate(tao->solution, &bnk->Gwork));
101848a46eb9SPierre Jolivet   if (!bnk->unprojected_gradient) PetscCall(VecDuplicate(tao->solution, &bnk->unprojected_gradient));
101948a46eb9SPierre Jolivet   if (!bnk->unprojected_gradient_old) PetscCall(VecDuplicate(tao->solution, &bnk->unprojected_gradient_old));
102048a46eb9SPierre Jolivet   if (!bnk->Diag_min) PetscCall(VecDuplicate(tao->solution, &bnk->Diag_min));
102148a46eb9SPierre Jolivet   if (!bnk->Diag_max) PetscCall(VecDuplicate(tao->solution, &bnk->Diag_max));
1022e031d6f5SAlp Dener   if (bnk->max_cg_its > 0) {
1023c4b75bccSAlp Dener     /* Ensure that the important common vectors are shared between BNK and embedded BNCG */
1024c4b75bccSAlp Dener     bnk->bncg_ctx = (TAO_BNCG *)bnk->bncg->data;
10259566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient_old)));
10269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient_old));
102789da521bSAlp Dener     bnk->bncg_ctx->unprojected_gradient_old = bnk->unprojected_gradient_old;
10289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient)));
10299566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient));
1030c4b75bccSAlp Dener     bnk->bncg_ctx->unprojected_gradient = bnk->unprojected_gradient;
10319566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->Gold)));
10329566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->G_old));
1033c4b75bccSAlp Dener     bnk->bncg_ctx->G_old = bnk->Gold;
10349566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->gradient)));
10359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->gradient));
1036c4b75bccSAlp Dener     bnk->bncg->gradient = tao->gradient;
10379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->stepdirection)));
10389566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->stepdirection));
1039c4b75bccSAlp Dener     bnk->bncg->stepdirection = tao->stepdirection;
10409566063dSJacob Faibussowitsch     PetscCall(TaoSetSolution(bnk->bncg, tao->solution));
1041c4b75bccSAlp Dener     /* Copy over some settings from BNK into BNCG */
10429566063dSJacob Faibussowitsch     PetscCall(TaoSetMaximumIterations(bnk->bncg, bnk->max_cg_its));
10439566063dSJacob Faibussowitsch     PetscCall(TaoSetTolerances(bnk->bncg, tao->gatol, tao->grtol, tao->gttol));
10449566063dSJacob Faibussowitsch     PetscCall(TaoSetFunctionLowerBound(bnk->bncg, tao->fmin));
10459566063dSJacob Faibussowitsch     PetscCall(TaoSetConvergenceTest(bnk->bncg, tao->ops->convergencetest, tao->cnvP));
10469566063dSJacob Faibussowitsch     PetscCall(TaoSetObjective(bnk->bncg, tao->ops->computeobjective, tao->user_objP));
10479566063dSJacob Faibussowitsch     PetscCall(TaoSetGradient(bnk->bncg, NULL, tao->ops->computegradient, tao->user_gradP));
10489566063dSJacob Faibussowitsch     PetscCall(TaoSetObjectiveAndGradient(bnk->bncg, NULL, tao->ops->computeobjectiveandgradient, tao->user_objgradP));
10499566063dSJacob Faibussowitsch     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)tao, (PetscObject)(bnk->bncg)));
1050c4b75bccSAlp Dener     for (i = 0; i < tao->numbermonitors; ++i) {
10519566063dSJacob Faibussowitsch       PetscCall(TaoSetMonitor(bnk->bncg, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]));
10529566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)(tao->monitorcontext[i])));
1053e031d6f5SAlp Dener     }
1054e031d6f5SAlp Dener   }
105583c8fe1dSLisandro Dalcin   bnk->X_inactive    = NULL;
105683c8fe1dSLisandro Dalcin   bnk->G_inactive    = NULL;
105783c8fe1dSLisandro Dalcin   bnk->inactive_work = NULL;
105883c8fe1dSLisandro Dalcin   bnk->active_work   = NULL;
105983c8fe1dSLisandro Dalcin   bnk->inactive_idx  = NULL;
106083c8fe1dSLisandro Dalcin   bnk->active_idx    = NULL;
106183c8fe1dSLisandro Dalcin   bnk->active_lower  = NULL;
106283c8fe1dSLisandro Dalcin   bnk->active_upper  = NULL;
106383c8fe1dSLisandro Dalcin   bnk->active_fixed  = NULL;
106483c8fe1dSLisandro Dalcin   bnk->M             = NULL;
106583c8fe1dSLisandro Dalcin   bnk->H_inactive    = NULL;
106683c8fe1dSLisandro Dalcin   bnk->Hpre_inactive = NULL;
10673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1068eb910715SAlp Dener }
1069eb910715SAlp Dener 
1070eb910715SAlp Dener /*------------------------------------------------------------*/
1071df278d8fSAlp Dener 
1072d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoDestroy_BNK(Tao tao)
1073d71ae5a4SJacob Faibussowitsch {
1074eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1075eb910715SAlp Dener 
1076eb910715SAlp Dener   PetscFunctionBegin;
10779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->W));
10789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Xold));
10799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Gold));
10809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Xwork));
10819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Gwork));
10829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->unprojected_gradient));
10839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->unprojected_gradient_old));
10849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Diag_min));
10859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Diag_max));
10869566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_lower));
10879566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_upper));
10889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_fixed));
10899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_idx));
10909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->inactive_idx));
10919566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->Hpre_inactive));
10929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->H_inactive));
10939566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&bnk->bncg));
1094a958fbfcSStefano Zampini   PetscCall(KSPDestroy(&tao->ksp));
10959566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
10963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1097eb910715SAlp Dener }
1098eb910715SAlp Dener 
1099eb910715SAlp Dener /*------------------------------------------------------------*/
1100df278d8fSAlp Dener 
1101d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetFromOptions_BNK(Tao tao, PetscOptionItems *PetscOptionsObject)
1102d71ae5a4SJacob Faibussowitsch {
1103eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1104eb910715SAlp Dener 
1105eb910715SAlp Dener   PetscFunctionBegin;
1106d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Newton-Krylov method for bound constrained optimization");
11079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_init_type", "radius initialization type", "", BNK_INIT, BNK_INIT_TYPES, BNK_INIT[bnk->init_type], &bnk->init_type, NULL));
11089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_update_type", "radius update type", "", BNK_UPDATE, BNK_UPDATE_TYPES, BNK_UPDATE[bnk->update_type], &bnk->update_type, NULL));
11099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_as_type", "active set estimation method", "", BNK_AS, BNK_AS_TYPES, BNK_AS[bnk->as_type], &bnk->as_type, NULL));
11109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_sval", "(developer) Hessian perturbation starting value", "", bnk->sval, &bnk->sval, NULL));
11119566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imin", "(developer) minimum initial Hessian perturbation", "", bnk->imin, &bnk->imin, NULL));
11129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imax", "(developer) maximum initial Hessian perturbation", "", bnk->imax, &bnk->imax, NULL));
11139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imfac", "(developer) initial merit factor for Hessian perturbation", "", bnk->imfac, &bnk->imfac, NULL));
11149566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmin", "(developer) minimum Hessian perturbation", "", bnk->pmin, &bnk->pmin, NULL));
11159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmax", "(developer) maximum Hessian perturbation", "", bnk->pmax, &bnk->pmax, NULL));
11169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pgfac", "(developer) Hessian perturbation growth factor", "", bnk->pgfac, &bnk->pgfac, NULL));
11179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_psfac", "(developer) Hessian perturbation shrink factor", "", bnk->psfac, &bnk->psfac, NULL));
11189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmgfac", "(developer) merit growth factor for Hessian perturbation", "", bnk->pmgfac, &bnk->pmgfac, NULL));
11199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmsfac", "(developer) merit shrink factor for Hessian perturbation", "", bnk->pmsfac, &bnk->pmsfac, NULL));
11209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta1", "(developer) threshold for rejecting step (-tao_bnk_update_type reduction)", "", bnk->eta1, &bnk->eta1, NULL));
11219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta2", "(developer) threshold for accepting marginal step (-tao_bnk_update_type reduction)", "", bnk->eta2, &bnk->eta2, NULL));
11229566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta3", "(developer) threshold for accepting reasonable step (-tao_bnk_update_type reduction)", "", bnk->eta3, &bnk->eta3, NULL));
11239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta4", "(developer) threshold for accepting good step (-tao_bnk_update_type reduction)", "", bnk->eta4, &bnk->eta4, NULL));
11249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha1", "(developer) radius reduction factor for rejected step (-tao_bnk_update_type reduction)", "", bnk->alpha1, &bnk->alpha1, NULL));
11259566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha2", "(developer) radius reduction factor for marginally accepted bad step (-tao_bnk_update_type reduction)", "", bnk->alpha2, &bnk->alpha2, NULL));
11269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha3", "(developer) radius increase factor for reasonable accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha3, &bnk->alpha3, NULL));
11279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha4", "(developer) radius increase factor for good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha4, &bnk->alpha4, NULL));
11289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha5", "(developer) radius increase factor for very good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha5, &bnk->alpha5, NULL));
11299566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu1", "(developer) threshold for small line-search step length (-tao_bnk_update_type step)", "", bnk->nu1, &bnk->nu1, NULL));
11309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu2", "(developer) threshold for reasonable line-search step length (-tao_bnk_update_type step)", "", bnk->nu2, &bnk->nu2, NULL));
11319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu3", "(developer) threshold for large line-search step length (-tao_bnk_update_type step)", "", bnk->nu3, &bnk->nu3, NULL));
11329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu4", "(developer) threshold for very large line-search step length (-tao_bnk_update_type step)", "", bnk->nu4, &bnk->nu4, NULL));
11339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_omega1", "(developer) radius reduction factor for very small line-search step length (-tao_bnk_update_type step)", "", bnk->omega1, &bnk->omega1, NULL));
11349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_omega2", "(developer) radius reduction factor for small line-search step length (-tao_bnk_update_type step)", "", bnk->omega2, &bnk->omega2, NULL));
11359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_omega3", "(developer) radius factor for decent line-search step length (-tao_bnk_update_type step)", "", bnk->omega3, &bnk->omega3, NULL));
11369566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_omega4", "(developer) radius increase factor for large line-search step length (-tao_bnk_update_type step)", "", bnk->omega4, &bnk->omega4, NULL));
11379566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_omega5", "(developer) radius increase factor for very large line-search step length (-tao_bnk_update_type step)", "", bnk->omega5, &bnk->omega5, NULL));
11389566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu1_i", "(developer) threshold for accepting very good step (-tao_bnk_init_type interpolation)", "", bnk->mu1_i, &bnk->mu1_i, NULL));
11399566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu2_i", "(developer) threshold for accepting good step (-tao_bnk_init_type interpolation)", "", bnk->mu2_i, &bnk->mu2_i, NULL));
11409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma1_i", "(developer) radius reduction factor for rejected very bad step (-tao_bnk_init_type interpolation)", "", bnk->gamma1_i, &bnk->gamma1_i, NULL));
11419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma2_i", "(developer) radius reduction factor for rejected bad step (-tao_bnk_init_type interpolation)", "", bnk->gamma2_i, &bnk->gamma2_i, NULL));
11429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma3_i", "(developer) radius increase factor for accepted good step (-tao_bnk_init_type interpolation)", "", bnk->gamma3_i, &bnk->gamma3_i, NULL));
11439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma4_i", "(developer) radius increase factor for accepted very good step (-tao_bnk_init_type interpolation)", "", bnk->gamma4_i, &bnk->gamma4_i, NULL));
11449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta_i", "(developer) trust region interpolation factor (-tao_bnk_init_type interpolation)", "", bnk->theta_i, &bnk->theta_i, NULL));
11459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu1", "(developer) threshold for accepting very good step (-tao_bnk_update_type interpolation)", "", bnk->mu1, &bnk->mu1, NULL));
11469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu2", "(developer) threshold for accepting good step (-tao_bnk_update_type interpolation)", "", bnk->mu2, &bnk->mu2, NULL));
11479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma1", "(developer) radius reduction factor for rejected very bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma1, &bnk->gamma1, NULL));
11489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma2", "(developer) radius reduction factor for rejected bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma2, &bnk->gamma2, NULL));
11499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma3", "(developer) radius increase factor for accepted good step (-tao_bnk_update_type interpolation)", "", bnk->gamma3, &bnk->gamma3, NULL));
11509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma4", "(developer) radius increase factor for accepted very good step (-tao_bnk_update_type interpolation)", "", bnk->gamma4, &bnk->gamma4, NULL));
11519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta", "(developer) trust region interpolation factor (-tao_bnk_update_type interpolation)", "", bnk->theta, &bnk->theta, NULL));
11529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_min_radius", "(developer) lower bound on initial radius", "", bnk->min_radius, &bnk->min_radius, NULL));
11539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_max_radius", "(developer) upper bound on radius", "", bnk->max_radius, &bnk->max_radius, NULL));
11549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_epsilon", "(developer) tolerance used when computing actual and predicted reduction", "", bnk->epsilon, &bnk->epsilon, NULL));
11559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", bnk->as_tol, &bnk->as_tol, NULL));
11569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_step", "(developer) step length used when estimating actively bounded variables", "", bnk->as_step, &bnk->as_step, NULL));
11579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-tao_bnk_max_cg_its", "number of BNCG iterations to take for each Newton step", "", bnk->max_cg_its, &bnk->max_cg_its, NULL));
1158d0609cedSBarry Smith   PetscOptionsHeadEnd();
11598ebe3e4eSStefano Zampini 
11609566063dSJacob Faibussowitsch   PetscCall(TaoSetOptionsPrefix(bnk->bncg, ((PetscObject)(tao))->prefix));
11619566063dSJacob Faibussowitsch   PetscCall(TaoAppendOptionsPrefix(bnk->bncg, "tao_bnk_cg_"));
11629566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(bnk->bncg));
11638ebe3e4eSStefano Zampini 
11649566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(tao->ksp, ((PetscObject)(tao))->prefix));
11659566063dSJacob Faibussowitsch   PetscCall(KSPAppendOptionsPrefix(tao->ksp, "tao_bnk_"));
11669566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(tao->ksp));
11673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1168eb910715SAlp Dener }
1169eb910715SAlp Dener 
1170eb910715SAlp Dener /*------------------------------------------------------------*/
1171df278d8fSAlp Dener 
1172d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoView_BNK(Tao tao, PetscViewer viewer)
1173d71ae5a4SJacob Faibussowitsch {
1174eb910715SAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
1175eb910715SAlp Dener   PetscInt  nrejects;
1176eb910715SAlp Dener   PetscBool isascii;
1177eb910715SAlp Dener 
1178eb910715SAlp Dener   PetscFunctionBegin;
11799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1180eb910715SAlp Dener   if (isascii) {
11819566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1182b17ffb64SBarry Smith     PetscCall(TaoView(bnk->bncg, viewer));
1183b9ac7092SAlp Dener     if (bnk->M) {
11849566063dSJacob Faibussowitsch       PetscCall(MatLMVMGetRejectCount(bnk->M, &nrejects));
118563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Rejected BFGS updates: %" PetscInt_FMT "\n", nrejects));
1186eb910715SAlp Dener     }
118763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "CG steps: %" PetscInt_FMT "\n", bnk->tot_cg_its));
118863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Newton steps: %" PetscInt_FMT "\n", bnk->newt));
118948a46eb9SPierre Jolivet     if (bnk->M) PetscCall(PetscViewerASCIIPrintf(viewer, "BFGS steps: %" PetscInt_FMT "\n", bnk->bfgs));
119063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", bnk->sgrad));
119163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Gradient steps: %" PetscInt_FMT "\n", bnk->grad));
11929566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP termination reasons:\n"));
119363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  atol: %" PetscInt_FMT "\n", bnk->ksp_atol));
119463a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  rtol: %" PetscInt_FMT "\n", bnk->ksp_rtol));
119563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  ctol: %" PetscInt_FMT "\n", bnk->ksp_ctol));
119663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  negc: %" PetscInt_FMT "\n", bnk->ksp_negc));
119763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dtol: %" PetscInt_FMT "\n", bnk->ksp_dtol));
119863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  iter: %" PetscInt_FMT "\n", bnk->ksp_iter));
119963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  othr: %" PetscInt_FMT "\n", bnk->ksp_othr));
12009566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
1201eb910715SAlp Dener   }
12023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1203eb910715SAlp Dener }
1204eb910715SAlp Dener 
1205eb910715SAlp Dener /* ---------------------------------------------------------- */
1206df278d8fSAlp Dener 
1207eb910715SAlp Dener /*MC
1208eb910715SAlp Dener   TAOBNK - Shared base-type for Bounded Newton-Krylov type algorithms.
120966ed3702SAlp Dener   At each iteration, the BNK methods solve the symmetric
1210eb910715SAlp Dener   system of equations to obtain the step diretion dk:
1211eb910715SAlp Dener               Hk dk = -gk
12122b97c8d8SAlp Dener   for free variables only. The step can be globalized either through
12132b97c8d8SAlp Dener   trust-region methods, or a line search, or a heuristic mixture of both.
1214eb910715SAlp Dener 
1215eb910715SAlp Dener     Options Database Keys:
12169fa2b5dcSStefano Zampini + -tao_bnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
12179fa2b5dcSStefano Zampini . -tao_bnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
12189fa2b5dcSStefano Zampini . -tao_bnk_update_type - trust radius update method ("step", "direction", "interpolation")
12199fa2b5dcSStefano Zampini . -tao_bnk_as_type - active-set estimation method ("none", "bertsekas")
12209fa2b5dcSStefano Zampini . -tao_bnk_as_tol - (developer) initial tolerance used in estimating bounded active variables (-as_type bertsekas)
12219fa2b5dcSStefano Zampini . -tao_bnk_as_step - (developer) trial step length used in estimating bounded active variables (-as_type bertsekas)
12229fa2b5dcSStefano Zampini . -tao_bnk_sval - (developer) Hessian perturbation starting value
12239fa2b5dcSStefano Zampini . -tao_bnk_imin - (developer) minimum initial Hessian perturbation
12249fa2b5dcSStefano Zampini . -tao_bnk_imax - (developer) maximum initial Hessian perturbation
12259fa2b5dcSStefano Zampini . -tao_bnk_pmin - (developer) minimum Hessian perturbation
12269fa2b5dcSStefano Zampini . -tao_bnk_pmax - (developer) aximum Hessian perturbation
12279fa2b5dcSStefano Zampini . -tao_bnk_pgfac - (developer) Hessian perturbation growth factor
12289fa2b5dcSStefano Zampini . -tao_bnk_psfac - (developer) Hessian perturbation shrink factor
12299fa2b5dcSStefano Zampini . -tao_bnk_imfac - (developer) initial merit factor for Hessian perturbation
12309fa2b5dcSStefano Zampini . -tao_bnk_pmgfac - (developer) merit growth factor for Hessian perturbation
12319fa2b5dcSStefano Zampini . -tao_bnk_pmsfac - (developer) merit shrink factor for Hessian perturbation
12329fa2b5dcSStefano Zampini . -tao_bnk_eta1 - (developer) threshold for rejecting step (-update_type reduction)
12339fa2b5dcSStefano Zampini . -tao_bnk_eta2 - (developer) threshold for accepting marginal step (-update_type reduction)
12349fa2b5dcSStefano Zampini . -tao_bnk_eta3 - (developer) threshold for accepting reasonable step (-update_type reduction)
12359fa2b5dcSStefano Zampini . -tao_bnk_eta4 - (developer) threshold for accepting good step (-update_type reduction)
12369fa2b5dcSStefano Zampini . -tao_bnk_alpha1 - (developer) radius reduction factor for rejected step (-update_type reduction)
12379fa2b5dcSStefano Zampini . -tao_bnk_alpha2 - (developer) radius reduction factor for marginally accepted bad step (-update_type reduction)
12389fa2b5dcSStefano Zampini . -tao_bnk_alpha3 - (developer) radius increase factor for reasonable accepted step (-update_type reduction)
12399fa2b5dcSStefano Zampini . -tao_bnk_alpha4 - (developer) radius increase factor for good accepted step (-update_type reduction)
12409fa2b5dcSStefano Zampini . -tao_bnk_alpha5 - (developer) radius increase factor for very good accepted step (-update_type reduction)
12419fa2b5dcSStefano Zampini . -tao_bnk_epsilon - (developer) tolerance for small pred/actual ratios that trigger automatic step acceptance (-update_type reduction)
12429fa2b5dcSStefano Zampini . -tao_bnk_mu1 - (developer) threshold for accepting very good step (-update_type interpolation)
12439fa2b5dcSStefano Zampini . -tao_bnk_mu2 - (developer) threshold for accepting good step (-update_type interpolation)
12449fa2b5dcSStefano Zampini . -tao_bnk_gamma1 - (developer) radius reduction factor for rejected very bad step (-update_type interpolation)
12459fa2b5dcSStefano Zampini . -tao_bnk_gamma2 - (developer) radius reduction factor for rejected bad step (-update_type interpolation)
12469fa2b5dcSStefano Zampini . -tao_bnk_gamma3 - (developer) radius increase factor for accepted good step (-update_type interpolation)
12479fa2b5dcSStefano Zampini . -tao_bnk_gamma4 - (developer) radius increase factor for accepted very good step (-update_type interpolation)
12489fa2b5dcSStefano Zampini . -tao_bnk_theta - (developer) trust region interpolation factor (-update_type interpolation)
12499fa2b5dcSStefano Zampini . -tao_bnk_nu1 - (developer) threshold for small line-search step length (-update_type step)
12509fa2b5dcSStefano Zampini . -tao_bnk_nu2 - (developer) threshold for reasonable line-search step length (-update_type step)
12519fa2b5dcSStefano Zampini . -tao_bnk_nu3 - (developer) threshold for large line-search step length (-update_type step)
12529fa2b5dcSStefano Zampini . -tao_bnk_nu4 - (developer) threshold for very large line-search step length (-update_type step)
12539fa2b5dcSStefano Zampini . -tao_bnk_omega1 - (developer) radius reduction factor for very small line-search step length (-update_type step)
12549fa2b5dcSStefano Zampini . -tao_bnk_omega2 - (developer) radius reduction factor for small line-search step length (-update_type step)
12559fa2b5dcSStefano Zampini . -tao_bnk_omega3 - (developer) radius factor for decent line-search step length (-update_type step)
12569fa2b5dcSStefano Zampini . -tao_bnk_omega4 - (developer) radius increase factor for large line-search step length (-update_type step)
12579fa2b5dcSStefano Zampini . -tao_bnk_omega5 - (developer) radius increase factor for very large line-search step length (-update_type step)
12589fa2b5dcSStefano Zampini . -tao_bnk_mu1_i -  (developer) threshold for accepting very good step (-init_type interpolation)
12599fa2b5dcSStefano Zampini . -tao_bnk_mu2_i -  (developer) threshold for accepting good step (-init_type interpolation)
12609fa2b5dcSStefano Zampini . -tao_bnk_gamma1_i - (developer) radius reduction factor for rejected very bad step (-init_type interpolation)
12619fa2b5dcSStefano Zampini . -tao_bnk_gamma2_i - (developer) radius reduction factor for rejected bad step (-init_type interpolation)
12629fa2b5dcSStefano Zampini . -tao_bnk_gamma3_i - (developer) radius increase factor for accepted good step (-init_type interpolation)
12639fa2b5dcSStefano Zampini . -tao_bnk_gamma4_i - (developer) radius increase factor for accepted very good step (-init_type interpolation)
12649fa2b5dcSStefano Zampini - -tao_bnk_theta_i - (developer) trust region interpolation factor (-init_type interpolation)
1265eb910715SAlp Dener 
1266eb910715SAlp Dener   Level: beginner
1267eb910715SAlp Dener M*/
1268eb910715SAlp Dener 
1269d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoCreate_BNK(Tao tao)
1270d71ae5a4SJacob Faibussowitsch {
1271eb910715SAlp Dener   TAO_BNK *bnk;
1272b9ac7092SAlp Dener   PC       pc;
1273eb910715SAlp Dener 
1274eb910715SAlp Dener   PetscFunctionBegin;
12754dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&bnk));
1276eb910715SAlp Dener 
1277eb910715SAlp Dener   tao->ops->setup          = TaoSetUp_BNK;
1278eb910715SAlp Dener   tao->ops->view           = TaoView_BNK;
1279eb910715SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNK;
1280eb910715SAlp Dener   tao->ops->destroy        = TaoDestroy_BNK;
1281eb910715SAlp Dener 
1282eb910715SAlp Dener   /*  Override default settings (unless already changed) */
1283eb910715SAlp Dener   if (!tao->max_it_changed) tao->max_it = 50;
1284eb910715SAlp Dener   if (!tao->trust0_changed) tao->trust0 = 100.0;
1285eb910715SAlp Dener 
1286eb910715SAlp Dener   tao->data = (void *)bnk;
1287eb910715SAlp Dener 
128866ed3702SAlp Dener   /*  Hessian shifting parameters */
1289e0ed867bSAlp Dener   bnk->computehessian = TaoBNKComputeHessian;
1290e0ed867bSAlp Dener   bnk->computestep    = TaoBNKComputeStep;
1291e0ed867bSAlp Dener 
1292eb910715SAlp Dener   bnk->sval  = 0.0;
1293eb910715SAlp Dener   bnk->imin  = 1.0e-4;
1294eb910715SAlp Dener   bnk->imax  = 1.0e+2;
1295eb910715SAlp Dener   bnk->imfac = 1.0e-1;
1296eb910715SAlp Dener 
1297eb910715SAlp Dener   bnk->pmin   = 1.0e-12;
1298eb910715SAlp Dener   bnk->pmax   = 1.0e+2;
1299eb910715SAlp Dener   bnk->pgfac  = 1.0e+1;
1300eb910715SAlp Dener   bnk->psfac  = 4.0e-1;
1301eb910715SAlp Dener   bnk->pmgfac = 1.0e-1;
1302eb910715SAlp Dener   bnk->pmsfac = 1.0e-1;
1303eb910715SAlp Dener 
1304eb910715SAlp Dener   /*  Default values for trust-region radius update based on steplength */
1305eb910715SAlp Dener   bnk->nu1 = 0.25;
1306eb910715SAlp Dener   bnk->nu2 = 0.50;
1307eb910715SAlp Dener   bnk->nu3 = 1.00;
1308eb910715SAlp Dener   bnk->nu4 = 1.25;
1309eb910715SAlp Dener 
1310eb910715SAlp Dener   bnk->omega1 = 0.25;
1311eb910715SAlp Dener   bnk->omega2 = 0.50;
1312eb910715SAlp Dener   bnk->omega3 = 1.00;
1313eb910715SAlp Dener   bnk->omega4 = 2.00;
1314eb910715SAlp Dener   bnk->omega5 = 4.00;
1315eb910715SAlp Dener 
1316eb910715SAlp Dener   /*  Default values for trust-region radius update based on reduction */
1317eb910715SAlp Dener   bnk->eta1 = 1.0e-4;
1318eb910715SAlp Dener   bnk->eta2 = 0.25;
1319eb910715SAlp Dener   bnk->eta3 = 0.50;
1320eb910715SAlp Dener   bnk->eta4 = 0.90;
1321eb910715SAlp Dener 
1322eb910715SAlp Dener   bnk->alpha1 = 0.25;
1323eb910715SAlp Dener   bnk->alpha2 = 0.50;
1324eb910715SAlp Dener   bnk->alpha3 = 1.00;
1325eb910715SAlp Dener   bnk->alpha4 = 2.00;
1326eb910715SAlp Dener   bnk->alpha5 = 4.00;
1327eb910715SAlp Dener 
1328eb910715SAlp Dener   /*  Default values for trust-region radius update based on interpolation */
1329eb910715SAlp Dener   bnk->mu1 = 0.10;
1330eb910715SAlp Dener   bnk->mu2 = 0.50;
1331eb910715SAlp Dener 
1332eb910715SAlp Dener   bnk->gamma1 = 0.25;
1333eb910715SAlp Dener   bnk->gamma2 = 0.50;
1334eb910715SAlp Dener   bnk->gamma3 = 2.00;
1335eb910715SAlp Dener   bnk->gamma4 = 4.00;
1336eb910715SAlp Dener 
1337eb910715SAlp Dener   bnk->theta = 0.05;
1338eb910715SAlp Dener 
1339eb910715SAlp Dener   /*  Default values for trust region initialization based on interpolation */
1340eb910715SAlp Dener   bnk->mu1_i = 0.35;
1341eb910715SAlp Dener   bnk->mu2_i = 0.50;
1342eb910715SAlp Dener 
1343eb910715SAlp Dener   bnk->gamma1_i = 0.0625;
1344eb910715SAlp Dener   bnk->gamma2_i = 0.5;
1345eb910715SAlp Dener   bnk->gamma3_i = 2.0;
1346eb910715SAlp Dener   bnk->gamma4_i = 5.0;
1347eb910715SAlp Dener 
1348eb910715SAlp Dener   bnk->theta_i = 0.25;
1349eb910715SAlp Dener 
1350eb910715SAlp Dener   /*  Remaining parameters */
1351c0f10754SAlp Dener   bnk->max_cg_its = 0;
1352eb910715SAlp Dener   bnk->min_radius = 1.0e-10;
1353eb910715SAlp Dener   bnk->max_radius = 1.0e10;
1354770b7498SAlp Dener   bnk->epsilon    = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0 / 3.0);
13550a4511e9SAlp Dener   bnk->as_tol     = 1.0e-3;
13560a4511e9SAlp Dener   bnk->as_step    = 1.0e-3;
135762675beeSAlp Dener   bnk->dmin       = 1.0e-6;
135862675beeSAlp Dener   bnk->dmax       = 1.0e6;
1359eb910715SAlp Dener 
136083c8fe1dSLisandro Dalcin   bnk->M           = NULL;
136183c8fe1dSLisandro Dalcin   bnk->bfgs_pre    = NULL;
1362eb910715SAlp Dener   bnk->init_type   = BNK_INIT_INTERPOLATION;
13637b1c7716SAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION;
13642f75a4aaSAlp Dener   bnk->as_type     = BNK_AS_BERTSEKAS;
1365eb910715SAlp Dener 
1366e031d6f5SAlp Dener   /* Create the embedded BNCG solver */
13679566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PetscObjectComm((PetscObject)tao), &bnk->bncg));
13689566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)bnk->bncg, (PetscObject)tao, 1));
13699566063dSJacob Faibussowitsch   PetscCall(TaoSetType(bnk->bncg, TAOBNCG));
1370e031d6f5SAlp Dener 
1371c0f10754SAlp Dener   /* Create the line search */
13729566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch));
13739566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
1374f4db9bf7SStefano Zampini   PetscCall(TaoLineSearchSetType(tao->linesearch, TAOLINESEARCHMT));
13759566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao));
1376eb910715SAlp Dener 
1377eb910715SAlp Dener   /*  Set linear solver to default for symmetric matrices */
13789566063dSJacob Faibussowitsch   PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
13799566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
13809566063dSJacob Faibussowitsch   PetscCall(KSPSetType(tao->ksp, KSPSTCG));
13819566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
13829566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLMVM));
13833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1384eb910715SAlp Dener }
1385