Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/mv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Base: abs, inv, adjoint, exp, getindex
export Mv

export norm, rev, dual, involute, proj, refl, rot, exp_with_hint, scalar, even, odd
export undual, mag2, mag, shirokov_inverse, hitzer_inverse, sp
# export \cdot, \wedge, \intprod, \intprodr, \odot, \boxtimes, \circledast, \times
export +, -, *, /, ^, |, %, ==, !=, <, >, <<, >>, ~, ⋅, ∧, ⨼, ⨽, ⊙, ⊠, ⊛, ×
# Operator precedence: they have the same precedence, unlike in math
Expand Down Expand Up @@ -364,3 +365,60 @@ Odd-grade part.
x.__pow__(y)
end
end

# ── galgebra 0.6.0 additions ──────────────────────────────────────────────────

@doc raw"""
Inverse of `dual()`: `undual(dual(A)) == A` and `dual(undual(A)) == A`.

`undual(A) = A.undual()` ``\equiv I^2 A^{\bot}``
"""
@define_unary_op(Mv, undual, undual)

@doc raw"""
Squared magnitude: sum of absolute values of grade-wise norm-squareds.

`mag2(A) = A.mag2()`

For Euclidean metrics this equals `norm(A)^2`; for non-Euclidean metrics
it differs from `norm2` since it sums `|⟨A⟩_r * ~⟨A⟩_r|` per grade.
"""
@define_unary_op(Mv, mag2, mag2)

@doc raw"""
Magnitude: square root of `mag2(A)`.

`mag(A) = A.mag()`

Equals `norm(A)` only for Euclidean metrics.
"""
@define_unary_op(Mv, mag, mag)

@doc raw"""
Multivector inverse via Shirokov's algorithm (Theorem 4, arXiv:2005.04015).

`shirokov_inverse(A) = A.shirokov_inverse()`

Works for any Clifford algebra. Raises an error if A has no inverse.
"""
@define_unary_op(Mv, shirokov_inverse, shirokov_inverse)

@doc raw"""
Multivector inverse via Hitzer–Sangwine algorithm.

`hitzer_inverse(A) = A.hitzer_inverse()`

Efficient for ``n < 6`` (number of basis vectors). Raises an error if A has no inverse.
"""
@define_unary_op(Mv, hitzer_inverse, hitzer_inverse)

@doc raw"""
Scalar product of A and B: ``\langle A B \rangle``.

`sp(A, B)` ``\equiv (A B)_0``

Note: differs from `A ⊛ B` which is ``\langle A \tilde{B} \rangle``.
Pass `switch="rev"` to use ``\langle \tilde{A} B \rangle`` instead.
"""
sp(A::Mv, B::Mv) = A.sp(B)
sp(A::Mv, B::Mv, switch::AbstractString) = A.sp(B, switch)
18 changes: 17 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,27 @@ end
if V ∉ [Spacetime, PGA2D, PGA3D, CGA2D, CGA3D]
@test abs(R) == norm(R) == R.norm()
end

# galgebra 0.6.0 additions: mag2/mag (grade-wise sum of |norm2|, differs from norm in non-Euclidean)
@test mag2(v) == v.mag2()
@test mag(v) == v.mag()

@test ~A == A[:~] == rev(A) == A.rev()

if V ∉ [Dual, PGA2D, PGA3D, CGA2D, CGA3D]
@test A' == dual(A) == A.dual() == adjoint(A) == A * I # Ga.dual_mode_value is default to "I+"
@test (v)⁻¹ == v[:⁻¹] == v^-1 == inv(v) == v.inv()
@test v^-2 == (v^2).inv()
# galgebra 0.6.0: undual is inverse of dual
@test undual(dual(v)) == v
@test dual(undual(v)) == v
end

@test (A)ˣ == A[:*] == involute(A) == (A)₊ - (A)₋ == A[:+] - A[:-] == A.even() - A.odd()
@test (A)ǂ == A[:ǂ] == conj(A) == involute(A).rev()
@test (A)ǂ == A[:ǂ] == conj(A) == involute(A).rev()
# galgebra 0.6.0: g_invol() and ccon() are new names for involute/conj
@test involute(A) == A.g_invol()
@test conj(A) == A.ccon()

if V ∉ [Spacetime, PGA2D, PGA3D, CGA2D, CGA3D]
@test R^-2 == (R^2).inv()
Expand All @@ -126,6 +136,9 @@ end
if V ∈ [Cl2, Cl3]
@test (v)⁻¹ == (~v) / norm(v)^2 == v / v^2
@test (R)⁻¹ == (~R) / norm(R)^2 == R / R^2
# galgebra 0.6.0: alternative inverse algorithms
@test shirokov_inverse(v) == v.shirokov_inverse() == inv(v)
@test hitzer_inverse(v) == v.hitzer_inverse() == inv(v)
end

@test v^0 == 1
Expand All @@ -147,6 +160,9 @@ end
# @test typeof(scalar(A)) == Sym
@test typeof(A[0]) == Mv
@test scalar(A) == A.scalar() == A[0].obj
# galgebra 0.6.0: sp is (A*B).scalar(), distinct from A ⊛ B = (A*~B).scalar()
@test sp(A, B) == A.sp(B)
@test sp(A, B) == (A * B).scalar()
@test (A)₊ == A[:+] == even(A) == A.even()
@test (A)₋ == A[:-] == odd(A) == A.odd()

Expand Down
Loading