Files
ConformalLabpp/doc/reviewer/java-ignore-crossvalidation.md
Tarik Moussa 267ae965ab docs(reviewer): Tier-2 exhausted (genus≥2 → Phase 13); Tier-3 Lawson scoped as mini-project
- regular_uniformization.xml / LetterB01_canonical_group.xml are genus≥2
  hyperbolic Fuchsian-group uniformizations (12-edge fundamental polygon), not
  genus-1 → Phase 13, not Tier 2.
- Tier-2 is therefore exhausted (only Wente, deferred to Phase 9f quad/cyclic).
- Tier-3 Lawson HyperIdeal golden vectors require a low-level halfedge genus-2
  multi-edge generator (4 verts/12 edges) + jtem Triangulator replication;
  scoped as a dedicated follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00

232 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Cross-validation potential of the Java `@Ignore`d tests
> **Purpose.** The upstream Java library (`de.varylab.discreteconformal`) has
> 22 test files with `@Ignore`d tests. This document classifies them by *why*
> they are ignored and by their *cross-validation value for the C++ port*, so
> that the highest-value golden oracles get ported first.
>
> **Created:** 2026-05-29 (external-reviewer pass). See also
> `doc/reviewer/java-port-audit.md` and PR #27 (`tests/java-golden-oracles`).
---
## 1 — Two root causes for `@Ignore`
| Cause | Count | Meaning for the C++ port |
|---|---|---|
| **`requires ARM64 PETSc native lib`** (class-level) | 15 files | **Not a logic problem.** Java solves via PETSc/TAO (native lib) which does not run on ARM64. The C++ port uses **Eigen** (no PETSc) and *can* run these scenarios — **iff** the feature is ported **and** the Java test carries a hard-coded expected value. |
| **Logic / known-issue** (method-level) | ~8 methods | Mostly mark **Java gaps** (no Hessian, layout unfinished) or **ARM64 FP flakiness**. Usually **not** reliable oracles. |
A critical distinction: PR #27 cross-validates **functional evaluations**
(energy/gradient — no solver, so no PETSc needed). The **full-solve** golden
values exist **only** as hard-coded vectors recorded from a historical x86
PETSc run — and those live exclusively in `HyperIdealConvergenceTest`.
---
## 2 — Already locked by PR #27 (do not duplicate)
`tests/java-golden-oracles` pins, bit-for-bit (1e-12), against compiled Java:
- `HyperIdealGoldenJava` — Clausen/Л/ImLi₂, ζ₁₃/₁₄/₁₅/ζ, both tetrahedron-volume formulas.
- `EuclideanGoldenJava` / `SphericalGoldenJava` — angle formulas, β relations, Л energy terms, **small full-mesh oracles** on a tetrahedron (gradient `Θ−Σα`, `ΔE = E(x)E(0)`).
- `SphericalGoldenJava.FullMeshEdgeDofGradient` — edge-DOF gradient.
- `PeriodMatrix.NormalizeModulus_GoldenJava` — τ-reduction fold convention.
These cover the **unit math cores** and **functional evaluation**. They do
**not** cover **solver/convergence** or **full uniformization**.
---
## 3 — Priority ranking for new cross-validation
### 🟢 HIGH — real golden oracle, feature already in C++
| Item | Java source | Oracle | Blocker / effort |
|---|---|---|---|
| **HyperIdeal Lawson convergence** | `HyperIdealConvergenceTest.testHyperIdealConvergence` | **hard-coded golden u\*** (perfectly symmetric — robust to DOF order) | needs a **low-level half-edge generator** (`make_lawson_square_tiled`); CGAL `add_face` cannot build it (multi-edges, see §5). Effort: medium (12 d). |
Golden solution (Lawson square-tiled, BLMVM, tol 1e-10), 22 DOFs:
```
vertices (×4, θ=2π) : 1.1462158341786262
edges (×12, θ=π/2) : 1.7627471737467797 / …7866 (symmetric pair)
edges (×6, θ=π aux): 2.633915794495759
```
Assertion strategy: because the values are symmetric per DOF-class, assert
*per class* (every vertex DOF ≈ 1.14621…, every π/2-edge ≈ 1.76274…, every
π-edge ≈ 2.63391…) to 1e-6 — **no DOF-order fidelity required**.
### 🟡 MEDIUM — golden/strong oracle, needs asset or near-term phase
| Item | Java source | Oracle | Blocker |
|---|---|---|---|
| **Genus-1 uniformization** | `UniformizerTest.testGenus1` (Wente, 1240 V) | angle-sum = 2π + vertex count (self-consistency) | needs `wente.obj` asset + a "load OBJ → uniformize" path; C++ Euclidean solver exists. |
| **HyperIdeal Lawson + branch points** | `…WithBranchPoints` | hard-coded golden u\* (near-symmetric — DOF order matters more) | same generator as HIGH + branch-point variant. |
| **HyperIdeal layout** | `HyperIdealLayoutTest` | layout positions | needs the generator + `layout.hpp` hyper-ideal path exercised. |
| **Euclidean big-model scale** | `EuclideanUnwrapperPetscTest.testStaticUnwrapBigModel` | mostly self-check | scale/robustness cross-check; low oracle strength. |
### 🔵 LATER — feature not yet in C++ (Phase 9d.2 / 10c / 13 / 11)
| Item | Java source | Maps to |
|---|---|---|
| Genus-2 uniformization | `UniformizerTest.testGenus2` (Lawson 2498) | Phase 10c / 13 |
| HyperIdeal hyperelliptic convergence | `…HyperEllipticCurveLawson` (has golden u\*) | Phase 13 |
| Hyperbolic disk uniformization | `HyperbolicDiskUniformizationTest` | Phase 10c (gated on holonomy bug) |
| Möbius centring (grad/Hessian/convergence golden) | `MobiusCenteringFunctionalTest` | Phase 9d.4 |
| Quasi-isothermic suite (SinCondition, SNES, Utility, Layout, ConformalStructure) | `…quasiisothermic.*` | Phase 10e |
| Schottky uniformisation | `SchottkyUtilityTest` | Phase 11a |
| Circle-domain (multiply-connected) | `CircleDomainUnwrapperTest` | Phase 11c |
| Electrostatic-sphere baseline | `ElectrostaticSphereFunctionalTest` | Phase 10c (optional) |
### ⚪ NON-ORACLE — do **not** port as cross-validation
| Item | Why it is not an oracle |
|---|---|
| `HyperIdealFunctionalTest.testHessian` (`@Ignore@Override`, empty) | Java has **no** HyperIdeal Hessian (`hasHessian()==false`). C++ *adds* it (block-FD, Phase 9b) → validate against C++ FD, not Java. Documents the C++ delta. |
| `ElectrostaticSphereFunctionalTest.testHessian` | same — Hessian not implemented in Java. |
| `HyperbolicLayoutTest.testDoLayout` | throws `"Not implemented correctly yet!"`**Java itself unfinished**; no reference to validate against. |
| `SurfaceCurveUtilityTest.testCreateSurfaceCurves` | known issue: non-deterministic edge count on ARM64 — **flaky**, not a stable oracle. |
| `HyperbolicCyclicConvergenceTest.testEuclideanConvergence` | known issue: ARM64 FP accumulation, angle sum outside 1e-8 — **flaky**. |
| `HyperIdealUtilityTest.testZeta13` | asserts ζ₁₃(0.1,0.1,0.1)=0.1, which looks **wrong**; the other volume/ζ tests already run and are ported. Verify the correct value before any use. |
| `HyperIdealPluginTest` | plugin/TAO-application wiring, not pure math. |
| `TwoHoleExample.testLetterB` | demo/example, no assertion of record. |
| `SphericalUnwrapperTest` PETSc variants | the **MTJ** variants (not ignored) already cover the same cases on `cathead`. |
---
## 3b — Effort-adjusted tiering (2026-05-29 inventory)
> A broader scan (not just `@Ignore`d tests) revealed that the §3 ranking was
> **effort-blind**: cheaper, equally-valuable oracles exist than the Lawson
> generator. Re-tiered by **value / cost**:
| Tier | Oracle | Mesh / asset | Solver | Golden | C++ status | Cost |
|---|---|---|---|---|---|---|
| **1** | `EuclideanCyclicConvergenceTest` | `cathead.obj` *(already in C++)* | MTJ BiCGstab (no PETSc) | `α_opp+α_opp = π0.1` @1e-12 (per-edge φ target) | `euclidean_functional` ✅, `phi_e` ✅, cathead ✅ | **near-zero** |
| **1** | `SphericalConvergenceTest` | octahedron | MTJ Newton (no PETSc) | self-consistency (const. curvature) | spherical ✅, `make_octahedron_face` ✅ | low |
| **2** | Wente genus-1 uniformization | `wente_torus02.obj` + `wente_uniformization.xml` | — (stored result) | exact `IsometryPSL2R` uniformizing-group generators | holonomy/`MobiusMap` ✅; **needs XML reader** | medium |
| ~~2~~**4** | `regular_uniformization.xml`, `LetterB01_canonical_group.xml` | (stored) | — | full `IsometryPSL2R` Fuchsian group + 12-edge `FundamentalPolygon` | **genus ≥ 2 hyperbolic** (not genus-1) → Phase 13 | future |
| **3** | HyperIdeal Lawson convergence (3 golden vectors) | combinatorial `createLawsonSquareTiled` | — (hard-coded u\*) | symmetric u\* | needs **low-level half-edge generator** (§5) | high |
| **4** | genus-2 (`genus2.xml`/`lawson2498.obj`), holomorphic forms (`HolomorphicEuclideanUniformization_*.xml`), Schottky (`genus2.xml`), hyperelliptic | assets present in Java | — | various | Phases 10a/10c/11/13 | future |
**Tier-2 status (2026-05-30): exhausted.** The only genus-1 case is Wente
(deferred to Phase 9f, quad/cyclic). `regular_uniformization.xml` and
`LetterB01_canonical_group.xml` are **genus ≥ 2 hyperbolic** uniformizations
(full PSL(2,) Fuchsian groups + a 12-edge fundamental polygon) → Phase 13, not
Tier 2.
**Tier-3 status: a dedicated mini-project (gated on a mesh generator).** The
Lawson golden vectors require `createLawsonSquareTiled`: a genus-2 surface with
**4 vertices / 12 edges → multi-edges** (≥2 edges per vertex pair). CGAL
`add_face` / polygon-soup / OFF are all vertex-pair-keyed and **cannot** build
it; it needs hand-wired **low-level Surface_mesh halfedge construction**
(`add_edge` + explicit `set_next`/`set_vertex`/`set_face`, then `is_valid`),
plus replicating the external jtem `Triangulator` diagonal choice. The golden
vector is perfectly symmetric (4×1.1462 / 12×1.7627 / 6×2.6339), so a
*symmetry-preserving* triangulation may reproduce the three values without an
exact Triangulator match — but that is unverified. Recommended as its own
focused PR (`make_lawson_square_tiled` + golden-vector oracle), not a quick add.
**Key correction:** the Lawson generator (originally flagged HIGH) is actually
**Tier 3** — higher effort than Tier 1/2. Cheapest first wins:
1. **Tier 1 — `EuclideanCyclicConvergenceTest` on cathead** (asset already
present; the C++ edge gradient `G_e = α_opp(f⁺)+α_opp(f⁻) φ_e` makes the
Java assertion `α_opp+α_opp = π0.1` exactly the converged `G_e = 0`
condition with `phi_e = π0.1`). Fails if the solver ignores a non-default
`φ`, so it is a genuine check, not a tautology.
2. **Tier 1 — `SphericalConvergenceTest`** on the octahedron.
3. **Tier 2 — Wente genus-1 uniformization** (needs a small `UniformizationData`
XML reader; strongest deterministic pipeline oracle that maps to landed C++).
4. **Tier 3 — Lawson generator** (only after Tiers 12).
### Build-verification finding (2026-05-29) → resolved (2026-05-30)
Attempting the Tier-1 `EuclideanCyclicConvergenceTest` port **build-verified** a
blocker first: `newton_euclidean``euclidean_hessian` threw *"edge DOFs are
not supported"*. The cyclic functional needs **vertex + edge** DOFs (the
*gradient* supported them; the *analytic cotangent Hessian* did not). That is
why PR #27 cross-validated only the cyclic *evaluation*, never a solve.
**Resolved (2026-05-30):** implemented a **block-FD edge-DOF Euclidean Hessian**
(`euclidean_hessian_block_fd` / `_sym` in `euclidean_hessian.hpp`, mirroring
`hyper_ideal_hessian_block_fd`); `newton_euclidean` now routes cyclic layouts
(edge DOFs present) through it, vertex-only layouts still use the analytic
cotangent Laplacian.
**Landed (`test_euclidean_functional.cpp`, all GREEN, 243/243 cgal tests pass):**
-`CyclicCircularEdge_PhiEntersGradient_CatHead` — solver-free check that the
circular-edge φ enters the gradient exactly (`ΔG_e = Δφ_e` @1e-12).
-`CyclicCircularEdge_CatHead_JavaXVal` — **the full Java convergence
oracle**: prescribe φ = π0.1 on one interior ("circular") edge of cathead,
solve the cyclic Newton, assert the realised `α_opp+α_opp = π0.1` @1e-9.
-`CyclicHessian_BlockFD_MatchesGradientFD_Tetrahedron` — the block-FD edge-DOF
Hessian matches the column-wise gradient FD on the full cyclic layout.
> DOF note: only the **single** circular edge gets an edge DOF (as in Java's
> one `circularHoleEdge`). Giving *every* edge a DOF makes λ_e redundant with
> u_i+u_j (a V-dim null space) and stalls Newton.
Spherical convergence (Tier-1 #2) was found **already covered** by
`test_newton_solver` (`Spherical_ConvergesFromPerturbation` et al.), and
`make_octahedron_face()` is a single face, not a closed octahedron — so it adds
little.
### Tier-2 (Wente) finding (2026-05-30) — needs a quad/cyclic pipeline
`wente_torus02.obj` is a **quad mesh** (1240 quads, genus 1), and the Java
`wente_uniformization.xml` golden (uniformizing group → τ = (√2+i√6)/(2√2) =
½ + i·√3/2, the hexagonal torus) comes from Java's **cyclic (quad) net**
uniformization. The C++ period-matrix pipeline (`run_torus_pipeline`) is
**triangle-based**, so a faithful bit-vs-Java comparison would require triangulating
(which changes the discrete conformal structure → no exact match) or a
**quad/cyclic period-matrix pipeline** — that belongs to **Phase 9f** (general
polygon meshes), not the triangle path. → Tier 2 deferred to Phase 9f; the
hexagonal golden τ is recorded here for when that lands.
### Done instead (2026-05-30): full analytic edge-DOF Hessian
With Tier-2 gated on a quad pipeline, the higher-value clean win was upgrading
the cyclic Hessian from block-FD to **fully analytic** (closed-form
`∂α_i/∂s_i = _i²/4A`, `∂α_i/∂s_j = ½cot α_i _j²/4A`), satisfying the
`novelty-statement.md §3.2` "analytic Hessians, not finite difference" claim for
the Euclidean path. Verified against block-FD and gradient-FD.
### Other generators in the Java tree
`HyperellipticCurveGenerator` (→ Phase 13), `SchottkyGenerator` (→ Phase 11a),
`FunctionalTest.createOctahedron/createTetrahedron` (trivial — C++ has
`make_octahedron_face` / `make_tetrahedron`).
---
## 4 — Recommended order of work
1. **Port `make_lawson_square_tiled()`** (low-level half-edge; see §5) →
unblocks the single HIGH oracle and the MED branch-point variant in one go.
2. Add `HyperIdealLawsonGoldenJava` test using the **per-class symmetric**
assertion above (robust, no DOF-order matching).
3. Add `wente.obj` asset → genus-1 uniformization self-consistency (MED).
4. Defer LATER items to their phases; revisit golden vectors then
(branch-point and hyperelliptic golden u\* are already recorded in the
Java tests and can be reused verbatim once the generator exists).
---
## 5 — Why the Lawson mesh needs a low-level generator
`HyperIdealGenerator.createLawsonSquareTiledBase()` builds a **genus-2**
surface with **4 vertices and 12 edges** (24 half-edges), then triangulates
6 quad faces (adding 6 diagonal "aux" edges, θ=π; the 12 originals get θ=π/2).
With only 4 vertices and 12 edges, **most vertex pairs carry more than one
edge** (multi-edges). CGAL `Surface_mesh::add_face` and polygon-soup builders
key edges by their endpoint vertex pair and therefore **cannot represent
multi-edges** — they would either fail or glue the surface into the wrong
topology. Java sidesteps this with explicit half-edge IDs and
`linkOppositeEdge` / `linkNextEdge`.
The C++ port must replicate this with the **low-level half-edge API**
(`add_vertex`, `add_edge`, and explicit `set_next` / `set_target` /
`set_face` connectivity), mirroring the exact opposite/next links from
`createLawsonSquareTiledBase()` (edges 023). The symmetric golden vector
then makes the resulting test robust even though CGAL's DOF ordering differs
from Java's.