156#include "sequoia/PlatformSpecific/Preprocessor.hpp"
166namespace sequoia::maths
202 { t += t } -> std::same_as<T&>;
203 { t + t } -> std::convertible_to<T>;
213 { t -= t } -> std::same_as<T&>;
214 { t - t } -> std::convertible_to<T>;
224 { t *= t } -> std::same_as<T&>;
225 { t * t } -> std::convertible_to<T>;
235 { t /= t } -> std::same_as<T&>;
236 { t / t } -> std::convertible_to<T>;
269 template<arithmetic T>
272 template<std::
floating_po
int T>
294 template<std::
floating_po
int T>
297 template<std::
floating_po
int T>
323 && weakly_abelian_group_under_addition_v<T>
324 && multiplication_weakly_distributive_over_addition_v<T>
326 && is_subtractable_v<T>
327 && is_multiplicable_v<T>;
346 typename T::commutative_ring_type;
357 typename T::field_type;
382 typename T::commutative_ring_type;
392 requires { { T::dimension } -> std::convertible_to<std::size_t>; }
400 requires {
typename T::set_type; }
426 typename T::is_convex_space;
427 requires std::convertible_to<typename T::is_convex_space, std::true_type>;
437 typename T::is_affine_space;
438 requires std::convertible_to<typename T::is_affine_space, std::true_type>;
448 typename T::is_free_module;
449 requires std::convertible_to<typename T::is_free_module, std::true_type>;
459 typename T::is_vector_space;
460 requires std::convertible_to<typename T::is_vector_space, std::true_type>;
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>);
491 typename T::vector_space_type;
503 typename T::free_module_type;
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>));
546 template<convex_space ConvexSpace>
549 template<convex_space ConvexSpace>
550 requires identifies_as_free_module_v<ConvexSpace> || identifies_as_vector_space_v<ConvexSpace>
553 using type = ConvexSpace;
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>
560 using type = ConvexSpace::free_module_type;
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>
567 using type = ConvexSpace::vector_space_type;
570 template<convex_space ConvexSpace>
571 using free_module_type_of_t = free_module_type_of<ConvexSpace>::type;
578 template<convex_space ConvexSpace>
581 using type = free_module_type_of_t<ConvexSpace>::commutative_ring_type;
584 template<convex_space ConvexSpace>
588 using type = free_module_type_of_t<ConvexSpace>::field_type;
591 template<convex_space ConvexSpace>
592 using commutative_ring_type_of_t = commutative_ring_type_of<ConvexSpace>::type;
594 template<convex_space ConvexSpace>
595 using space_value_type = commutative_ring_type_of_t<ConvexSpace>;
601 template<convex_space ConvexSpace>
602 inline constexpr std::size_t
dimension_of{free_module_type_of_t<ConvexSpace>::dimension};
614 concept basis = has_free_module_type_v<B> || has_vector_space_type_v<B>;
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>; });
651 template<
class V,
class ConvexSpace>
653 (dimension_of<ConvexSpace> == 1)
654 &&
requires(V& v,
const space_value_type<ConvexSpace>& val) { { v(val) } -> std::convertible_to<
decltype(val)>; }
665 template<
class V,
class ConvexSpace>
667 requires (V& v,
const std::array<space_value_type<ConvexSpace>, dimension_of<ConvexSpace>>& values) {
668 { v(values) } -> std::convertible_to<
decltype(values)>;
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>);
704 template<arithmetic T>
706 constexpr T operator()(
const T val)
const
708 if(val < T{})
throw std::domain_error{std::format(
"Value {} less than zero", val)};
713 template<arithmetic T>
714 requires std::is_unsigned_v<T>
716 constexpr T operator()(
const T val)
const
761 template<
class... Ts>
767 inline constexpr bool has_common_ring_v{
771 template<free_module... Ts>
772 requires (
sizeof...(Ts) >= 1) && has_common_ring_v<commutative_ring_type_of_t<Ts>...>
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 + ...)};
787 using is_affine_space = std::true_type;
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...>
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;
803 template<
class... Ts>
874 template<convex_space From,
class To>
886 template<vector_space From,
class To>
901 template<convex_space C>
907 using is_convex_space = std::true_type;
913 template<affine_space A>
919 using is_affine_space = std::true_type;
925 template<vector_space V>
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};
961 using dual_of_t = dual_of<T>::type;
1030 template<affine_space AffineSpace, basis_for<free_module_type_of_t<AffineSpace>> Basis,
class Origin>
1036 template<vector_space VectorSpace, basis_for<free_module_type_of_t<VectorSpace>> Basis>
1042 template<free_module FreeModule, basis_for<free_module_type_of_t<FreeModule>> Basis>
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;
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};
1095 constexpr explicit coordinates_base(std::span<const value_type, D> vals)
noexcept(has_identity_validator)
1096 : m_Values{validate(vals, m_Validator)}
1099 template<
class... Ts>
1100 requires (D > 1) && (
sizeof...(Ts) == D) && (std::convertible_to<Ts, value_type> && ...)
1102 : m_Values{m_Validator(std::array<value_type, D>{ts...})}
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)}
1111 template<
class Self>
1112 constexpr Self& operator+=(
this Self& self,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1114 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
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)
1122 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1126 template<
class Self>
1127 constexpr Self& operator-=(
this Self& self,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1129 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs -= rhs; });
1133 template<
class Self>
1134 constexpr Self& operator*=(
this Self& self, value_type u)
noexcept(has_identity_validator)
1135 requires has_distinguished_origin
1137 self.for_each_element([u](value_type& x) {
return x *= u; });
1141 template<
class Self>
1142 constexpr Self& operator/=(
this Self& self, value_type u)
1145 self.for_each_element([u](value_type& x) {
return x /= u; });
1149 template<
class Derived>
1150 requires std::is_base_of_v<coordinates_base, Derived>
1152 friend constexpr Derived operator+(Derived c,
const displacement_coordinates_type& v)
noexcept(has_identity_validator) {
return c += v; }
1154 template<
class Derived>
1155 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>)
1157 friend constexpr Derived
operator+(
const displacement_coordinates_type& v, Derived c)
noexcept(has_identity_validator)
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
1165 friend constexpr Derived
operator+(Derived c,
const Derived& v)
noexcept(has_identity_validator)
1170 template<
class Derived>
1171 requires std::is_base_of_v<coordinates_base, Derived>
1173 friend constexpr Derived operator-(Derived c,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1178 template<
class Derived>
1179 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1181 friend constexpr Derived operator*(Derived v, value_type u)
noexcept(has_identity_validator)
1186 template<
class Derived>
1187 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1189 friend constexpr Derived operator*(value_type u, Derived v)
noexcept(has_identity_validator)
1194 template<
class Derived>
1197 friend constexpr Derived operator/(Derived v, value_type u)
1203 constexpr const validator_type& validator()
const noexcept {
return m_Validator; }
1206 constexpr std::span<const value_type, D> values()
const noexcept {
return m_Values; }
1209 constexpr std::span<value_type, D> values()
noexcept requires(has_identity_validator) {
return m_Values; }
1212 constexpr const value_type& value()
const noexcept requires (D == 1) {
return m_Values[0]; }
1215 constexpr value_type& value()
noexcept requires (D == 1) && has_identity_validator {
return m_Values[0]; }
1219 constexpr explicit operator bool() const noexcept requires (D == 1) && std::convertible_to<value_type,
bool>
1225 constexpr value_type operator[](std::size_t i)
const {
return m_Values[i]; }
1228 constexpr value_type& operator[](std::size_t i)
requires(has_identity_validator) {
return m_Values[i]; }
1231 friend constexpr bool operator==(
const coordinates_base& lhs,
const coordinates_base& rhs)
noexcept {
return lhs.m_Values == rhs.m_Values; }
1234 friend constexpr auto operator<=>(
const coordinates_base& lhs,
const coordinates_base& rhs)
noexcept
1235 requires (D == 1) && std::totally_ordered<value_type>
1237 return lhs.value() <=> rhs.value();
1240 coordinates_base(
const coordinates_base&) =
default;
1241 coordinates_base(coordinates_base&&) noexcept = default;
1243 coordinates_base& operator=(const coordinates_base&) = default;
1244 coordinates_base& operator=(coordinates_base&&) noexcept = default;
1246 ~coordinates_base() = default;
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)
1252 if constexpr(has_identity_validator)
1254 std::ranges::for_each(std::views::zip(self.values(), rhs), [&f](
auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
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);
1264 template<
class Self,
class Fn>
1265 requires std::invocable<Fn, value_type&>
1266 constexpr void for_each_element(
this Self& self, Fn f)
1268 if constexpr(has_identity_validator)
1270 std::ranges::for_each(self.values(), f);
1274 auto tmp{self.m_Values};
1275 std::ranges::for_each(tmp, f);
1276 self.m_Values = validate(tmp, self.m_Validator);
1280 SEQUOIA_NO_UNIQUE_ADDRESS validator_type m_Validator;
1281 std::array<value_type, D> m_Values{};
1284 static std::array<value_type, D> validate(std::span<const value_type, D> vals, Validator& validator)
1286 return validate(utilities::to_array(vals), validator);
1290 static std::array<value_type, D> validate(std::array<value_type, D> vals, Validator& validator)
1292 if constexpr(validator_for_array<Validator, ConvexSpace>)
1293 return validator(vals);
1295 return {validator(vals.front())};
1303 template<convex_space ConvexSpace, basis_for<free_module_type_of_t<ConvexSpace>> Basis,
class Origin, val
idator_for<ConvexSpace> Val
idator>
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};
1314 friend constexpr displacement_coordinates_type operator-(
const coordinates& lhs,
const coordinates& rhs)
noexcept(has_identity_validator)
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>{});
1322 constexpr coordinates operator+()
const noexcept(has_identity_validator)
1328 constexpr coordinates operator-()
const noexcept(has_identity_validator)
1330 return coordinates{utilities::to_array(this->values(), [](value_type t) {
return -t; })};
1339 template<std::
size_t D>
1342 constexpr static std::size_t dimension{D};
1348 template<std::
size_t D>
1351 constexpr static std::size_t dimension{D};
1357 template<std::
size_t D>
1360 constexpr static std::size_t dimension{D};
1367 template<std::
size_t D>
1370 constexpr static std::size_t dimension{D};
1376 template<std::
size_t D>
1379 constexpr static std::size_t dimension{D};
1384 inline constexpr bool is_orthonormal_basis_v{
1386 typename B::orthonormal;
1387 requires std::same_as<typename B::orthonormal, std::true_type>;
1391 template<vector_space V>
1394 template<vector_space V>
1395 inline constexpr bool has_norm_v{
1397 { norm(v) } -> std::convertible_to<typename V::field_type>;
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>;
1414 template<std::
size_t D, std::
floating_po
int T>
1418 using field_type = T;
1419 using is_vector_space = std::true_type;
1420 constexpr static std::size_t dimension{D};
1422 template<basis Basis>
1423 requires is_orthonormal_basis_v<Basis>
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); });
1430 template<basis Basis>
1431 requires is_orthonormal_basis_v<Basis>
1435 return inner_product(v, w);
1438 template<basis Basis>
1439 requires is_orthonormal_basis_v<Basis>
1443 if constexpr(D == 1)
1445 return std::abs(v.value());
1449 return std::sqrt(inner_product(v, v));
1454 template<std::
size_t D, std::
floating_po
int T>
1459 using is_affine_space = std::true_type;
1462 template<std::
floating_po
int T>
1467 using is_convex_space = std::true_type;
1470 template<std::
size_t D, std::
floating_po
int T, basis Basis,
class Origin>
1473 template<std::
size_t D, std::
floating_po
int T, basis Basis>
1476 template<std::
size_t D, std::
floating_po
int T>
1480 using orthonormal = std::true_type;
1483 template<std::
size_t D, std::
floating_po
int T>
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