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 6198282dbSAlp Dener bound constrained minimization problems. 7c14b763aSAlp Dener 8198282dbSAlp Dener ------------------------------------------------------------ 9198282dbSAlp Dener 10198282dbSAlp Dener initialize trust radius (default: BNK_INIT_INTERPOLATION) 11198282dbSAlp Dener x_0 = VecMedian(x_0) 12198282dbSAlp Dener f_0, g_0 = TaoComputeObjectiveAndGradient(x_0) 13198282dbSAlp Dener pg_0 = VecBoundGradientProjection(g_0) 14198282dbSAlp Dener check convergence at pg_0 15198282dbSAlp Dener niter = 0 16198282dbSAlp Dener step_accepted = true 17198282dbSAlp Dener 18198282dbSAlp Dener while niter <= max_it 19198282dbSAlp Dener niter += 1 20198282dbSAlp Dener H_k = TaoComputeHessian(x_k) 21198282dbSAlp Dener if pc_type == BNK_PC_BFGS 22198282dbSAlp Dener add correction to BFGS approx 23198282dbSAlp Dener if scale_type == BNK_SCALE_AHESS 24198282dbSAlp Dener D = VecMedian(1e-6, abs(diag(H_k)), 1e6) 25198282dbSAlp Dener scale BFGS with VecReciprocal(D) 26198282dbSAlp Dener end 27198282dbSAlp Dener end 28198282dbSAlp Dener 29198282dbSAlp Dener if pc_type = BNK_PC_BFGS 30198282dbSAlp Dener B_k = BFGS 31198282dbSAlp Dener else 32198282dbSAlp Dener B_k = VecMedian(1e-6, abs(diag(H_k)), 1e6) 33198282dbSAlp Dener B_k = VecReciprocal(B_k) 34198282dbSAlp Dener end 35198282dbSAlp Dener w = x_k - VecMedian(x_k - 0.001*B_k*g_k) 36198282dbSAlp Dener eps = min(eps, norm2(w)) 37198282dbSAlp Dener determine the active and inactive index sets such that 38198282dbSAlp Dener L = {i : (x_k)_i <= l_i + eps && (g_k)_i > 0} 39198282dbSAlp Dener U = {i : (x_k)_i >= u_i - eps && (g_k)_i < 0} 40198282dbSAlp Dener F = {i : l_i = (x_k)_i = u_i} 41198282dbSAlp Dener A = {L + U + F} 42198282dbSAlp Dener I = {i : i not in A} 43198282dbSAlp Dener 44198282dbSAlp Dener generate the reduced system Hr_k dr_k = -gr_k for variables in I 45198282dbSAlp Dener if pc_type == BNK_PC_BFGS && scale_type == BNK_SCALE_PHESS 46198282dbSAlp Dener D = VecMedian(1e-6, abs(diag(Hr_k)), 1e6) 47198282dbSAlp Dener scale BFGS with VecReciprocal(D) 48198282dbSAlp Dener end 49198282dbSAlp Dener solve Hr_k dr_k = -gr_k 50198282dbSAlp Dener set d_k to (l - x) for variables in L, (u - x) for variables in U, and 0 for variables in F 51198282dbSAlp Dener 52198282dbSAlp Dener x_{k+1} = VecMedian(x_k + d_k) 53198282dbSAlp Dener s = x_{k+1} - x_k 54198282dbSAlp Dener prered = dot(s, 0.5*gr_k - Hr_k*s) 55198282dbSAlp Dener f_{k+1} = TaoComputeObjective(x_{k+1}) 56198282dbSAlp Dener actred = f_k - f_{k+1} 57198282dbSAlp Dener 58198282dbSAlp Dener oldTrust = trust 59198282dbSAlp Dener step_accepted, trust = TaoBNKUpdateTrustRadius(default: BNK_UPDATE_REDUCTION) 60198282dbSAlp Dener if step_accepted 61198282dbSAlp Dener g_{k+1} = TaoComputeGradient(x_{k+1}) 62198282dbSAlp Dener pg_{k+1} = VecBoundGradientProjection(g_{k+1}) 63198282dbSAlp Dener count the accepted Newton step 64198282dbSAlp Dener else 65198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 66198282dbSAlp Dener dr_k = -BFGS*gr_k for variables in I 67198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 68198282dbSAlp Dener reset the BFGS preconditioner 69198282dbSAlp Dener calculate scale delta and apply it to BFGS 70198282dbSAlp Dener dr_k = -BFGS*gr_k for variables in I 71198282dbSAlp Dener if dot(d_k, pg_k)) >= 0 || norm(d_k) == NaN || norm(d_k) == Inf 72198282dbSAlp Dener dr_k = -gr_k for variables in I 73198282dbSAlp Dener end 74198282dbSAlp Dener end 75198282dbSAlp Dener end 76198282dbSAlp Dener 77198282dbSAlp Dener x_{k+1}, f_{k+1}, g_{k+1}, ls_failed = TaoBNKPerformLineSearch() 78198282dbSAlp Dener if ls_failed 79198282dbSAlp Dener f_{k+1} = f_k 80198282dbSAlp Dener x_{k+1} = x_k 81198282dbSAlp Dener g_{k+1} = g_k 82198282dbSAlp Dener pg_{k+1} = pg_k 83198282dbSAlp Dener terminate 84198282dbSAlp Dener else 85198282dbSAlp Dener pg_{k+1} = VecBoundGradientProjection(g_{k+1}) 86198282dbSAlp Dener trust = oldTrust 87198282dbSAlp Dener trust = TaoBNKUpdateTrustRadius(BNK_UPDATE_STEP) 88198282dbSAlp Dener count the accepted step type (Newton, BFGS, scaled grad or grad) 89198282dbSAlp Dener end 90198282dbSAlp Dener end 91198282dbSAlp Dener 92198282dbSAlp Dener check convergence at pg_{k+1} 93198282dbSAlp 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 1039b6ef848SAlp Dener PetscReal resnorm, oldTrust, prered, actred, stepNorm, steplen; 104e031d6f5SAlp Dener PetscBool cgTerminate, 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; 110c0f10754SAlp Dener ierr = TaoBNKInitialize(tao, bnk->init_type, &stepAccepted);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 118e031d6f5SAlp Dener /* Take BNCG steps (if enabled) to trade-off Hessian evaluations for more gradient evaluations */ 119e031d6f5SAlp Dener ierr = TaoBNKTakeCGSteps(tao, &cgTerminate);CHKERRQ(ierr); 120e031d6f5SAlp Dener if (cgTerminate) { 121e031d6f5SAlp Dener tao->reason = bnk->bncg->reason; 122e031d6f5SAlp Dener PetscFunctionReturn(0); 123e031d6f5SAlp Dener } 124e031d6f5SAlp Dener 125*08752603SAlp Dener /* Compute the hessian and update the BFGS preconditioner at the new iterate */ 126*08752603SAlp Dener if (stepAccepted) {ierr = TaoBNKComputeHessian(tao);CHKERRQ(ierr);} 127c14b763aSAlp Dener 1288d5ead36SAlp Dener /* Use the common BNK kernel to compute the Newton step (for inactive variables only) */ 12962675beeSAlp Dener ierr = TaoBNKComputeStep(tao, shift, &ksp_reason);CHKERRQ(ierr); 130c14b763aSAlp Dener 131c14b763aSAlp Dener /* Store current solution before it changes */ 132c14b763aSAlp Dener oldTrust = tao->trust; 133c14b763aSAlp Dener bnk->fold = bnk->f; 134c14b763aSAlp Dener ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr); 135c14b763aSAlp Dener ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr); 136c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr); 137c14b763aSAlp Dener 138c14b763aSAlp Dener /* Temporarily accept the step and project it into the bounds */ 139c14b763aSAlp Dener ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr); 140c14b763aSAlp Dener ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr); 141c14b763aSAlp Dener 142c14b763aSAlp Dener /* Check if the projection changed the step direction */ 143c14b763aSAlp Dener ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 1448d5ead36SAlp Dener ierr = VecAXPY(tao->stepdirection, -1.0, bnk->Xold);CHKERRQ(ierr); 145c14b763aSAlp Dener ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr); 146c14b763aSAlp Dener if (stepNorm != bnk->dnorm) { 1478d5ead36SAlp Dener /* Projection changed the step, so we have to recompute predicted reduction. 1488d5ead36SAlp Dener However, we deliberately do not change the step norm and the trust radius 1498d5ead36SAlp Dener in order for the safeguard to more closely mimic a piece-wise linesearch 1508d5ead36SAlp Dener along the bounds. */ 1515e9b73cbSAlp Dener ierr = TaoBNKRecomputePred(tao, tao->stepdirection, &prered);CHKERRQ(ierr); 152c14b763aSAlp Dener } else { 153c14b763aSAlp Dener /* Step did not change, so we can just recover the pre-computed prediction */ 154c14b763aSAlp Dener ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr); 155c14b763aSAlp Dener } 156c14b763aSAlp Dener prered = -prered; 157c14b763aSAlp Dener 158c14b763aSAlp Dener /* Compute the actual reduction and update the trust radius */ 159c14b763aSAlp Dener ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr); 160c14b763aSAlp Dener actred = bnk->fold - bnk->f; 16128017e9fSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, bnk->update_type, stepType, &stepAccepted);CHKERRQ(ierr); 162c14b763aSAlp Dener 163c14b763aSAlp Dener if (stepAccepted) { 164c14b763aSAlp Dener /* Step is good, evaluate the gradient and the hessian */ 1658d5ead36SAlp Dener steplen = 1.0; 166e465cd6fSAlp Dener ++bnk->newt; 167c14b763aSAlp Dener ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 168c14b763aSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 169c14b763aSAlp Dener } else { 170c14b763aSAlp Dener /* Trust-region rejected the step. Revert the solution. */ 171c14b763aSAlp Dener bnk->f = bnk->fold; 172c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 173c14b763aSAlp Dener 174c14b763aSAlp Dener /* Trigger the line search */ 175e465cd6fSAlp Dener ierr = TaoBNKSafeguardStep(tao, ksp_reason, &stepType);CHKERRQ(ierr); 176c14b763aSAlp Dener ierr = TaoBNKPerformLineSearch(tao, stepType, &steplen, &ls_reason);CHKERRQ(ierr); 177c14b763aSAlp Dener if (ls_reason != TAOLINESEARCH_SUCCESS && ls_reason != TAOLINESEARCH_SUCCESS_USER) { 178c14b763aSAlp Dener /* Line search failed, revert solution and terminate */ 179c0f10754SAlp Dener stepAccepted = PETSC_FALSE; 180c14b763aSAlp Dener bnk->f = bnk->fold; 181c14b763aSAlp Dener ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 182c14b763aSAlp Dener ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr); 183c14b763aSAlp Dener ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr); 184c14b763aSAlp Dener tao->trust = 0.0; 185c14b763aSAlp Dener tao->reason = TAO_DIVERGED_LS_FAILURE; 186c14b763aSAlp Dener } else { 187198282dbSAlp Dener /* compute the projected gradient */ 188198282dbSAlp Dener ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 1899b6ef848SAlp Dener ierr = VecNorm(tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr); 1909b6ef848SAlp Dener if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number"); 191c14b763aSAlp Dener /* Line search succeeded so we should update the trust radius based on the LS step length */ 192770b7498SAlp Dener tao->trust = oldTrust; 19328017e9fSAlp Dener ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, BNK_UPDATE_STEP, stepType, &stepAccepted);CHKERRQ(ierr); 19462675beeSAlp Dener /* count the accepted step type */ 19562675beeSAlp Dener ierr = TaoBNKAddStepCounts(tao, stepType);CHKERRQ(ierr); 196c14b763aSAlp Dener } 197c14b763aSAlp Dener } 198c14b763aSAlp Dener 199c14b763aSAlp Dener /* Check for termination */ 2009b6ef848SAlp Dener ierr = VecFischer(tao->solution, bnk->unprojected_gradient, tao->XL, tao->XU, bnk->Gwork);CHKERRQ(ierr); 2019b6ef848SAlp Dener ierr = VecNorm(bnk->Gwork, NORM_2, &resnorm);CHKERRQ(ierr); 2029b6ef848SAlp Dener ierr = TaoLogConvergenceHistory(tao, bnk->f, resnorm, 0.0, tao->ksp_its);CHKERRQ(ierr); 2039b6ef848SAlp Dener ierr = TaoMonitor(tao, tao->niter, bnk->f, resnorm, 0.0, steplen);CHKERRQ(ierr); 204c14b763aSAlp Dener ierr = (*tao->ops->convergencetest)(tao, tao->cnvP);CHKERRQ(ierr); 205c14b763aSAlp Dener } 206c14b763aSAlp Dener PetscFunctionReturn(0); 207c14b763aSAlp Dener } 208c14b763aSAlp Dener 209df278d8fSAlp Dener /*------------------------------------------------------------*/ 210df278d8fSAlp Dener 2119b6ef848SAlp Dener PETSC_INTERN PetscErrorCode TaoSetUp_BNTL(Tao tao) 2129b6ef848SAlp Dener { 2139b6ef848SAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 2149b6ef848SAlp Dener PetscErrorCode ierr; 2159b6ef848SAlp Dener 2169b6ef848SAlp Dener PetscFunctionBegin; 2179b6ef848SAlp Dener ierr = TaoSetUp_BNK(tao);CHKERRQ(ierr); 2189b6ef848SAlp Dener if (!bnk->is_nash && !bnk->is_stcg && !bnk->is_gltr) SETERRQ(PETSC_COMM_SELF,1,"Must use a trust-region CG method for KSP (KSPNASH, KSPSTCG, KSPGLTR)"); 2199b6ef848SAlp Dener PetscFunctionReturn(0); 2209b6ef848SAlp Dener } 2219b6ef848SAlp Dener 2229b6ef848SAlp Dener /*------------------------------------------------------------*/ 2239b6ef848SAlp Dener 2249b6ef848SAlp Dener PETSC_INTERN PetscErrorCode TaoCreate_BNTL(Tao tao) 225c14b763aSAlp Dener { 226c14b763aSAlp Dener TAO_BNK *bnk; 227c14b763aSAlp Dener PetscErrorCode ierr; 228c14b763aSAlp Dener 229c14b763aSAlp Dener PetscFunctionBegin; 230c14b763aSAlp Dener ierr = TaoCreate_BNK(tao);CHKERRQ(ierr); 231c14b763aSAlp Dener tao->ops->solve=TaoSolve_BNTL; 2329b6ef848SAlp Dener tao->ops->setup=TaoSetUp_BNTL; 233c14b763aSAlp Dener 234c14b763aSAlp Dener bnk = (TAO_BNK *)tao->data; 235c14b763aSAlp Dener bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */ 236c14b763aSAlp Dener PetscFunctionReturn(0); 237c14b763aSAlp Dener }