|  | // This file is part of Eigen, a lightweight C++ template library | 
|  | // for linear algebra. | 
|  | // | 
|  | // Copyright (C) 2013 Christian Seiler <christian@iwakd.de> | 
|  | // | 
|  | // This Source Code Form is subject to the terms of the Mozilla | 
|  | // Public License v. 2.0. If a copy of the MPL was not distributed | 
|  | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
|  |  | 
|  | #ifndef EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H | 
|  | #define EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H | 
|  |  | 
|  | namespace Eigen { | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | template<typename list> struct tensor_static_symgroup_permutate; | 
|  |  | 
|  | template<int... nn> | 
|  | struct tensor_static_symgroup_permutate<numeric_list<int, nn...>> | 
|  | { | 
|  | constexpr static std::size_t N = sizeof...(nn); | 
|  |  | 
|  | template<typename T> | 
|  | constexpr static inline std::array<T, N> run(const std::array<T, N>& indices) | 
|  | { | 
|  | return {{indices[nn]...}}; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template<typename indices_, int flags_> | 
|  | struct tensor_static_symgroup_element | 
|  | { | 
|  | typedef indices_ indices; | 
|  | constexpr static int flags = flags_; | 
|  | }; | 
|  |  | 
|  | template<typename Gen, int N> | 
|  | struct tensor_static_symgroup_element_ctor | 
|  | { | 
|  | typedef tensor_static_symgroup_element< | 
|  | typename gen_numeric_list_swapped_pair<int, N, Gen::One, Gen::Two>::type, | 
|  | Gen::Flags | 
|  | > type; | 
|  | }; | 
|  |  | 
|  | template<int N> | 
|  | struct tensor_static_symgroup_identity_ctor | 
|  | { | 
|  | typedef tensor_static_symgroup_element< | 
|  | typename gen_numeric_list<int, N>::type, | 
|  | 0 | 
|  | > type; | 
|  | }; | 
|  |  | 
|  | template<typename iib> | 
|  | struct tensor_static_symgroup_multiply_helper | 
|  | { | 
|  | template<int... iia> | 
|  | constexpr static inline numeric_list<int, get<iia, iib>::value...> helper(numeric_list<int, iia...>) { | 
|  | return numeric_list<int, get<iia, iib>::value...>(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template<typename A, typename B> | 
|  | struct tensor_static_symgroup_multiply | 
|  | { | 
|  | private: | 
|  | typedef typename A::indices iia; | 
|  | typedef typename B::indices iib; | 
|  | constexpr static int ffa = A::flags; | 
|  | constexpr static int ffb = B::flags; | 
|  |  | 
|  | public: | 
|  | static_assert(iia::count == iib::count, "Cannot multiply symmetry elements with different number of indices."); | 
|  |  | 
|  | typedef tensor_static_symgroup_element< | 
|  | decltype(tensor_static_symgroup_multiply_helper<iib>::helper(iia())), | 
|  | ffa ^ ffb | 
|  | > type; | 
|  | }; | 
|  |  | 
|  | template<typename A, typename B> | 
|  | struct tensor_static_symgroup_equality | 
|  | { | 
|  | typedef typename A::indices iia; | 
|  | typedef typename B::indices iib; | 
|  | constexpr static int ffa = A::flags; | 
|  | constexpr static int ffb = B::flags; | 
|  | static_assert(iia::count == iib::count, "Cannot compare symmetry elements with different number of indices."); | 
|  |  | 
|  | constexpr static bool value = is_same<iia, iib>::value; | 
|  |  | 
|  | private: | 
|  | /* this should be zero if they are identical, or else the tensor | 
|  | * will be forced to be pure real, pure imaginary or even pure zero | 
|  | */ | 
|  | constexpr static int flags_cmp_ = ffa ^ ffb; | 
|  |  | 
|  | /* either they are not equal, then we don't care whether the flags | 
|  | * match, or they are equal, and then we have to check | 
|  | */ | 
|  | constexpr static bool is_zero      = value && flags_cmp_ == NegationFlag; | 
|  | constexpr static bool is_real      = value && flags_cmp_ == ConjugationFlag; | 
|  | constexpr static bool is_imag      = value && flags_cmp_ == (NegationFlag | ConjugationFlag); | 
|  |  | 
|  | public: | 
|  | constexpr static int global_flags = | 
|  | (is_real ? GlobalRealFlag : 0) | | 
|  | (is_imag ? GlobalImagFlag : 0) | | 
|  | (is_zero ? GlobalZeroFlag : 0); | 
|  | }; | 
|  |  | 
|  | template<std::size_t NumIndices, typename... Gen> | 
|  | struct tensor_static_symgroup | 
|  | { | 
|  | typedef StaticSGroup<Gen...> type; | 
|  | constexpr static std::size_t size = type::static_size; | 
|  | }; | 
|  |  | 
|  | template<typename Index, std::size_t N, int... ii, int... jj> | 
|  | constexpr static inline std::array<Index, N> tensor_static_symgroup_index_permute(std::array<Index, N> idx, internal::numeric_list<int, ii...>, internal::numeric_list<int, jj...>) | 
|  | { | 
|  | return {{ idx[ii]..., idx[jj]... }}; | 
|  | } | 
|  |  | 
|  | template<typename Index, int... ii> | 
|  | static inline std::vector<Index> tensor_static_symgroup_index_permute(std::vector<Index> idx, internal::numeric_list<int, ii...>) | 
|  | { | 
|  | std::vector<Index> result{{ idx[ii]... }}; | 
|  | std::size_t target_size = idx.size(); | 
|  | for (std::size_t i = result.size(); i < target_size; i++) | 
|  | result.push_back(idx[i]); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | template<typename T> struct tensor_static_symgroup_do_apply; | 
|  |  | 
|  | template<typename first, typename... next> | 
|  | struct tensor_static_symgroup_do_apply<internal::type_list<first, next...>> | 
|  | { | 
|  | template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args> | 
|  | static inline RV run(const std::array<Index, NumIndices>& idx, RV initial, Args&&... args) | 
|  | { | 
|  | static_assert(NumIndices >= SGNumIndices, "Can only apply symmetry group to objects that have at least the required amount of indices."); | 
|  | typedef typename internal::gen_numeric_list<int, NumIndices - SGNumIndices, SGNumIndices>::type remaining_indices; | 
|  | initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices(), remaining_indices()), first::flags, initial, std::forward<Args>(args)...); | 
|  | return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...); | 
|  | } | 
|  |  | 
|  | template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args> | 
|  | static inline RV run(const std::vector<Index>& idx, RV initial, Args&&... args) | 
|  | { | 
|  | eigen_assert(idx.size() >= SGNumIndices && "Can only apply symmetry group to objects that have at least the required amount of indices."); | 
|  | initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices()), first::flags, initial, std::forward<Args>(args)...); | 
|  | return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | template<EIGEN_TPL_PP_SPEC_HACK_DEF(typename, empty)> | 
|  | struct tensor_static_symgroup_do_apply<internal::type_list<EIGEN_TPL_PP_SPEC_HACK_USE(empty)>> | 
|  | { | 
|  | template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args> | 
|  | static inline RV run(const std::array<Index, NumIndices>&, RV initial, Args&&...) | 
|  | { | 
|  | // do nothing | 
|  | return initial; | 
|  | } | 
|  |  | 
|  | template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args> | 
|  | static inline RV run(const std::vector<Index>&, RV initial, Args&&...) | 
|  | { | 
|  | // do nothing | 
|  | return initial; | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end namespace internal | 
|  |  | 
|  | template<typename... Gen> | 
|  | class StaticSGroup | 
|  | { | 
|  | constexpr static std::size_t NumIndices = internal::tensor_symmetry_num_indices<Gen...>::value; | 
|  | typedef internal::group_theory::enumerate_group_elements< | 
|  | internal::tensor_static_symgroup_multiply, | 
|  | internal::tensor_static_symgroup_equality, | 
|  | typename internal::tensor_static_symgroup_identity_ctor<NumIndices>::type, | 
|  | internal::type_list<typename internal::tensor_static_symgroup_element_ctor<Gen, NumIndices>::type...> | 
|  | > group_elements; | 
|  | typedef typename group_elements::type ge; | 
|  | public: | 
|  | constexpr inline StaticSGroup() {} | 
|  | constexpr inline StaticSGroup(const StaticSGroup<Gen...>&) {} | 
|  | constexpr inline StaticSGroup(StaticSGroup<Gen...>&&) {} | 
|  |  | 
|  | template<typename Op, typename RV, typename Index, std::size_t N, typename... Args> | 
|  | static inline RV apply(const std::array<Index, N>& idx, RV initial, Args&&... args) | 
|  | { | 
|  | return internal::tensor_static_symgroup_do_apply<ge>::template run<Op, RV, NumIndices>(idx, initial, args...); | 
|  | } | 
|  |  | 
|  | template<typename Op, typename RV, typename Index, typename... Args> | 
|  | static inline RV apply(const std::vector<Index>& idx, RV initial, Args&&... args) | 
|  | { | 
|  | eigen_assert(idx.size() == NumIndices); | 
|  | return internal::tensor_static_symgroup_do_apply<ge>::template run<Op, RV, NumIndices>(idx, initial, args...); | 
|  | } | 
|  |  | 
|  | constexpr static std::size_t static_size = ge::count; | 
|  |  | 
|  | constexpr static inline std::size_t size() { | 
|  | return ge::count; | 
|  | } | 
|  | constexpr static inline int globalFlags() { return group_elements::global_flags; } | 
|  |  | 
|  | template<typename Tensor_, typename... IndexTypes> | 
|  | inline internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>> operator()(Tensor_& tensor, typename Tensor_::Index firstIndex, IndexTypes... otherIndices) const | 
|  | { | 
|  | static_assert(sizeof...(otherIndices) + 1 == Tensor_::NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); | 
|  | return operator()(tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices>{{firstIndex, otherIndices...}}); | 
|  | } | 
|  |  | 
|  | template<typename Tensor_> | 
|  | inline internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>> operator()(Tensor_& tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices> const& indices) const | 
|  | { | 
|  | return internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>>(tensor, *this, indices); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end namespace Eigen | 
|  |  | 
|  | #endif // EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H | 
|  |  | 
|  | /* | 
|  | * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; | 
|  | */ |