StaticSymmetry.h
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2013 Christian Seiler <christian@iwakd.de>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H
00011 #define EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H
00012 
00013 namespace Eigen {
00014 
00015 namespace internal {
00016 
00017 template<typename list> struct tensor_static_symgroup_permutate;
00018 
00019 template<int... nn>
00020 struct tensor_static_symgroup_permutate<numeric_list<int, nn...>>
00021 {
00022   constexpr static std::size_t N = sizeof...(nn);
00023 
00024   template<typename T>
00025   constexpr static inline std::array<T, N> run(const std::array<T, N>& indices)
00026   {
00027     return {{indices[nn]...}};
00028   }
00029 };
00030 
00031 template<typename indices_, int flags_>
00032 struct tensor_static_symgroup_element
00033 {
00034   typedef indices_ indices;
00035   constexpr static int flags = flags_;
00036 };
00037 
00038 template<typename Gen, int N>
00039 struct tensor_static_symgroup_element_ctor
00040 {
00041   typedef tensor_static_symgroup_element<
00042     typename gen_numeric_list_swapped_pair<int, N, Gen::One, Gen::Two>::type,
00043     Gen::Flags
00044   > type;
00045 };
00046 
00047 template<int N>
00048 struct tensor_static_symgroup_identity_ctor
00049 {
00050   typedef tensor_static_symgroup_element<
00051     typename gen_numeric_list<int, N>::type,
00052     0
00053   > type;
00054 };
00055 
00056 template<typename iib>
00057 struct tensor_static_symgroup_multiply_helper
00058 {
00059   template<int... iia>
00060   constexpr static inline numeric_list<int, get<iia, iib>::value...> helper(numeric_list<int, iia...>) {
00061     return numeric_list<int, get<iia, iib>::value...>();
00062   }
00063 };
00064 
00065 template<typename A, typename B>
00066 struct tensor_static_symgroup_multiply
00067 {
00068   private:
00069     typedef typename A::indices iia;
00070     typedef typename B::indices iib;
00071     constexpr static int ffa = A::flags;
00072     constexpr static int ffb = B::flags;
00073   
00074   public:
00075     static_assert(iia::count == iib::count, "Cannot multiply symmetry elements with different number of indices.");
00076 
00077     typedef tensor_static_symgroup_element<
00078       decltype(tensor_static_symgroup_multiply_helper<iib>::helper(iia())),
00079       ffa ^ ffb
00080     > type;
00081 };
00082 
00083 template<typename A, typename B>
00084 struct tensor_static_symgroup_equality
00085 {
00086     typedef typename A::indices iia;
00087     typedef typename B::indices iib;
00088     constexpr static int ffa = A::flags;
00089     constexpr static int ffb = B::flags;
00090     static_assert(iia::count == iib::count, "Cannot compare symmetry elements with different number of indices.");
00091 
00092     constexpr static bool value = is_same<iia, iib>::value;
00093 
00094   private:
00095     /* this should be zero if they are identical, or else the tensor
00096      * will be forced to be pure real, pure imaginary or even pure zero
00097      */
00098     constexpr static int flags_cmp_ = ffa ^ ffb;
00099 
00100     /* either they are not equal, then we don't care whether the flags
00101      * match, or they are equal, and then we have to check
00102      */
00103     constexpr static bool is_zero      = value && flags_cmp_ == NegationFlag;
00104     constexpr static bool is_real      = value && flags_cmp_ == ConjugationFlag;
00105     constexpr static bool is_imag      = value && flags_cmp_ == (NegationFlag | ConjugationFlag);
00106 
00107   public:
00108     constexpr static int global_flags = 
00109       (is_real ? GlobalRealFlag : 0) |
00110       (is_imag ? GlobalImagFlag : 0) |
00111       (is_zero ? GlobalZeroFlag : 0);
00112 };
00113 
00114 template<std::size_t NumIndices, typename... Gen>
00115 struct tensor_static_symgroup
00116 {
00117   typedef StaticSGroup<Gen...> type;
00118   constexpr static std::size_t size = type::static_size;
00119 };
00120 
00121 template<typename Index, std::size_t N, int... ii, int... jj>
00122 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...>)
00123 {
00124   return {{ idx[ii]..., idx[jj]... }};
00125 }
00126 
00127 template<typename Index, int... ii>
00128 static inline std::vector<Index> tensor_static_symgroup_index_permute(std::vector<Index> idx, internal::numeric_list<int, ii...>)
00129 {
00130   std::vector<Index> result{{ idx[ii]... }};
00131   std::size_t target_size = idx.size();
00132   for (std::size_t i = result.size(); i < target_size; i++)
00133     result.push_back(idx[i]);
00134   return result;
00135 }
00136 
00137 template<typename T> struct tensor_static_symgroup_do_apply;
00138 
00139 template<typename first, typename... next>
00140 struct tensor_static_symgroup_do_apply<internal::type_list<first, next...>>
00141 {
00142   template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args>
00143   static inline RV run(const std::array<Index, NumIndices>& idx, RV initial, Args&&... args)
00144   {
00145     static_assert(NumIndices >= SGNumIndices, "Can only apply symmetry group to objects that have at least the required amount of indices.");
00146     typedef typename internal::gen_numeric_list<int, NumIndices - SGNumIndices, SGNumIndices>::type remaining_indices;
00147     initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices(), remaining_indices()), first::flags, initial, std::forward<Args>(args)...);
00148     return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...);
00149   }
00150 
00151   template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args>
00152   static inline RV run(const std::vector<Index>& idx, RV initial, Args&&... args)
00153   {
00154     eigen_assert(idx.size() >= SGNumIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
00155     initial = Op::run(tensor_static_symgroup_index_permute(idx, typename first::indices()), first::flags, initial, std::forward<Args>(args)...);
00156     return tensor_static_symgroup_do_apply<internal::type_list<next...>>::template run<Op, RV, SGNumIndices>(idx, initial, args...);
00157   }
00158 };
00159 
00160 template<EIGEN_TPL_PP_SPEC_HACK_DEF(typename, empty)>
00161 struct tensor_static_symgroup_do_apply<internal::type_list<EIGEN_TPL_PP_SPEC_HACK_USE(empty)>>
00162 {
00163   template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, std::size_t NumIndices, typename... Args>
00164   static inline RV run(const std::array<Index, NumIndices>&, RV initial, Args&&...)
00165   {
00166     // do nothing
00167     return initial;
00168   }
00169 
00170   template<typename Op, typename RV, std::size_t SGNumIndices, typename Index, typename... Args>
00171   static inline RV run(const std::vector<Index>&, RV initial, Args&&...)
00172   {
00173     // do nothing
00174     return initial;
00175   }
00176 };
00177 
00178 } // end namespace internal
00179 
00180 template<typename... Gen>
00181 class StaticSGroup
00182 {
00183     constexpr static std::size_t NumIndices = internal::tensor_symmetry_num_indices<Gen...>::value;
00184     typedef internal::group_theory::enumerate_group_elements<
00185       internal::tensor_static_symgroup_multiply,
00186       internal::tensor_static_symgroup_equality,
00187       typename internal::tensor_static_symgroup_identity_ctor<NumIndices>::type,
00188       internal::type_list<typename internal::tensor_static_symgroup_element_ctor<Gen, NumIndices>::type...>
00189     > group_elements;
00190     typedef typename group_elements::type ge;
00191   public:
00192     constexpr inline StaticSGroup() {}
00193     constexpr inline StaticSGroup(const StaticSGroup<Gen...>&) {}
00194     constexpr inline StaticSGroup(StaticSGroup<Gen...>&&) {}
00195 
00196     template<typename Op, typename RV, typename Index, std::size_t N, typename... Args>
00197     static inline RV apply(const std::array<Index, N>& idx, RV initial, Args&&... args)
00198     {
00199       return internal::tensor_static_symgroup_do_apply<ge>::template run<Op, RV, NumIndices>(idx, initial, args...);
00200     }
00201 
00202     template<typename Op, typename RV, typename Index, typename... Args>
00203     static inline RV apply(const std::vector<Index>& idx, RV initial, Args&&... args)
00204     {
00205       eigen_assert(idx.size() == NumIndices);
00206       return internal::tensor_static_symgroup_do_apply<ge>::template run<Op, RV, NumIndices>(idx, initial, args...);
00207     }
00208 
00209     constexpr static std::size_t static_size = ge::count;
00210 
00211     constexpr static inline std::size_t size() {
00212       return ge::count;
00213     }
00214     constexpr static inline int globalFlags() { return group_elements::global_flags; }
00215 
00216     template<typename Tensor_, typename... IndexTypes>
00217     inline internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>> operator()(Tensor_& tensor, typename Tensor_::Index firstIndex, IndexTypes... otherIndices) const
00218     {
00219       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.");
00220       return operator()(tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices>{{firstIndex, otherIndices...}});
00221     }
00222 
00223     template<typename Tensor_>
00224     inline internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>> operator()(Tensor_& tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices> const& indices) const
00225     {
00226       return internal::tensor_symmetry_value_setter<Tensor_, StaticSGroup<Gen...>>(tensor, *this, indices);
00227     }
00228 };
00229 
00230 } // end namespace Eigen
00231 
00232 #endif // EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H
00233 
00234 /*
00235  * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
00236  */
 All Classes Functions Variables Typedefs Enumerator