Skip to content

Changes since version 0.9.2

New Features

  • OPNS/IPNS flag on the algebra — the OPNS/IPNS interpretation flag moves off per-call opns=... keyword arguments and onto the algebra itself. Algebra.opns (mutable, default True) is delegated by MV.opns and forwarded by all eight Basis* classes, so the setting is read once from the algebra for both creation and analysis.
  • Typed per-entity analyzers — explicit public analyzers (analyze_point, analyze_direction, analyze_line, analyze_plane, analyze_circle, analyze_sphere, analyze_point_pair, analyze_hpoint, analyze_hdirection, analyze_space) in every analysis_* module, reading mv.algebra.opns and raising on a mismatched structure.
  • MV-accepting entity constructors — Point(mv), Direction(mv), Line(mv), Plane(mv), Circle(mv), Sphere(mv), PointPair(mv), HPoint(mv), HDirection(mv), and Space(mv) convert a multivector via the matching typed analyzer. Nested fields auto-convert their MV arguments too (each Point/Direction/scalar component), plus Line.from_points(start, end).
  • Geometry.__call__ — geo(obj) now forwards to create(obj) for entities/operators and to analyze(obj) for multivectors.
  • E = einf ^ eo member added to BasisN3 and BasisN2.
  • Color enum — a default colour palette (StrEnum) in viz/_colors.py, exported from viz.
  • Extended algebra/MV operator surface — galgebra-parity operators added to Algebra and MV: grade involutions/conjugates (grade_involution, grade_conj), scalar_product(rev=...), qform, norm2, norm, exp, even/odd grade extraction, cp/acp/rc, gp_min/gp_max, type probes (is_vector, is_base, is_blade, is_versor, is_grade), coefficient helpers (blade_coefs, components, get_coefs), blade/versor factorization, and reverse/conjugate-flagged product variants (gp_rev/gp_conj/ip_rev/ip_conj/op_rev/op_conj).
  • MV.prune(tol=...) — prune() now accepts an optional tolerance, defaulting to algebra.precision, instead of silently using a hard-coded value.
  • Random entity generators — RndPoint/RndDirection (plus the Distribution/Uniform/Normal base classes) generate Point/Direction dataclasses from per-coordinate distributions. Geometry(algebra, seed=...) owns a seeded NumPy generator (geo.rng), and geo(RndPoint(...)) / geo([RndPoint(...) for _ in range(n)]) (or count=n) materialize them into MVs via the algebra's create dispatch, honoring OPNS/IPNS.
  • macOS compilation (Apple Intel + Apple Silicon) — the C++ bindings now compile on macOS. Apple Clang/libc++ portability fixes (removing the invalid std forward declaration in StrideIterator.h and fixing a lambda this-capture in Matrix.h) enable Intel (x86_64) builds, while gating the x86-only includes/intrinsics (<x86intrin.h>, _mm_popcnt_u32) and compile flags (-msse4.1/-mpopcnt) behind an x86 check enables Apple Silicon (arm64) builds.
  • Precompiled Apple Silicon wheels — the publish workflow now builds and uploads precompiled macosx_*_arm64 wheels (via macos-14) for CPython 3.12 and 3.13, alongside the existing Linux/Windows wheels.

Breaking Changes

  • Removed opns from the analysis and creation paths — analyze*, analyze_entity, create_entity, create, and Geometry no longer accept an opns override; they read algebra.opns.
  • Removed geometry-creating methods from basis classes — point/direction/line/plane/vector/rotor no longer live on Basis*; geometry is created only through the geometry submodule.
  • E2/E3 create_point no longer raises — a point maps to its Euclidean components independent of OPNS/IPNS.
  • Imaginary entities now raise NotImplementedError — ImagPointPair, ImagCircle, and imaginary ImagSphere in N2/N3 are not yet implemented.

Bug Fixes

  • N2/N3 point-pair separation — the point-pair decomposer returned the wrong point distance (half the true value in N2) and an unnormalized direction. S* is now normalized by its e₀ coefficient and separation = 2·half_dist.
  • N2/N3 circle/point-pair normalisation — the IPNS circle/point-pair was not normalized by its e₀ coefficient before extracting centre and radius, so a globally scaled MV produced a wrong radius. Fixed in _decompose_circle and mirrored into the other N2/N3 decomposers.

Refactor

  • Entities split into per-entity modules — the 700-line entities.py is split into entities/ (point, direction, line, plane, circle, sphere, point_pair, hpoint, hdirection, space) with shared _util.py / _coerce.py helpers (to_point / to_direction / to_float).
  • Analyzer registry — analysis.py registers the typed analyzers with entities at import time, removing the lazy-import cycle.
  • Operator constructors — operators.py now explicitly coerces entity/MV/float arguments, and ReflectionLine/ReflectionPlane no longer accept legacy keyword fallbacks.
  • Example scripts updated — all examples under py/examples/ now use the new API: no opns= keyword arguments, geometry created through the geometry submodule (or string conversion) instead of the removed basis factories, PGA demos rewritten around e0/e0_recip rather than einf/eo, and geo.create/geo.which_entity/geo.which_operator annotated with the dual create/analyze behavior of Geometry.__call__.