Files
ConformalLabpp/doc/reviewer/java-ignore-crossvalidation.md
Tarik Moussa c472748e46
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m1s
API Docs / doc-build (pull_request) Successful in 53s
Markdown link check / check (pull_request) Successful in 58s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Failing after 2m14s
docs(reviewer): refresh §4 to mark Tier-1/3 done (stale TODO removed)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00

16 KiB
Raw Blame History

Cross-validation potential of the Java @Ignored tests

Purpose. The upstream Java library (de.varylab.discreteconformal) has 22 test files with @Ignored 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) DONE — PR #30 via low-level half-edge make_lawson_square_tiled (CGAL add_face can't: multi-edges, §5).

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* DONE — PR #30 (stellar subdivision + ideal centres; per-class symmetric @1e-4).
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 @Ignored 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
24 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 — plain + branch-points low-level half-edge make_lawson_square_tiled newton_hyper_ideal hard-coded golden u* DONE — PR #30 (test_lawson_hyperideal.cpp) done
3 ⏸️ HyperIdeal Lawson hyperelliptic lawson_curve_source.xml + HyperIdealHyperellipticUtility non-symmetric golden u* deferred — needs XML-format reader + jReality-geometry θ port future
4 genus-2 (genus2.xml/lawson2498.obj), holomorphic forms (HolomorphicEuclideanUniformization_*.xml), Schottky (genus2.xml) 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 (2026-05-30): DONE for plain + branch-points (PR #30). The Lawson base is a genus-2 surface with 4 vertices / 12 edges → multi-edges, so CGAL add_face/OFF/polygon-soup cannot build it; make_lawson_square_tiled (test_lawson_hyperideal.cpp) uses the low-level Surface_mesh half-edge API (add_edge + set_target/set_next/set_face/set_halfedge), then triangulate_faces (plain) or Euler::add_center_vertex (branch-points, stellar). Two key findings made this clean:

  1. The golden vectors are symmetric per geometric class, so the external jtem Triangulator/StellarLinear orderings need not be replicated — any consistent triangulation/stellar reproduces the values.
  2. Java's index-based θ split is actually geometric (original vs diagonal; base vs spoke); branch-point centres are ideal vertices (b = 0).

newton_hyper_ideal converges (from x0 = 1.0, unconstrained — Java needed bounded BLMVM) to both golden vectors:

  • plain: vertices 1.1462158341786262 / original 1.7627471737467797 / aux 2.633915794495759
  • branch-points: vertices 1.3169579 / base 2.2924317 / spokes 0

Hyperelliptic (the 3rd Lawson variant) is deferred (option c). It needs a reader for lawson_curve_source.xml (Java conformal-data HalfedgeEmbedding, 26 vtx / 144 half-edges, a cut surface) and a port of HyperIdealHyperellipticUtility.calculateCircleIntersections, which derives θ via jReality Pn (elliptic/hyperbolic), MatrixBuilder (rotate / hyperbolic translate) and stereographic projection. Its golden vector is not class-symmetric (mixed ±values), so no symmetry shortcut — mesh and θ must match exactly. Viable approaches: (A) port the jReality geometry, or (B) run a Java dumper for θ + connectivity (no PETSc needed) and hard-code them. Both are multi-step with numerical-replication risk → its own future task.

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 — deferred to Phase 9f (quad/cyclic pipeline; wente_torus02.obj is a quad mesh, not triangle).
  4. Tier 3 — Lawson generator DONE (PR #30): plain + branch-points golden oracles GREEN; hyperelliptic deferred (option c).

Status summary (2026-05-30)

  • Tier 1 done (PR #29): cyclic φ oracle + full analytic edge-DOF Hessian.
  • Tier 2 — exhausted; Wente → Phase 9f, the rest → Phase 13.
  • Tier 3 done (PR #30): plain + branch-points Lawson golden oracles; hyperelliptic deferred.

Build-verification finding (2026-05-29) → resolved (2026-05-30)

Attempting the Tier-1 EuclideanCyclicConvergenceTest port build-verified a blocker first: newton_euclideaneuclidean_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_JavaXValthe 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).


  1. DONE (PR #29) — Tier 1: cyclic φ oracle + full analytic edge-DOF Hessian.
  2. DONE (PR #30) — Tier 3: make_lawson_square_tiled() (low-level half-edge; §5) + plain & branch-points golden oracles (per-class symmetric, no DOF-order matching needed).
  3. ⏸️ Deferred — Lawson hyperelliptic variant (XML-format reader + HyperIdealHyperellipticUtility / jReality θ; non-symmetric golden).
  4. ⏸️ Phase 9f — Wente genus-1 uniformization (quad/cyclic pipeline).
  5. Phase 10a/10c/11/13 — LATER items (genus-2, holomorphic forms, Schottky); golden u* / data recorded in the Java tests for reuse then.

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.