1 #include <petsctaolinesearch.h> 2 #include <../src/tao/bound/impls/bncg/bncg.h> 3 4 #define CG_FletcherReeves 0 5 #define CG_PolakRibiere 1 6 #define CG_PolakRibierePlus 2 7 #define CG_HestenesStiefel 3 8 #define CG_DaiYuan 4 9 #define CG_Types 5 10 11 static const char *CG_Table[64] = {"fr", "pr", "prp", "hs", "dy"}; 12 13 PetscErrorCode TaoBNCGResetStepForNewInactives(Tao tao, Vec step) 14 { 15 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 16 PetscErrorCode ierr; 17 const PetscScalar *xl, *xo, *xn, *xu, *gn, *go; 18 PetscInt size, i; 19 PetscScalar *s; 20 21 PetscFunctionBegin; 22 ierr = VecGetLocalSize(tao->solution, &size);CHKERRQ(ierr); 23 ierr = VecGetArrayRead(cg->unprojected_gradient_old, &go);CHKERRQ(ierr); 24 ierr = VecGetArrayRead(cg->unprojected_gradient, &gn);CHKERRQ(ierr); 25 ierr = VecGetArrayRead(cg->X_old, &xo);CHKERRQ(ierr); 26 ierr = VecGetArrayRead(tao->solution, &xn);CHKERRQ(ierr); 27 ierr = VecGetArrayRead(tao->XL, &xl);CHKERRQ(ierr); 28 ierr = VecGetArrayRead(tao->XU, &xu);CHKERRQ(ierr); 29 ierr = VecGetArray(step, &s);CHKERRQ(ierr); 30 for (i=0; i<size; i++) { 31 if (xl[i] == xu[i]) { 32 s[i] = 0.0; 33 } else { 34 if (xl[i] > PETSC_NINFINITY) { 35 if ((xn[i] == xl[i] && gn[i] < 0.0) && (xo[i] == xl[i] && go[i] >= 0.0)) { 36 s[i] = -gn[i]; 37 } 38 } 39 if (xu[i] < PETSC_NINFINITY) { 40 if ((xn[i] == xu[i] && gn[i] > 0.0) && (xo[i] == xu[i] && go[i] <= 0.0)) { 41 s[i] = -gn[i]; 42 } 43 } 44 } 45 } 46 ierr = VecRestoreArrayRead(cg->unprojected_gradient_old, &go);CHKERRQ(ierr); 47 ierr = VecRestoreArrayRead(cg->unprojected_gradient, &gn);CHKERRQ(ierr); 48 ierr = VecRestoreArrayRead(cg->X_old, &xo);CHKERRQ(ierr); 49 ierr = VecRestoreArrayRead(tao->solution, &xn);CHKERRQ(ierr); 50 ierr = VecRestoreArrayRead(tao->XL, &xl);CHKERRQ(ierr); 51 ierr = VecRestoreArrayRead(tao->XU, &xu);CHKERRQ(ierr); 52 ierr = VecRestoreArray(step, &s);CHKERRQ(ierr); 53 PetscFunctionReturn(0); 54 } 55 56 PetscErrorCode TaoBNCGSetRecycleFlag(Tao tao, PetscBool recycle) 57 { 58 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 59 60 PetscFunctionBegin; 61 cg->recycle = recycle; 62 PetscFunctionReturn(0); 63 } 64 65 static PetscErrorCode TaoSolve_BNCG(Tao tao) 66 { 67 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 68 PetscErrorCode ierr; 69 TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 70 PetscReal step=1.0,gnorm,gnorm2,delta,gd,ginner,beta,dnorm; 71 PetscReal gd_old,gnorm2_old,f_old; 72 PetscBool cg_restart; 73 74 PetscFunctionBegin; 75 /* Project the current point onto the feasible set */ 76 ierr = TaoComputeVariableBounds(tao);CHKERRQ(ierr); 77 ierr = TaoLineSearchSetVariableBounds(tao->linesearch,tao->XL,tao->XU);CHKERRQ(ierr); 78 79 /* Project the initial point onto the feasible region */ 80 ierr = VecMedian(tao->XL,tao->solution,tao->XU,tao->solution);CHKERRQ(ierr); 81 82 /* Compute the objective function and criteria */ 83 if (!cg->recycle) { 84 ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &cg->f, cg->unprojected_gradient);CHKERRQ(ierr); 85 } 86 ierr = VecNorm(cg->unprojected_gradient,NORM_2,&gnorm);CHKERRQ(ierr); 87 if (PetscIsInfOrNanReal(cg->f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 88 89 /* Project the gradient and calculate the norm */ 90 ierr = VecBoundGradientProjection(cg->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 91 ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); 92 gnorm2 = gnorm*gnorm; 93 94 /* Convergence check */ 95 tao->niter = 0; 96 tao->reason = TAO_CONTINUE_ITERATING; 97 ierr = TaoLogConvergenceHistory(tao, cg->f, gnorm, 0.0, tao->ksp_its);CHKERRQ(ierr); 98 ierr = TaoMonitor(tao, tao->niter, cg->f, gnorm, 0.0, step);CHKERRQ(ierr); 99 ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 100 if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 101 102 /* Start optimization iterations */ 103 f_old = cg->f; 104 gnorm2_old = gnorm2; 105 ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr); 106 ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr); 107 ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr); 108 cg->ls_fails = cg->broken_ortho = cg->descent_error = 0; 109 cg->resets = -1; 110 while (tao->reason == TAO_CONTINUE_ITERATING) { 111 /* Check restart conditions for using steepest descent */ 112 cg_restart = PETSC_FALSE; 113 ierr = VecDot(tao->gradient, cg->G_old, &ginner);CHKERRQ(ierr); 114 ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm);CHKERRQ(ierr); 115 if (tao->niter == 0 && !cg->recycle && dnorm != 0.0) { 116 /* 1) First iteration, with recycle disabled, and a non-zero previous step */ 117 cg_restart = PETSC_TRUE; 118 } else if (PetscAbsScalar(ginner) >= cg->eta * gnorm2) { 119 /* 2) Gradients are far from orthogonal */ 120 cg_restart = PETSC_TRUE; 121 cg->broken_ortho++; 122 } 123 124 /* Compute CG step */ 125 if (cg_restart) { 126 beta = 0.0; 127 cg->resets++; 128 } else { 129 switch (cg->cg_type) { 130 case CG_FletcherReeves: 131 beta = gnorm2 / gnorm2_old; 132 break; 133 134 case CG_PolakRibiere: 135 beta = (gnorm2 - ginner) / gnorm2_old; 136 break; 137 138 case CG_PolakRibierePlus: 139 beta = PetscMax((gnorm2-ginner)/gnorm2_old, 0.0); 140 break; 141 142 case CG_HestenesStiefel: 143 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 144 ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr); 145 beta = (gnorm2 - ginner) / (gd - gd_old); 146 break; 147 148 case CG_DaiYuan: 149 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 150 ierr = VecDot(cg->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr); 151 beta = gnorm2 / (gd - gd_old); 152 break; 153 154 default: 155 beta = 0.0; 156 break; 157 } 158 } 159 160 /* Compute the direction d=-g + beta*d */ 161 ierr = VecAXPBY(tao->stepdirection, -1.0, beta, tao->gradient);CHKERRQ(ierr); 162 ierr = TaoBNCGResetStepForNewInactives(tao, tao->stepdirection);CHKERRQ(ierr); 163 164 /* Verify that this is a descent direction */ 165 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 166 ierr = VecNorm(tao->stepdirection, NORM_2, &dnorm); 167 if (gd > -cg->rho*PetscPowReal(dnorm, cg->pow)) { 168 /* Not a descent direction, so we reset back to projected gradient descent */ 169 ierr = VecAXPBY(tao->stepdirection, -1.0, 0.0, tao->gradient);CHKERRQ(ierr); 170 cg->resets++; 171 cg->descent_error++; 172 } 173 174 /* update initial steplength choice */ 175 delta = 1.0; 176 delta = PetscMax(delta, cg->delta_min); 177 delta = PetscMin(delta, cg->delta_max); 178 179 /* Store solution and gradient info before it changes */ 180 ierr = VecCopy(tao->solution, cg->X_old);CHKERRQ(ierr); 181 ierr = VecCopy(tao->gradient, cg->G_old);CHKERRQ(ierr); 182 ierr = VecCopy(cg->unprojected_gradient, cg->unprojected_gradient_old);CHKERRQ(ierr); 183 gnorm2_old = gnorm2; 184 f_old = cg->f; 185 186 /* Perform bounded line search */ 187 ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,delta);CHKERRQ(ierr); 188 ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr); 189 ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); 190 191 /* Check linesearch failure */ 192 if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 193 cg->ls_fails++; 194 /* Restore previous point */ 195 gnorm2 = gnorm2_old; 196 cg->f = f_old; 197 ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr); 198 ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr); 199 ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr); 200 201 /* Fall back on the unscaled gradient step */ 202 delta = 1.0; 203 ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 204 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 205 206 ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,delta);CHKERRQ(ierr); 207 ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &cg->f, cg->unprojected_gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr); 208 ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); 209 210 if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER){ 211 cg->ls_fails++; 212 /* Restore previous point */ 213 gnorm2 = gnorm2_old; 214 cg->f = f_old; 215 ierr = VecCopy(cg->X_old, tao->solution);CHKERRQ(ierr); 216 ierr = VecCopy(cg->G_old, tao->gradient);CHKERRQ(ierr); 217 ierr = VecCopy(cg->unprojected_gradient_old, cg->unprojected_gradient);CHKERRQ(ierr); 218 219 /* Nothing left to do but fail out of the optimization */ 220 step = 0.0; 221 tao->reason = TAO_DIVERGED_LS_FAILURE; 222 } 223 } 224 225 /* Compute the projected gradient and its norm */ 226 ierr = VecBoundGradientProjection(cg->unprojected_gradient,tao->solution,tao->XL,tao->XU,tao->gradient);CHKERRQ(ierr); 227 ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); 228 gnorm2 = gnorm*gnorm; 229 230 /* Convergence test */ 231 tao->niter++; 232 ierr = TaoLogConvergenceHistory(tao, cg->f, gnorm, 0.0, tao->ksp_its);CHKERRQ(ierr); 233 ierr = TaoMonitor(tao, tao->niter, cg->f, gnorm, 0.0, step);CHKERRQ(ierr); 234 ierr = (*tao->ops->convergencetest)(tao,tao->cnvP);CHKERRQ(ierr); 235 } 236 PetscFunctionReturn(0); 237 } 238 239 static PetscErrorCode TaoSetUp_BNCG(Tao tao) 240 { 241 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 242 PetscErrorCode ierr; 243 244 PetscFunctionBegin; 245 if (!tao->gradient) {ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);} 246 if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr); } 247 if (!cg->X_old) {ierr = VecDuplicate(tao->solution,&cg->X_old);CHKERRQ(ierr);} 248 if (!cg->G_old) {ierr = VecDuplicate(tao->gradient,&cg->G_old);CHKERRQ(ierr); } 249 if (!cg->unprojected_gradient) {ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient);CHKERRQ(ierr);} 250 if (!cg->unprojected_gradient_old) {ierr = VecDuplicate(tao->gradient,&cg->unprojected_gradient_old);CHKERRQ(ierr);} 251 PetscFunctionReturn(0); 252 } 253 254 static PetscErrorCode TaoDestroy_BNCG(Tao tao) 255 { 256 TAO_BNCG *cg = (TAO_BNCG*) tao->data; 257 PetscErrorCode ierr; 258 259 PetscFunctionBegin; 260 if (tao->setupcalled) { 261 ierr = VecDestroy(&cg->X_old);CHKERRQ(ierr); 262 ierr = VecDestroy(&cg->G_old);CHKERRQ(ierr); 263 ierr = VecDestroy(&cg->unprojected_gradient);CHKERRQ(ierr); 264 ierr = VecDestroy(&cg->unprojected_gradient_old);CHKERRQ(ierr); 265 } 266 ierr = PetscFree(tao->data);CHKERRQ(ierr); 267 PetscFunctionReturn(0); 268 } 269 270 static PetscErrorCode TaoSetFromOptions_BNCG(PetscOptionItems *PetscOptionsObject,Tao tao) 271 { 272 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 273 PetscErrorCode ierr; 274 275 PetscFunctionBegin; 276 ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr); 277 ierr = PetscOptionsHead(PetscOptionsObject,"Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr); 278 ierr = PetscOptionsReal("-tao_BNCG_eta","restart tolerance", "", cg->eta,&cg->eta,NULL);CHKERRQ(ierr); 279 ierr = PetscOptionsReal("-tao_BNCG_rho","descent direction tolerance", "", cg->rho,&cg->rho,NULL);CHKERRQ(ierr); 280 ierr = PetscOptionsReal("-tao_BNCG_pow","descent direction exponent", "", cg->pow,&cg->pow,NULL);CHKERRQ(ierr); 281 ierr = PetscOptionsEList("-tao_BNCG_type","cg formula", "", CG_Table, CG_Types, CG_Table[cg->cg_type], &cg->cg_type,NULL);CHKERRQ(ierr); 282 ierr = PetscOptionsReal("-tao_BNCG_delta_min","minimum delta value", "", cg->delta_min,&cg->delta_min,NULL);CHKERRQ(ierr); 283 ierr = PetscOptionsReal("-tao_BNCG_delta_max","maximum delta value", "", cg->delta_max,&cg->delta_max,NULL);CHKERRQ(ierr); 284 ierr = PetscOptionsBool("-tao_BNCG_recycle","enable recycling the existing solution and gradient at the start of a new solve","",cg->recycle,&cg->recycle,NULL);CHKERRQ(ierr); 285 ierr = PetscOptionsTail();CHKERRQ(ierr); 286 PetscFunctionReturn(0); 287 } 288 289 static PetscErrorCode TaoView_BNCG(Tao tao, PetscViewer viewer) 290 { 291 PetscBool isascii; 292 TAO_BNCG *cg = (TAO_BNCG*)tao->data; 293 PetscErrorCode ierr; 294 295 PetscFunctionBegin; 296 ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr); 297 if (isascii) { 298 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 299 ierr = PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cg->cg_type]);CHKERRQ(ierr); 300 ierr = PetscViewerASCIIPrintf(viewer, "Resets: %i\n", cg->resets);CHKERRQ(ierr); 301 ierr = PetscViewerASCIIPrintf(viewer, " Broken ortho: %i\n", cg->broken_ortho);CHKERRQ(ierr); 302 ierr = PetscViewerASCIIPrintf(viewer, " Not a descent dir.: %i\n", cg->descent_error);CHKERRQ(ierr); 303 ierr = PetscViewerASCIIPrintf(viewer, "Line search fails: %i\n", cg->ls_fails);CHKERRQ(ierr); 304 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 305 } 306 PetscFunctionReturn(0); 307 } 308 309 /*MC 310 TAOBNCG - Bound-constrained Nonlinear Conjugate Gradient method. 311 312 Options Database Keys: 313 + -tao_BNCG_eta <r> - restart tolerance 314 . -tao_BNCG_type <taocg_type> - cg formula 315 . -tao_BNCG_delta_min <r> - minimum delta value 316 - -tao_BNCG_delta_max <r> - maximum delta value 317 318 Notes: 319 CG formulas are: 320 "fr" - Fletcher-Reeves 321 "pr" - Polak-Ribiere 322 "prp" - Polak-Ribiere-Plus 323 "hs" - Hestenes-Steifel 324 "dy" - Dai-Yuan 325 Level: beginner 326 M*/ 327 328 329 PETSC_EXTERN PetscErrorCode TaoCreate_BNCG(Tao tao) 330 { 331 TAO_BNCG *cg; 332 const char *morethuente_type = TAOLINESEARCHMT; 333 PetscErrorCode ierr; 334 335 PetscFunctionBegin; 336 tao->ops->setup = TaoSetUp_BNCG; 337 tao->ops->solve = TaoSolve_BNCG; 338 tao->ops->view = TaoView_BNCG; 339 tao->ops->setfromoptions = TaoSetFromOptions_BNCG; 340 tao->ops->destroy = TaoDestroy_BNCG; 341 342 /* Override default settings (unless already changed) */ 343 if (!tao->max_it_changed) tao->max_it = 2000; 344 if (!tao->max_funcs_changed) tao->max_funcs = 4000; 345 346 /* Note: nondefault values should be used for nonlinear conjugate gradient */ 347 /* method. In particular, gtol should be less that 0.5; the value used in */ 348 /* Nocedal and Wright is 0.10. We use the default values for the */ 349 /* linesearch because it seems to work better. */ 350 ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr); 351 ierr = PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1);CHKERRQ(ierr); 352 ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr); 353 ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr); 354 ierr = TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix);CHKERRQ(ierr); 355 356 ierr = PetscNewLog(tao,&cg);CHKERRQ(ierr); 357 tao->data = (void*)cg; 358 cg->rho = 1e-4; 359 cg->pow = 2.1; 360 cg->eta = 0.5; 361 cg->delta_min = 1e-7; 362 cg->delta_max = 100; 363 cg->cg_type = CG_DaiYuan; 364 cg->recycle = PETSC_FALSE; 365 PetscFunctionReturn(0); 366 } 367