C++23 header-only library for computational geometry and physics on arbitrary Riemannian manifolds — spheres, hyperbolic space, and custom surfaces as first-class concepts, not hardcoded types - Va...

1 points•Vaniello•9 days ago•1 comment•

1 comment

Vaniello9 days ago
std gave C++ a shared vocabulary and deliberately implements no domain. It composes with everything precisely because it commits to nothing.

Nobody gave C++ that vocabulary for spaces. Everyone computes in Euclidean space and never asked for more. Geometry stopped being about that a long time ago: points on a sphere, in hyperbolic space, on the manifold of SPD matrices, on curved spacetime. Every one of those is a separate library with its own types.

Spatium is both halves: concepts that say what a space is, and a body of work that speaks them.

It started as a language exercise. I was learning templates, read about concepts, had just lost a couple of thousand lines of vectors and matrices, and rewrote it clean. My favourite way to learn a language is to take something that writes simply and demands everything of you. That is where the generality comes from — it was never shaped to a task.

First file five months ago, two of which I didn't touch it. The present shape is the last two. I build it with Claude, which every commit says in its trailer.

Set → MetricSpace → Manifold → RiemannianManifold → Surface — contracts. Define exp_map(), log_map(), project() on your own struct, static_assert the concept, and meshing, subdivision, geodesics, Voronoi, Riemannian optimization and the physics integrators all work on it. There is no per-space code, because there is no per-space anything.

A contract is not a base class, so other people's types fit without conversion.

Dual<T>, forward-mode autodiff, satisfies Scalar — which is how the exact Christoffel symbols get computed with no hand-derived partials. Boost's 50-digit Real50 drops into the same slot. chart_of() lets a space declared outside the library into the scene DSL.

None of the three knows about the other two.

Implemented: Euclidean spaces, spheres, hyperbolic space, parametric and implicit surfaces, SO(3), SE(3), SPD(n) under two metrics, Schwarzschild and Kerr, the heat method, IPC, XPBD, variational and Lie-group integrators, wave equations, BVH, polynomial solvers, arbitrary precision. 133 headers, 1060 tests.

The scene DSL describes a scene as spaces — torus(), offset(), scatter() — rather than as meshes. The description stays a graph instead of becoming geometry.

34 nodes describe 2,021,984 objects. Geometry worth 64,654,768 vertices is stored as 39,272 — 1646x less. The frame renders in under a gigabyte.

That isn't a renderer trick.

If it can compute that, what can't it compute?

rsc/ picks what to compute a problem with: Newton or bisection, double or fifty digits, analytic or tessellated. Alongside it, a search that composes registry operations into sequences.

It fits in a repository this size because the library is its own oracle: a candidate is correct when running it reproduces the reference. No labelled data. Ask it to reach a target using only addition and you get a sequence, or the answer that it is unreachable in N steps.

The operations are concept-constrained and none of them names a space, so a chain is a program over the concept. I found one on a sphere and replayed it unchanged on Euclidean space and on a torus — where subdivision projects onto the sphere, onto nothing, and onto the torus respectively. The specification "ten times the faces, longest edge at most 0.45 of the original" holds on all three. In absolute units it holds only where it was found. Searching each space directly finds a chain of the same length.

Structure transfers, constants don't. Five mesh operations — a small result. But AlphaTensor's discoveries are bound to their ring and do not generalise themselves, and the question here isn't compute, it's whether there is an interface the generalisation can be checked through. Here the compiler does the checking.

Apache 2.0, header-only, no mandatory dependencies. Most of this mathematics exists somewhere already — behind a license you negotiate, or a stack you adopt whole. Implementations are what turn a standard into something anyone can use rather than a few people on terms.

Checks: our own SVD against Eigen, where we lose at N=16 and the docs say so; binomial_coefficient against Python's math.comb over 4.5M pairs; a quartic-solver bug found and pinned with a regression test; sound from a solved wave equation, not a sample.

The roadmap has 30 open [want] items, and that list is only what I managed to find. I'm not a researcher, I don't do ML, I've never shipped a game — I built these because I kept hearing they were needed. Someone who works in those fields will see what I couldn't.

Build something strange with it. Issues and PRs welcome.

Read the full thread on Hacker News →

Related stories