![]() |
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_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
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).