xref: /petsc/src/tao/bound/impls/bnk/bnk.c (revision cd929ea3f739fd9f7b6394f772cb40b9d4e6d97c)
1eb910715SAlp Dener #include <petsctaolinesearch.h>
2eb910715SAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
3eb910715SAlp Dener 
4eb910715SAlp Dener #include <petscksp.h>
5eb910715SAlp Dener 
6e031d6f5SAlp Dener static const char *BNK_PC[64] = {"none", "ahess", "bfgs", "petsc"};
7e031d6f5SAlp Dener static const char *BFGS_SCALE[64] = {"ahess", "phess", "bfgs"};
8e031d6f5SAlp Dener static const char *BNK_INIT[64] = {"constant", "direction", "interpolation"};
9e031d6f5SAlp Dener static const char *BNK_UPDATE[64] = {"step", "reduction", "interpolation"};
10e031d6f5SAlp Dener static const char *BNK_AS[64] = {"none", "bertsekas"};
11e031d6f5SAlp Dener 
12e031d6f5SAlp Dener /*------------------------------------------------------------*/
13e031d6f5SAlp Dener 
14*cd929ea3SAlp Dener PetscErrorCode TaoBNKPreconBFGS(PC BFGSpc, Vec X, Vec Y)
15eb910715SAlp Dener {
16eb910715SAlp Dener   PetscErrorCode ierr;
17*cd929ea3SAlp Dener   Mat *M;
18eb910715SAlp Dener 
19eb910715SAlp Dener   PetscFunctionBegin;
20*cd929ea3SAlp Dener   ierr = PCShellGetContext(BFGSpc, (void**)&M);CHKERRQ(ierr);
21*cd929ea3SAlp Dener   ierr = MatSolve(*M, X, Y);CHKERRQ(ierr);
22eb910715SAlp Dener   PetscFunctionReturn(0);
23eb910715SAlp Dener }
24eb910715SAlp Dener 
25df278d8fSAlp Dener /*------------------------------------------------------------*/
26df278d8fSAlp Dener 
27df278d8fSAlp Dener /* Routine for initializing the KSP solver, the BFGS preconditioner, and the initial trust radius estimation */
28df278d8fSAlp Dener 
29c0f10754SAlp Dener PetscErrorCode TaoBNKInitialize(Tao tao, PetscInt initType, PetscBool *needH)
30eb910715SAlp Dener {
31eb910715SAlp Dener   PetscErrorCode               ierr;
32eb910715SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
33eb910715SAlp Dener   PC                           pc;
34eb910715SAlp Dener 
3589da521bSAlp Dener   PetscReal                    f_min, ftrial, prered, actred, kappa, sigma, resnorm;
36eb910715SAlp Dener   PetscReal                    tau, tau_1, tau_2, tau_max, tau_min, max_radius;
3789da521bSAlp Dener   PetscReal                    delta;
38eb910715SAlp Dener 
39c4b75bccSAlp Dener   PetscInt                     n,N,nDiff;
40eb910715SAlp Dener 
41eb910715SAlp Dener   PetscInt                     i_max = 5;
42eb910715SAlp Dener   PetscInt                     j_max = 1;
43eb910715SAlp Dener   PetscInt                     i, j;
44eb910715SAlp Dener 
45eb910715SAlp Dener   PetscFunctionBegin;
4628017e9fSAlp Dener   /* Project the current point onto the feasible set */
4728017e9fSAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
48e031d6f5SAlp Dener   ierr = TaoSetVariableBounds(bnk->bncg, tao->XL, tao->XU);CHKERRQ(ierr);
49*cd929ea3SAlp Dener   if (tao->bounded) PetscFunctionReturn(0); {
5028017e9fSAlp Dener     ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
51*cd929ea3SAlp Dener   }
5228017e9fSAlp Dener 
5328017e9fSAlp Dener   /* Project the initial point onto the feasible region */
543b063059SAlp Dener   ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
5528017e9fSAlp Dener 
5628017e9fSAlp Dener   /* Check convergence criteria */
5728017e9fSAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr);
5861be54a6SAlp Dener   ierr = TaoBNKEstimateActiveSet(tao, bnk->as_type);CHKERRQ(ierr);
5961be54a6SAlp Dener   ierr = VecCopy(bnk->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
6061be54a6SAlp Dener   ierr = VecISSet(tao->gradient, bnk->active_idx, 0.0);CHKERRQ(ierr);
6108752603SAlp Dener   ierr = VecNorm(tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
6228017e9fSAlp Dener 
63c0f10754SAlp Dener   /* Test the initial point for convergence */
6489da521bSAlp Dener   ierr = VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W);CHKERRQ(ierr);
6589da521bSAlp Dener   ierr = VecNorm(bnk->W, NORM_2, &resnorm);CHKERRQ(ierr);
66b4a30f08SAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(resnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
67e031d6f5SAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,resnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
68e031d6f5SAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,resnorm,0.0,1.0);CHKERRQ(ierr);
69c0f10754SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
70c0f10754SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
71c0f10754SAlp Dener 
72e031d6f5SAlp Dener   /* Reset KSP stopping reason counters */
73eb910715SAlp Dener   bnk->ksp_atol = 0;
74eb910715SAlp Dener   bnk->ksp_rtol = 0;
75eb910715SAlp Dener   bnk->ksp_dtol = 0;
76eb910715SAlp Dener   bnk->ksp_ctol = 0;
77eb910715SAlp Dener   bnk->ksp_negc = 0;
78eb910715SAlp Dener   bnk->ksp_iter = 0;
79eb910715SAlp Dener   bnk->ksp_othr = 0;
80eb910715SAlp Dener 
81e031d6f5SAlp Dener   /* Reset accepted step type counters */
82e031d6f5SAlp Dener   bnk->tot_cg_its = 0;
83e031d6f5SAlp Dener   bnk->newt = 0;
84e031d6f5SAlp Dener   bnk->bfgs = 0;
85e031d6f5SAlp Dener   bnk->sgrad = 0;
86e031d6f5SAlp Dener   bnk->grad = 0;
87e031d6f5SAlp Dener 
88fed79b8eSAlp Dener   /* Initialize the Hessian perturbation */
89fed79b8eSAlp Dener   bnk->pert = bnk->sval;
90fed79b8eSAlp Dener 
91937a31a1SAlp Dener   /* Reset initial steplength to zero (this helps BNCG reset its direction internally) */
92937a31a1SAlp Dener   ierr = VecSet(tao->stepdirection, 0.0);CHKERRQ(ierr);
93937a31a1SAlp Dener 
94e031d6f5SAlp Dener   /* Allocate the vectors needed for the BFGS approximation */
95e031d6f5SAlp Dener   if (BNK_PC_BFGS == bnk->pc_type) {
96e031d6f5SAlp Dener     if (!bnk->M) {
97eb910715SAlp Dener       ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr);
98eb910715SAlp Dener       ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr);
99*cd929ea3SAlp Dener       ierr = MatCreateLBFGS(((PetscObject)tao)->comm,n,N,&bnk->M);CHKERRQ(ierr);
100*cd929ea3SAlp Dener       if (bnk->active_idx) {
101*cd929ea3SAlp Dener         ierr = MatCreateSubMatrixVirtual(bnk->M, bnk->inactive_idx, bnk->inactive_idx, &bnk->M_inactive);
102*cd929ea3SAlp Dener       } else {
103*cd929ea3SAlp Dener         ierr = PetscObjectReference((PetscObject)bnk->M);CHKERRQ(ierr);
104*cd929ea3SAlp Dener         bnk->M_inactive = bnk->M;
105*cd929ea3SAlp Dener       }
106*cd929ea3SAlp Dener       ierr = PetscObjectReference((PetscObject)bnk->M);CHKERRQ(ierr);
107*cd929ea3SAlp Dener       ierr = MatLMVMAllocate(bnk->M,tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
108eb910715SAlp Dener     }
109e031d6f5SAlp Dener     if (bnk->bfgs_scale_type != BFGS_SCALE_BFGS && !bnk->Diag) {
110e031d6f5SAlp Dener       ierr = VecDuplicate(tao->solution,&bnk->Diag);CHKERRQ(ierr);
1115e9b73cbSAlp Dener     }
112e031d6f5SAlp Dener   }
113e031d6f5SAlp Dener 
114e031d6f5SAlp Dener   /* Prepare the min/max vectors for safeguarding diagonal scales */
11562675beeSAlp Dener   ierr = VecSet(bnk->Diag_min, bnk->dmin);CHKERRQ(ierr);
11662675beeSAlp Dener   ierr = VecSet(bnk->Diag_max, bnk->dmax);CHKERRQ(ierr);
117eb910715SAlp Dener 
118eb910715SAlp Dener   /* Modify the preconditioner to use the bfgs approximation */
119eb910715SAlp Dener   ierr = KSPGetPC(tao->ksp, &pc);CHKERRQ(ierr);
120eb910715SAlp Dener   switch(bnk->pc_type) {
121eb910715SAlp Dener   case BNK_PC_NONE:
122eb910715SAlp Dener     ierr = PCSetType(pc, PCNONE);CHKERRQ(ierr);
123eb910715SAlp Dener     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
124eb910715SAlp Dener     break;
125eb910715SAlp Dener 
126eb910715SAlp Dener   case BNK_PC_AHESS:
127eb910715SAlp Dener     ierr = PCSetType(pc, PCJACOBI);CHKERRQ(ierr);
128eb910715SAlp Dener     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
129eb910715SAlp Dener     ierr = PCJacobiSetUseAbs(pc,PETSC_TRUE);CHKERRQ(ierr);
130eb910715SAlp Dener     break;
131eb910715SAlp Dener 
132eb910715SAlp Dener   case BNK_PC_BFGS:
133eb910715SAlp Dener     ierr = PCSetType(pc, PCSHELL);CHKERRQ(ierr);
134eb910715SAlp Dener     ierr = PCSetFromOptions(pc);CHKERRQ(ierr);
135eb910715SAlp Dener     ierr = PCShellSetName(pc, "bfgs");CHKERRQ(ierr);
136*cd929ea3SAlp Dener     ierr = PCShellSetContext(pc, bnk->M_inactive);CHKERRQ(ierr);
137*cd929ea3SAlp Dener     ierr = PCShellSetApply(pc, TaoBNKPreconBFGS);CHKERRQ(ierr);
138eb910715SAlp Dener     break;
139eb910715SAlp Dener 
140eb910715SAlp Dener   default:
141eb910715SAlp Dener     /* Use the pc method set by pc_type */
142eb910715SAlp Dener     break;
143eb910715SAlp Dener   }
144eb910715SAlp Dener 
145eb910715SAlp Dener   /* Initialize trust-region radius.  The initialization is only performed
146eb910715SAlp Dener      when we are using Nash, Steihaug-Toint or the Generalized Lanczos method. */
147c0f10754SAlp Dener   *needH = PETSC_TRUE;
148eb910715SAlp Dener   if (bnk->is_nash || bnk->is_stcg || bnk->is_gltr) {
14962675beeSAlp Dener     switch(initType) {
150eb910715SAlp Dener     case BNK_INIT_CONSTANT:
151eb910715SAlp Dener       /* Use the initial radius specified */
152c0f10754SAlp Dener       tao->trust = tao->trust0;
153eb910715SAlp Dener       break;
154eb910715SAlp Dener 
155eb910715SAlp Dener     case BNK_INIT_INTERPOLATION:
156c0f10754SAlp Dener       /* Use interpolation based on the initial Hessian */
157eb910715SAlp Dener       max_radius = 0.0;
15808752603SAlp Dener       tao->trust = tao->trust0;
159eb910715SAlp Dener       for (j = 0; j < j_max; ++j) {
1600a4511e9SAlp Dener         f_min = bnk->f;
161eb910715SAlp Dener         sigma = 0.0;
162eb910715SAlp Dener 
163c0f10754SAlp Dener         if (*needH) {
16462602cfbSAlp Dener           /* Compute the Hessian at the new step, and extract the inactive subsystem */
165e031d6f5SAlp Dener           ierr = TaoBNKComputeHessian(tao);CHKERRQ(ierr);
16608752603SAlp Dener           ierr = TaoBNKEstimateActiveSet(tao, BNK_AS_NONE);CHKERRQ(ierr);
16789da521bSAlp Dener           ierr = MatDestroy(&bnk->H_inactive);CHKERRQ(ierr);
16889da521bSAlp Dener           if (bnk->active_idx) {
1692ab2a32cSAlp Dener             ierr = MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive);CHKERRQ(ierr);
17028017e9fSAlp Dener           } else {
17108752603SAlp Dener             ierr = MatDuplicate(tao->hessian, MAT_COPY_VALUES, &bnk->H_inactive);CHKERRQ(ierr);
17228017e9fSAlp Dener           }
173c0f10754SAlp Dener           *needH = PETSC_FALSE;
174eb910715SAlp Dener         }
175eb910715SAlp Dener 
176eb910715SAlp Dener         for (i = 0; i < i_max; ++i) {
17762602cfbSAlp Dener           /* Take a steepest descent step and snap it to bounds */
17862602cfbSAlp Dener           ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
17962602cfbSAlp Dener           ierr = VecAXPY(tao->solution, -tao->trust/bnk->gnorm, tao->gradient);CHKERRQ(ierr);
1803b063059SAlp Dener           ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
18189da521bSAlp Dener           /* Compute the step we actually accepted */
182eb910715SAlp Dener           ierr = VecCopy(tao->solution, bnk->W);CHKERRQ(ierr);
18362602cfbSAlp Dener           ierr = VecAXPY(bnk->W, -1.0, bnk->Xold);CHKERRQ(ierr);
18462602cfbSAlp Dener           /* Compute the objective at the trial */
18562602cfbSAlp Dener           ierr = TaoComputeObjective(tao, tao->solution, &ftrial);CHKERRQ(ierr);
186b4a30f08SAlp Dener           if (PetscIsInfOrNanReal(bnk->f)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
18762602cfbSAlp Dener           ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
188eb910715SAlp Dener           if (PetscIsInfOrNanReal(ftrial)) {
189eb910715SAlp Dener             tau = bnk->gamma1_i;
190eb910715SAlp Dener           } else {
1910a4511e9SAlp Dener             if (ftrial < f_min) {
1920a4511e9SAlp Dener               f_min = ftrial;
193eb910715SAlp Dener               sigma = -tao->trust / bnk->gnorm;
194eb910715SAlp Dener             }
19508752603SAlp Dener 
196770b7498SAlp Dener             /* Compute the predicted and actual reduction */
19789da521bSAlp Dener             if (bnk->active_idx) {
19808752603SAlp Dener               ierr = VecGetSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
19908752603SAlp Dener               ierr = VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work);CHKERRQ(ierr);
2002ab2a32cSAlp Dener             } else {
20108752603SAlp Dener               bnk->X_inactive = bnk->W;
20208752603SAlp Dener               bnk->inactive_work = bnk->Xwork;
2032ab2a32cSAlp Dener             }
20408752603SAlp Dener             ierr = MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work);CHKERRQ(ierr);
20508752603SAlp Dener             ierr = VecDot(bnk->X_inactive, bnk->inactive_work, &prered);CHKERRQ(ierr);
20689da521bSAlp Dener             if (bnk->active_idx) {
20708752603SAlp Dener               ierr = VecRestoreSubVector(bnk->W, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
20808752603SAlp Dener               ierr = VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work);CHKERRQ(ierr);
2092ab2a32cSAlp Dener             }
210eb910715SAlp Dener             prered = tao->trust * (bnk->gnorm - 0.5 * tao->trust * prered / (bnk->gnorm * bnk->gnorm));
211eb910715SAlp Dener             actred = bnk->f - ftrial;
2123105154fSTodd Munson             if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
213eb910715SAlp Dener               kappa = 1.0;
2143105154fSTodd Munson             } else {
215eb910715SAlp Dener               kappa = actred / prered;
216eb910715SAlp Dener             }
217eb910715SAlp Dener 
218eb910715SAlp Dener             tau_1 = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust + (1.0 - bnk->theta_i) * prered - actred);
219eb910715SAlp Dener             tau_2 = bnk->theta_i * bnk->gnorm * tao->trust / (bnk->theta_i * bnk->gnorm * tao->trust - (1.0 + bnk->theta_i) * prered + actred);
220eb910715SAlp Dener             tau_min = PetscMin(tau_1, tau_2);
221eb910715SAlp Dener             tau_max = PetscMax(tau_1, tau_2);
222eb910715SAlp Dener 
223eb910715SAlp Dener             if (PetscAbsScalar(kappa - 1.0) <= bnk->mu1_i) {
224eb910715SAlp Dener               /*  Great agreement */
225eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
226eb910715SAlp Dener 
227eb910715SAlp Dener               if (tau_max < 1.0) {
228eb910715SAlp Dener                 tau = bnk->gamma3_i;
2293105154fSTodd Munson               } else if (tau_max > bnk->gamma4_i) {
230eb910715SAlp Dener                 tau = bnk->gamma4_i;
2313105154fSTodd Munson               } else {
232eb910715SAlp Dener                 tau = tau_max;
233eb910715SAlp Dener               }
2348f8a4e06SAlp Dener             } else if (PetscAbsScalar(kappa - 1.0) <= bnk->mu2_i) {
235eb910715SAlp Dener               /*  Good agreement */
236eb910715SAlp Dener               max_radius = PetscMax(max_radius, tao->trust);
237eb910715SAlp Dener 
238eb910715SAlp Dener               if (tau_max < bnk->gamma2_i) {
239eb910715SAlp Dener                 tau = bnk->gamma2_i;
240eb910715SAlp Dener               } else if (tau_max > bnk->gamma3_i) {
241eb910715SAlp Dener                 tau = bnk->gamma3_i;
242eb910715SAlp Dener               } else {
243eb910715SAlp Dener                 tau = tau_max;
244eb910715SAlp Dener               }
2458f8a4e06SAlp Dener             } else {
246eb910715SAlp Dener               /*  Not good agreement */
247eb910715SAlp Dener               if (tau_min > 1.0) {
248eb910715SAlp Dener                 tau = bnk->gamma2_i;
249eb910715SAlp Dener               } else if (tau_max < bnk->gamma1_i) {
250eb910715SAlp Dener                 tau = bnk->gamma1_i;
251eb910715SAlp Dener               } else if ((tau_min < bnk->gamma1_i) && (tau_max >= 1.0)) {
252eb910715SAlp Dener                 tau = bnk->gamma1_i;
2533105154fSTodd Munson               } else if ((tau_1 >= bnk->gamma1_i) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
254eb910715SAlp Dener                 tau = tau_1;
2553105154fSTodd Munson               } else if ((tau_2 >= bnk->gamma1_i) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1_i) || (tau_2 >= 1.0))) {
256eb910715SAlp Dener                 tau = tau_2;
257eb910715SAlp Dener               } else {
258eb910715SAlp Dener                 tau = tau_max;
259eb910715SAlp Dener               }
260eb910715SAlp Dener             }
261eb910715SAlp Dener           }
262eb910715SAlp Dener           tao->trust = tau * tao->trust;
263eb910715SAlp Dener         }
264eb910715SAlp Dener 
2650a4511e9SAlp Dener         if (f_min < bnk->f) {
266937a31a1SAlp Dener           /* We accidentally found a solution better than the initial, so accept it */
2670a4511e9SAlp Dener           bnk->f = f_min;
268937a31a1SAlp Dener           ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
269eb910715SAlp Dener           ierr = VecAXPY(tao->solution,sigma,tao->gradient);CHKERRQ(ierr);
2703b063059SAlp Dener           ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
271937a31a1SAlp Dener           ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
272937a31a1SAlp Dener           ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
27309164190SAlp Dener           ierr = TaoComputeGradient(tao,tao->solution,bnk->unprojected_gradient);CHKERRQ(ierr);
27461be54a6SAlp Dener           ierr = TaoBNKEstimateActiveSet(tao, bnk->as_type);CHKERRQ(ierr);
27561be54a6SAlp Dener           ierr = VecCopy(bnk->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
27661be54a6SAlp Dener           ierr = VecISSet(tao->gradient, bnk->active_idx, 0.0);CHKERRQ(ierr);
277937a31a1SAlp Dener           /* Compute gradient at the new iterate and flip switch to compute the Hessian later */
278c4b75bccSAlp Dener           ierr = VecNorm(tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
279c0f10754SAlp Dener           *needH = PETSC_TRUE;
280937a31a1SAlp Dener           /* Test the new step for convergence */
28189da521bSAlp Dener           ierr = VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->W);CHKERRQ(ierr);
28289da521bSAlp Dener           ierr = VecNorm(bnk->W, NORM_2, &resnorm);CHKERRQ(ierr);
283b4a30f08SAlp Dener           if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
284e031d6f5SAlp Dener           ierr = TaoLogConvergenceHistory(tao,bnk->f,resnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
285e031d6f5SAlp Dener           ierr = TaoMonitor(tao,tao->niter,bnk->f,resnorm,0.0,1.0);CHKERRQ(ierr);
286eb910715SAlp Dener           ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
287eb910715SAlp Dener           if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
288937a31a1SAlp Dener           /* active BNCG recycling early because we have a stepdirection computed */
289937a31a1SAlp Dener           ierr = TaoBNCGSetRecycleFlag(bnk->bncg, PETSC_TRUE);CHKERRQ(ierr);
290eb910715SAlp Dener         }
291eb910715SAlp Dener       }
292eb910715SAlp Dener       tao->trust = PetscMax(tao->trust, max_radius);
293e031d6f5SAlp Dener 
294e031d6f5SAlp Dener       /* Ensure that the trust radius is within the limits */
295e031d6f5SAlp Dener       tao->trust = PetscMax(tao->trust, bnk->min_radius);
296e031d6f5SAlp Dener       tao->trust = PetscMin(tao->trust, bnk->max_radius);
297eb910715SAlp Dener       break;
298eb910715SAlp Dener 
299eb910715SAlp Dener     default:
300eb910715SAlp Dener       /* Norm of the first direction will initialize radius */
301eb910715SAlp Dener       tao->trust = 0.0;
302eb910715SAlp Dener       break;
303eb910715SAlp Dener     }
304eb910715SAlp Dener   }
305e031d6f5SAlp Dener 
306eb910715SAlp Dener   /* Set initial scaling for the BFGS preconditioner
307eb910715SAlp Dener      This step is done after computing the initial trust-region radius
308eb910715SAlp Dener      since the function value may have decreased */
309eb910715SAlp Dener   if (BNK_PC_BFGS == bnk->pc_type) {
3109b6ef848SAlp Dener     delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
311*cd929ea3SAlp Dener     ierr = MatLMVMSetJ0Scale(bnk->M, delta);CHKERRQ(ierr);
312eb910715SAlp Dener   }
313eb910715SAlp Dener   PetscFunctionReturn(0);
314eb910715SAlp Dener }
315eb910715SAlp Dener 
316df278d8fSAlp Dener /*------------------------------------------------------------*/
317df278d8fSAlp Dener 
31862675beeSAlp Dener /* Routine for computing the Hessian and preparing the preconditioner at the new iterate */
31962675beeSAlp Dener 
32062675beeSAlp Dener PetscErrorCode TaoBNKComputeHessian(Tao tao)
32162675beeSAlp Dener {
32262675beeSAlp Dener   PetscErrorCode               ierr;
32362675beeSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
324c4b75bccSAlp Dener   PetscBool                    diagExists;
325c4b75bccSAlp Dener   PetscReal                    delta;
32662675beeSAlp Dener 
32762675beeSAlp Dener   PetscFunctionBegin;
32862675beeSAlp Dener   /* Compute the Hessian */
32962675beeSAlp Dener   ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
33062675beeSAlp Dener   /* Add a correction to the BFGS preconditioner */
3317ab9f534SAlp Dener   if (BNK_PC_BFGS == bnk->pc_type && bnk->M) {
33262675beeSAlp Dener     ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
33362675beeSAlp Dener     /* Update the BFGS diagonal scaling */
334c4b75bccSAlp Dener     ierr = MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &diagExists);CHKERRQ(ierr);
335c4b75bccSAlp Dener     if (BFGS_SCALE_AHESS == bnk->bfgs_scale_type && diagExists) {
33662675beeSAlp Dener       ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
33762675beeSAlp Dener       ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
33862675beeSAlp Dener       ierr = VecMedian(bnk->Diag_min, bnk->Diag, bnk->Diag_max, bnk->Diag);CHKERRQ(ierr);
33962675beeSAlp Dener       ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
340*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Diag(bnk->M,bnk->Diag);CHKERRQ(ierr);
341c4b75bccSAlp Dener     } else {
342c4b75bccSAlp Dener       /* Fall back onto stand-alone BFGS scaling */
343c4b75bccSAlp Dener       delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
344*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Scale(bnk->M,delta);CHKERRQ(ierr);
34562675beeSAlp Dener     }
34662675beeSAlp Dener   }
34762675beeSAlp Dener   PetscFunctionReturn(0);
34862675beeSAlp Dener }
34962675beeSAlp Dener 
35062675beeSAlp Dener /*------------------------------------------------------------*/
35162675beeSAlp Dener 
3522f75a4aaSAlp Dener /* Routine for estimating the active set */
3532f75a4aaSAlp Dener 
35408752603SAlp Dener PetscErrorCode TaoBNKEstimateActiveSet(Tao tao, PetscInt asType)
3552f75a4aaSAlp Dener {
3562f75a4aaSAlp Dener   PetscErrorCode               ierr;
3572f75a4aaSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
358c4b75bccSAlp Dener   PetscBool                    hessComputed, diagExists;
3592f75a4aaSAlp Dener 
3602f75a4aaSAlp Dener   PetscFunctionBegin;
361*cd929ea3SAlp Dener   if (!tao->bounded) PetscFunctionReturn(0);
36208752603SAlp Dener   switch (asType) {
3632f75a4aaSAlp Dener   case BNK_AS_NONE:
3642f75a4aaSAlp Dener     ierr = ISDestroy(&bnk->inactive_idx);CHKERRQ(ierr);
3652f75a4aaSAlp Dener     ierr = VecWhichInactive(tao->XL, tao->solution, bnk->unprojected_gradient, tao->XU, PETSC_TRUE, &bnk->inactive_idx);CHKERRQ(ierr);
3662f75a4aaSAlp Dener     ierr = ISDestroy(&bnk->active_idx);CHKERRQ(ierr);
3672f75a4aaSAlp Dener     ierr = ISComplementVec(bnk->inactive_idx, tao->solution, &bnk->active_idx);CHKERRQ(ierr);
3682f75a4aaSAlp Dener     break;
3692f75a4aaSAlp Dener 
3702f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
3712f75a4aaSAlp Dener     /* Compute the trial step vector with which we will estimate the active set at the next iteration */
3727ab9f534SAlp Dener     if (BNK_PC_BFGS == bnk->pc_type && bnk->M) {
3732f75a4aaSAlp Dener       /* If the BFGS preconditioner matrix is available, we will construct a trial step with it */
374*cd929ea3SAlp Dener       ierr = MatSolve(bnk->M, bnk->unprojected_gradient, bnk->W);CHKERRQ(ierr);
3752f75a4aaSAlp Dener     } else {
37661be54a6SAlp Dener       ierr = MatAssembled(tao->hessian, &hessComputed);CHKERRQ(ierr);
377c4b75bccSAlp Dener       ierr = MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &diagExists);CHKERRQ(ierr);
378c4b75bccSAlp Dener       if (hessComputed && diagExists) {
3799b6ef848SAlp Dener         /* BFGS preconditioner doesn't exist so let's invert the absolute diagonal of the Hessian instead onto the gradient */
3802f75a4aaSAlp Dener         ierr = MatGetDiagonal(tao->hessian, bnk->Xwork);CHKERRQ(ierr);
3819b6ef848SAlp Dener         ierr = VecAbs(bnk->Xwork);CHKERRQ(ierr);
3829b6ef848SAlp Dener         ierr = VecMedian(bnk->Diag_min, bnk->Xwork, bnk->Diag_max, bnk->Xwork);CHKERRQ(ierr);
3832f75a4aaSAlp Dener         ierr = VecReciprocal(bnk->Xwork);CHKERRQ(ierr);CHKERRQ(ierr);
3842f75a4aaSAlp Dener         ierr = VecPointwiseMult(bnk->W, bnk->Xwork, bnk->unprojected_gradient);CHKERRQ(ierr);
38561be54a6SAlp Dener       } else {
386c4b75bccSAlp Dener         /* If the Hessian or its diagonal does not exist, we will simply use gradient step */
38761be54a6SAlp Dener         ierr = VecCopy(bnk->unprojected_gradient, bnk->W);CHKERRQ(ierr);
38861be54a6SAlp Dener       }
3892f75a4aaSAlp Dener     }
3902f75a4aaSAlp Dener     ierr = VecScale(bnk->W, -1.0);CHKERRQ(ierr);
39189da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, bnk->unprojected_gradient, bnk->W, bnk->Xwork, bnk->as_step, &bnk->as_tol,
39289da521bSAlp Dener                                    &bnk->active_lower, &bnk->active_upper, &bnk->active_fixed, &bnk->active_idx, &bnk->inactive_idx);CHKERRQ(ierr);
393c4b75bccSAlp Dener     break;
3942f75a4aaSAlp Dener 
3952f75a4aaSAlp Dener   default:
3962f75a4aaSAlp Dener     break;
3972f75a4aaSAlp Dener   }
3982f75a4aaSAlp Dener   PetscFunctionReturn(0);
3992f75a4aaSAlp Dener }
4002f75a4aaSAlp Dener 
4012f75a4aaSAlp Dener /*------------------------------------------------------------*/
4022f75a4aaSAlp Dener 
4032f75a4aaSAlp Dener /* Routine for bounding the step direction */
4042f75a4aaSAlp Dener 
405a1318120SAlp Dener PetscErrorCode TaoBNKBoundStep(Tao tao, PetscInt asType, Vec step)
4062f75a4aaSAlp Dener {
4072f75a4aaSAlp Dener   PetscErrorCode               ierr;
4082f75a4aaSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
4092f75a4aaSAlp Dener 
4102f75a4aaSAlp Dener   PetscFunctionBegin;
411*cd929ea3SAlp Dener   if (!tao->bounded) PetscFunctionReturn(0);
412a1318120SAlp Dener   switch (asType) {
4132f75a4aaSAlp Dener   case BNK_AS_NONE:
414c4b75bccSAlp Dener     ierr = VecISSet(step, bnk->active_idx, 0.0);CHKERRQ(ierr);
4152f75a4aaSAlp Dener     break;
4162f75a4aaSAlp Dener 
4172f75a4aaSAlp Dener   case BNK_AS_BERTSEKAS:
418c4b75bccSAlp Dener     ierr = TaoBoundStep(tao->solution, tao->XL, tao->XU, bnk->active_lower, bnk->active_upper, bnk->active_fixed, 1.0, step);CHKERRQ(ierr);
4192f75a4aaSAlp Dener     break;
4202f75a4aaSAlp Dener 
4212f75a4aaSAlp Dener   default:
4222f75a4aaSAlp Dener     break;
4232f75a4aaSAlp Dener   }
4242f75a4aaSAlp Dener   PetscFunctionReturn(0);
4252f75a4aaSAlp Dener }
4262f75a4aaSAlp Dener 
427e031d6f5SAlp Dener /*------------------------------------------------------------*/
428e031d6f5SAlp Dener 
429e031d6f5SAlp Dener /* Routine for taking a finite number of BNCG iterations to
430e031d6f5SAlp Dener    accelerate Newton convergence.
431e031d6f5SAlp Dener 
432e031d6f5SAlp Dener    In practice, this approach simply trades off Hessian evaluations
433e031d6f5SAlp Dener    for more gradient evaluations.
434e031d6f5SAlp Dener */
435e031d6f5SAlp Dener 
436c0f10754SAlp Dener PetscErrorCode TaoBNKTakeCGSteps(Tao tao, PetscBool *terminate)
437c0f10754SAlp Dener {
438c0f10754SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
439c0f10754SAlp Dener   PetscErrorCode               ierr;
440c0f10754SAlp Dener 
441c0f10754SAlp Dener   PetscFunctionBegin;
442c0f10754SAlp Dener   *terminate = PETSC_FALSE;
443c0f10754SAlp Dener   if (bnk->max_cg_its > 0) {
444c4b75bccSAlp Dener     /* Copy the current function value (important vectors are already shared) */
445c0f10754SAlp Dener     bnk->bncg_ctx->f = bnk->f;
446c0f10754SAlp Dener     /* Take some small finite number of BNCG iterations */
447c0f10754SAlp Dener     ierr = TaoSolve(bnk->bncg);CHKERRQ(ierr);
448c0f10754SAlp Dener     /* Add the number of gradient and function evaluations to the total */
449c0f10754SAlp Dener     tao->nfuncs += bnk->bncg->nfuncs;
450c0f10754SAlp Dener     tao->nfuncgrads += bnk->bncg->nfuncgrads;
451c0f10754SAlp Dener     tao->ngrads += bnk->bncg->ngrads;
452c0f10754SAlp Dener     tao->nhess += bnk->bncg->nhess;
453e031d6f5SAlp Dener     bnk->tot_cg_its += bnk->bncg->niter;
454c4b75bccSAlp Dener     /* Extract the BNCG function value out and save it into BNK */
455c0f10754SAlp Dener     bnk->f = bnk->bncg_ctx->f;
456c0f10754SAlp 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) {
457c0f10754SAlp Dener       *terminate = PETSC_TRUE;
45861be54a6SAlp Dener     } else {
45933c78596SAlp Dener       ierr = TaoBNKEstimateActiveSet(tao, bnk->as_type);CHKERRQ(ierr);
460c0f10754SAlp Dener     }
461c0f10754SAlp Dener   }
462c0f10754SAlp Dener   PetscFunctionReturn(0);
463c0f10754SAlp Dener }
464c0f10754SAlp Dener 
4652f75a4aaSAlp Dener /*------------------------------------------------------------*/
4662f75a4aaSAlp Dener 
467c0f10754SAlp Dener /* Routine for computing the Newton step. */
468df278d8fSAlp Dener 
46962675beeSAlp Dener PetscErrorCode TaoBNKComputeStep(Tao tao, PetscBool shift, KSPConvergedReason *ksp_reason)
470eb910715SAlp Dener {
471eb910715SAlp Dener   PetscErrorCode               ierr;
472eb910715SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
473eb910715SAlp Dener 
474e465cd6fSAlp Dener   PetscReal                    delta;
475eb910715SAlp Dener   PetscInt                     bfgsUpdates = 0;
476eb910715SAlp Dener   PetscInt                     kspits;
477c4b75bccSAlp Dener   PetscBool                    diagExists;
478eb910715SAlp Dener 
479eb910715SAlp Dener   PetscFunctionBegin;
48089da521bSAlp Dener   /* If there are no inactive variables left, save some computation and return an adjusted zero step
48189da521bSAlp Dener      that has (l-x) and (u-x) for lower and upper bounded variables. */
48289da521bSAlp Dener   if (!bnk->inactive_idx) {
48389da521bSAlp Dener     ierr = VecSet(tao->stepdirection, 0.0);CHKERRQ(ierr);
484a1318120SAlp Dener     ierr = TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection);CHKERRQ(ierr);
48589da521bSAlp Dener     PetscFunctionReturn(0);
48689da521bSAlp Dener   }
48789da521bSAlp Dener 
4885e9b73cbSAlp Dener   /* Prepare the reduced sub-matrices for the inactive set */
4893105154fSTodd Munson   if (BNK_PC_BFGS == bnk->pc_type) {
490*cd929ea3SAlp Dener     ierr = MatDestroy(&bnk->M_inactive);CHKERRQ(ierr);
491*cd929ea3SAlp Dener     if (bnk->active_idx) {
492*cd929ea3SAlp Dener       ierr = MatCreateSubMatrixVirtual(bnk->M, bnk->inactive_idx, bnk->inactive_idx, &bnk->M_inactive);CHKERRQ(ierr);
493*cd929ea3SAlp Dener     } else {
494*cd929ea3SAlp Dener       bnk->M_inactive = bnk->M;
495*cd929ea3SAlp Dener       ierr = PetscObjectReference((PetscObject)bnk->M);CHKERRQ(ierr);
496*cd929ea3SAlp Dener     }
4973105154fSTodd Munson   }
49889da521bSAlp Dener   if (bnk->active_idx) {
49933c78596SAlp Dener     ierr = MatDestroy(&bnk->H_inactive);CHKERRQ(ierr);
5005e9b73cbSAlp Dener     ierr = MatCreateSubMatrix(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->H_inactive);CHKERRQ(ierr);
501eb3ba6a7SAlp Dener     if (tao->hessian == tao->hessian_pre) {
502eb3ba6a7SAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
503eb3ba6a7SAlp Dener     } else {
50433c78596SAlp Dener       ierr = MatDestroy(&bnk->Hpre_inactive);CHKERRQ(ierr);
5055e9b73cbSAlp Dener       ierr = MatCreateSubMatrix(tao->hessian_pre, bnk->inactive_idx, bnk->inactive_idx, MAT_INITIAL_MATRIX, &bnk->Hpre_inactive);CHKERRQ(ierr);
506eb3ba6a7SAlp Dener     }
5072f75a4aaSAlp Dener   } else {
50833c78596SAlp Dener     ierr = MatDestroy(&bnk->H_inactive);CHKERRQ(ierr);
50933c78596SAlp Dener     ierr = MatDuplicate(tao->hessian, MAT_COPY_VALUES, &bnk->H_inactive);CHKERRQ(ierr);
51062675beeSAlp Dener     if (tao->hessian == tao->hessian_pre) {
51162675beeSAlp Dener       bnk->Hpre_inactive = bnk->H_inactive;
51262675beeSAlp Dener     } else {
51333c78596SAlp Dener       ierr = MatDestroy(&bnk->Hpre_inactive);CHKERRQ(ierr);
51433c78596SAlp Dener       ierr = MatDuplicate(tao->hessian_pre, MAT_COPY_VALUES, &bnk->Hpre_inactive);CHKERRQ(ierr);
51562675beeSAlp Dener     }
51662675beeSAlp Dener   }
51762675beeSAlp Dener 
51862675beeSAlp Dener   /* Shift the reduced Hessian matrix */
51962675beeSAlp Dener   if ((shift) && (bnk->pert > 0)) {
52062675beeSAlp Dener     ierr = MatShift(bnk->H_inactive, bnk->pert);CHKERRQ(ierr);
52162675beeSAlp Dener     if (bnk->H_inactive != bnk->Hpre_inactive) {
52262675beeSAlp Dener       ierr = MatShift(bnk->Hpre_inactive, bnk->pert);CHKERRQ(ierr);
52362675beeSAlp Dener     }
52462675beeSAlp Dener   }
52562675beeSAlp Dener 
52662675beeSAlp Dener   /* Update the diagonal scaling for the BFGS preconditioner, this time with the Hessian perturbation */
52762675beeSAlp Dener   if ((BNK_PC_BFGS == bnk->pc_type) && (BFGS_SCALE_PHESS == bnk->bfgs_scale_type)) {
528c4b75bccSAlp Dener     ierr = MatHasOperation(bnk->H_inactive, MATOP_GET_DIAGONAL, &diagExists);CHKERRQ(ierr);
529c4b75bccSAlp Dener     if (diagExists) {
53062675beeSAlp Dener       /* Obtain diagonal for the bfgs preconditioner  */
5315e9b73cbSAlp Dener       ierr = VecSet(bnk->Diag, 1.0);CHKERRQ(ierr);
53289da521bSAlp Dener       if (bnk->active_idx) {
5335e9b73cbSAlp Dener         ierr = VecGetSubVector(bnk->Diag, bnk->inactive_idx, &bnk->Diag_red);CHKERRQ(ierr);
5345e9b73cbSAlp Dener       } else {
5355e9b73cbSAlp Dener         bnk->Diag_red = bnk->Diag;
5365e9b73cbSAlp Dener       }
5375e9b73cbSAlp Dener       ierr = MatGetDiagonal(bnk->H_inactive, bnk->Diag_red);CHKERRQ(ierr);
53889da521bSAlp Dener       if (bnk->active_idx) {
5395e9b73cbSAlp Dener         ierr = VecRestoreSubVector(bnk->Diag, bnk->inactive_idx, &bnk->Diag_red);CHKERRQ(ierr);
5405e9b73cbSAlp Dener       }
54162675beeSAlp Dener       ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
54262675beeSAlp Dener       ierr = VecMedian(bnk->Diag_min, bnk->Diag, bnk->Diag_max, bnk->Diag);CHKERRQ(ierr);
54362675beeSAlp Dener       ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
544*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Diag(bnk->M,bnk->Diag);CHKERRQ(ierr);
545c4b75bccSAlp Dener     } else {
546c4b75bccSAlp Dener       /* Fall back onto stand-alone BFGS scaling */
547c4b75bccSAlp Dener       delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
548*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Scale(bnk->M,delta);CHKERRQ(ierr);
549c4b75bccSAlp Dener     }
5502f75a4aaSAlp Dener   }
55109164190SAlp Dener 
552eb910715SAlp Dener   /* Solve the Newton system of equations */
553937a31a1SAlp Dener   tao->ksp_its = 0;
5542f75a4aaSAlp Dener   ierr = VecSet(tao->stepdirection, 0.0);CHKERRQ(ierr);
5555e9b73cbSAlp Dener   ierr = KSPReset(tao->ksp);CHKERRQ(ierr);
55609164190SAlp Dener   ierr = KSPSetOperators(tao->ksp,bnk->H_inactive,bnk->Hpre_inactive);CHKERRQ(ierr);
5575e9b73cbSAlp Dener   ierr = VecCopy(bnk->unprojected_gradient, bnk->Gwork);CHKERRQ(ierr);
55889da521bSAlp Dener   if (bnk->active_idx) {
5595e9b73cbSAlp Dener     ierr = VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive);CHKERRQ(ierr);
5605e9b73cbSAlp Dener     ierr = VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
5615e9b73cbSAlp Dener   } else {
5625e9b73cbSAlp Dener     bnk->G_inactive = bnk->unprojected_gradient;
5635e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
56428017e9fSAlp Dener   }
565eb910715SAlp Dener   if (bnk->is_nash || bnk->is_stcg || bnk->is_gltr) {
566fed79b8eSAlp Dener     ierr = KSPCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr);
5675e9b73cbSAlp Dener     ierr = KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive);CHKERRQ(ierr);
568eb910715SAlp Dener     ierr = KSPGetIterationNumber(tao->ksp,&kspits);CHKERRQ(ierr);
569eb910715SAlp Dener     tao->ksp_its+=kspits;
570eb910715SAlp Dener     tao->ksp_tot_its+=kspits;
571080d2917SAlp Dener     ierr = KSPCGGetNormD(tao->ksp,&bnk->dnorm);CHKERRQ(ierr);
572eb910715SAlp Dener 
573eb910715SAlp Dener     if (0.0 == tao->trust) {
574eb910715SAlp Dener       /* Radius was uninitialized; use the norm of the direction */
575080d2917SAlp Dener       if (bnk->dnorm > 0.0) {
576080d2917SAlp Dener         tao->trust = bnk->dnorm;
577eb910715SAlp Dener 
578eb910715SAlp Dener         /* Modify the radius if it is too large or small */
579eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
580eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
581eb910715SAlp Dener       } else {
582eb910715SAlp Dener         /* The direction was bad; set radius to default value and re-solve
583eb910715SAlp Dener            the trust-region subproblem to get a direction */
584eb910715SAlp Dener         tao->trust = tao->trust0;
585eb910715SAlp Dener 
586eb910715SAlp Dener         /* Modify the radius if it is too large or small */
587eb910715SAlp Dener         tao->trust = PetscMax(tao->trust, bnk->min_radius);
588eb910715SAlp Dener         tao->trust = PetscMin(tao->trust, bnk->max_radius);
589eb910715SAlp Dener 
590fed79b8eSAlp Dener         ierr = KSPCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr);
5915e9b73cbSAlp Dener         ierr = KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive);CHKERRQ(ierr);
592eb910715SAlp Dener         ierr = KSPGetIterationNumber(tao->ksp,&kspits);CHKERRQ(ierr);
593eb910715SAlp Dener         tao->ksp_its+=kspits;
594eb910715SAlp Dener         tao->ksp_tot_its+=kspits;
595080d2917SAlp Dener         ierr = KSPCGGetNormD(tao->ksp,&bnk->dnorm);CHKERRQ(ierr);
596eb910715SAlp Dener 
597080d2917SAlp Dener         if (bnk->dnorm == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero");
598eb910715SAlp Dener       }
599eb910715SAlp Dener     }
600eb910715SAlp Dener   } else {
6015e9b73cbSAlp Dener     ierr = KSPSolve(tao->ksp, bnk->G_inactive, bnk->X_inactive);CHKERRQ(ierr);
602eb910715SAlp Dener     ierr = KSPGetIterationNumber(tao->ksp, &kspits);CHKERRQ(ierr);
603eb910715SAlp Dener     tao->ksp_its += kspits;
604eb910715SAlp Dener     tao->ksp_tot_its+=kspits;
605eb910715SAlp Dener   }
6065e9b73cbSAlp Dener   /* Restore sub vectors back */
60789da521bSAlp Dener   if (bnk->active_idx) {
6085e9b73cbSAlp Dener     ierr = VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive);CHKERRQ(ierr);
6095e9b73cbSAlp Dener     ierr = VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
6105e9b73cbSAlp Dener   }
611770b7498SAlp Dener   /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
612fed79b8eSAlp Dener   ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
613a1318120SAlp Dener   ierr = TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection);CHKERRQ(ierr);
614770b7498SAlp Dener 
615770b7498SAlp Dener   /* Record convergence reasons */
616e465cd6fSAlp Dener   ierr = KSPGetConvergedReason(tao->ksp, ksp_reason);CHKERRQ(ierr);
617e465cd6fSAlp Dener   if (KSP_CONVERGED_ATOL == *ksp_reason) {
618770b7498SAlp Dener     ++bnk->ksp_atol;
619e465cd6fSAlp Dener   } else if (KSP_CONVERGED_RTOL == *ksp_reason) {
620770b7498SAlp Dener     ++bnk->ksp_rtol;
621e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_CONSTRAINED == *ksp_reason) {
622770b7498SAlp Dener     ++bnk->ksp_ctol;
623e465cd6fSAlp Dener   } else if (KSP_CONVERGED_CG_NEG_CURVE == *ksp_reason) {
624770b7498SAlp Dener     ++bnk->ksp_negc;
625e465cd6fSAlp Dener   } else if (KSP_DIVERGED_DTOL == *ksp_reason) {
626770b7498SAlp Dener     ++bnk->ksp_dtol;
627e465cd6fSAlp Dener   } else if (KSP_DIVERGED_ITS == *ksp_reason) {
628770b7498SAlp Dener     ++bnk->ksp_iter;
629770b7498SAlp Dener   } else {
630770b7498SAlp Dener     ++bnk->ksp_othr;
631770b7498SAlp Dener   }
632fed79b8eSAlp Dener 
633fed79b8eSAlp Dener   /* Make sure the BFGS preconditioner is healthy */
634fed79b8eSAlp Dener   if (bnk->pc_type == BNK_PC_BFGS) {
635*cd929ea3SAlp Dener     ierr = MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
636e465cd6fSAlp Dener     if ((KSP_DIVERGED_INDEFINITE_PC == *ksp_reason) && (bfgsUpdates > 1)) {
637fed79b8eSAlp Dener       /* Preconditioner is numerically indefinite; reset the approximation. */
6389b6ef848SAlp Dener       delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
639*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Scale(bnk->M,delta);CHKERRQ(ierr);
640*cd929ea3SAlp Dener       ierr = MatLMVMReset(bnk->M, PETSC_FALSE);CHKERRQ(ierr);
64109164190SAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
642eb910715SAlp Dener     }
643fed79b8eSAlp Dener   }
644e465cd6fSAlp Dener   PetscFunctionReturn(0);
645e465cd6fSAlp Dener }
646eb910715SAlp Dener 
64762675beeSAlp Dener /*------------------------------------------------------------*/
64862675beeSAlp Dener 
6495e9b73cbSAlp Dener /* Routine for recomputing the predicted reduction for a given step vector */
6505e9b73cbSAlp Dener 
6515e9b73cbSAlp Dener PetscErrorCode TaoBNKRecomputePred(Tao tao, Vec S, PetscReal *prered)
6525e9b73cbSAlp Dener {
6535e9b73cbSAlp Dener   PetscErrorCode               ierr;
6545e9b73cbSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
6555e9b73cbSAlp Dener 
6565e9b73cbSAlp Dener   PetscFunctionBegin;
6575e9b73cbSAlp Dener   /* Extract subvectors associated with the inactive set */
65889da521bSAlp Dener   if (bnk->active_idx){
6595e9b73cbSAlp Dener     ierr = VecGetSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
6605e9b73cbSAlp Dener     ierr = VecGetSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work);CHKERRQ(ierr);
6615e9b73cbSAlp Dener     ierr = VecGetSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive);CHKERRQ(ierr);
6625e9b73cbSAlp Dener   } else {
6635e9b73cbSAlp Dener     bnk->X_inactive = tao->stepdirection;
6645e9b73cbSAlp Dener     bnk->inactive_work = bnk->Xwork;
6655e9b73cbSAlp Dener     bnk->G_inactive = bnk->Gwork;
6665e9b73cbSAlp Dener   }
6675e9b73cbSAlp Dener   /* Recompute the predicted decrease based on the quadratic model */
6685e9b73cbSAlp Dener   ierr = MatMult(bnk->H_inactive, bnk->X_inactive, bnk->inactive_work);CHKERRQ(ierr);
6695e9b73cbSAlp Dener   ierr = VecAYPX(bnk->inactive_work, -0.5, bnk->G_inactive);CHKERRQ(ierr);
67033c78596SAlp Dener   ierr = VecDot(bnk->inactive_work, bnk->X_inactive, prered);CHKERRQ(ierr);
6715e9b73cbSAlp Dener   /* Restore the sub vectors */
67289da521bSAlp Dener   if (bnk->active_idx){
6735e9b73cbSAlp Dener     ierr = VecRestoreSubVector(tao->stepdirection, bnk->inactive_idx, &bnk->X_inactive);CHKERRQ(ierr);
6745e9b73cbSAlp Dener     ierr = VecRestoreSubVector(bnk->Xwork, bnk->inactive_idx, &bnk->inactive_work);CHKERRQ(ierr);
6755e9b73cbSAlp Dener     ierr = VecRestoreSubVector(bnk->Gwork, bnk->inactive_idx, &bnk->G_inactive);CHKERRQ(ierr);
6765e9b73cbSAlp Dener   }
6775e9b73cbSAlp Dener   PetscFunctionReturn(0);
6785e9b73cbSAlp Dener }
6795e9b73cbSAlp Dener 
6805e9b73cbSAlp Dener /*------------------------------------------------------------*/
6815e9b73cbSAlp Dener 
68262675beeSAlp Dener /* Routine for ensuring that the Newton step is a descent direction.
68362675beeSAlp Dener 
68462675beeSAlp Dener    The step direction falls back onto BFGS, scaled gradient and gradient steps
68562675beeSAlp Dener    in the event that the Newton step fails the test.
68662675beeSAlp Dener */
68762675beeSAlp Dener 
688e465cd6fSAlp Dener PetscErrorCode TaoBNKSafeguardStep(Tao tao, KSPConvergedReason ksp_reason, PetscInt *stepType)
689e465cd6fSAlp Dener {
690e465cd6fSAlp Dener   PetscErrorCode               ierr;
691e465cd6fSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
692e465cd6fSAlp Dener 
693e465cd6fSAlp Dener   PetscReal                    gdx, delta, e_min;
694e465cd6fSAlp Dener   PetscInt                     bfgsUpdates;
695e465cd6fSAlp Dener 
696e465cd6fSAlp Dener   PetscFunctionBegin;
697080d2917SAlp Dener   ierr = VecDot(tao->stepdirection, tao->gradient, &gdx);CHKERRQ(ierr);
698eb910715SAlp Dener   if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
699eb910715SAlp Dener     /* Newton step is not descent or direction produced Inf or NaN
700eb910715SAlp Dener        Update the perturbation for next time */
701eb910715SAlp Dener     if (bnk->pert <= 0.0) {
702eb910715SAlp Dener       /* Initialize the perturbation */
703eb910715SAlp Dener       bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
704eb910715SAlp Dener       if (bnk->is_gltr) {
705eb910715SAlp Dener         ierr = KSPCGGLTRGetMinEig(tao->ksp,&e_min);CHKERRQ(ierr);
706eb910715SAlp Dener         bnk->pert = PetscMax(bnk->pert, -e_min);
707eb910715SAlp Dener       }
708eb910715SAlp Dener     } else {
709eb910715SAlp Dener       /* Increase the perturbation */
710eb910715SAlp Dener       bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
711eb910715SAlp Dener     }
712eb910715SAlp Dener 
713eb910715SAlp Dener     if (BNK_PC_BFGS != bnk->pc_type) {
714eb910715SAlp Dener       /* We don't have the bfgs matrix around and updated
715eb910715SAlp Dener          Must use gradient direction in this case */
716080d2917SAlp Dener       ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr);
717eb910715SAlp Dener       *stepType = BNK_GRADIENT;
718eb910715SAlp Dener     } else {
719eb910715SAlp Dener       /* Attempt to use the BFGS direction */
720*cd929ea3SAlp Dener       ierr = MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
721eb910715SAlp Dener 
7228d5ead36SAlp Dener       /* Check for success (descent direction)
7238d5ead36SAlp Dener          NOTE: Negative gdx here means not a descent direction because
7248d5ead36SAlp Dener          the fall-back step is missing a negative sign. */
725080d2917SAlp Dener       ierr = VecDot(tao->gradient, tao->stepdirection, &gdx);CHKERRQ(ierr);
7263105154fSTodd Munson       if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
727eb910715SAlp Dener         /* BFGS direction is not descent or direction produced not a number
728eb910715SAlp Dener            We can assert bfgsUpdates > 1 in this case because
729eb910715SAlp Dener            the first solve produces the scaled gradient direction,
730eb910715SAlp Dener            which is guaranteed to be descent */
731eb910715SAlp Dener 
732eb910715SAlp Dener         /* Use steepest descent direction (scaled) */
7339b6ef848SAlp Dener         delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
734*cd929ea3SAlp Dener         ierr = MatLMVMSetJ0Scale(bnk->M, delta);CHKERRQ(ierr);
735*cd929ea3SAlp Dener         ierr = MatLMVMReset(bnk->M, PETSC_FALSE);CHKERRQ(ierr);
73609164190SAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
737*cd929ea3SAlp Dener         ierr = MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
738eb910715SAlp Dener 
739eb910715SAlp Dener         *stepType = BNK_SCALED_GRADIENT;
740eb910715SAlp Dener       } else {
741*cd929ea3SAlp Dener         ierr = MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
742eb910715SAlp Dener         if (1 == bfgsUpdates) {
743eb910715SAlp Dener           /* The first BFGS direction is always the scaled gradient */
744eb910715SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
745eb910715SAlp Dener         } else {
746eb910715SAlp Dener           *stepType = BNK_BFGS;
747eb910715SAlp Dener         }
748eb910715SAlp Dener       }
749eb910715SAlp Dener     }
7508d5ead36SAlp Dener     /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
7518d5ead36SAlp Dener     ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
752a1318120SAlp Dener     ierr = TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection);CHKERRQ(ierr);
753eb910715SAlp Dener   } else {
754eb910715SAlp Dener     /* Computed Newton step is descent */
755eb910715SAlp Dener     switch (ksp_reason) {
756eb910715SAlp Dener     case KSP_DIVERGED_NANORINF:
757eb910715SAlp Dener     case KSP_DIVERGED_BREAKDOWN:
758eb910715SAlp Dener     case KSP_DIVERGED_INDEFINITE_MAT:
759eb910715SAlp Dener     case KSP_DIVERGED_INDEFINITE_PC:
760eb910715SAlp Dener     case KSP_CONVERGED_CG_NEG_CURVE:
761eb910715SAlp Dener       /* Matrix or preconditioner is indefinite; increase perturbation */
762eb910715SAlp Dener       if (bnk->pert <= 0.0) {
763eb910715SAlp Dener         /* Initialize the perturbation */
764eb910715SAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
765eb910715SAlp Dener         if (bnk->is_gltr) {
766eb910715SAlp Dener           ierr = KSPCGGLTRGetMinEig(tao->ksp, &e_min);CHKERRQ(ierr);
767eb910715SAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
768eb910715SAlp Dener         }
769eb910715SAlp Dener       } else {
770eb910715SAlp Dener         /* Increase the perturbation */
771eb910715SAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
772eb910715SAlp Dener       }
773eb910715SAlp Dener       break;
774eb910715SAlp Dener 
775eb910715SAlp Dener     default:
776eb910715SAlp Dener       /* Newton step computation is good; decrease perturbation */
777eb910715SAlp Dener       bnk->pert = PetscMin(bnk->psfac * bnk->pert, bnk->pmsfac * bnk->gnorm);
778eb910715SAlp Dener       if (bnk->pert < bnk->pmin) {
779eb910715SAlp Dener         bnk->pert = 0.0;
780eb910715SAlp Dener       }
781eb910715SAlp Dener       break;
782eb910715SAlp Dener     }
783fed79b8eSAlp Dener     *stepType = BNK_NEWTON;
784eb910715SAlp Dener   }
785eb910715SAlp Dener   PetscFunctionReturn(0);
786eb910715SAlp Dener }
787eb910715SAlp Dener 
788df278d8fSAlp Dener /*------------------------------------------------------------*/
789df278d8fSAlp Dener 
790df278d8fSAlp Dener /* Routine for performing a bound-projected More-Thuente line search.
791df278d8fSAlp Dener 
792df278d8fSAlp Dener   Includes fallbacks to BFGS, scaled gradient, and unscaled gradient steps if the
793df278d8fSAlp Dener   Newton step does not produce a valid step length.
794df278d8fSAlp Dener */
795df278d8fSAlp Dener 
796937a31a1SAlp Dener PetscErrorCode TaoBNKPerformLineSearch(Tao tao, PetscInt *stepType, PetscReal *steplen, TaoLineSearchConvergedReason *reason)
797c14b763aSAlp Dener {
798c14b763aSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
799c14b763aSAlp Dener   PetscErrorCode ierr;
800c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
801c14b763aSAlp Dener 
802c14b763aSAlp Dener   PetscReal      e_min, gdx, delta;
803c14b763aSAlp Dener   PetscInt       bfgsUpdates;
804c14b763aSAlp Dener 
805c14b763aSAlp Dener   PetscFunctionBegin;
806c14b763aSAlp Dener   /* Perform the linesearch */
807c14b763aSAlp Dener   ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason);CHKERRQ(ierr);
808c14b763aSAlp Dener   ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
809c14b763aSAlp Dener 
810937a31a1SAlp Dener   while (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER && *stepType != BNK_GRADIENT) {
811c14b763aSAlp Dener     /* Linesearch failed, revert solution */
812c14b763aSAlp Dener     bnk->f = bnk->fold;
813c14b763aSAlp Dener     ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
814c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
815c14b763aSAlp Dener 
816937a31a1SAlp Dener     switch(*stepType) {
817c14b763aSAlp Dener     case BNK_NEWTON:
8188d5ead36SAlp Dener       /* Failed to obtain acceptable iterate with Newton step
819c14b763aSAlp Dener          Update the perturbation for next time */
820c14b763aSAlp Dener       if (bnk->pert <= 0.0) {
821c14b763aSAlp Dener         /* Initialize the perturbation */
822c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->imax, PetscMax(bnk->imin, bnk->imfac * bnk->gnorm));
823c14b763aSAlp Dener         if (bnk->is_gltr) {
824c14b763aSAlp Dener           ierr = KSPCGGLTRGetMinEig(tao->ksp,&e_min);CHKERRQ(ierr);
825c14b763aSAlp Dener           bnk->pert = PetscMax(bnk->pert, -e_min);
826c14b763aSAlp Dener         }
827c14b763aSAlp Dener       } else {
828c14b763aSAlp Dener         /* Increase the perturbation */
829c14b763aSAlp Dener         bnk->pert = PetscMin(bnk->pmax, PetscMax(bnk->pgfac * bnk->pert, bnk->pmgfac * bnk->gnorm));
830c14b763aSAlp Dener       }
831c14b763aSAlp Dener 
832c14b763aSAlp Dener       if (BNK_PC_BFGS != bnk->pc_type) {
833c14b763aSAlp Dener         /* We don't have the bfgs matrix around and being updated
834c14b763aSAlp Dener            Must use gradient direction in this case */
835937a31a1SAlp Dener         ierr = VecCopy(bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
836937a31a1SAlp Dener         *stepType = BNK_GRADIENT;
837c14b763aSAlp Dener       } else {
838c14b763aSAlp Dener         /* Attempt to use the BFGS direction */
839*cd929ea3SAlp Dener         ierr = MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
8408d5ead36SAlp Dener         /* Check for success (descent direction)
8418d5ead36SAlp Dener            NOTE: Negative gdx means not a descent direction because the step here is missing a negative sign. */
842c14b763aSAlp Dener         ierr = VecDot(tao->gradient, tao->stepdirection, &gdx);CHKERRQ(ierr);
8433105154fSTodd Munson         if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
844c14b763aSAlp Dener           /* BFGS direction is not descent or direction produced not a number
845c14b763aSAlp Dener              We can assert bfgsUpdates > 1 in this case
846c14b763aSAlp Dener              Use steepest descent direction (scaled) */
8479b6ef848SAlp Dener           delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
848*cd929ea3SAlp Dener           ierr = MatLMVMSetJ0Scale(bnk->M, delta);CHKERRQ(ierr);
849*cd929ea3SAlp Dener           ierr = MatLMVMReset(bnk->M, PETSC_FALSE);CHKERRQ(ierr);
850c14b763aSAlp Dener           ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
851*cd929ea3SAlp Dener           ierr = MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
852c14b763aSAlp Dener 
853c14b763aSAlp Dener           bfgsUpdates = 1;
854937a31a1SAlp Dener           *stepType = BNK_SCALED_GRADIENT;
855c14b763aSAlp Dener         } else {
856*cd929ea3SAlp Dener           ierr = MatLMVMGetUpdateCount(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
857c14b763aSAlp Dener           if (1 == bfgsUpdates) {
858c14b763aSAlp Dener             /* The first BFGS direction is always the scaled gradient */
859937a31a1SAlp Dener             *stepType = BNK_SCALED_GRADIENT;
860c14b763aSAlp Dener           } else {
861937a31a1SAlp Dener             *stepType = BNK_BFGS;
862c14b763aSAlp Dener           }
863c14b763aSAlp Dener         }
864c14b763aSAlp Dener       }
865c14b763aSAlp Dener       break;
866c14b763aSAlp Dener 
867c14b763aSAlp Dener     case BNK_BFGS:
868c14b763aSAlp Dener       /* Can only enter if pc_type == BNK_PC_BFGS
869c14b763aSAlp Dener          Failed to obtain acceptable iterate with BFGS step
870c14b763aSAlp Dener          Attempt to use the scaled gradient direction */
8719b6ef848SAlp Dener       delta = 2.0 * PetscMax(1.0, PetscAbsScalar(bnk->f)) / (bnk->gnorm*bnk->gnorm);
872*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Scale(bnk->M, delta);CHKERRQ(ierr);
873*cd929ea3SAlp Dener       ierr = MatLMVMReset(bnk->M, PETSC_FALSE);CHKERRQ(ierr);
874c14b763aSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
875*cd929ea3SAlp Dener       ierr = MatSolve(bnk->M, bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
876c14b763aSAlp Dener 
877c14b763aSAlp Dener       bfgsUpdates = 1;
878937a31a1SAlp Dener       *stepType = BNK_SCALED_GRADIENT;
879c14b763aSAlp Dener       break;
880c14b763aSAlp Dener 
881c14b763aSAlp Dener     case BNK_SCALED_GRADIENT:
882c14b763aSAlp Dener       /* Can only enter if pc_type == BNK_PC_BFGS
883c14b763aSAlp Dener          The scaled gradient step did not produce a new iterate;
884937a31a1SAlp Dener          reset the BFGS matrix and attemp to use the gradient direction. */
885*cd929ea3SAlp Dener       ierr = MatLMVMSetJ0Scale(bnk->M,1.0);CHKERRQ(ierr);
886*cd929ea3SAlp Dener       ierr = MatLMVMReset(bnk->M, PETSC_FALSE);CHKERRQ(ierr);
887c14b763aSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
888937a31a1SAlp Dener       ierr = VecCopy(bnk->unprojected_gradient, tao->stepdirection);CHKERRQ(ierr);
889c14b763aSAlp Dener 
890c14b763aSAlp Dener       bfgsUpdates = 1;
891937a31a1SAlp Dener       *stepType = BNK_GRADIENT;
892c14b763aSAlp Dener       break;
893c14b763aSAlp Dener     }
8948d5ead36SAlp Dener     /* Make sure the safeguarded fall-back step is zero for actively bounded variables */
8958d5ead36SAlp Dener     ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
896a1318120SAlp Dener     ierr = TaoBNKBoundStep(tao, bnk->as_type, tao->stepdirection);CHKERRQ(ierr);
897c14b763aSAlp Dener 
8988d5ead36SAlp Dener     /* Perform one last line search with the fall-back step */
899c14b763aSAlp Dener     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &bnk->f, bnk->unprojected_gradient, tao->stepdirection, steplen, &ls_reason);CHKERRQ(ierr);
900c14b763aSAlp Dener     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
901c14b763aSAlp Dener   }
902c14b763aSAlp Dener   *reason = ls_reason;
903c14b763aSAlp Dener   PetscFunctionReturn(0);
904c14b763aSAlp Dener }
905c14b763aSAlp Dener 
906df278d8fSAlp Dener /*------------------------------------------------------------*/
907df278d8fSAlp Dener 
908df278d8fSAlp Dener /* Routine for updating the trust radius.
909df278d8fSAlp Dener 
910df278d8fSAlp Dener   Function features three different update methods:
911df278d8fSAlp Dener   1) Line-search step length based
912df278d8fSAlp Dener   2) Predicted decrease on the CG quadratic model
913df278d8fSAlp Dener   3) Interpolation
914df278d8fSAlp Dener */
915df278d8fSAlp Dener 
91628017e9fSAlp Dener PetscErrorCode TaoBNKUpdateTrustRadius(Tao tao, PetscReal prered, PetscReal actred, PetscInt updateType, PetscInt stepType, PetscBool *accept)
917080d2917SAlp Dener {
918080d2917SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
919080d2917SAlp Dener   PetscErrorCode ierr;
920080d2917SAlp Dener 
921b1c2d0e3SAlp Dener   PetscReal      step, kappa;
922080d2917SAlp Dener   PetscReal      gdx, tau_1, tau_2, tau_min, tau_max;
923080d2917SAlp Dener 
924080d2917SAlp Dener   PetscFunctionBegin;
925080d2917SAlp Dener   /* Update trust region radius */
926080d2917SAlp Dener   *accept = PETSC_FALSE;
92728017e9fSAlp Dener   switch(updateType) {
928080d2917SAlp Dener   case BNK_UPDATE_STEP:
929c14b763aSAlp Dener     *accept = PETSC_TRUE; /* always accept here because line search succeeded */
930080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
931080d2917SAlp Dener       ierr = TaoLineSearchGetStepLength(tao->linesearch, &step);CHKERRQ(ierr);
932080d2917SAlp Dener       if (step < bnk->nu1) {
933080d2917SAlp Dener         /* Very bad step taken; reduce radius */
934080d2917SAlp Dener         tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
935080d2917SAlp Dener       } else if (step < bnk->nu2) {
936080d2917SAlp Dener         /* Reasonably bad step taken; reduce radius */
937080d2917SAlp Dener         tao->trust = bnk->omega2 * PetscMin(bnk->dnorm, tao->trust);
938080d2917SAlp Dener       } else if (step < bnk->nu3) {
939080d2917SAlp Dener         /*  Reasonable step was taken; leave radius alone */
940080d2917SAlp Dener         if (bnk->omega3 < 1.0) {
941080d2917SAlp Dener           tao->trust = bnk->omega3 * PetscMin(bnk->dnorm, tao->trust);
942080d2917SAlp Dener         } else if (bnk->omega3 > 1.0) {
943080d2917SAlp Dener           tao->trust = PetscMax(bnk->omega3 * bnk->dnorm, tao->trust);
944080d2917SAlp Dener         }
945080d2917SAlp Dener       } else if (step < bnk->nu4) {
946080d2917SAlp Dener         /*  Full step taken; increase the radius */
947080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega4 * bnk->dnorm, tao->trust);
948080d2917SAlp Dener       } else {
949080d2917SAlp Dener         /*  More than full step taken; increase the radius */
950080d2917SAlp Dener         tao->trust = PetscMax(bnk->omega5 * bnk->dnorm, tao->trust);
951080d2917SAlp Dener       }
952080d2917SAlp Dener     } else {
953080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
954080d2917SAlp Dener       tao->trust = bnk->omega1 * PetscMin(bnk->dnorm, tao->trust);
955080d2917SAlp Dener     }
956080d2917SAlp Dener     break;
957080d2917SAlp Dener 
958080d2917SAlp Dener   case BNK_UPDATE_REDUCTION:
959080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
960b1c2d0e3SAlp Dener       if (prered < 0.0) {
961fed79b8eSAlp Dener         /* The predicted reduction has the wrong sign.  This cannot
962fed79b8eSAlp Dener            happen in infinite precision arithmetic.  Step should
963fed79b8eSAlp Dener            be rejected! */
964080d2917SAlp Dener         tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
9653105154fSTodd Munson       } else {
966b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
967080d2917SAlp Dener           tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
968080d2917SAlp Dener         } else {
9693105154fSTodd Munson           if ((PetscAbsScalar(actred) <= PetscMax(1.0, PetscAbsScalar(bnk->f))*bnk->epsilon) && (PetscAbsScalar(prered) <= PetscMax(1.0, PetscAbsScalar(bnk->f))*bnk->epsilon)) {
970080d2917SAlp Dener             kappa = 1.0;
9713105154fSTodd Munson           } else {
972080d2917SAlp Dener             kappa = actred / prered;
973080d2917SAlp Dener           }
974fed79b8eSAlp Dener 
975fed79b8eSAlp Dener           /* Accept or reject the step and update radius */
976080d2917SAlp Dener           if (kappa < bnk->eta1) {
977fed79b8eSAlp Dener             /* Reject the step */
978080d2917SAlp Dener             tao->trust = bnk->alpha1 * PetscMin(tao->trust, bnk->dnorm);
9793105154fSTodd Munson           } else {
980fed79b8eSAlp Dener             /* Accept the step */
981c133c014SAlp Dener             *accept = PETSC_TRUE;
982c133c014SAlp Dener             /* Update the trust region radius only if the computed step is at the trust radius boundary */
9838d5ead36SAlp Dener             if (bnk->dnorm == tao->trust) {
984080d2917SAlp Dener               if (kappa < bnk->eta2) {
985080d2917SAlp Dener                 /* Marginal bad step */
986c133c014SAlp Dener                 tao->trust = bnk->alpha2 * tao->trust;
9873105154fSTodd Munson               } else if (kappa < bnk->eta3) {
988fed79b8eSAlp Dener                 /* Reasonable step */
989fed79b8eSAlp Dener                 tao->trust = bnk->alpha3 * tao->trust;
9903105154fSTodd Munson               } else if (kappa < bnk->eta4) {
991080d2917SAlp Dener                 /* Good step */
992c133c014SAlp Dener                 tao->trust = bnk->alpha4 * tao->trust;
9933105154fSTodd Munson               } else {
994080d2917SAlp Dener                 /* Very good step */
995c133c014SAlp Dener                 tao->trust = bnk->alpha5 * tao->trust;
996080d2917SAlp Dener               }
997c133c014SAlp Dener             }
998080d2917SAlp Dener           }
999080d2917SAlp Dener         }
1000080d2917SAlp Dener       }
1001080d2917SAlp Dener     } else {
1002080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
1003080d2917SAlp Dener       tao->trust = bnk->alpha1 * PetscMin(bnk->dnorm, tao->trust);
1004080d2917SAlp Dener     }
1005080d2917SAlp Dener     break;
1006080d2917SAlp Dener 
1007080d2917SAlp Dener   default:
1008080d2917SAlp Dener     if (stepType == BNK_NEWTON) {
1009b1c2d0e3SAlp Dener       if (prered < 0.0) {
1010080d2917SAlp Dener         /*  The predicted reduction has the wrong sign.  This cannot */
1011080d2917SAlp Dener         /*  happen in infinite precision arithmetic.  Step should */
1012080d2917SAlp Dener         /*  be rejected! */
1013080d2917SAlp Dener         tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
1014080d2917SAlp Dener       } else {
1015b1c2d0e3SAlp Dener         if (PetscIsInfOrNanReal(actred)) {
1016080d2917SAlp Dener           tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
1017080d2917SAlp Dener         } else {
1018080d2917SAlp Dener           if ((PetscAbsScalar(actred) <= bnk->epsilon) && (PetscAbsScalar(prered) <= bnk->epsilon)) {
1019080d2917SAlp Dener             kappa = 1.0;
1020080d2917SAlp Dener           } else {
1021080d2917SAlp Dener             kappa = actred / prered;
1022080d2917SAlp Dener           }
1023080d2917SAlp Dener 
1024080d2917SAlp Dener           ierr = VecDot(tao->gradient, tao->stepdirection, &gdx);CHKERRQ(ierr);
1025080d2917SAlp Dener           tau_1 = bnk->theta * gdx / (bnk->theta * gdx - (1.0 - bnk->theta) * prered + actred);
1026080d2917SAlp Dener           tau_2 = bnk->theta * gdx / (bnk->theta * gdx + (1.0 + bnk->theta) * prered - actred);
1027080d2917SAlp Dener           tau_min = PetscMin(tau_1, tau_2);
1028080d2917SAlp Dener           tau_max = PetscMax(tau_1, tau_2);
1029080d2917SAlp Dener 
1030080d2917SAlp Dener           if (kappa >= 1.0 - bnk->mu1) {
1031080d2917SAlp Dener             /*  Great agreement */
1032080d2917SAlp Dener             *accept = PETSC_TRUE;
1033080d2917SAlp Dener             if (tau_max < 1.0) {
1034080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
1035080d2917SAlp Dener             } else if (tau_max > bnk->gamma4) {
1036080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma4 * bnk->dnorm);
1037080d2917SAlp Dener             } else {
1038080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
1039080d2917SAlp Dener             }
1040080d2917SAlp Dener           } else if (kappa >= 1.0 - bnk->mu2) {
1041080d2917SAlp Dener             /*  Good agreement */
1042080d2917SAlp Dener             *accept = PETSC_TRUE;
1043080d2917SAlp Dener             if (tau_max < bnk->gamma2) {
1044080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
1045080d2917SAlp Dener             } else if (tau_max > bnk->gamma3) {
1046080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, bnk->gamma3 * bnk->dnorm);
1047080d2917SAlp Dener             } else if (tau_max < 1.0) {
1048080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
1049080d2917SAlp Dener             } else {
1050080d2917SAlp Dener               tao->trust = PetscMax(tao->trust, tau_max * bnk->dnorm);
1051080d2917SAlp Dener             }
1052080d2917SAlp Dener           } else {
1053080d2917SAlp Dener             /*  Not good agreement */
1054080d2917SAlp Dener             if (tau_min > 1.0) {
1055080d2917SAlp Dener               tao->trust = bnk->gamma2 * PetscMin(tao->trust, bnk->dnorm);
1056080d2917SAlp Dener             } else if (tau_max < bnk->gamma1) {
1057080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
1058080d2917SAlp Dener             } else if ((tau_min < bnk->gamma1) && (tau_max >= 1.0)) {
1059080d2917SAlp Dener               tao->trust = bnk->gamma1 * PetscMin(tao->trust, bnk->dnorm);
1060080d2917SAlp Dener             } else if ((tau_1 >= bnk->gamma1) && (tau_1 < 1.0) && ((tau_2 < bnk->gamma1) || (tau_2 >= 1.0))) {
1061080d2917SAlp Dener               tao->trust = tau_1 * PetscMin(tao->trust, bnk->dnorm);
1062080d2917SAlp Dener             } else if ((tau_2 >= bnk->gamma1) && (tau_2 < 1.0) && ((tau_1 < bnk->gamma1) || (tau_2 >= 1.0))) {
1063080d2917SAlp Dener               tao->trust = tau_2 * PetscMin(tao->trust, bnk->dnorm);
1064080d2917SAlp Dener             } else {
1065080d2917SAlp Dener               tao->trust = tau_max * PetscMin(tao->trust, bnk->dnorm);
1066080d2917SAlp Dener             }
1067080d2917SAlp Dener           }
1068080d2917SAlp Dener         }
1069080d2917SAlp Dener       }
1070080d2917SAlp Dener     } else {
1071080d2917SAlp Dener       /*  Newton step was not good; reduce the radius */
1072080d2917SAlp Dener       tao->trust = bnk->gamma1 * PetscMin(bnk->dnorm, tao->trust);
1073080d2917SAlp Dener     }
107428017e9fSAlp Dener     break;
1075080d2917SAlp Dener   }
1076c133c014SAlp Dener   /* Make sure the radius does not violate min and max settings */
1077c133c014SAlp Dener   tao->trust = PetscMin(tao->trust, bnk->max_radius);
1078fed79b8eSAlp Dener   tao->trust = PetscMax(tao->trust, bnk->min_radius);
1079080d2917SAlp Dener   PetscFunctionReturn(0);
1080080d2917SAlp Dener }
1081080d2917SAlp Dener 
1082eb910715SAlp Dener /* ---------------------------------------------------------- */
1083df278d8fSAlp Dener 
108462675beeSAlp Dener PetscErrorCode TaoBNKAddStepCounts(Tao tao, PetscInt stepType)
108562675beeSAlp Dener {
108662675beeSAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
108762675beeSAlp Dener 
108862675beeSAlp Dener   PetscFunctionBegin;
108962675beeSAlp Dener   switch (stepType) {
109062675beeSAlp Dener   case BNK_NEWTON:
109162675beeSAlp Dener     ++bnk->newt;
109262675beeSAlp Dener     break;
109362675beeSAlp Dener   case BNK_BFGS:
109462675beeSAlp Dener     ++bnk->bfgs;
109562675beeSAlp Dener     break;
109662675beeSAlp Dener   case BNK_SCALED_GRADIENT:
109762675beeSAlp Dener     ++bnk->sgrad;
109862675beeSAlp Dener     break;
109962675beeSAlp Dener   case BNK_GRADIENT:
110062675beeSAlp Dener     ++bnk->grad;
110162675beeSAlp Dener     break;
110262675beeSAlp Dener   default:
110362675beeSAlp Dener     break;
110462675beeSAlp Dener   }
110562675beeSAlp Dener   PetscFunctionReturn(0);
110662675beeSAlp Dener }
110762675beeSAlp Dener 
110862675beeSAlp Dener /* ---------------------------------------------------------- */
110962675beeSAlp Dener 
11109b6ef848SAlp Dener PetscErrorCode TaoSetUp_BNK(Tao tao)
1111eb910715SAlp Dener {
1112eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1113eb910715SAlp Dener   PetscErrorCode ierr;
11149b6ef848SAlp Dener   KSPType        ksp_type;
1115e031d6f5SAlp Dener   PetscInt       i;
1116eb910715SAlp Dener 
1117eb910715SAlp Dener   PetscFunctionBegin;
1118c4b75bccSAlp Dener   if (!tao->gradient) {
1119c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
1120c4b75bccSAlp Dener   }
1121c4b75bccSAlp Dener   if (!tao->stepdirection) {
1122c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);
1123c4b75bccSAlp Dener   }
1124c4b75bccSAlp Dener   if (!bnk->W) {
1125c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->W);CHKERRQ(ierr);
1126c4b75bccSAlp Dener   }
1127c4b75bccSAlp Dener   if (!bnk->Xold) {
1128c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Xold);CHKERRQ(ierr);
1129c4b75bccSAlp Dener   }
1130c4b75bccSAlp Dener   if (!bnk->Gold) {
1131c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Gold);CHKERRQ(ierr);
1132c4b75bccSAlp Dener   }
1133c4b75bccSAlp Dener   if (!bnk->Xwork) {
1134c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Xwork);CHKERRQ(ierr);
1135c4b75bccSAlp Dener   }
1136c4b75bccSAlp Dener   if (!bnk->Gwork) {
1137c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Gwork);CHKERRQ(ierr);
1138c4b75bccSAlp Dener   }
1139c4b75bccSAlp Dener   if (!bnk->unprojected_gradient) {
1140c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->unprojected_gradient);CHKERRQ(ierr);
1141c4b75bccSAlp Dener   }
1142c4b75bccSAlp Dener   if (!bnk->unprojected_gradient_old) {
1143c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->unprojected_gradient_old);CHKERRQ(ierr);
1144c4b75bccSAlp Dener   }
1145c4b75bccSAlp Dener   if (!bnk->Diag_min) {
1146c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Diag_min);CHKERRQ(ierr);
1147c4b75bccSAlp Dener   }
1148c4b75bccSAlp Dener   if (!bnk->Diag_max) {
1149c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&bnk->Diag_max);CHKERRQ(ierr);
1150c4b75bccSAlp Dener   }
1151e031d6f5SAlp Dener   if (bnk->max_cg_its > 0) {
1152c4b75bccSAlp Dener     /* Ensure that the important common vectors are shared between BNK and embedded BNCG */
1153c4b75bccSAlp Dener     bnk->bncg_ctx = (TAO_BNCG *)bnk->bncg->data;
115489da521bSAlp Dener     ierr = PetscObjectReference((PetscObject)(bnk->unprojected_gradient_old));CHKERRQ(ierr);
115589da521bSAlp Dener     ierr = VecDestroy(&bnk->bncg_ctx->unprojected_gradient_old);CHKERRQ(ierr);
115689da521bSAlp Dener     bnk->bncg_ctx->unprojected_gradient_old = bnk->unprojected_gradient_old;
1157c4b75bccSAlp Dener     ierr = PetscObjectReference((PetscObject)(bnk->unprojected_gradient));CHKERRQ(ierr);
1158c4b75bccSAlp Dener     ierr = VecDestroy(&bnk->bncg_ctx->unprojected_gradient);CHKERRQ(ierr);
1159c4b75bccSAlp Dener     bnk->bncg_ctx->unprojected_gradient = bnk->unprojected_gradient;
1160c4b75bccSAlp Dener     ierr = PetscObjectReference((PetscObject)(bnk->Gold));CHKERRQ(ierr);
1161c4b75bccSAlp Dener     ierr = VecDestroy(&bnk->bncg_ctx->G_old);CHKERRQ(ierr);
1162c4b75bccSAlp Dener     bnk->bncg_ctx->G_old = bnk->Gold;
1163c4b75bccSAlp Dener     ierr = PetscObjectReference((PetscObject)(tao->gradient));CHKERRQ(ierr);
1164c4b75bccSAlp Dener     ierr = VecDestroy(&bnk->bncg->gradient);CHKERRQ(ierr);
1165c4b75bccSAlp Dener     bnk->bncg->gradient = tao->gradient;
1166c4b75bccSAlp Dener     ierr = PetscObjectReference((PetscObject)(tao->stepdirection));CHKERRQ(ierr);
1167c4b75bccSAlp Dener     ierr = VecDestroy(&bnk->bncg->stepdirection);CHKERRQ(ierr);
1168c4b75bccSAlp Dener     bnk->bncg->stepdirection = tao->stepdirection;
1169c4b75bccSAlp Dener     ierr = TaoSetInitialVector(bnk->bncg, tao->solution);CHKERRQ(ierr);
1170c4b75bccSAlp Dener     /* Copy over some settings from BNK into BNCG */
1171e031d6f5SAlp Dener     ierr = TaoSetMaximumIterations(bnk->bncg, bnk->max_cg_its);CHKERRQ(ierr);
1172e031d6f5SAlp Dener     ierr = TaoSetTolerances(bnk->bncg, tao->gatol, tao->grtol, tao->gttol);CHKERRQ(ierr);
1173e031d6f5SAlp Dener     ierr = TaoSetFunctionLowerBound(bnk->bncg, tao->fmin);CHKERRQ(ierr);
1174937a31a1SAlp Dener     ierr = TaoSetConvergenceTest(bnk->bncg, tao->ops->convergencetest, tao->cnvP);CHKERRQ(ierr);
1175e031d6f5SAlp Dener     ierr = TaoSetObjectiveRoutine(bnk->bncg, tao->ops->computeobjective, tao->user_objP);CHKERRQ(ierr);
1176e031d6f5SAlp Dener     ierr = TaoSetGradientRoutine(bnk->bncg, tao->ops->computegradient, tao->user_gradP);CHKERRQ(ierr);
1177e031d6f5SAlp Dener     ierr = TaoSetObjectiveAndGradientRoutine(bnk->bncg, tao->ops->computeobjectiveandgradient, tao->user_objgradP);CHKERRQ(ierr);
1178e031d6f5SAlp Dener     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)tao, (PetscObject)(bnk->bncg));CHKERRQ(ierr);
1179c4b75bccSAlp Dener     for (i=0; i<tao->numbermonitors; ++i) {
1180e031d6f5SAlp Dener       ierr = TaoSetMonitor(bnk->bncg, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]);CHKERRQ(ierr);
1181e031d6f5SAlp Dener       ierr = PetscObjectReference((PetscObject)(tao->monitorcontext[i]));CHKERRQ(ierr);
1182e031d6f5SAlp Dener     }
1183e031d6f5SAlp Dener   }
1184eb910715SAlp Dener   bnk->Diag = 0;
1185c0f10754SAlp Dener   bnk->Diag_red = 0;
1186c0f10754SAlp Dener   bnk->X_inactive = 0;
1187c0f10754SAlp Dener   bnk->G_inactive = 0;
118862675beeSAlp Dener   bnk->inactive_work = 0;
118962675beeSAlp Dener   bnk->active_work = 0;
119062675beeSAlp Dener   bnk->inactive_idx = 0;
119162675beeSAlp Dener   bnk->active_idx = 0;
119262675beeSAlp Dener   bnk->active_lower = 0;
119362675beeSAlp Dener   bnk->active_upper = 0;
119462675beeSAlp Dener   bnk->active_fixed = 0;
1195eb910715SAlp Dener   bnk->M = 0;
119609164190SAlp Dener   bnk->H_inactive = 0;
119709164190SAlp Dener   bnk->Hpre_inactive = 0;
11989b6ef848SAlp Dener   ierr = KSPGetType(tao->ksp,&ksp_type);CHKERRQ(ierr);
11999b6ef848SAlp Dener   ierr = PetscStrcmp(ksp_type,KSPCGNASH,&bnk->is_nash);CHKERRQ(ierr);
12009b6ef848SAlp Dener   ierr = PetscStrcmp(ksp_type,KSPCGSTCG,&bnk->is_stcg);CHKERRQ(ierr);
12019b6ef848SAlp Dener   ierr = PetscStrcmp(ksp_type,KSPCGGLTR,&bnk->is_gltr);CHKERRQ(ierr);
1202eb910715SAlp Dener   PetscFunctionReturn(0);
1203eb910715SAlp Dener }
1204eb910715SAlp Dener 
1205eb910715SAlp Dener /*------------------------------------------------------------*/
1206df278d8fSAlp Dener 
1207eb910715SAlp Dener static PetscErrorCode TaoDestroy_BNK(Tao tao)
1208eb910715SAlp Dener {
1209eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1210eb910715SAlp Dener   PetscErrorCode ierr;
1211eb910715SAlp Dener 
1212eb910715SAlp Dener   PetscFunctionBegin;
1213eb910715SAlp Dener   if (tao->setupcalled) {
1214eb910715SAlp Dener     ierr = VecDestroy(&bnk->W);CHKERRQ(ierr);
1215eb910715SAlp Dener     ierr = VecDestroy(&bnk->Xold);CHKERRQ(ierr);
1216eb910715SAlp Dener     ierr = VecDestroy(&bnk->Gold);CHKERRQ(ierr);
121709164190SAlp Dener     ierr = VecDestroy(&bnk->Xwork);CHKERRQ(ierr);
121809164190SAlp Dener     ierr = VecDestroy(&bnk->Gwork);CHKERRQ(ierr);
121909164190SAlp Dener     ierr = VecDestroy(&bnk->unprojected_gradient);CHKERRQ(ierr);
122009164190SAlp Dener     ierr = VecDestroy(&bnk->unprojected_gradient_old);CHKERRQ(ierr);
122162675beeSAlp Dener     ierr = VecDestroy(&bnk->Diag_min);CHKERRQ(ierr);
122262675beeSAlp Dener     ierr = VecDestroy(&bnk->Diag_max);CHKERRQ(ierr);
1223c4b75bccSAlp Dener   }
1224ca964c49SAlp Dener   ierr = ISDestroy(&bnk->active_lower);CHKERRQ(ierr);
1225ca964c49SAlp Dener   ierr = ISDestroy(&bnk->active_upper);CHKERRQ(ierr);
1226ca964c49SAlp Dener   ierr = ISDestroy(&bnk->active_fixed);CHKERRQ(ierr);
1227ca964c49SAlp Dener   ierr = ISDestroy(&bnk->active_idx);CHKERRQ(ierr);
1228ca964c49SAlp Dener   ierr = ISDestroy(&bnk->inactive_idx);CHKERRQ(ierr);
12295e9b73cbSAlp Dener   ierr = VecDestroy(&bnk->Diag);CHKERRQ(ierr);
1230eb910715SAlp Dener   ierr = MatDestroy(&bnk->M);CHKERRQ(ierr);
1231*cd929ea3SAlp Dener   ierr = MatDestroy(&bnk->M_inactive);CHKERRQ(ierr);
1232c4b75bccSAlp Dener   if (bnk->Hpre_inactive != tao->hessian_pre && bnk->Hpre_inactive != bnk->H_inactive) {
1233c4b75bccSAlp Dener     ierr = MatDestroy(&bnk->Hpre_inactive);CHKERRQ(ierr);
1234c4b75bccSAlp Dener   }
1235c4b75bccSAlp Dener   if (bnk->H_inactive != tao->hessian) {
1236c4b75bccSAlp Dener     ierr = MatDestroy(&bnk->H_inactive);CHKERRQ(ierr);
1237c4b75bccSAlp Dener   }
1238ca964c49SAlp Dener   ierr = TaoDestroy(&bnk->bncg);CHKERRQ(ierr);
1239eb910715SAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
1240eb910715SAlp Dener   PetscFunctionReturn(0);
1241eb910715SAlp Dener }
1242eb910715SAlp Dener 
1243eb910715SAlp Dener /*------------------------------------------------------------*/
1244df278d8fSAlp Dener 
1245eb910715SAlp Dener static PetscErrorCode TaoSetFromOptions_BNK(PetscOptionItems *PetscOptionsObject,Tao tao)
1246eb910715SAlp Dener {
1247eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1248eb910715SAlp Dener   PetscErrorCode ierr;
1249eb910715SAlp Dener 
1250eb910715SAlp Dener   PetscFunctionBegin;
1251eb910715SAlp Dener   ierr = PetscOptionsHead(PetscOptionsObject,"Newton line search method for unconstrained optimization");CHKERRQ(ierr);
12528d5ead36SAlp Dener   ierr = PetscOptionsEList("-tao_bnk_pc_type", "pc type", "", BNK_PC, BNK_PC_TYPES, BNK_PC[bnk->pc_type], &bnk->pc_type, 0);CHKERRQ(ierr);
12538d5ead36SAlp Dener   ierr = PetscOptionsEList("-tao_bnk_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[bnk->bfgs_scale_type], &bnk->bfgs_scale_type, 0);CHKERRQ(ierr);
12548d5ead36SAlp Dener   ierr = PetscOptionsEList("-tao_bnk_init_type", "radius initialization type", "", BNK_INIT, BNK_INIT_TYPES, BNK_INIT[bnk->init_type], &bnk->init_type, 0);CHKERRQ(ierr);
12558d5ead36SAlp Dener   ierr = PetscOptionsEList("-tao_bnk_update_type", "radius update type", "", BNK_UPDATE, BNK_UPDATE_TYPES, BNK_UPDATE[bnk->update_type], &bnk->update_type, 0);CHKERRQ(ierr);
12562f75a4aaSAlp Dener   ierr = PetscOptionsEList("-tao_bnk_as_type", "active set estimation method", "", BNK_AS, BNK_AS_TYPES, BNK_AS[bnk->as_type], &bnk->as_type, 0);CHKERRQ(ierr);
1257748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_sval", "(developer) Hessian perturbation starting value", "", bnk->sval, &bnk->sval,NULL);CHKERRQ(ierr);
1258748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_imin", "(developer) minimum initial Hessian perturbation", "", bnk->imin, &bnk->imin,NULL);CHKERRQ(ierr);
1259748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_imax", "(developer) maximum initial Hessian perturbation", "", bnk->imax, &bnk->imax,NULL);CHKERRQ(ierr);
1260748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_imfac", "(developer) initial merit factor for Hessian perturbation", "", bnk->imfac, &bnk->imfac,NULL);CHKERRQ(ierr);
1261748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_pmin", "(developer) minimum Hessian perturbation", "", bnk->pmin, &bnk->pmin,NULL);CHKERRQ(ierr);
1262748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_pmax", "(developer) maximum Hessian perturbation", "", bnk->pmax, &bnk->pmax,NULL);CHKERRQ(ierr);
1263748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_pgfac", "(developer) Hessian perturbation growth factor", "", bnk->pgfac, &bnk->pgfac,NULL);CHKERRQ(ierr);
1264748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_psfac", "(developer) Hessian perturbation shrink factor", "", bnk->psfac, &bnk->psfac,NULL);CHKERRQ(ierr);
1265748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_pmgfac", "(developer) merit growth factor for Hessian perturbation", "", bnk->pmgfac, &bnk->pmgfac,NULL);CHKERRQ(ierr);
1266748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_pmsfac", "(developer) merit shrink factor for Hessian perturbation", "", bnk->pmsfac, &bnk->pmsfac,NULL);CHKERRQ(ierr);
1267748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_eta1", "(developer) threshold for rejecting step (-tao_bnk_update_type reduction)", "", bnk->eta1, &bnk->eta1,NULL);CHKERRQ(ierr);
1268748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_eta2", "(developer) threshold for accepting marginal step (-tao_bnk_update_type reduction)", "", bnk->eta2, &bnk->eta2,NULL);CHKERRQ(ierr);
1269748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_eta3", "(developer) threshold for accepting reasonable step (-tao_bnk_update_type reduction)", "", bnk->eta3, &bnk->eta3,NULL);CHKERRQ(ierr);
1270748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_eta4", "(developer) threshold for accepting good step (-tao_bnk_update_type reduction)", "", bnk->eta4, &bnk->eta4,NULL);CHKERRQ(ierr);
1271748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_alpha1", "(developer) radius reduction factor for rejected step (-tao_bnk_update_type reduction)", "", bnk->alpha1, &bnk->alpha1,NULL);CHKERRQ(ierr);
1272748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_alpha2", "(developer) radius reduction factor for marginally accepted bad step (-tao_bnk_update_type reduction)", "", bnk->alpha2, &bnk->alpha2,NULL);CHKERRQ(ierr);
1273748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_alpha3", "(developer) radius increase factor for reasonable accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha3, &bnk->alpha3,NULL);CHKERRQ(ierr);
1274748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_alpha4", "(developer) radius increase factor for good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha4, &bnk->alpha4,NULL);CHKERRQ(ierr);
1275748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_alpha5", "(developer) radius increase factor for very good accepted step (-tao_bnk_update_type reduction)", "", bnk->alpha5, &bnk->alpha5,NULL);CHKERRQ(ierr);
1276748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_nu1", "(developer) threshold for small line-search step length (-tao_bnk_update_type step)", "", bnk->nu1, &bnk->nu1,NULL);CHKERRQ(ierr);
1277748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_nu2", "(developer) threshold for reasonable line-search step length (-tao_bnk_update_type step)", "", bnk->nu2, &bnk->nu2,NULL);CHKERRQ(ierr);
1278748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_nu3", "(developer) threshold for large line-search step length (-tao_bnk_update_type step)", "", bnk->nu3, &bnk->nu3,NULL);CHKERRQ(ierr);
1279748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_nu4", "(developer) threshold for very large line-search step length (-tao_bnk_update_type step)", "", bnk->nu4, &bnk->nu4,NULL);CHKERRQ(ierr);
1280748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1281748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_omega2", "(developer) radius reduction factor for small line-search step length (-tao_bnk_update_type step)", "", bnk->omega2, &bnk->omega2,NULL);CHKERRQ(ierr);
1282748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_omega3", "(developer) radius factor for decent line-search step length (-tao_bnk_update_type step)", "", bnk->omega3, &bnk->omega3,NULL);CHKERRQ(ierr);
1283748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_omega4", "(developer) radius increase factor for large line-search step length (-tao_bnk_update_type step)", "", bnk->omega4, &bnk->omega4,NULL);CHKERRQ(ierr);
1284748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1285748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_mu1_i", "(developer) threshold for accepting very good step (-tao_bnk_init_type interpolation)", "", bnk->mu1_i, &bnk->mu1_i,NULL);CHKERRQ(ierr);
1286748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_mu2_i", "(developer) threshold for accepting good step (-tao_bnk_init_type interpolation)", "", bnk->mu2_i, &bnk->mu2_i,NULL);CHKERRQ(ierr);
1287748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1288748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1289748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1290748696b1SAlp Dener   ierr = 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);CHKERRQ(ierr);
1291748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_theta_i", "(developer) trust region interpolation factor (-tao_bnk_init_type interpolation)", "", bnk->theta_i, &bnk->theta_i,NULL);CHKERRQ(ierr);
1292748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_mu1", "(developer) threshold for accepting very good step (-tao_bnk_update_type interpolation)", "", bnk->mu1, &bnk->mu1,NULL);CHKERRQ(ierr);
1293748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_mu2", "(developer) threshold for accepting good step (-tao_bnk_update_type interpolation)", "", bnk->mu2, &bnk->mu2,NULL);CHKERRQ(ierr);
1294748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_gamma1", "(developer) radius reduction factor for rejected very bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma1, &bnk->gamma1,NULL);CHKERRQ(ierr);
1295748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_gamma2", "(developer) radius reduction factor for rejected bad step (-tao_bnk_update_type interpolation)", "", bnk->gamma2, &bnk->gamma2,NULL);CHKERRQ(ierr);
1296748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_gamma3", "(developer) radius increase factor for accepted good step (-tao_bnk_update_type interpolation)", "", bnk->gamma3, &bnk->gamma3,NULL);CHKERRQ(ierr);
1297748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_gamma4", "(developer) radius increase factor for accepted very good step (-tao_bnk_update_type interpolation)", "", bnk->gamma4, &bnk->gamma4,NULL);CHKERRQ(ierr);
1298748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_theta", "(developer) trust region interpolation factor (-tao_bnk_update_type interpolation)", "", bnk->theta, &bnk->theta,NULL);CHKERRQ(ierr);
1299748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_min_radius", "(developer) lower bound on initial radius", "", bnk->min_radius, &bnk->min_radius,NULL);CHKERRQ(ierr);
1300748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_max_radius", "(developer) upper bound on radius", "", bnk->max_radius, &bnk->max_radius,NULL);CHKERRQ(ierr);
1301748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_epsilon", "(developer) tolerance used when computing actual and predicted reduction", "", bnk->epsilon, &bnk->epsilon,NULL);CHKERRQ(ierr);
1302748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_as_tol", "(developer) initial tolerance used when estimating actively bounded variables", "", bnk->as_tol, &bnk->as_tol,NULL);CHKERRQ(ierr);
1303748696b1SAlp Dener   ierr = PetscOptionsReal("-tao_bnk_as_step", "(developer) step length used when estimating actively bounded variables", "", bnk->as_step, &bnk->as_step,NULL);CHKERRQ(ierr);
1304c0f10754SAlp Dener   ierr = 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);CHKERRQ(ierr);
1305eb910715SAlp Dener   ierr = PetscOptionsTail();CHKERRQ(ierr);
130633c78596SAlp Dener   ierr = TaoSetFromOptions(bnk->bncg);CHKERRQ(ierr);
1307eb910715SAlp Dener   ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
1308eb910715SAlp Dener   ierr = KSPSetFromOptions(tao->ksp);CHKERRQ(ierr);
1309eb910715SAlp Dener   PetscFunctionReturn(0);
1310eb910715SAlp Dener }
1311eb910715SAlp Dener 
1312eb910715SAlp Dener /*------------------------------------------------------------*/
1313df278d8fSAlp Dener 
1314eb910715SAlp Dener static PetscErrorCode TaoView_BNK(Tao tao, PetscViewer viewer)
1315eb910715SAlp Dener {
1316eb910715SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
1317eb910715SAlp Dener   PetscInt       nrejects;
1318eb910715SAlp Dener   PetscBool      isascii;
1319eb910715SAlp Dener   PetscErrorCode ierr;
1320eb910715SAlp Dener 
1321eb910715SAlp Dener   PetscFunctionBegin;
1322eb910715SAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
1323eb910715SAlp Dener   if (isascii) {
1324eb910715SAlp Dener     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1325eb910715SAlp Dener     if (BNK_PC_BFGS == bnk->pc_type && bnk->M) {
1326*cd929ea3SAlp Dener       ierr = MatLMVMGetRejectCount(bnk->M,&nrejects);CHKERRQ(ierr);
1327eb910715SAlp Dener       ierr = PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n",nrejects);CHKERRQ(ierr);
1328eb910715SAlp Dener     }
1329e031d6f5SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "CG steps: %D\n", bnk->tot_cg_its);CHKERRQ(ierr);
1330eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Newton steps: %D\n", bnk->newt);CHKERRQ(ierr);
1331eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "BFGS steps: %D\n", bnk->bfgs);CHKERRQ(ierr);
1332eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Scaled gradient steps: %D\n", bnk->sgrad);CHKERRQ(ierr);
1333eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", bnk->grad);CHKERRQ(ierr);
1334eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "KSP termination reasons:\n");CHKERRQ(ierr);
1335eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  atol: %D\n", bnk->ksp_atol);CHKERRQ(ierr);
1336eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  rtol: %D\n", bnk->ksp_rtol);CHKERRQ(ierr);
1337eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  ctol: %D\n", bnk->ksp_ctol);CHKERRQ(ierr);
1338eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  negc: %D\n", bnk->ksp_negc);CHKERRQ(ierr);
1339eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  dtol: %D\n", bnk->ksp_dtol);CHKERRQ(ierr);
1340eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  iter: %D\n", bnk->ksp_iter);CHKERRQ(ierr);
1341eb910715SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  othr: %D\n", bnk->ksp_othr);CHKERRQ(ierr);
1342eb910715SAlp Dener     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1343eb910715SAlp Dener   }
1344eb910715SAlp Dener   PetscFunctionReturn(0);
1345eb910715SAlp Dener }
1346eb910715SAlp Dener 
1347eb910715SAlp Dener /* ---------------------------------------------------------- */
1348df278d8fSAlp Dener 
1349eb910715SAlp Dener /*MC
1350eb910715SAlp Dener   TAOBNK - Shared base-type for Bounded Newton-Krylov type algorithms.
135166ed3702SAlp Dener   At each iteration, the BNK methods solve the symmetric
1352eb910715SAlp Dener   system of equations to obtain the step diretion dk:
1353eb910715SAlp Dener               Hk dk = -gk
13542b97c8d8SAlp Dener   for free variables only. The step can be globalized either through
13552b97c8d8SAlp Dener   trust-region methods, or a line search, or a heuristic mixture of both.
1356eb910715SAlp Dener 
1357eb910715SAlp Dener     Options Database Keys:
1358748696b1SAlp Dener + -tao_max_cg_its - maximum number of bounded conjugate-gradient iterations taken in each Newton loop
1359748696b1SAlp Dener . -tao_bnk_pc_type - preconditioner type ("none", "ahess", "bfgs", "petsc")
13603cb832f1SAlp Dener . -tao_bnk_bfgs_scale_type - BFGS preconditioner diagonal scaling type ("ahess", "phess", "bfgs")
13613cb832f1SAlp Dener . -tao_bnk_init_type - trust radius initialization method ("constant", "direction", "interpolation")
13623cb832f1SAlp Dener . -tao_bnk_update_type - trust radius update method ("step", "direction", "interpolation")
13633cb832f1SAlp Dener . -tao_bnk_as_type - active-set estimation method ("none", "bertsekas")
1364748696b1SAlp Dener . -tao_bnk_as_tol - (developer) initial tolerance used in estimating bounded active variables (-tao_bnk_as_type bertsekas)
1365748696b1SAlp Dener . -tao_bnk_as_step - (developer) trial step length used in estimating bounded active variables (-tao_bnk_as_type bertsekas)
1366748696b1SAlp Dener . -tao_bnk_sval - (developer) Hessian perturbation starting value
1367748696b1SAlp Dener . -tao_bnk_imin - (developer) minimum initial Hessian perturbation
1368748696b1SAlp Dener . -tao_bnk_imax - (developer) maximum initial Hessian perturbation
1369748696b1SAlp Dener . -tao_bnk_pmin - (developer) minimum Hessian perturbation
1370748696b1SAlp Dener . -tao_bnk_pmax - (developer) aximum Hessian perturbation
1371748696b1SAlp Dener . -tao_bnk_pgfac - (developer) Hessian perturbation growth factor
1372748696b1SAlp Dener . -tao_bnk_psfac - (developer) Hessian perturbation shrink factor
1373748696b1SAlp Dener . -tao_bnk_imfac - (developer) initial merit factor for Hessian perturbation
1374748696b1SAlp Dener . -tao_bnk_pmgfac - (developer) merit growth factor for Hessian perturbation
1375748696b1SAlp Dener . -tao_bnk_pmsfac - (developer) merit shrink factor for Hessian perturbation
1376748696b1SAlp Dener . -tao_bnk_eta1 - (developer) threshold for rejecting step (-tao_bnk_update_type reduction)
1377748696b1SAlp Dener . -tao_bnk_eta2 - (developer) threshold for accepting marginal step (-tao_bnk_update_type reduction)
1378748696b1SAlp Dener . -tao_bnk_eta3 - (developer) threshold for accepting reasonable step (-tao_bnk_update_type reduction)
1379748696b1SAlp Dener . -tao_bnk_eta4 - (developer) threshold for accepting good step (-tao_bnk_update_type reduction)
1380748696b1SAlp Dener . -tao_bnk_alpha1 - (developer) radius reduction factor for rejected step (-tao_bnk_update_type reduction)
1381748696b1SAlp Dener . -tao_bnk_alpha2 - (developer) radius reduction factor for marginally accepted bad step (-tao_bnk_update_type reduction)
1382748696b1SAlp Dener . -tao_bnk_alpha3 - (developer) radius increase factor for reasonable accepted step (-tao_bnk_update_type reduction)
1383748696b1SAlp Dener . -tao_bnk_alpha4 - (developer) radius increase factor for good accepted step (-tao_bnk_update_type reduction)
1384748696b1SAlp Dener . -tao_bnk_alpha5 - (developer) radius increase factor for very good accepted step (-tao_bnk_update_type reduction)
1385748696b1SAlp Dener . -tao_bnk_epsilon - (developer) tolerance for small pred/actual ratios that trigger automatic step acceptance (-tao_bnk_update_type reduction)
1386748696b1SAlp Dener . -tao_bnk_mu1 - (developer) threshold for accepting very good step (-tao_bnk_update_type interpolation)
1387748696b1SAlp Dener . -tao_bnk_mu2 - (developer) threshold for accepting good step (-tao_bnk_update_type interpolation)
1388748696b1SAlp Dener . -tao_bnk_gamma1 - (developer) radius reduction factor for rejected very bad step (-tao_bnk_update_type interpolation)
1389748696b1SAlp Dener . -tao_bnk_gamma2 - (developer) radius reduction factor for rejected bad step (-tao_bnk_update_type interpolation)
1390748696b1SAlp Dener . -tao_bnk_gamma3 - (developer) radius increase factor for accepted good step (-tao_bnk_update_type interpolation)
1391748696b1SAlp Dener . -tao_bnk_gamma4 - (developer) radius increase factor for accepted very good step (-tao_bnk_update_type interpolation)
1392748696b1SAlp Dener . -tao_bnk_theta - (developer) trust region interpolation factor (-tao_bnk_update_type interpolation)
1393748696b1SAlp Dener . -tao_bnk_nu1 - (developer) threshold for small line-search step length (-tao_bnk_update_type step)
1394748696b1SAlp Dener . -tao_bnk_nu2 - (developer) threshold for reasonable line-search step length (-tao_bnk_update_type step)
1395748696b1SAlp Dener . -tao_bnk_nu3 - (developer) threshold for large line-search step length (-tao_bnk_update_type step)
1396748696b1SAlp Dener . -tao_bnk_nu4 - (developer) threshold for very large line-search step length (-tao_bnk_update_type step)
1397748696b1SAlp Dener . -tao_bnk_omega1 - (developer) radius reduction factor for very small line-search step length (-tao_bnk_update_type step)
1398748696b1SAlp Dener . -tao_bnk_omega2 - (developer) radius reduction factor for small line-search step length (-tao_bnk_update_type step)
1399748696b1SAlp Dener . -tao_bnk_omega3 - (developer) radius factor for decent line-search step length (-tao_bnk_update_type step)
1400748696b1SAlp Dener . -tao_bnk_omega4 - (developer) radius increase factor for large line-search step length (-tao_bnk_update_type step)
1401748696b1SAlp Dener . -tao_bnk_omega5 - (developer) radius increase factor for very large line-search step length (-tao_bnk_update_type step)
1402748696b1SAlp Dener . -tao_bnk_mu1_i -  (developer) threshold for accepting very good step (-tao_bnk_init_type interpolation)
1403748696b1SAlp Dener . -tao_bnk_mu2_i -  (developer) threshold for accepting good step (-tao_bnk_init_type interpolation)
1404748696b1SAlp Dener . -tao_bnk_gamma1_i - (developer) radius reduction factor for rejected very bad step (-tao_bnk_init_type interpolation)
1405748696b1SAlp Dener . -tao_bnk_gamma2_i - (developer) radius reduction factor for rejected bad step (-tao_bnk_init_type interpolation)
1406748696b1SAlp Dener . -tao_bnk_gamma3_i - (developer) radius increase factor for accepted good step (-tao_bnk_init_type interpolation)
1407748696b1SAlp Dener . -tao_bnk_gamma4_i - (developer) radius increase factor for accepted very good step (-tao_bnk_init_type interpolation)
1408748696b1SAlp Dener - -tao_bnk_theta_i - (developer) trust region interpolation factor (-tao_bnk_init_type interpolation)
1409eb910715SAlp Dener 
1410eb910715SAlp Dener   Level: beginner
1411eb910715SAlp Dener M*/
1412eb910715SAlp Dener 
1413eb910715SAlp Dener PetscErrorCode TaoCreate_BNK(Tao tao)
1414eb910715SAlp Dener {
1415eb910715SAlp Dener   TAO_BNK        *bnk;
1416eb910715SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
1417eb910715SAlp Dener   PetscErrorCode ierr;
1418eb910715SAlp Dener 
1419eb910715SAlp Dener   PetscFunctionBegin;
1420eb910715SAlp Dener   ierr = PetscNewLog(tao,&bnk);CHKERRQ(ierr);
1421eb910715SAlp Dener 
1422eb910715SAlp Dener   tao->ops->setup = TaoSetUp_BNK;
1423eb910715SAlp Dener   tao->ops->view = TaoView_BNK;
1424eb910715SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNK;
1425eb910715SAlp Dener   tao->ops->destroy = TaoDestroy_BNK;
1426eb910715SAlp Dener 
1427eb910715SAlp Dener   /*  Override default settings (unless already changed) */
1428eb910715SAlp Dener   if (!tao->max_it_changed) tao->max_it = 50;
1429eb910715SAlp Dener   if (!tao->trust0_changed) tao->trust0 = 100.0;
1430eb910715SAlp Dener 
1431eb910715SAlp Dener   tao->data = (void*)bnk;
1432eb910715SAlp Dener 
143366ed3702SAlp Dener   /*  Hessian shifting parameters */
1434eb910715SAlp Dener   bnk->sval   = 0.0;
1435eb910715SAlp Dener   bnk->imin   = 1.0e-4;
1436eb910715SAlp Dener   bnk->imax   = 1.0e+2;
1437eb910715SAlp Dener   bnk->imfac  = 1.0e-1;
1438eb910715SAlp Dener 
1439eb910715SAlp Dener   bnk->pmin   = 1.0e-12;
1440eb910715SAlp Dener   bnk->pmax   = 1.0e+2;
1441eb910715SAlp Dener   bnk->pgfac  = 1.0e+1;
1442eb910715SAlp Dener   bnk->psfac  = 4.0e-1;
1443eb910715SAlp Dener   bnk->pmgfac = 1.0e-1;
1444eb910715SAlp Dener   bnk->pmsfac = 1.0e-1;
1445eb910715SAlp Dener 
1446eb910715SAlp Dener   /*  Default values for trust-region radius update based on steplength */
1447eb910715SAlp Dener   bnk->nu1 = 0.25;
1448eb910715SAlp Dener   bnk->nu2 = 0.50;
1449eb910715SAlp Dener   bnk->nu3 = 1.00;
1450eb910715SAlp Dener   bnk->nu4 = 1.25;
1451eb910715SAlp Dener 
1452eb910715SAlp Dener   bnk->omega1 = 0.25;
1453eb910715SAlp Dener   bnk->omega2 = 0.50;
1454eb910715SAlp Dener   bnk->omega3 = 1.00;
1455eb910715SAlp Dener   bnk->omega4 = 2.00;
1456eb910715SAlp Dener   bnk->omega5 = 4.00;
1457eb910715SAlp Dener 
1458eb910715SAlp Dener   /*  Default values for trust-region radius update based on reduction */
1459eb910715SAlp Dener   bnk->eta1 = 1.0e-4;
1460eb910715SAlp Dener   bnk->eta2 = 0.25;
1461eb910715SAlp Dener   bnk->eta3 = 0.50;
1462eb910715SAlp Dener   bnk->eta4 = 0.90;
1463eb910715SAlp Dener 
1464eb910715SAlp Dener   bnk->alpha1 = 0.25;
1465eb910715SAlp Dener   bnk->alpha2 = 0.50;
1466eb910715SAlp Dener   bnk->alpha3 = 1.00;
1467eb910715SAlp Dener   bnk->alpha4 = 2.00;
1468eb910715SAlp Dener   bnk->alpha5 = 4.00;
1469eb910715SAlp Dener 
1470eb910715SAlp Dener   /*  Default values for trust-region radius update based on interpolation */
1471eb910715SAlp Dener   bnk->mu1 = 0.10;
1472eb910715SAlp Dener   bnk->mu2 = 0.50;
1473eb910715SAlp Dener 
1474eb910715SAlp Dener   bnk->gamma1 = 0.25;
1475eb910715SAlp Dener   bnk->gamma2 = 0.50;
1476eb910715SAlp Dener   bnk->gamma3 = 2.00;
1477eb910715SAlp Dener   bnk->gamma4 = 4.00;
1478eb910715SAlp Dener 
1479eb910715SAlp Dener   bnk->theta = 0.05;
1480eb910715SAlp Dener 
1481eb910715SAlp Dener   /*  Default values for trust region initialization based on interpolation */
1482eb910715SAlp Dener   bnk->mu1_i = 0.35;
1483eb910715SAlp Dener   bnk->mu2_i = 0.50;
1484eb910715SAlp Dener 
1485eb910715SAlp Dener   bnk->gamma1_i = 0.0625;
1486eb910715SAlp Dener   bnk->gamma2_i = 0.5;
1487eb910715SAlp Dener   bnk->gamma3_i = 2.0;
1488eb910715SAlp Dener   bnk->gamma4_i = 5.0;
1489eb910715SAlp Dener 
1490eb910715SAlp Dener   bnk->theta_i = 0.25;
1491eb910715SAlp Dener 
1492eb910715SAlp Dener   /*  Remaining parameters */
1493c0f10754SAlp Dener   bnk->max_cg_its = 0;
1494eb910715SAlp Dener   bnk->min_radius = 1.0e-10;
1495eb910715SAlp Dener   bnk->max_radius = 1.0e10;
1496770b7498SAlp Dener   bnk->epsilon = PetscPowReal(PETSC_MACHINE_EPSILON, 2.0/3.0);
14970a4511e9SAlp Dener   bnk->as_tol = 1.0e-3;
14980a4511e9SAlp Dener   bnk->as_step = 1.0e-3;
149962675beeSAlp Dener   bnk->dmin = 1.0e-6;
150062675beeSAlp Dener   bnk->dmax = 1.0e6;
1501eb910715SAlp Dener 
1502*cd929ea3SAlp Dener   bnk->pc_type         = BNK_PC_BFGS;
1503*cd929ea3SAlp Dener   bnk->bfgs_scale_type = BFGS_SCALE_AHESS;
1504eb910715SAlp Dener   bnk->init_type       = BNK_INIT_INTERPOLATION;
1505fed79b8eSAlp Dener   bnk->update_type     = BNK_UPDATE_INTERPOLATION;
15062f75a4aaSAlp Dener   bnk->as_type         = BNK_AS_BERTSEKAS;
1507eb910715SAlp Dener 
1508e031d6f5SAlp Dener   /* Create the embedded BNCG solver */
1509e031d6f5SAlp Dener   ierr = TaoCreate(PetscObjectComm((PetscObject)tao), &bnk->bncg);CHKERRQ(ierr);
1510e031d6f5SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)bnk->bncg, (PetscObject)tao, 1);CHKERRQ(ierr);
1511e031d6f5SAlp Dener   ierr = TaoSetOptionsPrefix(bnk->bncg, "tao_bnk_");CHKERRQ(ierr);
1512e031d6f5SAlp Dener   ierr = TaoSetType(bnk->bncg, TAOBNCG);CHKERRQ(ierr);
1513e031d6f5SAlp Dener 
1514c0f10754SAlp Dener   /* Create the line search */
1515eb910715SAlp Dener   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch);CHKERRQ(ierr);
1516eb910715SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr);
1517e031d6f5SAlp Dener   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
1518eb910715SAlp Dener   ierr = TaoLineSearchSetType(tao->linesearch,morethuente_type);CHKERRQ(ierr);
1519eb910715SAlp Dener   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch,tao);CHKERRQ(ierr);
1520eb910715SAlp Dener 
1521eb910715SAlp Dener   /*  Set linear solver to default for symmetric matrices */
1522eb910715SAlp Dener   ierr = KSPCreate(((PetscObject)tao)->comm,&tao->ksp);CHKERRQ(ierr);
1523eb910715SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1);CHKERRQ(ierr);
1524eb910715SAlp Dener   ierr = KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix);CHKERRQ(ierr);
1525eb910715SAlp Dener   ierr = KSPSetType(tao->ksp,KSPCGSTCG);CHKERRQ(ierr);
1526eb910715SAlp Dener   PetscFunctionReturn(0);
1527eb910715SAlp Dener }
1528