1 #include <petsctaolinesearch.h> 2 #include <../src/tao/unconstrained/impls/cg/taocg.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 #undef __FUNCT__ 14 #define __FUNCT__ "TaoSolve_CG" 15 static PetscErrorCode TaoSolve_CG(Tao tao) 16 { 17 TAO_CG *cgP = (TAO_CG*)tao->data; 18 PetscErrorCode ierr; 19 TaoConvergedReason reason = TAO_CONTINUE_ITERATING; 20 TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING; 21 PetscReal step=1.0,f,gnorm,gnorm2,delta,gd,ginner,beta; 22 PetscReal gd_old,gnorm2_old,f_old; 23 PetscInt iter=0; 24 25 PetscFunctionBegin; 26 if (tao->XL || tao->XU || tao->ops->computebounds) { 27 ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by cg algorithm\n");CHKERRQ(ierr); 28 } 29 30 /* Check convergence criteria */ 31 ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);CHKERRQ(ierr); 32 ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); 33 if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 34 35 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, step, &reason);CHKERRQ(ierr); 36 if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 37 38 /* Set initial direction to -gradient */ 39 ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr); 40 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 41 gnorm2 = gnorm*gnorm; 42 43 /* Set initial scaling for the function */ 44 if (f != 0.0) { 45 delta = 2.0*PetscAbsScalar(f) / gnorm2; 46 delta = PetscMax(delta,cgP->delta_min); 47 delta = PetscMin(delta,cgP->delta_max); 48 } else { 49 delta = 2.0 / gnorm2; 50 delta = PetscMax(delta,cgP->delta_min); 51 delta = PetscMin(delta,cgP->delta_max); 52 } 53 /* Set counter for gradient and reset steps */ 54 cgP->ngradsteps = 0; 55 cgP->nresetsteps = 0; 56 57 while (1) { 58 /* Save the current gradient information */ 59 f_old = f; 60 gnorm2_old = gnorm2; 61 ierr = VecCopy(tao->solution, cgP->X_old);CHKERRQ(ierr); 62 ierr = VecCopy(tao->gradient, cgP->G_old);CHKERRQ(ierr); 63 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 64 if ((gd >= 0) || PetscIsInfOrNanReal(gd)) { 65 ++cgP->ngradsteps; 66 if (f != 0.0) { 67 delta = 2.0*PetscAbsScalar(f) / gnorm2; 68 delta = PetscMax(delta,cgP->delta_min); 69 delta = PetscMin(delta,cgP->delta_max); 70 } else { 71 delta = 2.0 / gnorm2; 72 delta = PetscMax(delta,cgP->delta_min); 73 delta = PetscMin(delta,cgP->delta_max); 74 } 75 76 ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr); 77 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 78 } 79 80 /* Search direction for improving point */ 81 ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,delta); 82 ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr); 83 ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); 84 if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 85 /* Linesearch failed */ 86 /* Reset factors and use scaled gradient step */ 87 ++cgP->nresetsteps; 88 f = f_old; 89 gnorm2 = gnorm2_old; 90 ierr = VecCopy(cgP->X_old, tao->solution);CHKERRQ(ierr); 91 ierr = VecCopy(cgP->G_old, tao->gradient);CHKERRQ(ierr); 92 93 if (f != 0.0) { 94 delta = 2.0*PetscAbsScalar(f) / gnorm2; 95 delta = PetscMax(delta,cgP->delta_min); 96 delta = PetscMin(delta,cgP->delta_max); 97 } else { 98 delta = 2.0 / gnorm2; 99 delta = PetscMax(delta,cgP->delta_min); 100 delta = PetscMin(delta,cgP->delta_max); 101 } 102 103 ierr = VecCopy(tao->gradient, tao->stepdirection);CHKERRQ(ierr); 104 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 105 106 ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,delta); 107 ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr); 108 ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); 109 110 if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) { 111 /* Linesearch failed again */ 112 /* switch to unscaled gradient */ 113 f = f_old; 114 gnorm2 = gnorm2_old; 115 ierr = VecCopy(cgP->X_old, tao->solution);CHKERRQ(ierr); 116 ierr = VecCopy(cgP->G_old, tao->gradient);CHKERRQ(ierr); 117 delta = 1.0; 118 ierr = VecCopy(tao->solution, tao->stepdirection);CHKERRQ(ierr); 119 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 120 121 ierr = TaoLineSearchSetInitialStepLength(tao->linesearch,delta); 122 ierr = TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, tao->stepdirection, &step, &ls_status);CHKERRQ(ierr); 123 ierr = TaoAddLineSearchCounts(tao);CHKERRQ(ierr); 124 if (ls_status != TAOLINESEARCH_SUCCESS && 125 ls_status != TAOLINESEARCH_SUCCESS_USER) { 126 127 /* Line search failed for last time -- give up */ 128 f = f_old; 129 gnorm2 = gnorm2_old; 130 ierr = VecCopy(cgP->X_old, tao->solution);CHKERRQ(ierr); 131 ierr = VecCopy(cgP->G_old, tao->gradient);CHKERRQ(ierr); 132 step = 0.0; 133 reason = TAO_DIVERGED_LS_FAILURE; 134 tao->reason = TAO_DIVERGED_LS_FAILURE; 135 } 136 } 137 } 138 139 /* Check for bad value */ 140 ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); 141 if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1,"User-provided compute function generated Inf or NaN"); 142 143 /* Check for termination */ 144 gnorm2 =gnorm * gnorm; 145 iter++; 146 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, step, &reason);CHKERRQ(ierr); 147 if (reason != TAO_CONTINUE_ITERATING) { 148 break; 149 } 150 151 /* Check for restart condition */ 152 ierr = VecDot(tao->gradient, cgP->G_old, &ginner);CHKERRQ(ierr); 153 if (PetscAbsScalar(ginner) >= cgP->eta * gnorm2) { 154 /* Gradients far from orthognal; use steepest descent direction */ 155 beta = 0.0; 156 } else { 157 /* Gradients close to orthogonal; use conjugate gradient formula */ 158 switch (cgP->cg_type) { 159 case CG_FletcherReeves: 160 beta = gnorm2 / gnorm2_old; 161 break; 162 163 case CG_PolakRibiere: 164 beta = (gnorm2 - ginner) / gnorm2_old; 165 break; 166 167 case CG_PolakRibierePlus: 168 beta = PetscMax((gnorm2-ginner)/gnorm2_old, 0.0); 169 break; 170 171 case CG_HestenesStiefel: 172 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 173 ierr = VecDot(cgP->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr); 174 beta = (gnorm2 - ginner) / (gd - gd_old); 175 break; 176 177 case CG_DaiYuan: 178 ierr = VecDot(tao->gradient, tao->stepdirection, &gd);CHKERRQ(ierr); 179 ierr = VecDot(cgP->G_old, tao->stepdirection, &gd_old);CHKERRQ(ierr); 180 beta = gnorm2 / (gd - gd_old); 181 break; 182 183 default: 184 beta = 0.0; 185 break; 186 } 187 } 188 189 /* Compute the direction d=-g + beta*d */ 190 ierr = VecAXPBY(tao->stepdirection, -1.0, beta, tao->gradient);CHKERRQ(ierr); 191 192 /* update initial steplength choice */ 193 delta = 1.0; 194 delta = PetscMax(delta, cgP->delta_min); 195 delta = PetscMin(delta, cgP->delta_max); 196 } 197 PetscFunctionReturn(0); 198 } 199 200 #undef __FUNCT__ 201 #define __FUNCT__ "TaoSetUp_CG" 202 static PetscErrorCode TaoSetUp_CG(Tao tao) 203 { 204 TAO_CG *cgP = (TAO_CG*)tao->data; 205 PetscErrorCode ierr; 206 207 PetscFunctionBegin; 208 if (!tao->gradient) {ierr = VecDuplicate(tao->solution,&tao->gradient);CHKERRQ(ierr);} 209 if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution,&tao->stepdirection);CHKERRQ(ierr); } 210 if (!cgP->X_old) {ierr = VecDuplicate(tao->solution,&cgP->X_old);CHKERRQ(ierr);} 211 if (!cgP->G_old) {ierr = VecDuplicate(tao->gradient,&cgP->G_old);CHKERRQ(ierr); } 212 PetscFunctionReturn(0); 213 } 214 215 #undef __FUNCT__ 216 #define __FUNCT__ "TaoDestroy_CG" 217 static PetscErrorCode TaoDestroy_CG(Tao tao) 218 { 219 TAO_CG *cgP = (TAO_CG*) tao->data; 220 PetscErrorCode ierr; 221 222 PetscFunctionBegin; 223 if (tao->setupcalled) { 224 ierr = VecDestroy(&cgP->X_old);CHKERRQ(ierr); 225 ierr = VecDestroy(&cgP->G_old);CHKERRQ(ierr); 226 } 227 ierr = TaoLineSearchDestroy(&tao->linesearch);CHKERRQ(ierr); 228 ierr = PetscFree(tao->data);CHKERRQ(ierr); 229 PetscFunctionReturn(0); 230 } 231 232 #undef __FUNCT__ 233 #define __FUNCT__ "TaoSetFromOptions_CG" 234 static PetscErrorCode TaoSetFromOptions_CG(Tao tao) 235 { 236 TAO_CG *cgP = (TAO_CG*)tao->data; 237 PetscErrorCode ierr; 238 239 PetscFunctionBegin; 240 ierr = TaoLineSearchSetFromOptions(tao->linesearch);CHKERRQ(ierr); 241 ierr = PetscOptionsHead("Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(ierr); 242 ierr = PetscOptionsReal("-tao_cg_eta","restart tolerance", "", cgP->eta,&cgP->eta,0);CHKERRQ(ierr); 243 ierr = PetscOptionsEList("-tao_cg_type","cg formula", "", CG_Table, CG_Types, CG_Table[cgP->cg_type], &cgP->cg_type, 0);CHKERRQ(ierr); 244 ierr = PetscOptionsReal("-tao_cg_delta_min","minimum delta value", "", cgP->delta_min,&cgP->delta_min,0);CHKERRQ(ierr); 245 ierr = PetscOptionsReal("-tao_cg_delta_max","maximum delta value", "", cgP->delta_max,&cgP->delta_max,0);CHKERRQ(ierr); 246 ierr = PetscOptionsTail();CHKERRQ(ierr); 247 PetscFunctionReturn(0); 248 } 249 250 #undef __FUNCT__ 251 #define __FUNCT__ "TaoView_CG" 252 static PetscErrorCode TaoView_CG(Tao tao, PetscViewer viewer) 253 { 254 PetscBool isascii; 255 TAO_CG *cgP = (TAO_CG*)tao->data; 256 PetscErrorCode ierr; 257 258 PetscFunctionBegin; 259 ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr); 260 if (isascii) { 261 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 262 ierr = PetscViewerASCIIPrintf(viewer, "CG Type: %s\n", CG_Table[cgP->cg_type]);CHKERRQ(ierr); 263 ierr = PetscViewerASCIIPrintf(viewer, "Gradient steps: %D\n", cgP->ngradsteps);CHKERRQ(ierr); 264 ierr= PetscViewerASCIIPrintf(viewer, "Reset steps: %D\n", cgP->nresetsteps);CHKERRQ(ierr); 265 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 266 } 267 PetscFunctionReturn(0); 268 } 269 270 271 EXTERN_C_BEGIN 272 #undef __FUNCT__ 273 #define __FUNCT__ "TaoCreate_CG" 274 PetscErrorCode TaoCreate_CG(Tao tao) 275 { 276 TAO_CG *cgP; 277 const char *morethuente_type = TAOLINESEARCH_MT; 278 PetscErrorCode ierr; 279 280 PetscFunctionBegin; 281 tao->ops->setup = TaoSetUp_CG; 282 tao->ops->solve = TaoSolve_CG; 283 tao->ops->view = TaoView_CG; 284 tao->ops->setfromoptions = TaoSetFromOptions_CG; 285 tao->ops->destroy = TaoDestroy_CG; 286 287 tao->max_it = 2000; 288 tao->max_funcs = 4000; 289 tao->fatol = 1e-4; 290 tao->frtol = 1e-4; 291 292 /* Note: nondefault values should be used for nonlinear conjugate gradient */ 293 /* method. In particular, gtol should be less that 0.5; the value used in */ 294 /* Nocedal and Wright is 0.10. We use the default values for the */ 295 /* linesearch because it seems to work better. */ 296 ierr = TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch);CHKERRQ(ierr); 297 ierr = TaoLineSearchSetType(tao->linesearch, morethuente_type);CHKERRQ(ierr); 298 ierr = TaoLineSearchUseTaoRoutines(tao->linesearch, tao);CHKERRQ(ierr); 299 300 ierr = PetscNewLog(tao,&cgP);CHKERRQ(ierr); 301 tao->data = (void*)cgP; 302 cgP->eta = 0.1; 303 cgP->delta_min = 1e-7; 304 cgP->delta_max = 100; 305 cgP->cg_type = CG_PolakRibierePlus; 306 PetscFunctionReturn(0); 307 } 308 EXTERN_C_END 309