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