00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006, 2007, 2008, 2009, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_SEARCH_VEC_H 00024 #define O2SCL_SEARCH_VEC_H 00025 00026 #include <iostream> 00027 #include <string> 00028 #include <gsl/gsl_spline.h> 00029 #include <o2scl/err_hnd.h> 00030 #include <o2scl/collection.h> 00031 #include <o2scl/ovector_tlate.h> 00032 00033 /* \file search_vec.h 00034 \brief File for definitions for \ref search_vec 00035 00036 \comment 00037 This file isn't included in Doxygen at the moment since there 00038 isn't anything in this file other than the search_vec class. 00039 \endcomment 00040 */ 00041 00042 #ifndef DOXYGENP 00043 namespace o2scl { 00044 #endif 00045 00046 /** 00047 \brief Searching class for monotonic data with caching 00048 00049 A searching class for monotonic vectors. A caching system 00050 similar to \c gsl_interp_accel is used. 00051 00052 To find the interval containing a value, use find_interval(). If 00053 you happen to know in advance that the vector is increasing or 00054 decreasing, then you can use find_interval_inc() or 00055 find_interval_dec() instead. To ignore the caching and just use 00056 straight binary search, you can use bsearch_inc() or 00057 bsearch_dec() for increasing or decreasing arrays respectively. 00058 00059 If you want to allow the function to return <tt>n-1</tt>, to 00060 indicate the value is larger than or equal to the last element, 00061 use find_interval_uncons(). 00062 00063 Alternatively, if you just want to find the index with the 00064 element closest to a specified value, use ordered_lookup(). Note 00065 that ordered_lookup() is slightly different than \ref 00066 ovector_tlate::lookup(), since the latter does not assume the 00067 data is monotonic. 00068 */ 00069 template<class vec_t> class search_vec { 00070 00071 #ifndef DOXYGEN_INTERNAL 00072 00073 protected: 00074 00075 /// Storage for the most recent index 00076 size_t cache; 00077 00078 #endif 00079 00080 public: 00081 00082 search_vec() { 00083 cache=0; 00084 } 00085 00086 /** \brief Search an increasing or decreasing vector for the interval 00087 containing <tt>x0</tt> 00088 */ 00089 size_t find_interval(const double x0, size_t n, const vec_t &x) { 00090 if (x[0]<x[n-1]) return find_interval_inc(x0,n,x); 00091 return find_interval_dec(x0,n,x); 00092 } 00093 00094 /** 00095 \brief Search an increasing vector for the interval 00096 containing <tt>x0</tt> 00097 00098 This function operates in the same way as 00099 <tt>gsl_interp_accel_find()</tt>, except that it does not 00100 record cache hits and misses. 00101 */ 00102 size_t find_interval_inc(const double x0, size_t n, const vec_t &x) { 00103 size_t x_index=cache; 00104 00105 // Make sure the cached value is not outside the array. 00106 if (x_index>n-1) x_index=n/2; 00107 00108 if (x0<x[x_index]) { 00109 cache=bsearch_inc(x0,x,0,x_index); 00110 } else if (x0>=x[x_index+1]) { 00111 cache=bsearch_inc(x0,x,x_index,n-1); 00112 } 00113 00114 return cache; 00115 } 00116 00117 /** \brief Search a decreasing vector for the interval 00118 containing <tt>x0</tt> 00119 */ 00120 size_t find_interval_dec(const double x0, size_t n, const vec_t &x) { 00121 size_t x_index=cache; 00122 00123 // Make sure the cached value is not outside the array. 00124 if (x_index>n-1) x_index=n/2; 00125 00126 if (x0>x[x_index]) { 00127 cache=bsearch_dec(x0,x,0,x_index); 00128 } else if (x0<x[x_index+1]) { 00129 cache=bsearch_dec(x0,x,x_index,n-1); 00130 } 00131 00132 return cache; 00133 } 00134 00135 /** 00136 \brief Find the index of x0 in the ordered array \c x 00137 00138 This returns the index i for which x[i] is as close 00139 as possible to x0 if x[i] is either increasing or decreasing. 00140 00141 If some of the values in the ovector are not finite, then 00142 the output of this function is not defined. 00143 00144 If you have a non-monotonic \ref ovector or \ref uvector 00145 object, consider using \ref ovector_view_tlate::lookup() or 00146 \ref uvector_view_tlate::lookup() instead of this function. 00147 00148 Generally, if there are two adjacent entries with the same 00149 value, this function will return the entry with the smaller 00150 index. (This is the same as the convention in \ref 00151 ovector_view_tlate::lookup() and \ref 00152 uvector_view_tlate::lookup() ). 00153 00154 \future This is not as efficient as it could be, as it just 00155 uses the <tt>find_interval</tt> functions and then adjusts the 00156 answer at the end if necessary. 00157 */ 00158 size_t ordered_lookup(const double x0, size_t n, const vec_t &x) { 00159 size_t row; 00160 00161 if (x[0]<=x[n-1]) { 00162 00163 // Increasing case 00164 00165 if (x0>=x[n-1]) { 00166 row=n-1; 00167 } else { 00168 row=find_interval_inc(x0,n,x); 00169 if (row<n-1 && fabs(x[row+1]-x0)<fabs(x[row]-x0)) row++; 00170 } 00171 00172 } else { 00173 00174 // Decreasing case 00175 00176 if (x0<=x[n-1]) { 00177 row=n-1; 00178 } else { 00179 row=find_interval_dec(x0,n,x); 00180 if (row<n-1 && fabs(x[row+1]-x0)<fabs(x[row]-x0)) row++; 00181 } 00182 } 00183 00184 return row; 00185 } 00186 00187 /** \brief Search an increasing or decreasing vector for the interval 00188 containing <tt>x0</tt> including the open interval at the end 00189 00190 This returns the index i for which x[i]<=x0<x[i+1]. 00191 00192 This function operates just as find_interval(), except that in 00193 the case of increasing arrays, it will return <tt>n-1</tt> if 00194 <tt>x0</tt> is greater than the last element in the array. The 00195 decreasing case is handled analogously. 00196 00197 If some of the values in the vector are not finite, then the 00198 output of this function is not defined. 00199 00200 */ 00201 size_t find_interval_uncons(const double x0, size_t n, const vec_t &x) { 00202 size_t row; 00203 00204 if (x[0]<=x[n-1]) { 00205 00206 // Increasing case 00207 00208 if (x0>=x[n-1]) row=n-1; 00209 else row=find_interval_inc(x0,n,x); 00210 00211 } else { 00212 // Decreasing case 00213 00214 if (x0<=x[n-1]) row=n-1; 00215 else row=find_interval_dec(x0,n,x); 00216 } 00217 00218 return row; 00219 } 00220 00221 /** 00222 \brief Binary search a part of an increasing vector for 00223 the interval containing <tt>x0</tt>. 00224 00225 This function performs a binary search of between 00226 <tt>x[lo]</tt> and <tt>x[hi]</tt> (inclusive). It returns 00227 - \c lo if \c x0 < <tt>x[lo]</tt> 00228 - \c i if <tt>x[i]</tt> <= \c x0 < <tt>x[i+1]</tt> 00229 for \c lo <= \c i < \c hi 00230 - \c hi-1 if \c x0 >= \c <tt>x[hi]</tt> 00231 00232 This function operates in the same way as 00233 <tt>gsl_interp_bsearch()</tt>. 00234 00235 The cache is not used for this function. 00236 00237 \note The value of \c hi for an <tt>n</tt> element array 00238 is typically <tt>n-1</tt>, e.g. For <tt>double x[10]</tt> 00239 one would use <tt>bsearch_inc(1.0,x,0,9)</tt>. 00240 */ 00241 size_t bsearch_inc(const double x0, const vec_t &x, 00242 size_t lo, size_t hi) const { 00243 while (hi>lo+1) { 00244 size_t i=(hi+lo)/2; 00245 if (x[i]>x0) { 00246 hi=i; 00247 } else { 00248 lo=i; 00249 } 00250 } 00251 00252 return lo; 00253 } 00254 00255 /** 00256 \brief Binary search a part of an decreasing vector for 00257 the interval containing <tt>x0</tt>. 00258 00259 This function performs a binary search of between 00260 <tt>x[lo]</tt> and <tt>x[hi]</tt> (inclusive). It returns 00261 - \c lo if \c x0 > <tt>x[lo]</tt> 00262 - \c i if <tt>x[i]</tt> >= \c x0 > <tt>x[i+1]</tt> 00263 for \c lo <= \c i < \c hi 00264 - \c hi-1 if \c x0 <= \c <tt>x[hi]</tt> 00265 00266 The cache is not used for this function. 00267 00268 \note The value of \c hi for an <tt>n</tt> element array 00269 is typically <tt>n-1</tt>, e.g. For <tt>double x[10]</tt> 00270 one would use <tt>bsearch_dec(1.0,x,0,9)</tt>. 00271 */ 00272 size_t bsearch_dec(const double x0, const vec_t &x, 00273 size_t lo, size_t hi) const { 00274 while (hi>lo+1) { 00275 size_t i=(hi+lo)/2; 00276 if (x[i]<x0) { 00277 hi=i; 00278 } else { 00279 lo=i; 00280 } 00281 } 00282 00283 return lo; 00284 } 00285 00286 }; 00287 00288 #ifndef DOXYGENP 00289 } 00290 #endif 00291 00292 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page