docs: split Phase 9a into 9a.1 (CPEuclidean) + 9a.2 (InversiveDistance)

Audit during Phase 9a preparation revealed:

* The Java repo `varylab/conformallab` does NOT contain
  `InversiveDistanceFunctional.java`.  The original roadmap mention
  was based on a misreading.
* The closest existing Java class is `CPEuclideanFunctional.java`
  (260 lines, with FunctionalTest), implementing the Bobenko-Pinkall-
  Springborn 2010 face-based circle-packing functional.

These two functionals are mathematically distinct (face-dual vs vertex-
based) but related: BPS-CP generalises inversive-distance via the
intersection angle parameter θ_e (I_ij = cos θ_e for orthogonal
limit, I_ij = 1 for tangential).

The roadmap is now split into:
- 9a.1  CPEuclideanFunctional  (Java port + test, BPS 2010 reference)
- 9a.2  InversiveDistanceFunctional  (from-literature, Luo 2004
        + Glickenstein 2011)

Both belong in Phase 9a; cross-validation between them in the
tangential limit (θ=0 ⇔ I=1) becomes a Phase 9a acceptance test.

The tutorial `doc/tutorials/add-inversive-distance.md` is corrected:
it no longer claims `InversiveDistanceFunctional.java` exists upstream,
and cites Luo 2004 + Glickenstein 2011 + Bowers-Stephenson 2004 instead.
Updated edge-length formula from incorrect hyperbolic cosh form to
the correct Luo §3 Euclidean form:
  ℓ_ij² = exp(2u_i) + exp(2u_j) + 2 I_ij exp(u_i + u_j)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-19 23:18:57 +02:00
parent e435e143c6
commit 48e6d2131e
2 changed files with 121 additions and 17 deletions

View File

@@ -75,11 +75,79 @@ mesh type.
Java features from `de.varylab.discreteconformal` not yet in C++:
```
9a Inversive-distance functional (Luo 2004 / BowersStephenson)
9a Circle-packing / inversive-distance functionals
───────────────────────────────────────────────
Status: discovered during 9a-prep audit (2026-05-19) that the
original roadmap mention "inversive_distance_functional.hpp" was
based on a misreading — the Java repo at de.varylab.discreteconformal
does NOT contain InversiveDistanceFunctional.java. It contains the
related CPEuclideanFunctional.java which is the face-dual variant
(Bobenko-Pinkall-Springborn 2010). These are two mathematically
distinct models that both belong in this phase. Plan split:
9a.1 CPEuclideanFunctional (FACE-based circle packing)
→ cp_euclidean_functional.hpp
Java reference: CPEuclideanFunctional.java (260 lines) + test
Mathematical reference:
Bobenko, Pinkall, Springborn (2010) — "Discrete conformal maps
and ideal hyperbolic polyhedra", Geom. Topol. 14, 379-426.
DOFs: ρ_f per FACE (log-radius of the face-circle)
Constants: θ_e per edge (intersection angle, π/2 = orthogonal)
φ_f per face (target face-angle sum, default 2π)
Energy: E(ρ) = -Σ_f φ_f·ρ_f
+ Σ_e [½·p(θ*_e, Δρ_e)·Δρ_e + Λ(θ*_e + p)]
where p = 2·atan(tan(θ*/2)·tanh(Δρ/2)),
Λ = Clausen function, θ* = π θ.
Hessian: analytic, 2×2 per interior edge:
h_jk = sin(θ) / (cosh(Δρ) cos(θ))
Gauge: first face is pinned (ρ_0 = 0)
New CGAL entry: CGAL::discrete_circle_packing_euclidean(mesh, np)
Test suite: test_cp_euclidean_functional.cpp
(Dodecahedron-with-removed-face, θ=π/2,
FD gradient check, FD-vs-analytic Hessian check)
9a.2 Inversive-distance functional (VERTEX-based)
→ inversive_distance_functional.hpp
Follows the exact same pattern as the three existing functionals.
→ newton_inversive_distance()
→ New test suite: test_inversive_distance.cpp
Java reference: NONE (does not exist upstream)
Mathematical reference:
Luo, F. (2004) "Combinatorial Yamabe Flow on Surfaces",
Commun. Contemp. Math. 6(5), 765-780.
Bowers, P. & Stephenson, K. (2004) "Uniformizing dessins
and Belyĭ maps via circle packing", Mem. AMS 170(805).
Glickenstein, D. (2011) "Discrete conformal variations and
scalar curvature on piecewise flat manifolds",
J. Diff. Geom. 87(2), 201-238 (analytic Hessian).
DOFs: u_i per VERTEX (u_i = log r_i)
Constants: I_ij per edge (inversive distance, computed
once from initial geometry:
I_ij = (_ij² r_i² r_j²)
/ (2 r_i r_j))
Θ_v per vertex (target cone angle, default 2π)
Edge length: _ij(u)² = e^{2u_i} + e^{2u_j} + 2 I_ij e^{u_i+u_j}
Angles: identical half-tangent atan2 form to Euclidean
Gradient: ∂E/∂u_v = Θ_v Σ_{T∋v} α_v(T)
(Luo 2004 Lemma 3.1)
Energy: path integral E(u) = ∫₀¹⟨G(tu),u⟩dt
(Luo's 1-form is closed; no general closed form,
use 10-point Gauss-Legendre as in Euclidean)
Hessian: FD for MVP; analytic (Glickenstein 2011 eq. 4.6)
as future optimisation
Gauge: first vertex pinned (u_0 = 0)
New CGAL entry: CGAL::discrete_inversive_distance_map(mesh, np)
Test suite: test_inversive_distance_functional.cpp
(small triangle + quad + tetra, FD gradient
check, convergence test, special case I=1
coincides with tangential circle packing)
Cross-validation between 9a.1 and 9a.2 (Glickenstein 2011 §5):
In the tangential limit (θ_e = 0 in 9a.1 ⇔ I_ij = 1 in 9a.2),
both functionals describe the same circle packing. Their
converged radii must satisfy
ρ_f(9a.1) vs ½·log(r_i·r_j) (9a.2)
under the appropriate vertex↔face dual correspondence. This
cross-check is part of the Phase 9a acceptance tests.
9b Analytic HyperIdeal Hessian
→ Replace FD Hessian in hyper_ideal_hessian.hpp