docs: full audit — fix 4 wrong port/research labels + consolidated research-track
Some checks failed
C++ Tests / test-fast (push) Successful in 2m50s
C++ Tests / test-fast (pull_request) Successful in 2m36s
API Docs / doc-build (pull_request) Successful in 1m10s
C++ Tests / test-cgal (push) Has been skipped
C++ Tests / test-cgal (pull_request) Failing after 10m25s
Some checks failed
C++ Tests / test-fast (push) Successful in 2m50s
C++ Tests / test-fast (pull_request) Successful in 2m36s
API Docs / doc-build (pull_request) Successful in 1m10s
C++ Tests / test-cgal (push) Has been skipped
C++ Tests / test-cgal (pull_request) Failing after 10m25s
A full audit of `doc/` plus root-level markdown files (27 files) against
the actual ground truth in the C++ code and the local Java repository at
`/Users/tarikmoussa/Desktop/conformallab/` revealed four pre-existing
mis-labels and a stale test count. All are corrected here.
Audit findings — corrected
─────────────────────────
1. **`InversiveDistanceFunctional` mis-labelled as Java port** (4 doc sites)
Empirical verification:
find /Users/tarikmoussa/Desktop/conformallab -iname "*nversive*"
(zero matches)
The class does NOT exist in `de.varylab.discreteconformal`. The C++
implementation is built from Luo 2004 + Glickenstein 2011 + Bowers-
Stephenson 2004 — new research, not a port.
Fixed in: java-parity.md, references.md, add-inversive-distance.md.
2. **HyperIdeal Hessian mis-labelled as "Java has analytic Hessian"**
Empirical verification: `HyperIdealFunctional.java:295-298`:
public boolean hasHessian() { return false; }
Java has NO Hessian at all. Both the FD (Phase 4a) and the block-FD
(Phase 9b) Hessians in C++ are research beyond the Java port. The
chain rule (b,a) → ℓ → ζ → α/β is the *mathematical formulation*
from Springborn 2020, not something Java implements.
Fixed in: java-parity.md.
3. **Stale test count** README:87 said "28 suites, 170 tests" — current
actual is 35 suites, 176 CGAL + 36 non-CGAL. Fixed.
4. **Tutorial framing** — `add-inversive-distance.md` was framed as
"porting an InversiveDistanceFunctional.java" that does not exist.
Rewritten as "Implementing the Inversive-Distance functional from
Luo 2004" with prominent verification block at top.
New document: `doc/roadmap/research-track.md`
─────────────────────────────────────────────
Consolidates everything in conformallab++ that goes beyond a Java port:
* Items already on `main`: HyperIdeal FD Hessian, period matrix τ
partial-research components, Möbius holonomy storage.
* Items on open PRs: CP-Euclidean (PR #8, port), Inversive-Distance
(PR #8, research), block-FD Hessian (PR #9, research).
* Planned research with full citations:
- **Phase 9b-analytic** — full analytic HyperIdeal Hessian via
Schläfli identity (Schläfli 1858/60) and chain rule through
ζ₁₃/ζ₁₄/ζ₁₅, citing Springborn 2020 §4, Cho-Kim 1999,
Glickenstein 2011 §4. Includes acceptance-criteria checklist
(per-case derivative cross-checks, gauge null space, PSD,
measured ≥ 3× speed-up, LaTeX correctness note).
- **Phase 9a.2-analytic** — analytic inversive-distance Hessian
via Glickenstein 2011 eq. (4.6).
- **Phase 10c** — full uniformization for genus g ≥ 2 (Fuchsian
group representation) — fully new research, no Java reference.
- **geometry-central** GC-1/2/3 exploratory track.
* Java backlog summary: 11 worth-porting Java classes identified by
the parallel survey (FundamentalPolygonUtility, DiscreteHarmonicForm-
Utility, DiscreteHolomorphicFormUtility, CanonicalBasisUtility,
HyperbolicCyclicFunctional, QuasiisothermicUtility, KoebePolyhedron, …).
~6 500 Java lines, ~5 months of porting work, organised by phase.
Updated documents
─────────────────
* CLAUDE.md
- New "Port-vs-research maintenance rule" with empirical verification
command and the four corrected mis-labels.
- Doc map: 23 → 24 documents (research-track.md added).
* README.md
- Test count corrected (170 → 176+36).
* doc/math/references.md
- Luo 2004 entry corrected ("new research" instead of "not yet ported").
- New entries for Bowers-Stephenson 2004, Glickenstein 2011,
Bobenko-Pinkall-Springborn 2010, Schläfli 1858/60.
* doc/roadmap/phases.md
- Phase 9 reorganised: 9a split into 9a.1 (port) / 9a.2 (research),
9b clarified as research (Java has no Hessian), 9c expanded with
Java line counts and effort estimates.
- Phase 10 reorganised: 10a/10b/10c with their Java prerequisites
explicitly listed; 10c flagged as "fully new research".
- Phase 10b' added: parallel research track (hyperbolic functional,
quasi-isothermic, Möbius centering).
- Phase 10c' added: optional Java-port additions (Koebe, circle
patterns, electrostatic sphere).
* doc/roadmap/java-parity.md
- Inversive-distance row: ❌ Java, ❌ C++ (Phase 9a.2) — new research.
- CP-Euclidean row added: ✅ Java, ❌ C++ (Phase 9a.1) — port.
- HyperIdeal Hessian row: ❌ Java, ⚠️ FD + block-FD in C++.
- Worth-porting table replaced with the survey results (12 classes,
Java line counts, suggested phases).
- "HyperIdeal Hessian: FD vs analytic" section rewritten with the
correction notice.
* doc/tutorials/add-inversive-distance.md
- Rewritten end-to-end with prominent verification block at top.
- Now correctly framed as "Implementing the Inversive-Distance
functional from Luo 2004" — research, not port.
- Includes the four required cross-validations:
limit cases, Bowers-Stephenson round-trip, FD-vs-analytic,
cross-validation against euclidean_functional at u=0.
- New "How to know if it's a port or research" closing section
with the empirical verification command.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
28
CLAUDE.md
28
CLAUDE.md
@@ -288,9 +288,34 @@ Root-level files added at v0.7.0:
|
|||||||
- `scripts/try_it.sh` — one-script quickstart: build → 209 tests → example run
|
- `scripts/try_it.sh` — one-script quickstart: build → 209 tests → example run
|
||||||
- CMake install target: `cmake --install build --prefix /usr/local` → headers land in `include/conformallab/`
|
- CMake install target: `cmake --install build --prefix /usr/local` → headers land in `include/conformallab/`
|
||||||
|
|
||||||
|
## Port-vs-research maintenance rule (2026-05-21 audit)
|
||||||
|
|
||||||
|
Before claiming something "ports X from Java", **verify empirically**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find /Users/tarikmoussa/Desktop/conformallab -iname "*X*"
|
||||||
|
grep -r "ClassName" /Users/tarikmoussa/Desktop/conformallab/src
|
||||||
|
```
|
||||||
|
|
||||||
|
If zero matches, the work is **new research** — add it to
|
||||||
|
`doc/roadmap/research-track.md` with primary literature citations,
|
||||||
|
**not** to `doc/roadmap/java-parity.md`.
|
||||||
|
|
||||||
|
The 2026-05-21 audit found four pre-existing mis-labels:
|
||||||
|
|
||||||
|
| Item | Wrong claim | Reality |
|
||||||
|
|---|---|---|
|
||||||
|
| `InversiveDistanceFunctional` | "Java port (Luo 2004)" | No such Java class exists |
|
||||||
|
| HyperIdeal Hessian (FD) | "Phase 4a" | Research — Java has `hasHessian()==false` |
|
||||||
|
| HyperIdeal Hessian (analytic) | "Phase 9b port" | Research — derivation via Schläfli 1858 |
|
||||||
|
| Tutorial framing | "ports `InversiveDistanceFunctional.java`" | Implementation from Luo 2004 + Glickenstein 2011 |
|
||||||
|
|
||||||
|
All four are corrected as of this commit. Future contributors must
|
||||||
|
follow the empirical verification rule above before any new claim.
|
||||||
|
|
||||||
## Documentation map
|
## Documentation map
|
||||||
|
|
||||||
23 documents across 6 categories. Read the relevant one before reasoning from scratch
|
24 documents across 6 categories. Read the relevant one before reasoning from scratch
|
||||||
— do not hallucinate content that is already written down.
|
— do not hallucinate content that is already written down.
|
||||||
|
|
||||||
### Mathematics & theory
|
### Mathematics & theory
|
||||||
@@ -338,6 +363,7 @@ Root-level files added at v0.7.0:
|
|||||||
|---|---|
|
|---|---|
|
||||||
| Phases 1–10 with status and sub-tasks | `doc/roadmap/phases.md` |
|
| Phases 1–10 with status and sub-tasks | `doc/roadmap/phases.md` |
|
||||||
| Which Java classes are ported, which are planned, which are skipped? | `doc/roadmap/java-parity.md` |
|
| Which Java classes are ported, which are planned, which are skipped? | `doc/roadmap/java-parity.md` |
|
||||||
|
| New research items (beyond Java) — citations, acceptance criteria | `doc/roadmap/research-track.md` |
|
||||||
|
|
||||||
### Tutorials & onboarding
|
### Tutorials & onboarding
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ Layout2D layout = euclidean_layout(mesh, res.x, maps);
|
|||||||
| **Getting started** — build modes, single-test invocation, CLI, Docker | [doc/getting-started.md](doc/getting-started.md) |
|
| **Getting started** — build modes, single-test invocation, CLI, Docker | [doc/getting-started.md](doc/getting-started.md) |
|
||||||
| **Pipeline API** — all three geometries, holonomy, serialisation | [doc/api/pipeline.md](doc/api/pipeline.md) |
|
| **Pipeline API** — all three geometries, holonomy, serialisation | [doc/api/pipeline.md](doc/api/pipeline.md) |
|
||||||
| **Public headers** — all 24 headers with descriptions | [doc/api/headers.md](doc/api/headers.md) |
|
| **Public headers** — all 24 headers with descriptions | [doc/api/headers.md](doc/api/headers.md) |
|
||||||
| **Test suites** — 28 suites, 170 tests, individual counts | [doc/api/tests.md](doc/api/tests.md) |
|
| **Test suites** — 35 suites, 176+36 tests, individual counts | [doc/api/tests.md](doc/api/tests.md) |
|
||||||
| **Extending** — new functionals, geometry modes, porting from Java | [doc/api/extending.md](doc/api/extending.md) |
|
| **Extending** — new functionals, geometry modes, porting from Java | [doc/api/extending.md](doc/api/extending.md) |
|
||||||
| **Processing unit contracts** — preconditions / provides table | [doc/api/contracts.md](doc/api/contracts.md) |
|
| **Processing unit contracts** — preconditions / provides table | [doc/api/contracts.md](doc/api/contracts.md) |
|
||||||
| **CGAL package design** — Phase 8 target, YAML pipeline | [doc/api/cgal-package.md](doc/api/cgal-package.md) |
|
| **CGAL package design** — Phase 8 target, YAML pipeline | [doc/api/cgal-package.md](doc/api/cgal-package.md) |
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ Java reference implementation: [github.com/varylab/conformallab](https://github.
|
|||||||
| **Springborn** — *Ideal Hyperbolic Polyhedra and Discrete Uniformization*, Discrete & Computational Geometry (2020) | `hyper_ideal_geometry.hpp` — ζ₁₃/ζ₁₄/ζ₁₅ functions; `hyper_ideal_functional.hpp` |
|
| **Springborn** — *Ideal Hyperbolic Polyhedra and Discrete Uniformization*, Discrete & Computational Geometry (2020) | `hyper_ideal_geometry.hpp` — ζ₁₃/ζ₁₄/ζ₁₅ functions; `hyper_ideal_functional.hpp` |
|
||||||
| **Pinkall, Polthier** — *Computing Discrete Minimal Surfaces and Their Conjugates*, Experimental Mathematics (1993) | `euclidean_hessian.hpp` — cotangent Laplacian |
|
| **Pinkall, Polthier** — *Computing Discrete Minimal Surfaces and Their Conjugates*, Experimental Mathematics (1993) | `euclidean_hessian.hpp` — cotangent Laplacian |
|
||||||
| **Bobenko, Springborn** — *Variational Principles for Circle Patterns and Koebe's Theorem*, Transactions AMS (2004) | Variational angle-sum framework underlying all three functionals |
|
| **Bobenko, Springborn** — *Variational Principles for Circle Patterns and Koebe's Theorem*, Transactions AMS (2004) | Variational angle-sum framework underlying all three functionals |
|
||||||
| **Luo** — *Combinatorial Yamabe Flow on Surfaces*, Communications in Contemporary Mathematics (2004) | Inversive-distance functional — **not yet ported**, Phase 9a |
|
| **Luo** — *Combinatorial Yamabe Flow on Surfaces*, Communications in Contemporary Mathematics (2004) | Inversive-distance functional — **new research** in Phase 9a.2 (no Java original; implemented from this paper + Glickenstein 2011 + Bowers-Stephenson 2004) |
|
||||||
|
| **Bowers, Stephenson** — *Uniformizing dessins and Belyĭ maps via circle packing*, Memoirs of the AMS 170(805) (2004) | Bowers-Stephenson identity I_ij = (ℓ²−r_i²−r_j²)/(2 r_i r_j) used to initialise inversive distance from input geometry (Phase 9a.2) |
|
||||||
|
| **Glickenstein** — *Discrete conformal variations and scalar curvature on piecewise flat manifolds*, J. Differential Geometry 87 (2011) | Analytic Hessian of the inversive-distance functional (eq. 4.6) and cross-correspondence I_ij = cos θ_e between vertex-based (9a.2) and face-based (9a.1) circle packings |
|
||||||
|
| **Bobenko, Pinkall, Springborn** — *Discrete conformal maps and ideal hyperbolic polyhedra*, Geometry & Topology 14 (2010) | Face-based circle-packing functional (`CPEuclideanFunctional.java` → `cp_euclidean_functional.hpp`, Phase 9a.1) |
|
||||||
|
| **Schläfli** — *On the multiple integral ∫dx dy …*, Quarterly Journal of Pure and Applied Mathematics (1858/60) | Volume differential `2 dV = Σ_e aₑ dαₑ + Σ_v bᵥ dβᵥ` — foundation for the analytic HyperIdeal Hessian via Schläfli identity (Phase 9b-analytic, **new research beyond Java**) |
|
||||||
| **Erickson, Whittlesey** — *Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm |
|
| **Erickson, Whittlesey** — *Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm |
|
||||||
| **Bobenko, Springborn** — *A Discrete Laplace–Beltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights |
|
| **Bobenko, Springborn** — *A Discrete Laplace–Beltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights |
|
||||||
| **Desbrun, Kanso, Tong** — *Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a |
|
| **Desbrun, Kanso, Tong** — *Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a |
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ as the reference implementation for expected behaviour, edge cases, and test cas
|
|||||||
| Euclidean functional — energy, gradient | ✅ | ✅ | |
|
| Euclidean functional — energy, gradient | ✅ | ✅ | |
|
||||||
| Spherical functional — energy, gradient, gauge-fix | ✅ | ✅ | |
|
| Spherical functional — energy, gradient, gauge-fix | ✅ | ✅ | |
|
||||||
| HyperIdeal functional — energy, gradient | ✅ | ✅ | |
|
| HyperIdeal functional — energy, gradient | ✅ | ✅ | |
|
||||||
| Inversive-distance functional (Luo 2004) | ✅ | ❌ Phase 9a | `InversiveDistanceFunctional.java` |
|
| Inversive-distance functional (Luo 2004) | ❌ *(not in Java)* | ❌ Phase 9a.2 | **No Java source.** Implemented in C++ from Luo 2004 + Glickenstein 2011 + Bowers-Stephenson 2004 — **new research, not a port**. Verified: `find /Users/tarikmoussa/Desktop/conformallab -iname "*nversive*"` returns zero. |
|
||||||
|
| CP-Euclidean functional (BPS 2010) | ✅ | ❌ Phase 9a.1 | `CPEuclideanFunctional.java` (260 lines) — face-based circle packing |
|
||||||
| Euclidean Hessian — cotangent Laplacian | ✅ analytic | ✅ analytic | Pinkall–Polthier (1993) |
|
| Euclidean Hessian — cotangent Laplacian | ✅ analytic | ✅ analytic | Pinkall–Polthier (1993) |
|
||||||
| Spherical Hessian — ∂α/∂u via law of cosines | ✅ analytic | ✅ analytic | |
|
| Spherical Hessian — ∂α/∂u via law of cosines | ✅ analytic | ✅ analytic | |
|
||||||
| HyperIdeal Hessian — ζ → lᵢⱼ → β/α chain | ✅ analytic | ⚠️ symmetric FD | Phase 9b |
|
| HyperIdeal Hessian — analytic via ζ → l → β/α | ❌ *(`hasHessian()==false`)* | ⚠️ FD (Phase 4a) → block-FD (Phase 9b) | **Java has NO Hessian for HyperIdeal** (verified: `HyperIdealFunctional.java:295-298` declares `hasHessian() { return false; }`). Both C++ Hessian variants are **new research beyond Java**; analytic Schläfli-based variant is Phase 9b-analytic. |
|
||||||
| Newton solver | ✅ | ✅ | |
|
| Newton solver | ✅ | ✅ | |
|
||||||
| SparseQR fallback for gauge modes | unknown | ✅ | New in C++ |
|
| SparseQR fallback for gauge modes | unknown | ✅ | New in C++ |
|
||||||
| Cone metrics — prescribed Θᵥ ≠ 2π | ✅ fully | ⚠️ data structure only | |
|
| Cone metrics — prescribed Θᵥ ≠ 2π | ✅ fully | ⚠️ data structure only | |
|
||||||
@@ -48,12 +49,22 @@ They are candidates for Phase 9 or Phase 10.
|
|||||||
|
|
||||||
| Java class | Description | Phase |
|
| Java class | Description | Phase |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `InversiveDistanceFunctional` | Inversive-distance conformal energy | 9a |
|
| `CPEuclideanFunctional` | Face-based circle-packing energy (BPS 2010) | 9a.1 |
|
||||||
| `DiscreteHarmonicFormUtility` | Discrete harmonic 1-forms | 10a prerequisite |
|
| `FundamentalPolygonUtility` (698 lines) | Construction + canonicalisation of 4g-gons for genus-g | 9c |
|
||||||
| `DiscreteHolomorphicFormUtility` | Holomorphic differentials on discrete surfaces | 10a |
|
| `CanonicalFormUtility` (532 lines) | High-level wrapper for 9c — drives canonicalisation pipeline | 9c |
|
||||||
| `DiscreteRiemannUtility` | Discrete Riemann surfaces | 10 |
|
| `CuttingUtility` + `SurgeryUtility` (~800 lines) | Mesh cuts and gluing operations needed for fundamental domains | 9c (foundation) |
|
||||||
| `CanonicalBasisUtility` | Canonical homology basis for genus g | 9c / 10 |
|
| `DiscreteHarmonicFormUtility` (657 lines) | Discrete harmonic 1-forms via cotangent Laplacian (Hodge theory) | 10a prerequisite |
|
||||||
| `HomologyUtility` | Homology computation | 9c |
|
| `DiscreteHolomorphicFormUtility` (285 lines) | Holomorphic differentials via Mercat complex structure | 10a (Bobenko-Springborn 2004 §6) |
|
||||||
|
| `CanonicalBasisUtility` (337 lines) | Symplectic homology basis with intersection-form normalisation | 10a prerequisite |
|
||||||
|
| `DiscreteRiemannUtility` (186 lines) | Period matrix τ, Siegel reduction (genus g) | 10b |
|
||||||
|
| `DualityUtility` (308 lines), `HomologyUtility` (122 lines) | Primal/dual cohomology, cycle generators | 10a support |
|
||||||
|
| `HyperbolicCyclicFunctional` (530 lines) | Discrete hyperbolic conformal energy (analogue of Euclidean) — completes the geometry suite | 10b–c |
|
||||||
|
| `QuasiisothermicUtility` + `SinConditionApplication` (~1200 lines) | Lawson-correspondence parametrisation, sin-condition functional | 10b |
|
||||||
|
| `KoebePolyhedron` (321 lines) | Koebe–Andreev–Thurston circle-packing construction | 10c |
|
||||||
|
| `ElectrostaticSphereFunctional`, `MobiusCenteringFunctional` | Sphere-domain pre-processing functionals | 10c (optional) |
|
||||||
|
|
||||||
|
Note: items marked as *new research* (e.g. Inversive Distance, HyperIdeal Hessian variants)
|
||||||
|
are tracked separately in `doc/roadmap/research-track.md`.
|
||||||
| `HomotopyUtility` | Homotopy generators | 9c |
|
| `HomotopyUtility` | Homotopy generators | 9c |
|
||||||
| `SpanningTreeUtility` | Spanning tree algorithms | 8 / infrastructure |
|
| `SpanningTreeUtility` | Spanning tree algorithms | 8 / infrastructure |
|
||||||
| `SurgeryUtility` | Mesh surgery (cut/glue) | — |
|
| `SurgeryUtility` | Mesh surgery (cut/glue) | — |
|
||||||
@@ -65,22 +76,30 @@ They are candidates for Phase 9 or Phase 10.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## HyperIdeal Hessian: FD vs. analytic
|
## HyperIdeal Hessian — correction of an earlier mis-claim
|
||||||
|
|
||||||
The Java library computes the HyperIdeal Hessian analytically through the chain:
|
> **2026-05-21 audit:** A previous version of this document claimed
|
||||||
|
> "the Java library computes the HyperIdeal Hessian analytically through the
|
||||||
|
> chain (bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ". **This is incorrect.**
|
||||||
|
> The Java source file `HyperIdealFunctional.java` line 295-298 declares
|
||||||
|
> ```java
|
||||||
|
> @Override
|
||||||
|
> public boolean hasHessian() {
|
||||||
|
> return false;
|
||||||
|
> }
|
||||||
|
> ```
|
||||||
|
> i.e. the upstream Java implementation supplies **no** HyperIdeal Hessian at
|
||||||
|
> all — neither analytic nor numerical. The chain rule above is the
|
||||||
|
> *mathematical formulation* (from Springborn 2020 §4 + Schläfli 1858), not
|
||||||
|
> something the Java code implements.
|
||||||
|
|
||||||
```
|
### Actual state of HyperIdeal Hessian in conformallab++
|
||||||
(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ / βᵢ
|
|
||||||
```
|
|
||||||
|
|
||||||
conformallab++ uses a **symmetric finite-difference approximation**:
|
| Variant | Status | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Phase 4a — full FD `H[i,j] = (G(x+εeⱼ)[i] − G(x−εeⱼ)[i]) / (2ε)` | ✅ implemented | O(n·F) cost; PSD by Springborn 2020 strict convexity |
|
||||||
|
| Phase 9b — block-FD (per-face 6×6 local block, scatter to global) | ✅ implemented (PR #9) | O(F·36) cost; ~96× speed-up over Phase 4a measured on V=200 mesh |
|
||||||
|
| Phase 9b-analytic — Schläfli identity + chain rule through ζ₁₃/ζ₁₄/ζ₁₅ | 🔲 planned (research) | See `doc/roadmap/research-track.md` for the formal plan and citations |
|
||||||
|
|
||||||
```
|
All three are **new research beyond the Java port**. Java parity for
|
||||||
H[i,j] = ( G(x + ε·eⱼ)[i] − G(x − ε·eⱼ)[i] ) / (2ε), ε = 1e-5
|
HyperIdeal stops at the gradient.
|
||||||
```
|
|
||||||
|
|
||||||
Accuracy: O(ε²) ≈ 10⁻¹⁰ relative error. PSD guaranteed by strict convexity (Springborn 2020).
|
|
||||||
Cost: n extra gradient evaluations per Newton step.
|
|
||||||
Impact: negligible for meshes < 500 DOFs; measurable for larger meshes.
|
|
||||||
|
|
||||||
The analytic Hessian is deferred to Phase 9b.
|
|
||||||
|
|||||||
@@ -70,27 +70,63 @@ mesh type.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ◼ Remaining porting — Phase 9
|
## ◼ Phase 9 — Mixed: remaining Java port + first research extensions
|
||||||
|
|
||||||
Java features from `de.varylab.discreteconformal` not yet in C++:
|
> **Audit 2026-05-21:** Phase 9 was originally framed as "remaining
|
||||||
|
> porting", but a closer look at the local Java repository revealed:
|
||||||
|
> several Phase-9 items are **not** in Java at all (`InversiveDistanceFunctional`
|
||||||
|
> does not exist; `HyperIdealFunctional.java:295-298` declares `hasHessian()=false`).
|
||||||
|
> The plan below now distinguishes Java-port items from research items.
|
||||||
|
> Full research catalogue: [`research-track.md`](research-track.md).
|
||||||
|
|
||||||
```
|
```
|
||||||
9a Inversive-distance functional (Luo 2004 / Bowers–Stephenson)
|
9a — Circle-packing functionals (split 2026-05-19)
|
||||||
→ inversive_distance_functional.hpp
|
─────────────────────────────────────────────────────
|
||||||
Follows the exact same pattern as the three existing functionals.
|
|
||||||
→ newton_inversive_distance()
|
|
||||||
→ New test suite: test_inversive_distance.cpp
|
|
||||||
|
|
||||||
9b Analytic HyperIdeal Hessian
|
9a.1 CPEuclideanFunctional (Java port)
|
||||||
→ Replace FD Hessian in hyper_ideal_hessian.hpp
|
→ cp_euclidean_functional.hpp
|
||||||
Direct differentiation through the chain:
|
Java source: CPEuclideanFunctional.java (260 lines)
|
||||||
(bᵢ, aₑ) → lᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ / βᵢ
|
Mathematical reference: Bobenko-Pinkall-Springborn 2010
|
||||||
Relevant for meshes > 500 DOFs (current FD Hessian is slow there).
|
Status: 🟡 PR #8 open, 10 tests passing.
|
||||||
|
|
||||||
|
9a.2 Inversive-distance functional (RESEARCH, not a port)
|
||||||
|
→ inversive_distance_functional.hpp
|
||||||
|
Java source: NONE. Empirically verified.
|
||||||
|
Mathematical reference: Luo 2004 + Bowers-Stephenson 2004 + Glickenstein 2011
|
||||||
|
Status: 🟡 PR #8 open, 11 tests passing.
|
||||||
|
Cross-validation: G_id(0) = G_eu(0) at 1e-10 (Glickenstein §5).
|
||||||
|
|
||||||
|
9b — HyperIdeal Hessian (RESEARCH — Java has no Hessian at all)
|
||||||
|
─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
9b Block-FD HyperIdeal Hessian
|
||||||
|
→ Replace full FD in hyper_ideal_hessian.hpp
|
||||||
|
Java source: NONE (HyperIdealFunctional.java:295-298 declares
|
||||||
|
hasHessian()==false; Java has NO Hessian).
|
||||||
|
Algorithm: per-face 6×6 block, scatter to global sparse matrix.
|
||||||
|
Status: 🟡 PR #9 open, 7 tests passing, ~96× speed-up measured.
|
||||||
|
|
||||||
|
9b-analytic Full analytic HyperIdeal Hessian via Schläfli identity
|
||||||
|
→ planned, see research-track.md
|
||||||
|
Mathematical source: Springborn 2020 §4 + Schläfli 1858/60
|
||||||
|
+ Cho-Kim 1999 + Glickenstein 2011 §4
|
||||||
|
Algorithm: explicit chain rule through (bᵢ,aₑ) → ℓᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ
|
||||||
|
Includes: short LaTeX correctness note in doc/math/.
|
||||||
|
Effort: 10–14 days net. Trigger: profiling on V > 5000.
|
||||||
|
|
||||||
|
9c — Genus g > 1 fundamental domain (Java port + research extensions)
|
||||||
|
──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
9c 4g-polygon boundary walk (genus g > 1)
|
9c 4g-polygon boundary walk (genus g > 1)
|
||||||
→ Extend compute_fundamental_domain() beyond genus 1
|
→ Extend compute_fundamental_domain() beyond genus 1
|
||||||
Algorithm outline already in fundamental_domain.hpp as TODO(Phase 9).
|
Java sources: FundamentalPolygonUtility.java (698 lines)
|
||||||
Java reference: FundamentalDomainUtility.java
|
+ CanonicalFormUtility.java (532 lines)
|
||||||
|
+ CuttingUtility / SurgeryUtility (~800 lines)
|
||||||
|
Mathematical source: Poincaré 1882 + Sechelmann 2016 §5
|
||||||
|
Research component: bridging to conformallab++ cut_graph.hpp
|
||||||
|
+ holonomy infrastructure.
|
||||||
|
Effort: ~2 weeks for fundamental polygon, +2 weeks for surgery
|
||||||
|
layer, +1 week integration.
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -151,24 +187,61 @@ variational principle of Bobenko–Springborn 2004).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ◼ New research — Phase 10+
|
## ◼ Phase 10 — Genus g ≥ 2 (research with partial Java support)
|
||||||
|
|
||||||
No direct Java reference implementation exists for these items.
|
Most Phase-10 items have partial Java references (utility classes for
|
||||||
|
forms and homology) but the **assembly** into a working uniformization
|
||||||
|
pipeline is research. Full catalogue with primary literature:
|
||||||
|
[`research-track.md`](research-track.md).
|
||||||
|
|
||||||
```
|
```
|
||||||
Phase 10 Global uniformization for genus g ≥ 2
|
Phase 10 Global uniformization for genus g ≥ 2
|
||||||
|
|
||||||
10a Discrete holomorphic differentials
|
10a Discrete holomorphic and harmonic 1-forms
|
||||||
Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
|
→ Integrate basis 1-forms ωᵢ along b-cycles of the cut graph.
|
||||||
Mathematical basis: Bobenko–Springborn (2004), §6.
|
Mathematical reference: Bobenko-Springborn 2004 §6 + Mercat 2001.
|
||||||
Java partial reference: DiscreteHolomorphicFormUtility.java
|
Java sources (partial, port-with-research):
|
||||||
|
CanonicalBasisUtility.java 337 lines (homology basis)
|
||||||
|
HomologyUtility.java 122 lines
|
||||||
|
DualityUtility.java 308 lines
|
||||||
|
DiscreteHarmonicFormUtility.java 657 lines
|
||||||
|
DiscreteHolomorphicFormUtility.java 285 lines
|
||||||
|
Effort: ~6 weeks net (4 utility ports + 1 integration).
|
||||||
|
|
||||||
10b Siegel period matrix Ω ∈ H_g (g×g complex symmetric, Im(Ω) > 0)
|
10b Siegel period matrix Ω ∈ H_g (g×g complex symmetric, Im(Ω) > 0)
|
||||||
Ωᵢⱼ = ∫_{bⱼ} ωᵢ
|
→ Ωᵢⱼ = ∫_{bⱼ} ωᵢ
|
||||||
Reduction to Siegel fundamental domain via Sp(2g,ℤ).
|
→ Reduction to Siegel fundamental domain via Sp(2g,ℤ).
|
||||||
Requires: 10a
|
Mathematical reference: Bobenko-Springborn 2004 + Gottschling 1959.
|
||||||
|
Java partial reference: DiscreteRiemannUtility.java (186 lines).
|
||||||
|
Requires: 10a.
|
||||||
|
Effort: ~1 week net after 10a.
|
||||||
|
|
||||||
|
10b' Alternative methods (parallel research track)
|
||||||
|
→ HyperbolicCyclicFunctional (Java, 530 lines) — completes the
|
||||||
|
classical three-mode set with hyperbolic energy.
|
||||||
|
→ Quasi-isothermic parametrisation (Lawson correspondence):
|
||||||
|
QuasiisothermicUtility.java + SinConditionApplication.java
|
||||||
|
(~1 200 Java lines combined).
|
||||||
|
→ MobiusCenteringFunctional (Java, 289 lines) — sphere centering.
|
||||||
|
Each independent; can be tackled in any order.
|
||||||
|
|
||||||
10c Full uniformization for genus g ≥ 2
|
10c Full uniformization for genus g ≥ 2
|
||||||
Embedding as H²/Γ with Γ ⊂ PSL(2,ℝ) a Fuchsian group.
|
→ Embedding as H²/Γ with Γ ⊂ PSL(2,ℝ) a Fuchsian group.
|
||||||
Requires: 10a + 10b + stable cut graph for g ≥ 2 (Phase 9c)
|
Mathematical reference: Sechelmann 2016 §6 (discrete instance);
|
||||||
|
Bers 1960 (continuous theory).
|
||||||
|
Java reference: NONE — Java has the polygon + period matrix
|
||||||
|
pieces but does not assemble them into
|
||||||
|
a Fuchsian-group representation.
|
||||||
|
Status: **fully new research.**
|
||||||
|
Requires: 10a + 10b + Phase 9c.
|
||||||
|
|
||||||
|
10c' Optional Java-port additions (low priority)
|
||||||
|
→ KoebePolyhedron.java (321 lines) — Koebe-Andreev-Thurston
|
||||||
|
circle packings. Adds a fifth DCE method.
|
||||||
|
→ ElectrostaticSphereFunctional (127 lines) — sphere
|
||||||
|
distribution baseline.
|
||||||
|
→ CirclePatternLayout / CirclePatternUtility — face-circle
|
||||||
|
pattern layouts.
|
||||||
|
None of these are required for the genus-g uniformization
|
||||||
|
pipeline; they extend the breadth of methods.
|
||||||
```
|
```
|
||||||
|
|||||||
317
doc/roadmap/research-track.md
Normal file
317
doc/roadmap/research-track.md
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
# Research Track — items beyond the Java port
|
||||||
|
|
||||||
|
> **Purpose:** This document consolidates everything in conformallab++
|
||||||
|
> that goes *beyond* a port of `de.varylab.discreteconformal`. Items
|
||||||
|
> listed here are **new research**, drawn from published mathematical
|
||||||
|
> sources (not from Java code). They are separated from the
|
||||||
|
> port-tracking sheet `doc/roadmap/java-parity.md` so that the porting
|
||||||
|
> work and the research work can be planned independently.
|
||||||
|
>
|
||||||
|
> **Created:** 2026-05-21, after a full doc audit that identified four
|
||||||
|
> items previously mislabelled as "ports". This document corrects the
|
||||||
|
> record and extends it with the explicit research plan for Phase
|
||||||
|
> 9b-analytic.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to read this document
|
||||||
|
|
||||||
|
Every entry has the structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
### <item>
|
||||||
|
* Mathematical source(s): <papers with year, journal, equation/section>
|
||||||
|
* Java reference: NONE (or: partial — <class>, with the note "<what>")
|
||||||
|
* Status: 🔲 planned · 🟡 PR open · ✅ landed · ❌ blocked
|
||||||
|
* Acceptance criteria: <what tests/proofs must pass>
|
||||||
|
* Effort: small / medium / large
|
||||||
|
* Phase: 9b-analytic / 9c / 10a / 10b / 10c
|
||||||
|
```
|
||||||
|
|
||||||
|
The phase numbers match `doc/roadmap/phases.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Items already on `main` (research, not port)
|
||||||
|
|
||||||
|
### Hyper-ideal Hessian — FD (Phase 4a, ✅ landed)
|
||||||
|
* **Mathematical source:** symmetric central difference of the
|
||||||
|
analytic gradient `G = (β − Θ, α − θ)` (Springborn 2020 §4 for the
|
||||||
|
gradient itself).
|
||||||
|
* **Java reference:** `HyperIdealFunctional.java:295-298` declares
|
||||||
|
`hasHessian() { return false; }` — **Java has no Hessian at all**.
|
||||||
|
* **Status:** ✅ landed in `code/include/hyper_ideal_hessian.hpp` Phase 4a.
|
||||||
|
* **Why a research item, not a port:** the existing Phase 4a label
|
||||||
|
describes only *when* it was added to the C++ project, not Java
|
||||||
|
parity. The Hessian is a conformallab++ addition.
|
||||||
|
* **Effort:** small (already done).
|
||||||
|
|
||||||
|
### Period matrix τ for genus 1 (Phase 7, ✅ landed)
|
||||||
|
* **Mathematical source:**
|
||||||
|
- Sechelmann (2016) *Variational Methods for Discrete Surface
|
||||||
|
Parameterization* §4 — SL(2,ℤ) reduction algorithm.
|
||||||
|
- Bobenko-Springborn (2004) §6 — period matrix definition.
|
||||||
|
* **Java reference:** partial — `PeriodMatrixUtility.java` exists in Java
|
||||||
|
with similar functionality (this *is* a port).
|
||||||
|
* **Status:** ✅ landed in `code/include/period_matrix.hpp`.
|
||||||
|
* **Note:** listed here only because parts of `phase-9a-validation.md`
|
||||||
|
reference it as research; clarification — the genus-1 period matrix is
|
||||||
|
a Java port, the **genus g ≥ 2** extension (Phase 10b) is research.
|
||||||
|
|
||||||
|
### Möbius holonomy in SU(1,1) (Phase 7, ✅ landed)
|
||||||
|
* **Mathematical source:** Bobenko-Springborn (2004) §5; Sechelmann
|
||||||
|
(2016) §3 for the SU(1,1) representation.
|
||||||
|
* **Java reference:** partial — Java has Möbius transformations but not
|
||||||
|
the holonomy-around-cut-graph computation in the same form.
|
||||||
|
* **Status:** ✅ landed in `code/include/layout.hpp` (`MobiusMap` class).
|
||||||
|
* **Why partially research:** the half-edge `uv` storage for proper
|
||||||
|
seam-aware texture atlasing is new in conformallab++.
|
||||||
|
|
||||||
|
### Cross-API consistency tests (Phase 7 stubs, ✅ landed)
|
||||||
|
* `EuclideanFunctional.GradientCheck_Hessian` and the spherical analog
|
||||||
|
were ported from Java `@Ignore` stubs and given real bodies.
|
||||||
|
* See `doc/architecture/phase-9a-validation.md` for the full mapping.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Items currently on open PRs
|
||||||
|
|
||||||
|
### CP-Euclidean functional (Phase 9a.1, 🟡 PR #8)
|
||||||
|
* **Mathematical source:** Bobenko, Pinkall, Springborn (2010).
|
||||||
|
*Discrete conformal maps and ideal hyperbolic polyhedra.*
|
||||||
|
Geometry & Topology 14, 379–426.
|
||||||
|
* **Java reference:** ✅ `CPEuclideanFunctional.java` (260 lines + 88-line
|
||||||
|
`CPEuclideanFunctionalTest.java`). **This one IS a port.**
|
||||||
|
* **Status:** 🟡 PR #8 open, 10 tests including Java-test parity.
|
||||||
|
* **Note:** listed here because the *face-based* DOF structure is new in
|
||||||
|
conformallab++ (existing functionals all have vertex/edge DOFs); the
|
||||||
|
trait API generalisation needed for it is research-flavoured but the
|
||||||
|
algorithm itself is a port.
|
||||||
|
|
||||||
|
### Inversive-distance functional (Phase 9a.2, 🟡 PR #8)
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Luo, F.** (2004). *Combinatorial Yamabe Flow on Surfaces.*
|
||||||
|
Comm. Contemp. Math. 6(5), 765–780. → edge-length formula §3,
|
||||||
|
gradient identity Lemma 3.1.
|
||||||
|
- **Bowers, P. L. & Stephenson, K.** (2004). *Uniformizing dessins
|
||||||
|
and Belyĭ maps via circle packing.* Memoirs of the AMS 170(805).
|
||||||
|
→ inversive-distance identity `I_ij = (ℓ²−r_i²−r_j²)/(2 r_i r_j)`.
|
||||||
|
- **Glickenstein, D.** (2011). *Discrete conformal variations and
|
||||||
|
scalar curvature on piecewise flat manifolds.* J. Diff. Geom.
|
||||||
|
87(2), 201–238. → §5 correspondence `I_ij = cos θ_e`, eq. 4.6
|
||||||
|
analytic Hessian (used later by Phase 9b-analytic mirror).
|
||||||
|
* **Java reference:** ❌ **none.** Verified empirically:
|
||||||
|
```bash
|
||||||
|
$ find /Users/tarikmoussa/Desktop/conformallab -iname "*nversive*"
|
||||||
|
(zero matches)
|
||||||
|
```
|
||||||
|
* **Status:** 🟡 PR #8 open, 11 tests including limit-case verification
|
||||||
|
and cross-validation with `euclidean_functional.hpp` at `u = 0`.
|
||||||
|
* **Acceptance criteria (all met):**
|
||||||
|
- Three limit-cases of Luo's `ℓ²` formula at machine precision
|
||||||
|
(tangent, orthogonal, inside-tangent).
|
||||||
|
- Bowers-Stephenson round-trip identity at machine precision.
|
||||||
|
- FD-vs-analytic gradient check ≤ 1e-6 on triangle, quad-strip, tetra.
|
||||||
|
- Cross-validation `G_id(0) = G_eu(0)` at 1e-10 (Glickenstein §5).
|
||||||
|
|
||||||
|
### Hyper-ideal Hessian — block-FD (Phase 9b, 🟡 PR #9)
|
||||||
|
* **Mathematical source:** per-face locality lemma:
|
||||||
|
`∂G_x/∂y = Σ_{f: x,y ∈ local(f)} ∂(β or α)/∂y at f`.
|
||||||
|
Same gradient as Phase 4a (Springborn 2020 §4).
|
||||||
|
* **Java reference:** ❌ none (`hasHessian() == false`).
|
||||||
|
* **Status:** 🟡 PR #9 open, 7 tests, measured 96× speed-up over Phase 4a.
|
||||||
|
* **Why research:** the locality lemma + 6×6 block-scatter is a
|
||||||
|
conformallab++ algorithmic contribution; it makes Hessian-based Newton
|
||||||
|
viable on meshes that the upstream Java cannot solve in reasonable
|
||||||
|
time at all (since it has no Hessian).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Planned research (not yet PR)
|
||||||
|
|
||||||
|
### Hyper-ideal Hessian — full analytic (Phase 9b-analytic, 🔲 planned)
|
||||||
|
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Schläfli, L.** (1858/60). *On the multiple integral
|
||||||
|
∫dx dy …* Quart. J. Pure & Appl. Math. → second-order Schläfli
|
||||||
|
identity: `2 dV = Σ_e aₑ dαₑ + Σ_v bᵥ dβᵥ` for any hyperbolic
|
||||||
|
polyhedron, with corresponding bilinear differential on second
|
||||||
|
derivatives.
|
||||||
|
- **Springborn, B.** (2020). *Ideal Hyperbolic Polyhedra and
|
||||||
|
Discrete Uniformization.* Discrete & Comput. Geom. → §4 for the
|
||||||
|
hyper-ideal energy whose gradient is `(β − Θ, α − θ)`, hence
|
||||||
|
Hessian is the Schläfli bilinear form's restriction to the
|
||||||
|
constraint surface.
|
||||||
|
- **Cho, Y. & Kim, H.** (1999). *On the volume formula for
|
||||||
|
hyperbolic tetrahedra.* Discr. Comput. Geom. 22, 347–366.
|
||||||
|
→ explicit derivative formulas for `∂α/∂a`, `∂α/∂b`, `∂β/∂a`,
|
||||||
|
`∂β/∂b` at hyperbolic tetrahedra.
|
||||||
|
- **Glickenstein, D.** (2011) §4 — analogous derivation for the
|
||||||
|
cone-vertex case (extending the formulas across the ideal /
|
||||||
|
hyper-ideal vertex boundary).
|
||||||
|
|
||||||
|
* **Java reference:** ❌ none.
|
||||||
|
|
||||||
|
* **Chain of differentiation:**
|
||||||
|
|
||||||
|
```
|
||||||
|
(bᵢ, aₑ) → ℓᵢⱼ via lij() (closed form: ζ₁₃, ζ₁₄, ζ₁₅)
|
||||||
|
→ βᵢ via zeta() (law of cosines)
|
||||||
|
→ αᵢⱼ via alpha_ij() (zeta + sigma_i + sigma_ij)
|
||||||
|
```
|
||||||
|
|
||||||
|
Each arrow is a smooth function in the interior of its domain. The
|
||||||
|
chain rule then gives, for each face:
|
||||||
|
|
||||||
|
```
|
||||||
|
∂βᵢ/∂(bⱼ, aₑ) = Σ_k (∂βᵢ/∂ℓₖ) · (∂ℓₖ/∂(bⱼ, aₑ))
|
||||||
|
∂αᵢⱼ/∂(bₖ, aₑ) = (similar, with β-dependence factored)
|
||||||
|
```
|
||||||
|
|
||||||
|
These are then assembled into the local 6×6 block, scattered the
|
||||||
|
same way as block-FD (Phase 9b).
|
||||||
|
|
||||||
|
* **Acceptance criteria:**
|
||||||
|
- Each of the four partial-derivative formulas (`∂α/∂a`, `∂α/∂b`,
|
||||||
|
`∂β/∂a`, `∂β/∂b`) cross-checked against block-FD at random `x` on
|
||||||
|
every supported vertex configuration:
|
||||||
|
- all hyper-ideal vertices (general case)
|
||||||
|
- one ideal vertex (`σᵢ`/`σⱼ`/`σₖ` ideal branches)
|
||||||
|
- two ideal vertices
|
||||||
|
- Schläfli identity `H · x = 0` for the constant-vector `x` that
|
||||||
|
corresponds to a global Möbius dilation must hold numerically
|
||||||
|
(gauge null space).
|
||||||
|
- PSD property preserved (Springborn 2020 §4.3).
|
||||||
|
- Measured speed-up over Phase 9b block-FD ≥ 3× (asymptotic ~6×).
|
||||||
|
- **Correctness proof:** a short LaTeX note in
|
||||||
|
`doc/math/hyperideal-hessian-derivation.tex` showing each
|
||||||
|
Schläfli + chain-rule step with edge-cases.
|
||||||
|
|
||||||
|
* **Effort:** large (10–14 days net). Significant share of the time
|
||||||
|
is the formal derivation note and the per-case symbolic verification.
|
||||||
|
|
||||||
|
* **Phase:** 9b-analytic.
|
||||||
|
|
||||||
|
* **Why deferred:** Phase 9b (block-FD) already removes the practical
|
||||||
|
Hessian bottleneck (96× speed-up measured). Analytic gives only
|
||||||
|
another ~6× but at substantial implementation + verification cost.
|
||||||
|
Land on demand when profiling on a real V > 5000 application points
|
||||||
|
to it as the new bottleneck.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Inversive-distance Hessian — full analytic (Phase 9a.2-analytic, 🔲 planned)
|
||||||
|
|
||||||
|
* **Mathematical source:** Glickenstein, D. (2011) eq. (4.6).
|
||||||
|
* **Java reference:** ❌ none.
|
||||||
|
* **Chain:** `(uᵢ, uⱼ) → ℓᵢⱼ → αᵢⱼ` with `∂ℓ²/∂u_i = 2(r_i² + I r_i r_j)`.
|
||||||
|
* **Effort:** medium (5–7 days, less involved than HyperIdeal because
|
||||||
|
the chain has fewer levels and no `σ` intermediaries).
|
||||||
|
* **Status:** 🔲 planned, mirrors Phase 9b-analytic in spirit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Genus g ≥ 2 fundamental domain (Phase 9c, 🔲 planned)
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Poincaré, H.** (1882). *Théorie des groupes fuchsiens.*
|
||||||
|
Acta Math. 1, 1–62. → 4g-gon construction.
|
||||||
|
- **Sechelmann** (2016) §5 for the canonical-form algorithm.
|
||||||
|
* **Java reference:** ✅ partial — `FundamentalPolygonUtility.java`
|
||||||
|
(698 lines) + `CanonicalFormUtility.java` (532 lines) exist; this is
|
||||||
|
a port-with-research-extensions (the C++ side will need to bridge to
|
||||||
|
the cut-graph + holonomy infrastructure already in conformallab++).
|
||||||
|
* **Effort:** large (10–14 days).
|
||||||
|
* **Status:** roadmap item, no PR yet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Discrete holomorphic and harmonic 1-forms (Phase 10a, 🔲 planned)
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Mercat, C.** (2001). *Discrete Riemann surfaces and the Ising
|
||||||
|
model.* Comm. Math. Phys. 218, 177–216. → discrete complex
|
||||||
|
structure on a quad mesh.
|
||||||
|
- **Bobenko, A. I. & Springborn, B.** (2004) §6 — discrete
|
||||||
|
harmonic and holomorphic 1-forms on triangulated surfaces.
|
||||||
|
* **Java reference:** ✅ `DiscreteHarmonicFormUtility.java` (657 lines)
|
||||||
|
+ `DiscreteHolomorphicFormUtility.java` (285 lines). Port-with-
|
||||||
|
research: the C++ port can choose between literal Java translation
|
||||||
|
and a redesign that uses `cut_graph.hpp` + `period_matrix.hpp`
|
||||||
|
natively (research opportunity).
|
||||||
|
* **Effort:** very large (3+ weeks); see java-parity.md.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Siegel period matrix Ω ∈ H_g (Phase 10b, 🔲 planned)
|
||||||
|
* **Mathematical sources:**
|
||||||
|
- **Bobenko-Springborn (2004)** §6 for the discrete formula
|
||||||
|
`Ω_{ij} = ∫_{b_j} ω_i`.
|
||||||
|
- Siegel-fundamental-domain reduction algorithm (Gottschling 1959).
|
||||||
|
* **Java reference:** ✅ partial — `DiscreteRiemannUtility.java`
|
||||||
|
(186 lines).
|
||||||
|
* **Acceptance criteria:** `Ω` symmetric, `Im(Ω) > 0`, in the standard
|
||||||
|
fundamental domain of `Sp(2g, ℤ)`.
|
||||||
|
* **Effort:** medium (1 week after 10a).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Full uniformization for genus g ≥ 2 (Phase 10c, 🔲 planned)
|
||||||
|
* **Mathematical source:** classical (Poincaré 1883; Bers 1960);
|
||||||
|
Sechelmann 2016 §6 for the discrete instance.
|
||||||
|
* **Java reference:** ❌ none — Java has the polygon + period matrix
|
||||||
|
pieces but does not assemble them into a Fuchsian group representation.
|
||||||
|
* **Status:** **fully new research** — depends on 9c + 10a + 10b.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### geometry-central cross-comparison track (Optional, 🔲 exploratory)
|
||||||
|
Three independent items (GC-1/2/3) tracked separately in
|
||||||
|
`doc/roadmap/phases.md` and analysed in detail in
|
||||||
|
`doc/architecture/geometry-central-comparison.md`. They are **purely
|
||||||
|
exploratory**, not roadmap commitments.
|
||||||
|
|
||||||
|
| ID | Item | Effort |
|
||||||
|
|---|---|---|
|
||||||
|
| GC-1 | Output-vector cross-validation against geometry-central | small (2 days) |
|
||||||
|
| GC-2 | Intrinsic Delaunay pre-conditioning via Ptolemaic flips | medium (1 week) |
|
||||||
|
| GC-3 | Ptolemaic flip-based solver as alternative backend | research (Phase 10+) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Java features still worth porting
|
||||||
|
|
||||||
|
These are tracked separately in
|
||||||
|
[`java-parity.md`](java-parity.md), summarised here only for cross-reference:
|
||||||
|
|
||||||
|
| Java class | Lines | Suggested phase | Effort |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `FundamentalPolygonUtility` + `CanonicalFormUtility` | 698 + 532 | 9c | 2 weeks |
|
||||||
|
| `CuttingUtility` + `SurgeryUtility` | 584 + 217 | 9c foundation | 2 weeks |
|
||||||
|
| `DiscreteHarmonicFormUtility` | 657 | 10a | 2 weeks |
|
||||||
|
| `DiscreteHolomorphicFormUtility` | 285 | 10a | 2 weeks |
|
||||||
|
| `CanonicalBasisUtility` | 337 | 10a prereq | 1 week |
|
||||||
|
| `DualityUtility` + `HomologyUtility` | 308 + 122 | 10a support | 1 week |
|
||||||
|
| `DiscreteRiemannUtility` | 186 | 10b | small |
|
||||||
|
| `HyperbolicCyclicFunctional` | 530 | 10b–c | 2 weeks |
|
||||||
|
| `QuasiisothermicUtility` + `SinConditionApplication` | ~1 200 | 10b | 3 weeks |
|
||||||
|
| `KoebePolyhedron` | 321 | 10c | 2 weeks |
|
||||||
|
| `MobiusCenteringFunctional`, `ElectrostaticSphereFunctional` | 289 + 127 | 10c (optional) | small |
|
||||||
|
|
||||||
|
Total identified backlog: ~6 500 Java lines, estimated ~5 months of work
|
||||||
|
to bring it all over. None of it changes the **mathematical** scope —
|
||||||
|
all 11 items above sit within Phases 9c, 10a, 10b, 10c.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Maintenance rule
|
||||||
|
|
||||||
|
If a future PR claims "ports X from Java", **first verify** by:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find /Users/tarikmoussa/Desktop/conformallab -iname "*X*"
|
||||||
|
grep -r "ClassName" /Users/tarikmoussa/Desktop/conformallab/src
|
||||||
|
```
|
||||||
|
|
||||||
|
If either returns zero matches, the item is research and belongs in
|
||||||
|
**this** document, not in `java-parity.md`. Add it with the structured
|
||||||
|
template above, including the primary literature reference and the
|
||||||
|
acceptance criteria.
|
||||||
@@ -1,33 +1,84 @@
|
|||||||
# Tutorial: Porting the Inversive-Distance Functional (Phase 9a)
|
# Tutorial: Implementing the Inversive-Distance Functional (Phase 9a.2)
|
||||||
|
|
||||||
This is a complete, step-by-step example of how to add a new functional
|
This tutorial walks through adding a **new** discrete-conformal functional
|
||||||
to conformallab++. It ports `InversiveDistanceFunctional.java` from the
|
to conformallab++. The running example is the **vertex-based inversive-
|
||||||
Java reference implementation (Luo 2004).
|
distance functional** of Luo (2004), used as Phase 9a.2 of the roadmap.
|
||||||
|
|
||||||
|
> ## ⚠️ This is research, not a port
|
||||||
|
>
|
||||||
|
> An earlier draft of this document claimed this functional was a port of
|
||||||
|
> `de.varylab.discreteconformal.functional.InversiveDistanceFunctional`.
|
||||||
|
> **That Java class does not exist.** Verified empirically:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> $ find /Users/tarikmoussa/Desktop/conformallab -iname "*nversive*"
|
||||||
|
> (zero results)
|
||||||
|
> $ grep -r "InversiveDistance" /Users/tarikmoussa/Desktop/conformallab/src
|
||||||
|
> (zero matches)
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> The closest Java cousin is `CPEuclideanFunctional.java`, which implements
|
||||||
|
> the **face-based** circle-packing variant (Phase 9a.1). The vertex-based
|
||||||
|
> inversive-distance functional (this tutorial) is built **from the
|
||||||
|
> literature**, not from a Java reference, and the correctness validation
|
||||||
|
> is cross-checked against three sources:
|
||||||
|
>
|
||||||
|
> 1. **Luo, F.** (2004). *Combinatorial Yamabe Flow on Surfaces.* Comm. Contemp. Math. 6(5), 765–780.
|
||||||
|
> 2. **Bowers, P. L. & Stephenson, K.** (2004). *Uniformizing dessins and Belyĭ maps via circle packing.* Mem. AMS 170(805).
|
||||||
|
> 3. **Glickenstein, D.** (2011). *Discrete conformal variations and scalar curvature on piecewise flat manifolds.* J. Differential Geometry 87(2), 201–238.
|
||||||
|
>
|
||||||
|
> The tutorial below has been re-written to match this reality.
|
||||||
|
|
||||||
**Prerequisite:** Read [doc/api/extending.md](../api/extending.md) first
|
**Prerequisite:** Read [doc/api/extending.md](../api/extending.md) first
|
||||||
for the general pattern. This tutorial fills in every detail for one
|
for the general functional-porting pattern. This tutorial fills in the
|
||||||
specific case.
|
mathematical and code details for one specific case.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Mathematical background
|
## Mathematical background
|
||||||
|
|
||||||
Inversive distance (Luo 2004) uses a different edge-length update formula:
|
Inversive-distance circle packing parametrises **each vertex** by a circle
|
||||||
|
of radius `r_i = exp(u_i)`. Two adjacent circles have an *inversive
|
||||||
|
distance* `I_ij` that is a fixed constant of the edge, derived once from
|
||||||
|
the initial geometry via the Bowers–Stephenson identity:
|
||||||
|
|
||||||
```
|
```
|
||||||
Given inversive distances I_{ij} ∈ ℝ for each edge {i,j}:
|
I_ij = ( ℓ_ij² − r_i² − r_j² ) / ( 2 r_i r_j ) (Bowers-Stephenson 2004)
|
||||||
|
|
||||||
cosh(l̃_{ij}) = I_{ij} · cosh((u_i + u_j) / 2)
|
|
||||||
+ (cosh²((u_i - u_j) / 2) - 1) · ...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For the Euclidean version the angle formula is the same law of cosines,
|
Geometric interpretation of `I_ij`:
|
||||||
but the log-lengths Λ̃ are computed differently from the u-vector.
|
|
||||||
|
|
||||||
**Reference:** Luo, F. (2004). *Combinatorial Yamabe Flow on Surfaces*.
|
| Range | Configuration |
|
||||||
Communications in Contemporary Mathematics, 6(5), 765–780.
|
|---|---|
|
||||||
|
| `I_ij = +1` | tangent circles (Koebe-style) |
|
||||||
|
| `I_ij ∈ (0, 1)` | overlapping with intersection angle `φ`, `I = cos φ` |
|
||||||
|
| `I_ij = 0` | orthogonal circles |
|
||||||
|
| `I_ij ∈ (−1, 0)` | disjoint circles, inversive distance > 1 |
|
||||||
|
| `I_ij ≤ −1` | impossible packing |
|
||||||
|
|
||||||
**Java source:** `de.varylab.discreteconformal.functional.InversiveDistanceFunctional`
|
The edge length under a state `u` is then determined by Luo's formula:
|
||||||
|
|
||||||
|
```
|
||||||
|
ℓ_ij(u)² = exp(2 u_i) + exp(2 u_j) + 2 I_ij exp(u_i + u_j)
|
||||||
|
= r_i² + r_j² + 2 I_ij r_i r_j (Luo 2004 §3)
|
||||||
|
```
|
||||||
|
|
||||||
|
The angle formula is the same numerically-stable half-tangent law of
|
||||||
|
cosines used by `euclidean_functional.hpp`; only the way `ℓ_ij` is
|
||||||
|
computed from `u` is different.
|
||||||
|
|
||||||
|
The gradient is the standard Yamabe-flow gradient:
|
||||||
|
|
||||||
|
```
|
||||||
|
∂E/∂u_v = Θ_v − Σ_{T ∋ v} α_v(T) (Luo 2004 Lemma 3.1)
|
||||||
|
```
|
||||||
|
|
||||||
|
The energy is a path integral of the gradient (Luo's 1-form is closed on
|
||||||
|
the domain where every triangle is valid); we use the same 10-point
|
||||||
|
Gauss-Legendre quadrature as `euclidean_functional.hpp`.
|
||||||
|
|
||||||
|
The Hessian is finite-difference for the MVP; an analytic form
|
||||||
|
(Glickenstein 2011 eq. 4.6) is documented in the research-track roadmap.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -38,165 +89,212 @@ cp code/include/euclidean_functional.hpp \
|
|||||||
code/include/inversive_distance_functional.hpp
|
code/include/inversive_distance_functional.hpp
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit the new file:
|
Modify the maps struct: replace `lambda0` (Euclidean log-length) with the
|
||||||
|
inversive-distance constant `I_e` and the initial radius `r0` (used for
|
||||||
|
the Bowers-Stephenson init).
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#pragma once
|
|
||||||
// inversive_distance_functional.hpp
|
|
||||||
//
|
|
||||||
// Phase 9a — Inversive-distance discrete conformal functional (Luo 2004).
|
|
||||||
// Ported from de.varylab.discreteconformal.functional.InversiveDistanceFunctional.
|
|
||||||
//
|
|
||||||
// Usage: identical to euclidean_functional.hpp — replace lambda0 with
|
|
||||||
// inversive_distance0 (the initial inversive distances per edge).
|
|
||||||
|
|
||||||
#include "conformal_mesh.hpp"
|
|
||||||
#include <Eigen/Dense>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace conformallab {
|
|
||||||
|
|
||||||
struct InversiveDistanceMaps {
|
struct InversiveDistanceMaps {
|
||||||
CGAL::Surface_mesh<CGAL::Simple_cartesian<double>::Point_3>
|
ConformalMesh::Property_map<Vertex_index, int> v_idx; // DOF index (−1 = pinned)
|
||||||
::Property_map<Edge_index, double> inv_dist0; ///< I_{ij} per edge
|
ConformalMesh::Property_map<Vertex_index, double> theta_v; // target cone angle
|
||||||
CGAL::Surface_mesh<CGAL::Simple_cartesian<double>::Point_3>
|
ConformalMesh::Property_map<Vertex_index, double> r0; // initial radius r_i^(0)
|
||||||
::Property_map<Vertex_index, double> theta_v; ///< target corner angles Θ_v
|
ConformalMesh::Property_map<Edge_index, double> I_e; // inversive distance per edge
|
||||||
CGAL::Surface_mesh<CGAL::Simple_cartesian<double>::Point_3>
|
|
||||||
::Property_map<Vertex_index, int> v_idx; ///< DOF index (-1 = pinned)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ... (follow euclidean_functional.hpp exactly, replacing lambda0 with inv_dist0
|
|
||||||
// and the angle formula with the Luo (2004) version)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Then implement the four entry points that any functional needs in
|
||||||
|
conformallab++:
|
||||||
|
|
||||||
|
- `setup_inversive_distance_maps(mesh)` — create maps with defaults.
|
||||||
|
- `compute_inversive_distance_init_from_mesh(mesh, m)` — choose `r_i^(0)`
|
||||||
|
from the input geometry, then compute `I_ij` via Bowers-Stephenson.
|
||||||
|
- `inversive_distance_gradient(mesh, x, m)` — Luo's `Θ − Σ α`.
|
||||||
|
- `inversive_distance_energy(mesh, x, m)` — 10-point Gauss-Legendre path integral.
|
||||||
|
|
||||||
|
For the full implementation, see `code/include/inversive_distance_functional.hpp`
|
||||||
|
(part of PR #8).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 2 — Implement the energy, gradient, and angle formula
|
## Step 2 — Edge-length kernel
|
||||||
|
|
||||||
The Euclidean angle formula uses the law of cosines on edge lengths
|
The single new pure-math primitive is the Luo edge-length formula. Wrap
|
||||||
derived from log-lengths. For inversive distance, the edge lengths
|
it in a small detail helper so the gradient function reads cleanly:
|
||||||
are derived from inversive distances I_{ij} and the u-vector:
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// Euclidean (reference):
|
namespace id_detail {
|
||||||
// lambda_ij = lambda0_ij + u_i + u_j
|
|
||||||
// l_ij = exp(lambda_ij / 2)
|
|
||||||
|
|
||||||
// Inversive distance (Luo 2004):
|
// ℓ² = exp(2u_i) + exp(2u_j) + 2 I exp(u_i + u_j)
|
||||||
// cosh(l̃_ij) = I_ij * cosh((u_i + u_j) / 2) [simplified form]
|
// Returns -1 on degenerate input (no valid packing).
|
||||||
// l̃_ij = acosh(I_ij * cosh((u_i + u_j) / 2))
|
inline double edge_length_squared(double u_i, double u_j, double I_ij) {
|
||||||
|
double ri = std::exp(u_i);
|
||||||
|
double rj = std::exp(u_j);
|
||||||
|
double l2 = ri*ri + rj*rj + 2.0 * I_ij * ri * rj;
|
||||||
|
return l2 > 0.0 ? l2 : -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace id_detail
|
||||||
```
|
```
|
||||||
|
|
||||||
Then the **corner angle** at vertex k opposite edge {i,j} in triangle {i,j,k}
|
This is the only place where the inversive-distance model differs from
|
||||||
is computed by the standard law of cosines from l̃_{ij}, l̃_{jk}, l̃_{ki}.
|
the Euclidean one. All downstream code (angle computation, gradient
|
||||||
|
accumulation, energy integration) is structurally identical.
|
||||||
The **gradient** is the same as Euclidean:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
G_v = Σ_{faces containing v} alpha_v(face, u) − Theta_v
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 3 — Write the gradient-check test
|
## Step 3 — Reuse `euclidean_angles()`
|
||||||
|
|
||||||
Create `code/tests/cgal/test_inversive_distance.cpp`:
|
The half-tangent law of cosines is independent of how lengths were
|
||||||
|
obtained. Feed `log(ℓ²)` to the existing helper to compute the three
|
||||||
|
corner angles per face:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include "inversive_distance_functional.hpp"
|
auto fa = euclidean_angles(std::log(l12sq), std::log(l23sq), std::log(l31sq));
|
||||||
#include "mesh_factory.hpp"
|
```
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
// Finite-difference gradient check: copy the pattern from
|
This is the **non-trivial reuse** that justifies the structural similarity
|
||||||
// test_euclidean_functional.cpp :: EuclideanFunctional.GradientCheck_Triangle
|
to the Euclidean functional — we get the law-of-cosines numerics for free,
|
||||||
TEST(InversiveDistance, GradientCheck_Triangle)
|
and only the edge-length input changes.
|
||||||
{
|
|
||||||
// Build a single equilateral triangle (open mesh, no boundary issues).
|
|
||||||
ConformalMesh mesh = MeshFactory::make_open_mesh(MeshFactory::Kind::triangle);
|
|
||||||
InversiveDistanceMaps maps = setup_inversive_distance_maps(mesh);
|
|
||||||
compute_inversive_distance0_from_mesh(mesh, maps); // I_ij from 3D edge lengths
|
|
||||||
|
|
||||||
const int n = /* count free DOFs */;
|
---
|
||||||
std::vector<double> x0(n, 0.0);
|
|
||||||
constexpr double eps = 1e-5;
|
|
||||||
|
|
||||||
auto G = inversive_distance_gradient(mesh, x0, maps);
|
## Step 4 — Validation tests
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
The acceptance criteria for this functional are stricter than for a Java
|
||||||
auto xp = x0; xp[i] += eps;
|
port because there is no reference implementation to compare against. We
|
||||||
auto xm = x0; xm[i] -= eps;
|
need **three independent validations**:
|
||||||
double Ep = inversive_distance_energy(mesh, xp, maps);
|
|
||||||
double Em = inversive_distance_energy(mesh, xm, maps);
|
### 4.1 Limit-case edge lengths
|
||||||
double fd = (Ep - Em) / (2.0 * eps);
|
|
||||||
EXPECT_NEAR(G[i], fd, 1e-6) << "gradient mismatch at DOF " << i;
|
Each of Luo's special cases (`I = 1` tangent, `I = 0` orthogonal,
|
||||||
|
`I = −1` inside-tangent) gives a closed-form `ℓ` that must be reproduced
|
||||||
|
to machine precision:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST(InversiveDistanceFunctional, EdgeLengthFormula_TangentialLimit) {
|
||||||
|
// r_i=1, r_j=2, I=1: ℓ² = 1 + 4 + 2·1·1·2 = 9 ⇒ ℓ = 3 = r_i + r_j
|
||||||
|
double l2 = id_detail::edge_length_squared(0.0, std::log(2.0), 1.0);
|
||||||
|
EXPECT_NEAR(std::sqrt(l2), 3.0, 1e-12);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Three such tests cover the diagnostic special cases.
|
||||||
|
|
||||||
|
### 4.2 Bowers-Stephenson round-trip
|
||||||
|
|
||||||
|
The initialisation `compute_inversive_distance_init_from_mesh` must be
|
||||||
|
self-consistent: starting from `(ℓ_3d, r_i, r_j)` and computing `I_ij`,
|
||||||
|
the round-trip back through Luo's formula must give the original `ℓ`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST(InversiveDistanceFunctional, BowersStephensonRoundTrip) {
|
||||||
|
auto mesh = make_triangle();
|
||||||
|
auto m = setup_inversive_distance_maps(mesh);
|
||||||
|
compute_inversive_distance_init_from_mesh(mesh, m);
|
||||||
|
|
||||||
|
for (auto e : mesh.edges()) {
|
||||||
|
double l_3d = /* mesh 3-D edge length */;
|
||||||
|
double ri = m.r0[mesh.source(mesh.halfedge(e))];
|
||||||
|
double rj = m.r0[mesh.target(mesh.halfedge(e))];
|
||||||
|
double l_rec = std::sqrt(ri*ri + rj*rj + 2.0 * m.I_e[e] * ri * rj);
|
||||||
|
EXPECT_NEAR(l_rec, l_3d, 1e-12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Run with:
|
### 4.3 FD-vs-analytic gradient check
|
||||||
|
|
||||||
```bash
|
Standard pattern from every functional in conformallab++ — see
|
||||||
./build/conformallab_cgal_tests --gtest_filter="InversiveDistance.*"
|
`test_euclidean_functional.cpp`. Compare the analytic gradient
|
||||||
|
to a symmetric finite difference of the energy.
|
||||||
|
|
||||||
|
### 4.4 Cross-validation against `euclidean_functional.hpp`
|
||||||
|
|
||||||
|
At `u = 0`, both functionals reconstruct the input 3-D edge length
|
||||||
|
exactly (Euclidean via `compute_lambda0`, inversive distance via
|
||||||
|
Bowers-Stephenson). Therefore the actual angle sums are identical,
|
||||||
|
and the two gradients (with default `Θ_v = 2π`) must match component-wise:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
TEST(InversiveDistanceFunctional, AngleDefectAtU0_AgreesWithEuclideanAtU0) {
|
||||||
|
auto G_id = inversive_distance_gradient(mesh, /*x=0*/, m_id);
|
||||||
|
auto G_eu = euclidean_gradient (mesh, /*x=0*/, m_eu);
|
||||||
|
for (size_t i = 0; i < G_id.size(); ++i)
|
||||||
|
EXPECT_NEAR(G_id[i], G_eu[i], 1e-10);
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This is the empirical statement of Glickenstein 2011 §5: different
|
||||||
|
parametrisations of the same initial discrete metric produce the same
|
||||||
|
Newton-time-zero gradient.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 4 — Register in CMakeLists
|
## Step 5 — Register the tests
|
||||||
|
|
||||||
Add to `code/tests/cgal/CMakeLists.txt` inside the `add_executable` block:
|
In `code/tests/cgal/CMakeLists.txt`:
|
||||||
|
|
||||||
```cmake
|
```cmake
|
||||||
# ── Phase 9a: Inversive-distance functional ────────────────────────────────
|
# ── Phase 9a.2: InversiveDistance (Luo 2004 + Glickenstein 2011) ─────────
|
||||||
test_inversive_distance.cpp
|
# Vertex-based inversive-distance circle-packing functional. No Java
|
||||||
|
# reference; implemented from the literature. Cross-validated against
|
||||||
|
# EuclideanCyclicFunctional at the natural initial geometry (u = 0).
|
||||||
|
test_inversive_distance_functional.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ctest --test-dir build -R "InversiveDistance" --output-on-failure
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 5 — Add a Newton wrapper
|
## Step 6 — Newton solver
|
||||||
|
|
||||||
In `code/include/newton_solver.hpp` add:
|
Once the functional passes its tests, wire a Newton wrapper into
|
||||||
|
`newton_solver.hpp`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
/// Solve the inversive-distance conformal problem.
|
|
||||||
/// \see newton_euclidean() — identical structure.
|
|
||||||
inline NewtonResult newton_inversive_distance(
|
inline NewtonResult newton_inversive_distance(
|
||||||
ConformalMesh& mesh,
|
ConformalMesh& mesh,
|
||||||
std::vector<double> x0,
|
std::vector<double> x0,
|
||||||
const InversiveDistanceMaps& m,
|
const InversiveDistanceMaps& m,
|
||||||
double tol = 1e-8,
|
double tol = 1e-8,
|
||||||
int max_iter = 200)
|
int max_iter = 200);
|
||||||
{
|
|
||||||
// Copy newton_euclidean() exactly, replacing euclidean_* with
|
|
||||||
// inversive_distance_*. The Hessian is PSD (Luo 2004, Thm. 1),
|
|
||||||
// so SimplicialLDLT with SparseQR fallback applies directly.
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The body is structurally identical to `newton_euclidean()` — same
|
||||||
|
SimplicialLDLT + SparseQR fallback, same termination test. Only the
|
||||||
|
inner gradient / Hessian calls differ.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 6 — Verify against Java output
|
## Checklist for a new functional
|
||||||
|
|
||||||
The Java library outputs text results for a triangulated torus. To compare:
|
- [ ] `code/include/<name>_functional.hpp` compiles
|
||||||
|
- [ ] Limit-case edge-length tests pass at machine precision
|
||||||
1. Run Java ConformalLab on the same OFF mesh with Inversive-Distance mode.
|
- [ ] Round-trip identity (init ⇄ length formula) verified
|
||||||
2. Record the final gradient norm and angle sums.
|
- [ ] FD-vs-analytic gradient check passes on triangle, quad strip, tetra
|
||||||
3. Run the C++ equivalent and check:
|
- [ ] Cross-validation test against an existing functional at `u = 0`
|
||||||
|
- [ ] Newton wrapper added to `newton_solver.hpp`
|
||||||
```cpp
|
- [ ] Registered in `code/tests/cgal/CMakeLists.txt`
|
||||||
EXPECT_LT(res.grad_inf_norm, 1e-8);
|
- [ ] `doc/roadmap/java-parity.md` updated (port status or research note)
|
||||||
EXPECT_LT(res.iterations, 50); // inversive-distance converges faster than hyper-ideal
|
- [ ] `doc/math/references.md` extended with the primary paper(s)
|
||||||
```
|
- [ ] If this is *new research* beyond Java: add an entry in
|
||||||
|
`doc/roadmap/research-track.md` with citations and acceptance criteria
|
||||||
**Java reference:** `InversiveDistanceFunctionalTest.java` in `de.varylab.discreteconformal.test`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Checklist
|
## How to know if it's a port or research
|
||||||
|
|
||||||
- [ ] `code/include/inversive_distance_functional.hpp` compiles
|
Run the local Java-repo check **first** before writing any tutorial doc:
|
||||||
- [ ] `GradientCheck_Triangle` passes
|
|
||||||
- [ ] `GradientCheck_OpenMesh` passes (copy from Euclidean tests)
|
```bash
|
||||||
- [ ] Newton converges on `torus_4x4.off`
|
find /Users/tarikmoussa/Desktop/conformallab -iname "*<feature>*"
|
||||||
- [ ] Result matches Java output (gradient norm < 1e-8 on same mesh)
|
grep -r "<ClassName>" /Users/tarikmoussa/Desktop/conformallab/src
|
||||||
- [ ] Registered in `CMakeLists.txt`
|
```
|
||||||
- [ ] `doc/roadmap/java-parity.md` updated: Phase 9a → ✅
|
|
||||||
|
If both return zero matches, the feature is **not** in Java and any C++
|
||||||
|
implementation is **new research**, not a port. The tutorial framing and
|
||||||
|
the `doc/roadmap/research-track.md` entry should reflect this from day one.
|
||||||
|
|||||||
Reference in New Issue
Block a user