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 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};
1096 constexpr explicit coordinates_base(std::span<const value_type, D> vals)
noexcept(has_identity_validator)
1097 : m_Values{validate(vals, m_Validator)}
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...})}
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)}
1112 template<
class Self>
1113 constexpr Self& operator+=(
this Self& self,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1115 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
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)
1123 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs += rhs; });
1127 template<
class Self>
1128 constexpr Self& operator-=(
this Self& self,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1130 self.apply_to_each_element(v.values(), [](value_type& lhs, value_type rhs){ lhs -= rhs; });
1134 template<
class Self>
1135 constexpr Self& operator*=(
this Self& self, value_type u)
noexcept(has_identity_validator)
1136 requires has_distinguished_origin
1138 self.for_each_element([u](value_type& x) {
return x *= u; });
1142 template<
class Self>
1143 constexpr Self& operator/=(
this Self& self, value_type u)
1146 self.for_each_element([u](value_type& x) {
return x /= u; });
1150 template<
class Self>
1152 constexpr Self operator+(
this const Self& self)
noexcept
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>)
1162 constexpr Self
operator-(
this const Self& self)
noexcept(has_identity_validator)
1164 return Self{utilities::to_array(self.values(), [](value_type t) { return -t; })};
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>>
1172 friend constexpr typename Derived::displacement_coordinates_type
operator-(
const Derived& lhs,
const Derived& rhs)
noexcept(has_identity_validator)
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>{});
1179 template<
class Derived>
1180 requires std::is_base_of_v<coordinates_base, Derived>
1182 friend constexpr Derived operator+(Derived c,
const displacement_coordinates_type& v)
noexcept(has_identity_validator) {
return c += v; }
1184 template<
class Derived>
1185 requires std::is_base_of_v<coordinates_base, Derived> && (!std::is_same_v<Derived, displacement_coordinates_type>)
1187 friend constexpr Derived
operator+(
const displacement_coordinates_type& v, Derived c)
noexcept(has_identity_validator)
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
1195 friend constexpr Derived
operator+(Derived c,
const Derived& v)
noexcept(has_identity_validator)
1200 template<
class Derived>
1201 requires std::is_base_of_v<coordinates_base, Derived>
1203 friend constexpr Derived operator-(Derived c,
const displacement_coordinates_type& v)
noexcept(has_identity_validator)
1208 template<
class Derived>
1209 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1211 friend constexpr Derived operator*(Derived v, value_type u)
noexcept(has_identity_validator)
1216 template<
class Derived>
1217 requires std::is_base_of_v<coordinates_base, Derived> && has_distinguished_origin
1219 friend constexpr Derived operator*(value_type u, Derived v)
noexcept(has_identity_validator)
1224 template<
class Derived>
1227 friend constexpr Derived operator/(Derived v, value_type u)
1233 constexpr const validator_type& validator()
const noexcept {
return m_Validator; }
1236 constexpr std::span<const value_type, D> values()
const noexcept {
return m_Values; }
1239 constexpr std::span<value_type, D> values()
noexcept requires has_freely_mutable_components {
return m_Values; }
1242 constexpr const value_type& value()
const noexcept requires (D == 1) {
return m_Values[0]; }
1245 constexpr value_type& value()
noexcept requires (D == 1) && has_freely_mutable_components {
return m_Values[0]; }
1249 constexpr explicit operator bool() const noexcept requires (D == 1) && std::convertible_to<value_type,
bool>
1255 constexpr value_type operator[](std::size_t i)
const {
return m_Values[i]; }
1258 constexpr value_type& operator[](std::size_t i)
requires has_freely_mutable_components {
return m_Values[i]; }
1261 constexpr auto begin() const noexcept {
return m_Values.begin(); }
1264 constexpr auto end() const noexcept {
return m_Values.end(); }
1267 constexpr auto rbegin() const noexcept {
return m_Values.rbegin(); }
1270 constexpr auto rend() const noexcept {
return m_Values.rend(); }
1273 constexpr auto cbegin() const noexcept {
return begin(); }
1276 constexpr auto cend() const noexcept {
return end(); }
1279 constexpr auto crbegin() const noexcept {
return rbegin(); }
1282 constexpr auto crend() const noexcept {
return rend(); }
1285 constexpr auto begin() noexcept requires has_freely_mutable_components {
return m_Values.begin(); }
1288 constexpr auto end() noexcept requires has_freely_mutable_components {
return m_Values.end(); }
1291 constexpr auto rbegin() noexcept requires has_freely_mutable_components {
return m_Values.rbegin(); }
1294 constexpr auto rend() noexcept requires has_freely_mutable_components {
return m_Values.rend(); }
1298 friend constexpr bool operator==(
const coordinates_base& lhs,
const coordinates_base& rhs)
noexcept {
return lhs.m_Values == rhs.m_Values; }
1301 friend constexpr auto operator<=>(
const coordinates_base& lhs,
const coordinates_base& rhs)
noexcept
1302 requires (D == 1) && std::totally_ordered<value_type>
1304 return lhs.value() <=> rhs.value();
1307 coordinates_base(
const coordinates_base&) =
default;
1308 coordinates_base(coordinates_base&&) noexcept = default;
1310 coordinates_base& operator=(const coordinates_base&) = default;
1311 coordinates_base& operator=(coordinates_base&&) noexcept = default;
1313 ~coordinates_base() = default;
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)
1319 if constexpr(has_identity_validator)
1321 std::ranges::for_each(std::views::zip(self.m_Values, rhs), [&f](
auto&& z){ f(std::get<0>(z), std::get<1>(z)); });
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);
1331 template<
class Self,
class Fn>
1332 requires std::invocable<Fn, value_type&>
1333 constexpr void for_each_element(
this Self& self, Fn f)
1335 if constexpr(has_identity_validator)
1337 std::ranges::for_each(self.values(), f);
1341 auto tmp{self.m_Values};
1342 std::ranges::for_each(tmp, f);
1343 self.m_Values = validate(tmp, self.m_Validator);
1347 SEQUOIA_NO_UNIQUE_ADDRESS validator_type m_Validator;
1348 std::array<value_type, D> m_Values{};
1351 static std::array<value_type, D> validate(std::span<const value_type, D> vals, Validator& validator)
1353 return validate(utilities::to_array(vals), validator);
1357 static std::array<value_type, D> validate(std::array<value_type, D> vals, Validator& validator)
1359 if constexpr(validator_for_array<Validator, ConvexSpace>)
1360 return validator(vals);
1362 return {validator(vals.front())};
1370 template<convex_space ConvexSpace, basis_for<free_module_type_of_t<ConvexSpace>> Basis,
class Origin, val
idator_for<ConvexSpace> Val
idator>
1374 using coordinates_base<ConvexSpace, Basis, Origin, Validator>::coordinates_base;
1382 template<std::
size_t D>
1385 constexpr static std::size_t dimension{D};
1391 template<std::
size_t D>
1394 constexpr static std::size_t dimension{D};
1400 template<std::
size_t D>
1403 constexpr static std::size_t dimension{D};
1410 template<std::
size_t D>
1413 constexpr static std::size_t dimension{D};
1419 template<std::
size_t D>
1422 constexpr static std::size_t dimension{D};
1427 inline constexpr bool is_orthonormal_basis_v{
1429 typename B::orthonormal;
1430 requires std::same_as<typename B::orthonormal, std::true_type>;
1434 template<vector_space V>
1437 template<vector_space V>
1438 inline constexpr bool has_norm_v{
1440 { norm(v) } -> std::convertible_to<typename V::field_type>;
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>;
1459 template<std::
floating_po
int T, std::
size_t D,
class Arena=mathematical_arena>
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};
1468 template<basis Basis>
1469 requires is_orthonormal_basis_v<Basis>
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); });
1476 template<basis Basis>
1477 requires is_orthonormal_basis_v<Basis>
1481 return inner_product(v, w);
1484 template<basis Basis>
1485 requires is_orthonormal_basis_v<Basis>
1489 if constexpr(D == 1)
1491 return std::abs(v.value());
1495 return std::sqrt(inner_product(v, v));
1500 template<std::
floating_po
int T, std::
size_t D,
class Arena=mathematical_arena>
1505 using is_affine_space = std::true_type;
1506 using arena_type = Arena;
1509 template<std::
floating_po
int T,
class Arena=mathematical_arena>
1514 using is_convex_space = std::true_type;
1515 using arena_type = Arena;
1518 template<std::
floating_po
int T, std::
size_t D, basis Basis,
class Origin,
class Arena=mathematical_arena>
1521 template<std::
floating_po
int T, std::
size_t D, basis Basis,
class Arena=mathematical_arena>
1529 template<free_module M>
1532 using free_module_type = M;
1535 template<free_module M>
1541 template<free_module M>
1547 template<std::
floating_po
int T, std::
size_t D,
class Arena=mathematical_arena>
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