Object-oriented Scientific Computing Library: Version 0.910
tensor_old.h
Go to the documentation of this file.
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_TENSOR_OLD_H
00024 #define O2SCL_TENSOR_OLD_H
00025 
00026 /** \file tensor_old.h
00027     \brief File for definitions of tensor_olds
00028 */
00029 
00030 #include <iostream>
00031 #include <cstdlib>
00032 #include <string>
00033 #include <fstream>
00034 #include <sstream>
00035 
00036 #include <gsl/gsl_matrix.h>
00037 #include <gsl/gsl_ieee_utils.h>
00038 
00039 #include <o2scl/err_hnd.h>
00040 #include <o2scl/uvector_tlate.h>
00041 #include <o2scl/umatrix_tlate.h>
00042 #include <o2scl/smart_interp.h>
00043 
00044 #ifndef DOXYGENP
00045 namespace o2scl {
00046 #endif
00047   
00048   /** \brief Tensor_Old class with arbitrary dimensions
00049 
00050       The elements of a tensor_old are typically specified as a list of
00051       <tt>size_t</tt> numbers with length equal to the tensor_old rank.
00052       For a rank-4 tensor_old named \c t, the element 
00053       <tt>t[1][2][0][3]</tt> can be obtained with something similar to 
00054       \code
00055       size_t ix[4]={1,2,0,3};
00056       double x=t.get(ix);
00057       \endcode
00058 
00059       Empty tensor_olds have zero rank.
00060 
00061       Slices of tensor_olds are subsets obtained from fixing the index of
00062       several dimensions, while letting other dimensions vary. For a
00063       slice with one dimension not fixed, see \ref vector_slice(). For
00064       a slice with two dimensions not fixed, see \ref matrix_slice().
00065 
00066       For I/O with tensor_olds, see \ref hdf_io.h .
00067 
00068       \future Could implement arithmetic operators + and - and some
00069       different products. 
00070 
00071       \future Implement copies to and from vector
00072       and matrices 
00073 
00074       \future Implement tensor_old contractions, i.e. tensor_old
00075       = tensor_old * tensor_old 
00076 
00077       \future Consider making a template type to replace double,
00078       e.g. <tt>value_t</tt>.
00079 
00080       \future Could be interesting to write an iterator for this class.
00081 
00082       \comment
00083       A tensor_old is defined to be empty if it's rank is zero. A tensor_old's
00084       rank should be zero if and only if no memory has been allocated
00085       for it.
00086 
00087       I could have chosen to make set() functions virtual functions
00088       instead of templates. However, many of these functions may be
00089       templates anyway when I generalize this class to hold floats or
00090       ints rather than just doubles. 
00091       \endcomment
00092   */
00093   class tensor_old {
00094 
00095 #ifndef DOXYGEN_INTERNAL
00096 
00097   protected:
00098 
00099     /// The data
00100     double *data;
00101 
00102     /// A rank-sized array of the sizes of each dimension
00103     size_t *size;
00104 
00105     /// Rank
00106     size_t rk;
00107 
00108 #endif
00109 
00110   public:
00111     
00112     /// Create an empty tensor_old with zero rank
00113     tensor_old() {
00114       rk=0;
00115       data=0;
00116       size=0;
00117     }
00118 
00119     /** \brief Create a tensor_old of rank \c rank with sizes given in \c dim
00120         
00121         The parameter \c dim must be a pointer to an array of sizes
00122         with length \c rank. If the user requests any of the sizes to
00123         be zero, this constructor will call the error handler, create
00124         an empty tensor_old, and will allocate no memory.
00125     */
00126     template<class uint_vec_t> 
00127       tensor_old(size_t rank, const uint_vec_t &dim) {
00128       if (rank==0) {
00129         data=0;
00130         size=0;
00131       } else {
00132         for(size_t i=0;i<rk;i++) {
00133           if (dim[i]==0) {        
00134             rk=0;
00135             O2SCL_ERR2("Requested zero size with non-zero rank in ",
00136                        "tensor_old::tensor_old<>(size_t, uint_vec_t &)",gsl_einval);
00137           }
00138         }
00139         rk=rank;
00140         size=new size_t[rk];
00141         size_t tot=1;
00142         for(size_t i=0;i<rk;i++) {
00143           size[i]=dim[i];
00144           tot*=size[i];
00145         }
00146         data=new double[tot];
00147       }
00148     }
00149 
00150     ~tensor_old() {
00151       if (rk>0) {
00152         delete[] size;
00153         delete[] data;
00154         rk=0;
00155       }
00156     }
00157 
00158     /// \name Set functions
00159     //@{
00160     /// Set the element indexed by \c index to value \c val
00161     template<class uint_vec_t>
00162       void set(const uint_vec_t &index, double val) {
00163 #if O2SCL_NO_RANGE_CHECK
00164 #else
00165       if (rk==0) {
00166         O2SCL_ERR("Empty tensor_old in set().",gsl_einval);
00167         return;
00168       }
00169       if (index[0]>=size[0]) {
00170         O2SCL_ERR("Index greater than size in set().",gsl_eindex);
00171         return;
00172       }
00173 #endif
00174       size_t ix=index[0];
00175       for(size_t i=1;i<rk;i++) {
00176 #if O2SCL_NO_RANGE_CHECK
00177 #else
00178         if (index[i]>=size[i]) {
00179           O2SCL_ERR("Index greater than size in get().",gsl_eindex);
00180           return;
00181         }
00182 #endif
00183         ix*=size[i];
00184         ix+=index[i];
00185       }
00186       data[ix]=val;
00187       return;
00188     }
00189 
00190     /// Set all elements in a tensor_old to some fixed value
00191     void set_all(double x) {
00192       for(size_t i=0;i<total_size();i++) data[i]=x;
00193       return;
00194     }
00195     //@}
00196 
00197     /// \name Get functions
00198     //@{
00199     /// Get the element indexed by \c index
00200     template<class uint_vec_t> double &get(const uint_vec_t &index) {
00201 #if O2SCL_NO_RANGE_CHECK
00202 #else
00203       if (rk==0) {
00204         O2SCL_ERR("Empty tensor_old in get().",gsl_einval);
00205         return data[0];
00206       }
00207       if (index[0]>=size[0]) {
00208         O2SCL_ERR("Index greater than size in get().",gsl_eindex);
00209         return data[0];
00210       }
00211 #endif
00212       size_t ix=index[0];
00213       for(size_t i=1;i<rk;i++) {
00214 #if O2SCL_NO_RANGE_CHECK
00215 #else
00216         if (index[i]>=size[i]) {
00217           O2SCL_ERR("Index greater than size in get().",gsl_eindex);
00218           return data[0];
00219         }
00220 #endif
00221         ix*=size[i];
00222         ix+=index[i];
00223       }
00224       return data[ix];
00225     }
00226 
00227     /// Get a const reference to the element indexed by \c index
00228     template<class uint_vec_t> 
00229       double const &get(const uint_vec_t &index) const {
00230 #if O2SCL_NO_RANGE_CHECK
00231 #else
00232       if (rk==0) {
00233         O2SCL_ERR("Empty tensor_old in get().",gsl_einval);
00234         return data[0];
00235       }
00236       if (index[0]>=size[0]) {
00237         O2SCL_ERR("Index greater than size in get().",gsl_eindex);
00238         return data[0];
00239       }
00240 #endif
00241       size_t ix=index[0];
00242       for(size_t i=1;i<rk;i++) {
00243 #if O2SCL_NO_RANGE_CHECK
00244 #else
00245         if (index[i]>=size[i]) {
00246           O2SCL_ERR("Index greater than size in get().",gsl_eindex);
00247           return data[0];
00248         }
00249 #endif
00250         ix*=size[i];
00251         ix+=index[i];
00252       }
00253       return data[ix];
00254     }
00255     //@}
00256     
00257     /// \name Slice functions
00258     //@{
00259     /** \brief Fix all but one index to create a vector
00260 
00261         This fixes all of the indices to the values given in \c index
00262         except for the index number \c ix, and returns the
00263         corresponding vector, whose length is equal to the size of the
00264         tensor_old in that index. The value <tt>index[ix]</tt> is ignored.
00265 
00266         For example, for a rank 3 tensor_old allocated with
00267         \code
00268         tensor_old t;
00269         size_t dim[3]={3,4,5};
00270         t.tensor_old_allocate(3,dim);
00271         \endcode
00272         the following code
00273         \code
00274         size_t index[3]={1,0,3};
00275         ovector_view v=t.vector_slice(1,index);
00276         \endcode
00277         Gives a vector \c v of length 4 which refers to the values
00278         <tt>t(1,0,3)</tt>, <tt>t(1,1,3)</tt>, <tt>t(1,2,3)</tt>, and
00279         <tt>t(1,3,3)</tt>.
00280     */
00281     template<class uint_vec_t> 
00282       ovector_array_stride vector_slice(size_t ix, const uint_vec_t &index) {
00283       if (ix+1>rk) {
00284         O2SCL_ERR("Specified index to large in tensor_old::vector_slice()",
00285                   gsl_einval);
00286       }
00287       size_t start;
00288       if (ix==0) start=0;
00289       else start=index[0];
00290       for(size_t i=1;i<rk;i++) {
00291         start*=size[i];
00292         if (i!=ix) start+=index[i];
00293       }
00294       size_t stride=1;
00295       for(size_t i=ix+1;i<rk;i++) stride*=size[i];
00296       return ovector_array_stride(size[ix],data+start,stride);
00297     }
00298 
00299     /** \brief Fix all but two indices to create a matrix
00300 
00301         This fixes all of the indices to the values given in \c index
00302         except for the index number \c ix and the last index, and
00303         returns the corresponding matrix, whose size is equal to the
00304         size of the tensor_old in the two indices which are not fixed.
00305 
00306         Since the last index is always fixed, the parameter \c ix
00307         is limited to be \f$ \in [0,\mathrm{rank}-2] \f$.
00308     */
00309     template<class uint_vec_t> 
00310       omatrix_array matrix_slice(size_t ix, const uint_vec_t &index) {
00311       if (ix+1>=rk) {
00312         O2SCL_ERR("Specified index to large in tensor_old::matrix_slice()",
00313                   gsl_einval);
00314       }
00315       size_t start=0, tot=size[0];
00316       for(size_t i=1;i<rk;i++) {
00317         tot*=size[i];
00318       }
00319       // This O(rank^2) algorithm could possibly 
00320       // be replaced with a O(rank) one in the future
00321       for(size_t i=0;i<rk-1;i++) {
00322         if (i!=ix) {
00323           size_t adj=index[i];
00324           for(size_t j=i+1;j<rk;j++) adj*=size[j];
00325           start+=adj;
00326         }
00327       }
00328       size_t tda=1;
00329       if (ix==rk-1) {
00330         tda=0;
00331       } else {
00332         for(size_t i=ix+1;i<rk;i++) tda*=size[i];
00333       }
00334       return omatrix_array(data+start,tda,size[ix],size[rk-1]);
00335     }
00336     //@}
00337 
00338     /// \name Memory allocation
00339     //@{
00340     /** \brief Allocate space for a tensor_old of rank \c rank with sizes
00341         given in \c dim
00342         
00343         The parameter \c dim must be a pointer to an array of sizes
00344         with length \c rank. 
00345 
00346         If memory was previously allocated, it will be freed before
00347         the new allocation.
00348 
00349         If the user requests any of the sizes to be zero, this
00350         function will call the error handler and will allocate no
00351         memory. If memory was previously allocated, the tensor_old is left
00352         unmodified and no deallocation is performed.
00353     */
00354     template<class uint_vec_t> 
00355       void tensor_old_allocate(size_t rank, const uint_vec_t &dim) {
00356       for(size_t i=0;i<rk;i++) {
00357         if (dim[i]==0) {
00358           O2SCL_ERR2("Requested zero size in tensor_old::",
00359                      "tensor_old(size_t, size_t *)",gsl_einval);
00360         }
00361       }
00362       if (rk>0) tensor_old_free();
00363       rk=rank;
00364       size=new size_t[rk];
00365       size_t tot=1;
00366       for(size_t i=0;i<rk;i++) {
00367         size[i]=dim[i];
00368         tot*=size[i];
00369       }
00370       data=new double[tot];
00371       return;
00372     }
00373 
00374     /// Free allocated space (also sets rank to zero)
00375     void tensor_old_free() {
00376       if (rk>0) {
00377         delete[] size;
00378         delete[] data;
00379         rk=0;
00380       }
00381       return;
00382     }
00383     //@}
00384 
00385     /// \name Size functions
00386     //@{
00387     /// Return the rank of the tensor_old
00388     size_t get_rank() const { return rk; }
00389 
00390     /// Returns the size of the ith index
00391     size_t get_size(size_t i) const { 
00392       if (i<rk) {
00393         return size[i]; 
00394       }
00395       O2SCL_ERR_RET("Requested index exceeding rank in get_size()",
00396                     gsl_einval);
00397     }
00398     
00399     /// Return the full array of sizes
00400     const size_t *get_size_arr() const {
00401       return size;
00402     }
00403 
00404     /// Return the full array of sizes
00405     const double *get_data() const {
00406       return data;
00407     }
00408 
00409 #ifndef DOXYGENP
00410     // For HDF I/O. Undocumented. Probably should be replaced by
00411     // friend function or something else?
00412     double *get_data_non_const() {
00413       return data;
00414     }
00415 #endif
00416 
00417     /** \brief Returns the size of the tensor_old (the product of 
00418         the sizes over every index)
00419     */
00420     size_t total_size() const { 
00421       if (rk==0) return 0;
00422       size_t tot=1;
00423       for(size_t i=0;i<rk;i++) tot*=size[i];
00424       return tot;
00425     }
00426     //@}
00427 
00428     /// \name Index manipulation
00429     //@{
00430     /// Pack the indices into a single array index
00431     template<class uint_vec_t> 
00432       size_t pack_indices(const uint_vec_t &index) {
00433       if (rk==0) {
00434         O2SCL_ERR("Empty tensor_old in pack_indices().",gsl_einval);
00435         return 0;
00436       }
00437       if (index[0]>=size[0]) {
00438         O2SCL_ERR("Index greater than size in pack_indices().",gsl_eindex);
00439         return 0;
00440       }
00441       size_t ix=index[0];
00442       for(size_t i=1;i<rk;i++) {
00443         if (index[i]>=size[i]) {
00444           O2SCL_ERR("Index greater than size in pack_indices().",gsl_eindex);
00445           return 0;
00446         }
00447         ix*=size[i];
00448         ix+=index[i];
00449       }
00450       return ix;
00451     }
00452     
00453     /// Unpack the single array index into indices
00454     template<class uint_vec_t> 
00455       void unpack_indices(size_t ix, uint_vec_t &index) {
00456       if (ix>total_size()) {
00457         O2SCL_ERR("Index greater than total size in unpack_indices().",
00458                   gsl_eindex);
00459         return;
00460       }
00461       size_t ix2, sub_size;
00462       for(size_t i=0;i<rk;i++) {
00463         if (i==rk-1) {
00464           index[i]=ix;
00465         } else {
00466           sub_size=1;
00467           for(size_t j=i+1;j<rk;j++) sub_size*=size[j];
00468           index[i]=ix/sub_size;
00469           // (Remember we're doing integer arithmetic here.)
00470           ix-=sub_size*(ix/sub_size);
00471         }
00472       }
00473       return;
00474     }
00475     //@}
00476 
00477   };
00478 
00479   /** \brief Tensor_Old class with arbitrary dimensions with a grid
00480 
00481       This tensor_old class allows one to assign the indexes to 
00482       numerical scales, so that n-dimensional interpolation can
00483       be performed. To set the grid, use set_grid() and then
00484       interpolation can be done using interpolate().
00485       
00486       By convention, member functions ending in the _val 
00487       suffix return the closest grid-point to some user-specified
00488       values. 
00489 
00490       \comment
00491       I like how hist_new only allows you to set the
00492       grid if it's the same size as the old grid or the tensor_old
00493       is empty. This same practice could be applied here, to
00494       force the user to clear the tensor_old before resetting the grid.
00495       (10/24/11 - Actually, maybe this is a bad idea, because
00496       this class is more analogous to ovector, which doesn't
00497       behave this way.)
00498       \endcomment
00499 
00500       \future Only allocate space for grid if it is set
00501       \future Could implement arithmetic operators + and - and some
00502       different products.
00503       \future Consider creating a set_grid() function which
00504       takes grids from an object like hist_grid. Maybe make a 
00505       constructor for a tensor_old_grid object which just takes 
00506       as input a set of grids?
00507   */
00508   class tensor_old_grid : public tensor_old {
00509 
00510 #ifndef DOXYGEN_INTERNAL
00511 
00512   protected:
00513 
00514     /// A rank-sized set of arrays for the grid points
00515     double **grd;
00516 
00517     /// If true, the grid has been set by the user
00518     bool grid_set;
00519     
00520     /// The interpolation manager
00521     base_interp_mgr<double *> *bim1;
00522 
00523     /// The subvector interpolation manager
00524     base_interp_mgr<array_const_subvector> *bim2;
00525 
00526 #endif
00527 
00528   public:
00529     
00530     /// Create an empty tensor_old with zero rank
00531   tensor_old_grid() : tensor_old() {
00532       grd=0;
00533       grid_set=false;
00534       bim1=&dim1;
00535       bim2=&dim2;
00536     }
00537     
00538     /** \brief Create a tensor_old of rank \c rank with sizes given in \c dim
00539         
00540         The parameter \c dim must be a pointer to an array of sizes
00541         with length \c rank. If the user requests any of the sizes to
00542         be zero, this constructor will call the error handler, create
00543         an empty tensor_old, and will allocate no memory.
00544     */
00545     template<class uint_vec_t> 
00546       tensor_old_grid(size_t rank, const uint_vec_t &dim) : tensor_old(rank,dim) {
00547       grid_set=false;
00548       for(size_t i=0;i<rk;i++) {
00549         if (dim[i]==0) {
00550           rk=0;
00551           O2SCL_ERR("Requested zero size in tensor_old::tensor_old(size_t, size_t *)",
00552                     gsl_einval);
00553         }
00554       }
00555       grd=new double *[rk];
00556       for(size_t i=0;i<rk;i++) {
00557         grd[i]=new double[size[i]];
00558       }
00559     }
00560 
00561     ~tensor_old_grid() {
00562       if (rk>0) {
00563         for(size_t i=0;i<rk;i++) delete[] grd[i];
00564         delete[] size;
00565         delete[] data;
00566         rk=0;
00567       }
00568     }
00569 
00570     /// \name Set functions
00571     //@{
00572     /// Set the element closest to grid point \c grdp to value \c val
00573     template<class vec_t> 
00574       int set_val(const vec_t &grdp, double val) {
00575 
00576       // Find indices
00577       size_t *index=new size_t[rk];
00578       for(size_t i=0;i<rk;i++) index[i]=lookup_grid(i,grdp[i]);
00579       
00580       // Pack
00581       size_t ix=index[0];
00582       for(size_t i=1;i<rk;i++) {
00583         ix*=size[i];
00584         ix+=index[i];
00585       }
00586 
00587       // Delete memory for indices
00588       delete[] index;
00589 
00590       // Set value
00591       data[ix]=val;
00592 
00593       return 0;
00594     }
00595 
00596     /** \brief Set the element closest to grid point \c grdp to value 
00597         \c val
00598         
00599         The parameters \c closest and \c grdp may be identical,
00600         allowing one to update a vector \c grdp with the
00601         closest grid point.
00602     */
00603     template<class vec_t, class vec2_t> 
00604       int set_val(const vec_t &grdp, double val, vec2_t &closest) {
00605 
00606       // Find indices
00607       size_t *index=new size_t[rk];
00608       for(size_t i=0;i<rk;i++) {
00609         index[i]=lookup_grid_val(i,grdp[i],closest[i]);
00610       }
00611       
00612       // Pack
00613       size_t ix=index[0];
00614       for(size_t i=1;i<rk;i++) {
00615         ix*=size[i];
00616         ix+=index[i];
00617       }
00618 
00619       // Delete memory for indices
00620       delete[] index;
00621 
00622       // Set value
00623       data[ix]=val;
00624 
00625       return 0;
00626     }
00627     //@}
00628 
00629     /// \name Get functions
00630     //@{
00631     /// Get the element closest to grid point \c grdp 
00632     template<class vec_t> 
00633       double get_val(const vec_t &grdp) {
00634       
00635       // Find indices
00636       size_t *index=new size_t[rk];
00637       for(size_t i=0;i<rk;i++) index[i]=lookup_grid(i,grdp[i]);
00638 
00639       // Pack
00640       size_t ix=index[0];
00641       for(size_t i=1;i<rk;i++) {
00642         ix*=size[i];
00643         ix+=index[i];
00644       }
00645 
00646       // Delete memory for indices
00647       delete[] index;
00648 
00649       // Set value
00650       return data[ix];
00651     }
00652 
00653     /// Get the element closest to grid point \c grdp to value \c val
00654     template<class vec_t, class vec2_t> 
00655       double get_val(const vec_t &grdp, const vec2_t &closest) {
00656       
00657       // Find indices
00658       size_t *index=new size_t[rk];
00659       for(size_t i=0;i<rk;i++) {
00660         index[i]=lookup_grid_val(i,grdp[i],closest[i]);
00661       }
00662       
00663       // Pack
00664       size_t ix=index[0];
00665       for(size_t i=1;i<rk;i++) {
00666         ix*=size[i];
00667         ix+=index[i];
00668       }
00669 
00670       // Delete memory for indices
00671       delete[] index;
00672 
00673       // Set value
00674       return data[ix];
00675     }
00676     //@}
00677     
00678     /// \name Memory allocation
00679     //@{
00680     /** \brief Allocate space for a tensor_old of rank \c rank with sizes
00681         given in \c dim
00682         
00683         The parameter \c dim must be a pointer to an array of sizes
00684         with length \c rank. 
00685 
00686         If memory was previously allocated, it will be freed before
00687         the new allocation and previously specified grid data will 
00688         be lost.
00689 
00690         If the user requests any of the sizes to be zero, this
00691         function will call the error handler and will allocate no
00692         memory. If memory was previously allocated, the tensor_old is left
00693         unmodified and no deallocation is performed.
00694     */
00695     template<class uint_vec_t>
00696       int tensor_old_allocate(size_t rank, const uint_vec_t &dim) {
00697       for(size_t i=0;i<rk;i++) {
00698         if (dim[i]==0) {
00699           O2SCL_ERR2_RET("Requested zero size in ",
00700                          "tensor_old::tensor_old(size_t,uint_vec_t &)",gsl_einval);
00701         }
00702       }
00703       if (rk>0) tensor_old_free();
00704       rk=rank;
00705       size=new size_t[rk];
00706       grd=new double *[rk];
00707       size_t tot=1;
00708       for(size_t i=0;i<rk;i++) {
00709         size[i]=dim[i];
00710         grd[i]=new double[size[i]];
00711         tot*=size[i];
00712       }
00713       data=new double[tot];
00714       return 0;
00715     }
00716 
00717     /// Free allocated space (also sets rank to zero)
00718     int tensor_old_free() {
00719       if (rk>0) {
00720         for(size_t i=0;i<rk;i++) delete[] grd[i];
00721         delete[] size;
00722         delete[] grd;
00723         delete[] data;
00724         rk=0;
00725       }
00726       return 0;
00727     }
00728     //@}
00729 
00730     /// \name Grid manipulation
00731     //@{
00732     /// Return true if the grid has been set
00733     bool is_grid_set() const { return grid_set; }
00734 
00735     /** \brief Set the grid
00736 
00737         The grid must be specified for all of the dimensions at
00738         once. Denote \f$ (\mathrm{size})_0 \f$ as the size
00739         of the first dimension, \f$ (\mathrm{size})_1 \f$ as the
00740         size of the second dimesion, and so on. Then the 
00741         first \f$ (\mathrm{size})_0 \f$ entries in \c grid must
00742         be the grid for the first dimension, the next 
00743         \f$ (\mathrm{size})_1 \f$ entries must be the grid
00744         for the second dimension, and so on. Thus \c grid
00745         must be a vector of size
00746         \f[
00747         \sum_{i=0}^{\mathrm{rank}} (\mathrm{size})_i
00748         \f]
00749 
00750         Note that the grid is copied so the function argument may
00751         be destroyed by the user after calling set_grid() without
00752         affecting the tensor_old grid. 
00753 
00754         \future Define a more generic interface for matrix types
00755     */
00756     template<class vec_t>
00757       int set_grid(const vec_t &grid) {
00758       if (rk==0) {
00759         O2SCL_ERR2_RET("Tried to set grid for empty tensor_old in ",
00760                        "tensor_old_grid::set_grid().",gsl_einval);
00761       }
00762       size_t ix=0;
00763       for(size_t i=0;i<rk;i++) {
00764         for(size_t j=0;j<size[i];j++) {
00765           grd[i][j]=grid[ix];
00766           ix++;
00767         }
00768       }
00769       grid_set=true;
00770       return 0;
00771     }
00772 
00773 #ifndef DOXGYENP
00774     // Temporary(?). Undocumented for now. 
00775     int set_grid_old(double **vals) {
00776       for(size_t i=0;i<rk;i++) {
00777         for(size_t j=0;j<size[i];j++) {
00778           grd[i][j]=vals[i][j];
00779         }
00780       }
00781       grid_set=true;
00782       return 0;
00783     }
00784 #endif
00785 
00786     /// Lookup index for grid closest to \c val
00787     size_t lookup_grid(size_t i, double val) {
00788       if (i<rk && grid_set) {
00789         size_t best=0;
00790         double min=fabs(grd[i][0]-val);
00791         for(size_t j=0;j<size[i];j++) {
00792           if (fabs(grd[i][j]-val)<min) {
00793             best=j;
00794             min=fabs(grd[i][j]-val);
00795           }
00796         }
00797         return best;
00798       }
00799       return 0;
00800     }
00801 
00802     /// Lookup index for grid closest to \c val
00803     double get_grid(size_t i, size_t j) const {
00804       if (i<rk && grid_set) {
00805         return grd[i][j];
00806       }
00807       return 0;
00808     }
00809 
00810     /** \brief Lookup indices for grid closest point to \c vals
00811 
00812         The values in \c vals are not modified by this function.
00813         
00814         \comment
00815         This function must have a different name than 
00816         lookup_grid() because the template types cause
00817         confusion between the two functions.
00818         \endcomment
00819     */
00820     template<class vec_t, class uint_vec_t>
00821       int lookup_grid_vec(const vec_t &vals, 
00822                           const uint_vec_t &indices) const {
00823       for(size_t k=0;k<rk;k++) {
00824         indices[k]=0;
00825         double min=fabs(grd[k][0]-vals[k]);
00826         for(size_t j=0;j<size[k];j++) {
00827           if (fabs(grd[k][j]-vals[k])<min) {
00828             indices[k]=j;
00829             min=fabs(grd[k][j]-vals[k]);
00830           }
00831         }
00832       }
00833       return 0;
00834     }
00835 
00836     /// Lookup index for grid closest to \c val, returning the grid point
00837     size_t lookup_grid_val(size_t i, double &val, double &val2) {
00838       if (i<rk && grid_set) {
00839         size_t best=0;
00840         double min=fabs(grd[i][0]-val);
00841         val2=grd[i][0];
00842         for(size_t j=0;j<size[i];j++) {
00843           if (fabs(grd[i][j]-val)<min) {
00844             best=j;
00845             min=fabs(grd[i][j]-val);
00846             val2=grd[i][j];
00847           }
00848         }
00849         return best;
00850       }
00851       return 0;
00852     }
00853   
00854     /// \name Interpolation
00855     //@{
00856     def_interp_mgr<double *,linear_interp> dim1;
00857     def_interp_mgr<array_const_subvector,linear_interp> dim2;
00858 
00859     /// Set interpolation managers
00860     int set_interp(base_interp_mgr<double *> &bi1,
00861                    base_interp_mgr<array_const_subvector> &bi2) {
00862       bim1=&bi1;
00863       bim2=&bi2;
00864       return 0;
00865     }
00866 
00867     /** \brief Interpolate values \c vals into the tensor_old, 
00868         returning the result
00869       
00870         This is a quick and dirty implementation of n-dimensional
00871         interpolation by recursive application of the 1-dimensional
00872         routine from \ref smart_interp_vec, using the base
00873         interpolation object specified in the template parameter \c
00874         base_interp_t. This will be slow for sufficiently large data
00875         sets.
00876 
00877         \future Maybe make this a template as well?
00878 
00879         \future It should be straightforward to improve the scaling of
00880         this algorithm significantly by creating a "window" of local
00881         points around the point of interest. This could be done easily
00882         by constructing an initial subtensor_old. However, this should
00883         probably be superceded by a more generic alternative which
00884         avoids explicit use of the 1-d interpolation types.
00885     */
00886     double interpolate(double *vals) {
00887       typedef smart_interp_vec<double *,array_const_subvector,
00888         double *, pointer_alloc<double> > interp_t;
00889       
00890       if (rk==1) {
00891         
00892         sma_interp_vec<double *> si(size[0],grd[0],data);
00893         return si.interp(vals[0]);
00894 
00895       } else {
00896         
00897         // Get total number of interpolations at this level
00898         size_t ss=1;
00899         for(size_t i=1;i<rk;i++) ss*=size[i];
00900 
00901         // Create space for y vectors and interpolators
00902         double **yvec=new double *[ss];
00903         interp_t **si=new interp_t *[ss];
00904         for(size_t i=0;i<ss;i++) yvec[i]=new double[size[0]];
00905         
00906         // Create space for interpolation results
00907         tensor_old_grid tdat;
00908         tdat.tensor_old_allocate(rk-1,size+1);
00909 
00910         // Set grid for temporary tensor_old
00911         tdat.set_grid_old(grd+1);
00912 
00913         // Create starting coordinate and counter
00914         size_t *co=new size_t[rk];
00915         for(size_t i=0;i<rk;i++) co[i]=0;
00916         size_t cnt=0;
00917 
00918         // Loop over every interpolation
00919         bool done=false;
00920         while(done==false) {
00921 
00922           // Fill yvector with the appropriate data
00923           for(size_t i=0;i<size[0];i++) {
00924             co[0]=i;
00925             yvec[cnt][i]=get(co);
00926           }
00927         
00928           si[cnt]=new interp_t(*bim1,*bim2,size[0],grd[0],yvec[cnt]);
00929           
00930           tdat.set(co+1,si[cnt]->interp(vals[0]));
00931 
00932           // Go to next interpolation
00933           cnt++;
00934           co[rk-1]++;
00935           // carry if necessary
00936           for(int j=rk-1;j>0;j--) {
00937             if (co[j]>=size[j]) {
00938               co[j]=0;
00939               co[j-1]++;
00940             }
00941           }
00942 
00943           // Test if done
00944           if (cnt==ss) done=true;
00945 
00946           // End of while loop
00947         }
00948       
00949         // Now call the next level of interpolation
00950         double res=tdat.interpolate(vals+1);
00951         
00952         tdat.tensor_old_free();
00953         for(size_t i=0;i<ss;i++) {
00954           delete[] yvec[i];
00955           delete si[i];
00956         }
00957         delete[] co;
00958         delete[] si;
00959         delete[] yvec;
00960 
00961         return res;
00962       }
00963     }
00964     //@}
00965 
00966   };
00967 
00968   /** \brief Rank 1 tensor_old
00969    */
00970   class tensor_old1 : public tensor_old {
00971   public:
00972     
00973     /// Create an empty tensor_old
00974   tensor_old1() : tensor_old() {}
00975 
00976     /// Create a rank 1 tensor_oldy of size \c sz
00977   tensor_old1(size_t sz) : tensor_old(1,&sz) {}
00978         
00979     /// Get the element indexed by \c ix
00980     double &get(size_t ix) { return tensor_old::get(&ix); }
00981 
00982     /// Get the element indexed by \c ix
00983     const double &get(size_t ix) const { return tensor_old::get(&ix); }
00984         
00985     /// Set the element indexed by \c index to value \c val
00986     void set(size_t index, double val) 
00987     { tensor_old::set(&index,val); }
00988     
00989     /** \brief Set the element indexed by \c index to value \c val
00990 
00991         (We have to explicitly provide this version since the set()
00992         function is overloaded in this child of \ref tensor_old.)
00993     */
00994     void set(size_t *index, double val) {
00995       tensor_old::set(index,val);
00996     }
00997 
00998     /// Get an element using array-like indexing
00999     double &operator[](size_t ix) { return this->data[ix]; }
01000     
01001     /// Get an element using operator()
01002     double &operator()(size_t ix) { return this->data[ix]; }
01003   };
01004 
01005   /** \brief Rank 2 tensor_old with a grid
01006    */
01007   class tensor_old_grid1 : public tensor_old_grid {
01008      
01009   public:
01010      
01011     /// Create an empty tensor_old
01012   tensor_old_grid1() : tensor_old_grid() {}
01013       
01014     /// Create a rank 2 tensor_old of size \c (sz,sz2,sz3)
01015   tensor_old_grid1(size_t sz) : tensor_old_grid() {
01016       this->rk=1;
01017       this->size=new size_t[1];
01018       this->grd=new double *[1];
01019       this->size[0]=sz;
01020       this->grd[0]=new double[sz];
01021       size_t tot=sz;
01022       this->data=new double[tot];
01023       this->grid_set=false;
01024     }
01025    
01026     ~tensor_old_grid1() {
01027       if (this->rk>0) {
01028         for(size_t i=0;i<this->rk;i++) {
01029           delete[] this->grd[i];
01030         }
01031         delete[] this->size;
01032         delete[] this->grd;
01033         delete[] this->data;
01034         this->rk=0;
01035       }
01036     }
01037    
01038     /// Get the element indexed by \c (ix1)
01039     double &get(size_t ix1) { 
01040       size_t sz[1]={ix1};
01041       return tensor_old_grid ::get(sz); 
01042     }
01043 
01044     /// Get the element indexed by \c (ix1)
01045     const double &get(size_t ix1) const { 
01046       size_t sz[1]={ix1};
01047       return tensor_old_grid ::get(sz); 
01048     }
01049  
01050     /// Set the element indexed by \c (ix1) to value \c val
01051     void set(size_t ix1, double val) {
01052       size_t sz[1]={ix1};
01053       tensor_old_grid ::set(sz,val); 
01054     }
01055 
01056     /// Interpolate \c x and return the results
01057     double interp(double x) {
01058       return interpolate(&x);
01059     }
01060   };
01061 
01062   /** \brief Rank 2 tensor_old
01063    */
01064   class tensor_old2 : public tensor_old {
01065   public:
01066 
01067     /// Create an empty tensor_old
01068   tensor_old2() : tensor_old() {}
01069 
01070     /// Create a rank 2 tensor_old of size \c (sz,sz2)
01071   tensor_old2(size_t sz, size_t sz2) : tensor_old() {
01072       this->rk=2;
01073       this->size=new size_t[2];
01074       this->size[0]=sz;
01075       this->size[1]=sz2;
01076       size_t tot=sz*sz2;
01077       this->data=new double[tot];
01078     }
01079         
01080     /// Get the element indexed by \c (ix1,ix2)
01081     double &get(size_t ix1, size_t ix2) { 
01082       size_t sz[2]={ix1,ix2};
01083       return tensor_old::get(sz); 
01084     }
01085 
01086     /// Get the element indexed by \c (ix1,ix2)
01087     const double &get(size_t ix1, size_t ix2) const { 
01088       size_t sz[2]={ix1,ix2};
01089       return tensor_old::get(sz); 
01090     }
01091 
01092     /// Set the element indexed by \c (ix1,ix2) to value \c val
01093     void set(size_t ix1, size_t ix2, double val) {
01094       size_t sz[2]={ix1,ix2};
01095       tensor_old::set(sz,val); 
01096       return;
01097     }
01098 
01099     /** \brief Set the element indexed by \c index to value \c val
01100 
01101         (We have to explicitly provide this version since the set()
01102         function is overloaded in this child of \ref tensor_old.)
01103     */
01104     void set(size_t *index, double val) {
01105       tensor_old::set(index,val);
01106       return;
01107     }
01108 
01109     /// Get the element indexed by \c (ix1,ix2)
01110     double &operator()(size_t ix, size_t iy) 
01111     { return this->data[ix*this->size[1]+iy]; }
01112   };
01113   
01114   /** \brief Rank 2 tensor_old with a grid
01115    */
01116   class tensor_old_grid2 : public tensor_old_grid {
01117      
01118   public:
01119      
01120     /// Create an empty tensor_old
01121   tensor_old_grid2() : tensor_old_grid() {}
01122 
01123     /// Create a rank 2 tensor_old of size \c (sz,sz2)
01124   tensor_old_grid2(size_t sz, size_t sz2) : tensor_old_grid() {
01125       this->rk=2;
01126       this->size=new size_t[2];
01127       this->grd=new double *[2];
01128       this->size[0]=sz;
01129       this->size[1]=sz2;
01130       this->grd[0]=new double[sz];
01131       this->grd[1]=new double[sz2];
01132       size_t tot=sz*sz2;
01133       this->data=new double[tot];
01134       this->grid_set=false;
01135     }
01136    
01137     ~tensor_old_grid2() {
01138       if (this->rk>0) {
01139         for(size_t i=0;i<this->rk;i++) {
01140           delete[] this->grd[i];
01141         }
01142         delete[] this->size;
01143         delete[] this->grd;
01144         delete[] this->data;
01145         this->rk=0;
01146       }
01147     }
01148    
01149     /// Get the element indexed by \c (ix1,ix2)
01150     double &get(size_t ix1, size_t ix2) { 
01151       size_t sz[2]={ix1,ix2};
01152       return tensor_old_grid ::get(sz); 
01153     }
01154 
01155     /// Get the element indexed by \c (ix1,ix2)
01156     const double &get(size_t ix1, size_t ix2) const { 
01157       size_t sz[2]={ix1,ix2};
01158       return tensor_old_grid ::get(sz); 
01159     }
01160  
01161     /// Set the element indexed by \c (ix1,ix2) to value \c val
01162     void set(size_t ix1, size_t ix2, double val) {
01163       size_t sz[2]={ix1,ix2};
01164       tensor_old_grid ::set(sz,val); 
01165       return;
01166     }
01167 
01168     /// Interpolate \c (x,y) and return the results
01169     double interp(double x, double y) {
01170       double arr[2]={x,y};
01171       return interpolate(arr);
01172     }
01173   };
01174   
01175   /** \brief Rank 3 tensor_old
01176    */
01177   class tensor_old3 : public tensor_old {
01178   public:
01179 
01180     /// Create an empty tensor_old
01181   tensor_old3() : tensor_old() {}
01182 
01183     /// Create a rank 3 tensor_old of size \c (sz,sz2,sz3)
01184   tensor_old3(size_t sz, size_t sz2, size_t sz3) : tensor_old() {
01185       this->rk=3;
01186       this->size=new size_t[3];
01187       this->size[0]=sz;
01188       this->size[1]=sz2;
01189       this->size[2]=sz3;
01190       size_t tot=sz*sz2*sz3;
01191       this->data=new double[tot];
01192     }
01193         
01194     /// Get the element indexed by \c (ix1,ix2,ix3)
01195     double &get(size_t ix1, size_t ix2, size_t ix3) { 
01196       size_t sz[3]={ix1,ix2,ix3};
01197       return tensor_old::get(sz); 
01198     }
01199 
01200     /// Get the element indexed by \c (ix1,ix2,ix3)
01201     const double &get(size_t ix1, size_t ix2, size_t ix3) const { 
01202       size_t sz[3]={ix1,ix2,ix3};
01203       return tensor_old::get(sz); 
01204     }
01205 
01206     /// Set the element indexed by \c (ix1,ix2,ix3) to value \c val
01207     void set(size_t ix1, size_t ix2, size_t ix3, double val) {
01208       size_t sz[3]={ix1,ix2, ix3};
01209       tensor_old::set(sz,val); 
01210       return;
01211     }
01212 
01213     /** \brief Set the element indexed by \c index to value \c val
01214 
01215         (We have to explicitly provide this version since the set()
01216         function is overloaded in this child of \ref tensor_old.)
01217     */
01218     void set(size_t *index, double val) {
01219       tensor_old::set(index,val);
01220       return;
01221     }
01222   };
01223   
01224   /** \brief Rank 3 tensor_old with a grid
01225    */
01226   class tensor_old_grid3 : public tensor_old_grid {
01227      
01228   public:
01229      
01230     /// Create an empty tensor_old
01231   tensor_old_grid3() : tensor_old_grid () {}
01232 
01233     /// Create a rank 3 tensor_old of size \c (sz,sz2,sz3)
01234   tensor_old_grid3(size_t sz, size_t sz2, size_t sz3) : tensor_old_grid () {
01235       this->rk=3;
01236       this->size=new size_t[3];
01237       this->grd=new double *[3];
01238       this->size[0]=sz;
01239       this->size[1]=sz2;
01240       this->size[2]=sz3;
01241       this->grd[0]=new double[sz];
01242       this->grd[1]=new double[sz2];
01243       this->grd[2]=new double[sz3];
01244       size_t tot=sz*sz2*sz3;
01245       this->data=new double[tot];
01246       this->grid_set=false;
01247     }
01248    
01249     ~tensor_old_grid3() {
01250       if (this->rk>0) {
01251         for(size_t i=0;i<this->rk;i++) {
01252           delete[] this->grd[i];
01253         }
01254         delete[] this->size;
01255         delete[] this->grd;
01256         delete[] this->data;
01257         this->rk=0;
01258       }
01259     }
01260    
01261     /// Get the element indexed by \c (ix1,ix2,ix3)
01262     double &get(size_t ix1, size_t ix2, size_t ix3) { 
01263       size_t sz[3]={ix1,ix2,ix3};
01264       return tensor_old_grid ::get(sz); 
01265     }
01266  
01267     /// Get the element indexed by \c (ix1,ix2,ix3)
01268     const double &get(size_t ix1, size_t ix2, size_t ix3) const { 
01269       size_t sz[3]={ix1,ix2,ix3};
01270       return tensor_old_grid ::get(sz); 
01271     }
01272  
01273     /// Set the element indexed by \c (ix1,ix2,ix3) to value \c val
01274     void set(size_t ix1, size_t ix2, size_t ix3, double val) {
01275       size_t sz[3]={ix1,ix2, ix3};
01276       tensor_old_grid ::set(sz,val); 
01277       return;
01278     }
01279 
01280     /// Interpolate \c (x,y,z) and return the results
01281     double interp(double x, double y, double z) {
01282       double arr[3]={x,y,z};
01283       return interpolate(arr);
01284     }
01285   };
01286   
01287   /** \brief Rank 4 tensor_old
01288    */
01289   class tensor_old4 : public tensor_old {
01290 
01291   public:
01292 
01293     /// Create an empty tensor_old
01294   tensor_old4() : tensor_old() {}
01295 
01296     /// Create a rank 4 tensor_old of size \c (sz,sz2,sz3,sz4)
01297   tensor_old4(size_t sz, size_t sz2, size_t sz3, size_t sz4) : 
01298     tensor_old() {
01299       this->rk=4;
01300       this->size=new size_t[4];
01301       this->size[0]=sz;
01302       this->size[1]=sz2;
01303       this->size[2]=sz3;
01304       this->size[3]=sz4;
01305       size_t tot=sz*sz2*sz3*sz4;
01306       this->data=new double[tot];
01307     }
01308         
01309     /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
01310     double &get(size_t ix1, size_t ix2, size_t ix3, size_t ix4) { 
01311       size_t sz[4]={ix1,ix2,ix3,ix4};
01312       return tensor_old::get(sz); 
01313     }
01314 
01315     /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
01316     const double &get(size_t ix1, size_t ix2, size_t ix3, 
01317                       size_t ix4) const { 
01318       size_t sz[4]={ix1,ix2,ix3,ix4};
01319       return tensor_old::get(sz); 
01320     }
01321 
01322     /// Set the element indexed by \c (ix1,ix2,ix3,ix4) to value \c val
01323     void set(size_t ix1, size_t ix2, size_t ix3, size_t ix4, 
01324             double val) {
01325       size_t sz[4]={ix1,ix2,ix3,ix4};
01326       tensor_old::set(sz,val); 
01327       return;
01328     }
01329 
01330     /** \brief Set the element indexed by \c index to value \c val
01331 
01332         (We have to explicitly provide this version since the set()
01333         function is overloaded in this child of \ref tensor_old.)
01334     */
01335     void set(size_t *index, double val) {
01336       tensor_old::set(index,val);
01337       return;
01338     }
01339   };
01340 
01341   /** \brief Rank 4 tensor_old with a grid
01342    */
01343   class tensor_old_grid4 : public tensor_old_grid {
01344      
01345   public:
01346      
01347     /// Create an empty tensor_old
01348   tensor_old_grid4() : tensor_old_grid () {}
01349 
01350     /// Create a rank 4 tensor_old of size \c (sz,sz2,sz3,sz4)
01351   tensor_old_grid4(size_t sz, size_t sz2, size_t sz3,
01352                size_t sz4) : tensor_old_grid () {
01353       this->rk=4;
01354       this->size=new size_t[4];
01355       this->grd=new double *[4];
01356       this->size[0]=sz;
01357       this->size[1]=sz2;
01358       this->size[2]=sz3;
01359       this->size[3]=sz4;
01360       this->grd[0]=new double[sz];
01361       this->grd[1]=new double[sz2];
01362       this->grd[2]=new double[sz3];
01363       this->grd[3]=new double[sz4];
01364       size_t tot=sz*sz2*sz3*sz4;
01365       this->data=new double[tot];
01366       this->grid_set=false;
01367     }
01368    
01369     ~tensor_old_grid4() {
01370       if (this->rk>0) {
01371         for(size_t i=0;i<this->rk;i++) {
01372           delete[] this->grd[i];
01373         }
01374         delete[] this->size;
01375         delete[] this->grd;
01376         delete[] this->data;
01377         this->rk=0;
01378       }
01379     }
01380    
01381     /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
01382     double &get(size_t ix1, size_t ix2, size_t ix3, size_t ix4) { 
01383       size_t sz[4]={ix1,ix2,ix3,ix4};
01384       return tensor_old_grid ::get(sz); 
01385     }
01386     
01387     /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
01388     const double &get(size_t ix1, size_t ix2, size_t ix3,
01389                       size_t ix4) const { 
01390       size_t sz[4]={ix1,ix2,ix3,ix4};
01391       return tensor_old_grid ::get(sz); 
01392     }
01393     
01394     /// Set the element indexed by \c (ix1,ix2,ix3,ix4) to value \c val
01395     void set(size_t ix1, size_t ix2, size_t ix3, size_t ix4,
01396             double val) {
01397       size_t sz[4]={ix1,ix2,ix3,ix4};
01398       tensor_old_grid ::set(sz,val); 
01399       return;
01400     }
01401 
01402     /// Interpolate \c (x,y,z,a) and return the results
01403     double interp(double x, double y, double z, double a) {
01404       double arr[4]={x,y,z,a};
01405       return interpolate(arr);
01406     }
01407   };
01408   
01409 #ifndef DOXYGENP
01410 }
01411 #endif
01412 
01413 #endif
01414 
01415 
01416 
 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.