// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2013 Christian Seiler // // 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 struct tensor_static_symgroup_permutate; template struct tensor_static_symgroup_permutate> { constexpr static std::size_t N = sizeof...(nn); template constexpr static inline std::array run(const std::array& indices) { return {{indices[nn]...}}; } }; template struct tensor_static_symgroup_element { typedef indices_ indices; constexpr static int flags = flags_; }; template struct tensor_static_symgroup_element_ctor { typedef tensor_static_symgroup_element< typename gen_numeric_list_swapped_pair::type, Gen::Flags > type; }; template struct tensor_static_symgroup_identity_ctor { typedef tensor_static_symgroup_element< typename gen_numeric_list::type, 0 > type; }; template struct tensor_static_symgroup_multiply_helper { template constexpr static inline numeric_list::value...> helper(numeric_list) { return numeric_list::value...>(); } }; template 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::helper(iia())), ffa ^ ffb > type; }; template 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::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 struct tensor_static_symgroup { typedef StaticSGroup type; constexpr static std::size_t size = type::static_size; }; template constexpr static inline std::array tensor_static_symgroup_index_permute(std::array idx, internal::numeric_list, internal::numeric_list) { return {{ idx[ii]..., idx[jj]... }}; } template static inline std::vector tensor_static_symgroup_index_permute(std::vector idx, internal::numeric_list) { std::vector 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 struct tensor_static_symgroup_do_apply; template struct tensor_static_symgroup_do_apply> { template static inline RV run(const std::array& 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::type remaining_indices; initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices(), remaining_indices()), first::flags, initial, std::forward(args)...); return tensor_static_symgroup_do_apply>::template run(idx, initial, args...); } template static inline RV run(const std::vector& 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)...); return tensor_static_symgroup_do_apply>::template run(idx, initial, args...); } }; template struct tensor_static_symgroup_do_apply> { template static inline RV run(const std::array&, RV initial, Args&&...) { // do nothing return initial; } template static inline RV run(const std::vector&, RV initial, Args&&...) { // do nothing return initial; } }; } // end namespace internal template class StaticSGroup { constexpr static std::size_t NumIndices = internal::tensor_symmetry_num_indices::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::type, internal::type_list::type...> > group_elements; typedef typename group_elements::type ge; public: constexpr inline StaticSGroup() {} constexpr inline StaticSGroup(const StaticSGroup&) {} constexpr inline StaticSGroup(StaticSGroup&&) {} template static inline RV apply(const std::array& idx, RV initial, Args&&... args) { return internal::tensor_static_symgroup_do_apply::template run(idx, initial, args...); } template static inline RV apply(const std::vector& idx, RV initial, Args&&... args) { eigen_assert(idx.size() == NumIndices); return internal::tensor_static_symgroup_do_apply::template run(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 inline internal::tensor_symmetry_value_setter> 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{{firstIndex, otherIndices...}}); } template inline internal::tensor_symmetry_value_setter> operator()(Tensor_& tensor, std::array const& indices) const { return internal::tensor_symmetry_value_setter>(tensor, *this, indices); } }; } // end namespace Eigen #endif // EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H /* * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; */