Sequoia
Loading...
Searching...
No Matches
Classes | Concepts | Typedefs | Variables
Spaces.hpp File Reference

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
 

Detailed Description

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:

  1. The union, S', of a set of points, S, and an exception state, E
  2. A vector space, V such that: A. The difference of any two points in S is in V B. An element of V, when added to S remains either in S or maps to E Note that, since every point in S is mapped by elements of V into E, and there is no mapping from E back into S, the action of the additive group of V is not bijective, violating one of the axioms of affine spaces.

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.

Variable Documentation

◆ has_common_ring_v

template<weak_commutative_ring... Rs>
constexpr bool sequoia::maths::has_common_ring_v
inlineconstexpr
Initial value:
{
((weak_field<Rs> && ...) || (!weak_field<Rs> && ...)) && requires { typename std::common_type<Rs...>::type; }
}
concept representing reasonable approximations to a field.
Definition: Spaces.hpp:334

◆ has_inner_product_v

template<vector_space V>
constexpr bool sequoia::maths::has_inner_product_v
inlineconstexpr
Initial value:
{
requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
{ inner_product(v, v) } -> std::convertible_to<typename V::field_type>;
}
}

◆ has_norm_v

template<vector_space V>
constexpr bool sequoia::maths::has_norm_v
inlineconstexpr
Initial value:
{
requires (const vector_coordinates<V, arbitary_basis<V>>& v) {
{ norm(v) } -> std::convertible_to<typename V::field_type>;
}
}

◆ is_orthonormal_basis_v

template<class B >
constexpr bool sequoia::maths::is_orthonormal_basis_v
inlineconstexpr
Initial value:
{
requires {
typename B::orthonormal;
requires std::same_as<typename B::orthonormal, std::true_type>;
}
}