Basic arithmetic¶
Addition¶
-
template<typename _TensorLHS, typename _TensorRHS, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorLHS>::type>::value>* = nullptr, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorRHS>::type>::value>* = nullptr>
inline constexpr auto operator+(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ Addition of two tensors of same rank and dimension.
tmech::tensor<double, 3, 2> a,b,c; a.randn(); b.randn(); c = a + b;
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Right hand side tensor expression.
Subtraction¶
-
template<typename _TensorLHS, typename _TensorRHS, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorLHS>::type>::value>* = nullptr, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorRHS>::type>::value>* = nullptr>
inline constexpr auto operator-(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ Subtraction of two tensors of same rank and dimension.
tmech::tensor<double, 3, 2> a,b,c; a.randn(); b.randn(); c = a - b;
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Right hand side tensor expression.
Single contraction¶
-
template<typename _TensorLHS, typename _TensorRHS, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorLHS>::type>::value>* = nullptr, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_TensorRHS>::type>::value>* = nullptr>
inline constexpr auto operator*(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ Single contraction of two tensors. Assume that the left hand side tensor is of rank m and the right hand side tensor of rank n. The resulting tensor is of rank m+n-2. The most right index of the left hand side tensor is contracted with the most left index of the right hand tensor.
tmech::tensor<double, 3, 2> a,b,c; a.randn(); b.randn(); c = a * b;
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Right hand side tensor expression.
Scalar update¶
-
template<typename _Scalar, typename _Tensor, typename std::enable_if<std::is_fundamental<typename std::decay<_Scalar>::type>::value>::type* = nullptr, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_Tensor>::type>::value>* = nullptr>
inline constexpr auto operator*(_Scalar __scalar, _Tensor &&__tensor)¶ Scalar update of a tensor.
tmech::tensor<double, 3, 2> a,b; a.randn(); b = 2.0*a;
- Template Parameters:
_Tensor – Tensor object
_Scalar – Scalar type. Must be a std::fundamental
- Parameters:
__scalar – Scalar
__tensor – Tensor expression.
-
template<typename _Scalar, typename _Tensor, typename std::enable_if<std::is_fundamental<typename std::decay<_Scalar>::type>::value>::type* = nullptr, typename std::enable_if_t<tmech::is_tensor_type<typename std::decay<_Tensor>::type>::value>* = nullptr>
inline constexpr auto operator/(_Tensor &&__tensor, _Scalar &&__scalar)¶ Tensor division by a scalar.
tmech::tensor<double, 3, 2> a,b; a.randn(); b = a/2.0;
- Template Parameters:
_Tensor – Tensor object
_Scalar – Scalar type. Must be a std::fundamental
- Parameters:
__scalar – Scalar
__tensor – Tensor expression.
Basis rearrangement¶
General basis rearrangement¶
-
template<typename _Sequence, typename _Tensor, typename, typename>
inline constexpr auto basis_change(_Tensor &&__tensor)¶ General basis rearrangement. Controlled by template parameter _Sequence, which contains the new order of bases.
Self assignment//Basis 1,2,3,4 is swaped to 3,4,1,2. tmech::tensor<double, 3, 4> A, B; A.randn(); B = tmech::basis_change<tmech::sequence<3,4,1,2>>(A); B = tmech::basis_change<tmech::sequence<3,4,1,2>>(A+2*A);
//Basis 1,2,3,4 is swaped to 3,4,1,2. tmech::tensor<double, 3, 4> A; A.randn(); A = tmech::eval(tmech::basis_change<tmech::sequence<3,4,1,2>>(A)); A = tmech::eval(tmech::basis_change<tmech::sequence<3,4,1,2>>(A+2*A));
- Template Parameters:
_Sequence – A tmech::sequence<>, which contains the new order of bases
_Derived – Tensor object
- Parameters:
__tensor – Tensor expression from which the basis rearrangement is to be formed
Transposition¶
-
template<typename _Tensor, typename>
inline constexpr auto trans(_Tensor &&__tensor)¶ Wrapper function for transposition for a second-order tensor and major transposition of a fourth-order tensor.
The transpose of a second-order tensor in index notation
.\ The transpose of a fourth-order tensor in index notation
.
tmech::tensor<double,3,2> A, B; A.randn(); B = tmech::trans(A);
tmech::tensor<double,3,2> A; A.randn(); A = tmech::eval(tmech::trans(A));
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the transposition is to be formed.
Left basis transposition¶
-
template<typename _Tensor, typename>
constexpr auto transl(_Tensor &&__tensor)¶ Transposition of the left base a fourth-order tensor
.
tmech::tensor<double,3,4> A, B; A.randn(); B = tmech::transl(A);
tmech::tensor<double,3,4> A; A.randn(); A = tmech::eval(tmech::transl(A));
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the left transpose part is to be formed.
Outer product¶
General outer product¶
-
template<typename _SequenceLHS, typename _SequenceRHS, typename _TensorLHS, typename _TensorRHS, typename, typename>
inline constexpr auto outer_product(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ General outer product. Controlled by template parameters _SequenceLHS and _SequenceRHS. Bases contained in sequence _SequenceLHS are used for ordered element acces in __lhs tensor expression. Bases contained in sequence _SequenceRHS are used for ordered element acces in __rhs tensor expression. Both togther peform outer product.
using SeqL = tmech::sequence<1,2>; using SeqR = tmech::sequence<3,4>; //Bases 1,2 of the new tensor C //are given by a and bases 3,4 are //given by b. tmech::tensor<double, 3, 2> a, b; tmech::tensor<double, 3, 4> C; C = tmech::outer_product<SeqL, SeqR>(a,b);
- Template Parameters:
_SequenceLHS – Left hand side sequence, which contains numbers of bases to peform the outer product.
_SequenceRHS – Right hand side sequence, which contains numbers of bases to peform the outer product.
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Dyadic product¶
-
template<typename _TensorLHS, typename _TensorRHS, typename, typename>
constexpr auto otimes(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ The dyadic product between a tensor object of order n and a tensor object of order m is a tensor of order m + n. The dyadic product between two first-order tensors is defined as.
tmech::tensor<double,3,2> A, B; tmech::tensor<double,3,4> C{tmech::otimes(A,B)}; tmech::tensor<double,3,6> D{tmech::otimes(C,B)}; tmech::tensor<double,3,8> E{tmech::otimes(C,C)};
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Lower dyadic product¶
-
template<typename _TensorLHS, typename _TensorRHS, typename, typename>
constexpr auto otimesl(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ The
product between two second-order tensors is defined as.
tmech::tensor<double,3,2> A, B; tmech::tensor<double,3,4> C{tmech::otimesl(A,B)};
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Upper dyadic product¶
-
template<typename _TensorLHS, typename _TensorRHS, typename, typename>
constexpr auto otimesu(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ The
product between two second-order tensors is defined as.
tmech::tensor<double,3,2> A, B; tmech::tensor<double,3,4> C{tmech::otimesu(A,B)};
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Inner product¶
General inner product¶
-
template<typename _SequenceLHS, typename _SequenceRHS, typename _TensorLHS, typename _TensorRHS, typename, typename>
inline constexpr auto inner_product(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ General inner product. Controlled by template parameters _SequenceLHS and _SequenceRHS. Bases contained in sequence _SequenceLHS are contracted with bases contained in sequence _SequenceRHS.
using SeqL = tmech::sequence<3,4>; using SeqR = tmech::sequence<1,2>; //Double contraction of two 4th order tensors tmech::tensor<double, 3, 4> A, B, C; C = tmech::inner_product<SeqL, SeqR>(A,B); //Double contraction of a 4th and a 2th order tensor tmech::tensor<double, 3, 2> a, c; c = tmech::inner_product<SeqL, SeqR>(C,a);
- Template Parameters:
_SequenceLHS – Left hand side sequence, which contains the numbers of bases used for contraction.
_SequenceRHS – Right hand side sequence, which contains the numbers of bases used for contraction.
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Double contraction¶
-
template<typename _TensorLHS, typename _TensorRHS, typename, typename>
inline constexpr auto dcontract(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ A double contraction between two tensors objects contracts the two most right and left indices. The result of a double contraction between a tensor of order n and a tensor of order m is a tensor of order m + n - 4.
tmech::tensor<double,3,4> A; tmech::tensor<double,3,2> B; A.randn(); B.randn(); auto c{tmech::dcontract(A,B)};
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Fourth contraction¶
-
template<typename _TensorLHS, typename _TensorRHS, typename, typename>
inline constexpr auto ddcontract(_TensorLHS &&__tensor_lhs, _TensorRHS &&__tensor_rhs)¶ A fourth contraction between two tensors objects contracts the fourth most right and left indices. The result of a double contraction between a tensor of order n and a tensor of order m is a tensor of order m + n - 8.
tmech::tensor<double,3,4> A; tmech::tensor<double,3,2> B; A.randn(); B.randn(); auto c{tmech::ddcontract(A,B)};
- Template Parameters:
_TensorLHS – Left hand side tensor object
_TensorRHS – Right hand side tensor object
- Parameters:
__tensor_lhs – Left hand side tensor expression.
__tensor_rhs – Reft hand side tensor expression.
Invers of a tensor¶
Second order tensors and fourth order tensors with minior-symmetry¶
-
template<typename _Tensor, typename, typename ..._Sequences>
inline constexpr auto inv(_Tensor &&__tensor, _Sequences...)¶ Inverse of a second- and a fourth-order tensor. The inverse of a second order tensor is defined by
, where
is the second order identity tensor.
tmech::tensor<double, 3, 2> A, B; A.randn(); B = tmech::inv(A);
The inverse of a fourth order tensor depends on the minior-symmetry. Using the following differentiation rule
yields a minior-symmetry in the first and in the second pair of indicies
and
, respectively. In this case the inverse is defined by
.
tmech::tensor<double, 3, 4> A, B; A.randn(); //the sequences are indicating the pairs of minior-symmetry B = tmech::inv<tmech::sequence<1,2>, tmech::sequence<3,4>>(A); // the rule above is the most used one, therefore the following is sufficient. // the correct indicies are set inside the function. B = tmech::inv(A);
Using the following differentiation rule
, yields a minior symmetry in the outer and in the inner pair of indicies
and
, respectively.
tmech::tensor<double, 3, 4> A, B; A.randn(); //the sequences are indicating the pairs of minior-symmetry B = tmech::inv<tmech::sequence<1,4>, tmech::sequence<2,3>>(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the inverse is to be formed.
Fully anisotropic tensors¶
-
template<typename _Tensor, typename, typename ..._Sequences>
inline constexpr auto invf(_Tensor &&__tensor, _Sequences...)¶ Inverse of a second- and a full anisotropic fourth-order tensor. The inverse of a second order tensor is defined by
, where
is the second order identity tensor. In the case of a second oder tensor the ouput is the same as from the function inv.
tmech::tensor<double, 3, 2> A, B; A.randn(); B = tmech::invf(A); //or B = tmech::inv(A);
This function assumes, that a fourth order tensor has no minior-symmetry and is therefore fully anisotropic. In this case the inverse is defined by
.
tmech::tensor<double, 3, 4> A, B; A.randn(); B = tmech::invf<tmech::sequence<1,2,3,4>>(A); // the rule above is the most used one, therefore the following is sufficient. // the correct indicies are set inside the function. B = tmech::invf(A);
Using other kind of differentiation rules as
must be indicated, due to the internal storage scheme. For example using
.
tmech::tensor<double, 3, 4> A, B; A.randn(); B = tmech::invf<tmech::sequence<1,3,4,2>>(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the inverse is to be formed.
Volumetric and deviatoric parts¶
Volumetric part¶
-
template<typename _Tensor, typename>
inline constexpr auto vol(_Tensor &&__tensor)¶ Volumetric part of a second-order tensor
, where
is the dimension.
tmech::tensor<double,3,2> A, B; A.randn(); B = tmech::vol(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the volumetric part is to be formed.
Deviatoric part¶
-
template<typename _Tensor, typename>
inline constexpr auto dev(_Tensor &&__tensor)¶ Deviatoric part of a second-order tensor
.
tmech::tensor<double,3,2> A, B; A.randn(); B = tmech::dev(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the deviatoric part is to be formed.
Symmetric and skew-symmetric parts¶
Symmetric part¶
-
template<typename _Tensor, typename>
constexpr auto sym(_Tensor &&__tensor)¶ Symmetric part of a second-order tensor
.
tmech::tensor<double,3,2> A, B; A.randn(); B = tmech::sym(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the symmetric part is to be formed.
Skew-symmetric part¶
-
template<typename _Tensor, typename>
constexpr auto skew(_Tensor &&__tensor)¶ Skew-symmetric part of a second-order tensor
.
tmech::tensor<double, 3, 2> A, B; A.randn(); B = tmech::skew(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the skew-symmetric part is to be formed.
Isotropic tensor functions¶
General function¶
-
template<typename _Function, typename _Tensor, typename>
inline constexpr auto isotropic_tensor_function(_Tensor &&__tensor)¶ Isotropic tensor function of a symmetric second-order tensor.
struct sqrt{ template<typename T> static constexpr inline auto apply(T const& value){return std::sqrt(value);} template<typename T> static constexpr inline auto derivative(T const& value){return 1./(2.*std::sqrt(value));} }; tmech::tensor<double, 3, 2> A, B; A.randn(); B = tmech::isotropic_tensor_function<sqrt>(A);
- Template Parameters:
_Function –
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Square root¶
-
template<typename _Tensor, typename>
inline constexpr auto sqrt(_Tensor &&__tensor)¶ Square root of a positive semi-definite symmetric second-order tensor
. The square is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
tmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); B = tmech::sqrt(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Exponential map¶
-
template<typename _Tensor, typename>
inline constexpr auto exp_sym(_Tensor &&__tensor)¶ Exponential map
of a positive semi-definite symmetric second-order tensor. The exponential map is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
tmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); B = tmech::exp_sym(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Logarithmic map¶
-
template<typename _Tensor, typename>
inline constexpr auto log(_Tensor &&__tensor)¶ Logarithmic map
of a positive semi-definite symmetric second-order tensor. The Logarithmic map is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
tmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); B = tmech::log(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Positive-negative decomposition¶
General method¶
-
template<typename _Tensor, typename>
inline constexpr auto positive_negative_decomposition(_Tensor &&__tensor)¶ Positive and negative decomposition
of a positive semi-definite symmetric second-order tensor is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
tmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); auto A_pos_neg = tmech::positive_negative_decomposition(A); auto A_pos = A_pos_neg.positive(); auto A_neg = A_pos_neg.negative();
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Only positive part¶
-
template<typename _Tensor, typename>
inline constexpr auto positive(_Tensor &&__tensor)¶ The positive part
of a positive semi-definite symmetric second-order tensor is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
If both partstmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); B = tmech::positive(A);
and
are needed use
positive_negative_decomposition().- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Only negative part¶
-
template<typename _Tensor, typename>
inline constexpr auto negative(_Tensor &&__tensor)¶ The negative part
of a positive semi-definite symmetric second-order tensor is given by spectral decomposition.
whereis the number of non repeated eigenvalues
and
is the corresponding eigenbase.
If both partstmech::tensor<double, 3, 2> A, B; A = tmech::sym(tmech::randn<double,3,2>()); B = tmech::negative(A);
and
are needed use
positive_negative_decomposition().- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression
Eigen-decomposition¶
-
template<typename _Tensor, typename>
inline constexpr auto eigen_decomposition(_Tensor &&__tensor)¶ Eigendecomposition of a positive semi-definite symmetric second-order tensor.
whereis the number of non repeated eigenvalues,
are the corresponding eigenvalues,
eigenvectors and
eigenbasen.
Using eigenbases to get the inverse
tmech::tensor<double, 3, 2> A, A_inv; A = tmech::sym(tmech::randn<double,3,2>()); auto A_eig = tmech::eigen_decomposition(A); const auto[eigenvalues, eigenbasis]{A_eig.decompose_eigenbasis()}; const auto idx{A_eig.non_repeated_eigenvalues_index()}; for(std::size_t i{0}; i<A_eig.number_non_repeated_eigenvalues(); ++i){ A_inv += (1.0/eigenvalues[idx[i]])*eigenbasis[idx[i]]; } std::cout<<std::boolalpha<<tmech::almost_equal(tmech::inv(A), A_inv, 5e-7)<<std::endl;
Using eigenvectors to get the inverse
tmech::tensor<double, 3, 2> A, A_inv; A = tmech::sym(tmech::randn<double,3,2>()); auto A_eig = tmech::eigen_decomposition(A); const auto[eigenvalues, eigenvectors]{A_eig.decompose()}; const auto idx{A_eig.non_repeated_eigenvalues_index()}; for(std::size_t i{0}; i<A_eig.number_non_repeated_eigenvalues(); ++i){ A_inv += (1.0/eigenvalues[idx[i]])*tmech::otimes(eigenvectors[idx[i]],eigenvectors[idx[i]]); } std::cout<<std::boolalpha<<tmech::almost_equal(tmech::inv(A), A_inv, 5e-7)<<std::endl;
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression, from which the eigen decomposition is to be computed.
Sign decomposition¶
-
template<typename _Tensor, typename>
inline constexpr auto sign(_Tensor &&__tensor, typename std::decay<_Tensor>::type::value_type __eps = 5e-7, std::size_t __max_iter = 10)¶ Sign tensor decomposition of a second-order tensor.
The decomposition is based on a Newton iteration as describet here.which converges quadratically tofor any
having no pure imaginary eigenvalues.
tmech::tensor<double, 3, 2> A, B; A.randn(); B = tmech::sign(A);
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression from which the inverse is to be formed.
__eps – Tolerance for Newton iteration
__max_iter – Maximum of Newton iterations
Polar decomposition¶
-
template<typename _Tensor, typename>
inline constexpr auto polar_decomposition(_Tensor &&__tensor, bool const __newton_method, typename std::decay<_Tensor>::type::value_type const __tol, std::size_t const __max_steps)¶ Polar decomposition of a positive semi-definite symmetric second-order tensor.
whereis an orthogonal tensor also knwon as the rotation tensor,
and
are symmetric tensors called the right and the left stretch tensor, respectively. This function provides two different method to determine
,
and
. The frist method uses spectral decomposition
//use the spectral decomposition tmech::tensor<double, 3, 2> F; F.randn(); auto F_polar = tmech::polar_decomposition(F); F = F_polar.R()*F_polar.U(); F = F_polar.V()*F_polar.R();
The second one is based on a Newton iteration
//use the newton iteration tmech::tensor<double, 3, 2> F; F.randn(); auto F_polar = tmech::polar_decomposition(F, // tensor to decompose true, //use newton iteration 5e-7, // tolerance 5 // number of max steps ); F = F_polar.R()*F_polar.U(); F = F_polar.V()*F_polar.R();
The following derivatives are also important
explicit results are given here//use the spectral decomposition tmech::tensor<double, 3, 2> F; F.randn(); auto F_polar = tmech::polar_decomposition(F); auto dR = F_polar.R().derivative(); auto dU = F_polar.U().derivative(); auto dV = F_polar.V().derivative();
- Template Parameters:
_Tensor – Tensor object
- Parameters:
__tensor – Tensor expression, from which the polar decomposition is to be computed.
__newton_method – True if Newton iteration should be used
__tol – Tolerance for Newton iteration
__max_steps – Maximum number of Newton iterations
Exponential map¶
-
template<typename _Tensor, typename>
inline constexpr auto exp(_Tensor &&__tensor)¶ Exponential map of a nonsymmetric second order tensor.
tmech::tensor<double, 3, 2> A{9.064107e-01, -4.649874e-01, 4.431378e-01, 1.557860e+00, 2.493285e-01, -3.458549e-01, 1.747649e+00, -3.824761e-01, -8.110930e-01}; tmech::tensor<double, 3, 2>Aexp{2.333496383103521e+00, -9.424245337660712e-01, 6.174107765089896e-01, 2.458154759604529e+00, 7.615487934000856e-01, 1.403592316302926e-01, 1.701192794766057e+00, -7.849258234991792e-01, 8.233614408596337e-01}; std::cout<<std::boolalpha <<tmech::almost_equal(Aexp, tmech::exp(A), 5e-7)<<std::endl; //check the derivative const auto func_exp = [](auto const& tensor){return tmech::exp(tensor);}; std::cout<<std::boolalpha <<tmech::almost_equal(tmech::num_diff_central<tmech::sequence<1,2,3,4>>(func_exp,A), tmech::exp(A).derivative(), 5e-7)<<std::endl;