test: add end-to-end skewed-torus and synthetic holonomy Re(τ)<0 tests
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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<double> x0(static_cast<std::size_t>(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
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user