Files
ConformalLabpp/doc/reviewer/java-ignore-crossvalidation.md
Tarik Moussa ea5f01d73d feat(euclidean): block-FD edge-DOF Hessian → cyclic Newton + Java convergence oracle
Implements the edge-DOF (cyclic) Euclidean Hessian, unblocking the full cyclic
Newton solve, and enables the Java EuclideanCyclicConvergenceTest cross-validation.

- euclidean_hessian.hpp: `euclidean_hessian_block_fd` / `_sym` — per-face 6×6
  block FD over (u1,u2,u3,λ12,λ23,λ31), mirroring hyper_ideal_hessian_block_fd.
  Per-face outputs carry the gradient signs (−α vertex, +α_opp edge), so the
  result equals ∂G/∂x by construction (locality lemma). Analytic vertex-only
  cotangent Hessian unchanged (still used for vertex-only layouts).
- newton_solver.hpp: newton_euclidean routes cyclic layouts (edge DOFs present)
  through the block-FD Hessian; vertex-only path unchanged.
- tests:
  * CyclicCircularEdge_CatHead_JavaXVal (now GREEN) — prescribe φ=π−0.1 on one
    interior edge, solve, assert realised α_opp+α_opp = π−0.1 @1e-9.
  * CyclicCircularEdge_PhiEntersGradient_CatHead — solver-free φ-wiring check.
  * CyclicHessian_BlockFD_MatchesGradientFD_Tetrahedron — Hessian correctness.

243/243 cgal tests pass; vertex-only Euclidean Newton unaffected.

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

197 lines
12 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** | `regular_uniformization.xml` | (stored) | — | uniformization data | needs XML reader | medium |
| **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 |
**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. → next genuinely-new target: **Tier 2 (Wente uniformization XML)**. A
full *analytic* edge-DOF Hessian (vs the current block-FD) remains a future
optimisation.
### 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.