namespace ewalena  0.2.15
ewalena is not an acronym
include/ewalena/base/tensor.h
Go to the documentation of this file.
00001 // -------------------------------------------------------------------
00002 // @author Toby D. Young
00003 // @version $Id: tensor.h 999 2012-11-28 17:36:29Z oneliefleft $
00004 //
00005 // Copyright 2012 namespace ewalena authors. All rights reserved.
00006 //
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions
00009 // are met:
00010 //
00011 // 1. Redistributions of source code must retain the above copyright
00012 //    notice, this list of conditions and the following disclaimer.
00013 //
00014 // 2. Redistributions in binary form must reproduce the above
00015 //    copyright notice, this list of conditions and the following
00016 //    disclaimer in the documentation and/or other materials provided
00017 //    with the distribution.
00018 //
00019 // THIS SOFTWARE IS PROVIDED BY THE NAMEPSACE EWALENA AUTHORS ``AS
00020 // IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00023 // NAMESPACE EWALENA AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00024 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00026 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00027 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00028 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00030 // OF THE POSSIBILITY OF SUCH DAMAGE.
00031 //
00032 // The views and conclusions contained in the software and
00033 // documentation are those of the authors and should not be
00034 // interpreted as representing official policies, either expressed or
00035 // implied, of the namespace ewalena authors.
00036 // -------------------------------------------------------------------
00037 
00038 #include <cassert>
00039 #include <cstdarg>
00040 #include <cstdlib>
00041 #include <cstring>
00042 #include <cmath>
00043 #include <vector>
00044 #include <iostream>
00045 
00046 #ifndef __ewalena_tensor_h
00047 #define __ewalena_tensor_h
00048 
00049 #ifdef EWALENA_HAVE_CONFIG_H
00050 #include <ewalena/base/config.h>
00051 #endif
00052 
00053 #include <ewalena/base/utilities.h>
00054 
00055 #ifdef EWALENA_HAVE_DEAL_II
00056 #include <deal.II/base/tensor.h>
00057 #endif
00058 
00059 namespace ewalena
00060 {
00061   
00068   template <int dim, int rank, typename ValueType = double>
00069     class Tensor
00070     {
00071 
00072     public:
00073     
00077     Tensor (const bool zero = true);
00078     
00082     ~Tensor ();
00083     
00088     Tensor (const Tensor &T);
00089     
00094     ValueType& operator () (const unsigned int index, ...);
00095     
00100     const ValueType& operator () (const unsigned int index, ...) const;
00101     
00105     unsigned int n_components () const;
00106     
00110     void reinit (); 
00111     
00116     void clone (const Tensor<dim, rank, ValueType> &T);
00117     
00123     void invert (const Tensor<dim, rank, ValueType> &T);
00124     
00128     void sadd (const ValueType                    &a,
00129                const Tensor<dim, rank, ValueType> &T_a);
00130     
00135     void sadd (const ValueType                    &a,
00136                const Tensor<dim, rank, ValueType> &T_a,
00137                const ValueType                    &b,
00138                const Tensor<dim, rank, ValueType> &T_b);
00139     
00144     void sadd (const ValueType                    &a,
00145                const Tensor<dim, rank, ValueType> &T_a,
00146                const ValueType                    &b,
00147                const Tensor<dim, rank, ValueType> &T_b,
00148                const ValueType                    &c,
00149                const Tensor<dim, rank, ValueType> &T_c);
00150 
00155     void sadd (const std::vector<ValueType>                     &a,
00156                const std::vector<Tensor<dim, rank, ValueType> > &T_a);
00157 
00162     Tensor<dim, rank, ValueType> operator + (const Tensor<dim, rank, ValueType> &T);
00163 
00168     Tensor<dim, rank, ValueType> operator - (const Tensor<dim, rank, ValueType> &T);
00169     
00174     void operator += (const Tensor<dim, rank, ValueType> &T);
00175     
00180     void operator -= (const Tensor<dim, rank, ValueType> &T);
00181     
00186     void operator *= (const ValueType &scalar);
00187     
00192     void operator /= (const ValueType &scalar);
00193     
00198     bool operator == (const Tensor<dim, rank, ValueType> &T) const;
00199     
00203     bool is_symmetric () const;
00204     
00209     std::pair<unsigned int, unsigned int> voight_components () const; 
00210 
00214     friend std::ostream& operator << (std::ostream                       &output, 
00215                                       const Tensor<dim, rank, ValueType> &T)
00216     {
00217       for (unsigned int i=0; i<T.__n_components; ++i) 
00218 
00219         /* Try to pretty print */
00220         (T.data[i]<(ValueType) 0)
00221           ?
00222           output << T.data[i] << " "
00223           :
00224           output << " " 
00225                  << T.data[i] << " "; 
00226       
00227       return output; 
00228     }
00229     
00234     inline
00235     const 
00236     ValueType* operator* () const
00237     {
00238       return (*this).data;
00239     }
00240     
00245     inline
00246     ValueType* operator* ()
00247     {
00248       return (*this).data;
00249     }
00250     
00251     protected:
00252     
00258     unsigned int __n_components;
00259     
00263     int __dim;
00264     
00268     int __rank;
00269     
00270     private:
00271     
00276     ValueType *data;
00277     
00278     }; /* Tensor */
00279   
00280   /*-------------- Inline and Other Functions -----------------------*/
00281   
00282   template <int dim, int rank, typename ValueType>
00283     inline 
00284     ValueType& 
00285     Tensor<dim, rank, ValueType>::operator () (const unsigned int index, ...) 
00286     {
00287       /* Assert this object is initialised. */
00288       assert (__n_components != 0);
00289       assert (index < dim);
00290       
00291       /* Indices imply rank > zero. */
00292       unsigned int decimal = index;
00293       
00294       /* Initialise value list. */
00295       va_list index_list;
00296       va_start (index_list, index); 
00297       
00298       /* Count from one, as is done in base conversions, and to
00299          prevent a compiler warning: comparison of unsigned expression
00300          < 0 is always false. */
00301       for (unsigned int i=1; i<rank; ++i)  
00302         {
00303 
00304           /* Read index from list and convert base_dim to base_10. */
00305           unsigned int base_dim  = va_arg (index_list, unsigned int);
00306           decimal               += static_cast<unsigned int> (Math::pow (dim, i) * base_dim);
00307           
00308           assert (base_dim < dim);
00309         }
00310       
00311       /* Finalise value list. */
00312       va_end (index_list);
00313       
00314       /* Check that this index is in bounds. */
00315       assert (decimal < __n_components);
00316       return data[decimal];
00317     }
00318   
00319   /* This operator works in exactly the same way as the read-write
00320      operator above. Perhaps there is a way to simply call the above
00321      routine instead of duplicating that code? */
00322   template <int dim, int rank, typename ValueType>
00323     inline 
00324     const ValueType& 
00325     Tensor<dim, rank, ValueType>::operator () (const unsigned int index, ...) const
00326     {
00327       assert (__n_components != 0);
00328       assert (index < dim);
00329       
00330       unsigned int decimal = index;
00331       
00332       va_list index_list;
00333       va_start (index_list, index); 
00334       for (unsigned int i=1; i<rank; ++i) 
00335         {
00336           unsigned int base_dim  = va_arg (index_list, unsigned int);
00337           decimal               += static_cast<unsigned int> (Math::pow (dim, i) * base_dim);
00338           
00339           assert (base_dim < dim);
00340         }
00341       va_end (index_list);
00342 
00343       assert (decimal < __n_components);
00344       return data[decimal];
00345     }
00346 
00347   template <int dim, int rank, typename ValueType>
00348     inline
00349     unsigned int
00350     Tensor<dim, rank, ValueType>::n_components () const
00351     {
00352       return __n_components;
00353     }
00354 
00355   template <int dim, int rank, typename ValueType>
00356     inline 
00357     Tensor<dim, rank, ValueType>
00358     Tensor<dim, rank, ValueType>::operator + (const Tensor<dim, rank, ValueType> &T) 
00359     {
00360       assert (__n_components != 0);
00361       assert (T.__n_components  == __n_components);
00362 
00363       Tensor<dim, rank, ValueType> tensor;
00364       tensor.reinit ();
00365 
00366       for (unsigned int i=0; i<__n_components; ++i)
00367         tensor.data[i] = data[i] + T.data[i];
00368 
00369       return tensor;
00370     }
00371 
00372   template <int dim, int rank, typename ValueType>
00373     inline 
00374     Tensor<dim, rank, ValueType>
00375     Tensor<dim, rank, ValueType>::operator - (const Tensor<dim, rank, ValueType> &T) 
00376     {
00377       assert (__n_components != 0);
00378       assert (T.__n_components  == __n_components);
00379 
00380       Tensor<dim, rank, ValueType> tensor;
00381       tensor.reinit ();
00382 
00383       for (unsigned int i=0; i<__n_components; ++i)
00384         tensor.data[i] = data[i] - T.data[i];
00385 
00386       return tensor;
00387     }
00388   
00389   template <int dim, int rank, typename ValueType>
00390     inline 
00391     void
00392     Tensor<dim, rank, ValueType>::operator += (const Tensor<dim, rank, ValueType> &T) 
00393     {
00394       assert (__n_components != 0);
00395       assert (T.__n_components  == __n_components);
00396       
00397       for (unsigned int i=0; i<__n_components; ++i)
00398         data[i] += T.data[i];
00399     }
00400 
00401   template <int dim, int rank, typename ValueType>
00402     inline 
00403     void
00404     Tensor<dim, rank, ValueType>::operator -= (const Tensor<dim, rank, ValueType> &T) 
00405     {
00406       assert (__n_components != 0);
00407       assert (T.__n_components  == __n_components);
00408       
00409       for (unsigned int i=0; i<__n_components; ++i)
00410         data[i] -= T.data[i];
00411     }
00412   
00413   template <int dim, int rank, typename ValueType>
00414     inline 
00415     void
00416     Tensor<dim, rank, ValueType>::operator *= (const ValueType &scalar) 
00417     {
00418       assert (__n_components != 0);
00419 
00420       for (unsigned int i=0; i<__n_components; ++i)
00421         data[i] *= scalar;
00422     }
00423 
00424   template <int dim, int rank, typename ValueType>
00425     inline 
00426     void
00427     Tensor<dim, rank, ValueType>::operator /= (const ValueType &scalar) 
00428     {
00429       assert (__n_components != 0);
00430 
00431       for (unsigned int i=0; i<__n_components; ++i)
00432         data[i] /= scalar;
00433     }
00434 
00435   template <int dim, int rank, typename ValueType>
00436     inline 
00437     bool
00438     Tensor<dim, rank, ValueType>::operator == (const Tensor<dim, rank, ValueType> &T) const
00439     {
00440       assert (T.__n_components == __n_components);
00441 
00442       return static_cast<bool> (!std::memcmp (this->data, T.data, sizeof(ValueType)*__n_components));
00443     }
00444 
00445   template <int dim, int rank, typename ValueType>
00446     inline
00447     void
00448     Tensor<dim, rank, ValueType>::sadd (const ValueType                    &a,
00449                                         const Tensor<dim, rank, ValueType> &T_a) 
00450     {
00451       /* Check this tensor is fo non-zero size and also check the
00452          input tensors are also of the same size as that. */
00453       assert (__n_components != 0);
00454       assert (T_a.__n_components  == __n_components);
00455 
00456       /* Scale add these tensors thus: */
00457       for (unsigned int i=0; i<n_components (); ++i)
00458         this->data[i] += a*T_a.data[i];
00459     }
00460   
00461   template <int dim, int rank, typename ValueType>
00462     inline
00463     void
00464     Tensor<dim, rank, ValueType>::sadd (const ValueType                    &a,
00465                                         const Tensor<dim, rank, ValueType> &T_a,
00466                                         const ValueType                    &b,
00467                                         const Tensor<dim, rank, ValueType> &T_b) 
00468     {
00469       /* Same as above but for two tensors. */      
00470       assert (__n_components != 0);
00471       assert (T_a.__n_components  == __n_components);
00472       assert (T_b.__n_components  == __n_components);
00473       
00474       for (unsigned int i=0; i<n_components (); ++i)
00475         this->data[i] += a*T_a.data[i] + b*T_b.data[i];
00476     }
00477 
00478   template <int dim, int rank, typename ValueType>
00479     inline
00480     void
00481     Tensor<dim, rank, ValueType>::sadd (const ValueType                    &a,
00482                                         const Tensor<dim, rank, ValueType> &T_a,
00483                                         const ValueType                    &b,
00484                                         const Tensor<dim, rank, ValueType> &T_b,
00485                                         const ValueType                    &c,
00486                                         const Tensor<dim, rank, ValueType> &T_c) 
00487     {
00488       /* Same as above but for two tensors. */
00489       assert (__n_components != 0);
00490       assert (T_a.__n_components  == __n_components);
00491       assert (T_b.__n_components  == __n_components);
00492       assert (T_c.__n_components  == __n_components);
00493 
00494       for (unsigned int i=0; i<n_components (); ++i)
00495         this->data[i] += a*T_a.data[i] + b*T_b.data[i] + c*T_c.data[i];
00496     }
00497 
00498   template <int dim, int rank, typename ValueType>
00499     inline
00500     void
00501     Tensor<dim, rank, ValueType>::sadd (const std::vector<ValueType>                     &a,
00502                                         const std::vector<Tensor<dim, rank, ValueType> > &T_a) 
00503     {
00504       /* Same as above but for a std::vector of tensors. */
00505       assert (__n_components != 0);
00506 
00507       /* Insist that the number of constants and the number of tensors
00508          to scale-add are of the same size. */
00509       assert (T_a.size ()  == a.size ());
00510 
00511       for (unsigned int i=0; i<a.size (); ++i)
00512         {
00513           assert (__n_components != 0);
00514           assert (T_a[i].__n_components  == __n_components);
00515 
00516           /* Iteratively call the single scale-add (above). */
00517           this->sadd (a[i], T_a[i]);
00518         }
00519     }
00520 
00521   /*-------------- Rank 2 --------------------------------------------*/
00522 
00523   /* This routine is a definiative plagarism from the class
00524      Matrix<ValueType>. Thus, if anything goes wrong here, it will
00525      probably need to be reported there too. */
00526   template <int dim, int rank, typename ValueType>
00527     inline
00528     void
00529     Tensor<dim, rank, ValueType>::invert (const Tensor<dim, rank, ValueType> &T) 
00530     {
00531       /* This should always be true  */
00532       assert (dim < 4);
00533       assert (rank == 2);
00534 
00535       assert (T.data);
00536       assert ((*this).data);
00537 
00538       switch (dim)
00539         {
00540         case 0:
00541           {
00542             /* Undefined operation.  */
00543             assert (false);
00544           }
00545           
00546         case 1:
00547           {
00548             assert (T(0,0)!=ValueType (0));
00549             (*this)(0,0) = ValueType (1) / T(0,0);
00550             break;
00551           }
00552           
00553         case 2:
00554           {
00555             const ValueType determinant = T(0,0)*T(1,1) - T(0,1)*T(1,0);
00556             assert (determinant!=ValueType (0));
00557             
00558             (*this)(0,0) =  T(1,1) / determinant;
00559             (*this)(0,1) = -T(0,1) / determinant;
00560             (*this)(1,0) = -T(1,0) / determinant;
00561             (*this)(1,1) =  T(0,0) / determinant;
00562             
00563             break;
00564           }
00565 
00566         case 3: 
00567           {
00568             const ValueType determinant 
00569               = T(0,0)*(T(2,2)*T(1,1) - T(2,1)*T(1,2))
00570               - T(1,0)*(T(2,2)*T(0,1) - T(2,1)*T(0,2))
00571               + T(2,0)*(T(1,2)*T(0,1) - T(1,1)*T(0,2));
00572             assert (determinant!=ValueType (0));
00573 
00574             (*this)(0,0) =    (T(2,2)*T(1,1) - T(2,1)*T(1,2)) / determinant;
00575             (*this)(0,1) =  - (T(2,2)*T(0,1) - T(2,1)*T(0,2)) / determinant;
00576             (*this)(0,2) =    (T(1,2)*T(0,1) - T(1,1)*T(0,2)) / determinant;
00577 
00578             (*this)(1,0) =  - (T(2,2)*T(1,0) - T(2,0)*T(1,2)) / determinant;
00579             (*this)(1,1) =    (T(2,2)*T(0,0) - T(2,0)*T(0,2)) / determinant;
00580             (*this)(1,2) =  - (T(1,2)*T(0,0) - T(1,0)*T(0,2)) / determinant;
00581 
00582             (*this)(2,0) =    (T(2,1)*T(1,0) - T(2,0)*T(1,1)) / determinant;
00583             (*this)(2,1) =  - (T(2,1)*T(0,0) - T(2,0)*T(0,1)) / determinant;
00584             (*this)(2,2) =    (T(1,1)*T(0,0) - T(1,0)*T(0,1)) / determinant;
00585 
00586             break; 
00587 
00588           }
00589 
00590           /* This is not likely to work well for big or even medium
00591              sized matrices - so don't do it. */
00592         default:
00593           assert (false);
00594         }
00595 
00596     }
00597 
00598   /*-------------- Rank 2 --------------------------------------------*/
00599 
00604   template <int dim, typename ValueType>
00605     inline
00606     Tensor<dim, 2, ValueType> contract (const Tensor<dim, 2, ValueType> &T_a,
00607                                         const Tensor<dim, 4, ValueType> &T_b) 
00608     {
00609       Tensor<dim, 2, ValueType> tensor;
00610       
00611       for (unsigned int i=0; i<dim; ++i)
00612         for (unsigned int j=0; j<dim; ++j)
00613           for (unsigned int k=0; k<dim; ++k)
00614             for (unsigned int l=0; l<dim; ++l)
00615               tensor(k,l) += T_a(i,j)*T_b(i,j,k,l);
00616       
00617       return tensor;
00618     }
00619   
00624   template <int dim, typename ValueType>
00625     inline
00626     Tensor<dim, 2, ValueType> contract (const Tensor<dim, 4, ValueType> &T_a,
00627                                         const Tensor<dim, 2, ValueType> &T_b) 
00628     {
00629       Tensor<dim, 2, ValueType> tensor;
00630       
00631       for (unsigned int i=0; i<dim; ++i)
00632         for (unsigned int j=0; j<dim; ++j)
00633           for (unsigned int k=0; k<dim; ++k)
00634             for (unsigned int l=0; l<dim; ++l)
00635               tensor(i,j) += T_a(i,j,k,l)*T_b(k,l);
00636       
00637       return tensor;
00638     }
00639   
00640   /*-------------- Rank 1 --------------------------------------------*/
00641   
00646   template <int dim, typename ValueType>
00647     inline
00648     Tensor<dim, 1, ValueType> contract (const Tensor<dim, 3, ValueType> &T_a,
00649                                         const Tensor<dim, 2, ValueType> &T_b) 
00650     {
00651       Tensor<dim, 1, ValueType> tensor;
00652       
00653       for (unsigned int i=0; i<dim; ++i)
00654         for (unsigned int j=0; j<dim; ++j)
00655           for (unsigned int k=0; k<dim; ++k)
00656             tensor(i) += T_a(i,j,k)*T_b(j,k);
00657       
00658       return tensor;
00659     }
00660   
00661   /*-------------- Scalar --------------------------------------------*/
00662 
00663   
00664 } /* namespace ewalena */
00665   
00666 #endif /* __ewalena_tensor_h */
00667   
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines