xref: /petsc/src/tao/bound/impls/bnk/bntl.c (revision 198282db2bfc4cc7307b0b13cb98d7a27b116ed7)
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
6*198282dbSAlp Dener  bound constrained minimization problems.
7c14b763aSAlp Dener 
8*198282dbSAlp Dener  ------------------------------------------------------------
9*198282dbSAlp Dener 
10*198282dbSAlp Dener  initialize trust radius (default: BNK_INIT_INTERPOLATION)
11*198282dbSAlp Dener  x_0 = VecMedian(x_0)
12*198282dbSAlp Dener  f_0, g_0 = TaoComputeObjectiveAndGradient(x_0)
13*198282dbSAlp Dener  pg_0 = VecBoundGradientProjection(g_0)
14*198282dbSAlp Dener  check convergence at pg_0
15*198282dbSAlp Dener  niter = 0
16*198282dbSAlp Dener  step_accepted = true
17*198282dbSAlp Dener 
18*198282dbSAlp Dener  while niter <= max_it
19*198282dbSAlp Dener     niter += 1
20*198282dbSAlp Dener     H_k = TaoComputeHessian(x_k)
21*198282dbSAlp Dener     if pc_type == BNK_PC_BFGS
22*198282dbSAlp Dener       add correction to BFGS approx
23*198282dbSAlp Dener       if scale_type == BNK_SCALE_AHESS
24*198282dbSAlp Dener         D = VecMedian(1e-6, abs(diag(H_k)), 1e6)
25*198282dbSAlp Dener         scale BFGS with VecReciprocal(D)
26*198282dbSAlp Dener       end
27*198282dbSAlp Dener     end
28*198282dbSAlp Dener 
29*198282dbSAlp Dener     if pc_type = BNK_PC_BFGS
30*198282dbSAlp Dener       B_k = BFGS
31*198282dbSAlp Dener     else
32*198282dbSAlp Dener       B_k = VecMedian(1e-6, abs(diag(H_k)), 1e6)
33*198282dbSAlp Dener       B_k = VecReciprocal(B_k)
34*198282dbSAlp Dener     end
35*198282dbSAlp Dener     w = x_k - VecMedian(x_k - 0.001*B_k*g_k)
36*198282dbSAlp Dener     eps = min(eps, norm2(w))
37*198282dbSAlp Dener     determine the active and inactive index sets such that
38*198282dbSAlp Dener       L = {i : (x_k)_i <= l_i + eps && (g_k)_i > 0}
39*198282dbSAlp Dener       U = {i : (x_k)_i >= u_i - eps && (g_k)_i < 0}
40*198282dbSAlp Dener       F = {i : l_i = (x_k)_i = u_i}
41*198282dbSAlp Dener       A = {L + U + F}
42*198282dbSAlp Dener       I = {i : i not in A}
43*198282dbSAlp Dener 
44*198282dbSAlp Dener     generate the reduced system Hr_k dr_k = -gr_k for variables in I
45*198282dbSAlp Dener     if pc_type == BNK_PC_BFGS && scale_type == BNK_SCALE_PHESS
46*198282dbSAlp Dener       D = VecMedian(1e-6, abs(diag(Hr_k)), 1e6)
47*198282dbSAlp Dener       scale BFGS with VecReciprocal(D)
48*198282dbSAlp Dener     end
49*198282dbSAlp Dener     solve Hr_k dr_k = -gr_k
50*198282dbSAlp Dener     set d_k to (l - x) for variables in L, (u - x) for variables in U, and 0 for variables in F
51*198282dbSAlp Dener 
52*198282dbSAlp Dener     x_{k+1} = VecMedian(x_k + d_k)
53*198282dbSAlp Dener     s = x_{k+1} - x_k
54*198282dbSAlp Dener     prered = dot(s, 0.5*gr_k - Hr_k*s)
55*198282dbSAlp Dener     f_{k+1} = TaoComputeObjective(x_{k+1})
56*198282dbSAlp Dener     actred = f_k - f_{k+1}
57*198282dbSAlp Dener 
58*198282dbSAlp Dener     oldTrust = trust
59*198282dbSAlp Dener     step_accepted, trust = TaoBNKUpdateTrustRadius(default: BNK_UPDATE_REDUCTION)
60*198282dbSAlp Dener     if step_accepted
61*198282dbSAlp Dener       g_{k+1} = TaoComputeGradient(x_{k+1})
62*198282dbSAlp Dener       pg_{k+1} = VecBoundGradientProjection(g_{k+1})
63*198282dbSAlp Dener       count the accepted Newton step
64*198282dbSAlp Dener     else
65*198282dbSAlp Dener       if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
66*198282dbSAlp Dener         dr_k = -BFGS*gr_k for variables in I
67*198282dbSAlp Dener         if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
68*198282dbSAlp Dener           reset the BFGS preconditioner
69*198282dbSAlp Dener           calculate scale delta and apply it to BFGS
70*198282dbSAlp Dener           dr_k = -BFGS*gr_k for variables in I
71*198282dbSAlp Dener           if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf
72*198282dbSAlp Dener             dr_k = -gr_k for variables in I
73*198282dbSAlp Dener           end
74*198282dbSAlp Dener         end
75*198282dbSAlp Dener       end
76*198282dbSAlp Dener 
77*198282dbSAlp Dener       x_{k+1}, f_{k+1}, g_{k+1}, ls_failed = TaoBNKPerformLineSearch()
78*198282dbSAlp Dener       if ls_failed
79*198282dbSAlp Dener         f_{k+1} = f_k
80*198282dbSAlp Dener         x_{k+1} = x_k
81*198282dbSAlp Dener         g_{k+1} = g_k
82*198282dbSAlp Dener         pg_{k+1} = pg_k
83*198282dbSAlp Dener         terminate
84*198282dbSAlp Dener       else
85*198282dbSAlp Dener         pg_{k+1} = VecBoundGradientProjection(g_{k+1})
86*198282dbSAlp Dener         trust = oldTrust
87*198282dbSAlp Dener         trust = TaoBNKUpdateTrustRadius(BNK_UPDATE_STEP)
88*198282dbSAlp Dener         count the accepted step type (Newton, BFGS, scaled grad or grad)
89*198282dbSAlp Dener       end
90*198282dbSAlp Dener     end
91*198282dbSAlp Dener 
92*198282dbSAlp Dener     check convergence at pg_{k+1}
93*198282dbSAlp 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 
103e465cd6fSAlp Dener   PetscReal                    oldTrust, prered, actred, stepNorm, steplen;
10462675beeSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE, 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;
11062675beeSAlp Dener   ierr = TaoBNKInitialize(tao, bnk->init_type);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++;
116c14b763aSAlp Dener     tao->ksp_its=0;
11762675beeSAlp Dener 
11862675beeSAlp Dener     /* Compute the hessian and update the BFGS preconditioner at the new iterate*/
11962675beeSAlp Dener     ierr = TaoBNKComputeHessian(tao);CHKERRQ(ierr);
120c14b763aSAlp Dener 
1218d5ead36SAlp Dener     /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */
12262675beeSAlp Dener     ierr = TaoBNKComputeStep(tao, shift, &ksp_reason);CHKERRQ(ierr);
123c14b763aSAlp Dener 
124c14b763aSAlp Dener     /* Store current solution before it changes */
125c14b763aSAlp Dener     oldTrust = tao->trust;
126c14b763aSAlp Dener     bnk->fold = bnk->f;
127c14b763aSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
128c14b763aSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
129c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
130c14b763aSAlp Dener 
131c14b763aSAlp Dener     /* Temporarily accept the step and project it into the bounds */
132c14b763aSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
133c14b763aSAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
134c14b763aSAlp Dener 
135c14b763aSAlp Dener     /* Check if the projection changed the step direction */
136c14b763aSAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
1378d5ead36SAlp Dener     ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
138c14b763aSAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
139c14b763aSAlp Dener     if (stepNorm != bnk->dnorm) {
1408d5ead36SAlp Dener       /* Projection changed the step, so we have to recompute predicted reduction.
1418d5ead36SAlp Dener          However, we deliberately do not change the step norm and the trust radius
1428d5ead36SAlp Dener          in order for the safeguard to more closely mimic a piece-wise linesearch
1438d5ead36SAlp Dener          along the bounds. */
14428017e9fSAlp Dener       ierr = MatMult(bnk->H_inactive, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr);
145*198282dbSAlp Dener       ierr = VecAYPX(bnk->Xwork, -0.5, bnk->G_inactive);CHKERRQ(ierr);
146c14b763aSAlp Dener       ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered);
147c14b763aSAlp Dener     } else {
148c14b763aSAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
149c14b763aSAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
150c14b763aSAlp Dener     }
151c14b763aSAlp Dener     prered = -prered;
152c14b763aSAlp Dener 
153c14b763aSAlp Dener     /* Compute the actual reduction and update the trust radius */
154c14b763aSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
155c14b763aSAlp Dener     actred = bnk->fold - bnk->f;
15628017e9fSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr);
157c14b763aSAlp Dener 
158c14b763aSAlp Dener     if (stepAccepted) {
159c14b763aSAlp Dener       /* Step is good, evaluate the gradient and the hessian */
1608d5ead36SAlp Dener       steplen = 1.0;
161e465cd6fSAlp Dener       ++bnk->newt;
162c14b763aSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
163c14b763aSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
164c14b763aSAlp Dener     } else {
165c14b763aSAlp Dener       /* Trust-region rejected the step. Revert the solution. */
166c14b763aSAlp Dener       bnk->f = bnk->fold;
167c14b763aSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
168c14b763aSAlp Dener 
169c14b763aSAlp Dener       /* Trigger the line search */
170e465cd6fSAlp Dener       ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
171c14b763aSAlp Dener       ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
172c14b763aSAlp Dener       if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
173c14b763aSAlp Dener         /* Line search failed, revert solution and terminate */
174c14b763aSAlp Dener         bnk->f = bnk->fold;
175c14b763aSAlp Dener         ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
176c14b763aSAlp Dener         ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
177c14b763aSAlp Dener         ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
178c14b763aSAlp Dener         tao->trust = 0.0;
179c14b763aSAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
180c14b763aSAlp Dener       } else {
181*198282dbSAlp Dener         /* compute the projected gradient */
182*198282dbSAlp Dener         ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
183c14b763aSAlp Dener         /* Line search succeeded so we should update the trust radius based on the LS step length */
184770b7498SAlp Dener         tao->trust = oldTrust;
18528017e9fSAlp Dener         ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, BNK_UPDATE_STEP, stepType, &stepAccepted);CHKERRQ(ierr);
18662675beeSAlp Dener         /* count the accepted step type */
18762675beeSAlp Dener         ierr = TaoBNKAddStepCounts(tao, stepType);CHKERRQ(ierr);
188c14b763aSAlp Dener       }
189c14b763aSAlp Dener     }
190c14b763aSAlp Dener 
191c14b763aSAlp Dener     /*  Check for termination */
192c14b763aSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
193c14b763aSAlp Dener     if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
194c14b763aSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
1958d5ead36SAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
196c14b763aSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
197c14b763aSAlp Dener   }
198c14b763aSAlp Dener   PetscFunctionReturn(0);
199c14b763aSAlp Dener }
200c14b763aSAlp Dener 
201df278d8fSAlp Dener /*------------------------------------------------------------*/
202df278d8fSAlp Dener 
203c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao)
204c14b763aSAlp Dener {
205c14b763aSAlp Dener   TAO_BNK        *bnk;
206c14b763aSAlp Dener   PetscErrorCode ierr;
207c14b763aSAlp Dener 
208c14b763aSAlp Dener   PetscFunctionBegin;
209c14b763aSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
210c14b763aSAlp Dener   tao->ops->solve=TaoSolve_BNTL;
211c14b763aSAlp Dener 
212c14b763aSAlp Dener   bnk = (TAO_BNK *)tao->data;
213c14b763aSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
214c14b763aSAlp Dener   bnk->sval = 0.0; /* disable Hessian shifting */
215c14b763aSAlp Dener   PetscFunctionReturn(0);
216c14b763aSAlp Dener }