-
Notifications
You must be signed in to change notification settings - Fork 0
/
inverse.jl
56 lines (47 loc) · 2.07 KB
/
inverse.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
#---Inverses and division--------------------------------------------------------------------------#
"""
CliffordNumbers.InverseException(msg)
No inverse exists for the given input. Optional parameter `msg` is a descriptive error string.
"""
struct InverseException <: Exception
msg::String
end
function Base.showerror(io::IO, ex::InverseException)
print(io, typeof(ex), ": ", ex.msg)
end
"""
CliffordNumbers.versor_inverse(x::AbstractCliffordNumber)
Calculates the versor inverse of `x`, equal to `x' / abs2(x)`.
The versor inverse is only guaranteed to be an inverse for versors. Not all Clifford
numbers have a well-defined inverse, (for instance, in algebras with 2 or more positive-squaring,
dimensions, 1 + e₁ has no inverse). To validate the result, use `inv(x)` instead.
"""
versor_inverse(x::AbstractCliffordNumber) = x' / abs2(x)
"""
inv(x::AbstractCliffordNumber) -> AbstractCliffordNumber
Calculates the inverse of `x`, if it exists, using the versor inverse formula `x' / abs2(x)`. The
result is tested to check if its left and right products with `x` are approximately 1, and a
`CliffordNumbers.InverseException` is thrown if this test does not pass.
"""
function Base.inv(x::AbstractCliffordNumber)
invx = versor_inverse(x)
# Pseudovectors and pseudoscalars always have inverses
# Scalars and vectors are handled with separate methods below
if x isa KVector && dimension(signature(x)) - grade(x) in (0,1)
return invx
# Explicitly check that the inverse exists
elseif x * invx ≈ 1 && invx * x ≈ 1
return invx
else
throw(
InverseException(
"The result of x' / abs2(x) was not an inverse.\n" *
"Note that not all Clifford numbers will have an inverse."
)
)
end
end
Base.inv(x::KVector{0,Q}) where Q = KVector{0,Q}(inv(scalar(x)))
Base.inv(x::KVector{1,Q}) where Q = versor_inverse(x)
/(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q}) where Q = x * inv(y)
\(x::AbstractCliffordNumber{Q}, y::AbstractCliffordNumber{Q}) where Q = inv(x) * y