![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, 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 <o2scl/err_hnd.h> 00029 #include <o2scl/ovector_tlate.h> 00030 #include <o2scl/vector.h> 00031 00032 #ifndef DOXYGENP 00033 namespace o2scl { 00034 #endif 00035 00036 /** \brief Searching class for monotonic data with caching 00037 00038 A searching class for monotonic vectors. A caching system 00039 similar to \c gsl_interp_accel is used. 00040 00041 To find the interval containing a value, use find(). If you 00042 happen to know in advance that the vector is increasing or 00043 decreasing, then you can use find_inc() or find_dec() 00044 instead. To ignore the caching and just use straight binary 00045 search, you can use the functions in \ref vector.h . 00046 00047 Alternatively, if you just want to find the index with the 00048 element closest to a specified value, use ordered_lookup(). Note 00049 that ordered_lookup() is slightly different than \ref 00050 ovector_tlate::lookup(), since the latter does not assume the 00051 data is monotonic. 00052 00053 The functions find_inc(), find_dec() and find() are designed 00054 to return the lower index of an interval containing the 00055 desired point, and as a result will never return the 00056 last index of a vector, e.g. for a vector of size <tt>n</tt> 00057 they always return a number between <tt>0</tt> and <tt>n-2</tt> 00058 inclusive. See \ref search_vec_ext for an alternative. 00059 00060 \note The behavior of these functions is undefined if some of 00061 the user-specified data is not finite or not strictly 00062 monotonic. Two adjacent data points should not be equal. This 00063 class does not verify that the user-specified data has these 00064 properties. 00065 00066 \note This class does not store a copy of the data, 00067 but only a pointer to it. This means that one can safely 00068 modify the data after the constructor is called, so long 00069 as one does not make the vector smaller (as the cache 00070 might then point to a value outside the new vector) and 00071 so long as the new vector is still monotonic. 00072 00073 00074 \future Consider a sanity check to ensure that the 00075 cache is never larger than the vector length. 00076 */ 00077 template<class vec_t> class search_vec { 00078 00079 #ifndef DOXYGEN_INTERNAL 00080 00081 protected: 00082 00083 /** \brief Storage for the most recent index 00084 00085 \note This is marked mutable to ensure const-correctness is 00086 straightforward. 00087 */ 00088 mutable size_t cache; 00089 00090 /// The vector to be searched 00091 const vec_t *v; 00092 00093 /// The vector size 00094 const size_t n; 00095 00096 #endif 00097 00098 public: 00099 00100 /** \brief Create a searching object with vector \c x of size \c nn 00101 */ 00102 search_vec(size_t nn, const vec_t &x) : v(&x), n(nn) { 00103 if (nn<2) { 00104 O2SCL_ERR("Vector too small in search_vec::search_vec().", 00105 gsl_einval); 00106 } 00107 cache=0; 00108 } 00109 00110 /** \brief Search an increasing or decreasing vector for the 00111 interval containing <tt>x0</tt> 00112 00113 This function is identical to find_inc() if the data is 00114 increasing, and find_dec() if the data is decreasing. 00115 */ 00116 size_t find(const double x0) const { 00117 if ((*v)[0]<(*v)[n-1]) return find_inc(x0); 00118 return find_dec(x0); 00119 } 00120 00121 /** \brief Search an increasing vector for the interval 00122 containing <tt>x0</tt> 00123 00124 This function is a cached version of \ref vector_bsearch_inc() 00125 , analogous to <tt>gsl_interp_accel_find()</tt>, except 00126 that it does not internally record cache hits and 00127 misses. 00128 00129 */ 00130 size_t find_inc(const double x0) const { 00131 if (x0<(*v)[cache]) { 00132 cache=vector_bsearch_inc<vec_t,double>(x0,*v,0,cache); 00133 } else if (x0>=(*v)[cache+1]) { 00134 cache=vector_bsearch_inc<vec_t,double>(x0,*v,cache,n-1); 00135 } 00136 return cache; 00137 } 00138 00139 /** \brief Search a decreasing vector for the interval 00140 containing <tt>x0</tt> 00141 00142 This function is a cached version of \ref vector_bsearch_dec() 00143 . The operation of this function is undefined if the data is 00144 not strictly monotonic, i.e. if some of the data elements are 00145 equal. 00146 */ 00147 size_t find_dec(const double x0) const { 00148 if (x0>(*v)[cache]) { 00149 cache=vector_bsearch_dec<vec_t,double>(x0,*v,0,cache); 00150 } else if (x0<=(*v)[cache+1]) { 00151 cache=vector_bsearch_dec<vec_t,double>(x0,*v,cache,n-1); 00152 } 00153 return cache; 00154 } 00155 00156 /** \brief Find the index of x0 in the ordered array \c x 00157 00158 This returns the index i for which x[i] is as close as 00159 possible to x0 if x[i] is either increasing or decreasing. 00160 00161 If you have a non-monotonic vector, you can use \ref 00162 vector_lookup() instead, or if you a non-monotonic \ref 00163 ovector or \ref uvector object, consider using \ref 00164 ovector_view_tlate::lookup() or \ref 00165 uvector_view_tlate::lookup() instead of this function. 00166 00167 Generally, if there are two adjacent entries with the same 00168 value, this function will return the entry with the smaller 00169 index. (This is the same as the convention in \ref 00170 ovector_view_tlate::lookup() and \ref 00171 uvector_view_tlate::lookup() ). 00172 00173 \future This function just uses the <tt>find</tt> functions 00174 and then adjusts the answer at the end if necessary. It might 00175 be possible to improve the speed by rewriting this from 00176 scratch. 00177 */ 00178 size_t ordered_lookup(const double x0) const { 00179 if (n<1) { 00180 O2SCL_ERR2_RET("Not enough data for ", 00181 "search_vec::ordered_lookup().",gsl_einval); 00182 } 00183 00184 size_t row; 00185 00186 if ((*v)[0]<=(*v)[n-1]) { 00187 00188 // Increasing case 00189 00190 if (x0>=(*v)[n-1]) { 00191 row=n-1; 00192 } else { 00193 row=find_inc(x0); 00194 if (row<n-1 && fabs((*v)[row+1]-x0)<fabs((*v)[row]-x0)) row++; 00195 } 00196 00197 } else { 00198 00199 // Decreasing case 00200 00201 if (x0<=(*v)[n-1]) { 00202 row=n-1; 00203 } else { 00204 row=find_dec(x0); 00205 if (row<n-1 && fabs((*v)[row+1]-x0)<fabs((*v)[row]-x0)) row++; 00206 } 00207 } 00208 00209 return row; 00210 } 00211 00212 }; 00213 00214 /** \brief An extended search_vec which is allowed to return 00215 the last element 00216 */ 00217 template<class vec_t> class search_vec_ext : 00218 public search_vec<vec_t> { 00219 00220 public: 00221 00222 /** \brief Create a searching object for vector \c x of size 00223 \c nn 00224 00225 \future This could be rewritten to allow vectors with 00226 only one element (5/2/11: It looks like this might have 00227 been done already?) 00228 */ 00229 /// Create a searching object with vector \c x of size \c nn 00230 search_vec_ext(size_t nn, vec_t &x) : search_vec<vec_t>(nn,x) { 00231 //if (n<1) { 00232 //O2SCL_ERR_RET("Vector too small in search_vec_ext::search_vec_ext().", 00233 //gsl_einval); 00234 //} 00235 } 00236 00237 /** \brief Search an increasing or decreasing vector for the interval 00238 containing <tt>x0</tt> 00239 */ 00240 size_t find(const double x0) const { 00241 if ((*this->v)[0]<(*this->v)[this->n-1]) return find_inc(x0); 00242 return find_dec(x0); 00243 } 00244 00245 /** \brief Search an increasing vector for the interval 00246 containing <tt>x0</tt> 00247 */ 00248 size_t find_inc(const double x0) const { 00249 if (x0<(*this->v)[this->cache]) { 00250 this->cache=vector_bsearch_inc<vec_t,double> 00251 (x0,*this->v,0,this->cache); 00252 } else if (this->cache<this->n-1 && x0>=(*this->v)[this->cache+1]) { 00253 this->cache=vector_bsearch_inc<vec_t,double> 00254 (x0,*this->v,this->cache,this->n); 00255 } 00256 return this->cache; 00257 } 00258 00259 /** \brief Search a decreasing vector for the interval 00260 containing <tt>x0</tt> 00261 */ 00262 size_t find_dec(const double x0) const { 00263 if (x0>(*this->v)[this->cache]) { 00264 this->cache=vector_bsearch_dec<vec_t,double> 00265 (x0,*this->v,0,this->cache); 00266 } else if (this->cache<this->n-1 && x0<=(*this->v)[this->cache+1]) { 00267 this->cache=vector_bsearch_dec<vec_t,double> 00268 (x0,*this->v,this->cache,this->n); 00269 } 00270 return this->cache; 00271 } 00272 00273 }; 00274 00275 #ifndef DOXYGENP 00276 } 00277 #endif 00278 00279 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).