xref: /petsc/src/tao/bound/impls/bnk/bntl.c (revision 61be54a68cd238714af883d2215bb04911cc1c21)
1c14b763aSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2c14b763aSAlp Dener #include <petscksp.h>
3c14b763aSAlp Dener 
4c14b763aSAlp Dener /*
5c14b763aSAlp Dener  Implements Newton's Method with a trust region approach for solving
6198282dbSAlp Dener  bound constrained minimization problems.
7c14b763aSAlp Dener 
8198282dbSAlp Dener  ------------------------------------------------------------
9198282dbSAlp Dener 
10198282dbSAlp Dener  initialize trust radius (default: BNK_INIT_INTERPOLATION)
11198282dbSAlp Dener  x_0 = VecMedian(x_0)
12198282dbSAlp Dener  f_0, g_0 = TaoComputeObjectiveAndGradient(x_0)
13198282dbSAlp Dener  pg_0 = VecBoundGradientProjection(g_0)
14198282dbSAlp Dener  check convergence at pg_0
15198282dbSAlp Dener  niter = 0
16198282dbSAlp Dener  step_accepted = true
17198282dbSAlp Dener 
18198282dbSAlp Dener  while niter <= max_it
19198282dbSAlp Dener     niter += 1
20198282dbSAlp Dener     H_k = TaoComputeHessian(x_k)
21198282dbSAlp Dener     if pc_type == BNK_PC_BFGS
22198282dbSAlp Dener       add correction to BFGS approx
23198282dbSAlp Dener       if scale_type == BNK_SCALE_AHESS
24198282dbSAlp Dener         D = VecMedian(1e-6, abs(diag(H_k)), 1e6)
25198282dbSAlp Dener         scale BFGS with VecReciprocal(D)
26198282dbSAlp Dener       end
27198282dbSAlp Dener     end
28198282dbSAlp Dener 
29198282dbSAlp Dener     if pc_type = BNK_PC_BFGS
30198282dbSAlp Dener       B_k = BFGS
31198282dbSAlp Dener     else
32198282dbSAlp Dener       B_k = VecMedian(1e-6, abs(diag(H_k)), 1e6)
33198282dbSAlp Dener       B_k = VecReciprocal(B_k)
34198282dbSAlp Dener     end
35198282dbSAlp Dener     w = x_k - VecMedian(x_k - 0.001*B_k*g_k)
36198282dbSAlp Dener     eps = min(eps, norm2(w))
37198282dbSAlp Dener     determine the active and inactive index sets such that
38198282dbSAlp Dener       L = {i : (x_k)_i <= l_i + eps && (g_k)_i > 0}
39198282dbSAlp Dener       U = {i : (x_k)_i >= u_i - eps && (g_k)_i < 0}
40198282dbSAlp Dener       F = {i : l_i = (x_k)_i = u_i}
41198282dbSAlp Dener       A = {L + U + F}
42198282dbSAlp Dener       I = {i : i not in A}
43198282dbSAlp Dener 
44198282dbSAlp Dener     generate the reduced system Hr_k dr_k = -gr_k for variables in I
45198282dbSAlp Dener     if pc_type == BNK_PC_BFGS && scale_type == BNK_SCALE_PHESS
46198282dbSAlp Dener       D = VecMedian(1e-6, abs(diag(Hr_k)), 1e6)
47198282dbSAlp Dener       scale BFGS with VecReciprocal(D)
48198282dbSAlp Dener     end
49198282dbSAlp Dener     solve Hr_k dr_k = -gr_k
50198282dbSAlp Dener     set d_k to (l - x) for variables in L, (u - x) for variables in U, and 0 for variables in F
51198282dbSAlp Dener 
52198282dbSAlp Dener     x_{k+1} = VecMedian(x_k + d_k)
53198282dbSAlp Dener     s = x_{k+1} - x_k
54198282dbSAlp Dener     prered = dot(s, 0.5*gr_k - Hr_k*s)
55198282dbSAlp Dener     f_{k+1} = TaoComputeObjective(x_{k+1})
56198282dbSAlp Dener     actred = f_k - f_{k+1}
57198282dbSAlp Dener 
58198282dbSAlp Dener     oldTrust = trust
59198282dbSAlp Dener     step_accepted, trust = TaoBNKUpdateTrustRadius(default: BNK_UPDATE_REDUCTION)
60198282dbSAlp Dener     if step_accepted
61198282dbSAlp Dener       g_{k+1} = TaoComputeGradient(x_{k+1})
62198282dbSAlp Dener       pg_{k+1} = VecBoundGradientProjection(g_{k+1})
63198282dbSAlp Dener       count the accepted Newton step
64198282dbSAlp Dener     else
65198282dbSAlp Dener       if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
66198282dbSAlp Dener         dr_k = -BFGS*gr_k for variables in I
67198282dbSAlp Dener         if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
68198282dbSAlp Dener           reset the BFGS preconditioner
69198282dbSAlp Dener           calculate scale delta and apply it to BFGS
70198282dbSAlp Dener           dr_k = -BFGS*gr_k for variables in I
71198282dbSAlp Dener           if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
72198282dbSAlp Dener             dr_k = -gr_k for variables in I
73198282dbSAlp Dener           end
74198282dbSAlp Dener         end
75198282dbSAlp Dener       end
76198282dbSAlp Dener 
77198282dbSAlp Dener       x_{k+1}, f_{k+1}, g_{k+1}, ls_failed = TaoBNKPerformLineSearch()
78198282dbSAlp Dener       if ls_failed
79198282dbSAlp Dener         f_{k+1} = f_k
80198282dbSAlp Dener         x_{k+1} = x_k
81198282dbSAlp Dener         g_{k+1} = g_k
82198282dbSAlp Dener         pg_{k+1} = pg_k
83198282dbSAlp Dener         terminate
84198282dbSAlp Dener       else
85198282dbSAlp Dener         pg_{k+1} = VecBoundGradientProjection(g_{k+1})
86198282dbSAlp Dener         trust = oldTrust
87198282dbSAlp Dener         trust = TaoBNKUpdateTrustRadius(BNK_UPDATE_STEP)
88198282dbSAlp Dener         count the accepted step type (Newton, BFGS, scaled grad or grad)
89198282dbSAlp Dener       end
90198282dbSAlp Dener     end
91198282dbSAlp Dener 
92198282dbSAlp Dener     check convergence at pg_{k+1}
93198282dbSAlp Dener  end
94c14b763aSAlp Dener */
95c14b763aSAlp Dener 
96c14b763aSAlp Dener static PetscErrorCode TaoSolve_BNTL(Tao tao)
97c14b763aSAlp Dener {
98c14b763aSAlp Dener   PetscErrorCode               ierr;
99c14b763aSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
100e465cd6fSAlp Dener   KSPConvergedReason           ksp_reason;
101c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
102c14b763aSAlp Dener 
1039b6ef848SAlp Dener   PetscReal                    resnorm, oldTrust, prered, actred, stepNorm, steplen;
104937a31a1SAlp Dener   PetscBool                    cgTerminate, needH = PETSC_TRUE, stepAccepted, shift = PETSC_FALSE;
10528017e9fSAlp Dener   PetscInt                     stepType;
106c14b763aSAlp Dener 
107c14b763aSAlp Dener   PetscFunctionBegin;
10828017e9fSAlp Dener   /* Initialize the preconditioner, KSP solver and trust radius/line search */
109c14b763aSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
110937a31a1SAlp Dener   ierr = TaoBNKInitialize(tao, bnk->init_type, &needH);CHKERRQ(ierr);
11128017e9fSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
112c14b763aSAlp Dener 
113c14b763aSAlp Dener   /* Have not converged; continue with Newton method */
114c14b763aSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
115c14b763aSAlp Dener     tao->niter++;
11662675beeSAlp Dener 
117937a31a1SAlp Dener     if (needH) {
118e031d6f5SAlp Dener       /* Take BNCG steps (if enabled) to trade-off Hessian evaluations for more gradient evaluations */
119e031d6f5SAlp Dener       ierr = TaoBNKTakeCGSteps(tao, &cgTerminate);CHKERRQ(ierr);
120e031d6f5SAlp Dener       if (cgTerminate) {
121e031d6f5SAlp Dener         tao->reason = bnk->bncg->reason;
122e031d6f5SAlp Dener         PetscFunctionReturn(0);
123e031d6f5SAlp Dener       }
12408752603SAlp Dener       /* Compute the hessian and update the BFGS preconditioner at the new iterate */
125937a31a1SAlp Dener       ierr = TaoBNKComputeHessian(tao);CHKERRQ(ierr);
126937a31a1SAlp Dener       needH = PETSC_FALSE;
127937a31a1SAlp Dener     }
128c14b763aSAlp Dener 
1298d5ead36SAlp Dener     /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */
13062675beeSAlp Dener     ierr = TaoBNKComputeStep(tao, shift, &ksp_reason);CHKERRQ(ierr);
131c14b763aSAlp Dener 
132c14b763aSAlp Dener     /* Store current solution before it changes */
133c14b763aSAlp Dener     oldTrust = tao->trust;
134c14b763aSAlp Dener     bnk->fold = bnk->f;
135c14b763aSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
136c14b763aSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
137c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
138c14b763aSAlp Dener 
139c14b763aSAlp Dener     /* Temporarily accept the step and project it into the bounds */
140c14b763aSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
141c14b763aSAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
142c14b763aSAlp Dener 
143c14b763aSAlp Dener     /* Check if the projection changed the step direction */
144c14b763aSAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
1458d5ead36SAlp Dener     ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
146c14b763aSAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
147c14b763aSAlp Dener     if (stepNorm != bnk->dnorm) {
1488d5ead36SAlp Dener       /* Projection changed the step, so we have to recompute predicted reduction.
1498d5ead36SAlp Dener          However, we deliberately do not change the step norm and the trust radius
1508d5ead36SAlp Dener          in order for the safeguard to more closely mimic a piece-wise linesearch
1518d5ead36SAlp Dener          along the bounds. */
1525e9b73cbSAlp Dener       ierr = TaoBNKRecomputePred(tao, tao->stepdirection, &prered);CHKERRQ(ierr);
153c14b763aSAlp Dener     } else {
154c14b763aSAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
155c14b763aSAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
156c14b763aSAlp Dener     }
157c14b763aSAlp Dener     prered = -prered;
158c14b763aSAlp Dener 
159c14b763aSAlp Dener     /* Compute the actual reduction and update the trust radius */
160c14b763aSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
161c14b763aSAlp Dener     actred = bnk->fold - bnk->f;
16228017e9fSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr);
163c14b763aSAlp Dener 
164c14b763aSAlp Dener     if (stepAccepted) {
165c14b763aSAlp Dener       /* Step is good, evaluate the gradient and the hessian */
1668d5ead36SAlp Dener       steplen = 1.0;
167937a31a1SAlp Dener       needH = PETSC_TRUE;
168e465cd6fSAlp Dener       ++bnk->newt;
169c14b763aSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
170*61be54a6SAlp Dener       ierr = TaoBNKEstimateActiveSet(tao, bnk->as_type);CHKERRQ(ierr);
171*61be54a6SAlp Dener       ierr = VecCopy(bnk->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
172*61be54a6SAlp Dener       ierr = VecISSet(tao->gradient, bnk->active_idx, 0.0);CHKERRQ(ierr);
173c14b763aSAlp Dener     } else {
174c14b763aSAlp Dener       /* Trust-region rejected the step. Revert the solution. */
175c14b763aSAlp Dener       bnk->f = bnk->fold;
176c14b763aSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
177c14b763aSAlp Dener       /* Trigger the line search */
178e465cd6fSAlp Dener       ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
179937a31a1SAlp Dener       ierr = TaoBNKPerformLineSearch(tao, &stepType, &steplen, &ls_reason);CHKERRQ(ierr);
180c14b763aSAlp Dener       if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
181c14b763aSAlp Dener         /* Line search failed, revert solution and terminate */
182c0f10754SAlp Dener         stepAccepted = PETSC_FALSE;
183937a31a1SAlp Dener         needH = PETSC_FALSE;
184c14b763aSAlp Dener         bnk->f = bnk->fold;
185c14b763aSAlp Dener         ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
186c14b763aSAlp Dener         ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
187c14b763aSAlp Dener         ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
188c14b763aSAlp Dener         tao->trust = 0.0;
189c14b763aSAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
190c14b763aSAlp Dener       } else {
191937a31a1SAlp Dener         /* new iterate so we need to recompute the Hessian */
192937a31a1SAlp Dener         needH = PETSC_TRUE;
193198282dbSAlp Dener         /* compute the projected gradient */
194*61be54a6SAlp Dener         ierr = TaoBNKEstimateActiveSet(tao, bnk->as_type);CHKERRQ(ierr);
195*61be54a6SAlp Dener         ierr = VecCopy(bnk->unprojected_gradient, tao->gradient);CHKERRQ(ierr);
196*61be54a6SAlp Dener         ierr = VecISSet(tao->gradient, bnk->active_idx, 0.0);CHKERRQ(ierr);
1979b6ef848SAlp Dener         ierr = VecNorm(tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
1989b6ef848SAlp Dener         if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
199c14b763aSAlp Dener         /* Line search succeeded so we should update the trust radius based on the LS step length */
200770b7498SAlp Dener         tao->trust = oldTrust;
20128017e9fSAlp Dener         ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, BNK_UPDATE_STEP, stepType, &stepAccepted);CHKERRQ(ierr);
20262675beeSAlp Dener         /* count the accepted step type */
20362675beeSAlp Dener         ierr = TaoBNKAddStepCounts(tao, stepType);CHKERRQ(ierr);
204c14b763aSAlp Dener       }
205c14b763aSAlp Dener     }
206c14b763aSAlp Dener 
207c14b763aSAlp Dener     /*  Check for termination */
2089b6ef848SAlp Dener     ierr = VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->Gwork);CHKERRQ(ierr);
2099b6ef848SAlp Dener     ierr = VecNorm(bnk->Gwork, NORM_2, &resnorm);CHKERRQ(ierr);
2109b6ef848SAlp Dener     ierr = TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr);
2119b6ef848SAlp Dener     ierr = TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, steplen);CHKERRQ(ierr);
212c14b763aSAlp Dener     ierr = (*tao->ops->convergencetest)(tao, tao->cnvP);CHKERRQ(ierr);
213c14b763aSAlp Dener   }
214c14b763aSAlp Dener   PetscFunctionReturn(0);
215c14b763aSAlp Dener }
216c14b763aSAlp Dener 
217df278d8fSAlp Dener /*------------------------------------------------------------*/
218df278d8fSAlp Dener 
2199b6ef848SAlp Dener PETSC_INTERN PetscErrorCode TaoSetUp_BNTL(Tao tao)
2209b6ef848SAlp Dener {
2219b6ef848SAlp Dener   TAO_BNK        *bnk = (TAO_BNK *)tao->data;
2229b6ef848SAlp Dener   PetscErrorCode ierr;
2239b6ef848SAlp Dener 
2249b6ef848SAlp Dener   PetscFunctionBegin;
2259b6ef848SAlp Dener   ierr = TaoSetUp_BNK(tao);CHKERRQ(ierr);
2269b6ef848SAlp Dener   if (!bnk->is_nash && !bnk->is_stcg && !bnk->is_gltr) SETERRQ(PETSC_COMM_SELF,1,"Must use a trust-region CG method for KSP (KSPNASH, KSPSTCG, KSPGLTR)");
2279b6ef848SAlp Dener   PetscFunctionReturn(0);
2289b6ef848SAlp Dener }
2299b6ef848SAlp Dener 
2309b6ef848SAlp Dener /*------------------------------------------------------------*/
2319b6ef848SAlp Dener 
2329b6ef848SAlp Dener PETSC_INTERN PetscErrorCode TaoCreate_BNTL(Tao tao)
233c14b763aSAlp Dener {
234c14b763aSAlp Dener   TAO_BNK        *bnk;
235c14b763aSAlp Dener   PetscErrorCode ierr;
236c14b763aSAlp Dener 
237c14b763aSAlp Dener   PetscFunctionBegin;
238c14b763aSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
239c14b763aSAlp Dener   tao->ops->solve=TaoSolve_BNTL;
2409b6ef848SAlp Dener   tao->ops->setup=TaoSetUp_BNTL;
241c14b763aSAlp Dener 
242c14b763aSAlp Dener   bnk = (TAO_BNK *)tao->data;
243c14b763aSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
244c14b763aSAlp Dener   PetscFunctionReturn(0);
245c14b763aSAlp Dener }