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