xref: /petsc/src/tao/bound/impls/bnk/bntl.c (revision 28017e9fc366e9d0379085f0860b391dd2763ed7)
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;
16e465cd6fSAlp Dener   KSPConvergedReason           ksp_reason;
17c14b763aSAlp Dener   TaoLineSearchConvergedReason ls_reason;
18c14b763aSAlp Dener 
19e465cd6fSAlp Dener   PetscReal                    oldTrust, prered, actred, stepNorm, steplen;
20c14b763aSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE;
21*28017e9fSAlp Dener   PetscInt                     stepType;
22c14b763aSAlp Dener 
23c14b763aSAlp Dener   PetscFunctionBegin;
24*28017e9fSAlp Dener   /* Initialize the preconditioner, KSP solver and trust radius/line search */
25c14b763aSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
26c14b763aSAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
27*28017e9fSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
28c14b763aSAlp Dener 
29c14b763aSAlp Dener   /* Have not converged; continue with Newton method */
30c14b763aSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
31c14b763aSAlp Dener     tao->niter++;
32c14b763aSAlp Dener     tao->ksp_its=0;
33c14b763aSAlp Dener     /* Compute the Hessian */
34c14b763aSAlp Dener     ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
35c14b763aSAlp Dener     /* Update the BFGS preconditioner */
36c14b763aSAlp Dener     if (BNK_PC_BFGS == bnk->pc_type) {
37c14b763aSAlp Dener       if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
38c14b763aSAlp Dener         /* Obtain diagonal for the bfgs preconditioner  */
39c14b763aSAlp Dener         ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
40c14b763aSAlp Dener         ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
41c14b763aSAlp Dener         ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
42c14b763aSAlp Dener         ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
43c14b763aSAlp Dener       }
44c14b763aSAlp Dener       /* Update the limited memory preconditioner and get existing # of updates */
45c14b763aSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
46c14b763aSAlp Dener     }
47c14b763aSAlp Dener 
488d5ead36SAlp Dener     /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */
49e465cd6fSAlp Dener     ierr = TaoBNKComputeStep(tao, &ksp_reason);CHKERRQ(ierr);
50c14b763aSAlp Dener 
51c14b763aSAlp Dener     /* Store current solution before it changes */
52c14b763aSAlp Dener     oldTrust = tao->trust;
53c14b763aSAlp Dener     bnk->fold = bnk->f;
54c14b763aSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
55c14b763aSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
56c14b763aSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
57c14b763aSAlp Dener 
58c14b763aSAlp Dener     /* Temporarily accept the step and project it into the bounds */
59c14b763aSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
60c14b763aSAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
61c14b763aSAlp Dener 
62c14b763aSAlp Dener     /* Check if the projection changed the step direction */
63c14b763aSAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
648d5ead36SAlp Dener     ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
65c14b763aSAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
66c14b763aSAlp Dener     if (stepNorm != bnk->dnorm) {
678d5ead36SAlp Dener       /* Projection changed the step, so we have to recompute predicted reduction.
688d5ead36SAlp Dener          However, we deliberately do not change the step norm and the trust radius
698d5ead36SAlp Dener          in order for the safeguard to more closely mimic a piece-wise linesearch
708d5ead36SAlp Dener          along the bounds. */
71*28017e9fSAlp Dener       ierr = MatMult(bnk->H_inactive, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr);
72c14b763aSAlp Dener       ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr);
73c14b763aSAlp Dener       ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered);
74c14b763aSAlp Dener     } else {
75c14b763aSAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
76c14b763aSAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
77c14b763aSAlp Dener     }
78c14b763aSAlp Dener     prered = -prered;
79c14b763aSAlp Dener 
80c14b763aSAlp Dener     /* Compute the actual reduction and update the trust radius */
81c14b763aSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
82c14b763aSAlp Dener     actred = bnk->fold - bnk->f;
83*28017e9fSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr);
84c14b763aSAlp Dener 
85c14b763aSAlp Dener     if (stepAccepted) {
86c14b763aSAlp Dener       /* Step is good, evaluate the gradient and the hessian */
878d5ead36SAlp Dener       steplen = 1.0;
88e465cd6fSAlp Dener       ++bnk->newt;
89c14b763aSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
90c14b763aSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
91c14b763aSAlp Dener     } else {
92c14b763aSAlp Dener       /* Trust-region rejected the step. Revert the solution. */
93c14b763aSAlp Dener       bnk->f = bnk->fold;
94c14b763aSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
95c14b763aSAlp Dener 
96c14b763aSAlp Dener       /* Trigger the line search */
97e465cd6fSAlp Dener       ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
98c14b763aSAlp Dener       ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
99c14b763aSAlp Dener       if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
100c14b763aSAlp Dener         /* Line search failed, revert solution and terminate */
101c14b763aSAlp Dener         bnk->f = bnk->fold;
102c14b763aSAlp Dener         ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
103c14b763aSAlp Dener         ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
104c14b763aSAlp Dener         ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
105c14b763aSAlp Dener         tao->trust = 0.0;
106c14b763aSAlp Dener         tao->reason = TAO_DIVERGED_LS_FAILURE;
107c14b763aSAlp Dener       } else {
108c14b763aSAlp Dener         /* Line search succeeded so we should update the trust radius based on the LS step length */
109770b7498SAlp Dener         tao->trust = oldTrust;
110*28017e9fSAlp Dener         ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, BNK_UPDATE_STEP, stepType, &stepAccepted);CHKERRQ(ierr);
111e465cd6fSAlp Dener         /* count the accepted step types */
112e465cd6fSAlp Dener         switch (stepType) {
113e465cd6fSAlp Dener         case BNK_NEWTON:
114e465cd6fSAlp Dener           ++bnk->newt;
115e465cd6fSAlp Dener           break;
116e465cd6fSAlp Dener         case BNK_BFGS:
117e465cd6fSAlp Dener           ++bnk->bfgs;
118e465cd6fSAlp Dener           break;
119e465cd6fSAlp Dener         case BNK_SCALED_GRADIENT:
120e465cd6fSAlp Dener           ++bnk->sgrad;
121e465cd6fSAlp Dener           break;
122e465cd6fSAlp Dener         case BNK_GRADIENT:
123e465cd6fSAlp Dener           ++bnk->grad;
124e465cd6fSAlp Dener           break;
125e465cd6fSAlp Dener         default:
126e465cd6fSAlp Dener           break;
127e465cd6fSAlp Dener         }
128c14b763aSAlp Dener       }
129c14b763aSAlp Dener     }
130c14b763aSAlp Dener 
131c14b763aSAlp Dener     /*  Check for termination */
132c14b763aSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
133c14b763aSAlp Dener     if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
134c14b763aSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
1358d5ead36SAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
136c14b763aSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
137c14b763aSAlp Dener   }
138c14b763aSAlp Dener   PetscFunctionReturn(0);
139c14b763aSAlp Dener }
140c14b763aSAlp Dener 
141df278d8fSAlp Dener /*------------------------------------------------------------*/
142df278d8fSAlp Dener 
143c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao)
144c14b763aSAlp Dener {
145c14b763aSAlp Dener   TAO_BNK        *bnk;
146c14b763aSAlp Dener   PetscErrorCode ierr;
147c14b763aSAlp Dener 
148c14b763aSAlp Dener   PetscFunctionBegin;
149c14b763aSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
150c14b763aSAlp Dener   tao->ops->solve=TaoSolve_BNTL;
151c14b763aSAlp Dener 
152c14b763aSAlp Dener   bnk = (TAO_BNK *)tao->data;
153c14b763aSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
154c14b763aSAlp Dener   bnk->sval = 0.0; /* disable Hessian shifting */
155c14b763aSAlp Dener   PetscFunctionReturn(0);
156c14b763aSAlp Dener }