From 2325328f776585bf6cd71985c468a556c983ed14 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Sun, 31 May 2026 00:39:35 +0200 Subject: [PATCH] =?UTF-8?q?test:=20add=20end-to-end=20skewed-torus=20and?= =?UTF-8?q?=20synthetic=20holonomy=20Re(=CF=84)<0=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finding-H from doc/reviewer/external-audit-2026-05-30.md (java-port-audit missing-test item 7). Guards against a regression where compute_period_matrix reverts to reduce_to_fundamental_domain (no mirror fold) instead of normalizeModulus (Finding 6 fix, Java-faithful): such a revert would silently produce Re(τ) < 0 for lattices where the natural generators give a negative real part. Two new tests in test_phase7.cpp: 1. SkewedTorus_ReTauNegativeBeforeNorm_FoldedToPositive - New mesh: code/data/off/torus_skewed_4x4.off Flat 4×4 torus on parallelogram lattice ω₁=(4,0) ω₂=(-1,4); 16 vertices, 32 triangles, χ=0 (genus 1). - Full pipeline: newton_euclidean → cut_graph → euclidean_layout → compute_period_matrix(reduce=false) + compute_period_matrix(reduce=true) - Asserts: raw Re(τ) < 0, normalized Re(τ) ∈ [0,½], Im(τ) > 0, |τ| ≥ 1 2. SyntheticHolonomy_NegativeReTau_NormalizedToPositive - Bypasses mesh; supplies explicit ω₁=(4,0) ω₂=(-1,4) directly - Asserts raw τ = -0.25+i (to 1e-10), normalized τ = 0.25+i (to 1e-9) - Pin-points the mirror fold: Re(-0.25) → Re(+0.25) 277/277 CGAL tests pass, 0 failed. Co-Authored-By: Claude Sonnet 4.6 --- code/data/off/torus_skewed_4x4.off | 50 +++++++++++ code/tests/cgal/test_phase7.cpp | 103 ++++++++++++++++++++++ doc/reviewer/external-audit-2026-05-30.md | 2 +- 3 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 code/data/off/torus_skewed_4x4.off diff --git a/code/data/off/torus_skewed_4x4.off b/code/data/off/torus_skewed_4x4.off new file mode 100644 index 0000000..b987cd2 --- /dev/null +++ b/code/data/off/torus_skewed_4x4.off @@ -0,0 +1,50 @@ +OFF +16 32 0 +0.0 0.0 0.0 +1.0 0.0 0.0 +2.0 0.0 0.0 +3.0 0.0 0.0 +-0.25 1.0 0.0 +0.75 1.0 0.0 +1.75 1.0 0.0 +2.75 1.0 0.0 +-0.5 2.0 0.0 +0.5 2.0 0.0 +1.5 2.0 0.0 +2.5 2.0 0.0 +-0.75 3.0 0.0 +0.25 3.0 0.0 +1.25 3.0 0.0 +2.25 3.0 0.0 +3 0 1 5 +3 0 5 4 +3 1 2 6 +3 1 6 5 +3 2 3 7 +3 2 7 6 +3 3 0 4 +3 3 4 7 +3 4 5 9 +3 4 9 8 +3 5 6 10 +3 5 10 9 +3 6 7 11 +3 6 11 10 +3 7 4 8 +3 7 8 11 +3 8 9 13 +3 8 13 12 +3 9 10 14 +3 9 14 13 +3 10 11 15 +3 10 15 14 +3 11 8 12 +3 11 12 15 +3 12 13 1 +3 12 1 0 +3 13 14 2 +3 13 2 1 +3 14 15 3 +3 14 3 2 +3 15 12 0 +3 15 0 3 diff --git a/code/tests/cgal/test_phase7.cpp b/code/tests/cgal/test_phase7.cpp index 06c9647..79d45a3 100644 --- a/code/tests/cgal/test_phase7.cpp +++ b/code/tests/cgal/test_phase7.cpp @@ -502,6 +502,109 @@ TEST(HolonomyEndToEnd, Torus8x8_TauMatchesRevolutionModulus) check_torus("torus_8x8.off", /*R=*/3.0, /*r=*/1.0, /*rel_tol=*/0.05); } +// ════════════════════════════════════════════════════════════════════════════ +// Finding-H (java-port-audit item 7, external-audit-2026-05-30): +// End-to-end torus with Re(τ) < 0 before normalizeModulus +// +// torus_skewed_4x4.off is a flat torus on a parallelogram lattice +// ω₁ = (4, 0) ω₂ = (−1, 4) +// The raw τ = ω₂/ω₁ = (−0.25 + i), Re < 0. +// After normalizeModulus the mirror fold gives τ = (0.25 + i), Re ≥ 0. +// +// This guards against a regression where compute_period_matrix uses +// reduce_to_fundamental_domain (old code, no mirror fold) instead of +// normalizeModulus (Java-faithful, finding 6 fix) — in that case the +// pipeline would silently report τ with Re < 0 instead of Re ≥ 0. +// ════════════════════════════════════════════════════════════════════════════ + +TEST(HolonomyEndToEnd, SkewedTorus_ReTauNegativeBeforeNorm_FoldedToPositive) +{ + // ── Load the skewed flat torus ──────────────────────────────────────── + const std::string path = + std::string(CONFORMALLAB_DATA_DIR) + "/off/torus_skewed_4x4.off"; + ConformalMesh mesh = load_mesh(path); + ASSERT_GT(mesh.number_of_vertices(), 0u) << "Failed to load torus_skewed_4x4.off"; + ASSERT_EQ(conformallab::euler_characteristic(mesh), 0) + << "Mesh must be a torus (χ=0)"; + + // ── Run the full pipeline ───────────────────────────────────────────── + EuclideanMaps maps = setup_euclidean_maps(mesh); + compute_euclidean_lambda0_from_mesh(mesh, maps); + + int idx = 0; + bool pinned = false; + for (auto v : mesh.vertices()) { + if (!pinned) { maps.v_idx[v] = -1; pinned = true; } + else maps.v_idx[v] = idx++; + } + enforce_gauss_bonnet(mesh, maps); + + std::vector x0(static_cast(idx), 0.0); + auto res = newton_euclidean(mesh, x0, maps); + ASSERT_TRUE(res.converged) << "Newton did not converge on skewed flat torus"; + + CutGraph cg = compute_cut_graph(mesh); + HolonomyData hol; + euclidean_layout(mesh, res.x, maps, &cg, &hol, /*normalise=*/false); + + ASSERT_EQ(hol.translations.size(), 2u) << "Expected exactly 2 holonomy generators"; + + // ── Raw τ (no normalization) must have Re < 0 ───────────────────────── + // This confirms the mesh geometry does produce a τ with negative real + // part, making the normalizeModulus step non-trivial. + PeriodData pd_raw = compute_period_matrix(hol, /*reduce=*/false); + EXPECT_LT(pd_raw.tau.real(), 0.0) + << "Raw τ must have Re < 0 for this skewed lattice" + << " (got Re = " << pd_raw.tau.real() << ")"; + + // ── Normalized τ must have Re ≥ 0 (normalizeModulus was applied) ───── + PeriodData pd = compute_period_matrix(hol, /*reduce=*/true); + EXPECT_GE(pd.tau.real(), -1e-10) + << "Normalized τ must have Re ≥ 0 (normalizeModulus mirror fold)" + << " (got Re = " << pd.tau.real() << ")"; + EXPECT_GT(pd.tau.imag(), 0.0) + << "τ must lie in the upper half-plane"; + EXPECT_GE(std::abs(pd.tau), 1.0 - 1e-9) + << "|τ| ≥ 1 (fundamental domain condition)"; + + // ── Additional fundamental-domain conditions ─────────────────────────── + // These are the normalizeModulus guarantees (Finding 6 / java-port-audit). + EXPECT_LE(pd.tau.real(), 0.5 + 1e-9) + << "normalizeModulus must produce Re(τ) ≤ ½"; + // The exact value depends on which generators tree-cotree finds; + // we do NOT assert a specific numeric value here (generator choice is + // an implementation detail of the tree-cotree algorithm, not of + // normalizeModulus). The assertions above are sufficient to confirm + // that the mirror fold was applied. +} + +// ════════════════════════════════════════════════════════════════════════════ +// Finding-H synthetic sanity: compute_period_matrix with explicit Re(τ)<0 +// holonomy verifies the mirror fold numerically (no mesh, no tree-cotree). +// ════════════════════════════════════════════════════════════════════════════ + +TEST(HolonomyEndToEnd, SyntheticHolonomy_NegativeReTau_NormalizedToPositive) +{ + // Lattice: ω₁=(4,0), ω₂=(-1,4) → τ_raw = (-1+4i)/4 = -0.25+i + // normalizeModulus: Re=-0.25 < 0 → mirror: τ = -conj(τ) = +0.25+i + HolonomyData hol; + hol.translations = { + Eigen::Vector2d(4.0, 0.0), + Eigen::Vector2d(-1.0, 4.0) + }; + + PeriodData pd_raw = compute_period_matrix(hol, /*reduce=*/false); + EXPECT_NEAR(pd_raw.tau.real(), -0.25, 1e-10) << "Raw Re(τ) must be -0.25"; + EXPECT_NEAR(pd_raw.tau.imag(), 1.0, 1e-10) << "Raw Im(τ) must be 1.0"; + + PeriodData pd = compute_period_matrix(hol, /*reduce=*/true); + EXPECT_GE(pd.tau.real(), 0.0 - 1e-9) << "Normalized Re(τ) ≥ 0"; + EXPECT_LE(pd.tau.real(), 0.5 + 1e-9) << "Normalized Re(τ) ≤ ½"; + EXPECT_NEAR(pd.tau.real(), 0.25, 1e-9) << "Mirror fold: Re = -0.25 → +0.25"; + EXPECT_NEAR(pd.tau.imag(), 1.0, 1e-9) << "Im(τ) preserved by mirror fold"; + EXPECT_GE(std::abs(pd.tau), 1.0 - 1e-9) << "|τ| ≥ 1"; +} + // ════════════════════════════════════════════════════════════════════════════ // FundamentalDomain — genus-1 parallelogram // ════════════════════════════════════════════════════════════════════════════ diff --git a/doc/reviewer/external-audit-2026-05-30.md b/doc/reviewer/external-audit-2026-05-30.md index ba865c0..bc867bc 100644 --- a/doc/reviewer/external-audit-2026-05-30.md +++ b/doc/reviewer/external-audit-2026-05-30.md @@ -706,7 +706,7 @@ index. Add a comment: | E | `cp_euclidean_functional.hpp` | 338–349, 373–387 | Inconsistency | Medium | ✅ Fixed 2026-05-31 | | F | test files | — | Test gap | Medium | ✅ Fixed 2026-05-31 | | G | test files | — | Test gap | Medium | ✅ Fixed 2026-05-31 | -| H | test files | — | Test gap | Medium | 🟠 Open | +| H | test files | — | Test gap | Medium | ✅ Fixed 2026-05-31 | | I | CI workflow | — | Arch risk | High | 🔵 Open | | MINOR-1 | `spherical_functional.hpp` | 404 | Doc error | Minor | 🟡 Open | | MINOR-2 | `spherical_functional.hpp` | 470–471 | Accuracy | Minor | 🟡 Open |