Sequoia
|
Abstractions pertaining to vector spaces, affine spaces and their generalizations. More...
#include "sequoia/Core/ContainerUtilities/ArrayUtilities.hpp"
#include "sequoia/Core/Meta/Concepts.hpp"
#include "sequoia/Core/Meta/TypeAlgorithms.hpp"
#include "sequoia/PlatformSpecific/Preprocessor.hpp"
#include <algorithm>
#include <cmath>
#include <concepts>
#include <complex>
#include <format>
#include <ranges>
#include <span>
Go to the source code of this file.
Classes | |
struct | sequoia::maths::weakly_abelian_group_under_addition< T > |
Trait for specifying whether a type behaves (appoximately) as an abelian group under addition. More... | |
struct | sequoia::maths::weakly_abelian_group_under_addition< T > |
struct | sequoia::maths::weakly_abelian_group_under_addition< std::complex< T > > |
struct | sequoia::maths::weakly_abelian_group_under_multiplication< T > |
Trait for specifying whether a type behaves (appoximately) as an abelian group under multiplication. More... | |
struct | sequoia::maths::weakly_abelian_group_under_multiplication< T > |
struct | sequoia::maths::weakly_abelian_group_under_multiplication< std::complex< T > > |
struct | sequoia::maths::weakly_abelian_group_under_multiplication< bool > |
struct | sequoia::maths::multiplication_weakly_distributive_over_addition< T > |
Trait for specifying whether a type exhibits multiplication that (approximately) distributes over addition. More... | |
struct | sequoia::maths::is_free_module< T > |
Helper that universal template parameters will obviate the need for. More... | |
struct | sequoia::maths::free_module_type_of< ConvexSpace > |
struct | sequoia::maths::commutative_ring_type_of< ConvexSpace > |
Helper to extract the commutative ring type of the free module associated with a convex space. More... | |
struct | sequoia::maths::commutative_ring_type_of< ConvexSpace > |
struct | sequoia::maths::is_identity_validator< T > |
Trait for validators that behave like the identity. More... | |
struct | sequoia::maths::is_identity_validator< std::identity > |
struct | sequoia::maths::half_line_validator |
A validator the the half line. More... | |
struct | sequoia::maths::defines_half_line< T > |
Trait to determine if a type defines the half line. More... | |
struct | sequoia::maths::defines_half_line< half_line_validator > |
struct | sequoia::maths::direct_product< Ts > |
struct | sequoia::maths::direct_product< Ts... > |
struct | sequoia::maths::is_direct_product< T > |
struct | sequoia::maths::is_direct_product< direct_product< Ts... > > |
struct | sequoia::maths::sets::convex_functionals< From, To > |
Class template for giving a name to convex functionals. More... | |
struct | sequoia::maths::sets::linear_functionals< From, To > |
Class template for giving a name to linear functionals. More... | |
struct | sequoia::maths::dual< C > |
Specialization for defining duals of convex spaces via convex functionals. More... | |
struct | sequoia::maths::dual< A > |
Specialization for defining duals of affine spaces via convex functionals. More... | |
struct | sequoia::maths::dual< V > |
Specialization for defining duals of vector spaces via linear functionals. More... | |
struct | sequoia::maths::is_dual< T > |
Helper to detect if a type is defined as a dual of something else. More... | |
struct | sequoia::maths::is_dual< dual< T > > |
struct | sequoia::maths::dual_of< T > |
Helper to generate the dual of a space, taking into account that the dual of the dual may be related to the original space. More... | |
struct | sequoia::maths::dual_of< dual< T > > |
struct | sequoia::maths::distinguished_origin |
Type to indicate a distinguished origin, relevant for free modules. More... | |
class | sequoia::maths::coordinates_base< ConvexSpace, Basis, Origin, Validator, DisplacementCoordinates > |
Class designed for inheritance by concerete coordinate types. More... | |
class | sequoia::maths::coordinates< ConvexSpace, Basis, Origin, Validator > |
Forward declaration for the coordinates class template. More... | |
struct | sequoia::maths::sets::Z< D > |
Class template for giving a name to the set of integers and its generalization to other dimensionalities. More... | |
struct | sequoia::maths::sets::N_0< D > |
Class template for giving a name to the set of semi-positive integers and its generalization to other dimensionalities. More... | |
struct | sequoia::maths::sets::R< D > |
Class template for giving a name to the set of real numbers and its generalization to other dimensionalities. More... | |
struct | sequoia::maths::sets::orthant< D > |
Class template for giving a name to the set of non-negative real numbers and its generalization to other dimensionalities. More... | |
struct | sequoia::maths::sets::C< D > |
Class template for giving a name to the set of complex numbers and its generalization to other dimensionalities. More... | |
struct | sequoia::maths::arbitary_basis< V > |
struct | sequoia::maths::euclidean_vector_space< D, T > |
struct | sequoia::maths::euclidean_affine_space< D, T > |
struct | sequoia::maths::euclidean_half_space< T > |
struct | sequoia::maths::standard_basis< D, T > |
Concepts | |
concept | sequoia::maths::weak_commutative_ring |
concept representing reasonable approximations to a commutative ring. | |
concept | sequoia::maths::weak_field |
concept representing reasonable approximations to a field. | |
concept | sequoia::maths::free_module |
concept for a free module, implicitly understood to be over a commutative ring. | |
concept | sequoia::maths::vector_space |
concept for a vector space, which is a special case of a free module | |
concept | sequoia::maths::convex_space |
concept for convex spaces | |
concept | sequoia::maths::affine_space |
concept for affine spaces | |
concept | sequoia::maths::basis |
A basis must identify the free module to which it corresponds. | |
concept | sequoia::maths::basis_for |
A concept to determine if a basis is appropriate for a particular free module. | |
concept | sequoia::maths::validator_for |
concept to check if a validator is compatible with a convex space. | |
concept | sequoia::maths::normed_vector_space |
concept | sequoia::maths::inner_product_space |
Typedefs | |
template<class T > | |
using | sequoia::maths::weakly_abelian_group_under_addition_t = typename weakly_abelian_group_under_addition< T >::type |
template<class T > | |
using | sequoia::maths::weakly_abelian_group_under_multiplication_t = typename weakly_abelian_group_under_multiplication< T >::type |
template<class T > | |
using | sequoia::maths::multiplication_weakly_distributive_over_addition_t = typename multiplication_weakly_distributive_over_addition< T >::type |
template<convex_space ConvexSpace> | |
using | sequoia::maths::free_module_type_of_t = free_module_type_of< ConvexSpace >::type |
template<convex_space ConvexSpace> | |
using | sequoia::maths::commutative_ring_type_of_t = commutative_ring_type_of< ConvexSpace >::type |
template<convex_space ConvexSpace> | |
using | sequoia::maths::space_value_type = commutative_ring_type_of_t< ConvexSpace > |
template<class T > | |
using | sequoia::maths::is_identity_validator_t = is_identity_validator< T >::type |
template<class T > | |
using | sequoia::maths::defines_half_line_t = typename defines_half_line< T >::type |
template<class T > | |
using | sequoia::maths::is_direct_product_t = is_direct_product< T >::type |
template<class T > | |
using | sequoia::maths::is_dual_t = is_dual< T >::type |
template<class T > | |
using | sequoia::maths::dual_of_t = dual_of< T >::type |
template<affine_space AffineSpace, basis_for< free_module_type_of_t< AffineSpace > > Basis, class Origin > | |
using | sequoia::maths::affine_coordinates = coordinates< AffineSpace, Basis, Origin, std::identity > |
Alias for coordinates of a point in an affine space with respect to a particular origin. | |
template<vector_space VectorSpace, basis_for< free_module_type_of_t< VectorSpace > > Basis> | |
using | sequoia::maths::vector_coordinates = affine_coordinates< VectorSpace, Basis, distinguished_origin > |
Alias for coordinates of an element of a vector space with respect to a particular basis. | |
template<free_module FreeModule, basis_for< free_module_type_of_t< FreeModule > > Basis> | |
using | sequoia::maths::free_module_coordinates = coordinates< FreeModule, Basis, distinguished_origin, std::identity > |
Alias for coordinates of an element of a free module with respect to a particular basis. | |
template<std::size_t D, std::floating_point T, basis Basis, class Origin > | |
using | sequoia::maths::euclidean_affine_coordinates = affine_coordinates< euclidean_affine_space< D, T >, Basis, Origin > |
template<std::size_t D, std::floating_point T, basis Basis> | |
using | sequoia::maths::euclidean_vector_coordinates = vector_coordinates< euclidean_vector_space< D, T >, Basis > |
template<std::size_t D, std::floating_point T> | |
using | sequoia::maths::vec_coords = euclidean_vector_coordinates< D, T, standard_basis< D, T > > |
Variables | |
template<class T > | |
constexpr bool | sequoia::maths::is_addable_v |
Compile time constant for addability. | |
template<class T > | |
constexpr bool | sequoia::maths::is_subtractable_v |
Compile time constant for subtractability. | |
template<class T > | |
constexpr bool | sequoia::maths::is_multiplicable_v |
Compile time constant for multiplicability. | |
template<class T > | |
constexpr bool | sequoia::maths::is_divisible_v |
Compile time constant for divisibility. | |
template<class T > | |
constexpr bool | sequoia::maths::weakly_abelian_group_under_addition_v {weakly_abelian_group_under_addition<T>::value} |
template<class T > | |
constexpr bool | sequoia::maths::weakly_abelian_group_under_multiplication_v {weakly_abelian_group_under_multiplication<T>::value} |
template<class T > | |
constexpr bool | sequoia::maths::multiplication_weakly_distributive_over_addition_v {multiplication_weakly_distributive_over_addition<T>::value} |
template<class T > | |
constexpr bool | sequoia::maths::has_commutative_ring_type_v |
Compile time constant reflecting whether a type exposes a nested type named commutative_ring_type which satisifes the weak_commutative_ring concept. | |
template<class T > | |
constexpr bool | sequoia::maths::has_field_type_v |
Compile time constant reflecting whether a type exposes a nested type named field_type which satisifes the weak_field concept. | |
template<class T > | |
constexpr bool | sequoia::maths::defines_commutative_ring_v {has_commutative_ring_type_v<T> || has_field_type_v<T>} |
Compile time constant reflecting whether a type exposes a nested type with the properties of a commutative ring. | |
template<class T > | |
constexpr bool | sequoia::maths::defines_field_v |
Reports whether a type exposes a nested type with the properties of a field. | |
template<class T > | |
constexpr bool | sequoia::maths::has_dimension_v |
Compile time constant reflecting whether a type exposes a nested value, dimension, convertible to a std::size_t. | |
template<class T > | |
constexpr bool | sequoia::maths::has_set_type_v |
Compile time constant reflecting whether a type exposes a nested type named set_type. | |
template<class T > | |
constexpr bool | sequoia::maths::identifies_as_convex_space_v |
Compile time constant reflecting whether a space self-identifies as convex. | |
template<class T > | |
constexpr bool | sequoia::maths::identifies_as_affine_space_v |
Compile time constant reflecting whether a space self-identifies as affine. | |
template<class T > | |
constexpr bool | sequoia::maths::identifies_as_free_module_v |
Compile time constant reflecting whether a space self-identifies as a free module. | |
template<class T > | |
constexpr bool | sequoia::maths::identifies_as_vector_space_v |
Compile time constant reflecting whether a space self-identifies as vector space. | |
template<class T > | |
constexpr bool | sequoia::maths::has_vector_space_type_v |
Compile time constant reflecting whether a type exposes a nested vector_space_type which satisfies the vector_space concept. | |
template<class T > | |
constexpr bool | sequoia::maths::has_free_module_type_v |
Compile time constant reflecting whether a type exposes a nested free_modul_type which satisfies the vector_space concept. | |
template<convex_space ConvexSpace> | |
constexpr std::size_t | sequoia::maths::dimension_of {free_module_type_of_t<ConvexSpace>::dimension} |
Helper to extract the dimension of the free module associated with a convex space. | |
template<class V , class ConvexSpace > | |
constexpr bool | sequoia::maths::validator_for_single_value |
Validators for spaces of dimension 1 must provide an operator() for validating single values. | |
template<class V , class ConvexSpace > | |
constexpr bool | sequoia::maths::validator_for_array |
Validators for spaces of dimension d>1 must provide an operator() for an array of d values. | |
template<class T > | |
constexpr bool | sequoia::maths::is_identity_validator_v {is_identity_validator<T>::value} |
template<class T > | |
constexpr bool | sequoia::maths::defines_half_line_v {defines_half_line<T>::value} |
template<weak_commutative_ring... Rs> | |
constexpr bool | sequoia::maths::has_common_ring_v |
template<class T > | |
constexpr bool | sequoia::maths::is_direct_product_v = is_direct_product<T>::value |
template<class T > | |
constexpr bool | sequoia::maths::is_dual_v {is_dual<T>::value} |
template<class B > | |
constexpr bool | sequoia::maths::is_orthonormal_basis_v |
template<vector_space V> | |
constexpr bool | sequoia::maths::has_norm_v |
template<vector_space V> | |
constexpr bool | sequoia::maths::has_inner_product_v |
Abstractions pertaining to vector spaces, affine spaces and their generalizations.
Representing abstract algebraic structures in C++ presents an interesting challenge. At root, the fundamental abstraction is a set; indeed, a vector space is nothing but a set with some additional structure defined. However, sets of objects are not straightforward to represent, in general, in C++.
Consider the real numbers. In C++ we can give a name to the is set by using the type system.
struct R {};
But what of the elements of R? Here we run into an immediate difficulty. We would like to associate them with the values of a type. But to truly do so we require a type with an infinite number of values (and uncountably so, in this case). Therefore, when seeking representations, particularly of infinite sets, we are generally reduced to approximations.
However, at least in so far as the set underpinning a particular vector space goes, it turns out that, for our purposes, we need go no further than naming it. As we will explain momentarily, this is because when dealing with vector spaces in practice, we are almost always interested in the coordinates of a vector with respect to a particular basis and not the abstract entities comprising the elements of the underlying set.
Before discussing coordinate systems, it is helpful to be more precise about the fundamental definition of a vector space. The first four axioms pertain just to the elements of the underlying set and amount to stating that a vector space is an abelian group under addition. Thus, vector addition is associative, commutative, has an identity element and admits an inverse.
However, the remaining properties of a vector space require not just the underlying set, V, but also a field, F. Canonical examples of a field include the rationals or the reals: sets admitting the standard arithmetic operations and for which every element has both an additive and multiplicative inverse. As such, we speak of a vector space over a field. A vector space admits a binary operation such that any element of V can be multiplied by any element of F, to give another element within V (or the same element for the multiplicative identity).
Every vector space admits at least one basis. For a vector space of dimension d, a basis is a set of d elements which are linearly independent and so span the space. Let the basis elements be denoted b_0, ..., b_{n-1}. Any vector in the space may be written as a linear combination:
v = a_0 b_0 + ... + a_{n-1} b_{n-1},
where the a_i are valued in the field, F. The set of these values [a_0, ..., a_{n-1}] are none other than the coordinates of v with respect to this particular basis. The [a_0, ..., a_{n-1}] are often informally referred to as a vector. However stricty speaking this is an abuse of terminology and conflates two distinct concepts: an actual vector which is an element of the set which forms the vector space, and a representation of this vector via the coordinates with respect to a particular basis. This distinction can be further reinforced by pointing out that two observers who agree they are talking about the same vector (i.e. set element) will nevertheless disagree on the coordinates if they are using different bases - as they are entirely entitled to do! To further add to the confusion, the coordinates may be referred to as a coordinate vector which is perhaps unfortunate.
Regardless, from the perspective of performing actual calculations, the coordinates are key. An crucial point to make is that, when dealing with the coordinates, the underlying elements of the set, V, make no explicit appearance. This is a manifestation of the fact that two vector spaces of the same dimension and over the same field are isomorphic. This is incredibly helpful since, for many practical purposes, we need not represent the underlying set beyond, at most, perhaps giving it a name. For example, consider the vector space formed by functions which map some set into a field: the question of how to represent the elements of this vector space in C++ is completely circumvented.
However, that is not to say that subtleties of imperfect representations of mathematical abstractions are entirely avoided; indeed, quite the contrary! The coordinates are valued in a field and so at this stage we must deal with the fact that C++ types such as float and double model the real numbers imperfectly. Nevertheless, the burden has been shifted from attempting to represent things in C++ that may be completely infeasible to things which can be done to reasonable approximation.
Vector spaces are just one of the things treated in the code that follows. There are several important generalizations. First, there are affine spaces, which comprise a set, A, together with a vector space, V, whose additive group acts freely and transitively on A. Intuitvely, we can start at any point in A and translate to any other point by adding the appropriate vector. In fact, the relationship is stronger than this: choosing any point in A and adding any vector in V will give a point in A. A nice example of an affine space is Euclidean space. Two observers in this space, Alice and Bob, are entirely entitled to define their location as the origin. Neither is more right than the other since this space has no distinguished origin. Alice and Bob will, in general, disagree about the coordinates of points in the space. However, they will agree on the vector which translates from one point to another (though if they compare vector coordinates, they may have ton contend with using different bases on the vector space!).
An affine space is sometimes described as a vector space which has forgotten its origin. Indeed, a vector space is an affine space over itself. This is interesting in terms of representing these concepts in C++. Since a vector space is a special case of an affine space, this suggests that an affine space concept is more fundamental, with the vector space being a refinement. However, a vector space is part of the definition of an affine space (a set and a vector space, satisfying certain conditions) and so it is this that will be reflected by the concepts defined below: the affine space concept depends on the vector_space concent, and not vice-versa.
It will be useful for our purposes to generalize affine spaces. Consider taking a convex subset, C, of an affine space. We may translate from any point in C to any other by adding the appropriate vector from V. However, there are elements of V which, when added to a point in C will take us outside of C and into the broader affine space into which it is a part. However, we do not want define Convex spaces via an embedding in a bigger space. There seems to be a solution which fits neatly into a C++ implementation. Define a convex space, C, to comprise:
The other interesting generialization is to consider relaxing a vector space's field to a ring. The resulting construction is called a module, which is a generalization of a vector space. Our motivation for this is that the integers form a commutative ring and not a field, since integers do not, in general, have multiplicative inverses valued within the integers. Rather than attempting to deal with modules in full generality, we restrict our attention to what may be the most useful, practical cases in the context of C++: free modules over commutative rings. Free modules are those which admit a basis.
In line with the above, we also consider affine spaces over free modules and their convex generalization where the action of the free module is not bijective.
The final issue to address is that question of why to bother modelling concepts such as vector spaces in the abstract sense if it is their coordinates which are the things of use from the perspective of practical computation. The point is that, for example, vector spaces and affine spaces admit different operations: whereas elements of a vector space can be added, the same is not true of the elements of the set underpinning an affine space. By introducing concepts for the abstract algebraic constructs, we can treat coordinates on all of these spaces in a common way by using constraints to enable or disable specific operations. Thus, the coordinates class template is templated on, amongst other things, a convex_space. To define such a space just requires introducing a struct exposing a small amount of data (types and values) known at compile time. These data determines whether we intend to model a vector space, a free module over a commutative space, an affine space or whatever. This is sufficient for the coordinates implementation to expose the correct set of operations.
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |
|
inlineconstexpr |