xref: /petsc/src/tao/bound/impls/bnk/bnk.c (revision b17ffb64abc38c285596c9668bc843ccd2c63938)
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 
9e031d6f5SAlp Dener /*------------------------------------------------------------*/
10e031d6f5SAlp Dener 
11df278d8fSAlp Dener /* Routine for initializing the KSP solver, the BFGS preconditioner, and the initial trust radius estimation */
12df278d8fSAlp Dener 
13d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKInitialize(Tao tao, PetscInt initType, PetscBool *needH)
14d71ae5a4SJacob Faibussowitsch {
15eb910715SAlp Dener   TAO_BNK          *bnk = (TAO_BNK *)tao->data;
16eb910715SAlp Dener   PC                pc;
1789da521bSAlp Dener   PetscReal         f_min, ftrial, prered, actred, kappa, sigma, resnorm;
18eb910715SAlp Dener   PetscReal         tau, tau_1, tau_2, tau_max, tau_min, max_radius;
190ad3a497SAlp Dener   PetscBool         is_bfgs, is_jacobi, is_symmetric, sym_set;
20c4b75bccSAlp Dener   PetscInt          n, N, nDiff;
21eb910715SAlp Dener   PetscInt          i_max = 5;
22eb910715SAlp Dener   PetscInt          j_max = 1;
23eb910715SAlp Dener   PetscInt          i, j;
242e6e4ca1SStefano Zampini   PetscVoidFunction kspTR;
25eb910715SAlp Dener 
26eb910715SAlp Dener   PetscFunctionBegin;
2728017e9fSAlp Dener   /* Project the current point onto the feasible set */
289566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
299566063dSJacob Faibussowitsch   PetscCall(TaoSetVariableBounds(bnk->bncg, tao->XL, tao->XU));
301baa6e33SBarry Smith   if (tao->bounded) PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch, tao->XL, tao->XU));
3128017e9fSAlp Dener 
3228017e9fSAlp Dener   /* Project the initial point onto the feasible region */
339566063dSJacob Faibussowitsch   PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
3428017e9fSAlp Dener 
3528017e9fSAlp Dener   /* Check convergence criteria */
369566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient));
379566063dSJacob Faibussowitsch   PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
389566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
399566063dSJacob Faibussowitsch   PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
409566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
4128017e9fSAlp Dener 
42c0f10754SAlp Dener   /* Test the initial point for convergence */
439566063dSJacob Faibussowitsch   PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
449566063dSJacob Faibussowitsch   PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
453c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(bnk->f) && !PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
469566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its));
479566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, 1.0));
48dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
49c0f10754SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
50c0f10754SAlp Dener 
51e031d6f5SAlp Dener   /* Reset KSP stopping reason counters */
52eb910715SAlp Dener   bnk->ksp_atol = 0;
53eb910715SAlp Dener   bnk->ksp_rtol = 0;
54eb910715SAlp Dener   bnk->ksp_dtol = 0;
55eb910715SAlp Dener   bnk->ksp_ctol = 0;
56eb910715SAlp Dener   bnk->ksp_negc = 0;
57eb910715SAlp Dener   bnk->ksp_iter = 0;
58eb910715SAlp Dener   bnk->ksp_othr = 0;
59eb910715SAlp Dener 
60e031d6f5SAlp Dener   /* Reset accepted step type counters */
61e031d6f5SAlp Dener   bnk->tot_cg_its = 0;
62e031d6f5SAlp Dener   bnk->newt       = 0;
63e031d6f5SAlp Dener   bnk->bfgs       = 0;
64e031d6f5SAlp Dener   bnk->sgrad      = 0;
65e031d6f5SAlp Dener   bnk->grad       = 0;
66e031d6f5SAlp Dener 
67fed79b8eSAlp Dener   /* Initialize the Hessian perturbation */
68fed79b8eSAlp Dener   bnk->pert = bnk->sval;
69fed79b8eSAlp Dener 
70937a31a1SAlp Dener   /* Reset initial steplength to zero (this helps BNCG reset its direction internally) */
719566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
72937a31a1SAlp Dener 
73e031d6f5SAlp Dener   /* Allocate the vectors needed for the BFGS approximation */
749566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &is_bfgs));
769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCJACOBI, &is_jacobi));
77b9ac7092SAlp Dener   if (is_bfgs) {
78b9ac7092SAlp Dener     bnk->bfgs_pre = pc;
799566063dSJacob Faibussowitsch     PetscCall(PCLMVMGetMatLMVM(bnk->bfgs_pre, &bnk->M));
809566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tao->solution, &n));
819566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tao->solution, &N));
829566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(bnk->M, n, n, N, N));
839566063dSJacob Faibussowitsch     PetscCall(MatLMVMAllocate(bnk->M, tao->solution, bnk->unprojected_gradient));
849566063dSJacob Faibussowitsch     PetscCall(MatIsSymmetricKnown(bnk->M, &sym_set, &is_symmetric));
853c859ba3SBarry Smith     PetscCheck(sym_set && is_symmetric, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix in the LMVM preconditioner must be symmetric.");
861baa6e33SBarry Smith   } else if (is_jacobi) PetscCall(PCJacobiSetUseAbs(pc, PETSC_TRUE));
87e031d6f5SAlp Dener 
88e031d6f5SAlp Dener   /* Prepare the min/max vectors for safeguarding diagonal scales */
899566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_min, bnk->dmin));
909566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_max, bnk->dmax));
91eb910715SAlp Dener 
92eb910715SAlp Dener   /* Initialize trust-region radius.  The initialization is only performed
93eb910715SAlp Dener      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
94c0f10754SAlp Dener   *needH = PETSC_TRUE;
959566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp, "KSPCGSetRadius_C", &kspTR));
962e6e4ca1SStefano Zampini   if (kspTR) {
9762675beeSAlp Dener     switch (initType) {
98eb910715SAlp Dener     case BNK_INIT_CONSTANT:
99eb910715SAlp Dener       /* Use the initial radius specified */
100c0f10754SAlp Dener       tao->trust = tao->trust0;
101eb910715SAlp Dener       break;
102eb910715SAlp Dener 
103eb910715SAlp Dener     case BNK_INIT_INTERPOLATION:
104c0f10754SAlp Dener       /* Use interpolation based on the initial Hessian */
105eb910715SAlp Dener       max_radius = 0.0;
10608752603SAlp Dener       tao->trust = tao->trust0;
107eb910715SAlp Dener       for (j = 0; j < j_max; ++j) {
1080a4511e9SAlp Dener         f_min = bnk->f;
109eb910715SAlp Dener         sigma = 0.0;
110eb910715SAlp Dener 
111c0f10754SAlp Dener         if (*needH) {
11262602cfbSAlp Dener           /* Compute the Hessian at the new step, and extract the inactive subsystem */
1139566063dSJacob Faibussowitsch           PetscCall((*bnk->computehessian)(tao));
1149566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, BNK_AS_NONE));
1159566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&bnk->H_inactive));
11689da521bSAlp Dener           if (bnk->active_idx) {
1179566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive));
11828017e9fSAlp Dener           } else {
1199566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)tao->hessian));
120c5e9d94cSAlp Dener             bnk->H_inactive = tao->hessian;
12128017e9fSAlp Dener           }
122c0f10754SAlp Dener           *needH = PETSC_FALSE;
123eb910715SAlp Dener         }
124eb910715SAlp Dener 
125eb910715SAlp Dener         for (i = 0; i < i_max; ++i) {
12662602cfbSAlp Dener           /* Take a steepest descent step and snap it to bounds */
1279566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
1289566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution, -tao->trust / bnk->gnorm, tao->gradient));
1299566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
13089da521bSAlp Dener           /* Compute the step we actually accepted */
1319566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->W));
1329566063dSJacob Faibussowitsch           PetscCall(VecAXPY(bnk->W, -1.0, bnk->Xold));
13362602cfbSAlp Dener           /* Compute the objective at the trial */
1349566063dSJacob Faibussowitsch           PetscCall(TaoComputeObjective(tao, tao->solution, &ftrial));
1353c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(bnk->f), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
1369566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->Xold, tao->solution));
137eb910715SAlp Dener           if (PetscIsInfOrNanReal(ftrial)) {
138eb910715SAlp Dener             tau = bnk->gamma1_i;
139eb910715SAlp Dener           } else {
1400a4511e9SAlp Dener             if (ftrial < f_min) {
1410a4511e9SAlp Dener               f_min = ftrial;
142eb910715SAlp Dener               sigma = -tao->trust / bnk->gnorm;
143eb910715SAlp Dener             }
14408752603SAlp Dener 
145770b7498SAlp Dener             /* Compute the predicted and actual reduction */
14689da521bSAlp Dener             if (bnk->active_idx) {
1479566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
1489566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1492ab2a32cSAlp Dener             } else {
15008752603SAlp Dener               bnk->X_inactive    = bnk->W;
15108752603SAlp Dener               bnk->inactive_work = bnk->Xwork;
1522ab2a32cSAlp Dener             }
1539566063dSJacob Faibussowitsch             PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
1549566063dSJacob Faibussowitsch             PetscCall(VecDot(bnk->X_inactive, bnk->inactive_work, &prered));
15589da521bSAlp Dener             if (bnk->active_idx) {
1569566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
1579566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1582ab2a32cSAlp Dener             }
159eb910715SAlp Dener             prered = tao->trust * (bnk->gnorm - 0.5 * tao->trust * prered / (bnk->gnorm * bnk->gnorm));
160eb910715SAlp Dener             actred = bnk->f - ftrial;
1613105154fSTodd Munson             if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
162eb910715SAlp Dener               kappa = 1.0;
1633105154fSTodd Munson             } else {
164eb910715SAlp Dener               kappa = actred / prered;
165eb910715SAlp Dener             }
166eb910715SAlp Dener 
167eb910715SAlp Dener             tau_1   = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust + (1.0 - bnk->theta_i) * prered - actred);
168eb910715SAlp Dener             tau_2   = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust - (1.0 + bnk->theta_i) * prered + actred);
169eb910715SAlp Dener             tau_min = PetscMin(tau_1, tau_2);
170eb910715SAlp Dener             tau_max = PetscMax(tau_1, tau_2);
171eb910715SAlp Dener 
17218cfbf8eSSatish Balay             if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu1_i) {
173eb910715SAlp Dener               /*  Great agreement */
174eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
175eb910715SAlp Dener 
176eb910715SAlp Dener               if (tau_max < 1.0) {
177eb910715SAlp Dener                 tau = bnk->gamma3_i;
1783105154fSTodd Munson               } else if (tau_max > bnk->gamma4_i) {
179eb910715SAlp Dener                 tau = bnk->gamma4_i;
1803105154fSTodd Munson               } else {
181eb910715SAlp Dener                 tau = tau_max;
182eb910715SAlp Dener               }
18318cfbf8eSSatish Balay             } else if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu2_i) {
184eb910715SAlp Dener               /*  Good agreement */
185eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
186eb910715SAlp Dener 
187eb910715SAlp Dener               if (tau_max < bnk->gamma2_i) {
188eb910715SAlp Dener                 tau = bnk->gamma2_i;
189eb910715SAlp Dener               } else if (tau_max > bnk->gamma3_i) {
190eb910715SAlp Dener                 tau = bnk->gamma3_i;
191eb910715SAlp Dener               } else {
192eb910715SAlp Dener                 tau = tau_max;
193eb910715SAlp Dener               }
1948f8a4e06SAlp Dener             } else {
195eb910715SAlp Dener               /*  Not good agreement */
196eb910715SAlp Dener               if (tau_min > 1.0) {
197eb910715SAlp Dener                 tau = bnk->gamma2_i;
198eb910715SAlp Dener               } else if (tau_max < bnk->gamma1_i) {
199eb910715SAlp Dener                 tau = bnk->gamma1_i;
200eb910715SAlp Dener               } else if ((tau_min < bnk->gamma1_i) && (tau_max >= 1.0)) {
201eb910715SAlp Dener                 tau = bnk->gamma1_i;
2023105154fSTodd Munson               } else if ((tau_1 >= bnk->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
203eb910715SAlp Dener                 tau = tau_1;
2043105154fSTodd Munson               } else if ((tau_2 >= bnk->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
205eb910715SAlp Dener                 tau = tau_2;
206eb910715SAlp Dener               } else {
207eb910715SAlp Dener                 tau = tau_max;
208eb910715SAlp Dener               }
209eb910715SAlp Dener             }
210eb910715SAlp Dener           }
211eb910715SAlp Dener           tao->trust = tau * tao->trust;
212eb910715SAlp Dener         }
213eb910715SAlp Dener 
2140a4511e9SAlp Dener         if (f_min < bnk->f) {
215937a31a1SAlp Dener           /* We accidentally found a solution better than the initial, so accept it */
2160a4511e9SAlp Dener           bnk->f = f_min;
2179566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
2189566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution, sigma, tao->gradient));
2199566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL, tao->XU, 0.0, &nDiff, tao->solution));
2209566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, tao->stepdirection));
2219566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->stepdirection, -1.0, bnk->Xold));
2229566063dSJacob Faibussowitsch           PetscCall(TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient));
2239566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
2249566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
2259566063dSJacob Faibussowitsch           PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
226937a31a1SAlp Dener           /* Compute gradient at the new iterate and flip switch to compute the Hessian later */
2279566063dSJacob Faibussowitsch           PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
228c0f10754SAlp Dener           *needH = PETSC_TRUE;
229937a31a1SAlp Dener           /* Test the new step for convergence */
2309566063dSJacob Faibussowitsch           PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
2319566063dSJacob Faibussowitsch           PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
2323c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(resnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
2339566063dSJacob Faibussowitsch           PetscCall(TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its));
2349566063dSJacob Faibussowitsch           PetscCall(TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, 1.0));
235dbbe0bcdSBarry Smith           PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
236eb910715SAlp Dener           if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
237937a31a1SAlp Dener           /* active BNCG recycling early because we have a stepdirection computed */
2389566063dSJacob Faibussowitsch           PetscCall(TaoSetRecycleHistory(bnk->bncg, PETSC_TRUE));
239eb910715SAlp Dener         }
240eb910715SAlp Dener       }
241eb910715SAlp Dener       tao->trust = PetscMax(tao->trust, max_radius);
242e031d6f5SAlp Dener 
243e031d6f5SAlp Dener       /* Ensure that the trust radius is within the limits */
244e031d6f5SAlp Dener       tao->trust = PetscMax(tao->trust, bnk->min_radius);
245e031d6f5SAlp Dener       tao->trust = PetscMin(tao->trust, bnk->max_radius);
246eb910715SAlp Dener       break;
247eb910715SAlp Dener 
248eb910715SAlp Dener     default:
249eb910715SAlp Dener       /* Norm of the first direction will initialize radius */
250eb910715SAlp Dener       tao->trust = 0.0;
251eb910715SAlp Dener       break;
252eb910715SAlp Dener     }
253eb910715SAlp Dener   }
254eb910715SAlp Dener   PetscFunctionReturn(0);
255eb910715SAlp Dener }
256eb910715SAlp Dener 
257df278d8fSAlp Dener /*------------------------------------------------------------*/
258df278d8fSAlp Dener 
259e0ed867bSAlp Dener /* Routine for computing the exact Hessian and preparing the preconditioner at the new iterate */
26062675beeSAlp Dener 
261d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKComputeHessian(Tao tao)
262d71ae5a4SJacob Faibussowitsch {
26362675beeSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
26462675beeSAlp Dener 
26562675beeSAlp Dener   PetscFunctionBegin;
26662675beeSAlp Dener   /* Compute the Hessian */
2679566063dSJacob Faibussowitsch   PetscCall(TaoComputeHessian(tao, tao->solution, tao->hessian, tao->hessian_pre));
26862675beeSAlp Dener   /* Add a correction to the BFGS preconditioner */
2691baa6e33SBarry Smith   if (bnk->M) PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
270e0ed867bSAlp Dener   /* Prepare the reduced sub-matrices for the inactive set */
2719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->Hpre_inactive));
2729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->H_inactive));
273f5766c09SAlp Dener   if (bnk->active_idx) {
2749566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive));
275e0ed867bSAlp Dener     if (tao->hessian == tao->hessian_pre) {
2769566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive));
277e0ed867bSAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
278e0ed867bSAlp Dener     } else {
2799566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(tao->hessian_pre, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->Hpre_inactive));
280e0ed867bSAlp Dener     }
2811baa6e33SBarry Smith     if (bnk->bfgs_pre) PetscCall(PCLMVMSetIS(bnk->bfgs_pre, bnk->inactive_idx));
282e0ed867bSAlp Dener   } else {
2839566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)tao->hessian));
284c5e9d94cSAlp Dener     bnk->H_inactive = tao->hessian;
285e0ed867bSAlp Dener     if (tao->hessian == tao->hessian_pre) {
2869566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive));
287e0ed867bSAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
288e0ed867bSAlp Dener     } else {
2899566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)tao->hessian_pre));
290c5e9d94cSAlp Dener       bnk->Hpre_inactive = tao->hessian_pre;
291e0ed867bSAlp Dener     }
2921baa6e33SBarry Smith     if (bnk->bfgs_pre) PetscCall(PCLMVMClearIS(bnk->bfgs_pre));
293e0ed867bSAlp Dener   }
29462675beeSAlp Dener   PetscFunctionReturn(0);
29562675beeSAlp Dener }
29662675beeSAlp Dener 
29762675beeSAlp Dener /*------------------------------------------------------------*/
29862675beeSAlp Dener 
2992f75a4aaSAlp Dener /* Routine for estimating the active set */
3002f75a4aaSAlp Dener 
301d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKEstimateActiveSet(Tao tao, PetscInt asType)
302d71ae5a4SJacob Faibussowitsch {
3032f75a4aaSAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
304f4db9bf7SStefano Zampini   PetscBool hessComputed, diagExists, hadactive;
3052f75a4aaSAlp Dener 
3062f75a4aaSAlp Dener   PetscFunctionBegin;
307f4db9bf7SStefano Zampini   hadactive = bnk->active_idx ? PETSC_TRUE : PETSC_FALSE;
30808752603SAlp Dener   switch (asType) {
3092f75a4aaSAlp Dener   case BNK_AS_NONE:
3109566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->inactive_idx));
3119566063dSJacob Faibussowitsch     PetscCall(VecWhichInactive(tao->XL, tao->solution, bnk->unprojected_gradient, tao->XU, PETSC_TRUE, &bnk->inactive_idx));
3129566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->active_idx));
3139566063dSJacob Faibussowitsch     PetscCall(ISComplementVec(bnk->inactive_idx, tao->solution, &bnk->active_idx));
3142f75a4aaSAlp Dener     break;
3152f75a4aaSAlp Dener 
3162f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
3172f75a4aaSAlp Dener     /* Compute the trial step vector with which we will estimate the active set at the next iteration */
318b9ac7092SAlp Dener     if (bnk->M) {
3192f75a4aaSAlp Dener       /* If the BFGS preconditioner matrix is available, we will construct a trial step with it */
3209566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, bnk->W));
3212f75a4aaSAlp Dener     } else {
322fc5ca067SStefano Zampini       hessComputed = diagExists = PETSC_FALSE;
32348a46eb9SPierre Jolivet       if (tao->hessian) PetscCall(MatAssembled(tao->hessian, &hessComputed));
32448a46eb9SPierre Jolivet       if (hessComputed) PetscCall(MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &diagExists));
325fc5ca067SStefano Zampini       if (diagExists) {
3269b6ef848SAlp Dener         /* BFGS preconditioner doesn't exist so let's invert the absolute diagonal of the Hessian instead onto the gradient */
3279566063dSJacob Faibussowitsch         PetscCall(MatGetDiagonal(tao->hessian, bnk->Xwork));
3289566063dSJacob Faibussowitsch         PetscCall(VecAbs(bnk->Xwork));
3299566063dSJacob Faibussowitsch         PetscCall(VecMedian(bnk->Diag_min, bnk->Xwork, bnk->Diag_max, bnk->Xwork));
3309566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(bnk->Xwork));
3319566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(bnk->W, bnk->Xwork, bnk->unprojected_gradient));
33261be54a6SAlp Dener       } else {
333c4b75bccSAlp Dener         /* If the Hessian or its diagonal does not exist, we will simply use gradient step */
3349566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, bnk->W));
33561be54a6SAlp Dener       }
3362f75a4aaSAlp Dener     }
3379566063dSJacob Faibussowitsch     PetscCall(VecScale(bnk->W, -1.0));
3389371c9d4SSatish 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));
339c4b75bccSAlp Dener     break;
3402f75a4aaSAlp Dener 
341d71ae5a4SJacob Faibussowitsch   default:
342d71ae5a4SJacob Faibussowitsch     break;
3432f75a4aaSAlp Dener   }
344f4db9bf7SStefano Zampini   bnk->resetksp = (PetscBool)(bnk->active_idx || hadactive); /* inactive Hessian size may have changed, need to reset operators */
3452f75a4aaSAlp Dener   PetscFunctionReturn(0);
3462f75a4aaSAlp Dener }
3472f75a4aaSAlp Dener 
3482f75a4aaSAlp Dener /*------------------------------------------------------------*/
3492f75a4aaSAlp Dener 
3502f75a4aaSAlp Dener /* Routine for bounding the step direction */
3512f75a4aaSAlp Dener 
352d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKBoundStep(Tao tao, PetscInt asType, Vec step)
353d71ae5a4SJacob Faibussowitsch {
3542f75a4aaSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
3552f75a4aaSAlp Dener 
3562f75a4aaSAlp Dener   PetscFunctionBegin;
357a1318120SAlp Dener   switch (asType) {
358d71ae5a4SJacob Faibussowitsch   case BNK_AS_NONE:
359d71ae5a4SJacob Faibussowitsch     PetscCall(VecISSet(step, bnk->active_idx, 0.0));
360d71ae5a4SJacob Faibussowitsch     break;
3612f75a4aaSAlp Dener 
362d71ae5a4SJacob Faibussowitsch   case BNK_AS_BERTSEKAS:
363d71ae5a4SJacob Faibussowitsch     PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, bnk->active_lower, bnk->active_upper, bnk->active_fixed, 1.0, step));
364d71ae5a4SJacob Faibussowitsch     break;
3652f75a4aaSAlp Dener 
366d71ae5a4SJacob Faibussowitsch   default:
367d71ae5a4SJacob Faibussowitsch     break;
3682f75a4aaSAlp Dener   }
3692f75a4aaSAlp Dener   PetscFunctionReturn(0);
3702f75a4aaSAlp Dener }
3712f75a4aaSAlp Dener 
372e031d6f5SAlp Dener /*------------------------------------------------------------*/
373e031d6f5SAlp Dener 
374e031d6f5SAlp Dener /* Routine for taking a finite number of BNCG iterations to
375e031d6f5SAlp Dener    accelerate Newton convergence.
376e031d6f5SAlp Dener 
377e031d6f5SAlp Dener    In practice, this approach simply trades off Hessian evaluations
378e031d6f5SAlp Dener    for more gradient evaluations.
379e031d6f5SAlp Dener */
380e031d6f5SAlp Dener 
381d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKTakeCGSteps(Tao tao, PetscBool *terminate)
382d71ae5a4SJacob Faibussowitsch {
383c0f10754SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
384c0f10754SAlp Dener 
385c0f10754SAlp Dener   PetscFunctionBegin;
386c0f10754SAlp Dener   *terminate = PETSC_FALSE;
387c0f10754SAlp Dener   if (bnk->max_cg_its > 0) {
388c4b75bccSAlp Dener     /* Copy the current function value (important vectors are already shared) */
389c0f10754SAlp Dener     bnk->bncg_ctx->f = bnk->f;
390c0f10754SAlp Dener     /* Take some small finite number of BNCG iterations */
3919566063dSJacob Faibussowitsch     PetscCall(TaoSolve(bnk->bncg));
392c0f10754SAlp Dener     /* Add the number of gradient and function evaluations to the total */
393c0f10754SAlp Dener     tao->nfuncs += bnk->bncg->nfuncs;
394c0f10754SAlp Dener     tao->nfuncgrads += bnk->bncg->nfuncgrads;
395c0f10754SAlp Dener     tao->ngrads += bnk->bncg->ngrads;
396c0f10754SAlp Dener     tao->nhess += bnk->bncg->nhess;
397e031d6f5SAlp Dener     bnk->tot_cg_its += bnk->bncg->niter;
398c4b75bccSAlp Dener     /* Extract the BNCG function value out and save it into BNK */
399c0f10754SAlp Dener     bnk->f = bnk->bncg_ctx->f;
400c0f10754SAlp 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) {
401c0f10754SAlp Dener       *terminate = PETSC_TRUE;
40261be54a6SAlp Dener     } else {
4039566063dSJacob Faibussowitsch       PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
404c0f10754SAlp Dener     }
405c0f10754SAlp Dener   }
406c0f10754SAlp Dener   PetscFunctionReturn(0);
407c0f10754SAlp Dener }
408c0f10754SAlp Dener 
4092f75a4aaSAlp Dener /*------------------------------------------------------------*/
4102f75a4aaSAlp Dener 
411c0f10754SAlp Dener /* Routine for computing the Newton step. */
412df278d8fSAlp Dener 
413d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKComputeStep(Tao tao, PetscBool shift, KSPConvergedReason *ksp_reason, PetscInt *step_type)
414d71ae5a4SJacob Faibussowitsch {
415eb910715SAlp Dener   TAO_BNK          *bnk         = (TAO_BNK *)tao->data;
416eb910715SAlp Dener   PetscInt          bfgsUpdates = 0;
417eb910715SAlp Dener   PetscInt          kspits;
418bddd1ffdSAlp Dener   PetscBool         is_lmvm;
4192e6e4ca1SStefano Zampini   PetscVoidFunction kspTR;
420eb910715SAlp Dener 
421eb910715SAlp Dener   PetscFunctionBegin;
42289da521bSAlp Dener   /* If there are no inactive variables left, save some computation and return an adjusted zero step
42389da521bSAlp Dener      that has (l-x) and (u-x) for lower and upper bounded variables. */
42489da521bSAlp Dener   if (!bnk->inactive_idx) {
4259566063dSJacob Faibussowitsch     PetscCall(VecSet(tao->stepdirection, 0.0));
4269566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
42789da521bSAlp Dener     PetscFunctionReturn(0);
42889da521bSAlp Dener   }
42989da521bSAlp Dener 
43062675beeSAlp Dener   /* Shift the reduced Hessian matrix */
431e831869dSStefano Zampini   if (shift && bnk->pert > 0) {
4329566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)tao->hessian, MATLMVM, &is_lmvm));
433f7bf01afSAlp Dener     if (is_lmvm) {
4349566063dSJacob Faibussowitsch       PetscCall(MatShift(tao->hessian, bnk->pert));
435f7bf01afSAlp Dener     } else {
4369566063dSJacob Faibussowitsch       PetscCall(MatShift(bnk->H_inactive, bnk->pert));
43748a46eb9SPierre Jolivet       if (bnk->H_inactive != bnk->Hpre_inactive) PetscCall(MatShift(bnk->Hpre_inactive, bnk->pert));
43862675beeSAlp Dener     }
439f7bf01afSAlp Dener   }
44062675beeSAlp Dener 
441eb910715SAlp Dener   /* Solve the Newton system of equations */
442937a31a1SAlp Dener   tao->ksp_its = 0;
4439566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
444f4db9bf7SStefano Zampini   if (bnk->resetksp) {
4459566063dSJacob Faibussowitsch     PetscCall(KSPReset(tao->ksp));
4469566063dSJacob Faibussowitsch     PetscCall(KSPResetFromOptions(tao->ksp));
447f4db9bf7SStefano Zampini     bnk->resetksp = PETSC_FALSE;
448f4db9bf7SStefano Zampini   }
4499566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(tao->ksp, bnk->H_inactive, bnk->Hpre_inactive));
4509566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, bnk->Gwork));
45189da521bSAlp Dener   if (bnk->active_idx) {
4529566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
4539566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
4545e9b73cbSAlp Dener   } else {
4555e9b73cbSAlp Dener     bnk->G_inactive = bnk->unprojected_gradient;
4565e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
45728017e9fSAlp Dener   }
4589566063dSJacob Faibussowitsch   PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
4599566063dSJacob Faibussowitsch   PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
4609566063dSJacob Faibussowitsch   PetscCall(KSPGetIterationNumber(tao->ksp, &kspits));
461eb910715SAlp Dener   tao->ksp_its += kspits;
462eb910715SAlp Dener   tao->ksp_tot_its += kspits;
463f4db9bf7SStefano Zampini   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp, "KSPCGGetNormD_C", &kspTR));
464f4db9bf7SStefano Zampini   if (kspTR) {
4659566063dSJacob Faibussowitsch     PetscCall(KSPCGGetNormD(tao->ksp, &bnk->dnorm));
466eb910715SAlp Dener 
467eb910715SAlp Dener     if (0.0 == tao->trust) {
468eb910715SAlp Dener       /* Radius was uninitialized; use the norm of the direction */
469080d2917SAlp Dener       if (bnk->dnorm > 0.0) {
470080d2917SAlp Dener         tao->trust = bnk->dnorm;
471eb910715SAlp Dener 
472eb910715SAlp Dener         /* Modify the radius if it is too large or small */
473eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
474eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
475eb910715SAlp Dener       } else {
476eb910715SAlp Dener         /* The direction was bad; set radius to default value and re-solve
477eb910715SAlp Dener            the trust-region subproblem to get a direction */
478eb910715SAlp Dener         tao->trust = tao->trust0;
479eb910715SAlp Dener 
480eb910715SAlp Dener         /* Modify the radius if it is too large or small */
481eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
482eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
483eb910715SAlp Dener 
4849566063dSJacob Faibussowitsch         PetscCall(KSPCGSetRadius(tao->ksp, tao->trust));
4859566063dSJacob Faibussowitsch         PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
4869566063dSJacob Faibussowitsch         PetscCall(KSPGetIterationNumber(tao->ksp, &kspits));
487eb910715SAlp Dener         tao->ksp_its += kspits;
488eb910715SAlp Dener         tao->ksp_tot_its += kspits;
4899566063dSJacob Faibussowitsch         PetscCall(KSPCGGetNormD(tao->ksp, &bnk->dnorm));
490eb910715SAlp Dener 
4913c859ba3SBarry Smith         PetscCheck(bnk->dnorm != 0.0, PetscObjectComm((PetscObject)tao), PETSC_ERR_PLIB, "Initial direction zero");
492eb910715SAlp Dener       }
493eb910715SAlp Dener     }
494eb910715SAlp Dener   }
4955e9b73cbSAlp Dener   /* Restore sub vectors back */
49689da521bSAlp Dener   if (bnk->active_idx) {
4979566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
4989566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
4995e9b73cbSAlp Dener   }
500770b7498SAlp Dener   /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
5019566063dSJacob Faibussowitsch   PetscCall(VecScale(tao->stepdirection, -1.0));
5029566063dSJacob Faibussowitsch   PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
503770b7498SAlp Dener 
504770b7498SAlp Dener   /* Record convergence reasons */
5059566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(tao->ksp, ksp_reason));
506e465cd6fSAlp Dener   if (KSP_CONVERGED_ATOL == *ksp_reason) {
507770b7498SAlp Dener     ++bnk->ksp_atol;
508e465cd6fSAlp Dener   } else if (KSP_CONVERGED_RTOL == *ksp_reason) {
509770b7498SAlp Dener     ++bnk->ksp_rtol;
510e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_CONSTRAINED == *ksp_reason) {
511770b7498SAlp Dener     ++bnk->ksp_ctol;
512e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_NEG_CURVE == *ksp_reason) {
513770b7498SAlp Dener     ++bnk->ksp_negc;
514e465cd6fSAlp Dener   } else if (KSP_DIVERGED_DTOL == *ksp_reason) {
515770b7498SAlp Dener     ++bnk->ksp_dtol;
516e465cd6fSAlp Dener   } else if (KSP_DIVERGED_ITS == *ksp_reason) {
517770b7498SAlp Dener     ++bnk->ksp_iter;
518770b7498SAlp Dener   } else {
519770b7498SAlp Dener     ++bnk->ksp_othr;
520770b7498SAlp Dener   }
521fed79b8eSAlp Dener 
522fed79b8eSAlp Dener   /* Make sure the BFGS preconditioner is healthy */
523b9ac7092SAlp Dener   if (bnk->M) {
5249566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
525b2d8c577SAlp Dener     if ((KSP_DIVERGED_INDEFINITE_PC == *ksp_reason) && (bfgsUpdates > 0)) {
526fed79b8eSAlp Dener       /* Preconditioner is numerically indefinite; reset the approximation. */
5279566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
5289566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
529eb910715SAlp Dener     }
530fed79b8eSAlp Dener   }
5316b591159SAlp Dener   *step_type = BNK_NEWTON;
532e465cd6fSAlp Dener   PetscFunctionReturn(0);
533e465cd6fSAlp Dener }
534eb910715SAlp Dener 
53562675beeSAlp Dener /*------------------------------------------------------------*/
53662675beeSAlp Dener 
5375e9b73cbSAlp Dener /* Routine for recomputing the predicted reduction for a given step vector */
5385e9b73cbSAlp Dener 
539d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKRecomputePred(Tao tao, Vec S, PetscReal *prered)
540d71ae5a4SJacob Faibussowitsch {
5415e9b73cbSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
5425e9b73cbSAlp Dener 
5435e9b73cbSAlp Dener   PetscFunctionBegin;
5445e9b73cbSAlp Dener   /* Extract subvectors associated with the inactive set */
54589da521bSAlp Dener   if (bnk->active_idx) {
5469566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
5479566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
5489566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5495e9b73cbSAlp Dener   } else {
5505e9b73cbSAlp Dener     bnk->X_inactive    = tao->stepdirection;
5515e9b73cbSAlp Dener     bnk->inactive_work = bnk->Xwork;
5525e9b73cbSAlp Dener     bnk->G_inactive    = bnk->Gwork;
5535e9b73cbSAlp Dener   }
5545e9b73cbSAlp Dener   /* Recompute the predicted decrease based on the quadratic model */
5559566063dSJacob Faibussowitsch   PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
5569566063dSJacob Faibussowitsch   PetscCall(VecAYPX(bnk->inactive_work, -0.5, bnk->G_inactive));
5579566063dSJacob Faibussowitsch   PetscCall(VecDot(bnk->inactive_work, bnk->X_inactive, prered));
5585e9b73cbSAlp Dener   /* Restore the sub vectors */
55989da521bSAlp Dener   if (bnk->active_idx) {
5609566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
5619566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
5629566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5635e9b73cbSAlp Dener   }
5645e9b73cbSAlp Dener   PetscFunctionReturn(0);
5655e9b73cbSAlp Dener }
5665e9b73cbSAlp Dener 
5675e9b73cbSAlp Dener /*------------------------------------------------------------*/
5685e9b73cbSAlp Dener 
56962675beeSAlp Dener /* Routine for ensuring that the Newton step is a descent direction.
57062675beeSAlp Dener 
57162675beeSAlp Dener    The step direction falls back onto BFGS, scaled gradient and gradient steps
57262675beeSAlp Dener    in the event that the Newton step fails the test.
57362675beeSAlp Dener */
57462675beeSAlp Dener 
575d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKSafeguardStep(Tao tao, KSPConvergedReason ksp_reason, PetscInt *stepType)
576d71ae5a4SJacob Faibussowitsch {
577e465cd6fSAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
578b2d8c577SAlp Dener   PetscReal gdx, e_min;
579e465cd6fSAlp Dener   PetscInt  bfgsUpdates;
580e465cd6fSAlp Dener 
581e465cd6fSAlp Dener   PetscFunctionBegin;
5826b591159SAlp Dener   switch (*stepType) {
5836b591159SAlp Dener   case BNK_NEWTON:
5849566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
585eb910715SAlp Dener     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
586eb910715SAlp Dener       /* Newton step is not descent or direction produced Inf or NaN
587eb910715SAlp Dener         Update the perturbation for next time */
588eb910715SAlp Dener       if (bnk->pert <= 0.0) {
5892e6e4ca1SStefano Zampini         PetscBool is_gltr;
5902e6e4ca1SStefano Zampini 
591eb910715SAlp Dener         /* Initialize the perturbation */
592eb910715SAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
5939566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
5942e6e4ca1SStefano Zampini         if (is_gltr) {
5959566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
596eb910715SAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
597eb910715SAlp Dener         }
598eb910715SAlp Dener       } else {
599eb910715SAlp Dener         /* Increase the perturbation */
600eb910715SAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
601eb910715SAlp Dener       }
602eb910715SAlp Dener 
6030ad3a497SAlp Dener       if (!bnk->M) {
604eb910715SAlp Dener         /* We don't have the bfgs matrix around and updated
605eb910715SAlp Dener           Must use gradient direction in this case */
6069566063dSJacob Faibussowitsch         PetscCall(VecCopy(tao->gradient, tao->stepdirection));
607eb910715SAlp Dener         *stepType = BNK_GRADIENT;
608eb910715SAlp Dener       } else {
609eb910715SAlp Dener         /* Attempt to use the BFGS direction */
6109566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
611eb910715SAlp Dener 
6128d5ead36SAlp Dener         /* Check for success (descent direction)
6138d5ead36SAlp Dener           NOTE: Negative gdx here means not a descent direction because
6148d5ead36SAlp Dener           the fall-back step is missing a negative sign. */
6159566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
6163105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
617eb910715SAlp Dener           /* BFGS direction is not descent or direction produced not a number
618eb910715SAlp Dener             We can assert bfgsUpdates > 1 in this case because
619eb910715SAlp Dener             the first solve produces the scaled gradient direction,
620eb910715SAlp Dener             which is guaranteed to be descent */
621eb910715SAlp Dener 
622eb910715SAlp Dener           /* Use steepest descent direction (scaled) */
6239566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
6249566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
6259566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
626eb910715SAlp Dener 
627eb910715SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
628eb910715SAlp Dener         } else {
6299566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
630eb910715SAlp Dener           if (1 == bfgsUpdates) {
631eb910715SAlp Dener             /* The first BFGS direction is always the scaled gradient */
632eb910715SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
633eb910715SAlp Dener           } else {
634eb910715SAlp Dener             *stepType = BNK_BFGS;
635eb910715SAlp Dener           }
636eb910715SAlp Dener         }
637eb910715SAlp Dener       }
6388d5ead36SAlp Dener       /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
6399566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection, -1.0));
6409566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
641eb910715SAlp Dener     } else {
642eb910715SAlp Dener       /* Computed Newton step is descent */
643eb910715SAlp Dener       switch (ksp_reason) {
644eb910715SAlp Dener       case KSP_DIVERGED_NANORINF:
645eb910715SAlp Dener       case KSP_DIVERGED_BREAKDOWN:
646eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_MAT:
647eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_PC:
648eb910715SAlp Dener       case KSP_CONVERGED_CG_NEG_CURVE:
649eb910715SAlp Dener         /* Matrix or preconditioner is indefinite; increase perturbation */
650eb910715SAlp Dener         if (bnk->pert <= 0.0) {
6512e6e4ca1SStefano Zampini           PetscBool is_gltr;
6522e6e4ca1SStefano Zampini 
653eb910715SAlp Dener           /* Initialize the perturbation */
654eb910715SAlp Dener           bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
6559566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
6562e6e4ca1SStefano Zampini           if (is_gltr) {
6579566063dSJacob Faibussowitsch             PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
658eb910715SAlp Dener             bnk->pert = PetscMax(bnk->pert, -e_min);
659eb910715SAlp Dener           }
660eb910715SAlp Dener         } else {
661eb910715SAlp Dener           /* Increase the perturbation */
662eb910715SAlp Dener           bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
663eb910715SAlp Dener         }
664eb910715SAlp Dener         break;
665eb910715SAlp Dener 
666eb910715SAlp Dener       default:
667eb910715SAlp Dener         /* Newton step computation is good; decrease perturbation */
668eb910715SAlp Dener         bnk->pert = PetscMin(bnk->psfac * bnk->pert, bnk->pmsfac * bnk->gnorm);
669ad540459SPierre Jolivet         if (bnk->pert < bnk->pmin) bnk->pert = 0.0;
670eb910715SAlp Dener         break;
671eb910715SAlp Dener       }
672fed79b8eSAlp Dener       *stepType = BNK_NEWTON;
673eb910715SAlp Dener     }
6746b591159SAlp Dener     break;
6756b591159SAlp Dener 
6766b591159SAlp Dener   case BNK_BFGS:
6776b591159SAlp Dener     /* Check for success (descent direction) */
6789566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
6796b591159SAlp Dener     if (gdx >= 0 || PetscIsInfOrNanReal(gdx)) {
6806b591159SAlp Dener       /* Step is not descent or solve was not successful
6816b591159SAlp Dener          Use steepest descent direction (scaled) */
6829566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
6839566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
6849566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, tao->gradient, tao->stepdirection));
6859566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection, -1.0));
6869566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
6876b591159SAlp Dener       *stepType = BNK_SCALED_GRADIENT;
6886b591159SAlp Dener     } else {
6896b591159SAlp Dener       *stepType = BNK_BFGS;
6906b591159SAlp Dener     }
6916b591159SAlp Dener     break;
6926b591159SAlp Dener 
693d71ae5a4SJacob Faibussowitsch   case BNK_SCALED_GRADIENT:
694d71ae5a4SJacob Faibussowitsch     break;
6956b591159SAlp Dener 
696d71ae5a4SJacob Faibussowitsch   default:
697d71ae5a4SJacob Faibussowitsch     break;
6986b591159SAlp Dener   }
6996b591159SAlp Dener 
700eb910715SAlp Dener   PetscFunctionReturn(0);
701eb910715SAlp Dener }
702eb910715SAlp Dener 
703df278d8fSAlp Dener /*------------------------------------------------------------*/
704df278d8fSAlp Dener 
705df278d8fSAlp Dener /* Routine for performing a bound-projected More-Thuente line search.
706df278d8fSAlp Dener 
707df278d8fSAlp Dener   Includes fallbacks to BFGS, scaled gradient, and unscaled gradient steps if the
708df278d8fSAlp Dener   Newton step does not produce a valid step length.
709df278d8fSAlp Dener */
710df278d8fSAlp Dener 
711d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKPerformLineSearch(Tao tao, PetscInt *stepType, PetscReal *steplen, TaoLineSearchConvergedReason *reason)
712d71ae5a4SJacob Faibussowitsch {
713c14b763aSAlp Dener   TAO_BNK                     *bnk = (TAO_BNK *)tao->data;
714c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
715b2d8c577SAlp Dener   PetscReal                    e_min, gdx;
716c14b763aSAlp Dener   PetscInt                     bfgsUpdates;
717c14b763aSAlp Dener 
718c14b763aSAlp Dener   PetscFunctionBegin;
719c14b763aSAlp Dener   /* Perform the linesearch */
7209566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
7219566063dSJacob Faibussowitsch   PetscCall(TaoAddLineSearchCounts(tao));
722c14b763aSAlp Dener 
723b2d8c577SAlp Dener   while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && *stepType != BNK_SCALED_GRADIENT && *stepType != BNK_GRADIENT) {
724c14b763aSAlp Dener     /* Linesearch failed, revert solution */
725c14b763aSAlp Dener     bnk->f = bnk->fold;
7269566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->Xold, tao->solution));
7279566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient));
728c14b763aSAlp Dener 
729937a31a1SAlp Dener     switch (*stepType) {
730c14b763aSAlp Dener     case BNK_NEWTON:
7318d5ead36SAlp Dener       /* Failed to obtain acceptable iterate with Newton step
732c14b763aSAlp Dener          Update the perturbation for next time */
733c14b763aSAlp Dener       if (bnk->pert <= 0.0) {
7342e6e4ca1SStefano Zampini         PetscBool is_gltr;
7352e6e4ca1SStefano Zampini 
736c14b763aSAlp Dener         /* Initialize the perturbation */
737c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
7389566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp), KSPGLTR, &is_gltr));
7392e6e4ca1SStefano Zampini         if (is_gltr) {
7409566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
741c14b763aSAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
742c14b763aSAlp Dener         }
743c14b763aSAlp Dener       } else {
744c14b763aSAlp Dener         /* Increase the perturbation */
745c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
746c14b763aSAlp Dener       }
747c14b763aSAlp Dener 
7480ad3a497SAlp Dener       if (!bnk->M) {
749c14b763aSAlp Dener         /* We don't have the bfgs matrix around and being updated
750c14b763aSAlp Dener            Must use gradient direction in this case */
7519566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, tao->stepdirection));
752937a31a1SAlp Dener         *stepType = BNK_GRADIENT;
753c14b763aSAlp Dener       } else {
754c14b763aSAlp Dener         /* Attempt to use the BFGS direction */
7559566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
7568d5ead36SAlp Dener         /* Check for success (descent direction)
7578d5ead36SAlp Dener            NOTE: Negative gdx means not a descent direction because the step here is missing a negative sign. */
7589566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
7593105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
760c14b763aSAlp Dener           /* BFGS direction is not descent or direction produced not a number
761c14b763aSAlp Dener              We can assert bfgsUpdates > 1 in this case
762c14b763aSAlp Dener              Use steepest descent direction (scaled) */
7639566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
7649566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
7659566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
766c14b763aSAlp Dener 
767c14b763aSAlp Dener           bfgsUpdates = 1;
768937a31a1SAlp Dener           *stepType   = BNK_SCALED_GRADIENT;
769c14b763aSAlp Dener         } else {
7709566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
771c14b763aSAlp Dener           if (1 == bfgsUpdates) {
772c14b763aSAlp Dener             /* The first BFGS direction is always the scaled gradient */
773937a31a1SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
774c14b763aSAlp Dener           } else {
775937a31a1SAlp Dener             *stepType = BNK_BFGS;
776c14b763aSAlp Dener           }
777c14b763aSAlp Dener         }
778c14b763aSAlp Dener       }
779c14b763aSAlp Dener       break;
780c14b763aSAlp Dener 
781c14b763aSAlp Dener     case BNK_BFGS:
782c14b763aSAlp Dener       /* Can only enter if pc_type == BNK_PC_BFGS
783c14b763aSAlp Dener          Failed to obtain acceptable iterate with BFGS step
784c14b763aSAlp Dener          Attempt to use the scaled gradient direction */
7859566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
7869566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
7879566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
788c14b763aSAlp Dener 
789c14b763aSAlp Dener       bfgsUpdates = 1;
790937a31a1SAlp Dener       *stepType   = BNK_SCALED_GRADIENT;
791c14b763aSAlp Dener       break;
792c14b763aSAlp Dener     }
7938d5ead36SAlp Dener     /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
7949566063dSJacob Faibussowitsch     PetscCall(VecScale(tao->stepdirection, -1.0));
7959566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
796c14b763aSAlp Dener 
7978d5ead36SAlp Dener     /* Perform one last line search with the fall-back step */
7989566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
7999566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
800c14b763aSAlp Dener   }
801c14b763aSAlp Dener   *reason = ls_reason;
802c14b763aSAlp Dener   PetscFunctionReturn(0);
803c14b763aSAlp Dener }
804c14b763aSAlp Dener 
805df278d8fSAlp Dener /*------------------------------------------------------------*/
806df278d8fSAlp Dener 
807df278d8fSAlp Dener /* Routine for updating the trust radius.
808df278d8fSAlp Dener 
809df278d8fSAlp Dener   Function features three different update methods:
810df278d8fSAlp Dener   1) Line-search step length based
811df278d8fSAlp Dener   2) Predicted decrease on the CG quadratic model
812df278d8fSAlp Dener   3) Interpolation
813df278d8fSAlp Dener */
814df278d8fSAlp Dener 
815d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKUpdateTrustRadius(Tao tao, PetscReal prered, PetscReal actred, PetscInt updateType, PetscInt stepType, PetscBool *accept)
816d71ae5a4SJacob Faibussowitsch {
817080d2917SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
818080d2917SAlp Dener 
819b1c2d0e3SAlp Dener   PetscReal step, kappa;
820080d2917SAlp Dener   PetscReal gdx, tau_1, tau_2, tau_min, tau_max;
821080d2917SAlp Dener 
822080d2917SAlp Dener   PetscFunctionBegin;
823080d2917SAlp Dener   /* Update trust region radius */
824080d2917SAlp Dener   *accept = PETSC_FALSE;
82528017e9fSAlp Dener   switch (updateType) {
826080d2917SAlp Dener   case BNK_UPDATE_STEP:
827c14b763aSAlp Dener     *accept = PETSC_TRUE; /* always accept here because line search succeeded */
828080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
8299566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchGetStepLength(tao->linesearch, &step));
830080d2917SAlp Dener       if (step < bnk->nu1) {
831080d2917SAlp Dener         /* Very bad step taken; reduce radius */
832080d2917SAlp Dener         tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
833080d2917SAlp Dener       } else if (step < bnk->nu2) {
834080d2917SAlp Dener         /* Reasonably bad step taken; reduce radius */
835080d2917SAlp Dener         tao->trust = bnk->omega2 * PetscMin(bnk->dnorm, tao->trust);
836080d2917SAlp Dener       } else if (step < bnk->nu3) {
837080d2917SAlp Dener         /*  Reasonable step was taken; leave radius alone */
838080d2917SAlp Dener         if (bnk->omega3 < 1.0) {
839080d2917SAlp Dener           tao->trust = bnk->omega3 * PetscMin(bnk->dnorm, tao->trust);
840080d2917SAlp Dener         } else if (bnk->omega3 > 1.0) {
841080d2917SAlp Dener           tao->trust = PetscMax(bnk->omega3 * bnk->dnorm, tao->trust);
842080d2917SAlp Dener         }
843080d2917SAlp Dener       } else if (step < bnk->nu4) {
844080d2917SAlp Dener         /*  Full step taken; increase the radius */
845080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega4 * bnk->dnorm, tao->trust);
846080d2917SAlp Dener       } else {
847080d2917SAlp Dener         /*  More than full step taken; increase the radius */
848080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega5 * bnk->dnorm, tao->trust);
849080d2917SAlp Dener       }
850080d2917SAlp Dener     } else {
851080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
852080d2917SAlp Dener       tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
853080d2917SAlp Dener     }
854080d2917SAlp Dener     break;
855080d2917SAlp Dener 
856080d2917SAlp Dener   case BNK_UPDATE_REDUCTION:
857080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
858e0ed867bSAlp Dener       if ((prered < 0.0) || PetscIsInfOrNanReal(prered)) {
859fed79b8eSAlp Dener         /* The predicted reduction has the wrong sign.  This cannot
860fed79b8eSAlp Dener            happen in infinite precision arithmetic.  Step should
861fed79b8eSAlp Dener            be rejected! */
862080d2917SAlp Dener         tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8633105154fSTodd Munson       } else {
864b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
865080d2917SAlp Dener           tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
866080d2917SAlp Dener         } else {
8673105154fSTodd Munson           if ((PetscAbsScalar(actred) <= PetscMax(1.0, PetscAbsScalar(bnk->f)) * bnk->epsilon) && (PetscAbsScalar(prered) <= PetscMax(1.0, PetscAbsScalar(bnk->f)) * bnk->epsilon)) {
868080d2917SAlp Dener             kappa = 1.0;
8693105154fSTodd Munson           } else {
870080d2917SAlp Dener             kappa = actred / prered;
871080d2917SAlp Dener           }
872fed79b8eSAlp Dener           /* Accept or reject the step and update radius */
873080d2917SAlp Dener           if (kappa < bnk->eta1) {
874fed79b8eSAlp Dener             /* Reject the step */
875080d2917SAlp Dener             tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8763105154fSTodd Munson           } else {
877fed79b8eSAlp Dener             /* Accept the step */
878c133c014SAlp Dener             *accept = PETSC_TRUE;
879c133c014SAlp Dener             /* Update the trust region radius only if the computed step is at the trust radius boundary */
8808d5ead36SAlp Dener             if (bnk->dnorm == tao->trust) {
881080d2917SAlp Dener               if (kappa < bnk->eta2) {
882080d2917SAlp Dener                 /* Marginal bad step */
883c133c014SAlp Dener                 tao->trust = bnk->alpha2 * tao->trust;
8843105154fSTodd Munson               } else if (kappa < bnk->eta3) {
885fed79b8eSAlp Dener                 /* Reasonable step */
886fed79b8eSAlp Dener                 tao->trust = bnk->alpha3 * tao->trust;
8873105154fSTodd Munson               } else if (kappa < bnk->eta4) {
888080d2917SAlp Dener                 /* Good step */
889c133c014SAlp Dener                 tao->trust = bnk->alpha4 * tao->trust;
8903105154fSTodd Munson               } else {
891080d2917SAlp Dener                 /* Very good step */
892c133c014SAlp Dener                 tao->trust = bnk->alpha5 * tao->trust;
893080d2917SAlp Dener               }
894c133c014SAlp Dener             }
895080d2917SAlp Dener           }
896080d2917SAlp Dener         }
897080d2917SAlp Dener       }
898080d2917SAlp Dener     } else {
899080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
900080d2917SAlp Dener       tao->trust = bnk->alpha1 * PetscMin(bnk->dnorm, tao->trust);
901080d2917SAlp Dener     }
902080d2917SAlp Dener     break;
903080d2917SAlp Dener 
904080d2917SAlp Dener   default:
905080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
906b1c2d0e3SAlp Dener       if (prered < 0.0) {
907080d2917SAlp Dener         /*  The predicted reduction has the wrong sign.  This cannot */
908080d2917SAlp Dener         /*  happen in infinite precision arithmetic.  Step should */
909080d2917SAlp Dener         /*  be rejected! */
910080d2917SAlp Dener         tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
911080d2917SAlp Dener       } else {
912b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
913080d2917SAlp Dener           tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
914080d2917SAlp Dener         } else {
915080d2917SAlp Dener           if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
916080d2917SAlp Dener             kappa = 1.0;
917080d2917SAlp Dener           } else {
918080d2917SAlp Dener             kappa = actred / prered;
919080d2917SAlp Dener           }
920080d2917SAlp Dener 
9219566063dSJacob Faibussowitsch           PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
922080d2917SAlp Dener           tau_1   = bnk->theta * gdx / (bnk->theta * gdx - (1.0 - bnk->theta) * prered + actred);
923080d2917SAlp Dener           tau_2   = bnk->theta * gdx / (bnk->theta * gdx + (1.0 + bnk->theta) * prered - actred);
924080d2917SAlp Dener           tau_min = PetscMin(tau_1, tau_2);
925080d2917SAlp Dener           tau_max = PetscMax(tau_1, tau_2);
926080d2917SAlp Dener 
927080d2917SAlp Dener           if (kappa >= 1.0 - bnk->mu1) {
928080d2917SAlp Dener             /*  Great agreement */
929080d2917SAlp Dener             *accept = PETSC_TRUE;
930080d2917SAlp Dener             if (tau_max < 1.0) {
931080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
932080d2917SAlp Dener             } else if (tau_max > bnk->gamma4) {
933080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma4 * bnk->dnorm);
934080d2917SAlp Dener             } else {
935080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
936080d2917SAlp Dener             }
937080d2917SAlp Dener           } else if (kappa >= 1.0 - bnk->mu2) {
938080d2917SAlp Dener             /*  Good agreement */
939080d2917SAlp Dener             *accept = PETSC_TRUE;
940080d2917SAlp Dener             if (tau_max < bnk->gamma2) {
941080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
942080d2917SAlp Dener             } else if (tau_max > bnk->gamma3) {
943080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
944080d2917SAlp Dener             } else if (tau_max < 1.0) {
945080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
946080d2917SAlp Dener             } else {
947080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
948080d2917SAlp Dener             }
949080d2917SAlp Dener           } else {
950080d2917SAlp Dener             /*  Not good agreement */
951080d2917SAlp Dener             if (tau_min > 1.0) {
952080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
953080d2917SAlp Dener             } else if (tau_max < bnk->gamma1) {
954080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
955080d2917SAlp Dener             } else if ((tau_min < bnk->gamma1) && (tau_max >= 1.0)) {
956080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
957080d2917SAlp Dener             } else if ((tau_1 >= bnk->gamma1) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1) || (tau_2 >= 1.0))) {
958080d2917SAlp Dener               tao->trust = tau_1 * PetscMin(tao->trust, bnk->dnorm);
959080d2917SAlp Dener             } else if ((tau_2 >= bnk->gamma1) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1) || (tau_2 >= 1.0))) {
960080d2917SAlp Dener               tao->trust = tau_2 * PetscMin(tao->trust, bnk->dnorm);
961080d2917SAlp Dener             } else {
962080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
963080d2917SAlp Dener             }
964080d2917SAlp Dener           }
965080d2917SAlp Dener         }
966080d2917SAlp Dener       }
967080d2917SAlp Dener     } else {
968080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
969080d2917SAlp Dener       tao->trust = bnk->gamma1 * PetscMin(bnk->dnorm, tao->trust);
970080d2917SAlp Dener     }
97128017e9fSAlp Dener     break;
972080d2917SAlp Dener   }
973c133c014SAlp Dener   /* Make sure the radius does not violate min and max settings */
974c133c014SAlp Dener   tao->trust = PetscMin(tao->trust, bnk->max_radius);
975fed79b8eSAlp Dener   tao->trust = PetscMax(tao->trust, bnk->min_radius);
976080d2917SAlp Dener   PetscFunctionReturn(0);
977080d2917SAlp Dener }
978080d2917SAlp Dener 
979eb910715SAlp Dener /* ---------------------------------------------------------- */
980df278d8fSAlp Dener 
981d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoBNKAddStepCounts(Tao tao, PetscInt stepType)
982d71ae5a4SJacob Faibussowitsch {
98362675beeSAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
98462675beeSAlp Dener 
98562675beeSAlp Dener   PetscFunctionBegin;
98662675beeSAlp Dener   switch (stepType) {
987d71ae5a4SJacob Faibussowitsch   case BNK_NEWTON:
988d71ae5a4SJacob Faibussowitsch     ++bnk->newt;
989d71ae5a4SJacob Faibussowitsch     break;
990d71ae5a4SJacob Faibussowitsch   case BNK_BFGS:
991d71ae5a4SJacob Faibussowitsch     ++bnk->bfgs;
992d71ae5a4SJacob Faibussowitsch     break;
993d71ae5a4SJacob Faibussowitsch   case BNK_SCALED_GRADIENT:
994d71ae5a4SJacob Faibussowitsch     ++bnk->sgrad;
995d71ae5a4SJacob Faibussowitsch     break;
996d71ae5a4SJacob Faibussowitsch   case BNK_GRADIENT:
997d71ae5a4SJacob Faibussowitsch     ++bnk->grad;
998d71ae5a4SJacob Faibussowitsch     break;
999d71ae5a4SJacob Faibussowitsch   default:
1000d71ae5a4SJacob Faibussowitsch     break;
100162675beeSAlp Dener   }
100262675beeSAlp Dener   PetscFunctionReturn(0);
100362675beeSAlp Dener }
100462675beeSAlp Dener 
100562675beeSAlp Dener /* ---------------------------------------------------------- */
100662675beeSAlp Dener 
1007d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetUp_BNK(Tao tao)
1008d71ae5a4SJacob Faibussowitsch {
1009eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1010e031d6f5SAlp Dener   PetscInt i;
1011eb910715SAlp Dener 
1012eb910715SAlp Dener   PetscFunctionBegin;
101348a46eb9SPierre Jolivet   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
101448a46eb9SPierre Jolivet   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
101548a46eb9SPierre Jolivet   if (!bnk->W) PetscCall(VecDuplicate(tao->solution, &bnk->W));
101648a46eb9SPierre Jolivet   if (!bnk->Xold) PetscCall(VecDuplicate(tao->solution, &bnk->Xold));
101748a46eb9SPierre Jolivet   if (!bnk->Gold) PetscCall(VecDuplicate(tao->solution, &bnk->Gold));
101848a46eb9SPierre Jolivet   if (!bnk->Xwork) PetscCall(VecDuplicate(tao->solution, &bnk->Xwork));
101948a46eb9SPierre Jolivet   if (!bnk->Gwork) PetscCall(VecDuplicate(tao->solution, &bnk->Gwork));
102048a46eb9SPierre Jolivet   if (!bnk->unprojected_gradient) PetscCall(VecDuplicate(tao->solution, &bnk->unprojected_gradient));
102148a46eb9SPierre Jolivet   if (!bnk->unprojected_gradient_old) PetscCall(VecDuplicate(tao->solution, &bnk->unprojected_gradient_old));
102248a46eb9SPierre Jolivet   if (!bnk->Diag_min) PetscCall(VecDuplicate(tao->solution, &bnk->Diag_min));
102348a46eb9SPierre Jolivet   if (!bnk->Diag_max) PetscCall(VecDuplicate(tao->solution, &bnk->Diag_max));
1024e031d6f5SAlp Dener   if (bnk->max_cg_its > 0) {
1025c4b75bccSAlp Dener     /* Ensure that the important common vectors are shared between BNK and embedded BNCG */
1026c4b75bccSAlp Dener     bnk->bncg_ctx = (TAO_BNCG *)bnk->bncg->data;
10279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient_old)));
10289566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient_old));
102989da521bSAlp Dener     bnk->bncg_ctx->unprojected_gradient_old = bnk->unprojected_gradient_old;
10309566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient)));
10319566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient));
1032c4b75bccSAlp Dener     bnk->bncg_ctx->unprojected_gradient = bnk->unprojected_gradient;
10339566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->Gold)));
10349566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->G_old));
1035c4b75bccSAlp Dener     bnk->bncg_ctx->G_old = bnk->Gold;
10369566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->gradient)));
10379566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->gradient));
1038c4b75bccSAlp Dener     bnk->bncg->gradient = tao->gradient;
10399566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->stepdirection)));
10409566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->stepdirection));
1041c4b75bccSAlp Dener     bnk->bncg->stepdirection = tao->stepdirection;
10429566063dSJacob Faibussowitsch     PetscCall(TaoSetSolution(bnk->bncg, tao->solution));
1043c4b75bccSAlp Dener     /* Copy over some settings from BNK into BNCG */
10449566063dSJacob Faibussowitsch     PetscCall(TaoSetMaximumIterations(bnk->bncg, bnk->max_cg_its));
10459566063dSJacob Faibussowitsch     PetscCall(TaoSetTolerances(bnk->bncg, tao->gatol, tao->grtol, tao->gttol));
10469566063dSJacob Faibussowitsch     PetscCall(TaoSetFunctionLowerBound(bnk->bncg, tao->fmin));
10479566063dSJacob Faibussowitsch     PetscCall(TaoSetConvergenceTest(bnk->bncg, tao->ops->convergencetest, tao->cnvP));
10489566063dSJacob Faibussowitsch     PetscCall(TaoSetObjective(bnk->bncg, tao->ops->computeobjective, tao->user_objP));
10499566063dSJacob Faibussowitsch     PetscCall(TaoSetGradient(bnk->bncg, NULL, tao->ops->computegradient, tao->user_gradP));
10509566063dSJacob Faibussowitsch     PetscCall(TaoSetObjectiveAndGradient(bnk->bncg, NULL, tao->ops->computeobjectiveandgradient, tao->user_objgradP));
10519566063dSJacob Faibussowitsch     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)tao, (PetscObject)(bnk->bncg)));
1052c4b75bccSAlp Dener     for (i = 0; i < tao->numbermonitors; ++i) {
10539566063dSJacob Faibussowitsch       PetscCall(TaoSetMonitor(bnk->bncg, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]));
10549566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)(tao->monitorcontext[i])));
1055e031d6f5SAlp Dener     }
1056e031d6f5SAlp Dener   }
105783c8fe1dSLisandro Dalcin   bnk->X_inactive    = NULL;
105883c8fe1dSLisandro Dalcin   bnk->G_inactive    = NULL;
105983c8fe1dSLisandro Dalcin   bnk->inactive_work = NULL;
106083c8fe1dSLisandro Dalcin   bnk->active_work   = NULL;
106183c8fe1dSLisandro Dalcin   bnk->inactive_idx  = NULL;
106283c8fe1dSLisandro Dalcin   bnk->active_idx    = NULL;
106383c8fe1dSLisandro Dalcin   bnk->active_lower  = NULL;
106483c8fe1dSLisandro Dalcin   bnk->active_upper  = NULL;
106583c8fe1dSLisandro Dalcin   bnk->active_fixed  = NULL;
106683c8fe1dSLisandro Dalcin   bnk->M             = NULL;
106783c8fe1dSLisandro Dalcin   bnk->H_inactive    = NULL;
106883c8fe1dSLisandro Dalcin   bnk->Hpre_inactive = NULL;
1069eb910715SAlp Dener   PetscFunctionReturn(0);
1070eb910715SAlp Dener }
1071eb910715SAlp Dener 
1072eb910715SAlp Dener /*------------------------------------------------------------*/
1073df278d8fSAlp Dener 
1074d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoDestroy_BNK(Tao tao)
1075d71ae5a4SJacob Faibussowitsch {
1076eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1077eb910715SAlp Dener 
1078eb910715SAlp Dener   PetscFunctionBegin;
10799566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->W));
10809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Xold));
10819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Gold));
10829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Xwork));
10839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Gwork));
10849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->unprojected_gradient));
10859566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->unprojected_gradient_old));
10869566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Diag_min));
10879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bnk->Diag_max));
10889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_lower));
10899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_upper));
10909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_fixed));
10919566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_idx));
10929566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->inactive_idx));
10939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->Hpre_inactive));
10949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->H_inactive));
10959566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&bnk->bncg));
1096a958fbfcSStefano Zampini   PetscCall(KSPDestroy(&tao->ksp));
10979566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
1098eb910715SAlp Dener   PetscFunctionReturn(0);
1099eb910715SAlp Dener }
1100eb910715SAlp Dener 
1101eb910715SAlp Dener /*------------------------------------------------------------*/
1102df278d8fSAlp Dener 
1103d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetFromOptions_BNK(Tao tao, PetscOptionItems *PetscOptionsObject)
1104d71ae5a4SJacob Faibussowitsch {
1105eb910715SAlp Dener   TAO_BNK *bnk = (TAO_BNK *)tao->data;
1106eb910715SAlp Dener 
1107eb910715SAlp Dener   PetscFunctionBegin;
1108d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Newton-Krylov method for bound constrained optimization");
11099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_init_type", "radius initialization type", "", BNK_INIT, BNK_INIT_TYPES, BNK_INIT[bnk->init_type], &bnk->init_type, NULL));
11109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_update_type", "radius update type", "", BNK_UPDATE, BNK_UPDATE_TYPES, BNK_UPDATE[bnk->update_type], &bnk->update_type, NULL));
11119566063dSJacob 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));
11129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_sval", "(developer) Hessian perturbation starting value", "", bnk->sval, &bnk->sval, NULL));
11139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imin", "(developer) minimum initial Hessian perturbation", "", bnk->imin, &bnk->imin, NULL));
11149566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imax", "(developer) maximum initial Hessian perturbation", "", bnk->imax, &bnk->imax, NULL));
11159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imfac", "(developer) initial merit factor for Hessian perturbation", "", bnk->imfac, &bnk->imfac, NULL));
11169566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmin", "(developer) minimum Hessian perturbation", "", bnk->pmin, &bnk->pmin, NULL));
11179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmax", "(developer) maximum Hessian perturbation", "", bnk->pmax, &bnk->pmax, NULL));
11189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pgfac", "(developer) Hessian perturbation growth factor", "", bnk->pgfac, &bnk->pgfac, NULL));
11199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_psfac", "(developer) Hessian perturbation shrink factor", "", bnk->psfac, &bnk->psfac, NULL));
11209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmgfac", "(developer) merit growth factor for Hessian perturbation", "", bnk->pmgfac, &bnk->pmgfac, NULL));
11219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmsfac", "(developer) merit shrink factor for Hessian perturbation", "", bnk->pmsfac, &bnk->pmsfac, NULL));
11229566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta1", "(developer) threshold for rejecting step (-tao_bnk_update_type reduction)", "", bnk->eta1, &bnk->eta1, NULL));
11239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta2", "(developer) threshold for accepting marginal step (-tao_bnk_update_type reduction)", "", bnk->eta2, &bnk->eta2, NULL));
11249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta3", "(developer) threshold for accepting reasonable step (-tao_bnk_update_type reduction)", "", bnk->eta3, &bnk->eta3, NULL));
11259566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta4", "(developer) threshold for accepting good step (-tao_bnk_update_type reduction)", "", bnk->eta4, &bnk->eta4, NULL));
11269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha1", "(developer) radius reduction factor for rejected step (-tao_bnk_update_type reduction)", "", bnk->alpha1, &bnk->alpha1, NULL));
11279566063dSJacob 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));
11289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha3", "(developer) radius increase factor for reasonable accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha3, &bnk->alpha3, NULL));
11299566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha4", "(developer) radius increase factor for good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha4, &bnk->alpha4, NULL));
11309566063dSJacob 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));
11319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu1", "(developer) threshold for small line-search step length (-tao_bnk_update_type step)", "", bnk->nu1, &bnk->nu1, NULL));
11329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu2", "(developer) threshold for reasonable line-search step length (-tao_bnk_update_type step)", "", bnk->nu2, &bnk->nu2, NULL));
11339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu3", "(developer) threshold for large line-search step length (-tao_bnk_update_type step)", "", bnk->nu3, &bnk->nu3, NULL));
11349566063dSJacob 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));
11359566063dSJacob 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));
11369566063dSJacob 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));
11379566063dSJacob 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));
11389566063dSJacob 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));
11399566063dSJacob 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));
11409566063dSJacob 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));
11419566063dSJacob 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));
11429566063dSJacob 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));
11439566063dSJacob 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));
11449566063dSJacob 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));
11459566063dSJacob 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));
11469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta_i", "(developer) trust region interpolation factor (-tao_bnk_init_type interpolation)", "", bnk->theta_i, &bnk->theta_i, NULL));
11479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu1", "(developer) threshold for accepting very good step (-tao_bnk_update_type interpolation)", "", bnk->mu1, &bnk->mu1, NULL));
11489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu2", "(developer) threshold for accepting good step (-tao_bnk_update_type interpolation)", "", bnk->mu2, &bnk->mu2, NULL));
11499566063dSJacob 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));
11509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma2", "(developer) radius reduction factor for rejected bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma2, &bnk->gamma2, NULL));
11519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma3", "(developer) radius increase factor for accepted good step (-tao_bnk_update_type interpolation)", "", bnk->gamma3, &bnk->gamma3, NULL));
11529566063dSJacob 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));
11539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta", "(developer) trust region interpolation factor (-tao_bnk_update_type interpolation)", "", bnk->theta, &bnk->theta, NULL));
11549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_min_radius", "(developer) lower bound on initial radius", "", bnk->min_radius, &bnk->min_radius, NULL));
11559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_max_radius", "(developer) upper bound on radius", "", bnk->max_radius, &bnk->max_radius, NULL));
11569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_epsilon", "(developer) tolerance used when computing actual and predicted reduction", "", bnk->epsilon, &bnk->epsilon, NULL));
11579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", bnk->as_tol, &bnk->as_tol, NULL));
11589566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_step", "(developer) step length used when estimating actively bounded variables", "", bnk->as_step, &bnk->as_step, NULL));
11599566063dSJacob 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));
1160d0609cedSBarry Smith   PetscOptionsHeadEnd();
11618ebe3e4eSStefano Zampini 
11629566063dSJacob Faibussowitsch   PetscCall(TaoSetOptionsPrefix(bnk->bncg, ((PetscObject)(tao))->prefix));
11639566063dSJacob Faibussowitsch   PetscCall(TaoAppendOptionsPrefix(bnk->bncg, "tao_bnk_cg_"));
11649566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(bnk->bncg));
11658ebe3e4eSStefano Zampini 
11669566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(tao->ksp, ((PetscObject)(tao))->prefix));
11679566063dSJacob Faibussowitsch   PetscCall(KSPAppendOptionsPrefix(tao->ksp, "tao_bnk_"));
11689566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(tao->ksp));
1169eb910715SAlp Dener   PetscFunctionReturn(0);
1170eb910715SAlp Dener }
1171eb910715SAlp Dener 
1172eb910715SAlp Dener /*------------------------------------------------------------*/
1173df278d8fSAlp Dener 
1174d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoView_BNK(Tao tao, PetscViewer viewer)
1175d71ae5a4SJacob Faibussowitsch {
1176eb910715SAlp Dener   TAO_BNK  *bnk = (TAO_BNK *)tao->data;
1177eb910715SAlp Dener   PetscInt  nrejects;
1178eb910715SAlp Dener   PetscBool isascii;
1179eb910715SAlp Dener 
1180eb910715SAlp Dener   PetscFunctionBegin;
11819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1182eb910715SAlp Dener   if (isascii) {
11839566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1184*b17ffb64SBarry Smith     PetscCall(TaoView(bnk->bncg, viewer));
1185b9ac7092SAlp Dener     if (bnk->M) {
11869566063dSJacob Faibussowitsch       PetscCall(MatLMVMGetRejectCount(bnk->M, &nrejects));
118763a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Rejected BFGS updates: %" PetscInt_FMT "\n", nrejects));
1188eb910715SAlp Dener     }
118963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "CG steps: %" PetscInt_FMT "\n", bnk->tot_cg_its));
119063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Newton steps: %" PetscInt_FMT "\n", bnk->newt));
119148a46eb9SPierre Jolivet     if (bnk->M) PetscCall(PetscViewerASCIIPrintf(viewer, "BFGS steps: %" PetscInt_FMT "\n", bnk->bfgs));
119263a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %" PetscInt_FMT "\n", bnk->sgrad));
119363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Gradient steps: %" PetscInt_FMT "\n", bnk->grad));
11949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP termination reasons:\n"));
119563a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  atol: %" PetscInt_FMT "\n", bnk->ksp_atol));
119663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  rtol: %" PetscInt_FMT "\n", bnk->ksp_rtol));
119763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  ctol: %" PetscInt_FMT "\n", bnk->ksp_ctol));
119863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  negc: %" PetscInt_FMT "\n", bnk->ksp_negc));
119963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dtol: %" PetscInt_FMT "\n", bnk->ksp_dtol));
120063a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  iter: %" PetscInt_FMT "\n", bnk->ksp_iter));
120163a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  othr: %" PetscInt_FMT "\n", bnk->ksp_othr));
12029566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
1203eb910715SAlp Dener   }
1204eb910715SAlp Dener   PetscFunctionReturn(0);
1205eb910715SAlp Dener }
1206eb910715SAlp Dener 
1207eb910715SAlp Dener /* ---------------------------------------------------------- */
1208df278d8fSAlp Dener 
1209eb910715SAlp Dener /*MC
1210eb910715SAlp Dener   TAOBNK - Shared base-type for Bounded Newton-Krylov type algorithms.
121166ed3702SAlp Dener   At each iteration, the BNK methods solve the symmetric
1212eb910715SAlp Dener   system of equations to obtain the step diretion dk:
1213eb910715SAlp Dener               Hk dk = -gk
12142b97c8d8SAlp Dener   for free variables only. The step can be globalized either through
12152b97c8d8SAlp Dener   trust-region methods, or a line search, or a heuristic mixture of both.
1216eb910715SAlp Dener 
1217eb910715SAlp Dener     Options Database Keys:
12189fa2b5dcSStefano Zampini + -tao_bnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
12199fa2b5dcSStefano Zampini . -tao_bnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
12209fa2b5dcSStefano Zampini . -tao_bnk_update_type - trust radius update method ("step", "direction", "interpolation")
12219fa2b5dcSStefano Zampini . -tao_bnk_as_type - active-set estimation method ("none", "bertsekas")
12229fa2b5dcSStefano Zampini . -tao_bnk_as_tol - (developer) initial tolerance used in estimating bounded active variables (-as_type bertsekas)
12239fa2b5dcSStefano Zampini . -tao_bnk_as_step - (developer) trial step length used in estimating bounded active variables (-as_type bertsekas)
12249fa2b5dcSStefano Zampini . -tao_bnk_sval - (developer) Hessian perturbation starting value
12259fa2b5dcSStefano Zampini . -tao_bnk_imin - (developer) minimum initial Hessian perturbation
12269fa2b5dcSStefano Zampini . -tao_bnk_imax - (developer) maximum initial Hessian perturbation
12279fa2b5dcSStefano Zampini . -tao_bnk_pmin - (developer) minimum Hessian perturbation
12289fa2b5dcSStefano Zampini . -tao_bnk_pmax - (developer) aximum Hessian perturbation
12299fa2b5dcSStefano Zampini . -tao_bnk_pgfac - (developer) Hessian perturbation growth factor
12309fa2b5dcSStefano Zampini . -tao_bnk_psfac - (developer) Hessian perturbation shrink factor
12319fa2b5dcSStefano Zampini . -tao_bnk_imfac - (developer) initial merit factor for Hessian perturbation
12329fa2b5dcSStefano Zampini . -tao_bnk_pmgfac - (developer) merit growth factor for Hessian perturbation
12339fa2b5dcSStefano Zampini . -tao_bnk_pmsfac - (developer) merit shrink factor for Hessian perturbation
12349fa2b5dcSStefano Zampini . -tao_bnk_eta1 - (developer) threshold for rejecting step (-update_type reduction)
12359fa2b5dcSStefano Zampini . -tao_bnk_eta2 - (developer) threshold for accepting marginal step (-update_type reduction)
12369fa2b5dcSStefano Zampini . -tao_bnk_eta3 - (developer) threshold for accepting reasonable step (-update_type reduction)
12379fa2b5dcSStefano Zampini . -tao_bnk_eta4 - (developer) threshold for accepting good step (-update_type reduction)
12389fa2b5dcSStefano Zampini . -tao_bnk_alpha1 - (developer) radius reduction factor for rejected step (-update_type reduction)
12399fa2b5dcSStefano Zampini . -tao_bnk_alpha2 - (developer) radius reduction factor for marginally accepted bad step (-update_type reduction)
12409fa2b5dcSStefano Zampini . -tao_bnk_alpha3 - (developer) radius increase factor for reasonable accepted step (-update_type reduction)
12419fa2b5dcSStefano Zampini . -tao_bnk_alpha4 - (developer) radius increase factor for good accepted step (-update_type reduction)
12429fa2b5dcSStefano Zampini . -tao_bnk_alpha5 - (developer) radius increase factor for very good accepted step (-update_type reduction)
12439fa2b5dcSStefano Zampini . -tao_bnk_epsilon - (developer) tolerance for small pred/actual ratios that trigger automatic step acceptance (-update_type reduction)
12449fa2b5dcSStefano Zampini . -tao_bnk_mu1 - (developer) threshold for accepting very good step (-update_type interpolation)
12459fa2b5dcSStefano Zampini . -tao_bnk_mu2 - (developer) threshold for accepting good step (-update_type interpolation)
12469fa2b5dcSStefano Zampini . -tao_bnk_gamma1 - (developer) radius reduction factor for rejected very bad step (-update_type interpolation)
12479fa2b5dcSStefano Zampini . -tao_bnk_gamma2 - (developer) radius reduction factor for rejected bad step (-update_type interpolation)
12489fa2b5dcSStefano Zampini . -tao_bnk_gamma3 - (developer) radius increase factor for accepted good step (-update_type interpolation)
12499fa2b5dcSStefano Zampini . -tao_bnk_gamma4 - (developer) radius increase factor for accepted very good step (-update_type interpolation)
12509fa2b5dcSStefano Zampini . -tao_bnk_theta - (developer) trust region interpolation factor (-update_type interpolation)
12519fa2b5dcSStefano Zampini . -tao_bnk_nu1 - (developer) threshold for small line-search step length (-update_type step)
12529fa2b5dcSStefano Zampini . -tao_bnk_nu2 - (developer) threshold for reasonable line-search step length (-update_type step)
12539fa2b5dcSStefano Zampini . -tao_bnk_nu3 - (developer) threshold for large line-search step length (-update_type step)
12549fa2b5dcSStefano Zampini . -tao_bnk_nu4 - (developer) threshold for very large line-search step length (-update_type step)
12559fa2b5dcSStefano Zampini . -tao_bnk_omega1 - (developer) radius reduction factor for very small line-search step length (-update_type step)
12569fa2b5dcSStefano Zampini . -tao_bnk_omega2 - (developer) radius reduction factor for small line-search step length (-update_type step)
12579fa2b5dcSStefano Zampini . -tao_bnk_omega3 - (developer) radius factor for decent line-search step length (-update_type step)
12589fa2b5dcSStefano Zampini . -tao_bnk_omega4 - (developer) radius increase factor for large line-search step length (-update_type step)
12599fa2b5dcSStefano Zampini . -tao_bnk_omega5 - (developer) radius increase factor for very large line-search step length (-update_type step)
12609fa2b5dcSStefano Zampini . -tao_bnk_mu1_i -  (developer) threshold for accepting very good step (-init_type interpolation)
12619fa2b5dcSStefano Zampini . -tao_bnk_mu2_i -  (developer) threshold for accepting good step (-init_type interpolation)
12629fa2b5dcSStefano Zampini . -tao_bnk_gamma1_i - (developer) radius reduction factor for rejected very bad step (-init_type interpolation)
12639fa2b5dcSStefano Zampini . -tao_bnk_gamma2_i - (developer) radius reduction factor for rejected bad step (-init_type interpolation)
12649fa2b5dcSStefano Zampini . -tao_bnk_gamma3_i - (developer) radius increase factor for accepted good step (-init_type interpolation)
12659fa2b5dcSStefano Zampini . -tao_bnk_gamma4_i - (developer) radius increase factor for accepted very good step (-init_type interpolation)
12669fa2b5dcSStefano Zampini - -tao_bnk_theta_i - (developer) trust region interpolation factor (-init_type interpolation)
1267eb910715SAlp Dener 
1268eb910715SAlp Dener   Level: beginner
1269eb910715SAlp Dener M*/
1270eb910715SAlp Dener 
1271d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoCreate_BNK(Tao tao)
1272d71ae5a4SJacob Faibussowitsch {
1273eb910715SAlp Dener   TAO_BNK *bnk;
1274b9ac7092SAlp Dener   PC       pc;
1275eb910715SAlp Dener 
1276eb910715SAlp Dener   PetscFunctionBegin;
12774dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&bnk));
1278eb910715SAlp Dener 
1279eb910715SAlp Dener   tao->ops->setup          = TaoSetUp_BNK;
1280eb910715SAlp Dener   tao->ops->view           = TaoView_BNK;
1281eb910715SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNK;
1282eb910715SAlp Dener   tao->ops->destroy        = TaoDestroy_BNK;
1283eb910715SAlp Dener 
1284eb910715SAlp Dener   /*  Override default settings (unless already changed) */
1285eb910715SAlp Dener   if (!tao->max_it_changed) tao->max_it = 50;
1286eb910715SAlp Dener   if (!tao->trust0_changed) tao->trust0 = 100.0;
1287eb910715SAlp Dener 
1288eb910715SAlp Dener   tao->data = (void *)bnk;
1289eb910715SAlp Dener 
129066ed3702SAlp Dener   /*  Hessian shifting parameters */
1291e0ed867bSAlp Dener   bnk->computehessian = TaoBNKComputeHessian;
1292e0ed867bSAlp Dener   bnk->computestep    = TaoBNKComputeStep;
1293e0ed867bSAlp Dener 
1294eb910715SAlp Dener   bnk->sval  = 0.0;
1295eb910715SAlp Dener   bnk->imin  = 1.0e-4;
1296eb910715SAlp Dener   bnk->imax  = 1.0e+2;
1297eb910715SAlp Dener   bnk->imfac = 1.0e-1;
1298eb910715SAlp Dener 
1299eb910715SAlp Dener   bnk->pmin   = 1.0e-12;
1300eb910715SAlp Dener   bnk->pmax   = 1.0e+2;
1301eb910715SAlp Dener   bnk->pgfac  = 1.0e+1;
1302eb910715SAlp Dener   bnk->psfac  = 4.0e-1;
1303eb910715SAlp Dener   bnk->pmgfac = 1.0e-1;
1304eb910715SAlp Dener   bnk->pmsfac = 1.0e-1;
1305eb910715SAlp Dener 
1306eb910715SAlp Dener   /*  Default values for trust-region radius update based on steplength */
1307eb910715SAlp Dener   bnk->nu1 = 0.25;
1308eb910715SAlp Dener   bnk->nu2 = 0.50;
1309eb910715SAlp Dener   bnk->nu3 = 1.00;
1310eb910715SAlp Dener   bnk->nu4 = 1.25;
1311eb910715SAlp Dener 
1312eb910715SAlp Dener   bnk->omega1 = 0.25;
1313eb910715SAlp Dener   bnk->omega2 = 0.50;
1314eb910715SAlp Dener   bnk->omega3 = 1.00;
1315eb910715SAlp Dener   bnk->omega4 = 2.00;
1316eb910715SAlp Dener   bnk->omega5 = 4.00;
1317eb910715SAlp Dener 
1318eb910715SAlp Dener   /*  Default values for trust-region radius update based on reduction */
1319eb910715SAlp Dener   bnk->eta1 = 1.0e-4;
1320eb910715SAlp Dener   bnk->eta2 = 0.25;
1321eb910715SAlp Dener   bnk->eta3 = 0.50;
1322eb910715SAlp Dener   bnk->eta4 = 0.90;
1323eb910715SAlp Dener 
1324eb910715SAlp Dener   bnk->alpha1 = 0.25;
1325eb910715SAlp Dener   bnk->alpha2 = 0.50;
1326eb910715SAlp Dener   bnk->alpha3 = 1.00;
1327eb910715SAlp Dener   bnk->alpha4 = 2.00;
1328eb910715SAlp Dener   bnk->alpha5 = 4.00;
1329eb910715SAlp Dener 
1330eb910715SAlp Dener   /*  Default values for trust-region radius update based on interpolation */
1331eb910715SAlp Dener   bnk->mu1 = 0.10;
1332eb910715SAlp Dener   bnk->mu2 = 0.50;
1333eb910715SAlp Dener 
1334eb910715SAlp Dener   bnk->gamma1 = 0.25;
1335eb910715SAlp Dener   bnk->gamma2 = 0.50;
1336eb910715SAlp Dener   bnk->gamma3 = 2.00;
1337eb910715SAlp Dener   bnk->gamma4 = 4.00;
1338eb910715SAlp Dener 
1339eb910715SAlp Dener   bnk->theta = 0.05;
1340eb910715SAlp Dener 
1341eb910715SAlp Dener   /*  Default values for trust region initialization based on interpolation */
1342eb910715SAlp Dener   bnk->mu1_i = 0.35;
1343eb910715SAlp Dener   bnk->mu2_i = 0.50;
1344eb910715SAlp Dener 
1345eb910715SAlp Dener   bnk->gamma1_i = 0.0625;
1346eb910715SAlp Dener   bnk->gamma2_i = 0.5;
1347eb910715SAlp Dener   bnk->gamma3_i = 2.0;
1348eb910715SAlp Dener   bnk->gamma4_i = 5.0;
1349eb910715SAlp Dener 
1350eb910715SAlp Dener   bnk->theta_i = 0.25;
1351eb910715SAlp Dener 
1352eb910715SAlp Dener   /*  Remaining parameters */
1353c0f10754SAlp Dener   bnk->max_cg_its = 0;
1354eb910715SAlp Dener   bnk->min_radius = 1.0e-10;
1355eb910715SAlp Dener   bnk->max_radius = 1.0e10;
1356770b7498SAlp Dener   bnk->epsilon    = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0 / 3.0);
13570a4511e9SAlp Dener   bnk->as_tol     = 1.0e-3;
13580a4511e9SAlp Dener   bnk->as_step    = 1.0e-3;
135962675beeSAlp Dener   bnk->dmin       = 1.0e-6;
136062675beeSAlp Dener   bnk->dmax       = 1.0e6;
1361eb910715SAlp Dener 
136283c8fe1dSLisandro Dalcin   bnk->M           = NULL;
136383c8fe1dSLisandro Dalcin   bnk->bfgs_pre    = NULL;
1364eb910715SAlp Dener   bnk->init_type   = BNK_INIT_INTERPOLATION;
13657b1c7716SAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION;
13662f75a4aaSAlp Dener   bnk->as_type     = BNK_AS_BERTSEKAS;
1367eb910715SAlp Dener 
1368e031d6f5SAlp Dener   /* Create the embedded BNCG solver */
13699566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PetscObjectComm((PetscObject)tao), &bnk->bncg));
13709566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)bnk->bncg, (PetscObject)tao, 1));
13719566063dSJacob Faibussowitsch   PetscCall(TaoSetType(bnk->bncg, TAOBNCG));
1372e031d6f5SAlp Dener 
1373c0f10754SAlp Dener   /* Create the line search */
13749566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch));
13759566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
1376f4db9bf7SStefano Zampini   PetscCall(TaoLineSearchSetType(tao->linesearch, TAOLINESEARCHMT));
13779566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao));
1378eb910715SAlp Dener 
1379eb910715SAlp Dener   /*  Set linear solver to default for symmetric matrices */
13809566063dSJacob Faibussowitsch   PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
13819566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
13829566063dSJacob Faibussowitsch   PetscCall(KSPSetType(tao->ksp, KSPSTCG));
13839566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
13849566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLMVM));
1385eb910715SAlp Dener   PetscFunctionReturn(0);
1386eb910715SAlp Dener }
1387