feat(phase4): HyperIdeal Newton solver, SparseQR fallback, examples, docs

Phase 4 complete — 87 CGAL tests pass, 2 skipped.

Newton solver (phase4a):
- hyper_ideal_hessian.hpp: symmetric FD Hessian (O(ε²), PSD by convexity)
- newton_hyper_ideal(): Newton + backtracking for the HyperIdeal functional
- detail::solve_with_fallback(): optional bool* fallback_used parameter
- solve_linear_system(): public API exposing LDLT→SparseQR fallback

SparseQR fallback tests (SparseQRFallback.*):
- FullRankSystem_CorrectSolution: LDLT path, fallback_used=false
- SingularMatrix_FallbackActivated: zero-pivot → QR activated, fallback_used=true
- Euclidean_ClosedMeshNoPinConverges: gauge-mode null space handled via QR

HyperIdeal Newton tests (NewtonSolver.HyperIdeal_*):
- ConvergesTriangleAllVariable, ResultFieldsConsistent,
  ConvergesTetrahedron, SparseQRFallbackNoCrash
- Natural-target base point (b=1.0, a=0.5) — x=0 is degenerate in log-space

Pipeline tests (test_pipeline.cpp):
- End-to-end: all three geometries, mesh I/O round-trip, solve+export

Example programs (code/examples/):
- example_euclidean.cpp:   headless Euclidean pipeline
- example_hyper_ideal.cpp: headless HyperIdeal pipeline
- example_viewer.cpp:      interactive libigl viewer with jet colour map

README:
- Mathematical scope table: C++ vs Java original (18 rows)
- "For mathematicians" section: mental model, step-by-step new-functional
  guide, half-edge traversal snippets, recommended reading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-05-13 00:11:25 +02:00
parent e70689d29f
commit 3f124eb071
12 changed files with 1798 additions and 165 deletions

View File

@@ -20,7 +20,9 @@
#include "conformal_mesh.hpp"
#include "mesh_builder.hpp"
#include "hyper_ideal_functional.hpp"
#include "hyper_ideal_hessian.hpp"
#include <gtest/gtest.h>
#include <Eigen/Dense>
#include <cmath>
#include <vector>
@@ -52,9 +54,19 @@ static std::vector<double> make_x_all_variable(
// @Ignore in Java: no Hessian implemented
// ════════════════════════════════════════════════════════════════════════════
TEST(HyperIdealFunctional, GradientCheck_Hessian)
TEST(HyperIdealFunctional, HessianSymmetryCheck)
{
GTEST_SKIP() << "@Ignore in Java Hessian not implemented in the functional";
// Hessian is now implemented (numerical FD). Verify it is symmetric.
auto mesh = make_triangle();
auto maps = setup_hyper_ideal_maps(mesh);
int n = assign_all_dof_indices(mesh, maps);
std::vector<double> x(static_cast<std::size_t>(n), 0.5);
auto H = hyper_ideal_hessian_sym(mesh, x, maps);
Eigen::MatrixXd Hd(H);
EXPECT_NEAR((Hd - Hd.transpose()).norm(), 0.0, 1e-8)
<< "HyperIdeal Hessian must be symmetric";
}
// ════════════════════════════════════════════════════════════════════════════