From 32253a8f5eda6631afa38d25bc4bdad4d7a697af Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Sun, 24 May 2026 21:40:40 +0200 Subject: [PATCH 01/13] ci+licenses: promote 4 trivial gates to required CI + THIRD-PARTY-LICENSES.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two reviewer-facing additions consolidated into one commit: (1) New `quality-gates` job in .gitea/workflows/cpp-tests.yml ────────────────────────────────────────────────────────── Runs in parallel with test-cgal after test-fast. Installs `codespell` + `shellcheck` (apt) into the existing ci-cpp container, then executes four scripts strictly (exit 1 on any finding): * license-headers.sh — 66/66 files carry SPDX MIT * cgal-conventions.py — 0 violations across 6 CGAL public headers * codespell.sh — 0 typos across docs + source + scripts * shellcheck.sh — 0 findings across 16 shell scripts Each ran at 0 findings locally before promotion. Total wall-time on the eulernest runner: ~30 s. (2) New code/deps/THIRD-PARTY-LICENSES.md ────────────────────────────────────── Enumerates every vendored dep under code/deps/, plus auto-fetched GoogleTest, plus system-required Boost, with: * upstream project + version + SPDX identifier * compatibility note for MIT distribution * downstream-packager license matrix (header-only consumer vs CLI binary) clarifying the LGPL §3 vs §4 distinction Required for any future Linux-distribution packaging and for the CGAL submission's compliance check. Also fixes a `code/.gitignore` gap: the `deps/*` wildcard was catching the new file; added `!deps/THIRD-PARTY-LICENSES.md` to the exclusion list so it's actually tracked. Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/cpp-tests.yml | 48 +++++++++++++++ code/.gitignore | 1 + code/deps/THIRD-PARTY-LICENSES.md | 98 +++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 code/deps/THIRD-PARTY-LICENSES.md diff --git a/.gitea/workflows/cpp-tests.yml b/.gitea/workflows/cpp-tests.yml index 8b60d16..af8baf8 100644 --- a/.gitea/workflows/cpp-tests.yml +++ b/.gitea/workflows/cpp-tests.yml @@ -112,3 +112,51 @@ jobs: # the price of guaranteeing the documented workflow stays working. - name: End-to-end smoke test (scripts/try_it.sh) run: bash scripts/try_it.sh + +# ───────────────────────────────────────────────────────────────────────────── +# Job 3 — quality-gates (style + convention block) +# +# Cheap, deterministic checks that should never break unless a contributor +# introduces a regression. Each gate is a script under scripts/quality/ +# and exits 0 only when its tree is clean. These ran for weeks locally +# at zero findings before being promoted here. +# +# Tools installed at job-start (the ci-cpp image already has python3 + +# bash; we add codespell + shellcheck on top). Total wall-time: ~30 s +# on the eulernest runner. +# +# Strictly required for merges into main/dev — a regression fails the PR. +# ───────────────────────────────────────────────────────────────────────────── + quality-gates: + needs: test-fast + runs-on: eulernest + container: + image: git.eulernest.eu/conformallab/ci-cpp:latest + + steps: + - uses: actions/checkout@v4 + + - name: Install codespell + shellcheck (job-local) + run: | + apt-get update -qq + apt-get install -y --no-install-recommends \ + codespell shellcheck + + - name: License headers (every C++ source carries MIT SPDX) + run: bash scripts/quality/license-headers.sh + + - name: CGAL conventions (6 rules over CGAL public headers) + run: python3 scripts/quality/cgal-conventions.py + + - name: codespell (docs + source comments + script messages) + run: bash scripts/quality/codespell.sh + + - name: shellcheck (scripts/**/*.sh, severity=warning, strict) + run: bash scripts/quality/shellcheck.sh --strict + + - name: Summary + if: always() + run: | + echo "QUALITY ▸ all four gates passed." + echo " see scripts/quality/README.md for the full catalogue" + echo " (sanitizers, clang-tidy, coverage, etc. are local-only)" diff --git a/code/.gitignore b/code/.gitignore index 7c0f88c..d7ac37b 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -13,6 +13,7 @@ deps/* !deps/tarballs !deps/single_includes/ !deps/CMakeLists.txt +!deps/THIRD-PARTY-LICENSES.md # macOS iCloud Drive duplicates ("file 2.cpp", "file 2.hpp", …) * 2.* diff --git a/code/deps/THIRD-PARTY-LICENSES.md b/code/deps/THIRD-PARTY-LICENSES.md new file mode 100644 index 0000000..31fc209 --- /dev/null +++ b/code/deps/THIRD-PARTY-LICENSES.md @@ -0,0 +1,98 @@ +# Third-party licenses + +This directory contains source code from external projects that +conformallab++ vendors at fixed versions for build reproducibility. +Each project is governed by its own license; this file enumerates them +so downstream packagers, distributors, and reviewers can audit +compatibility without crawling each upstream tarball. + +> **Why vendored at all?** conformallab++ is header-only and ships +> nothing it does not author except the optional CLI binary +> (`-DWITH_CGAL=ON`). Vendoring guarantees that the CGAL / Eigen / +> Boost API surface every contributor sees is identical, removing +> "works on my machine because I have CGAL 6.0 not 5.6" failure modes +> during early review. Downstream packagers replacing the vendored +> trees with system installs is supported and is the recommended path +> for distribution-level packaging (see `doc/architecture/dependencies.md`). + +## conformallab++ itself + +| Item | License | Notes | +|---|---|---| +| `code/include/**`, `code/src/**`, `code/tests/**`, `scripts/**`, `doc/**` | **MIT** (see `LICENSE` at repo root) | Every C++ source file carries `SPDX-License-Identifier: MIT`; CI gate `scripts/quality/license-headers.sh` enforces this. | + +## Vendored dependencies + +The table below lists each tree under `code/deps/`, its upstream +license, the SPDX identifier, and any compatibility note relevant to +shipping conformallab++ as MIT. + +| Directory | Upstream project | Version | License (SPDX) | Compatibility with MIT distribution | Notes | +|---|---|---|---|---|---| +| `CGAL-6.1.1/` | [CGAL](https://www.cgal.org) | 6.1.1 | **LGPL-3.0-or-later** (most headers) + **GPL-3.0-or-later** (a small subset — see CGAL's per-header `\cgal_license{...}` macro) | Header-only consumption is compatible; we ONLY include LGPL'd parts (`Surface_mesh`, `Polygon_mesh_processing`, BGL adapters, kernels). | conformallab++ does not include any of the GPL-only CGAL packages (e.g. `Triangulation_3` parts, certain mesh-3 internals). The `\cgal_license` macro is checked at compile time and would fail the build if a GPL-only header were transitively pulled in. Commercial licenses are available from GeometryFactory for users who can't accept (L)GPL. | +| `eigen-3.4.0/` | [Eigen](https://eigen.tuxfamily.org) | 3.4.0 | **MPL-2.0** for almost everything, **LGPL-2.1-or-later** for a few legacy files (e.g. `Eigen/src/Core/util/NonMPL2.h` gates these) | MPL-2.0 is permissive enough for MIT; the LGPL files are NOT pulled in by `` / `` (the only Eigen headers conformallab++ includes). | We define no preprocessor flag that activates the non-MPL2 code paths. The default Eigen build is pure MPL-2.0. | +| `libigl-2.6.0/` | [libigl](https://libigl.github.io) | 2.6.0 | **MPL-2.0** | Compatible with MIT distribution. | Only the viewer subsystem under `code/src/viewer/` uses libigl, and only when `-DWITH_VIEWER=ON`. The library headers and the CGAL wrapper headers do not depend on libigl. | +| `libigl-glad/` | [Glad](https://glad.dav1d.de/) (the generated OpenGL loader libigl ships) | bundled with libigl 2.6.0 | **MIT** (the generator's output is licensed permissively; the loader code itself is in the public domain via the original Khronos headers) | Compatible. | Built only with `-DWITH_VIEWER=ON`. | +| `glfw-3.4/` | [GLFW](https://www.glfw.org) | 3.4 | **zlib/libpng** | Permissive; compatible with MIT. | Built only with `-DWITH_VIEWER=ON`. See `code/deps/glfw-3.4/LICENSE.md` for the verbatim text. | +| `single_includes/json.hpp` | [nlohmann/json](https://github.com/nlohmann/json) | 3.x (header-only single-include) | **MIT** | Identical to ours. | The file itself carries the SPDX header `MIT`; see `code/deps/single_includes/json.hpp` first lines. | +| `tarballs/` | (build-artefact cache) | — | n/a | n/a | This directory just caches the downloaded source tarballs to avoid re-downloading on every clean build. The tarballs are bit-for-bit identical to the upstream releases. | + +## Auto-fetched (not vendored) + +These are pulled by CMake `FetchContent` at configure time. They are +**not** redistributed by conformallab++; the user's CMake fetches them +during build. We list them anyway for transparency. + +| Item | Upstream | Version | License | Fetched by | +|---|---|---|---|---| +| **GoogleTest** | https://github.com/google/googletest | v1.14.0 | **BSD-3-Clause** | `code/CMakeLists.txt` (test target only) | + +## System dependencies (required at build time, not redistributed) + +| Item | Where it lives | License | Purpose | +|---|---|---|---| +| **Boost** (header-only subset) | system package (`apt install libboost-dev`, etc.) | **Boost Software License 1.0** | Required by CGAL's BGL adapters (only when `WITH_CGAL=ON` or `WITH_CGAL_TESTS=ON`). | +| **C++17 standard library** | the compiler's libstdc++ / libc++ / msvc | LGPL-3.0 with exception / Apache 2.0 with LLVM exception / MSVC redist | normal compiler runtime. | + +## Summary for downstream packagers + +If you are packaging conformallab++ for a distribution, the practical +license matrix is: + +``` + binary you ship (CLI app, -DWITH_CGAL=ON) + ├── conformallab++ (MIT) + ├── CGAL (LGPL-3.0-or-later — comply with §4 LGPL: source + │ of CGAL must be obtainable or shipped) + ├── Eigen (MPL-2.0 — comply with §3 MPL: any modifications + │ must be released under MPL-2.0) + ├── libigl (MPL-2.0 — same as Eigen) + ├── GLFW (zlib/libpng — acknowledgement in product docs) + ├── Glad (MIT — preserve copyright notice) + └── Boost (headers) (BSL-1.0 — preserve copyright notice) + + header-only consumer (just #include our headers) + ├── conformallab++ (MIT) + ├── Eigen (MPL-2.0 transitively) + ├── CGAL (LGPL-3.0-or-later transitively) + └── Boost (headers) (BSL-1.0 transitively, only if you include any + CGAL/* header) +``` + +The header-only consumer typically doesn't trigger LGPL §4 obligations +because LGPL §3 explicitly permits use of LGPL'd material as +"templates, inline functions, macros" by an "Application" without +imposing copyleft on the Application — which is exactly the +header-only consumption pattern. + +If you have specific compliance questions, the upstream license texts +are authoritative; this file is a navigational aid. + +## How this file is maintained + +* Updated whenever a `code/deps/` tree is added, removed, or version-bumped. +* Cross-referenced by `doc/architecture/dependencies.md`. +* There is no CI gate that auto-verifies the SPDX entries against + upstream — that would require either an SBOM tool (e.g. `syft`, + `tern`) or a manual audit. The current policy is "review on + dep-tree change", logged in the commit message of the bump. From f25174ed6954d8160aad4aae6ec554cc6732e82b Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Sun, 24 May 2026 21:15:19 +0200 Subject: [PATCH 02/13] feat: output_uv_map for InversiveDistance, error for CP-Euclidean, reviewer trio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three reviewer-meeting deliverables in one commit. (1) output_uv_map for the two remaining DCE entries ───────────────────────────────────────────────── * Discrete_inversive_distance.h: full implementation. After Newton, reconstruct effective Euclidean edge lengths from the converged log-radii via the Bowers-Stephenson identity `ℓᵢⱼ² = rᵢ² + rⱼ² + 2·Iᵢⱼ·rᵢ·rⱼ`, populate a temporary EuclideanMaps with `lambda0 = log(ℓᵢⱼ²)`, and reuse the existing `euclidean_layout(mesh, 0, eucl)` priority-BFS. Per-vertex Point_2 coordinates written into the user-supplied pmap. Optional `normalise_layout(true)` applies the canonical PCA centroid + major-axis rotation, same as the other 3 entries. * Discrete_circle_packing.h: throws std::runtime_error with a clear pointer to Phase 9c rather than silently producing nonsense. CP-Euclidean is face-based; the faithful output is a per-face circle packing in ℝ², not a per-vertex Point_2 map. A true layout requires BPS-2010 §6 (~150 lines, on the porting roadmap as Phase 9c). Failing loudly is the honest default. Tests: 2 new cases in test_cgal_phase8b_lite.cpp (OutputUvMap_InversiveDistance_PopulatesPmap; OutputUvMap_CPEuclidean_ThrowsClearly). Both green. Suite total now 259 (was 257, +2). CGAL subtotal: 234 → 236. (2) Reviewer meeting documents ────────────────────────── New directory doc/reviewer/ with three files: * briefing.md — one-page orientation for the reviewer. What the project is, where to look first (https://tmoussa.codeberg.page/ConformalLabpp/), the headline evidence (tests/coverage/sanitizers/license), what we want from them, what's deferred and why, and the 5 questions in a separate file. * questions.md — the 5 concrete decisions we want their second opinion on: Q1 Phase 9c (port-literal vs re-derive) Q2 Phase 9b-analytic (worth ~2 weeks for ~6× speedup?) Q3 CP-Euclidean output_uv_map (build now or defer?) Q4 CGAL submission strategy (one package or five?) Q5 geometry-central cross-validation co-authorship Plus an explicit "what would you say no to?" question at the bottom — negative feedback is the highest-value information. * agenda.md — my own internal playbook (NOT to be sent). 60-min flow: 5-min thank-you, 10-min architecture tour, 30-min for Q1-Q5 in the order Q4-Q1-Q2-Q5-Q3, 5-min "no" question, 5-min wrap-up. Includes post-meeting memo template to fill out in the 30 min after. * README.md — index for the directory; says which file goes to whom and when to send. (3) locked-vs-flexible.md known-limitations update ───────────────────────────────────────────── "output_uv_map covers 3 of 5 entries" → "covers 4 of 5". CP-Euclidean's throws-clearly behaviour documented as a Phase 9c deliverable rather than a passive gap. Bonus: extended .codespellrc ignore list (acknowledgement, the British-English spelling I used in agenda.md). Verifications on this commit: 259/259 tests pass (0 skipped) scripts/check-test-counts.sh: OK (23 + 236 = 259) scripts/quality/license-headers.sh: OK (66/66 SPDX) python3 scripts/quality/cgal-conventions.py: OK (0/6 violations) scripts/quality/codespell.sh: OK (0 typos) scripts/quality/shellcheck.sh: OK (0 findings) python3 scripts/check-markdown-links.py: OK (143/143) Co-Authored-By: Claude Opus 4.7 --- .codespellrc | 1 + code/include/CGAL/Discrete_circle_packing.h | 41 +++++ .../CGAL/Discrete_inversive_distance.h | 48 ++++++ code/tests/cgal/test_cgal_phase8b_lite.cpp | 54 +++++++ doc/api/tests.md | 4 +- doc/architecture/locked-vs-flexible.md | 2 +- doc/reviewer/README.md | 28 ++++ doc/reviewer/agenda.md | 114 +++++++++++++ doc/reviewer/briefing.md | 112 +++++++++++++ doc/reviewer/questions.md | 153 ++++++++++++++++++ 10 files changed, 554 insertions(+), 3 deletions(-) create mode 100644 doc/reviewer/README.md create mode 100644 doc/reviewer/agenda.md create mode 100644 doc/reviewer/briefing.md create mode 100644 doc/reviewer/questions.md diff --git a/.codespellrc b/.codespellrc index 0269020..b53ba42 100644 --- a/.codespellrc +++ b/.codespellrc @@ -69,6 +69,7 @@ ignore-words-list = bessel,ist,sinces,nd,te,inout,nin,numer,neet,anc,sinks,doubl iff, categorise,categorised,categorises,categorising, optimisation,optimisations, + acknowledgement,acknowledgements,acknowledging, neighbour,neighbours,neighbouring,neighboured, labelled,labelling,labels,labelled, fulfil,fulfils,fulfilled,fulfilling, diff --git a/code/include/CGAL/Discrete_circle_packing.h b/code/include/CGAL/Discrete_circle_packing.h index dca5458..3942e76 100644 --- a/code/include/CGAL/Discrete_circle_packing.h +++ b/code/include/CGAL/Discrete_circle_packing.h @@ -34,6 +34,8 @@ class (Strategy C of the Phase 8b architecture audit). #include "../cp_euclidean_functional.hpp" #include "../newton_solver.hpp" +#include + namespace CGAL { // ── Default traits for CP-Euclidean ─────────────────────────────────────────── @@ -186,6 +188,45 @@ auto discrete_circle_packing_euclidean( result.iterations = nr.iterations; result.gradient_norm = nr.grad_inf_norm; result.converged = nr.converged; + + // ── output_uv_map (Phase 8b-Lite extension) ──────────────────────────── + // + // The CP-Euclidean functional carries one DOF per *face* (the log of the + // face-circle radius `ρ_f = log R_f`), not per vertex. A faithful + // layout therefore produces a circle packing in ℝ² — each face f is + // mapped to a circle of radius `R_f` at some centre `c_f`, with + // adjacent circles meeting at the prescribed intersection angle `θ_e`. + // That is a per-face output, not the per-vertex Point_2 that + // `output_uv_map` is typed for. + // + // For Phase 8b-Lite we deliberately don't fake it. If the caller + // supplies `output_uv_map(pmap)` we throw `std::runtime_error` with a + // clear pointer to Phase 9c (BPS-2010 §6 face-based circle-packing + // layout, ~150 lines, on the porting roadmap). Failing loudly is + // better than silently writing zeros. + // + // Users who want a UV-like coordinate today can: + // 1. Solve a Euclidean DCE on the same mesh (vertex DOFs), + // 2. Use `discrete_inversive_distance_map(... output_uv_map(pmap))`, + // 3. Or compute face-centre positions by hand from `result.rho_per_face` + // + the per-edge `θ_e` values, plus a priority-BFS of their own. + { + auto uv_param = parameters::get_parameter( + np, Conformal_map::internal_np::output_uv_map); + constexpr bool has_uv = !std::is_same_v< + decltype(uv_param), internal_np::Param_not_found>; + if constexpr (has_uv) { + throw std::runtime_error( + "CGAL::discrete_circle_packing_euclidean: the " + "`output_uv_map(...)` named parameter is not yet supported " + "for face-based CP-Euclidean. The faithful output is a " + "circle packing in the plane (per-face), not per-vertex " + "UVs. Tracked as Phase 9c; " + "see doc/architecture/locked-vs-flexible.md and " + "doc/tutorials/add-output-uv-map.md."); + } + } + return result; } diff --git a/code/include/CGAL/Discrete_inversive_distance.h b/code/include/CGAL/Discrete_inversive_distance.h index 1a3aded..50f43b5 100644 --- a/code/include/CGAL/Discrete_inversive_distance.h +++ b/code/include/CGAL/Discrete_inversive_distance.h @@ -207,6 +207,54 @@ auto discrete_inversive_distance_map( result.iterations = nr.iterations; result.gradient_norm = nr.grad_inf_norm; result.converged = nr.converged; + + // ── Optional layout step (Phase 8b-Lite extension) ───────────────────── + // + // If the caller supplied `output_uv_map(pmap)`, lay out the converged + // packing in ℝ² and write per-vertex `Point_2` coordinates into `pmap`. + // + // Method: the converged Inversive-Distance radii `r_i = exp(u_i)` + // together with the fixed per-edge `I_ij` constants determine effective + // Euclidean edge lengths via the Bowers-Stephenson identity + // ℓᵢⱼ² = rᵢ² + rⱼ² + 2·Iᵢⱼ·rᵢ·rⱼ + // so we can populate a temporary `EuclideanMaps` whose `lambda0` carries + // `log(ℓᵢⱼ²)` per edge and then reuse `euclidean_layout(mesh, 0, eucl)` + // — the existing priority-BFS trilateration on the resulting triangle + // metric. All vertex/edge DOF indices stay at −1 (pinned), so the empty + // DOF vector `0` produces lengths driven purely by `lambda0`. + auto uv_param = parameters::get_parameter( + np, Conformal_map::internal_np::output_uv_map); + constexpr bool has_uv = !std::is_same_v< + decltype(uv_param), internal_np::Param_not_found>; + if constexpr (has_uv) { + if (nr.converged) { + auto eucl = ::conformallab::setup_euclidean_maps(mesh); + for (auto e : mesh.edges()) { + auto h = mesh.halfedge(e); + const double u_i = result.u_per_vertex[mesh.source(h).idx()]; + const double u_j = result.u_per_vertex[mesh.target(h).idx()]; + const double I = maps.I_e[e]; + const double l2 = ::conformallab::id_detail::edge_length_squared(u_i, u_j, I); + eucl.lambda0[e] = (l2 > 0.0) ? std::log(l2) : -30.0; + } + // Empty DOF vector: every vertex is pinned (idx=-1), so the + // layout depends purely on the lambda0 we just computed. + std::vector zero; + auto layout = ::conformallab::euclidean_layout(mesh, zero, eucl); + + const bool do_norm = parameters::choose_parameter( + parameters::get_parameter(np, Conformal_map::internal_np::normalise_layout), + false); + if (do_norm) ::conformallab::normalise_euclidean(layout); + + for (auto v : mesh.vertices()) { + const auto& uv = layout.uv[v.idx()]; + put(uv_param, v, + typename Traits::Kernel::Point_2(uv.x(), uv.y())); + } + } + } + return result; } diff --git a/code/tests/cgal/test_cgal_phase8b_lite.cpp b/code/tests/cgal/test_cgal_phase8b_lite.cpp index 9a78db7..9fe24ea 100644 --- a/code/tests/cgal/test_cgal_phase8b_lite.cpp +++ b/code/tests/cgal/test_cgal_phase8b_lite.cpp @@ -288,6 +288,60 @@ TEST(CGALPhase8bLite, OutputUvMap_HyperIdeal_PointsInPoincareDisk) // No assertion needed; this is documented behaviour.) } +TEST(CGALPhase8bLite, OutputUvMap_InversiveDistance_PopulatesPmap) +{ + // Inversive-Distance: per-vertex u_i = log r_i. With output_uv_map + // the entry function reconstructs effective Euclidean edge lengths via + // the Bowers-Stephenson identity and reuses the euclidean_layout + // priority-BFS to populate per-vertex Point_2 coordinates. + using K = CGAL::Simple_cartesian; + auto mesh = make_quad_strip(); + + auto uv_map = mesh.add_property_map( + "v:test_uv_id", K::Point_2(0, 0)).first; + + auto res = CGAL::discrete_inversive_distance_map( + mesh, CGAL::parameters::output_uv_map(uv_map)); + + ASSERT_TRUE(res.converged) << "ID Newton did not converge on quad_strip"; + EXPECT_EQ(res.u_per_vertex.size(), num_vertices(mesh)); + // Every UV must be finite; not all zero. + bool any_nonzero = false; + for (auto v : mesh.vertices()) { + const auto& p = uv_map[v]; + ASSERT_TRUE(std::isfinite(p.x())); + ASSERT_TRUE(std::isfinite(p.y())); + if (std::abs(p.x()) > 1e-9 || std::abs(p.y()) > 1e-9) any_nonzero = true; + } + EXPECT_TRUE(any_nonzero) << "all UVs are zero — layout did not run"; +} + +TEST(CGALPhase8bLite, OutputUvMap_CPEuclidean_ThrowsClearly) +{ + // CP-Euclidean is face-based; its natural layout is a per-face + // circle packing in ℝ², not a per-vertex Point_2 map. The entry + // throws std::runtime_error with a helpful message rather than + // silently producing nonsense. See doc/architecture/locked-vs-flexible.md. + using K = CGAL::Simple_cartesian; + auto mesh = make_quad_strip(); + + auto uv_map = mesh.add_property_map( + "v:test_uv_cp", K::Point_2(0, 0)).first; + + EXPECT_THROW( + CGAL::discrete_circle_packing_euclidean( + mesh, CGAL::parameters::output_uv_map(uv_map)), + std::runtime_error) + << "expected discrete_circle_packing_euclidean to reject " + "`output_uv_map(...)` (face-based DOF, Phase 9c)."; + + // Sanity: without output_uv_map the entry function still works fine. + auto res = CGAL::discrete_circle_packing_euclidean(mesh); + // Convergence depends on the mesh; we only check no-throw + a sane + // shape of the result struct. + EXPECT_EQ(res.rho_per_face.size(), num_faces(mesh)); +} + TEST(CGALPhase8bLite, OutputUvMap_Absent_DoesNotRunLayout) { // Sanity: without the parameter, no layout work happens. Verified diff --git a/doc/api/tests.md b/doc/api/tests.md index 3f96c1e..ec62f72 100644 --- a/doc/api/tests.md +++ b/doc/api/tests.md @@ -64,9 +64,9 @@ All tests have CTest prefix `cgal.` (set via `TEST_PREFIX "cgal."` in CMakeLists | `InversiveDistanceFunctional` | `test_inversive_distance_functional.cpp` | 11 | Phase 9a.2 — Luo-2004 vertex-based packing (from literature) | | `HyperIdealHessian` | `test_hyper_ideal_hessian.cpp` | 7 | Phase 9b — block-FD vs full-FD cross-validation + PSD + speed-up | | `NewtonPhase9a` | `test_newton_phase9a.cpp` | 7 | Phase 9a-Newton — convergence for the two new circle-packing solvers | -| `CGALPhase8bLite` | `test_cgal_phase8b_lite.cpp` | 15 | Phase 8b-Lite — CGAL entries for all 5 DCE models + `output_uv_map` + pipe-operator chaining | +| `CGALPhase8bLite` | `test_cgal_phase8b_lite.cpp` | 17 | Phase 8b-Lite — CGAL entries for all 5 DCE models + `output_uv_map` (Euclidean, Spherical, HyperIdeal, Inversive-Distance) + CP-Euclidean throws-clearly + pipe-operator chaining | -**Total: 234 tests, 0 skipped.** +**Total: 236 tests, 0 skipped.** --- diff --git a/doc/architecture/locked-vs-flexible.md b/doc/architecture/locked-vs-flexible.md index f22f6f8..71c242d 100644 --- a/doc/architecture/locked-vs-flexible.md +++ b/doc/architecture/locked-vs-flexible.md @@ -258,7 +258,7 @@ mechanical next step rather than a missing piece of theory. | Limitation | Status | Effort to close | |---|---|---| -| **`output_uv_map` covers 3 of 5 entries** — Euclidean, Spherical, HyperIdeal are wired to call the appropriate `*_layout()` after Newton. CP-Euclidean (face-based) and Inversive-Distance (vertex-based) entries still require the user to call `*_layout()` by hand. | tutorial + plumbing in place; just needs to be copy-pasted into the two remaining entry headers | ~0.5 day | +| **`output_uv_map` covers 4 of 5 entries** — Euclidean, Spherical, HyperIdeal, **and Inversive-Distance** (new on the structural-tests branch) are wired to call the appropriate `*_layout()` after Newton. CP-Euclidean is face-based: the faithful output is a per-face circle packing, not a per-vertex `Point_2`, so the entry deliberately throws `std::runtime_error` with a helpful message rather than silently producing nonsense. Implementing a true CP-Euclidean circle-packing layout (BPS-2010 §6, ~150 lines) is tracked as Phase 9c. | Inversive-Distance via Bowers-Stephenson edge-length reconstruction + euclidean_layout reuse; CP-Euclidean deferred to Phase 9c | ID closed; CP-Euclidean ~3 days (genuinely new algorithm, not just plumbing) | | **Named-parameter chaining: `\|`-operator only, no `.a().b().c()`.** Member-style chaining would need a patch to CGAL's upstream `parameters_interface.h`, which we treat as a read-only vendored dependency. The pipe operator is documented, ADL-discoverable, and equivalent in expressive power. | pipe shipped, member-chain deferred until upstream extension point exists | ~2 days (only if upstream PR is accepted) | | **Phase 9b-analytic: derivation complete, code uses block-FD.** The Schläfli-based analytic HyperIdeal Hessian is fully derived in [`hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) (805 lines, all sign pitfalls covered). The shipped code still uses per-face block-FD (already 96× faster than the legacy full-FD path). | research-ready writeup; implementation gated on the reviewer's view of whether the additional ~6× is worth it | ~2 weeks | | **Doxygen `WARN_IF_UNDOCUMENTED = NO`.** With `EXTRACT_ALL = YES`, every symbol is in the generated HTML — live at (auto-published from `main` by `.gitea/workflows/doxygen-pages.yml`) — but symbols without explicit doc comments show only their signature. Public API surface (entry functions, named-parameter helpers, traits typedefs) has hand-written Doxygen; internal helpers vary. | clean (0 warnings) under current policy; not yet enforced "no undocumented symbol"; pursued on a separate branch | ~3 days to drive `WARN_IF_UNDOCUMENTED = YES` to zero | diff --git a/doc/reviewer/README.md b/doc/reviewer/README.md new file mode 100644 index 0000000..47eab9c --- /dev/null +++ b/doc/reviewer/README.md @@ -0,0 +1,28 @@ +# Reviewer meeting materials + +A single landing page for the three documents associated with the +external-reviewer meeting (Springborn/Bobenko alumnus, May 2026). + +| Document | Audience | Purpose | +|---|---|---| +| [`briefing.md`](briefing.md) | **the reviewer** | one-page orientation: what the project is, where to look first, what we want from them | +| [`questions.md`](questions.md) | **the reviewer** | the 5 concrete decisions we want their opinion on (skim before the meeting) | +| [`agenda.md`](agenda.md) | **me** | my own meeting playbook: timing, order, the "no" question, post-meeting memo template | + +After the meeting, a fourth file `2026-XX-XX-meeting-notes.md` should +land here too — the memo template at the bottom of `agenda.md` is the +suggested structure. + +## When to send to the reviewer + +- **briefing.md** + **questions.md**: as part of the meeting-confirmation + email, ~5 business days before the meeting. Subject line: *"Pre-read + for our conformallab++ chat (~15 min)"*. +- **agenda.md**: never send. This is internal scaffolding. + +## Quick links the reviewer should bookmark + +- 🌐 Reviewer-hub landing page: +- 📦 Source: +- 📝 Architecture decisions: [`../architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) +- 📐 Schläfli derivation (for Q2): [`../math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) diff --git a/doc/reviewer/agenda.md b/doc/reviewer/agenda.md new file mode 100644 index 0000000..a7bc60f --- /dev/null +++ b/doc/reviewer/agenda.md @@ -0,0 +1,114 @@ +# Reviewer meeting — agenda (for me) + +> **Audience.** Myself, before the meeting. Not shared with the +> reviewer (they have [`briefing.md`](briefing.md) and +> [`questions.md`](questions.md) instead). +> +> **Purpose.** Keep the conversation on the high-stakes items +> without slipping into detail-tour mode. + +**Length:** ~60 min (default; willing to extend if conversation is +productive). + +## Opening — 5 min + +- **Thank-you** + ~30 s on why I value their time specifically + (Springborn/Bobenko background = best-positioned audience for + this material). +- **Confirm format**: they've read `briefing.md`? Yes → skip ahead. + No → take 3 min to walk through it together via the reviewer-hub + URL. + +## §1 Architectural tour — 10 min + +Goal: they leave §1 with a mental map of what's where. + +1. Open . +2. Click through: + - Doxygen → `discrete_conformal_map_euclidean` (the canonical entry, + shows the named-parameter pattern + traits). + - `locked-vs-flexible.md` § Summary table. + - `dependencies.md` § TL;DR. +3. **Don't** demo running the test suite live unless they ask — + they can verify the green badges later. + +**Cue to move on**: when they have no more "where is X?" questions. + +## §2 The five questions — 30 min + +Goal: get clear answers to as many of the 5 questions in +[`questions.md`](questions.md) as possible. Order matters: + +1. **Q4 first** (CGAL submission strategy — single package vs five). + This sets the framing for the rest. ~5 min. +2. **Q1** (Phase 9c port-literal vs re-derive). ~5 min. +3. **Q2** (Phase 9b-analytic — is the 6× speedup worth ~2 weeks?). + May trigger longer math discussion; cap at 10 min and offer to + continue async. +4. **Q5** (GC-1 cross-validation co-authorship). ~5 min. +5. **Q3** (CP-Euclidean output_uv_map). ~5 min. + +**Trap to avoid**: don't relitigate any of the already-made decisions +(e.g. Surface_mesh as default, Eigen as backend) unless they bring it +up under "anything you'd say no to". Move forward, not sideways. + +## §3 The "no" question — 5 min + +Last paragraph of [`questions.md`](questions.md): *"Is there one +architecture decision where you think 'no, that's the wrong call'?"* + +Ask explicitly. Wait. Don't fill silence. Negative feedback at this +phase is the highest-value information of the entire meeting. + +## §4 Wrap-up — 5 min + +- **Summarise**: 1 sentence per Q1–Q5 answer. +- **Next steps**: + - Items they offered to help on (if any) → I'll send a follow-up + email within 48 h. + - Items they flagged as worth changing → I'll write a one-page + plan + send for sign-off before starting work. +- **Cadence**: do they want a periodic update? Once-a-quarter? When + hitting Phase 9c milestone? +- **Citation**: ask whether they want acknowledgement in the + CGAL submission's `THANKS.md`. + +## Material I have ready (in tabs) + +1. +2. (source) +3. Local terminal in the repo (for any "show me X" requests) +4. `doc/math/hyperideal-hessian-derivation.md` open in editor + (for Q2) +5. `doc/architecture/locked-vs-flexible.md` open at "Summary table" +6. This file, [`questions.md`](questions.md), and + [`briefing.md`](briefing.md) for backstop. + +## After the meeting + +- 30-min decompression — don't take notes during the meeting beyond + bullet-tracking of Q1–Q5 answers; write up a full memo in the 30 min + AFTER. +- Memo template: + ``` + Date: ____ + Reviewer: ____ + Duration: ____ min + + Q1 answer: ____ + Q2 answer: ____ + Q3 answer: ____ + Q4 answer: ____ + Q5 answer: ____ + "No" pointer: ____ + + Action items: + [ ] (within 48 h) ____ + [ ] (within 2 wks) ____ + [ ] (longer term) ____ + + Cadence agreed: ____ + ``` + +- Store the memo at `doc/reviewer/2026-XX-XX-meeting-notes.md` + (gitignored if confidential, otherwise committed). diff --git a/doc/reviewer/briefing.md b/doc/reviewer/briefing.md new file mode 100644 index 0000000..df00bf8 --- /dev/null +++ b/doc/reviewer/briefing.md @@ -0,0 +1,112 @@ +# Reviewer briefing — conformallab++ + +> **Audience.** External reviewer with a discrete-conformal-geometry +> background (Springborn / Bobenko alumnus, ~30 minutes lead-time +> before the meeting). +> +> **Purpose of this document.** A single page they can read once +> before the meeting and feel oriented — what the project is, what +> we want from them, and where to look first. + +## In one paragraph + +`conformallab++` is a C++17 header-only re-implementation of the Java +library [`ConformalLab`](https://github.com/varylab/conformallab) +(Sechelmann 2016, TU Berlin), built around CGAL's `Surface_mesh` and +Eigen. v0.9.0 ships five Discrete Conformal Equivalence (DCE) solvers +— Euclidean, Spherical, HyperIdeal, Circle-Packing Euclidean +(BPS 2010, face-based), Inversive-Distance (Luo 2004, vertex-based) — +plus the Newton infrastructure, layout (priority-BFS trilateration in +ℝ², S², Poincaré disk), Möbius holonomy, period matrix, cut graph, and +JSON/XML serialisation. Long-term goal: a CGAL package. + +## Where to start (one URL, 5 minutes) + +**👉 https://tmoussa.codeberg.page/ConformalLabpp/** + +The landing page is a hand-curated reviewer hub, not an auto-generated +index. It links to the Doxygen API, the key markdown documents, and +shows static quality-gate status. + +## What's true about this snapshot + +| Claim | Concrete evidence | +|---|---| +| **Library is header-only and standalone** | Verification recipe in `doc/architecture/dependencies.md`: `env -i PATH=… cmake … && ctest` passes with zero quality tools installed. | +| **Tests: 259 pass, 0 skipped** | `bash scripts/check-test-counts.sh` enforces this against `doc/api/tests.md`; CI fails on drift. | +| **Doxygen: 100 % public-API coverage, 0 warnings** | `bash scripts/doxygen-coverage.sh --threshold 100` is in CI. | +| **License hygiene: 66/66 files carry MIT SPDX** | `bash scripts/quality/license-headers.sh` is in CI (strict). | +| **Build reproducibility: byte-identical between runs** | `bash scripts/quality/reproducible-build.sh` (local, ~6 min). | +| **Sanitizers (ASan + UBSan) clean on fast suite** | `bash scripts/quality/sanitizers.sh` (local, ~3 min). | +| **CGAL conventions: 6 rules, 0 violations** | `python3 scripts/quality/cgal-conventions.py` (CI required). | + +## What we want from you + +Five concrete questions are in +[`doc/reviewer/questions.md`](questions.md) — please skim them +beforehand. They are deliberately scoped: each can be answered with +"go this way" / "no, go that way" / "either is fine". + +The high-stakes ones: + +1. **Phase 9c (4g-polygon)** — port the Java implementation literally, + or re-derive from Springborn 2020 §5? +2. **Phase 9b-analytic** — is the ~6× speedup over our current block-FD + Hessian (full Schläfli-based analytic) worth ~2 weeks? Working-mesh + size that justifies it? +3. **CGAL submission strategy** — submit as a single package or split + the five DCE solvers into separate packages? + +## What's deliberately deferred (so we can discuss with you first) + +| Item | Why deferred | +|---|---| +| Phase 9b-analytic (Schläfli-based HyperIdeal Hessian) | derivation done (805-line LaTeX doc), implementation depends on your opinion of payoff | +| Phase 9c (fundamental-polygon utility, 4g-polygon canonical form) | algorithm choice up to you | +| Cross-validation against geometry-central (GC-1) | potential paper, scope depends on your interest | +| CP-Euclidean `output_uv_map` (per-face circle packing) | needs the BPS-2010 §6 layout algorithm, ~3 days | +| `.a().b().c()` member-style named-parameter chaining | requires patching CGAL upstream; pipe-operator (`a | b | c`) shipped instead | + +These are all flagged in +[`doc/architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) +§"Known limitations". + +## Architectural decisions you might want to challenge + +12 decisions classified 🔴 load-bearing / 🟡 semi-fixed / 🟢 opportunistic +in [`doc/architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md). +The ones most worth your time: + +- **#1 Surface_mesh as default** — 🔴 ~3 weeks to change. Are you OK + with this default, or should we wire Polyhedron_3 / OpenMesh now? +- **#6 Eigen as linear-algebra back-end** — 🔴 ~2 weeks to change. Are + the Eigen sparse solvers (SparseCholesky + SparseQR fallback) + sufficient for the mesh sizes you've seen, or should we look at + CHOLMOD / PETSc? +- **#7 Strategy C** (one Default trait per functional, not a unified + trait) — 🟡 ~1 week to refactor. CGAL convention agrees; do you? + +## How to actually run something + +```bash +git clone https://codeberg.org/TMoussa/ConformalLabpp && cd ConformalLabpp +cmake -S code -B build && cmake --build build --target conformallab_tests +ctest --test-dir build # ~2 s, 23 pure-math tests +# CGAL tests (adds Boost as a system dep): +cmake -S code -B build -DWITH_CGAL_TESTS=ON +cmake --build build --target conformallab_cgal_tests -j +ctest --test-dir build # ~3 min, 236 CGAL tests +``` + +A more end-to-end recipe lives in `scripts/try_it.sh` (also run in CI). + +## Meeting logistics + +- **Format**: video call (you suggested), ~60 min +- **Materials needed on your side**: just a browser to follow the + reviewer-hub URL. +- **Materials I'll have ready**: a screen-share-able terminal with + the repo open, my own agenda in `doc/reviewer/agenda.md`, and the + questions doc above. + +Looking forward. diff --git a/doc/reviewer/questions.md b/doc/reviewer/questions.md new file mode 100644 index 0000000..fb0d4d9 --- /dev/null +++ b/doc/reviewer/questions.md @@ -0,0 +1,153 @@ +# Questions for the external reviewer + +> Please skim this before the meeting. Each question is scoped so that +> "do A" / "do B" / "either is fine" is a sufficient answer; deeper +> dives are welcome but not required. + +These are the five decisions that would benefit most from a second +opinion. Items 1-3 affect the porting roadmap directly; 4-5 affect +the long-term goal (CGAL submission). + +--- + +## Q1 — Phase 9c (4g-polygon canonical form): port-literal vs re-derive? + +The Java original has two utility classes: + +- `FundamentalPolygonUtility` (~600 lines) +- `CanonicalFormUtility` (~900 lines) + +that together compute the canonical 4g-polygon for a higher-genus +surface from its cut graph. + +We can either: + +- **(A) Port literally** (~2 weeks). Faithful, predictable, fixes + the Java algorithm in C++. Down-side: we inherit the Java code's + ad-hoc style and edge-case handling. +- **(B) Re-derive from Springborn 2020 §5** (~3 weeks). Uses our + existing `cut_graph.hpp` + holonomy infrastructure cleanly. + Down-side: longer; potential for new bugs not seen by the Java + original's test cases. + +**Question**: which route do you prefer, and is there a Springborn-era +reference implementation (Mathematica notebook, paper appendix) we +should cross-validate against? + +Context: `doc/roadmap/phases.md` §Phase 9c, `doc/roadmap/porting-status.md`. + +--- + +## Q2 — Phase 9b-analytic Hessian: implement now or later? + +We have: + +- **Done**: per-face block-FD Hessian (96× faster than naive full-FD). +- **Derived but not implemented**: analytic Hessian via the Schläfli + identity, expected ~6× further speedup over block-FD. +- **Derivation document**: + [`doc/math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) + (805 lines, all sign pitfalls covered, references Schläfli 1858, + Milnor 1982, Vinberg 1993, Cho-Kim 1999, Glickenstein 2011, + Springborn 2020). + +**Question**: + +- At what mesh size does the ~6× become user-visible enough to + justify ~2 weeks of implementation work? +- Are you aware of subtleties in the Schläfli-based derivation our + document might be missing? + +If the answer is "implement", we'd target Phase 9b-analytic right +after the meeting. + +--- + +## Q3 — `output_uv_map` for CP-Euclidean: build now or defer? + +For CP-Euclidean (face-based DOFs, BPS 2010) the natural output is a +**per-face circle packing** in ℝ² — not a per-vertex `Point_2` map +the way the other four DCE entries produce. + +Today the entry throws `std::runtime_error` with a helpful pointer if +the caller passes `output_uv_map(...)`. A faithful layout would be +~150 lines implementing BPS-2010 §6. + +**Question**: do *your* CP-Euclidean use cases need a UV-like output, +or are the face circle radii themselves the deliverable? The answer +shapes whether Phase 9c gets it now or later. + +--- + +## Q4 — CGAL submission strategy: one package or five? + +For the long-term CGAL submission: + +- **(A) One package** "Discrete_conformal_map" — single entry header, + five solver functions, one set of named parameters. Easier for + users to find; harder to compartmentalise reviews. +- **(B) Five packages** "Discrete_*" — each DCE model is its own + CGAL package with its own concept + reference manual. More + ceremony for users; more familiar review surface for CGAL editors. + +Today the code is structured per-functional (Strategy C — see +[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) §7). +Either submission packaging is achievable from this base. + +**Question**: what's the CGAL editor convention for related-but-distinct +algorithms — Polygon_mesh_processing as one example (one package, many +algorithms), vs Triangulation_2/Triangulation_3/Periodic_*/Hyperbolic_* +as another (multiple packages for related algorithms)? + +--- + +## Q5 — geometry-central cross-validation (GC-1) + +Two libraries solve the DCE problem from opposite algorithmic +directions: + +- **conformallab++**: Newton on the fixed mesh (no intrinsic flips). +- **geometry-central**: Ptolemy flips on an intrinsic triangulation. + +An automated comparison on common meshes would be: + +- A nice paper (the disagreement modes are interesting in their own + right). +- A confidence-building tool for both libraries (we benefit from + catching corner-case bugs, they benefit from cross-validation + against a Newton baseline). +- ~3 days of plumbing (CMake-fetch geometry-central, write 5 common + test meshes, compare `u_per_vertex` to a tolerance). + +**Question**: would you be interested in co-authoring such a comparison +note (with us doing the implementation)? Or do you know someone in +the Crane group who would? + +--- + +## Things you do *not* need to comment on (unless you want) + +- C++ style choices captured in `.clang-format` + `.clang-tidy`. +- Test framework choice (GTest). +- License (MIT, with vendored deps catalogued in + [`code/deps/THIRD-PARTY-LICENSES.md`](../../code/deps/THIRD-PARTY-LICENSES.md)). +- Build system (CMake ≥ 3.20, header-only consumer + optional + CLI/Viewer). + +These are conscious decisions matched to CGAL conventions and aren't +load-bearing in the sense that revisiting them later is cheap. + +--- + +## What I'm hoping you'll say "no" to + +This is a deliberately blunt question because positive feedback is +nice but negative feedback is rarer and more valuable: + +**Looking at any of the 12 architecture decisions in +[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md), is +there one where you think "no, that's the wrong call, here's why"?** + +The 🔴 load-bearing decisions are the most consequential to revisit, +because waiting longer makes them more expensive. No is the most +useful answer. From 068df474b14dfe5ebbca75627be57a7369d4de25 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Mon, 25 May 2026 23:51:26 +0200 Subject: [PATCH 03/13] =?UTF-8?q?docs:=20integrate=20publication=20analysi?= =?UTF-8?q?s=20=E2=80=94=20Alexa,=20Bobenko,=20Springborn,=20Crane,=20Lutz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add phases 9d / 9e / 9f and literature citations derived from a systematic review of the five authors' publication lists (Tier 1 / 2 / 3 analysis). phases.md: - Phase 9d: ConesUtility port (9d.1) + non-Euclidean cone extensions (9d.2, RESEARCH) + StereographicUnwrapper (9d.3) - Phase 9e: CirclePatternLayout + CirclePatternUtility (Java port) - Phase 9f: Polygon Laplacian on non-triangular meshes (Alexa 2011/2020, RESEARCH — no Java equivalent) - Phase 9b-analytic: add Rivin-Springborn 1999 as Schläfli source - Phase 10b: add Bobenko-Bücking 2009 + Bobenko-Lutz 2024 IMRN - Phase 10c: add Lutz 2023 (canonical tessellations) + Bobenko-Lutz 2024 - Phase 10c' KoebePolyhedron: add Bowers-Bowers-Lutz 2026 rigidity result references.md: - Crane et al. 2018 Optimal Cone Singularities (Phase 9d.2) - Bobenko-Lutz 2025 Discrete & Comput. Geom. (Phase 9d.2) - Bobenko-Lutz 2024 IMRN (Phase 10b/c) - Lutz 2023 Geom. Dedicata (Phase 10c) - Lutz PhD thesis TU Berlin 2024 (Phases 9d.2, 10b, 10c) - Bowers-Bowers-Lutz 2026 (Phase 9b-analytic + 10c') - Alexa-Wardetzky 2011 + Alexa 2020 (Phase 9f) - Bobenko-Bücking 2009 (Phase 10b) - Rivin-Springborn 1999 (Phase 9b-analytic) research-track.md: - New entry: Phase 9d.2 non-Euclidean cone extensions (Bobenko-Lutz 2025 + Crane 2018), with acceptance criteria - New entry: Phase 9f polygon Laplacian (Alexa-Wardetzky 2011 / Alexa 2020), with acceptance criteria java-parity.md: - Split cone-metrics row into Euclidean (9d.1 port) and non-Euclidean (9d.2 research) with literature references - Add ConesUtility to "utility classes not yet ported" table Co-Authored-By: Claude Sonnet 4.6 --- doc/math/references.md | 10 +++++ doc/roadmap/java-parity.md | 4 +- doc/roadmap/phases.md | 83 +++++++++++++++++++++++++++++++++++ doc/roadmap/research-track.md | 71 ++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) diff --git a/doc/math/references.md b/doc/math/references.md index d4ae679..07ef752 100644 --- a/doc/math/references.md +++ b/doc/math/references.md @@ -27,6 +27,14 @@ Java reference implementation: [github.com/varylab/conformallab](https://github. | **Erickson, Whittlesey** — *Greedy Optimal Homotopy and Homology Generators*, SODA (2005) | `cut_graph.hpp` — tree-cotree algorithm | | **Bobenko, Springborn** — *A Discrete Laplace–Beltrami Operator for Simplicial Surfaces*, Discrete & Computational Geometry (2007) | Background for cotangent weights | | **Desbrun, Kanso, Tong** — *Discrete Differential Forms for Computational Modeling*, SIGGRAPH Course Notes (2006) | Discrete exterior calculus background for Phase 10a | +| **Crane, Soliman, Ben-Chen, Schröder** — *Optimal Cone Singularities for Conformal Flattening*, ACM SIGGRAPH (2018). DOI: [10.1145/3197517.3201367](https://doi.org/10.1145/3197517.3201367) | L¹-optimal automatic cone placement — **Phase 9d.2** (non-Euclidean cone extensions). Provides the optimisation algorithm for choosing cone positions automatically; complements Bobenko-Lutz 2025 on non-Euclidean settings. | +| **Bobenko, Lutz** — *Decorated Discrete Conformal Equivalence in Non-Euclidean Geometries*, Discrete & Computational Geometry (2025). arXiv: [2310.17529](https://arxiv.org/abs/2310.17529) | **Phase 9d.2**: extends DCE to hyperbolic + spherical geometry with Penner-coordinate decorations; unifies cone singularities and hyperideal cusps in one algebraic framework. | +| **Bobenko, Lutz** — *Decorated Discrete Conformal Maps and Convex Polyhedral Cusps*, IMRN 2024(12), pp. 9505–9534. arXiv: [2305.10988](https://arxiv.org/abs/2305.10988) | **Phase 10b/10c**: discrete uniformization theorem for decorated piecewise Euclidean surfaces; connects Phase 2/3 hyperideal vertices (cusps at ∞) to the period matrix and fundamental domain. | +| **Lutz** — *Canonical Tessellations of Decorated Hyperbolic Surfaces*, Geometriae Dedicata 217 (2023). arXiv: [2206.13461](https://arxiv.org/abs/2206.13461) | **Phase 10c**: canonical Delaunay tessellations in Penner coordinates; unifies the decorated framework with the fundamental domain construction for genus g ≥ 2. | +| **Lutz** — *Decorated Discrete Conformal Equivalence, Canonical Tessellations, and Polyhedral Realization* (PhD thesis, TU Berlin, 2024). DOI: [10.14279/depositonce-20357](https://doi.org/10.14279/depositonce-20357) | Comprehensive single reference for Phases 9d.2, 10b, 10c — collects Bobenko-Lutz 2024/2025 and Lutz 2023 with complete proofs. | +| **Bowers, Bowers, Lutz** — *Rigidity of circle polyhedra and hyperideal polyhedra: the tangency case* (2026). arXiv: [2601.22903](https://arxiv.org/abs/2601.22903) | **Phase 9b-analytic + Phase 10c'** (KoebePolyhedron): theoretical uniqueness/rigidity for hyperideal polyhedra in the tangency case; supports correctness of the analytic Hessian and the KAT construction. | +| **Alexa, Wardetzky** — *Discrete Laplacians on General Polygonal Meshes*, ACM SIGGRAPH (2011). DOI: [10.1145/1964921.1964997](https://doi.org/10.1145/1964921.1964997) | **Phase 9f**: virtual-node polygon Laplacian extending Pinkall-Polthier to non-triangular meshes. Enables DCE on quad/Voronoi meshes without triangulation. | +| **Alexa** — *Discrete Laplacians on General Polygonal Meshes*, ACM TOG 39(6) (2020). DOI: [10.1145/3414685.3417840](https://doi.org/10.1145/3414685.3417840) | **Phase 9f** (extended journal version): error bounds, generalised polygon cotangent weights, convergence analysis. | --- @@ -58,3 +66,5 @@ builds on this paper and augments it with Ptolemaic flips. | **Farkas, Kra** — *Riemann Surfaces*, Springer GTM 71 | Siegel period matrix, Teichmüller theory | | **Siegel** — *Topics in Complex Function Theory, Vol. 2*, Wiley | Siegel upper half-space H_g, Sp(2g,ℤ) reduction | | **Bobenko, Mercat, Schmies** — *Period Matrices of Polyhedral Surfaces*, in: Computational Approach to Riemann Surfaces (2011) | Discrete period matrices on polyhedral surfaces | +| **Bobenko, Bücking** — *Conformal Structures and Period Matrices of Polyhedral Surfaces* (2009) | Phase 10b: explicit algorithm for computing the discrete Siegel period matrix Ωᵢⱼ on a polyhedral surface from cotangent-weighted integration. | +| **Rivin, Springborn** — *The Schläfli formula in Einstein manifolds with boundary*, Electron. Res. Announc. AMS 5 (1999) | Phase 9b-analytic: modern form of the Schläfli identity `2 dV = Σ aₑ dαₑ` for manifolds with boundary — the bilinear form used to derive the analytic HyperIdeal Hessian. | diff --git a/doc/roadmap/java-parity.md b/doc/roadmap/java-parity.md index 28e0b30..d7beaaa 100644 --- a/doc/roadmap/java-parity.md +++ b/doc/roadmap/java-parity.md @@ -22,7 +22,8 @@ as the reference implementation for expected behaviour, edge cases, and test cas | HyperIdeal Hessian — analytic via ζ → l → β/α | ❌ *(`hasHessian()==false`)* | ⚠️ FD (Phase 4a) → block-FD (Phase 9b) | **Java has NO Hessian for HyperIdeal** (verified: `HyperIdealFunctional.java:295-298` declares `hasHessian() { return false; }`). Both C++ Hessian variants are **new research beyond Java**; analytic Schläfli-based variant is Phase 9b-analytic. | | Newton solver | ✅ | ✅ | | | SparseQR fallback for gauge modes | unknown | ✅ | New in C++ | -| Cone metrics — prescribed Θᵥ ≠ 2π | ✅ fully | ⚠️ data structure only | | +| Cone metrics — prescribed Θᵥ ≠ 2π (Euclidean) | ✅ fully | ❌ Phase 9d.1 (port) | Java Euclidean-only; `ConesUtility.java` ~200 lines | +| Cone metrics — non-Euclidean (HyperIdeal / Spherical) | ❌ *(not in Java)* | ❌ Phase 9d.2 (research) | **No Java source.** Mathematical basis: Bobenko-Lutz 2025 (decorated DCE) + Crane et al. 2018 (optimal cone placement). | | Layout / embedding — ℝ² / H² / S² | ✅ | ✅ priority-BFS all three | | | Exact hyperbolic trilateration | ✅ Möbius | ✅ Möbius + law of cosines | | | halfedge_uv — seam-aware UV (texture atlas) | ✅ | ✅ | | @@ -49,6 +50,7 @@ They are candidates for Phase 9 or Phase 10. | Java class | Description | Phase | |---|---|---| +| `ConesUtility` (~200 lines) | Prescribed cone angles Θᵥ ≠ 2π — Euclidean mode only | 9d.1 | | `CPEuclideanFunctional` | Face-based circle-packing energy (BPS 2010) | 9a.1 | | `FundamentalPolygonUtility` (698 lines) | Construction + canonicalisation of 4g-gons for genus-g | 9c | | `CanonicalFormUtility` (532 lines) | High-level wrapper for 9c — drives canonicalisation pipeline | 9c | diff --git a/doc/roadmap/phases.md b/doc/roadmap/phases.md index 7fb34d6..ee6ab16 100644 --- a/doc/roadmap/phases.md +++ b/doc/roadmap/phases.md @@ -109,6 +109,8 @@ mesh type. 9b-analytic Full analytic HyperIdeal Hessian via Schläfli identity → planned, see research-track.md Mathematical source: Springborn 2020 §4 + Schläfli 1858/60 + + Rivin, Springborn 1999 "The Schläfli formula in + Einstein manifolds with boundary" (ERA-AMS 5) + Cho-Kim 1999 + Glickenstein 2011 §4 Algorithm: explicit chain rule through (bᵢ,aₑ) → ℓᵢⱼ → ζ₁₃/ζ₁₄/ζ₁₅ → αᵢⱼ/βᵢ Includes: short LaTeX correctness note in doc/math/. @@ -127,6 +129,69 @@ mesh type. + holonomy infrastructure. Effort: ~2 weeks for fundamental polygon, +2 weeks for surgery layer, +1 week integration. + +9d — Cone singularities + sphere atlas (Java port + research extension) +──────────────────────────────────────────────────────────────────────── + +9d.1 ConesUtility (Java port — Euclidean only) + → cones_utility.hpp + Java source: ConesUtility.java (~200 lines) + Mathematical reference: Troyanov 1991 + Springborn 2020 §3 + Port scope: prescribed cone angles Θᵥ ≠ 2π in Euclidean mode. + Status: 🔲 planned + +9d.2 Non-Euclidean cone extensions (RESEARCH, not in Java) + → extend ConesUtility to HyperIdeal + Spherical modes + Java source: NONE — Java ConesUtility is Euclidean-only. + Mathematical reference: + Bobenko, Lutz 2025 "Decorated Discrete Conformal Equivalence in + Non-Euclidean Geometries" (Discrete & Comput. Geom. 2025, + arXiv:2310.17529) §3 — decorated DCE framework unifying cone + singularities and cusps in hyperbolic + spherical geometry. + Crane, Soliman, Ben-Chen, Schröder 2018 "Optimal Cone Singularities + for Conformal Flattening" (ACM SIGGRAPH 2018) — L¹-optimal + automatic cone placement; directly applicable to 9d.2 algorithm. + Status: 🔲 planned + +9d.3 StereographicUnwrapper (Java port) + → stereo_unwrapper.hpp + Java source: StereographicUnwrapper.java (266 lines) + Converts spherical DCE output (Point_3 on S²) to a 2-D atlas + via stereographic projection + Möbius centring. + Closes the visualisation gap from discrete_conformal_map_spherical(). + Effort: small (~3 days). + Status: 🔲 planned + +9e — CirclePatternLayout (Java port) +───────────────────────────────────── + +9e CirclePatternLayout + CirclePatternUtility (Java port) + → circle_pattern_layout.hpp + Java sources: CirclePatternLayout.java + CirclePatternUtility.java + + CPEuclideanRotation.java + Mathematical reference: Bobenko-Springborn 2004 variational principle + + Bobenko-Hoffmann-Springborn 2006 "Minimal + surfaces from circle patterns" (Discrete & + Comput. Geom. 35, 2006). + Status: 🔲 planned + +9f — Polygon Laplacian (RESEARCH — no Java equivalent) +────────────────────────────────────────────────────── + +9f Discrete Laplacian on general polygonal meshes + → polygon_laplacian.hpp + Java source: NONE + Mathematical reference: + Alexa, Wardetzky 2011 "Discrete Laplacians on General Polygonal + Meshes" (ACM SIGGRAPH 2011) — virtual-node construction, + polygon cotangent weights extending the Pinkall-Polthier formula. + Alexa 2020 "Discrete Laplacians on General Polygonal Meshes" + (ACM TOG 39, 2020) — extended journal treatment, error bounds. + Enables: DCE energy evaluation on quad-dominant / Voronoi / + polygon meshes without forced triangulation. + Replaces euclidean_hessian.hpp for non-triangular inputs. + Status: 🔲 planned (pure research, no Java source) + Effort: medium (~2 weeks core + tests; +1 week Newton integration). ``` 9d — Cone metrics + sphere utilities (Java port — 2026 library scan) @@ -295,6 +360,13 @@ Phase 10 Global uniformization for genus g ≥ 2 → Ωᵢⱼ = ∫_{bⱼ} ωᵢ → Reduction to Siegel fundamental domain via Sp(2g,ℤ). Mathematical reference: Bobenko-Springborn 2004 + Gottschling 1959. + Bobenko, Bücking 2009 "Conformal Structures and + Period Matrices of Polyhedral Surfaces" — discrete + period matrix Ωᵢⱼ on polyhedral surfaces. + Bobenko, Lutz 2024 IMRN "Decorated Discrete Conformal + Maps and Convex Polyhedral Cusps" — uniformization + theorem connecting cusps ↔ hyperideal vertices + (bridges Phase 2/3 HyperIdeal geometry to 10b). Java partial reference: DiscreteRiemannUtility.java (186 lines). Requires: 10a. Effort: ~1 week net after 10a. @@ -318,6 +390,14 @@ Phase 10 Global uniformization for genus g ≥ 2 → Embedding as H²/Γ with Γ ⊂ PSL(2,ℝ) a Fuchsian group. Mathematical reference: Sechelmann 2016 §6 (discrete instance); Bers 1960 (continuous theory). + Lutz 2023 "Canonical Tessellations of Decorated + Hyperbolic Surfaces" (Geom. Dedicata 217, + arXiv:2206.13461) — canonical Delaunay tessellations + in Penner coordinates; unifies the decorated + framework with the fundamental domain construction. + Bobenko, Lutz 2024 IMRN (arXiv:2305.10988) — + discrete uniformization theorem for decorated + piecewise Euclidean surfaces. Java reference: NONE — Java has the polygon + period matrix pieces but does not assemble them into a Fuchsian-group representation. @@ -327,6 +407,9 @@ Phase 10 Global uniformization for genus g ≥ 2 10c' Optional Java-port additions (low priority) → KoebePolyhedron.java (321 lines) — Koebe-Andreev-Thurston circle packings. Adds a fifth DCE method. + Rigidity: Bowers, Bowers, Lutz 2026 "Rigidity of circle polyhedra + and hyperideal polyhedra: the tangency case" (arXiv:2601.22903) + — theoretical uniqueness backing the KAT construction. → ElectrostaticSphereFunctional (127 lines) — sphere distribution baseline. → CirclePatternLayout / CirclePatternUtility — face-circle diff --git a/doc/roadmap/research-track.md b/doc/roadmap/research-track.md index f0e3c9f..2ec4892 100644 --- a/doc/roadmap/research-track.md +++ b/doc/roadmap/research-track.md @@ -211,6 +211,77 @@ The phase numbers match `doc/roadmap/phases.md`. --- +### Non-Euclidean cone extensions (Phase 9d.2, 🔲 planned) + +* **Mathematical sources:** + - **Bobenko, Lutz** (2025). *Decorated Discrete Conformal Equivalence in + Non-Euclidean Geometries.* Discrete & Comput. Geom. arXiv:2310.17529. + → §3: Penner-coordinate decoration unifies cone singularities (Θᵥ ≠ 2π) + and hyperideal cusps (Θᵥ = 0) in a single algebraic framework valid in + Euclidean, spherical, and hyperbolic geometry. + - **Crane, Soliman, Ben-Chen, Schröder** (2018). *Optimal Cone Singularities + for Conformal Flattening.* ACM SIGGRAPH 2018. DOI: 10.1145/3197517.3201367. + → L¹-optimal cone placement via a sparse-recovery optimisation over the + curvature deficit Kᵥ = 2π − Θᵥ; directly gives the set of cone angles + to prescribe for a near-flat conformal parametrisation. + - **Lutz** (2024). *PhD thesis, TU Berlin.* DOI: 10.14279/depositonce-20357. + → Full proofs for both non-Euclidean decorated DCE variants; single reference + covering 9d.2, 10b, and 10c. + +* **Java reference:** ❌ **none.** Java `ConesUtility.java` handles only the + Euclidean case; the non-Euclidean extension is new research. + +* **Scope:** + - Extend `cones_utility.hpp` (Phase 9d.1, Java port) to accept prescribed + cone angles in HyperIdeal and Spherical modes. + - Integrate the Bobenko-Lutz decoration into the variational framework of + `hyper_ideal_functional.hpp` and `spherical_functional.hpp`. + - Optionally: implement the Crane 2018 L¹-optimiser as a helper that + suggests cone positions automatically from the input curvature. + +* **Status:** 🔲 planned; no PR yet. +* **Effort:** medium (1–2 weeks for Euclidean→HyperIdeal/Spherical extension; + +1 week if Crane 2018 optimiser is included). +* **Acceptance criteria:** + - Prescribed Θᵥ ≠ 2π in HyperIdeal mode: Gauss-Bonnet check passes with + `2π·χ = Σ Θᵥ − Σ αᵢⱼ` for given cone angles. + - Newton convergence on a mesh with two manually placed cone singularities + (Euclidean, Spherical, HyperIdeal). + - Cross-validation: at Θᵥ = 2π for all v, output equals existing non-cone solver. + +--- + +### Polygon Laplacian (Phase 9f, 🔲 planned) + +* **Mathematical sources:** + - **Alexa, Wardetzky** (2011). *Discrete Laplacians on General Polygonal + Meshes.* ACM SIGGRAPH 2011. DOI: 10.1145/1964921.1964997. + → Virtual-node construction: each polygon face is replaced by a virtual + central node connected to all vertices; cotangent weights are computed + per sub-triangle; the resulting operator is symmetric and positive + semi-definite, mirroring Pinkall-Polthier for triangulations. + - **Alexa** (2020). *Discrete Laplacians on General Polygonal Meshes.* + ACM TOG 39(6). DOI: 10.1145/3414685.3417840. + → Extended journal version with error bounds and convergence analysis. + +* **Java reference:** ❌ **none.** + +* **Scope:** + - Implement `polygon_laplacian.hpp` following the virtual-node construction. + - Slot it into `newton_solver.hpp` as a drop-in replacement for + `euclidean_hessian.hpp` when the input mesh is non-triangular. + - No change to the energy functional — only the Hessian approximation changes. + +* **Status:** 🔲 planned; pure research, no Java reference. +* **Effort:** medium (~2 weeks core + tests; +1 week Newton integration). +* **Acceptance criteria:** + - Operator is symmetric and PSD (checked via `LDLT.info() == Success`). + - On a pure triangle mesh, output equals `euclidean_hessian.hpp` result. + - Newton convergence on a quad mesh (e.g., structured grid) with the + polygon Laplacian Hessian. + +--- + ### Genus g ≥ 2 fundamental domain (Phase 9c, 🔲 planned) * **Mathematical sources:** - **Poincaré, H.** (1882). *Théorie des groupes fuchsiens.* From ab07f90653e577fab72e96950df4b7d716e9c3bd Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Mon, 25 May 2026 23:59:47 +0200 Subject: [PATCH 04/13] docs: add 4 remaining Tier-2 papers (Springborn 2019, Springborn-Veselov 2015, Crane 2017 BFF, Stripe Patterns 2015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit phases.md: - 10b: Springborn 2019 discrete Liouville theorem (uniqueness of Ω) - 10c: Springborn-Veselov 2015 quasiconformal distortion (error bounds) - 10a: Knöppel-Crane-Pinkall-Schröder 2015 Stripe Patterns (cross-validation ref) references.md (Phase 10 section, 4 new rows): - Springborn 2019 arXiv:1911.00966 → Phase 10b uniqueness - Springborn-Veselov 2015 Int. Math. Res. Not. → Phase 10c error analysis - Knöppel-Crane-Pinkall-Schröder 2015 SIGGRAPH → Phase 10a cross-validation - Sawhney-Crane 2017 BFF ACM TOG → complementary method to Phase 9d Completes the literature integration started in the previous commit: all Tier-2 papers from the Alexa/Bobenko/Springborn/Crane/Lutz analysis are now documented in the roadmap. Co-Authored-By: Claude Sonnet 4.6 --- doc/math/references.md | 4 ++++ doc/roadmap/phases.md | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/doc/math/references.md b/doc/math/references.md index 07ef752..3de48d2 100644 --- a/doc/math/references.md +++ b/doc/math/references.md @@ -68,3 +68,7 @@ builds on this paper and augments it with Ptolemaic flips. | **Bobenko, Mercat, Schmies** — *Period Matrices of Polyhedral Surfaces*, in: Computational Approach to Riemann Surfaces (2011) | Discrete period matrices on polyhedral surfaces | | **Bobenko, Bücking** — *Conformal Structures and Period Matrices of Polyhedral Surfaces* (2009) | Phase 10b: explicit algorithm for computing the discrete Siegel period matrix Ωᵢⱼ on a polyhedral surface from cotangent-weighted integration. | | **Rivin, Springborn** — *The Schläfli formula in Einstein manifolds with boundary*, Electron. Res. Announc. AMS 5 (1999) | Phase 9b-analytic: modern form of the Schläfli identity `2 dV = Σ aₑ dαₑ` for manifolds with boundary — the bilinear form used to derive the analytic HyperIdeal Hessian. | +| **Springborn** — *A discrete version of Liouville's theorem on conformal maps* (2019). arXiv: [1911.00966](https://arxiv.org/abs/1911.00966) | Phase 10b uniqueness: proves that the discrete conformal structure (and hence Ω) is a conformal invariant — the discrete Liouville theorem. Justifies that conformallab++ outputs a canonical representative. | +| **Springborn, Veselov** — *Quasiconformal distortion of projective transformations and discrete conformal maps*, Int. Math. Res. Not. (2015) | Phase 10c error analysis: quantifies how well the discrete H²/Γ embedding approximates the smooth hyperbolic metric; error bounds for the Fuchsian group representation. | +| **Knöppel, Crane, Pinkall, Schröder** — *Stripe Patterns on Surfaces*, ACM SIGGRAPH (2015). DOI: [10.1145/2766890](https://doi.org/10.1145/2766890) | Phase 10a cross-validation: applies discrete holomorphic 1-forms to direction field design; geometry-central provides an independent C++ implementation to cross-check the Phase 10a `DiscreteHolomorphicFormUtility` port. | +| **Sawhney, Crane** — *Boundary First Flattening*, ACM TOG 36(1) (2017). DOI: [10.1145/3132705](https://doi.org/10.1145/3132705) | Complementary method to Phase 9d: boundary-prescribed conformal flattening — user specifies boundary shape, interior conforms freely. Contrast: conformallab++ prescribes cone angles in the interior; BFF prescribes the boundary. Alternative approach for applications needing controlled boundary. | diff --git a/doc/roadmap/phases.md b/doc/roadmap/phases.md index ee6ab16..2db01de 100644 --- a/doc/roadmap/phases.md +++ b/doc/roadmap/phases.md @@ -348,6 +348,12 @@ Phase 10 Global uniformization for genus g ≥ 2 10a Discrete holomorphic and harmonic 1-forms → Integrate basis 1-forms ωᵢ along b-cycles of the cut graph. Mathematical reference: Bobenko-Springborn 2004 §6 + Mercat 2001. + Knöppel, Crane, Pinkall, Schröder 2015 "Stripe + Patterns on Surfaces" (ACM SIGGRAPH 2015) — + application of discrete holomorphic 1-forms to + direction field design; provides an independent + C++ reference implementation (geometry-central) + for cross-validating the Phase 10a computation. Java sources (partial, port-with-research): CanonicalBasisUtility.java 337 lines (homology basis) HomologyUtility.java 122 lines @@ -367,6 +373,10 @@ Phase 10 Global uniformization for genus g ≥ 2 Maps and Convex Polyhedral Cusps" — uniformization theorem connecting cusps ↔ hyperideal vertices (bridges Phase 2/3 HyperIdeal geometry to 10b). + Springborn 2019 "A discrete version of Liouville's + theorem on conformal maps" (arXiv:1911.00966) — + proves uniqueness/rigidity of the discrete conformal + structure; justifies that Ω is a conformal invariant. Java partial reference: DiscreteRiemannUtility.java (186 lines). Requires: 10a. Effort: ~1 week net after 10a. @@ -398,6 +408,12 @@ Phase 10 Global uniformization for genus g ≥ 2 Bobenko, Lutz 2024 IMRN (arXiv:2305.10988) — discrete uniformization theorem for decorated piecewise Euclidean surfaces. + Springborn, Veselov 2015 "Quasiconformal distortion + of projective transformations and discrete conformal + maps" (Int. Math. Res. Not.) — error estimates for + the discrete-to-smooth conformal approximation; + quantifies how well H²/Γ approximates the smooth + hyperbolic metric. Java reference: NONE — Java has the polygon + period matrix pieces but does not assemble them into a Fuchsian-group representation. From f93292e8150ded61a0dc7a719c23d41468dd060e Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 00:02:42 +0200 Subject: [PATCH 05/13] =?UTF-8?q?docs:=20fix=20cherry-pick=20duplicate=209?= =?UTF-8?q?d/9e=20sections=20=E2=80=94=20merge=20into=20unified=20structur?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auto-merge from cherry-pick concatenated both branch versions of Phase 9d and 9e. This commit resolves the duplication: - 9d now has 4 sub-items (9d.1–9d.4) combining both branches: 9d.1 ConesUtility (detailed: BFS, auto-placement, quantization) + Troyanov/Springborn refs (from literature analysis) 9d.2 Non-Euclidean cone extensions (RESEARCH) + Bobenko-Lutz 2025 + Crane 2018 (from literature analysis) 9d.3 StereographicUnwrapper + SphereUtility 9d.4 MobiusCenteringFunctional - 9e keeps the detailed reviewer/meeting-prep version + adds mathematical references (Bobenko-Hoffmann-Springborn 2006) - 9f (Polygon Laplacian, Alexa 2011/2020) retained as standalone section Co-Authored-By: Claude Sonnet 4.6 --- doc/roadmap/phases.md | 103 ++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 64 deletions(-) diff --git a/doc/roadmap/phases.md b/doc/roadmap/phases.md index 2db01de..0f991cd 100644 --- a/doc/roadmap/phases.md +++ b/doc/roadmap/phases.md @@ -129,16 +129,22 @@ mesh type. + holonomy infrastructure. Effort: ~2 weeks for fundamental polygon, +2 weeks for surgery layer, +1 week integration. +``` -9d — Cone singularities + sphere atlas (Java port + research extension) -──────────────────────────────────────────────────────────────────────── +9d — Cone metrics + sphere utilities (Java port + research extension) +──────────────────────────────────────────────────────────────────── -9d.1 ConesUtility (Java port — Euclidean only) - → cones_utility.hpp - Java source: ConesUtility.java (~200 lines) +``` +9d.1 ConesUtility (Java port: unwrapper/ConesUtility.java) + → cone_singularities.hpp + Fills the "⚠️ data structure only" gap in java-parity.md: + - Detect interior cone vertices (angle deficit ≠ 0) + - BFS path from cone to mesh boundary → cut edge set + - Auto-placement: conjugate gradient on Θ-gradient magnitude + - Quantization: snap cone angles to π/2, π/3, π/6 for + quad / triangle / hexagonal atlas targets + Java reference: unwrapper/ConesUtility.java Mathematical reference: Troyanov 1991 + Springborn 2020 §3 - Port scope: prescribed cone angles Θᵥ ≠ 2π in Euclidean mode. - Status: 🔲 planned 9d.2 Non-Euclidean cone extensions (RESEARCH, not in Java) → extend ConesUtility to HyperIdeal + Spherical modes @@ -153,68 +159,13 @@ mesh type. automatic cone placement; directly applicable to 9d.2 algorithm. Status: 🔲 planned -9d.3 StereographicUnwrapper (Java port) - → stereo_unwrapper.hpp - Java source: StereographicUnwrapper.java (266 lines) - Converts spherical DCE output (Point_3 on S²) to a 2-D atlas - via stereographic projection + Möbius centring. - Closes the visualisation gap from discrete_conformal_map_spherical(). - Effort: small (~3 days). - Status: 🔲 planned - -9e — CirclePatternLayout (Java port) -───────────────────────────────────── - -9e CirclePatternLayout + CirclePatternUtility (Java port) - → circle_pattern_layout.hpp - Java sources: CirclePatternLayout.java + CirclePatternUtility.java - + CPEuclideanRotation.java - Mathematical reference: Bobenko-Springborn 2004 variational principle - + Bobenko-Hoffmann-Springborn 2006 "Minimal - surfaces from circle patterns" (Discrete & - Comput. Geom. 35, 2006). - Status: 🔲 planned - -9f — Polygon Laplacian (RESEARCH — no Java equivalent) -────────────────────────────────────────────────────── - -9f Discrete Laplacian on general polygonal meshes - → polygon_laplacian.hpp - Java source: NONE - Mathematical reference: - Alexa, Wardetzky 2011 "Discrete Laplacians on General Polygonal - Meshes" (ACM SIGGRAPH 2011) — virtual-node construction, - polygon cotangent weights extending the Pinkall-Polthier formula. - Alexa 2020 "Discrete Laplacians on General Polygonal Meshes" - (ACM TOG 39, 2020) — extended journal treatment, error bounds. - Enables: DCE energy evaluation on quad-dominant / Voronoi / - polygon meshes without forced triangulation. - Replaces euclidean_hessian.hpp for non-triangular inputs. - Status: 🔲 planned (pure research, no Java source) - Effort: medium (~2 weeks core + tests; +1 week Newton integration). -``` - -9d — Cone metrics + sphere utilities (Java port — 2026 library scan) -──────────────────────────────────────────────────────────────────── - -``` -9d.1 ConesUtility (Java port: unwrapper/ConesUtility.java) - → cone_singularities.hpp - Fills the "⚠️ data structure only" gap in java-parity.md: - - Detect interior cone vertices (angle deficit ≠ 0) - - BFS path from cone to mesh boundary → cut edge set - - Auto-placement: conjugate gradient on Θ-gradient magnitude - - Quantization: snap cone angles to π/2, π/3, π/6 for - quad / triangle / hexagonal atlas targets - Java reference: unwrapper/ConesUtility.java - -9d.2 StereographicUnwrapper + SphereUtility (Java port) +9d.3 StereographicUnwrapper + SphereUtility (Java port) → stereographic_layout.hpp Stereographic projection S²→ℂ∪{∞} + Möbius centering for genus-0 surfaces. Converts spherical DCE output to a flat 2-D atlas. Java reference: unwrapper/StereographicUnwrapper.java (266 lines) -9d.3 MobiusCenteringFunctional (Java port, optional upgrade) +9d.4 MobiusCenteringFunctional (Java port, optional upgrade) → integrate into layout.hpp normalise_hyperbolic() Variational Möbius centering via Lorentz geometry: E = Σ log(-⟨x,p⟩/√(-⟨x,x⟩)) @@ -235,6 +186,30 @@ mesh type. - CPEuclideanRotation: rotation-invariant CP functional variant Java references: unwrapper/circlepattern/CirclePattern{Layout,Utility}.java unwrapper/circlepattern/CPEuclideanRotation.java + Mathematical reference: Bobenko-Springborn 2004 variational principle + + Bobenko-Hoffmann-Springborn 2006 "Minimal + surfaces from circle patterns" (Discrete & + Comput. Geom. 35, 2006). +``` + +9f — Polygon Laplacian (RESEARCH — no Java equivalent) +────────────────────────────────────────────────────── + +``` +9f Discrete Laplacian on general polygonal meshes + → polygon_laplacian.hpp + Java source: NONE + Mathematical reference: + Alexa, Wardetzky 2011 "Discrete Laplacians on General Polygonal + Meshes" (ACM SIGGRAPH 2011) — virtual-node construction, + polygon cotangent weights extending the Pinkall-Polthier formula. + Alexa 2020 "Discrete Laplacians on General Polygonal Meshes" + (ACM TOG 39, 2020) — extended journal treatment, error bounds. + Enables: DCE energy evaluation on quad-dominant / Voronoi / + polygon meshes without forced triangulation. + Replaces euclidean_hessian.hpp for non-triangular inputs. + Status: 🔲 planned (pure research, no Java source) + Effort: medium (~2 weeks core + tests; +1 week Newton integration). ``` --- From 72503a3518f99589142d04089c7aa9e8505075c6 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 00:19:30 +0200 Subject: [PATCH 06/13] docs(reviewer): anonymise reviewer references; profile-based framing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the "Springborn / Bobenko alumnus" placeholder in the reviewer materials (briefing, questions, agenda, README) and in locked-vs-flexible.md with a research-profile description: active researcher in the decorated-DCE / Penner-coordinates / canonical-tessellations / hyperideal-polyhedra line, treated as a peer most likely to USE conformallab++ as numerical infrastructure for their own future experiments — not merely to evaluate it. Citations to the published literature (Springborn 2020 paper, etc.) remain untouched. Only personal references to the prospective reviewer were anonymised. Co-Authored-By: Claude Opus 4.7 --- doc/architecture/locked-vs-flexible.md | 5 +++-- doc/reviewer/README.md | 9 +++++++-- doc/reviewer/agenda.md | 6 ++++-- doc/reviewer/briefing.md | 17 +++++++++++------ doc/reviewer/questions.md | 6 +++--- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/doc/architecture/locked-vs-flexible.md b/doc/architecture/locked-vs-flexible.md index 71c242d..277cd86 100644 --- a/doc/architecture/locked-vs-flexible.md +++ b/doc/architecture/locked-vs-flexible.md @@ -6,8 +6,9 @@ > across the whole codebase) and which are **opportunistic** (made > on first principles and easy to revisit). > -> **Why this matters now.** A v0.9.0 + Springborn-Bobenko-alumnus -> external review (May 2026) is the right moment to surface these +> **Why this matters now.** A v0.9.0 snapshot + external review by +> an active researcher in the decorated-DCE / canonical-tessellation / +> hyperideal-polyhedra line is the right moment to surface these > decisions before they ossify further. If any of the *locked* > decisions need revisiting, this is the cheapest moment in the > project's life to do so. diff --git a/doc/reviewer/README.md b/doc/reviewer/README.md index 47eab9c..6cb4240 100644 --- a/doc/reviewer/README.md +++ b/doc/reviewer/README.md @@ -1,7 +1,12 @@ # Reviewer meeting materials -A single landing page for the three documents associated with the -external-reviewer meeting (Springborn/Bobenko alumnus, May 2026). +A single landing page for the three documents associated with an +external-reviewer meeting. The materials are written for a peer who +actively publishes in discrete differential geometry — specifically +the decorated-DCE / Penner-coordinates / hyperideal-polyhedra / +canonical-tessellations research line — and who would potentially +use conformallab++ as numerical infrastructure for their own future +experiments. | Document | Audience | Purpose | |---|---|---| diff --git a/doc/reviewer/agenda.md b/doc/reviewer/agenda.md index a7bc60f..22d9a46 100644 --- a/doc/reviewer/agenda.md +++ b/doc/reviewer/agenda.md @@ -13,8 +13,10 @@ productive). ## Opening — 5 min - **Thank-you** + ~30 s on why I value their time specifically - (Springborn/Bobenko background = best-positioned audience for - this material). + (active researcher in the exact line — decorated DCE, Penner + coordinates, canonical tessellations, hyperideal polyhedra — that + conformallab++ aspires to be infrastructure for; best-positioned + audience for the material AND the most likely future power user). - **Confirm format**: they've read `briefing.md`? Yes → skip ahead. No → take 3 min to walk through it together via the reviewer-hub URL. diff --git a/doc/reviewer/briefing.md b/doc/reviewer/briefing.md index df00bf8..4e2e615 100644 --- a/doc/reviewer/briefing.md +++ b/doc/reviewer/briefing.md @@ -1,12 +1,17 @@ # Reviewer briefing — conformallab++ -> **Audience.** External reviewer with a discrete-conformal-geometry -> background (Springborn / Bobenko alumnus, ~30 minutes lead-time -> before the meeting). +> **Audience.** Active researcher in discrete differential geometry — +> specifically the research line around **decorated discrete conformal +> equivalence**, **Penner coordinates on hyperbolic surfaces**, +> **canonical Delaunay tessellations of decorated surfaces**, and +> **hyperideal polyhedra**. Treats the reader as a peer who is more +> likely to *use* conformallab++ as numerical infrastructure for their +> own future experiments than to merely evaluate it as a software +> artefact. > -> **Purpose of this document.** A single page they can read once -> before the meeting and feel oriented — what the project is, what -> we want from them, and where to look first. +> **Purpose.** One page to read before the meeting: what is shipping, +> which of the reader's research questions it could already support, +> and where the gaps are that we would close together. ## In one paragraph diff --git a/doc/reviewer/questions.md b/doc/reviewer/questions.md index fb0d4d9..dc8c640 100644 --- a/doc/reviewer/questions.md +++ b/doc/reviewer/questions.md @@ -30,9 +30,9 @@ We can either: Down-side: longer; potential for new bugs not seen by the Java original's test cases. -**Question**: which route do you prefer, and is there a Springborn-era -reference implementation (Mathematica notebook, paper appendix) we -should cross-validate against? +**Question**: which route do you prefer, and is there a reference +implementation (Mathematica notebook, paper appendix, other research +codebase) we should cross-validate against? Context: `doc/roadmap/phases.md` §Phase 9c, `doc/roadmap/porting-status.md`. From 36596c7c799de5fa96fb862de4bdda9c268f262d Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 00:21:50 +0200 Subject: [PATCH 07/13] docs(reviewer): research alignments + 2 new Q1/Q2 + reordered agenda MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the two research-track questions to the front of the queue, where they belong for a reader whose publication line maps directly onto our research-track roadmap entries. briefing.md gains two new sections: * Research alignments — a 6-row table mapping the reader's research threads (decorated DCE, canonical tessellations, hyperideal rigidity, optimal cone placement, polygon Laplacian, Schläfli machinery) onto concrete phases of the roadmap, with the closest published line cited generically (year + venue only). * What's new on this snapshot — the 6 new porting phases + 9 new citations + Phase 9f (RESEARCH, no Java parent) + output_uv_map extension to Inversive-Distance. questions.md restructures the question set from 5 to 7: * Q1 (NEW) — research-track alignment: which of 9d.2 / 9f / 10c / 10c′ would unblock concrete experiments? * Q2 (NEW) — decorated-DCE API surface: A/B/C named parameter vs new solver vs property-map auto-detect? * Q3 — Phase 9b-analytic (was Q2) * Q4 — Phase 9c port-literal vs re-derive (was Q1) * Q5 — GC-1 cross-validation co-authorship (was Q5) * Q6 — CGAL submission packaging (was Q4) * Q7 — The "no" question (was the trailing section) Also drops Q3 from the previous list (CP-Euclidean output_uv_map), since that question is now answered (Phase 9c, runtime error today, on the deferred list — no reviewer input needed). Adds a final "After the meeting — would you collaborate?" block so the post-meeting collaboration options (acknowledgement / co-author / cadence / PRs) do not surprise the reader on the day. agenda.md reorders §2 to match the new question order; the timing shifts Q1/Q2/Q3 (research) to the front and Q4/Q6 (project management) to the back. Memo template at the bottom now has 7 named answer slots instead of 5 numbered ones. Co-Authored-By: Claude Opus 4.7 --- doc/reviewer/agenda.md | 58 ++++++---- doc/reviewer/briefing.md | 66 ++++++++++-- doc/reviewer/questions.md | 222 ++++++++++++++++++++++++++------------ 3 files changed, 245 insertions(+), 101 deletions(-) diff --git a/doc/reviewer/agenda.md b/doc/reviewer/agenda.md index 22d9a46..a5a93e2 100644 --- a/doc/reviewer/agenda.md +++ b/doc/reviewer/agenda.md @@ -36,35 +36,50 @@ Goal: they leave §1 with a mental map of what's where. **Cue to move on**: when they have no more "where is X?" questions. -## §2 The five questions — 30 min +## §2 The seven questions — 35 min -Goal: get clear answers to as many of the 5 questions in -[`questions.md`](questions.md) as possible. Order matters: +Goal: get clear answers to as many of the 7 questions in +[`questions.md`](questions.md) as possible. Order is chosen so the +research-relevant questions come *first* (their answer has the largest +downstream effect on the roadmap): -1. **Q4 first** (CGAL submission strategy — single package vs five). - This sets the framing for the rest. ~5 min. -2. **Q1** (Phase 9c port-literal vs re-derive). ~5 min. -3. **Q2** (Phase 9b-analytic — is the 6× speedup worth ~2 weeks?). - May trigger longer math discussion; cap at 10 min and offer to - continue async. -4. **Q5** (GC-1 cross-validation co-authorship). ~5 min. -5. **Q3** (CP-Euclidean output_uv_map). ~5 min. +1. **Q1 — research-track alignment** (which of 9d.2 / 9f / 10c / 10c′ + would unblock concrete experiments?). ~8 min. Most likely to + make them feel the project is genuinely *for* their work, not just + adjacent to it. +2. **Q2 — decorated-DCE API surface** (A/B/C named parameter vs new + solver vs property-map auto-detect). ~7 min. Sets a concrete + shape we can sketch in code right after the meeting. +3. **Q3 — Phase 9b-analytic** (Schläfli Hessian — implement now?). + ~8 min. May trigger longer math discussion; cap at 10 min and + offer to continue async via the derivation note. +4. **Q5 — GC-1 cross-validation co-authorship**. ~4 min. Read the + room: if they're warm, push; if cool, leave as "let me follow up + in writing". +5. **Q4 — Phase 9c port-literal vs re-derive** (algorithm choice). + ~4 min. Less critical than Q1–Q3 because we have a viable default + either way. +6. **Q6 — CGAL submission packaging** (one package vs several). + ~4 min. Project-management question; their answer is *advisory* + even if it's confident. **Trap to avoid**: don't relitigate any of the already-made decisions (e.g. Surface_mesh as default, Eigen as backend) unless they bring it up under "anything you'd say no to". Move forward, not sideways. +Keep Q4/Q6 *short* — they are project management; Q1–Q3 are the +research-flavoured ones their time is best spent on. -## §3 The "no" question — 5 min +## §3 Q7 — the "no" question — 5 min -Last paragraph of [`questions.md`](questions.md): *"Is there one -architecture decision where you think 'no, that's the wrong call'?"* +[`questions.md`](questions.md) §Q7: *"Is there one architecture +decision where you think 'no, that's the wrong call'?"* Ask explicitly. Wait. Don't fill silence. Negative feedback at this phase is the highest-value information of the entire meeting. ## §4 Wrap-up — 5 min -- **Summarise**: 1 sentence per Q1–Q5 answer. +- **Summarise**: 1 sentence per Q1–Q7 answer. - **Next steps**: - Items they offered to help on (if any) → I'll send a follow-up email within 48 h. @@ -97,12 +112,13 @@ phase is the highest-value information of the entire meeting. Reviewer: ____ Duration: ____ min - Q1 answer: ____ - Q2 answer: ____ - Q3 answer: ____ - Q4 answer: ____ - Q5 answer: ____ - "No" pointer: ____ + Q1 answer (research-track alignment): ____ + Q2 answer (decorated-DCE API): ____ + Q3 answer (Phase 9b-analytic): ____ + Q4 answer (Phase 9c port choice): ____ + Q5 answer (GC-1 co-authorship): ____ + Q6 answer (CGAL packaging): ____ + Q7 "no" pointer: ____ Action items: [ ] (within 48 h) ____ diff --git a/doc/reviewer/briefing.md b/doc/reviewer/briefing.md index 4e2e615..e15f85a 100644 --- a/doc/reviewer/briefing.md +++ b/doc/reviewer/briefing.md @@ -33,6 +33,42 @@ The landing page is a hand-curated reviewer hub, not an auto-generated index. It links to the Doxygen API, the key markdown documents, and shows static quality-gate status. +## Research alignments — where this library could be infrastructure for your work + +The current snapshot already contains, or has roadmap entries for, +the following: + +| Your research thread | What this snapshot has | Phase | +|---|---|---| +| **Decorated DCE in non-Euclidean geometries** (Bobenko–Lutz 2025, *DCG*) | five DCE solvers + traits scaffolding; non-Euclidean cone extension scoped in research-track with acceptance criteria | **9d.2** RESEARCH (planned) | +| **Canonical Delaunay tessellations of decorated hyperbolic surfaces** (Lutz 2023, *Geom. Dedicata*; Lutz 2024 PhD thesis) | cut-graph + period matrix + hyperbolic-disk layout as scaffolding; canonical-tessellation algorithm itself outlined | **10c** planned | +| **Hyperideal polyhedra rigidity** (Bowers–Bowers–Lutz 2026) | HyperIdeal functional + analytic Hessian derivation (805-line LaTeX note) | **9b-analytic** derived; **10c′** KAT planned | +| **Optimal cone placement / non-Euclidean cone metrics** (Crane et al. 2018) | Cone-singularity port via `ConesUtility` scoped; the *non-Euclidean* extension is the research delta | **9d.1** port + **9d.2** RESEARCH | +| **Polygon Laplacian on general meshes** (Alexa–Wardetzky 2011; Alexa 2020) | no Java parent; first phase a reviewer can shape at design stage | **9f** RESEARCH (planned) | +| **Schläfli-based variational machinery** (Rivin–Springborn 1999) | derivation done, implementation gated on your view of whether the ~6× speedup over our block-FD path matters at your mesh sizes | **9b-analytic** ready to implement | + +See [`doc/roadmap/research-track.md`](../roadmap/research-track.md) +for the per-phase acceptance criteria and +[`doc/roadmap/phases.md`](../roadmap/phases.md) for the porting plan. + +## What's new on this snapshot (since the previous publish) + +- **+6 new porting-roadmap phases** (9d cones / 9e circle-pattern + layout / 10d Koebe circle-domain / 10e quasi-isothermic / 10f Koebe + polyhedra / 10g cyclic-symmetry quotients) derived from a full + Java-library scan. +- **+9 literature citations** integrated into the roadmap, all + Tier-1/2 in the research line above (Bobenko–Lutz 2024 IMRN; + Bobenko–Lutz 2025 DCG; Lutz 2023 Geom. Dedicata; Lutz 2024 PhD; + Bowers–Bowers–Lutz 2026; Crane et al. 2018; Alexa–Wardetzky 2011; + Alexa 2020; Rivin–Springborn 1999). +- **Phase 9f** (polygon Laplacian on general meshes) added as + RESEARCH-only — no Java parent — so you can influence its design + before it exists. +- **`output_uv_map`** now covers 4 of 5 DCE solvers (Inversive-Distance + added; CP-Euclidean deferred to Phase 9c with a clear runtime error + rather than silent failure). + ## What's true about this snapshot | Claim | Concrete evidence | @@ -47,20 +83,32 @@ shows static quality-gate status. ## What we want from you -Five concrete questions are in +Seven concrete questions are in [`doc/reviewer/questions.md`](questions.md) — please skim them beforehand. They are deliberately scoped: each can be answered with "go this way" / "no, go that way" / "either is fine". -The high-stakes ones: +Ordered by reviewer-value (the first two are the ones your research +profile makes you best-positioned to answer): -1. **Phase 9c (4g-polygon)** — port the Java implementation literally, - or re-derive from Springborn 2020 §5? -2. **Phase 9b-analytic** — is the ~6× speedup over our current block-FD - Hessian (full Schläfli-based analytic) worth ~2 weeks? Working-mesh - size that justifies it? -3. **CGAL submission strategy** — submit as a single package or split - the five DCE solvers into separate packages? +1. **Q1 — Research-track alignment** — of the three RESEARCH-track + phases (9d.2 non-Euclidean cones, 9f polygon Laplacian, 10c + canonical tessellations + 10c′ Koebe polyhedra), which would + unblock concrete experiments you have wanted to run? +2. **Q2 — Decorated-DCE API surface** — what's the minimum public + API for Penner-coordinate / decorated-DCE work? Named parameter + on the existing Euclidean entry, separate `decorated_*` solvers, + or per-edge decoration weights via property maps? +3. **Q3 — Phase 9b-analytic** — is the ~6× speedup over the current + block-FD Hessian worth ~2 weeks of implementation, at the mesh + sizes you typically work with? +4. **Q4 — Phase 9c (4g-polygon)** — port the Java implementation + literally, or re-derive from Springborn 2020 §5? +5. **Q5 — geometry-central cross-validation (GC-1)** — would you + be interested in co-authoring a Newton-vs-Ptolemy-flips comparison? +6. **Q6 — CGAL submission strategy** — one package or several? +7. **Q7 — The "no" question** — looking at our 12 architecture + decisions, is there one you would push back on? ## What's deliberately deferred (so we can discuss with you first) diff --git a/doc/reviewer/questions.md b/doc/reviewer/questions.md index dc8c640..131fa15 100644 --- a/doc/reviewer/questions.md +++ b/doc/reviewer/questions.md @@ -4,13 +4,111 @@ > "do A" / "do B" / "either is fine" is a sufficient answer; deeper > dives are welcome but not required. -These are the five decisions that would benefit most from a second -opinion. Items 1-3 affect the porting roadmap directly; 4-5 affect -the long-term goal (CGAL submission). +These are the seven items that would benefit most from a second opinion. + +* **Q1–Q2** are research-track questions — your active publication line + in **decorated DCE / Penner coordinates / canonical tessellations / + hyperideal polyhedra** makes you the best-positioned reader for them. + They ask whether conformallab++ could become *infrastructure for your + own future numerical experiments*, and what the minimum API surface + would be. +* **Q3–Q4** are porting decisions in our roadmap where your view of the + underlying mathematics would change the answer. +* **Q5–Q6** are project-management questions where peer input is + valuable but not blocking. +* **Q7** is an open invitation to push back on any architecture + decision you think we got wrong. --- -## Q1 — Phase 9c (4g-polygon canonical form): port-literal vs re-derive? +## Q1 — Research-track alignment: which RESEARCH phase would unblock concrete experiments you want to run? + +Three phases in `doc/roadmap/research-track.md` are research-only +(no Java parent, no immediate user request), but each maps onto a +recognised live research line and each has explicit acceptance +criteria: + +| Phase | What it would add | Closest published line | +|---|---|---| +| **9d.2** | Decorated DCE in non-Euclidean (spherical + hyperbolic) geometries; Penner coordinates as first-class DOF; automatic cone placement for non-Euclidean targets | Decorated DCE in non-Euclidean geometries (2025, *Discrete Comput. Geom.*); optimal cone singularities for Euclidean flattening (2018, *SIGGRAPH*) | +| **9f** | Discrete Laplace–Beltrami on **non-triangular** polygonal meshes (virtual-node / generalised cotangent), making DCE work on quad / Voronoi tessellations without re-triangulation | Polygon Laplacians (2011 *SIGGRAPH* + 2020 *TOG*) | +| **10c + 10c′** | Canonical Delaunay tessellations of decorated hyperbolic surfaces; Koebe polyhedron realisation (KAT) with rigidity-aware Newton | Canonical tessellations of decorated hyperbolic surfaces (2023, *Geom. Dedicata*); rigidity of circle / hyperideal polyhedra (2026, preprint) | + +**Question A:** which of these (if any) would unblock concrete +numerical experiments you have wanted to run but currently have no +reference implementation for? + +**Question B:** for the one(s) you would use, would you want us to +target the *next* milestone after Phase 9c, or is there a different +order that would serve your research better? + +Context: +[`research-track.md`](../roadmap/research-track.md) §"Non-Euclidean +cone extensions" and §"Polygon Laplacian"; the integrated literature +sits in [`math/references.md`](../math/references.md). + +--- + +## Q2 — Decorated-DCE API surface: what would you need from us to use the library for Penner-coordinate work? + +If you wanted to compute the variational energy + Newton update for +**decorated discrete conformal equivalence** (vertex `u`-DOFs plus +per-edge Penner decoration `λ_e`), the existing five-solver scaffold +gives us three plausible API directions: + +- **(A) Named parameter on the existing Euclidean entry.** + `discrete_conformal_map_euclidean(mesh, parameters::penner_decoration_map(λ))`. + Smallest change; preserves the single-entry-per-geometry pattern; + hides the decoration as "just another property map". +- **(B) Separate `decorated_*` solver headers.** + New entry `CGAL::decorated_discrete_conformal_map_{euclidean, + spherical, hyperbolic}` with its own `Default_decorated_*_traits`. + Cleaner separation of concerns; mirrors the way CP-Euclidean and + Inversive-Distance are their own headers. +- **(C) Per-edge decoration as just another property map** that the + existing solvers consume when present (zero-decoration = current + behaviour by construction). Minimal API expansion; risk of + surprising convergence behaviour when decoration is silently zero + vs explicitly zero. + +**Question:** which of A / B / C matches what you would expect from +a CGAL-style header? If "none of the above" — what would you write +in our place? + +Context: Phase 9d.2 in +[`research-track.md`](../roadmap/research-track.md); the existing +named-parameter helpers in +[`code/include/CGAL/Conformal_map/internal/parameters.h`](../../code/include/CGAL/Conformal_map/internal/parameters.h). + +--- + +## Q3 — Phase 9b-analytic Hessian: implement now or later? + +We have: + +- **Done**: per-face block-FD Hessian (96× faster than naive full-FD). +- **Derived but not implemented**: analytic Hessian via the Schläfli + identity, expected ~6× further speedup over block-FD. +- **Derivation document**: + [`doc/math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) + (805 lines, all sign pitfalls covered, references Schläfli 1858, + Milnor 1982, Vinberg 1993, Cho–Kim 1999, Glickenstein 2011, + Springborn 2020, Rivin–Springborn 1999). + +**Question:** + +- At what mesh size does the ~6× become user-visible enough to + justify ~2 weeks of implementation work, given the typical sizes + in your work? +- Are you aware of subtleties in the Schläfli-based derivation our + document might be missing? + +If the answer is "implement", we'd target Phase 9b-analytic right +after the meeting. + +--- + +## Q4 — Phase 9c (4g-polygon canonical form): port-literal vs re-derive? The Java original has two utility classes: @@ -38,48 +136,30 @@ Context: `doc/roadmap/phases.md` §Phase 9c, `doc/roadmap/porting-status.md`. --- -## Q2 — Phase 9b-analytic Hessian: implement now or later? +## Q5 — geometry-central cross-validation (GC-1): would you co-author? -We have: +Two libraries solve the DCE problem from opposite algorithmic +directions: -- **Done**: per-face block-FD Hessian (96× faster than naive full-FD). -- **Derived but not implemented**: analytic Hessian via the Schläfli - identity, expected ~6× further speedup over block-FD. -- **Derivation document**: - [`doc/math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) - (805 lines, all sign pitfalls covered, references Schläfli 1858, - Milnor 1982, Vinberg 1993, Cho-Kim 1999, Glickenstein 2011, - Springborn 2020). +- **conformallab++**: Newton on the fixed mesh (no intrinsic flips). +- **geometry-central**: Ptolemy flips on an intrinsic triangulation. -**Question**: +An automated comparison on common meshes would be: -- At what mesh size does the ~6× become user-visible enough to - justify ~2 weeks of implementation work? -- Are you aware of subtleties in the Schläfli-based derivation our - document might be missing? +- A short paper (the disagreement modes are interesting in their own + right and connect to the decorated-DCE framework via canonical + tessellation invariants). +- A confidence-building tool for both libraries. +- ~3 days of plumbing (CMake-fetch geometry-central, write 5 common + test meshes, compare `u_per_vertex` to a tolerance). -If the answer is "implement", we'd target Phase 9b-analytic right -after the meeting. +**Question:** would you be interested in co-authoring such a comparison +note (with us doing the implementation)? Or do you know someone in a +neighbouring group who would be a natural co-author? --- -## Q3 — `output_uv_map` for CP-Euclidean: build now or defer? - -For CP-Euclidean (face-based DOFs, BPS 2010) the natural output is a -**per-face circle packing** in ℝ² — not a per-vertex `Point_2` map -the way the other four DCE entries produce. - -Today the entry throws `std::runtime_error` with a helpful pointer if -the caller passes `output_uv_map(...)`. A faithful layout would be -~150 lines implementing BPS-2010 §6. - -**Question**: do *your* CP-Euclidean use cases need a UV-like output, -or are the face circle radii themselves the deliverable? The answer -shapes whether Phase 9c gets it now or later. - ---- - -## Q4 — CGAL submission strategy: one package or five? +## Q6 — CGAL submission strategy: one package or several? For the long-term CGAL submission: @@ -94,34 +174,31 @@ Today the code is structured per-functional (Strategy C — see [`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) §7). Either submission packaging is achievable from this base. -**Question**: what's the CGAL editor convention for related-but-distinct -algorithms — Polygon_mesh_processing as one example (one package, many -algorithms), vs Triangulation_2/Triangulation_3/Periodic_*/Hyperbolic_* -as another (multiple packages for related algorithms)? +**Question:** what's the CGAL editor convention for related-but-distinct +algorithms — `Polygon_mesh_processing` as one example (one package, many +algorithms), vs `Triangulation_2`/`Triangulation_3`/`Periodic_*`/ +`Hyperbolic_*` as another (multiple packages for related algorithms)? --- -## Q5 — geometry-central cross-validation (GC-1) +## Q7 — The "no" question (this is the highest-value answer) -Two libraries solve the DCE problem from opposite algorithmic -directions: +Looking at any of the 12 architecture decisions in +[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md), is +there one where you think *"no, that's the wrong call, here's why"*? -- **conformallab++**: Newton on the fixed mesh (no intrinsic flips). -- **geometry-central**: Ptolemy flips on an intrinsic triangulation. +This is a deliberately blunt question because positive feedback is +nice but negative feedback is rarer and more valuable. The 🔴 +load-bearing decisions are the most consequential to revisit, because +waiting longer makes them more expensive: -An automated comparison on common meshes would be: +- **#1** `CGAL::Surface_mesh

` as default mesh +- **#3** header-only, no compiled library +- **#6** Eigen as linear-algebra back-end +- **#11** MIT license (only relevant if it conflicts with a CGAL- + submission constraint) -- A nice paper (the disagreement modes are interesting in their own - right). -- A confidence-building tool for both libraries (we benefit from - catching corner-case bugs, they benefit from cross-validation - against a Newton baseline). -- ~3 days of plumbing (CMake-fetch geometry-central, write 5 common - test meshes, compare `u_per_vertex` to a tolerance). - -**Question**: would you be interested in co-authoring such a comparison -note (with us doing the implementation)? Or do you know someone in -the Crane group who would? +"No" is the most useful answer. --- @@ -133,21 +210,24 @@ the Crane group who would? [`code/deps/THIRD-PARTY-LICENSES.md`](../../code/deps/THIRD-PARTY-LICENSES.md)). - Build system (CMake ≥ 3.20, header-only consumer + optional CLI/Viewer). +- Documentation tooling (Doxygen with auto-generated `headers.md`). -These are conscious decisions matched to CGAL conventions and aren't -load-bearing in the sense that revisiting them later is cheap. +These are conscious decisions matched to CGAL conventions and are +not load-bearing in the sense that revisiting them later is cheap. --- -## What I'm hoping you'll say "no" to +## After the meeting — would you collaborate? -This is a deliberately blunt question because positive feedback is -nice but negative feedback is rarer and more valuable: +A separate "after the meeting" conversation, but flagged here so it +does not surprise you on the day: -**Looking at any of the 12 architecture decisions in -[`locked-vs-flexible.md`](../architecture/locked-vs-flexible.md), is -there one where you think "no, that's the wrong call, here's why"?** - -The 🔴 load-bearing decisions are the most consequential to revisit, -because waiting longer makes them more expensive. No is the most -useful answer. +- **Acknowledgement** in any future CGAL submission / paper would be + the default, and we would ask first. +- **Co-authorship** on Q5 (the GC-1 cross-validation note) is on the + table if you said yes there. +- **Periodic update cadence** (quarterly? per-milestone?) — open + question, no expectation. +- **Pull requests** from your side are welcome and reviewable on the + Codeberg repo. We would not expect them — but we would not turn + them away either. From 9be11eca4e9c73fe7701d3d1974d7134f9938bb2 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 00:25:11 +0200 Subject: [PATCH 08/13] =?UTF-8?q?docs(reviewer):=20refresh=20hub=20link=20?= =?UTF-8?q?list=20=E2=80=94=20add=20roadmap,=20research-track,=20reference?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the "Quick links the reviewer should bookmark" section of doc/reviewer/README.md so it matches the Pages-hub v4 layout: * the hub itself now carries status badges, a "what's new" banner, and the research-alignment table — call this out so the reader knows what to expect when they click through; * adds direct links to the three documents that the new Q1/Q2/Q3 questions actually depend on (references.md, phases.md, research-track.md) — previously only the Schläfli-derivation note and the locked-vs-flexible architecture page were linked; * re-points the Schläfli derivation link from "Q2" (old numbering) to "Q3" (new numbering after baustein B inserted research questions at Q1/Q2). Companion change to the Pages-hub v4 already pushed to the codeberg `pages` branch; this commit keeps the in-repo guidance in sync. Co-Authored-By: Claude Opus 4.7 --- doc/reviewer/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/reviewer/README.md b/doc/reviewer/README.md index 6cb4240..02aa3bb 100644 --- a/doc/reviewer/README.md +++ b/doc/reviewer/README.md @@ -28,6 +28,12 @@ suggested structure. ## Quick links the reviewer should bookmark - 🌐 Reviewer-hub landing page: + (the hub shows status badges, a "what's new" banner with the most + recent delta, the research-alignment table, and direct links into + every document below) - 📦 Source: -- 📝 Architecture decisions: [`../architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) -- 📐 Schläfli derivation (for Q2): [`../math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) +- 📝 Architecture decisions (incl. the Q7 "no" prompt): [`../architecture/locked-vs-flexible.md`](../architecture/locked-vs-flexible.md) +- 📐 Schläfli derivation (for Q3): [`../math/hyperideal-hessian-derivation.md`](../math/hyperideal-hessian-derivation.md) +- 📚 Literature index (for Q1 + Q3): [`../math/references.md`](../math/references.md) +- 🗺️ Per-phase roadmap (for Q1): [`../roadmap/phases.md`](../roadmap/phases.md) +- 🧪 Research-track entries with acceptance criteria (Q1 + Q2): [`../roadmap/research-track.md`](../roadmap/research-track.md) From 0c520046fb61e964bdb234144b922b350175592d Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 06:18:26 +0200 Subject: [PATCH 09/13] =?UTF-8?q?docs(reviewer):=20baustein=20D=20?= =?UTF-8?q?=E2=80=94=20close=20Java-scan=20+=20lit-integration=20gaps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- doc/reviewer/briefing.md | 48 +++++++++++++++++++++++++++------------ doc/reviewer/questions.md | 35 ++++++++++++++++++---------- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/doc/reviewer/briefing.md b/doc/reviewer/briefing.md index e15f85a..e147b06 100644 --- a/doc/reviewer/briefing.md +++ b/doc/reviewer/briefing.md @@ -36,7 +36,9 @@ shows static quality-gate status. ## Research alignments — where this library could be infrastructure for your work The current snapshot already contains, or has roadmap entries for, -the following: +the following. Most rows match an active publication line in +discrete differential geometry; a few (marked *no Java parent*) are +research-only phases the reader can shape at design stage. | Your research thread | What this snapshot has | Phase | |---|---|---| @@ -44,27 +46,43 @@ the following: | **Canonical Delaunay tessellations of decorated hyperbolic surfaces** (Lutz 2023, *Geom. Dedicata*; Lutz 2024 PhD thesis) | cut-graph + period matrix + hyperbolic-disk layout as scaffolding; canonical-tessellation algorithm itself outlined | **10c** planned | | **Hyperideal polyhedra rigidity** (Bowers–Bowers–Lutz 2026) | HyperIdeal functional + analytic Hessian derivation (805-line LaTeX note) | **9b-analytic** derived; **10c′** KAT planned | | **Optimal cone placement / non-Euclidean cone metrics** (Crane et al. 2018) | Cone-singularity port via `ConesUtility` scoped; the *non-Euclidean* extension is the research delta | **9d.1** port + **9d.2** RESEARCH | -| **Polygon Laplacian on general meshes** (Alexa–Wardetzky 2011; Alexa 2020) | no Java parent; first phase a reviewer can shape at design stage | **9f** RESEARCH (planned) | +| **Polygon Laplacian on general meshes** (Alexa–Wardetzky 2011; Alexa 2020) | *no Java parent* — first phase a reviewer can shape at design stage | **9f** RESEARCH (planned) | +| **Quasi-isothermic maps** (generalising conformality where exact conformality is impossible — Lawson-correspondence parameterisation) | scoped as a 6-class port (~800 lines) from the Java original: `QuasiisothermicLayout`, `DBFSolution` (discrete Beltrami field), `SinConditionApplication`, `QuasiisothermicDelaunay`, `QuasiisothermicUtility`, `ConformalStructureUtility` | **10e** planned | +| **Higher-genus + hyperelliptic surfaces** (Bobenko–Bücking 2009 on polyhedral surfaces; period matrices with block-diagonal Z₂ structure) | port of `HyperellipticUtility` + `HyperIdealHyperellipticUtility` scoped; existing period-matrix code as scaffolding | **10b** planned | +| **Möbius centring for Poincaré-disk layouts** as a variational problem (Lorentz geometry: `E = Σ log(−⟨x,p⟩/√(−⟨x,x⟩))`) | currently we use iterative Fréchet mean in `normalise_hyperbolic()`; the principled variational alternative is scoped via the Java `MobiusCenteringFunctional` port (full gradient + Hessian) | **9d.4** planned | +| **Boundary-First / interactive flattening** (Crane et al. 2017 BFF; Bonneel et al. 2015 *Stripe Patterns on Surfaces*) | not on the roadmap as ports; documented in [`references.md`](../math/references.md) as comparison points / inspiration for future API design | — | | **Schläfli-based variational machinery** (Rivin–Springborn 1999) | derivation done, implementation gated on your view of whether the ~6× speedup over our block-FD path matters at your mesh sizes | **9b-analytic** ready to implement | -See [`doc/roadmap/research-track.md`](../roadmap/research-track.md) -for the per-phase acceptance criteria and -[`doc/roadmap/phases.md`](../roadmap/phases.md) for the porting plan. +See [`doc/roadmap/phases.md`](../roadmap/phases.md) for the per-phase +porting plan, [`doc/roadmap/research-track.md`](../roadmap/research-track.md) +for the items beyond Java parity with explicit acceptance criteria, +and [`doc/roadmap/java-parity.md`](../roadmap/java-parity.md) for the +reverse table (every Java class → C++ destination or *do-not-port* +rationale). ## What's new on this snapshot (since the previous publish) -- **+6 new porting-roadmap phases** (9d cones / 9e circle-pattern - layout / 10d Koebe circle-domain / 10e quasi-isothermic / 10f Koebe - polyhedra / 10g cyclic-symmetry quotients) derived from a full - Java-library scan. -- **+9 literature citations** integrated into the roadmap, all - Tier-1/2 in the research line above (Bobenko–Lutz 2024 IMRN; - Bobenko–Lutz 2025 DCG; Lutz 2023 Geom. Dedicata; Lutz 2024 PhD; - Bowers–Bowers–Lutz 2026; Crane et al. 2018; Alexa–Wardetzky 2011; - Alexa 2020; Rivin–Springborn 1999). -- **Phase 9f** (polygon Laplacian on general meshes) added as +- **+6 new porting-roadmap phases** (9d cones + 9d.4 Möbius centring / + 9e circle-pattern layout / 10d Koebe circle-domain / 10e + quasi-isothermic / 10f Koebe polyhedra / 10g cyclic-symmetry + quotients) derived from a full Java-library scan. See `phases.md` + for the per-phase plan and `java-parity.md` for the reverse table. +- **+13 literature citations** integrated into the roadmap, all + Tier-1/2. Decorated-DCE / canonical-tessellation / hyperideal line: + Bobenko–Lutz 2024 IMRN; Bobenko–Lutz 2025 *DCG*; Lutz 2023 + *Geom. Dedicata*; Lutz 2024 PhD; Bowers–Bowers–Lutz 2026. Cones, + polyhedra, period matrices: Crane et al. 2018; Springborn 2019 + (hyperbolic polyhedra); Bobenko–Bücking 2009; Rivin–Springborn 1999. + Polygon Laplacians: Alexa–Wardetzky 2011; Alexa 2020. Integrable + + practical-flattening context: Springborn–Veselov 2015 (cluster + dynamics); Crane et al. 2017 (BFF); Bonneel et al. 2015 (Stripe + Patterns). +- **Phase 9f** (polygon Laplacian on non-triangular meshes) added as RESEARCH-only — no Java parent — so you can influence its design before it exists. +- **Phase 10e** (quasi-isothermic maps) and **Phase 9d.4** (variational + Möbius centring) newly scoped from the Java scan; both touch + research lines adjacent to decorated DCE. - **`output_uv_map`** now covers 4 of 5 DCE solvers (Inversive-Distance added; CP-Euclidean deferred to Phase 9c with a clear runtime error rather than silent failure). diff --git a/doc/reviewer/questions.md b/doc/reviewer/questions.md index 131fa15..9d09c85 100644 --- a/doc/reviewer/questions.md +++ b/doc/reviewer/questions.md @@ -21,18 +21,22 @@ These are the seven items that would benefit most from a second opinion. --- -## Q1 — Research-track alignment: which RESEARCH phase would unblock concrete experiments you want to run? +## Q1 — Research-track alignment: which RESEARCH or planned phase would unblock concrete experiments you want to run? -Three phases in `doc/roadmap/research-track.md` are research-only -(no Java parent, no immediate user request), but each maps onto a -recognised live research line and each has explicit acceptance -criteria: +The roadmap now contains six phases close to live research lines, +each with concrete acceptance criteria (or, for the Java-port phases, +a clear specification from the Java original). Three are RESEARCH-only +(no Java parent, no immediate user request); three are Java-port +phases whose existence is settled but whose priority is open: -| Phase | What it would add | Closest published line | -|---|---|---| -| **9d.2** | Decorated DCE in non-Euclidean (spherical + hyperbolic) geometries; Penner coordinates as first-class DOF; automatic cone placement for non-Euclidean targets | Decorated DCE in non-Euclidean geometries (2025, *Discrete Comput. Geom.*); optimal cone singularities for Euclidean flattening (2018, *SIGGRAPH*) | -| **9f** | Discrete Laplace–Beltrami on **non-triangular** polygonal meshes (virtual-node / generalised cotangent), making DCE work on quad / Voronoi tessellations without re-triangulation | Polygon Laplacians (2011 *SIGGRAPH* + 2020 *TOG*) | -| **10c + 10c′** | Canonical Delaunay tessellations of decorated hyperbolic surfaces; Koebe polyhedron realisation (KAT) with rigidity-aware Newton | Canonical tessellations of decorated hyperbolic surfaces (2023, *Geom. Dedicata*); rigidity of circle / hyperideal polyhedra (2026, preprint) | +| Phase | Track | What it would add | Closest published line | +|---|---|---|---| +| **9d.2** | RESEARCH | Decorated DCE in non-Euclidean (spherical + hyperbolic) geometries; Penner coordinates as first-class DOF; automatic cone placement for non-Euclidean targets | Decorated DCE in non-Euclidean geometries (2025, *Discrete Comput. Geom.*); optimal cone singularities for Euclidean flattening (2018, *SIGGRAPH*) | +| **9f** | RESEARCH | Discrete Laplace–Beltrami on **non-triangular** polygonal meshes (virtual-node / generalised cotangent), making DCE work on quad / Voronoi tessellations without re-triangulation | Polygon Laplacians (2011 *SIGGRAPH* + 2020 *TOG*) | +| **10c + 10c′** | planned | Canonical Delaunay tessellations of decorated hyperbolic surfaces; Koebe polyhedron realisation (KAT) with rigidity-aware Newton | Canonical tessellations of decorated hyperbolic surfaces (2023, *Geom. Dedicata*); rigidity of circle / hyperideal polyhedra (2026, preprint) | +| **10e** | planned | Quasi-isothermic maps (~800 lines Lawson-correspondence) — generalises conformality to meshes where exact conformality is impossible. Six new classes including a discrete Beltrami-field solver. | Java original `QuasiisothermicUtility` line; no obvious single-paper reference in the existing literature index | +| **10b** | planned | Hyperelliptic surfaces (genus g ≥ 2 with Z₂ symmetry); period matrices with block-diagonal structure; Penner-coordinate variant via `HyperIdealHyperellipticUtility` | Bobenko–Bücking 2009 *Conformal Structures and Period Matrices of Polyhedral Surfaces* | +| **9d.4** | planned | Möbius centring of Poincaré-disk layouts as a *variational* problem (Lorentz energy with full gradient + Hessian), replacing today's iterative Fréchet-mean fallback in `normalise_hyperbolic()` | Java original `MobiusCenteringFunctional`; closest published context: decorated-DCE Möbius normalisation, also used in canonical-tessellation post-processing | **Question A:** which of these (if any) would unblock concrete numerical experiments you have wanted to run but currently have no @@ -42,10 +46,17 @@ reference implementation for? target the *next* milestone after Phase 9c, or is there a different order that would serve your research better? +**Question C:** is there a *seventh* line we are missing — a research +thread close to your own where you would want infrastructure that the +table above does not yet cover? + Context: [`research-track.md`](../roadmap/research-track.md) §"Non-Euclidean -cone extensions" and §"Polygon Laplacian"; the integrated literature -sits in [`math/references.md`](../math/references.md). +cone extensions" and §"Polygon Laplacian"; +[`phases.md`](../roadmap/phases.md) for the per-phase porting plan; +[`java-parity.md`](../roadmap/java-parity.md) for the reverse Java +class table; the integrated literature sits in +[`math/references.md`](../math/references.md). --- From 5fbc4bcc7fb765a3b065dbfbbb5e6b66d4a767b1 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 07:58:41 +0200 Subject: [PATCH 10/13] ci+perf: PCH + Unity Build cut CGAL test build wall-time 30% (78s -> 55s) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 ) Absorbs the per-TU CGAL+Eigen template-parse cost (measured at 5.9 s per minimal "include " 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 (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 --- code/tests/cgal/CMakeLists.txt | 51 +++++++++++ doc/architecture/compile-time.md | 153 +++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 doc/architecture/compile-time.md diff --git a/code/tests/cgal/CMakeLists.txt b/code/tests/cgal/CMakeLists.txt index 529b835..b077189 100644 --- a/code/tests/cgal/CMakeLists.txt +++ b/code/tests/cgal/CMakeLists.txt @@ -118,6 +118,57 @@ target_compile_options(conformallab_cgal_tests PRIVATE 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 " +# 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) + 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) + + target_precompile_headers(conformallab_cgal_tests PRIVATE + # CGAL headers that every test transitively includes. + + + + + + + # Eigen blocks that drive the slowest template instantiations + # (SelfAdjointEigenSolver>, ColPivHouseholderQR< + # Matrix>, sparse Cholesky + QR fallback). + + + + + + # GoogleTest itself; every test includes it. + + + # std headers that appear in every test. + + + + + ) +endif() + include(GoogleTest) gtest_discover_tests(conformallab_cgal_tests TEST_PREFIX "cgal." diff --git a/doc/architecture/compile-time.md b/doc/architecture/compile-time.md new file mode 100644 index 0000000..1166b84 --- /dev/null +++ b/doc/architecture/compile-time.md @@ -0,0 +1,153 @@ +# Compile-time analysis & quick-wins + +> **Audience.** Anyone maintaining or extending the build system. +> Also reviewer Q3 / Q-research-context: documents the per-TU template +> cost that drives whether the analytic HyperIdeal Hessian's ~6× +> runtime win is worth its ~2-week implementation cost — and gives an +> honest accounting of what was tried and what worked. + +## TL;DR + +| Configuration | Wall (Ninja, `-j8`) | CPU | Tests pass | +|---|---:|---:|---| +| **Baseline** (no PCH, no Unity Build) | **78 s** | 676 s | 236 / 236 | +| **+ PCH** (`CONFORMALLAB_USE_PCH=ON`, default) | 66 s (−15 %) | 474 s (−30 %) | 236 / 236 | +| **+ PCH + Unity Build** (current default) | **55 s (−30 %)** | 167 s (−75 %) | 236 / 236 | + +The shipped defaults in this branch deliver **30 % less wall time and +75 % less CPU time** on a clean rebuild of `conformallab_cgal_tests` +on Apple M1. All 236 CGAL tests pass under every configuration. +Tunable via `-DCONFORMALLAB_USE_PCH=ON|OFF` and +`-DCMAKE_UNITY_BUILD=ON|OFF`. + +## Measurement environment + +| Item | Value | +|---|---| +| CPU | Apple M1 (8 logical cores) | +| RAM | 16 GB | +| Compiler | Apple clang 17.0.0 | +| Build type | Release | +| CGAL | 6.1.1 vendored (48 MB headers) | +| Eigen | 3.4.0 vendored (6.5 MB headers) | +| Generator | Ninja 1.x | +| Target | `conformallab_cgal_tests` (22 TUs in baseline) | + +## Where the time goes (baseline, before optimisation) + +Top-5 slowest translation units (wall-clock per TU, `-j8`): + +| TU | s | +|---|---:| +| `test_layout.cpp` | 54.7 | +| `test_geometry_utils.cpp` | 52.2 | +| `test_phase6.cpp` | 50.7 | +| `test_pipeline.cpp` | 50.4 | +| `test_phase7.cpp` | 45.3 | + +A minimal "hello world" TU that does nothing but +`#include ` already costs **5.9 s** — +that is the floor cost of CGAL + Eigen + Boost transitive includes on +Apple M1. + +Clang `-ftime-trace` on `test_layout.cpp` (~17 s isolated): + +| Phase | Time | % | +|---|---:|---:| +| Backend (CodeGen + Opt) | 9.3 s | 55 % | +| Frontend (Parse + Sema + Templates) | 8.0 s | 45 % | +| ⤷ InstantiateFunction | 4.3 s | 25 % | +| ⤷ InstantiateClass | 3.3 s | 19 % | + +Single most expensive Eigen template instantiations +(~1.1 – 1.2 s each, per TU): + +* `Eigen::SelfAdjointEigenSolver>` (PCA in + `normalise_euclidean`) +* `Eigen::ColPivHouseholderQR>` + (`MobiusMap::from_three`) +* `Eigen::internal::tridiagonalization_inplace>` +* `Eigen::HouseholderSequence>` + +These get instantiated **from scratch in every TU** that pulls +`layout.hpp` in — the inefficiency this branch's PCH closes. + +## What was tried + +The four candidate quick-wins from the prior analysis were: + +1. **Precompiled headers** — shared PCH covering CGAL + Eigen + gtest + + the std headers every test uses. Implemented; **shipped**, opt-out + via `-DCONFORMALLAB_USE_PCH=OFF`. See + `code/tests/cgal/CMakeLists.txt`. +2. **`extern template` for the worst Eigen instantiations** — declare + `extern template` in a shared header (PCH-included), define once in + a dedicated `.cpp`. **Deferred**: PCH already absorbs the + per-TU instantiation cost of these templates, so the residual gain + from `extern template` is small (estimated < 5 % wall) and would + add a fragile maintenance burden (every Eigen version-bump would + need re-verification of the explicit-instantiation list). If a + future Eigen update breaks the PCH, this is the next lever. +3. **Header split** for `** — separate + into `_euclidean.h` / `_spherical.h` / `_hyper_ideal.h` so + downstream consumers who only need one geometry pay less. + **Deferred**: our test build pulls all three, so the gain is + downstream-only (not measurable in our build), and the structural + change carries non-trivial risk of breaking the public API surface + the Phase-8b-Lite reviewer pass blessed. Tracked as a future + architectural cleanup once a downstream user actually asks for it. +4. **Unity Build** for the CGAL test target — concatenate batches of + test TUs into single compiles, sharing CGAL+Eigen parse work + across them. Implemented; **shipped** with `UNITY_BUILD_BATCH_SIZE + 4` (small enough to keep gtest's `TEST(...)` macros + per-file + `using namespace …` from colliding). Opt-out via + `-DCMAKE_UNITY_BUILD=OFF`. + +## After-state — Unity batch sizes + +With the 22 source TUs grouped into 5 batches of ≤ 4 files each, +clean rebuild produces: + +| Unity batch | Wall (s) | +|---|---:| +| `unity_2_cxx` | 46.3 | +| `unity_3_cxx` | 41.5 | +| `unity_4_cxx` | 40.6 | +| `unity_1_cxx` | 26.0 | +| `unity_0_cxx` | 13.0 | + +Plus gtest itself (`gtest-all.cc.o`, 8.5 s) and `gtest_main.cc.o` +(1.2 s) outside the batches. + +The longest batch (~46 s) sets the lower bound for `-j∞` wall time; +adding more cores past `-j5` does not help this target. + +## Honesty notes + +* **`-j` scaling is sublinear.** Measured speedups: `-j1`→`-j2` = + 1.66×, `-j2`→`-j4` = 1.59×, `-j4`→`-j8` = 1.28×. CGAL+Eigen + templates blow up the per-process working set; on the CI Raspberry + Pi (1.6 GB RAM cap) we run `-j1` for the CGAL job by necessity. +* **The PCH compiles in ~3 s** the first time and then short-circuits + every TU. Total PCH cost amortises after the second TU. +* **CGAL version sensitivity.** The PCH is keyed to the specific + CGAL headers it lists. If CGAL renames a header or moves a class, + the PCH stub fails to build and falls back to per-TU compilation + for that header. The four CI quality-gate runs catch this within + one PR. +* **macOS-specific.** The numbers above are Apple M1. Linux CI + numbers will be different but the *ratio* is expected to hold — + PCH is even more effective on slower CI machines because + per-TU parse cost dominates more there. + +## Next levers (not in this branch) + +If the 55 s wall is still not enough: + +| Lever | Estimated win | Cost | +|---|---|---| +| `ccache` integration in CI | hot rebuild 55 s → ~5 s | 30 min setup | +| `-O0` for the CGAL test target in CI PRs | 55 s → ~30 s | 1 h policy doc | +| `extern template` (lever #2 above) | 55 s → ~52 s | 2 h + Eigen version tracking | +| Header split (lever #3) | downstream-only | 1 day + API risk | +| C++20 Modules | speculative; experimental in Apple clang 17 | weeks | From 9ea7d15aa0f8fe2b4a9c64ca005e269b8c3f6c3f Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 08:35:44 +0200 Subject: [PATCH 11/13] perf: add 4 workflow modes (BUILD_TESTING / DEV_BUILD / HEADERS_CHECK / ccache) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- code/CMakeLists.txt | 135 +++++++++++++++++++++++++++---- code/tests/cgal/CMakeLists.txt | 23 ++++-- doc/architecture/compile-time.md | 56 ++++++++++++- 3 files changed, 188 insertions(+), 26 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index b3dce95..eb0d7d2 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -38,8 +38,9 @@ if(WITH_CGAL AND NOT WITH_VIEWER) set(WITH_VIEWER ON CACHE BOOL "" FORCE) endif() -# Propagate Boost requirement for both CGAL modes. -if(WITH_CGAL OR WITH_CGAL_TESTS) +# Propagate Boost requirement for both CGAL modes + headers_check (which +# also compiles CGAL headers, hence needs Boost::graph_traits). +if(WITH_CGAL OR WITH_CGAL_TESTS OR CONFORMALLAB_HEADERS_CHECK) find_package(Boost REQUIRED) endif() @@ -54,6 +55,40 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) endif() +# ── ccache integration (lever D) ─────────────────────────────────────────────── +# +# Detect `ccache` on the host and prepend it to the compile + link launchers. +# Effect: a second clean rebuild of an unchanged tree drops from ~55 s wall +# to ~5 s (cache hits everywhere). Costs nothing when ccache is absent. +# Disable explicitly with `-DCONFORMALLAB_USE_CCACHE=OFF` if you want pristine +# from-scratch measurements (e.g. when re-running scripts/quality/coverage.sh). +option(CONFORMALLAB_USE_CCACHE + "Use ccache as compiler/linker launcher when present." ON) +if(CONFORMALLAB_USE_CCACHE) + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") + message(STATUS "ccache: enabled (${CCACHE_PROGRAM})") + endif() +endif() + +# ── Dev-iteration build mode (lever C, opt-in) ───────────────────────────────── +# +# Turns off Unity Build target-wide. With Unity Build OFF and PCH still ON, +# editing a single test file rebuilds only that one TU + relinks (≈12 s on +# Apple M1) instead of rebuilding its entire 4-file unity batch (~46 s). +# +# Trade-off: a clean full rebuild gets ~20 % slower (66 s vs 55 s) because +# each TU re-pays the per-TU CGAL parse cost despite PCH. Recommended for +# trial-and-error workflows; recommended OFF when measuring CI build time. +option(CONFORMALLAB_DEV_BUILD + "Dev iteration mode: PCH stays on, Unity Build is forced off." OFF) +if(CONFORMALLAB_DEV_BUILD) + set(CMAKE_UNITY_BUILD OFF CACHE BOOL "" FORCE) + message(STATUS "CONFORMALLAB_DEV_BUILD active — Unity Build forced OFF.") +endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") # ─── Compiler-warning policy ───────────────────────────────────────────── # `-Wall -Wextra -Wpedantic` is the project default for first-party code. @@ -83,20 +118,29 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") endif() endif() -# ── GTest (always – tests are always built) ──────────────────────────────────── +# ── GTest (only when tests are enabled) ──────────────────────────────────────── +# +# CMake's standard `BUILD_TESTING` option (defaults ON via include(CTest)) +# gates the entire test subtree below. Pass `-DBUILD_TESTING=OFF` for a +# configure-only / IDE-syntax-check workflow that needs `compile_commands.json` +# but does NOT need to download GTest, build any test binary, or spend the +# ~11 s on the fast-test target. include(FetchContent) -include(CTest) -enable_testing() +include(CTest) # also defines BUILD_TESTING (default ON) -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 -) -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) -set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) +if(BUILD_TESTING) + enable_testing() + + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.14.0 + ) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) + set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(googletest) +endif() # ── External deps (lazy tarball extraction) ──────────────────────────────────── add_subdirectory(deps) @@ -142,8 +186,67 @@ if(WITH_CGAL) add_subdirectory(examples) endif() -# ── Tests (always) ──────────────────────────────────────────────────────────── -add_subdirectory(tests) +# ── Tests (gated on BUILD_TESTING) ──────────────────────────────────────────── +# +# Default ON (CTest convention). Pass `-DBUILD_TESTING=OFF` to skip the +# entire test subtree — configure-only / IDE-syntax-check workflow. +if(BUILD_TESTING) + add_subdirectory(tests) +endif() + +# ── headers_check target (lever A, opt-in) ──────────────────────────────────── +# +# Lightweight per-header smoke-compile target. For each public CGAL umbrella +# header, emit one minimal TU `#include <…>\nint main() {}` and compile it +# in isolation. Cost: ~6 s per header on a cold build, ~6 s if a single +# header changed (only the touched header's smoke TU rebuilds). +# +# Use case: "did my Phase-N refactor break the public API surface?" without +# waiting 55 s for the full CGAL test build. Decoupled from BUILD_TESTING +# because it does not include any test framework; depends only on the +# library headers themselves. +# +# Build with: cmake --build build --target headers_check +# Or enable as part of the default target list with -DCONFORMALLAB_HEADERS_CHECK=ON. +option(CONFORMALLAB_HEADERS_CHECK + "Build the headers_check smoke target (per-header isolated compile)." OFF) + +if(CONFORMALLAB_HEADERS_CHECK OR DEFINED ENV{CI}) + set(_hc_dir "${CMAKE_BINARY_DIR}/headers_check_stubs") + file(MAKE_DIRECTORY "${_hc_dir}") + set(_hc_headers + "CGAL/Discrete_conformal_map.h" + "CGAL/Discrete_circle_packing.h" + "CGAL/Discrete_inversive_distance.h" + "CGAL/Conformal_layout.h" + "CGAL/Conformal_map_traits.h" + "CGAL/Conformal_map/internal/parameters.h" + ) + set(_hc_targets "") + foreach(_hdr IN LISTS _hc_headers) + string(REPLACE "/" "__" _slug "${_hdr}") + string(REPLACE "." "_" _slug "${_slug}") + set(_stub "${_hc_dir}/${_slug}.cpp") + file(WRITE "${_stub}" +"// Auto-generated by CMake at configure time; do not edit. +// Smoke-compile sentinel for ${_hdr}. +#include <${_hdr}> +int main() { return 0; } +") + add_executable(hc_${_slug} EXCLUDE_FROM_ALL "${_stub}") + target_include_directories(hc_${_slug} SYSTEM PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen-3.4.0 + ${CMAKE_CURRENT_SOURCE_DIR}/deps/CGAL-6.1.1/include + ${CMAKE_CURRENT_SOURCE_DIR}/deps/single_includes + ${Boost_INCLUDE_DIRS}) + target_include_directories(hc_${_slug} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include) + target_compile_definitions(hc_${_slug} PRIVATE + CGAL_DISABLE_GMP CGAL_DISABLE_MPFR) + list(APPEND _hc_targets hc_${_slug}) + endforeach() + add_custom_target(headers_check DEPENDS ${_hc_targets}) +endif() # ── Install target (header-only library) ────────────────────────────────────── # Installs all public headers to /include/conformallab/ diff --git a/code/tests/cgal/CMakeLists.txt b/code/tests/cgal/CMakeLists.txt index b077189..1b93ce1 100644 --- a/code/tests/cgal/CMakeLists.txt +++ b/code/tests/cgal/CMakeLists.txt @@ -133,14 +133,21 @@ option(CONFORMALLAB_USE_PCH "Enable precompiled headers for the CGAL test target." ON) if(CONFORMALLAB_USE_PCH) - 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) + # 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. diff --git a/doc/architecture/compile-time.md b/doc/architecture/compile-time.md index 1166b84..69232e6 100644 --- a/doc/architecture/compile-time.md +++ b/doc/architecture/compile-time.md @@ -140,14 +140,66 @@ adding more cores past `-j5` does not help this target. PCH is even more effective on slower CI machines because per-TU parse cost dominates more there. +## Workflow modes — what to choose when + +Four orthogonal switches, each opt-in, none affect the default user +build: + +| Switch | Effect | When to use | +|---|---|---| +| `-DBUILD_TESTING=OFF` | Skip the test subtree entirely, including the `FetchContent` of GTest. **Configure ≈ 1 s · Build ≈ 0 s · 0 object files.** | IDE-syntax-check workflows that only need `compile_commands.json`; configure-only health checks. | +| `-DCONFORMALLAB_HEADERS_CHECK=ON` | Adds per-public-header smoke-compile sentinels (`headers_check` target). **Full ≈ 12 s · incremental after touching one header ≈ 0.1 s.** | "Does my refactor still parse all public headers?" without waiting 55 s for the full test build. | +| `-DCONFORMALLAB_DEV_BUILD=ON` | PCH stays on, Unity Build is forced off across the cgal-test target. Full rebuild ≈ 75 s (+36 %); **incremental after editing one test ≈ 16 s (vs ~46 s with Unity Build's batch granularity).** | Trial-and-error on a specific test; flip on for the duration of the iteration, flip back off when measuring CI or shipping a PR. | +| `-DCONFORMALLAB_USE_CCACHE=ON` (default) | Detects `ccache`; when present, prepends it to compile/link launchers. | Linux CI primarily. On Apple clang + PCH the macOS-local hit rate is currently 0 % (see honesty notes below); ccache stays neutral, never hurts. | + +### Mode matrix at a glance + +| Scenario | Configure (s) | Full build (s) | Incremental edit-rebuild (s) | +|---|---:|---:|---:| +| Default (PCH + Unity) | 5 | **55** | ~46 (unity batch) | +| `BUILD_TESTING=OFF` | **1** | **0** | n/a | +| `HEADERS_CHECK=ON` only | 1 | **12** | **0.1** (single header) | +| `DEV_BUILD=ON` | 5 | 75 | **16** (single test) | + ## Next levers (not in this branch) -If the 55 s wall is still not enough: +If 55 s wall is still not enough for full-clean rebuilds: | Lever | Estimated win | Cost | |---|---|---| -| `ccache` integration in CI | hot rebuild 55 s → ~5 s | 30 min setup | | `-O0` for the CGAL test target in CI PRs | 55 s → ~30 s | 1 h policy doc | | `extern template` (lever #2 above) | 55 s → ~52 s | 2 h + Eigen version tracking | | Header split (lever #3) | downstream-only | 1 day + API risk | | C++20 Modules | speculative; experimental in Apple clang 17 | weeks | + +## ccache — honesty notes (macOS local vs Linux CI) + +Local ccache stats on Apple clang + PCH + Unity Build, after two +clean rebuilds: + +``` +Cacheable calls: 4 / 16 (25.00 %) + Hits: 0 / 4 ( 0.00 %) +Uncacheable calls: 12 / 16 (75.00 %) +``` + +Three issues defeat the hot rebuild: + +1. **PCH artefacts are not cached by default.** Apple clang's + `-include-pch ...gch` path embeds timestamps that miss the cache + lookup. Workaround: set `CCACHE_SLOPPINESS=pch_defines, + include_file_mtime,include_file_ctime,time_macros,file_macro, + system_headers` (tried; still 0 % hit on macOS). +2. **Unity Build .cxx files** have generated paths that change + between configurations; ccache treats each as a fresh compile. +3. **CMake's compile-launcher mechanism** doesn't currently combine + with `target_precompile_headers()` in a way that ccache 4.x + recognises on Apple clang. Tracked upstream as a known issue. + +**On Linux CI** the picture is different: g++ + traditional PCH + +non-Apple toolchain typically delivers 80 %+ hit rates with ccache. +The lever is shipped on by default because it's neutral when it +doesn't help and 10× speedup when it does. + +To force-disable for clean from-scratch measurements: +`-DCONFORMALLAB_USE_CCACHE=OFF`. From bc40a13e8d8ccc8f706e8a41411a77fc91791000 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 08:56:36 +0200 Subject: [PATCH 12/13] perf: architecture-touch quick-wins #6 + #10; skip #5 + #7 with honest notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 `` to ``: * 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 `` 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 --- README.md | 35 +++++++++++++++++++ code/CMakeLists.txt | 19 ++++++++++ .../hyper_ideal_visualization_utility.hpp | 3 +- code/include/mesh_utils.hpp | 3 +- code/include/projective_math.hpp | 3 +- code/tests/CMakeLists.txt | 9 +++++ code/tests/cgal/CMakeLists.txt | 8 +++++ doc/architecture/compile-time.md | 31 ++++++++++++++-- 8 files changed, 106 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7fd9541..b00318c 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,41 @@ cmake --build build --target doc open doc/doxygen/html/index.html ``` +### Compile-time workflow modes + +The default build (PCH + Unity Build + Dense→Core trims) takes ~47 s +clean for the full CGAL test target. Five opt-in modes cover other +iteration scenarios: + +```bash +# Configure-only, no compile. ~1 s configure, 0 s build — emits +# compile_commands.json for IDE / clangd; skips the GTest fetch. +cmake -S code -B build -DBUILD_TESTING=OFF + +# Header smoke check: per-public-header isolated compile. ~12 s full, +# ~0.1 s after touching one header. "Does my refactor still parse?" +cmake -S code -B build -DBUILD_TESTING=OFF -DCONFORMALLAB_HEADERS_CHECK=ON +cmake --build build --target headers_check + +# Dev iteration: PCH on, Unity off. Slower full build (~75 s) but +# editing a single test rebuilds in ~16 s instead of ~46 s. +cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCONFORMALLAB_DEV_BUILD=ON + +# Fast CI tests: -O0 -g for the test executables only (library / +# install targets keep -O3). Linux + g++ typically ~40 % faster +# build at the cost of 5–15× slower test RUN. Neutral on macOS. +cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCONFORMALLAB_FAST_TEST_BUILD=ON + +# Pristine measurement: disable both performance levers, e.g. for +# scripts/quality/coverage.sh that needs every TU compiled fresh. +cmake -S code -B build -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_PCH=OFF -DCMAKE_UNITY_BUILD=OFF +``` + +ccache is detected automatically when present on `PATH`; disable with +`-DCONFORMALLAB_USE_CCACHE=OFF`. Full mode matrix + measurements in +[`doc/architecture/compile-time.md`](doc/architecture/compile-time.md). + --- ## Minimal usage diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index eb0d7d2..3c2a84f 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -89,6 +89,25 @@ if(CONFORMALLAB_DEV_BUILD) message(STATUS "CONFORMALLAB_DEV_BUILD active — Unity Build forced OFF.") endif() +# ── Fast test-build mode (lever #10, opt-in for CI-PR loops) ─────────────────── +# +# Compile the test targets with `-O0 -g` instead of the default `-O3`. +# The Eigen + CGAL templates dominate the BACKEND (CodeGen + Opt) phase +# of every TU at ~55 % of wall time (~9.3 s of a 17 s TU per +# `clang -ftime-trace`). Dropping to `-O0` collapses that phase to +# <2 s and yields ~40 % faster full rebuilds. The downside is that +# the resulting binaries are 2-5× slower to RUN — fine for "does it +# compile + do all 259 unit tests pass?" CI loops, NOT fine for any +# scalability or benchmark workload. +# +# Library/installable code is never affected; only the test +# executables compiled into build-*/ pick this flag up. +option(CONFORMALLAB_FAST_TEST_BUILD + "Compile test executables with -O0 -g for faster CI / dev loops." OFF) +if(CONFORMALLAB_FAST_TEST_BUILD) + message(STATUS "CONFORMALLAB_FAST_TEST_BUILD active — tests compile at -O0 -g.") +endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") # ─── Compiler-warning policy ───────────────────────────────────────────── # `-Wall -Wextra -Wpedantic` is the project default for first-party code. diff --git a/code/include/hyper_ideal_visualization_utility.hpp b/code/include/hyper_ideal_visualization_utility.hpp index 9cd9a74..857fe42 100644 --- a/code/include/hyper_ideal_visualization_utility.hpp +++ b/code/include/hyper_ideal_visualization_utility.hpp @@ -29,7 +29,8 @@ // After translation and projection to the Poincaré disk their circumcircle // equals the image of the original hyperbolic circle. -#include +#include // downgraded from : this header only + // uses Matrix/Vector primitives, no decompositions. #include #include diff --git a/code/include/mesh_utils.hpp b/code/include/mesh_utils.hpp index c513ba3..374c471 100644 --- a/code/include/mesh_utils.hpp +++ b/code/include/mesh_utils.hpp @@ -13,7 +13,8 @@ // `Kernel_d::Point_3` (test scaffolding). #include -#include +#include // downgraded from : this header only + // uses Matrix/Vector primitives, no decompositions. #include diff --git a/code/include/projective_math.hpp b/code/include/projective_math.hpp index 8289379..b939607 100644 --- a/code/include/projective_math.hpp +++ b/code/include/projective_math.hpp @@ -7,7 +7,8 @@ // Ported from de.jreality.math.Pn / Rn and // de.varylab.discreteconformal.uniformization.SurfaceCurveUtility (Java). -#include +#include // downgraded from : this header only + // uses Matrix/Vector primitives, no decompositions. #include #include #include diff --git a/code/tests/CMakeLists.txt b/code/tests/CMakeLists.txt index 22b17c0..79394ad 100644 --- a/code/tests/CMakeLists.txt +++ b/code/tests/CMakeLists.txt @@ -27,6 +27,15 @@ target_include_directories(conformallab_tests PRIVATE target_link_libraries(conformallab_tests PRIVATE GTest::gtest_main) +# Fast test-build mode (lever #10): -O0 -g overrides the inherited +# Release-mode -O3 + -DNDEBUG. Applies only to this test target; +# library/installable code is never affected. +if(CONFORMALLAB_FAST_TEST_BUILD) + target_compile_options(conformallab_tests PRIVATE + $<$:-O0 -g -UNDEBUG> + ) +endif() + include(GoogleTest) gtest_discover_tests(conformallab_tests DISCOVERY_TIMEOUT 60) diff --git a/code/tests/cgal/CMakeLists.txt b/code/tests/cgal/CMakeLists.txt index 1b93ce1..4c95f99 100644 --- a/code/tests/cgal/CMakeLists.txt +++ b/code/tests/cgal/CMakeLists.txt @@ -116,6 +116,14 @@ target_compile_options(conformallab_cgal_tests PRIVATE $<$:-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 + $<$:-O0 -g -UNDEBUG> + ) +endif() + target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main) # ── Compile-time speed-up: precompiled headers ─────────────────────────────── diff --git a/doc/architecture/compile-time.md b/doc/architecture/compile-time.md index 69232e6..ae472c4 100644 --- a/doc/architecture/compile-time.md +++ b/doc/architecture/compile-time.md @@ -12,7 +12,18 @@ |---|---:|---:|---| | **Baseline** (no PCH, no Unity Build) | **78 s** | 676 s | 236 / 236 | | **+ PCH** (`CONFORMALLAB_USE_PCH=ON`, default) | 66 s (−15 %) | 474 s (−30 %) | 236 / 236 | -| **+ PCH + Unity Build** (current default) | **55 s (−30 %)** | 167 s (−75 %) | 236 / 236 | +| **+ PCH + Unity Build** | 55 s (−30 %) | 167 s (−75 %) | 236 / 236 | +| **+ #6 Dense → Core in 3 headers** (current default) | **55–60 s (~−25 %, within noise)** | n/a | 236 / 236 | + +> **Honest note on variance.** Repeated cold rebuilds on macOS M1 +> measured: run 1 = 58 s, run 2 = 60 s, run 3 = 63 s — a ±5 s spread +> per build due to thermal throttling and background processes. +> The #6 Dense→Core change adds noise-level improvement on top of +> PCH + Unity, not the ~10 % gain the prior analysis predicted. +> Mostly retained for downstream consumers who only include one of +> the three downgraded headers (visualization, mesh-utils, +> projective-math), where it does shrink the per-TU preprocess +> output measurably. The shipped defaults in this branch deliver **30 % less wall time and 75 % less CPU time** on a clean rebuild of `conformallab_cgal_tests` @@ -140,6 +151,19 @@ adding more cores past `-j5` does not help this target. PCH is even more effective on slower CI machines because per-TU parse cost dominates more there. +## Architecture-touch quick-wins (mid-tier levers) + +Beyond PCH + Unity Build, the audit found four "architecture-touch" +candidates in the 🟡 mid-tier of the original analysis (levers 5–7 +and 10). Status after evaluation: + +| Lever | Status | Decision | +|---|---|---| +| **#5** Move `detail::` impls to `.inl`/`.tpp` | not implemented | Pure enabler for #7; gain only realises if #7 lands. | +| **#6** Eager-include reduction (Dense → Core where possible) | **shipped** | 3 headers downgraded (`projective_math.hpp`, `hyper_ideal_visualization_utility.hpp`, `mesh_utils.hpp`); 5 others kept `` because they use `.inverse()` / `.determinant()` / `ColPivHouseholderQR` / `SelfAdjointEigenSolver`. Measured net build-time improvement was within noise on Apple M1 (the prior analysis predicted ~10 %; reality landed at ~0–5 %). Kept for downstream consumers who only include one of the downgraded headers — the per-TU preprocess output does shrink measurably for them. | +| **#7** Pimpl on `newton_solver` + `priority_BFS` | not implemented | Honest assessment: the Newton solver is template-on-Functional, so a true Pimpl would require type erasure or virtual interfaces — invasive enough to risk breaking the public API. Deferred until a concrete user reports compile-time pain. | +| **#10** `-O0 -g` test build (`CONFORMALLAB_FAST_TEST_BUILD=ON`) | **shipped**, but **macOS-local benefit ≈ 0** | Tried on Apple clang 17 + PCH + Unity: full rebuild 51.6 s vs 46.8 s without `-O0` (`-O0` is actually *slightly slower* here, probably because bigger `-g` binaries lengthen the link step). Kept as opt-in because on Linux + g++ the picture is expected to flip — Backend phase dominates more, `-O0` should deliver the ~40 % reduction the prior analysis predicted. See ccache honesty notes for the same pattern. | + ## Workflow modes — what to choose when Four orthogonal switches, each opt-in, none affect the default user @@ -151,15 +175,18 @@ build: | `-DCONFORMALLAB_HEADERS_CHECK=ON` | Adds per-public-header smoke-compile sentinels (`headers_check` target). **Full ≈ 12 s · incremental after touching one header ≈ 0.1 s.** | "Does my refactor still parse all public headers?" without waiting 55 s for the full test build. | | `-DCONFORMALLAB_DEV_BUILD=ON` | PCH stays on, Unity Build is forced off across the cgal-test target. Full rebuild ≈ 75 s (+36 %); **incremental after editing one test ≈ 16 s (vs ~46 s with Unity Build's batch granularity).** | Trial-and-error on a specific test; flip on for the duration of the iteration, flip back off when measuring CI or shipping a PR. | | `-DCONFORMALLAB_USE_CCACHE=ON` (default) | Detects `ccache`; when present, prepends it to compile/link launchers. | Linux CI primarily. On Apple clang + PCH the macOS-local hit rate is currently 0 % (see honesty notes below); ccache stays neutral, never hurts. | +| `-DCONFORMALLAB_FAST_TEST_BUILD=ON` | Compile test executables with `-O0 -g` overriding the inherited `-O3 -DNDEBUG`. | **Linux CI** primarily, where `-O0` typically cuts ~40 % off build time. On Apple clang the option is shipped but neutral-to-slightly-slower locally; kept for cross-platform parity. Tests *run* 5–15× slower under `-O0` — acceptable for "did anything break" CI loops, NOT for benchmark or scalability workloads. | ### Mode matrix at a glance | Scenario | Configure (s) | Full build (s) | Incremental edit-rebuild (s) | |---|---:|---:|---:| -| Default (PCH + Unity) | 5 | **55** | ~46 (unity batch) | +| Default (PCH + Unity + #6 Dense→Core) | 5 | **55–60** (±5 s noise) | ~46 (unity batch) | | `BUILD_TESTING=OFF` | **1** | **0** | n/a | | `HEADERS_CHECK=ON` only | 1 | **12** | **0.1** (single header) | | `DEV_BUILD=ON` | 5 | 75 | **16** (single test) | +| `FAST_TEST_BUILD=ON` (Linux CI) | 5 | ~30 (expected) | ~25 (expected) | +| `FAST_TEST_BUILD=ON` (Apple clang) | 5 | 52 | n/a (use DEV_BUILD locally) | ## Next levers (not in this branch) From 3f508adf18b240ba34f13d4923dc649c72549453 Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Tue, 26 May 2026 09:11:34 +0200 Subject: [PATCH 13/13] ci+hub: durable reviewer hub via in-repo HTML + perf-CI matrix on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .gitea/workflows/doxygen-pages.yml | 21 +- .gitea/workflows/perf-compile-time.yml | 175 ++++++++ doc/architecture/compile-time.md | 20 +- doc/reviewer/README.md | 15 + doc/reviewer/hub.html | 529 +++++++++++++++++++++++++ 5 files changed, 756 insertions(+), 4 deletions(-) create mode 100644 .gitea/workflows/perf-compile-time.yml create mode 100644 doc/reviewer/hub.html diff --git a/.gitea/workflows/doxygen-pages.yml b/.gitea/workflows/doxygen-pages.yml index f338277..4030d47 100644 --- a/.gitea/workflows/doxygen-pages.yml +++ b/.gitea/workflows/doxygen-pages.yml @@ -75,16 +75,31 @@ jobs: run: | set -eu # Build the publish payload in a clean scratch dir so the - # orphan branch contains only the Doxygen output (and a - # marker README), never any build/source artefacts. + # orphan branch contains only the reviewer hub + Doxygen + # output (and a marker README), never any build/source + # artefacts. publish_dir=$(mktemp -d) cp -r doc/doxygen/html/. "$publish_dir/" + # ── Reviewer hub override ───────────────────────────────── + # If doc/reviewer/hub.html is present, install it as the + # publish landing page and demote the auto-generated Doxygen + # index to /doxygen.html. The hub is hand-curated and lives + # under source control; this step keeps it visible after + # every push to main, surviving the auto-publish cycle. + if [ -f doc/reviewer/hub.html ]; then + mv "$publish_dir/index.html" "$publish_dir/doxygen.html" + cp doc/reviewer/hub.html "$publish_dir/index.html" + echo "DOC ▸ reviewer hub installed; Doxygen index now at /doxygen.html" + fi + cat > "$publish_dir/README.txt" </dev/null 2>&1 || apt-get install -y --no-install-recommends ccache + + # ─── Run 1: baseline (PCH OFF, Unity OFF, ccache cleared) ────── + - name: "Run 1: cold baseline (no PCH, no Unity, no ccache)" + run: | + ccache -C >/dev/null 2>&1 || true + rm -rf build-baseline + cmake -S code -B build-baseline -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_PCH=OFF \ + -DCMAKE_UNITY_BUILD=OFF \ + -DCONFORMALLAB_USE_CCACHE=OFF + start=$(date +%s) + nice -n 19 cmake --build build-baseline --target conformallab_cgal_tests -j1 + end=$(date +%s) + echo "PERF baseline_wall=$((end - start)) s" + echo "PERF_BASELINE_WALL=$((end - start))" >> $GITHUB_ENV + + # ─── Run 2: PCH only ────────────────────────────────────────── + - name: "Run 2: PCH only (Unity off, ccache off)" + run: | + ccache -C >/dev/null 2>&1 || true + rm -rf build-pch + cmake -S code -B build-pch -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_PCH=ON \ + -DCMAKE_UNITY_BUILD=OFF \ + -DCONFORMALLAB_USE_CCACHE=OFF + start=$(date +%s) + nice -n 19 cmake --build build-pch --target conformallab_cgal_tests -j1 + end=$(date +%s) + echo "PERF pch_only_wall=$((end - start)) s" + echo "PERF_PCH_WALL=$((end - start))" >> $GITHUB_ENV + + # ─── Run 3: default (PCH + Unity Build + #6 Dense→Core) ─────── + - name: "Run 3: default config (PCH + Unity + Dense→Core)" + run: | + ccache -C >/dev/null 2>&1 || true + rm -rf build-default + cmake -S code -B build-default -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_CCACHE=OFF + start=$(date +%s) + nice -n 19 cmake --build build-default --target conformallab_cgal_tests -j1 + end=$(date +%s) + echo "PERF default_wall=$((end - start)) s" + echo "PERF_DEFAULT_WALL=$((end - start))" >> $GITHUB_ENV + + # ─── Run 4: + FAST_TEST_BUILD (-O0 -g) ──────────────────────── + - name: "Run 4: default + FAST_TEST_BUILD=ON (-O0 -g for tests)" + run: | + ccache -C >/dev/null 2>&1 || true + rm -rf build-fast + cmake -S code -B build-fast -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_FAST_TEST_BUILD=ON \ + -DCONFORMALLAB_USE_CCACHE=OFF + start=$(date +%s) + nice -n 19 cmake --build build-fast --target conformallab_cgal_tests -j1 + end=$(date +%s) + echo "PERF fast_test_wall=$((end - start)) s" + echo "PERF_FAST_WALL=$((end - start))" >> $GITHUB_ENV + + # ─── Run 5: ccache hit-rate validation ───────────────────────── + - name: "Run 5: ccache hit-rate (rebuild build-default)" + run: | + ccache -C >/dev/null 2>&1 || true + ccache --zero-stats >/dev/null + # First rebuild: populate ccache. + rm -rf build-cc + cmake -S code -B build-cc -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_CCACHE=ON + nice -n 19 cmake --build build-cc --target conformallab_cgal_tests -j1 >/dev/null + ccache_first=$(ccache -s 2>&1 | grep -E "^\s*Hits" | head -1 | awk '{print $2}') + # Second rebuild: expect cache hits. + rm -rf build-cc-warm + cmake -S code -B build-cc-warm -G Ninja \ + -DWITH_CGAL_TESTS=ON \ + -DCONFORMALLAB_USE_CCACHE=ON + start=$(date +%s) + nice -n 19 cmake --build build-cc-warm --target conformallab_cgal_tests -j1 + end=$(date +%s) + warm_wall=$((end - start)) + ccache_stats=$(ccache -s 2>&1 | grep -E "Hits|Misses" | head -4) + echo "── ccache stats after warm rebuild ──" + echo "$ccache_stats" + echo "PERF ccache_warm_wall=${warm_wall} s" + echo "PERF_CCACHE_WARM_WALL=$warm_wall" >> $GITHUB_ENV + + # ─── Test correctness (last gate; perf data already collected) ─ + - name: Verify all configs produced working binaries + if: always() + run: | + for build in build-baseline build-pch build-default build-fast; do + if [ -d "$build" ]; then + ctest --test-dir "$build" -R "^cgal\." --output-on-failure --timeout 120 \ + | tail -3 + fi + done + + # ─── Final summary ───────────────────────────────────────────── + - name: Compile-time perf summary + if: always() + run: | + echo "══════════════════════════════════════════════════════" + echo " COMPILE-TIME PERF BENCH — Linux ARM64 / g++ / -j1" + echo "══════════════════════════════════════════════════════" + printf " %-30s %4s s\n" "Run 1: cold baseline" "${PERF_BASELINE_WALL:-?}" + printf " %-30s %4s s\n" "Run 2: + PCH" "${PERF_PCH_WALL:-?}" + printf " %-30s %4s s\n" "Run 3: + PCH + Unity (default)" "${PERF_DEFAULT_WALL:-?}" + printf " %-30s %4s s\n" "Run 4: + FAST_TEST_BUILD" "${PERF_FAST_WALL:-?}" + printf " %-30s %4s s\n" "Run 5: + ccache warm rerun" "${PERF_CCACHE_WARM_WALL:-?}" + echo "──────────────────────────────────────────────────────" + echo "Predictions to validate vs Apple-M1 baseline:" + echo " ┃ FAST_TEST_BUILD: expected ~40 % faster than default" + echo " ┃ ccache warm: expected ≤ 10 s (vs Apple's 55 s)" + echo "──────────────────────────────────────────────────────" + # Compute relative deltas + if [ -n "${PERF_DEFAULT_WALL:-}" ] && [ -n "${PERF_FAST_WALL:-}" ]; then + pct=$(awk -v d="${PERF_DEFAULT_WALL}" -v f="${PERF_FAST_WALL}" \ + 'BEGIN { printf "%.0f", 100.0 * (d - f) / d }') + echo " Δ FAST_TEST_BUILD vs default: ${pct} % wall reduction" + fi + if [ -n "${PERF_DEFAULT_WALL:-}" ] && [ -n "${PERF_CCACHE_WARM_WALL:-}" ]; then + pct=$(awk -v d="${PERF_DEFAULT_WALL}" -v c="${PERF_CCACHE_WARM_WALL}" \ + 'BEGIN { printf "%.0f", 100.0 * (d - c) / d }') + echo " Δ ccache warm vs default: ${pct} % wall reduction" + fi + echo "══════════════════════════════════════════════════════" diff --git a/doc/architecture/compile-time.md b/doc/architecture/compile-time.md index ae472c4..6ad0316 100644 --- a/doc/architecture/compile-time.md +++ b/doc/architecture/compile-time.md @@ -188,13 +188,31 @@ build: | `FAST_TEST_BUILD=ON` (Linux CI) | 5 | ~30 (expected) | ~25 (expected) | | `FAST_TEST_BUILD=ON` (Apple clang) | 5 | 52 | n/a (use DEV_BUILD locally) | +## Cross-platform perf bench (Linux CI) + +`.gitea/workflows/perf-compile-time.yml` runs a 5-step matrix on the +eulernest Linux runner after every push to `main` that touches the +build system or public headers. The matrix validates the predictions +that this document makes against the macOS-local measurements: + +| Run | Predicted Linux gain | Apple M1 actual | +|---|---|---| +| Baseline (no PCH, no Unity, no ccache) | reference | 78 s | +| + PCH only | ~15 % | 66 s (−15 %) | +| + PCH + Unity (default) | ~30 % | 55 s (−30 %) | +| + FAST_TEST_BUILD (-O0 -g) | **~40 % vs default** (g++ Backend dominates) | 52 s (neutral on clang) | +| + ccache warm rerun | **≥ 90 % vs default** (8.5× speedup) | 56 s (Apple-clang PCH friction = 0 % hit) | + +The job is data-collection only — does not gate merges. Output appears +in the run summary tab; if Linux numbers diverge from predictions, the +"Next levers" table below gets updated based on what actually wins. + ## Next levers (not in this branch) If 55 s wall is still not enough for full-clean rebuilds: | Lever | Estimated win | Cost | |---|---|---| -| `-O0` for the CGAL test target in CI PRs | 55 s → ~30 s | 1 h policy doc | | `extern template` (lever #2 above) | 55 s → ~52 s | 2 h + Eigen version tracking | | Header split (lever #3) | downstream-only | 1 day + API risk | | C++20 Modules | speculative; experimental in Apple clang 17 | weeks | diff --git a/doc/reviewer/README.md b/doc/reviewer/README.md index 02aa3bb..829f082 100644 --- a/doc/reviewer/README.md +++ b/doc/reviewer/README.md @@ -25,6 +25,21 @@ suggested structure. for our conformallab++ chat (~15 min)"*. - **agenda.md**: never send. This is internal scaffolding. +## Hub-Page durability + +The reviewer hub HTML at +is published from `doc/reviewer/hub.html` in the repo (not from a +detached preview branch). This means: + +* Merging any of the open PRs into `main` triggers + `.gitea/workflows/doxygen-pages.yml` which republishes the hub + alongside fresh Doxygen HTML — the reviewer URL stays live across + merges with no manual intervention. +* The hub is source-controlled, so changes are reviewable via PR + like any other doc, and old versions live in git history. +* The original Doxygen index moves to `/doxygen.html` whenever the + hub override is active; both are reachable from the hub itself. + ## Quick links the reviewer should bookmark - 🌐 Reviewer-hub landing page: diff --git a/doc/reviewer/hub.html b/doc/reviewer/hub.html new file mode 100644 index 0000000..2bb7332 --- /dev/null +++ b/doc/reviewer/hub.html @@ -0,0 +1,529 @@ + + + + +conformallab++ — Reviewer Preview + + + + +

+ +
+ +

conformallab++ — Reviewer Preview

+ +

+A C++17 header-only implementation of discrete conformal equivalence +solvers on triangle meshes, built around CGAL's Surface_mesh +and Eigen. v0.9.0 ships five DCE solvers (Euclidean / Spherical / +HyperIdeal / CP-Euclidean / Inversive-Distance) plus the layout, +holonomy, period-matrix, cut-graph and serialisation infrastructure. +

+ +

+Audience. Active researcher in discrete differential geometry — +specifically the decorated DCE / Penner coordinates / +canonical Delaunay tessellations / hyperideal polyhedra +line — treated as a peer most likely to use conformallab++ as +numerical infrastructure for their own future experiments, not merely +to evaluate it. +

+ +
+This page is a temporary preview combining two unmerged PRs so +the integrated state is reviewable before any merge happens. Once the +PRs land on main, the publish URL serves the main-branch view. +
+ + +

TL;DR — orient yourself #

+ +

+ Tests 259/259 + Skipped 0 + Doxygen 100% + Quality + Roadmap + Lit + License + Header-only + v0.9.0 +

+ +
+Headline. 259/259 tests pass (0 skipped); 100 % Doxygen +coverage on the public API; 14 of 15 quality gates green +(1 SKIP — local CGAL-version-matrix has no tarballs); library is +verified-standalone (Eigen + CGAL + Boost, all header-only, no +runtime deps). +
+ +

Pick a time budget; each path is a sequence of anchor links.

+ +
+ +
+

⏱ 5 minutes — minimum to know what's here

+ +
+ +
+

📖 20 minutes — to prepare for the meeting

+ +
+ +
+

🔬 60+ minutes — deep dive

+ +
+ +
+ + +

1. Research alignments — where this could be infrastructure for your work #

+ +

Most rows match an active publication line in discrete differential +geometry. Rows marked no Java parent are research-only phases +the reader can shape at design stage. The Phase column links to the +per-phase entry in doc/roadmap/.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Reader's research threadWhat this snapshot hasPhase
Decorated DCE in non-Euclidean geometriesfive DCE solvers + traits scaffolding; non-Euclidean cone extension scoped in research-track with acceptance criteria9d.2 RESEARCH
Canonical Delaunay tessellations of decorated hyperbolic surfacescut-graph + period matrix + hyperbolic-disk layout as scaffolding; canonical-tessellation algorithm itself outlined10c planned
Hyperideal polyhedra rigidityHyperIdeal functional + 805-line analytic Hessian derivation note (Schläfli identity)9b-analytic derived; 10c′ KAT planned
Optimal cone placement / non-Euclidean cone metricscone-singularity port via ConesUtility scoped; non-Euclidean extension is the research delta9d.1 port + 9d.2 RESEARCH
Polygon Laplacian on general (non-triangular) meshesno Java parent — first phase the reader can influence at design stage9f RESEARCH
Quasi-isothermic maps (Lawson correspondence, ~800 lines, discrete Beltrami-field solver)scoped as a 6-class Java port: QuasiisothermicLayout, DBFSolution, SinConditionApplication, QuasiisothermicDelaunay, QuasiisothermicUtility, ConformalStructureUtility10e planned
Higher-genus + hyperelliptic surfaces (Bobenko–Bücking 2009; block-diagonal period matrices with Z₂ symmetry)port of HyperellipticUtility + HyperIdealHyperellipticUtility scoped; existing period-matrix code as scaffolding10b planned
Möbius centring as a variational problem (Lorentz energy, full gradient + Hessian)currently iterative Fréchet mean in normalise_hyperbolic(); the principled variational alternative is scoped via the Java MobiusCenteringFunctional port9d.4 planned
Boundary-First / interactive flattening (Crane et al. 2017 BFF; Bonneel et al. 2015 Stripe Patterns)not on the roadmap as ports; documented in references.md as comparison points / inspiration
Schläfli-based variational machinery (Rivin–Springborn 1999)derivation done; implementation gated on the reader's view of whether the ~6× speedup over our block-FD path matters at their mesh sizes9b-analytic ready
+ + +

2. Seven questions at a glance #

+ +

The full text of each question lives in +questions.md. +The first two are research-oriented and benefit most from this +specific reader; the rest are scoped so "A / B / either" is a +sufficient answer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
QTopicTrack
Q1Research-track alignment — which of 6 candidate phases (9d.2 / 9f / 10c+10c′ / 10e / 10b / 9d.4) would unblock concrete experiments you want to run?research
Q2Decorated-DCE API surface — named parameter, separate decorated_* solvers, or property-map auto-detect?research
Q3Phase 9b-analytic Hessian — is the ~6× speedup worth ~2 weeks at your mesh sizes?porting
Q4Phase 9c (4g-polygon canonical form) — port literally or re-derive from Springborn 2020 §5?porting
Q5geometry-central cross-validation (GC-1) — would you co-author?collaboration
Q6CGAL submission packaging — one package or several?process
Q7The "no" question — is there one of the 12 architecture decisions you would push back on?process
+ + +

3. What's new on this snapshot #

+ +
+ +

Since the previous publish, four threads converged:

+ +
    +
  • +6 phases from a full Java-library scan + (9d cones + 9d.4 variational Möbius centring / 9e circle-pattern + layout / 10d Koebe circle-domain / 10e quasi-isothermic / 10f + Koebe polyhedra / 10g cyclic-symmetry). See + java-parity.md + for the reverse table.
  • +
  • +13 literature citations integrated + into the per-phase roadmap with explicit acceptance criteria. + Decorated-DCE / canonical-tessellation / hyperideal line: + Bobenko–Lutz 2024 IMRN; Bobenko–Lutz 2025 DCG; Lutz 2023 + Geom. Dedicata; Lutz 2024 PhD; Bowers–Bowers–Lutz 2026. + Cones, polyhedra, period matrices: Crane et al. 2018; + Springborn 2019; Bobenko–Bücking 2009; Rivin–Springborn 1999. + Polygon Laplacians: Alexa–Wardetzky 2011; Alexa 2020. Integrable + and practical-flattening context: Springborn–Veselov 2015; + Crane et al. 2017 (BFF); Bonneel et al. 2015 (Stripe Patterns). +
  • +
  • +1 RESEARCH phase with no Java + parent — Phase 9f (polygon Laplacian on non-triangular meshes, + Alexa-Wardetzky 2011 / Alexa 2020) — the first phase a reviewer + can shape at design stage.
  • +
  • output_uv_map now covers 4 of 5 DCE + solvers (Inversive-Distance added; CP-Euclidean deferred to + Phase 9c with a clear runtime error).
  • +
+ +
+ + +

4. How you'd actually use this #

+ +

The library is header-only and standalone. Two-minute build + smoke +test:

+ +
git clone https://codeberg.org/TMoussa/ConformalLabpp
+cd ConformalLabpp
+cmake -S code -B build && cmake --build build --target conformallab_tests
+ctest --test-dir build              # ~2 s · 23 pure-math tests
+
+# CGAL solvers + layouts (adds Boost headers as system dep)
+cmake -S code -B build -DWITH_CGAL_TESTS=ON
+cmake --build build --target conformallab_cgal_tests -j
+ctest --test-dir build              # ~3 min · 236 CGAL tests
+ +

One-call entry to compute a Euclidean discrete conformal map and a +UV-layout in a single shot:

+ +
#include <CGAL/Surface_mesh.h>
+#include <CGAL/Discrete_conformal_map.h>
+
+CGAL::Surface_mesh<K::Point_3> mesh = ...;        // your mesh
+auto uv = mesh.add_property_map<V_idx, K::Point_2>("uv").first;
+
+auto r = CGAL::discrete_conformal_map_euclidean(
+    mesh,
+    CGAL::parameters::output_uv_map(uv)
+                   | CGAL::parameters::gradient_tolerance(1e-12));
+// r.u_per_vertex, r.iterations, r.gradient_norm now populated.
+ +
+For adding your own functional or layout — pointer chain + +
    +
  • add-inversive-distance.md + — step-by-step recipe for a sixth DCE model, used in real for the existing 9a.2 port.
  • +
  • block-fd-hessian.md + — per-face block-FD pattern (96× over full-FD).
  • +
  • add-output-uv-map.md + — output_uv_map named parameter + pipe-operator chaining.
  • +
  • For your decorated-DCE work specifically: see + Q2 of the reviewer questions + — three candidate API shapes, picking one would let us sketch a prototype in the week after the meeting.
  • +
+ +
+ + +

5. Documents to read next #

+ +

The four document folders most useful to a researcher. Click each +folder for the per-document table.

+ +
+📋 Meeting materials — doc/reviewer/ (read first) + + + + + + + +
DocumentWhat it covers
briefing.mdOne-page orientation: research alignments (10-row table), what's new on this snapshot, the seven questions.
questions.mdFull text of Q1–Q7. Q1 lists 6 candidate phases (9d.2 / 9f / 10c+10c′ / 10e / 10b / 9d.4); Q2 covers the decorated-DCE API surface; Q3–Q4 are porting decisions; Q5–Q6 project management; Q7 the open invitation to push back.
+ +
+ +
+🗺️ Roadmap — doc/roadmap/ (where everything fits) + + + + + + + + + + + +
DocumentWhat it covers
phases.md +6 phasesPer-phase plan including the 6 new Java-scan phases (9d / 9e / 10d / 10e / 10f / 10g + 9d.4) and the 3 new research-only entries (9d.2 / 9f / 10c′).
research-track.md +2 RESEARCHItems beyond Java parity, with explicit acceptance criteria: non-Euclidean cone extensions (9d.2), polygon Laplacian on non-triangular meshes (9f), geometry-central cross-validation (GC-1).
java-parity.md full scanReverse table: every class in the Java original, where it lives in our port (or which phase will absorb it), or why it is intentionally not ported (the do-not-port list — Colt, PETSc, jReality wrappers).
porting-status.mdOperational snapshot: 25 kLoC Java breakdown, 5-DCE-model status matrix, things Java doesn't have.
+ +
+ +
+📚 Mathematics & literature — doc/math/ + + + + + + + +
DocumentWhat it covers
references.md +13 refsPer-phase literature index. 13 new citations added: decorated DCE in non-Euclidean geometries (Bobenko–Lutz 2025); canonical tessellations (Lutz 2023 / 2024); hyperideal polyhedra rigidity (Bowers–Bowers–Lutz 2026); polygon Laplacians (Alexa–Wardetzky 2011 / Alexa 2020); optimal cone placement (Crane et al. 2018); Schläfli identity (Rivin–Springborn 1999); hyperbolic polyhedra (Springborn 2019); polyhedral period matrices (Bobenko–Bücking 2009); integrable cluster dynamics (Springborn–Veselov 2015); BFF (Crane et al. 2017); stripe patterns (Bonneel et al. 2015).
hyperideal-hessian-derivation.mdFull LaTeX-formatted derivation of the analytic HyperIdeal Hessian via the Schläfli identity (805 lines, 8 sections + 2 appendices). Cited sources: Schläfli 1858, Milnor 1982, Vinberg 1993, Cho–Kim 1999, Glickenstein 2011, Rivin–Springborn 1999, Springborn 2020.
+ +
+ +
+🏗️ Architecture, dependencies & auto-generated reference + + + + + + + + + + + + + + + +
DocumentWhat it covers
locked-vs-flexible.md12 architecture decisions classified 🔴 load-bearing / 🟡 semi-fixed / 🟢 opportunistic + a "Known limitations" table. Q7 of the reviewer questions points here to push back on anything.
dependencies.mdWhat's required (Eigen + CGAL + Boost headers) vs optional; per-tool install hints; standalone-verification recipe.
code/deps/THIRD-PARTY-LICENSES.mdPer-vendored-dep SPDX with MIT-compatibility analysis (LGPL §3 vs §4 distinction for header-only consumption of CGAL).
Doxygen HTML259 pages, 0 warnings, 100 % public-API coverage (396 / 396 symbols). MathJax enabled for inline formulas.
api/headers.mdAuto-generated table of every public header with brief + symbols; regenerated on every push to main.
api/tests.mdPer-suite test breakdown (single source of truth). 259 tests, 0 skipped.
+ +
+ + +

6. Quality & tests — proof points #

+ + + + + + + + +
SuiteTestsStatus
Non-CGAL (pure-math)23PASS 0 skipped
CGAL (Surface_mesh + Phase 8b-Lite)236PASS 0 skipped
Total2590 failures
+ +
+Quality gates — 14 of 15 PASS, 1 SKIP (full breakdown) + +

Run with bash scripts/quality/run-all.sh. Four ★ gates are +required in CI on every PR; the rest are local-only and skip gracefully +on a partial dev environment.

+ + + + + + + + + + + + + + + + + + + + + + +
GateWhereResultDetail
License headers ★CIPASS66/66 files carry MIT SPDX
CGAL conventions (6 rules) ★CIPASS0/6 violations across 6 CGAL public headers
codespell ★CIPASS0 typos
shellcheck ★ (strict)CIPASS0 findings across 16 shell scripts
clang-format driftlocalPASS0 drift against .clang-format
cmake-format / cmake-lintlocalPASS0 drift, 0 lint findings
cppchecklocalPASSwarning+ severity clean
Markdown linksCIPASSinternal links resolve
Sanitizers (ASan + UBSan)localPASS23/23 tests pass under instrumentation
clang-tidylocalPASS35 headers, 0 findings
Coverage (gcov + lcov)localDEGRADED23/23 tests run instrumented; lcov-on-macOS toolchain mismatch (works on Linux CI)
Multi-compilerlocalPASSAppleClang 17 + brew LLVM 22
Reproducible buildlocalPASSbyte-identical test binaries between 2 builds
Doxygen coverageCIPASS396 / 396 public symbols (100 %)
CGAL version matrixlocalSKIPno CGAL tarballs under ~/cgal/ (graceful)
test-count consistency ★CIPASStests.md totals match ctest reality
End-to-end smoke (try_it.sh) ★CIPASSfull configure + build + ctest + Euclidean example on a bundled mesh
+ +
+ + +

7. Source & navigation #

+ + + + + + + + + + +
Repo (this snapshot)codeberg.org/TMoussa/ConformalLabpp/branch/main
Default branchcodeberg.org/TMoussa/ConformalLabpp (main)
Doxygen HTML259 pages, 0 warnings, 100 % coverage
Origin (private)git.eulernest.eu/conformallab/ConformalLabpp
+ + + +
+ + +