From 5e28c41549c5e71011bb9312104d1d30e919e53f Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Thu, 14 Nov 2013 22:27:06 +0100 Subject: [PATCH 1/4] C++11: add template metaprogramming helpers Create a new directory CXX11 under unsupported/Eigen that contains code that requires C++11. In that directory, add a few generic templates useful for any module relying on C++11. These templates may be included with #include <[unsupported/]Eigen/CXX11/Core>. At the moment, this will only provide templates in the Eigen::internal namespace. --- unsupported/Eigen/CXX11/Core | 41 ++ .../Eigen/CXX11/src/Core/util/CXX11Meta.h | 504 ++++++++++++++++++ .../CXX11/src/Core/util/CXX11Workarounds.h | 104 ++++ unsupported/test/CMakeLists.txt | 8 + unsupported/test/cxx11_meta.cpp | 343 ++++++++++++ 5 files changed, 1000 insertions(+) create mode 100644 unsupported/Eigen/CXX11/Core create mode 100644 unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h create mode 100644 unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h create mode 100644 unsupported/test/cxx11_meta.cpp diff --git a/unsupported/Eigen/CXX11/Core b/unsupported/Eigen/CXX11/Core new file mode 100644 index 000000000..1b1f1dcc1 --- /dev/null +++ b/unsupported/Eigen/CXX11/Core @@ -0,0 +1,41 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_CORE_MODULE +#define EIGEN_CXX11_CORE_MODULE + +#include + +#include + +/** \defgroup CXX11_Core_Module C++11 Core Module + * + * This module provides common core features for all modules that + * explicitly depend on C++11. Currently, this is only the Tensor + * module. Note that at this stage, you should not need to include + * this module directly. + * + * \code + * #include + * \endcode + */ + +#include + +#include "src/Core/util/CXX11Workarounds.h" +#include "src/Core/util/CXX11Meta.h" + +#include + +#endif // EIGEN_CXX11_CORE_MODULE + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h b/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h new file mode 100644 index 000000000..55d3cc37b --- /dev/null +++ b/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h @@ -0,0 +1,504 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_CXX11META_H +#define EIGEN_CXX11META_H + +namespace Eigen { + +namespace internal { + +/** \internal + * \file CXX11/Core/util/CXX11Meta.h + * This file contains generic metaprogramming classes which are not specifically related to Eigen. + * This file expands upon Core/util/Meta.h and adds support for C++11 specific features. + */ + +template +struct type_list { constexpr static int count = sizeof...(tt); }; + +template +struct type_list { constexpr static int count = sizeof...(tt) + 1; typedef t first_type; }; + +template +struct numeric_list { constexpr static std::size_t count = sizeof...(nn); }; + +template +struct numeric_list { constexpr static std::size_t count = sizeof...(nn) + 1; constexpr static T first_value = n; }; + +/* numeric list constructors + * + * equivalencies: + * constructor result + * typename gen_numeric_list::type numeric_list + * typename gen_numeric_list_reversed::type numeric_list + * typename gen_numeric_list_swapped_pair::type numeric_list + * typename gen_numeric_list_repeated::type numeric_list + */ + +template struct gen_numeric_list : gen_numeric_list {}; +template struct gen_numeric_list { typedef numeric_list type; }; + +template struct gen_numeric_list_reversed : gen_numeric_list_reversed {}; +template struct gen_numeric_list_reversed { typedef numeric_list type; }; + +template struct gen_numeric_list_swapped_pair : gen_numeric_list_swapped_pair {}; +template struct gen_numeric_list_swapped_pair { typedef numeric_list type; }; + +template struct gen_numeric_list_repeated : gen_numeric_list_repeated {}; +template struct gen_numeric_list_repeated { typedef numeric_list type; }; + +/* list manipulation: concatenate */ + +template struct concat; + +template struct concat, type_list> { typedef type_list type; }; +template struct concat, numeric_list > { typedef numeric_list type; }; + +template struct mconcat; +template struct mconcat { typedef a type; }; +template struct mconcat : concat {}; +template struct mconcat : concat::type> {}; + +/* list manipulation: extract slices */ + +template struct take; +template struct take> : concat, typename take>::type> {}; +template struct take> { typedef type_list<> type; }; +template struct take<0, type_list> { typedef type_list<> type; }; +template<> struct take<0, type_list<>> { typedef type_list<> type; }; + +template struct take> : concat, typename take>::type> {}; +template struct take> { typedef numeric_list type; }; +template struct take<0, numeric_list> { typedef numeric_list type; }; +template struct take<0, numeric_list> { typedef numeric_list type; }; + +template struct h_skip_helper_numeric; +template struct h_skip_helper_numeric : h_skip_helper_numeric {}; +template struct h_skip_helper_numeric { typedef numeric_list type; }; +template struct h_skip_helper_numeric { typedef numeric_list type; }; +template struct h_skip_helper_numeric { typedef numeric_list type; }; + +template struct h_skip_helper_type; +template struct h_skip_helper_type : h_skip_helper_type {}; +template struct h_skip_helper_type<0, t, tt...> { typedef type_list type; }; +template struct h_skip_helper_type { typedef type_list<> type; }; +template<> struct h_skip_helper_type<0> { typedef type_list<> type; }; + +template +struct h_skip { + template + constexpr static inline typename h_skip_helper_numeric::type helper(numeric_list) { return typename h_skip_helper_numeric::type(); } + template + constexpr static inline typename h_skip_helper_type::type helper(type_list) { return typename h_skip_helper_type::type(); } +}; + +template struct skip { typedef decltype(h_skip::helper(a())) type; }; + +template struct slice : take::type> {}; + +/* list manipulation: retrieve single element from list */ + +template struct get; + +template struct get> : get> {}; +template struct get<0, type_list> { typedef a type; }; +template struct get> { static_assert((n - n) < 0, "meta-template get: The element to extract from a list must be smaller than the size of the list."); }; + +template struct get> : get> {}; +template struct get<0, numeric_list> { constexpr static int value = a; }; +template struct get> { static_assert((n - n) < 0, "meta-template get: The element to extract from a list must be smaller than the size of the list."); }; + +/* always get type, regardless of dummy; good for parameter pack expansion */ + +template struct id_numeric { typedef t type; }; +template struct id_type { typedef t type; }; + +/* equality checking, flagged version */ + +template struct is_same_gf : is_same { constexpr static int global_flags = 0; }; + +/* apply_op to list */ + +template< + bool from_left, // false + template class op, + typename additional_param, + typename... values +> +struct h_apply_op_helper { typedef type_list::type...> type; }; +template< + template class op, + typename additional_param, + typename... values +> +struct h_apply_op_helper { typedef type_list::type...> type; }; + +template< + bool from_left, + template class op, + typename additional_param +> +struct h_apply_op +{ + template + constexpr static typename h_apply_op_helper::type helper(type_list) + { return typename h_apply_op_helper::type(); } +}; + +template< + template class op, + typename additional_param, + typename a +> +struct apply_op_from_left { typedef decltype(h_apply_op::helper(a())) type; }; + +template< + template class op, + typename additional_param, + typename a +> +struct apply_op_from_right { typedef decltype(h_apply_op::helper(a())) type; }; + +/* see if an element is in a list */ + +template< + template class test, + typename check_against, + typename h_list, + bool last_check_positive = false +> +struct contained_in_list; + +template< + template class test, + typename check_against, + typename h_list +> +struct contained_in_list +{ + constexpr static bool value = true; +}; + +template< + template class test, + typename check_against, + typename a, + typename... as +> +struct contained_in_list, false> : contained_in_list, test::value> {}; + +template< + template class test, + typename check_against + EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, empty) +> +struct contained_in_list, false> { constexpr static bool value = false; }; + +/* see if an element is in a list and check for global flags */ + +template< + template class test, + typename check_against, + typename h_list, + int default_flags = 0, + bool last_check_positive = false, + int last_check_flags = default_flags +> +struct contained_in_list_gf; + +template< + template class test, + typename check_against, + typename h_list, + int default_flags, + int last_check_flags +> +struct contained_in_list_gf +{ + constexpr static bool value = true; + constexpr static int global_flags = last_check_flags; +}; + +template< + template class test, + typename check_against, + typename a, + typename... as, + int default_flags, + int last_check_flags +> +struct contained_in_list_gf, default_flags, false, last_check_flags> : contained_in_list_gf, default_flags, test::value, test::global_flags> {}; + +template< + template class test, + typename check_against + EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, empty), + int default_flags, + int last_check_flags +> +struct contained_in_list_gf, default_flags, false, last_check_flags> { constexpr static bool value = false; constexpr static int global_flags = default_flags; }; + +/* generic reductions */ + +template< + typename Reducer, + typename... Ts +> struct reduce; + +template< + typename Reducer, + typename A, + typename... Ts +> struct reduce +{ + constexpr static inline A run(A a, Ts...) { return a; } +}; + +template< + typename Reducer, + typename A, + typename B, + typename... Ts +> struct reduce +{ + constexpr static inline auto run(A a, B b, Ts... ts) -> decltype(Reducer::run(a, reduce::run(b, ts...))) { + return Reducer::run(a, reduce::run(b, ts...)); + } +}; + +/* generic binary operations */ + +struct sum_op { template constexpr static inline auto run(A a, B b) -> decltype(a + b) { return a + b; } }; +struct product_op { template constexpr static inline auto run(A a, B b) -> decltype(a * b) { return a * b; } }; + +struct logical_and_op { template constexpr static inline auto run(A a, B b) -> decltype(a && b) { return a && b; } }; +struct logical_or_op { template constexpr static inline auto run(A a, B b) -> decltype(a || b) { return a || b; } }; + +struct equal_op { template constexpr static inline auto run(A a, B b) -> decltype(a == b) { return a == b; } }; +struct not_equal_op { template constexpr static inline auto run(A a, B b) -> decltype(a != b) { return a != b; } }; +struct lesser_op { template constexpr static inline auto run(A a, B b) -> decltype(a < b) { return a < b; } }; +struct lesser_equal_op { template constexpr static inline auto run(A a, B b) -> decltype(a <= b) { return a <= b; } }; +struct greater_op { template constexpr static inline auto run(A a, B b) -> decltype(a < b) { return a < b; } }; +struct greater_equal_op { template constexpr static inline auto run(A a, B b) -> decltype(a >= b) { return a >= b; } }; + +/* generic unary operations */ + +struct not_op { template constexpr static inline auto run(A a) -> decltype(!a) { return !a; } }; +struct negation_op { template constexpr static inline auto run(A a) -> decltype(-a) { return -a; } }; +struct greater_equal_zero_op { template constexpr static inline auto run(A a) -> decltype(a >= 0) { return a >= 0; } }; + + +/* reductions for lists */ + +// using auto -> return value spec makes ICC 13.0 and 13.1 crash here, so we have to hack it +// together in front... (13.0 doesn't work with array_prod/array_reduce/... anyway, but 13.1 +// does... +template +constexpr inline decltype(reduce::run((*((Ts*)0))...)) arg_prod(Ts... ts) +{ + return reduce::run(ts...); +} + +template +constexpr inline decltype(reduce::run((*((Ts*)0))...)) arg_sum(Ts... ts) +{ + return reduce::run(ts...); +} + +/* reverse arrays */ + +template +constexpr inline Array h_array_reverse(Array arr, numeric_list) +{ + return {{std_array_get(arr)...}}; +} + +template +constexpr inline std::array array_reverse(std::array arr) +{ + return h_array_reverse(arr, typename gen_numeric_list::type()); +} + +/* generic array reductions */ + +// can't reuse standard reduce() interface above because Intel's Compiler +// *really* doesn't like it, so we just reimplement the stuff +// (start from N - 1 and work down to 0 because specialization for +// n == N - 1 also doesn't work in Intel's compiler, so it goes into +// an infinite loop) +template +struct h_array_reduce { + constexpr static inline auto run(std::array arr) -> decltype(Reducer::run(h_array_reduce::run(arr), std_array_get(arr))) + { + return Reducer::run(h_array_reduce::run(arr), std_array_get(arr)); + } +}; + +template +struct h_array_reduce +{ + constexpr static inline T run(std::array arr) + { + return std_array_get<0>(arr); + } +}; + +template +constexpr inline auto array_reduce(std::array arr) -> decltype(h_array_reduce::run(arr)) +{ + return h_array_reduce::run(arr); +} + +/* standard array reductions */ + +template +constexpr inline auto array_sum(std::array arr) -> decltype(array_reduce(arr)) +{ + return array_reduce(arr); +} + +template +constexpr inline auto array_prod(std::array arr) -> decltype(array_reduce(arr)) +{ + return array_reduce(arr); +} + +/* zip an array */ + +template +constexpr inline std::array h_array_zip(std::array a, std::array b, numeric_list) +{ + return std::array{{ Op::run(std_array_get(a), std_array_get(b))... }}; +} + +template +constexpr inline std::array array_zip(std::array a, std::array b) +{ + return h_array_zip(a, b, typename gen_numeric_list::type()); +} + +/* zip an array and reduce the result */ + +template +constexpr inline auto h_array_zip_and_reduce(std::array a, std::array b, numeric_list) -> decltype(reduce::type...>::run(Op::run(std_array_get(a), std_array_get(b))...)) +{ + return reduce::type...>::run(Op::run(std_array_get(a), std_array_get(b))...); +} + +template +constexpr inline auto array_zip_and_reduce(std::array a, std::array b) -> decltype(h_array_zip_and_reduce(a, b, typename gen_numeric_list::type())) +{ + return h_array_zip_and_reduce(a, b, typename gen_numeric_list::type()); +} + +/* apply stuff to an array */ + +template +constexpr inline std::array h_array_apply(std::array a, numeric_list) +{ + return std::array{{ Op::run(std_array_get(a))... }}; +} + +template +constexpr inline std::array array_apply(std::array a) +{ + return h_array_apply(a, typename gen_numeric_list::type()); +} + +/* apply stuff to an array and reduce */ + +template +constexpr inline auto h_array_apply_and_reduce(std::array arr, numeric_list) -> decltype(reduce::type...>::run(Op::run(std_array_get(arr))...)) +{ + return reduce::type...>::run(Op::run(std_array_get(arr))...); +} + +template +constexpr inline auto array_apply_and_reduce(std::array a) -> decltype(h_array_apply_and_reduce(a, typename gen_numeric_list::type())) +{ + return h_array_apply_and_reduce(a, typename gen_numeric_list::type()); +} + +/* repeat a value n times (and make an array out of it + * usage: + * std::array = repeat<16>(42); + */ + +template +struct h_repeat +{ + template + constexpr static inline std::array run(t v, numeric_list) + { + return {{ typename id_numeric::type(v)... }}; + } +}; + +template +constexpr std::array repeat(t v) { return h_repeat::run(v, typename gen_numeric_list::type()); } + +/* instantiate a class by a C-style array */ +template +struct h_instantiate_by_c_array; + +template +struct h_instantiate_by_c_array +{ + static InstType run(ArrType* arr, Ps... args) + { + return h_instantiate_by_c_array::run(arr + 1, args..., arr[0]); + } +}; + +template +struct h_instantiate_by_c_array +{ + static InstType run(ArrType* arr, Ps... args) + { + return h_instantiate_by_c_array::run(arr + 1, arr[0], args...); + } +}; + +template +struct h_instantiate_by_c_array +{ + static InstType run(ArrType* arr, Ps... args) + { + (void)arr; + return InstType(args...); + } +}; + +template +struct h_instantiate_by_c_array +{ + static InstType run(ArrType* arr, Ps... args) + { + (void)arr; + return InstType(args...); + } +}; + +template +InstType instantiate_by_c_array(ArrType* arr) +{ + return h_instantiate_by_c_array::run(arr); +} + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11META_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h b/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h new file mode 100644 index 000000000..eec38b343 --- /dev/null +++ b/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h @@ -0,0 +1,104 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_CXX11WORKAROUNDS_H +#define EIGEN_CXX11WORKAROUNDS_H + +/* COMPATIBILITY CHECKS + * (so users of compilers that are too old get some realistic error messages) + */ +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER < 1310) +#error Intel Compiler only supports required C++ features since version 13.1. +// note that most stuff in principle works with 13.0 but when combining +// some features, at some point 13.0 will just fail with an internal assertion +#elif defined(__clang__) && (__clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 1)) +// note that it _should_ work with 3.1 but it was only tested with 3.2 +#error Clang C++ Compiler (clang++) only supports required C++ features since version 3.1. +#elif defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)) +// G++ < 4.6 by default will continue processing the source files - even if we use #error to make +// it error out. For this reason, we use the pragma to make sure G++ aborts at the first error +// it sees. Unfortunately, that is still not our #error directive, but at least the output is +// short enough the user has a chance to see that the compiler version is not sufficient for +// the funky template mojo we use. +#pragma GCC diagnostic error "-Wfatal-errors" +#error GNU C++ Compiler (g++) only supports required C++ features since version 4.6. +#endif + +/* Check that the compiler at least claims to support C++11. It might not be sufficient + * because the compiler may not implement it correctly, but at least we'll know. + */ +#if __cplusplus <= 199711L +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic error "-Wfatal-errors" +#endif +#error This library needs at least a C++11 compliant compiler. If you use g++/clang, please enable the -std=c++11 compiler flag. (-std=c++0x on older versions.) +#endif + +namespace Eigen { + +namespace internal { + +/* std::get is only constexpr in C++14, not yet in C++11 + * - libstdc++ from version 4.7 onwards has it nevertheless, + * so use that + * - libstdc++ older versions: use _M_instance directly + * - libc++ all versions so far: use __elems_ directly + * - all other libs: use std::get to be portable, but + * this may not be constexpr + */ +#if defined(__GLIBCXX__) && __GLIBCXX__ < 20120322 +#define STD_GET_ARR_HACK a._M_instance[I] +#elif defined(_LIBCPP_VERSION) +#define STD_GET_ARR_HACK a.__elems_[I] +#else +#define STD_GET_ARR_HACK std::template get(a) +#endif + +template constexpr inline T& std_array_get(std::array& a) { return (T&) STD_GET_ARR_HACK; } +template constexpr inline T&& std_array_get(std::array&& a) { return (T&&) STD_GET_ARR_HACK; } +template constexpr inline T const& std_array_get(std::array const& a) { return (T const&) STD_GET_ARR_HACK; } + +#undef STD_GET_ARR_HACK + +/* Suppose you have a template of the form + * template struct X; + * And you want to specialize it in such a way: + * template struct X> { ::: }; + * template<> struct X> { ::: }; + * This will work in Intel's compiler 13.0, but only to some extent in g++ 4.6, since + * g++ can only match templates called with parameter packs if the number of template + * arguments is not a fixed size (so inside the first specialization, referencing + * X> will fail in g++). On the other hand, g++ will accept the following: + * template struct X> { ::: }: + * as an additional (!) specialization, which will then only match the empty case. + * But Intel's compiler 13.0 won't accept that, it will only accept the empty syntax, + * so we have to create a workaround for this. + */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define EIGEN_TPL_PP_SPEC_HACK_DEF(mt, n) mt... n +#define EIGEN_TPL_PP_SPEC_HACK_DEFC(mt, n) , EIGEN_TPL_PP_SPEC_HACK_DEF(mt, n) +#define EIGEN_TPL_PP_SPEC_HACK_USE(n) n... +#define EIGEN_TPL_PP_SPEC_HACK_USEC(n) , n... +#else +#define EIGEN_TPL_PP_SPEC_HACK_DEF(mt, n) +#define EIGEN_TPL_PP_SPEC_HACK_DEFC(mt, n) +#define EIGEN_TPL_PP_SPEC_HACK_USE(n) +#define EIGEN_TPL_PP_SPEC_HACK_USEC(n) +#endif + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11WORKAROUNDS_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 38c89a234..841cab9d7 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -92,3 +92,11 @@ ei_add_test(gmres) ei_add_test(minres) ei_add_test(levenberg_marquardt) ei_add_test(bdcsvd) + +option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF) +if(EIGEN_TEST_CXX11) + # FIXME: add C++11 compiler switch in some portable way + # (MSVC doesn't need any for example, so this will + # clash there) + ei_add_test(cxx11_meta "-std=c++0x") +endif() diff --git a/unsupported/test/cxx11_meta.cpp b/unsupported/test/cxx11_meta.cpp new file mode 100644 index 000000000..03a9efe54 --- /dev/null +++ b/unsupported/test/cxx11_meta.cpp @@ -0,0 +1,343 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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/. + +#include "main.h" + +#include + +using Eigen::internal::is_same; +using Eigen::internal::type_list; +using Eigen::internal::numeric_list; +using Eigen::internal::gen_numeric_list; +using Eigen::internal::gen_numeric_list_reversed; +using Eigen::internal::gen_numeric_list_swapped_pair; +using Eigen::internal::gen_numeric_list_repeated; +using Eigen::internal::concat; +using Eigen::internal::mconcat; +using Eigen::internal::take; +using Eigen::internal::skip; +using Eigen::internal::slice; +using Eigen::internal::get; +using Eigen::internal::id_numeric; +using Eigen::internal::id_type; +using Eigen::internal::is_same_gf; +using Eigen::internal::apply_op_from_left; +using Eigen::internal::apply_op_from_right; +using Eigen::internal::contained_in_list; +using Eigen::internal::contained_in_list_gf; +using Eigen::internal::arg_prod; +using Eigen::internal::arg_sum; +using Eigen::internal::sum_op; +using Eigen::internal::product_op; +using Eigen::internal::array_reverse; +using Eigen::internal::array_sum; +using Eigen::internal::array_prod; +using Eigen::internal::array_reduce; +using Eigen::internal::array_zip; +using Eigen::internal::array_zip_and_reduce; +using Eigen::internal::array_apply; +using Eigen::internal::array_apply_and_reduce; +using Eigen::internal::repeat; +using Eigen::internal::instantiate_by_c_array; + +struct dummy_a {}; +struct dummy_b {}; +struct dummy_c {}; +struct dummy_d {}; +struct dummy_e {}; + +// dummy operation for testing apply +template struct dummy_op; +template<> struct dummy_op { typedef dummy_c type; }; +template<> struct dummy_op { typedef dummy_d type; }; +template<> struct dummy_op { typedef dummy_a type; }; +template<> struct dummy_op { typedef dummy_d type; }; +template<> struct dummy_op { typedef dummy_b type; }; +template<> struct dummy_op { typedef dummy_d type; }; +template<> struct dummy_op { typedef dummy_e type; }; +template<> struct dummy_op { typedef dummy_e type; }; +template<> struct dummy_op { typedef dummy_e type; }; + +template struct dummy_test { constexpr static bool value = false; constexpr static int global_flags = 0; }; +template<> struct dummy_test { constexpr static bool value = true; constexpr static int global_flags = 1; }; +template<> struct dummy_test { constexpr static bool value = true; constexpr static int global_flags = 2; }; +template<> struct dummy_test { constexpr static bool value = true; constexpr static int global_flags = 4; }; + +struct times2_op { template static A run(A v) { return v * 2; } }; + +struct dummy_inst +{ + int c; + + dummy_inst() : c(0) {} + explicit dummy_inst(int) : c(1) {} + dummy_inst(int, int) : c(2) {} + dummy_inst(int, int, int) : c(3) {} + dummy_inst(int, int, int, int) : c(4) {} + dummy_inst(int, int, int, int, int) : c(5) {} +}; + +static void test_gen_numeric_list() +{ + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); +} + +static void test_concat() +{ + VERIFY((is_same, type_list<>>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + + VERIFY((is_same>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + VERIFY((is_same, type_list>::type, type_list>::value)); + + VERIFY((is_same>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); + VERIFY((is_same, numeric_list>::type, numeric_list>::value)); +} + +static void test_slice() +{ + typedef type_list tl; + typedef numeric_list il; + + VERIFY((is_same::type, type_list<>>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, type_list<>>::value)); + + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); + + VERIFY((is_same::type, typename take<3, tl>::type>::value)); + VERIFY((is_same::type, typename take<3, il>::type>::value)); + VERIFY((is_same::type, type_list>::value)); + VERIFY((is_same::type, numeric_list>::value)); +} + +static void test_get() +{ + typedef type_list tl; + typedef numeric_list il; + + VERIFY((is_same::type, dummy_a>::value)); + VERIFY((is_same::type, dummy_a>::value)); + VERIFY((is_same::type, dummy_b>::value)); + VERIFY((is_same::type, dummy_b>::value)); + VERIFY((is_same::type, dummy_c>::value)); + VERIFY((is_same::type, dummy_c>::value)); + + VERIFY_IS_EQUAL(((int)get<0, il>::value), 4); + VERIFY_IS_EQUAL(((int)get<1, il>::value), 8); + VERIFY_IS_EQUAL(((int)get<2, il>::value), 15); + VERIFY_IS_EQUAL(((int)get<3, il>::value), 16); + VERIFY_IS_EQUAL(((int)get<4, il>::value), 23); + VERIFY_IS_EQUAL(((int)get<5, il>::value), 42); +} + +static void test_id_helper(dummy_a a, dummy_a b, dummy_a c) +{ + (void)a; + (void)b; + (void)c; +} + +template +static void test_id_numeric() +{ + test_id_helper(typename id_numeric::type()...); +} + +template +static void test_id_type() +{ + test_id_helper(typename id_type::type()...); +} + +static void test_id() +{ + // don't call VERIFY here, just assume it works if it compiles + // (otherwise it will complain that it can't find the function) + test_id_numeric<1, 4, 6>(); + test_id_type(); +} + +static void test_is_same_gf() +{ + VERIFY((!is_same_gf::value)); + VERIFY((!!is_same_gf::value)); + VERIFY_IS_EQUAL((!!is_same_gf::global_flags), 0); + VERIFY_IS_EQUAL((!!is_same_gf::global_flags), 0); +} + +static void test_apply_op() +{ + typedef type_list tl; + VERIFY((!!is_same::type, type_list>::value)); + VERIFY((!!is_same::type, type_list>::value)); +} + +static void test_contained_in_list() +{ + typedef type_list tl; + + VERIFY((!!contained_in_list::value)); + VERIFY((!!contained_in_list::value)); + VERIFY((!!contained_in_list::value)); + VERIFY((!contained_in_list::value)); + VERIFY((!contained_in_list::value)); + + VERIFY((!!contained_in_list_gf::value)); + VERIFY((!!contained_in_list_gf::value)); + VERIFY((!!contained_in_list_gf::value)); + VERIFY((!contained_in_list_gf::value)); + VERIFY((!contained_in_list_gf::value)); + + VERIFY_IS_EQUAL(((int)contained_in_list_gf::global_flags), 1); + VERIFY_IS_EQUAL(((int)contained_in_list_gf::global_flags), 2); + VERIFY_IS_EQUAL(((int)contained_in_list_gf::global_flags), 4); + VERIFY_IS_EQUAL(((int)contained_in_list_gf::global_flags), 0); + VERIFY_IS_EQUAL(((int)contained_in_list_gf::global_flags), 0); +} + +static void test_arg_reductions() +{ + VERIFY_IS_EQUAL(arg_sum(1,2,3,4), 10); + VERIFY_IS_EQUAL(arg_prod(1,2,3,4), 24); + VERIFY_IS_APPROX(arg_sum(0.5, 2, 5), 7.5); + VERIFY_IS_APPROX(arg_prod(0.5, 2, 5), 5.0); +} + +static void test_array_reverse_and_reduce() +{ + std::array a{{4, 8, 15, 16, 23, 42}}; + std::array b{{42, 23, 16, 15, 8, 4}}; + + // there is no operator<< for std::array, so VERIFY_IS_EQUAL will + // not compile + VERIFY((array_reverse(a) == b)); + VERIFY((array_reverse(b) == a)); + VERIFY_IS_EQUAL((array_sum(a)), 108); + VERIFY_IS_EQUAL((array_sum(b)), 108); + VERIFY_IS_EQUAL((array_prod(a)), 7418880); + VERIFY_IS_EQUAL((array_prod(b)), 7418880); +} + +static void test_array_zip_and_apply() +{ + std::array a{{4, 8, 15, 16, 23, 42}}; + std::array b{{0, 1, 2, 3, 4, 5}}; + std::array c{{4, 9, 17, 19, 27, 47}}; + std::array d{{0, 8, 30, 48, 92, 210}}; + std::array e{{0, 2, 4, 6, 8, 10}}; + + VERIFY((array_zip(a, b) == c)); + VERIFY((array_zip(a, b) == d)); + VERIFY((array_apply(b) == e)); + VERIFY_IS_EQUAL((array_apply_and_reduce(a)), 216); + VERIFY_IS_EQUAL((array_apply_and_reduce(b)), 30); + VERIFY_IS_EQUAL((array_zip_and_reduce(a, b)), 14755932); + VERIFY_IS_EQUAL((array_zip_and_reduce(a, b)), 388); +} + +static void test_array_misc() +{ + std::array a3{{1, 1, 1}}; + std::array a6{{2, 2, 2, 2, 2, 2}}; + VERIFY((repeat<3, int>(1) == a3)); + VERIFY((repeat<6, int>(2) == a6)); + + int data[5] = { 0, 1, 2, 3, 4 }; + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 0); + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 1); + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 2); + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 3); + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 4); + VERIFY_IS_EQUAL((instantiate_by_c_array(data).c), 5); +} + +void test_cxx11_meta() +{ + CALL_SUBTEST(test_gen_numeric_list()); + CALL_SUBTEST(test_concat()); + CALL_SUBTEST(test_slice()); + CALL_SUBTEST(test_get()); + CALL_SUBTEST(test_id()); + CALL_SUBTEST(test_is_same_gf()); + CALL_SUBTEST(test_apply_op()); + CALL_SUBTEST(test_contained_in_list()); + CALL_SUBTEST(test_arg_reductions()); + CALL_SUBTEST(test_array_reverse_and_reduce()); + CALL_SUBTEST(test_array_zip_and_apply()); + CALL_SUBTEST(test_array_misc()); +} + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ From f97b3cd0249228820807229a2d529260522ba8c7 Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Thu, 14 Nov 2013 22:52:37 +0100 Subject: [PATCH 2/4] CXX11/Tensor: add simple initial tensor implementation This commit adds an initial implementation of a class template Tensor that allows for the storage of objects with more than two indices. Currently, only storing data and setting the object to zero for POD data types are implemented. --- unsupported/Eigen/CXX11/Tensor | 40 +++ unsupported/Eigen/CXX11/src/Tensor/Tensor.h | 314 ++++++++++++++++++ .../Eigen/CXX11/src/Tensor/TensorStorage.h | 126 +++++++ unsupported/test/CMakeLists.txt | 1 + unsupported/test/cxx11_tensor_simple.cpp | 271 +++++++++++++++ 5 files changed, 752 insertions(+) create mode 100644 unsupported/Eigen/CXX11/Tensor create mode 100644 unsupported/Eigen/CXX11/src/Tensor/Tensor.h create mode 100644 unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h create mode 100644 unsupported/test/cxx11_tensor_simple.cpp diff --git a/unsupported/Eigen/CXX11/Tensor b/unsupported/Eigen/CXX11/Tensor new file mode 100644 index 000000000..083d8c0a7 --- /dev/null +++ b/unsupported/Eigen/CXX11/Tensor @@ -0,0 +1,40 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_TENSOR_MODULE +#define EIGEN_CXX11_TENSOR_MODULE + +#include + +#include + +/** \defgroup CXX11_Tensor_Module Tensor Module + * + * This module provides a Tensor class for storing arbitrarily indexed + * objects. + * + * \code + * #include + * \endcode + */ + +#include +#include + +#include "src/Tensor/TensorStorage.h" +#include "src/Tensor/Tensor.h" + +#include + +#endif // EIGEN_CXX11_TENSOR_MODULE + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/Tensor/Tensor.h b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h new file mode 100644 index 000000000..c40905af4 --- /dev/null +++ b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h @@ -0,0 +1,314 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_TENSOR_TENSOR_H +#define EIGEN_CXX11_TENSOR_TENSOR_H + +namespace Eigen { + +/** \class Tensor + * \ingroup CXX11_Tensor_Module + * + * \brief The tensor class. + * + * The %Tensor class is the work-horse for all \em dense tensors within Eigen. + * + * The %Tensor class encompasses only dynamic-size objects so far. + * + * The first two template parameters are required: + * \tparam Scalar_ \anchor tensor_tparam_scalar Numeric type, e.g. float, double, int or std::complex. + * User defined scalar types are supported as well (see \ref user_defined_scalars "here"). + * \tparam NumIndices_ Number of indices (i.e. rank of the tensor) + * + * The remaining template parameters are optional -- in most cases you don't have to worry about them. + * \tparam Options_ \anchor tensor_tparam_options A combination of either \b #RowMajor or \b #ColMajor, and of either + * \b #AutoAlign or \b #DontAlign. + * The former controls \ref TopicStorageOrders "storage order", and defaults to column-major. The latter controls alignment, which is required + * for vectorization. It defaults to aligning tensors. Note that tensors currently do not support any operations that profit from vectorization. + * Support for such operations (i.e. adding two tensors etc.) is planned. + * + * You can access elements of tensors using normal subscripting: + * + * \code + * Eigen::Tensor t(10, 10, 10, 10); + * t(0, 1, 2, 3) = 42.0; + * \endcode + * + * This class can be extended with the help of the plugin mechanism described on the page + * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_TENSOR_PLUGIN. + * + * Some notes: + * + *
+ *
Relation to other parts of Eigen:
+ *
The midterm developement goal for this class is to have a similar hierarchy as Eigen uses for matrices, so that + * taking blocks or using tensors in expressions is easily possible, including an interface with the vector/matrix code + * by providing .asMatrix() and .asVector() (or similar) methods for rank 2 and 1 tensors. However, currently, the %Tensor + * class does not provide any of these features and is only available as a stand-alone class that just allows for + * coefficient access. Also, when fixed-size tensors are implemented, the number of template arguments is likely to + * change dramatically.
+ *
+ * + * \ref TopicStorageOrders + */ +template +class Tensor; + +namespace internal { +template +struct traits> +{ + typedef Scalar_ Scalar; + typedef Dense StorageKind; + typedef DenseIndex Index; + enum { + Options = Options_ + }; +}; + +template +struct tensor_index_linearization_helper +{ + constexpr static inline Index run(std::array const& indices, std::array const& dimensions) + { + return std_array_get(indices) + + std_array_get(dimensions) * + tensor_index_linearization_helper::run(indices, dimensions); + } +}; + +template +struct tensor_index_linearization_helper +{ + constexpr static inline Index run(std::array const& indices, std::array const&) + { + return std_array_get(indices); + } +}; +} // end namespace internal + +template +class Tensor +{ + static_assert(NumIndices_ >= 1, "A tensor must have at least one index."); + + public: + typedef Tensor Self; + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef Self DenseType; + + constexpr static int Options = Options_; + constexpr static std::size_t NumIndices = NumIndices_; + + protected: + TensorStorage m_storage; + + public: + EIGEN_STRONG_INLINE Index dimension(std::size_t n) const { return m_storage.dimensions()[n]; } + EIGEN_STRONG_INLINE std::array dimensions() const { return m_storage.dimensions(); } + EIGEN_STRONG_INLINE Index size() const { return internal::array_prod(m_storage.dimensions()); } + EIGEN_STRONG_INLINE Scalar *data() { return m_storage.data(); } + EIGEN_STRONG_INLINE const Scalar *data() const { return m_storage.data(); } + + // This makes EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + // work, because that uses base().coeffRef() - and we don't yet + // implement a similar class hierarchy + inline Self& base() { return *this; } + inline const Self& base() const { return *this; } + + void setZero() + { + // FIXME: until we have implemented packet access and the + // expression engine w.r.t. nullary ops, use this + // as a kludge. Only works with POD types, but for + // any standard usage, this shouldn't be a problem + memset((void *)data(), 0, size() * sizeof(Scalar)); + } + + inline Self& operator=(Self const& other) + { + m_storage = other.m_storage; + return *this; + } + + template + inline const Scalar& coeff(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const + { + static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); + return coeff(std::array{{firstIndex, secondIndex, otherIndices...}}); + } + + inline const Scalar& coeff(const std::array& indices) const + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + inline const Scalar& coeff(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + + template + inline Scalar& coeffRef(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) + { + static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); + return coeffRef(std::array{{firstIndex, secondIndex, otherIndices...}}); + } + + inline Scalar& coeffRef(const std::array& indices) + { + eigen_internal_assert(checkIndexRange(indices)); + return m_storage.data()[linearizedIndex(indices)]; + } + + inline Scalar& coeffRef(Index index) + { + eigen_internal_assert(index >= 0 && index < size()); + return m_storage.data()[index]; + } + + template + inline const Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) const + { + static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); + return this->operator()(std::array{{firstIndex, secondIndex, otherIndices...}}); + } + + inline const Scalar& operator()(const std::array& indices) const + { + eigen_assert(checkIndexRange(indices)); + return coeff(indices); + } + + inline const Scalar& operator()(Index index) const + { + eigen_internal_assert(index >= 0 && index < size()); + return coeff(index); + } + + inline const Scalar& operator[](Index index) const + { + static_assert(NumIndices == 1, "The bracket operator is only for vectors, use the parenthesis operator instead."); + return coeff(index); + } + + template + inline Scalar& operator()(Index firstIndex, Index secondIndex, IndexTypes... otherIndices) + { + static_assert(sizeof...(otherIndices) + 2 == NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor."); + return operator()(std::array{{firstIndex, secondIndex, otherIndices...}}); + } + + inline Scalar& operator()(const std::array& indices) + { + eigen_assert(checkIndexRange(indices)); + return coeffRef(indices); + } + + inline Scalar& operator()(Index index) + { + eigen_assert(index >= 0 && index < size()); + return coeffRef(index); + } + + inline Scalar& operator[](Index index) + { + static_assert(NumIndices == 1, "The bracket operator is only for vectors, use the parenthesis operator instead."); + return coeffRef(index); + } + + inline Tensor() + : m_storage() + { + } + + inline Tensor(const Self& other) + : m_storage(other.m_storage) + { + } + + inline Tensor(Self&& other) + : m_storage(other.m_storage) + { + } + + template + inline Tensor(Index firstDimension, IndexTypes... otherDimensions) + : m_storage() + { + static_assert(sizeof...(otherDimensions) + 1 == NumIndices, "Number of dimensions used to construct a tensor must be equal to the rank of the tensor."); + resize(std::array{{firstDimension, otherDimensions...}}); + } + + inline Tensor(std::array dimensions) + : m_storage(internal::array_prod(dimensions), dimensions) + { + EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + } + + template + void resize(Index firstDimension, IndexTypes... otherDimensions) + { + static_assert(sizeof...(otherDimensions) + 1 == NumIndices, "Number of dimensions used to resize a tensor must be equal to the rank of the tensor."); + resize(std::array{{firstDimension, otherDimensions...}}); + } + + void resize(const std::array& dimensions) + { + std::size_t i; + Index size = Index(1); + for (i = 0; i < NumIndices; i++) { + internal::check_rows_cols_for_overflow::run(size, dimensions[i]); + size *= dimensions[i]; + } + #ifdef EIGEN_INITIALIZE_COEFFS + bool size_changed = size != this->size(); + m_storage.resize(size, dimensions); + if(size_changed) EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED + #else + m_storage.resize(size, dimensions); + #endif + } + + protected: + bool checkIndexRange(const std::array& indices) const + { + using internal::array_apply_and_reduce; + using internal::array_zip_and_reduce; + using internal::greater_equal_zero_op; + using internal::logical_and_op; + using internal::lesser_op; + + return + // check whether the indices are all >= 0 + array_apply_and_reduce(indices) && + // check whether the indices fit in the dimensions + array_zip_and_reduce(indices, m_storage.dimensions()); + } + + inline Index linearizedIndex(const std::array& indices) const + { + return internal::tensor_index_linearization_helper::run(indices, m_storage.dimensions()); + } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSOR_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h b/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h new file mode 100644 index 000000000..50040147d --- /dev/null +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h @@ -0,0 +1,126 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_TENSOR_TENSORSTORAGE_H +#define EIGEN_CXX11_TENSOR_TENSORSTORAGE_H + +#ifdef EIGEN_TENSOR_STORAGE_CTOR_PLUGIN + #define EIGEN_INTERNAL_TENSOR_STORAGE_CTOR_PLUGIN EIGEN_TENSOR_STORAGE_CTOR_PLUGIN; +#else + #define EIGEN_INTERNAL_TENSOR_STORAGE_CTOR_PLUGIN +#endif + +namespace Eigen { + +/** \internal + * + * \class TensorStorage + * \ingroup CXX11_Tensor_Module + * + * \brief Stores the data of a tensor + * + * This class stores the data of fixed-size, dynamic-size or mixed tensors + * in a way as compact as possible. + * + * \sa Tensor + */ +template class TensorStorage; + +// pure-dynamic, but without specification of all dimensions explicitly +template +class TensorStorage + : public TensorStorage::type> +{ + typedef TensorStorage::type> Base_; + public: + TensorStorage() = default; + TensorStorage(const TensorStorage&) = default; + TensorStorage(TensorStorage&&) = default; + TensorStorage(internal::constructor_without_unaligned_array_assert) : Base_(internal::constructor_without_unaligned_array_assert()) {} + TensorStorage(DenseIndex size, const std::array& dimensions) : Base_(size, dimensions) {} + TensorStorage& operator=(const TensorStorage&) = default; +}; + +// pure dynamic +template +class TensorStorage::type> +{ + T *m_data; + std::array m_dimensions; + + typedef TensorStorage::type> Self_; + public: + TensorStorage() : m_data(0), m_dimensions(internal::template repeat(0)) {} + TensorStorage(internal::constructor_without_unaligned_array_assert) + : m_data(0), m_dimensions(internal::template repeat(0)) {} + TensorStorage(DenseIndex size, const std::array& dimensions) + : m_data(internal::conditional_aligned_new_auto(size)), m_dimensions(dimensions) + { EIGEN_INTERNAL_TENSOR_STORAGE_CTOR_PLUGIN } + TensorStorage(const Self_& other) + : m_data(internal::conditional_aligned_new_auto(internal::array_prod(other.m_dimensions))) + , m_dimensions(other.m_dimensions) + { + internal::smart_copy(other.m_data, other.m_data+internal::array_prod(other.m_dimensions), m_data); + } + Self_& operator=(const Self_& other) + { + if (this != &other) { + Self_ tmp(other); + this->swap(tmp); + } + return *this; + } + TensorStorage(Self_&& other) + : m_data(std::move(other.m_data)), m_dimensions(std::move(other.m_dimensions)) + { + other.m_data = nullptr; + } + Self_& operator=(Self_&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_dimensions, other.m_dimensions); + return *this; + } + ~TensorStorage() { internal::conditional_aligned_delete_auto(m_data, internal::array_prod(m_dimensions)); } + void swap(Self_& other) + { std::swap(m_data,other.m_data); std::swap(m_dimensions,other.m_dimensions); } + std::array dimensions(void) const {return m_dimensions;} + void conservativeResize(DenseIndex size, const std::array& nbDimensions) + { + m_data = internal::conditional_aligned_realloc_new_auto(m_data, size, internal::array_prod(m_dimensions)); + m_dimensions = nbDimensions; + } + void resize(DenseIndex size, const std::array& nbDimensions) + { + if(size != internal::array_prod(m_dimensions)) + { + internal::conditional_aligned_delete_auto(m_data, internal::array_prod(m_dimensions)); + if (size) + m_data = internal::conditional_aligned_new_auto(size); + else + m_data = 0; + EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN + } + m_dimensions = nbDimensions; + } + const T *data() const { return m_data; } + T *data() { return m_data; } +}; + +// TODO: implement fixed-size stuff + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSOR_TENSORSTORAGE_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 841cab9d7..61e8f56fd 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -99,4 +99,5 @@ if(EIGEN_TEST_CXX11) # (MSVC doesn't need any for example, so this will # clash there) ei_add_test(cxx11_meta "-std=c++0x") + ei_add_test(cxx11_tensor_simple "-std=c++0x") endif() diff --git a/unsupported/test/cxx11_tensor_simple.cpp b/unsupported/test/cxx11_tensor_simple.cpp new file mode 100644 index 000000000..6875a4e58 --- /dev/null +++ b/unsupported/test/cxx11_tensor_simple.cpp @@ -0,0 +1,271 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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/. + +#include "main.h" + +#include + +using Eigen::Tensor; +using Eigen::RowMajor; + +static void test_1d() +{ + Tensor vec1(6); + Tensor vec2(6); + Tensor vec3; + Tensor vec4; + + vec3.resize(6); + vec4.resize(6); + + vec1(0) = 4; vec2(0) = 0; vec3(0) = 5; + vec1(1) = 8; vec2(1) = 1; vec3(1) = 4; + vec1(2) = 15; vec2(2) = 2; vec3(2) = 3; + vec1(3) = 16; vec2(3) = 3; vec3(3) = 2; + vec1(4) = 23; vec2(4) = 4; vec3(4) = 1; + vec1(5) = 42; vec2(5) = 5; vec3(5) = 0; + vec4.setZero(); + + VERIFY_IS_EQUAL((vec1.size()), 6); + VERIFY_IS_EQUAL((vec1.dimensions()[0]), 6); + + VERIFY_IS_EQUAL((vec1[0]), 4); + VERIFY_IS_EQUAL((vec1[1]), 8); + VERIFY_IS_EQUAL((vec1[2]), 15); + VERIFY_IS_EQUAL((vec1[3]), 16); + VERIFY_IS_EQUAL((vec1[4]), 23); + VERIFY_IS_EQUAL((vec1[5]), 42); + + VERIFY_IS_EQUAL((vec2[0]), 0); + VERIFY_IS_EQUAL((vec2[1]), 1); + VERIFY_IS_EQUAL((vec2[2]), 2); + VERIFY_IS_EQUAL((vec2[3]), 3); + VERIFY_IS_EQUAL((vec2[4]), 4); + VERIFY_IS_EQUAL((vec2[5]), 5); + + VERIFY_IS_EQUAL((vec3[0]), 5); + VERIFY_IS_EQUAL((vec3[1]), 4); + VERIFY_IS_EQUAL((vec3[2]), 3); + VERIFY_IS_EQUAL((vec3[3]), 2); + VERIFY_IS_EQUAL((vec3[4]), 1); + VERIFY_IS_EQUAL((vec3[5]), 0); + + VERIFY_IS_EQUAL((vec4[0]), 0); + VERIFY_IS_EQUAL((vec4[1]), 0); + VERIFY_IS_EQUAL((vec4[2]), 0); + VERIFY_IS_EQUAL((vec4[3]), 0); + VERIFY_IS_EQUAL((vec4[4]), 0); + VERIFY_IS_EQUAL((vec4[5]), 0); + + Tensor vec5(vec1); + + VERIFY_IS_EQUAL((vec5(0)), 4); + VERIFY_IS_EQUAL((vec5(1)), 8); + VERIFY_IS_EQUAL((vec5(2)), 15); + VERIFY_IS_EQUAL((vec5(3)), 16); + VERIFY_IS_EQUAL((vec5(4)), 23); + VERIFY_IS_EQUAL((vec5(5)), 42); + + VERIFY_IS_EQUAL((vec5.data()[0]), 4); + VERIFY_IS_EQUAL((vec5.data()[1]), 8); + VERIFY_IS_EQUAL((vec5.data()[2]), 15); + VERIFY_IS_EQUAL((vec5.data()[3]), 16); + VERIFY_IS_EQUAL((vec5.data()[4]), 23); + VERIFY_IS_EQUAL((vec5.data()[5]), 42); +} + +static void test_2d() +{ + Tensor mat1(2,3); + Tensor mat2(2,3); + + mat1(0,0) = 0; + mat1(0,1) = 1; + mat1(0,2) = 2; + mat1(1,0) = 3; + mat1(1,1) = 4; + mat1(1,2) = 5; + + mat2(0,0) = 0; + mat2(0,1) = 1; + mat2(0,2) = 2; + mat2(1,0) = 3; + mat2(1,1) = 4; + mat2(1,2) = 5; + + VERIFY_IS_EQUAL((mat1.size()), 6); + VERIFY_IS_EQUAL((mat1.dimensions()[0]), 2); + VERIFY_IS_EQUAL((mat1.dimensions()[1]), 3); + + VERIFY_IS_EQUAL((mat2.size()), 6); + VERIFY_IS_EQUAL((mat2.dimensions()[0]), 2); + VERIFY_IS_EQUAL((mat2.dimensions()[1]), 3); + + VERIFY_IS_EQUAL((mat1.data()[0]), 0); + VERIFY_IS_EQUAL((mat1.data()[1]), 3); + VERIFY_IS_EQUAL((mat1.data()[2]), 1); + VERIFY_IS_EQUAL((mat1.data()[3]), 4); + VERIFY_IS_EQUAL((mat1.data()[4]), 2); + VERIFY_IS_EQUAL((mat1.data()[5]), 5); + + VERIFY_IS_EQUAL((mat2.data()[0]), 0); + VERIFY_IS_EQUAL((mat2.data()[1]), 1); + VERIFY_IS_EQUAL((mat2.data()[2]), 2); + VERIFY_IS_EQUAL((mat2.data()[3]), 3); + VERIFY_IS_EQUAL((mat2.data()[4]), 4); + VERIFY_IS_EQUAL((mat2.data()[5]), 5); +} + +static void test_3d() +{ + Tensor epsilon(3,3,3); + epsilon.setZero(); + epsilon(0,1,2) = epsilon(2,0,1) = epsilon(1,2,0) = 1; + epsilon(2,1,0) = epsilon(0,2,1) = epsilon(1,0,2) = -1; + + VERIFY_IS_EQUAL((epsilon.size()), 27); + VERIFY_IS_EQUAL((epsilon.dimensions()[0]), 3); + VERIFY_IS_EQUAL((epsilon.dimensions()[1]), 3); + VERIFY_IS_EQUAL((epsilon.dimensions()[2]), 3); + + VERIFY_IS_EQUAL((epsilon(0,0,0)), 0); + VERIFY_IS_EQUAL((epsilon(0,0,1)), 0); + VERIFY_IS_EQUAL((epsilon(0,0,2)), 0); + VERIFY_IS_EQUAL((epsilon(0,1,0)), 0); + VERIFY_IS_EQUAL((epsilon(0,1,1)), 0); + VERIFY_IS_EQUAL((epsilon(0,2,0)), 0); + VERIFY_IS_EQUAL((epsilon(0,2,2)), 0); + VERIFY_IS_EQUAL((epsilon(1,0,0)), 0); + VERIFY_IS_EQUAL((epsilon(1,0,1)), 0); + VERIFY_IS_EQUAL((epsilon(1,1,0)), 0); + VERIFY_IS_EQUAL((epsilon(1,1,1)), 0); + VERIFY_IS_EQUAL((epsilon(1,1,2)), 0); + VERIFY_IS_EQUAL((epsilon(1,2,1)), 0); + VERIFY_IS_EQUAL((epsilon(1,2,2)), 0); + VERIFY_IS_EQUAL((epsilon(2,0,0)), 0); + VERIFY_IS_EQUAL((epsilon(2,0,2)), 0); + VERIFY_IS_EQUAL((epsilon(2,1,1)), 0); + VERIFY_IS_EQUAL((epsilon(2,1,2)), 0); + VERIFY_IS_EQUAL((epsilon(2,2,0)), 0); + VERIFY_IS_EQUAL((epsilon(2,2,1)), 0); + VERIFY_IS_EQUAL((epsilon(2,2,2)), 0); + + VERIFY_IS_EQUAL((epsilon(0,1,2)), 1); + VERIFY_IS_EQUAL((epsilon(2,0,1)), 1); + VERIFY_IS_EQUAL((epsilon(1,2,0)), 1); + VERIFY_IS_EQUAL((epsilon(2,1,0)), -1); + VERIFY_IS_EQUAL((epsilon(0,2,1)), -1); + VERIFY_IS_EQUAL((epsilon(1,0,2)), -1); + + std::array dims{{2,3,4}}; + Tensor t1(dims); + Tensor t2(dims); + + VERIFY_IS_EQUAL((t1.size()), 24); + VERIFY_IS_EQUAL((t1.dimensions()[0]), 2); + VERIFY_IS_EQUAL((t1.dimensions()[1]), 3); + VERIFY_IS_EQUAL((t1.dimensions()[2]), 4); + + VERIFY_IS_EQUAL((t2.size()), 24); + VERIFY_IS_EQUAL((t2.dimensions()[0]), 2); + VERIFY_IS_EQUAL((t2.dimensions()[1]), 3); + VERIFY_IS_EQUAL((t2.dimensions()[2]), 4); + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 4; k++) { + t1(i, j, k) = 100 * i + 10 * j + k; + t2(i, j, k) = 100 * i + 10 * j + k; + } + } + } + + VERIFY_IS_EQUAL((t1.data()[0]), 0); + VERIFY_IS_EQUAL((t1.data()[1]), 100); + VERIFY_IS_EQUAL((t1.data()[2]), 10); + VERIFY_IS_EQUAL((t1.data()[3]), 110); + VERIFY_IS_EQUAL((t1.data()[4]), 20); + VERIFY_IS_EQUAL((t1.data()[5]), 120); + VERIFY_IS_EQUAL((t1.data()[6]), 1); + VERIFY_IS_EQUAL((t1.data()[7]), 101); + VERIFY_IS_EQUAL((t1.data()[8]), 11); + VERIFY_IS_EQUAL((t1.data()[9]), 111); + VERIFY_IS_EQUAL((t1.data()[10]), 21); + VERIFY_IS_EQUAL((t1.data()[11]), 121); + VERIFY_IS_EQUAL((t1.data()[12]), 2); + VERIFY_IS_EQUAL((t1.data()[13]), 102); + VERIFY_IS_EQUAL((t1.data()[14]), 12); + VERIFY_IS_EQUAL((t1.data()[15]), 112); + VERIFY_IS_EQUAL((t1.data()[16]), 22); + VERIFY_IS_EQUAL((t1.data()[17]), 122); + VERIFY_IS_EQUAL((t1.data()[18]), 3); + VERIFY_IS_EQUAL((t1.data()[19]), 103); + VERIFY_IS_EQUAL((t1.data()[20]), 13); + VERIFY_IS_EQUAL((t1.data()[21]), 113); + VERIFY_IS_EQUAL((t1.data()[22]), 23); + VERIFY_IS_EQUAL((t1.data()[23]), 123); + + VERIFY_IS_EQUAL((t2.data()[0]), 0); + VERIFY_IS_EQUAL((t2.data()[1]), 1); + VERIFY_IS_EQUAL((t2.data()[2]), 2); + VERIFY_IS_EQUAL((t2.data()[3]), 3); + VERIFY_IS_EQUAL((t2.data()[4]), 10); + VERIFY_IS_EQUAL((t2.data()[5]), 11); + VERIFY_IS_EQUAL((t2.data()[6]), 12); + VERIFY_IS_EQUAL((t2.data()[7]), 13); + VERIFY_IS_EQUAL((t2.data()[8]), 20); + VERIFY_IS_EQUAL((t2.data()[9]), 21); + VERIFY_IS_EQUAL((t2.data()[10]), 22); + VERIFY_IS_EQUAL((t2.data()[11]), 23); + VERIFY_IS_EQUAL((t2.data()[12]), 100); + VERIFY_IS_EQUAL((t2.data()[13]), 101); + VERIFY_IS_EQUAL((t2.data()[14]), 102); + VERIFY_IS_EQUAL((t2.data()[15]), 103); + VERIFY_IS_EQUAL((t2.data()[16]), 110); + VERIFY_IS_EQUAL((t2.data()[17]), 111); + VERIFY_IS_EQUAL((t2.data()[18]), 112); + VERIFY_IS_EQUAL((t2.data()[19]), 113); + VERIFY_IS_EQUAL((t2.data()[20]), 120); + VERIFY_IS_EQUAL((t2.data()[21]), 121); + VERIFY_IS_EQUAL((t2.data()[22]), 122); + VERIFY_IS_EQUAL((t2.data()[23]), 123); +} + +static void test_simple_assign() +{ + Tensor epsilon(3,3,3); + epsilon.setZero(); + epsilon(0,1,2) = epsilon(2,0,1) = epsilon(1,2,0) = 1; + epsilon(2,1,0) = epsilon(0,2,1) = epsilon(1,0,2) = -1; + + Tensor e2(2,3,1); + e2.setZero(); + VERIFY_IS_EQUAL((e2(1,2,0)), 0); + + e2 = epsilon; + VERIFY_IS_EQUAL((e2(1,2,0)), 1); + VERIFY_IS_EQUAL((e2(0,1,2)), 1); + VERIFY_IS_EQUAL((e2(2,0,1)), 1); + VERIFY_IS_EQUAL((e2(2,1,0)), -1); + VERIFY_IS_EQUAL((e2(0,2,1)), -1); + VERIFY_IS_EQUAL((e2(1,0,2)), -1); +} + +void test_cxx11_tensor_simple() +{ + CALL_SUBTEST(test_1d()); + CALL_SUBTEST(test_2d()); + CALL_SUBTEST(test_3d()); + CALL_SUBTEST(test_simple_assign()); +} + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ From 03a956925a969e3759418bd1e0fced82eb5f9d12 Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Thu, 14 Nov 2013 23:35:11 +0100 Subject: [PATCH 3/4] CXX11/TensorSymmetry: add symmetry support for Tensor class Add a symCoeff() method to the Tensor class template that allows the user of the class to set multiple elements of a tensor at once if they are connected by a symmetry operation with respect to the tensor's indices (symmetry/antisymmetry/hermiticity/antihermiticity under echange of two indices and combination thereof for different pairs of indices). A compile-time resolution of the required symmetry groups via meta templates is also implemented. For small enough groups this is used to unroll the loop that goes through all the elements of the Tensor that are connected by this group. For larger groups or groups where the symmetries are defined at run time, a standard run-time implementation of the same algorithm is provided. For example, the following code completely initializes all elements of the totally antisymmetric tensor in three dimensions ('epsilon tensor'): SGroup<3, AntiSymmetry<0,1>, AntiSymmetry<1,2>> sym; Eigen::Tensor epsilon(3,3,3); epsilon.setZero(); epsilon.symCoeff(sym, 0, 1, 2) = 1; --- unsupported/Eigen/CXX11/TensorSymmetry | 41 + unsupported/Eigen/CXX11/src/Tensor/Tensor.h | 15 + .../src/TensorSymmetry/DynamicSymmetry.h | 265 ++++++ .../CXX11/src/TensorSymmetry/StaticSymmetry.h | 216 +++++ .../Eigen/CXX11/src/TensorSymmetry/Symmetry.h | 312 +++++++ .../TensorSymmetry/util/TemplateGroupTheory.h | 667 ++++++++++++++ unsupported/test/CMakeLists.txt | 1 + unsupported/test/cxx11_tensor_symmetry.cpp | 819 ++++++++++++++++++ 8 files changed, 2336 insertions(+) create mode 100644 unsupported/Eigen/CXX11/TensorSymmetry create mode 100644 unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h create mode 100644 unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h create mode 100644 unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h create mode 100644 unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h create mode 100644 unsupported/test/cxx11_tensor_symmetry.cpp diff --git a/unsupported/Eigen/CXX11/TensorSymmetry b/unsupported/Eigen/CXX11/TensorSymmetry new file mode 100644 index 000000000..5bbab0a80 --- /dev/null +++ b/unsupported/Eigen/CXX11/TensorSymmetry @@ -0,0 +1,41 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_MODULE +#define EIGEN_CXX11_TENSORSYMMETRY_MODULE + +#include + +#include + +/** \defgroup CXX11_TensorSymmetry_Module Tensor Symmetry Module + * + * This module provides a classes that allow for the definition of + * symmetries w.r.t. tensor indices. + * + * Including this module will implicitly include the Tensor module. + * + * \code + * #include + * \endcode + */ + +#include "src/TensorSymmetry/util/TemplateGroupTheory.h" +#include "src/TensorSymmetry/Symmetry.h" +#include "src/TensorSymmetry/StaticSymmetry.h" +#include "src/TensorSymmetry/DynamicSymmetry.h" + +#include + +#endif // EIGEN_CXX11_TENSORSYMMETRY_MODULE + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/Tensor/Tensor.h b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h index c40905af4..ff3d6513e 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/Tensor.h +++ b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h @@ -92,6 +92,9 @@ struct tensor_index_linearization_helper return std_array_get(indices); } }; + +/* Forward-declaration required for the symmetry support. */ +template class tensor_symmetry_value_setter; } // end namespace internal template @@ -283,6 +286,18 @@ class Tensor #endif } + template + internal::tensor_symmetry_value_setter symCoeff(const Symmetry_& symmetry, Index firstIndex, IndexTypes... otherIndices) + { + return symCoeff(symmetry, std::array{{firstIndex, otherIndices...}}); + } + + template + internal::tensor_symmetry_value_setter symCoeff(const Symmetry_& symmetry, std::array const& indices) + { + return internal::tensor_symmetry_value_setter(*this, symmetry, indices); + } + protected: bool checkIndexRange(const std::array& indices) const { diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h new file mode 100644 index 000000000..87332610d --- /dev/null +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h @@ -0,0 +1,265 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_DYNAMICSYMMETRY_H +#define EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H + +namespace Eigen { + +class DynamicSGroup +{ + public: + inline explicit DynamicSGroup(std::size_t numIndices) : m_numIndices(numIndices), m_elements(), m_generators(), m_globalFlags(0) { m_elements.push_back(ge(Generator(0, 0, 0))); } + inline DynamicSGroup(const DynamicSGroup& o) : m_numIndices(o.m_numIndices), m_elements(o.m_elements), m_generators(o.m_generators), m_globalFlags(o.m_globalFlags) { } + inline DynamicSGroup(DynamicSGroup&& o) : m_numIndices(o.m_numIndices), m_elements(), m_generators(o.m_generators), m_globalFlags(o.m_globalFlags) { std::swap(m_elements, o.m_elements); } + inline DynamicSGroup& operator=(const DynamicSGroup& o) { m_numIndices = o.m_numIndices; m_elements = o.m_elements; m_generators = o.m_generators; m_globalFlags = o.m_globalFlags; return *this; } + inline DynamicSGroup& operator=(DynamicSGroup&& o) { m_numIndices = o.m_numIndices; std::swap(m_elements, o.m_elements); m_generators = o.m_generators; m_globalFlags = o.m_globalFlags; return *this; } + + void add(int one, int two, int flags = 0); + + template + inline void add(Gen_) { add(Gen_::One, Gen_::Two, Gen_::Flags); } + inline void addSymmetry(int one, int two) { add(one, two, 0); } + inline void addAntiSymmetry(int one, int two) { add(one, two, NegationFlag); } + inline void addHermiticity(int one, int two) { add(one, two, ConjugationFlag); } + inline void addAntiHermiticity(int one, int two) { add(one, two, NegationFlag | ConjugationFlag); } + + template + inline RV apply(const std::array& idx, RV initial, Args&&... args) const + { + eigen_assert(N == m_numIndices); + for (std::size_t i = 0; i < size(); i++) + initial = Op::run(h_permute(i, idx, typename internal::gen_numeric_list::type()), m_elements[i].flags, initial, std::forward(args)...); + return initial; + } + + template + inline RV apply(const std::vector& idx, RV initial, Args&&... args) const + { + eigen_assert(idx.size() == m_numIndices); + for (std::size_t i = 0; i < size(); i++) + initial = Op::run(h_permute(i, idx), m_elements[i].flags, initial, std::forward(args)...); + return initial; + } + + inline int globalFlags() const { return m_globalFlags; } + inline std::size_t size() const { return m_elements.size(); } + private: + struct GroupElement { + std::vector representation; + int flags; + bool isId() const + { + for (std::size_t i = 0; i < representation.size(); i++) + if (i != (size_t)representation[i]) + return false; + return true; + } + }; + struct Generator { + int one; + int two; + int flags; + constexpr inline Generator(int one_, int two_, int flags_) : one(one_), two(two_), flags(flags_) {} + }; + + std::size_t m_numIndices; + std::vector m_elements; + std::vector m_generators; + int m_globalFlags; + + template + inline std::array h_permute(std::size_t which, const std::array& idx, internal::numeric_list) const + { + return std::array{{ idx[m_elements[which].representation[n]]... }}; + } + + template + inline std::vector h_permute(std::size_t which, std::vector idx) const + { + std::vector result; + result.reserve(idx.size()); + for (auto k : m_elements[which].representation) + result.push_back(idx[k]); + return result; + } + + inline GroupElement ge(Generator const& g) const + { + GroupElement result; + result.representation.reserve(m_numIndices); + result.flags = g.flags; + for (std::size_t k = 0; k < m_numIndices; k++) { + if (k == (std::size_t)g.one) + result.representation.push_back(g.two); + else if (k == (std::size_t)g.two) + result.representation.push_back(g.one); + else + result.representation.push_back(int(k)); + } + return result; + } + + GroupElement mul(GroupElement, GroupElement) const; + inline GroupElement mul(Generator g1, GroupElement g2) const + { + return mul(ge(g1), g2); + } + + inline GroupElement mul(GroupElement g1, Generator g2) const + { + return mul(g1, ge(g2)); + } + + inline GroupElement mul(Generator g1, Generator g2) const + { + return mul(ge(g1), ge(g2)); + } + + inline int findElement(GroupElement e) const + { + for (auto ee : m_elements) { + if (ee.representation == e.representation) + return ee.flags ^ e.flags; + } + return -1; + } + + void updateGlobalFlags(int flagDiffOfSameGenerator); +}; + +// dynamic symmetry group that auto-adds the template parameters in the constructor +template +class DynamicSGroupFromTemplateArgs : public DynamicSGroup +{ + public: + inline DynamicSGroupFromTemplateArgs() : DynamicSGroup(NumIndices) + { + add_all(internal::type_list()); + } + inline DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs const& other) : DynamicSGroup(other) { } + inline DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs&& other) : DynamicSGroup(other) { } + inline DynamicSGroupFromTemplateArgs& operator=(const DynamicSGroupFromTemplateArgs& o) { DynamicSGroup::operator=(o); return *this; } + inline DynamicSGroupFromTemplateArgs& operator=(DynamicSGroupFromTemplateArgs&& o) { DynamicSGroup::operator=(o); return *this; } + + private: + template + inline void add_all(internal::type_list) + { + add(Gen1()); + add_all(internal::type_list()); + } + + inline void add_all(internal::type_list<>) + { + } +}; + +inline DynamicSGroup::GroupElement DynamicSGroup::mul(GroupElement g1, GroupElement g2) const +{ + eigen_internal_assert(g1.representation.size() == m_numIndices); + eigen_internal_assert(g2.representation.size() == m_numIndices); + + GroupElement result; + result.representation.reserve(m_numIndices); + for (std::size_t i = 0; i < m_numIndices; i++) + result.representation.push_back(g2.representation[g1.representation[i]]); + result.flags = g1.flags ^ g2.flags; + return result; +} + +inline void DynamicSGroup::add(int one, int two, int flags) +{ + eigen_assert(one >= 0 && (std::size_t)one < m_numIndices); + eigen_assert(two >= 0 && (std::size_t)two < m_numIndices); + eigen_assert(one != two); + Generator g{one, two ,flags}; + GroupElement e = ge(g); + + /* special case for first generator */ + if (m_elements.size() == 1) { + while (!e.isId()) { + m_elements.push_back(e); + e = mul(e, g); + } + + if (e.flags > 0) + updateGlobalFlags(e.flags); + + // only add in case we didn't have identity + if (m_elements.size() > 1) + m_generators.push_back(g); + return; + } + + int p = findElement(e); + if (p >= 0) { + updateGlobalFlags(p); + return; + } + + std::size_t coset_order = m_elements.size(); + m_elements.push_back(e); + for (std::size_t i = 1; i < coset_order; i++) + m_elements.push_back(mul(m_elements[i], e)); + m_generators.push_back(g); + + std::size_t coset_rep = coset_order; + do { + for (auto g : m_generators) { + e = mul(m_elements[coset_rep], g); + p = findElement(e); + if (p < 0) { + // element not yet in group + m_elements.push_back(e); + for (std::size_t i = 1; i < coset_order; i++) + m_elements.push_back(mul(m_elements[i], e)); + } else if (p > 0) { + updateGlobalFlags(p); + } + } + coset_rep += coset_order; + } while (coset_rep < m_elements.size()); +} + +inline void DynamicSGroup::updateGlobalFlags(int flagDiffOfSameGenerator) +{ + switch (flagDiffOfSameGenerator) { + case 0: + default: + // nothing happened + break; + case NegationFlag: + // every element is it's own negative => whole tensor is zero + m_globalFlags |= GlobalZeroFlag; + break; + case ConjugationFlag: + // every element is it's own conjugate => whole tensor is real + m_globalFlags |= GlobalRealFlag; + break; + case (NegationFlag | ConjugationFlag): + // every element is it's own negative conjugate => whole tensor is imaginary + m_globalFlags |= GlobalImagFlag; + break; + /* NOTE: + * since GlobalZeroFlag == GlobalRealFlag | GlobalImagFlag, if one generator + * causes the tensor to be real and the next one to be imaginary, this will + * trivially give the correct result + */ + } +} + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h new file mode 100644 index 000000000..048e753fc --- /dev/null +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h @@ -0,0 +1,216 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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) +{ + return {{ idx[ii]... }}; +} + +template +static inline std::vector tensor_static_symgroup_index_permute(std::vector idx, internal::numeric_list) +{ + return {{ idx[ii]... }}; +} + +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) + { + 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 + static inline RV run(const std::vector& idx, RV initial, Args&&... args) + { + 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 +{ + 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; } +}; + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSORSYMMETRY_STATICSYMMETRY_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h new file mode 100644 index 000000000..40ad8d7ff --- /dev/null +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h @@ -0,0 +1,312 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_SYMMETRY_H +#define EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H + +namespace Eigen { + +enum { + NegationFlag = 0x01, + ConjugationFlag = 0x02 +}; + +enum { + GlobalRealFlag = 0x01, + GlobalImagFlag = 0x02, + GlobalZeroFlag = 0x03 +}; + +namespace internal { + +template struct tensor_symmetry_pre_analysis; +template struct tensor_static_symgroup; +template struct tensor_static_symgroup_if; +template struct tensor_symmetry_calculate_flags; +template struct tensor_symmetry_assign_value; + +} // end namespace internal + +template +struct Symmetry +{ + static_assert(One_ != Two_, "Symmetries must cover distinct indices."); + constexpr static int One = One_; + constexpr static int Two = Two_; + constexpr static int Flags = 0; +}; + +template +struct AntiSymmetry +{ + static_assert(One_ != Two_, "Symmetries must cover distinct indices."); + constexpr static int One = One_; + constexpr static int Two = Two_; + constexpr static int Flags = NegationFlag; +}; + +template +struct Hermiticity +{ + static_assert(One_ != Two_, "Symmetries must cover distinct indices."); + constexpr static int One = One_; + constexpr static int Two = Two_; + constexpr static int Flags = ConjugationFlag; +}; + +template +struct AntiHermiticity +{ + static_assert(One_ != Two_, "Symmetries must cover distinct indices."); + constexpr static int One = One_; + constexpr static int Two = Two_; + constexpr static int Flags = ConjugationFlag | NegationFlag; +}; + +/** \class DynamicSGroup + * \ingroup TensorSymmetry_Module + * + * \brief Dynamic symmetry group + * + * The %DynamicSGroup class represents a symmetry group that need not be known at + * compile time. It is useful if one wants to support arbitrary run-time defineable + * symmetries for tensors, but it is also instantiated if a symmetry group is defined + * at compile time that would be either too large for the compiler to reasonably + * generate (using templates to calculate this at compile time is very inefficient) + * or that the compiler could generate the group but that it wouldn't make sense to + * unroll the loop for setting coefficients anymore. + */ +class DynamicSGroup; + +/** \internal + * + * \class DynamicSGroupFromTemplateArgs + * \ingroup TensorSymmetry_Module + * + * \brief Dynamic symmetry group, initialized from template arguments + * + * This class is a child class of DynamicSGroup. It uses the template arguments + * specified to initialize itself. + */ +template +class DynamicSGroupFromTemplateArgs; + +/** \class StaticSGroup + * \ingroup TensorSymmetry_Module + * + * \brief Static symmetry group + * + * This class represents a symmetry group that is known and resolved completely + * at compile time. Ideally, no run-time penalty is incurred compared to the + * manual unrolling of the symmetry. + * + * CAUTION: + * + * Do not use this class directly for large symmetry groups. The compiler + * may run into a limit, or segfault or in the very least will take a very, + * very, very long time to compile the code. Use the SGroup class instead + * if you want a static group. That class contains logic that will + * automatically select the DynamicSGroup class instead if the symmetry + * group becomes too large. (In that case, unrolling may not even be + * beneficial.) + */ +template +class StaticSGroup; + +/** \class SGroup + * \ingroup TensorSymmetry_Module + * + * \brief Symmetry group, initialized from template arguments + * + * This class represents a symmetry group whose generators are already + * known at compile time. It may or may not be resolved at compile time, + * depending on the estimated size of the group. + * + * \sa StaticSGroup + * \sa DynamicSGroup + */ +template +class SGroup : public internal::tensor_symmetry_pre_analysis::root_type +{ + public: + typedef typename internal::tensor_symmetry_pre_analysis::root_type Base; + + // make standard constructors + assignment operators public + inline SGroup() : Base() { } + inline SGroup(const SGroup& other) : Base(other) { } + inline SGroup(SGroup&& other) : Base(other) { } + inline SGroup& operator=(const SGroup& other) { Base::operator=(other); return *this; } + inline SGroup& operator=(SGroup&& other) { Base::operator=(other); return *this; } + + // all else is defined in the base class +}; + +namespace internal { + +/** \internal + * + * \class tensor_symmetry_pre_analysis + * \ingroup TensorSymmetry_Module + * + * \brief Pre-select whether to use a static or dynamic symmetry group + * + * When a symmetry group could in principle be determined at compile time, + * this template implements the logic whether to actually do that or whether + * to rather defer that to runtime. + * + * The logic is as follows: + *
+ *
No generators (trivial symmetry):
+ *
Use a trivial static group. Ideally, this has no performance impact + * compared to not using symmetry at all. In practice, this might not + * be the case.
+ *
More than 4 generators:
+ *
Calculate the group at run time, it is likely far too large for the + * compiler to be able to properly generate it in a realistic time.
+ *
Up to and including 4 generators:
+ *
Actually enumerate all group elements, but then check how many there + * are. If there are more than 16, it is unlikely that unrolling the + * loop (as is done in the static compile-time case) is sensible, so + * use a dynamic group instead. If there are at most 16 elements, actually + * use that static group. Note that the largest group with 4 generators + * still compiles with reasonable resources.
+ *
+ * + * Note: Example compile time performance with g++-4.6 on an Intenl Core i5-3470 + * with 16 GiB RAM (all generators non-redundant and the subgroups don't + * factorize): + * + * # Generators -O0 -ggdb -O2 + * ------------------------------------------------------------------- + * 1 0.5 s / 250 MiB 0.45s / 230 MiB + * 2 0.5 s / 260 MiB 0.5 s / 250 MiB + * 3 0.65s / 310 MiB 0.62s / 310 MiB + * 4 2.2 s / 860 MiB 1.7 s / 770 MiB + * 5 130 s / 13000 MiB 120 s / 11000 MiB + * + * It is clear that everything is still very efficient up to 4 generators, then + * the memory and CPU requirements become unreasonable. Thus we only instantiate + * the template group theory logic if the number of generators supplied is 4 or + * lower, otherwise this will be forced to be done during runtime, where the + * algorithm is reasonably fast. + */ +template +struct tensor_symmetry_pre_analysis +{ + typedef StaticSGroup root_type; +}; + +template +struct tensor_symmetry_pre_analysis +{ + constexpr static std::size_t max_static_generators = 4; + constexpr static std::size_t max_static_elements = 16; + typedef tensor_static_symgroup_if<(sizeof...(Gens_) + 1 <= max_static_generators), NumIndices, Gen_, Gens_...> helper; + constexpr static std::size_t possible_size = helper::size; + + typedef typename conditional< + possible_size == 0 || possible_size >= max_static_elements, + DynamicSGroupFromTemplateArgs, + typename helper::type + >::type root_type; +}; + +template +struct tensor_static_symgroup_if +{ + constexpr static std::size_t size = 0; + typedef void type; +}; + +template +struct tensor_static_symgroup_if : tensor_static_symgroup {}; + +template +struct tensor_symmetry_assign_value +{ + typedef typename Tensor_::Index Index; + typedef typename Tensor_::Scalar Scalar; + constexpr static std::size_t NumIndices = Tensor_::NumIndices; + + static inline int run(const std::array& transformed_indices, int transformation_flags, int dummy, Tensor_& tensor, const Scalar& value_) + { + Scalar value(value_); + if (transformation_flags & ConjugationFlag) + value = numext::conj(value); + if (transformation_flags & NegationFlag) + value = -value; + tensor.coeffRef(transformed_indices) = value; + return dummy; + } +}; + +template +struct tensor_symmetry_calculate_flags +{ + typedef typename Tensor_::Index Index; + constexpr static std::size_t NumIndices = Tensor_::NumIndices; + + static inline int run(const std::array& transformed_indices, int transform_flags, int current_flags, const std::array& orig_indices) + { + if (transformed_indices == orig_indices) { + if (transform_flags & (ConjugationFlag | NegationFlag)) + return current_flags | GlobalImagFlag; // anti-hermitian diagonal + else if (transform_flags & ConjugationFlag) + return current_flags | GlobalRealFlag; // hermitian diagonal + else if (transform_flags & NegationFlag) + return current_flags | GlobalZeroFlag; // anti-symmetric diagonal + } + return current_flags; + } +}; + +template +class tensor_symmetry_value_setter +{ + public: + typedef typename Tensor_::Index Index; + typedef typename Tensor_::Scalar Scalar; + constexpr static std::size_t NumIndices = Tensor_::NumIndices; + + inline tensor_symmetry_value_setter(Tensor_& tensor, Symmetry_ const& symmetry, std::array const& indices) + : m_tensor(tensor), m_symmetry(symmetry), m_indices(indices) { } + + inline tensor_symmetry_value_setter& operator=(Scalar const& value) + { + doAssign(value); + return *this; + } + private: + Tensor_& m_tensor; + Symmetry_ m_symmetry; + std::array m_indices; + + inline void doAssign(Scalar const& value) + { + #ifdef EIGEN_TENSOR_SYMMETRY_CHECK_VALUES + int value_flags = m_symmetry.template apply, int>(m_indices, m_symmetry.globalFlags(), m_indices); + if (value_flags & GlobalRealFlag) + eigen_assert(numext::imag(value) == 0); + if (value_flags & GlobalImagFlag) + eigen_assert(numext::real(value) == 0); + #endif + m_symmetry.template apply, int>(m_indices, 0, m_tensor, value); + } +}; + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSORSYMMETRY_SYMMETRY_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h new file mode 100644 index 000000000..716d7d2e5 --- /dev/null +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h @@ -0,0 +1,667 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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_TEMPLATEGROUPTHEORY_H +#define EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H + +namespace Eigen { + +namespace internal { + +namespace group_theory { + +/** \internal + * \file CXX11/Tensor/util/TemplateGroupTheory.h + * This file contains C++ templates that implement group theory algorithms. + * + * The algorithms allow for a compile-time analysis of finite groups. + * + * Currently only Dimino's algorithm is implemented, which returns a list + * of all elements in a group given a set of (possibly redundant) generators. + * (One could also do that with the so-called orbital algorithm, but that + * is much more expensive and usually has no advantages.) + */ + +/********************************************************************** + * "Ok kid, here is where it gets complicated." + * - Amelia Pond in the "Doctor Who" episode + * "The Big Bang" + * + * Dimino's algorithm + * ================== + * + * The following is Dimino's algorithm in sequential form: + * + * Input: identity element, list of generators, equality check, + * multiplication operation + * Output: list of group elements + * + * 1. add identity element + * 2. remove identities from list of generators + * 3. add all powers of first generator that aren't the + * identity element + * 4. go through all remaining generators: + * a. if generator is already in the list of elements + * -> do nothing + * b. otherwise + * i. remember current # of elements + * (i.e. the size of the current subgroup) + * ii. add all current elements (which includes + * the identity) each multiplied from right + * with the current generator to the group + * iii. add all remaining cosets that are generated + * by products of the new generator with itself + * and all other generators seen so far + * + * In functional form, this is implemented as a long set of recursive + * templates that have a complicated relationship. + * + * The main interface for Dimino's algorithm is the template + * enumerate_group_elements. All lists are implemented as variadic + * type_list and numeric_list + * templates. + * + * 'Calling' templates is usually done via typedefs. + * + * This algorithm is an extended version of the basic version. The + * extension consists in the fact that each group element has a set + * of flags associated with it. Multiplication of two group elements + * with each other results in a group element whose flags are the + * XOR of the flags of the previous elements. Each time the algorithm + * notices that a group element it just calculated is already in the + * list of current elements, the flags of both will be compared and + * added to the so-called 'global flags' of the group. + * + * The rationale behind this extension is that this allows not only + * for the description of symmetries between tensor indices, but + * also allows for the description of hermiticity, antisymmetry and + * antihermiticity. Negation and conjugation each are specific bit + * in the flags value and if two different ways to reach a group + * element lead to two different flags, this poses a constraint on + * the allowed values of the resulting tensor. For example, if a + * group element is reach both with and without the conjugation + * flags, it is clear that the resulting tensor has to be real. + * + * Note that this flag mechanism is quite generic and may have other + * uses beyond tensor properties. + * + * IMPORTANT: + * This algorithm assumes the group to be finite. If you try to + * run it with a group that's infinite, the algorithm will only + * terminate once you hit a compiler limit (max template depth). + * Also note that trying to use this implementation to create a + * very large group will probably either make you hit the same + * limit, cause the compiler to segfault or at the very least + * take a *really* long time (hours, days, weeks - sic!) to + * compile. It is not recommended to plug in more than 4 + * generators, unless they are independent of each other. + */ + +/** \internal + * + * \class strip_identities + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Cleanse a list of group elements of the identity element + * + * This template is used to make a first pass through all initial + * generators of Dimino's algorithm and remove the identity + * elements. + * + * \sa enumerate_group_elements + */ +template class Equality, typename id, typename L> struct strip_identities; + +template< + template class Equality, + typename id, + typename t, + typename... ts +> +struct strip_identities> +{ + typedef typename conditional< + Equality::value, + typename strip_identities>::type, + typename concat, typename strip_identities>::type>::type + >::type type; + constexpr static int global_flags = Equality::global_flags | strip_identities>::global_flags; +}; + +template< + template class Equality, + typename id + EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, ts) +> +struct strip_identities> +{ + typedef type_list<> type; + constexpr static int global_flags = 0; +}; + +/** \internal + * + * \class dimino_first_step_elements_helper + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Recursive template that adds powers of the first generator to the list of group elements + * + * This template calls itself recursively to add powers of the first + * generator to the list of group elements. It stops if it reaches + * the identity element again. + * + * \sa enumerate_group_elements, dimino_first_step_elements + */ +template< + template class Multiply, + template class Equality, + typename id, + typename g, + typename current_element, + typename elements, + bool dont_add_current_element // = false +> +struct dimino_first_step_elements_helper : + public dimino_first_step_elements_helper< + Multiply, + Equality, + id, + g, + typename Multiply::type, + typename concat>::type, + Equality::type, id>::value + > {}; + +template< + template class Multiply, + template class Equality, + typename id, + typename g, + typename current_element, + typename elements +> +struct dimino_first_step_elements_helper +{ + typedef elements type; + constexpr static int global_flags = Equality::global_flags; +}; + +/** \internal + * + * \class dimino_first_step_elements + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Add all powers of the first generator to the list of group elements + * + * This template takes the first non-identity generator and generates the initial + * list of elements which consists of all powers of that generator. For a group + * with just one generated, it would be enumerated after this. + * + * \sa enumerate_group_elements + */ +template< + template class Multiply, + template class Equality, + typename id, + typename generators +> +struct dimino_first_step_elements +{ + typedef typename get<0, generators>::type first_generator; + typedef typename skip<1, generators>::type next_generators; + typedef type_list generators_done; + + typedef dimino_first_step_elements_helper< + Multiply, + Equality, + id, + first_generator, + first_generator, + type_list, + false + > helper; + typedef typename helper::type type; + constexpr static int global_flags = helper::global_flags; +}; + +/** \internal + * + * \class dimino_get_coset_elements + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Generate all elements of a specific coset + * + * This template generates all the elements of a specific coset by + * multiplying all elements in the given subgroup with the new + * coset representative. Note that the first element of the + * subgroup is always the identity element, so the first element of + * ther result of this template is going to be the coset + * representative itself. + * + * Note that this template accepts an additional boolean parameter + * that specifies whether to actually generate the coset (true) or + * just return an empty list (false). + * + * \sa enumerate_group_elements, dimino_add_cosets_for_rep + */ +template< + template class Multiply, + typename sub_group_elements, + typename new_coset_rep, + bool generate_coset // = true +> +struct dimino_get_coset_elements +{ + typedef typename apply_op_from_right::type type; +}; + +template< + template class Multiply, + typename sub_group_elements, + typename new_coset_rep +> +struct dimino_get_coset_elements +{ + typedef type_list<> type; +}; + +/** \internal + * + * \class dimino_add_cosets_for_rep + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Recursive template for adding coset spaces + * + * This template multiplies the coset representative with a generator + * from the list of previous generators. If the new element is not in + * the group already, it adds the corresponding coset. Finally it + * proceeds to call itself with the next generator from the list. + * + * \sa enumerate_group_elements, dimino_add_all_coset_spaces + */ +template< + template class Multiply, + template class Equality, + typename id, + typename sub_group_elements, + typename elements, + typename generators, + typename rep_element, + int sub_group_size +> +struct dimino_add_cosets_for_rep; + +template< + template class Multiply, + template class Equality, + typename id, + typename sub_group_elements, + typename elements, + typename g, + typename... gs, + typename rep_element, + int sub_group_size +> +struct dimino_add_cosets_for_rep, rep_element, sub_group_size> +{ + typedef typename Multiply::type new_coset_rep; + typedef contained_in_list_gf _cil; + constexpr static bool add_coset = !_cil::value; + + typedef typename dimino_get_coset_elements< + Multiply, + sub_group_elements, + new_coset_rep, + add_coset + >::type coset_elements; + + typedef dimino_add_cosets_for_rep< + Multiply, + Equality, + id, + sub_group_elements, + typename concat::type, + type_list, + rep_element, + sub_group_size + > _helper; + + typedef typename _helper::type type; + constexpr static int global_flags = _cil::global_flags | _helper::global_flags; + + /* Note that we don't have to update global flags here, since + * we will only add these elements if they are not part of + * the group already. But that only happens if the coset rep + * is not already in the group, so the check for the coset rep + * will catch this. + */ +}; + +template< + template class Multiply, + template class Equality, + typename id, + typename sub_group_elements, + typename elements + EIGEN_TPL_PP_SPEC_HACK_DEFC(typename, empty), + typename rep_element, + int sub_group_size +> +struct dimino_add_cosets_for_rep, rep_element, sub_group_size> +{ + typedef elements type; + constexpr static int global_flags = 0; +}; + +/** \internal + * + * \class dimino_add_all_coset_spaces + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Recursive template for adding all coset spaces for a new generator + * + * This template tries to go through the list of generators (with + * the help of the dimino_add_cosets_for_rep template) as long as + * it still finds elements that are not part of the group and add + * the corresponding cosets. + * + * \sa enumerate_group_elements, dimino_add_cosets_for_rep + */ +template< + template class Multiply, + template class Equality, + typename id, + typename sub_group_elements, + typename elements, + typename generators, + int sub_group_size, + int rep_pos, + bool stop_condition // = false +> +struct dimino_add_all_coset_spaces +{ + typedef typename get::type rep_element; + typedef dimino_add_cosets_for_rep< + Multiply, + Equality, + id, + sub_group_elements, + elements, + generators, + rep_element, + sub_group_elements::count + > _ac4r; + typedef typename _ac4r::type new_elements; + + constexpr static int new_rep_pos = rep_pos + sub_group_elements::count; + constexpr static bool new_stop_condition = new_rep_pos >= new_elements::count; + + typedef dimino_add_all_coset_spaces< + Multiply, + Equality, + id, + sub_group_elements, + new_elements, + generators, + sub_group_size, + new_rep_pos, + new_stop_condition + > _helper; + + typedef typename _helper::type type; + constexpr static int global_flags = _helper::global_flags | _ac4r::global_flags; +}; + +template< + template class Multiply, + template class Equality, + typename id, + typename sub_group_elements, + typename elements, + typename generators, + int sub_group_size, + int rep_pos +> +struct dimino_add_all_coset_spaces +{ + typedef elements type; + constexpr static int global_flags = 0; +}; + +/** \internal + * + * \class dimino_add_generator + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Enlarge the group by adding a new generator. + * + * It accepts a boolean parameter that determines if the generator is redundant, + * i.e. was already seen in the group. In that case, it reduces to a no-op. + * + * \sa enumerate_group_elements, dimino_add_all_coset_spaces + */ +template< + template class Multiply, + template class Equality, + typename id, + typename elements, + typename generators_done, + typename current_generator, + bool redundant // = false +> +struct dimino_add_generator +{ + /* this template is only called if the generator is not redundant + * => all elements of the group multiplied with the new generator + * are going to be new elements of the most trivial coset space + */ + typedef typename apply_op_from_right::type multiplied_elements; + typedef typename concat::type new_elements; + + constexpr static int rep_pos = elements::count; + + typedef dimino_add_all_coset_spaces< + Multiply, + Equality, + id, + elements, // elements of previous subgroup + new_elements, + typename concat>::type, + elements::count, // size of previous subgroup + rep_pos, + false // don't stop (because rep_pos >= new_elements::count is always false at this point) + > _helper; + typedef typename _helper::type type; + constexpr static int global_flags = _helper::global_flags; +}; + +template< + template class Multiply, + template class Equality, + typename id, + typename elements, + typename generators_done, + typename current_generator +> +struct dimino_add_generator +{ + // redundant case + typedef elements type; + constexpr static int global_flags = 0; +}; + +/** \internal + * + * \class dimino_add_remaining_generators + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Recursive template that adds all remaining generators to a group + * + * Loop through the list of generators that remain and successively + * add them to the group. + * + * \sa enumerate_group_elements, dimino_add_generator + */ +template< + template class Multiply, + template class Equality, + typename id, + typename generators_done, + typename remaining_generators, + typename elements +> +struct dimino_add_remaining_generators +{ + typedef typename get<0, remaining_generators>::type first_generator; + typedef typename skip<1, remaining_generators>::type next_generators; + + typedef contained_in_list_gf _cil; + + typedef dimino_add_generator< + Multiply, + Equality, + id, + elements, + generators_done, + first_generator, + _cil::value + > _helper; + + typedef typename _helper::type new_elements; + + typedef dimino_add_remaining_generators< + Multiply, + Equality, + id, + typename concat>::type, + next_generators, + new_elements + > _next_iter; + + typedef typename _next_iter::type type; + constexpr static int global_flags = + _cil::global_flags | + _helper::global_flags | + _next_iter::global_flags; +}; + +template< + template class Multiply, + template class Equality, + typename id, + typename generators_done, + typename elements +> +struct dimino_add_remaining_generators, elements> +{ + typedef elements type; + constexpr static int global_flags = 0; +}; + +/** \internal + * + * \class enumerate_group_elements_noid + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Helper template that implements group element enumeration + * + * This is a helper template that implements the actual enumeration + * of group elements. This has been split so that the list of + * generators can be cleansed of the identity element before + * performing the actual operation. + * + * \sa enumerate_group_elements + */ +template< + template class Multiply, + template class Equality, + typename id, + typename generators, + int initial_global_flags = 0 +> +struct enumerate_group_elements_noid +{ + typedef dimino_first_step_elements first_step; + typedef typename first_step::type first_step_elements; + + typedef dimino_add_remaining_generators< + Multiply, + Equality, + id, + typename first_step::generators_done, + typename first_step::next_generators, // remaining_generators + typename first_step::type // first_step elements + > _helper; + + typedef typename _helper::type type; + constexpr static int global_flags = + initial_global_flags | + first_step::global_flags | + _helper::global_flags; +}; + +// in case when no generators are specified +template< + template class Multiply, + template class Equality, + typename id, + int initial_global_flags +> +struct enumerate_group_elements_noid, initial_global_flags> +{ + typedef type_list type; + constexpr static int global_flags = initial_global_flags; +}; + +/** \internal + * + * \class enumerate_group_elements + * \ingroup CXX11_TensorSymmetry_Module + * + * \brief Enumerate all elements in a finite group + * + * This template enumerates all elements in a finite group. It accepts + * the following template parameters: + * + * \tparam Multiply The multiplication operation that multiplies two group elements + * with each other. + * \tparam Equality The equality check operation that checks if two group elements + * are equal to another. + * \tparam id The identity element + * \tparam _generators A list of (possibly redundant) generators of the group + */ +template< + template class Multiply, + template class Equality, + typename id, + typename _generators +> +struct enumerate_group_elements + : public enumerate_group_elements_noid< + Multiply, + Equality, + id, + typename strip_identities::type, + strip_identities::global_flags + > +{ +}; + +} // end namespace group_theory + +} // end namespace internal + +} // end namespace Eigen + +#endif // EIGEN_CXX11_TENSORSYMMETRY_TEMPLATEGROUPTHEORY_H + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ diff --git a/unsupported/test/CMakeLists.txt b/unsupported/test/CMakeLists.txt index 61e8f56fd..0a6c56c19 100644 --- a/unsupported/test/CMakeLists.txt +++ b/unsupported/test/CMakeLists.txt @@ -100,4 +100,5 @@ if(EIGEN_TEST_CXX11) # clash there) ei_add_test(cxx11_meta "-std=c++0x") ei_add_test(cxx11_tensor_simple "-std=c++0x") + ei_add_test(cxx11_tensor_symmetry "-std=c++0x") endif() diff --git a/unsupported/test/cxx11_tensor_symmetry.cpp b/unsupported/test/cxx11_tensor_symmetry.cpp new file mode 100644 index 000000000..ebbc8a68d --- /dev/null +++ b/unsupported/test/cxx11_tensor_symmetry.cpp @@ -0,0 +1,819 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008-2009 Gael Guennebaud +// Copyright (C) 2006-2008 Benoit Jacob +// +// 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/. + +#include "main.h" + +#include +#include + +#include +#include + +using Eigen::Tensor; +using Eigen::SGroup; +using Eigen::DynamicSGroup; +using Eigen::StaticSGroup; +using Eigen::Symmetry; +using Eigen::AntiSymmetry; +using Eigen::Hermiticity; +using Eigen::AntiHermiticity; + +using Eigen::NegationFlag; +using Eigen::ConjugationFlag; +using Eigen::GlobalZeroFlag; +using Eigen::GlobalRealFlag; +using Eigen::GlobalImagFlag; + +// helper function to determine if the compiler intantiated a static +// or dynamic symmetry group +template +bool isDynGroup(StaticSGroup const& dummy) +{ + (void)dummy; + return false; +} + +bool isDynGroup(DynamicSGroup const& dummy) +{ + (void)dummy; + return true; +} + +// helper class for checking that the symmetry groups are correct +struct checkIdx { + template + static inline int doCheck_(ArrType e, int flags, int dummy, std::set& found, std::map const& expected) + { + // use decimal representation of value + uint64_t value = e[0]; + for (std::size_t i = 1; i < e.size(); i++) + value = value * 10 + e[i]; + + // we want to make sure that we find each element + auto it = expected.find(value); + VERIFY((it != expected.end())); + VERIFY_IS_EQUAL(it->second, flags); + + // we want to make sure we only have each element once; + // set::insert returns true for the second part of the pair + // if the element was really inserted and not already there + auto p = found.insert(value); + VERIFY((p.second)); + + return dummy; + } + + static inline int run(std::vector e, int flags, int dummy, std::set& found, std::map const& expected) + { + return doCheck_(e, flags, dummy, found, expected); + } + + template + static inline int run(std::array e, int flags, int dummy, std::set& found, std::map const& expected) + { + return doCheck_(e, flags, dummy, found, expected); + } +}; + +static void test_symgroups_static() +{ + std::array identity{{0,1,2,3,4,5,6}}; + + // Simple static symmetry group + StaticSGroup<7, + AntiSymmetry<0,1>, + Hermiticity<0,2> + > group; + + std::set found; + std::map expected; + expected[ 123456] = 0; + expected[1023456] = NegationFlag; + expected[2103456] = ConjugationFlag; + expected[1203456] = ConjugationFlag | NegationFlag; + expected[2013456] = ConjugationFlag | NegationFlag; + expected[ 213456] = ConjugationFlag; + + VERIFY_IS_EQUAL(group.size(), 6u); + VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag); + group.apply(identity, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 6u); +} + +static void test_symgroups_dynamic() +{ + std::vector identity; + for (int i = 0; i <= 6; i++) + identity.push_back(i); + + // Simple dynamic symmetry group + DynamicSGroup group(7); + group.add(0,1,NegationFlag); + group.add(0,2,ConjugationFlag); + + VERIFY_IS_EQUAL(group.size(), 6u); + VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag); + + std::set found; + std::map expected; + expected[ 123456] = 0; + expected[1023456] = NegationFlag; + expected[2103456] = ConjugationFlag; + expected[1203456] = ConjugationFlag | NegationFlag; + expected[2013456] = ConjugationFlag | NegationFlag; + expected[ 213456] = ConjugationFlag; + + VERIFY_IS_EQUAL(group.size(), 6u); + VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag); + group.apply(identity, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 6u); +} + +static void test_symgroups_selection() +{ + std::array identity7{{0,1,2,3,4,5,6}}; + std::array identity10{{0,1,2,3,4,5,6,7,8,9}}; + + { + // Do the same test as in test_symgroups_static but + // require selection via SGroup + SGroup<7, + AntiSymmetry<0,1>, + Hermiticity<0,2> + > group; + + std::set found; + std::map expected; + expected[ 123456] = 0; + expected[1023456] = NegationFlag; + expected[2103456] = ConjugationFlag; + expected[1203456] = ConjugationFlag | NegationFlag; + expected[2013456] = ConjugationFlag | NegationFlag; + expected[ 213456] = ConjugationFlag; + + VERIFY(!isDynGroup(group)); + VERIFY_IS_EQUAL(group.size(), 6u); + VERIFY_IS_EQUAL(group.globalFlags(), GlobalImagFlag); + group.apply(identity7, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 6u); + } + + { + // simple factorizing group: 5 generators, 2^5 = 32 elements + // selection should make this dynamic, although static group + // can still be reasonably generated + SGroup<10, + Symmetry<0,1>, + Symmetry<2,3>, + Symmetry<4,5>, + Symmetry<6,7>, + Symmetry<8,9> + > group; + + std::set found; + std::map expected; + expected[ 123456789] = 0; expected[ 123456798] = 0; expected[ 123457689] = 0; expected[ 123457698] = 0; + expected[ 123546789] = 0; expected[ 123546798] = 0; expected[ 123547689] = 0; expected[ 123547698] = 0; + expected[ 132456789] = 0; expected[ 132456798] = 0; expected[ 132457689] = 0; expected[ 132457698] = 0; + expected[ 132546789] = 0; expected[ 132546798] = 0; expected[ 132547689] = 0; expected[ 132547698] = 0; + expected[1023456789] = 0; expected[1023456798] = 0; expected[1023457689] = 0; expected[1023457698] = 0; + expected[1023546789] = 0; expected[1023546798] = 0; expected[1023547689] = 0; expected[1023547698] = 0; + expected[1032456789] = 0; expected[1032456798] = 0; expected[1032457689] = 0; expected[1032457698] = 0; + expected[1032546789] = 0; expected[1032546798] = 0; expected[1032547689] = 0; expected[1032547698] = 0; + + VERIFY(isDynGroup(group)); + VERIFY_IS_EQUAL(group.size(), 32u); + VERIFY_IS_EQUAL(group.globalFlags(), 0); + group.apply(identity10, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 32u); + + // no verify that we could also generate a static group + // with these generators + found.clear(); + StaticSGroup<10, + Symmetry<0,1>, + Symmetry<2,3>, + Symmetry<4,5>, + Symmetry<6,7>, + Symmetry<8,9> + > group_static; + VERIFY_IS_EQUAL(group_static.size(), 32u); + VERIFY_IS_EQUAL(group_static.globalFlags(), 0); + group_static.apply(identity10, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 32u); + } + + { + // try to create a HUGE group + SGroup<7, + Symmetry<0,1>, + Symmetry<1,2>, + Symmetry<2,3>, + Symmetry<3,4>, + Symmetry<4,5>, + Symmetry<5,6> + > group; + + std::set found; + uint64_t pre_expected[5040] = { + 123456, 1023456, 213456, 2013456, 1203456, 2103456, 132456, 1032456, 312456, 3012456, 1302456, 3102456, + 231456, 2031456, 321456, 3021456, 2301456, 3201456, 1230456, 2130456, 1320456, 3120456, 2310456, 3210456, + 124356, 1024356, 214356, 2014356, 1204356, 2104356, 142356, 1042356, 412356, 4012356, 1402356, 4102356, + 241356, 2041356, 421356, 4021356, 2401356, 4201356, 1240356, 2140356, 1420356, 4120356, 2410356, 4210356, + 134256, 1034256, 314256, 3014256, 1304256, 3104256, 143256, 1043256, 413256, 4013256, 1403256, 4103256, + 341256, 3041256, 431256, 4031256, 3401256, 4301256, 1340256, 3140256, 1430256, 4130256, 3410256, 4310256, + 234156, 2034156, 324156, 3024156, 2304156, 3204156, 243156, 2043156, 423156, 4023156, 2403156, 4203156, + 342156, 3042156, 432156, 4032156, 3402156, 4302156, 2340156, 3240156, 2430156, 4230156, 3420156, 4320156, + 1234056, 2134056, 1324056, 3124056, 2314056, 3214056, 1243056, 2143056, 1423056, 4123056, 2413056, 4213056, + 1342056, 3142056, 1432056, 4132056, 3412056, 4312056, 2341056, 3241056, 2431056, 4231056, 3421056, 4321056, + 123546, 1023546, 213546, 2013546, 1203546, 2103546, 132546, 1032546, 312546, 3012546, 1302546, 3102546, + 231546, 2031546, 321546, 3021546, 2301546, 3201546, 1230546, 2130546, 1320546, 3120546, 2310546, 3210546, + 125346, 1025346, 215346, 2015346, 1205346, 2105346, 152346, 1052346, 512346, 5012346, 1502346, 5102346, + 251346, 2051346, 521346, 5021346, 2501346, 5201346, 1250346, 2150346, 1520346, 5120346, 2510346, 5210346, + 135246, 1035246, 315246, 3015246, 1305246, 3105246, 153246, 1053246, 513246, 5013246, 1503246, 5103246, + 351246, 3051246, 531246, 5031246, 3501246, 5301246, 1350246, 3150246, 1530246, 5130246, 3510246, 5310246, + 235146, 2035146, 325146, 3025146, 2305146, 3205146, 253146, 2053146, 523146, 5023146, 2503146, 5203146, + 352146, 3052146, 532146, 5032146, 3502146, 5302146, 2350146, 3250146, 2530146, 5230146, 3520146, 5320146, + 1235046, 2135046, 1325046, 3125046, 2315046, 3215046, 1253046, 2153046, 1523046, 5123046, 2513046, 5213046, + 1352046, 3152046, 1532046, 5132046, 3512046, 5312046, 2351046, 3251046, 2531046, 5231046, 3521046, 5321046, + 124536, 1024536, 214536, 2014536, 1204536, 2104536, 142536, 1042536, 412536, 4012536, 1402536, 4102536, + 241536, 2041536, 421536, 4021536, 2401536, 4201536, 1240536, 2140536, 1420536, 4120536, 2410536, 4210536, + 125436, 1025436, 215436, 2015436, 1205436, 2105436, 152436, 1052436, 512436, 5012436, 1502436, 5102436, + 251436, 2051436, 521436, 5021436, 2501436, 5201436, 1250436, 2150436, 1520436, 5120436, 2510436, 5210436, + 145236, 1045236, 415236, 4015236, 1405236, 4105236, 154236, 1054236, 514236, 5014236, 1504236, 5104236, + 451236, 4051236, 541236, 5041236, 4501236, 5401236, 1450236, 4150236, 1540236, 5140236, 4510236, 5410236, + 245136, 2045136, 425136, 4025136, 2405136, 4205136, 254136, 2054136, 524136, 5024136, 2504136, 5204136, + 452136, 4052136, 542136, 5042136, 4502136, 5402136, 2450136, 4250136, 2540136, 5240136, 4520136, 5420136, + 1245036, 2145036, 1425036, 4125036, 2415036, 4215036, 1254036, 2154036, 1524036, 5124036, 2514036, 5214036, + 1452036, 4152036, 1542036, 5142036, 4512036, 5412036, 2451036, 4251036, 2541036, 5241036, 4521036, 5421036, + 134526, 1034526, 314526, 3014526, 1304526, 3104526, 143526, 1043526, 413526, 4013526, 1403526, 4103526, + 341526, 3041526, 431526, 4031526, 3401526, 4301526, 1340526, 3140526, 1430526, 4130526, 3410526, 4310526, + 135426, 1035426, 315426, 3015426, 1305426, 3105426, 153426, 1053426, 513426, 5013426, 1503426, 5103426, + 351426, 3051426, 531426, 5031426, 3501426, 5301426, 1350426, 3150426, 1530426, 5130426, 3510426, 5310426, + 145326, 1045326, 415326, 4015326, 1405326, 4105326, 154326, 1054326, 514326, 5014326, 1504326, 5104326, + 451326, 4051326, 541326, 5041326, 4501326, 5401326, 1450326, 4150326, 1540326, 5140326, 4510326, 5410326, + 345126, 3045126, 435126, 4035126, 3405126, 4305126, 354126, 3054126, 534126, 5034126, 3504126, 5304126, + 453126, 4053126, 543126, 5043126, 4503126, 5403126, 3450126, 4350126, 3540126, 5340126, 4530126, 5430126, + 1345026, 3145026, 1435026, 4135026, 3415026, 4315026, 1354026, 3154026, 1534026, 5134026, 3514026, 5314026, + 1453026, 4153026, 1543026, 5143026, 4513026, 5413026, 3451026, 4351026, 3541026, 5341026, 4531026, 5431026, + 234516, 2034516, 324516, 3024516, 2304516, 3204516, 243516, 2043516, 423516, 4023516, 2403516, 4203516, + 342516, 3042516, 432516, 4032516, 3402516, 4302516, 2340516, 3240516, 2430516, 4230516, 3420516, 4320516, + 235416, 2035416, 325416, 3025416, 2305416, 3205416, 253416, 2053416, 523416, 5023416, 2503416, 5203416, + 352416, 3052416, 532416, 5032416, 3502416, 5302416, 2350416, 3250416, 2530416, 5230416, 3520416, 5320416, + 245316, 2045316, 425316, 4025316, 2405316, 4205316, 254316, 2054316, 524316, 5024316, 2504316, 5204316, + 452316, 4052316, 542316, 5042316, 4502316, 5402316, 2450316, 4250316, 2540316, 5240316, 4520316, 5420316, + 345216, 3045216, 435216, 4035216, 3405216, 4305216, 354216, 3054216, 534216, 5034216, 3504216, 5304216, + 453216, 4053216, 543216, 5043216, 4503216, 5403216, 3450216, 4350216, 3540216, 5340216, 4530216, 5430216, + 2345016, 3245016, 2435016, 4235016, 3425016, 4325016, 2354016, 3254016, 2534016, 5234016, 3524016, 5324016, + 2453016, 4253016, 2543016, 5243016, 4523016, 5423016, 3452016, 4352016, 3542016, 5342016, 4532016, 5432016, + 1234506, 2134506, 1324506, 3124506, 2314506, 3214506, 1243506, 2143506, 1423506, 4123506, 2413506, 4213506, + 1342506, 3142506, 1432506, 4132506, 3412506, 4312506, 2341506, 3241506, 2431506, 4231506, 3421506, 4321506, + 1235406, 2135406, 1325406, 3125406, 2315406, 3215406, 1253406, 2153406, 1523406, 5123406, 2513406, 5213406, + 1352406, 3152406, 1532406, 5132406, 3512406, 5312406, 2351406, 3251406, 2531406, 5231406, 3521406, 5321406, + 1245306, 2145306, 1425306, 4125306, 2415306, 4215306, 1254306, 2154306, 1524306, 5124306, 2514306, 5214306, + 1452306, 4152306, 1542306, 5142306, 4512306, 5412306, 2451306, 4251306, 2541306, 5241306, 4521306, 5421306, + 1345206, 3145206, 1435206, 4135206, 3415206, 4315206, 1354206, 3154206, 1534206, 5134206, 3514206, 5314206, + 1453206, 4153206, 1543206, 5143206, 4513206, 5413206, 3451206, 4351206, 3541206, 5341206, 4531206, 5431206, + 2345106, 3245106, 2435106, 4235106, 3425106, 4325106, 2354106, 3254106, 2534106, 5234106, 3524106, 5324106, + 2453106, 4253106, 2543106, 5243106, 4523106, 5423106, 3452106, 4352106, 3542106, 5342106, 4532106, 5432106, + 123465, 1023465, 213465, 2013465, 1203465, 2103465, 132465, 1032465, 312465, 3012465, 1302465, 3102465, + 231465, 2031465, 321465, 3021465, 2301465, 3201465, 1230465, 2130465, 1320465, 3120465, 2310465, 3210465, + 124365, 1024365, 214365, 2014365, 1204365, 2104365, 142365, 1042365, 412365, 4012365, 1402365, 4102365, + 241365, 2041365, 421365, 4021365, 2401365, 4201365, 1240365, 2140365, 1420365, 4120365, 2410365, 4210365, + 134265, 1034265, 314265, 3014265, 1304265, 3104265, 143265, 1043265, 413265, 4013265, 1403265, 4103265, + 341265, 3041265, 431265, 4031265, 3401265, 4301265, 1340265, 3140265, 1430265, 4130265, 3410265, 4310265, + 234165, 2034165, 324165, 3024165, 2304165, 3204165, 243165, 2043165, 423165, 4023165, 2403165, 4203165, + 342165, 3042165, 432165, 4032165, 3402165, 4302165, 2340165, 3240165, 2430165, 4230165, 3420165, 4320165, + 1234065, 2134065, 1324065, 3124065, 2314065, 3214065, 1243065, 2143065, 1423065, 4123065, 2413065, 4213065, + 1342065, 3142065, 1432065, 4132065, 3412065, 4312065, 2341065, 3241065, 2431065, 4231065, 3421065, 4321065, + 123645, 1023645, 213645, 2013645, 1203645, 2103645, 132645, 1032645, 312645, 3012645, 1302645, 3102645, + 231645, 2031645, 321645, 3021645, 2301645, 3201645, 1230645, 2130645, 1320645, 3120645, 2310645, 3210645, + 126345, 1026345, 216345, 2016345, 1206345, 2106345, 162345, 1062345, 612345, 6012345, 1602345, 6102345, + 261345, 2061345, 621345, 6021345, 2601345, 6201345, 1260345, 2160345, 1620345, 6120345, 2610345, 6210345, + 136245, 1036245, 316245, 3016245, 1306245, 3106245, 163245, 1063245, 613245, 6013245, 1603245, 6103245, + 361245, 3061245, 631245, 6031245, 3601245, 6301245, 1360245, 3160245, 1630245, 6130245, 3610245, 6310245, + 236145, 2036145, 326145, 3026145, 2306145, 3206145, 263145, 2063145, 623145, 6023145, 2603145, 6203145, + 362145, 3062145, 632145, 6032145, 3602145, 6302145, 2360145, 3260145, 2630145, 6230145, 3620145, 6320145, + 1236045, 2136045, 1326045, 3126045, 2316045, 3216045, 1263045, 2163045, 1623045, 6123045, 2613045, 6213045, + 1362045, 3162045, 1632045, 6132045, 3612045, 6312045, 2361045, 3261045, 2631045, 6231045, 3621045, 6321045, + 124635, 1024635, 214635, 2014635, 1204635, 2104635, 142635, 1042635, 412635, 4012635, 1402635, 4102635, + 241635, 2041635, 421635, 4021635, 2401635, 4201635, 1240635, 2140635, 1420635, 4120635, 2410635, 4210635, + 126435, 1026435, 216435, 2016435, 1206435, 2106435, 162435, 1062435, 612435, 6012435, 1602435, 6102435, + 261435, 2061435, 621435, 6021435, 2601435, 6201435, 1260435, 2160435, 1620435, 6120435, 2610435, 6210435, + 146235, 1046235, 416235, 4016235, 1406235, 4106235, 164235, 1064235, 614235, 6014235, 1604235, 6104235, + 461235, 4061235, 641235, 6041235, 4601235, 6401235, 1460235, 4160235, 1640235, 6140235, 4610235, 6410235, + 246135, 2046135, 426135, 4026135, 2406135, 4206135, 264135, 2064135, 624135, 6024135, 2604135, 6204135, + 462135, 4062135, 642135, 6042135, 4602135, 6402135, 2460135, 4260135, 2640135, 6240135, 4620135, 6420135, + 1246035, 2146035, 1426035, 4126035, 2416035, 4216035, 1264035, 2164035, 1624035, 6124035, 2614035, 6214035, + 1462035, 4162035, 1642035, 6142035, 4612035, 6412035, 2461035, 4261035, 2641035, 6241035, 4621035, 6421035, + 134625, 1034625, 314625, 3014625, 1304625, 3104625, 143625, 1043625, 413625, 4013625, 1403625, 4103625, + 341625, 3041625, 431625, 4031625, 3401625, 4301625, 1340625, 3140625, 1430625, 4130625, 3410625, 4310625, + 136425, 1036425, 316425, 3016425, 1306425, 3106425, 163425, 1063425, 613425, 6013425, 1603425, 6103425, + 361425, 3061425, 631425, 6031425, 3601425, 6301425, 1360425, 3160425, 1630425, 6130425, 3610425, 6310425, + 146325, 1046325, 416325, 4016325, 1406325, 4106325, 164325, 1064325, 614325, 6014325, 1604325, 6104325, + 461325, 4061325, 641325, 6041325, 4601325, 6401325, 1460325, 4160325, 1640325, 6140325, 4610325, 6410325, + 346125, 3046125, 436125, 4036125, 3406125, 4306125, 364125, 3064125, 634125, 6034125, 3604125, 6304125, + 463125, 4063125, 643125, 6043125, 4603125, 6403125, 3460125, 4360125, 3640125, 6340125, 4630125, 6430125, + 1346025, 3146025, 1436025, 4136025, 3416025, 4316025, 1364025, 3164025, 1634025, 6134025, 3614025, 6314025, + 1463025, 4163025, 1643025, 6143025, 4613025, 6413025, 3461025, 4361025, 3641025, 6341025, 4631025, 6431025, + 234615, 2034615, 324615, 3024615, 2304615, 3204615, 243615, 2043615, 423615, 4023615, 2403615, 4203615, + 342615, 3042615, 432615, 4032615, 3402615, 4302615, 2340615, 3240615, 2430615, 4230615, 3420615, 4320615, + 236415, 2036415, 326415, 3026415, 2306415, 3206415, 263415, 2063415, 623415, 6023415, 2603415, 6203415, + 362415, 3062415, 632415, 6032415, 3602415, 6302415, 2360415, 3260415, 2630415, 6230415, 3620415, 6320415, + 246315, 2046315, 426315, 4026315, 2406315, 4206315, 264315, 2064315, 624315, 6024315, 2604315, 6204315, + 462315, 4062315, 642315, 6042315, 4602315, 6402315, 2460315, 4260315, 2640315, 6240315, 4620315, 6420315, + 346215, 3046215, 436215, 4036215, 3406215, 4306215, 364215, 3064215, 634215, 6034215, 3604215, 6304215, + 463215, 4063215, 643215, 6043215, 4603215, 6403215, 3460215, 4360215, 3640215, 6340215, 4630215, 6430215, + 2346015, 3246015, 2436015, 4236015, 3426015, 4326015, 2364015, 3264015, 2634015, 6234015, 3624015, 6324015, + 2463015, 4263015, 2643015, 6243015, 4623015, 6423015, 3462015, 4362015, 3642015, 6342015, 4632015, 6432015, + 1234605, 2134605, 1324605, 3124605, 2314605, 3214605, 1243605, 2143605, 1423605, 4123605, 2413605, 4213605, + 1342605, 3142605, 1432605, 4132605, 3412605, 4312605, 2341605, 3241605, 2431605, 4231605, 3421605, 4321605, + 1236405, 2136405, 1326405, 3126405, 2316405, 3216405, 1263405, 2163405, 1623405, 6123405, 2613405, 6213405, + 1362405, 3162405, 1632405, 6132405, 3612405, 6312405, 2361405, 3261405, 2631405, 6231405, 3621405, 6321405, + 1246305, 2146305, 1426305, 4126305, 2416305, 4216305, 1264305, 2164305, 1624305, 6124305, 2614305, 6214305, + 1462305, 4162305, 1642305, 6142305, 4612305, 6412305, 2461305, 4261305, 2641305, 6241305, 4621305, 6421305, + 1346205, 3146205, 1436205, 4136205, 3416205, 4316205, 1364205, 3164205, 1634205, 6134205, 3614205, 6314205, + 1463205, 4163205, 1643205, 6143205, 4613205, 6413205, 3461205, 4361205, 3641205, 6341205, 4631205, 6431205, + 2346105, 3246105, 2436105, 4236105, 3426105, 4326105, 2364105, 3264105, 2634105, 6234105, 3624105, 6324105, + 2463105, 4263105, 2643105, 6243105, 4623105, 6423105, 3462105, 4362105, 3642105, 6342105, 4632105, 6432105, + 123564, 1023564, 213564, 2013564, 1203564, 2103564, 132564, 1032564, 312564, 3012564, 1302564, 3102564, + 231564, 2031564, 321564, 3021564, 2301564, 3201564, 1230564, 2130564, 1320564, 3120564, 2310564, 3210564, + 125364, 1025364, 215364, 2015364, 1205364, 2105364, 152364, 1052364, 512364, 5012364, 1502364, 5102364, + 251364, 2051364, 521364, 5021364, 2501364, 5201364, 1250364, 2150364, 1520364, 5120364, 2510364, 5210364, + 135264, 1035264, 315264, 3015264, 1305264, 3105264, 153264, 1053264, 513264, 5013264, 1503264, 5103264, + 351264, 3051264, 531264, 5031264, 3501264, 5301264, 1350264, 3150264, 1530264, 5130264, 3510264, 5310264, + 235164, 2035164, 325164, 3025164, 2305164, 3205164, 253164, 2053164, 523164, 5023164, 2503164, 5203164, + 352164, 3052164, 532164, 5032164, 3502164, 5302164, 2350164, 3250164, 2530164, 5230164, 3520164, 5320164, + 1235064, 2135064, 1325064, 3125064, 2315064, 3215064, 1253064, 2153064, 1523064, 5123064, 2513064, 5213064, + 1352064, 3152064, 1532064, 5132064, 3512064, 5312064, 2351064, 3251064, 2531064, 5231064, 3521064, 5321064, + 123654, 1023654, 213654, 2013654, 1203654, 2103654, 132654, 1032654, 312654, 3012654, 1302654, 3102654, + 231654, 2031654, 321654, 3021654, 2301654, 3201654, 1230654, 2130654, 1320654, 3120654, 2310654, 3210654, + 126354, 1026354, 216354, 2016354, 1206354, 2106354, 162354, 1062354, 612354, 6012354, 1602354, 6102354, + 261354, 2061354, 621354, 6021354, 2601354, 6201354, 1260354, 2160354, 1620354, 6120354, 2610354, 6210354, + 136254, 1036254, 316254, 3016254, 1306254, 3106254, 163254, 1063254, 613254, 6013254, 1603254, 6103254, + 361254, 3061254, 631254, 6031254, 3601254, 6301254, 1360254, 3160254, 1630254, 6130254, 3610254, 6310254, + 236154, 2036154, 326154, 3026154, 2306154, 3206154, 263154, 2063154, 623154, 6023154, 2603154, 6203154, + 362154, 3062154, 632154, 6032154, 3602154, 6302154, 2360154, 3260154, 2630154, 6230154, 3620154, 6320154, + 1236054, 2136054, 1326054, 3126054, 2316054, 3216054, 1263054, 2163054, 1623054, 6123054, 2613054, 6213054, + 1362054, 3162054, 1632054, 6132054, 3612054, 6312054, 2361054, 3261054, 2631054, 6231054, 3621054, 6321054, + 125634, 1025634, 215634, 2015634, 1205634, 2105634, 152634, 1052634, 512634, 5012634, 1502634, 5102634, + 251634, 2051634, 521634, 5021634, 2501634, 5201634, 1250634, 2150634, 1520634, 5120634, 2510634, 5210634, + 126534, 1026534, 216534, 2016534, 1206534, 2106534, 162534, 1062534, 612534, 6012534, 1602534, 6102534, + 261534, 2061534, 621534, 6021534, 2601534, 6201534, 1260534, 2160534, 1620534, 6120534, 2610534, 6210534, + 156234, 1056234, 516234, 5016234, 1506234, 5106234, 165234, 1065234, 615234, 6015234, 1605234, 6105234, + 561234, 5061234, 651234, 6051234, 5601234, 6501234, 1560234, 5160234, 1650234, 6150234, 5610234, 6510234, + 256134, 2056134, 526134, 5026134, 2506134, 5206134, 265134, 2065134, 625134, 6025134, 2605134, 6205134, + 562134, 5062134, 652134, 6052134, 5602134, 6502134, 2560134, 5260134, 2650134, 6250134, 5620134, 6520134, + 1256034, 2156034, 1526034, 5126034, 2516034, 5216034, 1265034, 2165034, 1625034, 6125034, 2615034, 6215034, + 1562034, 5162034, 1652034, 6152034, 5612034, 6512034, 2561034, 5261034, 2651034, 6251034, 5621034, 6521034, + 135624, 1035624, 315624, 3015624, 1305624, 3105624, 153624, 1053624, 513624, 5013624, 1503624, 5103624, + 351624, 3051624, 531624, 5031624, 3501624, 5301624, 1350624, 3150624, 1530624, 5130624, 3510624, 5310624, + 136524, 1036524, 316524, 3016524, 1306524, 3106524, 163524, 1063524, 613524, 6013524, 1603524, 6103524, + 361524, 3061524, 631524, 6031524, 3601524, 6301524, 1360524, 3160524, 1630524, 6130524, 3610524, 6310524, + 156324, 1056324, 516324, 5016324, 1506324, 5106324, 165324, 1065324, 615324, 6015324, 1605324, 6105324, + 561324, 5061324, 651324, 6051324, 5601324, 6501324, 1560324, 5160324, 1650324, 6150324, 5610324, 6510324, + 356124, 3056124, 536124, 5036124, 3506124, 5306124, 365124, 3065124, 635124, 6035124, 3605124, 6305124, + 563124, 5063124, 653124, 6053124, 5603124, 6503124, 3560124, 5360124, 3650124, 6350124, 5630124, 6530124, + 1356024, 3156024, 1536024, 5136024, 3516024, 5316024, 1365024, 3165024, 1635024, 6135024, 3615024, 6315024, + 1563024, 5163024, 1653024, 6153024, 5613024, 6513024, 3561024, 5361024, 3651024, 6351024, 5631024, 6531024, + 235614, 2035614, 325614, 3025614, 2305614, 3205614, 253614, 2053614, 523614, 5023614, 2503614, 5203614, + 352614, 3052614, 532614, 5032614, 3502614, 5302614, 2350614, 3250614, 2530614, 5230614, 3520614, 5320614, + 236514, 2036514, 326514, 3026514, 2306514, 3206514, 263514, 2063514, 623514, 6023514, 2603514, 6203514, + 362514, 3062514, 632514, 6032514, 3602514, 6302514, 2360514, 3260514, 2630514, 6230514, 3620514, 6320514, + 256314, 2056314, 526314, 5026314, 2506314, 5206314, 265314, 2065314, 625314, 6025314, 2605314, 6205314, + 562314, 5062314, 652314, 6052314, 5602314, 6502314, 2560314, 5260314, 2650314, 6250314, 5620314, 6520314, + 356214, 3056214, 536214, 5036214, 3506214, 5306214, 365214, 3065214, 635214, 6035214, 3605214, 6305214, + 563214, 5063214, 653214, 6053214, 5603214, 6503214, 3560214, 5360214, 3650214, 6350214, 5630214, 6530214, + 2356014, 3256014, 2536014, 5236014, 3526014, 5326014, 2365014, 3265014, 2635014, 6235014, 3625014, 6325014, + 2563014, 5263014, 2653014, 6253014, 5623014, 6523014, 3562014, 5362014, 3652014, 6352014, 5632014, 6532014, + 1235604, 2135604, 1325604, 3125604, 2315604, 3215604, 1253604, 2153604, 1523604, 5123604, 2513604, 5213604, + 1352604, 3152604, 1532604, 5132604, 3512604, 5312604, 2351604, 3251604, 2531604, 5231604, 3521604, 5321604, + 1236504, 2136504, 1326504, 3126504, 2316504, 3216504, 1263504, 2163504, 1623504, 6123504, 2613504, 6213504, + 1362504, 3162504, 1632504, 6132504, 3612504, 6312504, 2361504, 3261504, 2631504, 6231504, 3621504, 6321504, + 1256304, 2156304, 1526304, 5126304, 2516304, 5216304, 1265304, 2165304, 1625304, 6125304, 2615304, 6215304, + 1562304, 5162304, 1652304, 6152304, 5612304, 6512304, 2561304, 5261304, 2651304, 6251304, 5621304, 6521304, + 1356204, 3156204, 1536204, 5136204, 3516204, 5316204, 1365204, 3165204, 1635204, 6135204, 3615204, 6315204, + 1563204, 5163204, 1653204, 6153204, 5613204, 6513204, 3561204, 5361204, 3651204, 6351204, 5631204, 6531204, + 2356104, 3256104, 2536104, 5236104, 3526104, 5326104, 2365104, 3265104, 2635104, 6235104, 3625104, 6325104, + 2563104, 5263104, 2653104, 6253104, 5623104, 6523104, 3562104, 5362104, 3652104, 6352104, 5632104, 6532104, + 124563, 1024563, 214563, 2014563, 1204563, 2104563, 142563, 1042563, 412563, 4012563, 1402563, 4102563, + 241563, 2041563, 421563, 4021563, 2401563, 4201563, 1240563, 2140563, 1420563, 4120563, 2410563, 4210563, + 125463, 1025463, 215463, 2015463, 1205463, 2105463, 152463, 1052463, 512463, 5012463, 1502463, 5102463, + 251463, 2051463, 521463, 5021463, 2501463, 5201463, 1250463, 2150463, 1520463, 5120463, 2510463, 5210463, + 145263, 1045263, 415263, 4015263, 1405263, 4105263, 154263, 1054263, 514263, 5014263, 1504263, 5104263, + 451263, 4051263, 541263, 5041263, 4501263, 5401263, 1450263, 4150263, 1540263, 5140263, 4510263, 5410263, + 245163, 2045163, 425163, 4025163, 2405163, 4205163, 254163, 2054163, 524163, 5024163, 2504163, 5204163, + 452163, 4052163, 542163, 5042163, 4502163, 5402163, 2450163, 4250163, 2540163, 5240163, 4520163, 5420163, + 1245063, 2145063, 1425063, 4125063, 2415063, 4215063, 1254063, 2154063, 1524063, 5124063, 2514063, 5214063, + 1452063, 4152063, 1542063, 5142063, 4512063, 5412063, 2451063, 4251063, 2541063, 5241063, 4521063, 5421063, + 124653, 1024653, 214653, 2014653, 1204653, 2104653, 142653, 1042653, 412653, 4012653, 1402653, 4102653, + 241653, 2041653, 421653, 4021653, 2401653, 4201653, 1240653, 2140653, 1420653, 4120653, 2410653, 4210653, + 126453, 1026453, 216453, 2016453, 1206453, 2106453, 162453, 1062453, 612453, 6012453, 1602453, 6102453, + 261453, 2061453, 621453, 6021453, 2601453, 6201453, 1260453, 2160453, 1620453, 6120453, 2610453, 6210453, + 146253, 1046253, 416253, 4016253, 1406253, 4106253, 164253, 1064253, 614253, 6014253, 1604253, 6104253, + 461253, 4061253, 641253, 6041253, 4601253, 6401253, 1460253, 4160253, 1640253, 6140253, 4610253, 6410253, + 246153, 2046153, 426153, 4026153, 2406153, 4206153, 264153, 2064153, 624153, 6024153, 2604153, 6204153, + 462153, 4062153, 642153, 6042153, 4602153, 6402153, 2460153, 4260153, 2640153, 6240153, 4620153, 6420153, + 1246053, 2146053, 1426053, 4126053, 2416053, 4216053, 1264053, 2164053, 1624053, 6124053, 2614053, 6214053, + 1462053, 4162053, 1642053, 6142053, 4612053, 6412053, 2461053, 4261053, 2641053, 6241053, 4621053, 6421053, + 125643, 1025643, 215643, 2015643, 1205643, 2105643, 152643, 1052643, 512643, 5012643, 1502643, 5102643, + 251643, 2051643, 521643, 5021643, 2501643, 5201643, 1250643, 2150643, 1520643, 5120643, 2510643, 5210643, + 126543, 1026543, 216543, 2016543, 1206543, 2106543, 162543, 1062543, 612543, 6012543, 1602543, 6102543, + 261543, 2061543, 621543, 6021543, 2601543, 6201543, 1260543, 2160543, 1620543, 6120543, 2610543, 6210543, + 156243, 1056243, 516243, 5016243, 1506243, 5106243, 165243, 1065243, 615243, 6015243, 1605243, 6105243, + 561243, 5061243, 651243, 6051243, 5601243, 6501243, 1560243, 5160243, 1650243, 6150243, 5610243, 6510243, + 256143, 2056143, 526143, 5026143, 2506143, 5206143, 265143, 2065143, 625143, 6025143, 2605143, 6205143, + 562143, 5062143, 652143, 6052143, 5602143, 6502143, 2560143, 5260143, 2650143, 6250143, 5620143, 6520143, + 1256043, 2156043, 1526043, 5126043, 2516043, 5216043, 1265043, 2165043, 1625043, 6125043, 2615043, 6215043, + 1562043, 5162043, 1652043, 6152043, 5612043, 6512043, 2561043, 5261043, 2651043, 6251043, 5621043, 6521043, + 145623, 1045623, 415623, 4015623, 1405623, 4105623, 154623, 1054623, 514623, 5014623, 1504623, 5104623, + 451623, 4051623, 541623, 5041623, 4501623, 5401623, 1450623, 4150623, 1540623, 5140623, 4510623, 5410623, + 146523, 1046523, 416523, 4016523, 1406523, 4106523, 164523, 1064523, 614523, 6014523, 1604523, 6104523, + 461523, 4061523, 641523, 6041523, 4601523, 6401523, 1460523, 4160523, 1640523, 6140523, 4610523, 6410523, + 156423, 1056423, 516423, 5016423, 1506423, 5106423, 165423, 1065423, 615423, 6015423, 1605423, 6105423, + 561423, 5061423, 651423, 6051423, 5601423, 6501423, 1560423, 5160423, 1650423, 6150423, 5610423, 6510423, + 456123, 4056123, 546123, 5046123, 4506123, 5406123, 465123, 4065123, 645123, 6045123, 4605123, 6405123, + 564123, 5064123, 654123, 6054123, 5604123, 6504123, 4560123, 5460123, 4650123, 6450123, 5640123, 6540123, + 1456023, 4156023, 1546023, 5146023, 4516023, 5416023, 1465023, 4165023, 1645023, 6145023, 4615023, 6415023, + 1564023, 5164023, 1654023, 6154023, 5614023, 6514023, 4561023, 5461023, 4651023, 6451023, 5641023, 6541023, + 245613, 2045613, 425613, 4025613, 2405613, 4205613, 254613, 2054613, 524613, 5024613, 2504613, 5204613, + 452613, 4052613, 542613, 5042613, 4502613, 5402613, 2450613, 4250613, 2540613, 5240613, 4520613, 5420613, + 246513, 2046513, 426513, 4026513, 2406513, 4206513, 264513, 2064513, 624513, 6024513, 2604513, 6204513, + 462513, 4062513, 642513, 6042513, 4602513, 6402513, 2460513, 4260513, 2640513, 6240513, 4620513, 6420513, + 256413, 2056413, 526413, 5026413, 2506413, 5206413, 265413, 2065413, 625413, 6025413, 2605413, 6205413, + 562413, 5062413, 652413, 6052413, 5602413, 6502413, 2560413, 5260413, 2650413, 6250413, 5620413, 6520413, + 456213, 4056213, 546213, 5046213, 4506213, 5406213, 465213, 4065213, 645213, 6045213, 4605213, 6405213, + 564213, 5064213, 654213, 6054213, 5604213, 6504213, 4560213, 5460213, 4650213, 6450213, 5640213, 6540213, + 2456013, 4256013, 2546013, 5246013, 4526013, 5426013, 2465013, 4265013, 2645013, 6245013, 4625013, 6425013, + 2564013, 5264013, 2654013, 6254013, 5624013, 6524013, 4562013, 5462013, 4652013, 6452013, 5642013, 6542013, + 1245603, 2145603, 1425603, 4125603, 2415603, 4215603, 1254603, 2154603, 1524603, 5124603, 2514603, 5214603, + 1452603, 4152603, 1542603, 5142603, 4512603, 5412603, 2451603, 4251603, 2541603, 5241603, 4521603, 5421603, + 1246503, 2146503, 1426503, 4126503, 2416503, 4216503, 1264503, 2164503, 1624503, 6124503, 2614503, 6214503, + 1462503, 4162503, 1642503, 6142503, 4612503, 6412503, 2461503, 4261503, 2641503, 6241503, 4621503, 6421503, + 1256403, 2156403, 1526403, 5126403, 2516403, 5216403, 1265403, 2165403, 1625403, 6125403, 2615403, 6215403, + 1562403, 5162403, 1652403, 6152403, 5612403, 6512403, 2561403, 5261403, 2651403, 6251403, 5621403, 6521403, + 1456203, 4156203, 1546203, 5146203, 4516203, 5416203, 1465203, 4165203, 1645203, 6145203, 4615203, 6415203, + 1564203, 5164203, 1654203, 6154203, 5614203, 6514203, 4561203, 5461203, 4651203, 6451203, 5641203, 6541203, + 2456103, 4256103, 2546103, 5246103, 4526103, 5426103, 2465103, 4265103, 2645103, 6245103, 4625103, 6425103, + 2564103, 5264103, 2654103, 6254103, 5624103, 6524103, 4562103, 5462103, 4652103, 6452103, 5642103, 6542103, + 134562, 1034562, 314562, 3014562, 1304562, 3104562, 143562, 1043562, 413562, 4013562, 1403562, 4103562, + 341562, 3041562, 431562, 4031562, 3401562, 4301562, 1340562, 3140562, 1430562, 4130562, 3410562, 4310562, + 135462, 1035462, 315462, 3015462, 1305462, 3105462, 153462, 1053462, 513462, 5013462, 1503462, 5103462, + 351462, 3051462, 531462, 5031462, 3501462, 5301462, 1350462, 3150462, 1530462, 5130462, 3510462, 5310462, + 145362, 1045362, 415362, 4015362, 1405362, 4105362, 154362, 1054362, 514362, 5014362, 1504362, 5104362, + 451362, 4051362, 541362, 5041362, 4501362, 5401362, 1450362, 4150362, 1540362, 5140362, 4510362, 5410362, + 345162, 3045162, 435162, 4035162, 3405162, 4305162, 354162, 3054162, 534162, 5034162, 3504162, 5304162, + 453162, 4053162, 543162, 5043162, 4503162, 5403162, 3450162, 4350162, 3540162, 5340162, 4530162, 5430162, + 1345062, 3145062, 1435062, 4135062, 3415062, 4315062, 1354062, 3154062, 1534062, 5134062, 3514062, 5314062, + 1453062, 4153062, 1543062, 5143062, 4513062, 5413062, 3451062, 4351062, 3541062, 5341062, 4531062, 5431062, + 134652, 1034652, 314652, 3014652, 1304652, 3104652, 143652, 1043652, 413652, 4013652, 1403652, 4103652, + 341652, 3041652, 431652, 4031652, 3401652, 4301652, 1340652, 3140652, 1430652, 4130652, 3410652, 4310652, + 136452, 1036452, 316452, 3016452, 1306452, 3106452, 163452, 1063452, 613452, 6013452, 1603452, 6103452, + 361452, 3061452, 631452, 6031452, 3601452, 6301452, 1360452, 3160452, 1630452, 6130452, 3610452, 6310452, + 146352, 1046352, 416352, 4016352, 1406352, 4106352, 164352, 1064352, 614352, 6014352, 1604352, 6104352, + 461352, 4061352, 641352, 6041352, 4601352, 6401352, 1460352, 4160352, 1640352, 6140352, 4610352, 6410352, + 346152, 3046152, 436152, 4036152, 3406152, 4306152, 364152, 3064152, 634152, 6034152, 3604152, 6304152, + 463152, 4063152, 643152, 6043152, 4603152, 6403152, 3460152, 4360152, 3640152, 6340152, 4630152, 6430152, + 1346052, 3146052, 1436052, 4136052, 3416052, 4316052, 1364052, 3164052, 1634052, 6134052, 3614052, 6314052, + 1463052, 4163052, 1643052, 6143052, 4613052, 6413052, 3461052, 4361052, 3641052, 6341052, 4631052, 6431052, + 135642, 1035642, 315642, 3015642, 1305642, 3105642, 153642, 1053642, 513642, 5013642, 1503642, 5103642, + 351642, 3051642, 531642, 5031642, 3501642, 5301642, 1350642, 3150642, 1530642, 5130642, 3510642, 5310642, + 136542, 1036542, 316542, 3016542, 1306542, 3106542, 163542, 1063542, 613542, 6013542, 1603542, 6103542, + 361542, 3061542, 631542, 6031542, 3601542, 6301542, 1360542, 3160542, 1630542, 6130542, 3610542, 6310542, + 156342, 1056342, 516342, 5016342, 1506342, 5106342, 165342, 1065342, 615342, 6015342, 1605342, 6105342, + 561342, 5061342, 651342, 6051342, 5601342, 6501342, 1560342, 5160342, 1650342, 6150342, 5610342, 6510342, + 356142, 3056142, 536142, 5036142, 3506142, 5306142, 365142, 3065142, 635142, 6035142, 3605142, 6305142, + 563142, 5063142, 653142, 6053142, 5603142, 6503142, 3560142, 5360142, 3650142, 6350142, 5630142, 6530142, + 1356042, 3156042, 1536042, 5136042, 3516042, 5316042, 1365042, 3165042, 1635042, 6135042, 3615042, 6315042, + 1563042, 5163042, 1653042, 6153042, 5613042, 6513042, 3561042, 5361042, 3651042, 6351042, 5631042, 6531042, + 145632, 1045632, 415632, 4015632, 1405632, 4105632, 154632, 1054632, 514632, 5014632, 1504632, 5104632, + 451632, 4051632, 541632, 5041632, 4501632, 5401632, 1450632, 4150632, 1540632, 5140632, 4510632, 5410632, + 146532, 1046532, 416532, 4016532, 1406532, 4106532, 164532, 1064532, 614532, 6014532, 1604532, 6104532, + 461532, 4061532, 641532, 6041532, 4601532, 6401532, 1460532, 4160532, 1640532, 6140532, 4610532, 6410532, + 156432, 1056432, 516432, 5016432, 1506432, 5106432, 165432, 1065432, 615432, 6015432, 1605432, 6105432, + 561432, 5061432, 651432, 6051432, 5601432, 6501432, 1560432, 5160432, 1650432, 6150432, 5610432, 6510432, + 456132, 4056132, 546132, 5046132, 4506132, 5406132, 465132, 4065132, 645132, 6045132, 4605132, 6405132, + 564132, 5064132, 654132, 6054132, 5604132, 6504132, 4560132, 5460132, 4650132, 6450132, 5640132, 6540132, + 1456032, 4156032, 1546032, 5146032, 4516032, 5416032, 1465032, 4165032, 1645032, 6145032, 4615032, 6415032, + 1564032, 5164032, 1654032, 6154032, 5614032, 6514032, 4561032, 5461032, 4651032, 6451032, 5641032, 6541032, + 345612, 3045612, 435612, 4035612, 3405612, 4305612, 354612, 3054612, 534612, 5034612, 3504612, 5304612, + 453612, 4053612, 543612, 5043612, 4503612, 5403612, 3450612, 4350612, 3540612, 5340612, 4530612, 5430612, + 346512, 3046512, 436512, 4036512, 3406512, 4306512, 364512, 3064512, 634512, 6034512, 3604512, 6304512, + 463512, 4063512, 643512, 6043512, 4603512, 6403512, 3460512, 4360512, 3640512, 6340512, 4630512, 6430512, + 356412, 3056412, 536412, 5036412, 3506412, 5306412, 365412, 3065412, 635412, 6035412, 3605412, 6305412, + 563412, 5063412, 653412, 6053412, 5603412, 6503412, 3560412, 5360412, 3650412, 6350412, 5630412, 6530412, + 456312, 4056312, 546312, 5046312, 4506312, 5406312, 465312, 4065312, 645312, 6045312, 4605312, 6405312, + 564312, 5064312, 654312, 6054312, 5604312, 6504312, 4560312, 5460312, 4650312, 6450312, 5640312, 6540312, + 3456012, 4356012, 3546012, 5346012, 4536012, 5436012, 3465012, 4365012, 3645012, 6345012, 4635012, 6435012, + 3564012, 5364012, 3654012, 6354012, 5634012, 6534012, 4563012, 5463012, 4653012, 6453012, 5643012, 6543012, + 1345602, 3145602, 1435602, 4135602, 3415602, 4315602, 1354602, 3154602, 1534602, 5134602, 3514602, 5314602, + 1453602, 4153602, 1543602, 5143602, 4513602, 5413602, 3451602, 4351602, 3541602, 5341602, 4531602, 5431602, + 1346502, 3146502, 1436502, 4136502, 3416502, 4316502, 1364502, 3164502, 1634502, 6134502, 3614502, 6314502, + 1463502, 4163502, 1643502, 6143502, 4613502, 6413502, 3461502, 4361502, 3641502, 6341502, 4631502, 6431502, + 1356402, 3156402, 1536402, 5136402, 3516402, 5316402, 1365402, 3165402, 1635402, 6135402, 3615402, 6315402, + 1563402, 5163402, 1653402, 6153402, 5613402, 6513402, 3561402, 5361402, 3651402, 6351402, 5631402, 6531402, + 1456302, 4156302, 1546302, 5146302, 4516302, 5416302, 1465302, 4165302, 1645302, 6145302, 4615302, 6415302, + 1564302, 5164302, 1654302, 6154302, 5614302, 6514302, 4561302, 5461302, 4651302, 6451302, 5641302, 6541302, + 3456102, 4356102, 3546102, 5346102, 4536102, 5436102, 3465102, 4365102, 3645102, 6345102, 4635102, 6435102, + 3564102, 5364102, 3654102, 6354102, 5634102, 6534102, 4563102, 5463102, 4653102, 6453102, 5643102, 6543102, + 234561, 2034561, 324561, 3024561, 2304561, 3204561, 243561, 2043561, 423561, 4023561, 2403561, 4203561, + 342561, 3042561, 432561, 4032561, 3402561, 4302561, 2340561, 3240561, 2430561, 4230561, 3420561, 4320561, + 235461, 2035461, 325461, 3025461, 2305461, 3205461, 253461, 2053461, 523461, 5023461, 2503461, 5203461, + 352461, 3052461, 532461, 5032461, 3502461, 5302461, 2350461, 3250461, 2530461, 5230461, 3520461, 5320461, + 245361, 2045361, 425361, 4025361, 2405361, 4205361, 254361, 2054361, 524361, 5024361, 2504361, 5204361, + 452361, 4052361, 542361, 5042361, 4502361, 5402361, 2450361, 4250361, 2540361, 5240361, 4520361, 5420361, + 345261, 3045261, 435261, 4035261, 3405261, 4305261, 354261, 3054261, 534261, 5034261, 3504261, 5304261, + 453261, 4053261, 543261, 5043261, 4503261, 5403261, 3450261, 4350261, 3540261, 5340261, 4530261, 5430261, + 2345061, 3245061, 2435061, 4235061, 3425061, 4325061, 2354061, 3254061, 2534061, 5234061, 3524061, 5324061, + 2453061, 4253061, 2543061, 5243061, 4523061, 5423061, 3452061, 4352061, 3542061, 5342061, 4532061, 5432061, + 234651, 2034651, 324651, 3024651, 2304651, 3204651, 243651, 2043651, 423651, 4023651, 2403651, 4203651, + 342651, 3042651, 432651, 4032651, 3402651, 4302651, 2340651, 3240651, 2430651, 4230651, 3420651, 4320651, + 236451, 2036451, 326451, 3026451, 2306451, 3206451, 263451, 2063451, 623451, 6023451, 2603451, 6203451, + 362451, 3062451, 632451, 6032451, 3602451, 6302451, 2360451, 3260451, 2630451, 6230451, 3620451, 6320451, + 246351, 2046351, 426351, 4026351, 2406351, 4206351, 264351, 2064351, 624351, 6024351, 2604351, 6204351, + 462351, 4062351, 642351, 6042351, 4602351, 6402351, 2460351, 4260351, 2640351, 6240351, 4620351, 6420351, + 346251, 3046251, 436251, 4036251, 3406251, 4306251, 364251, 3064251, 634251, 6034251, 3604251, 6304251, + 463251, 4063251, 643251, 6043251, 4603251, 6403251, 3460251, 4360251, 3640251, 6340251, 4630251, 6430251, + 2346051, 3246051, 2436051, 4236051, 3426051, 4326051, 2364051, 3264051, 2634051, 6234051, 3624051, 6324051, + 2463051, 4263051, 2643051, 6243051, 4623051, 6423051, 3462051, 4362051, 3642051, 6342051, 4632051, 6432051, + 235641, 2035641, 325641, 3025641, 2305641, 3205641, 253641, 2053641, 523641, 5023641, 2503641, 5203641, + 352641, 3052641, 532641, 5032641, 3502641, 5302641, 2350641, 3250641, 2530641, 5230641, 3520641, 5320641, + 236541, 2036541, 326541, 3026541, 2306541, 3206541, 263541, 2063541, 623541, 6023541, 2603541, 6203541, + 362541, 3062541, 632541, 6032541, 3602541, 6302541, 2360541, 3260541, 2630541, 6230541, 3620541, 6320541, + 256341, 2056341, 526341, 5026341, 2506341, 5206341, 265341, 2065341, 625341, 6025341, 2605341, 6205341, + 562341, 5062341, 652341, 6052341, 5602341, 6502341, 2560341, 5260341, 2650341, 6250341, 5620341, 6520341, + 356241, 3056241, 536241, 5036241, 3506241, 5306241, 365241, 3065241, 635241, 6035241, 3605241, 6305241, + 563241, 5063241, 653241, 6053241, 5603241, 6503241, 3560241, 5360241, 3650241, 6350241, 5630241, 6530241, + 2356041, 3256041, 2536041, 5236041, 3526041, 5326041, 2365041, 3265041, 2635041, 6235041, 3625041, 6325041, + 2563041, 5263041, 2653041, 6253041, 5623041, 6523041, 3562041, 5362041, 3652041, 6352041, 5632041, 6532041, + 245631, 2045631, 425631, 4025631, 2405631, 4205631, 254631, 2054631, 524631, 5024631, 2504631, 5204631, + 452631, 4052631, 542631, 5042631, 4502631, 5402631, 2450631, 4250631, 2540631, 5240631, 4520631, 5420631, + 246531, 2046531, 426531, 4026531, 2406531, 4206531, 264531, 2064531, 624531, 6024531, 2604531, 6204531, + 462531, 4062531, 642531, 6042531, 4602531, 6402531, 2460531, 4260531, 2640531, 6240531, 4620531, 6420531, + 256431, 2056431, 526431, 5026431, 2506431, 5206431, 265431, 2065431, 625431, 6025431, 2605431, 6205431, + 562431, 5062431, 652431, 6052431, 5602431, 6502431, 2560431, 5260431, 2650431, 6250431, 5620431, 6520431, + 456231, 4056231, 546231, 5046231, 4506231, 5406231, 465231, 4065231, 645231, 6045231, 4605231, 6405231, + 564231, 5064231, 654231, 6054231, 5604231, 6504231, 4560231, 5460231, 4650231, 6450231, 5640231, 6540231, + 2456031, 4256031, 2546031, 5246031, 4526031, 5426031, 2465031, 4265031, 2645031, 6245031, 4625031, 6425031, + 2564031, 5264031, 2654031, 6254031, 5624031, 6524031, 4562031, 5462031, 4652031, 6452031, 5642031, 6542031, + 345621, 3045621, 435621, 4035621, 3405621, 4305621, 354621, 3054621, 534621, 5034621, 3504621, 5304621, + 453621, 4053621, 543621, 5043621, 4503621, 5403621, 3450621, 4350621, 3540621, 5340621, 4530621, 5430621, + 346521, 3046521, 436521, 4036521, 3406521, 4306521, 364521, 3064521, 634521, 6034521, 3604521, 6304521, + 463521, 4063521, 643521, 6043521, 4603521, 6403521, 3460521, 4360521, 3640521, 6340521, 4630521, 6430521, + 356421, 3056421, 536421, 5036421, 3506421, 5306421, 365421, 3065421, 635421, 6035421, 3605421, 6305421, + 563421, 5063421, 653421, 6053421, 5603421, 6503421, 3560421, 5360421, 3650421, 6350421, 5630421, 6530421, + 456321, 4056321, 546321, 5046321, 4506321, 5406321, 465321, 4065321, 645321, 6045321, 4605321, 6405321, + 564321, 5064321, 654321, 6054321, 5604321, 6504321, 4560321, 5460321, 4650321, 6450321, 5640321, 6540321, + 3456021, 4356021, 3546021, 5346021, 4536021, 5436021, 3465021, 4365021, 3645021, 6345021, 4635021, 6435021, + 3564021, 5364021, 3654021, 6354021, 5634021, 6534021, 4563021, 5463021, 4653021, 6453021, 5643021, 6543021, + 2345601, 3245601, 2435601, 4235601, 3425601, 4325601, 2354601, 3254601, 2534601, 5234601, 3524601, 5324601, + 2453601, 4253601, 2543601, 5243601, 4523601, 5423601, 3452601, 4352601, 3542601, 5342601, 4532601, 5432601, + 2346501, 3246501, 2436501, 4236501, 3426501, 4326501, 2364501, 3264501, 2634501, 6234501, 3624501, 6324501, + 2463501, 4263501, 2643501, 6243501, 4623501, 6423501, 3462501, 4362501, 3642501, 6342501, 4632501, 6432501, + 2356401, 3256401, 2536401, 5236401, 3526401, 5326401, 2365401, 3265401, 2635401, 6235401, 3625401, 6325401, + 2563401, 5263401, 2653401, 6253401, 5623401, 6523401, 3562401, 5362401, 3652401, 6352401, 5632401, 6532401, + 2456301, 4256301, 2546301, 5246301, 4526301, 5426301, 2465301, 4265301, 2645301, 6245301, 4625301, 6425301, + 2564301, 5264301, 2654301, 6254301, 5624301, 6524301, 4562301, 5462301, 4652301, 6452301, 5642301, 6542301, + 3456201, 4356201, 3546201, 5346201, 4536201, 5436201, 3465201, 4365201, 3645201, 6345201, 4635201, 6435201, + 3564201, 5364201, 3654201, 6354201, 5634201, 6534201, 4563201, 5463201, 4653201, 6453201, 5643201, 6543201, + 1234560, 2134560, 1324560, 3124560, 2314560, 3214560, 1243560, 2143560, 1423560, 4123560, 2413560, 4213560, + 1342560, 3142560, 1432560, 4132560, 3412560, 4312560, 2341560, 3241560, 2431560, 4231560, 3421560, 4321560, + 1235460, 2135460, 1325460, 3125460, 2315460, 3215460, 1253460, 2153460, 1523460, 5123460, 2513460, 5213460, + 1352460, 3152460, 1532460, 5132460, 3512460, 5312460, 2351460, 3251460, 2531460, 5231460, 3521460, 5321460, + 1245360, 2145360, 1425360, 4125360, 2415360, 4215360, 1254360, 2154360, 1524360, 5124360, 2514360, 5214360, + 1452360, 4152360, 1542360, 5142360, 4512360, 5412360, 2451360, 4251360, 2541360, 5241360, 4521360, 5421360, + 1345260, 3145260, 1435260, 4135260, 3415260, 4315260, 1354260, 3154260, 1534260, 5134260, 3514260, 5314260, + 1453260, 4153260, 1543260, 5143260, 4513260, 5413260, 3451260, 4351260, 3541260, 5341260, 4531260, 5431260, + 2345160, 3245160, 2435160, 4235160, 3425160, 4325160, 2354160, 3254160, 2534160, 5234160, 3524160, 5324160, + 2453160, 4253160, 2543160, 5243160, 4523160, 5423160, 3452160, 4352160, 3542160, 5342160, 4532160, 5432160, + 1234650, 2134650, 1324650, 3124650, 2314650, 3214650, 1243650, 2143650, 1423650, 4123650, 2413650, 4213650, + 1342650, 3142650, 1432650, 4132650, 3412650, 4312650, 2341650, 3241650, 2431650, 4231650, 3421650, 4321650, + 1236450, 2136450, 1326450, 3126450, 2316450, 3216450, 1263450, 2163450, 1623450, 6123450, 2613450, 6213450, + 1362450, 3162450, 1632450, 6132450, 3612450, 6312450, 2361450, 3261450, 2631450, 6231450, 3621450, 6321450, + 1246350, 2146350, 1426350, 4126350, 2416350, 4216350, 1264350, 2164350, 1624350, 6124350, 2614350, 6214350, + 1462350, 4162350, 1642350, 6142350, 4612350, 6412350, 2461350, 4261350, 2641350, 6241350, 4621350, 6421350, + 1346250, 3146250, 1436250, 4136250, 3416250, 4316250, 1364250, 3164250, 1634250, 6134250, 3614250, 6314250, + 1463250, 4163250, 1643250, 6143250, 4613250, 6413250, 3461250, 4361250, 3641250, 6341250, 4631250, 6431250, + 2346150, 3246150, 2436150, 4236150, 3426150, 4326150, 2364150, 3264150, 2634150, 6234150, 3624150, 6324150, + 2463150, 4263150, 2643150, 6243150, 4623150, 6423150, 3462150, 4362150, 3642150, 6342150, 4632150, 6432150, + 1235640, 2135640, 1325640, 3125640, 2315640, 3215640, 1253640, 2153640, 1523640, 5123640, 2513640, 5213640, + 1352640, 3152640, 1532640, 5132640, 3512640, 5312640, 2351640, 3251640, 2531640, 5231640, 3521640, 5321640, + 1236540, 2136540, 1326540, 3126540, 2316540, 3216540, 1263540, 2163540, 1623540, 6123540, 2613540, 6213540, + 1362540, 3162540, 1632540, 6132540, 3612540, 6312540, 2361540, 3261540, 2631540, 6231540, 3621540, 6321540, + 1256340, 2156340, 1526340, 5126340, 2516340, 5216340, 1265340, 2165340, 1625340, 6125340, 2615340, 6215340, + 1562340, 5162340, 1652340, 6152340, 5612340, 6512340, 2561340, 5261340, 2651340, 6251340, 5621340, 6521340, + 1356240, 3156240, 1536240, 5136240, 3516240, 5316240, 1365240, 3165240, 1635240, 6135240, 3615240, 6315240, + 1563240, 5163240, 1653240, 6153240, 5613240, 6513240, 3561240, 5361240, 3651240, 6351240, 5631240, 6531240, + 2356140, 3256140, 2536140, 5236140, 3526140, 5326140, 2365140, 3265140, 2635140, 6235140, 3625140, 6325140, + 2563140, 5263140, 2653140, 6253140, 5623140, 6523140, 3562140, 5362140, 3652140, 6352140, 5632140, 6532140, + 1245630, 2145630, 1425630, 4125630, 2415630, 4215630, 1254630, 2154630, 1524630, 5124630, 2514630, 5214630, + 1452630, 4152630, 1542630, 5142630, 4512630, 5412630, 2451630, 4251630, 2541630, 5241630, 4521630, 5421630, + 1246530, 2146530, 1426530, 4126530, 2416530, 4216530, 1264530, 2164530, 1624530, 6124530, 2614530, 6214530, + 1462530, 4162530, 1642530, 6142530, 4612530, 6412530, 2461530, 4261530, 2641530, 6241530, 4621530, 6421530, + 1256430, 2156430, 1526430, 5126430, 2516430, 5216430, 1265430, 2165430, 1625430, 6125430, 2615430, 6215430, + 1562430, 5162430, 1652430, 6152430, 5612430, 6512430, 2561430, 5261430, 2651430, 6251430, 5621430, 6521430, + 1456230, 4156230, 1546230, 5146230, 4516230, 5416230, 1465230, 4165230, 1645230, 6145230, 4615230, 6415230, + 1564230, 5164230, 1654230, 6154230, 5614230, 6514230, 4561230, 5461230, 4651230, 6451230, 5641230, 6541230, + 2456130, 4256130, 2546130, 5246130, 4526130, 5426130, 2465130, 4265130, 2645130, 6245130, 4625130, 6425130, + 2564130, 5264130, 2654130, 6254130, 5624130, 6524130, 4562130, 5462130, 4652130, 6452130, 5642130, 6542130, + 1345620, 3145620, 1435620, 4135620, 3415620, 4315620, 1354620, 3154620, 1534620, 5134620, 3514620, 5314620, + 1453620, 4153620, 1543620, 5143620, 4513620, 5413620, 3451620, 4351620, 3541620, 5341620, 4531620, 5431620, + 1346520, 3146520, 1436520, 4136520, 3416520, 4316520, 1364520, 3164520, 1634520, 6134520, 3614520, 6314520, + 1463520, 4163520, 1643520, 6143520, 4613520, 6413520, 3461520, 4361520, 3641520, 6341520, 4631520, 6431520, + 1356420, 3156420, 1536420, 5136420, 3516420, 5316420, 1365420, 3165420, 1635420, 6135420, 3615420, 6315420, + 1563420, 5163420, 1653420, 6153420, 5613420, 6513420, 3561420, 5361420, 3651420, 6351420, 5631420, 6531420, + 1456320, 4156320, 1546320, 5146320, 4516320, 5416320, 1465320, 4165320, 1645320, 6145320, 4615320, 6415320, + 1564320, 5164320, 1654320, 6154320, 5614320, 6514320, 4561320, 5461320, 4651320, 6451320, 5641320, 6541320, + 3456120, 4356120, 3546120, 5346120, 4536120, 5436120, 3465120, 4365120, 3645120, 6345120, 4635120, 6435120, + 3564120, 5364120, 3654120, 6354120, 5634120, 6534120, 4563120, 5463120, 4653120, 6453120, 5643120, 6543120, + 2345610, 3245610, 2435610, 4235610, 3425610, 4325610, 2354610, 3254610, 2534610, 5234610, 3524610, 5324610, + 2453610, 4253610, 2543610, 5243610, 4523610, 5423610, 3452610, 4352610, 3542610, 5342610, 4532610, 5432610, + 2346510, 3246510, 2436510, 4236510, 3426510, 4326510, 2364510, 3264510, 2634510, 6234510, 3624510, 6324510, + 2463510, 4263510, 2643510, 6243510, 4623510, 6423510, 3462510, 4362510, 3642510, 6342510, 4632510, 6432510, + 2356410, 3256410, 2536410, 5236410, 3526410, 5326410, 2365410, 3265410, 2635410, 6235410, 3625410, 6325410, + 2563410, 5263410, 2653410, 6253410, 5623410, 6523410, 3562410, 5362410, 3652410, 6352410, 5632410, 6532410, + 2456310, 4256310, 2546310, 5246310, 4526310, 5426310, 2465310, 4265310, 2645310, 6245310, 4625310, 6425310, + 2564310, 5264310, 2654310, 6254310, 5624310, 6524310, 4562310, 5462310, 4652310, 6452310, 5642310, 6542310, + 3456210, 4356210, 3546210, 5346210, 4536210, 5436210, 3465210, 4365210, 3645210, 6345210, 4635210, 6435210, + 3564210, 5364210, 3654210, 6354210, 5634210, 6534210, 4563210, 5463210, 4653210, 6453210, 5643210, 6543210 + }; + std::map expected; + for (std::size_t i = 0; i < 5040; i++) + expected[pre_expected[i]] = 0; // flags are 0, everything is symmetric here + + VERIFY(isDynGroup(group)); + VERIFY_IS_EQUAL(group.size(), 5040u); + VERIFY_IS_EQUAL(group.globalFlags(), 0); + group.apply(identity7, 0, found, expected); + VERIFY_IS_EQUAL(found.size(), 5040u); + } +} + +static void test_tensor_epsilon() +{ + SGroup<3, AntiSymmetry<0,1>, AntiSymmetry<1,2>> sym; + Tensor epsilon(3,3,3); + + epsilon.setZero(); + epsilon.symCoeff(sym, 0, 1, 2) = 1; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 3; k++) { + VERIFY_IS_EQUAL((epsilon(i,j,k)), (- (j - i) * (k - j) * (i - k) / 2) ); + } + } + } +} + +static void test_tensor_sym() +{ + SGroup<4, Symmetry<0,1>, Symmetry<2,3>> sym; + Tensor t(10,10,10,10); + + t.setZero(); + + for (int l = 0; l < 10; l++) { + for (int k = l; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = j; i < 10; i++) { + t.symCoeff(sym, i, j, k, l) = (i + j) * (k + l); + } + } + } + } + + for (int l = 0; l < 10; l++) { + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 10; i++) { + VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l))); + } + } + } + } + +} + +static void test_tensor_asym() +{ + SGroup<4, AntiSymmetry<0,1>, AntiSymmetry<2,3>> sym; + Tensor t(10,10,10,10); + + t.setZero(); + + for (int l = 0; l < 10; l++) { + for (int k = l + 1; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = j + 1; i < 10; i++) { + t.symCoeff(sym, i, j, k, l) = ((i * j) + (k * l)); + } + } + } + } + + for (int l = 0; l < 10; l++) { + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 10; i++) { + if (i < j && k < l) + VERIFY_IS_EQUAL((t(i, j, k, l)), (((i * j) + (k * l)))); + else if (i > j && k > l) + VERIFY_IS_EQUAL((t(i, j, k, l)), (((i * j) + (k * l)))); + else if (i < j && k > l) + VERIFY_IS_EQUAL((t(i, j, k, l)), (- ((i * j) + (k * l)))); + else if (i > j && k < l) + VERIFY_IS_EQUAL((t(i, j, k, l)), (- ((i * j) + (k * l)))); + else + VERIFY_IS_EQUAL((t(i, j, k, l)), 0); + } + } + } + } +} + +static void test_tensor_dynsym() +{ + DynamicSGroup sym(4); + sym.addSymmetry(0,1); + sym.addSymmetry(2,3); + Tensor t(10,10,10,10); + + t.setZero(); + + for (int l = 0; l < 10; l++) { + for (int k = l; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = j; i < 10; i++) { + t.symCoeff(sym, i, j, k, l) = (i + j) * (k + l); + } + } + } + } + + for (int l = 0; l < 10; l++) { + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 10; i++) { + VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l))); + } + } + } + } +} + +static void test_tensor_randacc() +{ + SGroup<4, Symmetry<0,1>, Symmetry<2,3>> sym; + Tensor t(10,10,10,10); + + t.setZero(); + + // set elements 1 million times, that way we access the + // entire matrix + for (int n = 0; n < 1000000; n++) { + int i = rand() % 10; + int j = rand() % 10; + int k = rand() % 10; + int l = rand() % 10; + // only access those indices in a given order + if (i < j) + std::swap(i, j); + if (k < l) + std::swap(k, l); + t.symCoeff(sym, i, j, k, l) = (i + j) * (k + l); + } + + for (int l = 0; l < 10; l++) { + for (int k = 0; k < 10; k++) { + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 10; i++) { + VERIFY_IS_EQUAL((t(i, j, k, l)), ((i + j) * (k + l))); + } + } + } + } +} + +void test_cxx11_tensor_symmetry() +{ + CALL_SUBTEST(test_symgroups_static()); + CALL_SUBTEST(test_symgroups_dynamic()); + CALL_SUBTEST(test_symgroups_selection()); + CALL_SUBTEST(test_tensor_epsilon()); + CALL_SUBTEST(test_tensor_sym()); + CALL_SUBTEST(test_tensor_asym()); + CALL_SUBTEST(test_tensor_dynsym()); + CALL_SUBTEST(test_tensor_randacc()); +} + +/* + * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; + */ From f6bac196d55c1658902ec09058023209021cdd1b Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Sat, 16 Nov 2013 00:03:23 +0100 Subject: [PATCH 4/4] C++11/Tensor: Fix copyright headers --- unsupported/Eigen/CXX11/Core | 3 +-- unsupported/Eigen/CXX11/Tensor | 3 +-- unsupported/Eigen/CXX11/TensorSymmetry | 3 +-- unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h | 3 +-- unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h | 3 +-- unsupported/Eigen/CXX11/src/Tensor/Tensor.h | 3 +-- unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h | 3 +-- unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h | 3 +-- unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h | 3 +-- unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h | 3 +-- .../Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h | 3 +-- unsupported/test/cxx11_meta.cpp | 3 +-- unsupported/test/cxx11_tensor_simple.cpp | 3 +-- unsupported/test/cxx11_tensor_symmetry.cpp | 3 +-- 14 files changed, 14 insertions(+), 28 deletions(-) diff --git a/unsupported/Eigen/CXX11/Core b/unsupported/Eigen/CXX11/Core index 1b1f1dcc1..4dc4ab224 100644 --- a/unsupported/Eigen/CXX11/Core +++ b/unsupported/Eigen/CXX11/Core @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/Tensor b/unsupported/Eigen/CXX11/Tensor index 083d8c0a7..f2c5129b3 100644 --- a/unsupported/Eigen/CXX11/Tensor +++ b/unsupported/Eigen/CXX11/Tensor @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/TensorSymmetry b/unsupported/Eigen/CXX11/TensorSymmetry index 5bbab0a80..027c6087f 100644 --- a/unsupported/Eigen/CXX11/TensorSymmetry +++ b/unsupported/Eigen/CXX11/TensorSymmetry @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h b/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h index 55d3cc37b..d6b5d75d9 100644 --- a/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h +++ b/unsupported/Eigen/CXX11/src/Core/util/CXX11Meta.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h b/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h index eec38b343..356ae10cf 100644 --- a/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h +++ b/unsupported/Eigen/CXX11/src/Core/util/CXX11Workarounds.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/Tensor/Tensor.h b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h index ff3d6513e..c6216e14c 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/Tensor.h +++ b/unsupported/Eigen/CXX11/src/Tensor/Tensor.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h b/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h index 50040147d..a34600ee6 100644 --- a/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h +++ b/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h index 87332610d..b5738b778 100644 --- a/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h index 048e753fc..c5a630105 100644 --- a/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h index 40ad8d7ff..f0813086a 100644 --- a/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h b/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h index 716d7d2e5..0fe0b7c46 100644 --- a/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h +++ b/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/test/cxx11_meta.cpp b/unsupported/test/cxx11_meta.cpp index 03a9efe54..a9843e9a9 100644 --- a/unsupported/test/cxx11_meta.cpp +++ b/unsupported/test/cxx11_meta.cpp @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/test/cxx11_tensor_simple.cpp b/unsupported/test/cxx11_tensor_simple.cpp index 6875a4e58..ea512c9cc 100644 --- a/unsupported/test/cxx11_tensor_simple.cpp +++ b/unsupported/test/cxx11_tensor_simple.cpp @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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 diff --git a/unsupported/test/cxx11_tensor_symmetry.cpp b/unsupported/test/cxx11_tensor_symmetry.cpp index ebbc8a68d..e8dfffd92 100644 --- a/unsupported/test/cxx11_tensor_symmetry.cpp +++ b/unsupported/test/cxx11_tensor_symmetry.cpp @@ -1,8 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud -// Copyright (C) 2006-2008 Benoit Jacob +// 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