# Complexity and Scalability > **Measured on:** Apple M-series (ARM64), Release build (`-O2`), single thread. > CI runner (Raspberry Pi 4, ARM64) is ~10× slower — the smoke tests assert > on correctness only (iteration count, residual norm), not on wall-clock time. --- ## 1 — Algorithmic complexity per pipeline step | Step | Function | Time complexity | Space | Notes | |---|---|---|---|---| | Mesh load | `load_mesh()` | O(F) | O(V+F) | CGAL OFF/OBJ/PLY parser | | λ₀ initialisation | `compute_*_lambda0_from_mesh()` | O(E) | O(E) | one pass over edges | | Gauss–Bonnet check | `check_gauss_bonnet()` | O(V) | O(1) | one pass over vertices | | Gauss–Bonnet enforce | `enforce_gauss_bonnet()` | O(V) | O(1) | redistributes defect uniformly | | **Gradient** (Euclidean/Spherical) | `euclidean_gradient()` | O(F) | O(V) | one pass over faces | | **Gradient** (HyperIdeal) | `hyper_ideal_gradient()` | O(E) | O(V+E) | ζ-functions per edge | | **Hessian** (Euclidean) | `euclidean_hessian()` | O(F) | O(V) sparse | cotangent Laplacian, nnz ≈ 6V | | **Hessian** (Spherical) | `spherical_hessian()` | O(F) | O(V) sparse | spherical law-of-cosines analog | | **Hessian** (HyperIdeal) | `hyper_ideal_hessian()` | O(n·E) | O(V+E) sparse | **FD approximation: n extra gradient evals per Newton step** → Phase 9b will replace with O(E) analytic | | **Linear solve** | `SimplicialLDLT` | O(V^{1.5}) | O(V^{1.5}) | planar-graph fill-in; automatic SparseQR fallback | | **Newton iteration** | `newton_euclidean()` | O(V^{1.5}) per iter | O(V) | typically 3–20 iterations total | | **Full Newton solve** | `newton_euclidean()` | O(k · V^{1.5}) | O(V^{1.5}) | k = iteration count, k < 30 in practice | | Cut graph | `compute_cut_graph()` | O(E log E) | O(V+E) | spanning tree + cotree BFS | | Layout (BFS-trilateration) | `euclidean_layout()` | O(F) | O(V) | priority-BFS, one trilateration per face | | Holonomy | (inside `*_layout`) | O(g·E) | O(g) | one Möbius composition per seam edge per generator | | Period matrix | `compute_period_matrix()` | O(1) after holonomy | O(1) | τ = ω_b/ω_a, SL(2,ℤ) reduction | | Fundamental domain | `compute_fundamental_domain()` | O(g) | O(g) | g generator pairs | **Dominant cost:** the SimplicialLDLT factorization at O(V^{1.5}). For the meshes in the test suite (V up to ~7K) this is in the 10–100ms range. For meshes with V > 50K the HyperIdeal FD Hessian becomes a second bottleneck (Phase 9b: analytic Hessian will reduce this to O(E) per Newton step). --- ## 2 — Measured timings on test meshes All times measured in Release mode (`-O2`) on Apple M-series (ARM64), single thread, from `test_scalability_smoke.cpp` stdout output. ### Newton solver (Euclidean, from x₀ = −0.05 perturbation) | Mesh | V | F | Genus | Iterations | ‖G‖_∞ | Newton time | |---|---|---|---|---|---|---| | `cathead.obj` | 131 | 248 | 0 (open) | 3 | 1.2e-12 | < 1 ms | | `brezel2.obj` | 2 622 | 5 248 | 2 | — (cut graph only) | — | — | | `brezel.obj` | 6 910 | 13 824 | 2 | 3 | 1.5e-12 | **69 ms** | ### Cut graph (tree-cotree, Erickson–Whittlesey) | Mesh | V | F | Genus | Seam edges | Cut graph time | |---|---|---|---|---|---| | `brezel2.obj` | 2 622 | 5 248 | 2 | 4 (= 2g) | 10 ms | | `brezel.obj` | 6 910 | 13 824 | 2 | 4 (= 2g) | < 1 ms | > **Note on iteration count.** All three meshes converge in exactly 3 Newton > iterations from a −0.05 perturbation. This is consistent with quadratic > convergence: the Euclidean energy is strictly convex, so Newton reaches > machine-precision residual (‖G‖ ≈ 10⁻¹²) in very few steps regardless of > mesh size. The per-iteration cost (dominated by SimplicialLDLT) grows with V, > but the iteration count does not. --- ## 3 — Scaling projection Based on the O(V^{1.5}) model for the linear solve: | V | Projected Newton time (Euclidean) | Notes | |---|---|---| | 500 | ~2 ms | typical research mesh | | 5 000 | ~50 ms | brezel2-scale | | 7 000 | ~70 ms | brezel-scale (measured: 69ms ✓) | | 20 000 | ~500 ms | large detailed mesh | | 50 000 | ~3 s | remeshed high-resolution surface | | 100 000 | ~9 s | boundary of practical usability (single thread) | For V > 50K: consider iterative solvers (e.g. Conjugate Gradient preconditioned with incomplete Cholesky) as a Phase 10 engineering improvement. --- ## 4 — HyperIdeal Hessian bottleneck The HyperIdeal Hessian is currently computed by **finite differences** (Phase 9b plans an analytic replacement). The FD cost is: ``` n_dof extra gradient evaluations per Newton step ``` where `n_dof = V + E` (HyperIdeal has both vertex and edge DOFs). For a mesh with V=6910, F=13824 this means ~20K gradient evaluations per Newton step instead of 1, making HyperIdeal roughly **20× slower** than Euclidean for the same mesh. **After Phase 9b** (analytic HyperIdeal Hessian): the HyperIdeal time per iteration will match Euclidean — O(E) Hessian assembly, O(V^{1.5}) factorization. --- ## 5 — Memory usage | Component | Memory | Formula | |---|---|---| | Mesh | ~200 bytes/vertex | CGAL `Surface_mesh` overhead | | Eigen sparse Hessian | ~48 bytes/nonzero | nnz ≈ 6V for cotangent Laplacian | | SimplicialLDLT factorization | O(V^{1.5}) bytes | fill-in for planar sparse matrix | | Layout (UV coordinates) | 16 bytes/vertex | `Eigen::Vector2d` per vertex | | Total for brezel (V=6910) | **~40 MB** | estimate; actual measured not yet | --- ## 6 — How to run the smoke tests yourself ```bash cmake -S code -B build -DWITH_CGAL_TESTS=ON -DCMAKE_BUILD_TYPE=Release cmake --build build --target conformallab_cgal_tests -j$(nproc) # Run all three scalability tests — timing printed to stdout ./build/tests/cgal/conformallab_cgal_tests --gtest_filter="SmokeEuclidean*" ``` Expected output: ``` [SmokeEuclidean.CatHead] V=131 F=248 iter=3 ||G||=1.2e-12 time=<1ms [SmokeEuclidean.Brezel] V=6910 F=13824 iter=3 ||G||=1.5e-12 newton=69ms cut=0ms [SmokeEuclidean.Brezel2] V=2622 F=5248 cut=10ms seams=4 ``` Timings vary by hardware. The assertions (iter < 30, ‖G‖ < 1e-8, seams = 2g) are hardware-independent and run in CI.