xref: /petsc/src/tao/bound/impls/bnk/bntr.c (revision 28017e9fc366e9d0379085f0860b391dd2763ed7)
1fed79b8eSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2fed79b8eSAlp Dener #include <petscksp.h>
3fed79b8eSAlp Dener 
4fed79b8eSAlp Dener /*
5fed79b8eSAlp Dener  Implements Newton's Method with a trust region approach for solving
6fed79b8eSAlp Dener  bound constrained minimization problems.
7fed79b8eSAlp Dener 
8df278d8fSAlp Dener  The linear system solve has to be done with a conjugate gradient method.
9fed79b8eSAlp Dener */
10fed79b8eSAlp Dener 
11fed79b8eSAlp Dener static PetscErrorCode TaoSolve_BNTR(Tao tao)
12fed79b8eSAlp Dener {
13fed79b8eSAlp Dener   PetscErrorCode               ierr;
14fed79b8eSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
15e465cd6fSAlp Dener   KSPConvergedReason           ksp_reason;
16fed79b8eSAlp Dener 
178d5ead36SAlp Dener   PetscReal                    oldTrust, prered, actred, stepNorm, steplen;
18fed79b8eSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE;
19e465cd6fSAlp Dener   PetscInt                     stepType = BNK_NEWTON;
20fed79b8eSAlp Dener 
21fed79b8eSAlp Dener   PetscFunctionBegin;
22*28017e9fSAlp Dener   /* Initialize the preconditioner, KSP solver and trust radius/line search */
23fed79b8eSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
24fed79b8eSAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
25*28017e9fSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
26fed79b8eSAlp Dener 
27fed79b8eSAlp Dener   /* Have not converged; continue with Newton method */
28fed79b8eSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
2966ed3702SAlp Dener 
30fed79b8eSAlp Dener     if (stepAccepted) {
31fed79b8eSAlp Dener       tao->niter++;
32fed79b8eSAlp Dener       tao->ksp_its=0;
33fed79b8eSAlp Dener       /* Compute the Hessian */
34fed79b8eSAlp Dener       ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
35fed79b8eSAlp Dener       /* Update the BFGS preconditioner */
36fed79b8eSAlp Dener       if (BNK_PC_BFGS == bnk->pc_type) {
37fed79b8eSAlp Dener         if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
38fed79b8eSAlp Dener           /* Obtain diagonal for the bfgs preconditioner  */
39fed79b8eSAlp Dener           ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
40fed79b8eSAlp Dener           ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
41fed79b8eSAlp Dener           ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
42fed79b8eSAlp Dener           ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
43fed79b8eSAlp Dener         }
44fed79b8eSAlp Dener         /* Update the limited memory preconditioner and get existing # of updates */
45fed79b8eSAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
46fed79b8eSAlp Dener       }
47fed79b8eSAlp Dener     }
48fed79b8eSAlp Dener 
498d5ead36SAlp Dener     /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */
50e465cd6fSAlp Dener     ierr = TaoBNKComputeStep(tao, &ksp_reason);CHKERRQ(ierr);
51fed79b8eSAlp Dener 
52fed79b8eSAlp Dener     /* Store current solution before it changes */
53fed79b8eSAlp Dener     oldTrust = tao->trust;
54fed79b8eSAlp Dener     bnk->fold = bnk->f;
55fed79b8eSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
56fed79b8eSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
57fed79b8eSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
58fed79b8eSAlp Dener 
59b1c2d0e3SAlp Dener     /* Temporarily accept the step and project it into the bounds */
60fed79b8eSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
61b1c2d0e3SAlp Dener     ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr);
62b1c2d0e3SAlp Dener 
63b1c2d0e3SAlp Dener     /* Check if the projection changed the step direction */
64b1c2d0e3SAlp Dener     ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr);
658d5ead36SAlp Dener     ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr);
66b1c2d0e3SAlp Dener     ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr);
67b1c2d0e3SAlp Dener     if (stepNorm != bnk->dnorm) {
688d5ead36SAlp Dener       /* Projection changed the step, so we have to recompute predicted reduction.
698d5ead36SAlp Dener          However, we deliberately do not change the step norm and the trust radius
708d5ead36SAlp Dener          in order for the safeguard to more closely mimic a piece-wise linesearch
718d5ead36SAlp Dener          along the bounds. */
72*28017e9fSAlp Dener       ierr = MatMult(bnk->H_inactive, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr);
73b1c2d0e3SAlp Dener       ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr);
74b1c2d0e3SAlp Dener       ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered);
75b1c2d0e3SAlp Dener     } else {
76b1c2d0e3SAlp Dener       /* Step did not change, so we can just recover the pre-computed prediction */
77b1c2d0e3SAlp Dener       ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
78b1c2d0e3SAlp Dener     }
79b1c2d0e3SAlp Dener     prered = -prered;
80b1c2d0e3SAlp Dener 
81b1c2d0e3SAlp Dener     /* Compute the actual reduction and update the trust radius */
82fed79b8eSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
83b1c2d0e3SAlp Dener     actred = bnk->fold - bnk->f;
84*28017e9fSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr);
85fed79b8eSAlp Dener 
86fed79b8eSAlp Dener     if (stepAccepted) {
8766ed3702SAlp Dener       /* Step is good, evaluate the gradient and the hessian */
888d5ead36SAlp Dener       steplen = 1.0;
89e465cd6fSAlp Dener       ++bnk->newt;
90fed79b8eSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
91fed79b8eSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
92fed79b8eSAlp Dener     } else {
93fed79b8eSAlp Dener       /* Step is bad, revert old solution and re-solve with new radius*/
948d5ead36SAlp Dener       steplen = 0.0;
95fed79b8eSAlp Dener       bnk->f = bnk->fold;
96fed79b8eSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
97fed79b8eSAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
98fed79b8eSAlp Dener       ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
9973e4db90SAlp Dener       if (oldTrust == tao->trust) {
10073e4db90SAlp Dener         /* Can't change the radius anymore so just terminate */
101fed79b8eSAlp Dener         tao->reason = TAO_DIVERGED_TR_REDUCTION;
102fed79b8eSAlp Dener       }
103fed79b8eSAlp Dener     }
104fed79b8eSAlp Dener 
105fed79b8eSAlp Dener     /*  Check for termination */
106fed79b8eSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr);
10773e4db90SAlp Dener     if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
108fed79b8eSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
1098d5ead36SAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
110fed79b8eSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
111fed79b8eSAlp Dener   }
112fed79b8eSAlp Dener   PetscFunctionReturn(0);
113fed79b8eSAlp Dener }
114fed79b8eSAlp Dener 
115df278d8fSAlp Dener /*------------------------------------------------------------*/
116df278d8fSAlp Dener 
117fed79b8eSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTR(Tao tao)
118fed79b8eSAlp Dener {
119fed79b8eSAlp Dener   TAO_BNK        *bnk;
120fed79b8eSAlp Dener   PetscErrorCode ierr;
121fed79b8eSAlp Dener 
122fed79b8eSAlp Dener   PetscFunctionBegin;
123fed79b8eSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
124fed79b8eSAlp Dener   tao->ops->solve=TaoSolve_BNTR;
125fed79b8eSAlp Dener 
126fed79b8eSAlp Dener   bnk = (TAO_BNK *)tao->data;
12766ed3702SAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */
12866ed3702SAlp Dener   bnk->sval = 0.0; /* disable Hessian shifting */
129fed79b8eSAlp Dener   PetscFunctionReturn(0);
130fed79b8eSAlp Dener }