xref: /petsc/src/tao/bound/impls/bnk/bnk.c (revision 9566063d113dddea24716c546802770db7481bc0)
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 
13c0f10754SAlp Dener PetscErrorCode TaoBNKInitialize(Tao tao, PetscInt initType, PetscBool *needH)
14eb910715SAlp Dener {
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 */
28*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
29*9566063dSJacob Faibussowitsch   PetscCall(TaoSetVariableBounds(bnk->bncg, tao->XL, tao->XU));
30b9ac7092SAlp Dener   if (tao->bounded) {
31*9566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU));
32cd929ea3SAlp Dener   }
3328017e9fSAlp Dener 
3428017e9fSAlp Dener   /* Project the initial point onto the feasible region */
35*9566063dSJacob Faibussowitsch   PetscCall(TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution));
3628017e9fSAlp Dener 
3728017e9fSAlp Dener   /* Check convergence criteria */
38*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient));
39*9566063dSJacob Faibussowitsch   PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
40*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
41*9566063dSJacob Faibussowitsch   PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
42*9566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
4328017e9fSAlp Dener 
44c0f10754SAlp Dener   /* Test the initial point for convergence */
45*9566063dSJacob Faibussowitsch   PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
46*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
473c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(bnk->f) && !PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
48*9566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao,bnk->f,resnorm,0.0,tao->ksp_its));
49*9566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao,tao->niter,bnk->f,resnorm,0.0,1.0));
50*9566063dSJacob Faibussowitsch   PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
51c0f10754SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
52c0f10754SAlp Dener 
53e031d6f5SAlp Dener   /* Reset KSP stopping reason counters */
54eb910715SAlp Dener   bnk->ksp_atol = 0;
55eb910715SAlp Dener   bnk->ksp_rtol = 0;
56eb910715SAlp Dener   bnk->ksp_dtol = 0;
57eb910715SAlp Dener   bnk->ksp_ctol = 0;
58eb910715SAlp Dener   bnk->ksp_negc = 0;
59eb910715SAlp Dener   bnk->ksp_iter = 0;
60eb910715SAlp Dener   bnk->ksp_othr = 0;
61eb910715SAlp Dener 
62e031d6f5SAlp Dener   /* Reset accepted step type counters */
63e031d6f5SAlp Dener   bnk->tot_cg_its = 0;
64e031d6f5SAlp Dener   bnk->newt = 0;
65e031d6f5SAlp Dener   bnk->bfgs = 0;
66e031d6f5SAlp Dener   bnk->sgrad = 0;
67e031d6f5SAlp Dener   bnk->grad = 0;
68e031d6f5SAlp Dener 
69fed79b8eSAlp Dener   /* Initialize the Hessian perturbation */
70fed79b8eSAlp Dener   bnk->pert = bnk->sval;
71fed79b8eSAlp Dener 
72937a31a1SAlp Dener   /* Reset initial steplength to zero (this helps BNCG reset its direction internally) */
73*9566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
74937a31a1SAlp Dener 
75e031d6f5SAlp Dener   /* Allocate the vectors needed for the BFGS approximation */
76*9566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
77*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &is_bfgs));
78*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCJACOBI, &is_jacobi));
79b9ac7092SAlp Dener   if (is_bfgs) {
80b9ac7092SAlp Dener     bnk->bfgs_pre = pc;
81*9566063dSJacob Faibussowitsch     PetscCall(PCLMVMGetMatLMVM(bnk->bfgs_pre, &bnk->M));
82*9566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tao->solution, &n));
83*9566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tao->solution, &N));
84*9566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(bnk->M, n, n, N, N));
85*9566063dSJacob Faibussowitsch     PetscCall(MatLMVMAllocate(bnk->M, tao->solution, bnk->unprojected_gradient));
86*9566063dSJacob Faibussowitsch     PetscCall(MatIsSymmetricKnown(bnk->M, &sym_set, &is_symmetric));
873c859ba3SBarry Smith     PetscCheck(sym_set && is_symmetric,PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix in the LMVM preconditioner must be symmetric.");
88b9ac7092SAlp Dener   } else if (is_jacobi) {
89*9566063dSJacob Faibussowitsch     PetscCall(PCJacobiSetUseAbs(pc,PETSC_TRUE));
90e031d6f5SAlp Dener   }
91e031d6f5SAlp Dener 
92e031d6f5SAlp Dener   /* Prepare the min/max vectors for safeguarding diagonal scales */
93*9566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_min, bnk->dmin));
94*9566063dSJacob Faibussowitsch   PetscCall(VecSet(bnk->Diag_max, bnk->dmax));
95eb910715SAlp Dener 
96eb910715SAlp Dener   /* Initialize trust-region radius.  The initialization is only performed
97eb910715SAlp Dener      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
98c0f10754SAlp Dener   *needH = PETSC_TRUE;
99*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp,"KSPCGSetRadius_C",&kspTR));
1002e6e4ca1SStefano Zampini   if (kspTR) {
10162675beeSAlp Dener     switch (initType) {
102eb910715SAlp Dener     case BNK_INIT_CONSTANT:
103eb910715SAlp Dener       /* Use the initial radius specified */
104c0f10754SAlp Dener       tao->trust = tao->trust0;
105eb910715SAlp Dener       break;
106eb910715SAlp Dener 
107eb910715SAlp Dener     case BNK_INIT_INTERPOLATION:
108c0f10754SAlp Dener       /* Use interpolation based on the initial Hessian */
109eb910715SAlp Dener       max_radius = 0.0;
11008752603SAlp Dener       tao->trust = tao->trust0;
111eb910715SAlp Dener       for (j = 0; j < j_max; ++j) {
1120a4511e9SAlp Dener         f_min = bnk->f;
113eb910715SAlp Dener         sigma = 0.0;
114eb910715SAlp Dener 
115c0f10754SAlp Dener         if (*needH) {
11662602cfbSAlp Dener           /* Compute the Hessian at the new step, and extract the inactive subsystem */
117*9566063dSJacob Faibussowitsch           PetscCall((*bnk->computehessian)(tao));
118*9566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, BNK_AS_NONE));
119*9566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&bnk->H_inactive));
12089da521bSAlp Dener           if (bnk->active_idx) {
121*9566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive));
12228017e9fSAlp Dener           } else {
123*9566063dSJacob Faibussowitsch             PetscCall(PetscObjectReference((PetscObject)tao->hessian));
124c5e9d94cSAlp Dener             bnk->H_inactive = tao->hessian;
12528017e9fSAlp Dener           }
126c0f10754SAlp Dener           *needH = PETSC_FALSE;
127eb910715SAlp Dener         }
128eb910715SAlp Dener 
129eb910715SAlp Dener         for (i = 0; i < i_max; ++i) {
13062602cfbSAlp Dener           /* Take a steepest descent step and snap it to bounds */
131*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
132*9566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution, -tao->trust/bnk->gnorm, tao->gradient));
133*9566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution));
13489da521bSAlp Dener           /* Compute the step we actually accepted */
135*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->W));
136*9566063dSJacob Faibussowitsch           PetscCall(VecAXPY(bnk->W, -1.0, bnk->Xold));
13762602cfbSAlp Dener           /* Compute the objective at the trial */
138*9566063dSJacob Faibussowitsch           PetscCall(TaoComputeObjective(tao, tao->solution, &ftrial));
1393c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(bnk->f),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
140*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->Xold, tao->solution));
141eb910715SAlp Dener           if (PetscIsInfOrNanReal(ftrial)) {
142eb910715SAlp Dener             tau = bnk->gamma1_i;
143eb910715SAlp Dener           } else {
1440a4511e9SAlp Dener             if (ftrial < f_min) {
1450a4511e9SAlp Dener               f_min = ftrial;
146eb910715SAlp Dener               sigma = -tao->trust / bnk->gnorm;
147eb910715SAlp Dener             }
14808752603SAlp Dener 
149770b7498SAlp Dener             /* Compute the predicted and actual reduction */
15089da521bSAlp Dener             if (bnk->active_idx) {
151*9566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
152*9566063dSJacob Faibussowitsch               PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1532ab2a32cSAlp Dener             } else {
15408752603SAlp Dener               bnk->X_inactive = bnk->W;
15508752603SAlp Dener               bnk->inactive_work = bnk->Xwork;
1562ab2a32cSAlp Dener             }
157*9566063dSJacob Faibussowitsch             PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
158*9566063dSJacob Faibussowitsch             PetscCall(VecDot(bnk->X_inactive, bnk->inactive_work, &prered));
15989da521bSAlp Dener             if (bnk->active_idx) {
160*9566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive));
161*9566063dSJacob Faibussowitsch               PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
1622ab2a32cSAlp Dener             }
163eb910715SAlp Dener             prered = tao->trust * (bnk->gnorm - 0.5 * tao->trust * prered / (bnk->gnorm * bnk->gnorm));
164eb910715SAlp Dener             actred = bnk->f - ftrial;
1653105154fSTodd Munson             if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
166eb910715SAlp Dener               kappa = 1.0;
1673105154fSTodd Munson             } else {
168eb910715SAlp Dener               kappa = actred / prered;
169eb910715SAlp Dener             }
170eb910715SAlp Dener 
171eb910715SAlp Dener             tau_1 = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust + (1.0 - bnk->theta_i) * prered - actred);
172eb910715SAlp Dener             tau_2 = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust - (1.0 + bnk->theta_i) * prered + actred);
173eb910715SAlp Dener             tau_min = PetscMin(tau_1, tau_2);
174eb910715SAlp Dener             tau_max = PetscMax(tau_1, tau_2);
175eb910715SAlp Dener 
17618cfbf8eSSatish Balay             if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu1_i) {
177eb910715SAlp Dener               /*  Great agreement */
178eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
179eb910715SAlp Dener 
180eb910715SAlp Dener               if (tau_max < 1.0) {
181eb910715SAlp Dener                 tau = bnk->gamma3_i;
1823105154fSTodd Munson               } else if (tau_max > bnk->gamma4_i) {
183eb910715SAlp Dener                 tau = bnk->gamma4_i;
1843105154fSTodd Munson               } else {
185eb910715SAlp Dener                 tau = tau_max;
186eb910715SAlp Dener               }
18718cfbf8eSSatish Balay             } else if (PetscAbsScalar(kappa - (PetscReal)1.0) <= bnk->mu2_i) {
188eb910715SAlp Dener               /*  Good agreement */
189eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
190eb910715SAlp Dener 
191eb910715SAlp Dener               if (tau_max < bnk->gamma2_i) {
192eb910715SAlp Dener                 tau = bnk->gamma2_i;
193eb910715SAlp Dener               } else if (tau_max > bnk->gamma3_i) {
194eb910715SAlp Dener                 tau = bnk->gamma3_i;
195eb910715SAlp Dener               } else {
196eb910715SAlp Dener                 tau = tau_max;
197eb910715SAlp Dener               }
1988f8a4e06SAlp Dener             } else {
199eb910715SAlp Dener               /*  Not good agreement */
200eb910715SAlp Dener               if (tau_min > 1.0) {
201eb910715SAlp Dener                 tau = bnk->gamma2_i;
202eb910715SAlp Dener               } else if (tau_max < bnk->gamma1_i) {
203eb910715SAlp Dener                 tau = bnk->gamma1_i;
204eb910715SAlp Dener               } else if ((tau_min < bnk->gamma1_i) && (tau_max >= 1.0)) {
205eb910715SAlp Dener                 tau = bnk->gamma1_i;
2063105154fSTodd Munson               } else if ((tau_1 >= bnk->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
207eb910715SAlp Dener                 tau = tau_1;
2083105154fSTodd Munson               } else if ((tau_2 >= bnk->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
209eb910715SAlp Dener                 tau = tau_2;
210eb910715SAlp Dener               } else {
211eb910715SAlp Dener                 tau = tau_max;
212eb910715SAlp Dener               }
213eb910715SAlp Dener             }
214eb910715SAlp Dener           }
215eb910715SAlp Dener           tao->trust = tau * tao->trust;
216eb910715SAlp Dener         }
217eb910715SAlp Dener 
2180a4511e9SAlp Dener         if (f_min < bnk->f) {
219937a31a1SAlp Dener           /* We accidentally found a solution better than the initial, so accept it */
2200a4511e9SAlp Dener           bnk->f = f_min;
221*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, bnk->Xold));
222*9566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->solution,sigma,tao->gradient));
223*9566063dSJacob Faibussowitsch           PetscCall(TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution));
224*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(tao->solution, tao->stepdirection));
225*9566063dSJacob Faibussowitsch           PetscCall(VecAXPY(tao->stepdirection, -1.0, bnk->Xold));
226*9566063dSJacob Faibussowitsch           PetscCall(TaoComputeGradient(tao,tao->solution,bnk->unprojected_gradient));
227*9566063dSJacob Faibussowitsch           PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
228*9566063dSJacob Faibussowitsch           PetscCall(VecCopy(bnk->unprojected_gradient, tao->gradient));
229*9566063dSJacob Faibussowitsch           PetscCall(VecISSet(tao->gradient, bnk->active_idx, 0.0));
230937a31a1SAlp Dener           /* Compute gradient at the new iterate and flip switch to compute the Hessian later */
231*9566063dSJacob Faibussowitsch           PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm));
232c0f10754SAlp Dener           *needH = PETSC_TRUE;
233937a31a1SAlp Dener           /* Test the new step for convergence */
234*9566063dSJacob Faibussowitsch           PetscCall(VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W));
235*9566063dSJacob Faibussowitsch           PetscCall(VecNorm(bnk->W, NORM_2, &resnorm));
2363c859ba3SBarry Smith           PetscCheck(!PetscIsInfOrNanReal(resnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
237*9566063dSJacob Faibussowitsch           PetscCall(TaoLogConvergenceHistory(tao,bnk->f,resnorm,0.0,tao->ksp_its));
238*9566063dSJacob Faibussowitsch           PetscCall(TaoMonitor(tao,tao->niter,bnk->f,resnorm,0.0,1.0));
239*9566063dSJacob Faibussowitsch           PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
240eb910715SAlp Dener           if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
241937a31a1SAlp Dener           /* active BNCG recycling early because we have a stepdirection computed */
242*9566063dSJacob Faibussowitsch           PetscCall(TaoSetRecycleHistory(bnk->bncg, PETSC_TRUE));
243eb910715SAlp Dener         }
244eb910715SAlp Dener       }
245eb910715SAlp Dener       tao->trust = PetscMax(tao->trust, max_radius);
246e031d6f5SAlp Dener 
247e031d6f5SAlp Dener       /* Ensure that the trust radius is within the limits */
248e031d6f5SAlp Dener       tao->trust = PetscMax(tao->trust, bnk->min_radius);
249e031d6f5SAlp Dener       tao->trust = PetscMin(tao->trust, bnk->max_radius);
250eb910715SAlp Dener       break;
251eb910715SAlp Dener 
252eb910715SAlp Dener     default:
253eb910715SAlp Dener       /* Norm of the first direction will initialize radius */
254eb910715SAlp Dener       tao->trust = 0.0;
255eb910715SAlp Dener       break;
256eb910715SAlp Dener     }
257eb910715SAlp Dener   }
258eb910715SAlp Dener   PetscFunctionReturn(0);
259eb910715SAlp Dener }
260eb910715SAlp Dener 
261df278d8fSAlp Dener /*------------------------------------------------------------*/
262df278d8fSAlp Dener 
263e0ed867bSAlp Dener /* Routine for computing the exact Hessian and preparing the preconditioner at the new iterate */
26462675beeSAlp Dener 
26562675beeSAlp Dener PetscErrorCode TaoBNKComputeHessian(Tao tao)
26662675beeSAlp Dener {
26762675beeSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
26862675beeSAlp Dener 
26962675beeSAlp Dener   PetscFunctionBegin;
27062675beeSAlp Dener   /* Compute the Hessian */
271*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre));
27262675beeSAlp Dener   /* Add a correction to the BFGS preconditioner */
273b9ac7092SAlp Dener   if (bnk->M) {
274*9566063dSJacob Faibussowitsch     PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
27562675beeSAlp Dener   }
276e0ed867bSAlp Dener   /* Prepare the reduced sub-matrices for the inactive set */
277*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->Hpre_inactive));
278*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->H_inactive));
279f5766c09SAlp Dener   if (bnk->active_idx) {
280*9566063dSJacob Faibussowitsch     PetscCall(MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive));
281e0ed867bSAlp Dener     if (tao->hessian == tao->hessian_pre) {
282*9566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive));
283e0ed867bSAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
284e0ed867bSAlp Dener     } else {
285*9566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(tao->hessian_pre, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->Hpre_inactive));
286e0ed867bSAlp Dener     }
287e0ed867bSAlp Dener     if (bnk->bfgs_pre) {
288*9566063dSJacob Faibussowitsch       PetscCall(PCLMVMSetIS(bnk->bfgs_pre, bnk->inactive_idx));
289e0ed867bSAlp Dener     }
290e0ed867bSAlp Dener   } else {
291*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)tao->hessian));
292c5e9d94cSAlp Dener     bnk->H_inactive = tao->hessian;
293e0ed867bSAlp Dener     if (tao->hessian == tao->hessian_pre) {
294*9566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive));
295e0ed867bSAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
296e0ed867bSAlp Dener     } else {
297*9566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)tao->hessian_pre));
298c5e9d94cSAlp Dener       bnk->Hpre_inactive = tao->hessian_pre;
299e0ed867bSAlp Dener     }
300e0ed867bSAlp Dener     if (bnk->bfgs_pre) {
301*9566063dSJacob Faibussowitsch       PetscCall(PCLMVMClearIS(bnk->bfgs_pre));
302e0ed867bSAlp Dener     }
303e0ed867bSAlp Dener   }
30462675beeSAlp Dener   PetscFunctionReturn(0);
30562675beeSAlp Dener }
30662675beeSAlp Dener 
30762675beeSAlp Dener /*------------------------------------------------------------*/
30862675beeSAlp Dener 
3092f75a4aaSAlp Dener /* Routine for estimating the active set */
3102f75a4aaSAlp Dener 
31108752603SAlp Dener PetscErrorCode TaoBNKEstimateActiveSet(Tao tao, PetscInt asType)
3122f75a4aaSAlp Dener {
3132f75a4aaSAlp Dener   PetscErrorCode ierr;
3142f75a4aaSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
315c4b75bccSAlp Dener   PetscBool      hessComputed, diagExists;
3162f75a4aaSAlp Dener 
3172f75a4aaSAlp Dener   PetscFunctionBegin;
31808752603SAlp Dener   switch (asType) {
3192f75a4aaSAlp Dener   case BNK_AS_NONE:
320*9566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->inactive_idx));
321*9566063dSJacob Faibussowitsch     PetscCall(VecWhichInactive(tao->XL, tao->solution, bnk->unprojected_gradient, tao->XU, PETSC_TRUE, &bnk->inactive_idx));
322*9566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bnk->active_idx));
323*9566063dSJacob Faibussowitsch     PetscCall(ISComplementVec(bnk->inactive_idx, tao->solution, &bnk->active_idx));
3242f75a4aaSAlp Dener     break;
3252f75a4aaSAlp Dener 
3262f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
3272f75a4aaSAlp Dener     /* Compute the trial step vector with which we will estimate the active set at the next iteration */
328b9ac7092SAlp Dener     if (bnk->M) {
3292f75a4aaSAlp Dener       /* If the BFGS preconditioner matrix is available, we will construct a trial step with it */
330*9566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, bnk->W));
3312f75a4aaSAlp Dener     } else {
332fc5ca067SStefano Zampini       hessComputed = diagExists = PETSC_FALSE;
333f5766c09SAlp Dener       if (tao->hessian) {
334*9566063dSJacob Faibussowitsch         PetscCall(MatAssembled(tao->hessian, &hessComputed));
335f5766c09SAlp Dener       }
336fc5ca067SStefano Zampini       if (hessComputed) {
337*9566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &diagExists));
338fc5ca067SStefano Zampini       }
339fc5ca067SStefano Zampini       if (diagExists) {
3409b6ef848SAlp Dener         /* BFGS preconditioner doesn't exist so let's invert the absolute diagonal of the Hessian instead onto the gradient */
341*9566063dSJacob Faibussowitsch         PetscCall(MatGetDiagonal(tao->hessian, bnk->Xwork));
342*9566063dSJacob Faibussowitsch         PetscCall(VecAbs(bnk->Xwork));
343*9566063dSJacob Faibussowitsch         PetscCall(VecMedian(bnk->Diag_min, bnk->Xwork, bnk->Diag_max, bnk->Xwork));
344*9566063dSJacob Faibussowitsch         PetscCall(VecReciprocal(bnk->Xwork));
345*9566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMult(bnk->W, bnk->Xwork, bnk->unprojected_gradient));
34661be54a6SAlp Dener       } else {
347c4b75bccSAlp Dener         /* If the Hessian or its diagonal does not exist, we will simply use gradient step */
348*9566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, bnk->W));
34961be54a6SAlp Dener       }
3502f75a4aaSAlp Dener     }
351*9566063dSJacob Faibussowitsch     PetscCall(VecScale(bnk->W, -1.0));
35289da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, bnk->unprojected_gradient, bnk->W, bnk->Xwork, bnk->as_step, &bnk->as_tol,
353*9566063dSJacob Faibussowitsch                                    &bnk->active_lower, &bnk->active_upper, &bnk->active_fixed, &bnk->active_idx, &bnk->inactive_idx);PetscCall(ierr);
354c4b75bccSAlp Dener     break;
3552f75a4aaSAlp Dener 
3562f75a4aaSAlp Dener   default:
3572f75a4aaSAlp Dener     break;
3582f75a4aaSAlp Dener   }
3592f75a4aaSAlp Dener   PetscFunctionReturn(0);
3602f75a4aaSAlp Dener }
3612f75a4aaSAlp Dener 
3622f75a4aaSAlp Dener /*------------------------------------------------------------*/
3632f75a4aaSAlp Dener 
3642f75a4aaSAlp Dener /* Routine for bounding the step direction */
3652f75a4aaSAlp Dener 
366a1318120SAlp Dener PetscErrorCode TaoBNKBoundStep(Tao tao, PetscInt asType, Vec step)
3672f75a4aaSAlp Dener {
3682f75a4aaSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
3692f75a4aaSAlp Dener 
3702f75a4aaSAlp Dener   PetscFunctionBegin;
371a1318120SAlp Dener   switch (asType) {
3722f75a4aaSAlp Dener   case BNK_AS_NONE:
373*9566063dSJacob Faibussowitsch     PetscCall(VecISSet(step, bnk->active_idx, 0.0));
3742f75a4aaSAlp Dener     break;
3752f75a4aaSAlp Dener 
3762f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
377*9566063dSJacob Faibussowitsch     PetscCall(TaoBoundStep(tao->solution, tao->XL, tao->XU, bnk->active_lower, bnk->active_upper, bnk->active_fixed, 1.0, step));
3782f75a4aaSAlp Dener     break;
3792f75a4aaSAlp Dener 
3802f75a4aaSAlp Dener   default:
3812f75a4aaSAlp Dener     break;
3822f75a4aaSAlp Dener   }
3832f75a4aaSAlp Dener   PetscFunctionReturn(0);
3842f75a4aaSAlp Dener }
3852f75a4aaSAlp Dener 
386e031d6f5SAlp Dener /*------------------------------------------------------------*/
387e031d6f5SAlp Dener 
388e031d6f5SAlp Dener /* Routine for taking a finite number of BNCG iterations to
389e031d6f5SAlp Dener    accelerate Newton convergence.
390e031d6f5SAlp Dener 
391e031d6f5SAlp Dener    In practice, this approach simply trades off Hessian evaluations
392e031d6f5SAlp Dener    for more gradient evaluations.
393e031d6f5SAlp Dener */
394e031d6f5SAlp Dener 
395c0f10754SAlp Dener PetscErrorCode TaoBNKTakeCGSteps(Tao tao, PetscBool *terminate)
396c0f10754SAlp Dener {
397c0f10754SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
398c0f10754SAlp Dener 
399c0f10754SAlp Dener   PetscFunctionBegin;
400c0f10754SAlp Dener   *terminate = PETSC_FALSE;
401c0f10754SAlp Dener   if (bnk->max_cg_its > 0) {
402c4b75bccSAlp Dener     /* Copy the current function value (important vectors are already shared) */
403c0f10754SAlp Dener     bnk->bncg_ctx->f = bnk->f;
404c0f10754SAlp Dener     /* Take some small finite number of BNCG iterations */
405*9566063dSJacob Faibussowitsch     PetscCall(TaoSolve(bnk->bncg));
406c0f10754SAlp Dener     /* Add the number of gradient and function evaluations to the total */
407c0f10754SAlp Dener     tao->nfuncs += bnk->bncg->nfuncs;
408c0f10754SAlp Dener     tao->nfuncgrads += bnk->bncg->nfuncgrads;
409c0f10754SAlp Dener     tao->ngrads += bnk->bncg->ngrads;
410c0f10754SAlp Dener     tao->nhess += bnk->bncg->nhess;
411e031d6f5SAlp Dener     bnk->tot_cg_its += bnk->bncg->niter;
412c4b75bccSAlp Dener     /* Extract the BNCG function value out and save it into BNK */
413c0f10754SAlp Dener     bnk->f = bnk->bncg_ctx->f;
414c0f10754SAlp 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) {
415c0f10754SAlp Dener       *terminate = PETSC_TRUE;
41661be54a6SAlp Dener     } else {
417*9566063dSJacob Faibussowitsch       PetscCall(TaoBNKEstimateActiveSet(tao, bnk->as_type));
418c0f10754SAlp Dener     }
419c0f10754SAlp Dener   }
420c0f10754SAlp Dener   PetscFunctionReturn(0);
421c0f10754SAlp Dener }
422c0f10754SAlp Dener 
4232f75a4aaSAlp Dener /*------------------------------------------------------------*/
4242f75a4aaSAlp Dener 
425c0f10754SAlp Dener /* Routine for computing the Newton step. */
426df278d8fSAlp Dener 
4276b591159SAlp Dener PetscErrorCode TaoBNKComputeStep(Tao tao, PetscBool shift, KSPConvergedReason *ksp_reason, PetscInt *step_type)
428eb910715SAlp Dener {
429eb910715SAlp Dener   TAO_BNK           *bnk = (TAO_BNK *)tao->data;
430eb910715SAlp Dener   PetscInt          bfgsUpdates = 0;
431eb910715SAlp Dener   PetscInt          kspits;
432bddd1ffdSAlp Dener   PetscBool         is_lmvm;
4332e6e4ca1SStefano Zampini   PetscVoidFunction kspTR;
434eb910715SAlp Dener 
435eb910715SAlp Dener   PetscFunctionBegin;
43689da521bSAlp Dener   /* If there are no inactive variables left, save some computation and return an adjusted zero step
43789da521bSAlp Dener      that has (l-x) and (u-x) for lower and upper bounded variables. */
43889da521bSAlp Dener   if (!bnk->inactive_idx) {
439*9566063dSJacob Faibussowitsch     PetscCall(VecSet(tao->stepdirection, 0.0));
440*9566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
44189da521bSAlp Dener     PetscFunctionReturn(0);
44289da521bSAlp Dener   }
44389da521bSAlp Dener 
44462675beeSAlp Dener   /* Shift the reduced Hessian matrix */
445e831869dSStefano Zampini   if (shift && bnk->pert > 0) {
446*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)tao->hessian, MATLMVM, &is_lmvm));
447f7bf01afSAlp Dener     if (is_lmvm) {
448*9566063dSJacob Faibussowitsch       PetscCall(MatShift(tao->hessian, bnk->pert));
449f7bf01afSAlp Dener     } else {
450*9566063dSJacob Faibussowitsch       PetscCall(MatShift(bnk->H_inactive, bnk->pert));
45162675beeSAlp Dener       if (bnk->H_inactive != bnk->Hpre_inactive) {
452*9566063dSJacob Faibussowitsch         PetscCall(MatShift(bnk->Hpre_inactive, bnk->pert));
45362675beeSAlp Dener       }
45462675beeSAlp Dener     }
455f7bf01afSAlp Dener   }
45662675beeSAlp Dener 
457eb910715SAlp Dener   /* Solve the Newton system of equations */
458937a31a1SAlp Dener   tao->ksp_its = 0;
459*9566063dSJacob Faibussowitsch   PetscCall(VecSet(tao->stepdirection, 0.0));
460*9566063dSJacob Faibussowitsch   PetscCall(KSPReset(tao->ksp));
461*9566063dSJacob Faibussowitsch   PetscCall(KSPResetFromOptions(tao->ksp));
462*9566063dSJacob Faibussowitsch   PetscCall(KSPSetOperators(tao->ksp,bnk->H_inactive,bnk->Hpre_inactive));
463*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(bnk->unprojected_gradient, bnk->Gwork));
46489da521bSAlp Dener   if (bnk->active_idx) {
465*9566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
466*9566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
4675e9b73cbSAlp Dener   } else {
4685e9b73cbSAlp Dener     bnk->G_inactive = bnk->unprojected_gradient;
4695e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
47028017e9fSAlp Dener   }
471*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectQueryFunction((PetscObject)tao->ksp,"KSPCGSetRadius_C",&kspTR));
4722e6e4ca1SStefano Zampini   if (kspTR) {
473*9566063dSJacob Faibussowitsch     PetscCall(KSPCGSetRadius(tao->ksp,tao->trust));
474*9566063dSJacob Faibussowitsch     PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
475*9566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(tao->ksp,&kspits));
476eb910715SAlp Dener     tao->ksp_its += kspits;
477eb910715SAlp Dener     tao->ksp_tot_its += kspits;
478*9566063dSJacob Faibussowitsch     PetscCall(KSPCGGetNormD(tao->ksp,&bnk->dnorm));
479eb910715SAlp Dener 
480eb910715SAlp Dener     if (0.0 == tao->trust) {
481eb910715SAlp Dener       /* Radius was uninitialized; use the norm of the direction */
482080d2917SAlp Dener       if (bnk->dnorm > 0.0) {
483080d2917SAlp Dener         tao->trust = bnk->dnorm;
484eb910715SAlp Dener 
485eb910715SAlp Dener         /* Modify the radius if it is too large or small */
486eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
487eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
488eb910715SAlp Dener       } else {
489eb910715SAlp Dener         /* The direction was bad; set radius to default value and re-solve
490eb910715SAlp Dener            the trust-region subproblem to get a direction */
491eb910715SAlp Dener         tao->trust = tao->trust0;
492eb910715SAlp Dener 
493eb910715SAlp Dener         /* Modify the radius if it is too large or small */
494eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
495eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
496eb910715SAlp Dener 
497*9566063dSJacob Faibussowitsch         PetscCall(KSPCGSetRadius(tao->ksp,tao->trust));
498*9566063dSJacob Faibussowitsch         PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
499*9566063dSJacob Faibussowitsch         PetscCall(KSPGetIterationNumber(tao->ksp,&kspits));
500eb910715SAlp Dener         tao->ksp_its += kspits;
501eb910715SAlp Dener         tao->ksp_tot_its += kspits;
502*9566063dSJacob Faibussowitsch         PetscCall(KSPCGGetNormD(tao->ksp,&bnk->dnorm));
503eb910715SAlp Dener 
5043c859ba3SBarry Smith         PetscCheck(bnk->dnorm != 0.0,PetscObjectComm((PetscObject)tao),PETSC_ERR_PLIB, "Initial direction zero");
505eb910715SAlp Dener       }
506eb910715SAlp Dener     }
507eb910715SAlp Dener   } else {
508*9566063dSJacob Faibussowitsch     PetscCall(KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive));
509*9566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(tao->ksp, &kspits));
510eb910715SAlp Dener     tao->ksp_its += kspits;
511eb910715SAlp Dener     tao->ksp_tot_its += kspits;
512eb910715SAlp Dener   }
5135e9b73cbSAlp Dener   /* Restore sub vectors back */
51489da521bSAlp Dener   if (bnk->active_idx) {
515*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
516*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
5175e9b73cbSAlp Dener   }
518770b7498SAlp Dener   /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
519*9566063dSJacob Faibussowitsch   PetscCall(VecScale(tao->stepdirection, -1.0));
520*9566063dSJacob Faibussowitsch   PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
521770b7498SAlp Dener 
522770b7498SAlp Dener   /* Record convergence reasons */
523*9566063dSJacob Faibussowitsch   PetscCall(KSPGetConvergedReason(tao->ksp, ksp_reason));
524e465cd6fSAlp Dener   if (KSP_CONVERGED_ATOL == *ksp_reason) {
525770b7498SAlp Dener     ++bnk->ksp_atol;
526e465cd6fSAlp Dener   } else if (KSP_CONVERGED_RTOL == *ksp_reason) {
527770b7498SAlp Dener     ++bnk->ksp_rtol;
528e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_CONSTRAINED == *ksp_reason) {
529770b7498SAlp Dener     ++bnk->ksp_ctol;
530e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_NEG_CURVE == *ksp_reason) {
531770b7498SAlp Dener     ++bnk->ksp_negc;
532e465cd6fSAlp Dener   } else if (KSP_DIVERGED_DTOL == *ksp_reason) {
533770b7498SAlp Dener     ++bnk->ksp_dtol;
534e465cd6fSAlp Dener   } else if (KSP_DIVERGED_ITS == *ksp_reason) {
535770b7498SAlp Dener     ++bnk->ksp_iter;
536770b7498SAlp Dener   } else {
537770b7498SAlp Dener     ++bnk->ksp_othr;
538770b7498SAlp Dener   }
539fed79b8eSAlp Dener 
540fed79b8eSAlp Dener   /* Make sure the BFGS preconditioner is healthy */
541b9ac7092SAlp Dener   if (bnk->M) {
542*9566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
543b2d8c577SAlp Dener     if ((KSP_DIVERGED_INDEFINITE_PC == *ksp_reason) && (bfgsUpdates > 0)) {
544fed79b8eSAlp Dener       /* Preconditioner is numerically indefinite; reset the approximation. */
545*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
546*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
547eb910715SAlp Dener     }
548fed79b8eSAlp Dener   }
5496b591159SAlp Dener   *step_type = BNK_NEWTON;
550e465cd6fSAlp Dener   PetscFunctionReturn(0);
551e465cd6fSAlp Dener }
552eb910715SAlp Dener 
55362675beeSAlp Dener /*------------------------------------------------------------*/
55462675beeSAlp Dener 
5555e9b73cbSAlp Dener /* Routine for recomputing the predicted reduction for a given step vector */
5565e9b73cbSAlp Dener 
5575e9b73cbSAlp Dener PetscErrorCode TaoBNKRecomputePred(Tao tao, Vec S, PetscReal *prered)
5585e9b73cbSAlp Dener {
5595e9b73cbSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
5605e9b73cbSAlp Dener 
5615e9b73cbSAlp Dener   PetscFunctionBegin;
5625e9b73cbSAlp Dener   /* Extract subvectors associated with the inactive set */
56389da521bSAlp Dener   if (bnk->active_idx) {
564*9566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
565*9566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
566*9566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5675e9b73cbSAlp Dener   } else {
5685e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
5695e9b73cbSAlp Dener     bnk->inactive_work = bnk->Xwork;
5705e9b73cbSAlp Dener     bnk->G_inactive = bnk->Gwork;
5715e9b73cbSAlp Dener   }
5725e9b73cbSAlp Dener   /* Recompute the predicted decrease based on the quadratic model */
573*9566063dSJacob Faibussowitsch   PetscCall(MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work));
574*9566063dSJacob Faibussowitsch   PetscCall(VecAYPX(bnk->inactive_work, -0.5, bnk->G_inactive));
575*9566063dSJacob Faibussowitsch   PetscCall(VecDot(bnk->inactive_work, bnk->X_inactive, prered));
5765e9b73cbSAlp Dener   /* Restore the sub vectors */
57789da521bSAlp Dener   if (bnk->active_idx) {
578*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive));
579*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work));
580*9566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive));
5815e9b73cbSAlp Dener   }
5825e9b73cbSAlp Dener   PetscFunctionReturn(0);
5835e9b73cbSAlp Dener }
5845e9b73cbSAlp Dener 
5855e9b73cbSAlp Dener /*------------------------------------------------------------*/
5865e9b73cbSAlp Dener 
58762675beeSAlp Dener /* Routine for ensuring that the Newton step is a descent direction.
58862675beeSAlp Dener 
58962675beeSAlp Dener    The step direction falls back onto BFGS, scaled gradient and gradient steps
59062675beeSAlp Dener    in the event that the Newton step fails the test.
59162675beeSAlp Dener */
59262675beeSAlp Dener 
593e465cd6fSAlp Dener PetscErrorCode TaoBNKSafeguardStep(Tao tao, KSPConvergedReason ksp_reason, PetscInt *stepType)
594e465cd6fSAlp Dener {
595e465cd6fSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
596b2d8c577SAlp Dener   PetscReal      gdx, e_min;
597e465cd6fSAlp Dener   PetscInt       bfgsUpdates;
598e465cd6fSAlp Dener 
599e465cd6fSAlp Dener   PetscFunctionBegin;
6006b591159SAlp Dener   switch (*stepType) {
6016b591159SAlp Dener   case BNK_NEWTON:
602*9566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
603eb910715SAlp Dener     if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
604eb910715SAlp Dener       /* Newton step is not descent or direction produced Inf or NaN
605eb910715SAlp Dener         Update the perturbation for next time */
606eb910715SAlp Dener       if (bnk->pert <= 0.0) {
6072e6e4ca1SStefano Zampini         PetscBool is_gltr;
6082e6e4ca1SStefano Zampini 
609eb910715SAlp Dener         /* Initialize the perturbation */
610eb910715SAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
611*9566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp),KSPGLTR,&is_gltr));
6122e6e4ca1SStefano Zampini         if (is_gltr) {
613*9566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp,&e_min));
614eb910715SAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
615eb910715SAlp Dener         }
616eb910715SAlp Dener       } else {
617eb910715SAlp Dener         /* Increase the perturbation */
618eb910715SAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
619eb910715SAlp Dener       }
620eb910715SAlp Dener 
6210ad3a497SAlp Dener       if (!bnk->M) {
622eb910715SAlp Dener         /* We don't have the bfgs matrix around and updated
623eb910715SAlp Dener           Must use gradient direction in this case */
624*9566063dSJacob Faibussowitsch         PetscCall(VecCopy(tao->gradient, tao->stepdirection));
625eb910715SAlp Dener         *stepType = BNK_GRADIENT;
626eb910715SAlp Dener       } else {
627eb910715SAlp Dener         /* Attempt to use the BFGS direction */
628*9566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
629eb910715SAlp Dener 
6308d5ead36SAlp Dener         /* Check for success (descent direction)
6318d5ead36SAlp Dener           NOTE: Negative gdx here means not a descent direction because
6328d5ead36SAlp Dener           the fall-back step is missing a negative sign. */
633*9566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
6343105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
635eb910715SAlp Dener           /* BFGS direction is not descent or direction produced not a number
636eb910715SAlp Dener             We can assert bfgsUpdates > 1 in this case because
637eb910715SAlp Dener             the first solve produces the scaled gradient direction,
638eb910715SAlp Dener             which is guaranteed to be descent */
639eb910715SAlp Dener 
640eb910715SAlp Dener           /* Use steepest descent direction (scaled) */
641*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
642*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
643*9566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
644eb910715SAlp Dener 
645eb910715SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
646eb910715SAlp Dener         } else {
647*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
648eb910715SAlp Dener           if (1 == bfgsUpdates) {
649eb910715SAlp Dener             /* The first BFGS direction is always the scaled gradient */
650eb910715SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
651eb910715SAlp Dener           } else {
652eb910715SAlp Dener             *stepType = BNK_BFGS;
653eb910715SAlp Dener           }
654eb910715SAlp Dener         }
655eb910715SAlp Dener       }
6568d5ead36SAlp Dener       /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
657*9566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection, -1.0));
658*9566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
659eb910715SAlp Dener     } else {
660eb910715SAlp Dener       /* Computed Newton step is descent */
661eb910715SAlp Dener       switch (ksp_reason) {
662eb910715SAlp Dener       case KSP_DIVERGED_NANORINF:
663eb910715SAlp Dener       case KSP_DIVERGED_BREAKDOWN:
664eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_MAT:
665eb910715SAlp Dener       case KSP_DIVERGED_INDEFINITE_PC:
666eb910715SAlp Dener       case KSP_CONVERGED_CG_NEG_CURVE:
667eb910715SAlp Dener         /* Matrix or preconditioner is indefinite; increase perturbation */
668eb910715SAlp Dener         if (bnk->pert <= 0.0) {
6692e6e4ca1SStefano Zampini           PetscBool is_gltr;
6702e6e4ca1SStefano Zampini 
671eb910715SAlp Dener           /* Initialize the perturbation */
672eb910715SAlp Dener           bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
673*9566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp),KSPGLTR,&is_gltr));
6742e6e4ca1SStefano Zampini           if (is_gltr) {
675*9566063dSJacob Faibussowitsch             PetscCall(KSPGLTRGetMinEig(tao->ksp, &e_min));
676eb910715SAlp Dener             bnk->pert = PetscMax(bnk->pert, -e_min);
677eb910715SAlp Dener           }
678eb910715SAlp Dener         } else {
679eb910715SAlp Dener           /* Increase the perturbation */
680eb910715SAlp Dener           bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
681eb910715SAlp Dener         }
682eb910715SAlp Dener         break;
683eb910715SAlp Dener 
684eb910715SAlp Dener       default:
685eb910715SAlp Dener         /* Newton step computation is good; decrease perturbation */
686eb910715SAlp Dener         bnk->pert = PetscMin(bnk->psfac * bnk->pert, bnk->pmsfac * bnk->gnorm);
687eb910715SAlp Dener         if (bnk->pert < bnk->pmin) {
688eb910715SAlp Dener           bnk->pert = 0.0;
689eb910715SAlp Dener         }
690eb910715SAlp Dener         break;
691eb910715SAlp Dener       }
692fed79b8eSAlp Dener       *stepType = BNK_NEWTON;
693eb910715SAlp Dener     }
6946b591159SAlp Dener     break;
6956b591159SAlp Dener 
6966b591159SAlp Dener   case BNK_BFGS:
6976b591159SAlp Dener     /* Check for success (descent direction) */
698*9566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->stepdirection, tao->gradient, &gdx));
6996b591159SAlp Dener     if (gdx >= 0 || PetscIsInfOrNanReal(gdx)) {
7006b591159SAlp Dener       /* Step is not descent or solve was not successful
7016b591159SAlp Dener          Use steepest descent direction (scaled) */
702*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
703*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
704*9566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, tao->gradient, tao->stepdirection));
705*9566063dSJacob Faibussowitsch       PetscCall(VecScale(tao->stepdirection,-1.0));
706*9566063dSJacob Faibussowitsch       PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
7076b591159SAlp Dener       *stepType = BNK_SCALED_GRADIENT;
7086b591159SAlp Dener     } else {
7096b591159SAlp Dener       *stepType = BNK_BFGS;
7106b591159SAlp Dener     }
7116b591159SAlp Dener     break;
7126b591159SAlp Dener 
7136b591159SAlp Dener   case BNK_SCALED_GRADIENT:
7146b591159SAlp Dener     break;
7156b591159SAlp Dener 
7166b591159SAlp Dener   default:
7176b591159SAlp Dener     break;
7186b591159SAlp Dener   }
7196b591159SAlp Dener 
720eb910715SAlp Dener   PetscFunctionReturn(0);
721eb910715SAlp Dener }
722eb910715SAlp Dener 
723df278d8fSAlp Dener /*------------------------------------------------------------*/
724df278d8fSAlp Dener 
725df278d8fSAlp Dener /* Routine for performing a bound-projected More-Thuente line search.
726df278d8fSAlp Dener 
727df278d8fSAlp Dener   Includes fallbacks to BFGS, scaled gradient, and unscaled gradient steps if the
728df278d8fSAlp Dener   Newton step does not produce a valid step length.
729df278d8fSAlp Dener */
730df278d8fSAlp Dener 
731937a31a1SAlp Dener PetscErrorCode TaoBNKPerformLineSearch(Tao tao, PetscInt *stepType, PetscReal *steplen, TaoLineSearchConvergedReason *reason)
732c14b763aSAlp Dener {
733c14b763aSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
734c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
735b2d8c577SAlp Dener   PetscReal                    e_min, gdx;
736c14b763aSAlp Dener   PetscInt                     bfgsUpdates;
737c14b763aSAlp Dener 
738c14b763aSAlp Dener   PetscFunctionBegin;
739c14b763aSAlp Dener   /* Perform the linesearch */
740*9566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
741*9566063dSJacob Faibussowitsch   PetscCall(TaoAddLineSearchCounts(tao));
742c14b763aSAlp Dener 
743b2d8c577SAlp Dener   while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && *stepType != BNK_SCALED_GRADIENT && *stepType != BNK_GRADIENT) {
744c14b763aSAlp Dener     /* Linesearch failed, revert solution */
745c14b763aSAlp Dener     bnk->f = bnk->fold;
746*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->Xold, tao->solution));
747*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient));
748c14b763aSAlp Dener 
749937a31a1SAlp Dener     switch(*stepType) {
750c14b763aSAlp Dener     case BNK_NEWTON:
7518d5ead36SAlp Dener       /* Failed to obtain acceptable iterate with Newton step
752c14b763aSAlp Dener          Update the perturbation for next time */
753c14b763aSAlp Dener       if (bnk->pert <= 0.0) {
7542e6e4ca1SStefano Zampini         PetscBool is_gltr;
7552e6e4ca1SStefano Zampini 
756c14b763aSAlp Dener         /* Initialize the perturbation */
757c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
758*9566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)(tao->ksp),KSPGLTR,&is_gltr));
7592e6e4ca1SStefano Zampini         if (is_gltr) {
760*9566063dSJacob Faibussowitsch           PetscCall(KSPGLTRGetMinEig(tao->ksp,&e_min));
761c14b763aSAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
762c14b763aSAlp Dener         }
763c14b763aSAlp Dener       } else {
764c14b763aSAlp Dener         /* Increase the perturbation */
765c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
766c14b763aSAlp Dener       }
767c14b763aSAlp Dener 
7680ad3a497SAlp Dener       if (!bnk->M) {
769c14b763aSAlp Dener         /* We don't have the bfgs matrix around and being updated
770c14b763aSAlp Dener            Must use gradient direction in this case */
771*9566063dSJacob Faibussowitsch         PetscCall(VecCopy(bnk->unprojected_gradient, tao->stepdirection));
772937a31a1SAlp Dener         *stepType = BNK_GRADIENT;
773c14b763aSAlp Dener       } else {
774c14b763aSAlp Dener         /* Attempt to use the BFGS direction */
775*9566063dSJacob Faibussowitsch         PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
7768d5ead36SAlp Dener         /* Check for success (descent direction)
7778d5ead36SAlp Dener            NOTE: Negative gdx means not a descent direction because the step here is missing a negative sign. */
778*9566063dSJacob Faibussowitsch         PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
7793105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
780c14b763aSAlp Dener           /* BFGS direction is not descent or direction produced not a number
781c14b763aSAlp Dener              We can assert bfgsUpdates > 1 in this case
782c14b763aSAlp Dener              Use steepest descent direction (scaled) */
783*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
784*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
785*9566063dSJacob Faibussowitsch           PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
786c14b763aSAlp Dener 
787c14b763aSAlp Dener           bfgsUpdates = 1;
788937a31a1SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
789c14b763aSAlp Dener         } else {
790*9566063dSJacob Faibussowitsch           PetscCall(MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates));
791c14b763aSAlp Dener           if (1 == bfgsUpdates) {
792c14b763aSAlp Dener             /* The first BFGS direction is always the scaled gradient */
793937a31a1SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
794c14b763aSAlp Dener           } else {
795937a31a1SAlp Dener             *stepType = BNK_BFGS;
796c14b763aSAlp Dener           }
797c14b763aSAlp Dener         }
798c14b763aSAlp Dener       }
799c14b763aSAlp Dener       break;
800c14b763aSAlp Dener 
801c14b763aSAlp Dener     case BNK_BFGS:
802c14b763aSAlp Dener       /* Can only enter if pc_type == BNK_PC_BFGS
803c14b763aSAlp Dener          Failed to obtain acceptable iterate with BFGS step
804c14b763aSAlp Dener          Attempt to use the scaled gradient direction */
805*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(bnk->M, PETSC_FALSE));
806*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient));
807*9566063dSJacob Faibussowitsch       PetscCall(MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection));
808c14b763aSAlp Dener 
809c14b763aSAlp Dener       bfgsUpdates = 1;
810937a31a1SAlp Dener       *stepType = BNK_SCALED_GRADIENT;
811c14b763aSAlp Dener       break;
812c14b763aSAlp Dener     }
8138d5ead36SAlp Dener     /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
814*9566063dSJacob Faibussowitsch     PetscCall(VecScale(tao->stepdirection, -1.0));
815*9566063dSJacob Faibussowitsch     PetscCall(TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection));
816c14b763aSAlp Dener 
8178d5ead36SAlp Dener     /* Perform one last line search with the fall-back step */
818*9566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason));
819*9566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
820c14b763aSAlp Dener   }
821c14b763aSAlp Dener   *reason = ls_reason;
822c14b763aSAlp Dener   PetscFunctionReturn(0);
823c14b763aSAlp Dener }
824c14b763aSAlp Dener 
825df278d8fSAlp Dener /*------------------------------------------------------------*/
826df278d8fSAlp Dener 
827df278d8fSAlp Dener /* Routine for updating the trust radius.
828df278d8fSAlp Dener 
829df278d8fSAlp Dener   Function features three different update methods:
830df278d8fSAlp Dener   1) Line-search step length based
831df278d8fSAlp Dener   2) Predicted decrease on the CG quadratic model
832df278d8fSAlp Dener   3) Interpolation
833df278d8fSAlp Dener */
834df278d8fSAlp Dener 
83528017e9fSAlp Dener PetscErrorCode TaoBNKUpdateTrustRadius(Tao tao, PetscReal prered, PetscReal actred, PetscInt updateType, PetscInt stepType, PetscBool *accept)
836080d2917SAlp Dener {
837080d2917SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
838080d2917SAlp Dener 
839b1c2d0e3SAlp Dener   PetscReal      step, kappa;
840080d2917SAlp Dener   PetscReal      gdx, tau_1, tau_2, tau_min, tau_max;
841080d2917SAlp Dener 
842080d2917SAlp Dener   PetscFunctionBegin;
843080d2917SAlp Dener   /* Update trust region radius */
844080d2917SAlp Dener   *accept = PETSC_FALSE;
84528017e9fSAlp Dener   switch(updateType) {
846080d2917SAlp Dener   case BNK_UPDATE_STEP:
847c14b763aSAlp Dener     *accept = PETSC_TRUE; /* always accept here because line search succeeded */
848080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
849*9566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchGetStepLength(tao->linesearch, &step));
850080d2917SAlp Dener       if (step < bnk->nu1) {
851080d2917SAlp Dener         /* Very bad step taken; reduce radius */
852080d2917SAlp Dener         tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
853080d2917SAlp Dener       } else if (step < bnk->nu2) {
854080d2917SAlp Dener         /* Reasonably bad step taken; reduce radius */
855080d2917SAlp Dener         tao->trust = bnk->omega2 * PetscMin(bnk->dnorm, tao->trust);
856080d2917SAlp Dener       } else if (step < bnk->nu3) {
857080d2917SAlp Dener         /*  Reasonable step was taken; leave radius alone */
858080d2917SAlp Dener         if (bnk->omega3 < 1.0) {
859080d2917SAlp Dener           tao->trust = bnk->omega3 * PetscMin(bnk->dnorm, tao->trust);
860080d2917SAlp Dener         } else if (bnk->omega3 > 1.0) {
861080d2917SAlp Dener           tao->trust = PetscMax(bnk->omega3 * bnk->dnorm, tao->trust);
862080d2917SAlp Dener         }
863080d2917SAlp Dener       } else if (step < bnk->nu4) {
864080d2917SAlp Dener         /*  Full step taken; increase the radius */
865080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega4 * bnk->dnorm, tao->trust);
866080d2917SAlp Dener       } else {
867080d2917SAlp Dener         /*  More than full step taken; increase the radius */
868080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega5 * bnk->dnorm, tao->trust);
869080d2917SAlp Dener       }
870080d2917SAlp Dener     } else {
871080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
872080d2917SAlp Dener       tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
873080d2917SAlp Dener     }
874080d2917SAlp Dener     break;
875080d2917SAlp Dener 
876080d2917SAlp Dener   case BNK_UPDATE_REDUCTION:
877080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
878e0ed867bSAlp Dener       if ((prered < 0.0) || PetscIsInfOrNanReal(prered)) {
879fed79b8eSAlp Dener         /* The predicted reduction has the wrong sign.  This cannot
880fed79b8eSAlp Dener            happen in infinite precision arithmetic.  Step should
881fed79b8eSAlp Dener            be rejected! */
882080d2917SAlp Dener         tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8833105154fSTodd Munson       } else {
884b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
885080d2917SAlp Dener           tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
886080d2917SAlp Dener         } else {
8873105154fSTodd Munson           if ((PetscAbsScalar(actred) <= PetscMax(1.0, PetscAbsScalar(bnk->f))*bnk->epsilon) && (PetscAbsScalar(prered) <= PetscMax(1.0, PetscAbsScalar(bnk->f))*bnk->epsilon)) {
888080d2917SAlp Dener             kappa = 1.0;
8893105154fSTodd Munson           } else {
890080d2917SAlp Dener             kappa = actred / prered;
891080d2917SAlp Dener           }
892fed79b8eSAlp Dener           /* Accept or reject the step and update radius */
893080d2917SAlp Dener           if (kappa < bnk->eta1) {
894fed79b8eSAlp Dener             /* Reject the step */
895080d2917SAlp Dener             tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
8963105154fSTodd Munson           } else {
897fed79b8eSAlp Dener             /* Accept the step */
898c133c014SAlp Dener             *accept = PETSC_TRUE;
899c133c014SAlp Dener             /* Update the trust region radius only if the computed step is at the trust radius boundary */
9008d5ead36SAlp Dener             if (bnk->dnorm == tao->trust) {
901080d2917SAlp Dener               if (kappa < bnk->eta2) {
902080d2917SAlp Dener                 /* Marginal bad step */
903c133c014SAlp Dener                 tao->trust = bnk->alpha2 * tao->trust;
9043105154fSTodd Munson               } else if (kappa < bnk->eta3) {
905fed79b8eSAlp Dener                 /* Reasonable step */
906fed79b8eSAlp Dener                 tao->trust = bnk->alpha3 * tao->trust;
9073105154fSTodd Munson               } else if (kappa < bnk->eta4) {
908080d2917SAlp Dener                 /* Good step */
909c133c014SAlp Dener                 tao->trust = bnk->alpha4 * tao->trust;
9103105154fSTodd Munson               } else {
911080d2917SAlp Dener                 /* Very good step */
912c133c014SAlp Dener                 tao->trust = bnk->alpha5 * tao->trust;
913080d2917SAlp Dener               }
914c133c014SAlp Dener             }
915080d2917SAlp Dener           }
916080d2917SAlp Dener         }
917080d2917SAlp Dener       }
918080d2917SAlp Dener     } else {
919080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
920080d2917SAlp Dener       tao->trust = bnk->alpha1 * PetscMin(bnk->dnorm, tao->trust);
921080d2917SAlp Dener     }
922080d2917SAlp Dener     break;
923080d2917SAlp Dener 
924080d2917SAlp Dener   default:
925080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
926b1c2d0e3SAlp Dener       if (prered < 0.0) {
927080d2917SAlp Dener         /*  The predicted reduction has the wrong sign.  This cannot */
928080d2917SAlp Dener         /*  happen in infinite precision arithmetic.  Step should */
929080d2917SAlp Dener         /*  be rejected! */
930080d2917SAlp Dener         tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
931080d2917SAlp Dener       } else {
932b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
933080d2917SAlp Dener           tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
934080d2917SAlp Dener         } else {
935080d2917SAlp Dener           if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
936080d2917SAlp Dener             kappa = 1.0;
937080d2917SAlp Dener           } else {
938080d2917SAlp Dener             kappa = actred / prered;
939080d2917SAlp Dener           }
940080d2917SAlp Dener 
941*9566063dSJacob Faibussowitsch           PetscCall(VecDot(tao->gradient, tao->stepdirection, &gdx));
942080d2917SAlp Dener           tau_1 = bnk->theta * gdx / (bnk->theta * gdx - (1.0 - bnk->theta) * prered + actred);
943080d2917SAlp Dener           tau_2 = bnk->theta * gdx / (bnk->theta * gdx + (1.0 + bnk->theta) * prered - actred);
944080d2917SAlp Dener           tau_min = PetscMin(tau_1, tau_2);
945080d2917SAlp Dener           tau_max = PetscMax(tau_1, tau_2);
946080d2917SAlp Dener 
947080d2917SAlp Dener           if (kappa >= 1.0 - bnk->mu1) {
948080d2917SAlp Dener             /*  Great agreement */
949080d2917SAlp Dener             *accept = PETSC_TRUE;
950080d2917SAlp Dener             if (tau_max < 1.0) {
951080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
952080d2917SAlp Dener             } else if (tau_max > bnk->gamma4) {
953080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma4 * bnk->dnorm);
954080d2917SAlp Dener             } else {
955080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
956080d2917SAlp Dener             }
957080d2917SAlp Dener           } else if (kappa >= 1.0 - bnk->mu2) {
958080d2917SAlp Dener             /*  Good agreement */
959080d2917SAlp Dener             *accept = PETSC_TRUE;
960080d2917SAlp Dener             if (tau_max < bnk->gamma2) {
961080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
962080d2917SAlp Dener             } else if (tau_max > bnk->gamma3) {
963080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
964080d2917SAlp Dener             } else if (tau_max < 1.0) {
965080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
966080d2917SAlp Dener             } else {
967080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
968080d2917SAlp Dener             }
969080d2917SAlp Dener           } else {
970080d2917SAlp Dener             /*  Not good agreement */
971080d2917SAlp Dener             if (tau_min > 1.0) {
972080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
973080d2917SAlp Dener             } else if (tau_max < bnk->gamma1) {
974080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
975080d2917SAlp Dener             } else if ((tau_min < bnk->gamma1) && (tau_max >= 1.0)) {
976080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
977080d2917SAlp Dener             } else if ((tau_1 >= bnk->gamma1) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1) || (tau_2 >= 1.0))) {
978080d2917SAlp Dener               tao->trust = tau_1 * PetscMin(tao->trust, bnk->dnorm);
979080d2917SAlp Dener             } else if ((tau_2 >= bnk->gamma1) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1) || (tau_2 >= 1.0))) {
980080d2917SAlp Dener               tao->trust = tau_2 * PetscMin(tao->trust, bnk->dnorm);
981080d2917SAlp Dener             } else {
982080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
983080d2917SAlp Dener             }
984080d2917SAlp Dener           }
985080d2917SAlp Dener         }
986080d2917SAlp Dener       }
987080d2917SAlp Dener     } else {
988080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
989080d2917SAlp Dener       tao->trust = bnk->gamma1 * PetscMin(bnk->dnorm, tao->trust);
990080d2917SAlp Dener     }
99128017e9fSAlp Dener     break;
992080d2917SAlp Dener   }
993c133c014SAlp Dener   /* Make sure the radius does not violate min and max settings */
994c133c014SAlp Dener   tao->trust = PetscMin(tao->trust, bnk->max_radius);
995fed79b8eSAlp Dener   tao->trust = PetscMax(tao->trust, bnk->min_radius);
996080d2917SAlp Dener   PetscFunctionReturn(0);
997080d2917SAlp Dener }
998080d2917SAlp Dener 
999eb910715SAlp Dener /* ---------------------------------------------------------- */
1000df278d8fSAlp Dener 
100162675beeSAlp Dener PetscErrorCode TaoBNKAddStepCounts(Tao tao, PetscInt stepType)
100262675beeSAlp Dener {
100362675beeSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
100462675beeSAlp Dener 
100562675beeSAlp Dener   PetscFunctionBegin;
100662675beeSAlp Dener   switch (stepType) {
100762675beeSAlp Dener   case BNK_NEWTON:
100862675beeSAlp Dener     ++bnk->newt;
100962675beeSAlp Dener     break;
101062675beeSAlp Dener   case BNK_BFGS:
101162675beeSAlp Dener     ++bnk->bfgs;
101262675beeSAlp Dener     break;
101362675beeSAlp Dener   case BNK_SCALED_GRADIENT:
101462675beeSAlp Dener     ++bnk->sgrad;
101562675beeSAlp Dener     break;
101662675beeSAlp Dener   case BNK_GRADIENT:
101762675beeSAlp Dener     ++bnk->grad;
101862675beeSAlp Dener     break;
101962675beeSAlp Dener   default:
102062675beeSAlp Dener     break;
102162675beeSAlp Dener   }
102262675beeSAlp Dener   PetscFunctionReturn(0);
102362675beeSAlp Dener }
102462675beeSAlp Dener 
102562675beeSAlp Dener /* ---------------------------------------------------------- */
102662675beeSAlp Dener 
10279b6ef848SAlp Dener PetscErrorCode TaoSetUp_BNK(Tao tao)
1028eb910715SAlp Dener {
1029eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1030e031d6f5SAlp Dener   PetscInt       i;
1031eb910715SAlp Dener 
1032eb910715SAlp Dener   PetscFunctionBegin;
1033c4b75bccSAlp Dener   if (!tao->gradient) {
1034*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->gradient));
1035c4b75bccSAlp Dener   }
1036c4b75bccSAlp Dener   if (!tao->stepdirection) {
1037*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->stepdirection));
1038c4b75bccSAlp Dener   }
1039c4b75bccSAlp Dener   if (!bnk->W) {
1040*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->W));
1041c4b75bccSAlp Dener   }
1042c4b75bccSAlp Dener   if (!bnk->Xold) {
1043*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Xold));
1044c4b75bccSAlp Dener   }
1045c4b75bccSAlp Dener   if (!bnk->Gold) {
1046*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Gold));
1047c4b75bccSAlp Dener   }
1048c4b75bccSAlp Dener   if (!bnk->Xwork) {
1049*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Xwork));
1050c4b75bccSAlp Dener   }
1051c4b75bccSAlp Dener   if (!bnk->Gwork) {
1052*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Gwork));
1053c4b75bccSAlp Dener   }
1054c4b75bccSAlp Dener   if (!bnk->unprojected_gradient) {
1055*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->unprojected_gradient));
1056c4b75bccSAlp Dener   }
1057c4b75bccSAlp Dener   if (!bnk->unprojected_gradient_old) {
1058*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->unprojected_gradient_old));
1059c4b75bccSAlp Dener   }
1060c4b75bccSAlp Dener   if (!bnk->Diag_min) {
1061*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Diag_min));
1062c4b75bccSAlp Dener   }
1063c4b75bccSAlp Dener   if (!bnk->Diag_max) {
1064*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&bnk->Diag_max));
1065c4b75bccSAlp Dener   }
1066e031d6f5SAlp Dener   if (bnk->max_cg_its > 0) {
1067c4b75bccSAlp Dener     /* Ensure that the important common vectors are shared between BNK and embedded BNCG */
1068c4b75bccSAlp Dener     bnk->bncg_ctx = (TAO_BNCG *)bnk->bncg->data;
1069*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient_old)));
1070*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient_old));
107189da521bSAlp Dener     bnk->bncg_ctx->unprojected_gradient_old = bnk->unprojected_gradient_old;
1072*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->unprojected_gradient)));
1073*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->unprojected_gradient));
1074c4b75bccSAlp Dener     bnk->bncg_ctx->unprojected_gradient = bnk->unprojected_gradient;
1075*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(bnk->Gold)));
1076*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg_ctx->G_old));
1077c4b75bccSAlp Dener     bnk->bncg_ctx->G_old = bnk->Gold;
1078*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->gradient)));
1079*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->gradient));
1080c4b75bccSAlp Dener     bnk->bncg->gradient = tao->gradient;
1081*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)(tao->stepdirection)));
1082*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->bncg->stepdirection));
1083c4b75bccSAlp Dener     bnk->bncg->stepdirection = tao->stepdirection;
1084*9566063dSJacob Faibussowitsch     PetscCall(TaoSetSolution(bnk->bncg, tao->solution));
1085c4b75bccSAlp Dener     /* Copy over some settings from BNK into BNCG */
1086*9566063dSJacob Faibussowitsch     PetscCall(TaoSetMaximumIterations(bnk->bncg, bnk->max_cg_its));
1087*9566063dSJacob Faibussowitsch     PetscCall(TaoSetTolerances(bnk->bncg, tao->gatol, tao->grtol, tao->gttol));
1088*9566063dSJacob Faibussowitsch     PetscCall(TaoSetFunctionLowerBound(bnk->bncg, tao->fmin));
1089*9566063dSJacob Faibussowitsch     PetscCall(TaoSetConvergenceTest(bnk->bncg, tao->ops->convergencetest, tao->cnvP));
1090*9566063dSJacob Faibussowitsch     PetscCall(TaoSetObjective(bnk->bncg, tao->ops->computeobjective, tao->user_objP));
1091*9566063dSJacob Faibussowitsch     PetscCall(TaoSetGradient(bnk->bncg, NULL, tao->ops->computegradient, tao->user_gradP));
1092*9566063dSJacob Faibussowitsch     PetscCall(TaoSetObjectiveAndGradient(bnk->bncg, NULL, tao->ops->computeobjectiveandgradient, tao->user_objgradP));
1093*9566063dSJacob Faibussowitsch     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)tao, (PetscObject)(bnk->bncg)));
1094c4b75bccSAlp Dener     for (i=0; i<tao->numbermonitors; ++i) {
1095*9566063dSJacob Faibussowitsch       PetscCall(TaoSetMonitor(bnk->bncg, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]));
1096*9566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)(tao->monitorcontext[i])));
1097e031d6f5SAlp Dener     }
1098e031d6f5SAlp Dener   }
109983c8fe1dSLisandro Dalcin   bnk->X_inactive = NULL;
110083c8fe1dSLisandro Dalcin   bnk->G_inactive = NULL;
110183c8fe1dSLisandro Dalcin   bnk->inactive_work = NULL;
110283c8fe1dSLisandro Dalcin   bnk->active_work = NULL;
110383c8fe1dSLisandro Dalcin   bnk->inactive_idx = NULL;
110483c8fe1dSLisandro Dalcin   bnk->active_idx = NULL;
110583c8fe1dSLisandro Dalcin   bnk->active_lower = NULL;
110683c8fe1dSLisandro Dalcin   bnk->active_upper = NULL;
110783c8fe1dSLisandro Dalcin   bnk->active_fixed = NULL;
110883c8fe1dSLisandro Dalcin   bnk->M = NULL;
110983c8fe1dSLisandro Dalcin   bnk->H_inactive = NULL;
111083c8fe1dSLisandro Dalcin   bnk->Hpre_inactive = NULL;
1111eb910715SAlp Dener   PetscFunctionReturn(0);
1112eb910715SAlp Dener }
1113eb910715SAlp Dener 
1114eb910715SAlp Dener /*------------------------------------------------------------*/
1115df278d8fSAlp Dener 
1116e0ed867bSAlp Dener PetscErrorCode TaoDestroy_BNK(Tao tao)
1117eb910715SAlp Dener {
1118eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1119eb910715SAlp Dener 
1120eb910715SAlp Dener   PetscFunctionBegin;
1121eb910715SAlp Dener   if (tao->setupcalled) {
1122*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->W));
1123*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Xold));
1124*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Gold));
1125*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Xwork));
1126*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Gwork));
1127*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->unprojected_gradient));
1128*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->unprojected_gradient_old));
1129*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Diag_min));
1130*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&bnk->Diag_max));
1131c4b75bccSAlp Dener   }
1132*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_lower));
1133*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_upper));
1134*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_fixed));
1135*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->active_idx));
1136*9566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&bnk->inactive_idx));
1137*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->Hpre_inactive));
1138*9566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bnk->H_inactive));
1139*9566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&bnk->bncg));
1140*9566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
1141eb910715SAlp Dener   PetscFunctionReturn(0);
1142eb910715SAlp Dener }
1143eb910715SAlp Dener 
1144eb910715SAlp Dener /*------------------------------------------------------------*/
1145df278d8fSAlp Dener 
1146e0ed867bSAlp Dener PetscErrorCode TaoSetFromOptions_BNK(PetscOptionItems *PetscOptionsObject,Tao tao)
1147eb910715SAlp Dener {
1148eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1149eb910715SAlp Dener 
1150eb910715SAlp Dener   PetscFunctionBegin;
1151*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHead(PetscOptionsObject,"Newton-Krylov method for bound constrained optimization"));
1152*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_init_type", "radius initialization type", "", BNK_INIT, BNK_INIT_TYPES, BNK_INIT[bnk->init_type], &bnk->init_type, NULL));
1153*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEList("-tao_bnk_update_type", "radius update type", "", BNK_UPDATE, BNK_UPDATE_TYPES, BNK_UPDATE[bnk->update_type], &bnk->update_type, NULL));
1154*9566063dSJacob 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));
1155*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_sval", "(developer) Hessian perturbation starting value", "", bnk->sval, &bnk->sval,NULL));
1156*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imin", "(developer) minimum initial Hessian perturbation", "", bnk->imin, &bnk->imin,NULL));
1157*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imax", "(developer) maximum initial Hessian perturbation", "", bnk->imax, &bnk->imax,NULL));
1158*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_imfac", "(developer) initial merit factor for Hessian perturbation", "", bnk->imfac, &bnk->imfac,NULL));
1159*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmin", "(developer) minimum Hessian perturbation", "", bnk->pmin, &bnk->pmin,NULL));
1160*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmax", "(developer) maximum Hessian perturbation", "", bnk->pmax, &bnk->pmax,NULL));
1161*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pgfac", "(developer) Hessian perturbation growth factor", "", bnk->pgfac, &bnk->pgfac,NULL));
1162*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_psfac", "(developer) Hessian perturbation shrink factor", "", bnk->psfac, &bnk->psfac,NULL));
1163*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmgfac", "(developer) merit growth factor for Hessian perturbation", "", bnk->pmgfac, &bnk->pmgfac,NULL));
1164*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_pmsfac", "(developer) merit shrink factor for Hessian perturbation", "", bnk->pmsfac, &bnk->pmsfac,NULL));
1165*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta1", "(developer) threshold for rejecting step (-tao_bnk_update_type reduction)", "", bnk->eta1, &bnk->eta1,NULL));
1166*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta2", "(developer) threshold for accepting marginal step (-tao_bnk_update_type reduction)", "", bnk->eta2, &bnk->eta2,NULL));
1167*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta3", "(developer) threshold for accepting reasonable step (-tao_bnk_update_type reduction)", "", bnk->eta3, &bnk->eta3,NULL));
1168*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_eta4", "(developer) threshold for accepting good step (-tao_bnk_update_type reduction)", "", bnk->eta4, &bnk->eta4,NULL));
1169*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha1", "(developer) radius reduction factor for rejected step (-tao_bnk_update_type reduction)", "", bnk->alpha1, &bnk->alpha1,NULL));
1170*9566063dSJacob 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));
1171*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha3", "(developer) radius increase factor for reasonable accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha3, &bnk->alpha3,NULL));
1172*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_alpha4", "(developer) radius increase factor for good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha4, &bnk->alpha4,NULL));
1173*9566063dSJacob 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));
1174*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu1", "(developer) threshold for small line-search step length (-tao_bnk_update_type step)", "", bnk->nu1, &bnk->nu1,NULL));
1175*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu2", "(developer) threshold for reasonable line-search step length (-tao_bnk_update_type step)", "", bnk->nu2, &bnk->nu2,NULL));
1176*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_nu3", "(developer) threshold for large line-search step length (-tao_bnk_update_type step)", "", bnk->nu3, &bnk->nu3,NULL));
1177*9566063dSJacob 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));
1178*9566063dSJacob 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));
1179*9566063dSJacob 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));
1180*9566063dSJacob 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));
1181*9566063dSJacob 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));
1182*9566063dSJacob 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));
1183*9566063dSJacob 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));
1184*9566063dSJacob 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));
1185*9566063dSJacob 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));
1186*9566063dSJacob 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));
1187*9566063dSJacob 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));
1188*9566063dSJacob 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));
1189*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta_i", "(developer) trust region interpolation factor (-tao_bnk_init_type interpolation)", "", bnk->theta_i, &bnk->theta_i,NULL));
1190*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu1", "(developer) threshold for accepting very good step (-tao_bnk_update_type interpolation)", "", bnk->mu1, &bnk->mu1,NULL));
1191*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_mu2", "(developer) threshold for accepting good step (-tao_bnk_update_type interpolation)", "", bnk->mu2, &bnk->mu2,NULL));
1192*9566063dSJacob 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));
1193*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma2", "(developer) radius reduction factor for rejected bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma2, &bnk->gamma2,NULL));
1194*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_gamma3", "(developer) radius increase factor for accepted good step (-tao_bnk_update_type interpolation)", "", bnk->gamma3, &bnk->gamma3,NULL));
1195*9566063dSJacob 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));
1196*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_theta", "(developer) trust region interpolation factor (-tao_bnk_update_type interpolation)", "", bnk->theta, &bnk->theta,NULL));
1197*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_min_radius", "(developer) lower bound on initial radius", "", bnk->min_radius, &bnk->min_radius,NULL));
1198*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_max_radius", "(developer) upper bound on radius", "", bnk->max_radius, &bnk->max_radius,NULL));
1199*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_epsilon", "(developer) tolerance used when computing actual and predicted reduction", "", bnk->epsilon, &bnk->epsilon,NULL));
1200*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", bnk->as_tol, &bnk->as_tol,NULL));
1201*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bnk_as_step", "(developer) step length used when estimating actively bounded variables", "", bnk->as_step, &bnk->as_step,NULL));
1202*9566063dSJacob 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));
1203*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsTail());
12048ebe3e4eSStefano Zampini 
1205*9566063dSJacob Faibussowitsch   PetscCall(TaoSetOptionsPrefix(bnk->bncg,((PetscObject)(tao))->prefix));
1206*9566063dSJacob Faibussowitsch   PetscCall(TaoAppendOptionsPrefix(bnk->bncg,"tao_bnk_cg_"));
1207*9566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(bnk->bncg));
12088ebe3e4eSStefano Zampini 
1209*9566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(tao->ksp,((PetscObject)(tao))->prefix));
1210*9566063dSJacob Faibussowitsch   PetscCall(KSPAppendOptionsPrefix(tao->ksp,"tao_bnk_"));
1211*9566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(tao->ksp));
1212eb910715SAlp Dener   PetscFunctionReturn(0);
1213eb910715SAlp Dener }
1214eb910715SAlp Dener 
1215eb910715SAlp Dener /*------------------------------------------------------------*/
1216df278d8fSAlp Dener 
1217e0ed867bSAlp Dener PetscErrorCode TaoView_BNK(Tao tao, PetscViewer viewer)
1218eb910715SAlp Dener {
1219eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1220eb910715SAlp Dener   PetscInt       nrejects;
1221eb910715SAlp Dener   PetscBool      isascii;
1222eb910715SAlp Dener 
1223eb910715SAlp Dener   PetscFunctionBegin;
1224*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
1225eb910715SAlp Dener   if (isascii) {
1226*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1227b9ac7092SAlp Dener     if (bnk->M) {
1228*9566063dSJacob Faibussowitsch       PetscCall(MatLMVMGetRejectCount(bnk->M,&nrejects));
1229*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Rejected BFGS updates: %D\n",nrejects));
1230eb910715SAlp Dener     }
1231*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "CG steps: %D\n", bnk->tot_cg_its));
1232*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Newton steps: %D\n", bnk->newt));
1233b9ac7092SAlp Dener     if (bnk->M) {
1234*9566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "BFGS steps: %D\n", bnk->bfgs));
1235b9ac7092SAlp Dener     }
1236*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %D\n", bnk->sgrad));
1237*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", bnk->grad));
1238*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP termination reasons:\n"));
1239*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  atol: %D\n", bnk->ksp_atol));
1240*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  rtol: %D\n", bnk->ksp_rtol));
1241*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  ctol: %D\n", bnk->ksp_ctol));
1242*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  negc: %D\n", bnk->ksp_negc));
1243*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dtol: %D\n", bnk->ksp_dtol));
1244*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  iter: %D\n", bnk->ksp_iter));
1245*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  othr: %D\n", bnk->ksp_othr));
1246*9566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
1247eb910715SAlp Dener   }
1248eb910715SAlp Dener   PetscFunctionReturn(0);
1249eb910715SAlp Dener }
1250eb910715SAlp Dener 
1251eb910715SAlp Dener /* ---------------------------------------------------------- */
1252df278d8fSAlp Dener 
1253eb910715SAlp Dener /*MC
1254eb910715SAlp Dener   TAOBNK - Shared base-type for Bounded Newton-Krylov type algorithms.
125566ed3702SAlp Dener   At each iteration, the BNK methods solve the symmetric
1256eb910715SAlp Dener   system of equations to obtain the step diretion dk:
1257eb910715SAlp Dener               Hk dk = -gk
12582b97c8d8SAlp Dener   for free variables only. The step can be globalized either through
12592b97c8d8SAlp Dener   trust-region methods, or a line search, or a heuristic mixture of both.
1260eb910715SAlp Dener 
1261eb910715SAlp Dener     Options Database Keys:
12629fa2b5dcSStefano Zampini + -tao_bnk_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
12639fa2b5dcSStefano Zampini . -tao_bnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
12649fa2b5dcSStefano Zampini . -tao_bnk_update_type - trust radius update method ("step", "direction", "interpolation")
12659fa2b5dcSStefano Zampini . -tao_bnk_as_type - active-set estimation method ("none", "bertsekas")
12669fa2b5dcSStefano Zampini . -tao_bnk_as_tol - (developer) initial tolerance used in estimating bounded active variables (-as_type bertsekas)
12679fa2b5dcSStefano Zampini . -tao_bnk_as_step - (developer) trial step length used in estimating bounded active variables (-as_type bertsekas)
12689fa2b5dcSStefano Zampini . -tao_bnk_sval - (developer) Hessian perturbation starting value
12699fa2b5dcSStefano Zampini . -tao_bnk_imin - (developer) minimum initial Hessian perturbation
12709fa2b5dcSStefano Zampini . -tao_bnk_imax - (developer) maximum initial Hessian perturbation
12719fa2b5dcSStefano Zampini . -tao_bnk_pmin - (developer) minimum Hessian perturbation
12729fa2b5dcSStefano Zampini . -tao_bnk_pmax - (developer) aximum Hessian perturbation
12739fa2b5dcSStefano Zampini . -tao_bnk_pgfac - (developer) Hessian perturbation growth factor
12749fa2b5dcSStefano Zampini . -tao_bnk_psfac - (developer) Hessian perturbation shrink factor
12759fa2b5dcSStefano Zampini . -tao_bnk_imfac - (developer) initial merit factor for Hessian perturbation
12769fa2b5dcSStefano Zampini . -tao_bnk_pmgfac - (developer) merit growth factor for Hessian perturbation
12779fa2b5dcSStefano Zampini . -tao_bnk_pmsfac - (developer) merit shrink factor for Hessian perturbation
12789fa2b5dcSStefano Zampini . -tao_bnk_eta1 - (developer) threshold for rejecting step (-update_type reduction)
12799fa2b5dcSStefano Zampini . -tao_bnk_eta2 - (developer) threshold for accepting marginal step (-update_type reduction)
12809fa2b5dcSStefano Zampini . -tao_bnk_eta3 - (developer) threshold for accepting reasonable step (-update_type reduction)
12819fa2b5dcSStefano Zampini . -tao_bnk_eta4 - (developer) threshold for accepting good step (-update_type reduction)
12829fa2b5dcSStefano Zampini . -tao_bnk_alpha1 - (developer) radius reduction factor for rejected step (-update_type reduction)
12839fa2b5dcSStefano Zampini . -tao_bnk_alpha2 - (developer) radius reduction factor for marginally accepted bad step (-update_type reduction)
12849fa2b5dcSStefano Zampini . -tao_bnk_alpha3 - (developer) radius increase factor for reasonable accepted step (-update_type reduction)
12859fa2b5dcSStefano Zampini . -tao_bnk_alpha4 - (developer) radius increase factor for good accepted step (-update_type reduction)
12869fa2b5dcSStefano Zampini . -tao_bnk_alpha5 - (developer) radius increase factor for very good accepted step (-update_type reduction)
12879fa2b5dcSStefano Zampini . -tao_bnk_epsilon - (developer) tolerance for small pred/actual ratios that trigger automatic step acceptance (-update_type reduction)
12889fa2b5dcSStefano Zampini . -tao_bnk_mu1 - (developer) threshold for accepting very good step (-update_type interpolation)
12899fa2b5dcSStefano Zampini . -tao_bnk_mu2 - (developer) threshold for accepting good step (-update_type interpolation)
12909fa2b5dcSStefano Zampini . -tao_bnk_gamma1 - (developer) radius reduction factor for rejected very bad step (-update_type interpolation)
12919fa2b5dcSStefano Zampini . -tao_bnk_gamma2 - (developer) radius reduction factor for rejected bad step (-update_type interpolation)
12929fa2b5dcSStefano Zampini . -tao_bnk_gamma3 - (developer) radius increase factor for accepted good step (-update_type interpolation)
12939fa2b5dcSStefano Zampini . -tao_bnk_gamma4 - (developer) radius increase factor for accepted very good step (-update_type interpolation)
12949fa2b5dcSStefano Zampini . -tao_bnk_theta - (developer) trust region interpolation factor (-update_type interpolation)
12959fa2b5dcSStefano Zampini . -tao_bnk_nu1 - (developer) threshold for small line-search step length (-update_type step)
12969fa2b5dcSStefano Zampini . -tao_bnk_nu2 - (developer) threshold for reasonable line-search step length (-update_type step)
12979fa2b5dcSStefano Zampini . -tao_bnk_nu3 - (developer) threshold for large line-search step length (-update_type step)
12989fa2b5dcSStefano Zampini . -tao_bnk_nu4 - (developer) threshold for very large line-search step length (-update_type step)
12999fa2b5dcSStefano Zampini . -tao_bnk_omega1 - (developer) radius reduction factor for very small line-search step length (-update_type step)
13009fa2b5dcSStefano Zampini . -tao_bnk_omega2 - (developer) radius reduction factor for small line-search step length (-update_type step)
13019fa2b5dcSStefano Zampini . -tao_bnk_omega3 - (developer) radius factor for decent line-search step length (-update_type step)
13029fa2b5dcSStefano Zampini . -tao_bnk_omega4 - (developer) radius increase factor for large line-search step length (-update_type step)
13039fa2b5dcSStefano Zampini . -tao_bnk_omega5 - (developer) radius increase factor for very large line-search step length (-update_type step)
13049fa2b5dcSStefano Zampini . -tao_bnk_mu1_i -  (developer) threshold for accepting very good step (-init_type interpolation)
13059fa2b5dcSStefano Zampini . -tao_bnk_mu2_i -  (developer) threshold for accepting good step (-init_type interpolation)
13069fa2b5dcSStefano Zampini . -tao_bnk_gamma1_i - (developer) radius reduction factor for rejected very bad step (-init_type interpolation)
13079fa2b5dcSStefano Zampini . -tao_bnk_gamma2_i - (developer) radius reduction factor for rejected bad step (-init_type interpolation)
13089fa2b5dcSStefano Zampini . -tao_bnk_gamma3_i - (developer) radius increase factor for accepted good step (-init_type interpolation)
13099fa2b5dcSStefano Zampini . -tao_bnk_gamma4_i - (developer) radius increase factor for accepted very good step (-init_type interpolation)
13109fa2b5dcSStefano Zampini - -tao_bnk_theta_i - (developer) trust region interpolation factor (-init_type interpolation)
1311eb910715SAlp Dener 
1312eb910715SAlp Dener   Level: beginner
1313eb910715SAlp Dener M*/
1314eb910715SAlp Dener 
1315eb910715SAlp Dener PetscErrorCode TaoCreate_BNK(Tao tao)
1316eb910715SAlp Dener {
1317eb910715SAlp Dener   TAO_BNK        *bnk;
1318eb910715SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
1319b9ac7092SAlp Dener   PC             pc;
1320eb910715SAlp Dener 
1321eb910715SAlp Dener   PetscFunctionBegin;
1322*9566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(tao,&bnk));
1323eb910715SAlp Dener 
1324eb910715SAlp Dener   tao->ops->setup = TaoSetUp_BNK;
1325eb910715SAlp Dener   tao->ops->view = TaoView_BNK;
1326eb910715SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNK;
1327eb910715SAlp Dener   tao->ops->destroy = TaoDestroy_BNK;
1328eb910715SAlp Dener 
1329eb910715SAlp Dener   /*  Override default settings (unless already changed) */
1330eb910715SAlp Dener   if (!tao->max_it_changed) tao->max_it = 50;
1331eb910715SAlp Dener   if (!tao->trust0_changed) tao->trust0 = 100.0;
1332eb910715SAlp Dener 
1333eb910715SAlp Dener   tao->data = (void*)bnk;
1334eb910715SAlp Dener 
133566ed3702SAlp Dener   /*  Hessian shifting parameters */
1336e0ed867bSAlp Dener   bnk->computehessian = TaoBNKComputeHessian;
1337e0ed867bSAlp Dener   bnk->computestep = TaoBNKComputeStep;
1338e0ed867bSAlp Dener 
1339eb910715SAlp Dener   bnk->sval   = 0.0;
1340eb910715SAlp Dener   bnk->imin   = 1.0e-4;
1341eb910715SAlp Dener   bnk->imax   = 1.0e+2;
1342eb910715SAlp Dener   bnk->imfac  = 1.0e-1;
1343eb910715SAlp Dener 
1344eb910715SAlp Dener   bnk->pmin   = 1.0e-12;
1345eb910715SAlp Dener   bnk->pmax   = 1.0e+2;
1346eb910715SAlp Dener   bnk->pgfac  = 1.0e+1;
1347eb910715SAlp Dener   bnk->psfac  = 4.0e-1;
1348eb910715SAlp Dener   bnk->pmgfac = 1.0e-1;
1349eb910715SAlp Dener   bnk->pmsfac = 1.0e-1;
1350eb910715SAlp Dener 
1351eb910715SAlp Dener   /*  Default values for trust-region radius update based on steplength */
1352eb910715SAlp Dener   bnk->nu1 = 0.25;
1353eb910715SAlp Dener   bnk->nu2 = 0.50;
1354eb910715SAlp Dener   bnk->nu3 = 1.00;
1355eb910715SAlp Dener   bnk->nu4 = 1.25;
1356eb910715SAlp Dener 
1357eb910715SAlp Dener   bnk->omega1 = 0.25;
1358eb910715SAlp Dener   bnk->omega2 = 0.50;
1359eb910715SAlp Dener   bnk->omega3 = 1.00;
1360eb910715SAlp Dener   bnk->omega4 = 2.00;
1361eb910715SAlp Dener   bnk->omega5 = 4.00;
1362eb910715SAlp Dener 
1363eb910715SAlp Dener   /*  Default values for trust-region radius update based on reduction */
1364eb910715SAlp Dener   bnk->eta1 = 1.0e-4;
1365eb910715SAlp Dener   bnk->eta2 = 0.25;
1366eb910715SAlp Dener   bnk->eta3 = 0.50;
1367eb910715SAlp Dener   bnk->eta4 = 0.90;
1368eb910715SAlp Dener 
1369eb910715SAlp Dener   bnk->alpha1 = 0.25;
1370eb910715SAlp Dener   bnk->alpha2 = 0.50;
1371eb910715SAlp Dener   bnk->alpha3 = 1.00;
1372eb910715SAlp Dener   bnk->alpha4 = 2.00;
1373eb910715SAlp Dener   bnk->alpha5 = 4.00;
1374eb910715SAlp Dener 
1375eb910715SAlp Dener   /*  Default values for trust-region radius update based on interpolation */
1376eb910715SAlp Dener   bnk->mu1 = 0.10;
1377eb910715SAlp Dener   bnk->mu2 = 0.50;
1378eb910715SAlp Dener 
1379eb910715SAlp Dener   bnk->gamma1 = 0.25;
1380eb910715SAlp Dener   bnk->gamma2 = 0.50;
1381eb910715SAlp Dener   bnk->gamma3 = 2.00;
1382eb910715SAlp Dener   bnk->gamma4 = 4.00;
1383eb910715SAlp Dener 
1384eb910715SAlp Dener   bnk->theta = 0.05;
1385eb910715SAlp Dener 
1386eb910715SAlp Dener   /*  Default values for trust region initialization based on interpolation */
1387eb910715SAlp Dener   bnk->mu1_i = 0.35;
1388eb910715SAlp Dener   bnk->mu2_i = 0.50;
1389eb910715SAlp Dener 
1390eb910715SAlp Dener   bnk->gamma1_i = 0.0625;
1391eb910715SAlp Dener   bnk->gamma2_i = 0.5;
1392eb910715SAlp Dener   bnk->gamma3_i = 2.0;
1393eb910715SAlp Dener   bnk->gamma4_i = 5.0;
1394eb910715SAlp Dener 
1395eb910715SAlp Dener   bnk->theta_i = 0.25;
1396eb910715SAlp Dener 
1397eb910715SAlp Dener   /*  Remaining parameters */
1398c0f10754SAlp Dener   bnk->max_cg_its = 0;
1399eb910715SAlp Dener   bnk->min_radius = 1.0e-10;
1400eb910715SAlp Dener   bnk->max_radius = 1.0e10;
1401770b7498SAlp Dener   bnk->epsilon = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0);
14020a4511e9SAlp Dener   bnk->as_tol = 1.0e-3;
14030a4511e9SAlp Dener   bnk->as_step = 1.0e-3;
140462675beeSAlp Dener   bnk->dmin = 1.0e-6;
140562675beeSAlp Dener   bnk->dmax = 1.0e6;
1406eb910715SAlp Dener 
140783c8fe1dSLisandro Dalcin   bnk->M           = NULL;
140883c8fe1dSLisandro Dalcin   bnk->bfgs_pre    = NULL;
1409eb910715SAlp Dener   bnk->init_type   = BNK_INIT_INTERPOLATION;
14107b1c7716SAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION;
14112f75a4aaSAlp Dener   bnk->as_type     = BNK_AS_BERTSEKAS;
1412eb910715SAlp Dener 
1413e031d6f5SAlp Dener   /* Create the embedded BNCG solver */
1414*9566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PetscObjectComm((PetscObject)tao), &bnk->bncg));
1415*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)bnk->bncg, (PetscObject)tao, 1));
1416*9566063dSJacob Faibussowitsch   PetscCall(TaoSetType(bnk->bncg, TAOBNCG));
1417e031d6f5SAlp Dener 
1418c0f10754SAlp Dener   /* Create the line search */
1419*9566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch));
1420*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
1421*9566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetType(tao->linesearch,morethuente_type));
1422*9566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch,tao));
1423eb910715SAlp Dener 
1424eb910715SAlp Dener   /*  Set linear solver to default for symmetric matrices */
1425*9566063dSJacob Faibussowitsch   PetscCall(KSPCreate(((PetscObject)tao)->comm,&tao->ksp));
1426*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
1427*9566063dSJacob Faibussowitsch   PetscCall(KSPSetType(tao->ksp,KSPSTCG));
1428*9566063dSJacob Faibussowitsch   PetscCall(KSPGetPC(tao->ksp, &pc));
1429*9566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCLMVM));
1430eb910715SAlp Dener   PetscFunctionReturn(0);
1431eb910715SAlp Dener }
1432