MUQ  0.4.3
NewtonTrust.cpp
Go to the documentation of this file.
2 
3 #include <stdio.h>
4 
5 using namespace muq::Optimization;
6 
8 
9 NewtonTrust::NewtonTrust(std::shared_ptr<muq::Modeling::ModPiece> const& cost,
10  boost::property_tree::ptree const& pt) : Optimizer(cost, pt),
11  maxRadius(pt.get("MaxRadius", std::numeric_limits<double>::infinity())),
12  initialRadius(pt.get("InitialRadius", std::min(1.0,maxRadius))),
13  acceptRatio(pt.get("AcceptRatio", 0.05)),
14  shrinkRatio(pt.get("ShrinkRatio", 0.25)),
15  growRatio(pt.get("GrowRatio", 0.75)),
16  shrinkRate(pt.get("ShrinkRate",0.25)),
17  growRate(pt.get("GrowRate", 2.0)),
18  trustTol(pt.get("TrustTol", std::min(1e-4,xtol_abs))),
19  printLevel(pt.get("PrintLevel", 0)){
20 }
21 
22 
23 
24 std::pair<Eigen::VectorXd, double> NewtonTrust::Solve(std::vector<Eigen::VectorXd> const& inputs) {
25 
26  // Trust region approach with a double dogleg step
28 
29  Eigen::VectorXd const& x0 = inputs.at(0);
30  Eigen::VectorXd x = x0;
31  Eigen::VectorXd step;
32 
33  if(printLevel>0){
34  std::cout << "Using NewtonTrust optimizer..." << std::endl;
35  std::cout << " Iteration, TrustRadius, fval, ||g||" << std::endl;
36  }
37 
38  double fval;
39 
40  for(int it=0; it<maxEvals; ++it) {
41 
42  opt->SetPoint(x);
43  fval = opt->Cost();
44  Eigen::VectorXd const& grad = opt->Gradient();
45 
46  if(printLevel>0){
47  char buf[1024];
48  std::sprintf(buf, " %9d, %11.3f, %4.3e, %5.3e\n", it, trustRadius, fval, grad.norm()); // create string and then cout so pybind11 can capture output
49  std::cout << std::string(buf);
50  }//std::printf(" %9d, %11.3f, %4.3e, %5.3e\n", it, trustRadius, fval, grad.norm());
51 
52  if(grad.norm() < xtol_abs)
53  return std::make_pair(x,fval);
54 
55  step = SolveSub(fval, x, grad);
56 
57  double modDelta = grad.dot(step)+0.5*step.dot(opt->ApplyHessian(step));
58  Eigen::VectorXd newX = x+step;
59 
60  double newf = opt->Cost(newX);
61  double rho = (newf-fval)/modDelta;
62 
63  // Update the position. If the model is really bad, we'll just stay put
64  if(rho>acceptRatio){
65 
66  if(step.norm() < xtol_abs)
67  return std::make_pair(newX,newf);
68 
69  if((fval-newf)<ftol_abs)
70  return std::make_pair(newX,newf);
71 
72  x = newX;
73  fval = newf;
74  }
75 
76  // Update the trust region size
77  if(rho<shrinkRatio){
78  trustRadius = shrinkRate*trustRadius; // shrink trust region
79  }else if((rho>growRatio)&&(std::abs(step.norm()-trustRadius)<1e-10)) {
81  }
82 
83  }
84 
85  return std::make_pair(x,fval);
86 }
87 
88 
89 Eigen::VectorXd NewtonTrust::SolveSub(double fval,
90  Eigen::VectorXd const& x0,
91  Eigen::VectorXd const& grad) {
92  const unsigned int dim = x0.size();
93 
94  // Current estimate of the subproblem minimum
95  Eigen::VectorXd z = Eigen::VectorXd::Zero(dim);
96 
97  // Related to the step direction
98  Eigen::VectorXd r = grad;
99  Eigen::VectorXd d = -r;
100 
101  // If the gradient is small enough where we're starting, then we're done
102  if(r.norm()<trustTol)
103  return z;
104 
105  Eigen::VectorXd Bd; // the Hessian (B) applied to a vector d
106 
107  double alpha, beta, gradd, dBd, rr;
108 
109  for(int i=0; i<dim; ++i){
110  Bd = opt->ApplyHessian(d);
111  gradd = grad.dot(d);
112  dBd = d.dot(Bd);
113  rr = r.squaredNorm();
114 
115  // If the Hessian isn't positive definite in this direction, we can go all
116  // the way to the trust region boundary
117  if(dBd<=0){
118  // do something
119 
120  double dz = d.dot(z);
121  double dd = d.squaredNorm();
122  double zz = z.squaredNorm();
123  double r2 = trustRadius*trustRadius;
124 
125  double tau1 = (-dz + sqrt(dz*dz - dd*(zz-r2)))/dd;
126  double tau2 = (-dz - sqrt(dz*dz - dd*(zz-r2)))/dd;
127 
128  double zBd = z.dot(Bd);
129  double mval1 = tau1*gradd + tau1*zBd + tau1*tau1*dBd;
130  double mval2 = tau2*gradd + tau2*zBd + tau2*tau2*dBd;
131 
132  return (mval1<mval2) ? (z+tau1*d) : (z+tau2*d);
133  }
134 
135  alpha = rr / dBd;
136  Eigen::VectorXd newZ = z + alpha * d;
137 
138  if(newZ.norm()>trustRadius){
139 
140  double dz = d.dot(z);
141  double dd = d.squaredNorm();
142  double zz = z.squaredNorm();
143  double r2 = trustRadius*trustRadius;
144 
145  double tau = (-dz + sqrt(dz*dz - dd*(zz-r2)))/dd;
146  return z + tau*d;
147  }
148 
149  z = newZ;
150 
151  r += alpha*Bd;
152 
153  if(r.norm()<trustTol)
154  return z;
155 
156  beta = r.squaredNorm() / rr;
157  d = (-r + beta*d).eval();
158  }
159 
160  return z;
161 }
REGISTER_OPTIMIZER(NewtonTrust, NewtonTrust) NewtonTrust
Definition: NewtonTrust.cpp:7
Newton optimizer with trust region to ensure global convergence.
Definition: NewtonTrust.h:19
Eigen::VectorXd SolveSub(double fval, Eigen::VectorXd const &x0, Eigen::VectorXd const &grad)
Definition: NewtonTrust.cpp:89
NewtonTrust(std::shared_ptr< muq::Modeling::ModPiece > const &cost, boost::property_tree::ptree const &pt)
const unsigned int printLevel
Definition: NewtonTrust.h:81
Solve an optimization problem.
Definition: Optimizer.h:21
std::shared_ptr< CostFunction > opt
The cost function that we are trying to minimize.
Definition: Optimizer.h:105
const unsigned int maxEvals
Maximum number of cost function evaluations.
Definition: Optimizer.h:123
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.h:3956