xref: /petsc/src/tao/bound/impls/bncg/bncg.c (revision cd929ea3f739fd9f7b6394f772cb40b9d4e6d97c)
1ac9112b8SAlp Dener #include <petsctaolinesearch.h>
2ac9112b8SAlp Dener #include <../src/tao/bound/impls/bncg/bncg.h>
3ac9112b8SAlp Dener 
4ac9112b8SAlp Dener #define CG_FletcherReeves       0
5ac9112b8SAlp Dener #define CG_PolakRibiere         1
6ac9112b8SAlp Dener #define CG_PolakRibierePlus     2
7ac9112b8SAlp Dener #define CG_HestenesStiefel      3
8ac9112b8SAlp Dener #define CG_DaiYuan              4
9560169d0SAlp Dener #define CG_GradientDescent      5
10560169d0SAlp Dener #define CG_Types                6
11ac9112b8SAlp Dener 
12560169d0SAlp Dener static const char *CG_Table[64] = {"fr", "pr", "prp", "hs", "dy", "gd"};
13ac9112b8SAlp Dener 
1461be54a6SAlp Dener #define CG_AS_NONE       0
1561be54a6SAlp Dener #define CG_AS_BERTSEKAS  1
1661be54a6SAlp Dener #define CG_AS_SIZE       2
17ac9112b8SAlp Dener 
1861be54a6SAlp Dener static const char *CG_AS_TYPE[64] = {"none", "bertsekas"};
19ac9112b8SAlp Dener 
20c0f10754SAlp Dener PetscErrorCode TaoBNCGSetRecycleFlag(Tao tao, PetscBool recycle)
21c0f10754SAlp Dener {
22c0f10754SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
23c0f10754SAlp Dener 
24c0f10754SAlp Dener   PetscFunctionBegin;
25c0f10754SAlp Dener   cg->recycle = recycle;
26c0f10754SAlp Dener   PetscFunctionReturn(0);
27c0f10754SAlp Dener }
28c0f10754SAlp Dener 
2961be54a6SAlp Dener PetscErrorCode TaoBNCGEstimateActiveSet(Tao tao, PetscInt asType)
3061be54a6SAlp Dener {
3161be54a6SAlp Dener   PetscErrorCode               ierr;
3261be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
3361be54a6SAlp Dener 
3461be54a6SAlp Dener   PetscFunctionBegin;
35*cd929ea3SAlp Dener   if (!tao->bounded) PetscFunctionReturn(0);
3661be54a6SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
3761be54a6SAlp Dener   if (cg->inactive_idx) {
3861be54a6SAlp Dener     ierr = ISDuplicate(cg->inactive_idx, &cg->inactive_old);CHKERRQ(ierr);
3961be54a6SAlp Dener     ierr = ISCopy(cg->inactive_idx, cg->inactive_old);CHKERRQ(ierr);
4061be54a6SAlp Dener   }
4161be54a6SAlp Dener   switch (asType) {
4261be54a6SAlp Dener   case CG_AS_NONE:
4361be54a6SAlp Dener     ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
4461be54a6SAlp Dener     ierr = VecWhichInactive(tao->XL, tao->solution, cg->unprojected_gradient, tao->XU, PETSC_TRUE, &cg->inactive_idx);CHKERRQ(ierr);
4561be54a6SAlp Dener     ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
4661be54a6SAlp Dener     ierr = ISComplementVec(cg->inactive_idx, tao->solution, &cg->active_idx);CHKERRQ(ierr);
4761be54a6SAlp Dener     break;
4861be54a6SAlp Dener 
4961be54a6SAlp Dener   case CG_AS_BERTSEKAS:
5061be54a6SAlp Dener     /* Use gradient descent to estimate the active set */
5161be54a6SAlp Dener     ierr = VecCopy(cg->unprojected_gradient, cg->W);CHKERRQ(ierr);
5261be54a6SAlp Dener     ierr = VecScale(cg->W, -1.0);CHKERRQ(ierr);
5389da521bSAlp Dener     ierr = TaoEstimateActiveBounds(tao->solution, tao->XL, tao->XU, cg->unprojected_gradient, cg->W, cg->work, cg->as_step, &cg->as_tol,
5489da521bSAlp Dener                                    &cg->active_lower, &cg->active_upper, &cg->active_fixed, &cg->active_idx, &cg->inactive_idx);CHKERRQ(ierr);
55c4b75bccSAlp Dener     break;
5661be54a6SAlp Dener 
5761be54a6SAlp Dener   default:
5861be54a6SAlp Dener     break;
5961be54a6SAlp Dener   }
6061be54a6SAlp Dener   PetscFunctionReturn(0);
6161be54a6SAlp Dener }
6261be54a6SAlp Dener 
63a1318120SAlp Dener PetscErrorCode TaoBNCGBoundStep(Tao tao, PetscInt asType, Vec step)
6461be54a6SAlp Dener {
6561be54a6SAlp Dener   PetscErrorCode               ierr;
6661be54a6SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG *)tao->data;
6761be54a6SAlp Dener 
6861be54a6SAlp Dener   PetscFunctionBegin;
69*cd929ea3SAlp Dener   if (!tao->bounded) PetscFunctionReturn(0);
70a1318120SAlp Dener   switch (asType) {
7161be54a6SAlp Dener   case CG_AS_NONE:
72c4b75bccSAlp Dener     ierr = VecISSet(step, cg->active_idx, 0.0);CHKERRQ(ierr);
7361be54a6SAlp Dener     break;
7461be54a6SAlp Dener 
7561be54a6SAlp Dener   case CG_AS_BERTSEKAS:
76c4b75bccSAlp Dener     ierr = TaoBoundStep(tao->solution, tao->XL, tao->XU, cg->active_lower, cg->active_upper, cg->active_fixed, 1.0, step);CHKERRQ(ierr);
7761be54a6SAlp Dener     break;
7861be54a6SAlp Dener 
7961be54a6SAlp Dener   default:
8061be54a6SAlp Dener     break;
8161be54a6SAlp Dener   }
8261be54a6SAlp Dener   PetscFunctionReturn(0);
8361be54a6SAlp Dener }
8461be54a6SAlp Dener 
85ac9112b8SAlp Dener static PetscErrorCode TaoSolve_BNCG(Tao tao)
86ac9112b8SAlp Dener {
87ac9112b8SAlp Dener   TAO_BNCG                     *cg = (TAO_BNCG*)tao->data;
88ac9112b8SAlp Dener   PetscErrorCode               ierr;
89ac9112b8SAlp Dener   TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING;
9089da521bSAlp Dener   PetscReal                    step=1.0,gnorm,gnorm2,gd,ginner,beta,dnorm;
9189da521bSAlp Dener   PetscReal                    gd_old,gnorm2_old,f_old,resnorm;
92560169d0SAlp Dener   PetscBool                    cg_restart, gd_fallback = PETSC_FALSE;
93c4b75bccSAlp Dener   PetscInt                     nDiff;
94ac9112b8SAlp Dener 
95ac9112b8SAlp Dener   PetscFunctionBegin;
96ac9112b8SAlp Dener   /*   Project the current point onto the feasible set */
97ac9112b8SAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
983b063059SAlp Dener   ierr = TaoBoundSolution(tao->solution, tao->XL,tao->XU, 0.0, &nDiff, tao->solution);CHKERRQ(ierr);
99*cd929ea3SAlp Dener   if (tao->bounded) {
100*cd929ea3SAlp Dener     ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
101*cd929ea3SAlp Dener   }
102ac9112b8SAlp Dener 
103e046c495SAlp Dener   if (nDiff > 0 || !cg->recycle) {
10411eb65dcSAlp Dener     /*  Solver is not being recycled so just compute the objective function and criteria */
105c0f10754SAlp Dener     ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient);CHKERRQ(ierr);
10611eb65dcSAlp Dener   } else {
10711eb65dcSAlp Dener     /* We are recycling, so we have to compute ||g_old||^2 for use in the CG step calculation */
10811eb65dcSAlp Dener     ierr = VecDot(cg->G_old, cg->G_old, &gnorm2_old);CHKERRQ(ierr);
109c0f10754SAlp Dener   }
110ac9112b8SAlp Dener   ierr = VecNorm(cg->unprojected_gradient,NORM_2,&gnorm);CHKERRQ(ierr);
111c0f10754SAlp Dener   if (PetscIsInfOrNanReal(cg->f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
112ac9112b8SAlp Dener 
11361be54a6SAlp Dener   /* Estimate the active set and compute the projected gradient */
11461be54a6SAlp Dener   ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
11561be54a6SAlp Dener 
116ac9112b8SAlp Dener   /* Project the gradient and calculate the norm */
11761be54a6SAlp Dener   ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
11861be54a6SAlp Dener   ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
119ac9112b8SAlp Dener   ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
120ac9112b8SAlp Dener   gnorm2 = gnorm*gnorm;
121ac9112b8SAlp Dener 
122ac9112b8SAlp Dener   /* Convergence check */
123e031d6f5SAlp Dener   tao->niter = 0;
124ac9112b8SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
125*cd929ea3SAlp Dener   ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
126*cd929ea3SAlp Dener   ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
127*cd929ea3SAlp Dener   ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
128*cd929ea3SAlp Dener   ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
129ac9112b8SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
130ac9112b8SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
131ac9112b8SAlp Dener 
132ac9112b8SAlp Dener   /* Start optimization iterations */
133e031d6f5SAlp Dener   cg->ls_fails = cg->broken_ortho = cg->descent_error = 0;
134ac9112b8SAlp Dener   cg->resets = -1;
135ac9112b8SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
136c4b75bccSAlp Dener     ++tao->niter;
13789da521bSAlp Dener 
13889da521bSAlp Dener     /* Check restart conditions for using steepest descent */
139ac9112b8SAlp Dener     cg_restart = PETSC_FALSE;
140ac9112b8SAlp Dener     ierr = VecDot(tao->gradient, cg->G_old, &ginner);CHKERRQ(ierr);
141937a31a1SAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr);
142c4b75bccSAlp Dener     if (tao->niter == 1 && !cg->recycle && dnorm != 0.0) {
143937a31a1SAlp Dener       /* 1) First iteration, with recycle disabled, and a non-zero previous step */
144ac9112b8SAlp Dener       cg_restart = PETSC_TRUE;
145ac9112b8SAlp Dener     } else if (PetscAbsScalar(ginner) >= cg->eta * gnorm2) {
146ac9112b8SAlp Dener       /* 2) Gradients are far from orthogonal */
147ac9112b8SAlp Dener       cg_restart = PETSC_TRUE;
148c4b75bccSAlp Dener       ++cg->broken_ortho;
149ac9112b8SAlp Dener     }
150ac9112b8SAlp Dener 
151ac9112b8SAlp Dener     /* Compute CG step */
152ac9112b8SAlp Dener     if (cg_restart) {
153ac9112b8SAlp Dener       beta = 0.0;
154c4b75bccSAlp Dener       ++cg->resets;
155ac9112b8SAlp Dener     } else {
156ac9112b8SAlp Dener       switch (cg->cg_type) {
157ac9112b8SAlp Dener       case CG_FletcherReeves:
158ac9112b8SAlp Dener         beta = gnorm2 / gnorm2_old;
159ac9112b8SAlp Dener         break;
160ac9112b8SAlp Dener 
161ac9112b8SAlp Dener       case CG_PolakRibiere:
162ac9112b8SAlp Dener         beta = (gnorm2 - ginner) / gnorm2_old;
163ac9112b8SAlp Dener         break;
164ac9112b8SAlp Dener 
165ac9112b8SAlp Dener       case CG_PolakRibierePlus:
166ac9112b8SAlp Dener         beta = PetscMax((gnorm2-ginner)/gnorm2_old, 0.0);
167ac9112b8SAlp Dener         break;
168ac9112b8SAlp Dener 
169ac9112b8SAlp Dener       case CG_HestenesStiefel:
170ac9112b8SAlp Dener         ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
171ac9112b8SAlp Dener         ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
172ac9112b8SAlp Dener         beta = (gnorm2 - ginner) / (gd - gd_old);
173ac9112b8SAlp Dener         break;
174ac9112b8SAlp Dener 
175ac9112b8SAlp Dener       case CG_DaiYuan:
176ac9112b8SAlp Dener         ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
177ac9112b8SAlp Dener         ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr);
178ac9112b8SAlp Dener         beta = gnorm2 / (gd - gd_old);
179ac9112b8SAlp Dener         break;
180ac9112b8SAlp Dener 
181560169d0SAlp Dener       case CG_GradientDescent:
182560169d0SAlp Dener         beta = 0.0;
183560169d0SAlp Dener         break;
184560169d0SAlp Dener 
185ac9112b8SAlp Dener       default:
186ac9112b8SAlp Dener         beta = 0.0;
187ac9112b8SAlp Dener         break;
188ac9112b8SAlp Dener       }
189ac9112b8SAlp Dener     }
190ac9112b8SAlp Dener 
191ac9112b8SAlp Dener     /*  Compute the direction d=-g + beta*d */
192ac9112b8SAlp Dener     ierr = VecAXPBY(tao->stepdirection, -1.0, beta, tao->gradient);CHKERRQ(ierr);
193a1318120SAlp Dener     ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
19489da521bSAlp Dener 
195560169d0SAlp Dener     if (cg->cg_type != CG_GradientDescent) {
19689da521bSAlp Dener       /* Figure out which previously active variables became inactive this iteration */
19761be54a6SAlp Dener       ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
19889da521bSAlp Dener       if (cg->inactive_idx && cg->inactive_old) {
1990b7db9bbSAlp Dener         ierr = ISDifference(cg->inactive_idx, cg->inactive_old, &cg->new_inactives);CHKERRQ(ierr);
20089da521bSAlp Dener       }
20189da521bSAlp Dener 
20289da521bSAlp Dener       /* Selectively reset the CG step those freshly inactive variables */
2037529f6b4SAlp Dener       if (cg->new_inactives) {
20461be54a6SAlp Dener         ierr = VecGetSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
20589da521bSAlp Dener         ierr = VecGetSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
20661be54a6SAlp Dener         ierr = VecCopy(cg->inactive_grad, cg->inactive_step);CHKERRQ(ierr);
20761be54a6SAlp Dener         ierr = VecScale(cg->inactive_step, -1.0);CHKERRQ(ierr);
20861be54a6SAlp Dener         ierr = VecRestoreSubVector(tao->stepdirection, cg->new_inactives, &cg->inactive_step);CHKERRQ(ierr);
20989da521bSAlp Dener         ierr = VecRestoreSubVector(cg->unprojected_gradient, cg->new_inactives, &cg->inactive_grad);CHKERRQ(ierr);
2107529f6b4SAlp Dener       }
211ac9112b8SAlp Dener 
212ac9112b8SAlp Dener       /* Verify that this is a descent direction */
213ac9112b8SAlp Dener       ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr);
214560169d0SAlp Dener       ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);
215ac9112b8SAlp Dener       if (gd > -cg->rho*PetscPowReal(dnorm, cg->pow)) {
216ac9112b8SAlp Dener         /* Not a descent direction, so we reset back to projected gradient descent */
217ac9112b8SAlp Dener         ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, tao->gradient);CHKERRQ(ierr);
218560169d0SAlp Dener         ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
219c4b75bccSAlp Dener         ++cg->resets;
220c4b75bccSAlp Dener         ++cg->descent_error;
221560169d0SAlp Dener         gd_fallback = PETSC_TRUE;
222560169d0SAlp Dener       } else {
223560169d0SAlp Dener         gd_fallback = PETSC_FALSE;
224560169d0SAlp Dener       }
225ac9112b8SAlp Dener     }
226ac9112b8SAlp Dener 
227ac9112b8SAlp Dener     /* Store solution and gradient info before it changes */
228ac9112b8SAlp Dener     ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr);
229ac9112b8SAlp Dener     ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr);
230ac9112b8SAlp Dener     ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr);
231ac9112b8SAlp Dener     gnorm2_old = gnorm2;
232c0f10754SAlp Dener     f_old = cg->f;
233ac9112b8SAlp Dener 
234ac9112b8SAlp Dener     /* Perform bounded line search */
235c0f10754SAlp Dener     ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
236ac9112b8SAlp Dener     ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
237ac9112b8SAlp Dener 
238ac9112b8SAlp Dener     /*  Check linesearch failure */
239ac9112b8SAlp Dener     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
240c4b75bccSAlp Dener       ++cg->ls_fails;
241ac9112b8SAlp Dener       /* Restore previous point */
242ac9112b8SAlp Dener       gnorm2 = gnorm2_old;
243c0f10754SAlp Dener       cg->f = f_old;
244ac9112b8SAlp Dener       ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr);
245ac9112b8SAlp Dener       ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr);
246ac9112b8SAlp Dener       ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr);
247ac9112b8SAlp Dener 
248560169d0SAlp Dener       if (cg->cg_type == CG_GradientDescent || gd_fallback){
249560169d0SAlp Dener         /* Nothing left to do but fail out of the optimization */
250560169d0SAlp Dener         step = 0.0;
251560169d0SAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
252560169d0SAlp Dener       } else {
253560169d0SAlp Dener         /* Fall back on the unscaled gradient step */
25461be54a6SAlp Dener         ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr);
255ac9112b8SAlp Dener         ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
256a1318120SAlp Dener         ierr = TaoBNCGBoundStep(tao, cg->as_type, tao->stepdirection);CHKERRQ(ierr);
257560169d0SAlp Dener 
258560169d0SAlp Dener         ierr = TaoLineSearchSetInitialStepLength(tao->linesearch, 1.0);CHKERRQ(ierr);
259c0f10754SAlp Dener         ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr);
260ac9112b8SAlp Dener         ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr);
261ac9112b8SAlp Dener 
262ac9112b8SAlp Dener         if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){
263560169d0SAlp Dener           cg->ls_fails++;
264ac9112b8SAlp Dener           /* Restore previous point */
265ac9112b8SAlp Dener           gnorm2 = gnorm2_old;
266c0f10754SAlp Dener           cg->f = f_old;
267ac9112b8SAlp Dener           ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr);
268ac9112b8SAlp Dener           ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr);
269ac9112b8SAlp Dener           ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr);
270ac9112b8SAlp Dener 
271ac9112b8SAlp Dener           /* Nothing left to do but fail out of the optimization */
272ac9112b8SAlp Dener           step = 0.0;
273ac9112b8SAlp Dener           tao->reason = TAO_DIVERGED_LS_FAILURE;
274ac9112b8SAlp Dener         }
275ac9112b8SAlp Dener       }
276560169d0SAlp Dener     }
277ac9112b8SAlp Dener 
278c4b75bccSAlp Dener     if (tao->reason != TAO_DIVERGED_LS_FAILURE) {
27961be54a6SAlp Dener       /* Estimate the active set at the new solution */
28061be54a6SAlp Dener       ierr = TaoBNCGEstimateActiveSet(tao, cg->as_type);CHKERRQ(ierr);
28161be54a6SAlp Dener 
282ac9112b8SAlp Dener       /* Compute the projected gradient and its norm */
28361be54a6SAlp Dener       ierr = VecCopy(cg->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
28461be54a6SAlp Dener       ierr = VecISSet(tao->gradient, cg->active_idx, 0.0);CHKERRQ(ierr);
285ac9112b8SAlp Dener       ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr);
286ac9112b8SAlp Dener       gnorm2 = gnorm*gnorm;
287c4b75bccSAlp Dener     }
288ac9112b8SAlp Dener 
289ac9112b8SAlp Dener     /* Convergence test */
29061be54a6SAlp Dener     ierr = VecFischer(tao->solution, cg->unprojected_gradient, tao->XL, tao->XU, cg->W);CHKERRQ(ierr);
29161be54a6SAlp Dener     ierr = VecNorm(cg->W, NORM_2, &resnorm);CHKERRQ(ierr);
292b4a30f08SAlp Dener     if (PetscIsInfOrNanReal(resnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
29361be54a6SAlp Dener     ierr = TaoLogConvergenceHistory(tao, cg->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
29461be54a6SAlp Dener     ierr = TaoMonitor(tao, tao->niter, cg->f, resnorm, 0.0, step);CHKERRQ(ierr);
295ac9112b8SAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
296ac9112b8SAlp Dener   }
297ac9112b8SAlp Dener   PetscFunctionReturn(0);
298ac9112b8SAlp Dener }
299ac9112b8SAlp Dener 
300ac9112b8SAlp Dener static PetscErrorCode TaoSetUp_BNCG(Tao tao)
301ac9112b8SAlp Dener {
302ac9112b8SAlp Dener   TAO_BNCG         *cg = (TAO_BNCG*)tao->data;
303ac9112b8SAlp Dener   PetscErrorCode ierr;
304ac9112b8SAlp Dener 
305ac9112b8SAlp Dener   PetscFunctionBegin;
306c4b75bccSAlp Dener   if (!tao->gradient) {
307c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);
308c4b75bccSAlp Dener   }
309c4b75bccSAlp Dener   if (!tao->stepdirection) {
310c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr);
311c4b75bccSAlp Dener   }
312c4b75bccSAlp Dener   if (!cg->W) {
313c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->W);CHKERRQ(ierr);
314c4b75bccSAlp Dener   }
315c4b75bccSAlp Dener   if (!cg->work) {
316c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->work);CHKERRQ(ierr);
317c4b75bccSAlp Dener   }
318c4b75bccSAlp Dener   if (!cg->X_old) {
319c4b75bccSAlp Dener     ierr = VecDuplicate(tao->solution,&cg->X_old);CHKERRQ(ierr);
320c4b75bccSAlp Dener   }
321c4b75bccSAlp Dener   if (!cg->G_old) {
322c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->G_old);CHKERRQ(ierr);
323c4b75bccSAlp Dener   }
324c4b75bccSAlp Dener   if (!cg->unprojected_gradient) {
325c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient);CHKERRQ(ierr);
326c4b75bccSAlp Dener   }
327c4b75bccSAlp Dener   if (!cg->unprojected_gradient_old) {
328c4b75bccSAlp Dener     ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient_old);CHKERRQ(ierr);
329c4b75bccSAlp Dener   }
330ac9112b8SAlp Dener   PetscFunctionReturn(0);
331ac9112b8SAlp Dener }
332ac9112b8SAlp Dener 
333ac9112b8SAlp Dener static PetscErrorCode TaoDestroy_BNCG(Tao tao)
334ac9112b8SAlp Dener {
335ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*) tao->data;
336ac9112b8SAlp Dener   PetscErrorCode ierr;
337ac9112b8SAlp Dener 
338ac9112b8SAlp Dener   PetscFunctionBegin;
339ac9112b8SAlp Dener   if (tao->setupcalled) {
34061be54a6SAlp Dener     ierr = VecDestroy(&cg->W);CHKERRQ(ierr);
341c4b75bccSAlp Dener     ierr = VecDestroy(&cg->work);CHKERRQ(ierr);
342ac9112b8SAlp Dener     ierr = VecDestroy(&cg->X_old);CHKERRQ(ierr);
343ac9112b8SAlp Dener     ierr = VecDestroy(&cg->G_old);CHKERRQ(ierr);
344ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient);CHKERRQ(ierr);
345ac9112b8SAlp Dener     ierr = VecDestroy(&cg->unprojected_gradient_old);CHKERRQ(ierr);
346ac9112b8SAlp Dener   }
347ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_lower);CHKERRQ(ierr);
348ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_upper);CHKERRQ(ierr);
349ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_fixed);CHKERRQ(ierr);
350ca964c49SAlp Dener   ierr = ISDestroy(&cg->active_idx);CHKERRQ(ierr);
351ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_idx);CHKERRQ(ierr);
352ca964c49SAlp Dener   ierr = ISDestroy(&cg->inactive_old);CHKERRQ(ierr);
353ca964c49SAlp Dener   ierr = ISDestroy(&cg->new_inactives);CHKERRQ(ierr);
354ac9112b8SAlp Dener   ierr = PetscFree(tao->data);CHKERRQ(ierr);
355ac9112b8SAlp Dener   PetscFunctionReturn(0);
356ac9112b8SAlp Dener }
357ac9112b8SAlp Dener 
358ac9112b8SAlp Dener static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao)
359ac9112b8SAlp Dener  {
360ac9112b8SAlp Dener     TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
361ac9112b8SAlp Dener     PetscErrorCode ierr;
362ac9112b8SAlp Dener 
363ac9112b8SAlp Dener     PetscFunctionBegin;
364ac9112b8SAlp Dener     ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr);
365ac9112b8SAlp Dener     ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr);
36661be54a6SAlp Dener     ierr = PetscOptionsReal("-tao_bncg_eta","restart tolerance", "", cg->eta,&cg->eta,NULL);CHKERRQ(ierr);
36761be54a6SAlp Dener     ierr = PetscOptionsReal("-tao_bncg_rho","descent direction tolerance", "", cg->rho,&cg->rho,NULL);CHKERRQ(ierr);
36861be54a6SAlp Dener     ierr = PetscOptionsReal("-tao_bncg_pow","descent direction exponent", "", cg->pow,&cg->pow,NULL);CHKERRQ(ierr);
36961be54a6SAlp Dener     ierr = PetscOptionsEList("-tao_bncg_type","cg formula", "", CG_Table, CG_Types, CG_Table[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr);
370*cd929ea3SAlp Dener     ierr = PetscOptionsEList("-tao_bncg_as_type","active set estimation method", "", CG_AS_TYPE, CG_AS_SIZE, CG_AS_TYPE[cg->as_type], &cg->as_type,NULL);CHKERRQ(ierr);
37161be54a6SAlp Dener     ierr = PetscOptionsBool("-tao_bncg_recycle","enable recycling the existing solution and gradient at the start of a new solve","",cg->recycle,&cg->recycle,NULL);CHKERRQ(ierr);
37261be54a6SAlp Dener     ierr = PetscOptionsReal("-tao_bncg_as_tol", "initial tolerance used when estimating actively bounded variables","",cg->as_tol,&cg->as_tol,NULL);CHKERRQ(ierr);
37361be54a6SAlp Dener     ierr = PetscOptionsReal("-tao_bncg_as_step", "step length used when estimating actively bounded variables","",cg->as_step,&cg->as_step,NULL);CHKERRQ(ierr);
374ac9112b8SAlp Dener    ierr = PetscOptionsTail();CHKERRQ(ierr);
375ac9112b8SAlp Dener    PetscFunctionReturn(0);
376ac9112b8SAlp Dener }
377ac9112b8SAlp Dener 
378ac9112b8SAlp Dener static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer)
379ac9112b8SAlp Dener {
380ac9112b8SAlp Dener   PetscBool      isascii;
381ac9112b8SAlp Dener   TAO_BNCG       *cg = (TAO_BNCG*)tao->data;
382ac9112b8SAlp Dener   PetscErrorCode ierr;
383ac9112b8SAlp Dener 
384ac9112b8SAlp Dener   PetscFunctionBegin;
385ac9112b8SAlp Dener   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
386ac9112b8SAlp Dener   if (isascii) {
387ac9112b8SAlp Dener     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
388ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type]);CHKERRQ(ierr);
389ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Resets: %i\n", cg->resets);CHKERRQ(ierr);
390ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  Broken ortho: %i\n", cg->broken_ortho);CHKERRQ(ierr);
391ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "  Not a descent dir.: %i\n", cg->descent_error);CHKERRQ(ierr);
392ac9112b8SAlp Dener     ierr = PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails);CHKERRQ(ierr);
393ac9112b8SAlp Dener     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
394ac9112b8SAlp Dener   }
395ac9112b8SAlp Dener   PetscFunctionReturn(0);
396ac9112b8SAlp Dener }
397ac9112b8SAlp Dener 
398ac9112b8SAlp Dener /*MC
399ac9112b8SAlp Dener      TAOBNCG -   Bound-constrained Nonlinear Conjugate Gradient method.
400ac9112b8SAlp Dener 
401ac9112b8SAlp Dener    Options Database Keys:
402c4b75bccSAlp Dener +      -tao_bncg_recycle - enable recycling the latest calculated gradient vector in subsequent TaoSolve() calls
403c4b75bccSAlp Dener .      -tao_bncg_eta <r> - restart tolerance
40461be54a6SAlp Dener .      -tao_bncg_type <taocg_type> - cg formula
405c4b75bccSAlp Dener .      -tao_bncg_as_type <none,bertsekas> - active set estimation method
406c4b75bccSAlp Dener .      -tao_bncg_as_tol <r> - tolerance used in Bertsekas active-set estimation
407c4b75bccSAlp Dener .      -tao_bncg_as_step <r> - trial step length used in Bertsekas active-set estimation
408ac9112b8SAlp Dener 
409ac9112b8SAlp Dener   Notes:
410ac9112b8SAlp Dener      CG formulas are:
411ac9112b8SAlp Dener          "fr" - Fletcher-Reeves
412ac9112b8SAlp Dener          "pr" - Polak-Ribiere
413ac9112b8SAlp Dener          "prp" - Polak-Ribiere-Plus
414ac9112b8SAlp Dener          "hs" - Hestenes-Steifel
415ac9112b8SAlp Dener          "dy" - Dai-Yuan
416560169d0SAlp Dener          "gd" - Gradient Descent
417ac9112b8SAlp Dener   Level: beginner
418ac9112b8SAlp Dener M*/
419ac9112b8SAlp Dener 
420ac9112b8SAlp Dener 
421ac9112b8SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao)
422ac9112b8SAlp Dener {
423ac9112b8SAlp Dener   TAO_BNCG       *cg;
424ac9112b8SAlp Dener   const char     *morethuente_type = TAOLINESEARCHMT;
425ac9112b8SAlp Dener   PetscErrorCode ierr;
426ac9112b8SAlp Dener 
427ac9112b8SAlp Dener   PetscFunctionBegin;
428ac9112b8SAlp Dener   tao->ops->setup = TaoSetUp_BNCG;
429ac9112b8SAlp Dener   tao->ops->solve = TaoSolve_BNCG;
430ac9112b8SAlp Dener   tao->ops->view = TaoView_BNCG;
431ac9112b8SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BNCG;
432ac9112b8SAlp Dener   tao->ops->destroy = TaoDestroy_BNCG;
433ac9112b8SAlp Dener 
434ac9112b8SAlp Dener   /* Override default settings (unless already changed) */
435ac9112b8SAlp Dener   if (!tao->max_it_changed) tao->max_it = 2000;
436ac9112b8SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
437ac9112b8SAlp Dener 
438ac9112b8SAlp Dener   /*  Note: nondefault values should be used for nonlinear conjugate gradient  */
439ac9112b8SAlp Dener   /*  method.  In particular, gtol should be less that 0.5; the value used in  */
440ac9112b8SAlp Dener   /*  Nocedal and Wright is 0.10.  We use the default values for the  */
441ac9112b8SAlp Dener   /*  linesearch because it seems to work better. */
442ac9112b8SAlp Dener   ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr);
443ac9112b8SAlp Dener   ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr);
444ac9112b8SAlp Dener   ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr);
445ac9112b8SAlp Dener   ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr);
446ac9112b8SAlp Dener   ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr);
447ac9112b8SAlp Dener 
448ac9112b8SAlp Dener   ierr = PetscNewLog(tao,&cg);CHKERRQ(ierr);
449ac9112b8SAlp Dener   tao->data = (void*)cg;
450ac9112b8SAlp Dener   cg->rho = 1e-4;
451ac9112b8SAlp Dener   cg->pow = 2.1;
452ac9112b8SAlp Dener   cg->eta = 0.5;
45361be54a6SAlp Dener   cg->as_step = 0.001;
45461be54a6SAlp Dener   cg->as_tol = 0.001;
45561be54a6SAlp Dener   cg->as_type = CG_AS_BERTSEKAS;
456ac9112b8SAlp Dener   cg->cg_type = CG_DaiYuan;
457c0f10754SAlp Dener   cg->recycle = PETSC_FALSE;
458ac9112b8SAlp Dener   PetscFunctionReturn(0);
459ac9112b8SAlp Dener }
460