Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define algebra multivector type #6

Merged
merged 1 commit into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions geometry/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ cc_library(
name = "geometry",
srcs = [
"src/algebra.hpp",
"src/detail/all_same.hpp",
"src/detail/contract_dimensions.hpp",
"src/detail/ordered.hpp",
"src/detail/sort_dimensions.hpp",
"src/detail/strictly_increasing.hpp",
],
Expand Down
61 changes: 61 additions & 0 deletions geometry/src/algebra.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#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"

Expand Down Expand Up @@ -33,6 +35,20 @@ struct algebra
template <std::size_t... Is>
struct blade;

/// determines if a type is a blade
/// @tparam T type
///
/// @{
template <class T>
struct is_blade : std::false_type
{};
template <std::size_t... Is>
struct is_blade<blade<Is...>> : std::true_type
{};
template <class T>
static constexpr auto is_blade_v = is_blade<T>::value;
/// @}

private:
template <std::size_t... Is>
static auto rebind(std::index_sequence<Is...>) -> blade<Is...>;
Expand Down Expand Up @@ -217,6 +233,51 @@ struct algebra
return x.coefficient * y.coefficient * e<Is..., Js...>;
}
};

/// multivector
/// @tparam Bs blade types
///
/// A linear combination of blades.
///
/// @note a multivector may be composed of only blades with the same grade
///
template <class... Bs>
struct multivector : Bs...
{
static_assert(
(is_blade_v<Bs> and ...), "`Bs` must be a specialization of blade");
static_assert(
detail::all_same_v<typename Bs::scalar_type...>,
"`Bs` must have the same scalar type");
static_assert(
detail::strictly_increasing(detail::ordered<Bs>{}...),
"`Bs` must be lexicographically sorted");

/// algebra type
///
using algebra_type = algebra;

/// construct a multivector from blades
///
constexpr multivector(Bs... bs) : Bs{bs}... {}

/// equality comparison
///
/// @{
[[nodiscard]]
friend constexpr auto
operator==(const multivector& x, const multivector& y) -> bool
{
return ((static_cast<const Bs&>(x) == static_cast<const Bs&>(y)) and ...);
}
[[nodiscard]]
friend constexpr auto
operator!=(const multivector& x, const multivector& y) -> bool
{
return not(x == y);
}
/// @}
};
};

} // namespace geometry
24 changes: 24 additions & 0 deletions geometry/src/detail/all_same.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <type_traits>

namespace geometry::detail {

template <class...>
struct all_same : std::false_type
{};

template <>
struct all_same<> : std::true_type
{};
template <class T>
struct all_same<T> : std::true_type
{};
template <class T, class... Ts>
struct all_same<T, Ts...> : std::bool_constant<((std::is_same_v<T, Ts>)and...)>
{};

template <class... Ts>
inline constexpr auto all_same_v = all_same<Ts...>::value;

} // namespace geometry::detail
33 changes: 33 additions & 0 deletions geometry/src/detail/ordered.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include <cstddef>
#include <tuple>

namespace geometry::detail {

template <class B>
class ordered
{
template <
template <std::size_t...>
class blade,
std::size_t... Is,
std::size_t... Js>
static constexpr auto
compare_dimensions(ordered<blade<Is...>>, ordered<blade<Js...>>)
{
return std::tuple{Is...} < std::tuple{Js...};
}

template <class B2>
friend constexpr auto operator<(ordered x, ordered<B2> y) -> bool
{
if constexpr (B::grade == B2::grade) {
return compare_dimensions(x, y);
} else {
return B::grade < B2::grade;
}
}
};

} // namespace geometry::detail
29 changes: 11 additions & 18 deletions geometry/src/detail/strictly_increasing.hpp
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
#pragma once

#include <array>
#include <cstddef>
#include <tuple>
#include <utility>

namespace geometry::detail {

inline constexpr class
{
template <class T>
static constexpr auto impl(std::index_sequence<>, const std::array<T, 1>&)
template <std::size_t... Is, class T>
static constexpr auto impl(std::index_sequence<Is...>, const T& values)
{
return true;
}
template <
std::size_t... Is,
class T,
class = std::enable_if_t<(sizeof...(Is) != 0)>>
static constexpr auto
impl(std::index_sequence<Is...>,
const std::array<T, sizeof...(Is) + 1>& values)
{
return ((std::get<Is>(values) < std::get<Is + 1>(values)) and ...);
if constexpr (sizeof...(Is) == 0) {
return true;
} else {
return (((std::get<Is>(values)) < (std::get<Is + 1>(values))) and ...);
}
}

public:
// 0-args
constexpr auto operator()() const { return true; }
// 1+-args
template <class... Ts>
constexpr auto operator()(std::size_t t0, Ts... ts) const
template <class T0, class... Ts>
constexpr auto operator()(T0 t0, Ts... ts) const
{
static_assert((std::is_same_v<std::size_t, Ts> and ...));
return impl(std::index_sequence_for<Ts...>{}, std::array{t0, ts...});
return impl(std::index_sequence_for<Ts...>{}, std::tuple{t0, ts...});
}
} strictly_increasing{};

Expand Down
13 changes: 11 additions & 2 deletions test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
load("@rules_cc//cc:defs.bzl", "cc_test")

cc_test(
name = "algebra_test",
srcs = ["algebra_test.cpp"],
name = "algebra_blade_test",
srcs = ["algebra_blade_test.cpp"],
deps = [
"//:geometry",
"@skytest",
],
)

cc_test(
name = "algebra_multivector_test",
srcs = ["algebra_multivector_test.cpp"],
deps = [
"//:geometry",
"@skytest",
Expand Down
File renamed without changes.
48 changes: 48 additions & 0 deletions test/algebra_multivector_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "geometry/geometry.hpp"
#include "skytest/skytest.hpp"

#include <cstddef>
#include <tuple>
#include <type_traits>

template <std::size_t... Is>
constexpr auto e = ::geometry::algebra<double, 2>::e<Is...>;

/// construct a multivector from blades
///
inline constexpr struct
{
template <
class... Bs,
class = std::enable_if_t<
sizeof...(Bs) != 0 and
::geometry::detail::all_same_v<typename Bs::algebra_type...>>>
[[nodiscard]]
constexpr auto
operator()(Bs... bs) const
{
using Algebra = std::common_type_t<typename Bs::algebra_type...>;
return typename Algebra::template multivector<Bs...>{bs...};
}
} multivector{};

auto main() -> int
{
using namespace ::skytest::literals;
using ::skytest::eq;
using ::skytest::expect;
using ::skytest::param_ref;

static constexpr auto multivectors = std::tuple{
multivector(e<>),
multivector(e<>, e<0>),
multivector(e<>, e<1>),
multivector(e<>, e<2>),
multivector(e<>, e<0>, e<1, 2>),
multivector(e<>, e<0, 1>, e<1, 2>),
multivector(e<>, e<0, 1, 2>)};

"multivector with same elements comparable"_ctest *
param_ref<multivectors> = //
[](auto v) { return expect(eq(v, v)); };
}