latest version v1.9 - last update 10 Apr 2010 |
00001 /* 00002 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 00003 * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany 00004 * 00005 * This file is part of the LTI-Computer Vision Library (LTI-Lib) 00006 * 00007 * The LTI-Lib is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public License (LGPL) 00009 * as published by the Free Software Foundation; either version 2.1 of 00010 * the License, or (at your option) any later version. 00011 * 00012 * The LTI-Lib is distributed in the hope that it will be 00013 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00014 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with the LTI-Lib; see the file LICENSE. If 00019 * not, write to the Free Software Foundation, Inc., 59 Temple Place - 00020 * Suite 330, Boston, MA 02111-1307, USA. 00021 */ 00022 00023 00024 /*---------------------------------------------------------------- 00025 * project ....: LTI Digital Image/Signal Processing Library 00026 * file .......: ltiTensor.h 00027 * authors ....: Pablo Alvarado 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 29.06.00 00030 * revisions ..: $Id: ltiTensor.h,v 1.6 2006/02/08 12:48:16 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_TENSOR_H_ 00034 #define _LTI_TENSOR_H_ 00035 00036 #include "ltiVector.h" 00037 #include "ltiMatrix.h" 00038 00039 namespace lti { 00040 /** 00041 * Tensor template class. 00042 * 00043 * The lti::tensor template container class allows the generation 00044 * multidimensional tables. If you only need first or second order 00045 * tensors, please use the lti::vector and lti::matrix instead (they 00046 * are more efficient!). 00047 * 00048 * The elements of the tensor will be indexed in each dimension \e i 00049 * between 0 an \f$n_i-1\f$. 00050 * 00051 * Example: 00052 * \code 00053 * lti::tensor<float> hist(3,10); // creates a 3rd order tensor with 10 00054 * // elements pro dimension. The total 00055 * // number of elements is 10^3=1000 00056 * \endcode 00057 * 00058 * To read the content of a tensor element use the access operator 00059 * at(). 00060 * 00061 * For tensors with order 0, the number of elements per dimension will be 00062 * ignored. 00063 * 00064 * @ingroup gAggregate 00065 */ 00066 template<class T> 00067 class tensor : public mathObject { 00068 public: 00069 /** 00070 * The iterator is equivalent to a lti::vector<T>::iterator 00071 */ 00072 typedef typename vector<T>::iterator iterator; 00073 00074 /** 00075 * The const_iterator is equivalent to a lti::vector<T>::const_iterator 00076 */ 00077 typedef typename vector<T>::const_iterator const_iterator; 00078 00079 /** 00080 * default constructor creates an empty tensor. 00081 */ 00082 tensor(); 00083 00084 /** 00085 * create a tensor of the given order. 00086 * 00087 * Each "dimension" will have the given number of elements, i.e. the tensor 00088 * will have \f$elements^{dimensions}\f$ elements. 00089 * 00090 * For tensors with order 0, the number of elements per dimension will be 00091 * ignored. 00092 * 00093 * @param order the order of the tensor. 00094 * @param elements the number of elements per dimension. 00095 */ 00096 tensor(const int& order,const int& elements); 00097 00098 /** 00099 * create a tensor of the given order. 00100 * 00101 * Each "dimension" \e i will have the number of elements indicated in 00102 * the \e i-th element of the vector <code>elements</code>. 00103 * 00104 * If the order differs from the size of the given vector, the 00105 * number of elements for the dimension \e i will be given by 00106 * \f$dim_i = elements[i \, mod \, elements.size()]\f$. 00107 * 00108 * This means, if you want a 6th-order tensor, and your elements-vector 00109 * has only three elements [10,15,5], the number of elements per dimension 00110 * will be [10,15,5,10,15,5] 00111 * 00112 * For tensors with order 0, the number of elements per dimension will be 00113 * ignored. 00114 * 00115 * @param order the order of the tensor 00116 * @param elements a vector with the number of elements per dimension 00117 */ 00118 tensor(const int& order,const ivector& elements); 00119 00120 /** 00121 * create this tensor as a copy of another tensor 00122 * @param other the tensor to be copied. 00123 */ 00124 tensor(const tensor<T>& other); 00125 00126 /** 00127 * destructor 00128 */ 00129 virtual ~tensor(); 00130 00131 /** 00132 * returns the name of this class: "tensor" 00133 */ 00134 const char* getTypeName() const {return "tensor";}; 00135 00136 /** 00137 * returns the order of this tensor 00138 */ 00139 inline int order() const; 00140 00141 /** 00142 * get the number of elements of the dimension <code>dim</code> 00143 * @param dimension the index of the dimension to be checked 00144 * @return the number of elements of the dimension specified by 00145 * <code>dim</code> 00146 */ 00147 inline const int& elementsInDimension(const int& dimension) const; 00148 00149 /** 00150 * get the number of elements per dimension 00151 */ 00152 inline const ivector& elementsPerDimension() const; 00153 00154 /** 00155 * returns a vector with the index of the first element of the tensor 00156 * (usually every element of the vector is 0) 00157 */ 00158 inline const ivector& getFirstIndex() const; 00159 00160 /** 00161 * returns a vector with the index to the last element of the tensor 00162 * (usually is the value returned by elementsPerDimension() minus (1,1,..1) 00163 */ 00164 inline const ivector& getLastIndex() const; 00165 00166 /** 00167 * returns an iterator pointing to the first element. 00168 * Note that you can not change the values of the tensor 00169 * elements when you use a const_iterator. See also begin() 00170 */ 00171 inline const_iterator begin() const { 00172 return theElements.begin(); 00173 }; 00174 00175 /** 00176 * returns an iterator pointing to the first element of the tensor. 00177 * The use of the interators is similar to the iterators of the 00178 * Standard Template Library (STL). 00179 * 00180 * If you need to iterate on all elements of the tensor, you can 00181 * use following code: 00182 * \code 00183 * int tmp,accu; // a temporal variable 00184 * lti::tensor<float> myTensor(3,10); // a 3rd order tensor with 00185 * // 10 elements/dim. (of type float) 00186 * lti::tensor<float>::iterator it; // an iterator 00187 * 00188 * for (it=myTensor.begin();it!=myTensor.end();it++) { 00189 * tmp = *it; // tmp has value of element pointed 00190 * // by the iterator. 00191 * accu += tmp; 00192 * (*it) = accu; // change the value in the tensor. 00193 * } 00194 * \endcode 00195 * 00196 * Please note that if you define <code>it</code> as a const_iterator, 00197 * you can not make something like <code>*it=accu</code>. 00198 */ 00199 inline iterator begin() { 00200 return theElements.begin(); 00201 } 00202 00203 /** 00204 * returns last index as a const iterator. 00205 * For an example see begin() 00206 */ 00207 inline const_iterator end() const { 00208 return theElements.end(); 00209 } 00210 00211 /** 00212 * returns last index as an iterator 00213 * For an example see begin() 00214 */ 00215 inline iterator end() { 00216 return theElements.end(); 00217 }; 00218 00219 /** 00220 * change the order and number of elements per dimension of the 00221 * tensor. All data will be lost! 00222 * 00223 * For tensors with order 0, the number of elements per dimension will be 00224 * ignored. 00225 * 00226 * @param order the new order of the tensor 00227 * @param elements the number of elements per dimension 00228 * @param initValue value to be copied at each element of the tensor 00229 * if the initData parameter is true 00230 * @param copyData copy the old data into the new tensor (WARNING: Not 00231 * implemented yet! (i.e. only false is correctly interpreted)) 00232 * @param initData initialize all data in the tensor with the value 00233 * specified in initValue. 00234 */ 00235 void resize(const int& order, 00236 const int& elements, 00237 const T& initValue = T(), 00238 const bool& copyData = false, 00239 const bool& initData = true); 00240 00241 /** 00242 * change the order and number of elements per dimension of the 00243 * tensor. All data will be lost! 00244 * 00245 * For tensors with order 0, the number of elements per dimension will be 00246 * ignored. 00247 * 00248 * @param order the new order of the tensor 00249 * @param elements the number of elements per dimension 00250 * @param initValue value to be copied at each element of the tensor 00251 * if the initData parameter is true 00252 * @param copyData copy the old data into the new tensor (WARNING: Not 00253 * implemented yet! (i.e. only false is correctly interpreted) 00254 * @param initData initialize all data in the tensor with the value 00255 * specified in initValue. 00256 */ 00257 void resize(const int& order, 00258 const ivector& elements, 00259 const T& initValue = T(), 00260 const bool& copyData = false, 00261 const bool& initData = true); 00262 00263 /** 00264 * transfer the data of this object into the receiver, leaving this 00265 * vector empty and the receiver as if a copy were done. 00266 * 00267 * This function makes a "memory block transfusion" to another 00268 * tensor. It is a very efficient way to make a copy of this 00269 * tensor, if you don't need the source data anymore! 00270 * 00271 * At the end of the detachment, this tensor will be empty. 00272 * 00273 * @param receiver the tensor that will receive the data 00274 */ 00275 void detach(tensor<T>& receiver); 00276 00277 /** 00278 * equivalent to resize(-1,0); 00279 */ 00280 void clear(); 00281 00282 /** 00283 * initialize all elements of the tensor with 0 (or another specified 00284 * number). 00285 */ 00286 void fill(const T& value = T(0)); 00287 00288 /** 00289 * fills the tensor elements with <code>iniValue</code> between 00290 * the n-dimensional points <code>from</code> and <code>to</code>. 00291 * @param iniValue the elements will be initialized with this 00292 * value. 00293 * @param from first element index 00294 * @param to last element index 00295 * 00296 * If <code>from</code> or <code>to</code> are out of bounds, 00297 * they will be (internaly) adjusted to a correct value. 00298 * 00299 * Example: 00300 * \code 00301 * lti::tensor<float> t(1,10); // first order tensor with 10 elements 00302 * t.clear(); 00303 * t.fill(9.0f,ivector(1,1),ivector(1,3)); // hist=[0,9,9,9,0,0,0,0,0,0] 00304 * \endcode 00305 */ 00306 void fill(const T& iniValue, 00307 const ivector& from, 00308 const ivector& to); 00309 00310 /** 00311 * read-only access to the element x of the tensor 00312 * @param x index of the tensor element to be accessed. It should 00313 * be between getFirstIndex() and getLastIndex() 00314 * @return a read-only reference to the element at index <code>x</code>. 00315 */ 00316 const T& at(const ivector& x) const; 00317 00318 /** 00319 * access element x of the tensor 00320 * @param x index of the tensor element to be accessed. It should 00321 * be between getFirstIndex() and getLastIndex() 00322 * @return a reference to the element at index <code>x</code>. 00323 */ 00324 T& at(const ivector& x); 00325 00326 /** 00327 * overload of the at() operator for zero-order tensors. 00328 * 00329 * This method is provided as a shortcut to avoid creating an empty vector 00330 * to access the zero-order tensor. If used with tensors of orders other 00331 * than zero, an assertion will be thrown (in debug mode) or an undefined 00332 * behaviour must be expected (in release mode). 00333 */ 00334 T& at(); 00335 00336 /** 00337 * overload of the at() operator for zero-order tensors. 00338 * 00339 * This method is provided as a shortcut to avoid creating an empty vector 00340 * to access the zero-order tensor. If used with tensors of orders other 00341 * than zero, an assertion will be thrown (in debug mode) or an undefined 00342 * behaviour must be expected (in release mode). 00343 */ 00344 const T& at() const; 00345 00346 /** 00347 * overload of the at() operator for first-order tensors. 00348 * 00349 * This method is provided as a shortcut to avoid creating a vector 00350 * with only one element to access the first-order tensor. If used 00351 * with tensors of orders other than one, an assertion will be 00352 * thrown (in debug mode) or an undefined behaviour must be 00353 * expected (in release mode). 00354 * 00355 * @param x equivalent to the first element of an index vector. 00356 */ 00357 T& at(const int& x); 00358 00359 /** 00360 * overload of the at() operator for first-order tensors. 00361 * 00362 * This method is provided as a shortcut to avoid creating a vector 00363 * with only one element to access the first-order tensor. If used 00364 * with tensors of orders other than one, an assertion will be 00365 * thrown (in debug mode) or an undefined behaviour must be 00366 * expected (in release mode). 00367 * 00368 * @param x equivalent to the first element of an index vector. 00369 */ 00370 const T& at(const int& x) const; 00371 00372 /** 00373 * overload of the at() operator for second-order tensors. 00374 * 00375 * This method is provided as a shortcut to avoid creating a vector 00376 * with only two elements to access the second-order tensor. If used 00377 * with tensors of orders other than two, an assertion will be 00378 * thrown (in debug mode) or an undefined behaviour must be 00379 * expected (in release mode). 00380 * 00381 * @param x equivalent to the first element of an index vector. 00382 * @param y equivalent to the second element of an index vector. 00383 */ 00384 T& at(const int& x,const int& y); 00385 00386 /** 00387 * overload of the at() operator for second-order tensors. 00388 * 00389 * This method is provided as a shortcut to avoid creating a vector 00390 * with only two elements to access the second-order tensor. If used 00391 * with tensors of orders other than two, an assertion will be 00392 * thrown (in debug mode) or an undefined behaviour must be 00393 * expected (in release mode). 00394 * 00395 * @param x equivalent to the first element of an index vector. 00396 * @param y equivalent to the second element of an index vector. 00397 */ 00398 const T& at(const int& x,const int& y) const; 00399 00400 /** 00401 * overload of the at() operator for third-order tensors. 00402 * 00403 * This method is provided as a shortcut to avoid creating a vector 00404 * with only three elements to access the third-order tensor. If used 00405 * with tensors of orders other than three, an assertion will be 00406 * thrown (in debug mode) or an undefined behaviour must be 00407 * expected (in release mode). 00408 * 00409 * @param x equivalent to the first element of an index vector. 00410 * @param y equivalent to the second element of an index vector. 00411 * @param z equivalent to the third element of an index vector. 00412 */ 00413 T& at(const int& x,const int& y,const int& z); 00414 00415 /** 00416 * overload of the at() operator for third-order tensors. 00417 * 00418 * This method is provided as a shortcut to avoid creating a vector 00419 * with only three elements to access the third-order tensor. If used 00420 * with tensors of orders other than three, an assertion will be 00421 * thrown (in debug mode) or an undefined behaviour must be 00422 * expected (in release mode). 00423 * 00424 * @param x equivalent to the first element of an index vector. 00425 * @param y equivalent to the second element of an index vector. 00426 * @param z equivalent to the third element of an index vector. 00427 */ 00428 const T& at(const int& x,const int& y,const int& z) const; 00429 00430 /** 00431 * assigment operator. 00432 * copy the contents of <code>other</code> in this %object. 00433 * @param other the source tensor to be copied. 00434 * @return a reference to this object 00435 */ 00436 tensor<T>& copy(const tensor<T>& other); 00437 00438 /** 00439 * copy the <code>other</code> tensor by casting each of its elements 00440 * @param other The tensor to be casted 00441 */ 00442 template<class U> 00443 tensor<T>& castFrom(const tensor<U>& other) { 00444 resize(other.dimensions(), other.elementsPerDimension()); 00445 00446 typename tensor<U>::const_iterator otherIt = other.begin(); 00447 typename tensor<U>::const_iterator endIt = other.end(); 00448 iterator thisIt = begin(); 00449 00450 for(;otherIt != endIt;++otherIt,++thisIt) { 00451 *thisIt = static_cast<T>(*otherIt); 00452 } 00453 00454 return (*this); 00455 }; 00456 00457 /** 00458 * create a clone of this tensor 00459 * @return a pointer to a copy of this tensor 00460 */ 00461 virtual mathObject* clone() const; 00462 00463 /** 00464 * compare this tensor with another one. 00465 * 00466 * @param other the other tensor to be compared with 00467 * @return true if both tensors have the same elements and same size 00468 */ 00469 bool equals(const tensor<T>& other) const; 00470 00471 /** compare this tensor with other 00472 * 00473 * @param other the other tensor to be compared with 00474 * @return true if both tensors have the same elements and same size 00475 */ 00476 inline bool operator==(const tensor<T>& other) const { 00477 return equals(other); 00478 }; 00479 00480 /** 00481 * compare this tensor with another one, and use the given tolerance to 00482 * determine if the value of each element of the other tensor 00483 * approximately equals the values of the actual tensor elements. 00484 * 00485 * An element \e x is approximately equal to another element \e y 00486 * with a tolerance \e t, if following equation holds: 00487 * <i>x</i>-t < <i>y</i> < <i>x</i>+t 00488 * 00489 * @param other the other tensor to be compared with 00490 * @param tolerance the tolerance to be used 00491 * 00492 * @return true if both tensors are approximatly equal 00493 */ 00494 bool prettyCloseTo(const tensor<T>& other, 00495 const T& tolerance) const; 00496 00497 /** 00498 * assigment operator (alias for copy(other)). 00499 * @param other the tensor to be copied 00500 * @return a reference to the actual tensor 00501 */ 00502 inline tensor<T>& operator=(const tensor<T>& other) {return copy(other);}; 00503 00504 /** 00505 * applies a C-function to each element of the tensor. 00506 * @param function a pointer to a C-function 00507 * @return a reference to the actual tensor 00508 */ 00509 tensor<T>& apply(T (*function)(T)); 00510 00511 /** 00512 * applies a C-function to each element of the tensor. 00513 * @param function a pointer to a C-function 00514 * @return a reference to the actual tensor 00515 */ 00516 tensor<T>& apply(T (*function)(const T&)); 00517 00518 /** 00519 * Elementwise multiplication. 00520 * Each element of this tensor will be multiplied with the elements 00521 * of the other tensor and the result will be left in this %object! 00522 * 00523 * @param other the other tensor to be multiplied with 00524 * @return a reference to the actual tensor 00525 */ 00526 tensor<T>& emultiply(const tensor<T>& other); 00527 00528 /** 00529 * Elementwise multiplication. 00530 * This tensor will contain the elementwise multiplication of the 00531 * elements in <code>first</code> and <code>second</code>. 00532 * 00533 * @param first the first tensor 00534 * @param second the second tensor will be multiplied with the 00535 * first tensor 00536 * @return a reference to the actual tensor 00537 */ 00538 tensor<T>& emultiply(const tensor<T>& first, 00539 const tensor<T>& second); 00540 00541 /** 00542 * Add another tensor of the same type and same order and 00543 * leave the result in this %object. 00544 * 00545 * @param other the other tensor to be added with 00546 * @return a reference to the actual tensor 00547 */ 00548 tensor<T>& add(const tensor<T>& other); 00549 00550 /** 00551 * Add two tensor and leave the result in this %object. 00552 * 00553 * @param first the first tensor. 00554 * @param second the second tensor will be added with the first 00555 * tensor 00556 * @return a reference to the actual tensor 00557 */ 00558 tensor<T>& add(const tensor<T>& first,const tensor<T>& second); 00559 00560 /** 00561 * Alias for add(const tensor& other) 00562 */ 00563 inline tensor<T>& operator+=(const tensor<T>& other) { 00564 return add(other); 00565 }; 00566 00567 /** 00568 * Subtracts another tensor of the same type and same order 00569 * and leaves the result in this %object 00570 * 00571 * @param other will be substracted from this tensor 00572 * @return a reference to the actual tensor 00573 */ 00574 tensor<T>& subtract(const tensor<T>& other); 00575 00576 /** 00577 * Subtracts two tensors and leaves the result in this %object. 00578 * @param first the first tensor 00579 * @param second the second tensor will be substracted from the 00580 * first tensor 00581 * @return a reference to the actual tensor 00582 */ 00583 tensor<T>& subtract(const tensor<T>& first, 00584 const tensor<T>& second); 00585 00586 /** 00587 * Alias for substract(const tensor& other) 00588 */ 00589 inline tensor<T>& operator-=(const tensor<T>& other) { 00590 return subtract(other); 00591 }; 00592 00593 /** 00594 * Multiply this tensor with a constant. 00595 * Returns this tensor. 00596 * 00597 * @param cst constant scalar to be multiplied with 00598 * @return a reference to the actual tensor 00599 */ 00600 tensor<T>& multiply(const T& cst); 00601 00602 /** 00603 * Multiply the other %tensor with a constant and leave the result here. 00604 * Returns a reference to this tensor. 00605 * 00606 * @param other the other tensor to be multiplied with the 00607 * constant value 00608 * @param cst constant scalar to be multiplied with the other tensor. 00609 * @return a reference to the actual tensor 00610 */ 00611 tensor<T>& multiply(const tensor<T>& other,const T& cst); 00612 00613 /** 00614 * alias for multiply(const T& cst) 00615 * @param cst constant scalar to be multiplied with 00616 * @return a reference to the actual tensor 00617 */ 00618 inline tensor<T>& operator*=(const T& cst) { 00619 return multiply(cst); 00620 }; 00621 00622 /** 00623 * Divide this tensor with a constant. 00624 * Returns this tensor. 00625 * 00626 * @param cst the elements of the tensor will be divided with this 00627 * constant 00628 * @return a reference to the actual tensor 00629 */ 00630 tensor<T>& divide(const T& cst); 00631 00632 /** 00633 * Divide the other tensor with a constant and leave the result here. 00634 * Returns a reference to this tensor. 00635 * 00636 * @param other the tensor to be divide by the constant value 00637 * @param cst the elements of the tensor will be divided with this 00638 * constant 00639 * @return a reference to the actual tensor 00640 */ 00641 tensor<T>& divide(const tensor<T>& other,const T& cst); 00642 00643 /** 00644 * Add constant to this tensor. This tensor is changed. 00645 * Returns this tensor. 00646 * @param cst constant scala to be added with each element 00647 * @return a reference to the actual tensor 00648 */ 00649 tensor<T>& add(const T& cst); 00650 00651 /** 00652 * Alias for add(const T& cst) 00653 */ 00654 tensor<T>& operator+=(const T& cst) { 00655 return add(cst); 00656 } 00657 00658 /** 00659 * Add constant to the other tensor and leave the result here. 00660 * Returns a reference to this tensor. 00661 * @param other the oder tensor 00662 * @param cst constant scala to be added with each element of the other 00663 * tensor 00664 * @return a reference to the actual tensor 00665 */ 00666 tensor<T>& add(const tensor<T>& other,const T& cst); 00667 00668 /** 00669 * write the object in the given ioHandler 00670 */ 00671 virtual bool write(ioHandler& handler,const bool complete = true) const; 00672 00673 /** 00674 * read the object from the given ioHandler 00675 */ 00676 virtual bool read(ioHandler& handler,const bool complete = true); 00677 00678 protected: 00679 /** 00680 * the total number of elements 00681 */ 00682 int totalNumberOfElements; 00683 00684 /** 00685 * the dimensionality of this tensor 00686 */ 00687 int theOrder; 00688 00689 /** 00690 * the data of the tensor 00691 */ 00692 vector<T> theElements; 00693 00694 /** 00695 * number of elements 00696 */ 00697 ivector theElementsPerDimension; 00698 00699 /** 00700 * a vector with the right dimension initialized with 0 00701 */ 00702 ivector firstIndex; 00703 00704 /** 00705 * a vector with the right dimension initialized with the 00706 * number of elements - 1 per dimension 00707 */ 00708 ivector lastIndex; 00709 00710 }; 00711 00712 /** @name Storable interface 00713 * Members for the storable interface 00714 */ 00715 //@{ 00716 /** 00717 * read the matrix from the given ioHandler. The complete flag indicates 00718 * if the enclosing begin and end should be also be read 00719 */ 00720 template <class T> 00721 bool read(ioHandler& handler,tensor<T>& hist,const bool complete=true) { 00722 return hist.read(handler,complete); 00723 } // immediate implementation to avoid MSVC++ bug!! 00724 00725 /** 00726 * write the matrix in the given ioHandler. The complete flag indicates 00727 * if the enclosing begin and end should be also be written or not 00728 */ 00729 template <class T> 00730 bool write(ioHandler& handler, 00731 const tensor<T>& hist, 00732 const bool complete=true) { 00733 return hist.write(handler,complete); 00734 } // immediate implementation to avoid MSVC++ bug!! 00735 //@} 00736 00737 } 00738 00739 namespace std { 00740 /// outputs the elements of the tensor on a stream 00741 template <class T> 00742 ostream& operator<<(ostream& s,const lti::tensor<T>& v); 00743 } 00744 00745 #include "ltiTensor_inline.h" 00746 00747 00748 #endif