1 #include <../src/tao/matrix/lmvmmat.h> 2 #include <../src/tao/unconstrained/impls/ntr/ntr.h> 3 4 #include <petscksp.h> 5 #include <petscpc.h> 6 #include <petsc-private/kspimpl.h> 7 #include <petsc-private/pcimpl.h> 8 9 #define NTR_KSP_NASH 0 10 #define NTR_KSP_STCG 1 11 #define NTR_KSP_GLTR 2 12 #define NTR_KSP_TYPES 3 13 14 #define NTR_PC_NONE 0 15 #define NTR_PC_AHESS 1 16 #define NTR_PC_BFGS 2 17 #define NTR_PC_PETSC 3 18 #define NTR_PC_TYPES 4 19 20 #define BFGS_SCALE_AHESS 0 21 #define BFGS_SCALE_BFGS 1 22 #define BFGS_SCALE_TYPES 2 23 24 #define NTR_INIT_CONSTANT 0 25 #define NTR_INIT_DIRECTION 1 26 #define NTR_INIT_INTERPOLATION 2 27 #define NTR_INIT_TYPES 3 28 29 #define NTR_UPDATE_REDUCTION 0 30 #define NTR_UPDATE_INTERPOLATION 1 31 #define NTR_UPDATE_TYPES 2 32 33 static const char *NTR_KSP[64] = { "nash", "stcg", "gltr"}; 34 35 static const char *NTR_PC[64] = { "none", "ahess", "bfgs", "petsc"}; 36 37 static const char *BFGS_SCALE[64] = { "ahess", "bfgs"}; 38 39 static const char *NTR_INIT[64] = { "constant", "direction", "interpolation"}; 40 41 static const char *NTR_UPDATE[64] = { "reduction", "interpolation"}; 42 43 /* Routine for BFGS preconditioner */ 44 static PetscErrorCode MatLMVMSolveShell(PC pc, Vec xin, Vec xout); 45 46 /* 47 TaoSolve_NTR - Implements Newton's Method with a trust region approach 48 for solving unconstrained minimization problems. 49 50 The basic algorithm is taken from MINPACK-2 (dstrn). 51 52 TaoSolve_NTR computes a local minimizer of a twice differentiable function 53 f by applying a trust region variant of Newton's method. At each stage 54 of the algorithm, we use the prconditioned conjugate gradient method to 55 determine an approximate minimizer of the quadratic equation 56 57 q(s) = <s, Hs + g> 58 59 subject to the trust region constraint 60 61 || s ||_M <= radius, 62 63 where radius is the trust region radius and M is a symmetric positive 64 definite matrix (the preconditioner). Here g is the gradient and H 65 is the Hessian matrix. 66 67 Note: TaoSolve_NTR MUST use the iterative solver KSPNASH, KSPSTCG, 68 or KSPGLTR. Thus, we set KSPNASH, KSPSTCG, or KSPGLTR in this 69 routine regardless of what the user may have previously specified. 70 */ 71 #undef __FUNCT__ 72 #define __FUNCT__ "TaoSolve_NTR" 73 static PetscErrorCode TaoSolve_NTR(Tao tao) 74 { 75 TAO_NTR *tr = (TAO_NTR *)tao->data; 76 PC pc; 77 KSPConvergedReason ksp_reason; 78 TaoConvergedReason reason; 79 PetscReal fmin, ftrial, prered, actred, kappa, sigma, beta; 80 PetscReal tau, tau_1, tau_2, tau_max, tau_min, max_radius; 81 PetscReal f, gnorm; 82 83 PetscReal delta; 84 PetscReal norm_d; 85 PetscErrorCode ierr; 86 PetscInt iter = 0; 87 PetscInt bfgsUpdates = 0; 88 PetscInt needH; 89 90 PetscInt i_max = 5; 91 PetscInt j_max = 1; 92 PetscInt i, j, N, n, its; 93 94 PetscFunctionBegin; 95 if (tao->XL || tao->XU || tao->ops->computebounds) { 96 ierr = PetscPrintf(((PetscObject)tao)->comm,"WARNING: Variable bounds have been set but will be ignored by ntr algorithm\n");CHKERRQ(ierr); 97 } 98 99 tao->trust = tao->trust0; 100 101 /* Modify the radius if it is too large or small */ 102 tao->trust = PetscMax(tao->trust, tr->min_radius); 103 tao->trust = PetscMin(tao->trust, tr->max_radius); 104 105 106 if (NTR_PC_BFGS == tr->pc_type && !tr->M) { 107 ierr = VecGetLocalSize(tao->solution,&n);CHKERRQ(ierr); 108 ierr = VecGetSize(tao->solution,&N);CHKERRQ(ierr); 109 ierr = MatCreateLMVM(((PetscObject)tao)->comm,n,N,&tr->M);CHKERRQ(ierr); 110 ierr = MatLMVMAllocateVectors(tr->M,tao->solution);CHKERRQ(ierr); 111 } 112 113 /* Check convergence criteria */ 114 ierr = TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient);CHKERRQ(ierr); 115 ierr = VecNorm(tao->gradient,NORM_2,&gnorm);CHKERRQ(ierr); 116 if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 117 needH = 1; 118 119 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr); 120 if (reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0); 121 122 /* Create vectors for the limited memory preconditioner */ 123 if ((NTR_PC_BFGS == tr->pc_type) && 124 (BFGS_SCALE_BFGS != tr->bfgs_scale_type)) { 125 if (!tr->Diag) { 126 ierr = VecDuplicate(tao->solution, &tr->Diag);CHKERRQ(ierr); 127 } 128 } 129 130 switch(tr->ksp_type) { 131 case NTR_KSP_NASH: 132 ierr = KSPSetType(tao->ksp, KSPNASH);CHKERRQ(ierr); 133 if (tao->ksp->ops->setfromoptions) { 134 (*tao->ksp->ops->setfromoptions)(tao->ksp); 135 } 136 break; 137 138 case NTR_KSP_STCG: 139 ierr = KSPSetType(tao->ksp, KSPSTCG);CHKERRQ(ierr); 140 if (tao->ksp->ops->setfromoptions) { 141 (*tao->ksp->ops->setfromoptions)(tao->ksp); 142 } 143 break; 144 145 default: 146 ierr = KSPSetType(tao->ksp, KSPGLTR);CHKERRQ(ierr); 147 if (tao->ksp->ops->setfromoptions) { 148 (*tao->ksp->ops->setfromoptions)(tao->ksp); 149 } 150 break; 151 } 152 153 /* Modify the preconditioner to use the bfgs approximation */ 154 ierr = KSPGetPC(tao->ksp, &pc);CHKERRQ(ierr); 155 switch(tr->pc_type) { 156 case NTR_PC_NONE: 157 ierr = PCSetType(pc, PCNONE);CHKERRQ(ierr); 158 if (pc->ops->setfromoptions) { 159 (*pc->ops->setfromoptions)(pc); 160 } 161 break; 162 163 case NTR_PC_AHESS: 164 ierr = PCSetType(pc, PCJACOBI);CHKERRQ(ierr); 165 if (pc->ops->setfromoptions) { 166 (*pc->ops->setfromoptions)(pc); 167 } 168 ierr = PCJacobiSetUseAbs(pc);CHKERRQ(ierr); 169 break; 170 171 case NTR_PC_BFGS: 172 ierr = PCSetType(pc, PCSHELL);CHKERRQ(ierr); 173 if (pc->ops->setfromoptions) { 174 (*pc->ops->setfromoptions)(pc); 175 } 176 ierr = PCShellSetName(pc, "bfgs");CHKERRQ(ierr); 177 ierr = PCShellSetContext(pc, tr->M);CHKERRQ(ierr); 178 ierr = PCShellSetApply(pc, MatLMVMSolveShell);CHKERRQ(ierr); 179 break; 180 181 default: 182 /* Use the pc method set by pc_type */ 183 break; 184 } 185 186 /* Initialize trust-region radius */ 187 switch(tr->init_type) { 188 case NTR_INIT_CONSTANT: 189 /* Use the initial radius specified */ 190 break; 191 192 case NTR_INIT_INTERPOLATION: 193 /* Use the initial radius specified */ 194 max_radius = 0.0; 195 196 for (j = 0; j < j_max; ++j) { 197 fmin = f; 198 sigma = 0.0; 199 200 if (needH) { 201 ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); 202 needH = 0; 203 } 204 205 for (i = 0; i < i_max; ++i) { 206 207 ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr); 208 ierr = VecAXPY(tr->W, -tao->trust/gnorm, tao->gradient);CHKERRQ(ierr); 209 ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); 210 211 if (PetscIsInfOrNanReal(ftrial)) { 212 tau = tr->gamma1_i; 213 } 214 else { 215 if (ftrial < fmin) { 216 fmin = ftrial; 217 sigma = -tao->trust / gnorm; 218 } 219 220 ierr = MatMult(tao->hessian, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 221 ierr = VecDot(tao->gradient, tao->stepdirection, &prered);CHKERRQ(ierr); 222 223 prered = tao->trust * (gnorm - 0.5 * tao->trust * prered / (gnorm * gnorm)); 224 actred = f - ftrial; 225 if ((PetscAbsScalar(actred) <= tr->epsilon) && 226 (PetscAbsScalar(prered) <= tr->epsilon)) { 227 kappa = 1.0; 228 } 229 else { 230 kappa = actred / prered; 231 } 232 233 tau_1 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust + (1.0 - tr->theta_i) * prered - actred); 234 tau_2 = tr->theta_i * gnorm * tao->trust / (tr->theta_i * gnorm * tao->trust - (1.0 + tr->theta_i) * prered + actred); 235 tau_min = PetscMin(tau_1, tau_2); 236 tau_max = PetscMax(tau_1, tau_2); 237 238 if (PetscAbsScalar(kappa - 1.0) <= tr->mu1_i) { 239 /* Great agreement */ 240 max_radius = PetscMax(max_radius, tao->trust); 241 242 if (tau_max < 1.0) { 243 tau = tr->gamma3_i; 244 } 245 else if (tau_max > tr->gamma4_i) { 246 tau = tr->gamma4_i; 247 } 248 else { 249 tau = tau_max; 250 } 251 } 252 else if (PetscAbsScalar(kappa - 1.0) <= tr->mu2_i) { 253 /* Good agreement */ 254 max_radius = PetscMax(max_radius, tao->trust); 255 256 if (tau_max < tr->gamma2_i) { 257 tau = tr->gamma2_i; 258 } 259 else if (tau_max > tr->gamma3_i) { 260 tau = tr->gamma3_i; 261 } 262 else { 263 tau = tau_max; 264 } 265 } 266 else { 267 /* Not good agreement */ 268 if (tau_min > 1.0) { 269 tau = tr->gamma2_i; 270 } 271 else if (tau_max < tr->gamma1_i) { 272 tau = tr->gamma1_i; 273 } 274 else if ((tau_min < tr->gamma1_i) && (tau_max >= 1.0)) { 275 tau = tr->gamma1_i; 276 } 277 else if ((tau_1 >= tr->gamma1_i) && (tau_1 < 1.0) && 278 ((tau_2 < tr->gamma1_i) || (tau_2 >= 1.0))) { 279 tau = tau_1; 280 } 281 else if ((tau_2 >= tr->gamma1_i) && (tau_2 < 1.0) && 282 ((tau_1 < tr->gamma1_i) || (tau_2 >= 1.0))) { 283 tau = tau_2; 284 } 285 else { 286 tau = tau_max; 287 } 288 } 289 } 290 tao->trust = tau * tao->trust; 291 } 292 293 if (fmin < f) { 294 f = fmin; 295 ierr = VecAXPY(tao->solution, sigma, tao->gradient);CHKERRQ(ierr); 296 ierr = TaoComputeGradient(tao,tao->solution, tao->gradient);CHKERRQ(ierr); 297 298 ierr = VecNorm(tao->gradient, NORM_2, &gnorm);CHKERRQ(ierr); 299 300 if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 301 needH = 1; 302 303 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, 1.0, &reason);CHKERRQ(ierr); 304 if (reason != TAO_CONTINUE_ITERATING) { 305 PetscFunctionReturn(0); 306 } 307 } 308 } 309 tao->trust = PetscMax(tao->trust, max_radius); 310 311 /* Modify the radius if it is too large or small */ 312 tao->trust = PetscMax(tao->trust, tr->min_radius); 313 tao->trust = PetscMin(tao->trust, tr->max_radius); 314 break; 315 316 default: 317 /* Norm of the first direction will initialize radius */ 318 tao->trust = 0.0; 319 break; 320 } 321 322 /* Set initial scaling for the BFGS preconditioner 323 This step is done after computing the initial trust-region radius 324 since the function value may have decreased */ 325 if (NTR_PC_BFGS == tr->pc_type) { 326 if (f != 0.0) { 327 delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm); 328 } 329 else { 330 delta = 2.0 / (gnorm*gnorm); 331 } 332 ierr = MatLMVMSetDelta(tr->M,delta);CHKERRQ(ierr); 333 } 334 335 /* Have not converged; continue with Newton method */ 336 while (reason == TAO_CONTINUE_ITERATING) { 337 ++iter; 338 tao->ksp_its=0; 339 /* Compute the Hessian */ 340 if (needH) { 341 ierr = TaoComputeHessian(tao,tao->solution,tao->hessian,tao->hessian_pre);CHKERRQ(ierr); 342 needH = 0; 343 } 344 345 if (NTR_PC_BFGS == tr->pc_type) { 346 if (BFGS_SCALE_AHESS == tr->bfgs_scale_type) { 347 /* Obtain diagonal for the bfgs preconditioner */ 348 ierr = MatGetDiagonal(tao->hessian, tr->Diag);CHKERRQ(ierr); 349 ierr = VecAbs(tr->Diag);CHKERRQ(ierr); 350 ierr = VecReciprocal(tr->Diag);CHKERRQ(ierr); 351 ierr = MatLMVMSetScale(tr->M,tr->Diag);CHKERRQ(ierr); 352 } 353 354 /* Update the limited memory preconditioner */ 355 ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr); 356 ++bfgsUpdates; 357 } 358 359 while (reason == TAO_CONTINUE_ITERATING) { 360 ierr = KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre);CHKERRQ(ierr); 361 362 /* Solve the trust region subproblem */ 363 if (NTR_KSP_NASH == tr->ksp_type) { 364 ierr = KSPNASHSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 365 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 366 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 367 tao->ksp_its+=its; 368 tao->ksp_tot_its+=its; 369 ierr = KSPNASHGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 370 } else if (NTR_KSP_STCG == tr->ksp_type) { 371 ierr = KSPSTCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 372 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 373 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 374 tao->ksp_its+=its; 375 tao->ksp_tot_its+=its; 376 ierr = KSPSTCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 377 } else { /* NTR_KSP_GLTR */ 378 ierr = KSPGLTRSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 379 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 380 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 381 tao->ksp_its+=its; 382 ierr = KSPGLTRGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 383 } 384 385 if (0.0 == tao->trust) { 386 /* Radius was uninitialized; use the norm of the direction */ 387 if (norm_d > 0.0) { 388 tao->trust = norm_d; 389 390 /* Modify the radius if it is too large or small */ 391 tao->trust = PetscMax(tao->trust, tr->min_radius); 392 tao->trust = PetscMin(tao->trust, tr->max_radius); 393 } 394 else { 395 /* The direction was bad; set radius to default value and re-solve 396 the trust-region subproblem to get a direction */ 397 tao->trust = tao->trust0; 398 399 /* Modify the radius if it is too large or small */ 400 tao->trust = PetscMax(tao->trust, tr->min_radius); 401 tao->trust = PetscMin(tao->trust, tr->max_radius); 402 403 if (NTR_KSP_NASH == tr->ksp_type) { 404 ierr = KSPNASHSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 405 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 406 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 407 tao->ksp_its+=its; 408 ierr = KSPNASHGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 409 } else if (NTR_KSP_STCG == tr->ksp_type) { 410 ierr = KSPSTCGSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 411 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 412 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 413 tao->ksp_its+=its; 414 ierr = KSPSTCGGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 415 } else { /* NTR_KSP_GLTR */ 416 ierr = KSPGLTRSetRadius(tao->ksp,tao->trust);CHKERRQ(ierr); 417 ierr = KSPSolve(tao->ksp, tao->gradient, tao->stepdirection);CHKERRQ(ierr); 418 ierr = KSPGetIterationNumber(tao->ksp,&its);CHKERRQ(ierr); 419 tao->ksp_its+=its; 420 ierr = KSPGLTRGetNormD(tao->ksp, &norm_d);CHKERRQ(ierr); 421 } 422 423 if (norm_d == 0.0) SETERRQ(PETSC_COMM_SELF,1, "Initial direction zero"); 424 } 425 } 426 ierr = VecScale(tao->stepdirection, -1.0);CHKERRQ(ierr); 427 ierr = KSPGetConvergedReason(tao->ksp, &ksp_reason);CHKERRQ(ierr); 428 if ((KSP_DIVERGED_INDEFINITE_PC == ksp_reason) && 429 (NTR_PC_BFGS == tr->pc_type) && (bfgsUpdates > 1)) { 430 /* Preconditioner is numerically indefinite; reset the 431 approximate if using BFGS preconditioning. */ 432 433 if (f != 0.0) { 434 delta = 2.0 * PetscAbsScalar(f) / (gnorm*gnorm); 435 } 436 else { 437 delta = 2.0 / (gnorm*gnorm); 438 } 439 ierr = MatLMVMSetDelta(tr->M, delta);CHKERRQ(ierr); 440 ierr = MatLMVMReset(tr->M);CHKERRQ(ierr); 441 ierr = MatLMVMUpdate(tr->M, tao->solution, tao->gradient);CHKERRQ(ierr); 442 bfgsUpdates = 1; 443 } 444 445 if (NTR_UPDATE_REDUCTION == tr->update_type) { 446 /* Get predicted reduction */ 447 if (NTR_KSP_NASH == tr->ksp_type) { 448 ierr = KSPNASHGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 449 } else if (NTR_KSP_STCG == tr->ksp_type) { 450 ierr = KSPSTCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 451 } else { /* gltr */ 452 ierr = KSPGLTRGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 453 } 454 455 if (prered >= 0.0) { 456 /* The predicted reduction has the wrong sign. This cannot 457 happen in infinite precision arithmetic. Step should 458 be rejected! */ 459 tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); 460 } 461 else { 462 /* Compute trial step and function value */ 463 ierr = VecCopy(tao->solution,tr->W);CHKERRQ(ierr); 464 ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr); 465 ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); 466 467 if (PetscIsInfOrNanReal(ftrial)) { 468 tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); 469 } else { 470 /* Compute and actual reduction */ 471 actred = f - ftrial; 472 prered = -prered; 473 if ((PetscAbsScalar(actred) <= tr->epsilon) && 474 (PetscAbsScalar(prered) <= tr->epsilon)) { 475 kappa = 1.0; 476 } 477 else { 478 kappa = actred / prered; 479 } 480 481 /* Accept or reject the step and update radius */ 482 if (kappa < tr->eta1) { 483 /* Reject the step */ 484 tao->trust = tr->alpha1 * PetscMin(tao->trust, norm_d); 485 } 486 else { 487 /* Accept the step */ 488 if (kappa < tr->eta2) { 489 /* Marginal bad step */ 490 tao->trust = tr->alpha2 * PetscMin(tao->trust, norm_d); 491 } 492 else if (kappa < tr->eta3) { 493 /* Reasonable step */ 494 tao->trust = tr->alpha3 * tao->trust; 495 } 496 else if (kappa < tr->eta4) { 497 /* Good step */ 498 tao->trust = PetscMax(tr->alpha4 * norm_d, tao->trust); 499 } 500 else { 501 /* Very good step */ 502 tao->trust = PetscMax(tr->alpha5 * norm_d, tao->trust); 503 } 504 break; 505 } 506 } 507 } 508 } 509 else { 510 /* Get predicted reduction */ 511 if (NTR_KSP_NASH == tr->ksp_type) { 512 ierr = KSPNASHGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 513 } else if (NTR_KSP_STCG == tr->ksp_type) { 514 ierr = KSPSTCGGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 515 } else { /* gltr */ 516 ierr = KSPGLTRGetObjFcn(tao->ksp,&prered);CHKERRQ(ierr); 517 } 518 519 if (prered >= 0.0) { 520 /* The predicted reduction has the wrong sign. This cannot 521 happen in infinite precision arithmetic. Step should 522 be rejected! */ 523 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); 524 } 525 else { 526 ierr = VecCopy(tao->solution, tr->W);CHKERRQ(ierr); 527 ierr = VecAXPY(tr->W, 1.0, tao->stepdirection);CHKERRQ(ierr); 528 ierr = TaoComputeObjective(tao, tr->W, &ftrial);CHKERRQ(ierr); 529 if (PetscIsInfOrNanReal(ftrial)) { 530 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); 531 } 532 else { 533 ierr = VecDot(tao->gradient, tao->stepdirection, &beta);CHKERRQ(ierr); 534 actred = f - ftrial; 535 prered = -prered; 536 if ((PetscAbsScalar(actred) <= tr->epsilon) && 537 (PetscAbsScalar(prered) <= tr->epsilon)) { 538 kappa = 1.0; 539 } 540 else { 541 kappa = actred / prered; 542 } 543 544 tau_1 = tr->theta * beta / (tr->theta * beta - (1.0 - tr->theta) * prered + actred); 545 tau_2 = tr->theta * beta / (tr->theta * beta + (1.0 + tr->theta) * prered - actred); 546 tau_min = PetscMin(tau_1, tau_2); 547 tau_max = PetscMax(tau_1, tau_2); 548 549 if (kappa >= 1.0 - tr->mu1) { 550 /* Great agreement; accept step and update radius */ 551 if (tau_max < 1.0) { 552 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d); 553 } 554 else if (tau_max > tr->gamma4) { 555 tao->trust = PetscMax(tao->trust, tr->gamma4 * norm_d); 556 } 557 else { 558 tao->trust = PetscMax(tao->trust, tau_max * norm_d); 559 } 560 break; 561 } 562 else if (kappa >= 1.0 - tr->mu2) { 563 /* Good agreement */ 564 565 if (tau_max < tr->gamma2) { 566 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d); 567 } 568 else if (tau_max > tr->gamma3) { 569 tao->trust = PetscMax(tao->trust, tr->gamma3 * norm_d); 570 } 571 else if (tau_max < 1.0) { 572 tao->trust = tau_max * PetscMin(tao->trust, norm_d); 573 } 574 else { 575 tao->trust = PetscMax(tao->trust, tau_max * norm_d); 576 } 577 break; 578 } 579 else { 580 /* Not good agreement */ 581 if (tau_min > 1.0) { 582 tao->trust = tr->gamma2 * PetscMin(tao->trust, norm_d); 583 } 584 else if (tau_max < tr->gamma1) { 585 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); 586 } 587 else if ((tau_min < tr->gamma1) && (tau_max >= 1.0)) { 588 tao->trust = tr->gamma1 * PetscMin(tao->trust, norm_d); 589 } 590 else if ((tau_1 >= tr->gamma1) && (tau_1 < 1.0) && 591 ((tau_2 < tr->gamma1) || (tau_2 >= 1.0))) { 592 tao->trust = tau_1 * PetscMin(tao->trust, norm_d); 593 } 594 else if ((tau_2 >= tr->gamma1) && (tau_2 < 1.0) && 595 ((tau_1 < tr->gamma1) || (tau_2 >= 1.0))) { 596 tao->trust = tau_2 * PetscMin(tao->trust, norm_d); 597 } 598 else { 599 tao->trust = tau_max * PetscMin(tao->trust, norm_d); 600 } 601 } 602 } 603 } 604 } 605 606 /* The step computed was not good and the radius was decreased. 607 Monitor the radius to terminate. */ 608 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr); 609 } 610 611 /* The radius may have been increased; modify if it is too large */ 612 tao->trust = PetscMin(tao->trust, tr->max_radius); 613 614 if (reason == TAO_CONTINUE_ITERATING) { 615 ierr = VecCopy(tr->W, tao->solution);CHKERRQ(ierr); 616 f = ftrial; 617 ierr = TaoComputeGradient(tao, tao->solution, tao->gradient); 618 ierr = VecNorm(tao->gradient, NORM_2, &gnorm);CHKERRQ(ierr); 619 if (PetscIsInfOrNanReal(f) || PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,1, "User provided compute function generated Inf or NaN"); 620 needH = 1; 621 ierr = TaoMonitor(tao, iter, f, gnorm, 0.0, tao->trust, &reason);CHKERRQ(ierr); 622 } 623 } 624 PetscFunctionReturn(0); 625 } 626 627 /*------------------------------------------------------------*/ 628 #undef __FUNCT__ 629 #define __FUNCT__ "TaoSetUp_NTR" 630 static PetscErrorCode TaoSetUp_NTR(Tao tao) 631 { 632 TAO_NTR *tr = (TAO_NTR *)tao->data; 633 PetscErrorCode ierr; 634 635 PetscFunctionBegin; 636 637 if (!tao->gradient) {ierr = VecDuplicate(tao->solution, &tao->gradient);CHKERRQ(ierr);} 638 if (!tao->stepdirection) {ierr = VecDuplicate(tao->solution, &tao->stepdirection);CHKERRQ(ierr);} 639 if (!tr->W) {ierr = VecDuplicate(tao->solution, &tr->W);CHKERRQ(ierr);} 640 641 tr->Diag = 0; 642 tr->M = 0; 643 644 645 PetscFunctionReturn(0); 646 } 647 648 /*------------------------------------------------------------*/ 649 #undef __FUNCT__ 650 #define __FUNCT__ "TaoDestroy_NTR" 651 static PetscErrorCode TaoDestroy_NTR(Tao tao) 652 { 653 TAO_NTR *tr = (TAO_NTR *)tao->data; 654 PetscErrorCode ierr; 655 656 PetscFunctionBegin; 657 if (tao->setupcalled) { 658 ierr = VecDestroy(&tr->W);CHKERRQ(ierr); 659 } 660 ierr = MatDestroy(&tr->M);CHKERRQ(ierr); 661 ierr = VecDestroy(&tr->Diag);CHKERRQ(ierr); 662 ierr = PetscFree(tao->data);CHKERRQ(ierr); 663 PetscFunctionReturn(0); 664 } 665 666 /*------------------------------------------------------------*/ 667 #undef __FUNCT__ 668 #define __FUNCT__ "TaoSetFromOptions_NTR" 669 static PetscErrorCode TaoSetFromOptions_NTR(Tao tao) 670 { 671 TAO_NTR *tr = (TAO_NTR *)tao->data; 672 PetscErrorCode ierr; 673 674 PetscFunctionBegin; 675 ierr = PetscOptionsHead("Newton trust region method for unconstrained optimization");CHKERRQ(ierr); 676 ierr = PetscOptionsEList("-tao_ntr_ksp_type", "ksp type", "", NTR_KSP, NTR_KSP_TYPES, NTR_KSP[tr->ksp_type], &tr->ksp_type, 0);CHKERRQ(ierr); 677 ierr = PetscOptionsEList("-tao_ntr_pc_type", "pc type", "", NTR_PC, NTR_PC_TYPES, NTR_PC[tr->pc_type], &tr->pc_type, 0);CHKERRQ(ierr); 678 ierr = PetscOptionsEList("-tao_ntr_bfgs_scale_type", "bfgs scale type", "", BFGS_SCALE, BFGS_SCALE_TYPES, BFGS_SCALE[tr->bfgs_scale_type], &tr->bfgs_scale_type, 0);CHKERRQ(ierr); 679 ierr = PetscOptionsEList("-tao_ntr_init_type", "tao->trust initialization type", "", NTR_INIT, NTR_INIT_TYPES, NTR_INIT[tr->init_type], &tr->init_type, 0);CHKERRQ(ierr); 680 ierr = PetscOptionsEList("-tao_ntr_update_type", "radius update type", "", NTR_UPDATE, NTR_UPDATE_TYPES, NTR_UPDATE[tr->update_type], &tr->update_type, 0);CHKERRQ(ierr); 681 ierr = PetscOptionsReal("-tao_ntr_eta1", "step is unsuccessful if actual reduction < eta1 * predicted reduction", "", tr->eta1, &tr->eta1, 0);CHKERRQ(ierr); 682 ierr = PetscOptionsReal("-tao_ntr_eta2", "", "", tr->eta2, &tr->eta2, 0);CHKERRQ(ierr); 683 ierr = PetscOptionsReal("-tao_ntr_eta3", "", "", tr->eta3, &tr->eta3, 0);CHKERRQ(ierr); 684 ierr = PetscOptionsReal("-tao_ntr_eta4", "", "", tr->eta4, &tr->eta4, 0);CHKERRQ(ierr); 685 ierr = PetscOptionsReal("-tao_ntr_alpha1", "", "", tr->alpha1, &tr->alpha1, 0);CHKERRQ(ierr); 686 ierr = PetscOptionsReal("-tao_ntr_alpha2", "", "", tr->alpha2, &tr->alpha2, 0);CHKERRQ(ierr); 687 ierr = PetscOptionsReal("-tao_ntr_alpha3", "", "", tr->alpha3, &tr->alpha3, 0);CHKERRQ(ierr); 688 ierr = PetscOptionsReal("-tao_ntr_alpha4", "", "", tr->alpha4, &tr->alpha4, 0);CHKERRQ(ierr); 689 ierr = PetscOptionsReal("-tao_ntr_alpha5", "", "", tr->alpha5, &tr->alpha5, 0);CHKERRQ(ierr); 690 ierr = PetscOptionsReal("-tao_ntr_mu1", "", "", tr->mu1, &tr->mu1, 0);CHKERRQ(ierr); 691 ierr = PetscOptionsReal("-tao_ntr_mu2", "", "", tr->mu2, &tr->mu2, 0);CHKERRQ(ierr); 692 ierr = PetscOptionsReal("-tao_ntr_gamma1", "", "", tr->gamma1, &tr->gamma1, 0);CHKERRQ(ierr); 693 ierr = PetscOptionsReal("-tao_ntr_gamma2", "", "", tr->gamma2, &tr->gamma2, 0);CHKERRQ(ierr); 694 ierr = PetscOptionsReal("-tao_ntr_gamma3", "", "", tr->gamma3, &tr->gamma3, 0);CHKERRQ(ierr); 695 ierr = PetscOptionsReal("-tao_ntr_gamma4", "", "", tr->gamma4, &tr->gamma4, 0);CHKERRQ(ierr); 696 ierr = PetscOptionsReal("-tao_ntr_theta", "", "", tr->theta, &tr->theta, 0);CHKERRQ(ierr); 697 ierr = PetscOptionsReal("-tao_ntr_mu1_i", "", "", tr->mu1_i, &tr->mu1_i, 0);CHKERRQ(ierr); 698 ierr = PetscOptionsReal("-tao_ntr_mu2_i", "", "", tr->mu2_i, &tr->mu2_i, 0);CHKERRQ(ierr); 699 ierr = PetscOptionsReal("-tao_ntr_gamma1_i", "", "", tr->gamma1_i, &tr->gamma1_i, 0);CHKERRQ(ierr); 700 ierr = PetscOptionsReal("-tao_ntr_gamma2_i", "", "", tr->gamma2_i, &tr->gamma2_i, 0);CHKERRQ(ierr); 701 ierr = PetscOptionsReal("-tao_ntr_gamma3_i", "", "", tr->gamma3_i, &tr->gamma3_i, 0);CHKERRQ(ierr); 702 ierr = PetscOptionsReal("-tao_ntr_gamma4_i", "", "", tr->gamma4_i, &tr->gamma4_i, 0);CHKERRQ(ierr); 703 ierr = PetscOptionsReal("-tao_ntr_theta_i", "", "", tr->theta_i, &tr->theta_i, 0);CHKERRQ(ierr); 704 ierr = PetscOptionsReal("-tao_ntr_min_radius", "lower bound on initial trust-region radius", "", tr->min_radius, &tr->min_radius, 0);CHKERRQ(ierr); 705 ierr = PetscOptionsReal("-tao_ntr_max_radius", "upper bound on trust-region radius", "", tr->max_radius, &tr->max_radius, 0);CHKERRQ(ierr); 706 ierr = PetscOptionsReal("-tao_ntr_epsilon", "tolerance used when computing actual and predicted reduction", "", tr->epsilon, &tr->epsilon, 0);CHKERRQ(ierr); 707 ierr = PetscOptionsTail();CHKERRQ(ierr); 708 ierr = KSPSetFromOptions(tao->ksp);CHKERRQ(ierr); 709 PetscFunctionReturn(0); 710 } 711 712 /*------------------------------------------------------------*/ 713 #undef __FUNCT__ 714 #define __FUNCT__ "TaoView_NTR" 715 static PetscErrorCode TaoView_NTR(Tao tao, PetscViewer viewer) 716 { 717 TAO_NTR *tr = (TAO_NTR *)tao->data; 718 PetscErrorCode ierr; 719 PetscInt nrejects; 720 PetscBool isascii; 721 722 PetscFunctionBegin; 723 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr); 724 if (isascii) { 725 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 726 if (NTR_PC_BFGS == tr->pc_type && tr->M) { 727 ierr = MatLMVMGetRejects(tr->M, &nrejects);CHKERRQ(ierr); 728 ierr = PetscViewerASCIIPrintf(viewer, "Rejected matrix updates: %D\n", nrejects);CHKERRQ(ierr); 729 } 730 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 731 } 732 PetscFunctionReturn(0); 733 } 734 735 /*------------------------------------------------------------*/ 736 /*MC 737 TAONTR - Newton's method with trust region for unconstrained minimization. 738 At each iteration, the Newton trust region method solves the system. 739 NTR expects a KSP solver with a trust region radius. 740 min_d .5 dT Hk d + gkT d, s.t. ||d|| < Delta_k 741 742 Options Database Keys: 743 + -tao_ntr_ksp_type - "nash","stcg","gltr" 744 . -tao_ntr_pc_type - "none","ahess","bfgs","petsc" 745 . -tao_ntr_bfgs_scale_type - type of scaling with bfgs pc, "ahess" or "bfgs" 746 . -tao_ntr_init_type - "constant","direction","interpolation" 747 . -tao_ntr_update_type - "reduction","interpolation" 748 . -tao_ntr_min_radius - lower bound on trust region radius 749 . -tao_ntr_max_radius - upper bound on trust region radius 750 . -tao_ntr_epsilon - tolerance for accepting actual / predicted reduction 751 . -tao_ntr_mu1_i - mu1 interpolation init factor 752 . -tao_ntr_mu2_i - mu2 interpolation init factor 753 . -tao_ntr_gamma1_i - gamma1 interpolation init factor 754 . -tao_ntr_gamma2_i - gamma2 interpolation init factor 755 . -tao_ntr_gamma3_i - gamma3 interpolation init factor 756 . -tao_ntr_gamma4_i - gamma4 interpolation init factor 757 . -tao_ntr_theta_i - thetha1 interpolation init factor 758 . -tao_ntr_eta1 - eta1 reduction update factor 759 . -tao_ntr_eta2 - eta2 reduction update factor 760 . -tao_ntr_eta3 - eta3 reduction update factor 761 . -tao_ntr_eta4 - eta4 reduction update factor 762 . -tao_ntr_alpha1 - alpha1 reduction update factor 763 . -tao_ntr_alpha2 - alpha2 reduction update factor 764 . -tao_ntr_alpha3 - alpha3 reduction update factor 765 . -tao_ntr_alpha4 - alpha4 reduction update factor 766 . -tao_ntr_alpha4 - alpha4 reduction update factor 767 . -tao_ntr_mu1 - mu1 interpolation update 768 . -tao_ntr_mu2 - mu2 interpolation update 769 . -tao_ntr_gamma1 - gamma1 interpolcation update 770 . -tao_ntr_gamma2 - gamma2 interpolcation update 771 . -tao_ntr_gamma3 - gamma3 interpolcation update 772 . -tao_ntr_gamma4 - gamma4 interpolation update 773 - -tao_ntr_theta - theta interpolation update 774 775 Level: beginner 776 M*/ 777 778 EXTERN_C_BEGIN 779 #undef __FUNCT__ 780 #define __FUNCT__ "TaoCreate_NTR" 781 PetscErrorCode TaoCreate_NTR(Tao tao) 782 { 783 TAO_NTR *tr; 784 PetscErrorCode ierr; 785 786 PetscFunctionBegin; 787 788 ierr = PetscNewLog(tao,&tr);CHKERRQ(ierr); 789 790 tao->ops->setup = TaoSetUp_NTR; 791 tao->ops->solve = TaoSolve_NTR; 792 tao->ops->view = TaoView_NTR; 793 tao->ops->setfromoptions = TaoSetFromOptions_NTR; 794 tao->ops->destroy = TaoDestroy_NTR; 795 796 tao->max_it = 50; 797 #if defined(PETSC_USE_REAL_SINGLE) 798 tao->fatol = 1e-5; 799 tao->frtol = 1e-5; 800 #else 801 tao->fatol = 1e-10; 802 tao->frtol = 1e-10; 803 #endif 804 tao->data = (void*)tr; 805 806 tao->trust0 = 100.0; 807 808 /* Standard trust region update parameters */ 809 tr->eta1 = 1.0e-4; 810 tr->eta2 = 0.25; 811 tr->eta3 = 0.50; 812 tr->eta4 = 0.90; 813 814 tr->alpha1 = 0.25; 815 tr->alpha2 = 0.50; 816 tr->alpha3 = 1.00; 817 tr->alpha4 = 2.00; 818 tr->alpha5 = 4.00; 819 820 /* Interpolation parameters */ 821 tr->mu1_i = 0.35; 822 tr->mu2_i = 0.50; 823 824 tr->gamma1_i = 0.0625; 825 tr->gamma2_i = 0.50; 826 tr->gamma3_i = 2.00; 827 tr->gamma4_i = 5.00; 828 829 tr->theta_i = 0.25; 830 831 /* Interpolation trust region update parameters */ 832 tr->mu1 = 0.10; 833 tr->mu2 = 0.50; 834 835 tr->gamma1 = 0.25; 836 tr->gamma2 = 0.50; 837 tr->gamma3 = 2.00; 838 tr->gamma4 = 4.00; 839 840 tr->theta = 0.05; 841 842 tr->min_radius = 1.0e-10; 843 tr->max_radius = 1.0e10; 844 tr->epsilon = 1.0e-6; 845 846 tr->ksp_type = NTR_KSP_STCG; 847 tr->pc_type = NTR_PC_BFGS; 848 tr->bfgs_scale_type = BFGS_SCALE_AHESS; 849 tr->init_type = NTR_INIT_INTERPOLATION; 850 tr->update_type = NTR_UPDATE_REDUCTION; 851 852 853 /* Set linear solver to default for trust region */ 854 ierr = KSPCreate(((PetscObject)tao)->comm, &tao->ksp);CHKERRQ(ierr); 855 856 PetscFunctionReturn(0); 857 858 859 } 860 EXTERN_C_END 861 862 863 #undef __FUNCT__ 864 #define __FUNCT__ "MatLMVMSolveShell" 865 static PetscErrorCode MatLMVMSolveShell(PC pc, Vec b, Vec x) 866 { 867 PetscErrorCode ierr; 868 Mat M; 869 PetscFunctionBegin; 870 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 871 PetscValidHeaderSpecific(b,VEC_CLASSID,2); 872 PetscValidHeaderSpecific(x,VEC_CLASSID,3); 873 ierr = PCShellGetContext(pc,(void**)&M);CHKERRQ(ierr); 874 ierr = MatLMVMSolve(M, b, x);CHKERRQ(ierr); 875 PetscFunctionReturn(0); 876 } 877