Skip to content

UD123/pga3d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Algebras: a study and comparison of geometric-algebra implementations

This repository collects small, self-contained Python implementations of several geometric algebras and the visualization tools used to compare their elements and transformations side by side. Each subpackage is kept independent so that the underlying representations (multivector layout, basis ordering, sign conventions) can be studied in isolation and then contrasted against the others.

The collection currently contains three implementations:

Section Module Algebra Underlying representation
PGA3D pga3d/ 3-D Projective Geometric Algebra R(3, 0, 1) 16-component multivector
SimpleGA simplega/ GA(2,0), GA(3,0), GA(3,1), quaternions grade-split (Even / Odd) blocks
Ganja ganja/ generic Algebra(p, q, r) dense 2^n component multivector

All figures in this README are generated from code in doc/; see the "Regenerating the figures" subsection of each section to reproduce them.


PGA3D

pga3d is a Python library for doing geometry in 3-D using 3-D Projective Geometric Algebra (R(3, 0, 1)). It exposes high-level objects (Point, Line, Plane, Translator, Rotor) so that intersections, joins, and rigid-body transformations are one-liners, while hiding the algebra from callers who do not want to learn it.

Benefits over linear-algebra-based libraries

  • Small core: once the algebra is set up, conversions, intersections, and joins are one-liners.
  • Translations and rotations compose with minimal loss of precision (compared with multiplying 4×4 matrices).
  • Transformations are linear in the algebra, so multiplying them yields smooth interpolation.
  • Edge cases are first-class: intersecting two parallel lines yields a point at infinity (a direction) rather than an exception.
  • No implicit choice of right-handed vs left-handed conventions.

Citation / upstream

This package is derived from Almar Klein's pga3d project, which served as the starting point for the implementation and API. See:

Background reading on (projective) geometric algebra:

Usage

All geometric objects and transformations live in the top-level pga3d package. Points, lines, and planes are built from incidence (e.g. a line is the join of two points), and Translator / Rotor act on any object via .project(...).

import math
from pga3d import Point, Line, Plane, Translator, Rotor

# Build geometric objects from points
p1 = Point(2, 3, 4)
p2 = Point(20, 3, 7)
p3 = Point(9, 12, 17)

line = Line.from_points(p1, p2)            # join of two points
plane = Plane.from_points(p1, p2, p3)      # join of three points

# Compose a rigid-body motion: rotate 90° around z, then translate by +3x
t = Translator.from_xyz(3, 0, 0)
r = Rotor.from_angle_and_line(math.pi / 2, Line.from_xyz(0, 0, 1))
m = t * r                                  # composition is just multiplication

p1_moved = m.project(p1)                   # apply the motion to a point

# Projection / intersection are one-liners
p_on_line = p1.project_onto(Line.from_points(p3, p1))
plane_through_origin = plane.project_onto(Point(0, 0, 0))

A runnable version of this snippet lives in pga3d/pga3d_examples.py.

Examples — elements and transformations

The figures below are produced by doc/generate_figures.py, which drives the plotting helpers in pga3d_display.py.

Single point Line from two points
A single Point(1, 2, 3). A Line joining two points.
Plane from three points Triangle scene
A Plane built from three points. Points, lines, and a plane drawn together.
Translation and rotation Projection onto a line
A point, its translation, and a composed translation+rotation. Projection of a point onto a line, with the supporting plane.

Examples — meet and join

In R(3, 0, 1) incidence is expressed by two products: the join (&, regressive product) builds higher-grade objects from lower-grade ones, and the meet (^, outer product) intersects them. The figures below are also generated by doc/generate_figures.py.

Join of two points Join of three points
p1 & p2 — join of two points is the line through them. p1 & p2 & p3 — join of three points is the plane through them.
Join of line and point Meet of two planes
line & p — join of a line and a point is the plane containing both. pi1 ^ pi2 — meet of two planes is their line of intersection.
Meet of three planes Meet of plane and line
pi1 ^ pi2 ^ pi3 — meet of three planes is their common point. pi ^ line — meet of a plane and a line is their intersection point.

Regenerating the figures

python doc/generate_figures.py

Status

Experimental and a work in progress.


SimpleGA

simplega is a Python port of the Julia package SimpleGA.jl by Chris Doran. It provides compact, grade-split implementations of several geometric algebras with a uniform API:

Algebra Module Underlying representation
GA(2,0) simplega/ga20.py complex numbers
GA(3,0) simplega/ga30.py quaternion-like (w, x, y, z)
GA(3,1) simplega/ga31.py 2×2 complex matrices
Quaternions simplega/quaternions.py (w, x, y, z)

Each algebra splits its multivectors into an Even part (grade 0 + grade 2) and an Odd part (grade 1 + grade 3) so the geometric product reduces to four small fixed-shape multiplications. The top-level simplega/init.py module exposes shared helpers: project, bivector_exp, inject, dot, tr, norm, adjoint, isapprox.

Citation / upstream

Documentation

A Python-side documentation set adapted from the upstream Julia docs lives under doc/simplega/:

  • Overview — installation, first example, the Even / Odd trick.
  • API reference — bases, arithmetic, projection, exponentiation, helpers.
  • Algebras — per-algebra notes for GA(2,0), GA(3,0), GA(3,1), and quaternions.

Usage

Each algebra exposes the same Even / Odd pair plus a set of basis elements. Multiplying an Odd by an Odd yields an Even (scalar + bivector); multiplying an Even by an Odd yields an Odd again. Rotations are written as the sandwich product R v R† where R is the exponential of a bivector.

import math
from simplega import ga30 as GA30
from simplega import project, bivector_exp, dot, norm

e1, e2, e3, I3 = GA30.e1, GA30.e2, GA30.e3, GA30.I3
Even = GA30.Even

# Build vectors (grade 1) and decompose the geometric product
v1 = 0.9 * e1 + 0.4 * e2
v2 = 0.4 * e1 + 0.8 * e3
g  = v1 * v2                              # Even = scalar + bivector

inner = project(g, 0)                     # <v1, v2>
outer = project(g, 2)                     # v1 ^ v2

# Build a rotor from a bivector and rotate a vector via sandwich product
B = Even(0.0, 0.0, 0.0, math.pi / 4)      # −(π/4)·e1e2  (90° around z)
R = bivector_exp(B)
v = 0.8 * e1 + 0.2 * e2 + 0.5 * e3
v_rot = R * v * R.adjoint                 # R v R†

print("|v|       =", norm(v))
print("|R v R†|  =", norm(v_rot))         # rotations preserve the norm

Quaternion-style rotations use the dedicated module:

import math
from simplega.quaternions import Quaternion

# 90° rotation around z as a unit quaternion
q = Quaternion(math.cos(math.pi / 4), 0.0, 0.0, math.sin(math.pi / 4))
p = Quaternion(0.0, 1.0, 0.0, 0.0)        # pure-imaginary = vector (1, 0, 0)
p_rot = q * p * q.conj()                  # → (0, 1, 0)

Examples — GA(3,0) elements and transformations

GA(3,0) is isomorphic to the quaternions: its Even subalgebra (scalar + bivectors) reproduces the quaternion algebra, and the sandwich product R v R† rotates a grade-1 vector v exactly like quaternion rotation. The figures below are produced by doc/generate_simplega_figures.py, which uses the GA30Visualizer class and the plot_grade_decomposition helper from simplega/ga30_visualization.py.

Odd element Even element
Odd element v = 0.8 e1 + 0.5 e2 − 0.6 e3 + 0.4 I3: arrow = grade-1 vector, sphere = grade-3 trivector. Even element B = 0.4 + 0.5 e2e3 + 0.7 e1e2 with its adjoint B†: disk = grade-2 bivector, wireframe sphere = grade-0 scalar.
Geometric product Sandwich rotation
Geometric product v1 v2 = <v1, v2> + v1 ^ v2: dashed line = inner product (scalar), disk + parallelogram = outer product (bivector). Sandwich rotation R v R† with R = exp(−(π/4) e1e2) — a 90° rotation around z applied to a general vector.
Even grade decomposition Odd grade decomposition
Grade decomposition of an Even element into its grade-0 scalar and grade-2 bivector parts. Grade decomposition of an Odd element into its grade-1 vector and grade-3 trivector parts.

Regenerating the figures

python doc/generate_simplega_figures.py

Standalone interactive demos for each algebra:

python simplega/ga30_visualization.py
python simplega/quaternion_visualization.py
python simplega/bivector_visualization.py

Ganja

ganja is an original Python reimplementation inspired by the API of ganja.js by Steven De Keninck. It provides a generic Algebra(p, q, r) factory that produces a full Clifford / geometric algebra of any signature, with a single dense Multivector type covering every grade.

The implementation is intentionally small (a few hundred lines) and is not a line-by-line port of the JavaScript source. It is written from first principles around a precomputed basis-blade sign table.

Citation / upstream

Usage

import math
from ganja import Algebra, graph

# 3-D projective geometric algebra: signature (3, 0, 1)
PGA3 = Algebra(3, 0, 1)
e1, e2, e3, e0 = PGA3.basis_vectors()      # e0 squares to 0

# Build a rotor as exp of a bivector and apply it via the sandwich product
B = (math.pi / 4) * (e1 ^ e2)              # 90° generator in the e1-e2 plane
R = B.exp()                                # rotor (unit norm)
rotated = R @ e1                           # equivalent to R * e1 * ~R

# A PGA point at (1, 2, 3): a trivector mixing e1e2e3 with the e0 blades
P = (e1 ^ e2 ^ e3) + 1*(e0 ^ e2 ^ e3) - 2*(e0 ^ e1 ^ e3) + 3*(e0 ^ e1 ^ e2)

# A PGA plane:  x + y + z = 1
plane = e1 + e2 + e3 - e0

# Render points / lines / planes side by side
ax = graph([P, "P(1,2,3)", "tab:red", plane, "plane", "tab:green",
            e2 ^ e3, "x-axis"],
           title="PGA(3,0,1) demo", lim=2.5, show=True)

Operator cheat sheet:

Operator Meaning
a * b geometric product
a ^ b outer (wedge) product
`a b`
~a reverse
R @ a sandwich product R a ~R
a.dual() / a.undual() duality (PGA-aware)
a.exp() exponential (closed form for pure bivectors)
a.grade(k) projection onto grade k

Examples — graph() rendering

The figures below are produced by doc/generate_ganja_figures.py.

PGA(3,0,1) demo PGA(2,0,1) demo
A point, a plane, and a line in 3-D PGA. Two points and a line in 2-D PGA.

Regenerating the figures

python doc/generate_ganja_figures.py

Status

The core algebra (arithmetic, projection, reverse, dual, exp, sandwich) is complete and validated against PGA identities. The graph() function currently supports 2-D and 3-D PGA; other signatures are accepted by the algebra layer but cannot yet be drawn.


Ganja — visualization gallery

A broader showcase of the graph() renderer, exercising every supported object kind in both 2-D and 3-D PGA. The scenes are produced by ganja/visualization_test.py, which can be run interactively or in headless mode:

python ganja/visualization_test.py            # opens matplotlib windows
python ganja/visualization_test.py --save     # writes PNGs to doc/

The script is adapted from the conventions of ganja.js by Steven De Keninck — in particular the Algebra.graph([...]) mixed-item rendering style (multivectors interleaved with labels, colours, polylines, and callables). The underlying algebra and renderer in this repository are original Python code; only the API style of the test scenes follows ganja.js.

PGA(3,0,1) basics PGA(3,0,1) rotor
Three Euclidean points, the x-axis line, and the plane x + y + z = 1 in 3-D PGA. Rotor sandwich R · P · ~R rotating a point 90° about the z-axis, with a gray reference arc.
PGA(3,0,1) translator PGA(3,0,1) meet
Translator sandwich T · L · ~T shifting the x-axis line by (0, 1, 0). Meet of the x-axis line and the plane x = 1 yields the point (1, 0, 0) via line ∧ plane.
PGA(2,0,1) basics PGA(2,0,1) polyline
Two 2-D points A, B, their joining line A ∨ B, and an independent line x + y = 1. A numpy polyline (Archimedean spiral) mixed with PGA points in a single graph() call.

Source / attribution

About

Projective Algebra in 3D - with examples and 3D graphs

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages