Files
ConformalLabpp/doc/api/contracts.md
Tarik Moussa 14134b99ce
Some checks failed
C++ Tests / test-fast (push) Successful in 2m25s
C++ Tests / test-cgal (push) Failing after 1m58s
docs: restructure documentation into focused files
README.md: reduced from 703 to ~75 lines — what/why, status, quick
start, minimal usage example, navigation table to doc/ files.

doc/architecture/overall_pipeline.md: trimmed — roadmap, extension
points, declarative pipeline YAML, and references sections removed
(each now has its own dedicated file). Replaced with a link table.

New files:
  doc/getting-started.md       — build modes, single-test invocation, CLI
  doc/api/pipeline.md          — full pipeline API with code for all 3 geometries
  doc/api/extending.md         — new functionals, geometry modes, Java porting guide
  doc/api/contracts.md         — processing unit preconditions/provides table
  doc/api/cgal-package.md      — Phase 8 CGAL package design + YAML pipeline (TODO)
  doc/math/geometry-modes.md   — Euclidean/Spherical/HyperIdeal comparison
  doc/math/references.md       — all papers by module
  doc/roadmap/phases.md        — Phases 1–10 with porting/research boundary
  doc/roadmap/java-parity.md   — Java vs C++ feature parity table
  doc/contributing.md          — language policy, test standards, release flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 21:17:15 +02:00

3.5 KiB
Raw Permalink Blame History

Processing Unit Contracts

Each pipeline unit has explicit preconditions and guarantees. A pipeline is valid if every unit's preconditions are satisfied by the outputs of all preceding units.


Contract table

Unit Preconditions Provides
load_mesh() Valid file path, supported format (OFF/OBJ/PLY) Manifold, oriented, triangulated ConformalMesh
setup_*_maps() Triangulated mesh Initialised property maps; lambda0 zeroed
compute_*_lambda0_from_mesh() setup_*_maps() called lambda0[e] set from 3-D edge lengths
check_gauss_bonnet() theta_v[v] set for all vertices Throws std::runtime_error if Σ(2πΘᵥ) ≠ 2π·χ(M)
enforce_gauss_bonnet() theta_v[v] set Σ(2πΘᵥ) = 2π·χ(M) guaranteed; theta_v modified
newton_euclidean() GB satisfied · DOFs assigned · lambda0 initialised NewtonResult.x — converged scale factors; .converged, .iterations, .grad_inf_norm
newton_spherical() GB satisfied · DOFs assigned · gauge vertex pinned Same as above
newton_hyper_ideal() assign_all_dof_indices() called · lambda0 initialised Same as above
compute_cut_graph() Closed, orientable, triangulated mesh CutGraph.cut_edge_flags — 2g seam edges; .genus
euclidean_layout() newton_euclidean() converged Layout2D.uv[v] · .halfedge_uv[h] · HolonomyData.translations
spherical_layout() newton_spherical() converged Layout3D.xyz[v]
hyper_ideal_layout() newton_hyper_ideal() converged Layout2D.uv[v] · .halfedge_uv[h] · HolonomyData.mobius_maps
normalise_euclidean() layout.success == true Centroid at origin, major axis = x-axis
normalise_hyperbolic() layout.success == true Weighted centroid at Poincaré disk origin
normalise_spherical() layout.success == true Area centroid at north pole
compute_period_matrix() hol.translations.size() >= 2 PeriodData.tau ∈ ; optionally SL(2,)-reduced
compute_fundamental_domain() HolonomyData (genus 1) CCW parallelogram {0, ω₁, ω₁+ω₂, ω₂} + edge identifications
tiling_neighbourhood() Layout2D + HolonomyData (genus 1) (2m+1)·(2n+1) translated layout copies
save_layout_off() Layout2D + mesh OFF file with UV coordinates
save_result_json/xml() NewtonResult + optional Layout2D JSON/XML serialised result

DOF assignment conventions

// Euclidean / Spherical: pin one vertex, assign sequential indices
maps.v_idx[first_vertex] = -1;          // pinned: u_v = 0
int idx = 0;
for (auto v : remaining_vertices)
    maps.v_idx[v] = idx++;

// HyperIdeal: all vertices and edges are free DOFs
int n_dofs = assign_all_dof_indices(mesh, maps);
// maps.v_idx[v] ∈ [0, n_v)
// maps.e_idx[e] ∈ [n_v, n_v + n_e)

-1 in v_idx or e_idx means the DOF is pinned (fixed at its lambda0 value). The solver never writes to pinned DOFs. All indexing is 0-based and contiguous.


GaussBonnet — the most common source of failure

Prescribing angles that violate GaussBonnet means no conformal factor can realise the target metric — the Newton solver will iterate indefinitely without converging.

// Option A: verify before solving (throws on violation)
check_gauss_bonnet(mesh, maps);

// Option B: auto-correct (redistributes defect uniformly across all vertices)
enforce_gauss_bonnet(mesh, maps);

The target violation is |Σ(2πΘᵥ) 2π·χ(M)| > tol. Default tolerance: 1e-10.