Symmetry.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_SYMMETRY_H
00011 #define EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H
00012 
00013 namespace Eigen {
00014 
00015 enum {
00016   NegationFlag           = 0x01,
00017   ConjugationFlag        = 0x02
00018 };
00019 
00020 enum {
00021   GlobalRealFlag         = 0x01,
00022   GlobalImagFlag         = 0x02,
00023   GlobalZeroFlag         = 0x03
00024 };
00025 
00026 namespace internal {
00027 
00028 template<std::size_t NumIndices, typename... Sym>                   struct tensor_symmetry_pre_analysis;
00029 template<std::size_t NumIndices, typename... Sym>                   struct tensor_static_symgroup;
00030 template<bool instantiate, std::size_t NumIndices, typename... Sym> struct tensor_static_symgroup_if;
00031 template<typename Tensor_> struct tensor_symmetry_calculate_flags;
00032 template<typename Tensor_> struct tensor_symmetry_assign_value;
00033 template<typename... Sym> struct tensor_symmetry_num_indices;
00034 
00035 } // end namespace internal
00036 
00037 template<int One_, int Two_>
00038 struct Symmetry
00039 {
00040   static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
00041   constexpr static int One = One_;
00042   constexpr static int Two = Two_;
00043   constexpr static int Flags = 0;
00044 };
00045 
00046 template<int One_, int Two_>
00047 struct AntiSymmetry
00048 {
00049   static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
00050   constexpr static int One = One_;
00051   constexpr static int Two = Two_;
00052   constexpr static int Flags = NegationFlag;
00053 };
00054 
00055 template<int One_, int Two_>
00056 struct Hermiticity
00057 {
00058   static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
00059   constexpr static int One = One_;
00060   constexpr static int Two = Two_;
00061   constexpr static int Flags = ConjugationFlag;
00062 };
00063 
00064 template<int One_, int Two_>
00065 struct AntiHermiticity
00066 {
00067   static_assert(One_ != Two_, "Symmetries must cover distinct indices.");
00068   constexpr static int One = One_;
00069   constexpr static int Two = Two_;
00070   constexpr static int Flags = ConjugationFlag | NegationFlag;
00071 };
00072 
00086 class DynamicSGroup;
00087 
00098 template<typename... Gen>
00099 class DynamicSGroupFromTemplateArgs;
00100 
00120 template<typename... Gen>
00121 class StaticSGroup;
00122 
00135 template<typename... Gen>
00136 class SGroup : public internal::tensor_symmetry_pre_analysis<internal::tensor_symmetry_num_indices<Gen...>::value, Gen...>::root_type
00137 {
00138   public:
00139     constexpr static std::size_t NumIndices = internal::tensor_symmetry_num_indices<Gen...>::value;
00140     typedef typename internal::tensor_symmetry_pre_analysis<NumIndices, Gen...>::root_type Base;
00141 
00142     // make standard constructors + assignment operators public
00143     inline SGroup() : Base() { }
00144     inline SGroup(const SGroup<Gen...>& other) : Base(other) { }
00145     inline SGroup(SGroup<Gen...>&& other) : Base(other) { }
00146     inline SGroup<Gen...>& operator=(const SGroup<Gen...>& other) { Base::operator=(other); return *this; }
00147     inline SGroup<Gen...>& operator=(SGroup<Gen...>&& other) { Base::operator=(other); return *this; }
00148 
00149     // all else is defined in the base class
00150 };
00151 
00152 namespace internal {
00153 
00154 template<typename... Sym> struct tensor_symmetry_num_indices
00155 {
00156   constexpr static std::size_t value = 1;
00157 };
00158 
00159 template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...>
00160 {
00161 private:
00162   constexpr static std::size_t One = static_cast<std::size_t>(One_);
00163   constexpr static std::size_t Two = static_cast<std::size_t>(Two_);
00164   constexpr static std::size_t Three = tensor_symmetry_num_indices<Sym...>::value;
00165 
00166   // don't use std::max, since it's not constexpr until C++14...
00167   constexpr static std::size_t maxOneTwoPlusOne = ((One > Two) ? One : Two) + 1;
00168 public:
00169   constexpr static std::size_t value = (maxOneTwoPlusOne > Three) ? maxOneTwoPlusOne : Three;
00170 };
00171 
00172 template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<AntiSymmetry<One_, Two_>, Sym...>
00173   : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
00174 template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<Hermiticity<One_, Two_>, Sym...>
00175   : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
00176 template<int One_, int Two_, typename... Sym> struct tensor_symmetry_num_indices<AntiHermiticity<One_, Two_>, Sym...>
00177   : public tensor_symmetry_num_indices<Symmetry<One_, Two_>, Sym...> {};
00178 
00226 template<std::size_t NumIndices>
00227 struct tensor_symmetry_pre_analysis<NumIndices>
00228 {
00229   typedef StaticSGroup<> root_type;
00230 };
00231 
00232 template<std::size_t NumIndices, typename Gen_, typename... Gens_>
00233 struct tensor_symmetry_pre_analysis<NumIndices, Gen_, Gens_...>
00234 {
00235   constexpr static std::size_t max_static_generators = 4;
00236   constexpr static std::size_t max_static_elements = 16;
00237   typedef tensor_static_symgroup_if<(sizeof...(Gens_) + 1 <= max_static_generators), NumIndices, Gen_, Gens_...> helper;
00238   constexpr static std::size_t possible_size = helper::size;
00239 
00240   typedef typename conditional<
00241     possible_size == 0 || possible_size >= max_static_elements,
00242     DynamicSGroupFromTemplateArgs<Gen_, Gens_...>,
00243     typename helper::type
00244   >::type root_type;
00245 };
00246 
00247 template<bool instantiate, std::size_t NumIndices, typename... Gens>
00248 struct tensor_static_symgroup_if
00249 {
00250   constexpr static std::size_t size = 0;
00251   typedef void type;
00252 };
00253 
00254 template<std::size_t NumIndices, typename... Gens>
00255 struct tensor_static_symgroup_if<true, NumIndices, Gens...> : tensor_static_symgroup<NumIndices, Gens...> {};
00256 
00257 template<typename Tensor_>
00258 struct tensor_symmetry_assign_value
00259 {
00260   typedef typename Tensor_::Index Index;
00261   typedef typename Tensor_::Scalar Scalar;
00262   constexpr static std::size_t NumIndices = Tensor_::NumIndices;
00263 
00264   static inline int run(const std::array<Index, NumIndices>& transformed_indices, int transformation_flags, int dummy, Tensor_& tensor, const Scalar& value_)
00265   {
00266     Scalar value(value_);
00267     if (transformation_flags & ConjugationFlag)
00268       value = numext::conj(value);
00269     if (transformation_flags & NegationFlag)
00270       value = -value;
00271     tensor.coeffRef(transformed_indices) = value;
00272     return dummy;
00273   }
00274 };
00275 
00276 template<typename Tensor_>
00277 struct tensor_symmetry_calculate_flags
00278 {
00279   typedef typename Tensor_::Index Index;
00280   constexpr static std::size_t NumIndices = Tensor_::NumIndices;
00281 
00282   static inline int run(const std::array<Index, NumIndices>& transformed_indices, int transform_flags, int current_flags, const std::array<Index, NumIndices>& orig_indices)
00283   {
00284     if (transformed_indices == orig_indices) {
00285       if (transform_flags & (ConjugationFlag | NegationFlag))
00286         return current_flags | GlobalImagFlag; // anti-hermitian diagonal
00287       else if (transform_flags & ConjugationFlag)
00288         return current_flags | GlobalRealFlag; // hermitian diagonal
00289       else if (transform_flags & NegationFlag)
00290         return current_flags | GlobalZeroFlag; // anti-symmetric diagonal
00291     }
00292     return current_flags;
00293   }
00294 };
00295 
00296 template<typename Tensor_, typename Symmetry_, int Flags = 0>
00297 class tensor_symmetry_value_setter
00298 {
00299   public:
00300     typedef typename Tensor_::Index Index;
00301     typedef typename Tensor_::Scalar Scalar;
00302     constexpr static std::size_t NumIndices = Tensor_::NumIndices;
00303 
00304     inline tensor_symmetry_value_setter(Tensor_& tensor, Symmetry_ const& symmetry, std::array<Index, NumIndices> const& indices)
00305       : m_tensor(tensor), m_symmetry(symmetry), m_indices(indices) { }
00306 
00307     inline tensor_symmetry_value_setter<Tensor_, Symmetry_, Flags>& operator=(Scalar const& value)
00308     {
00309       doAssign(value);
00310       return *this;
00311     }
00312   private:
00313     Tensor_& m_tensor;
00314     Symmetry_ m_symmetry;
00315     std::array<Index, NumIndices> m_indices;
00316 
00317     inline void doAssign(Scalar const& value)
00318     {
00319       #ifdef EIGEN_TENSOR_SYMMETRY_CHECK_VALUES
00320         int value_flags = m_symmetry.template apply<internal::tensor_symmetry_calculate_flags<Tensor_>, int>(m_indices, m_symmetry.globalFlags(), m_indices);
00321         if (value_flags & GlobalRealFlag)
00322           eigen_assert(numext::imag(value) == 0);
00323         if (value_flags & GlobalImagFlag)
00324           eigen_assert(numext::real(value) == 0);
00325       #endif
00326       m_symmetry.template apply<internal::tensor_symmetry_assign_value<Tensor_>, int>(m_indices, 0, m_tensor, value);
00327     }
00328 };
00329 
00330 } // end namespace internal
00331 
00332 } // end namespace Eigen
00333 
00334 #endif // EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H
00335 
00336 /*
00337  * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
00338  */
 All Classes Functions Variables Typedefs Enumerator