Implement Phase-Session P1 quick wins (4 independent additions):
9h.1: Add --tol and --max-iter CLI options to conformallab_core
- Newton solver tolerance [default 1e-8]
- Newton iteration limit [default 200]
- Thread both through run_euclidean / run_spherical / run_hyper_ideal
- Update CLI parameter table in documentation
9h.2: Add -g cp_euclidean and -g inversive_distance geometry routes
- run_cp_euclidean() & run_inversive_distance() pipelines (~60 lines each)
- Face-based DOF assignment for CP-Euclidean
- Vertex-based DOF assignment for Inversive-Distance
- Both integrated into CLI geometry validator (IsMember)
9g.1: Create conformal_quality.hpp with validation measures
- IsothermicityMeasure: metric anisotropy (conformality deviation)
- DiscreteConformalEquivalenceMeasure: length-cross-ratio residuals
- FlippedTriangles: detects inverted/degenerate triangles
- LengthCrossRatio: discrete conformal invariant computation
- ConvergenceUtility: aggregated convergence statistics (max/mean/sum)
- Ported from Java: plugin/visualizer + convergence utilities
- Includes sanity tests validating finite outputs on valid layouts
9d.3: Create stereographic_layout.hpp for S² → ℂ projection
- Stereographic projection from north pole: S² → ℂ ∪ {∞}
- Inverse projection: ℂ → S² for round-trip validation
- Möbius centring: centres the 2-D point cloud at origin
- stereographic_layout(Layout3D) -> Layout2D conversion
- Round-trip tests: south pole, equator, random sphere points
- Tests: projection/inverse consistency, north pole handling
Test results: 336/336 CGAL tests pass (272 pre-existing + 64 new from all phases)
- conformal_quality.cpp: 13 new tests (measures, isothermic, dce, convergence)
- stereographic_layout.cpp: 10 new tests (projection, inverse, round-trip, layout)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
273 lines
12 KiB
CMake
273 lines
12 KiB
CMake
# tests/cgal/CMakeLists.txt
|
||
#
|
||
# CGAL-dependent test target. Only built when -DWITH_CGAL=ON.
|
||
# Requires Boost (find_package(Boost REQUIRED) is called in the root CMakeLists).
|
||
#
|
||
# Run with:
|
||
# cmake -S code -B build -DWITH_CGAL=ON
|
||
# cmake --build build --target conformallab_cgal_tests
|
||
# ctest --test-dir build -R cgal
|
||
|
||
add_executable(conformallab_cgal_tests
|
||
# ── Phase 3a: mesh infrastructure ──────────────────────────────────────
|
||
test_conformal_mesh.cpp
|
||
|
||
# ── Phase 3b: HyperIdealFunctional ─────────────────────────────────────
|
||
test_hyper_ideal_functional.cpp
|
||
|
||
# ── Phase 3c + 3e: SphericalFunctional + gauge-fix ────────────────────
|
||
test_spherical_functional.cpp
|
||
|
||
# ── Phase 3d: EuclideanCyclicFunctional ───────────────────────────────
|
||
test_euclidean_functional.cpp
|
||
|
||
# ── Phase 3f: Hessians (cotangent Laplacian, spherical + Euclidean) ───
|
||
test_euclidean_hessian.cpp
|
||
test_spherical_hessian.cpp
|
||
|
||
# ── Phase 9b: Hyper-ideal Hessian — block-FD vs full-FD validation ───
|
||
# Verifies the O(F·36) block-local Hessian agrees with the
|
||
# O(F·n) full-FD baseline. Java upstream has no Hessian at all
|
||
# (HyperIdealFunctional.hasHessian() returns false) — both
|
||
# variants are conformallab++ extensions beyond the port.
|
||
test_hyper_ideal_hessian.cpp
|
||
|
||
# ── Phase 4a: Newton solver ────────────────────────────────────────────
|
||
test_newton_solver.cpp
|
||
|
||
# ── Phase 4b: Mesh I/O (CGAL::IO) ─────────────────────────────────────
|
||
test_mesh_io.cpp
|
||
|
||
# ── Phase 4c: End-to-end pipeline + user examples ─────────────────────
|
||
test_pipeline.cpp
|
||
|
||
# ── Phase 5: Layout / embedding + serialization ────────────────────────
|
||
test_layout.cpp
|
||
|
||
# ── Phase 6: Gauss–Bonnet, cut graph, exact trilateration, normalisation
|
||
test_phase6.cpp
|
||
|
||
# ── Phase 7: Java-parity layout — MobiusMap, priority BFS, halfedge_uv,
|
||
# period matrix, fundamental domain, tiling
|
||
test_phase7.cpp
|
||
|
||
# ── Java parity: geometry utility tests ──────────────────────────────────
|
||
# Ported from CuttinUtilityTest, UnwrapUtilityTest,
|
||
# ConvergenceUtilityTests, HomologyTest. All tests active —
|
||
# the v0.7.0 genus-2 homology stub was implemented in Phase 7
|
||
# (HomologyGenerators.Genus2_FourCutEdges, brezel2.obj).
|
||
test_geometry_utils.cpp
|
||
|
||
# ── Scalability smoke tests ────────────────────────────────────────────────
|
||
# Newton convergence on large real-world meshes (cathead, brezel, brezel2).
|
||
# Assert correctness only (< 30 iterations, ||G|| < 1e-8).
|
||
# Wall-clock time is printed for documentation but NOT asserted,
|
||
# so the tests remain stable on slow CI hardware (Raspberry Pi ARM64).
|
||
test_scalability_smoke.cpp
|
||
|
||
# ── Phase 8 MVP: new CGAL-style public API ────────────────────────────────
|
||
# First client of Conformal_map_traits.h + Discrete_conformal_map.h.
|
||
# Acceptance probe before Phase 9a (Inversive-Distance) lands.
|
||
test_cgal_traits_mvp.cpp
|
||
|
||
# ── Phase 9a.1: CPEuclideanFunctional (BPS 2010 circle packing) ──────────
|
||
# Face-based circle-packing functional ported from
|
||
# CPEuclideanFunctional.java. Reference: Bobenko-Pinkall-Springborn 2010.
|
||
test_cp_euclidean_functional.cpp
|
||
|
||
# ── Phase 9a.2: InversiveDistance (Luo 2004 + Glickenstein 2011) ─────────
|
||
# Vertex-based inversive-distance circle-packing functional. No Java
|
||
# reference; implemented from the literature. Cross-validated against
|
||
# EuclideanCyclicFunctional at the natural initial geometry (u = 0).
|
||
test_inversive_distance_functional.cpp
|
||
|
||
# ── Phase 9a: Newton solvers for the two new circle-packing functionals ──
|
||
# Convergence tests for newton_cp_euclidean (analytic Hessian) and
|
||
# newton_inversive_distance (FD Hessian).
|
||
test_newton_phase9a.cpp
|
||
|
||
# ── Tier-3 Java cross-validation: Lawson square-tiled HyperIdeal ─────────
|
||
# Low-level half-edge genus-2 generator + golden-vector convergence.
|
||
test_lawson_hyperideal.cpp
|
||
|
||
# ── Pn projective-metric substrate (de.jreality.math.Pn port) ───────────
|
||
# Inner product / norm / distance / geodesic interpolation in
|
||
# Euclidean, Elliptic, Hyperbolic signatures.
|
||
test_pn_geometry.cpp
|
||
|
||
# ── Phase 8b-Lite: CGAL entry wrappers for the 4 non-Euclidean modes ─────
|
||
# Spherical, HyperIdeal, CircleP-Euclidean, Inversive-Distance via
|
||
# <CGAL/Discrete_*.h> public API + Conformal_layout.h wrapper.
|
||
test_cgal_phase8b_lite.cpp
|
||
|
||
# ── Phase 9g.1: Conformal quality measures ─────────────────────────────────
|
||
# IsothermicityMeasure, DiscreteConformalEquivalenceMeasure, FlippedTriangles,
|
||
# LengthCrossRatio, ConvergenceUtility. Validates layout correctness and
|
||
# convergence metrics (ported from Java visualizer + convergence utilities).
|
||
test_conformal_quality.cpp
|
||
|
||
# ── Phase 9d.3: Stereographic projection for spherical layouts ──────────────
|
||
# Converts spherical layout (S²) to 2-D conformal map via stereographic
|
||
# projection + Möbius centring. Tests round-trip consistency.
|
||
test_stereographic_layout.cpp
|
||
)
|
||
|
||
target_include_directories(conformallab_cgal_tests SYSTEM PRIVATE
|
||
${CMAKE_SOURCE_DIR}/deps/eigen-3.4.0
|
||
${CMAKE_SOURCE_DIR}/deps/CGAL-6.1.1/include
|
||
${CMAKE_SOURCE_DIR}/deps/single_includes
|
||
${Boost_INCLUDE_DIRS}
|
||
)
|
||
|
||
target_include_directories(conformallab_cgal_tests PRIVATE
|
||
${CMAKE_SOURCE_DIR}/include
|
||
)
|
||
|
||
target_compile_definitions(conformallab_cgal_tests PRIVATE
|
||
CGAL_DISABLE_GMP
|
||
CGAL_DISABLE_MPFR
|
||
# Data directory — absolute path to code/data/ at build time.
|
||
# Used by tests that load real mesh files (cathead.obj, brezel2.obj, …).
|
||
CONFORMALLAB_DATA_DIR="${CMAKE_SOURCE_DIR}/data"
|
||
)
|
||
|
||
# Suppress warnings from CGAL/Boost headers
|
||
target_compile_options(conformallab_cgal_tests PRIVATE
|
||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-unused-parameter>
|
||
)
|
||
|
||
# Fast test-build mode (lever #10): -O0 -g overrides the inherited
|
||
# Release-mode -O3 + -DNDEBUG. Applies only to this test target.
|
||
if(CONFORMALLAB_FAST_TEST_BUILD)
|
||
target_compile_options(conformallab_cgal_tests PRIVATE
|
||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O0 -g -UNDEBUG>
|
||
)
|
||
endif()
|
||
|
||
# ── Low-memory build mode (for RAM-constrained CI runners, e.g. Raspberry Pi) ──
|
||
#
|
||
# Problem: CGAL + Eigen at -O3 drives cc1plus peak RAM to ~600-800 MB per
|
||
# Unity compilation unit on ARM64 Linux. A 1600 MB container limit with a
|
||
# batch of 4 files per unit causes OOM-kill during the build.
|
||
#
|
||
# This flag enables three orthogonal memory-saving measures:
|
||
#
|
||
# 1. -O0 (no debug info): drops cc1plus backend RAM by ~60-70 %.
|
||
# Optimizer passes (inlining, register allocation, constant propagation)
|
||
# dominate the backend. At -O0 they are entirely skipped → peak per
|
||
# TU falls from ~700 MB to ~150-200 MB on ARM64.
|
||
# We omit -g deliberately: debug info adds ~30-40 % object-file size
|
||
# and increases linker RSS. CI needs "does it compile + do tests pass",
|
||
# not debuggability.
|
||
#
|
||
# 2. PCH OFF: the precompiled header itself consumes ~200 MB to compile
|
||
# and is re-read by every TU. Disabling it saves the one-time PCH
|
||
# compilation cost; each TU re-parses CGAL headers, but at -O0 this
|
||
# is fast.
|
||
#
|
||
# 3. UNITY_BUILD_BATCH_SIZE=1: one source file per unity unit. Removes
|
||
# the "4 files × CGAL parse cost" multiplier; each cc1plus process
|
||
# only sees one file worth of templates.
|
||
#
|
||
# 4. Linker memory flag (GCC/Clang only): --no-keep-memory tells GNU ld
|
||
# to release symbol table memory after each input file instead of
|
||
# keeping it for cross-reference. Reduces linker RSS by 15-25 % at
|
||
# the cost of slightly longer link time.
|
||
#
|
||
# Activate with:
|
||
# cmake -S code -B build -DWITH_CGAL_TESTS=ON \
|
||
# -DCONFORMALLAB_LOW_MEMORY_BUILD=ON
|
||
# Expected peak per cc1plus: ~150-200 MB → fits in 1800-2000 MB container.
|
||
# Test runtime is 2-4× slower than Release (CGAL traversals unoptimized),
|
||
# but correctness is unaffected.
|
||
option(CONFORMALLAB_LOW_MEMORY_BUILD
|
||
"Build CGAL tests with -O0, no PCH, UNITY_BATCH_SIZE=1 for RAM-constrained CI." OFF)
|
||
|
||
if(CONFORMALLAB_LOW_MEMORY_BUILD)
|
||
message(STATUS "CONFORMALLAB_LOW_MEMORY_BUILD active: -O0, no PCH, unity batch 1.")
|
||
|
||
# 1. -O0, no debug info
|
||
target_compile_options(conformallab_cgal_tests PRIVATE
|
||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O0 -UNDEBUG>
|
||
)
|
||
|
||
# 2. PCH off — force-override the option so the block below is skipped
|
||
set(CONFORMALLAB_USE_PCH OFF CACHE BOOL "" FORCE)
|
||
|
||
# 3. Unity batch size = 1 (one source file per compilation unit)
|
||
set_target_properties(conformallab_cgal_tests PROPERTIES
|
||
UNITY_BUILD ON
|
||
UNITY_BUILD_MODE BATCH
|
||
UNITY_BUILD_BATCH_SIZE 1)
|
||
|
||
# 4. Linker memory hint (GNU ld / lld)
|
||
target_link_options(conformallab_cgal_tests PRIVATE
|
||
$<$<CXX_COMPILER_ID:GNU>:-Wl,--no-keep-memory>)
|
||
endif()
|
||
|
||
target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main)
|
||
|
||
# ── Compile-time speed-up: precompiled headers ───────────────────────────────
|
||
#
|
||
# The CGAL+Eigen template soup dominates every TU in this target:
|
||
# measured at 5.9 s per minimal "include <CGAL/Discrete_conformal_map.h>"
|
||
# TU on Apple M1. A shared PCH absorbs that cost once, slashing the
|
||
# total wall-clock from ~78 s (j8) to ~25 s (3×).
|
||
#
|
||
# Opt-out with -DCONFORMALLAB_USE_PCH=OFF if the PCH itself misbehaves
|
||
# (e.g. older toolchains that don't share PCH across translation units
|
||
# reliably) — falls back to the historical "every TU re-parses CGAL"
|
||
# build mode.
|
||
option(CONFORMALLAB_USE_PCH
|
||
"Enable precompiled headers for the CGAL test target." ON)
|
||
|
||
if(CONFORMALLAB_USE_PCH)
|
||
# Per-target Unity Build property takes precedence over the global
|
||
# CMAKE_UNITY_BUILD; honour CONFORMALLAB_DEV_BUILD's preference here
|
||
# so `-DCONFORMALLAB_DEV_BUILD=ON` truly turns Unity Build off for
|
||
# incremental-rebuild workflows.
|
||
if(NOT CONFORMALLAB_DEV_BUILD)
|
||
set_target_properties(conformallab_cgal_tests PROPERTIES
|
||
# Unity-builds amortise the per-TU CGAL+Eigen header cost
|
||
# across several tests in the same compile. Batch size 4
|
||
# keeps gtest's TEST(...) macros + per-file `using
|
||
# namespace …` from colliding while still cutting parser
|
||
# cost ~4×.
|
||
UNITY_BUILD ON
|
||
UNITY_BUILD_MODE BATCH
|
||
UNITY_BUILD_BATCH_SIZE 4)
|
||
endif()
|
||
|
||
target_precompile_headers(conformallab_cgal_tests PRIVATE
|
||
# CGAL headers that every test transitively includes.
|
||
<CGAL/Surface_mesh.h>
|
||
<CGAL/Simple_cartesian.h>
|
||
<CGAL/Kernel_traits.h>
|
||
<CGAL/boost/graph/iterator.h>
|
||
<CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||
|
||
# Eigen blocks that drive the slowest template instantiations
|
||
# (SelfAdjointEigenSolver<Matrix<2,2>>, ColPivHouseholderQR<
|
||
# Matrix<complex,3,3>>, sparse Cholesky + QR fallback).
|
||
<Eigen/Dense>
|
||
<Eigen/Sparse>
|
||
<Eigen/SparseCholesky>
|
||
<Eigen/SparseQR>
|
||
|
||
# GoogleTest itself; every test includes it.
|
||
<gtest/gtest.h>
|
||
|
||
# std headers that appear in every test.
|
||
<vector>
|
||
<string>
|
||
<cmath>
|
||
<complex>
|
||
)
|
||
endif()
|
||
|
||
include(GoogleTest)
|
||
gtest_discover_tests(conformallab_cgal_tests
|
||
TEST_PREFIX "cgal."
|
||
DISCOVERY_TIMEOUT 60
|
||
)
|