Files
ConformalLabpp/README.md
Tarik Moussa 8c353bb884 feat(phase3d+3e): port EuclideanCyclicFunctional + add SphericalFunctional gauge-fix
Phase 3d — EuclideanCyclicFunctional:
  • euclidean_geometry.hpp: t-value / atan2 corner-angle formula with
    centering trick (μ = (Λ̃₁₂+Λ̃₂₃+Λ̃₃₁)/6) for numerical stability
  • euclidean_functional.hpp: EuclideanMaps bundle, gradient (G_v = Θ_v − Σα_v,
    G_e = α_opp⁺ + α_opp⁻ − φ_e), 10-point GL path-integral energy,
    gradient_check_euclidean — identical halfedge convention to SphericalFunctional
  • test_euclidean_functional.cpp: 11 tests (1 skip) covering angle formula,
    right-isosceles triangle, angle sum = π, degenerate detection, gradient
    checks on triangle/quad-strip/tetrahedron/fan-5/mixed-pinned, NaN check

Phase 3e — Spherical gauge-fix:
  • spherical_gauge_shift(): Newton + backtracking line search to find t*
    where ΣG_v(x + t·1) = 0 (maximises E along the global scale direction);
    bisection used when sign change is detectable, Newton+backtrack otherwise
  • apply_spherical_gauge(): in-place wrapper
  • 3 new tests: GaugeFix_SpherTetVertexZerosSumGv, GaugeFix_ApplyInPlace,
    GaugeFix_AlreadyAtGaugeReturnsTNearZero

Total: 45 cgal tests pass, 3 skipped (@Ignore Hessian stubs, one per functional)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 07:39:14 +02:00

252 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# conformallab++
conformallab++ is a modern C++ reimplementation of the [ConformalLab](https://github.com/sechel/conformallab) software by Stefan Sechelmann for experiments in discrete conformal geometry and related mesh transformations.
The long-term goal is a **CGAL package** that brings discrete conformal maps (hyper-ideal, spherical, Euclidean) to the CGAL ecosystem using `CGAL::Surface_mesh` as the underlying half-edge data structure.
> **Status:** Phasen 3d + 3e abgeschlossen. Alle drei Kern-Geometrien (Hyper-Ideal, Sphärisch, Euklidisch) plus Sphärischer Gauge-Fix sind auf `ConformalMesh` portiert. **45 Tests, 3 skipped** (Hessian-Stubs). Nächster Schritt: Phase 3f (Hessian) → Phase 4 (Newton-Solver) — siehe [Roadmap](#roadmap).
---
## Features
| Area | Status |
|------|--------|
| Clausen / Lobachevsky / ImLi₂ functions | ✅ Phase 1 |
| Hyper-ideal geometry (ζ, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ) | ✅ Phase 2 |
| Hyper-ideal functional (energy + gradient, CGAL mesh) | ✅ Phase 3b |
| Spherical functional (energy + gradient, CGAL mesh) | ✅ Phase 3c |
| CGAL `Surface_mesh` infrastructure + mesh builders | ✅ Phase 3a |
| Euclidean functional (energy + gradient, CGAL mesh) | ✅ Phase 3d |
| Spherical gauge-fix (scale gauge for closed surfaces) | ✅ Phase 3e |
| Solvers (Newton, gradient flow) | 🔜 Phase 4 |
| XML serialisation / mesh I/O | 🔜 Phase 5 |
| Full CLI app | 🔜 Phase 5 |
---
## Build modes
| Mode | CMake flag | What gets built | CI |
|------|-----------|-----------------|-----|
| **Tests only** (default) | *(none)* | `conformallab_tests` · Eigen + GTest | ✅ runs automatically |
| **CGAL tests** | `-DWITH_CGAL=ON` | `conformallab_cgal_tests` · above + CGAL + system Boost | local only |
| **Viewer** | `-DWITH_VIEWER=ON` | `viewer` library · libigl / GLFW / GLAD | local only |
| **Full app** | `-DWITH_CGAL=ON` | `conformallab_core` CLI · all of the above | local only |
External dependencies are bundled as tarballs in `code/deps/tarballs/` and extracted lazily at CMake configure time (GTest is fetched from GitHub via `FetchContent`).
**Note on Boost:** `-DWITH_CGAL=ON` requires a system-installed Boost (header-only use by CGAL). The default `Tests only` mode needs no Boost.
---
## Prerequisites
| Tool | Minimum version |
|------|----------------|
| C++ compiler (GCC or Clang) | C++17 |
| CMake | 3.20 |
| Boost headers | 1.70 *(only with `-DWITH_CGAL=ON`)* |
---
## Getting started
```bash
git clone https://codeberg.org/TMoussa/ConformalLabpp
cd ConformalLabpp
```
### Tests only (CI default — no system deps needed)
```bash
cmake -S code -B build
cmake --build build --target conformallab_tests -j$(nproc)
ctest --test-dir build --output-on-failure
```
### CGAL mesh + functional tests (requires system Boost)
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build --target conformallab_cgal_tests -j$(nproc)
ctest --test-dir build -R "^cgal\." --output-on-failure
```
Expected output: **45 tests pass, 3 skipped** (the three `@Ignore` Hessian stubs, one per functional).
### Full CLI app (CGAL + viewer)
```bash
cmake -S code -B build -DWITH_CGAL=ON
cmake --build build -j$(nproc)
./code/bin/conformallab_core --input data/off/example.off --show
```
---
## Public headers (`code/include/`)
| Header | Description |
|--------|-------------|
| `clausen.hpp` | Clausen integral Cl₂, Lobachevsky Л, ImLi₂ |
| `hyper_ideal_geometry.hpp` | Pure-math ζ functions, lᵢⱼ, αᵢⱼ, σᵢ, σᵢⱼ |
| `hyper_ideal_utility.hpp` | Tetrahedron volume (Meyerhoff / KolpakovMednykh) |
| `hyper_ideal_functional.hpp` | Hyper-ideal energy + gradient on `ConformalMesh` |
| `spherical_geometry.hpp` | Spherical arc length, half-angle angle formula |
| `spherical_functional.hpp` | Spherical energy + gradient + gauge-fix on `ConformalMesh` |
| `euclidean_geometry.hpp` | Euclidean corner-angle formula (t-value / atan2) |
| `euclidean_functional.hpp` | Euclidean energy + gradient on `ConformalMesh` |
| `conformal_mesh.hpp` | `ConformalMesh` = `CGAL::Surface_mesh<Point3>`, index types, property-map helpers |
| `mesh_builder.hpp` | Factory meshes: triangle, tetrahedron, quad strip, fan, spherical tetrahedron, octahedron face |
| `discrete_elliptic_utility.hpp` | Discrete elliptic integrals |
| `matrix_utility.hpp` | Small linear-algebra helpers |
| `projective_math.hpp` | Projective geometry utilities |
---
## Project structure
```
code/
├── include/
│ ├── conformal_mesh.hpp # CGAL mesh type + property-map helpers
│ ├── mesh_builder.hpp # make_triangle / make_tetrahedron / …
│ ├── hyper_ideal_geometry.hpp # ζ, lᵢⱼ, αᵢⱼ — pure math
│ ├── hyper_ideal_functional.hpp # HyperIdealFunctional on ConformalMesh
│ ├── spherical_geometry.hpp # spherical arc length + angles
│ ├── spherical_functional.hpp # SphericalFunctional + gauge-fix on ConformalMesh
│ ├── euclidean_geometry.hpp # Euclidean corner-angle formula (t-value)
│ ├── euclidean_functional.hpp # EuclideanCyclicFunctional on ConformalMesh
│ ├── clausen.hpp # Clausen / Lobachevsky / ImLi₂
│ └── hyper_ideal_utility.hpp # Tetrahedron volumes
├── src/
│ ├── apps/v0/ # conformallab_core CLI (requires WITH_CGAL)
│ └── viewer/ # simple_viewer (requires WITH_VIEWER)
├── tests/
│ ├── CMakeLists.txt
│ ├── *.cpp # conformallab_tests (no CGAL)
│ └── cgal/
│ ├── CMakeLists.txt
│ ├── test_conformal_mesh.cpp # 14 mesh infrastructure tests
│ ├── test_hyper_ideal_functional.cpp # 6 hyper-ideal gradient checks
│ ├── test_spherical_functional.cpp # 11 spherical gradient + gauge-fix checks
│ └── test_euclidean_functional.cpp # 11 Euclidean gradient checks
└── deps/
├── tarballs/ # bundled dependency archives
├── eigen-3.4.0/ # header-only linear algebra (always extracted)
├── CGAL-6.1.1/ # header-only geometry (extracted with WITH_CGAL)
├── libigl-2.6.0/ # header-only viewer toolkit (extracted with WITH_VIEWER)
├── glfw-3.4/ # windowing (extracted with WITH_VIEWER)
├── libigl-glad/ # OpenGL loader (extracted with WITH_VIEWER)
└── single_includes/ # CLI11, json.hpp
```
---
## Test suites
### `conformallab_tests` (always built, runs in CI)
Pure-math tests requiring only Eigen:
- Clausen function, Lobachevsky function, ImLi₂
- Hyper-ideal geometry (ζ₁₃, ζ₁₄, ζ₁₅, lᵢⱼ, αᵢⱼ)
- Tetrahedron volume formulas (Meyerhoff, KolpakovMednykh)
### `conformallab_cgal_tests` (built with `-DWITH_CGAL=ON`)
CGAL `Surface_mesh` tests (test prefix `cgal.`):
| Suite | Tests | Description |
|-------|-------|-------------|
| `ConformalMeshTopology` | 4 | Euler characteristic, vertex/edge/face counts |
| `ConformalMeshTraversal` | 4 | Halfedge iteration, valence, opposite-halfedge |
| `ConformalMeshProperties` | 5 | Property maps: λ, θ, idx, α, geometry type |
| `ConformalMeshValidity` | 1 | CGAL validity check for all factory meshes |
| `HyperIdealFunctional` | 6 | Finite-difference gradient checks on triangle, tetrahedron, quad strip, fan |
| `SphericalFunctional` | 11 | Angle formula + gradient checks on spherical meshes + 3 gauge-fix tests |
| `EuclideanFunctional` | 11 | Angle formula + gradient checks on Euclidean meshes (triangle, quad strip, fan, tetrahedron) |
---
## Key design decisions
**CGAL as CoHDS replacement.** `CGAL::Surface_mesh<Point3>` replaces the Java `CoHDS` half-edge data structure. Vertex/edge/face/halfedge descriptors are `Vertex_index`, `Edge_index`, `Face_index`, `Halfedge_index` (typed integers, not raw handles).
**Property maps.** `mesh.add_property_map<Vertex_index, double>("v:lambda", 0.0)` replaces the Java adapter/decorator pattern. Multiple maps can be attached to one mesh without subclassing.
**Energy parameterisation.** Both functionals use a **DOF vector** `x` indexed by `v_idx[v]` / `e_idx[e]` (1 = pinned). This matches the Java `FunctionalTest` gradient-check convention.
**Spherical edge gradient.** For the spherical parameterisation where `Λᵢⱼ = λ°ᵢⱼ + uᵢ + uⱼ + λₑ` (additive edge DOF), the Schläfli identity gives `∂E/∂λₑ = (2α_opp S_f)/2` per face (Euclidean limit: `S_f = π`, recovering the familiar `α_opp⁺ + α_opp⁻ π`).
---
## CI
Tests run automatically on push to `main`, `dev`, and `claude/**` branches via a self-hosted Gitea Actions runner (`eulernest`, ARM64 Raspberry Pi). The pipeline uses a minimal Docker image (`git.eulernest.eu/conformallab/ci-cpp:latest`) with cmake, g++, git, and Node.js 20 pre-installed. **Only `conformallab_tests` runs in CI** (no Boost/CGAL dependency in the CI image).
The Dockerfile for the CI image lives in `.gitea/docker/Dockerfile.ci-cpp`. Build and push it once whenever the image needs updating:
```bash
docker buildx build \
--platform linux/arm64 \
-f .gitea/docker/Dockerfile.ci-cpp \
-t git.eulernest.eu/conformallab/ci-cpp:latest \
--push \
.gitea/docker/
```
---
## Roadmap
Die Phasen 13 sind abgeschlossen. Die folgenden Schritte schließen Phase 3 ab und
bereiten Phase 4 (Solver) vor. Die Zeitangaben sind grobe Schätzungen.
---
```
Phase 3d EuclideanCyclicFunctional portieren ✅ abgeschlossen
→ euclidean_geometry.hpp: t-Wert / atan2 Winkelformel
→ euclidean_functional.hpp: Energie + Gradient auf ConformalMesh
→ 11 Tests: Winkelformel, Gradient-Checks, NaN-Test, Fan, Mixed-Pinned
Phase 3e Gauge-Fix für SphericalFunctional ✅ abgeschlossen
→ spherical_gauge_shift() + apply_spherical_gauge() in
spherical_functional.hpp — Newton + Backtracking
→ 3 neue Tests: ZerosSumGv, ApplyInPlace, AlreadyAtGauge
Phase 3f Hessian (Sphärisch → Euklidisch) (23 Tage)
→ Analytischer Hessian = Kotangenten-Laplace-Operator
→ CGAL::Weights::cotangent_weight() als Basis für
die Kantenbeiträge nutzen (bereits in CGAL 6.0 enthalten)
→ Entsperrt Newton-/Trust-Region-Verfahren
→ Reihenfolge: Sphärisch zuerst (kleinster Hessian),
dann Euklidisch
Phase 3g PI-Konstante konsolidieren (< 1 Stunde)
→ conformallab::PI in hyper_ideal_geometry.hpp und
lokales pi in hyper_ideal_utility.hpp zusammenführen
→ Einzelne constants.hpp oder in conformal_mesh.hpp
Phase 4a Minimaler Newton-Solver (12 Tage)
→ Eigen SimplicialLDLT (bereits Projektabhängigkeit)
→ Newton-Schritt: Δx = H⁻¹·g mit Hessian aus 3f
→ Kein externer PETSc-Solver nötig für erste Tests
→ Konvergenzkriterium: ||g||∞ < tol
Phase 4b CGAL::IO für Mesh-Import/Export (< 1 Tag)
→ CGAL::IO::read_OBJ / write_OBJ auf Surface_mesh:
null Eigenentwicklung, sofort nutzbar
→ Ermöglicht Round-Trip-Tests gegen Java-Referenz-Meshes
→ Mittelfristig: CGAL::IO::read_OFF für .off-Dateien
(ersetzt Java-XML-Serialisierung für Testzwecke)
```
---
## License
conformallab++ is released under the MIT License (see [LICENSE](LICENSE)).