Expand description
$V_{EE}$ – Vector Expression Emitter: Geometric Algebra Code Generator
The goal of this crate is to generate optimized code for geometric algebra flavors. Currently,
this crate implements the symbolic reduction of multivector expressions up to polynomials with
rational coefficients. In contrast, rational polynomials and hence polynomial division is not
required for lower dimensional geometric algebra flavors as the inverse of a multivector is
given by multiplying it with the inverse of its mixed-grade norm, i.e., a Study number for
dimensions $D < 6$.1 See the examples below where the symbolic expressions are
generated in text form. The next releases will implement code forms (e.g., Rust code in various
profiles based on SIMD using lav with and without generics or arbitrary precision types
using rug). The pre-generated code forms will be provided along with the code generator
behind respective feature gates. When packages_as_namespaces is stable, each code form will
become a crate. Currently, the plane-based pistachio flavor – Projective Geometric Algebra
(PGA) – is implemented for $D \equiv N + 1 \le 8$ in all three metrics, i.e., elliptic,
hyperbolic, and parabolic (Euclidean).2 The 5D, 6D, and 7D PGAs (i.e., $N = 5$, $N = 6$,
and $N = 7$) are exploratory as there are no inverses based on Study numbers. They provide
dimension-agnostic insights regarding duality, the choice of basis blades, and grade-preserving
conditions among orthonormalization conditions. The PGA is especially of interest for computer
graphics (e.g., game and physics engines) as it is the most compact flavor (i.e., a one-up
flavor) unifying the established but scattered frameworks, e.g., homogeneous coordinates,
Plücker coordinates, (dual) quaternions, and screw theory. Even without any knowledge of
geometric algebra, an API can be more intuitive as it unifies the positional and directional
aspects of geometric entities (e.g., planes, lines, points) and the linear and angular aspects
of rigid-body dynamics in a dimension-agnostic way with closed-form (i.e., non-iterative)
solutions up to 4D (e.g., PgaP2, PgaP3, PgaP4).3
§Operators
Following table lists the common operators shared between flavors. The code for the first three
will be manually written based on Study numbers whereas the code for the remaining ones will be
automatically generated based on Multivector.
\gdef\e{
\boldsymbol e
}
\gdef\I{
\boldsymbol I
}
\gdef\norm{
\| a \| \equiv \sqrt{a \tilde a}
}
\gdef\unit{
\hat a \equiv \dfrac{a}{\| a \|}
}
\gdef\inv{
a^{-1} \equiv \dfrac{\tilde a}{\| a \|^2}
}
\gdef\rev{
\tilde a \equiv \sum_s (-1)^{s \choose 2} \lang a \rang_s
}
\gdef\pol{
a^{\perp} \equiv a\I
}
\gdef\not{
a^* \equiv \sum_s \lang a \rang_s^*
: \lang a \rang_s^* = \sum_i \alpha_i a_i^*
: a_i a_i^* = \I
}
\gdef\unnot{
a_* \equiv a^{***} \therefore (a^*)_* = a^{****} = a
}
\gdef\neg{
-a \equiv (-1)a
}
\gdef\add{
a + b \equiv \sum_s \lang a \rang_s + \sum_t \lang b \rang_t
}
\gdef\sub{
a - b \equiv \sum_s \lang a \rang_s - \sum_t \lang b \rang_t
}
\gdef\mul{
ab \equiv \sum_{s,t} \lang a \rang_s \lang b \rang_t
}
\gdef\div{
\dfrac{a}{b} \equiv ab^{-1}
}
\gdef\rem{
a \times b \equiv \frac{1}{2}(ab - ba)
}
\gdef\bitor{
a \mid b \equiv \sum_{s,t}
\lang
\lang a \rang_s
\lang b \rang_t
\rang_{\|s - t\|}
}
\gdef\bitxor{
a \wedge b \equiv \sum_{s,t}
\lang
\lang a \rang_s
\lang b \rang_t
\rang_{s + t}
}
\gdef\bitand{
a \vee b \equiv {(a^* \wedge b^*)}_*
}
\gdef\shl{
a \looparrowleft b
\equiv \sum_{s,t} (-1)^{st} \lang b \rang_t \lang a \rang_s \lang \tilde b \rang_t
}
\gdef\shr{
a \curvearrowright b \equiv (a \mid b) \tilde b
}
\gdef\from{
\lang a \rang_b \equiv \sum_{s \in \{t|b = \sum_t \lang b \rang_t\}} \lang a \rang_s
}| Operator | Name | Formula |
|---|---|---|
a.norm() | Norm (mixed grade) | $\norm$ |
a.unit() | Unit (orthonormal) | $\unit$ |
a.inv() | Inverse | $\inv$ |
a.rev() | Reverse | $\rev$ |
a.pol() | Polarity | $\pol$ |
!a | Dual (right complement) | $\not$ |
!!!a | Undual (left complement) | $\unnot$ |
-a | Negation (orientation) | $\neg$ |
B::from(a) | Selection (mixed grade) | $\from$ |
a + b, a += b | Sum | $\add$ |
a - b, a -= b | Difference | $\sub$ |
a * b, a *= b | Product (geometric) | $\mul$ |
a / b, a /= b | Quotient (geometric) | $\div$ |
a << b, a <<= b | Reflection ($a$ by $b$) | $\shl$ |
a >> b, a >>= b | Projection ($a$ onto $b$) | $\shr$ |
a % b | Commutator | $\rem$ |
a | b | Contraction (symmetric) | $\bitor$ |
a ^ b | Meet (progressive) | $\bitxor$ |
a & b | Join (regressive) | $\bitand$ |
§Examples
Generates the expression for rotating a point in PgaP3, i.e., the type alias of
Multivector parameterized for the Parabolic (Euclidean) 3D PGA. The PgaP3::pin() method
pins symbols of PgaP3::point() with the combining x below (i.e., the Unicode combining
diacritical mark "◌͓") to distinguish them from the symbols of
PgaP3::rotator().
use vee::{format_eq, PgaP3 as Vee};
// Assumes motor is not orthonormalized.
format_eq!(Vee::point().pin() << Vee::motor(), [
"+(+vv+xx+yy+zz)w͓e123",
"+(+(+vv+xx-yy-zz)X͓+2(+vz+xy)Y͓+2(-vy+xz)Z͓+2(-Vx-Xv-Yz+Zy)w͓)e032",
"+(+2(-vz+xy)X͓+(+vv-xx+yy-zz)Y͓+2(+vx+yz)Z͓+2(-Vy+Xz-Yv-Zx)w͓)e013",
"+(+2(+vy+xz)X͓+2(-vx+yz)Y͓+(+vv-xx-yy+zz)Z͓+2(-Vz-Xy+Yx-Zv)w͓)e021",
]);
// Assumes motor is orthonormalized.
format_eq!(Vee::point().pin() << Vee::motor().unit(), [
"+w͓e123",
"+(+(+1-2yy-2zz)X͓+2(+vz+xy)Y͓+2(-vy+xz)Z͓+2(-Vx-Xv-Yz+Zy)w͓)e032",
"+(+2(-vz+xy)X͓+(+1-2xx-2zz)Y͓+2(+vx+yz)Z͓+2(-Vy+Xz-Yv-Zx)w͓)e013",
"+(+2(+vy+xz)X͓+2(-vx+yz)Y͓+(+1-2xx-2yy)Z͓+2(-Vz-Xy+Yx-Zv)w͓)e021",
]);
// Assumes motor and point are (ortho)normalized where point has positive orientation.
format_eq!(Vee::point().eval([(('w', "e123"), 1)]).pin() << Vee::motor().unit(), [
"+e123",
"+(+2(-Vx-Xv-Yz+Zy)+(+1-2yy-2zz)X͓+2(+vz+xy)Y͓+2(-vy+xz)Z͓)e032",
"+(+2(-Vy+Xz-Yv-Zx)+2(-vz+xy)X͓+(+1-2xx-2zz)Y͓+2(+vx+yz)Z͓)e013",
"+(+2(-Vz-Xy+Yx-Zv)+2(+vy+xz)X͓+2(-vx+yz)Y͓+(+1-2xx-2yy)Z͓)e021",
]);The symbols are assigned to basis blades such that lowercase symbols are dual to their
corresponding uppercase symbols. For blades containing $\e_0$, uppercase symbols are used. The
PgaP3::swp() method swaps lowercase and uppercase symbols. This is useful for testing
duality equivalences.
use vee::{format_eq, PgaP3 as Vee};
format_eq!(Vee::plane(), ["+We0", "+xe1", "+ye2", "+ze3"]);
format_eq!(Vee::point(), ["+we123", "+Xe032", "+Ye013", "+Ze021"]);
assert_ne!(!Vee::plane(), Vee::point());
assert_eq!(!Vee::plane(), Vee::point().swp());Alternatively, symbols are labelled after their initially assigned basis blades starting with:
'p'if pinned withPgaP3::pin(),'l'if left-hand side as inPgaP3::lhs(),'r'if right-hand side as inPgaP3::rhs(),'v'otherwise.
use vee::{format_eq, PgaP3 as Vee};
format_eq!("{:#}", Vee::point().pin() << Vee::motor().unit(), [
"+p123*e123",
"+(+(+1-2*v31*v31-2*v12*v12)*p032+2*(+v*v12+v23*v31)*p013+2*(-v*v31+v23*v12)*p021\
+2*(-v0123*v23-v01*v-v02*v12+v03*v31)*p123)*e032",
"+(+2*(-v*v12+v23*v31)*p032+(+1-2*v23*v23-2*v12*v12)*p013+2*(+v*v23+v31*v12)*p021\
+2*(-v0123*v31+v01*v12-v02*v-v03*v23)*p123)*e013",
"+(+2*(+v*v31+v23*v12)*p032+2*(-v*v23+v31*v12)*p013+(+1-2*v23*v23-2*v31*v31)*p021\
+2*(-v0123*v12-v01*v31+v02*v23-v03*v)*p123)*e021",
]);The predominant sign is factored as well with "{:-}":
use vee::{format_eq, PgaP3 as Vee};
// Unfactored predominant sign.
format_eq!(Vee::point().pin() << Vee::motor(), [
"+(+vv+xx+yy+zz)w͓e123",
"+(+(+vv+xx-yy-zz)X͓+2(+vz+xy)Y͓+2(-vy+xz)Z͓+2(-Vx-Xv-Yz+Zy)w͓)e032",
"+(+2(-vz+xy)X͓+(+vv-xx+yy-zz)Y͓+2(+vx+yz)Z͓+2(-Vy+Xz-Yv-Zx)w͓)e013",
"+(+2(+vy+xz)X͓+2(-vx+yz)Y͓+(+vv-xx-yy+zz)Z͓+2(-Vz-Xy+Yx-Zv)w͓)e021",
// ^^^^^^^^^^^^^^^^^^
]);
// Factored predominant sign.
format_eq!("{:-}", Vee::point().pin() << Vee::motor(), [
"+(+vv+xx+yy+zz)w͓e123",
"+(+(+vv+xx-yy-zz)X͓+2(+vz+xy)Y͓+2(-vy+xz)Z͓-2(+Vx+Xv+Yz-Zy)w͓)e032",
"+(+2(-vz+xy)X͓+(+vv-xx+yy-zz)Y͓+2(+vx+yz)Z͓-2(+Vy-Xz+Yv+Zx)w͓)e013",
"+(+2(+vy+xz)X͓+2(-vx+yz)Y͓+(+vv-xx-yy+zz)Z͓-2(+Vz+Xy-Yx+Zv)w͓)e021",
// ^^^^^^^^^^^^^^^^^^
]);The factorization is skipped with "{:+}":
use vee::{format_eq, PgaP3 as Vee};
format_eq!("{:+}", Vee::point().pin() << Vee::motor(), [
"+(+vvw͓+w͓xx+w͓yy+w͓zz)e123",
"+(-2Vw͓x-2Xvw͓+X͓vv+X͓xx-X͓yy-X͓zz-2Yw͓z+2Y͓vz+2Y͓xy+2Zw͓y-2Z͓vy+2Z͓xz)e032",
"+(-2Vw͓y+2Xw͓z-2X͓vz+2X͓xy-2Yvw͓+Y͓vv-Y͓xx+Y͓yy-Y͓zz-2Zw͓x+2Z͓vx+2Z͓yz)e013",
"+(-2Vw͓z-2Xw͓y+2X͓vy+2X͓xz+2Yw͓x-2Y͓vx+2Y͓yz-2Zvw͓+Z͓vv-Z͓xx-Z͓yy+Z͓zz)e021",
]);S. De Keninck and M. Roelfs, “Normalization, square roots, and the exponential and logarithmic maps in geometric algebras of less than 6D”, Mathematical Methods in the Applied Sciences 47, 1425–1441. ↩
M. Roelfs and S. De Keninck, “Graded Symmetry Groups: Plane and Simple”, Advances in Applied Clifford Algebras 33. ↩
L. Dorst and S. De Keninck, “Physical Geometry by Plane-Based Geometric Algebra”, Advanced Computational Applications of Geometric Algebra, 43–76. ↩
Modules§
- pga
- Plane-Based Pistachio Flavor – Projective Geometric Algebra (PGA)
Macros§
Structs§
- Factorization
- Uniquely reduced but volatile form of symbolic polynomial factorization.
- Monomial
- Uniquely reduced form of a symbolic monomial expression.
- Multivector
- Uniquely reduced form of a symbolic multivector expression.
- Polynomial
- Uniquely reduced form of a symbolic polynomial expression.
- Rational
- Rational number in canonical form.
- Symbol
- Symbol as Unicode character with optional combining diacritical mark.
Enums§
- Tree
- Non-binary algebraic expression tree up to symbolic
Multivectorexpressions.
Traits§
- Algebra
- A geometric algebra defined by a flavor’s basis (i.e., all its basis blades).
- Choose
- Finds the binomial coefficient.
- Factor
- Finds the greatest common divisor (GCD) and the least common multiple (LCM).
Type Aliases§
- PgaE0
- Multivector for Elliptic 0D PGA.
- PgaE1
- Multivector for Elliptic 1D PGA.
- PgaE2
- Multivector for Elliptic 2D PGA.
- PgaE3
- Multivector for Elliptic 3D PGA.
- PgaE4
- Multivector for Elliptic 4D PGA.
- PgaE5
- Multivector for Elliptic 5D PGA (exploratory).
- PgaE6
- Multivector for Elliptic 6D PGA (exploratory).
- PgaE7
- Multivector for Elliptic 7D PGA (exploratory).
- PgaH0
- Multivector for Hyperbolic 0D PGA.
- PgaH1
- Multivector for Hyperbolic 1D PGA.
- PgaH2
- Multivector for Hyperbolic 2D PGA.
- PgaH3
- Multivector for Hyperbolic 3D PGA.
- PgaH4
- Multivector for Hyperbolic 4D PGA.
- PgaH5
- Multivector for Hyperbolic 5D PGA (exploratory).
- PgaH6
- Multivector for Hyperbolic 6D PGA (exploratory).
- PgaH7
- Multivector for Hyperbolic 7D PGA (exploratory).
- PgaP0
- Multivector for Parabolic (Euclidean) 0D PGA.
- PgaP1
- Multivector for Parabolic (Euclidean) 1D PGA.
- PgaP2
- Multivector for Parabolic (Euclidean) 2D PGA.
- PgaP3
- Multivector for Parabolic (Euclidean) 3D PGA.
- PgaP4
- Multivector for Parabolic (Euclidean) 4D PGA.
- PgaP5
- Multivector for Parabolic (Euclidean) 5D PGA (exploratory).
- PgaP6
- Multivector for Parabolic (Euclidean) 6D PGA (exploratory).
- PgaP7
- Multivector for Parabolic (Euclidean) 7D PGA (exploratory).