Sequoia
Loading...
Searching...
No Matches
Spaces.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2024. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
156#include "sequoia/PlatformSpecific/Preprocessor.hpp"
157
158#include <algorithm>
159#include <cmath>
160#include <concepts>
161#include <complex>
162#include <format>
163#include <ranges>
164#include <span>
165
166namespace sequoia::maths
167{
199 template<class T>
200 inline constexpr bool is_addable_v{
201 requires(T& t) {
202 { t += t } -> std::same_as<T&>;
203 { t + t } -> std::convertible_to<T>;
204 }
205 };
206
210 template<class T>
211 inline constexpr bool is_subtractable_v{
212 requires(T& t) {
213 { t -= t } -> std::same_as<T&>;
214 { t - t } -> std::convertible_to<T>;
215 }
216 };
217
221 template<class T>
222 inline constexpr bool is_multiplicable_v{
223 requires(T& t) {
224 { t *= t } -> std::same_as<T&>;
225 { t * t } -> std::convertible_to<T>;
226 }
227 };
228
232 template<class T>
233 inline constexpr bool is_divisible_v{
234 requires(T& t) {
235 { t /= t } -> std::same_as<T&>;
236 { t / t } -> std::convertible_to<T>;
237 }
238 };
239
260 template<class T>
261 struct weakly_abelian_group_under_addition : std::false_type {};
262
263 template<class T>
264 using weakly_abelian_group_under_addition_t = typename weakly_abelian_group_under_addition<T>::type;
265
266 template<class T>
267 inline constexpr bool weakly_abelian_group_under_addition_v{weakly_abelian_group_under_addition<T>::value};
268
269 template<arithmetic T>
270 struct weakly_abelian_group_under_addition<T> : std::true_type {};
271
272 template<std::floating_point T>
273 struct weakly_abelian_group_under_addition<std::complex<T>> : std::true_type {};
274
285 template<class T>
286 struct weakly_abelian_group_under_multiplication : std::false_type {};
287
288 template<class T>
289 using weakly_abelian_group_under_multiplication_t = typename weakly_abelian_group_under_multiplication<T>::type;
290
291 template<class T>
292 inline constexpr bool weakly_abelian_group_under_multiplication_v{weakly_abelian_group_under_multiplication<T>::value};
293
294 template<std::floating_point T>
295 struct weakly_abelian_group_under_multiplication<T> : std::true_type {};
296
297 template<std::floating_point T>
298 struct weakly_abelian_group_under_multiplication<std::complex<T>> : std::true_type {};
299
300 template<>
301 struct weakly_abelian_group_under_multiplication<bool> : std::true_type {};
302
307 template<class T>
309
310 template<class T>
311 using multiplication_weakly_distributive_over_addition_t = typename multiplication_weakly_distributive_over_addition<T>::type;
312
313 template<class T>
314 inline constexpr bool multiplication_weakly_distributive_over_addition_v{multiplication_weakly_distributive_over_addition<T>::value};
315
320 template<class T>
322 = std::regular<T>
323 && weakly_abelian_group_under_addition_v<T>
324 && multiplication_weakly_distributive_over_addition_v<T>
325 && is_addable_v<T>
326 && is_subtractable_v<T>
327 && is_multiplicable_v<T>;
328
333 template<class T>
334 concept weak_field = weak_commutative_ring<T> && weakly_abelian_group_under_multiplication_v<T> && is_divisible_v<T>;
335
343 template<class T>
344 inline constexpr bool has_commutative_ring_type_v{
345 requires {
346 typename T::commutative_ring_type;
348 }
349 };
350
354 template<class T>
355 inline constexpr bool has_field_type_v{
356 requires {
357 typename T::field_type;
359 }
360 };
361
368 template<class T>
369 inline constexpr bool defines_commutative_ring_v{has_commutative_ring_type_v<T> || has_field_type_v<T>};
370
378 template<class T>
379 inline constexpr bool defines_field_v{
380 has_field_type_v<T>
381 || requires {
382 typename T::commutative_ring_type;
384 }
385 };
386
390 template<class T>
391 inline constexpr bool has_dimension_v{
392 requires { { T::dimension } -> std::convertible_to<std::size_t>; }
393 };
394
398 template<class T>
399 inline constexpr bool has_set_type_v{
400 requires { typename T::set_type; }
401 };
402
423 template<class T>
424 inline constexpr bool identifies_as_convex_space_v{
425 requires {
426 typename T::is_convex_space;
427 requires std::convertible_to<typename T::is_convex_space, std::true_type>;
428 }
429 };
430
434 template<class T>
435 inline constexpr bool identifies_as_affine_space_v{
436 requires {
437 typename T::is_affine_space;
438 requires std::convertible_to<typename T::is_affine_space, std::true_type>;
439 }
440 };
441
445 template<class T>
446 inline constexpr bool identifies_as_free_module_v{
447 requires {
448 typename T::is_free_module;
449 requires std::convertible_to<typename T::is_free_module, std::true_type>;
450 }
451 };
452
456 template<class T>
457 inline constexpr bool identifies_as_vector_space_v{
458 requires {
459 typename T::is_vector_space;
460 requires std::convertible_to<typename T::is_vector_space, std::true_type>;
461 }
462 };
463
475 template<class T>
476 concept free_module = has_set_type_v<T> && has_dimension_v<T> && defines_commutative_ring_v<T> && (identifies_as_free_module_v<T> || identifies_as_vector_space_v<T>);
477
481 template<class T>
482 concept vector_space = free_module<T> && defines_field_v<T>;
483
488 template<class T>
489 inline constexpr bool has_vector_space_type_v{
490 requires {
491 typename T::vector_space_type;
493 }
494 };
495
500 template<class T>
501 inline constexpr bool has_free_module_type_v{
502 requires {
503 typename T::free_module_type;
505 }
506 };
507
515 template<class T>
518 || ( has_set_type_v<T>
519 && (has_vector_space_type_v<T> || has_free_module_type_v<T>)
520 && (identifies_as_convex_space_v<T> || identifies_as_affine_space_v<T>));
521
528 template<class T>
529 concept affine_space = vector_space<T> || (convex_space<T> && identifies_as_affine_space_v<T>);
530
534 template<class T>
535 struct is_free_module : std::integral_constant<bool, free_module<T>> {};
536
546 template<convex_space ConvexSpace>
548
549 template<convex_space ConvexSpace>
550 requires identifies_as_free_module_v<ConvexSpace> || identifies_as_vector_space_v<ConvexSpace>
551 struct free_module_type_of<ConvexSpace>
552 {
553 using type = ConvexSpace;
554 };
555
556 template<convex_space ConvexSpace>
557 requires (!identifies_as_free_module_v<ConvexSpace> && !identifies_as_vector_space_v<ConvexSpace>) && has_free_module_type_v<ConvexSpace>
559 {
560 using type = ConvexSpace::free_module_type;
561 };
562
563 template<convex_space ConvexSpace>
564 requires (!identifies_as_free_module_v<ConvexSpace> && !identifies_as_vector_space_v<ConvexSpace>) && has_vector_space_type_v<ConvexSpace>
565 struct free_module_type_of<ConvexSpace>
566 {
567 using type = ConvexSpace::vector_space_type;
568 };
569
570 template<convex_space ConvexSpace>
571 using free_module_type_of_t = free_module_type_of<ConvexSpace>::type;
572
578 template<convex_space ConvexSpace>
580 {
581 using type = free_module_type_of_t<ConvexSpace>::commutative_ring_type;
582 };
583
584 template<convex_space ConvexSpace>
585 requires vector_space<free_module_type_of_t<ConvexSpace>> && has_field_type_v<free_module_type_of_t<ConvexSpace>>
586 struct commutative_ring_type_of<ConvexSpace>
587 {
588 using type = free_module_type_of_t<ConvexSpace>::field_type;
589 };
590
591 template<convex_space ConvexSpace>
592 using commutative_ring_type_of_t = commutative_ring_type_of<ConvexSpace>::type;
593
594 template<convex_space ConvexSpace>
595 using space_value_type = commutative_ring_type_of_t<ConvexSpace>;
596
601 template<convex_space ConvexSpace>
602 inline constexpr std::size_t dimension_of{free_module_type_of_t<ConvexSpace>::dimension};
603
613 template<class B>
614 concept basis = has_free_module_type_v<B> || has_vector_space_type_v<B>;
615
619 template<class B, class M>
620 concept basis_for = basis<B> && ( requires { requires std::is_same_v<typename B::free_module_type, M> ; }
621 || requires { requires std::is_same_v<typename B::vector_space_type, M>; });
622
651 template<class V, class ConvexSpace>
652 inline constexpr bool validator_for_single_value{
653 (dimension_of<ConvexSpace> == 1)
654 && requires(V& v, const space_value_type<ConvexSpace>& val) { { v(val) } -> std::convertible_to<decltype(val)>; }
655 };
656
665 template<class V, class ConvexSpace>
666 inline constexpr bool validator_for_array{
667 requires (V& v, const std::array<space_value_type<ConvexSpace>, dimension_of<ConvexSpace>>& values) {
668 { v(values) } -> std::convertible_to<decltype(values)>;
669 }
670 };
671
675 template<class V, class ConvexSpace>
678 && std::default_initializable<V>
679 && std::constructible_from<V, V>
680 && (validator_for_single_value<V, ConvexSpace> || validator_for_array<V, ConvexSpace>);
681
685 template<class T>
686 struct is_identity_validator : std::false_type {};
687
688 template<class T>
689 using is_identity_validator_t = is_identity_validator<T>::type;
690
691 template<class T>
692 inline constexpr bool is_identity_validator_v{is_identity_validator<T>::value};
693
694 template<>
695 struct is_identity_validator<std::identity> : std::true_type {};
696
703 {
704 template<arithmetic T>
705 [[nodiscard]]
706 constexpr T operator()(const T val) const
707 {
708 if(val < T{}) throw std::domain_error{std::format("Value {} less than zero", val)};
709
710 return val;
711 }
712
713 template<arithmetic T>
714 requires std::is_unsigned_v<T>
715 [[nodiscard]]
716 constexpr T operator()(const T val) const
717 {
718 return val;
719 }
720 };
721
725 template<class T>
726 struct defines_half_line : std::false_type {};
727
728 template<class T>
729 using defines_half_line_t = typename defines_half_line<T>::type;
730
731 template<class T>
732 inline constexpr bool defines_half_line_v{defines_half_line<T>::value};
733
734 template<>
735 struct defines_half_line<half_line_validator> : std::true_type {};
736
761 template<class... Ts>
763 {
764 };
765
766 template<weak_commutative_ring... Rs>
767 inline constexpr bool has_common_ring_v{
768 ((weak_field<Rs> && ...) || (!weak_field<Rs> && ...)) && requires { typename std::common_type<Rs...>::type; }
769 };
770
771 template<free_module... Ts>
772 requires (sizeof...(Ts) >= 1) && has_common_ring_v<commutative_ring_type_of_t<Ts>...>
773 struct direct_product<Ts...>
774 {
775 using set_type = direct_product<typename Ts::set_type...>;
776 using commutative_ring_type = std::common_type_t<commutative_ring_type_of_t<Ts>...>;
777 using is_free_module = std::true_type;
778 constexpr static std::size_t dimension{(Ts::dimension + ...)};
779 };
780
781 template<affine_space... Ts>
782 requires (sizeof...(Ts) >= 1) && (!free_module<Ts> && ...)
783 struct direct_product<Ts...>
784 {
785 using set_type = direct_product<typename Ts::set_type...>;
786 using free_module_type = direct_product<free_module_type_of_t<Ts>...>;
787 using is_affine_space = std::true_type;
788 };
789
790 template<convex_space... Ts>
791 requires (sizeof...(Ts) >= 1)
792 && ((!affine_space<Ts> && ...) || ((free_module<Ts> || ...) && (!free_module<Ts> || ...)))
793 struct direct_product<Ts...>
794 {
795 using set_type = direct_product<typename Ts::set_type...>;
796 using free_module_type = direct_product<free_module_type_of_t<Ts>...>;
797 using is_convex_space = std::true_type;
798 };
799
800 template<class T>
801 struct is_direct_product : std::false_type {};
802
803 template<class... Ts>
804 struct is_direct_product<direct_product<Ts...>> : std::true_type {};
805
806 template<class T>
807 using is_direct_product_t = is_direct_product<T>::type;
808
809 template<class T>
810 inline constexpr bool is_direct_product_v = is_direct_product<T>::value;
811
865 namespace sets
866 {
874 template<convex_space From, class To>
876 {
877 };
878
886 template<vector_space From, class To>
888 {
889 };
890 }
891
895 template<class>
896 struct dual;
897
901 template<convex_space C>
902 requires (!affine_space<C>)
903 struct dual<C>
904 {
907 using is_convex_space = std::true_type;
908 };
909
913 template<affine_space A>
914 requires (!vector_space<A>)
915 struct dual<A>
916 {
919 using is_affine_space = std::true_type;
920 };
921
925 template<vector_space V>
926 struct dual<V>
927 {
928 using field_type = commutative_ring_type_of_t<V>;
930 using is_vector_space = std::true_type;
931 constexpr static auto dimension{V::dimension};
932 };
933
937 template<class T>
938 struct is_dual : std::false_type {};
939
940 template<class T>
941 struct is_dual<dual<T>> : std::true_type {};
942
943 template<class T>
944 using is_dual_t = is_dual<T>::type;
945
946 template<class T>
947 inline constexpr bool is_dual_v{is_dual<T>::value};
948
957 template<class>
958 struct dual_of;
959
960 template<class T>
961 using dual_of_t = dual_of<T>::type;
962
963 template<class T>
964 struct dual_of {
965 using type = dual<T>;
966 };
967
968 template<class T>
969 requires (!convex_space<T>) || (convex_space<T> && weak_field<commutative_ring_type_of_t<T>>)
970 struct dual_of<dual<T>> {
971 using type = T;
972 };
973
1011
1016 template<
1017 convex_space ConvexSpace,
1019 class Origin,
1020 validator_for<ConvexSpace> Validator
1021 >
1022 class coordinates;
1023
1030 template<affine_space AffineSpace, basis_for<free_module_type_of_t<AffineSpace>> Basis, class Origin>
1032
1036 template<vector_space VectorSpace, basis_for<free_module_type_of_t<VectorSpace>> Basis>
1038
1042 template<free_module FreeModule, basis_for<free_module_type_of_t<FreeModule>> Basis>
1044
1068 template<
1069 convex_space ConvexSpace,
1071 class Origin,
1072 validator_for<ConvexSpace> Validator,
1073 class DisplacementCoordinates=free_module_coordinates<free_module_type_of_t<ConvexSpace>, Basis>
1074 >
1076 {
1077 public:
1078 using convex_space_type = ConvexSpace;
1079 using basis_type = Basis;
1080 using validator_type = Validator;
1081 using origin_type = Origin;
1082 using set_type = ConvexSpace::set_type;
1083 using free_module_type = free_module_type_of_t<ConvexSpace>;
1084 using commutative_ring_type = commutative_ring_type_of_t<ConvexSpace>;
1085 using value_type = commutative_ring_type;
1086 using displacement_coordinates_type = DisplacementCoordinates;
1087
1088 constexpr static bool has_distinguished_origin{std::is_same_v<Origin, distinguished_origin>};
1089 constexpr static bool has_identity_validator{is_identity_validator_v<Validator>};
1090 constexpr static std::size_t dimension{free_module_type::dimension};
1091 constexpr static std::size_t D{dimension};
1092
1093 constexpr coordinates_base() noexcept = default;
1094
1095 constexpr explicit coordinates_base(std::span<const value_type, D> vals) noexcept(has_identity_validator)
1096 : m_Values{validate(vals, m_Validator)}
1097 {}
1098
1099 template<class... Ts>
1100 requires (D > 1) && (sizeof...(Ts) == D) && (std::convertible_to<Ts, value_type> && ...)
1101 constexpr coordinates_base(Ts... ts) noexcept(has_identity_validator)
1102 : m_Values{m_Validator(std::array<value_type, D>{ts...})}
1103 {}
1104
1105 template<class T>
1106 requires (D == 1) && (std::convertible_to<T, value_type>)
1107 constexpr explicit coordinates_base(T val) noexcept(has_identity_validator)
1108 : m_Values{m_Validator(val)}
1109 {}
1110
1111 template<class Self>
1112 constexpr Self& operator+=(this Self& self, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1113 {
1114 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1115 return self;
1116 }
1117
1118 template<class Self>
1119 requires has_distinguished_origin && (!std::is_same_v<coordinates_base, displacement_coordinates_type>)
1120 constexpr Self& operator+=(this Self& self, const coordinates_base& v) noexcept(has_identity_validator)
1121 {
1122 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1123 return self;
1124 }
1125
1126 template<class Self>
1127 constexpr Self& operator-=(this Self& self, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1128 {
1129 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs -= rhs; });
1130 return self;
1131 }
1132
1133 template<class Self>
1134 constexpr Self& operator*=(this Self& self, value_type u) noexcept(has_identity_validator)
1135 requires has_distinguished_origin
1136 {
1137 self.for_each_element([u](value_type& x) { return x *= u; });
1138 return self;
1139 }
1140
1141 template<class Self>
1142 constexpr Self& operator/=(this Self& self, value_type u)
1143 requires vector_space<free_module_type> && has_distinguished_origin
1144 {
1145 self.for_each_element([u](value_type& x) { return x /= u; });
1146 return self;
1147 }
1148
1149 template<class Derived>
1150 requires std::is_base_of_v<coordinates_base, Derived>
1151 [[nodiscard]]
1152 friend constexpr Derived operator+(Derived c, const displacement_coordinates_type& v) noexcept(has_identity_validator) { return c += v; }
1153
1154 template<class Derived>
1155 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>)
1156 [[nodiscard]]
1157 friend constexpr Derived operator+(const displacement_coordinates_type& v, Derived c) noexcept(has_identity_validator)
1158 {
1159 return c += v;
1160 }
1161
1162 template<class Derived>
1163 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>) && has_distinguished_origin
1164 [[nodiscard]]
1165 friend constexpr Derived operator+(Derived c, const Derived& v) noexcept(has_identity_validator)
1166 {
1167 return c += v;
1168 }
1169
1170 template<class Derived>
1171 requires std::is_base_of_v<coordinates_base, Derived>
1172 [[nodiscard]]
1173 friend constexpr Derived operator-(Derived c, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1174 {
1175 return c -= v;
1176 }
1177
1178 template<class Derived>
1179 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1180 [[nodiscard]]
1181 friend constexpr Derived operator*(Derived v, value_type u) noexcept(has_identity_validator)
1182 {
1183 return v *= u;
1184 }
1185
1186 template<class Derived>
1187 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1188 [[nodiscard]]
1189 friend constexpr Derived operator*(value_type u, Derived v) noexcept(has_identity_validator)
1190 {
1191 return v * u;
1192 }
1193
1194 template<class Derived>
1195 requires std::is_base_of_v<coordinates_base, Derived> && vector_space<free_module_type> && has_distinguished_origin
1196 [[nodiscard]]
1197 friend constexpr Derived operator/(Derived v, value_type u)
1198 {
1199 return v /= u;
1200 }
1201
1202 [[nodiscard]]
1203 constexpr const validator_type& validator() const noexcept { return m_Validator; }
1204
1205 [[nodiscard]]
1206 constexpr std::span<const value_type, D> values() const noexcept { return m_Values; }
1207
1208 [[nodiscard]]
1209 constexpr std::span<value_type, D> values() noexcept requires(has_identity_validator) { return m_Values; }
1210
1211 [[nodiscard]]
1212 constexpr const value_type& value() const noexcept requires (D == 1) { return m_Values[0]; }
1213
1214 [[nodiscard]]
1215 constexpr value_type& value() noexcept requires (D == 1) && has_identity_validator { return m_Values[0]; }
1216
1218 [[nodiscard]]
1219 constexpr explicit operator bool() const noexcept requires (D == 1) && std::convertible_to<value_type, bool>
1220 {
1221 return m_Values[0];
1222 }
1223
1224 [[nodiscard]]
1225 constexpr value_type operator[](std::size_t i) const { return m_Values[i]; }
1226
1227 [[nodiscard]]
1228 constexpr value_type& operator[](std::size_t i) requires(has_identity_validator) { return m_Values[i]; }
1229
1230 [[nodiscard]]
1231 friend constexpr bool operator==(const coordinates_base& lhs, const coordinates_base& rhs) noexcept { return lhs.m_Values == rhs.m_Values; }
1232
1233 [[nodiscard]]
1234 friend constexpr auto operator<=>(const coordinates_base& lhs, const coordinates_base& rhs) noexcept
1235 requires (D == 1) && std::totally_ordered<value_type>
1236 {
1237 return lhs.value() <=> rhs.value();
1238 }
1239 protected:
1240 coordinates_base(const coordinates_base&) = default;
1241 coordinates_base(coordinates_base&&) noexcept = default;
1242
1243 coordinates_base& operator=(const coordinates_base&) = default;
1244 coordinates_base& operator=(coordinates_base&&) noexcept = default;
1245
1246 ~coordinates_base() = default;
1247
1248 template<class Self, class Fn>
1249 requires std::invocable<Fn, value_type&, value_type>
1250 constexpr void apply_to_each_element(this Self& self, std::span<const value_type, D> rhs, Fn f)
1251 {
1252 if constexpr(has_identity_validator)
1253 {
1254 std::ranges::for_each(std::views::zip(self.values(), rhs), [&f](auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
1255 }
1256 else
1257 {
1258 auto tmp{self.m_Values};
1259 std::ranges::for_each(std::views::zip(tmp, rhs), [&f](auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
1260 self.m_Values = validate(tmp, self.m_Validator);
1261 }
1262 }
1263
1264 template<class Self, class Fn>
1265 requires std::invocable<Fn, value_type&>
1266 constexpr void for_each_element(this Self& self, Fn f)
1267 {
1268 if constexpr(has_identity_validator)
1269 {
1270 std::ranges::for_each(self.values(), f);
1271 }
1272 else
1273 {
1274 auto tmp{self.m_Values};
1275 std::ranges::for_each(tmp, f);
1276 self.m_Values = validate(tmp, self.m_Validator);
1277 }
1278 }
1279 private:
1280 SEQUOIA_NO_UNIQUE_ADDRESS validator_type m_Validator;
1281 std::array<value_type, D> m_Values{};
1282
1283 [[nodiscard]]
1284 static std::array<value_type, D> validate(std::span<const value_type, D> vals, Validator& validator)
1285 {
1286 return validate(utilities::to_array(vals), validator);
1287 }
1288
1289 [[nodiscard]]
1290 static std::array<value_type, D> validate(std::array<value_type, D> vals, Validator& validator)
1291 {
1292 if constexpr(validator_for_array<Validator, ConvexSpace>)
1293 return validator(vals);
1294 else
1295 return {validator(vals.front())};
1296 }
1297 };
1298
1303 template<convex_space ConvexSpace, basis_for<free_module_type_of_t<ConvexSpace>> Basis, class Origin, validator_for<ConvexSpace> Validator>
1304 class coordinates final : public coordinates_base<ConvexSpace, Basis, Origin, Validator>
1305 {
1306 public:
1308 using base_type::base_type;
1309 using displacement_coordinates_type = base_type::displacement_coordinates_type;
1310 using value_type = base_type::value_type;
1311 constexpr static bool has_identity_validator{base_type::has_identity_validator};
1312
1313 [[nodiscard]]
1314 friend constexpr displacement_coordinates_type operator-(const coordinates& lhs, const coordinates& rhs) noexcept(has_identity_validator)
1315 {
1316 return[&] <std::size_t... Is>(std::index_sequence<Is...>) {
1317 return displacement_coordinates_type{(lhs.values()[Is] - rhs.values()[Is])...};
1318 }(std::make_index_sequence<base_type::D>{});
1319 }
1320
1321 [[nodiscard]]
1322 constexpr coordinates operator+() const noexcept(has_identity_validator)
1323 {
1324 return coordinates{this->values()};
1325 }
1326
1327 [[nodiscard]]
1328 constexpr coordinates operator-() const noexcept(has_identity_validator)
1329 {
1330 return coordinates{utilities::to_array(this->values(), [](value_type t) { return -t; })};
1331 }
1332 };
1333
1334 namespace sets
1335 {
1339 template<std::size_t D>
1340 struct Z
1341 {
1342 constexpr static std::size_t dimension{D};
1343 };
1344
1348 template<std::size_t D>
1349 struct N_0
1350 {
1351 constexpr static std::size_t dimension{D};
1352 };
1353
1357 template<std::size_t D>
1358 struct R
1359 {
1360 constexpr static std::size_t dimension{D};
1361 };
1362
1363
1367 template<std::size_t D>
1368 struct orthant
1369 {
1370 constexpr static std::size_t dimension{D};
1371 };
1372
1376 template<std::size_t D>
1377 struct C
1378 {
1379 constexpr static std::size_t dimension{D};
1380 };
1381 }
1382
1383 template<class B>
1384 inline constexpr bool is_orthonormal_basis_v{
1385 requires {
1386 typename B::orthonormal;
1387 requires std::same_as<typename B::orthonormal, std::true_type>;
1388 }
1389 };
1390
1391 template<vector_space V>
1393
1394 template<vector_space V>
1395 inline constexpr bool has_norm_v{
1396 requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
1397 { norm(v) } -> std::convertible_to<typename V::field_type>;
1398 }
1399 };
1400
1401 template<vector_space V>
1402 inline constexpr bool has_inner_product_v{
1403 requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
1404 { inner_product(v, v) } -> std::convertible_to<typename V::field_type>;
1405 }
1406 };
1407
1408 template<class V>
1409 concept normed_vector_space = vector_space<V> && has_norm_v<V>;
1410
1411 template<class V>
1412 concept inner_product_space = vector_space<V> && has_inner_product_v<V>;
1413
1414 template<std::size_t D, std::floating_point T>
1416 {
1417 using set_type = sets::R<D>;
1418 using field_type = T;
1419 using is_vector_space = std::true_type;
1420 constexpr static std::size_t dimension{D};
1421
1422 template<basis Basis>
1423 requires is_orthonormal_basis_v<Basis>
1424 [[nodiscard]]
1425 friend constexpr field_type inner_product(const vector_coordinates<euclidean_vector_space, Basis>& v, const vector_coordinates<euclidean_vector_space, Basis>& w)
1426 {
1427 return std::ranges::fold_left(std::views::zip(v.values(), w.values()), field_type{}, [](field_type f, const auto& z){ return f + std::get<0>(z) * std::get<1>(z); });
1428 }
1429
1430 template<basis Basis>
1431 requires is_orthonormal_basis_v<Basis>
1432 [[nodiscard]]
1434 {
1435 return inner_product(v, w);
1436 }
1437
1438 template<basis Basis>
1439 requires is_orthonormal_basis_v<Basis>
1440 [[nodiscard]]
1441 friend constexpr field_type norm(const vector_coordinates<euclidean_vector_space, Basis>& v)
1442 {
1443 if constexpr(D == 1)
1444 {
1445 return std::abs(v.value());
1446 }
1447 else
1448 {
1449 return std::sqrt(inner_product(v, v));
1450 }
1451 }
1452 };
1453
1454 template<std::size_t D, std::floating_point T>
1456 {
1457 using set_type = sets::R<D>;
1459 using is_affine_space = std::true_type;
1460 };
1461
1462 template<std::floating_point T>
1464 {
1465 using set_type = sets::orthant<1>;
1467 using is_convex_space = std::true_type;
1468 };
1469
1470 template<std::size_t D, std::floating_point T, basis Basis, class Origin>
1472
1473 template<std::size_t D, std::floating_point T, basis Basis>
1475
1476 template<std::size_t D, std::floating_point T>
1478 {
1480 using orthonormal = std::true_type;
1481 };
1482
1483 template<std::size_t D, std::floating_point T>
1485}
Utility to convert an initializer_list into an array, potentially transforming the initializer_list i...
Concepts which are sufficiently general to appear in the sequoia namespace.
Class designed for inheritance by concerete coordinate types.
Definition: Spaces.hpp:1076
Forward declaration for the coordinates class template.
Definition: Spaces.hpp:1305
concept for affine spaces
Definition: Spaces.hpp:529
A concept to determine if a basis is appropriate for a particular free module.
Definition: Spaces.hpp:620
A basis must identify the free module to which it corresponds.
Definition: Spaces.hpp:614
concept for convex spaces
Definition: Spaces.hpp:517
concept for a free module, implicitly understood to be over a commutative ring.
Definition: Spaces.hpp:476
Definition: Spaces.hpp:1412
Definition: Spaces.hpp:1409
concept to check if a validator is compatible with a convex space.
Definition: Spaces.hpp:676
concept for a vector space, which is a special case of a free module
Definition: Spaces.hpp:482
concept representing reasonable approximations to a commutative ring.
Definition: Spaces.hpp:322
concept representing reasonable approximations to a field.
Definition: Spaces.hpp:334
constexpr bool is_multiplicable_v
Compile time constant for multiplicability.
Definition: Spaces.hpp:222
constexpr bool is_divisible_v
Compile time constant for divisibility.
Definition: Spaces.hpp:233
constexpr bool is_subtractable_v
Compile time constant for subtractability.
Definition: Spaces.hpp:211
constexpr bool is_addable_v
Compile time constant for addability.
Definition: Spaces.hpp:200
constexpr bool identifies_as_convex_space_v
Compile time constant reflecting whether a space self-identifies as convex.
Definition: Spaces.hpp:424
constexpr bool identifies_as_free_module_v
Compile time constant reflecting whether a space self-identifies as a free module.
Definition: Spaces.hpp:446
constexpr bool identifies_as_affine_space_v
Compile time constant reflecting whether a space self-identifies as affine.
Definition: Spaces.hpp:435
constexpr bool identifies_as_vector_space_v
Compile time constant reflecting whether a space self-identifies as vector space.
Definition: Spaces.hpp:457
constexpr bool has_commutative_ring_type_v
Compile time constant reflecting whether a type exposes a nested type named commutative_ring_type whi...
Definition: Spaces.hpp:344
constexpr bool has_free_module_type_v
Compile time constant reflecting whether a type exposes a nested free_modul_type which satisfies the ...
Definition: Spaces.hpp:501
constexpr bool defines_commutative_ring_v
Compile time constant reflecting whether a type exposes a nested type with the properties of a commut...
Definition: Spaces.hpp:369
constexpr bool has_field_type_v
Compile time constant reflecting whether a type exposes a nested type named field_type which satisife...
Definition: Spaces.hpp:355
constexpr bool has_vector_space_type_v
Compile time constant reflecting whether a type exposes a nested vector_space_type which satisfies th...
Definition: Spaces.hpp:489
constexpr bool has_dimension_v
Compile time constant reflecting whether a type exposes a nested value, dimension,...
Definition: Spaces.hpp:391
constexpr std::size_t dimension_of
Helper to extract the dimension of the free module associated with a convex space.
Definition: Spaces.hpp:602
constexpr bool defines_field_v
Reports whether a type exposes a nested type with the properties of a field.
Definition: Spaces.hpp:379
constexpr bool has_set_type_v
Compile time constant reflecting whether a type exposes a nested type named set_type.
Definition: Spaces.hpp:399
constexpr bool validator_for_single_value
Validators for spaces of dimension 1 must provide an operator() for validating single values.
Definition: Spaces.hpp:652
constexpr bool validator_for_array
Validators for spaces of dimension d>1 must provide an operator() for an array of d values.
Definition: Spaces.hpp:666
Definition: Spaces.hpp:1392
Helper to extract the commutative ring type of the free module associated with a convex space.
Definition: Spaces.hpp:580
Trait to determine if a type defines the half line.
Definition: Spaces.hpp:726
Definition: Spaces.hpp:763
Type to indicate a distinguished origin, relevant for free modules.
Definition: Spaces.hpp:1010
Specialization for units, such as degrees Celsius, for which the corresponding quantity cannot be inv...
Definition: PhysicalValues.hpp:37
Helper to generate the dual of a space, taking into account that the dual of the dual may be related ...
Definition: Spaces.hpp:964
Primary class template for defining duals.
Definition: Spaces.hpp:896
Definition: Spaces.hpp:1456
Definition: Spaces.hpp:1464
Definition: Spaces.hpp:1416
Helper to extract the free module type associated with a convex space.
Definition: Spaces.hpp:547
A validator the the half line.
Definition: Spaces.hpp:703
Definition: Spaces.hpp:801
Helper to detect if a type is defined as a dual of something else.
Definition: Spaces.hpp:938
Helper that universal template parameters will obviate the need for.
Definition: Spaces.hpp:535
Trait for validators that behave like the identity.
Definition: Spaces.hpp:686
Trait for specifying whether a type exhibits multiplication that (approximately) distributes over add...
Definition: Spaces.hpp:308
Class template for giving a name to the set of complex numbers and its generalization to other dimens...
Definition: Spaces.hpp:1378
Class template for giving a name to the set of semi-positive integers and its generalization to other...
Definition: Spaces.hpp:1350
Class template for giving a name to the set of real numbers and its generalization to other dimension...
Definition: Spaces.hpp:1359
Class template for giving a name to the set of integers and its generalization to other dimensionalit...
Definition: Spaces.hpp:1341
Class template for giving a name to convex functionals.
Definition: Spaces.hpp:876
Class template for giving a name to linear functionals.
Definition: Spaces.hpp:888
Class template for giving a name to the set of non-negative real numbers and its generalization to ot...
Definition: Spaces.hpp:1369
Definition: Spaces.hpp:1478
Trait for specifying whether a type behaves (appoximately) as an abelian group under addition.
Definition: Spaces.hpp:261
Trait for specifying whether a type behaves (appoximately) as an abelian group under multiplication.
Definition: Spaces.hpp:286