xref: /petsc/src/tao/bound/impls/bnk/bnls.c (revision 28017e9fc366e9d0379085f0860b391dd2763ed7)
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;
22e465cd6fSAlp 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;
33*28017e9fSAlp Dener   /* Initialize the preconditioner, KSP solver and trust radius/line search */
34eb910715SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
35eb910715SAlp Dener   ierr = TaoBNKInitialize(tao);CHKERRQ(ierr);
36*28017e9fSAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
37eb910715SAlp Dener 
38eb910715SAlp Dener   /* Have not converged; continue with Newton method */
39eb910715SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
40eb910715SAlp Dener     ++tao->niter;
41eb910715SAlp Dener     tao->ksp_its=0;
42eb910715SAlp Dener 
4309164190SAlp Dener     /* Compute the Hessian */
4409164190SAlp Dener     ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr);
45e465cd6fSAlp Dener     /* Shift the Hessian matrix */
46e465cd6fSAlp Dener     if (bnk->pert > 0) {
47e465cd6fSAlp Dener       ierr = MatShift(tao->hessian, bnk->pert);CHKERRQ(ierr);
48e465cd6fSAlp Dener       if (tao->hessian != tao->hessian_pre) {
49e465cd6fSAlp Dener         ierr = MatShift(tao->hessian_pre, bnk->pert);CHKERRQ(ierr);
50e465cd6fSAlp Dener       }
51e465cd6fSAlp Dener     }
52fed79b8eSAlp Dener     /* Update the BFGS preconditioner */
53fed79b8eSAlp Dener     if (BNK_PC_BFGS == bnk->pc_type) {
54fed79b8eSAlp Dener       if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) {
55fed79b8eSAlp Dener         /* Obtain diagonal for the bfgs preconditioner  */
56fed79b8eSAlp Dener         ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr);
57fed79b8eSAlp Dener         ierr = VecAbs(bnk->Diag);CHKERRQ(ierr);
58fed79b8eSAlp Dener         ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr);
59fed79b8eSAlp Dener         ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr);
60fed79b8eSAlp Dener       }
61fed79b8eSAlp Dener       /* Update the limited memory preconditioner and get existing # of updates */
62fed79b8eSAlp Dener       ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr);
63fed79b8eSAlp Dener       ierr = MatLMVMGetUpdates(bnk->M, &bfgsUpdates);CHKERRQ(ierr);
64fed79b8eSAlp Dener     }
65fed79b8eSAlp Dener 
668d5ead36SAlp Dener     /* Use the common BNK kernel to compute the safeguarded Newton step (for inactive variables only) */
67*28017e9fSAlp Dener     tao->trust = bnk->max_radius;
68e465cd6fSAlp Dener     ierr = TaoBNKComputeStep(tao, &ksp_reason);CHKERRQ(ierr);
69e465cd6fSAlp Dener     ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr);
70eb910715SAlp Dener 
71080d2917SAlp Dener     /* Store current solution before it changes */
72080d2917SAlp Dener     bnk->fold = bnk->f;
73eb910715SAlp Dener     ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr);
74eb910715SAlp Dener     ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr);
7509164190SAlp Dener     ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr);
76eb910715SAlp Dener 
77c14b763aSAlp Dener     /* Trigger the line search */
78c14b763aSAlp Dener     ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr);
79eb910715SAlp Dener 
80eb910715SAlp Dener     if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) {
81eb910715SAlp Dener       /* Failed to find an improving point */
82080d2917SAlp Dener       bnk->f = bnk->fold;
83eb910715SAlp Dener       ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr);
84eb910715SAlp Dener       ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr);
8509164190SAlp Dener       ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr);
86c14b763aSAlp Dener       steplen = 0.0;
87eb910715SAlp Dener       tao->reason = TAO_DIVERGED_LS_FAILURE;
88eb910715SAlp Dener       break;
89e465cd6fSAlp Dener     } else {
90e465cd6fSAlp Dener       /* count the accepted step types */
91e465cd6fSAlp Dener       switch (stepType) {
92e465cd6fSAlp Dener       case BNK_NEWTON:
93e465cd6fSAlp Dener         ++bnk->newt;
94e465cd6fSAlp Dener         break;
95e465cd6fSAlp Dener       case BNK_BFGS:
96e465cd6fSAlp Dener         ++bnk->bfgs;
97e465cd6fSAlp Dener         break;
98e465cd6fSAlp Dener       case BNK_SCALED_GRADIENT:
99e465cd6fSAlp Dener         ++bnk->sgrad;
100e465cd6fSAlp Dener         break;
101e465cd6fSAlp Dener       case BNK_GRADIENT:
102e465cd6fSAlp Dener         ++bnk->grad;
103e465cd6fSAlp Dener         break;
104e465cd6fSAlp Dener       default:
105e465cd6fSAlp Dener         break;
106e465cd6fSAlp Dener       }
107eb910715SAlp Dener     }
108eb910715SAlp Dener 
109eb910715SAlp Dener     /*  Check for termination */
110eb910715SAlp Dener     ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr);
111eb910715SAlp Dener     if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number");
112eb910715SAlp Dener     ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr);
113c14b763aSAlp Dener     ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr);
114eb910715SAlp Dener     ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr);
115eb910715SAlp Dener   }
116eb910715SAlp Dener   PetscFunctionReturn(0);
117eb910715SAlp Dener }
118eb910715SAlp Dener 
119df278d8fSAlp Dener /*------------------------------------------------------------*/
120df278d8fSAlp Dener 
121eb910715SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNLS(Tao tao)
122eb910715SAlp Dener {
123fed79b8eSAlp Dener   TAO_BNK        *bnk;
124eb910715SAlp Dener   PetscErrorCode ierr;
125eb910715SAlp Dener 
126eb910715SAlp Dener   PetscFunctionBegin;
127eb910715SAlp Dener   ierr = TaoCreate_BNK(tao);CHKERRQ(ierr);
128eb910715SAlp Dener   tao->ops->solve = TaoSolve_BNLS;
129fed79b8eSAlp Dener 
130fed79b8eSAlp Dener   bnk = (TAO_BNK *)tao->data;
131*28017e9fSAlp Dener   bnk->init_type = BNK_INIT_CONSTANT;
13266ed3702SAlp Dener   bnk->update_type = BNK_UPDATE_STEP; /* trust region updates based on line search step length */
133eb910715SAlp Dener   PetscFunctionReturn(0);
134eb910715SAlp Dener }