xref: /petsc/src/tao/bound/impls/bnk/bntl.c (revision e465cd6f30f93207df959d4c9fc4f47b6c5c3063)
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
6c14b763aSAlp Dener  bound constrained minimization problems. This version includes a
7c14b763aSAlp Dener  line search fall-back in the event of a trust region failure.
8c14b763aSAlp Dener 
9df278d8fSAlp Dener  The linear system solve has to be done with a conjugate gradient method.
10c14b763aSAlp Dener */
11c14b763aSAlp Dener 
12c14b763aSAlp Dener static PetscErrorCode TaoSolve_BNTL(Tao tao)
13c14b763aSAlp Dener {
14c14b763aSAlp Dener   PetscErrorCode               ierr;
15c14b763aSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
16*e465cd6fSAlp Dener   KSPConvergedReason           ksp_reason;
17c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
18c14b763aSAlp Dener 
19*e465cd6fSAlp Dener   PetscReal                    oldTrust, prered, actred, stepNorm, steplen;
20c14b763aSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE;
21*e465cd6fSAlp Dener   PetscInt                     stepType, updateType;
22c14b763aSAlp Dener 
23c14b763aSAlp Dener   PetscFunctionBegin;
24c14b763aSAlp Dener   /*   Project the current point onto the feasible set */
25c14b763aSAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
26c14b763aSAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
27c14b763aSAlp Dener 
28c14b763aSAlp Dener   /* Project the initial point onto the feasible region */
29c14b763aSAlp Dener   ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr);
30c14b763aSAlp Dener 
31c14b763aSAlp Dener   /* Check convergence criteria */
32c14b763aSAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr);
33c14b763aSAlp Dener   ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
34c14b763aSAlp Dener   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
35c14b763aSAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
36c14b763aSAlp Dener 
37c14b763aSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
38c14b763aSAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
39c14b763aSAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr);
40c14b763aSAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
41c14b763aSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
42c14b763aSAlp Dener 
43c14b763aSAlp Dener   /* Initialize the preconditioner and trust radius */
44c14b763aSAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
45c14b763aSAlp Dener 
46c14b763aSAlp Dener   /* Have not converged; continue with Newton method */
47c14b763aSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
48c14b763aSAlp Dener     tao->niter++;
49c14b763aSAlp Dener     tao->ksp_its=0;
50c14b763aSAlp Dener     /* Compute the Hessian */
51c14b763aSAlp Dener     ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
52c14b763aSAlp Dener     /* Update the BFGS preconditioner */
53c14b763aSAlp Dener     if (BNK_PC_BFGS == bnk->pc_type) {
54c14b763aSAlp Dener       if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
55c14b763aSAlp Dener         /* Obtain diagonal for the bfgs preconditioner  */
56c14b763aSAlp Dener         ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
57c14b763aSAlp Dener         ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
58c14b763aSAlp Dener         ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
59c14b763aSAlp Dener         ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
60c14b763aSAlp Dener       }
61c14b763aSAlp Dener       /* Update the limited memory preconditioner and get existing # of updates */
62c14b763aSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
63c14b763aSAlp Dener     }
64c14b763aSAlp Dener 
658d5ead36SAlp Dener     /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */
66*e465cd6fSAlp Dener     ierr = TaoBNKComputeStep(tao, &ksp_reason);CHKERRQ(ierr);
67c14b763aSAlp Dener 
68c14b763aSAlp Dener     /* Store current solution before it changes */
69c14b763aSAlp Dener     oldTrust = tao->trust;
70c14b763aSAlp Dener     bnk->fold = bnk->f;
71c14b763aSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
72c14b763aSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
73c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
74c14b763aSAlp Dener 
75c14b763aSAlp Dener     /* Temporarily accept the step and project it into the bounds */
76c14b763aSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
77c14b763aSAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
78c14b763aSAlp Dener 
79c14b763aSAlp Dener     /* Check if the projection changed the step direction */
80c14b763aSAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
818d5ead36SAlp Dener     ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
82c14b763aSAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
83c14b763aSAlp Dener     if (stepNorm != bnk->dnorm) {
848d5ead36SAlp Dener       /* Projection changed the step, so we have to recompute predicted reduction.
858d5ead36SAlp Dener          However, we deliberately do not change the step norm and the trust radius
868d5ead36SAlp Dener          in order for the safeguard to more closely mimic a piece-wise linesearch
878d5ead36SAlp Dener          along the bounds. */
88c14b763aSAlp Dener       ierr = MatMult(tao->hessian, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr);
89c14b763aSAlp Dener       ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr);
90c14b763aSAlp Dener       ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered);
91c14b763aSAlp Dener     } else {
92c14b763aSAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
93c14b763aSAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
94c14b763aSAlp Dener     }
95c14b763aSAlp Dener     prered = -prered;
96c14b763aSAlp Dener 
97c14b763aSAlp Dener     /* Compute the actual reduction and update the trust radius */
98c14b763aSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
99c14b763aSAlp Dener     actred = bnk->fold - bnk->f;
100c14b763aSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr);
101c14b763aSAlp Dener 
102c14b763aSAlp Dener     if (stepAccepted) {
103c14b763aSAlp Dener       /* Step is good, evaluate the gradient and the hessian */
1048d5ead36SAlp Dener       steplen = 1.0;
105*e465cd6fSAlp Dener       ++bnk->newt;
106c14b763aSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
107c14b763aSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
108c14b763aSAlp Dener     } else {
109c14b763aSAlp Dener       /* Trust-region rejected the step. Revert the solution. */
110c14b763aSAlp Dener       bnk->f = bnk->fold;
111c14b763aSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
112c14b763aSAlp Dener 
113c14b763aSAlp Dener       /* Trigger the line search */
114*e465cd6fSAlp Dener       ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
115c14b763aSAlp Dener       ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
116c14b763aSAlp Dener       if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
117c14b763aSAlp Dener         /* Line search failed, revert solution and terminate */
118c14b763aSAlp Dener         bnk->f = bnk->fold;
119c14b763aSAlp Dener         ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
120c14b763aSAlp Dener         ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
121c14b763aSAlp Dener         ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
122c14b763aSAlp Dener         tao->trust = 0.0;
123c14b763aSAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
124c14b763aSAlp Dener       } else {
125c14b763aSAlp Dener         /* Line search succeeded so we should update the trust radius based on the LS step length */
126c14b763aSAlp Dener         updateType = bnk->update_type;
127c14b763aSAlp Dener         bnk->update_type = BNK_UPDATE_STEP;
128770b7498SAlp Dener         tao->trust = oldTrust;
129c14b763aSAlp Dener         ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr);
130c14b763aSAlp Dener         bnk->update_type = updateType;
131*e465cd6fSAlp Dener         /* count the accepted step types */
132*e465cd6fSAlp Dener         switch (stepType) {
133*e465cd6fSAlp Dener         case BNK_NEWTON:
134*e465cd6fSAlp Dener           ++bnk->newt;
135*e465cd6fSAlp Dener           break;
136*e465cd6fSAlp Dener         case BNK_BFGS:
137*e465cd6fSAlp Dener           ++bnk->bfgs;
138*e465cd6fSAlp Dener           break;
139*e465cd6fSAlp Dener         case BNK_SCALED_GRADIENT:
140*e465cd6fSAlp Dener           ++bnk->sgrad;
141*e465cd6fSAlp Dener           break;
142*e465cd6fSAlp Dener         case BNK_GRADIENT:
143*e465cd6fSAlp Dener           ++bnk->grad;
144*e465cd6fSAlp Dener           break;
145*e465cd6fSAlp Dener         default:
146*e465cd6fSAlp Dener           break;
147*e465cd6fSAlp Dener         }
148c14b763aSAlp Dener       }
149c14b763aSAlp Dener     }
150c14b763aSAlp Dener 
151c14b763aSAlp Dener     /*  Check for termination */
152c14b763aSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
153c14b763aSAlp Dener     if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
154c14b763aSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
1558d5ead36SAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
156c14b763aSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
157c14b763aSAlp Dener   }
158c14b763aSAlp Dener   PetscFunctionReturn(0);
159c14b763aSAlp Dener }
160c14b763aSAlp Dener 
161df278d8fSAlp Dener /*------------------------------------------------------------*/
162df278d8fSAlp Dener 
163c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao)
164c14b763aSAlp Dener {
165c14b763aSAlp Dener   TAO_BNK        *bnk;
166c14b763aSAlp Dener   PetscErrorCode ierr;
167c14b763aSAlp Dener 
168c14b763aSAlp Dener   PetscFunctionBegin;
169c14b763aSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
170c14b763aSAlp Dener   tao->ops->solve=TaoSolve_BNTL;
171c14b763aSAlp Dener 
172c14b763aSAlp Dener   bnk = (TAO_BNK *)tao->data;
173c14b763aSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
174c14b763aSAlp Dener   bnk->sval = 0.0; /* disable Hessian shifting */
175c14b763aSAlp Dener   PetscFunctionReturn(0);
176c14b763aSAlp Dener }