All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
search_vec.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2014, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_SEARCH_VEC_H
24 #define O2SCL_SEARCH_VEC_H
25 
26 /** \file search_vec.h
27  \brief File defining \ref o2scl::search_vec and \ref o2scl::search_vec_ext
28 */
29 
30 #include <iostream>
31 #include <string>
32 #include <o2scl/err_hnd.h>
33 #include <o2scl/vector.h>
34 
35 #ifndef DOXYGEN_NO_O2NS
36 namespace o2scl {
37 #endif
38 
39  /** \brief Searching class for monotonic data with caching
40 
41  A searching class for monotonic vectors. A caching system
42  similar to \c gsl_interp_accel is used.
43 
44  To find the interval containing a value, use find(). If you
45  happen to know in advance that the vector is increasing or
46  decreasing, then you can use find_inc() or find_dec() instead.
47  To ignore the caching and just use straight binary search, you
48  can use the functions in \ref vector.h .
49 
50  Alternatively, if you just want to find the index with the
51  element closest to a specified value, use ordered_lookup().
52 
53  The functions find_inc(), find_dec() and find() are designed to
54  return the lower index of an interval containing the desired
55  point, and as a result will never return the last index of a
56  vector, e.g. for a vector of size <tt>n</tt> they always return
57  a number between <tt>0</tt> and <tt>n-2</tt> inclusive. See \ref
58  o2scl::search_vec_ext for an alternative.
59 
60  \note The behavior of these functions is undefined if some of
61  the user-specified data is not finite or not strictly monotonic.
62  Two adjacent data points should not be equal. This class does
63  not verify that the user-specified data has these properties.
64 
65  \note Because results are cached, this class is not thread-safe
66  and cannot be used simultaneously by different threads. (This
67  holds even for member functions marked const, because the cache
68  data member is marked as mutable.)
69 
70  \note This class does not store a copy of the data, but only a
71  pointer to it. This means that one can safely modify the data
72  after the constructor is called, so long as one does not make
73  the vector smaller (as the cache might then point to a value
74  outside the new vector) and so long as the new vector is still
75  monotonic. Copy constructors are also private to prevent
76  confusing situations which arise when bit-copying pointers.
77  */
78  template<class vec_t> class search_vec {
79 
80 #ifndef DOXYGEN_INTERNAL
81 
82  protected:
83 
84  /** \brief Storage for the most recent index
85 
86  \note This is marked mutable to ensure const-correctness is
87  straightforward.
88  */
89  mutable size_t cache;
90 
91  /// The vector to be searched
92  const vec_t *v;
93 
94  /// The vector size
95  size_t n;
96 
97 #endif
98 
99  public:
100 
101  /** \brief Create a blank searching object
102  */
103  search_vec() : v(0), n(0) {
104  }
105 
106  /** \brief Create a searching object with vector \c x of size \c nn
107  */
108  search_vec(size_t nn, const vec_t &x) : v(&x), n(nn) {
109  if (nn<2) {
110  std::string str=((std::string)"Vector too small (size=")+
111  o2scl::szttos(nn)+") in search_vec::search_vec().";
112  O2SCL_ERR(str.c_str(),exc_einval);
113  }
114  cache=0;
115  }
116 
117  /** \brief Set the vector to be searched
118  */
119  void set_vec(size_t nn, const vec_t &x) {
120  if (nn<2) {
121  std::string str=((std::string)"Vector too small (size=")+
122  o2scl::szttos(nn)+") in search_vec::set_vec().";
123  O2SCL_ERR(str.c_str(),exc_einval);
124  }
125  cache=0;
126  v=&x;
127  n=nn;
128  }
129 
130  /** \brief Search an increasing or decreasing vector for the
131  interval containing <tt>x0</tt>
132 
133  This function is identical to find_inc() if the data is
134  increasing, and find_dec() if the data is decreasing.
135  */
136  size_t find(const double x0) const {
137 #if !O2SCL_NO_RANGE_CHECK
138  if (cache>=n) {
139  O2SCL_ERR("Cache mis-alignment in search_vec::find().",
140  exc_esanity);
141  }
142 #endif
143  if ((*v)[0]<(*v)[n-1]) return find_inc(x0);
144  return find_dec(x0);
145  }
146 
147  /** \brief Search an increasing vector for the interval
148  containing <tt>x0</tt>
149 
150  This function is a cached version of \ref vector_bsearch_inc()
151  , analogous to <tt>gsl_interp_accel_find()</tt>, except
152  that it does not internally record cache hits and
153  misses.
154 
155  */
156  size_t find_inc(const double x0) const {
157  if (x0<(*v)[cache]) {
158  cache=vector_bsearch_inc<vec_t,double>(x0,*v,0,cache);
159  } else if (x0>=(*v)[cache+1]) {
160  cache=vector_bsearch_inc<vec_t,double>(x0,*v,cache,n-1);
161  }
162 #if !O2SCL_NO_RANGE_CHECK
163  if (cache>=n) {
164  O2SCL_ERR("Cache mis-alignment in search_vec::find_inc().",
165  exc_esanity);
166  }
167 #endif
168  return cache;
169  }
170 
171  /** \brief Search a decreasing vector for the interval
172  containing <tt>x0</tt>
173 
174  This function is a cached version of \ref vector_bsearch_dec()
175  . The operation of this function is undefined if the data is
176  not strictly monotonic, i.e. if some of the data elements are
177  equal.
178  */
179  size_t find_dec(const double x0) const {
180  if (x0>(*v)[cache]) {
181  cache=vector_bsearch_dec<vec_t,double>(x0,*v,0,cache);
182  } else if (x0<=(*v)[cache+1]) {
183  cache=vector_bsearch_dec<vec_t,double>(x0,*v,cache,n-1);
184  }
185 #if !O2SCL_NO_RANGE_CHECK
186  if (cache>=n) {
187  O2SCL_ERR("Cache mis-alignment in search_vec::find_dec().",
188  exc_esanity);
189  }
190 #endif
191  return cache;
192  }
193 
194  /** \brief Find the index of x0 in the ordered array \c x
195 
196  This returns the index i for which x[i] is as close as
197  possible to x0 if x[i] is either increasing or decreasing.
198 
199  If you have a non-monotonic vector, you can use \ref
200  vector_lookup() instead.
201 
202  Generally, if there are two adjacent entries with the same
203  value, this function will return the entry with the smaller
204  index.
205 
206  \future This function just uses the <tt>find</tt> functions
207  and then adjusts the answer at the end if necessary. It might
208  be possible to improve the speed by rewriting this from
209  scratch.
210  */
211  size_t ordered_lookup(const double x0) const {
212  if (n<1) {
213  std::string str=((std::string)"Not enough data (n=")+
214  o2scl::szttos(n)+") in search_vec::ordered_lookup().";
215  O2SCL_ERR(str.c_str(),exc_einval);
216  }
217 
218  size_t row;
219 
220  if ((*v)[0]<=(*v)[n-1]) {
221 
222  // Increasing case
223 
224  if (x0>=(*v)[n-1]) {
225  row=n-1;
226  } else {
227  row=find_inc(x0);
228  if (row<n-1 && fabs((*v)[row+1]-x0)<fabs((*v)[row]-x0)) row++;
229  }
230 
231  } else {
232 
233  // Decreasing case
234 
235  if (x0<=(*v)[n-1]) {
236  row=n-1;
237  } else {
238  row=find_dec(x0);
239  if (row<n-1 && fabs((*v)[row+1]-x0)<fabs((*v)[row]-x0)) row++;
240  }
241  }
242 
243  return row;
244  }
245 
246 #ifndef DOXYGEN_INTERNAL
247 
248  private:
249 
251  search_vec<vec_t>& operator=(const search_vec<vec_t>&);
252 
253 #endif
254 
255  };
256 
257  /** \brief An extended search_vec which is allowed to return
258  the last element
259 
260  \todo The constructor is too restrictive, as it actually calls
261  the parent search_vec constructor and thus requires nn<2 instead
262  of nn<1. Fix this.
263  */
264  template<class vec_t> class search_vec_ext :
265  public search_vec<vec_t> {
266 
267  public:
268 
269  /** \brief Create a blank searching object
270  */
271  search_vec_ext() : search_vec<vec_t>() {
272  }
273 
274  /** \brief Create a searching object for vector \c x of size
275  \c nn
276 
277  \future Ensure this is fully tested for vectors with
278  only one element.
279  */
280  search_vec_ext(size_t nn, const vec_t &x) : search_vec<vec_t>(nn,x) {
281  if (nn<1) {
282  std::string str=((std::string)"Vector too small (n=")+
283  o2scl::szttos(nn)+") in search_vec_ext::search_vec_ext().";
284  O2SCL_ERR(str.c_str(),exc_einval);
285  }
286  }
287 
288  /** \brief Search an increasing or decreasing vector for the interval
289  containing <tt>x0</tt>
290  */
291  size_t find(const double x0) const {
292 #if !O2SCL_NO_RANGE_CHECK
293  if (this->cache>=this->n) {
294  O2SCL_ERR("Cache mis-alignment in search_vec_ext::find().",
295  exc_esanity);
296  }
297 #endif
298  if ((*this->v)[0]<(*this->v)[this->n-1]) return find_inc(x0);
299  return find_dec(x0);
300  }
301 
302  /** \brief Search an increasing vector for the interval
303  containing <tt>x0</tt>
304  */
305  size_t find_inc(const double x0) const {
306  if (x0<(*this->v)[this->cache]) {
307  this->cache=vector_bsearch_inc<vec_t,double>
308  (x0,*this->v,0,this->cache);
309  } else if (this->cache<this->n-1 && x0>=(*this->v)[this->cache+1]) {
310  this->cache=vector_bsearch_inc<vec_t,double>
311  (x0,*this->v,this->cache,this->n);
312  }
313 #if !O2SCL_NO_RANGE_CHECK
314  if (this->cache>=this->n) {
315  O2SCL_ERR("Cache mis-alignment in search_vec_ext::find_inc().",
316  exc_esanity);
317  }
318 #endif
319  return this->cache;
320  }
321 
322  /** \brief Search a decreasing vector for the interval
323  containing <tt>x0</tt>
324  */
325  size_t find_dec(const double x0) const {
326  if (x0>(*this->v)[this->cache]) {
327  this->cache=vector_bsearch_dec<vec_t,double>
328  (x0,*this->v,0,this->cache);
329  } else if (this->cache<this->n-1 && x0<=(*this->v)[this->cache+1]) {
330  this->cache=vector_bsearch_dec<vec_t,double>
331  (x0,*this->v,this->cache,this->n);
332  }
333 #if !O2SCL_NO_RANGE_CHECK
334  if (this->cache>=this->n) {
335  O2SCL_ERR("Cache mis-alignment in search_vec_ext::find_dec().",
336  exc_esanity);
337  }
338 #endif
339  return this->cache;
340  }
341 
342 #ifndef DOXYGEN_INTERNAL
343 
344  private:
345 
347  search_vec_ext<vec_t>& operator=(const search_vec_ext<vec_t>&);
348 
349 #endif
350 
351  };
352 
353 #ifndef DOXYGEN_NO_O2NS
354 }
355 #endif
356 
357 #endif
size_t cache
Storage for the most recent index.
Definition: search_vec.h:89
size_t find_inc(const double x0) const
Search an increasing vector for the interval containing x0
Definition: search_vec.h:305
size_t find_dec(const double x0) const
Search a decreasing vector for the interval containing x0
Definition: search_vec.h:179
size_t n
The vector size.
Definition: search_vec.h:95
sanity check failed - shouldn't happen
Definition: err_hnd.h:65
invalid argument supplied by user
Definition: err_hnd.h:59
search_vec_ext()
Create a blank searching object.
Definition: search_vec.h:271
search_vec()
Create a blank searching object.
Definition: search_vec.h:103
search_vec(size_t nn, const vec_t &x)
Create a searching object with vector x of size nn.
Definition: search_vec.h:108
size_t find(const double x0) const
Search an increasing or decreasing vector for the interval containing x0
Definition: search_vec.h:291
const vec_t * v
The vector to be searched.
Definition: search_vec.h:92
size_t find(const double x0) const
Search an increasing or decreasing vector for the interval containing x0
Definition: search_vec.h:136
#define O2SCL_ERR(d, n)
Set an error with message d and code n.
Definition: err_hnd.h:273
Searching class for monotonic data with caching.
Definition: search_vec.h:78
size_t find_dec(const double x0) const
Search a decreasing vector for the interval containing x0
Definition: search_vec.h:325
An extended search_vec which is allowed to return the last element.
Definition: search_vec.h:264
size_t find_inc(const double x0) const
Search an increasing vector for the interval containing x0
Definition: search_vec.h:156
void set_vec(size_t nn, const vec_t &x)
Set the vector to be searched.
Definition: search_vec.h:119
search_vec_ext(size_t nn, const vec_t &x)
Create a searching object for vector x of size nn.
Definition: search_vec.h:280
std::string szttos(size_t x)
Convert a size_t to a string.
size_t ordered_lookup(const double x0) const
Find the index of x0 in the ordered array x.
Definition: search_vec.h:211

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..