xref: /petsc/src/tao/bound/impls/bnk/bntl.c (revision c14b763a6cf7f880663e735a012a7a3bdedc7594)
1*c14b763aSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2*c14b763aSAlp Dener #include <petscksp.h>
3*c14b763aSAlp Dener 
4*c14b763aSAlp Dener /*
5*c14b763aSAlp Dener  Implements Newton's Method with a trust region approach for solving
6*c14b763aSAlp Dener  bound constrained minimization problems. This version includes a
7*c14b763aSAlp Dener  line search fall-back in the event of a trust region failure.
8*c14b763aSAlp Dener 
9*c14b763aSAlp Dener  The linear system solve should be done with a conjugate gradient
10*c14b763aSAlp Dener  method, although any method can be used.
11*c14b763aSAlp Dener */
12*c14b763aSAlp Dener 
13*c14b763aSAlp Dener static PetscErrorCode TaoSolve_BNTL(Tao tao)
14*c14b763aSAlp Dener {
15*c14b763aSAlp Dener   PetscErrorCode               ierr;
16*c14b763aSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
17*c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
18*c14b763aSAlp Dener 
19*c14b763aSAlp Dener   PetscReal                    oldTrust, prered, actred, stepNorm, gdx, delta, steplen;
20*c14b763aSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE;
21*c14b763aSAlp Dener   PetscInt                     stepType, bfgsUpdates, updateType;
22*c14b763aSAlp Dener 
23*c14b763aSAlp Dener   PetscFunctionBegin;
24*c14b763aSAlp Dener   /*   Project the current point onto the feasible set */
25*c14b763aSAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
26*c14b763aSAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
27*c14b763aSAlp Dener 
28*c14b763aSAlp Dener   /* Project the initial point onto the feasible region */
29*c14b763aSAlp Dener   ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr);
30*c14b763aSAlp Dener 
31*c14b763aSAlp Dener   /* Check convergence criteria */
32*c14b763aSAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr);
33*c14b763aSAlp Dener   ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
34*c14b763aSAlp Dener   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
35*c14b763aSAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
36*c14b763aSAlp Dener 
37*c14b763aSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
38*c14b763aSAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
39*c14b763aSAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr);
40*c14b763aSAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
41*c14b763aSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
42*c14b763aSAlp Dener 
43*c14b763aSAlp Dener   /* Initialize the preconditioner and trust radius */
44*c14b763aSAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
45*c14b763aSAlp Dener 
46*c14b763aSAlp Dener   /* Have not converged; continue with Newton method */
47*c14b763aSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
48*c14b763aSAlp Dener 
49*c14b763aSAlp Dener     if (stepAccepted) {
50*c14b763aSAlp Dener       tao->niter++;
51*c14b763aSAlp Dener       tao->ksp_its=0;
52*c14b763aSAlp Dener       /* Compute the Hessian */
53*c14b763aSAlp Dener       ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
54*c14b763aSAlp Dener       /* Update the BFGS preconditioner */
55*c14b763aSAlp Dener       if (BNK_PC_BFGS == bnk->pc_type) {
56*c14b763aSAlp Dener         if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
57*c14b763aSAlp Dener           /* Obtain diagonal for the bfgs preconditioner  */
58*c14b763aSAlp Dener           ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
59*c14b763aSAlp Dener           ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
60*c14b763aSAlp Dener           ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
61*c14b763aSAlp Dener           ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
62*c14b763aSAlp Dener         }
63*c14b763aSAlp Dener         /* Update the limited memory preconditioner and get existing # of updates */
64*c14b763aSAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
65*c14b763aSAlp Dener       }
66*c14b763aSAlp Dener     }
67*c14b763aSAlp Dener 
68*c14b763aSAlp Dener     /* Use the common BNK kernel to compute the raw Newton step */
69*c14b763aSAlp Dener     ierr = TaoBNKComputeStep(tao, PETSC_FALSE, &stepType);CHKERRQ(ierr);
70*c14b763aSAlp Dener 
71*c14b763aSAlp Dener     /* Store current solution before it changes */
72*c14b763aSAlp Dener     oldTrust = tao->trust;
73*c14b763aSAlp Dener     bnk->fold = bnk->f;
74*c14b763aSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
75*c14b763aSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
76*c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
77*c14b763aSAlp Dener 
78*c14b763aSAlp Dener     /* Temporarily accept the step and project it into the bounds */
79*c14b763aSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
80*c14b763aSAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
81*c14b763aSAlp Dener 
82*c14b763aSAlp Dener     /* Check if the projection changed the step direction */
83*c14b763aSAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
84*c14b763aSAlp Dener     ierr = VecAXPBY(tao->stepdirection, -1.0, 1.0, bnk->Xold);CHKERRQ(ierr);
85*c14b763aSAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
86*c14b763aSAlp Dener     if (stepNorm != bnk->dnorm) {
87*c14b763aSAlp Dener       /* Projection changed the step, so we have to adjust trust radius and recompute predicted reduction */
88*c14b763aSAlp Dener       bnk->dnorm = stepNorm;
89*c14b763aSAlp Dener       tao->trust = bnk->dnorm;
90*c14b763aSAlp Dener       ierr = MatMult(tao->hessian, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr);
91*c14b763aSAlp Dener       ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr);
92*c14b763aSAlp Dener       ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered);
93*c14b763aSAlp Dener     } else {
94*c14b763aSAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
95*c14b763aSAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
96*c14b763aSAlp Dener     }
97*c14b763aSAlp Dener     prered = -prered;
98*c14b763aSAlp Dener 
99*c14b763aSAlp Dener     /* Compute the actual reduction and update the trust radius */
100*c14b763aSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
101*c14b763aSAlp Dener     actred = bnk->fold - bnk->f;
102*c14b763aSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr);
103*c14b763aSAlp Dener 
104*c14b763aSAlp Dener     if (stepAccepted) {
105*c14b763aSAlp Dener       /* Step is good, evaluate the gradient and the hessian */
106*c14b763aSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
107*c14b763aSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
108*c14b763aSAlp Dener     } else {
109*c14b763aSAlp Dener       /* Trust-region rejected the step. Revert the solution. */
110*c14b763aSAlp Dener       bnk->f = bnk->fold;
111*c14b763aSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
112*c14b763aSAlp Dener 
113*c14b763aSAlp Dener       /* Now check to make sure the Newton step is a descent direction... */
114*c14b763aSAlp Dener       ierr = VecDot(tao->stepdirection, tao->gradient, &gdx);CHKERRQ(ierr);
115*c14b763aSAlp Dener       if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) {
116*c14b763aSAlp Dener         /* Newton step is not descent or direction produced Inf or NaN */
117*c14b763aSAlp Dener         --bnk->newt;
118*c14b763aSAlp Dener         if (BNK_PC_BFGS != bnk->pc_type) {
119*c14b763aSAlp Dener           /* We don't have the BFGS matrix around and updated
120*c14b763aSAlp Dener              Must use gradient direction in this case */
121*c14b763aSAlp Dener           ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr);
122*c14b763aSAlp Dener           ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
123*c14b763aSAlp Dener           ++bnk->grad;
124*c14b763aSAlp Dener           stepType = BNK_GRADIENT;
125*c14b763aSAlp Dener         } else {
126*c14b763aSAlp Dener           /* We have the BFGS matrix, so attempt to use the BFGS direction */
127*c14b763aSAlp Dener           ierr = MatLMVMSolve(bnk->M, tao->gradient, tao->stepdirection);CHKERRQ(ierr);
128*c14b763aSAlp Dener           ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
129*c14b763aSAlp Dener 
130*c14b763aSAlp Dener           /* Check for success (descent direction) */
131*c14b763aSAlp Dener           ierr = VecDot(tao->stepdirection, tao->gradient, &gdx);CHKERRQ(ierr);
132*c14b763aSAlp Dener           if ((gdx >= 0) || PetscIsInfOrNanReal(gdx)) {
133*c14b763aSAlp Dener             /* BFGS direction is not descent or direction produced not a number
134*c14b763aSAlp Dener                We can assert bfgsUpdates > 1 in this case because
135*c14b763aSAlp Dener                the first solve produces the scaled gradient direction,
136*c14b763aSAlp Dener                which is guaranteed to be descent */
137*c14b763aSAlp Dener 
138*c14b763aSAlp Dener             /* Use steepest descent direction (scaled) */
139*c14b763aSAlp Dener             if (bnk->f != 0.0) {
140*c14b763aSAlp Dener               delta = 2.0 * PetscAbsScalar(bnk->f) / (bnk->gnorm*bnk->gnorm);
141*c14b763aSAlp Dener             } else {
142*c14b763aSAlp Dener               delta = 2.0 / (bnk->gnorm*bnk->gnorm);
143*c14b763aSAlp Dener             }
144*c14b763aSAlp Dener             ierr = MatLMVMSetDelta(bnk->M, delta);CHKERRQ(ierr);
145*c14b763aSAlp Dener             ierr = MatLMVMReset(bnk->M);CHKERRQ(ierr);
146*c14b763aSAlp Dener             ierr = MatLMVMUpdate(bnk->M, tao->solution, tao->gradient);CHKERRQ(ierr);
147*c14b763aSAlp Dener             ierr = MatLMVMSolve(bnk->M, tao->gradient, tao->stepdirection);CHKERRQ(ierr);
148*c14b763aSAlp Dener             ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr);
149*c14b763aSAlp Dener 
150*c14b763aSAlp Dener             ++bnk->sgrad;
151*c14b763aSAlp Dener             stepType = BNK_SCALED_GRADIENT;
152*c14b763aSAlp Dener           } else {
153*c14b763aSAlp Dener             ierr = MatLMVMGetUpdates(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
154*c14b763aSAlp Dener             if (1 == bfgsUpdates) {
155*c14b763aSAlp Dener               /* The first BFGS direction is always the scaled gradient */
156*c14b763aSAlp Dener               ++bnk->sgrad;
157*c14b763aSAlp Dener               stepType = BNK_SCALED_GRADIENT;
158*c14b763aSAlp Dener             } else {
159*c14b763aSAlp Dener               ++bnk->bfgs;
160*c14b763aSAlp Dener               stepType = BNK_BFGS;
161*c14b763aSAlp Dener             }
162*c14b763aSAlp Dener           }
163*c14b763aSAlp Dener         }
164*c14b763aSAlp Dener       }
165*c14b763aSAlp Dener 
166*c14b763aSAlp Dener       /* Trigger the line search */
167*c14b763aSAlp Dener       ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
168*c14b763aSAlp Dener       if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
169*c14b763aSAlp Dener         /* Line search failed, revert solution and terminate */
170*c14b763aSAlp Dener         bnk->f = bnk->fold;
171*c14b763aSAlp Dener         ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
172*c14b763aSAlp Dener         ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
173*c14b763aSAlp Dener         ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
174*c14b763aSAlp Dener         tao->trust = 0.0;
175*c14b763aSAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
176*c14b763aSAlp Dener       } else {
177*c14b763aSAlp Dener         /* Line search succeeded so we should update the trust radius based on the LS step length */
178*c14b763aSAlp Dener         updateType = bnk->update_type;
179*c14b763aSAlp Dener         bnk->update_type = BNK_UPDATE_STEP;
180*c14b763aSAlp Dener         ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr);
181*c14b763aSAlp Dener         bnk->update_type = updateType;
182*c14b763aSAlp Dener       }
183*c14b763aSAlp Dener     }
184*c14b763aSAlp Dener 
185*c14b763aSAlp Dener     /*  Check for termination */
186*c14b763aSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
187*c14b763aSAlp Dener     if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
188*c14b763aSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
189*c14b763aSAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr);
190*c14b763aSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
191*c14b763aSAlp Dener   }
192*c14b763aSAlp Dener   PetscFunctionReturn(0);
193*c14b763aSAlp Dener }
194*c14b763aSAlp Dener 
195*c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao)
196*c14b763aSAlp Dener {
197*c14b763aSAlp Dener   TAO_BNK        *bnk;
198*c14b763aSAlp Dener   PetscErrorCode ierr;
199*c14b763aSAlp Dener 
200*c14b763aSAlp Dener   PetscFunctionBegin;
201*c14b763aSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
202*c14b763aSAlp Dener   tao->ops->solve=TaoSolve_BNTL;
203*c14b763aSAlp Dener 
204*c14b763aSAlp Dener   bnk = (TAO_BNK *)tao->data;
205*c14b763aSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
206*c14b763aSAlp Dener   bnk->sval = 0.0; /* disable Hessian shifting */
207*c14b763aSAlp Dener   PetscFunctionReturn(0);
208*c14b763aSAlp Dener }