Abstract tangent bundle vector space type operations at compile-time
DOI Docs Stable Docs Dev Gitter Build Status Build status Coverage Status codecov.io
This package is a work in progress providing the necessary tools to work with arbitrary Manifold elements specified with an encoding having optional origin, point at infinity, and tangent bundle parameter.
Due to the parametric type system for the generating TensorBundle, the Julia compiler can fully preallocate and often cache values efficiently ahead of run-time.
Although intended for use with the Grassmann.jl package, DirectSum can be used independently.
Sponsor this at liberapay, GitHub Sponsors, Patreon, or Bandcamp; also available as part of the Tidelift Subscription.
Let n be the rank of a Manifold.
The type TensorBundle{n,P,g,ν,μ} uses byte-encoded data available at pre-compilation, where
P specifies the basis for up and down projection,
g is a bilinear form that specifies the metric of the space,
and μ is an integer specifying the order of the tangent bundle (i.e. multiplicity limit of Leibniz-Taylor monomials). Lastly, ν is the number of tangent variables.
The metric signature of the basis elements of a vector space V can be specified with the V"..." constructor by using + and - to specify whether the basis element of the corresponding index squares to +1 or -1.
For example, S"+++" constructs a positive definite 3-dimensional TensorBundle.
julia> R^3 == V"+++" == TensorBundle(3) true
It is also possible to specify an arbitrary DiagonalForm having numerical values for the basis with degeneracy D"1,1,1,0", although the Signature format has a more compact representation.
Further development will result in more metric types.
The direct sum operator ⊕ can be used to join spaces (alternatively +), and ' is an involution which toggles a dual vector space with inverted signature.
julia> V = R'⊕R^3 ⟨-+++⟩ julia> V' ⟨+---⟩' julia> W = V⊕V' ⟨-++++---⟩*
The direct sum of a TensorBundle and its dual V⊕V' represents the full mother space V*.
julia> collect(V) # all Submanifold vector basis elements DirectSum.Basis{⟨-+++⟩,16}(⟨____⟩, ⟨-___⟩, ⟨_+__⟩, ⟨__+_⟩, ⟨___+⟩, ⟨-+__⟩, ⟨-_+_⟩, ⟨-__+⟩, ⟨_++_⟩, ⟨_+_+⟩, ⟨__++⟩, ⟨-++_⟩, ⟨-+_+⟩, ⟨-_++⟩, ⟨_+++⟩, ⟨-+++⟩) julia> collect(Submanifold(V')) # all covector basis elements DirectSum.Basis{⟨+---⟩',16}(w, w1, w2, w3, w4, w12, w13, w14, w23, w24, w34, w123, w124, w134, w234, w1234) julia> collect(Submanifold(W)) # all mixed basis elements DirectSum.Basis{⟨-++++---⟩*,256}(v, v1, v2, v3, v4, w1, w2, w3, w4, v12, v13, v14, v1w1, v1w2, v1w3, v1w4, v23, v24, v2w1, v2w2, v2w3, v2w4, v34, v3w1, v3w2, v3w3, v3w4, v4w1, v4w2, v4w3, v4w4, w12, w13, w14, w23, w24, w34, v123, v124, v12w1, v12w2, v12w3, v12w4, v134, v13w1, v13w2, v13w3, v13w4, v14w1, v14w2, v14w3, v14w4, v1w12, v1w13, v1w14, v1w23, v1w24, v1w34, v234, v23w1, v23w2, v23w3, v23w4, v24w1, v24w2, v24w3, v24w4, v2w12, v2w13, v2w14, v2w23, v2w24, v2w34, v34w1, v34w2, v34w3, v34w4, v3w12, v3w13, v3w14, v3w23, v3w24, v3w34, v4w12, v4w13, v4w14, v4w23, v4w24, v4w34, w123, w124, w134, w234, v1234, v123w1, v123w2, v123w3, v123w4, v124w1, v124w2, v124w3, v124w4, v12w12, v12w13, v12w14, v12w23, v12w24, v12w34, v134w1, v134w2, v134w3, v134w4, v13w12, v13w13, v13w14, v13w23, v13w24, v13w34, v14w12, v14w13, v14w14, v14w23, v14w24, v14w34, v1w123, v1w124, v1w134, v1w234, v234w1, v234w2, v234w3, v234w4, v23w12, v23w13, v23w14, v23w23, v23w24, v23w34, v24w12, v24w13, v24w14, v24w23, v24w24, v24w34, v2w123, v2w124, v2w134, v2w234, v34w12, v34w13, v34w14, v34w23, v34w24, v34w34, v3w123, v3w124, v3w134, v3w234, v4w123, v4w124, v4w134, v4w234, w1234, v1234w1, v1234w2, v1234w3, v1234w4, v123w12, v123w13, v123w14, v123w23, v123w24, v123w34, v124w12, v124w13, v124w14, v124w23, v124w24, v124w34, v12w123, v12w124, v12w134, v12w234, v134w12, v134w13, v134w14, v134w23, v134w24, v134w34, v13w123, v13w124, v13w134, v13w234, v14w123, v14w124, v14w134, v14w234, v1w1234, v234w12, v234w13, v234w14, v234w23, v234w24, v234w34, v23w123, v23w124, v23w134, v23w234, v24w123, v24w124, v24w134, v24w234, v2w1234, v34w123, v34w124, v34w134, v34w234, v3w1234, v4w1234, v1234w12, v1234w13, v1234w14, v1234w23, v1234w24, v1234w34, v123w123, v123w124, v123w134, v123w234, v124w123, v124w124, v124w134, v124w234, v12w1234, v134w123, v134w124, v134w134, v134w234, v13w1234, v14w1234, v234w123, v234w124, v234w134, v234w234, v23w1234, v24w1234, v34w1234, v1234w123, v1234w124, v1234w134, v1234w234, v123w1234, v124w1234, v134w1234, v234w1234, v1234w1234)
In addition to the direct-sum operation, several others operations are supported, such as ∪, ∩, ⊆, ⊇ for set operations.
Due to the design of the TensorBundle dispatch, these operations enable code optimizations at compile-time provided by the bit parameters.
julia> R⊕R' ⊇ TensorBundle(1) true julia> R ∩ R' == TensorBundle(0) true julia> R ∪ R' == R⊕R' true
Remark, although some of the operations sometimes result in the same value as shown in the above examples, the ∪ and ⊕ are entirely different operations in general.
Calling manifolds with sets of indices constructs the subspace representations.
Given M(s::Int...) one can encode Submanifold{M,length(s),indexbits(s)} with induced orthogonal space, such that computing unions of submanifolds is done by inspecting the parameter s.
Operations on Manifold types is automatically handled at compile time.
julia> (R^5)(3,5) ⟨__+_+⟩ julia> dump(ans) Submanifold{2,⟨+++++⟩,0x0000000000000014} ⟨__+_+⟩
Here, calling a Manifold with a set of indices produces a Submanifold representation.
To help provide a commonly shared and readable indexing to the user, some print methods are provided:
julia> DirectSum.printindices(stdout,DirectSum.indices(UInt(2^62-1)),false,"v") v1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ julia> DirectSum.printindices(stdout,DirectSum.indices(UInt(2^62-1)),false,"w") w1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
An application of this is in the Grasmann package, where dual indexing is used.
Declaring an additional plane at infinity is done by specifying it in the string constructor with \infty at the first index (i.e. Riemann sphere S"∞+++"). The hyperbolic geometry can be declared by \emptyset subsequently (i.e. Minkowski spacetime S"∅+++").
Additionally, the null-basis based on the projective split for confromal geometric algebra would be specified with ∞∅ initially (i.e. 5D CGA S"∞∅+++"). These two declared basis elements are interpreted in the type system.
julia> Signature("∞∅++") ⟨∞∅++⟩
The index number n of the TensorBundle corresponds to the total number of generator elements. However, even though V"∞∅+++" is of type TensorBundle{5,3} with 5 generator elements, it can be internally recognized in the direct sum algebra as being an embedding of a 3-index TensorBundle{3,0} with additional encoding of the null-basis (origin and point at infinity) in the parameter P of the TensorBundle{n,P} type.
The tangent map takes V to its tangent space and can be applied repeatedly for higher orders, such that tangent(V,μ,ν) can be used to specify μ and ν.
julia> V = tangent(R^3) T1⟨+++1⟩ julia> tangent(V') T2⟨----1⟩' julia> V+V' T1⟨+++---11⟩*
The AbstractTensors package is intended for universal interoperability of the abstract TensorAlgebra type system.
All TensorAlgebra{V} subtypes have type parameter V, used to store a TensorBundle value obtained from DirectSum.jl.
By itself, this package does not impose any specifications or structure on the TensorAlgebra{V} subtypes and elements, aside from requiring V to be a TensorBundle.
This means that different packages can create tensor types having a common underlying TensorBundle structure.
The key to making the whole interoperability work is that each TensorAlgebra subtype shares a TensorBundle parameter (with all isbitstype parameters), which contains all the info needed at compile time to make decisions about conversions. So other packages need only use the vector space information to decide on how to convert based on the implementation of a type. If external methods are needed, they can be loaded by Requires when making a separate package with TensorAlgebra interoperability.
Since TensorBundle choices are fundamental to TensorAlgebra operations, the universal interoperability between TensorAlgebra{V} elements with different associated TensorBundle choices is naturally realized by applying the union morphism to operations.
More information about AbstractTensors is available at https://github.com/chakravala/AbstractTensors.jl
The Grassmann Submanifold elements vk and wk are linearly independent vector and covector elements of V, while the Leibniz Operator elements ∂k are partial tangent derivations and εk are dependent functions of the tangent manifold.
An element of a mixed-symmetry TensorAlgebra{V} is a multilinear mapping that is formally constructed by taking the tensor products of linear and multilinear maps.
Higher grade elements correspond to Submanifold subspaces, while higher order function elements become homogenous polynomials and Taylor series.
Combining the linear basis generating elements with each other using the multilinear tensor product yields a graded (decomposable) tensor Submanifold ⟨w1⊗⋯⊗wk⟩, where grade is determined by the number of anti-symmetric basis elements in its tensor product decomposition.
The algebra is partitioned into both symmetric and anti-symmetric tensor equivalence classes.
For the oriented sets of the Grassmann exterior algebra, the parity of (-1)^P is factored into transposition compositions when interchanging ordering of the tensor product argument permutations.
The symmetrical algebra does not need to track this parity, but has higher multiplicities in its indices.
Symmetric differential function algebra of Leibniz trivializes the orientation into a single class of index multi-sets, while Grassmann's exterior algebra is partitioned into two oriented equivalence classes by anti-symmetry.
Full tensor algebra can be sub-partitioned into equivalence classes in multiple ways based on the element symmetry, grade, and metric signature composite properties.
By virtue of Julia's multiple dispatch on the field type K, methods can specialize on the dimension n and grade G with a TensorBundle{n} via the TensorAlgebra{V} subtypes, such as Submanifold{V,G}, Single{V,G,B,K}.
The elements of the Basis can be generated in many ways using the Submanifold elements created by the @basis macro,
julia> using DirectSum; @basis R^3 # equivalent to basis"+++" (⟨+++⟩, v, v1, v2, v3, v12, v13, v23, v123) julia> typeof(V) # dispatch by vector space Signature{3,0,0x0000000000000000,0,0,1} julia> typeof(v13) # extensive type info Submanifold{⟨+++⟩,2,0x0000000000000005} julia> v1 ⊆ v12 true julia> v12 ⊆ V true
As a result of this macro, all of the Submanifold{V,G} elements generated by that TensorBundle become available in the local workspace with the specified naming.
The first argument provides signature specifications, the second argument is the variable name for the TensorBundle, and the third and fourth argument are the the prefixes of the Submanifold vector names (and covector basis names). By default, V is assigned the TensorBundle and v is the prefix for the Submanifold elements.
It is entirely possible to assign multiple different bases with different signatures without any problems. In the following command, the @basis macro arguments are used to assign the vector space name to S instead of V and basis elements to b instead of v, so that their local names do not interfere.
Alternatively, if you do not wish to assign these variables to your local workspace, the versatile DirctSum.Basis constructors can be used to contain them, which is exported to the user as the method Λ(V).
julia> indices(Λ(3).v12) 2-element Array{Int64,1}: 1 2
The parametric type formalism in DirectSum is highly expressive to enable the pre-allocation of geometric algebra computations for specific sparse-subalgebras, including the representation of rotational groups, Lie bivector algebras, and affine projective geometry.
In order to work with a TensorAlgebra{V}, it is necessary for some computations to be cached. This is usually done automatically when accessed.
Staging of precompilation and caching is designed so that a user can smoothly transition between very high dimensional and low dimensional algebras in a single session, with varying levels of extra caching and optimizations.
The parametric type formalism in DirectSum is highly expressive and enables pre-allocation of geometric algebra computations involving specific sparse subalgebras, including the representation of rotational groups.
It is possible to reach Single elements with up to N=62 vertices from a TensorAlgebra having higher maximum dimensions than supported by Julia natively.
The 62 indices require full alpha-numeric labeling with lower-case and capital letters. This now allows you to reach up to 4,611,686,018,427,387,904 dimensions with Julia using DirectSum. Then the volume element is
v1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Complete Submanifold allocations are only possible for N≤22, but sparse operations are also available at higher dimensions.
While DirectSum.Basis{V} is a container for the TensorAlgebra generators of V, the DirectSum.Basis is only cached for N≤8.
For the range of dimensions 8<N≤22,ドル the DirectSum.SparseBasis type is used.
julia> Λ(22) DirectSum.SparseBasis{⟨++++++++++++++++++++++⟩,4194304}(v, ..., v1234567890abcdefghijkl)
This is the largest SparseBasis that can be generated with Julia, due to array size limitations.
To reach higher dimensions with N>22, the DirectSum.ExtendedBasis type is used.
It is suficient to work with a 64-bit representation (which is the default). And it turns out that with 62 standard keyboard characters, this fits nicely.
At 22 dimensions and lower there is better caching, with further extra caching for 8 dimensions or less.
Thus, the largest Hilbert space that is fully reachable has 4,194,304 dimensions, but we can still reach out to 4,611,686,018,427,387,904 dimensions with the ExtendedBasis built in.
Complete Submanifold elements are not representable when ExtendedBasis is used, but the performance of the Submanifold and sparse elements is possible as it is for lower dimensions for the current SubAlgebra and TensorAlgebra types.
The sparse representations are a work in progress to be improved with time.
This package is still in its beginning stages and may have deprecating changes.