review: external audit v0.10.0 — all 14 findings resolved #33

Merged
user2595 merged 15 commits from review/external-audit-2026-05-30 into main 2026-05-30 23:20:00 +00:00
3 changed files with 40 additions and 25 deletions
Showing only changes of commit 7534c62c3d - Show all commits

View File

@@ -324,16 +324,19 @@ inline Eigen::SparseMatrix<double> cp_euclidean_hessian(const ConformalMesh&
return H;
}
/// FD gradient check for the CP-Euclidean functional. Mirrors the
/// Java `FunctionalTest`; default `eps = 1e-5`, `tol = 1e-6`.
/// FD gradient check for the CP-Euclidean functional (central differences).
/// Uses the same **relative** error criterion as every other gradient check in
/// this library: `|analytic fd| / max(1, |analytic|) < tol`.
/// Default `eps = 1e-5`, `tol = 1e-4` (matches Java `FunctionalTest`).
inline bool gradient_check_cp_euclidean(const ConformalMesh& mesh,
const std::vector<double>& x,
const CPEuclideanMaps& m,
double eps = 1e-5,
double tol = 1e-6)
double tol = 1e-4)
{
auto G = cp_euclidean_gradient(mesh, x, m);
const std::size_t n = G.size();
bool ok = true;
for (std::size_t i = 0; i < n; ++i) {
std::vector<double> xp = x, xm = x;
@@ -341,28 +344,33 @@ inline bool gradient_check_cp_euclidean(const ConformalMesh& mesh,
xm[i] -= eps;
const double Ep = cp_euclidean_energy(mesh, xp, m);
const double Em = cp_euclidean_energy(mesh, xm, m);
const double fd = (Ep - Em) / (2.0 * eps);
if (std::abs(G[i] - fd) > tol) {
const double fd = (Ep - Em) / (2.0 * eps);
const double err = std::abs(G[i] - fd);
const double scale = std::max(1.0, std::abs(G[i]));
if (err / scale > tol) {
std::cerr << "[cp-euclidean] FD gradient mismatch at DOF " << i
<< ": analytic=" << G[i]
<< " FD=" << fd
<< " diff=" << (G[i] - fd) << "\n";
return false;
<< " rel-err=" << (err / scale) << "\n";
ok = false;
}
}
return true;
return ok;
}
/// FD Hessian check for the CP-Euclidean functional. Verifies analytic
/// `H` column-by-column against `(G(x+εe_j) G(xεe_j)) / (2ε)`.
/// Uses the same **relative** error criterion as `hessian_check_euclidean`:
/// `|analytic fd| / max(1, |analytic|) < tol`.
inline bool hessian_check_cp_euclidean(const ConformalMesh& mesh,
const std::vector<double>& x,
const CPEuclideanMaps& m,
double eps = 1e-5,
double tol = 1e-5)
double tol = 1e-4)
{
const auto H = cp_euclidean_hessian(mesh, x, m);
const int n = static_cast<int>(H.rows());
bool ok = true;
for (int j = 0; j < n; ++j) {
std::vector<double> xp = x, xm = x;
@@ -372,19 +380,21 @@ inline bool hessian_check_cp_euclidean(const ConformalMesh& mesh,
auto Gm = cp_euclidean_gradient(mesh, xm, m);
for (int i = 0; i < n; ++i) {
double fd = (Gp[static_cast<std::size_t>(i)] - Gm[static_cast<std::size_t>(i)])
/ (2.0 * eps);
double an = H.coeff(i, j);
if (std::abs(an - fd) > tol) {
double fd = (Gp[static_cast<std::size_t>(i)] - Gm[static_cast<std::size_t>(i)])
/ (2.0 * eps);
double an = H.coeff(i, j);
double err = std::abs(an - fd);
double scale = std::max(1.0, std::abs(an));
if (err / scale > tol) {
std::cerr << "[cp-euclidean] FD Hessian mismatch at ("
<< i << "," << j << "): analytic=" << an
<< " FD=" << fd
<< " diff=" << (an - fd) << "\n";
return false;
<< " rel-err=" << (err / scale) << "\n";
ok = false;
}
}
}
return true;
return ok;
}
} // namespace conformallab

View File

@@ -354,32 +354,37 @@ inline double inversive_distance_energy(
}
/// FD gradient check for the Inversive-Distance functional (central diff).
/// Uses the same **relative** error criterion as every other gradient check:
/// `|analytic fd| / max(1, |analytic|) < tol`.
inline bool gradient_check_inversive_distance(
const ConformalMesh& mesh,
const std::vector<double>& x,
const InversiveDistanceMaps& m,
double eps = 1e-5,
double tol = 1e-6)
double tol = 1e-4)
{
auto G = inversive_distance_gradient(mesh, x, m);
const std::size_t n = G.size();
bool ok = true;
for (std::size_t i = 0; i < n; ++i) {
std::vector<double> xp = x, xm = x;
xp[i] += eps;
xm[i] -= eps;
double Ep = inversive_distance_energy(mesh, xp, m);
double Em = inversive_distance_energy(mesh, xm, m);
double fd = (Ep - Em) / (2.0 * eps);
if (std::abs(G[i] - fd) > tol) {
double Ep = inversive_distance_energy(mesh, xp, m);
double Em = inversive_distance_energy(mesh, xm, m);
double fd = (Ep - Em) / (2.0 * eps);
double err = std::abs(G[i] - fd);
double scale = std::max(1.0, std::abs(G[i]));
if (err / scale > tol) {
std::cerr << "[inversive-distance] FD gradient mismatch at DOF " << i
<< ": analytic=" << G[i]
<< " FD=" << fd
<< " diff=" << (G[i] - fd) << "\n";
return false;
<< " rel-err=" << (err / scale) << "\n";
ok = false;
}
}
return true;
return ok;
}
/// Newton equilibrium check: returns `true` iff the gradient at `x`

View File

@@ -703,7 +703,7 @@ index. Add a comment:
| B | `gauss_bonnet.hpp` | 8788, 128134 | API error | Medium | ✅ Fixed 2026-05-31 |
| C | `euclidean_hessian.hpp` | 2627, 5758 | Doc error | Medium | ✅ Fixed 2026-05-31 |
| D | `euclidean_functional.hpp` + 2 others | 97107 | Doc error | Medium | ✅ Fixed 2026-05-31 |
| E | `cp_euclidean_functional.hpp` | 338349, 373387 | Inconsistency | Medium | 🟡 Open |
| E | `cp_euclidean_functional.hpp` | 338349, 373387 | Inconsistency | Medium | ✅ Fixed 2026-05-31 |
| F | test files | — | Test gap | Medium | 🟠 Open |
| G | test files | — | Test gap | Medium | 🟠 Open |
| H | test files | — | Test gap | Medium | 🟠 Open |