-
Notifications
You must be signed in to change notification settings - Fork 0
/
kvector.jl
139 lines (102 loc) · 5.42 KB
/
kvector.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
KVector{K,Q,T,L} <: AbstractCliffordNumber{Q,T}
A multivector consisting only linear combinations of basis blades of grade `K` - in other words,
a k-vector.
k-vectors have `binomial(dimension(Q), K)` components.
"""
struct KVector{K,Q,T<:BaseNumber,L} <: AbstractCliffordNumber{Q,T}
data::NTuple{L,T}
function KVector{K,Q,T,L}(x::Tuple) where {K,Q,T,L}
@assert 0 <= K <= dimension(Q) "K can only range from 0 to $(dimension(Q)) (got $K)."
check_element_count(binomial(dimension(Q), K), L, x)
return new{K,Q,T,L}(x)
end
end
#---Constructors-----------------------------------------------------------------------------------#
KVector{K,Q,T}(x::Tuple{Vararg{BaseNumber,L}}) where {K,Q,T,L} = KVector{K,Q,T,L}(x)
KVector{K,Q}(x::Tuple{Vararg{T}}) where {K,Q,T<:BaseNumber} = KVector{K,Q,T}(x)
# Automatically convert arguments to a common type
KVector{K,Q}(x::Tuple{Vararg{BaseNumber}}) where {K,Q} = KVector{K,Q}(promote(x...))
# AbstractCliffordNumber{Q} constructor converts to a `KVector{0,Q}`
AbstractCliffordNumber{Q}(x::BaseNumber) where Q = KVector{0,Q}(x)
# UNDERSTAND: The type constraint on T is required. Why?
AbstractCliffordNumber{Q,T}(x::BaseNumber) where {Q,T<:BaseNumber} = KVector{0,Q,T}(x)
#---Number of elements-----------------------------------------------------------------------------#
nblades(::Type{<:KVector{K,Q}}) where {K,Q} = binomial(dimension(Q), K)
#---Indexing---------------------------------------------------------------------------------------#
bitindices_type(::Type{<:KVector{K,Q}}) where {K,Q} = KVector{K,Q}
"""
grade(::Type{<:KVector{K}}) = K
grade(x::KVector{K}) = k
Returns the grade represented by a `KVector{K}`, which is K.
"""
grade(::Type{<:KVector{K}}) where K = K
grade(x::KVector) = grade(typeof(x))
nonzero_grades(::Type{<:KVector{K}}) where K = K:K
@inline function getindex(b::BitIndices{Q,<:KVector{K}}, i::Integer) where {Q,K}
@boundscheck checkbounds(b, i)
return BitIndex{Q}(UInt(hamming_number(K, i)))
end
@inline @generated function to_index(::Type{C}, b::BitIndex{Q}) where {K,Q,C<:KVector{K,Q}}
ex = :(i = 1)
for n in 1:nblades(C)
a = BitIndices(C)[n]
ex = :($ex; is_same_blade($a, b) && (i = $n))
end
return :($ex; return i)
end
@inline to_index(k::KVector{K,Q}, b::BitIndex{Q}) where {K,Q} = to_index(typeof(k), b)
@inline function getindex(k::KVector{K,Q,T}, b::BitIndex{Q}) where {K,Q,T}
return ifelse(grade(b) === K, flipsign((@inbounds k.data[to_index(k, b)]), b), zero(T))
end
#---Multiplicative identity and pseudoscalar-------------------------------------------------------#
one(K::Type{<:KVector{<:Any,Q}}) where Q = KVector{0,Q}(scalar_type(K)(true))
# Default implementation for AbstractCliffordNumber subtypes if not explicitly given
one(C::Type{<:AbstractCliffordNumber{Q}}) where Q = one(KVector{0,Q,scalar_type(C)})
"""
pseudoscalar(C::Type{<:AbstractCliffordNumber{Q,T}}) -> KVector{dimension(Q),Q,T}
pseudoscalar(x::AbstractCliffordNumber{Q})
Returns the pseudoscalar associated with the signature `Q` of the argument. The result will have the
same scalar type as the input if such information is given; otherwise it will use `Bool` as the
scalar type so as to promote to any other numeric type.
"""
function pseudoscalar(C::Type{<:AbstractCliffordNumber{Q}}) where Q
return KVector{dimension(Q),Q}(scalar_type(C)(true))
end
pseudoscalar(x::AbstractCliffordNumber) = pseudoscalar(typeof(x))
#---Similar types----------------------------------------------------------------------------------#
function similar_type(::Type{<:KVector{K}}, ::Type{T}, ::Val{Q}) where {K,Q,T<:BaseNumber}
return KVector{K,Q,T,binomial(dimension(Q),K)}
end
function similar_type(::Type{<:KVector}, ::Type{T}, ::Val{Q}, ::Val{K}) where {K,Q,T<:BaseNumber}
return KVector{K,Q,T,binomial(dimension(Q),K)}
end
complement_type(::Type{KVector{K,Q,T,L}}) where {K,Q,T,L} = KVector{dimension(Q)-K,Q,T,L}
complement_type(::Type{KVector{K,Q,T}}) where {K,Q,T} = KVector{dimension(Q)-K,Q,T}
complement_type(::Type{KVector{K,Q}}) where {K,Q} = KVector{dimension(Q)-K,Q}
#---Show methods-----------------------------------------------------------------------------------#
short_typename(::Type{<:KVector{K,Q,T}}) where {K,Q,T} = KVector{K,Q,T}
#---Aliases for special KVector types--------------------------------------------------------------#
"""
CliffordScalar{Q,T} (alias for KVector{0,Q,T,1})
Represents a scalar of the Clifford algebra described by `Q`.
"""
const CliffordScalar{Q,T} = KVector{0,Q,T,1}
"""
CliffordVector{Q,T,L} (alias for KVector{1,Q,T,L})
Represents a 1-vector (or equivalently, a 1-blade) of the Clifford algebra described by `Q`. `L` is
constrained to be equal to `dimension(Q)`.
"""
const CliffordVector{Q,T,L} = KVector{1,Q,T,L}
"""
CliffordBivector{Q,T,L} (alias for KVector{2,Q,T,L})
Represents a bivector of the Clifford algebra described by `Q`. `L` is constrained to be equal to
`binomial(dimension(Q), 2)`.
Note that when `dimension(Q) > 3`, bivectors are *not* always 2-blades, meaning that they cannot
always be described as the wedge product of two 1-blades. An example is
`CliffordBivector{VGA(4)}(1, 0, 0, 0, 0, 1)`.
"""
const CliffordBivector{Q,T,L} = KVector{2,Q,T,L}
#---Special Z2CliffordNumber constructor-----------------------------------------------------------#
# Automatically infer if we want an even or odd Clifford number
Z2CliffordNumber(x::KVector{K}) where K = Z2CliffordNumber{isodd(K)}(x)