xref: /petsc/src/tao/bound/impls/bnk/bntr.c (revision fed79b8e9c1768c470b4d2001044b5840bd3f132)
1*fed79b8eSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2*fed79b8eSAlp Dener #include <petscksp.h>
3*fed79b8eSAlp Dener 
4*fed79b8eSAlp Dener /*
5*fed79b8eSAlp Dener  Implements Newton's Method with a trust region approach for solving
6*fed79b8eSAlp Dener  bound constrained minimization problems.
7*fed79b8eSAlp Dener 
8*fed79b8eSAlp Dener  The method can shift the Hessian matrix. The shifting procedure is
9*fed79b8eSAlp Dener  adapted from the PATH algorithm for solving complementarity
10*fed79b8eSAlp Dener  problems.
11*fed79b8eSAlp Dener 
12*fed79b8eSAlp Dener  The linear system solve should be done with a conjugate gradient
13*fed79b8eSAlp Dener  method, although any method can be used.
14*fed79b8eSAlp Dener */
15*fed79b8eSAlp Dener 
16*fed79b8eSAlp Dener static PetscErrorCode TaoSolve_BNTR(Tao tao)
17*fed79b8eSAlp Dener {
18*fed79b8eSAlp Dener   PetscErrorCode               ierr;
19*fed79b8eSAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
20*fed79b8eSAlp Dener 
21*fed79b8eSAlp Dener   PetscReal                    oldTrust;
22*fed79b8eSAlp Dener   PetscBool                    stepAccepted = PETSC_TRUE;
23*fed79b8eSAlp Dener   PetscInt                     stepType;
24*fed79b8eSAlp Dener 
25*fed79b8eSAlp Dener   PetscFunctionBegin;
26*fed79b8eSAlp Dener   /*   Project the current point onto the feasible set */
27*fed79b8eSAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
28*fed79b8eSAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
29*fed79b8eSAlp Dener 
30*fed79b8eSAlp Dener   /* Project the initial point onto the feasible region */
31*fed79b8eSAlp Dener   ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr);
32*fed79b8eSAlp Dener 
33*fed79b8eSAlp Dener   /* Check convergence criteria */
34*fed79b8eSAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr);
35*fed79b8eSAlp Dener   ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
36*fed79b8eSAlp Dener   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
37*fed79b8eSAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
38*fed79b8eSAlp Dener 
39*fed79b8eSAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
40*fed79b8eSAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
41*fed79b8eSAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr);
42*fed79b8eSAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
43*fed79b8eSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
44*fed79b8eSAlp Dener 
45*fed79b8eSAlp Dener   /* Initialize the preconditioner and trust radius */
46*fed79b8eSAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
47*fed79b8eSAlp Dener 
48*fed79b8eSAlp Dener   /* Have not converged; continue with Newton method */
49*fed79b8eSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
50*fed79b8eSAlp Dener     if (stepAccepted) {
51*fed79b8eSAlp Dener       tao->niter++;
52*fed79b8eSAlp Dener       tao->ksp_its=0;
53*fed79b8eSAlp Dener       /* Compute the Hessian */
54*fed79b8eSAlp Dener       ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
55*fed79b8eSAlp Dener       /* Update the BFGS preconditioner */
56*fed79b8eSAlp Dener       if (BNK_PC_BFGS == bnk->pc_type) {
57*fed79b8eSAlp Dener         if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
58*fed79b8eSAlp Dener           /* Obtain diagonal for the bfgs preconditioner  */
59*fed79b8eSAlp Dener           ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
60*fed79b8eSAlp Dener           ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
61*fed79b8eSAlp Dener           ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
62*fed79b8eSAlp Dener           ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
63*fed79b8eSAlp Dener         }
64*fed79b8eSAlp Dener         /* Update the limited memory preconditioner and get existing # of updates */
65*fed79b8eSAlp Dener         ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
66*fed79b8eSAlp Dener       }
67*fed79b8eSAlp Dener     }
68*fed79b8eSAlp Dener 
69*fed79b8eSAlp Dener     /* Use the common BNK kernel to compute the raw Newton step */
70*fed79b8eSAlp Dener     ierr = TaoBNKComputeStep(tao, PETSC_FALSE, &stepType);CHKERRQ(ierr);
71*fed79b8eSAlp Dener 
72*fed79b8eSAlp Dener     /* Store current solution before it changes */
73*fed79b8eSAlp Dener     oldTrust = tao->trust;
74*fed79b8eSAlp Dener     bnk->fold = bnk->f;
75*fed79b8eSAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
76*fed79b8eSAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
77*fed79b8eSAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
78*fed79b8eSAlp Dener 
79*fed79b8eSAlp Dener     /* Test the new step for acceptance */
80*fed79b8eSAlp Dener     ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr);
81*fed79b8eSAlp Dener     ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr);
82*fed79b8eSAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, bnk->fold, bnk->f, stepType, &stepAccepted);CHKERRQ(ierr);
83*fed79b8eSAlp Dener 
84*fed79b8eSAlp Dener     if (stepAccepted) {
85*fed79b8eSAlp Dener       /* Step is good, evaluate gradient and project it */
86*fed79b8eSAlp Dener       ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
87*fed79b8eSAlp Dener       ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
88*fed79b8eSAlp Dener     } else {
89*fed79b8eSAlp Dener       /* Step is bad, revert old solution and re-solve with new radius*/
90*fed79b8eSAlp Dener       bnk->f = bnk->fold;
91*fed79b8eSAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
92*fed79b8eSAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
93*fed79b8eSAlp Dener       ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
94*fed79b8eSAlp Dener       if (oldTrust == tao->trust) {
95*fed79b8eSAlp Dener         /* Can't shrink trust radius any further, so we have to terminate */
96*fed79b8eSAlp Dener         tao->reason = TAO_DIVERGED_TR_REDUCTION;
97*fed79b8eSAlp Dener       }
98*fed79b8eSAlp Dener     }
99*fed79b8eSAlp Dener 
100*fed79b8eSAlp Dener     /*  Check for termination */
101*fed79b8eSAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
102*fed79b8eSAlp Dener     if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
103*fed79b8eSAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
104*fed79b8eSAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr);
105*fed79b8eSAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
106*fed79b8eSAlp Dener   }
107*fed79b8eSAlp Dener   PetscFunctionReturn(0);
108*fed79b8eSAlp Dener }
109*fed79b8eSAlp Dener 
110*fed79b8eSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTR(Tao tao)
111*fed79b8eSAlp Dener {
112*fed79b8eSAlp Dener   TAO_BNK        *bnk;
113*fed79b8eSAlp Dener   PetscErrorCode ierr;
114*fed79b8eSAlp Dener 
115*fed79b8eSAlp Dener   PetscFunctionBegin;
116*fed79b8eSAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
117*fed79b8eSAlp Dener   tao->ops->solve=TaoSolve_BNTR;
118*fed79b8eSAlp Dener 
119*fed79b8eSAlp Dener   bnk = (TAO_BNK *)tao->data;
120*fed79b8eSAlp Dener   bnk->update_type = BNK_UPDATE_REDUCTION;
121*fed79b8eSAlp Dener   bnk->sval = 0.0;
122*fed79b8eSAlp Dener   PetscFunctionReturn(0);
123*fed79b8eSAlp Dener }