1*c14b763aSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h> 2*c14b763aSAlp Dener #include <petscksp.h> 3*c14b763aSAlp Dener 4*c14b763aSAlp Dener /* 5*c14b763aSAlp Dener Implements Newton's Method with a trust region approach for solving 6*c14b763aSAlp Dener bound constrained minimization problems. This version includes a 7*c14b763aSAlp Dener line search fall-back in the event of a trust region failure. 8*c14b763aSAlp Dener 9*c14b763aSAlp Dener The linear system solve should be done with a conjugate gradient 10*c14b763aSAlp Dener method, although any method can be used. 11*c14b763aSAlp Dener */ 12*c14b763aSAlp Dener 13*c14b763aSAlp Dener static PetscErrorCode TaoSolve_BNTL(Tao tao) 14*c14b763aSAlp Dener { 15*c14b763aSAlp Dener PetscErrorCode ierr; 16*c14b763aSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 17*c14b763aSAlp Dener TaoLineSearchConvergedReason ls_reason; 18*c14b763aSAlp Dener 19*c14b763aSAlp Dener PetscReal oldTrust, prered, actred, stepNorm, gdx, delta, steplen; 20*c14b763aSAlp Dener PetscBool stepAccepted = PETSC_TRUE; 21*c14b763aSAlp Dener PetscInt stepType, bfgsUpdates, updateType; 22*c14b763aSAlp Dener 23*c14b763aSAlp Dener PetscFunctionBegin; 24*c14b763aSAlp Dener /* Project the current point onto the feasible set */ 25*c14b763aSAlp Dener ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr); 26*c14b763aSAlp Dener ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr); 27*c14b763aSAlp Dener 28*c14b763aSAlp Dener /* Project the initial point onto the feasible region */ 29*c14b763aSAlp Dener ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr); 30*c14b763aSAlp Dener 31*c14b763aSAlp Dener /* Check convergence criteria */ 32*c14b763aSAlp Dener ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr); 33*c14b763aSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 34*c14b763aSAlp Dener ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr); 35*c14b763aSAlp Dener if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 36*c14b763aSAlp Dener 37*c14b763aSAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 38*c14b763aSAlp Dener ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr); 39*c14b763aSAlp Dener ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr); 40*c14b763aSAlp Dener ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 41*c14b763aSAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 42*c14b763aSAlp Dener 43*c14b763aSAlp Dener /* Initialize the preconditioner and trust radius */ 44*c14b763aSAlp Dener ierr = TaoBNKInitialize(tao);CHKERRQ(ierr); 45*c14b763aSAlp Dener 46*c14b763aSAlp Dener /* Have not converged; continue with Newton method */ 47*c14b763aSAlp Dener while (tao->reason == TAO_CONTINUE_ITERATING) { 48*c14b763aSAlp Dener 49*c14b763aSAlp Dener if (stepAccepted) { 50*c14b763aSAlp Dener tao->niter++; 51*c14b763aSAlp Dener tao->ksp_its=0; 52*c14b763aSAlp Dener /* Compute the Hessian */ 53*c14b763aSAlp Dener ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); 54*c14b763aSAlp Dener /* Update the BFGS preconditioner */ 55*c14b763aSAlp Dener if (BNK_PC_BFGS == bnk->pc_type) { 56*c14b763aSAlp Dener if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) { 57*c14b763aSAlp Dener /* Obtain diagonal for the bfgs preconditioner */ 58*c14b763aSAlp Dener ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr); 59*c14b763aSAlp Dener ierr = VecAbs(bnk->Diag);CHKERRQ(ierr); 60*c14b763aSAlp Dener ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr); 61*c14b763aSAlp Dener ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr); 62*c14b763aSAlp Dener } 63*c14b763aSAlp Dener /* Update the limited memory preconditioner and get existing # of updates */ 64*c14b763aSAlp Dener ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 65*c14b763aSAlp Dener } 66*c14b763aSAlp Dener } 67*c14b763aSAlp Dener 68*c14b763aSAlp Dener /* Use the common BNK kernel to compute the raw Newton step */ 69*c14b763aSAlp Dener ierr = TaoBNKComputeStep(tao, PETSC_FALSE, &stepType);CHKERRQ(ierr); 70*c14b763aSAlp Dener 71*c14b763aSAlp Dener /* Store current solution before it changes */ 72*c14b763aSAlp Dener oldTrust = tao->trust; 73*c14b763aSAlp Dener bnk->fold = bnk->f; 74*c14b763aSAlp Dener ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr); 75*c14b763aSAlp Dener ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr); 76*c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr); 77*c14b763aSAlp Dener 78*c14b763aSAlp Dener /* Temporarily accept the step and project it into the bounds */ 79*c14b763aSAlp Dener ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr); 80*c14b763aSAlp Dener ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr); 81*c14b763aSAlp Dener 82*c14b763aSAlp Dener /* Check if the projection changed the step direction */ 83*c14b763aSAlp Dener ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 84*c14b763aSAlp Dener ierr = VecAXPBY(tao->stepdirection, -1.0, 1.0, bnk->Xold);CHKERRQ(ierr); 85*c14b763aSAlp Dener ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr); 86*c14b763aSAlp Dener if (stepNorm != bnk->dnorm) { 87*c14b763aSAlp Dener /* Projection changed the step, so we have to adjust trust radius and recompute predicted reduction */ 88*c14b763aSAlp Dener bnk->dnorm = stepNorm; 89*c14b763aSAlp Dener tao->trust = bnk->dnorm; 90*c14b763aSAlp Dener ierr = MatMult(tao->hessian, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr); 91*c14b763aSAlp Dener ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr); 92*c14b763aSAlp Dener ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered); 93*c14b763aSAlp Dener } else { 94*c14b763aSAlp Dener /* Step did not change, so we can just recover the pre-computed prediction */ 95*c14b763aSAlp Dener ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr); 96*c14b763aSAlp Dener } 97*c14b763aSAlp Dener prered = -prered; 98*c14b763aSAlp Dener 99*c14b763aSAlp Dener /* Compute the actual reduction and update the trust radius */ 100*c14b763aSAlp Dener ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr); 101*c14b763aSAlp Dener actred = bnk->fold - bnk->f; 102*c14b763aSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr); 103*c14b763aSAlp Dener 104*c14b763aSAlp Dener if (stepAccepted) { 105*c14b763aSAlp Dener /* Step is good, evaluate the gradient and the hessian */ 106*c14b763aSAlp Dener ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 107*c14b763aSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 108*c14b763aSAlp Dener } else { 109*c14b763aSAlp Dener /* Trust-region rejected the step. Revert the solution. */ 110*c14b763aSAlp Dener bnk->f = bnk->fold; 111*c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 112*c14b763aSAlp Dener 113*c14b763aSAlp Dener /* Now check to make sure the Newton step is a descent direction... */ 114*c14b763aSAlp Dener ierr = VecDot(tao->stepdirection, tao->gradient, &gdx);CHKERRQ(ierr); 115*c14b763aSAlp Dener if ((gdx >= 0.0) || PetscIsInfOrNanReal(gdx)) { 116*c14b763aSAlp Dener /* Newton step is not descent or direction produced Inf or NaN */ 117*c14b763aSAlp Dener --bnk->newt; 118*c14b763aSAlp Dener if (BNK_PC_BFGS != bnk->pc_type) { 119*c14b763aSAlp Dener /* We don't have the BFGS matrix around and updated 120*c14b763aSAlp Dener Must use gradient direction in this case */ 121*c14b763aSAlp Dener ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr); 122*c14b763aSAlp Dener ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 123*c14b763aSAlp Dener ++bnk->grad; 124*c14b763aSAlp Dener stepType = BNK_GRADIENT; 125*c14b763aSAlp Dener } else { 126*c14b763aSAlp Dener /* We have the BFGS matrix, so attempt to use the BFGS direction */ 127*c14b763aSAlp Dener ierr = MatLMVMSolve(bnk->M, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 128*c14b763aSAlp Dener ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 129*c14b763aSAlp Dener 130*c14b763aSAlp Dener /* Check for success (descent direction) */ 131*c14b763aSAlp Dener ierr = VecDot(tao->stepdirection, tao->gradient, &gdx);CHKERRQ(ierr); 132*c14b763aSAlp Dener if ((gdx >= 0) || PetscIsInfOrNanReal(gdx)) { 133*c14b763aSAlp Dener /* BFGS direction is not descent or direction produced not a number 134*c14b763aSAlp Dener We can assert bfgsUpdates > 1 in this case because 135*c14b763aSAlp Dener the first solve produces the scaled gradient direction, 136*c14b763aSAlp Dener which is guaranteed to be descent */ 137*c14b763aSAlp Dener 138*c14b763aSAlp Dener /* Use steepest descent direction (scaled) */ 139*c14b763aSAlp Dener if (bnk->f != 0.0) { 140*c14b763aSAlp Dener delta = 2.0 * PetscAbsScalar(bnk->f) / (bnk->gnorm*bnk->gnorm); 141*c14b763aSAlp Dener } else { 142*c14b763aSAlp Dener delta = 2.0 / (bnk->gnorm*bnk->gnorm); 143*c14b763aSAlp Dener } 144*c14b763aSAlp Dener ierr = MatLMVMSetDelta(bnk->M, delta);CHKERRQ(ierr); 145*c14b763aSAlp Dener ierr = MatLMVMReset(bnk->M);CHKERRQ(ierr); 146*c14b763aSAlp Dener ierr = MatLMVMUpdate(bnk->M, tao->solution, tao->gradient);CHKERRQ(ierr); 147*c14b763aSAlp Dener ierr = MatLMVMSolve(bnk->M, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 148*c14b763aSAlp Dener ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 149*c14b763aSAlp Dener 150*c14b763aSAlp Dener ++bnk->sgrad; 151*c14b763aSAlp Dener stepType = BNK_SCALED_GRADIENT; 152*c14b763aSAlp Dener } else { 153*c14b763aSAlp Dener ierr = MatLMVMGetUpdates(bnk->M, &bfgsUpdates);CHKERRQ(ierr); 154*c14b763aSAlp Dener if (1 == bfgsUpdates) { 155*c14b763aSAlp Dener /* The first BFGS direction is always the scaled gradient */ 156*c14b763aSAlp Dener ++bnk->sgrad; 157*c14b763aSAlp Dener stepType = BNK_SCALED_GRADIENT; 158*c14b763aSAlp Dener } else { 159*c14b763aSAlp Dener ++bnk->bfgs; 160*c14b763aSAlp Dener stepType = BNK_BFGS; 161*c14b763aSAlp Dener } 162*c14b763aSAlp Dener } 163*c14b763aSAlp Dener } 164*c14b763aSAlp Dener } 165*c14b763aSAlp Dener 166*c14b763aSAlp Dener /* Trigger the line search */ 167*c14b763aSAlp Dener ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr); 168*c14b763aSAlp Dener if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) { 169*c14b763aSAlp Dener /* Line search failed, revert solution and terminate */ 170*c14b763aSAlp Dener bnk->f = bnk->fold; 171*c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 172*c14b763aSAlp Dener ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr); 173*c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr); 174*c14b763aSAlp Dener tao->trust = 0.0; 175*c14b763aSAlp Dener tao->reason = TAO_DIVERGED_LS_FAILURE; 176*c14b763aSAlp Dener } else { 177*c14b763aSAlp Dener /* Line search succeeded so we should update the trust radius based on the LS step length */ 178*c14b763aSAlp Dener updateType = bnk->update_type; 179*c14b763aSAlp Dener bnk->update_type = BNK_UPDATE_STEP; 180*c14b763aSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr); 181*c14b763aSAlp Dener bnk->update_type = updateType; 182*c14b763aSAlp Dener } 183*c14b763aSAlp Dener } 184*c14b763aSAlp Dener 185*c14b763aSAlp Dener /* Check for termination */ 186*c14b763aSAlp Dener ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr); 187*c14b763aSAlp Dener if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number"); 188*c14b763aSAlp Dener ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr); 189*c14b763aSAlp Dener ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr); 190*c14b763aSAlp Dener ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 191*c14b763aSAlp Dener } 192*c14b763aSAlp Dener PetscFunctionReturn(0); 193*c14b763aSAlp Dener } 194*c14b763aSAlp Dener 195*c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao) 196*c14b763aSAlp Dener { 197*c14b763aSAlp Dener TAO_BNK *bnk; 198*c14b763aSAlp Dener PetscErrorCode ierr; 199*c14b763aSAlp Dener 200*c14b763aSAlp Dener PetscFunctionBegin; 201*c14b763aSAlp Dener ierr = TaoCreate_BNK(tao);CHKERRQ(ierr); 202*c14b763aSAlp Dener tao->ops->solve=TaoSolve_BNTL; 203*c14b763aSAlp Dener 204*c14b763aSAlp Dener bnk = (TAO_BNK *)tao->data; 205*c14b763aSAlp Dener bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */ 206*c14b763aSAlp Dener bnk->sval = 0.0; /* disable Hessian shifting */ 207*c14b763aSAlp Dener PetscFunctionReturn(0); 208*c14b763aSAlp Dener }