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