1 #include <../src/tao/bound/impls/bnk/bnk.h> 2 #include <petscksp.h> 3 4 /* 5 Implements Newton's Method with a trust region approach for solving 6 bound constrained minimization problems. 7 8 The linear system solve should be done with a conjugate gradient 9 method, although any method can be used. 10 */ 11 12 static PetscErrorCode TaoSolve_BNTR(Tao tao) 13 { 14 PetscErrorCode ierr; 15 TAO_BNK *bnk = (TAO_BNK *)tao->data; 16 17 PetscReal oldTrust, prered, actred, stepNorm; 18 PetscBool stepAccepted = PETSC_TRUE; 19 PetscInt stepType; 20 21 PetscFunctionBegin; 22 /* Project the current point onto the feasible set */ 23 ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr); 24 ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr); 25 26 /* Project the initial point onto the feasible region */ 27 ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr); 28 29 /* Check convergence criteria */ 30 ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &bnk->f, bnk->unprojected_gradient);CHKERRQ(ierr); 31 ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 32 ierr = TaoGradientNorm(tao, tao->gradient,NORM_2,&bnk->gnorm);CHKERRQ(ierr); 33 if (PetscIsInfOrNanReal(bnk->f) || PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 34 35 tao->reason = TAO_CONTINUE_ITERATING; 36 ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr); 37 ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr); 38 ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 39 if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 40 41 /* Initialize the preconditioner and trust radius */ 42 ierr = TaoBNKInitialize(tao);CHKERRQ(ierr); 43 44 /* Have not converged; continue with Newton method */ 45 while (tao->reason == TAO_CONTINUE_ITERATING) { 46 47 if (stepAccepted) { 48 tao->niter++; 49 tao->ksp_its=0; 50 /* Compute the Hessian */ 51 ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); 52 /* Update the BFGS preconditioner */ 53 if (BNK_PC_BFGS == bnk->pc_type) { 54 if (BFGS_SCALE_PHESS == bnk->bfgs_scale_type) { 55 /* Obtain diagonal for the bfgs preconditioner */ 56 ierr = MatGetDiagonal(tao->hessian, bnk->Diag);CHKERRQ(ierr); 57 ierr = VecAbs(bnk->Diag);CHKERRQ(ierr); 58 ierr = VecReciprocal(bnk->Diag);CHKERRQ(ierr); 59 ierr = MatLMVMSetScale(bnk->M,bnk->Diag);CHKERRQ(ierr); 60 } 61 /* Update the limited memory preconditioner and get existing # of updates */ 62 ierr = MatLMVMUpdate(bnk->M, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 63 } 64 } 65 66 /* Use the common BNK kernel to compute the raw Newton step */ 67 ierr = TaoBNKComputeStep(tao, PETSC_FALSE, &stepType);CHKERRQ(ierr); 68 69 /* Store current solution before it changes */ 70 oldTrust = tao->trust; 71 bnk->fold = bnk->f; 72 ierr = VecCopy(tao->solution, bnk->Xold);CHKERRQ(ierr); 73 ierr = VecCopy(tao->gradient, bnk->Gold);CHKERRQ(ierr); 74 ierr = VecCopy(bnk->unprojected_gradient, bnk->unprojected_gradient_old);CHKERRQ(ierr); 75 76 /* Temporarily accept the step and project it into the bounds */ 77 ierr = VecAXPY(tao->solution, 1.0, tao->stepdirection);CHKERRQ(ierr); 78 ierr = VecMedian(tao->XL, tao->solution, tao->XU, tao->solution);CHKERRQ(ierr); 79 80 /* Check if the projection changed the step direction */ 81 ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 82 ierr = VecAXPBY(tao->stepdirection, -1.0, 1.0, bnk->Xold);CHKERRQ(ierr); 83 ierr = VecNorm(tao->stepdirection, NORM_2, &stepNorm);CHKERRQ(ierr); 84 if (stepNorm != bnk->dnorm) { 85 /* Projection changed the step, so we have to adjust trust radius and recompute predicted reduction */ 86 bnk->dnorm = stepNorm; 87 tao->trust = bnk->dnorm; 88 ierr = MatMult(tao->hessian, tao->stepdirection, bnk->Xwork);CHKERRQ(ierr); 89 ierr = VecAYPX(bnk->Xwork, -0.5, tao->gradient);CHKERRQ(ierr); 90 ierr = VecDot(bnk->Xwork, tao->stepdirection, &prered); 91 } else { 92 /* Step did not change, so we can just recover the pre-computed prediction */ 93 ierr = KSPCGGetObjFcn(tao->ksp, &prered);CHKERRQ(ierr); 94 } 95 prered = -prered; 96 97 /* Compute the actual reduction and update the trust radius */ 98 ierr = TaoComputeObjective(tao, tao->solution, &bnk->f);CHKERRQ(ierr); 99 actred = bnk->fold - bnk->f; 100 ierr = TaoBNKUpdateTrustRadius(tao, prered, actred, stepType, &stepAccepted);CHKERRQ(ierr); 101 102 if (stepAccepted) { 103 /* Step is good, evaluate the gradient and the hessian */ 104 ierr = TaoComputeGradient(tao, tao->solution, bnk->unprojected_gradient);CHKERRQ(ierr); 105 ierr = VecBoundGradientProjection(bnk->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 106 } else { 107 /* Step is bad, revert old solution and re-solve with new radius*/ 108 bnk->f = bnk->fold; 109 ierr = VecCopy(bnk->Xold, tao->solution);CHKERRQ(ierr); 110 ierr = VecCopy(bnk->Gold, tao->gradient);CHKERRQ(ierr); 111 ierr = VecCopy(bnk->unprojected_gradient_old, bnk->unprojected_gradient);CHKERRQ(ierr); 112 if (oldTrust == tao->trust) { 113 /* Can't change the radius anymore so just terminate */ 114 tao->reason = TAO_DIVERGED_TR_REDUCTION; 115 } 116 } 117 118 /* Check for termination */ 119 ierr = TaoGradientNorm(tao, tao->gradient, NORM_2, &bnk->gnorm);CHKERRQ(ierr); 120 if (PetscIsInfOrNanReal(bnk->gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User provided compute function generated Not-a-Number"); 121 ierr = TaoLogConvergenceHistory(tao,bnk->f,bnk->gnorm,0.0,tao->ksp_its);CHKERRQ(ierr); 122 ierr = TaoMonitor(tao,tao->niter,bnk->f,bnk->gnorm,0.0,tao->trust);CHKERRQ(ierr); 123 ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 124 } 125 PetscFunctionReturn(0); 126 } 127 128 PETSC_EXTERN PetscErrorCode TaoCreate_BNTR(Tao tao) 129 { 130 TAO_BNK *bnk; 131 PetscErrorCode ierr; 132 133 PetscFunctionBegin; 134 ierr = TaoCreate_BNK(tao);CHKERRQ(ierr); 135 tao->ops->solve=TaoSolve_BNTR; 136 137 bnk = (TAO_BNK *)tao->data; 138 bnk->update_type = BNK_UPDATE_REDUCTION; /* trust region updates based on predicted/actual reduction */ 139 bnk->sval = 0.0; /* disable Hessian shifting */ 140 PetscFunctionReturn(0); 141 }