Skip to content

Commit

Permalink
Document result_type argument of @symbolicga
Browse files Browse the repository at this point in the history
  • Loading branch information
Jollywatt committed Oct 2, 2023
1 parent dbbc132 commit 0f34aac
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://jollywatt.github.io/GeometricAlgebra.jl/dev/)
![Build Status](https://github.com/Jollywatt/GeometricAlgebra.jl/actions/workflows/CI.yml/badge.svg)
[![Coverage](https://codecov.io/gh/jollywatt/GeometricAlgebra.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/jollywatt/GeometricAlgebra.jl)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/jollywatt/GeometricAlgebra.jl)
[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/jollywatt/GeometricAlgebra.jl)

A Julia package for working with multivectors from geometric (or Clifford) algebra.

Expand Down
73 changes: 50 additions & 23 deletions src/generated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use_symbolic_optim(sig) = dimension(sig) <= 8
Create an array of symbolic values of the specified shape.
See also [`make_symbolic`](@ref).
# Example
```jldoctest
julia> GeometricAlgebra.symbolic_components(:a, 2, 3)
Expand All @@ -33,6 +36,23 @@ function symbolic_components(label::Symbol, dims::Integer...)
Any[SymbolicUtils.Term{Real}(getindex, [var, I...]) for I in indices]
end

"""
make_symbolic(a, label)
Multivector with symbolic components of the same type as the `Multivector` instance or type `a`.
See also [`symbolic_components`](@ref).
# Example
```jldoctest
julia> GeometricAlgebra.make_symbolic(Multivector{3,1}, :A)
3-component Multivector{3, 1, Vector{Any}}:
A[1] v1
A[2] v2
A[3] v3
```
"""
make_symbolic(::OrType{<:Multivector{Sig,K}}, label) where {Sig,K} = Multivector{Sig,K}(symbolic_components(label, ncomponents(Multivector{Sig,K})))
make_symbolic(::OrType{F}, label) where {F<:Function} = F.instance
make_symbolic(::OrType{Val{V}}, label) where {V} = Val(V)
Expand Down Expand Up @@ -218,28 +238,34 @@ end
Evaluate a symbolically optimised geometric algebra expression.
On macro expansion, `expr` is evaluated with symbolic multivectors (specified by `mv_grades`)
Upon macro expansion, `expr` is evaluated with symbolic multivectors (specified by `mv_grades`)
in the algebra defined by metric signature `sig`. The resulting symbolic expression
is then compiled and executed at runtime. If `result_type` is given, the components array
of the resulting `Multivector` is returned and converted to that type.
is then compiled and executed at runtime.
The `mv_grades` argument is a `NamedTuple` where `keys(mv_grades)`
defines the identifiers in `expr` to be interpreted as `Multivector`s,
while `values(mv_grades)` defines their respective grades.
The identifiers must exist at runtime, and can be a `Multivector` with matching
signature/grade or any iterable with the correct number of components.
The `grades` argument is a `NamedTuple` where `keys(grades)` defines the
identifiers in `expr` to be interpreted as `Multivector`s and `values(grades)`
defines their respective grades.
The identifiers must exist at runtime, and can be a `Multivector` of matching
signature and grade or any iterable with the correct number of components.
If `result_type` is given, then the components of the resulting multivector
are converted to that type. The result type `T` should implement `T(::Tuple)`,
e.g., `Tuple` or `MVector`.
Operations for which components do not have simple closed forms
(such as `exp` or `log`) are not amenable to symbolic evaluation.
!!! warning
Operations that are not amenable to symbolic evaluation
(such as `exp`, `log`, `sqrt`, etc) are not supported.
(You may test if operations work on symbolic multivectors
created with [`GeometricAlgebra.make_symbolic`](@ref).)
# Examples
```jldoctest
julia> let v = (1, 2, 0), R = exp(Multivector{3,2}([0, π/8, 0]))
# Rotate a tuple (viewed as a grade 1 vector) by a rotor.
@symbolicga 3 (v=1, R=0:2:4) grade(R*v*~R, 1) Tuple
# The compiled code evaluates the sandwich product and
# grade projection from a single analytic expression.
end
julia> v = (1, 2, 0); R = exp(Multivector{3,2}([0, π/8, 0]));
julia> # Rotate a tuple (interpreted as a grade 1 vector)
# by a rotor, returning a tuple.
@symbolicga 3 (v=1, R=0:2:4) grade(R*v*~R, 1) Tuple
(0.7071067811865475, 2.0, -0.7071067811865476)
```
```julia
Expand All @@ -256,9 +282,11 @@ end
```
"""
macro symbolicga(sig, mv_grades, expr, result_type=nothing)
Sig = @eval $sig
mv_grades = @eval $mv_grades
Sig = eval(sig)
mv_grades = eval(mv_grades)
@assert mv_grades isa NamedTuple
result_type = eval(result_type)

labels = keys(mv_grades)

symbolic_assignments = map(labels, mv_grades) do label, K
Expand All @@ -269,13 +297,12 @@ macro symbolicga(sig, mv_grades, expr, result_type=nothing)
$expr
end

# TODO: this should be improved. Assumes that result is a Multivector
if isnothing(result_type)
result_expr = toexpr(symbolic_result, MVector)
elseif result_type == :Tuple
result_expr = toexpr(Tuple(symbolic_result.comps), nothing)
result_expr = toexpr(symbolic_result, componentstype(Sig, 0))
else
result_expr = :($result_type($(toexpr.(symbolic_result.comps, MVector)...)))
symbolic_result isa Multivector || error("@symbolicga expression must evaluate to a Multivector when result_type ($result_type) is given; got $(typeof(symbolic_result)).")
symbolic_comps = Tuple(toexpr(comp, nothing) for comp in symbolic_result.comps)
result_expr = :($result_type(($(symbolic_comps...),)))
end

expr_assignments = map(labels, mv_grades) do label, K
Expand Down
15 changes: 13 additions & 2 deletions test/generated.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using GeometricAlgebra:
zeroslike,
make_symbolic
using GeometricAlgebra.SymbolicUtils
import GeometricAlgebra.SymbolicUtils
using GeometricAlgebra.StaticArrays:
MVector,
SVector


@testset "symbolic components" begin
Expand Down Expand Up @@ -46,11 +49,19 @@ end
y = (0, 1, 0)
z = (0, 0, 1)

@test @symbolicga(3, (x=1, y=1), x + y, Tuple) == (1, 1, 0)
@test @symbolicga(3, (x=1, y=1), x + y, SVector) === SVector(1, 1, 0)
@test @symbolicga(3, (x=1, y=1), x*y) == v12

R = exp/4*v12)
@assert grade(R) == 0:2:3
@test @symbolicga(3, (x=1, R=0:2:3), grade(~R*x*R, 1)) v2

joinpoints(a::Tuple, b::Tuple) = @symbolicga 3 (a=1, b=1) ab Tuple
meetlines(a::Tuple, b::Tuple) = @symbolicga 3 (a=2, b=2) ab Tuple
from_homogeneous((x, y, z)) = (x/z, y/z)

l1 = @inferred joinpoints((1, 0, 1), (0, 1, 1)) # line y = 1 - x
l2 = @inferred joinpoints((0, 0, 1), (1, 1, 1)) # line y = x
@test from_homogeneous(meetlines(l1, l2)) == (0.5, 0.5)

end

0 comments on commit 0f34aac

Please sign in to comment.