From bef5a0ceb7065beecf0fc38d77b8f4bbaf6dd42b Mon Sep 17 00:00:00 2001 From: Tarik Moussa Date: Sun, 31 May 2026 00:16:31 +0200 Subject: [PATCH] docs(euclidean-hessian): fix wrong cotangent formula in two comment blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finding-C from doc/reviewer/external-audit-2026-05-30.md. The box comment at the top and the function-level comment above euclidean_cot_weights() both stated: cot_k = (t_adj1·l123 − t_adj2·t_opp) / denom2 ← WRONG The correct formula (verified numerically on a 3-4-5 right triangle, expected cot1=4/3, cot2=3/4, cot3=0) is: cot_k = (t_opp · l123 − t_a · t_b) / denom2 where t_opp is the t-value of the edge OPPOSITE vertex k, and t_a/t_b are the t-values of the two edges ADJACENT to vertex k. The implementation in euclidean_cot_weights() was already correct; only the documentation was wrong. Changes (documentation only, zero code changes): - Box comment: rewritten with correct formula and explicit per-vertex assignment (cot1: t_opp=t23, t_a=t12, t_b=t31; etc.) - Box comment: added missing ½ factor to Hessian contribution lines - Function-level comment: corrected to (t_opp·l123 − t_a·t_b)/(8·Area) with a pointer to the box comment for the full assignment - Inline return comment in euclidean_cot_weights(): now shows the mapping (cot1: t_opp=t23, t_a=t12, t_b=t31) directly at the formula 263/263 CGAL tests pass, 0 failed. Co-Authored-By: Claude Sonnet 4.6 --- code/include/euclidean_hessian.hpp | 32 ++++++++++++++--------- doc/reviewer/external-audit-2026-05-30.md | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/code/include/euclidean_hessian.hpp b/code/include/euclidean_hessian.hpp index 5918c79..83f473d 100644 --- a/code/include/euclidean_hessian.hpp +++ b/code/include/euclidean_hessian.hpp @@ -17,18 +17,21 @@ // │ side lengths lij = exp(Λ̃ij/2): │ // │ │ // │ t12 = −l12+l23+l31, t23 = l12−l23+l31, t31 = l12+l23−l31 │ -// │ denom2 = 2·sqrt(t12·t23·t31·l123) = 8·Area │ +// │ l123 = l12+l23+l31, denom2 = 2·sqrt(t12·t23·t31·l123) = 8·Area │ // │ │ -// │ cot_k = (t_adj1·l123 − t_adj2·t_opp) / denom2 │ -// │ = cotangent of the angle αk at vertex k │ +// │ Cotangent at vertex k (opposite t_opp, adjacent t_a and t_b): │ +// │ cot_k = (t_opp · l123 − t_a · t_b) / denom2 │ // │ │ -// │ Hessian contributions per face: │ -// │ H[vi, vi] += cot_vj + cot_vk (diagonal, both non-opp angles) │ -// │ H[vi, vj] -= cot_vk (off-diagonal, for variable vi,vj│ +// │ Assignment (k ↔ opposite edge ↔ opposite t-value): │ +// │ cot1 (v1, opp l23): t_opp=t23, t_a=t12, t_b=t31 │ +// │ cot2 (v2, opp l31): t_opp=t31, t_a=t12, t_b=t23 │ +// │ cot3 (v3, opp l12): t_opp=t12, t_a=t23, t_b=t31 │ // │ │ -// │ This is exactly the cotangent-Laplace operator from Pinkall–Polthier. │ +// │ Hessian contributions per face (Pinkall–Polthier ½ factor): │ +// │ H[vi, vi] += (cot_vj + cot_vk) / 2 (diagonal) │ +// │ H[vi, vj] −= cot_vk / 2 (off-diagonal, variable pairs) │ // │ │ -// │ Pinned vertices (v_idx = −1) contribute to diagonal of neighbours but │ +// │ Pinned vertices (v_idx = −1) contribute to diagonal of neighbours but │ // │ do not create a column/row in H themselves. │ // └──────────────────────────────────────────────────────────────────────────┘ // @@ -54,7 +57,11 @@ namespace conformallab { // Given three Euclidean SIDE LENGTHS l12, l23, l31 (already exp(Λ̃/2)), // return the three cotangent weights (cot1, cot2, cot3). // -// cot_k = (t_adj·l123 − t_opp·t_other) / (8·Area) +// cot_k = (t_opp · l123 − t_a · t_b) / (8·Area) +// +// where t_opp is the t-value of the edge OPPOSITE vertex k, and t_a, t_b are +// the t-values of the two edges ADJACENT to vertex k. See the box comment at +// the top of this file for the explicit assignment of t_opp/t_a/t_b per vertex. // // Returns {0,0,0} for degenerate faces (triangle inequality violated or Area=0). /// Three Euclidean cotangent weights `(cot1, cot2, cot3)` for the @@ -85,9 +92,10 @@ inline EuclCotWeights euclidean_cot_weights(double l12, double l23, double l31) // denom2 = 2·sqrt(t12·t23·t31·l123) = 8·Area const double denom2 = 2.0 * std::sqrt(denom2_sq); - // cot at v1 (opposite l23): adjacent t-values are t12 and t31. - // cot at v2 (opposite l31): adjacent t-values are t12 and t23. - // cot at v3 (opposite l12): adjacent t-values are t23 and t31. + // Formula: cot_k = (t_opp · l123 − t_a · t_b) / denom2 + // cot1: t_opp=t23, t_a=t12, t_b=t31 (v1 opposite l23) + // cot2: t_opp=t31, t_a=t12, t_b=t23 (v2 opposite l31) + // cot3: t_opp=t12, t_a=t23, t_b=t31 (v3 opposite l12) return { (t23 * l123 - t31 * t12) / denom2, // cot1 (t31 * l123 - t12 * t23) / denom2, // cot2 diff --git a/doc/reviewer/external-audit-2026-05-30.md b/doc/reviewer/external-audit-2026-05-30.md index b76245c..16bdedc 100644 --- a/doc/reviewer/external-audit-2026-05-30.md +++ b/doc/reviewer/external-audit-2026-05-30.md @@ -701,7 +701,7 @@ index. Add a comment: |----|------|-------|------|----------|--------| | A | `hyper_ideal_functional.hpp` | 319–344 | Bug | Critical (mixed config) | ✅ Fixed 2026-05-30 | | B | `gauss_bonnet.hpp` | 87–88, 128–134 | API error | Medium | ✅ Fixed 2026-05-31 | -| C | `euclidean_hessian.hpp` | 26–27, 57–58 | Doc error | Medium | 🟡 Open | +| C | `euclidean_hessian.hpp` | 26–27, 57–58 | Doc error | Medium | ✅ Fixed 2026-05-31 | | D | `euclidean_functional.hpp` + 2 others | 97–107 | Doc error | Medium | 🟡 Open | | E | `cp_euclidean_functional.hpp` | 338–349, 373–387 | Inconsistency | Medium | 🟡 Open | | F | test files | — | Test gap | Medium | 🟠 Open |