xref: /petsc/src/tao/bound/impls/bnk/bnls.c (revision e465cd6f30f93207df959d4c9fc4f47b6c5c3063)
1eb910715SAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h>
2eb910715SAlp Dener #include <petscksp.h>
3eb910715SAlp Dener 
4eb910715SAlp Dener /*
5eb910715SAlp Dener  Implements Newton's Method with a line search approach for solving
62b97c8d8SAlp Dener  bound constrained minimization problems. A projected More'-Thuente line
7770b7498SAlp Dener  search is used to guarantee that the BFGS preconditioner remains positive
8eb910715SAlp Dener  definite.
9eb910715SAlp Dener 
10eb910715SAlp Dener  The method can shift the Hessian matrix. The shifting procedure is
11eb910715SAlp Dener  adapted from the PATH algorithm for solving complementarity
12eb910715SAlp Dener  problems.
13eb910715SAlp Dener 
14eb910715SAlp Dener  The linear system solve should be done with a conjugate gradient
15eb910715SAlp Dener  method, although any method can be used.
16eb910715SAlp Dener */
17eb910715SAlp Dener 
18eb910715SAlp Dener static PetscErrorCode TaoSolve_BNLS(Tao tao)
19eb910715SAlp Dener {
20eb910715SAlp Dener   PetscErrorCode               ierr;
21eb910715SAlp Dener   TAO_BNK                      *bnk = (TAO_BNK *)tao->data;
22*e465cd6fSAlp Dener   KSPConvergedReason           ksp_reason;
23eb910715SAlp Dener   TaoLineSearchConvergedReason ls_reason;
24eb910715SAlp Dener 
25c14b763aSAlp Dener   PetscReal                    f_full, prered, actred;
26c14b763aSAlp Dener   PetscReal                    steplen = 1.0;
27eb910715SAlp Dener 
28080d2917SAlp Dener   PetscBool                    trustAccept;
29eb910715SAlp Dener   PetscInt                     stepType;
30eb910715SAlp Dener   PetscInt                     bfgsUpdates = 0;
31eb910715SAlp Dener 
32eb910715SAlp Dener   PetscFunctionBegin;
3309164190SAlp Dener   /*   Project the current point onto the feasible set */
3409164190SAlp Dener   ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr);
3509164190SAlp Dener   ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr);
3609164190SAlp Dener 
3709164190SAlp Dener   /* Project the initial point onto the feasible region */
3809164190SAlp Dener   ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr);
39eb910715SAlp Dener 
40eb910715SAlp Dener   /* Check convergence criteria */
4109164190SAlp Dener   ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr);
4209164190SAlp Dener   ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr);
43eb910715SAlp Dener   ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
44eb910715SAlp Dener   if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN");
45eb910715SAlp Dener 
46eb910715SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
47eb910715SAlp Dener   ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
48c14b763aSAlp Dener   ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
49eb910715SAlp Dener   ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
50eb910715SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
51eb910715SAlp Dener 
52eb910715SAlp Dener   /* Initialize the preconditioner and trust radius */
53eb910715SAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
54eb910715SAlp Dener 
55eb910715SAlp Dener   /* Have not converged; continue with Newton method */
56eb910715SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
57eb910715SAlp Dener     ++tao->niter;
58eb910715SAlp Dener     tao->ksp_its=0;
59eb910715SAlp Dener 
6009164190SAlp Dener     /* Compute the Hessian */
6109164190SAlp Dener     ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
62*e465cd6fSAlp Dener     /* Shift the Hessian matrix */
63*e465cd6fSAlp Dener     if (bnk->pert > 0) {
64*e465cd6fSAlp Dener       ierr = MatShift(tao->hessian, bnk->pert);CHKERRQ(ierr);
65*e465cd6fSAlp Dener       if (tao->hessian != tao->hessian_pre) {
66*e465cd6fSAlp Dener         ierr = MatShift(tao->hessian_pre, bnk->pert);CHKERRQ(ierr);
67*e465cd6fSAlp Dener       }
68*e465cd6fSAlp Dener     }
69fed79b8eSAlp Dener     /* Update the BFGS preconditioner */
70fed79b8eSAlp Dener     if (BNK_PC_BFGS == bnk->pc_type) {
71fed79b8eSAlp Dener       if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
72fed79b8eSAlp Dener         /* Obtain diagonal for the bfgs preconditioner  */
73fed79b8eSAlp Dener         ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
74fed79b8eSAlp Dener         ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
75fed79b8eSAlp Dener         ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
76fed79b8eSAlp Dener         ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
77fed79b8eSAlp Dener       }
78fed79b8eSAlp Dener       /* Update the limited memory preconditioner and get existing # of updates */
79fed79b8eSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
80fed79b8eSAlp Dener       ierr = MatLMVMGetUpdates(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
81fed79b8eSAlp Dener     }
82fed79b8eSAlp Dener 
838d5ead36SAlp Dener     /* Use the common BNK kernel to compute the safeguarded Newton step (for inactive variables only) */
84*e465cd6fSAlp Dener     ierr = TaoBNKComputeStep(tao, &ksp_reason);CHKERRQ(ierr);
85*e465cd6fSAlp Dener     ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
86eb910715SAlp Dener 
87080d2917SAlp Dener     /* Store current solution before it changes */
88080d2917SAlp Dener     bnk->fold = bnk->f;
89eb910715SAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
90eb910715SAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
9109164190SAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
92eb910715SAlp Dener 
93c14b763aSAlp Dener     /* Trigger the line search */
94c14b763aSAlp Dener     ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
95eb910715SAlp Dener 
96eb910715SAlp Dener     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
97eb910715SAlp Dener       /* Failed to find an improving point */
98080d2917SAlp Dener       bnk->f = bnk->fold;
99eb910715SAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
100eb910715SAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
10109164190SAlp Dener       ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
102c14b763aSAlp Dener       steplen = 0.0;
103eb910715SAlp Dener       tao->reason = TAO_DIVERGED_LS_FAILURE;
104eb910715SAlp Dener       break;
105*e465cd6fSAlp Dener     } else {
106*e465cd6fSAlp Dener       /* count the accepted step types */
107*e465cd6fSAlp Dener       switch (stepType) {
108*e465cd6fSAlp Dener       case BNK_NEWTON:
109*e465cd6fSAlp Dener         ++bnk->newt;
110*e465cd6fSAlp Dener         break;
111*e465cd6fSAlp Dener       case BNK_BFGS:
112*e465cd6fSAlp Dener         ++bnk->bfgs;
113*e465cd6fSAlp Dener         break;
114*e465cd6fSAlp Dener       case BNK_SCALED_GRADIENT:
115*e465cd6fSAlp Dener         ++bnk->sgrad;
116*e465cd6fSAlp Dener         break;
117*e465cd6fSAlp Dener       case BNK_GRADIENT:
118*e465cd6fSAlp Dener         ++bnk->grad;
119*e465cd6fSAlp Dener         break;
120*e465cd6fSAlp Dener       default:
121*e465cd6fSAlp Dener         break;
122*e465cd6fSAlp Dener       }
123eb910715SAlp Dener     }
124eb910715SAlp Dener 
125080d2917SAlp Dener     /* update trust radius */
126080d2917SAlp Dener     ierr = TaoLineSearchGetFullStepObjective(tao->linesearch, &f_full);CHKERRQ(ierr);
127b1c2d0e3SAlp Dener     ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr);
128b1c2d0e3SAlp Dener     prered = -prered;
129b1c2d0e3SAlp Dener     actred = bnk->fold - f_full;
130b1c2d0e3SAlp Dener     ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &trustAccept);CHKERRQ(ierr);
131eb910715SAlp Dener 
132eb910715SAlp Dener     /*  Check for termination */
133eb910715SAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
134eb910715SAlp Dener     if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
135eb910715SAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
136c14b763aSAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
137eb910715SAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
138eb910715SAlp Dener   }
139eb910715SAlp Dener   PetscFunctionReturn(0);
140eb910715SAlp Dener }
141eb910715SAlp Dener 
142df278d8fSAlp Dener /*------------------------------------------------------------*/
143df278d8fSAlp Dener 
144eb910715SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNLS(Tao tao)
145eb910715SAlp Dener {
146fed79b8eSAlp Dener   TAO_BNK        *bnk;
147eb910715SAlp Dener   PetscErrorCode ierr;
148eb910715SAlp Dener 
149eb910715SAlp Dener   PetscFunctionBegin;
150eb910715SAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
151eb910715SAlp Dener   tao->ops->solve = TaoSolve_BNLS;
152fed79b8eSAlp Dener 
153fed79b8eSAlp Dener   bnk = (TAO_BNK *)tao->data;
15466ed3702SAlp Dener   bnk->update_type = BNK_UPDATE_STEP; /* trust region updates based on line search step length */
155eb910715SAlp Dener   PetscFunctionReturn(0);
156eb910715SAlp Dener }