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 }