diff --git a/geometry/BUILD.bazel b/geometry/BUILD.bazel index 1a5ff47..7e16d3b 100644 --- a/geometry/BUILD.bazel +++ b/geometry/BUILD.bazel @@ -7,8 +7,9 @@ cc_library( "src/detail/all_same.hpp", "src/detail/contract_dimensions.hpp", "src/detail/ordered.hpp", - "src/detail/sort_dimensions.hpp", "src/detail/strictly_increasing.hpp", + "src/detail/type_list.hpp", + "src/detail/type_sort.hpp", ], hdrs = ["geometry.hpp"], visibility = ["//:__subpackages__"], diff --git a/geometry/src/algebra.hpp b/geometry/src/algebra.hpp index 4ad1bb5..95047c9 100644 --- a/geometry/src/algebra.hpp +++ b/geometry/src/algebra.hpp @@ -3,8 +3,9 @@ #include "geometry/src/detail/all_same.hpp" #include "geometry/src/detail/contract_dimensions.hpp" #include "geometry/src/detail/ordered.hpp" -#include "geometry/src/detail/sort_dimensions.hpp" #include "geometry/src/detail/strictly_increasing.hpp" +#include "geometry/src/detail/type_list.hpp" +#include "geometry/src/detail/type_sort.hpp" #include #include @@ -35,6 +36,16 @@ struct algebra template struct blade; + /// multivector + /// @tparam Bs blade types + /// + /// A linear combination of blades. + /// + /// @note a multivector may be composed of only blades with the same grade + /// + template + struct multivector; + /// determines if a type is a blade /// @tparam T type /// @@ -50,25 +61,29 @@ struct algebra /// @} private: - template - static auto rebind(std::index_sequence) -> blade; + template + static auto rebind(detail::type_list) -> blade; template using rebind_t = decltype(rebind(Seq{})); + template + using sequence_t = + detail::type_list...>; + template using reified_blade_t = rebind_t>>>; + detail::type_sort_t>>>; template static constexpr auto reified_blade_coefficient_v = - (detail::sort_dimensions_swap_count_v> % 2 == 0 + (detail::type_sort_swap_count_v> % 2 == 0 ? scalar_type{1} : -scalar_type{1}) * scalar_type{detail::contract_dimensions_coefficient_v< detail::contraction_map::projective, - detail::sort_dimensions_t>>}; + detail::type_sort_t>>}; public: /// unit blade @@ -190,21 +205,38 @@ struct algebra /// addition /// + /// @{ [[nodiscard]] friend constexpr auto operator+(blade x, blade y) -> blade { return blade{x.coefficient + y.coefficient}; } + template + [[nodiscard]] + friend constexpr auto + operator+(blade x, blade y) + { + if constexpr ( + detail::ordered>{} < detail::ordered{}) { + return multivector, blade>{y, x}; + } else { + return multivector>{x, y}; + } + } + /// @} /// subtraction /// + /// @{ + template [[nodiscard]] friend constexpr auto - operator-(blade x, blade y) -> blade + operator-(blade x, blade y) { - return blade{x.coefficient - y.coefficient}; + return x + -y; } + /// @} /// scalar multiplication /// @@ -234,13 +266,6 @@ struct algebra } }; - /// multivector - /// @tparam Bs blade types - /// - /// A linear combination of blades. - /// - /// @note a multivector may be composed of only blades with the same grade - /// template struct multivector : Bs... { diff --git a/geometry/src/detail/contract_dimensions.hpp b/geometry/src/detail/contract_dimensions.hpp index 8229e6d..5a8bb5d 100644 --- a/geometry/src/detail/contract_dimensions.hpp +++ b/geometry/src/detail/contract_dimensions.hpp @@ -1,5 +1,7 @@ #pragma once +#include "geometry/src/detail/type_list.hpp" + #include #include @@ -14,49 +16,27 @@ struct contraction_map }; }; -template < - class Map, - class InSeq, - int Coeff = 1, - class OutSeq = std::index_sequence<>> +template > struct contract_dimensions { using type = OutSeq; static constexpr auto coefficient = Coeff; }; -template < - class Map, - std::size_t I0, - std::size_t... Is, - int Coeff, - std::size_t... Js> -struct contract_dimensions< - Map, - std::index_sequence, - Coeff, - std::index_sequence> - : contract_dimensions< - Map, - std::index_sequence, - Coeff, - std::index_sequence> +template +struct contract_dimensions, Coeff, type_list> + : contract_dimensions, Coeff, type_list> {}; -template < - class Map, - std::size_t I0, - std::size_t... Is, - int Coeff, - std::size_t... Js> +template struct contract_dimensions< Map, - std::index_sequence, + type_list, Coeff, - std::index_sequence> + type_list> : contract_dimensions< Map, - std::index_sequence, - Coeff * Map::template value, - std::index_sequence> + type_list, + Coeff * Map::template value, + type_list> {}; template diff --git a/geometry/src/detail/sort_dimensions.hpp b/geometry/src/detail/sort_dimensions.hpp deleted file mode 100644 index 7fa1ebb..0000000 --- a/geometry/src/detail/sort_dimensions.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace geometry::detail { - -template > -struct sort_swap_first -{ - using type = OutSeq; -}; -template -struct sort_swap_first, std::index_sequence> -{ - using type = std::index_sequence; -}; -template -struct sort_swap_first< - std::index_sequence, - std::index_sequence> - : std::conditional_t< - (I0 > I1), - sort_swap_first, - std::index_sequence>, - sort_swap_first, - std::index_sequence>> -{}; - -template -using sort_swap_first_t = typename sort_swap_first::type; - -template -struct sort_swap : sort_swap, Swaps + 1> -{}; -template -struct sort_swap< - std::index_sequence, - Swaps, - std::enable_if_t, - sort_swap_first_t>>>> -{ - using type = std::index_sequence; - static constexpr auto swap_count = Swaps; -}; - -template -struct sort_dimensions -{ - using type = typename sort_swap::type; -}; - -template -using sort_dimensions_t = typename sort_dimensions::type; - -template -struct sort_dimensions_swap_count - : std::integral_constant::swap_count> -{}; - -template -inline constexpr auto sort_dimensions_swap_count_v = - sort_dimensions_swap_count::value; - -} // namespace geometry::detail diff --git a/geometry/src/detail/type_list.hpp b/geometry/src/detail/type_list.hpp new file mode 100644 index 0000000..58f7733 --- /dev/null +++ b/geometry/src/detail/type_list.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace geometry::detail { + +template +struct type_list +{}; + +} // namespace geometry::detail diff --git a/geometry/src/detail/type_sort.hpp b/geometry/src/detail/type_sort.hpp new file mode 100644 index 0000000..274c37b --- /dev/null +++ b/geometry/src/detail/type_sort.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "geometry/src/detail/type_list.hpp" + +#include +#include +#include + +namespace geometry::detail { + +template > +struct sort_swap_first +{ + using type = OutSeq; +}; + +template +struct sort_swap_first, type_list> +{ + using type = type_list; +}; +template +struct sort_swap_first, type_list> + : std::conditional_t< + (I0{} > I1{}), + sort_swap_first, type_list>, + sort_swap_first, type_list>> +{}; + +template +using sort_swap_first_t = typename sort_swap_first::type; + +template +struct sort_swap : sort_swap, Swaps + 1> +{}; +template +struct sort_swap< + type_list, + Swaps, + std::enable_if_t< + std::is_same_v, sort_swap_first_t>>>> +{ + using type = type_list; + static constexpr auto swap_count = Swaps; +}; + +template +struct type_sort +{ + using type = typename sort_swap::type; +}; + +template +using type_sort_t = typename type_sort::type; + +template +struct type_sort_swap_count + : std::integral_constant::swap_count> +{}; + +template +inline constexpr auto type_sort_swap_count_v = type_sort_swap_count::value; + +} // namespace geometry::detail diff --git a/test/algebra_multivector_test.cpp b/test/algebra_multivector_test.cpp index cabeaa8..af478bd 100644 --- a/test/algebra_multivector_test.cpp +++ b/test/algebra_multivector_test.cpp @@ -45,4 +45,12 @@ auto main() -> int "multivector with same elements comparable"_ctest * param_ref = // [](auto v) { return expect(eq(v, v)); }; + + "multivector constructible from blade addition"_ctest = // + [] { + return expect( + eq(multivector(2 * e<0>, 3 * e<1>), 2 * e<0> + 3 * e<1>) and + eq(multivector(2 * e<0>, 3 * e<1>), 3 * e<1> + 2 * e<0>) and + eq(multivector(-2 * e<0>, 3 * e<1>), 3 * e<1> - 2 * e<0>)); + }; }