Skip to content

Commit c1dbf1e

Browse files
authored
Merge pull request #4271 from pleroy/MoveConcepts
Move algebra-related concepts to geometry
2 parents 1a822e2 + fc3a4d0 commit c1dbf1e

14 files changed

Lines changed: 194 additions & 170 deletions

geometry/barycentre_calculator.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
#include <vector>
55
#include <utility>
66

7-
#include "quantities/concepts.hpp"
7+
#include "geometry/concepts.hpp"
88
#include "quantities/named_quantities.hpp"
99

1010
namespace principia {
1111
namespace geometry {
1212
namespace _barycentre_calculator {
1313
namespace internal {
1414

15-
using namespace principia::quantities::_concepts;
15+
using namespace principia::geometry::_concepts;
1616
using namespace principia::quantities::_named_quantities;
1717

1818
template<affine Point, homogeneous_field Weight>

geometry/concepts.hpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,141 @@
11
#pragma once
22

3+
#include <concepts>
4+
#include <type_traits>
5+
6+
#include "base/traits.hpp"
7+
38
namespace principia {
49
namespace geometry {
510
namespace _concepts {
611
namespace internal {
712

13+
using namespace base::_traits;
14+
15+
// TODO(egg): additive_group should subsume affine, but we use it there.
16+
// We use `convertible_to` here because we want this concept to work with
17+
// Boost multiprecision types which heavily use implicit conversions.
18+
template<typename G>
19+
concept additive_group = requires(G x, G y, int n) {
20+
G{};
21+
{ +x } -> std::convertible_to<G>;
22+
{ -x } -> std::convertible_to<G>;
23+
{ x + y } -> std::convertible_to<G>;
24+
{ x - y } -> std::convertible_to<G>;
25+
{ x += y } -> std::convertible_to<G&>;
26+
{ x -= y } -> std::convertible_to<G&>;
27+
// An abelian group is a ℤ-module; we require the corresponding operations.
28+
{ n * x } -> std::convertible_to<G>;
29+
{ x * n } -> std::convertible_to<G>;
30+
{ x *= n } -> std::convertible_to<G&>;
31+
};
32+
33+
// A set acted upon simply transitively by an additive group.
34+
template<typename A>
35+
concept affine = requires(A x, A y) {
36+
{ x - y } -> additive_group;
37+
{ y + (x - y) } -> std::same_as<A>;
38+
{ y += (x - y) } -> std::same_as<A&>;
39+
{ y - (x - y) } -> std::same_as<A>;
40+
{ y -= (x - y) } -> std::same_as<A&>;
41+
};
42+
43+
// A graded ring restricted to its homogeneous elements; multiplication can
44+
// alter the type, and addition is only defined between homogeneous elements.
45+
template<typename A>
46+
concept homogeneous_ring =
47+
additive_group<A> && requires(A x, A y, A z) {
48+
// Really, multiplication should return a homogeneous_ring.
49+
{ x * y } -> additive_group;
50+
{ (x * y) * z } -> additive_group;
51+
{ (x * y) * z } -> std::same_as<decltype(x * (y * z))>;
52+
};
53+
54+
template<typename A>
55+
concept ring = homogeneous_ring<A> && requires(A x, A y) {
56+
{ x * y } -> std::same_as<A>;
57+
{ x *= y } -> std::same_as<A&>;
58+
};
59+
60+
// TODO(egg): field should subsume homogeneous_field, but we use it in
61+
// homogeneous_field.
62+
63+
template<typename K>
64+
concept field = ring<K> && !std::integral<K> && requires(K x, K y, K z) {
65+
{ 1 } -> std::convertible_to<K>;
66+
{ 1 / y } -> std::same_as<K>;
67+
{ x / y } -> std::same_as<K>;
68+
{ x /= y } -> std::same_as<K&>;
69+
};
70+
71+
// TODO(egg): vector_space should subsume homogeneous_vector_space, but we use
72+
// it in homogeneous_vector_space.
73+
74+
template<typename V, typename K>
75+
concept vector_space = field<K> && requires(K λ, V v) {
76+
{ λ * v } -> std::same_as<V>;
77+
{ v * λ } -> std::same_as<V>;
78+
{ v / λ } -> std::same_as<V>;
79+
{ v *= λ } -> std::same_as<V&>;
80+
{ v /= λ } -> std::same_as<V&>;
81+
};
82+
83+
// A graded field restricted to its homogeneous elements; multiplication and
84+
// division can alter the type, and addition is only defined between homogeneous
85+
// elements.
86+
template<typename K>
87+
concept homogeneous_field = homogeneous_ring<K> && requires(K x, K y, K z) {
88+
{ x / y } -> field;
89+
requires vector_space<K, decltype(x / y)>;
90+
{ (1 / x) } -> homogeneous_ring;
91+
{ 1 / (x * y) } -> std::same_as<decltype((1 / x) * (1 / y))>;
92+
{ (x * y) / z } -> std::same_as<K>;
93+
{ (x / y) * z } -> std::same_as<K>;
94+
};
95+
96+
template<typename V, typename K>
97+
concept homogeneous_vector_space =
98+
additive_group<V> && homogeneous_field<K> && requires(K λ, K μ, V v) {
99+
// Really, these operations should return a homogeneous_vector_space.
100+
requires vector_space<V, decltype(λ / μ)>;
101+
{ λ * v } -> additive_group;
102+
{ v * λ } -> std::same_as<decltype(λ * v)>;
103+
{ v / λ } -> additive_group;
104+
{ λ * v / λ } -> std::same_as<V>;
105+
{ (λ * μ) * v } -> additive_group;
106+
{ λ * (μ * v) } -> std::same_as<decltype((λ * μ) * v)>;
107+
};
108+
109+
template<typename V>
110+
concept real_vector_space = vector_space<V, double>;
111+
112+
template<typename A, typename K>
113+
concept affine_space = affine<A> && requires(A x, A y) {
114+
{ x - y } -> vector_space<K>;
115+
};
116+
117+
template<typename V>
118+
concept real_affine_space = affine_space<V, double>;
119+
8120
template<typename T1, typename T2>
9121
concept hilbert = requires(T1 const& t1, T2 const& t2) {
10122
InnerProduct(t1, t2);
11123
};
12124

13125
} // namespace internal
14126

127+
using internal::additive_group;
128+
using internal::affine;
129+
using internal::affine_space;
15130
using internal::hilbert;
131+
using internal::field;
132+
using internal::homogeneous_field;
133+
using internal::homogeneous_ring;
134+
using internal::homogeneous_vector_space;
135+
using internal::real_affine_space;
136+
using internal::real_vector_space;
137+
using internal::ring;
138+
using internal::vector_space;
16139

17140
} // namespace _concepts
18141
} // namespace geometry

geometry/concepts_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "geometry/concepts.hpp"
2+
3+
#include <string>
4+
5+
#include "gtest/gtest.h"
6+
#include "quantities/quantities.hpp"
7+
8+
namespace principia {
9+
namespace geometry {
10+
11+
using namespace principia::geometry::_concepts;
12+
using namespace principia::quantities::_quantities;
13+
14+
TEST(Concepts, Algebra) {
15+
static_assert(!affine<std::string>);
16+
static_assert(affine<std::byte*>);
17+
static_assert(affine<Length>);
18+
static_assert(affine<int>);
19+
static_assert(affine<double>);
20+
21+
static_assert(!additive_group<std::string>);
22+
static_assert(!additive_group<std::byte*>);
23+
static_assert(additive_group<Length>);
24+
static_assert(additive_group<int>);
25+
static_assert(additive_group<double>);
26+
27+
static_assert(homogeneous_ring<Length>);
28+
static_assert(homogeneous_ring<int>);
29+
static_assert(homogeneous_ring<double>);
30+
31+
static_assert(!ring<Length>);
32+
static_assert(ring<int>);
33+
static_assert(ring<double>);
34+
35+
static_assert(homogeneous_field<Length>);
36+
static_assert(!homogeneous_field<int>);
37+
static_assert(homogeneous_field<double>);
38+
39+
static_assert(!field<Length>);
40+
static_assert(!field<int>);
41+
static_assert(field<double>);
42+
}
43+
44+
TEST(Concepts, LinearAlgebra) {
45+
static_assert(homogeneous_vector_space<Length, Length>);
46+
static_assert(!vector_space<Length, Length>);
47+
static_assert(vector_space<double, double>);
48+
49+
static_assert(!real_vector_space<int>);
50+
}
51+
52+
} // namespace geometry
53+
} // namespace principia

geometry/geometry.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<ItemGroup>
7272
<ClCompile Include="barycentre_calculator_test.cpp" />
7373
<ClCompile Include="complexification_test.cpp" />
74+
<ClCompile Include="concepts_test.cpp" />
7475
<ClCompile Include="conformal_map_test.cpp" />
7576
<ClCompile Include="frame_test.cpp" />
7677
<ClCompile Include="grassmann_test.cpp" />

geometry/geometry.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,5 +271,8 @@
271271
<ClCompile Include="instant_test.cpp">
272272
<Filter>Test Files</Filter>
273273
</ClCompile>
274+
<ClCompile Include="concepts_test.cpp">
275+
<Filter>Test Files</Filter>
276+
</ClCompile>
274277
</ItemGroup>
275278
</Project>

geometry/pair.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#include "base/not_null.hpp"
99
#include "base/traits.hpp"
1010
#include "geometry/barycentre_calculator.hpp" // 🧙 For friendship.
11+
#include "geometry/concepts.hpp"
1112
#include "geometry/space.hpp"
12-
#include "quantities/concepts.hpp"
1313
#include "quantities/named_quantities.hpp"
1414
#include "serialization/geometry.pb.h"
1515

@@ -29,8 +29,8 @@ using namespace principia::base::_concepts;
2929
using namespace principia::base::_not_constructible;
3030
using namespace principia::base::_not_null;
3131
using namespace principia::base::_traits;
32+
using namespace principia::geometry::_concepts;
3233
using namespace principia::geometry::_space;
33-
using namespace principia::quantities::_concepts;
3434
using namespace principia::quantities::_named_quantities;
3535

3636
template<typename T1, typename T2>

geometry/point.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "base/concepts.hpp"
99
#include "base/not_null.hpp"
10+
#include "geometry/concepts.hpp"
1011
#include "quantities/concepts.hpp"
1112
#include "quantities/named_quantities.hpp"
1213
#include "serialization/geometry.pb.h"
@@ -18,6 +19,7 @@ namespace internal {
1819

1920
using namespace principia::base::_concepts;
2021
using namespace principia::base::_not_null;
22+
using namespace principia::geometry::_concepts;
2123
using namespace principia::quantities::_concepts;
2224
using namespace principia::quantities::_named_quantities;
2325

0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

numerics/fixed_arrays_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#include "numerics/fixed_arrays.hpp"
22

3+
#include "geometry/concepts.hpp"
34
#include "gmock/gmock.h"
45
#include "gtest/gtest.h"
56
#include "numerics/elementary_functions.hpp"
67
#include "numerics/transposed_view.hpp"
7-
#include "quantities/concepts.hpp"
88
#include "quantities/quantities.hpp"
99

1010
namespace principia {
1111
namespace numerics {
1212

13+
using namespace principia::geometry::_concepts;
1314
using namespace principia::numerics::_elementary_functions;
1415
using namespace principia::numerics::_fixed_arrays;
1516
using namespace principia::numerics::_transposed_view;
16-
using namespace principia::quantities::_concepts;
1717
using namespace principia::quantities::_quantities;
1818
using ::testing::Pointer;
1919

0 commit comments

Comments
 (0)