Commit Graph

99 Commits

Author SHA1 Message Date
Tarik Moussa
51d9844f7a docs(references): M1/M2/M4 citation fixes (audit quick-wins)
M1: Add two missing references used in hyper_ideal_utility:
  - Kolpakov, Mednykh (2006, arXiv math/0603097) — tetrahedron volume w/ one ideal vertex
  - Meyerhoff, Ushijima (2006) — tetrahedron volume w/ three ideal vertices

M2: Clarify BPS publication year: Geometry & Topology 2015 (arXiv 2010)
  - Update references.md to note "first posted 2010"
  - Normalize all code comments from "BPS-2010" → "BPS-2015" (published version)

M4: Standardize citation format in code comments
  - Normalize all "Luo (2004)" / "Luo-2004" / "Luo's 2004" → "Luo 2004"
  - Matches references.md convention: Author Year (no parens/dashes)

282/282 tests pass. Addresses M1, M2, M4 from math-derivation-citation audit.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-31 19:44:39 +02:00
Tarik Moussa
b274591aa8 docs(reviewer): aggregate all 12 audits into the index + record decisions
Some checks failed
C++ Tests / test-fast (pull_request) Failing after 1m58s
C++ Tests / quality-gates (pull_request) Has been skipped
C++ Tests / test-cgal (pull_request) Has been skipped
Adds a comprehensive 'External audit documents' section to the reviewer index:
- groups all 12 audits (correctness, API/perf/packaging, robustness)
- surfaces G0 (porting rights) as the cross-cutting release blocker
- records the decisions taken: coverage gate 80/70/90, API naming A1-A5
  (A1-A3 implemented in PR #36, A4-A5 deferred pending G0/G1)
- points a new session at the low-risk quick-win findings

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:46:05 +02:00
dc978cf5d3 Merge pull request 'review: usability audit v0.10.0 — all 11 findings resolved' (#34) from review/usability-audit-2026-05-31 into main
Some checks failed
C++ Tests / test-fast (push) Failing after 2m11s
C++ Tests / quality-gates (push) Has been skipped
API Docs / doc-build (push) Has been skipped
Markdown link check / check (push) Has been skipped
Mirror to Codeberg / mirror (push) Successful in 32s
C++ Tests / test-cgal (push) Has been skipped
2026-05-31 08:32:21 +00:00
Tarik Moussa
b213ad2265 docs(reviewer): add math-derivation & citation audit
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m23s
C++ Tests / quality-gates (pull_request) Has been skipped
C++ Tests / test-cgal (pull_request) Has been skipped
Checks code/docs against the published mathematics (vs java-port-audit which
checks code vs Java):
- M1: Kolpakov-Mednykh volume formula used in code but missing from references.md
- M2: BPS circle-packing paper cited as '2010' in code vs '2015' in references.md
- M3: post-2023/preprint citations back unimplemented phases — re-verify + clarify
  scope before submission
- M4: no canonical citation-key convention
- M5: large derivations numerically validated but prose unreviewed — expert sign-off

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:21:24 +02:00
Tarik Moussa
bad3c4a9ab docs(reviewer): add 4 gap audits — numerical, input-validation, thread-safety, dependency/license
Closes the dimensions the prior audits did not cover:

- numerical-stability: tolerance hierarchy (FD-step vs Newton tol), discontinuous
  clamps, cancellation in cotangent/area, magic constants.
- input-validation: malformed JSON/XML deserialization, NaN/Inf vertex coords on
  load, schema-drift handling.
- thread-safety: no mutable static state (good); undocumented same-mesh concurrency
  contract; Eigen threading.
- dependency-license: existing THIRD-PARTY-LICENSES matrix is sound but predicated
  on the MIT premise that G0 undermines; test meshes have no provenance/license.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:21:24 +02:00
Tarik Moussa
7902ae8e2c docs(reviewer): add external audits — test/error-handling, API/perf, CGAL readiness
Three complementary, self-contained audit documents (each actionable by a
fresh session, with file:line, code snippets, fixes, acceptance criteria):

- test-coverage-error-handling-audit: coverage gaps + error-handling robustness;
  agreed gate 80% line / 70% branch / 90% function.
- api-performance-audit: API-naming consistency (A1–A5, decided) + Newton-solver
  performance (B1 block-FD, redundant gradient evals, factorization reuse).
- cgal-submission-readiness-audit: G0 porting-rights blocker (original is
  unlicensed Varylab/TU-Berlin code; this is a derivative work — clarify with
  authors before any license/release), G1 license, layout, concept, manual, tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:21:24 +02:00
Tarik Moussa
37b538aae4 docs: Layout2D index semantics, CLI table, CLI roadmap (U9+U10+U11)
Some checks failed
C++ Tests / test-fast (push) Has been cancelled
C++ Tests / test-cgal (push) Has been cancelled
C++ Tests / quality-gates (push) Has been cancelled
API Docs / doc-build (push) Has been cancelled
Markdown link check / check (push) Has been cancelled
C++ Tests / test-fast (pull_request) Successful in 2m10s
C++ Tests / quality-gates (pull_request) Has been skipped
C++ Tests / test-cgal (pull_request) Has been skipped
U9 (layout.hpp + example_layout.cpp)
  Layout2D.uv and .halfedge_uv now have explicit Doxygen docs stating:
    - indexing: v.idx() / h.idx() (raw integer index)
    - length: mesh.number_of_vertices() / number_of_halfedges()
    - precondition: no vertex removal / collect_garbage() after loading
    - access pattern example in the doc comment
  example_layout.cpp: access site comment + static_cast<size_t>(v.idx())

U10 (getting-started.md)
  New 'CLI parameter reference' table (7 rows) added directly below the
  CLI usage examples; cross-references --help as the canonical source

U11 (doc/roadmap/phases.md)
  New Phase 9h 'CLI usability extensions' section inserted before Phase 10:
    9h.1  --tol / --max-iter solver-tuning params  (~30 min, no deps)
    9h.2  -g cp_euclidean / -g inversive_distance  (~2-4 h, needs 9a )
  Each sub-task has effort estimate, implementation sketch, and
  acceptance criteria so a future session can pick it up cold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:51:04 +02:00
Tarik Moussa
ccbfd852b2 docs(examples): use gauge-vertex overload everywhere (U6)
Finding-U6 from doc/reviewer/usability-audit-2026-05-31.md.

The Finding-D fix (external-audit-2026-05-30) added a clean one-call
gauge-vertex overload:
  assign_euclidean_vertex_dof_indices(mesh, maps, gauge_vertex)

But all user-facing code still showed the old verbose manual loop:
  auto vit = mesh.vertices().begin();
  maps.v_idx[*vit++] = -1;
  int idx = 0;
  for (; vit != mesh.vertices().end(); ++vit) maps.v_idx[*vit] = idx++;

Replaced in three places:
  README.md 'Minimal usage' code block
  example_euclidean.cpp Step 3
  example_layout.cpp  pin_first() helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:49:05 +02:00
Tarik Moussa
d1399ca82f docs: fix stale version, CGAL header, add LOW_MEMORY_BUILD docs (U4+U5+U7+U8)
U4 (README.md:17) — status line: v0.9.0 → v0.10.0, test count 0 → 277

U5 (Discrete_conformal_map.h:6-16) — \file Doxygen block rewritten:
  was: 'provides a single function … Spherical/hyperbolic scheduled for Phase 8b.2'
  now: lists all three discrete_conformal_map_* functions already present,
       plus pointers to the circle-packing companion headers

U7 (getting-started.md) — new 'Mode 4 — Low-memory build' section added
  after Mode 3; shows CONFORMALLAB_LOW_MEMORY_BUILD=ON with -j1 and explains
  the -O0 / no PCH / batch-1 tradeoffs for Raspberry Pi / ≤ 4 GB runners

U8 (README.md compile-time modes) — LOW_MEMORY_BUILD entry added to the
  compile-time workflow code block with a one-line explanation and the
  mandatory -j1 note

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:46:08 +02:00
Tarik Moussa
b8d6e23adf docs(contracts): fix three errors in processing-unit contract table (U3)
Finding-U3 from doc/reviewer/usability-audit-2026-05-31.md.

Three concrete errors corrected:

1. check_gauss_bonnet() row (was: implies all map types work)
   → now: 'EuclideanMaps/SphericalMaps only' — HyperIdealMaps overload
     is = delete (compile error since external-audit Finding-B fix)

2. enforce_gauss_bonnet() row (same issue)
   → same restriction note added

3. newton_hyper_ideal() preconditions (was: 'lambda0 initialised')
   → WRONG: HyperIdeal computes lengths from b_v, a_e via zeta functions
     internally; lambda0 plays no role.  Correct precondition:
     'no lambda0 needed · no GB pre-check'
   → Added explanation: strictly convex energy (Springborn 2020 Thm 1.3)
     → Newton converges for any targets without a pre-check

Gauss-Bonnet prose section also updated:
  - Examples now show EuclideanMaps/SphericalMaps explicitly
  - HyperIdeal compile-error note added with the correct hyperbolic
    identity Σ(2π-Θ_v) - Area = 2π·χ and why no pre-check is needed
  - Open-mesh note added (GB identity does not hold for boundary meshes)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:44:36 +02:00
Tarik Moussa
b20a835b82 doc(audit): add U10+U11 — CLI parameter docs and extension roadmap
U10: CLI has no parameter reference in README or getting-started.md.
     Documents all 7 current flags with defaults in the audit file so
     a future session can add the table to getting-started.md.

U11: Three useful CLI gaps documented as a roadmap item:
     - --tol / --max-iter: Newton solver tuning, currently hardcoded
     - -g cp_euclidean / -g inversive_distance: Phase-9a models not
       reachable from CLI despite being fully implemented in the library
     Each item has an effort estimate (~30 min / ~2 h) and concrete
     acceptance criteria so a future session can pick it up cold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:40:46 +02:00
Tarik Moussa
02a3745b67 examples: add real conformal-flattening + CGAL-API examples (U1+U2)
Finding-U1 and Finding-U2 from doc/reviewer/usability-audit-2026-05-31.md.

The existing examples (example_euclidean, example_layout, example_hyper_ideal)
all used the "natural theta" pattern which makes x*=0 trivially the
equilibrium — u_v ≈ 0 everywhere, no deformation. A new user following
these examples saw solver output but not conformal geometry.

New: example_flatten.cpp
  - PRIMARY USE CASE: conformally flatten a mesh to the plane
  - Sets Θ_v = 2π for all interior vertices (flat target)
  - Pins boundary vertices (no Gauss-Bonnet check for open meshes)
  - Demonstrates non-trivial u_v (cathead.obj: range ≈ 2.96, 5 Newton iters)
  - Documents the difference from "natural theta" explicitly

New: example_cgal_api.cpp
  - Demonstrates CGAL::discrete_conformal_map_euclidean (Discrete_conformal_map.h)
  - First runnable CGAL public API example; contrast with internal API
  - Documents the "natural theta" default behaviour and explains why u_v=0
  - Explains when to use CGAL API vs internal API

Both examples registered in code/examples/CMakeLists.txt and compile
cleanly with -DWITH_CGAL=ON.

Updated:
  - example_euclidean.cpp: prominent "TESTING CONVENTION" warning
  - example_layout.cpp: same warning on set_natural_theta helper
  - doc/getting-started.md: example_flatten is now the recommended
    "start here" example; note on natural-theta behaviour added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:35:37 +02:00
Tarik Moussa
fb9a15ab4a doc(reviewer): add usability audit 2026-05-31
External documentation and usability review of v0.10.0.
9 findings covering documentation correctness, API usability,
and new-user experience.

Critical:
  U1 — All examples show trivial identity map (natural theta),
       not real conformal flattening — new users see no-op output
  U2 — CGAL public API has zero runnable examples

Medium:
  U3 — contracts.md incorrect: check_gauss_bonnet row missing
       HyperIdeal restriction (deleted overload after Finding-B)
  U4 — README still shows v0.9.0 (current: v0.10.0, 277 tests)
  U5 — Discrete_conformal_map.h header comment describes Phase-8a
       state; all 5 entry functions already implemented
  U6 — New gauge-vertex overload (Finding-D) not reflected in
       README or examples — old verbose loop still shown

Minor:
  U7 — CONFORMALLAB_LOW_MEMORY_BUILD absent from getting-started.md
  U8 — CONFORMALLAB_LOW_MEMORY_BUILD absent from README table
  U9 — Layout2D.uv index semantics undocumented (v.idx() contract)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:28:20 +02:00
Tarik Moussa
449c5899c0 ci: re-enable CGAL tests with LOW_MEMORY_BUILD for Raspberry Pi runner
Finding-I from doc/reviewer/external-audit-2026-05-30.md.

Root cause: CGAL+Eigen at -O3 drives cc1plus peak RAM to ~700 MB per
Unity compilation unit (batch size 4) on ARM64.  With the 1600 MB
container limit the 2nd or 3rd TU reliably triggered OOM-kill, so
test-cgal was gated off via `if: false` since 2026-05-26.

Fix: new CMake option CONFORMALLAB_LOW_MEMORY_BUILD=ON applies four
orthogonal memory-saving measures to conformallab_cgal_tests:

  1. -O0 (no debug info): optimizer passes entirely skipped → cc1plus
     peak drops from ~700 MB to ~150-200 MB per TU on ARM64.
     Omitting -g avoids the additional object-file / linker RAM cost.

  2. CONFORMALLAB_USE_PCH=OFF: saves the one-time ~200 MB PCH
     compilation cost; each TU re-parses CGAL headers (fast at -O0).

  3. UNITY_BUILD_BATCH_SIZE=1: one source file per cc1plus invocation,
     removing the "4-file template-explosion" per-unit multiplier.

  4. -Wl,--no-keep-memory (GNU ld): linker releases symbol tables after
     each input file → ~15-25 % less linker RSS.

Verified locally with cmake -DCONFORMALLAB_LOW_MEMORY_BUILD=ON:
  277/277 CGAL tests pass, 31 s runtime (vs 2 s at -O3 — expected;
  tests run 15× slower without optimizer but all correct).

CI workflow changes (cpp-tests.yml):
  - test-cgal re-enabled: `if: github.event_name == 'pull_request'`
  - Configure step adds -DCONFORMALLAB_LOW_MEMORY_BUILD=ON
  - Container memory: 1600m → 2000m (--memory-swap=3000m for 1 GB swap
    headroom), using ~half of the Pi's 3-4 GB while leaving OS margin.

CLAUDE.md updated: new flag added to compile-time options table; CI
status row corrected from DISABLED to active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
59a26123c8 fix(minor): all five MINOR findings — doc, accuracy, and DRY
MINOR-1 (spherical_functional.hpp:426)
  Wrong comment said "second derivative < 0 for a convex functional".
  The spherical energy is *concave* (NSD Hessian); the monotone-f argument
  applies to both convex and concave functionals equally.  Comment rewritten
  to explain the actual physics: increasing scale increases all angles and
  thus reduces Σ G_v.

MINOR-2 (spherical_functional.hpp:494-495)
  Forward finite difference O(ε) → central finite difference O(ε²):
    old: dft = (sum_Gv(t + fd_eps) - ft) / fd_eps
    new: dft = (sum_Gv(t + fd_eps) - sum_Gv(t - fd_eps)) / (2*fd_eps)
  Same cost when the extra sum_Gv(t - fd_eps) replaces the cached ft.

MINOR-3 (euclidean_functional.hpp, spherical_functional.hpp,
         inversive_distance_functional.hpp)
  New header gauss_legendre.hpp centralises the 10-point Gauss-Legendre
  nodes and weights (gl10_nodes() / gl10_weights()).  The three energy
  functions now use the shared accessors instead of duplicated local
  static arrays.

MINOR-4 (euclidean_functional.hpp, spherical_functional.hpp,
         hyper_ideal_functional.hpp, inversive_distance_functional.hpp)
  halfedge_to_index() centralised in conformal_mesh.hpp.  All four local
  aliases (eucl_hidx, spher_hidx, hidx, id_detail::hidx) now delegate to
  it as one-line wrappers; the aliases are kept for now to avoid a larger
  call-site churn, clearly documented as thin wrappers.

MINOR-5 (clausen.hpp:33-38)
  Added a comment above inits() explaining the intentional off-by-one
  return value and how it interacts with csevl() — matching the Java
  Clausen.inits() / csevl() contract.

277/277 CGAL + 26/26 pure-math tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
2325328f77 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>
2026-05-31 01:17:27 +02:00
Tarik Moussa
adbf682f0f test: add degenerate-triangle limiting-angle and edge-DOF guard tests
Finding-F and Finding-G from doc/reviewer/external-audit-2026-05-30.md
(java-port-audit missing-test items 1 and 2).

Finding-F — Degenerate triangle: limiting angles (item 1)
  test_euclidean_functional.cpp:
    DegenerateTriangle_LimitingAngles_L{12,23,31}TooLong
      — verifies α_opposite = π, other two = 0, valid = false
      for all three edge-over-long cases
    DegenerateTriangle_GradientPicksUpPiCorner
      — end-to-end mesh test: forces effective l12 >> l23+l31 via
        lambda0, evaluates gradient, asserts G_v3 = π (not 2π from
        a skipped degenerate face) and G_v1=G_v2 = 2π

  test_spherical_functional.cpp:
    DegenerateTriangle_LimitingAngles_S{12,23,31}TooLong
      — same coverage for spherical_angles()

Finding-G — euclidean_hessian edge-DOF guard (item 2)
  test_euclidean_hessian.cpp:
    EdgeDOFGuard_Throws
      — assign_euclidean_all_dof_indices + euclidean_hessian → throw
    EdgeDOFGuard_VertexOnlyDoesNotThrow
      — vertex-only layout → no throw (regression guard)

275/275 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
7534c62c3d fix(gradient-checks): use relative error in all FD check functions
Finding-E from doc/reviewer/external-audit-2026-05-30.md.
Scan also uncovered the same issue in inversive_distance_functional.hpp.

Three functions used absolute error `|analytic - fd| > tol` while the
rest of the library (euclidean_functional, spherical_functional,
euclidean_hessian, hyper_ideal_functional) all use relative error
`|analytic - fd| / max(1, |analytic|) > tol`.

Absolute error is too strict for large gradients (false failures) and
too lenient for small gradients.

Fixed:
  cp_euclidean_functional.hpp  gradient_check_cp_euclidean()
  cp_euclidean_functional.hpp  hessian_check_cp_euclidean()
  inversive_distance_functional.hpp  gradient_check_inversive_distance()

All three now use the relative criterion and accumulate all failures
before returning (ok=false instead of early return on first mismatch).
Default tol updated from 1e-6/1e-5 to 1e-4, matching the Java
FunctionalTest convention used by all other checks in the library.
Error message updated to print rel-err instead of raw diff.

266/266 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
cfbbc1b21f fix(dof-assign): correct "pin before" docs + add gauge-vertex overloads
Finding-D from doc/reviewer/external-audit-2026-05-30.md.

All three DOF-assignment functions iterated over every vertex
unconditionally, overwriting any v_idx set before the call.  The
documentation said "pin before OR after" — the "before" option was
silently wrong (the pin would be overwritten).  For the
inversive-distance variant the doc explicitly said the pre-call pin
would make the function "a no-op for that vertex", which was false.

Changes (three headers):
- euclidean_functional.hpp  assign_euclidean_vertex_dof_indices()
- spherical_functional.hpp  assign_vertex_dof_indices()
- inversive_distance_functional.hpp  assign_inversive_distance_vertex_dof_indices()

For each:
  1. Single-arg overload: doc corrected to "pin AFTER, not before;
     pre-call pins are overwritten"
  2. New two-arg overload accepting a Vertex_index gauge: pins the
     requested vertex (v_idx=-1) in a single pass, preventing the
     user error entirely

Three new GTests in test_euclidean_functional.cpp:
  SingleArg_PinBeforeHasNoEffect        — documents the old pitfall
  TwoArg_GaugeIsPinnedOthersAreSequential — verifies the new overload
  TwoArg_NewtonConvergesWithGaugeOverload — end-to-end correctness

266/266 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
bef5a0ceb7 docs(euclidean-hessian): fix wrong cotangent formula in two comment blocks
Finding-C from doc/reviewer/external-audit-2026-05-30.md.

The box comment at the top and the function-level comment above
euclidean_cot_weights() both stated:

  cot_k = (t_adj1·l123 − t_adj2·t_opp) / denom2   ← WRONG

The correct formula (verified numerically on a 3-4-5 right triangle,
expected cot1=4/3, cot2=3/4, cot3=0) is:

  cot_k = (t_opp · l123 − t_a · t_b) / denom2

where t_opp is the t-value of the edge OPPOSITE vertex k, and t_a/t_b
are the t-values of the two edges ADJACENT to vertex k.

The implementation in euclidean_cot_weights() was already correct;
only the documentation was wrong.

Changes (documentation only, zero code changes):
- Box comment: rewritten with correct formula and explicit per-vertex
  assignment (cot1: t_opp=t23, t_a=t12, t_b=t31; etc.)
- Box comment: added missing ½ factor to Hessian contribution lines
- Function-level comment: corrected to (t_opp·l123 − t_a·t_b)/(8·Area)
  with a pointer to the box comment for the full assignment
- Inline return comment in euclidean_cot_weights(): now shows the
  mapping (cot1: t_opp=t23, t_a=t12, t_b=t31) directly at the formula

263/263 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
46c0b63de8 fix(gauss-bonnet): delete HyperIdeal overloads — wrong identity for hyperbolic metrics
Finding-B from doc/reviewer/external-audit-2026-05-30.md.

The Euclidean Gauss–Bonnet identity Σ(2π−Θ_v) = 2π·χ is ONLY valid for
flat/Euclidean and spherical metrics.  For hyperbolic metrics (HyperIdeal)
the correct identity is Σ(2π−Θ_v) − Area(M) = 2π·χ.  The previously
provided gauss_bonnet_sum(HyperIdealMaps) overload would silently pass the
wrong LHS to check_gauss_bonnet, which would always throw "deficit = ±Area"
for valid hyperbolic targets.

Fix:
- gauss_bonnet_sum(mesh, HyperIdealMaps)        → = delete + explanation comment
- enforce_gauss_bonnet(mesh, HyperIdealMaps&)   → = delete + explanation comment
- Header box comment rewritten with the correct hyperbolic Gauss–Bonnet
  identity and a clear "HyperIdeal: NOT SUPPORTED" section

New test in test_phase6.cpp:
- HyperIdeal_EuclideanSumDiscrepancy_DocumentsWhyCheckIsDeleted
  verifies numerically that the Euclidean sum = 0 but 2π·χ = 4π for a
  regular tetrahedron, documenting the −4π discrepancy that motivated
  the deletion
- Three compile-time static_asserts (SFINAE) confirm the overload is not
  invocable with HyperIdealMaps but remains so with Euclidean/SphericalMaps

263/263 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
faf96ee28c doc(roadmap): add research item for 2/3-ideal hyper-ideal volume formulas
Follow-up to the Finding-A fix (face_energy guard).  The throw is the
correct safe behaviour for now; the mathematically complete solution
requires formulas for semi-ideal and fully-ideal tetrahedra that are
absent from the Java reference.

Adds a structured research entry to research-track.md (Phase 9b+):
- primary references: Kolpakov-Mednykh arXiv:math/0603097, Milnor 1982,
  Vinberg 1985
- acceptance criteria: two new volume functions + gradient-check tests +
  limiting-behaviour continuity witness
- explicit note that the throw in face_energy() must not be removed
  without implementing and testing the replacement formulas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
9afefcbb7b fix(hyper-ideal): guard face_energy() against unsupported multi-ideal faces
Finding-A from doc/reviewer/external-audit-2026-05-30.md.

Root cause: both the Java reference (HyperIdealFunctional.java:222-231)
and the C++ port silently applied the one-ideal-vertex volume formula
to the first ideal vertex found in a face, ignoring any additional ideal
vertices.  For two or three ideal vertices this produces a wrong energy
value with no diagnostic.

Fix: add an ideal_count guard at the top of face_energy() that throws
std::logic_error for ideal_count >= 2.  The one-ideal (Kolpakov-Mednykh)
and zero-ideal (Meyerhoff/Ushijima) paths are unchanged and correct.

Three new GTests cover the three guard cases:
  MultiIdealGuard_TwoIdealVertices_Throws        (two ideal  → throw)
  MultiIdealGuard_AllThreeIdealVertices_Throws   (all ideal  → throw)
  MultiIdealGuard_ExactlyOneIdeal_DoesNotThrow   (one ideal  → no throw)

262/262 CGAL tests pass, 0 failed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
7f1a077269 doc(reviewer): add external audit 2026-05-30
Full external code review of v0.10.0 against all math-critical headers
(direct source read, not automated scan). Documents 5 open bugs/API errors,
3 test gaps inherited from java-port-audit.md, 1 architectural CI risk,
and 5 minor findings. Each finding is self-contained with file+line
references, a concrete fix proposal, and acceptance criteria so a new
session can pick up any single finding without prior context.

Key findings:
- FINDING-A (critical): face_energy() wrong for mixed ideal/hyper-ideal configs
- FINDING-B (medium):   Gauss–Bonnet API conceptually wrong for HyperIdeal
- FINDING-C (medium):   cotangent formula in euclidean_hessian.hpp header is wrong
- FINDING-D (medium):   DOF-assignment doc falsely claims "pin before" works
- FINDING-E (medium):   cp_euclidean gradient_check uses absolute not relative error
- FINDING-F/G/H:        three open test gaps from java-port-audit.md
- FINDING-I (arch):     246/272 CGAL tests not gated in CI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 01:17:27 +02:00
Tarik Moussa
8619043b79 docs(crossvalidation): fix stale test count 243→259 after PRs #29-31 merged
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m17s
API Docs / doc-build (pull_request) Successful in 1m1s
Markdown link check / check (pull_request) Successful in 43s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Failing after 1m52s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:36:51 +02:00
Tarik Moussa
c472748e46 docs(reviewer): refresh §4 to mark Tier-1/3 done (stale TODO removed)
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
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00
Tarik Moussa
082649ef40 docs(reviewer): mark Tier-3 done (PR #30); fix duplicated tier table
- Tier-3 (Lawson HyperIdeal) plain + branch-points marked DONE (PR #30,
  test_lawson_hyperideal.cpp); status, §3 HIGH/MED rows, §3b table and §4
  recommended-order updated accordingly.
- Hyperelliptic variant documented as deferred (option c): needs an XML-format
  reader for lawson_curve_source.xml + a port of HyperIdealHyperellipticUtility
  (jReality geometry θ); golden vector is non-symmetric.
- Removed a pre-existing duplicated/stale copy of the tier-table rows.
- Added a status summary (Tier 1  PR #29 · Tier 2 → Phase 9f/13 · Tier 3  PR #30).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00
Tarik Moussa
267ae965ab docs(reviewer): Tier-2 exhausted (genus≥2 → Phase 13); Tier-3 Lawson scoped as mini-project
- regular_uniformization.xml / LetterB01_canonical_group.xml are genus≥2
  hyperbolic Fuchsian-group uniformizations (12-edge fundamental polygon), not
  genus-1 → Phase 13, not Tier 2.
- Tier-2 is therefore exhausted (only Wente, deferred to Phase 9f quad/cyclic).
- Tier-3 Lawson HyperIdeal golden vectors require a low-level halfedge genus-2
  multi-edge generator (4 verts/12 edges) + jtem Triangulator replication;
  scoped as a dedicated follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00
Tarik Moussa
822a27da69 feat(euclidean): full analytic edge-DOF (cyclic) Hessian; Tier-2 Wente finding
Upgrades the cyclic Euclidean Hessian from block-FD to closed-form, satisfying
the novelty-statement §3.2 "analytic Hessians, not finite difference" claim for
the Euclidean path.

- euclidean_hessian.hpp: `euclidean_hessian_analytic` — closed-form cyclic
  Hessian from the law-of-cosines angle derivatives
    ∂α_i/∂s_i = ℓ_i²/4A,  ∂α_i/∂s_j = ½cot α_i − ℓ_j²/4A   (Σ_j = 0),
  chained to (u, λ_e) and sign-mapped to the gradient outputs (−α vertex,
  +α_opp edge). Reuses euclidean_cot_weights. Block-FD kept as cross-check.
- newton_solver.hpp: newton_euclidean cyclic path now uses the analytic Hessian.
- tests: CyclicHessian_Analytic_MatchesBlockFD_Tetrahedron — analytic == block-FD
  (1e-6), == gradient FD (1e-5), symmetric (1e-9). Existing cyclic convergence
  oracle still GREEN with the analytic Hessian routed in.

Tier-2 (Wente) finding: wente_torus02.obj is a QUAD mesh (1240 quads) and the
Java golden comes from cyclic (quad-net) uniformization; the C++ period-matrix
pipeline is triangle-based, so a faithful bit-vs-Java τ comparison needs a
quad/cyclic pipeline (Phase 9f). Deferred and documented; golden τ = ½+i√3/2.

244/244 cgal tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00
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
Tarik Moussa
5d74a94b78 test(euclidean): Tier-1 circular-edge φ cross-validation + cyclic-solve blocker
Build-verified attempt to port the Java EuclideanCyclicConvergenceTest
(cathead, "circular hole edge" φ = π−0.1).

-  GREEN `CyclicCircularEdge_PhiEntersGradient_CatHead`: solver-free
  cross-validation that the circular-edge φ target enters the cyclic edge
  gradient exactly (ΔG_e = −Δφ_e at 1e-12; no other component moves).
- ⏸️ DISABLED `CyclicCircularEdge_CatHead_JavaXVal`: the full Java convergence
  assertion (α_opp+α_opp = π−0.1), kept with golden semantics. Auto-activates
  once the edge-DOF Hessian lands.

Build-verification finding: `newton_euclidean` -> `euclidean_hessian` throws
"edge DOFs are not supported" — the cyclic full solve is blocked by a missing
edge-DOF Euclidean Hessian (gradient supports edge DOFs, analytic Hessian does
not). Spherical convergence (Tier-1 #2) is already covered by test_newton_solver.
Documented in doc/reviewer/java-ignore-crossvalidation.md.

All 13 EuclideanFunctional tests pass (1 disabled).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:32:02 +02:00
Tarik Moussa
41ad4a84d2 docs(reviewer): cross-validation analysis of Java @Ignore tests
Classifies the 22 Java @Ignore'd test files by root cause (ARM64 PETSc
native lib vs logic/known-issue) and by cross-validation value for the
C++ port.

- Notes what PR #27 already locks (math cores + functional-eval oracles)
  to avoid duplication.
- Priority ranking: HIGH (HyperIdeal Lawson convergence golden vector —
  records the exact u*), MEDIUM (genus-1 Wente uniformization, branch-point
  variant), LATER (genus-2/hyperelliptic/Mobius/quasi-isothermic/Schottky),
  NON-ORACLE (Java gaps: testHessian, testDoLayout; ARM64-flaky known issues).
- Documents why the Lawson mesh needs a low-level half-edge generator
  (4 vertices / 12 edges => multi-edges; CGAL add_face cannot build it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:28:54 +02:00
adfcb7b931 Merge pull request 'feat(geometry): pn_geometry.hpp — Pn projective-metric substrate (jReality port)' (#31) from feat/pn-geometry-substrate into main
Some checks failed
C++ Tests / test-fast (push) Successful in 2m21s
API Docs / doc-build (push) Has been skipped
Markdown link check / check (push) Successful in 54s
Mirror to Codeberg / mirror (push) Successful in 43s
C++ Tests / test-cgal (push) Has been skipped
C++ Tests / quality-gates (push) Has been cancelled
2026-05-30 15:26:23 +00:00
Tarik Moussa
330515ea90 docs(java-parity): P2/Matrix jReality notes + Phase 9c dependency warning
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m20s
API Docs / doc-build (pull_request) Successful in 52s
Markdown link check / check (pull_request) Successful in 1m1s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 2m24s
- Infrastructure table: add Matrix (→ Eigen inline, done) and P2 rows.
  P2 marked "port inline with Phase 9c" — almost exclusively consumed by
  FundamentalPolygon/CanonicalForm/SurfaceCurve (all Phase 9c), so building
  p2_geometry.hpp as a standalone ahead of 9c would be dead weight.
- Phase 9c rows in the utility table: ⚠️ annotation listing the exact P2.*
  methods needed (makeDirectIsometryFromFrames, projectP3ToP2,
  imbedMatrixP2InP3) plus the P2Big/cpp_dec_float_50 high-precision
  prerequisite for the group-relation product ∏gᵢ = Id.

Ensures a future Phase 9c session starts with full context and does not
discover the jReality/precision dependencies mid-port.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:20:35 +02:00
Tarik Moussa
149da15c64 feat(geometry): pn_geometry.hpp — Pn projective-metric substrate (jReality port)
Ports the small but pervasive de.jreality.math.Pn surface that the Java
algorithmic core uses across every not-yet-ported geometric phase:
HyperbolicLayout, SphericalLayout, FundamentalPolygon (9c), KoebePolyhedron
(10c'), quasi-isothermic (10e), hyperelliptic theta, CircleDomain (11c).
Porting it once unblocks all downstream consumers instead of re-deriving
the metric ad hoc per phase.

pn_geometry.hpp — header-only, Eigen, ~120 LOC:
  PnMetric { EUCLIDEAN=0, ELLIPTIC=+1, HYPERBOLIC=-1 } matching jReality.
  pn_inner_product  — bilinear form per signature.
  pn_norm / pn_dehomogenize / pn_set_to_length / pn_normalize.
  pn_distance_between — Euclidean (spatial), elliptic (acos), hyperbolic (acosh).
  pn_linear_interpolation — affine (E) and slerp (S/H constant-speed geodesic).

HYPERBOLIC uses the timelike-positive ("upper-sheet") convention, identical to
the already-verified projective_math.hpp::hyperbolicDistance; pn_distance_between
is regression-anchored against it in the tests.

test_pn_geometry.cpp — 6 tests, all GREEN:
  InnerProductSignatures, EuclideanDistance, EllipticDistanceIsAngle,
  HyperbolicDistanceClosedFormAndAnchor (+ projective_math.hpp anchor),
  NormAndScaling, LinearInterpolationGeodesic.

doc/roadmap/java-parity.md — new "Infrastructure / support layers" section:
  de.jreality.math.Pn   → pn_geometry.hpp (partial, 6 fns covering core usage)
  de.jreality.math.Rn   → Eigen (no separate port needed)
  MatrixBuilder         → not yet (only needed for hyperelliptic theta)
  conformallab XML types → not planned (GUI persistence, not algorithmic)

246/246 cgal tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 17:20:35 +02:00
a993a101e9 Merge pull request 'docs: citation audit (8 mis-citations fixed) + Phases 12/13' (#28) from docs/citation-audit-phases-12-13 into main
Some checks failed
C++ Tests / test-fast (push) Successful in 2m15s
API Docs / doc-build (push) Has been skipped
Markdown link check / check (push) Successful in 47s
Mirror to Codeberg / mirror (push) Successful in 27s
C++ Tests / test-cgal (push) Has been skipped
C++ Tests / quality-gates (push) Failing after 1m51s
Reviewed-on: #28
2026-05-30 08:06:33 +00:00
Tarik Moussa
26f4f0637d docs: citation audit + correct 8 mis-citations; add Phases 12/13
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 1m55s
API Docs / doc-build (pull_request) Successful in 53s
Markdown link check / check (pull_request) Successful in 50s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Failing after 1m56s
External reviewer pass over the literature references. Verified entries
against arXiv/DOI/publisher and corrected misattributions that had
propagated across the docs.

Corrected citations (consistent across all docs):
- Bowers-Bowers-Lutz 2026: title was the 2017 paper's
  -> "Rigidity of Koebe Polyhedra and Inversive Distance Circle Packings"
- Liouville theorem: "Springborn 2019" -> Pinkall & Springborn,
  Geom. Dedicata 214 (2021)
- Bobenko-Pinkall-Springborn: "G&T 14 (2010)" -> G&T 19(4) (2015), 2155-2215
- Optimal Cone Singularities: "Crane, Soliman, Ben-Chen, Schroeder"
  -> Soliman, Slepcev, Crane, ACM TOG 37(4)
- Schlaefli formula: "Rivin, Springborn 1999" -> Rivin, Schlenker
- Quasiconformal distortion: "Springborn, Veselov" -> Born, Buecking,
  Springborn (arXiv:1505.01341)
- Period matrices: "Bobenko, Buecking 2009" (was Bobenko-Mercat-Schmies'
  title) -> Bobenko-Mercat-Schmies 2011 + genuine Bobenko-Buecking 2021
- Fabricated entry: "Alexa 2020, DOI 10.1145/3414685.3417840" pointed to
  an unrelated paper (Pixelor) -> Bunge, Herholz, Kazhdan, Botsch 2020
- Stripe Patterns: "Bonneel et al. 2015" -> Knoeppel, Crane, Pinkall,
  Schroeder 2015

Equation-number corrections (verified against the PDFs):
- Glickenstein 2011 "eq. 4.6" -> "§5.2" (no such equation label exists)
- Springborn 2020 "eq. 4.6" -> "§4 variational gradient"
- inversive-distance attribution softened to classical inversive distance

Other:
- DBFEnergy bibliography (separate repo) and convergence half-sentence in
  novelty-statement.md §3.3 (Bobenko-Buecking 2021)
- Status legend (implemented vs planned) at top of references.md
- New Phase 12 (decorated DCE & geometric transition, Chain A, near-term)
  and Phase 13 (canonical tessellations & polyhedral realisation, Chain B
  capstone) in phases.md + research-track.md; 10c scope-boundary note
  clarifying infrastructure vs Lutz-specific algorithms

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:17:17 +02:00
Tarik Moussa
ba83974525 test: Java golden-value oracles for the five DCE math cores + P1-2/P1-3 fixes
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 1m57s
API Docs / doc-build (pull_request) Successful in 59s
Markdown link check / check (pull_request) Successful in 51s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 2m19s
Add bit-for-bit (1e-12) golden-value oracle tests pinning the C++ pure-math
and functional cores against the compiled upstream Java library (openjdk 17):

- HyperIdealGoldenJava: Clausen/Л/ImLi2, ζ13/14/15/ζ, both tetrahedron-volume
  formulas (real de.varylab…Clausen / HyperIdealUtility).
- EuclideanGoldenJava / SphericalGoldenJava: angle formulas + β relations + Л
  energy terms, plus FULL-MESH oracles driving the real EuclideanCyclicFunctional
  / SphericalFunctional on a shared tetrahedron — per-vertex gradient (Θ−Σα) and
  ΔE = E(x)−E(0) (C++ Gauss-Legendre path integral vs Java closed form).
- SphericalGoldenJava.FullMeshEdgeDofGradient: edge-DOF gradient (vertex + edge
  components, α_opp⁺+α_opp⁻−θ_e) vs raw conformalEnergyAndGradient — locks
  Finding 3 at the solution level (audit items 4 & 5).
- PeriodMatrix.NormalizeModulus_GoldenJava: τ-reduction fold convention vs the
  real DiscreteEllipticUtility.normalizeModulus (audit items 7 & 8).

Subtlety documented: the spherical oracles call Java's raw
conformalEnergyAndGradient, not evaluate() (which pre-runs a Brent gauge
maximization that C++ factors into the Newton solver's spherical_gauge_shift).

Also:
- P1-2 (layout.hpp): Euclidean holonomy now uses a per-cut-edge rigid-motion fit
  g(z)=a·z+b, exposing residual_rotation = |arg(a)| as a diagnostic; non-
  regressive (flat case a=1 reduces to the old midpoint formula).
- P1-3 (period_matrix.hpp): is_in_fundamental_domain fixed to the correct
  half-open SL(2,ℤ) domain (−½ ≤ Re < ½). Updated the now-exposed
  ComputePeriodMatrix_ReducedTau_InFD to assert the normalizeModulus domain
  (closed +½ edge) instead.

Test counts (single source of truth = doc/api/tests.md): 272/272 pass, 0
skipped (26 non-CGAL + 246 CGAL).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:08:37 +02:00
Tarik Moussa
a3ee9576d4 fix+test: Euclidean holonomy/τ end-to-end + spherical edge-DOF oracle (2026-05-29 audit)
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 1m57s
API Docs / doc-build (pull_request) Successful in 1m3s
Markdown link check / check (pull_request) Successful in 44s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 2m11s
Bundles the 2026-05-29 Java↔C++ math-correctness audit (doc/reviewer/
java-port-audit.md, 11 findings) with two follow-up fixes.

Audit code changes:
- Finding 3 (spherical_functional): edge-DOF replacement parameterization via
  spher_eff_lambda; edge gradient α_opp⁺+α_opp⁻−θ_e (drops additive −(S⁺+S⁻)/2)
- Finding 4 (spherical_hessian): always-compiled edge-DOF throw guard
- Finding 6 (period_matrix): faithful normalizeModulus (0≤Re≤½, Im≥0, |τ|≥1)
- Finding 9 (inversive_distance): degenerate-face limiting angles, no skip
- Findings 1/2 (euclidean): degenerate gradient limiting angles + Hessian guard

Euclidean holonomy/τ fix: develop the cut surface across the dual spanning tree
only (cut_graph now exposes is_dual_tree), so genus-1 cut edges yield
non-degenerate lattice generators. Previously τ came out 0 / NaN / 1e13 on the
bundled tori; now matches the analytic revolution modulus i·√(R²−r²)/r. Re-enabled
τ reporting in the Euclidean CLI; rewrote validation.md §3/§4 accordingly.

Tests (240 CGAL, 0 skipped):
- HolonomyEndToEnd ×3 — tori of revolution (4×4, hex 6×6, 8×8) vs analytic modulus
- SphericalFunctional.EdgeGradient_RegularTetClosedForm — independent closed-form
  π/3 oracle locking the Finding-3 edge formula (the path-integral FD check cannot
  detect a wrong-but-conservative gradient)

Also documents the latent spherical/hyperbolic holonomy-extraction bug (same
single-development pattern, dead code today) in research-track.md (Phase 9c/10),
and adds favour/normalisations to the codespell ignore list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 12:50:16 +02:00
Tarik Moussa
ca936b7652 docs: note high-precision requirement for Phase 9c/10 uniformization
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m0s
API Docs / doc-build (pull_request) Successful in 53s
Markdown link check / check (pull_request) Successful in 54s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Failing after 2m14s
The Java uniformization classes (FundamentalPolygonUtility, CanonicalFormUtility)
rely on the *Big arbitrary-precision geometry (MathContext(50)) because products
of hyperbolic isometry generators grow exponentially and double fails to verify
the group relation ∏gᵢ = Id. Record this planning-relevant prerequisite and
resolve the contradiction in java-parity.md, which previously listed *Big as
permanently out of scope.

- CLAUDE.md: † note on the Phase-9 not-yet-ported table
- java-parity.md: *Big exception (localized high-precision substrate for 9c/10)
- phases.md: precision prerequisite as 9c sub-task + effort estimate
- design-decisions.md: new "Scalar type: double, with one localized exception"

Core flattening (Newton/energy/Eigen solver) stays double; the substrate
(cpp_dec_float_50 / mpreal) is localized to the uniformization module only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 07:41:23 +02:00
Tarik Moussa
1ff5382c8b docs: record 2026-05-28 full-library scan findings in roadmap
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 1m55s
API Docs / doc-build (pull_request) Successful in 53s
Markdown link check / check (pull_request) Successful in 1m1s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Failing after 2m3s
Cross-referenced all 232 Java classes against the roadmap. New plan
entries for genuinely-useful, previously-unplanned items:
- 9g.1 conformal quality measures (Isothermicity, ConformalEquivalence,
  FlippedTriangles, LengthCrossRatio + ConvergenceUtility metrics)
- 9g.2 optional period-matrix convergence experiment (method only;
  Java harness depends on Mathematica/JLink + jReality, not ported)
- DEC operator layer (heds/dec/) noted as a 10a prerequisite
- HomotopyUtility -> 10a (explicit generator cycles; not covered by
  cut_graph.hpp, which yields only the 2g cut edges)
- SurfaceCurveUtility -> 9c; MercatorTextureProjection -> 9d.3 companion

Documented as deliberately out-of-scope: SpanningTreeUtility (subsumed
by cut_graph.hpp), convergence/* harness, datasource/* (jReality viewer
decoration), *Big arbitrary-precision geometry, jReality GUI, and the
MTJ/Tao/PETSc solver bindings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 06:53:09 +02:00
Tarik Moussa
569a03dc08 docs+tooling: doc-freshness gate, documentation-pass policy, token-hygiene
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m2s
API Docs / doc-build (pull_request) Successful in 1m8s
Markdown link check / check (pull_request) Successful in 52s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 1m59s
Refresh CLAUDE.md for v0.10.0 (3 CI jobs incl. disabled test-cgal,
compile-time option matrix, reviewer/pages docs, agentic + token-hygiene
workflow patterns) and condense the historical Phase-8/audit logs to
pointers.

Add the documentation-pass process so the single-source-of-truth rules
stay enforced:
  * scripts/quality/check-doc-freshness.sh — string-only drift gate
    (version/date across CITATION/CHANGELOG/CLAUDE, doc-map count), <1 s,
    registered in run-all.sh + quality README.
  * doc/release-policy.md — "Documentation passes" subsection (triggers +
    docs:sync rule); fix stale Phase-milestone mapping (v0.10.0 was
    reviewer-ready, 9c→v0.11.0) and the test-cgal CI mention.

Add shared Claude config (un-ignore the two files only):
  * .claude/settings.json — permission allowlist for safe repo commands.
  * .claude/token-hygiene.md — Tier-3 cache-discipline user guide that
    CLAUDE.md instructs Claude to remind the user about.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 06:15:14 +02:00
Tarik Moussa
11d660af49 fix(hub): correct double-branch/branch/main URL prefix + v0.10.0 badge
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m20s
API Docs / doc-build (pull_request) Successful in 49s
C++ Tests / test-cgal (pull_request) Failing after 8m18s
C++ Tests / quality-gates (pull_request) Successful in 1m52s
Two bugs in the reviewer hub HTML:

1. The earlier sed-rewrite that lifted the hub from
   `preview/reviewer-snapshot-v6` into `branch/main` accidentally
   produced `branch/branch/main` — sed pattern matched the
   `preview/reviewer-snapshot-v6` slug but the surrounding URL
   already had `/src/branch/` prefix.  All 25 in-hub links to the
   repo were broken with 404 on codeberg.org.

   Fix: `s|/src/branch/branch/main/|/src/branch/main/|g`.

2. The version pill in the badge strip still read v0.9.0 (stale
   from the original v0.9.0-era hub template).  Updated to v0.10.0.

The fix is in this in-repo source-of-truth file so any future manual
republication of the pages branch picks up the corrected hub.  The
just-pushed pages branch already has the fix applied; codeberg's
`tmoussa.codeberg.page` frontend cache (max-age=600 s) will refresh
over the next 10 minutes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:50:59 +02:00
Tarik Moussa
09a68a4569 release: v0.10.0 — reviewer-ready release
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m16s
API Docs / doc-build (pull_request) Successful in 49s
Markdown link check / check (pull_request) Successful in 51s
C++ Tests / test-cgal (pull_request) Failing after 7m34s
C++ Tests / quality-gates (pull_request) Successful in 2m20s
Post-merge consistency commit:

  * CITATION.cff version 0.9.0 → 0.10.0, date 2026-05-26
  * CHANGELOG.md — new "[0.10.0]" section listing all 13 commits
    that landed across PRs #17 / #18 / #19
  * Post-merge gate fixes:
      - doxygen_groups.h + doxygen_namespaces.h gain \\file briefs
      - .codespellrc extended (honour, thead, optimiser)
      - compile-time.md: unbalanced backtick on line 102 fixed
        (was confusing Doxygen's verbatim-block detector)

Final gate state on the merged main:
   259/259 tests pass
   test-count consistency
   markdown links 166/166 resolve (43 .md files)
   CGAL conventions 0/8 violations
   license-headers 68/68 carry MIT SPDX
   codespell 0 typos
   shellcheck 0 findings (18 scripts)
   Doxygen 396/396 symbols, 0 warnings

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:24:16 +02:00
Tarik Moussa
e874f73e29 docs+lint: post-merge consistency fixes after PRs #17/#18/#19 landed
Three small cleanups surfaced by running the full gate sweep on the
merged main:

1. CGAL conventions (CGAL-2 \\file briefs)
   doc-only headers `Conformal_map/doxygen_groups.h` and
   `Conformal_map/doxygen_namespaces.h` were missing the `\\file`
   brief required by the CGAL conventions check.  Added both.

2. codespell — three new triggers
   `code/tests/cgal/CMakeLists.txt` uses "honour", `doc/reviewer/hub.html`
   uses `<thead>` (HTML tag, false-positive for "thread"), and
   `doc/roadmap/research-track.md` uses "optimiser".  All three are
   British-English / HTML usage; added to `.codespellrc` ignore list.

3. Doxygen warning in `doc/architecture/compile-time.md:250`
   A trailing backtick-quoted CMake flag at end-of-file confused
   Doxygen's markdown parser into starting a never-closing verbatim
   block.  Rewrote the line to put the prose first and the backtick
   in the middle, not at end-of-file.

All gates green again on the merged main:
   259/259 tests pass
   test-count consistency
   markdown links 166/166 resolve
   CGAL conventions 0/8 violations
   license-headers 68/68 carry MIT SPDX
   codespell 0 typos
   shellcheck 0 findings (18 scripts)
   Doxygen 100% coverage, 0 warnings

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:19:55 +02:00
Tarik Moussa
3f508adf18 ci+hub: durable reviewer hub via in-repo HTML + perf-CI matrix on Linux
Some checks failed
C++ Tests / test-fast (pull_request) Successful in 2m16s
API Docs / doc-build (pull_request) Successful in 51s
Markdown link check / check (pull_request) Successful in 45s
C++ Tests / test-cgal (pull_request) Failing after 7m40s
C++ Tests / quality-gates (pull_request) Failing after 2m1s
Two additions that close out the reviewer-prep work cleanly:

1. doc/reviewer/hub.html  +  publish-workflow integration
   ──────────────────────────────────────────────────────
   Move the hand-curated reviewer hub from the codeberg `pages`
   branch (where it lived as an opaque snapshot) into the repo as
   `doc/reviewer/hub.html`.  `.gitea/workflows/doxygen-pages.yml`
   gains a conditional `if [ -f doc/reviewer/hub.html ]; then …`
   step that installs it as the publish `index.html` and demotes
   the auto-generated Doxygen index to `/doxygen.html`.

   Effect: merging any of the open PRs into main will trigger the
   workflow, which republishes BOTH the Doxygen + the reviewer hub
   together.  The reviewer URL stays live across merges with zero
   manual intervention.

   Source-controlled benefits:
     * hub edits go through normal PRs, not orphan-branch
       force-pushes
     * old hub versions live in git history
     * the in-repo links now target `branch/main/…` instead of the
       transient `preview/reviewer-snapshot-vN/…` paths

2. .gitea/workflows/perf-compile-time.yml — Linux CI bench
   ────────────────────────────────────────────────────────
   New workflow runs on every push to main that touches the build
   system or public headers.  Five-step matrix measures and reports:
     Run 1   cold baseline (no PCH, no Unity, no ccache)
     Run 2   + PCH only
     Run 3   + PCH + Unity (current default)
     Run 4   + FAST_TEST_BUILD=ON  (-O0 -g — Linux's expected ~40 % win)
     Run 5   + ccache warm rerun   (expected ≥ 90 % cache hit)

   Validates the Apple-M1 predictions in doc/architecture/compile-time.md
   against the Linux + g++ runner where Backend dominates more and
   the Apple-clang+PCH friction that defeats ccache locally does not
   apply.  Job is data-collection only; never blocks a merge.

doc updates:
  * doc/architecture/compile-time.md — new "Cross-platform perf bench"
    section linking to the workflow + the table of macOS-vs-Linux
    expected deltas.
  * doc/reviewer/README.md — new "Hub-Page durability" subsection
    explaining how the hub survives merges.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:15:09 +02:00
Tarik Moussa
bc40a13e8d perf: architecture-touch quick-wins #6 + #10; skip #5 + #7 with honest notes
Evaluated all four mid-tier architecture-touch levers from
doc/architecture/compile-time.md.  Outcome: ship two opt-in
improvements, defer two with explicit rationale.

#6 — Eager-include reduction (Dense → Core)   shipped
─────────────────────────────────────────────────────
Three headers downgraded from `<Eigen/Dense>` to `<Eigen/Core>`:
  * projective_math.hpp
  * hyper_ideal_visualization_utility.hpp
  * mesh_utils.hpp

All three only use Matrix/Vector primitives, no Eigen decompositions.
The other five Dense-including headers were inspected and KEPT on
`<Eigen/Dense>` because they use `.inverse()`, `.determinant()`,
`ColPivHouseholderQR`, or `SelfAdjointEigenSolver`.

Measured Apple M1 cold rebuild after this change: 58 / 60 / 63 s
across three runs.  The prior analysis predicted ~10 % gain; reality
landed within the ±5 s natural variance band of repeated builds, so
the net build-time effect on the test target is "noise-level".

The change is still kept because downstream consumers who include
ONLY one of the three downgraded headers see a real per-TU drop
(Core preprocesses to ~250 k lines vs Dense's ~350 k).

#10 — Fast test-build mode (-O0 -g)   shipped
───────────────────────────────────────────────
New option CONFORMALLAB_FAST_TEST_BUILD (default OFF).  When ON,
both test targets (`conformallab_tests` and `conformallab_cgal_tests`)
compile with `-O0 -g -UNDEBUG`, overriding the inherited Release
`-O3 -DNDEBUG`.

Measured Apple clang: 51.6 s vs 46.8 s without -O0 → slightly slower.
The Backend phase that prior analysis predicted would drop from 9.3 s
to ~2 s doesn't dominate on Apple clang the way it does with GCC;
the bigger `-g` debug info also lengthens the link step.

Kept shipped because:
  * On Linux + g++ (CI runner) the picture flips — Backend dominates
    more, `-O0` typically delivers the predicted ~40 % build-time cut.
  * Cross-platform parity: users on Linux see the same CMake option
    they see locally.

Honest documentation in doc/architecture/compile-time.md notes that
the Apple-clang-local benefit is currently 0 %.  Tests RUN ~15× slower
under `-O0` (1.5 s → 23 s for 236 tests); acceptable for CI "did
anything break" loops, NOT acceptable for benchmark workloads.

#5 — Move detail:: impls to .inl files  ⏸ deferred
───────────────────────────────────────────────────
Pure enabler for #7.  Without #7 landing, the .inl extraction would
just add an extra hop to header reading.  Reconsider once a concrete
maintenance reason emerges (e.g. a downstream user wants to override a
detail helper).

#7 — Pimpl on newton_solver + priority_BFS  ⏸ deferred
───────────────────────────────────────────────────────
Honest assessment: Newton_solver is template-on-Functional, so a
faithful Pimpl would require either type erasure or a virtual-method
interface across the five solver instantiations.  Estimated 1-2 weeks
of refactor with measurable API-surface risk.  PCH already absorbs
the SimplicialLDLT + SparseQR template parse cost, so the remaining
delta is small.  Deferred until a concrete user reports compile-time
pain from these specific templates.

Documentation
─────────────
README.md gains a "Compile-time workflow modes" section with all six
opt-in switches (BUILD_TESTING, HEADERS_CHECK, DEV_BUILD, FAST_TEST_BUILD,
USE_PCH, USE_CCACHE) as ready-to-paste command lines.

doc/architecture/compile-time.md gains:
  * an "Architecture-touch quick-wins" section with the four-row
    status table (5 deferred / 6 shipped / 7 deferred / 10 shipped)
  * the FAST_TEST_BUILD row added to the workflow-modes table
  * the mode-matrix table updated with Linux-vs-macOS expected values
  * an honest "variance" note explaining the ±5 s spread between
    repeated cold builds and why #6's net effect lands in that noise

Verified: default build 55 s (within usual variance), 236/236 tests
pass under default; FAST_TEST_BUILD=ON build 52 s, 236/236 PASS.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:15:09 +02:00
Tarik Moussa
9ea7d15aa0 perf: add 4 workflow modes (BUILD_TESTING / DEV_BUILD / HEADERS_CHECK / ccache)
Four orthogonal opt-in build modes on top of the existing PCH + Unity
defaults.  Each addresses a specific iteration scenario; defaults are
unchanged (PCH + Unity stays the canonical fast full-rebuild path).

(A) HEADERS_CHECK target — opt-in via -DCONFORMALLAB_HEADERS_CHECK=ON
    Per-public-header smoke-compile sentinels.  For each of the six
    public CGAL umbrella headers, a stub TU `#include <…>\nint main(){}`
    is generated at configure time and compiled in isolation.
      * Full headers_check build:  ≈ 12 s
      * Incremental after touching one header:  ≈ 0.1 s
    Use case: "did my refactor still parse the public API?" without
    waiting 55 s for the full CGAL test build.

(C) DEV_BUILD mode — opt-in via -DCONFORMALLAB_DEV_BUILD=ON
    PCH stays on; Unity Build is forced off (both globally AND on the
    cgal-tests target which previously overrode the global setting).
    Trade-off: full clean rebuild ~75 s (+36 % vs the 55 s default)
    but incremental rebuild after editing a single test file drops
    from ~46 s (unity batch) to ~16 s (single TU + relink).
    Flip on for trial-and-error sessions, flip off before measuring
    CI build time or shipping a PR.

(D) ccache integration — default ON, disable with -DCONFORMALLAB_USE_CCACHE=OFF
    Detects `ccache` on PATH and prepends it to compile + link
    launchers.  On Apple clang + PCH + Unity the macOS-local hit
    rate is currently 0 % (3 separate friction points documented
    in doc/architecture/compile-time.md § "ccache — honesty notes");
    stays neutral when it doesn't help.  Real payoff on Linux CI
    (g++ + traditional PCH) where 80 %+ hit rates are typical.

(BUILD_TESTING=OFF) Standard CMake gate, now respected end-to-end.
    Wrapped both `add_subdirectory(tests)` AND the FetchContent of
    GoogleTest in `if(BUILD_TESTING)`.  Pass `-DBUILD_TESTING=OFF`:
      * Configure ≈ 1 s
      * Build ≈ 0 s
      * 0 object files
      * No GTest fetch
    Use case: IDE-syntax-check workflow that needs
    `compile_commands.json` but does NOT need to download GTest
    or build any test binary.

doc/architecture/compile-time.md gains:
  * a "Workflow modes — what to choose when" section with a 4-row
    switch matrix and a "mode matrix at a glance" comparison table
  * a ccache honesty-notes block listing the three macOS friction
    points (PCH artefact caching, Unity Build path randomisation,
    CMake launcher integration) — Linux CI is where the lever pays
    off

Verified: default build 53 s wall, 236/236 tests pass; all opt-in
modes tested end-to-end with their expected workflow numbers
documented in the doc.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:15:09 +02:00
Tarik Moussa
5fbc4bcc7f ci+perf: PCH + Unity Build cut CGAL test build wall-time 30% (78s -> 55s)
Two structural compile-time optimisations on the conformallab_cgal_tests
target, both opt-out-able and verified safe (236/236 tests pass under
every configuration).

(1) Precompiled headers — option CONFORMALLAB_USE_PCH (default ON)
    target_precompile_headers(conformallab_cgal_tests PRIVATE
        <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/Dense> <Eigen/Sparse> <Eigen/SparseCholesky> <Eigen/SparseQR>
        <gtest/gtest.h>
        <vector> <string> <cmath> <complex>
    )
    Absorbs the per-TU CGAL+Eigen template-parse cost (measured at 5.9 s
    per minimal "include <CGAL/Discrete_conformal_map.h>" hello-world TU
    on Apple M1).

(2) Unity Build — UNITY_BUILD ON with UNITY_BUILD_BATCH_SIZE 4
    Concatenates the 22 test TUs into 5 batches of <=4 files each;
    CGAL+Eigen headers parsed once per batch instead of once per TU.
    Batch size 4 keeps gtest's TEST(...) macros and per-file
    `using namespace ...` from colliding across batched files.

Numbers (Apple M1, Ninja, -j8, clean rebuild)
─────────────────────────────────────────────
              wall    CPU    tests
baseline      78 s    676 s  236/236
+ PCH         66 s    474 s  236/236   (-15% wall, -30% CPU)
+ PCH + Unity 55 s    167 s  236/236   (-30% wall, -75% CPU)

Honest deferred items (documented in doc/architecture/compile-time.md):
  * `extern template` (lever #2 in the analysis) — subsumed by PCH;
    estimated residual gain <5%, would add Eigen-version fragility.
  * Header split <CGAL/Discrete_conformal_map_{euclidean,spherical,
    hyper_ideal}.h> (lever #3) — downstream-only benefit (our test
    build needs all three); kept as a future cleanup once a downstream
    user actually requests it.

Opt-outs: `-DCONFORMALLAB_USE_PCH=OFF` and `-DCMAKE_UNITY_BUILD=OFF`.

Detailed measurement methodology, per-TU breakdowns, clang
-ftime-trace template hot-spots, and a "what comes next" lever list
live in doc/architecture/compile-time.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:15:09 +02:00
Tarik Moussa
0c520046fb docs(reviewer): baustein D — close Java-scan + lit-integration gaps
Earlier baustein B (`07c653c`) added a 6-row Research-Alignments table
+ a "what's new" banner, but only surfaced ~75 % of what the four
Java-scan + literature-integration commits (`f854f0e`, `979f30c`,
`e8a118f`, `8daee1b`) had introduced.  This commit closes the gaps
identified in the lückenprüfung:

Research-Alignments table grows from 6 → 10 rows
─────────────────────────────────────────────────
* +quasi-isothermic maps  (Phase 10e, Java port — 6 classes incl.
  discrete Beltrami-field solver, Lawson correspondence ~800 lines)
* +higher-genus + hyperelliptic surfaces (Phase 10b — `HyperellipticUtility`
  + Bobenko–Bücking 2009)
* +Möbius centring as variational problem (Phase 9d.4 — replaces the
  iterative Fréchet-mean fallback in `normalise_hyperbolic()`)
* +Boundary-First / interactive flattening row (Crane 2017 BFF; Stripe
  Patterns 2015) — listed for comparison even though it is not on the
  porting roadmap, so the reader sees we know about it
* table caption clarifies that some rows are RESEARCH-only (no Java
  parent) and some are planned ports

"What's new" banner
───────────────────
* citation count corrected from "+9" to "+13" — the four Tier-2 papers
  added in commit `e8a118f` (Springborn 2019, Springborn–Veselov 2015,
  Crane 2017 BFF, Bonneel et al. 2015 Stripe Patterns) are now named
* phase count of "+6 phases" kept, but +Phase 9d.4 (Möbius centring)
  and +Phase 10e (quasi-isothermic) are now called out explicitly so
  the reader knows what is in the count
* cross-link to `java-parity.md` for the reverse table (every Java
  class → C++ destination or *do-not-port* rationale)

questions.md / Q1
─────────────────
* expand the table from 3 to 6 candidate phases — adding 10e (quasi-
  isothermic), 10b (hyperelliptic), and 9d.4 (Möbius centring) as
  options alongside the existing 9d.2 / 9f / 10c+10c′
* track column distinguishes RESEARCH-only from planned-port
* +Question C — "is there a seventh line we are missing?" — invites
  the reader to flag a research thread we have not scoped yet

Pages hub will be refreshed to v5 in a follow-up step (separate from
the in-repo commit, lives only on the codeberg `pages` branch).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 11:15:09 +02:00