variety-point-clouds
View on GitHubSampling algebraic varieties in real and complex projective space as point clouds.
with Fabian Lander
- Built with TypeScript / three.js
- Status Active
Readme
Sample point clouds on algebraic varieties in real and complex projective space (including links of singularities and Milnor fibers), embed them into high-dimensional matrix spaces via Veronese and projector embeddings, and visualize or export the results.
Quick start
npm install
npm run dev weierstrass-cubic
Demos
Each demo is a standalone Three.js app in demos/. Run any with npm run dev <name>.
| Demo | What it shows |
|---|---|
weierstrass-cubic | Elliptic curve in CP², rotating under U(3), with CSV export controls |
real-curve-rp2 | Real cubic in RP² in affine chart, O(3) rotation |
real-surface-rp3 | Steiner surface in RP³ in affine chart, O(4) rotation |
hyperelliptic | Hyperelliptic curves y² = f(x) of various genera in CP² |
milnor-fiber | Milnor fiber of various singularities with θ slider (includes the trefoil) |
seifert-surface | Closed Seifert surfaces (custom shader) with θ slider |
slice-rp4 | Quartic 3-fold in RP⁴, sliced through the 4th affine axis |
poincare-sphere | Poincaré homology sphere (link of E₈), sliced from R⁶ to R³ |
complex-surface-cp3 | Fermat quartic surface in CP³, 3 slice sliders through R⁶ |
complete-intersection | Real curves in RP³, complex curves in CP³, surfaces in RP⁴/⁵ |
Export
Sample a variety and write the embedded point cloud to disk. Every export also
writes a sidecar <out>.meta.json describing the dataset (variety ID, sampling
parameters, embedding, shape) so the file is self-describing.
# List all available varieties by stable ID
npm run export -- --list
# Weierstrass cubic, 10k points, ν₂ then projector → R³⁶, CSV
npm run export -- --variety weierstrass-cubic --points 10000 --veronese 2 --out points.csv
# Klein quartic → projector → R⁹, NumPy binary (load directly in Python)
npm run export -- --variety klein-quartic --points 5000 --format npy --out klein.npy
# Real-flat output: ν₂ then flatten C^N → R^{2N}
npm run export -- --variety weierstrass-cubic --veronese 2 --output real-flat --out flat.csv
# Singularity link (default = link, V(F) ∩ S^{2n-1})
npm run export -- --variety sing-z2-w3 --points 5000 --out trefoil.csv
# Singularity Milnor fiber at θ = π/4
npm run export -- --variety sing-z3-w5 --points 5000 --mode fiber --theta 0.785 --out e8-fiber.csv
Each row is a point in R^{N²} (projector) or R^{2N} (real-flat), where N is the target dimension after the optional Veronese map.
Building for the web
npm run build weierstrass-cubic # writes dist/weierstrass-cubic/ as a static site
Each demo builds into its own self-contained dist/<demo>/ subfolder (relative
paths, can be dropped anywhere on a site). Building another demo doesn’t clobber
previous builds.
Project structure
See src/README.md for the architecture overview. In brief:
src/
math/ Pure math primitives (complex, polynomials + algebra DSL, rotations, ...)
solvers/ Numerical samplers: rootfind + hypersurface/intersection/link samplers
embeddings/ High-dim embeddings: Veronese, projector
projections/ Pure functions CPnPoint → R³ (affine, stereographic, slicing, random projection, ...)
viewer/ Three.js infrastructure: Scene + PointBuffer + overlay
export/ Composable sample-and-embed pipeline + CSV / NPY / metadata writers
examples/ Predefined varieties (curves, surfaces, threefolds, singularities, intersections)
demos/ Standalone demos, one main.ts each
scripts/ CLI tools (run-demo, export)
tests/ Vitest suite — invariants over math, solvers, embeddings, projections, export
Docs
- docs/math.md — coordinates, samplers, embeddings, tolerances.
- docs/polynomials.md — design of the polynomial / symbolic-algebra layer.
- docs/methods.md — sampling-method roadmap (homotopy, witness sets, …).
- docs/performance.md — where time goes, what to optimize next.
How the math works
Sampling hypersurfaces. For a single polynomial F in CP^n, we sample V(F) by intersecting random complex lines with the variety and solving the resulting univariate polynomial via Durand-Kerner. A random walk grows a dense cloud.
Sampling complete intersections. For k > 1 equations V(F₁,…,Fₖ), line intersection doesn’t work (codimension k > 1 generically misses any line). Instead we use the non-square Newton: random starting point, Newton-correct via the minimum-norm pseudoinverse step Δz = J*(JJ*)⁻¹F.
Links of singularities. For F: C^n → C with a singularity at 0, the link V(F) ∩ S^{2n-1}_ε is sampled by random points on the sphere + Newton correction with radial reprojection. Same idea for Milnor fibers (preimage of a ray, restricted to the sphere).
Embeddings. Veronese ν_d : CP^n → CP^N (multinomial-weighted monomials) and the rank-1 projector embedding CP^n → R^{(n+1)²} give isometric embeddings into Euclidean space. Composed, they map any complex projective variety into a real vector space with no chart singularities — suitable for ML pipelines.
Tests
npm test # one-shot
npm run test:watch
Each test asserts a mathematical invariant (Veronese is norm-preserving, projector trace = 1, Newton-corrected samples lie on V(F), etc.).
Limitations
- Veronese multinomial weights overflow for degree > ~20.
- The complete-intersection sampler uses random starts: for varieties with very small basin of attraction the convergence rate can be poor.
- Random walks on the real locus can get stuck on one connected component.