GlobiPack  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
GlobiPack_GoldenQuadInterpBracket_def.hpp
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // GlobiPack: Collection of Scalar 1D globalizaton utilities
6 // Copyright (2009) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov)
39 //
40 // ***********************************************************************
41 // @HEADER
42 */
43 
44 #ifndef GLOBIPACK_GOLDEN_BRACKET_QUAD_INTERP_DEF_HPP
45 #define GLOBIPACK_GOLDEN_BRACKET_QUAD_INTERP_DEF_HPP
46 
47 
48 #include "GlobiPack_GoldenQuadInterpBracket_decl.hpp"
49 #include "Teuchos_TabularOutputter.hpp"
50 
51 
52 namespace GlobiPack {
53 
54 
55 // Constructor/Initializers/Accessors
56 
57 
58 template<typename Scalar>
60 {}
61 
62 
63 // Overridden from ParameterListAcceptor (simple forwarding functions)
64 
65 
66 template<typename Scalar>
68 {
69  //typedef ScalarTraits<Scalar> ST; // unused
70  paramList->validateParametersAndSetDefaults(*this->getValidParameters());
71  // ToDo: Add parameters!
72  setMyParamList(paramList);
73 }
74 
75 
76 template<typename Scalar>
78 {
79  static RCP<const ParameterList> validPL;
80  if (is_null(validPL)) {
83  // ToDo: Add parameters!
84  validPL = pl;
85  }
86  return validPL;
87 }
88 
89 
90 // Bracket
91 
92 
93 template<typename Scalar>
95  const MeritFunc1DBase<Scalar> &phi,
96  const Ptr<PointEval1D<Scalar> > &pointLower,
97  const Ptr<PointEval1D<Scalar> > &pointMiddle,
98  const Ptr<PointEval1D<Scalar> > &pointUpper,
99  const Ptr<int> &numIters
100  ) const
101 {
102 
103  using Teuchos::as;
105  typedef Teuchos::TabularOutputter TO;
106  typedef ScalarTraits<Scalar> ST;
107  using Teuchos::OSTab;
108 #ifdef TEUCHOS_DEBUG
109  typedef PointEval1D<Scalar> PE1D;
110 
111  TEUCHOS_TEST_FOR_EXCEPT(is_null(pointLower));
112  TEUCHOS_TEST_FOR_EXCEPT(is_null(pointUpper));
113  TEUCHOS_TEST_FOR_EXCEPT(is_null(pointMiddle));
114  TEUCHOS_ASSERT_INEQUALITY(pointLower->alpha, <, pointMiddle->alpha);
115  TEUCHOS_ASSERT_INEQUALITY(pointLower->phi, !=, PE1D::valNotGiven());
116  TEUCHOS_ASSERT_INEQUALITY(pointMiddle->phi, !=, PE1D::valNotGiven());
117 #endif
118 
119  const RCP<Teuchos::FancyOStream> out = this->getOStream();
120 
121  // ToDo: Make these variable!
122  const Scalar GOLDEN_RATIO = 1.618033988749895;
123  const Scalar SMALL_DIV = 1e-20;
124  const Scalar MAX_EXTRAP_FACTOR = 100.0;
125  const int MAX_TOTAL_ITERS = 30;
126 
127  *out << "\nStarting golden quadratic interpolating bracketing of the minimum ...\n\n";
128 
129  // Repeatedly evaluate the function along the search direction until
130  // we know we've bracketed a minimum.
131 
132  Scalar &alpha_l = pointLower->alpha, &phi_l = pointLower->phi;
133  Scalar &alpha_m = pointMiddle->alpha, &phi_m = pointMiddle->phi;
134  Scalar &alpha_u = pointUpper->alpha = ST::nan(), &phi_u = pointUpper->phi = ST::nan();
135 
136  Scalar tmp = ST::nan(), q = ST::nan(), r = ST::nan();
137 
138  const Scalar zero = ST::zero();
139 
140  // This does a simple backtracking
141  alpha_u = zero;
142  const Scalar goldinv = 1.0/(1.0+GOLDEN_RATIO);
143 
144  TabularOutputter tblout(out);
145 
146  tblout.pushFieldSpec("itr", TO::INT);
147  tblout.pushFieldSpec("alpha_l", TO::DOUBLE);
148  tblout.pushFieldSpec("alpha_m", TO::DOUBLE);
149  tblout.pushFieldSpec("alpha_u", TO::DOUBLE);
150  tblout.pushFieldSpec("phi_l", TO::DOUBLE);
151  tblout.pushFieldSpec("phi_m", TO::DOUBLE);
152  tblout.pushFieldSpec("phi_u", TO::DOUBLE);
153  tblout.pushFieldSpec("step type ", TO::STRING);
154 
155  tblout.outputHeader();
156 
157  int icount = 0;
158 
159  std::string stepType = "";
160 
161  //
162  // A) Find phi_l > phi_m first
163  //
164 
165  tblout.outputField("-");
166  tblout.outputField(alpha_l);
167  tblout.outputField(alpha_m);
168  tblout.outputField("-");
169  tblout.outputField(phi_l);
170  tblout.outputField(phi_m);
171  tblout.outputField("-");
172  tblout.outputField("start");
173  tblout.nextRow();
174 
175  for (; icount < MAX_TOTAL_ITERS; ++icount) {
176 
177  // ToDo: Put in a check for NAN and backtrack if you find it!
178 
179  if (phi_l > phi_m) {
180  break;
181  }
182 
183  stepType = "golden back";
184  alpha_u = alpha_m;
185  phi_u = phi_m;
186  alpha_m = goldinv * (alpha_u + GOLDEN_RATIO*alpha_l);
187  phi_m = computeValue<Scalar>(phi, alpha_m);
188 
189  tblout.outputField(icount);
190  tblout.outputField(alpha_l);
191  tblout.outputField(alpha_m);
192  tblout.outputField(alpha_u);
193  tblout.outputField(phi_l);
194  tblout.outputField(phi_m);
195  tblout.outputField(phi_u);
196  tblout.outputField(stepType);
197  tblout.nextRow();
198 
199  }
200 
201  if (alpha_u == zero) {
202  // The following factor of gold was reduced to (GOLDEN_RATIO-1) to save
203  // one function evaluation near convergence.
204  alpha_u = alpha_m + (GOLDEN_RATIO-1.0) * (alpha_m-alpha_l);
205  phi_u = computeValue<Scalar>(phi, alpha_u);
206  }
207 
208  //
209  // B) Quadratic interpolation iterations
210  //
211 
212  bool bracketedMin = false;
213 
214  for (; icount < MAX_TOTAL_ITERS; ++icount) {
215 
216  if (phi_m < phi_u) {
217  bracketedMin = true;
218  break;
219  }
220 
221  // find the extremum alpha_quad of a quadratic model interpolating there
222  // points
223  q = (phi_m-phi_l)*(alpha_m-alpha_u);
224  r = (phi_m-phi_u)*(alpha_m-alpha_l);
225 
226  // avoid division by small (q-r) by bounding with signed minimum
227  tmp = ST::magnitude(q-r);
228  tmp = (tmp > SMALL_DIV ? tmp : SMALL_DIV);
229  tmp = (q-r >= 0 ? tmp : -tmp);
230 
231  Scalar alpha_quad =
232  alpha_m - (q*(alpha_m-alpha_u) - r*(alpha_m-alpha_l))/(2.0*tmp);
233 
234  // maximum point for which we trust the interpolation
235  const Scalar alpha_lim = alpha_m + MAX_EXTRAP_FACTOR * (alpha_u-alpha_m);
236 
237  // now detect which interval alpha_quad is in and act accordingly
238  bool skipToNextIter = false;
239  Scalar phi_quad = ST::nan();
240  if ( (alpha_m-alpha_quad)*(alpha_quad-alpha_u) > zero ) { // [alpha_m, alpha_u]
241  phi_quad = computeValue<Scalar>(phi, alpha_quad);
242  if (phi_quad < phi_u) { // use points [b, alpha_quad, c]
243  alpha_l = alpha_m;
244  phi_l = phi_m;
245  alpha_m = alpha_quad;
246  phi_m = phi_quad;
247  skipToNextIter = true;
248  stepType = "alpha_quad middle";
249  }
250  else if (phi_quad > phi_m) { // use points [a, b, alpha_quad]
251  alpha_u = alpha_quad;
252  phi_u = phi_quad;
253  skipToNextIter = true;
254  stepType = "alpha_quad upper";
255  }
256  else {
257  alpha_quad = alpha_u + GOLDEN_RATIO*(alpha_u-alpha_m);
258  phi_quad = computeValue<Scalar>(phi, alpha_quad);
259  }
260  }
261 
262  if (!skipToNextIter) {
263 
264  if ((alpha_u-alpha_quad)*(alpha_quad-alpha_lim) > zero) { // [alpha_u, alpha_lim]
265  phi_quad = computeValue<Scalar>(phi, alpha_quad);
266  stepType = "[alpha_u, alpha_lim]";
267  if (phi_quad < phi_u) {
268  alpha_m = alpha_u;
269  alpha_u = alpha_quad;
270  alpha_quad = alpha_u + GOLDEN_RATIO*(alpha_u-alpha_m);
271  phi_m = phi_u;
272  phi_u = phi_quad;
273  phi_quad = computeValue<Scalar>(phi, alpha_quad);
274  stepType = "phi_quad < phi_u";
275  }
276  }
277  else if ((alpha_quad-alpha_lim)*(alpha_lim-alpha_u) >= zero ) { // [alpha_lim, inf]
278  alpha_quad = alpha_lim;
279  phi_quad = computeValue<Scalar>(phi, alpha_quad);
280  stepType = "[alpha_lim, inf]";
281  }
282  else { // [0,alpha_m]
283  alpha_quad = alpha_u + GOLDEN_RATIO*(alpha_u-alpha_m);
284  phi_quad = computeValue<Scalar>(phi, alpha_quad);
285  stepType = "[0, alpha_m]";
286  }
287 
288  // shift to newest 3 points before loop
289  alpha_l = alpha_m;
290  phi_l = phi_m;
291  alpha_m = alpha_u;
292  phi_m = phi_u;
293  alpha_u = alpha_quad;
294  phi_u = phi_quad;
295 
296  }
297 
298  tblout.outputField(icount);
299  tblout.outputField(alpha_l);
300  tblout.outputField(alpha_m);
301  tblout.outputField(alpha_u);
302  tblout.outputField(phi_l);
303  tblout.outputField(phi_m);
304  tblout.outputField(phi_u);
305  tblout.outputField(stepType);
306  tblout.nextRow();
307 
308  } // end for loop
309 
310  if (icount >= MAX_TOTAL_ITERS) {
311  *out <<"\nExceeded maximum number of iterations!.\n";
312  }
313 
314  if (!is_null(numIters)) {
315  *numIters = icount;
316  }
317 
318  *out << "\n";
319 
320  return bracketedMin;
321 
322 }
323 
324 
325 } // namespace GlobiPack
326 
327 
328 #endif // GLOBIPACK_GOLDEN_BRACKET_QUAD_INTERP_DEF_HPP
bool is_null(const boost::shared_ptr< T > &p)
basic_OSTab< char > OSTab
GoldenQuadInterpBracket()
Construct with default parameters.
#define TEUCHOS_ASSERT_INEQUALITY(val1, comp, val2)
void setParameterList(RCP< ParameterList > const &paramList)
bool bracketMinimum(const MeritFunc1DBase< Scalar > &phi, const Ptr< PointEval1D< Scalar > > &pointLower, const Ptr< PointEval1D< Scalar > > &pointMiddle, const Ptr< PointEval1D< Scalar > > &pointUpper, const Ptr< int > &numIters=Teuchos::null) const
Bracket the minimum of a 1D function.
Represents the evaluation point of the merit function phi(alpha) and/or is derivative Dphi(alpha)...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
RCP< const ParameterList > getValidParameters() const
TypeTo as(const TypeFrom &t)
Base class for 1D merit fucntions used in globalization methods.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)