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 }