Intrepid
/usr/src/RPM/BUILD/trilinos-11.12.1/packages/intrepid/src/Shared/MiniTensor/Intrepid_MiniTensor_Tensor.i.h
00001 // @HEADER
00002 // ************************************************************************
00003 //
00004 //                           Intrepid Package
00005 //                 Copyright (2007) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions: Alejandro Mota (amota@sandia.gov)
00038 //
00039 // ************************************************************************
00040 // @HEADER
00041 
00042 #if !defined(Intrepid_MiniTensor_Tensor_i_h)
00043 #define Intrepid_MiniTensor_Tensor_i_h
00044 
00045 namespace Intrepid {
00046 
00047 //
00048 // Constructor that initializes to NaNs
00049 //
00050 template<typename T, Index N>
00051 inline
00052 Tensor<T, N>::Tensor() :
00053 TensorBase<T, Store>::TensorBase()
00054 {
00055   return;
00056 }
00057 
00058 template<typename T, Index N>
00059 inline
00060 Tensor<T, N>::Tensor(Index const dimension) :
00061 TensorBase<T, Store>::TensorBase(dimension, ORDER)
00062 {
00063   return;
00064 }
00065 
00069 template<typename T, Index N>
00070 inline
00071 Tensor<T, N>::Tensor(ComponentValue const value) :
00072 TensorBase<T, Store>::TensorBase(N, ORDER, value)
00073 {
00074   return;
00075 }
00076 
00077 template<typename T, Index N>
00078 inline
00079 Tensor<T, N>::Tensor(Index const dimension, ComponentValue const value) :
00080 TensorBase<T, Store>::TensorBase(dimension, ORDER, value)
00081 {
00082   return;
00083 }
00084 
00085 //
00086 //  Create tensor from array
00087 //
00088 template<typename T, Index N>
00089 inline
00090 Tensor<T, N>::Tensor(T const * data_ptr) :
00091 TensorBase<T, Store>::TensorBase(N, ORDER, data_ptr)
00092 {
00093   return;
00094 }
00095 
00096 template<typename T, Index N>
00097 inline
00098 Tensor<T, N>::Tensor(Index const dimension, T const * data_ptr) :
00099 TensorBase<T, Store>::TensorBase(dimension, ORDER, data_ptr)
00100 {
00101   return;
00102 }
00103 
00104 //
00105 // Copy constructor
00106 //
00107 template<typename T, Index N>
00108 inline
00109 Tensor<T, N>::Tensor(Tensor<T, N> const & A) :
00110 TensorBase<T, Store>::TensorBase(A)
00111 {
00112   return;
00113 }
00114 
00115 //
00116 // Create tensor specifying components
00117 // \param  s00, s01, ... components in the R^2 canonical basis
00118 //
00119 template<typename T, Index N>
00120 inline
00121 Tensor<T, N>::Tensor(
00122     T const & s00, T const & s01,
00123     T const & s10, T const & s11)
00124 {
00125   Tensor<T, N> &
00126   self = (*this);
00127 
00128   self.set_dimension(2);
00129 
00130   self[0] = s00;
00131   self[1] = s01;
00132 
00133   self[2] = s10;
00134   self[3] = s11;
00135 
00136   return;
00137 }
00138 
00139 //
00140 // Create tensor specifying components
00141 // \param  s00, s01, ... components in the R^3 canonical basis
00142 //
00143 template<typename T, Index N>
00144 inline
00145 Tensor<T, N>::Tensor(
00146     T const & s00, T const & s01, T const & s02,
00147     T const & s10, T const & s11, T const & s12,
00148     T const & s20, T const & s21, T const & s22)
00149 {
00150   Tensor<T, N> &
00151   self = (*this);
00152 
00153   self.set_dimension(3);
00154 
00155   self[0] = s00;
00156   self[1] = s01;
00157   self[2] = s02;
00158 
00159   self[3] = s10;
00160   self[4] = s11;
00161   self[5] = s12;
00162 
00163   self[6] = s20;
00164   self[7] = s21;
00165   self[8] = s22;
00166 
00167   return;
00168 }
00169 
00170 //
00171 //  Create tensor from array with component order
00172 //
00173 template<typename T, Index N>
00174 inline
00175 Tensor<T, N>::Tensor(T const * data_ptr, ComponentOrder const component_order)
00176 {
00177   assert(data_ptr != NULL);
00178 
00179   fill(data_ptr, component_order);
00180 
00181   return;
00182 }
00183 
00184 template<typename T, Index N>
00185 inline
00186 Tensor<T, N>::Tensor(
00187     Index const dimension,
00188     T const * data_ptr,
00189     ComponentOrder const component_order)
00190 {
00191   assert(data_ptr != NULL);
00192 
00193   Tensor<T, N> &
00194   self = (*this);
00195 
00196   self.set_dimension(dimension);
00197 
00198   fill(data_ptr, component_order);
00199 
00200   return;
00201 }
00202 
00203 //
00204 // 2nd-order tensor from 4th-order tensor
00205 //
00206 template<typename T, Index N>
00207 inline
00208 Tensor<T, N>::Tensor(Tensor4<T, dimension_sqrt<N>::value> const & A)
00209 {
00210   Index const
00211   dimension_4th = A.get_dimension();
00212 
00213   Index const
00214   dimension_2nd = dimension_4th * dimension_4th;
00215 
00216   Tensor<T, N> &
00217   self = (*this);
00218 
00219   self.set_dimension(dimension_2nd);
00220 
00221   Index const
00222   number_components = dimension_2nd * dimension_2nd;
00223 
00224   for (Index i = 0; i < number_components; ++i) {
00225     self[i] = A[i];
00226   }
00227 
00228   return;
00229 }
00230 
00231 //
00232 // Simple destructor
00233 //
00234 template<typename T, Index N>
00235 inline
00236 Tensor<T, N>::~Tensor()
00237 {
00238   return;
00239 }
00240 
00241 //
00242 // Get dimension
00243 //
00244 template<typename T, Index N>
00245 inline
00246 Index
00247 Tensor<T, N>::get_dimension() const
00248 {
00249   return IS_DYNAMIC == true ? TensorBase<T, Store>::get_dimension() : N;
00250 }
00251 
00252 //
00253 // Set dimension
00254 //
00255 template<typename T, Index N>
00256 inline
00257 void
00258 Tensor<T, N>::set_dimension(Index const dimension)
00259 {
00260   if (IS_DYNAMIC == true) {
00261     TensorBase<T, Store>::set_dimension(dimension, ORDER);
00262   }
00263   else {
00264     assert(dimension == N);
00265   }
00266 
00267   return;
00268 }
00269 
00270 //
00271 // Indexing for constant tensor
00272 //
00273 template<typename T, Index N>
00274 inline
00275 T const &
00276 Tensor<T, N>::operator()(Index const i, Index const j) const
00277 {
00278   Tensor<T, N> const &
00279   self = (*this);
00280 
00281   Index const
00282   dimension = self.get_dimension();
00283 
00284   return self[i * dimension + j];
00285 }
00286 
00287 //
00288 //Tensor indexing
00289 //
00290 template<typename T, Index N>
00291 inline
00292 T &
00293 Tensor<T, N>::operator()(Index const i, Index const j)
00294 {
00295   Tensor<T, N> &
00296   self = (*this);
00297 
00298   Index const
00299   dimension = self.get_dimension();
00300 
00301   return self[i * dimension + j];
00302 }
00303 
00304 //
00305 // Fill components with value specification
00306 //
00307 template<typename T, Index N>
00308 inline
00309 void
00310 Tensor<T, N>::fill(ComponentValue const value)
00311 {
00312   TensorBase<T, Store>::fill(value);
00313   return;
00314 }
00315 
00316 //
00317 // Fill components with value as parameter
00318 //
00319 template<typename T, Index N>
00320 inline
00321 void
00322 Tensor<T, N>::fill(T const & s)
00323 {
00324   TensorBase<T, Store>::fill(s);
00325   return;
00326 }
00327 
00328 //
00329 // Fill components from array defined by pointer.
00330 //
00331 template<typename T, Index N>
00332 inline
00333 void
00334 Tensor<T, N>::fill(T const * data_ptr)
00335 {
00336   TensorBase<T, Store>::fill(data_ptr);
00337   return;
00338 }
00339 
00340 //
00341 // Fill components from array defined by pointer.
00342 //
00343 template<typename T, Index N>
00344 inline
00345 void
00346 Tensor<T, N>::fill(T const * data_ptr, ComponentOrder const component_order)
00347 {
00348   assert(data_ptr != NULL);
00349 
00350   Tensor<T, N> &
00351   self = (*this);
00352 
00353   Index const
00354   dimension = self.get_dimension();
00355 
00356   switch (dimension) {
00357 
00358     default:
00359       TensorBase<T, Store>::fill(data_ptr);
00360       break;
00361 
00362     case 3:
00363 
00364       switch (component_order) {
00365 
00366         case CANONICAL:
00367           TensorBase<T, Store>::fill(data_ptr);
00368           break;
00369 
00370         case SIERRA_FULL:
00371 
00372           //  0  1  2  3  4  5  6  7  8
00373           // XX YY ZZ XY YZ ZX YX ZY XZ
00374           //  0  4  8  1  5  6  3  7  2
00375           self[0] = data_ptr[0];
00376           self[4] = data_ptr[1];
00377           self[8] = data_ptr[2];
00378 
00379           self[1] = data_ptr[3];
00380           self[5] = data_ptr[4];
00381           self[6] = data_ptr[5];
00382 
00383           self[3] = data_ptr[6];
00384           self[7] = data_ptr[7];
00385           self[2] = data_ptr[8];
00386           break;
00387 
00388         case SIERRA_SYMMETRIC:
00389           self[0] = data_ptr[0];
00390           self[4] = data_ptr[1];
00391           self[8] = data_ptr[2];
00392 
00393           self[1] = data_ptr[3];
00394           self[5] = data_ptr[4];
00395           self[6] = data_ptr[5];
00396 
00397           self[3] = data_ptr[3];
00398           self[7] = data_ptr[4];
00399           self[2] = data_ptr[5];
00400           break;
00401 
00402         default:
00403           std::cerr << "ERROR: " << __PRETTY_FUNCTION__;
00404           std::cerr << std::endl;
00405           std::cerr << "Unknown component order.";
00406           std::cerr << std::endl;
00407           exit(1);
00408           break;
00409 
00410       }
00411 
00412       break;
00413   }
00414 
00415   return;
00416 }
00417 
00418 //
00419 // Tensor addition
00420 //
00421 template<typename S, typename T, Index N>
00422 inline
00423 Tensor<typename Promote<S, T>::type, N>
00424 operator+(Tensor<S, N> const & A, Tensor<T, N> const & B)
00425 {
00426   Tensor<typename Promote<S, T>::type, N>
00427   C(A.get_dimension());
00428 
00429   add(A, B, C);
00430 
00431   return C;
00432 }
00433 
00434 //
00435 // Tensor subtraction
00436 //
00437 template<typename S, typename T, Index N>
00438 inline
00439 Tensor<typename Promote<S, T>::type, N>
00440 operator-(Tensor<S, N> const & A, Tensor<T, N> const & B)
00441 {
00442   Tensor<typename Promote<S, T>::type, N>
00443   C(A.get_dimension());
00444 
00445   subtract(A, B, C);
00446 
00447   return C;
00448 }
00449 
00450 //
00451 // Tensor minus
00452 //
00453 template<typename T, Index N>
00454 inline
00455 Tensor<T, N>
00456 operator-(Tensor<T, N> const & A)
00457 {
00458   Tensor<T, N>
00459   B(A.get_dimension());
00460 
00461   minus(A, B);
00462 
00463   return B;
00464 }
00465 
00466 //
00467 // Tensor equality
00468 //
00469 template<typename T, Index N>
00470 inline
00471 bool
00472 operator==(Tensor<T, N> const & A, Tensor<T, N> const & B)
00473 {
00474   return equal(A, B);
00475 }
00476 
00477 //
00478 // Tensor inequality
00479 //
00480 template<typename T, Index N>
00481 inline
00482 bool
00483 operator!=(Tensor<T, N> const & A, Tensor<T, N> const & B)
00484 {
00485   return not_equal(A, B);
00486 }
00487 
00488 //
00489 // Scalar tensor product
00490 //
00491 template<typename S, typename T, Index N>
00492 inline
00493 typename lazy_disable_if< order_1234<S>, apply_tensor< Promote<S,T>, N> >::type
00494 operator*(S const & s, Tensor<T, N> const & A)
00495 {
00496   Tensor<typename Promote<S, T>::type, N>
00497   B(A.get_dimension());
00498 
00499   scale(A, s, B);
00500 
00501   return B;
00502 }
00503 
00504 //
00505 // Tensor scalar product
00506 //
00507 template<typename S, typename T, Index N>
00508 inline
00509 typename lazy_disable_if< order_1234<S>, apply_tensor< Promote<S,T>, N> >::type
00510 operator*(Tensor<T, N> const & A, S const & s)
00511 {
00512   Tensor<typename Promote<S, T>::type, N>
00513   B(A.get_dimension());
00514 
00515   scale(A, s, B);
00516 
00517   return B;
00518 }
00519 
00520 //
00521 // Tensor scalar division
00522 //
00523 template<typename S, typename T, Index N>
00524 inline
00525 Tensor<typename Promote<S, T>::type, N>
00526 operator/(Tensor<T, N> const & A, S const & s)
00527 {
00528   Tensor<typename Promote<S, T>::type, N>
00529   B(A.get_dimension());
00530 
00531   divide(A, s, B);
00532 
00533   return B;
00534 }
00535 
00536 //
00537 // Scalar tensor division
00538 //
00539 template<typename S, typename T, Index N>
00540 inline
00541 Tensor<typename Promote<S, T>::type, N>
00542 operator/(S const & s, Tensor<T, N> const & A)
00543 {
00544   Tensor<typename Promote<S, T>::type, N>
00545   B(A.get_dimension());
00546 
00547   split(A, s, B);
00548 
00549   return B;
00550 }
00551 
00552 //
00553 // Tensor vector product v = A u
00554 //
00555 template<typename S, typename T, Index N>
00556 inline
00557 Vector<typename Promote<S, T>::type, N>
00558 operator*(Tensor<T, N> const & A, Vector<S, N> const & u)
00559 {
00560   return dot(A, u);
00561 }
00562 
00563 //
00564 // Vector tensor product v = u A
00565 //
00566 template<typename S, typename T, Index N>
00567 inline
00568 Vector<typename Promote<S, T>::type, N>
00569 operator*(Vector<S, N> const & u, Tensor<T, N> const & A)
00570 {
00571   return dot(u, A);
00572 }
00573 
00574 //
00575 // Tensor dot product C = A B
00576 //
00577 template<typename S, typename T, Index N>
00578 inline
00579 Tensor<typename Promote<S, T>::type, N>
00580 operator*(Tensor<S, N> const & A, Tensor<T, N> const & B)
00581 {
00582   return dot(A, B);
00583 }
00584 
00585 namespace {
00586 
00587 template<typename S>
00588 bool
00589 greater_than(S const & a, S const & b)
00590 {
00591   return a.first > b.first;
00592 }
00593 
00594 } // anonymous namespace
00595 
00596 //
00597 // Sort and index in descending order. Useful for ordering singular values
00598 // and eigenvalues and corresponding vectors in the respective decompositions.
00599 //
00600 template<typename T, Index N>
00601 std::pair<Vector<T, N>, Tensor<T, N> >
00602 sort_permutation(Vector<T, N> const & u)
00603 {
00604 
00605   Index const
00606   dimension = u.get_dimension();
00607 
00608   std::vector<std::pair<T, Index > >
00609   s(dimension);
00610 
00611   for (Index i = 0; i < dimension; ++i) {
00612     s[i].first = u(i);
00613     s[i].second = i;
00614   }
00615 
00616   std::sort(s.begin(), s.end(), greater_than< std::pair<T, Index > > );
00617 
00618   Vector<T, N> v(dimension);
00619 
00620   Tensor<T, N>
00621   P = zero<T, N>(dimension);
00622 
00623   for (Index i = 0; i < dimension; ++i) {
00624     v(i) = s[i].first;
00625     P(s[i].second, i) = 1.0;
00626   }
00627 
00628   return std::make_pair(v, P);
00629 
00630 }
00631 
00632 //
00633 // Extract a row as a vector
00634 //
00635 template<typename T, Index N>
00636 Vector<T, N>
00637 row(Tensor<T, N> const & A, Index const i)
00638 {
00639   Index const
00640   dimension = A.get_dimension();
00641 
00642   Vector<T, N>
00643   v(dimension);
00644 
00645   switch (dimension) {
00646     default:
00647       for (Index j = 0; j < dimension; ++j) {
00648         v(j) = A(i,j);
00649       }
00650       break;
00651 
00652     case 2:
00653       v(0) = A(i,0);
00654       v(1) = A(i,1);
00655       break;
00656 
00657     case 3:
00658       v(0) = A(i,0);
00659       v(1) = A(i,1);
00660       v(2) = A(i,2);
00661       break;
00662   }
00663 
00664   return v;
00665 }
00666 
00667 //
00668 // Extract a column as a vector
00669 //
00670 template<typename T, Index N>
00671 Vector<T, N>
00672 col(Tensor<T, N> const & A, Index const j)
00673 {
00674   Index const
00675   dimension = A.get_dimension();
00676 
00677   Vector<T, N>
00678   v(dimension);
00679 
00680   switch (dimension) {
00681     default:
00682       for (Index i = 0; i < dimension; ++i) {
00683         v(i) = A(i,j);
00684       }
00685       break;
00686 
00687     case 2:
00688       v(0) = A(0,j);
00689       v(1) = A(1,j);
00690       break;
00691 
00692     case 3:
00693       v(0) = A(0,j);
00694       v(1) = A(1,j);
00695       v(2) = A(2,j);
00696       break;
00697   }
00698 
00699   return v;
00700 }
00701 
00702 //
00703 // R^N tensor vector product v = A u
00704 // \param A tensor
00705 // \param u vector
00706 // \return \f$ A u \f$
00707 //
00708 template<typename S, typename T, Index N>
00709 inline
00710 Vector<typename Promote<S, T>::type, N>
00711 dot(Tensor<T, N> const & A, Vector<S, N> const & u)
00712 {
00713   Index const
00714   dimension = A.get_dimension();
00715 
00716   assert(u.get_dimension() == dimension);
00717 
00718   Vector<typename Promote<S, T>::type, N>
00719   v(dimension);
00720 
00721   switch (dimension) {
00722 
00723     default:
00724       for (Index i = 0; i < dimension; ++i) {
00725 
00726         typename Promote<S, T>::type
00727         s = 0.0;
00728 
00729         for (Index p = 0; p < dimension; ++p) {
00730           s += A(i, p) * u(p);
00731         }
00732         v(i) = s;
00733       }
00734       break;
00735 
00736     case 3:
00737       v(0) = A(0,0)*u(0) + A(0,1)*u(1) + A(0,2)*u(2);
00738       v(1) = A(1,0)*u(0) + A(1,1)*u(1) + A(1,2)*u(2);
00739       v(2) = A(2,0)*u(0) + A(2,1)*u(1) + A(2,2)*u(2);
00740       break;
00741 
00742     case 2:
00743       v(0) = A(0,0)*u(0) + A(0,1)*u(1);
00744       v(1) = A(1,0)*u(0) + A(1,1)*u(1);
00745       break;
00746 
00747   }
00748 
00749   return v;
00750 }
00751 
00752 //
00753 // R^N vector tensor product v = u A
00754 // \param A tensor
00755 // \param u vector
00756 // \return \f$ u A = A^T u \f$
00757 //
00758 template<typename S, typename T, Index N>
00759 inline
00760 Vector<typename Promote<S, T>::type, N>
00761 dot(Vector<S, N> const & u, Tensor<T, N> const & A)
00762 {
00763   Index const
00764   dimension = A.get_dimension();
00765 
00766   assert(u.get_dimension() == dimension);
00767 
00768   Vector<typename Promote<S, T>::type, N>
00769   v(dimension);
00770 
00771   switch (dimension) {
00772 
00773     default:
00774       for (Index i = 0; i < dimension; ++i) {
00775 
00776         typename Promote<S, T>::type
00777         s = 0.0;
00778 
00779         for (Index p = 0; p < dimension; ++p) {
00780           s += A(p, i) * u(p);
00781         }
00782         v(i) = s;
00783       }
00784       break;
00785 
00786     case 3:
00787       v(0) = A(0,0)*u(0) + A(1,0)*u(1) + A(2,0)*u(2);
00788       v(1) = A(0,1)*u(0) + A(1,1)*u(1) + A(2,1)*u(2);
00789       v(2) = A(0,2)*u(0) + A(1,2)*u(1) + A(2,2)*u(2);
00790       break;
00791 
00792     case 2:
00793       v(0) = A(0,0)*u(0) + A(1,0)*u(1);
00794       v(1) = A(0,1)*u(0) + A(1,1)*u(1);
00795       break;
00796 
00797   }
00798 
00799   return v;
00800 }
00801 
00802 //
00803 // R^N tensor tensor product C = A B
00804 // \param A tensor
00805 // \param B tensor
00806 // \return a tensor \f$ A \cdot B \f$
00807 //
00808 template<typename S, typename T, Index N>
00809 inline
00810 Tensor<typename Promote<S, T>::type, N>
00811 dot(Tensor<S, N> const & A, Tensor<T, N> const & B)
00812 {
00813   Index const
00814   dimension = A.get_dimension();
00815 
00816   assert(B.get_dimension() == dimension);
00817 
00818   Tensor<typename Promote<S, T>::type, N>
00819   C(dimension);
00820 
00821   switch (dimension) {
00822 
00823     default:
00824       for (Index i = 0; i < dimension; ++i) {
00825         for (Index j = 0; j < dimension; ++j) {
00826 
00827           typename Promote<S, T>::type
00828           s = 0.0;
00829 
00830           for (Index p = 0; p < dimension; ++p) {
00831             s += A(i, p) * B(p, j);
00832           }
00833           C(i, j) = s;
00834         }
00835       }
00836       break;
00837 
00838     case 3:
00839       C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(1,0) + A(0,2)*B(2,0);
00840       C(0,1) = A(0,0)*B(0,1) + A(0,1)*B(1,1) + A(0,2)*B(2,1);
00841       C(0,2) = A(0,0)*B(0,2) + A(0,1)*B(1,2) + A(0,2)*B(2,2);
00842 
00843       C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(1,0) + A(1,2)*B(2,0);
00844       C(1,1) = A(1,0)*B(0,1) + A(1,1)*B(1,1) + A(1,2)*B(2,1);
00845       C(1,2) = A(1,0)*B(0,2) + A(1,1)*B(1,2) + A(1,2)*B(2,2);
00846 
00847       C(2,0) = A(2,0)*B(0,0) + A(2,1)*B(1,0) + A(2,2)*B(2,0);
00848       C(2,1) = A(2,0)*B(0,1) + A(2,1)*B(1,1) + A(2,2)*B(2,1);
00849       C(2,2) = A(2,0)*B(0,2) + A(2,1)*B(1,2) + A(2,2)*B(2,2);
00850       break;
00851 
00852     case 2:
00853       C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(1,0);
00854       C(0,1) = A(0,0)*B(0,1) + A(0,1)*B(1,1);
00855 
00856       C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(1,0);
00857       C(1,1) = A(1,0)*B(0,1) + A(1,1)*B(1,1);
00858       break;
00859 
00860   }
00861 
00862   return C;
00863 }
00864 
00865 //
00866 // R^N tensor tensor product C = A^T B
00867 // \param A tensor
00868 // \param B tensor
00869 // \return a tensor \f$ A^T \cdot B \f$
00870 //
00871 template<typename S, typename T, Index N>
00872 inline
00873 Tensor<typename Promote<S, T>::type, N>
00874 t_dot(Tensor<S, N> const & A, Tensor<T, N> const & B)
00875 {
00876   Index const
00877   dimension = A.get_dimension();
00878 
00879   assert(B.get_dimension() == dimension);
00880 
00881   Tensor<typename Promote<S, T>::type, N>
00882   C(dimension);
00883 
00884   switch (dimension) {
00885 
00886     default:
00887       for (Index i = 0; i < dimension; ++i) {
00888         for (Index j = 0; j < dimension; ++j) {
00889 
00890           typename Promote<S, T>::type
00891           s = 0.0;
00892 
00893           for (Index p = 0; p < dimension; ++p) {
00894             s += A(p, i) * B(p, j);
00895           }
00896           C(i, j) = s;
00897         }
00898       }
00899       break;
00900 
00901     case 3:
00902       C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(1,0) + A(2,0)*B(2,0);
00903       C(0,1) = A(0,0)*B(0,1) + A(1,0)*B(1,1) + A(2,0)*B(2,1);
00904       C(0,2) = A(0,0)*B(0,2) + A(1,0)*B(1,2) + A(2,0)*B(2,2);
00905 
00906       C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(1,0) + A(2,1)*B(2,0);
00907       C(1,1) = A(0,1)*B(0,1) + A(1,1)*B(1,1) + A(2,1)*B(2,1);
00908       C(1,2) = A(0,1)*B(0,2) + A(1,1)*B(1,2) + A(2,1)*B(2,2);
00909 
00910       C(2,0) = A(0,2)*B(0,0) + A(1,2)*B(1,0) + A(2,2)*B(2,0);
00911       C(2,1) = A(0,2)*B(0,1) + A(1,2)*B(1,1) + A(2,2)*B(2,1);
00912       C(2,2) = A(0,2)*B(0,2) + A(1,2)*B(1,2) + A(2,2)*B(2,2);
00913       break;
00914 
00915     case 2:
00916       C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(1,0);
00917       C(0,1) = A(0,0)*B(0,1) + A(1,0)*B(1,1);
00918 
00919       C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(1,0);
00920       C(1,1) = A(0,1)*B(0,1) + A(1,1)*B(1,1);
00921       break;
00922 
00923   }
00924 
00925   return C;
00926 }
00927 
00928 //
00929 // R^N tensor tensor product C = A B^T
00930 // \param A tensor
00931 // \param B tensor
00932 // \return a tensor \f$ A \cdot B^T \f$
00933 //
00934 template<typename S, typename T, Index N>
00935 inline
00936 Tensor<typename Promote<S, T>::type, N>
00937 dot_t(Tensor<S, N> const & A, Tensor<T, N> const & B)
00938 {
00939   Index const
00940   dimension = A.get_dimension();
00941 
00942   assert(B.get_dimension() == dimension);
00943 
00944   Tensor<typename Promote<S, T>::type, N>
00945   C(dimension);
00946 
00947   switch (dimension) {
00948 
00949     default:
00950       for (Index i = 0; i < dimension; ++i) {
00951         for (Index j = 0; j < dimension; ++j) {
00952 
00953           typename Promote<S, T>::type
00954           s = 0.0;
00955 
00956           for (Index p = 0; p < dimension; ++p) {
00957             s += A(i, p) * B(j, p);
00958           }
00959           C(i, j) = s;
00960         }
00961       }
00962       break;
00963 
00964     case 3:
00965       C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(0,1) + A(0,2)*B(0,2);
00966       C(0,1) = A(0,0)*B(1,0) + A(0,1)*B(1,1) + A(0,2)*B(1,2);
00967       C(0,2) = A(0,0)*B(2,0) + A(0,1)*B(2,1) + A(0,2)*B(2,2);
00968 
00969       C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(0,1) + A(1,2)*B(0,2);
00970       C(1,1) = A(1,0)*B(1,0) + A(1,1)*B(1,1) + A(1,2)*B(1,2);
00971       C(1,2) = A(1,0)*B(2,0) + A(1,1)*B(2,1) + A(1,2)*B(2,2);
00972 
00973       C(2,0) = A(2,0)*B(0,0) + A(2,1)*B(0,1) + A(2,2)*B(0,2);
00974       C(2,1) = A(2,0)*B(1,0) + A(2,1)*B(1,1) + A(2,2)*B(1,2);
00975       C(2,2) = A(2,0)*B(2,0) + A(2,1)*B(2,1) + A(2,2)*B(2,2);
00976       break;
00977 
00978     case 2:
00979       C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(0,1);
00980       C(0,1) = A(0,0)*B(1,0) + A(0,1)*B(1,1);
00981 
00982       C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(0,1);
00983       C(1,1) = A(1,0)*B(1,0) + A(1,1)*B(1,1);
00984       break;
00985 
00986   }
00987 
00988   return C;
00989 }
00990 
00991 //
00992 // R^N tensor tensor product C = A^T B^T
00993 // \param A tensor
00994 // \param B tensor
00995 // \return a tensor \f$ A^T \cdot B^T \f$
00996 //
00997 template<typename S, typename T, Index N>
00998 inline
00999 Tensor<typename Promote<S, T>::type, N>
01000 t_dot_t(Tensor<S, N> const & A, Tensor<T, N> const & B)
01001 {
01002   Index const
01003   dimension = A.get_dimension();
01004 
01005   assert(B.get_dimension() == dimension);
01006 
01007   Tensor<typename Promote<S, T>::type, N>
01008   C(dimension);
01009 
01010   switch (dimension) {
01011 
01012     default:
01013       for (Index i = 0; i < dimension; ++i) {
01014         for (Index j = 0; j < dimension; ++j) {
01015 
01016           typename Promote<S, T>::type
01017           s = 0.0;
01018 
01019           for (Index p = 0; p < dimension; ++p) {
01020             s += A(p, i) * B(j, p);
01021           }
01022           C(i, j) = s;
01023         }
01024       }
01025       break;
01026 
01027     case 3:
01028       C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(0,1) + A(2,0)*B(0,2);
01029       C(0,1) = A(0,0)*B(1,0) + A(1,0)*B(1,1) + A(2,0)*B(1,2);
01030       C(0,2) = A(0,0)*B(2,0) + A(1,0)*B(2,1) + A(2,0)*B(2,2);
01031 
01032       C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(0,1) + A(2,1)*B(0,2);
01033       C(1,1) = A(0,1)*B(1,0) + A(1,1)*B(1,1) + A(2,1)*B(1,2);
01034       C(1,2) = A(0,1)*B(2,0) + A(1,1)*B(2,1) + A(2,1)*B(2,2);
01035 
01036       C(2,0) = A(0,2)*B(0,0) + A(1,2)*B(0,1) + A(2,2)*B(0,2);
01037       C(2,1) = A(0,2)*B(1,0) + A(1,2)*B(1,1) + A(2,2)*B(1,2);
01038       C(2,2) = A(0,2)*B(2,0) + A(1,2)*B(2,1) + A(2,2)*B(2,2);
01039       break;
01040 
01041     case 2:
01042       C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(0,1);
01043       C(0,1) = A(0,0)*B(1,0) + A(1,0)*B(1,1);
01044 
01045       C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(0,1);
01046       C(1,1) = A(0,1)*B(1,0) + A(1,1)*B(1,1);
01047       break;
01048 
01049   }
01050 
01051   return C;
01052 }
01053 
01054 //
01055 // R^N tensor tensor double dot product (contraction)
01056 // \param A tensor
01057 // \param B tensor
01058 // \return a scalar \f$ A : B \f$
01059 //
01060 template<typename S, typename T, Index N>
01061 inline
01062 typename Promote<S, T>::type
01063 dotdot(Tensor<S, N> const & A, Tensor<T, N> const & B)
01064 {
01065   Index const
01066   dimension = A.get_dimension();
01067 
01068   assert(B.get_dimension() == dimension);
01069 
01070   typename Promote<S, T>::type
01071   s = 0.0;
01072 
01073   switch (dimension) {
01074 
01075     default:
01076       for (Index p = 0; p < dimension; ++p) {
01077         for (Index q = 0; q < dimension; ++q) {
01078           s += A(p, q) * B(p, q);
01079         }
01080       }
01081       break;
01082 
01083     case 3:
01084       s+= A(0,0)*B(0,0) + A(0,1)*B(0,1) + A(0,2)*B(0,2);
01085       s+= A(1,0)*B(1,0) + A(1,1)*B(1,1) + A(1,2)*B(1,2);
01086       s+= A(2,0)*B(2,0) + A(2,1)*B(2,1) + A(2,2)*B(2,2);
01087       break;
01088 
01089     case 2:
01090       s+= A(0,0)*B(0,0) + A(0,1)*B(0,1);
01091       s+= A(1,0)*B(1,0) + A(1,1)*B(1,1);
01092       break;
01093 
01094   }
01095 
01096   return s;
01097 }
01098 
01099 //
01100 // R^N dyad
01101 // \param u vector
01102 // \param v vector
01103 // \return \f$ u \otimes v \f$
01104 //
01105 template<typename S, typename T, Index N>
01106 inline
01107 Tensor<typename Promote<S, T>::type, N>
01108 dyad(Vector<S, N> const & u, Vector<T, N> const & v)
01109 {
01110   Index const
01111   dimension = u.get_dimension();
01112 
01113   assert(v.get_dimension() == dimension);
01114 
01115   Tensor<typename Promote<S, T>::type, N>
01116   A(dimension);
01117 
01118   switch (dimension) {
01119 
01120     default:
01121       for (Index i = 0; i < dimension; ++i) {
01122 
01123         typename Promote<S, T>::type const
01124         s = u(i);
01125 
01126         for (Index j = 0; j < dimension; ++j) {
01127           A(i, j) = s * v(j);
01128         }
01129       }
01130       break;
01131 
01132     case 3:
01133       A(0,0) = u(0) * v(0);
01134       A(0,1) = u(0) * v(1);
01135       A(0,2) = u(0) * v(2);
01136 
01137       A(1,0) = u(1) * v(0);
01138       A(1,1) = u(1) * v(1);
01139       A(1,2) = u(1) * v(2);
01140 
01141       A(2,0) = u(2) * v(0);
01142       A(2,1) = u(2) * v(1);
01143       A(2,2) = u(2) * v(2);
01144       break;
01145 
01146     case 2:
01147       A(0,0) = u(0) * v(0);
01148       A(0,1) = u(0) * v(1);
01149 
01150       A(1,0) = u(1) * v(0);
01151       A(1,1) = u(1) * v(1);
01152       break;
01153 
01154   }
01155 
01156   return A;
01157 }
01158 
01159 //
01160 // R^N bun operator, just for Jay, and now Reese too.
01161 // \param u vector
01162 // \param v vector
01163 // \return \f$ u \otimes v \f$
01164 //
01165 template<typename S, typename T, Index N>
01166 inline
01167 Tensor<typename Promote<S, T>::type, N>
01168 bun(Vector<S, N> const & u, Vector<T, N> const & v)
01169 {
01170   return dyad(u, v);
01171 }
01172 
01173 //
01174 // R^N tensor product
01175 // \param u vector
01176 // \param v vector
01177 // \return \f$ u \otimes v \f$
01178 //
01179 template<typename S, typename T, Index N>
01180 inline
01181 Tensor<typename Promote<S, T>::type, N>
01182 tensor(Vector<S, N> const & u, Vector<T, N> const & v)
01183 {
01184   return dyad(u, v);
01185 }
01186 
01187 //
01188 // R^N diagonal tensor from vector
01189 // \param v vector
01190 // \return A = diag(v)
01191 //
01192 template<typename T, Index N>
01193 Tensor<T, N>
01194 diag(Vector<T, N> const & v)
01195 {
01196   Index const
01197   dimension = v.get_dimension();
01198 
01199   Tensor<T, N>
01200   A = zero<T, N>(dimension);
01201 
01202   switch (dimension) {
01203 
01204     default:
01205       for (Index i = 0; i < dimension; ++i) {
01206         A(i, i) = v(i);
01207       }
01208       break;
01209 
01210     case 3:
01211       A(0,0) = v(0);
01212       A(1,1) = v(1);
01213       A(2,2) = v(2);
01214       break;
01215 
01216     case 2:
01217       A(0,0) = v(0);
01218       A(1,1) = v(1);
01219       break;
01220 
01221   }
01222 
01223   return A;
01224 }
01225 
01226 //
01227 // R^N diagonal of tensor in a vector
01228 // \param A tensor
01229 // \return v = diag(A)
01230 //
01231 template<typename T, Index N>
01232 Vector<T, N>
01233 diag(Tensor<T, N> const & A)
01234 {
01235   Index const
01236   dimension = A.get_dimension();
01237 
01238   Vector<T, N>
01239   v(dimension);
01240 
01241   switch (dimension) {
01242 
01243     default:
01244       for (Index i = 0; i < dimension; ++i) {
01245         v(i) = A(i, i);
01246       }
01247       break;
01248 
01249     case 3:
01250       v(0) = A(0,0);
01251       v(1) = A(1,1);
01252       v(2) = A(2,2);
01253       break;
01254 
01255     case 2:
01256       v(0) = A(0,0);
01257       v(1) = A(1,1);
01258       break;
01259 
01260   }
01261 
01262   return v;
01263 }
01264 
01265 //
01266 // Zero 2nd-order tensor
01267 // All components are zero
01268 //
01269 template<typename T, Index N>
01270 inline
01271 Tensor<T, N> const
01272 zero()
01273 {
01274   return Tensor<T, N>(N, ZEROS);
01275 }
01276 
01277 template<typename T>
01278 inline
01279 Tensor<T, DYNAMIC> const
01280 zero(Index const dimension)
01281 {
01282   return Tensor<T, DYNAMIC>(dimension, ZEROS);
01283 }
01284 
01285 template<typename T, Index N>
01286 inline
01287 Tensor<T, N> const
01288 zero(Index const dimension)
01289 {
01290   if (N != DYNAMIC) assert(dimension == N);
01291   return Tensor<T, N>(dimension, ZEROS);
01292 }
01293 
01294 //
01295 // R^N 2nd-order identity tensor
01296 //
01297 namespace {
01298 
01299 template< typename T, Index N>
01300 inline
01301 void ones_in_diagonal(Tensor<T, N> & A)
01302 {
01303   Index const
01304   dimension = A.get_dimension();
01305 
01306   switch (dimension) {
01307 
01308     default:
01309       for (Index i = 0; i < dimension; ++i) {
01310         A(i, i) = 1.0;
01311       }
01312       break;
01313 
01314     case 3:
01315       A(0,0) = 1.0;
01316       A(1,1) = 1.0;
01317       A(2,2) = 1.0;
01318       break;
01319 
01320     case 2:
01321       A(0,0) = 1.0;
01322       A(1,1) = 1.0;
01323       break;
01324 
01325   }
01326 
01327   return;
01328 }
01329 
01330 } // anonymous namespace
01331 
01332 template<typename T, Index N>
01333 inline
01334 Tensor<T, N> const
01335 identity()
01336 {
01337   Tensor<T, N> A(N, ZEROS);
01338   ones_in_diagonal(A);
01339   return A;
01340 }
01341 
01342 template<typename T>
01343 inline
01344 Tensor<T, DYNAMIC> const
01345 identity(Index const dimension)
01346 {
01347   Tensor<T, DYNAMIC> A(dimension, ZEROS);
01348   ones_in_diagonal(A);
01349   return A;
01350 }
01351 
01352 template<typename T, Index N>
01353 inline
01354 Tensor<T, N> const
01355 identity(Index const dimension)
01356 {
01357   if (N != DYNAMIC) assert(dimension == N);
01358 
01359   Tensor<T, N> A(dimension, ZEROS);
01360   ones_in_diagonal(A);
01361   return A;
01362 }
01363 
01364 //
01365 // R^N 2nd-order identity tensor, à la Matlab
01366 //
01367 template<typename T, Index N>
01368 inline
01369 Tensor<T, N> const
01370 eye()
01371 {
01372   return identity<T, N>();
01373 }
01374 
01375 template<typename T>
01376 inline
01377 Tensor<T, DYNAMIC> const
01378 eye(Index const dimension)
01379 {
01380   return identity<T>(dimension);
01381 }
01382 
01383 template<typename T, Index N>
01384 inline
01385 Tensor<T, N> const
01386 eye(Index const dimension)
01387 {
01388   return identity<T, N>(dimension);
01389 }
01390 
01391 //
01392 // R^N 2nd-order tensor transpose
01393 //
01394 template<typename T, Index N>
01395 inline
01396 Tensor<T, N>
01397 transpose(Tensor<T, N> const & A)
01398 {
01399   Index const
01400   dimension = A.get_dimension();
01401 
01402   Tensor<T, N>
01403   B = A;
01404 
01405   switch (dimension) {
01406 
01407     default:
01408       for (Index i = 0; i < dimension; ++i) {
01409         for (Index j = i + 1; j < dimension; ++j) {
01410           std::swap(B(i, j), B(j, i));
01411         }
01412       }
01413       break;
01414 
01415     case 3:
01416       std::swap(B(0,1), B(1,0));
01417       std::swap(B(0,2), B(2,0));
01418 
01419       std::swap(B(1,2), B(2,1));
01420 
01421       break;
01422 
01423     case 2:
01424       std::swap(B(0,1), B(1,0));
01425 
01426       break;
01427 
01428   }
01429 
01430   return B;
01431 }
01432 
01433 //
01434 // R^N symmetric part of 2nd-order tensor
01435 // \return \f$ \frac{1}{2}(A + A^T) \f$
01436 //
01437 template<typename T, Index N>
01438 inline
01439 Tensor<T, N>
01440 sym(Tensor<T, N> const & A)
01441 {
01442   Index const
01443   dimension = A.get_dimension();
01444 
01445   Tensor<T, N>
01446   B(dimension);
01447 
01448   switch (dimension) {
01449 
01450     default:
01451       B = 0.5 * (A + transpose(A));
01452       break;
01453 
01454     case 3:
01455     {
01456       T const & s00 = A(0,0);
01457       T const & s11 = A(1,1);
01458       T const & s22 = A(2,2);
01459 
01460       T const s01 = 0.5 * (A(0,1) + A(1,0));
01461       T const s02 = 0.5 * (A(0,2) + A(2,0));
01462       T const s12 = 0.5 * (A(1,2) + A(2,1));
01463 
01464       B(0,0) = s00;
01465       B(0,1) = s01;
01466       B(0,2) = s02;
01467 
01468       B(1,0) = s01;
01469       B(1,1) = s11;
01470       B(1,2) = s12;
01471 
01472       B(2,0) = s02;
01473       B(2,1) = s12;
01474       B(2,2) = s22;
01475     }
01476     break;
01477 
01478     case 2:
01479     {
01480       T const & s00 = A(0,0);
01481       T const & s11 = A(1,1);
01482 
01483       T const s01 = 0.5 * (A(0,1) + A(1,0));
01484 
01485       B(0,0) = s00;
01486       B(0,1) = s01;
01487 
01488       B(1,0) = s01;
01489       B(1,1) = s11;
01490     }
01491     break;
01492 
01493   }
01494 
01495   return B;
01496 }
01497 
01498 //
01499 // R^N skew symmetric part of 2nd-order tensor
01500 // \return \f$ \frac{1}{2}(A - A^T) \f$
01501 //
01502 template<typename T, Index N>
01503 inline
01504 Tensor<T, N>
01505 skew(Tensor<T, N> const & A)
01506 {
01507   Index const
01508   dimension = A.get_dimension();
01509 
01510   Tensor<T, N>
01511   B(dimension);
01512 
01513   switch (dimension) {
01514 
01515     default:
01516       B = 0.5 * (A - transpose(A));
01517       break;
01518 
01519     case 3:
01520     {
01521       T const s01 = 0.5*(A(0,1)-A(1,0));
01522       T const s02 = 0.5*(A(0,2)-A(2,0));
01523       T const s12 = 0.5*(A(1,2)-A(2,1));
01524 
01525       B(0,0) = 0.0;
01526       B(0,1) = s01;
01527       B(0,2) = s02;
01528 
01529       B(1,0) = -s01;
01530       B(1,1) = 0.0;
01531       B(1,2) = s12;
01532 
01533       B(2,0) = -s02;
01534       B(2,1) = -s12;
01535       B(2,2) = 0.0;
01536     }
01537     break;
01538 
01539     case 2:
01540     {
01541       T const s01 = 0.5*(A(0,1)-A(1,0));
01542 
01543       B(0,0) = 0.0;
01544       B(0,1) = s01;
01545 
01546       B(1,0) = -s01;
01547       B(1,1) = 0.0;
01548     }
01549     break;
01550 
01551   }
01552 
01553   return B;
01554 }
01555 
01556 //
01557 // R^N skew symmetric 2nd-order tensor from vector, undefined
01558 // for N!=3.
01559 // \param u vector
01560 //
01561 template<typename T, Index N>
01562 inline
01563 Tensor<T, N>
01564 skew(Vector<T, N> const & u)
01565 {
01566   Index const
01567   dimension = u.get_dimension();
01568 
01569   Tensor<T, N>
01570   A(dimension);
01571 
01572   switch (dimension) {
01573 
01574     case 3:
01575       A(0,0) = 0.0;
01576       A(0,1) = -u(2);
01577       A(0,2) = u(1);
01578 
01579       A(1,0) = u(2);
01580       A(1,1) = 0.0;
01581       A(1,2) = -u(0);
01582 
01583       A(2,0) = -u(1);
01584       A(2,1) = u(0);
01585       A(2,2) = 0.0;
01586       break;
01587 
01588     default:
01589       std::cerr << "ERROR: " << __PRETTY_FUNCTION__;
01590       std::cerr << std::endl;
01591       std::cerr << "Skew from vector undefined for R^" << N;
01592       std::cerr << std::endl;
01593       exit(1);
01594       break;
01595 
01596   }
01597 
01598   return A;
01599 }
01600 
01601 } // namespace Intrepid
01602 
01603 #endif // Intrepid_MiniTensor_Tensor_i_h