feat(euclidean): full analytic edge-DOF (cyclic) Hessian; Tier-2 Wente finding
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 1m59s
API Docs / doc-build (pull_request) Successful in 55s
Markdown link check / check (pull_request) Successful in 1m0s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 2m25s
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 1m59s
API Docs / doc-build (pull_request) Successful in 55s
Markdown link check / check (pull_request) Successful in 1m0s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 2m25s
Upgrades the cyclic Euclidean Hessian from block-FD to closed-form, satisfying
the novelty-statement §3.2 "analytic Hessians, not finite difference" claim for
the Euclidean path.
- euclidean_hessian.hpp: `euclidean_hessian_analytic` — closed-form cyclic
Hessian from the law-of-cosines angle derivatives
∂α_i/∂s_i = ℓ_i²/4A, ∂α_i/∂s_j = ½cot α_i − ℓ_j²/4A (Σ_j = 0),
chained to (u, λ_e) and sign-mapped to the gradient outputs (−α vertex,
+α_opp edge). Reuses euclidean_cot_weights. Block-FD kept as cross-check.
- newton_solver.hpp: newton_euclidean cyclic path now uses the analytic Hessian.
- tests: CyclicHessian_Analytic_MatchesBlockFD_Tetrahedron — analytic == block-FD
(1e-6), == gradient FD (1e-5), symmetric (1e-9). Existing cyclic convergence
oracle still GREEN with the analytic Hessian routed in.
Tier-2 (Wente) finding: wente_torus02.obj is a QUAD mesh (1240 quads) and the
Java golden comes from cyclic (quad-net) uniformization; the C++ period-matrix
pipeline is triangle-based, so a faithful bit-vs-Java τ comparison needs a
quad/cyclic pipeline (Phase 9f). Deferred and documented; golden τ = ½+i√3/2.
244/244 cgal tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -258,13 +258,13 @@ inline NewtonResult newton_euclidean(
|
||||
}
|
||||
|
||||
// ── Hessian + solve H·Δx = −G (SparseQR fallback for singular H) ──
|
||||
// Cyclic layout (edge DOFs present) → block-FD Hessian, which covers the
|
||||
// vertex-edge / edge-edge blocks the analytic cotangent Laplacian omits.
|
||||
// Vertex-only layout → analytic cotangent Laplacian (cheaper, exact).
|
||||
// Cyclic layout (edge DOFs present) → analytic cyclic Hessian, covering
|
||||
// the vertex-edge / edge-edge blocks the vertex-only cotangent Laplacian
|
||||
// omits. Vertex-only layout → analytic cotangent Laplacian.
|
||||
bool has_edge_dof = false;
|
||||
for (auto e : mesh.edges())
|
||||
if (m.e_idx[e] >= 0) { has_edge_dof = true; break; }
|
||||
auto H = has_edge_dof ? euclidean_hessian_block_fd_sym(mesh, x, m)
|
||||
auto H = has_edge_dof ? euclidean_hessian_analytic(mesh, x, m)
|
||||
: euclidean_hessian(mesh, x, m);
|
||||
bool ok = false;
|
||||
Eigen::VectorXd dx = detail::solve_with_fallback(H, -G, ok);
|
||||
|
||||
Reference in New Issue
Block a user