1c14b763aSAlp Dener #include <../src/tao/bound/impls/bnk/bnk.h> 2c14b763aSAlp Dener #include <petscksp.h> 3c14b763aSAlp Dener 4c14b763aSAlp Dener /* 5c14b763aSAlp Dener Implements Newton's Method with a trust region approach for solving 6*198282dbSAlp Dener bound constrained minimization problems. 7c14b763aSAlp Dener 8*198282dbSAlp Dener ------------------------------------------------------------ 9*198282dbSAlp Dener 10*198282dbSAlp Dener initialize trust radius (default: BNK_INIT_INTERPOLATION) 11*198282dbSAlp Dener x_0 = VecMedian(x_0) 12*198282dbSAlp Dener f_0, g_0 = TaoComputeObjectiveAndGradient(x_0) 13*198282dbSAlp Dener pg_0 = VecBoundGradientProjection(g_0) 14*198282dbSAlp Dener check convergence at pg_0 15*198282dbSAlp Dener niter = 0 16*198282dbSAlp Dener step_accepted = true 17*198282dbSAlp Dener 18*198282dbSAlp Dener while niter <= max_it 19*198282dbSAlp Dener niter += 1 20*198282dbSAlp Dener H_k = TaoComputeHessian(x_k) 21*198282dbSAlp Dener if pc_type == BNK_PC_BFGS 22*198282dbSAlp Dener add correction to BFGS approx 23*198282dbSAlp Dener if scale_type == BNK_SCALE_AHESS 24*198282dbSAlp Dener D = VecMedian(1e-6, abs(diag(H_k)), 1e6) 25*198282dbSAlp Dener scale BFGS with VecReciprocal(D) 26*198282dbSAlp Dener end 27*198282dbSAlp Dener end 28*198282dbSAlp Dener 29*198282dbSAlp Dener if pc_type = BNK_PC_BFGS 30*198282dbSAlp Dener B_k = BFGS 31*198282dbSAlp Dener else 32*198282dbSAlp Dener B_k = VecMedian(1e-6, abs(diag(H_k)), 1e6) 33*198282dbSAlp Dener B_k = VecReciprocal(B_k) 34*198282dbSAlp Dener end 35*198282dbSAlp Dener w = x_k - VecMedian(x_k - 0.001*B_k*g_k) 36*198282dbSAlp Dener eps = min(eps, norm2(w)) 37*198282dbSAlp Dener determine the active and inactive index sets such that 38*198282dbSAlp Dener L = {i : (x_k)_i <= l_i + eps && (g_k)_i > 0} 39*198282dbSAlp Dener U = {i : (x_k)_i >= u_i - eps && (g_k)_i < 0} 40*198282dbSAlp Dener F = {i : l_i = (x_k)_i = u_i} 41*198282dbSAlp Dener A = {L + U + F} 42*198282dbSAlp Dener I = {i : i not in A} 43*198282dbSAlp Dener 44*198282dbSAlp Dener generate the reduced system Hr_k dr_k = -gr_k for variables in I 45*198282dbSAlp Dener if pc_type == BNK_PC_BFGS && scale_type == BNK_SCALE_PHESS 46*198282dbSAlp Dener D = VecMedian(1e-6, abs(diag(Hr_k)), 1e6) 47*198282dbSAlp Dener scale BFGS with VecReciprocal(D) 48*198282dbSAlp Dener end 49*198282dbSAlp Dener solve Hr_k dr_k = -gr_k 50*198282dbSAlp Dener set d_k to (l - x) for variables in L, (u - x) for variables in U, and 0 for variables in F 51*198282dbSAlp Dener 52*198282dbSAlp Dener x_{k+1} = VecMedian(x_k + d_k) 53*198282dbSAlp Dener s = x_{k+1} - x_k 54*198282dbSAlp Dener prered = dot(s, 0.5*gr_k - Hr_k*s) 55*198282dbSAlp Dener f_{k+1} = TaoComputeObjective(x_{k+1}) 56*198282dbSAlp Dener actred = f_k - f_{k+1} 57*198282dbSAlp Dener 58*198282dbSAlp Dener oldTrust = trust 59*198282dbSAlp Dener step_accepted, trust = TaoBNKUpdateTrustRadius(default: BNK_UPDATE_REDUCTION) 60*198282dbSAlp Dener if step_accepted 61*198282dbSAlp Dener g_{k+1} = TaoComputeGradient(x_{k+1}) 62*198282dbSAlp Dener pg_{k+1} = VecBoundGradientProjection(g_{k+1}) 63*198282dbSAlp Dener count the accepted Newton step 64*198282dbSAlp Dener else 65*198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 66*198282dbSAlp Dener dr_k = -BFGS*gr_k for variables in I 67*198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 68*198282dbSAlp Dener reset the BFGS preconditioner 69*198282dbSAlp Dener calculate scale delta and apply it to BFGS 70*198282dbSAlp Dener dr_k = -BFGS*gr_k for variables in I 71*198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 72*198282dbSAlp Dener dr_k = -gr_k for variables in I 73*198282dbSAlp Dener end 74*198282dbSAlp Dener end 75*198282dbSAlp Dener end 76*198282dbSAlp Dener 77*198282dbSAlp Dener x_{k+1}, f_{k+1}, g_{k+1}, ls_failed = TaoBNKPerformLineSearch() 78*198282dbSAlp Dener if ls_failed 79*198282dbSAlp Dener f_{k+1} = f_k 80*198282dbSAlp Dener x_{k+1} = x_k 81*198282dbSAlp Dener g_{k+1} = g_k 82*198282dbSAlp Dener pg_{k+1} = pg_k 83*198282dbSAlp Dener terminate 84*198282dbSAlp Dener else 85*198282dbSAlp Dener pg_{k+1} = VecBoundGradientProjection(g_{k+1}) 86*198282dbSAlp Dener trust = oldTrust 87*198282dbSAlp Dener trust = TaoBNKUpdateTrustRadius(BNK_UPDATE_STEP) 88*198282dbSAlp Dener count the accepted step type (Newton, BFGS, scaled grad or grad) 89*198282dbSAlp Dener end 90*198282dbSAlp Dener end 91*198282dbSAlp Dener 92*198282dbSAlp Dener check convergence at pg_{k+1} 93*198282dbSAlp Dener end 94c14b763aSAlp Dener */ 95c14b763aSAlp Dener 96c14b763aSAlp Dener static PetscErrorCode TaoSolve_BNTL(Tao tao) 97c14b763aSAlp Dener { 98c14b763aSAlp Dener PetscErrorCode ierr; 99c14b763aSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 100e465cd6fSAlp Dener KSPConvergedReason ksp_reason; 101c14b763aSAlp Dener TaoLineSearchConvergedReason ls_reason; 102c14b763aSAlp Dener 103e465cd6fSAlp Dener PetscReal oldTrust, prered, actred, stepNorm, steplen; 10462675beeSAlp Dener PetscBool stepAccepted = PETSC_TRUE, shift = PETSC_FALSE; 10528017e9fSAlp Dener PetscInt stepType; 106c14b763aSAlp Dener 107c14b763aSAlp Dener PetscFunctionBegin; 10828017e9fSAlp Dener /* Initialize the preconditioner, KSP solver and trust radius/line search */ 109c14b763aSAlp Dener tao->reason = TAO_CONTINUE_ITERATING; 11062675beeSAlp Dener ierr = TaoBNKInitialize(tao, bnk->init_type);CHKERRQ(ierr); 11128017e9fSAlp Dener if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 112c14b763aSAlp Dener 113c14b763aSAlp Dener /* Have not converged; continue with Newton method */ 114c14b763aSAlp Dener while (tao->reason == TAO_CONTINUE_ITERATING) { 115c14b763aSAlp Dener tao->niter++; 116c14b763aSAlp Dener tao->ksp_its=0; 11762675beeSAlp Dener 11862675beeSAlp Dener /* Compute the hessian and update the BFGS preconditioner at the new iterate*/ 11962675beeSAlp Dener ierr = TaoBNKComputeHessian(tao);CHKERRQ(ierr); 120c14b763aSAlp Dener 1218d5ead36SAlp Dener /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */ 12262675beeSAlp Dener ierr = TaoBNKComputeStep(tao, shift, &ksp_reason);CHKERRQ(ierr); 123c14b763aSAlp Dener 124c14b763aSAlp Dener /* Store current solution before it changes */ 125c14b763aSAlp Dener oldTrust = tao->trust; 126c14b763aSAlp Dener bnk->fold = bnk->f; 127c14b763aSAlp Dener ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr); 128c14b763aSAlp Dener ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr); 129c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr); 130c14b763aSAlp Dener 131c14b763aSAlp Dener /* Temporarily accept the step and project it into the bounds */ 132c14b763aSAlp Dener ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr); 133c14b763aSAlp Dener ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr); 134c14b763aSAlp Dener 135c14b763aSAlp Dener /* Check if the projection changed the step direction */ 136c14b763aSAlp Dener ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 1378d5ead36SAlp Dener ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr); 138c14b763aSAlp Dener ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr); 139c14b763aSAlp Dener if (stepNorm != bnk->dnorm) { 1408d5ead36SAlp Dener /* Projection changed the step, so we have to recompute predicted reduction. 1418d5ead36SAlp Dener However, we deliberately do not change the step norm and the trust radius 1428d5ead36SAlp Dener in order for the safeguard to more closely mimic a piece-wise linesearch 1438d5ead36SAlp Dener along the bounds. */ 14428017e9fSAlp Dener ierr = MatMult(bnk->H_inactive, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr); 145*198282dbSAlp Dener ierr = VecAYPX(bnk->Xwork, -0.5, bnk->G_inactive);CHKERRQ(ierr); 146c14b763aSAlp Dener ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered); 147c14b763aSAlp Dener } else { 148c14b763aSAlp Dener /* Step did not change, so we can just recover the pre-computed prediction */ 149c14b763aSAlp Dener ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr); 150c14b763aSAlp Dener } 151c14b763aSAlp Dener prered = -prered; 152c14b763aSAlp Dener 153c14b763aSAlp Dener /* Compute the actual reduction and update the trust radius */ 154c14b763aSAlp Dener ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr); 155c14b763aSAlp Dener actred = bnk->fold - bnk->f; 15628017e9fSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr); 157c14b763aSAlp Dener 158c14b763aSAlp Dener if (stepAccepted) { 159c14b763aSAlp Dener /* Step is good, evaluate the gradient and the hessian */ 1608d5ead36SAlp Dener steplen = 1.0; 161e465cd6fSAlp Dener ++bnk->newt; 162c14b763aSAlp Dener ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 163c14b763aSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 164c14b763aSAlp Dener } else { 165c14b763aSAlp Dener /* Trust-region rejected the step. Revert the solution. */ 166c14b763aSAlp Dener bnk->f = bnk->fold; 167c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 168c14b763aSAlp Dener 169c14b763aSAlp Dener /* Trigger the line search */ 170e465cd6fSAlp Dener ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr); 171c14b763aSAlp Dener ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr); 172c14b763aSAlp Dener if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) { 173c14b763aSAlp Dener /* Line search failed, revert solution and terminate */ 174c14b763aSAlp Dener bnk->f = bnk->fold; 175c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 176c14b763aSAlp Dener ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr); 177c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr); 178c14b763aSAlp Dener tao->trust = 0.0; 179c14b763aSAlp Dener tao->reason = TAO_DIVERGED_LS_FAILURE; 180c14b763aSAlp Dener } else { 181*198282dbSAlp Dener /* compute the projected gradient */ 182*198282dbSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 183c14b763aSAlp Dener /* Line search succeeded so we should update the trust radius based on the LS step length */ 184770b7498SAlp Dener tao->trust = oldTrust; 18528017e9fSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, BNK_UPDATE_STEP, stepType, &stepAccepted);CHKERRQ(ierr); 18662675beeSAlp Dener /* count the accepted step type */ 18762675beeSAlp Dener ierr = TaoBNKAddStepCounts(tao, stepType);CHKERRQ(ierr); 188c14b763aSAlp Dener } 189c14b763aSAlp Dener } 190c14b763aSAlp Dener 191c14b763aSAlp Dener /* Check for termination */ 192c14b763aSAlp Dener ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr); 193c14b763aSAlp Dener if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number"); 194c14b763aSAlp Dener ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr); 1958d5ead36SAlp Dener ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,steplen);CHKERRQ(ierr); 196c14b763aSAlp Dener ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 197c14b763aSAlp Dener } 198c14b763aSAlp Dener PetscFunctionReturn(0); 199c14b763aSAlp Dener } 200c14b763aSAlp Dener 201df278d8fSAlp Dener /*------------------------------------------------------------*/ 202df278d8fSAlp Dener 203c14b763aSAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BNTL(Tao tao) 204c14b763aSAlp Dener { 205c14b763aSAlp Dener TAO_BNK *bnk; 206c14b763aSAlp Dener PetscErrorCode ierr; 207c14b763aSAlp Dener 208c14b763aSAlp Dener PetscFunctionBegin; 209c14b763aSAlp Dener ierr = TaoCreate_BNK(tao);CHKERRQ(ierr); 210c14b763aSAlp Dener tao->ops->solve=TaoSolve_BNTL; 211c14b763aSAlp Dener 212c14b763aSAlp Dener bnk = (TAO_BNK *)tao->data; 213c14b763aSAlp Dener bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */ 214c14b763aSAlp Dener bnk->sval = 0.0; /* disable Hessian shifting */ 215c14b763aSAlp Dener PetscFunctionReturn(0); 216c14b763aSAlp Dener }