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 bool has_freely_mutable_components{has_identity_validator && has_distinguished_origin};
1091 constexpr static std::size_t dimension{free_module_type::dimension};
1092 constexpr static std::size_t D{dimension};
1093
1094 constexpr coordinates_base() noexcept = default;
1095
1096 constexpr explicit coordinates_base(std::span<const value_type, D> vals) noexcept(has_identity_validator)
1097 : m_Values{validate(vals, m_Validator)}
1098 {}
1099
1100 template<class... Ts>
1101 requires (D > 1) && (std::convertible_to<Ts, value_type> && ...)
1102 constexpr explicit(sizeof...(Ts) == 1) coordinates_base(Ts... ts) noexcept(has_identity_validator)
1103 : m_Values{m_Validator(std::array<value_type, D>{ts...})}
1104 {}
1105
1106 template<class T>
1107 requires (D == 1) && (std::convertible_to<T, value_type>)
1108 constexpr explicit coordinates_base(T val) noexcept(has_identity_validator)
1109 : m_Values{m_Validator(val)}
1110 {}
1111
1112 template<class Self>
1113 constexpr Self& operator+=(this Self& self, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1114 {
1115 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1116 return self;
1117 }
1118
1119 template<class Self>
1120 requires has_distinguished_origin && (!std::is_same_v<coordinates_base, displacement_coordinates_type>)
1121 constexpr Self& operator+=(this Self& self, const coordinates_base& v) noexcept(has_identity_validator)
1122 {
1123 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1124 return self;
1125 }
1126
1127 template<class Self>
1128 constexpr Self& operator-=(this Self& self, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1129 {
1130 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs -= rhs; });
1131 return self;
1132 }
1133
1134 template<class Self>
1135 constexpr Self& operator*=(this Self& self, value_type u) noexcept(has_identity_validator)
1136 requires has_distinguished_origin
1137 {
1138 self.for_each_element([u](value_type& x) { return x *= u; });
1139 return self;
1140 }
1141
1142 template<class Self>
1143 constexpr Self& operator/=(this Self& self, value_type u)
1144 requires vector_space<free_module_type> && has_distinguished_origin
1145 {
1146 self.for_each_element([u](value_type& x) { return x /= u; });
1147 return self;
1148 }
1149
1150 template<class Self>
1151 [[nodiscard]]
1152 constexpr Self operator+(this const Self& self) noexcept
1153 {
1154 return self;
1155 }
1156
1157 template<class Self>
1158 requires std::constructible_from<Self, std::span<const value_type, D>>
1159 && has_distinguished_origin
1160 && (!std::is_unsigned_v<value_type>)
1161 [[nodiscard]]
1162 constexpr Self operator-(this const Self& self) noexcept(has_identity_validator)
1163 {
1164 return Self{utilities::to_array(self.values(), [](value_type t) { return -t; })};
1165 }
1166
1167 template<class Derived>
1168 requires std::is_base_of_v<coordinates_base, Derived>
1169 && (!std::is_same_v<Derived, displacement_coordinates_type>)
1170 && std::constructible_from<typename Derived::displacement_coordinates_type, std::span<const value_type, D>>
1171 [[nodiscard]]
1172 friend constexpr typename Derived::displacement_coordinates_type operator-(const Derived& lhs, const Derived& rhs) noexcept(has_identity_validator)
1173 {
1174 return[&] <std::size_t... Is>(std::index_sequence<Is...>) {
1175 return typename Derived::displacement_coordinates_type{(lhs.values()[Is] - rhs.values()[Is])...};
1176 }(std::make_index_sequence<D>{});
1177 }
1178
1179 template<class Derived>
1180 requires std::is_base_of_v<coordinates_base, Derived>
1181 [[nodiscard]]
1182 friend constexpr Derived operator+(Derived c, const displacement_coordinates_type& v) noexcept(has_identity_validator) { return c += v; }
1183
1184 template<class Derived>
1185 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>)
1186 [[nodiscard]]
1187 friend constexpr Derived operator+(const displacement_coordinates_type& v, Derived c) noexcept(has_identity_validator)
1188 {
1189 return c += v;
1190 }
1191
1192 template<class Derived>
1193 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>) && has_distinguished_origin
1194 [[nodiscard]]
1195 friend constexpr Derived operator+(Derived c, const Derived& v) noexcept(has_identity_validator)
1196 {
1197 return c += v;
1198 }
1199
1200 template<class Derived>
1201 requires std::is_base_of_v<coordinates_base, Derived>
1202 [[nodiscard]]
1203 friend constexpr Derived operator-(Derived c, const displacement_coordinates_type& v) noexcept(has_identity_validator)
1204 {
1205 return c -= v;
1206 }
1207
1208 template<class Derived>
1209 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1210 [[nodiscard]]
1211 friend constexpr Derived operator*(Derived v, value_type u) noexcept(has_identity_validator)
1212 {
1213 return v *= u;
1214 }
1215
1216 template<class Derived>
1217 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1218 [[nodiscard]]
1219 friend constexpr Derived operator*(value_type u, Derived v) noexcept(has_identity_validator)
1220 {
1221 return v * u;
1222 }
1223
1224 template<class Derived>
1225 requires std::is_base_of_v<coordinates_base, Derived> && vector_space<free_module_type> && has_distinguished_origin
1226 [[nodiscard]]
1227 friend constexpr Derived operator/(Derived v, value_type u)
1228 {
1229 return v /= u;
1230 }
1231
1232 [[nodiscard]]
1233 constexpr const validator_type& validator() const noexcept { return m_Validator; }
1234
1235 [[nodiscard]]
1236 constexpr std::span<const value_type, D> values() const noexcept { return m_Values; }
1237
1238 [[nodiscard]]
1239 constexpr std::span<value_type, D> values() noexcept requires has_freely_mutable_components { return m_Values; }
1240
1241 [[nodiscard]]
1242 constexpr const value_type& value() const noexcept requires (D == 1) { return m_Values[0]; }
1243
1244 [[nodiscard]]
1245 constexpr value_type& value() noexcept requires (D == 1) && has_freely_mutable_components { return m_Values[0]; }
1246
1248 [[nodiscard]]
1249 constexpr explicit operator bool() const noexcept requires (D == 1) && std::convertible_to<value_type, bool>
1250 {
1251 return m_Values[0];
1252 }
1253
1254 [[nodiscard]]
1255 constexpr value_type operator[](std::size_t i) const { return m_Values[i]; }
1256
1257 [[nodiscard]]
1258 constexpr value_type& operator[](std::size_t i) requires has_freely_mutable_components { return m_Values[i]; }
1259
1260 [[nodiscard]]
1261 constexpr auto begin() const noexcept { return m_Values.begin(); }
1262
1263 [[nodiscard]]
1264 constexpr auto end() const noexcept { return m_Values.end(); }
1265
1266 [[nodiscard]]
1267 constexpr auto rbegin() const noexcept { return m_Values.rbegin(); }
1268
1269 [[nodiscard]]
1270 constexpr auto rend() const noexcept { return m_Values.rend(); }
1271
1272 [[nodiscard]]
1273 constexpr auto cbegin() const noexcept { return begin(); }
1274
1275 [[nodiscard]]
1276 constexpr auto cend() const noexcept { return end(); }
1277
1278 [[nodiscard]]
1279 constexpr auto crbegin() const noexcept { return rbegin(); }
1280
1281 [[nodiscard]]
1282 constexpr auto crend() const noexcept { return rend(); }
1283
1284 [[nodiscard]]
1285 constexpr auto begin() noexcept requires has_freely_mutable_components { return m_Values.begin(); }
1286
1287 [[nodiscard]]
1288 constexpr auto end() noexcept requires has_freely_mutable_components { return m_Values.end(); }
1289
1290 [[nodiscard]]
1291 constexpr auto rbegin() noexcept requires has_freely_mutable_components { return m_Values.rbegin(); }
1292
1293 [[nodiscard]]
1294 constexpr auto rend() noexcept requires has_freely_mutable_components { return m_Values.rend(); }
1295
1296
1297 [[nodiscard]]
1298 friend constexpr bool operator==(const coordinates_base& lhs, const coordinates_base& rhs) noexcept { return lhs.m_Values == rhs.m_Values; }
1299
1300 [[nodiscard]]
1301 friend constexpr auto operator<=>(const coordinates_base& lhs, const coordinates_base& rhs) noexcept
1302 requires (D == 1) && std::totally_ordered<value_type>
1303 {
1304 return lhs.value() <=> rhs.value();
1305 }
1306 protected:
1307 coordinates_base(const coordinates_base&) = default;
1308 coordinates_base(coordinates_base&&) noexcept = default;
1309
1310 coordinates_base& operator=(const coordinates_base&) = default;
1311 coordinates_base& operator=(coordinates_base&&) noexcept = default;
1312
1313 ~coordinates_base() = default;
1314
1315 template<class Self, class Fn>
1316 requires std::invocable<Fn, value_type&, value_type>
1317 constexpr void apply_to_each_element(this Self& self, std::span<const value_type, D> rhs, Fn f)
1318 {
1319 if constexpr(has_identity_validator)
1320 {
1321 std::ranges::for_each(std::views::zip(self.m_Values, rhs), [&f](auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
1322 }
1323 else
1324 {
1325 auto tmp{self.m_Values};
1326 std::ranges::for_each(std::views::zip(tmp, rhs), [&f](auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
1327 self.m_Values = validate(tmp, self.m_Validator);
1328 }
1329 }
1330
1331 template<class Self, class Fn>
1332 requires std::invocable<Fn, value_type&>
1333 constexpr void for_each_element(this Self& self, Fn f)
1334 {
1335 if constexpr(has_identity_validator)
1336 {
1337 std::ranges::for_each(self.values(), f);
1338 }
1339 else
1340 {
1341 auto tmp{self.m_Values};
1342 std::ranges::for_each(tmp, f);
1343 self.m_Values = validate(tmp, self.m_Validator);
1344 }
1345 }
1346 private:
1347 SEQUOIA_NO_UNIQUE_ADDRESS validator_type m_Validator;
1348 std::array<value_type, D> m_Values{};
1349
1350 [[nodiscard]]
1351 static std::array<value_type, D> validate(std::span<const value_type, D> vals, Validator& validator)
1352 {
1353 return validate(utilities::to_array(vals), validator);
1354 }
1355
1356 [[nodiscard]]
1357 static std::array<value_type, D> validate(std::array<value_type, D> vals, Validator& validator)
1358 {
1359 if constexpr(validator_for_array<Validator, ConvexSpace>)
1360 return validator(vals);
1361 else
1362 return {validator(vals.front())};
1363 }
1364 };
1365
1370 template<convex_space ConvexSpace, basis_for<free_module_type_of_t<ConvexSpace>> Basis, class Origin, validator_for<ConvexSpace> Validator>
1371 class coordinates final : public coordinates_base<ConvexSpace, Basis, Origin, Validator>
1372 {
1373 public:
1374 using coordinates_base<ConvexSpace, Basis, Origin, Validator>::coordinates_base;
1375 };
1376
1377 namespace sets
1378 {
1382 template<std::size_t D>
1383 struct Z
1384 {
1385 constexpr static std::size_t dimension{D};
1386 };
1387
1391 template<std::size_t D>
1392 struct N_0
1393 {
1394 constexpr static std::size_t dimension{D};
1395 };
1396
1400 template<std::size_t D>
1401 struct R
1402 {
1403 constexpr static std::size_t dimension{D};
1404 };
1405
1406
1410 template<std::size_t D>
1411 struct orthant
1412 {
1413 constexpr static std::size_t dimension{D};
1414 };
1415
1419 template<std::size_t D>
1420 struct C
1421 {
1422 constexpr static std::size_t dimension{D};
1423 };
1424 }
1425
1426 template<class B>
1427 inline constexpr bool is_orthonormal_basis_v{
1428 requires {
1429 typename B::orthonormal;
1430 requires std::same_as<typename B::orthonormal, std::true_type>;
1431 }
1432 };
1433
1434 template<vector_space V>
1436
1437 template<vector_space V>
1438 inline constexpr bool has_norm_v{
1439 requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
1440 { norm(v) } -> std::convertible_to<typename V::field_type>;
1441 }
1442 };
1443
1444 template<vector_space V>
1445 inline constexpr bool has_inner_product_v{
1446 requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
1447 { inner_product(v, v) } -> std::convertible_to<typename V::field_type>;
1448 }
1449 };
1450
1451 template<class V>
1452 concept normed_vector_space = vector_space<V> && has_norm_v<V>;
1453
1454 template<class V>
1455 concept inner_product_space = vector_space<V> && has_inner_product_v<V>;
1456
1458
1459 template<std::floating_point T, std::size_t D, class Arena=mathematical_arena>
1461 {
1462 using set_type = sets::R<D>;
1463 using field_type = T;
1464 using is_vector_space = std::true_type;
1465 using arena_type = Arena;
1466 constexpr static std::size_t dimension{D};
1467
1468 template<basis Basis>
1469 requires is_orthonormal_basis_v<Basis>
1470 [[nodiscard]]
1471 friend constexpr field_type inner_product(const vector_coordinates<euclidean_vector_space, Basis>& v, const vector_coordinates<euclidean_vector_space, Basis>& w)
1472 {
1473 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); });
1474 }
1475
1476 template<basis Basis>
1477 requires is_orthonormal_basis_v<Basis>
1478 [[nodiscard]]
1480 {
1481 return inner_product(v, w);
1482 }
1483
1484 template<basis Basis>
1485 requires is_orthonormal_basis_v<Basis>
1486 [[nodiscard]]
1487 friend constexpr field_type norm(const vector_coordinates<euclidean_vector_space, Basis>& v)
1488 {
1489 if constexpr(D == 1)
1490 {
1491 return std::abs(v.value());
1492 }
1493 else
1494 {
1495 return std::sqrt(inner_product(v, v));
1496 }
1497 }
1498 };
1499
1500 template<std::floating_point T, std::size_t D, class Arena=mathematical_arena>
1502 {
1503 using set_type = sets::R<D>;
1505 using is_affine_space = std::true_type;
1506 using arena_type = Arena;
1507 };
1508
1509 template<std::floating_point T, class Arena=mathematical_arena>
1511 {
1512 using set_type = sets::orthant<1>;
1514 using is_convex_space = std::true_type;
1515 using arena_type = Arena;
1516 };
1517
1518 template<std::floating_point T, std::size_t D, basis Basis, class Origin, class Arena=mathematical_arena>
1520
1521 template<std::floating_point T, std::size_t D, basis Basis, class Arena=mathematical_arena>
1523
1529 template<free_module M>
1531 {
1532 using free_module_type = M;
1533 };
1534
1535 template<free_module M>
1537 {
1539 };
1540
1541 template<free_module M>
1543 {
1545 };
1546
1547 template<std::floating_point T, std::size_t D, class Arena=mathematical_arena>
1549}
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:1372
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:1455
Definition: Spaces.hpp:1452
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:1435
Right-handed bases for arbitrary D, build recursively from 1D.
Definition: Spaces.hpp:1531
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:1502
Definition: Spaces.hpp:1511
Definition: Spaces.hpp:1461
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
Definition: Spaces.hpp:1457
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:1421
Class template for giving a name to the set of semi-positive integers and its generalization to other...
Definition: Spaces.hpp:1393
Class template for giving a name to the set of real numbers and its generalization to other dimension...
Definition: Spaces.hpp:1402
Class template for giving a name to the set of integers and its generalization to other dimensionalit...
Definition: Spaces.hpp:1384
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:1412
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