Object-oriented Scientific Computing Library: Version 0.910
search_vec.h
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.