Provides classes for 4th- and 2nd order tensors and vectors. For example, a fourth order identity tensor in 3-D is obtained as follows:

#include <cppmat/cppmat.h>

int main()
  cppmat::cartesian::tensor4<double> A = cppmat::cartesian::tensor4<double>::I(3);


  std::cout << A << std::endl;

  return 0;


If you know that you will work in a fixed (and small) number of dimensions (e.g. 2 or 3), please consider using cppmat::tiny::cartesian instead of cppmat::cartesian. This is generally more efficient as it can take advantage of the knowledge that the arrays are fixed size and relatively small. Also several loops are unrolled.


The notation can be shortened to:

#include <cppmat/cppmat.h>

using T4 = cppmat::cartesian::tensor4<double>;

int main()
  T4 A = T4::I(3);


  return 0;



[var_cartesian_tensor4.h, var_cartesian_tensor4.hpp]

4th-order tensor (rank 4 tensor) of arbitrary dimension.

cppmat::cartesian::tensor4<double> A(3);

A(0,0,0,0) = ...


[var_cartesian_tensor2.h, var_cartesian_tensor2.hpp]

2nd-order tensor (rank 2 tensor) of arbitrary dimension.

cppmat::cartesian::tensor2<double> A(3);

A(0,0) = ...


[var_cartesian_tensor2s.h, var_cartesian_tensor2s.hpp]

Symmetric 2nd-order tensor.

cppmat::cartesian::tensor2s<double> A(3);

A(0,0) = ...

For example, for the case of 3 dimensions, the following components are stored:

[ X , X , X ;
      X , X ;
          X ]

The remaining components are inferred from symmetry. See cppmat::symmetric::matrix.


[var_cartesian_tensor2d.h, var_cartesian_tensor2d.hpp]

diagonal 2nd-order tensor.

cppmat::cartesian::tensor2d<double> A(3);

A(0,0) = ...

For example, for the case of 3 dimensions, the following components are stored:

[ X         ;
      X     ;
          X ]

The remaining components are imposed to be zero. See cppmat::diagonal::matrix.


[var_cartesian_vector.h, var_cartesian_vector.hpp]

Vector (rank 1 tensor) of arbitrary dimension. For example:

cppmat::cartesian::vector<double> A(3);

A(0) = ...


Because of the flexibility of C++ it is easy to switch between these specialized classes and the more general cppmat::cartesian::tensor2 classes. For example, the following will work:

using T2  = cppmat::cartesian::tensor2 <double>;
using T2d = cppmat::cartesian::tensor2d<double>;

T2d I = T2d::I(3);
T2  A = I;

or even

T2 I = T2d::I(3);

Also arithmetic works:

T2d A = 3.0 * I;

Note that it is even possible to perform arithmetic between the three different 2nd-order tensor classes, whereby the output type depends on the type of operator.

Finally, all the Methods accept all three classes - cppmat::cartesian::tensor2, cppmat::cartesian::tensor2s, cppmat::cartesian::tensor2d - allowing their usage without any prior type casting. In fact the methods will often perform better for the specialized classes since fewer operations are needed.


The easy automatic conversion described above is not possible from a class to another where more assumptions on the structure are made (e.g. from cppmat::cartesian::tensor2 to cppmat::cartesian::tensor2d) because information is (potentially) lost.


All the methods of cppmat::array (or cppmat::matrix, cppmat::symmetric::matrix, cppmat::symmetric::matrix, or cppmat::vector) are overloaded. In addition, the following tensor algebra is available.


Below the rank can be inferred from the indices, but should be easy to understand even without them. Pseudo-code is used to introduce the methods. For the first method it is short for:

cppmat::cartesian::tensor4<double> A = cppmat::cartesian::tensor4<double>::I(3);
cppmat::cartesian::tensor2<double> B = cppmat::cartesian::tensor2<double>::I(3);

cppmat::cartesian::tensor2<double> C = A.ddot(B);

Finally, each occurrence of cppmat::cartesian::tensor2 can be replaced by cppmat::cartesian::tensor2s or cppmat::cartesian::tensor2d. The latter two often perform better.

  • cppmat::cartesian::tensor4<X>:

    • cppmat::cartesian::tensor4<X> C = A.ddot(const cppmat::cartesian::tensor4<X> &B)

      Double tensor contraction : C_{ijmn} = A_{ijkl} B_{lkmn}

    • cppmat::cartesian::tensor2<X> C = A.ddot(const cppmat::cartesian::tensor2<X> &B)

      Double tensor contraction C_{ij} = A_{ijkl} B_{lk}

    • cppmat::cartesian::tensor4<X> C = A.T()

      Transposition C_{lkji} = A_{ijkl}

    • cppmat::cartesian::tensor4<X> C = A.LT()

      Left transposition C_{jikl} = A_{ijkl}

    • cppmat::cartesian::tensor4<X> C = A.RT()

      Right transposition C_{ijlk} = A_{ijkl}

  • cppmat::cartesian::tensor2<X>:

    • cppmat::cartesian::tensor2<X> C = A.ddot(const cppmat::cartesian::tensor4<X> &B)

      Double tensor contraction C_{kl} = A_{ij} B_{jikl}

    • X C = A.ddot(const cppmat::cartesian::tensor2<X> &B)

      Double tensor contraction C = A_{ij} B_{ji}

    • cppmat::cartesian::tensor2<X> C = A.dot(const cppmat::cartesian::tensor2<X> &B)

      Tensor contraction C_{ik} = A_{ij} B_{jk}

    • cppmat::cartesian::vector<X> C = A.dot(const cppmat::cartesian::vector<X> &B)

      Tensor contraction C_{i} = A_{ij} B_{j}

    • cppmat::cartesian::tensor4<X> C = A.dyadic(const cppmat::cartesian::tensor2<X> &B)

      Dyadic product C_{ijkl} = A_{ij} B_{kl}

    • cppmat::cartesian::tensor2<X> C = A.T()

      Transposition C_{ji} = A_{ij}

    • X C = A.trace()

      The trace of the tensor (i.e. the sum of the diagonal components) C = A_{ii}

    • X C = A.det()

      The determinant C = \det \underline{\bm{A}}

    • cppmat::cartesian::tensor2<X> C = A.inv()

      The inverse C_{ij} = A_{ij}^{-1}

  • cppmat::cartesian::vector<X>:

    • X C = A.dot(const cppmat::cartesian::vector<X> &B)

      Tensor contraction C = A_{i} B_{i}

    • cppmat::cartesian::vector<X> C = A.dot(const cppmat::cartesian::tensor2<X> &B)

      Tensor contraction C_{j} = A_{i} B_{ij}

    • cppmat::cartesian::tensor2<X> C = A.dyadic(const cppmat::cartesian::vector<X> &B)

      Dyadic product C_{ij} = A_{i} B_{j}

    • cppmat::cartesian::vector<X> C = A.cross(const cppmat::cartesian::vector<X> &B)

      Cross product \vec{C} = \vec{A} \otimes \vec{B}


One can also call the methods as functions using cppmmat::ddot(A,B), cppmmat::dot(A,B), cppmmat::dyadic(A,B), cppmmat::cross(A,B), cppmmat::T(A), cppmmat::RT(A), cppmmat::LT(A), cppmmat::inv(A), cppmmat::det(A), and cppmmat::trace(A). This is fully equivalent (in fact the class methods call these external functions).