refactor(api): consistent naming for spherical + hyper-ideal helpers (A1–A3)
Standardize the low-level free-function API on <verb>_<geom>_<rest>, matching the already-consistent setup_<geom>_maps. Old names kept as [[deprecated]] inline aliases for one release; all internal call sites migrated. Renames: assign_vertex_dof_indices -> assign_spherical_vertex_dof_indices assign_all_spherical_dof_indices -> assign_spherical_all_dof_indices assign_all_dof_indices -> assign_hyper_ideal_all_dof_indices compute_lambda0_from_mesh -> compute_spherical_lambda0_from_mesh gradient_check -> gradient_check_hyper_ideal A4/A5 (public CGAL API) intentionally deferred pending the license/ provenance decision (see CGAL submission audit G0/G1). Verified: 277/277 CGAL tests pass, no deprecation warnings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -58,7 +58,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// ── Step 2: set up functional maps ────────────────────────────────────
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
std::cout << "[example_hyper_ideal] DOFs: " << n
|
||||
<< " (" << mesh.number_of_vertices() << " vertex + "
|
||||
|
||||
@@ -345,7 +345,7 @@ auto discrete_conformal_map_spherical(
|
||||
Conformal_map_result<FT> result;
|
||||
|
||||
auto maps = ::conformallab::setup_spherical_maps(mesh);
|
||||
::conformallab::compute_lambda0_from_mesh(mesh, maps);
|
||||
::conformallab::compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
|
||||
auto theta_param = parameters::get_parameter(
|
||||
np, Conformal_map::internal_np::vertex_curvature_map);
|
||||
@@ -499,7 +499,7 @@ auto discrete_conformal_map_hyper_ideal(
|
||||
maps.theta_v[v] = get(theta_param, v);
|
||||
}
|
||||
|
||||
const int n = ::conformallab::assign_all_dof_indices(mesh, maps);
|
||||
const int n = ::conformallab::assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
const FT tol = parameters::choose_parameter(
|
||||
parameters::get_parameter(np, Conformal_map::internal_np::gradient_tolerance),
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
// ─────
|
||||
// auto mesh = make_tetrahedron();
|
||||
// auto maps = setup_hyper_ideal_maps(mesh);
|
||||
// int n = assign_all_dof_indices(mesh, maps); // all variable
|
||||
// int n = assign_hyper_ideal_all_dof_indices(mesh, maps); // all variable
|
||||
// std::vector<double> x(n, 1.0);
|
||||
// auto res = evaluate_hyper_ideal(mesh, x, maps);
|
||||
// // res.energy, res.gradient
|
||||
@@ -104,7 +104,7 @@ inline int hyper_ideal_dimension(const ConformalMesh& mesh, const HyperIdealMaps
|
||||
/// rotational mode for an all-hyper-ideal configuration).
|
||||
///
|
||||
/// \returns total DOF count = `num_vertices(mesh) + num_edges(mesh)`.
|
||||
inline int assign_all_dof_indices(ConformalMesh& mesh, HyperIdealMaps& m)
|
||||
inline int assign_hyper_ideal_all_dof_indices(ConformalMesh& mesh, HyperIdealMaps& m)
|
||||
{
|
||||
int idx = 0;
|
||||
for (auto v : mesh.vertices()) m.v_idx[v] = idx++;
|
||||
@@ -112,6 +112,11 @@ inline int assign_all_dof_indices(ConformalMesh& mesh, HyperIdealMaps& m)
|
||||
return idx;
|
||||
}
|
||||
|
||||
/// \deprecated Use `assign_hyper_ideal_all_dof_indices` (API-naming audit A1).
|
||||
[[deprecated("renamed to assign_hyper_ideal_all_dof_indices")]]
|
||||
inline int assign_all_dof_indices(ConformalMesh& mesh, HyperIdealMaps& m)
|
||||
{ return assign_hyper_ideal_all_dof_indices(mesh, m); }
|
||||
|
||||
// ── Evaluation result ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Output of `evaluate_hyper_ideal()` — the energy value and (optionally)
|
||||
@@ -467,7 +472,7 @@ inline HyperIdealResult evaluate_hyper_ideal(
|
||||
///
|
||||
/// Returns `true` iff `|G[i] − fd[i]| / max(1, |G[i]|) < tol` for every
|
||||
/// DOF. Defaults `eps = 1e-5`, `tol = 1e-4` match the Java `FunctionalTest`.
|
||||
inline bool gradient_check(
|
||||
inline bool gradient_check_hyper_ideal(
|
||||
ConformalMesh& mesh,
|
||||
const std::vector<double>& x0,
|
||||
const HyperIdealMaps& m,
|
||||
@@ -500,4 +505,14 @@ inline bool gradient_check(
|
||||
return ok;
|
||||
}
|
||||
|
||||
/// \deprecated Use `gradient_check_hyper_ideal` (API-naming audit A3).
|
||||
[[deprecated("renamed to gradient_check_hyper_ideal")]]
|
||||
inline bool gradient_check(
|
||||
ConformalMesh& mesh,
|
||||
const std::vector<double>& x0,
|
||||
const HyperIdealMaps& m,
|
||||
double eps = 1E-5,
|
||||
double tol = 1E-4)
|
||||
{ return gradient_check_hyper_ideal(mesh, x0, m, eps, tol); }
|
||||
|
||||
} // namespace conformallab
|
||||
|
||||
@@ -384,7 +384,7 @@ inline NewtonResult newton_spherical(
|
||||
///
|
||||
/// DOF layout: first V_free entries are vertex variables b_v (hyper-ideal radii),
|
||||
/// followed by E entries for edge variables a_e (intersection angles).
|
||||
/// Use assign_all_dof_indices(mesh, maps) to set v_idx and e_idx automatically —
|
||||
/// Use assign_hyper_ideal_all_dof_indices(mesh, maps) to set v_idx and e_idx automatically —
|
||||
/// no vertex needs to be pinned.
|
||||
///
|
||||
/// \param mesh Input triangulated surface, genus g ≥ 1.
|
||||
|
||||
@@ -75,7 +75,7 @@ struct SphericalMaps {
|
||||
///
|
||||
/// Defaults match the Euclidean defaults except that `lambda0 = 0` here
|
||||
/// gives `l_e = π` which is degenerate on the unit sphere — always call
|
||||
/// `compute_lambda0_from_mesh(mesh, m)` next on a real mesh.
|
||||
/// `compute_spherical_lambda0_from_mesh(mesh, m)` next on a real mesh.
|
||||
inline SphericalMaps setup_spherical_maps(ConformalMesh& mesh)
|
||||
{
|
||||
SphericalMaps m;
|
||||
@@ -96,7 +96,7 @@ inline SphericalMaps setup_spherical_maps(ConformalMesh& mesh)
|
||||
///
|
||||
/// On closed spherical surfaces exactly one gauge vertex must be pinned
|
||||
/// to remove the global-scale null mode.
|
||||
inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
inline int assign_spherical_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{
|
||||
int idx = 0;
|
||||
for (auto v : mesh.vertices()) m.v_idx[v] = idx++;
|
||||
@@ -108,7 +108,7 @@ inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
/// surfaces to fix the global-scale gauge mode in a single call.
|
||||
///
|
||||
/// \returns The number of free DOFs assigned (`num_vertices − 1`).
|
||||
inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m,
|
||||
inline int assign_spherical_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m,
|
||||
Vertex_index gauge)
|
||||
{
|
||||
int idx = 0;
|
||||
@@ -117,10 +117,22 @@ inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m,
|
||||
return idx;
|
||||
}
|
||||
|
||||
/// \deprecated Use `assign_spherical_vertex_dof_indices`. Kept one release for
|
||||
/// source compatibility (API-naming audit A1, 2026-05-31).
|
||||
[[deprecated("renamed to assign_spherical_vertex_dof_indices")]]
|
||||
inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{ return assign_spherical_vertex_dof_indices(mesh, m); }
|
||||
|
||||
/// \deprecated Use `assign_spherical_vertex_dof_indices`.
|
||||
[[deprecated("renamed to assign_spherical_vertex_dof_indices")]]
|
||||
inline int assign_vertex_dof_indices(ConformalMesh& mesh, SphericalMaps& m,
|
||||
Vertex_index gauge)
|
||||
{ return assign_spherical_vertex_dof_indices(mesh, m, gauge); }
|
||||
|
||||
/// Assign DOF indices for all vertices AND all edges (vertex-DOFs first,
|
||||
/// then edge-DOFs). Mirrors `assign_euclidean_all_dof_indices` for the
|
||||
/// cyclic spherical formulation.
|
||||
inline int assign_all_spherical_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
inline int assign_spherical_all_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{
|
||||
int idx = 0;
|
||||
for (auto v : mesh.vertices()) m.v_idx[v] = idx++;
|
||||
@@ -128,6 +140,11 @@ inline int assign_all_spherical_dof_indices(ConformalMesh& mesh, SphericalMaps&
|
||||
return idx;
|
||||
}
|
||||
|
||||
/// \deprecated Use `assign_spherical_all_dof_indices` (API-naming audit A1).
|
||||
[[deprecated("renamed to assign_spherical_all_dof_indices")]]
|
||||
inline int assign_all_spherical_dof_indices(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{ return assign_spherical_all_dof_indices(mesh, m); }
|
||||
|
||||
/// Count the free DOFs (vertices + edges with index `≥ 0`).
|
||||
inline int spherical_dimension(const ConformalMesh& mesh, const SphericalMaps& m)
|
||||
{
|
||||
@@ -145,7 +162,7 @@ inline int spherical_dimension(const ConformalMesh& mesh, const SphericalMaps& m
|
||||
///
|
||||
/// \pre Every vertex `v` of `mesh` lies on the unit sphere (norm = 1).
|
||||
/// \pre No edge is degenerate (`p_i ≠ p_j` and `p_i ≠ -p_j`).
|
||||
inline void compute_lambda0_from_mesh(ConformalMesh& mesh, SphericalMaps& m)
|
||||
inline void compute_spherical_lambda0_from_mesh(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{
|
||||
for (auto e : mesh.edges()) {
|
||||
auto h = mesh.halfedge(e);
|
||||
@@ -163,6 +180,11 @@ inline void compute_lambda0_from_mesh(ConformalMesh& mesh, SphericalMaps& m)
|
||||
}
|
||||
}
|
||||
|
||||
/// \deprecated Use `compute_spherical_lambda0_from_mesh` (API-naming audit A2).
|
||||
[[deprecated("renamed to compute_spherical_lambda0_from_mesh")]]
|
||||
inline void compute_lambda0_from_mesh(ConformalMesh& mesh, SphericalMaps& m)
|
||||
{ compute_spherical_lambda0_from_mesh(mesh, m); }
|
||||
|
||||
// ── Evaluation result ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Output of `evaluate_spherical()` — energy plus optional gradient.
|
||||
|
||||
@@ -234,8 +234,8 @@ static int run_spherical(ConformalMesh& mesh,
|
||||
"has genus " << g << " — convergence is not guaranteed.\n";
|
||||
|
||||
auto maps = cl::setup_spherical_maps(mesh);
|
||||
cl::compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = cl::assign_vertex_dof_indices(mesh, maps);
|
||||
cl::compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = cl::assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), 0.0);
|
||||
auto res = cl::newton_spherical(mesh, x0, maps);
|
||||
@@ -277,7 +277,7 @@ static int run_hyper_ideal(ConformalMesh& mesh,
|
||||
bool verbose)
|
||||
{
|
||||
auto maps = cl::setup_hyper_ideal_maps(mesh);
|
||||
int n = cl::assign_all_dof_indices(mesh, maps);
|
||||
int n = cl::assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// Natural targets at base point (b=1, a=0.5)
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
|
||||
@@ -493,8 +493,8 @@ TEST(SphericalLayout, SphericalTetrahedron_NewtonConverges_AngleSumsTwoPi)
|
||||
ConformalMesh mesh = make_spherical_tetrahedron();
|
||||
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps); // SphericalMaps version
|
||||
int n = assign_vertex_dof_indices(mesh, maps); // pins gauge_vertex, assigns DOFs
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps); // SphericalMaps version
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps); // pins gauge_vertex, assigns DOFs
|
||||
// Note: enforce_gauss_bonnet not needed — natural theta from mesh satisfies Σ(2π-Θ)>0.
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), 0.0);
|
||||
|
||||
@@ -41,10 +41,10 @@ static std::vector<double> make_x_all_variable(
|
||||
ConformalMesh& mesh, HyperIdealMaps& maps,
|
||||
double b_val, double a_val)
|
||||
{
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
std::vector<double> x(static_cast<std::size_t>(n));
|
||||
|
||||
// Vertices first, then edges (matching assign_all_dof_indices order)
|
||||
// Vertices first, then edges (matching assign_hyper_ideal_all_dof_indices order)
|
||||
for (auto v : mesh.vertices())
|
||||
x[static_cast<std::size_t>(maps.v_idx[v])] = b_val;
|
||||
for (auto e : mesh.edges())
|
||||
@@ -62,7 +62,7 @@ TEST(HyperIdealFunctional, HessianSymmetryCheck)
|
||||
// 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);
|
||||
int n = assign_hyper_ideal_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);
|
||||
@@ -86,7 +86,7 @@ TEST(HyperIdealFunctional, GradientCheck_AllHyperIdealTriangle)
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
auto x = make_x_all_variable(mesh, maps, /*b=*/1.0, /*a=*/0.5);
|
||||
|
||||
EXPECT_TRUE(gradient_check(mesh, x, maps))
|
||||
EXPECT_TRUE(gradient_check_hyper_ideal(mesh, x, maps))
|
||||
<< "Finite-difference gradient check failed on all-hyper-ideal triangle";
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ TEST(HyperIdealFunctional, GradientCheck_ExtendedDomain)
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
auto x = make_x_all_variable(mesh, maps, /*b=*/2.0, /*a=*/1.5);
|
||||
|
||||
EXPECT_TRUE(gradient_check(mesh, x, maps))
|
||||
EXPECT_TRUE(gradient_check_hyper_ideal(mesh, x, maps))
|
||||
<< "Finite-difference gradient check failed in extended domain";
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ TEST(HyperIdealFunctional, GradientCheck_TetrahedronAllVariable)
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
auto x = make_x_all_variable(mesh, maps, /*b=*/1.0, /*a=*/0.5);
|
||||
|
||||
EXPECT_TRUE(gradient_check(mesh, x, maps))
|
||||
EXPECT_TRUE(gradient_check_hyper_ideal(mesh, x, maps))
|
||||
<< "Finite-difference gradient check failed on all-variable tetrahedron";
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ TEST(HyperIdealFunctional, EnergyFiniteAtTestPoint)
|
||||
{
|
||||
auto mesh = make_quad_strip();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// Values taken from the Java testFunctionalAtNaNValue spirit:
|
||||
// large-ish but positive DOF values that could expose degenerate paths.
|
||||
@@ -177,7 +177,7 @@ TEST(HyperIdealFunctional, GradientCheck_MixedIdealHyperIdeal)
|
||||
// DOF vector: [b1, b2, a_e0, a_e1, a_e2]
|
||||
std::vector<double> x = {1.0, 1.0, 0.5, 0.5, 0.5};
|
||||
|
||||
EXPECT_TRUE(gradient_check(mesh, x, maps))
|
||||
EXPECT_TRUE(gradient_check_hyper_ideal(mesh, x, maps))
|
||||
<< "Finite-difference gradient check failed for mixed ideal / hyper-ideal";
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ TEST(HyperIdealFunctional, GradientCheck_Fan6AllVariable)
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
auto x = make_x_all_variable(mesh, maps, /*b=*/1.0, /*a=*/0.5);
|
||||
|
||||
EXPECT_TRUE(gradient_check(mesh, x, maps))
|
||||
EXPECT_TRUE(gradient_check_hyper_ideal(mesh, x, maps))
|
||||
<< "Finite-difference gradient check failed on fan-6 mesh";
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ TEST(HyperIdealHessian, PureHelperMatchesMeshHelper)
|
||||
{
|
||||
auto mesh = make_tetrahedron();
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
for (auto f : mesh.faces()) {
|
||||
@@ -119,7 +119,7 @@ TEST(HyperIdealHessian, BlockFD_MatchesFullFD_ClosedTetrahedron)
|
||||
{
|
||||
auto mesh = make_tetrahedron();
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
auto H_full = hyper_ideal_hessian_sym (mesh, x, m);
|
||||
@@ -141,7 +141,7 @@ TEST(HyperIdealHessian, BlockFD_MatchesFullFD_Open3FaceMesh)
|
||||
{
|
||||
auto mesh = make_open_3face_mesh();
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
auto H_full = hyper_ideal_hessian_sym (mesh, x, m);
|
||||
@@ -196,7 +196,7 @@ TEST(HyperIdealHessian, BlockFD_IsPSD)
|
||||
{
|
||||
auto mesh = make_tetrahedron();
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
auto H = hyper_ideal_hessian_block_fd_sym(mesh, x, m);
|
||||
@@ -226,7 +226,7 @@ TEST(HyperIdealHessian, BlockFD_SparsityMatchesFaceAdjacency)
|
||||
{
|
||||
auto mesh = make_open_3face_mesh();
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
auto H = hyper_ideal_hessian_block_fd(mesh, x, m);
|
||||
@@ -307,7 +307,7 @@ TEST(HyperIdealHessian, BlockFD_FasterThanFullFD)
|
||||
// Theoretical ratio: ~42×. We assert ≥ 3× to leave wide CI tolerance.
|
||||
auto mesh = make_tet_strip(100);
|
||||
auto m = setup_hyper_ideal_maps(mesh);
|
||||
const int n = assign_all_dof_indices(mesh, m);
|
||||
const int n = assign_hyper_ideal_all_dof_indices(mesh, m);
|
||||
auto x = natural_x(mesh, m);
|
||||
|
||||
using clk = std::chrono::steady_clock;
|
||||
|
||||
@@ -160,7 +160,7 @@ TEST(LawsonHyperIdeal, ConvergenceGoldenVector_JavaXVal)
|
||||
ConformalMesh m = make_lawson_square_tiled(&original);
|
||||
|
||||
HyperIdealMaps maps = setup_hyper_ideal_maps(m); // Θ_v=2π, θ_e=π
|
||||
const int n = assign_all_dof_indices(m, maps); // all vertices + edges
|
||||
const int n = assign_hyper_ideal_all_dof_indices(m, maps); // all vertices + edges
|
||||
ASSERT_EQ(n, 4 + 18); // 4 b + 18 a = 22 DOFs
|
||||
|
||||
// θ_e = π/2 for the 12 original edges; the 6 diagonals keep the default π.
|
||||
|
||||
@@ -178,8 +178,8 @@ TEST(Layout, Spherical_PreservesArcLengths)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// Solve to identity
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), 0.0);
|
||||
@@ -212,8 +212,8 @@ TEST(Layout, Spherical_PositionsOnUnitSphere)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), 0.0);
|
||||
auto layout = spherical_layout(mesh, x, maps);
|
||||
@@ -233,7 +233,7 @@ TEST(Layout, HyperIdeal_SuccessAndFinitePositions)
|
||||
{
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// Natural equilibrium at (b=1, a=0.5)
|
||||
std::vector<double> xbase(static_cast<std::size_t>(n));
|
||||
|
||||
@@ -77,8 +77,8 @@ TEST(NewtonSolver, Spherical_ConvergesFromPerturbation)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.2);
|
||||
auto res = newton_spherical(mesh, x0, maps, /*tol=*/1e-8, /*max_iter=*/50);
|
||||
@@ -96,8 +96,8 @@ TEST(NewtonSolver, Spherical_FewIterations)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.2);
|
||||
auto res = newton_spherical(mesh, x0, maps, /*tol=*/1e-8, /*max_iter=*/50);
|
||||
@@ -114,8 +114,8 @@ TEST(NewtonSolver, Spherical_ConvergesFromLargePerturbation)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.5);
|
||||
auto res = newton_spherical(mesh, x0, maps, /*tol=*/1e-8, /*max_iter=*/100);
|
||||
@@ -134,8 +134,8 @@ TEST(NewtonSolver, Spherical_ResultFieldsConsistent)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.1);
|
||||
auto res = newton_spherical(mesh, x0, maps, /*tol=*/1e-8);
|
||||
@@ -306,7 +306,7 @@ TEST(NewtonSolver, HyperIdeal_ConvergesTriangleAllVariable)
|
||||
{
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// xbase = (b=1.0, a=0.5) is the equilibrium after natural-target setup.
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
@@ -331,7 +331,7 @@ TEST(NewtonSolver, HyperIdeal_ResultFieldsConsistent)
|
||||
{
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
|
||||
@@ -357,7 +357,7 @@ TEST(NewtonSolver, HyperIdeal_ConvergesTetrahedron)
|
||||
{
|
||||
auto mesh = make_tetrahedron();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
|
||||
@@ -384,7 +384,7 @@ TEST(NewtonSolver, HyperIdeal_SparseQRFallbackNoCrash)
|
||||
{
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// Leave targets at their default (0): solver tries to solve but the
|
||||
// "equilibrium" is at some unknown x*. With valid starting point the
|
||||
|
||||
@@ -434,7 +434,7 @@ static Layout2D make_hyper_ideal_layout_normalised(bool normalise)
|
||||
{
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> xbase(static_cast<std::size_t>(n));
|
||||
for (auto v : mesh.vertices()) {
|
||||
|
||||
@@ -148,8 +148,8 @@ TEST(Pipeline, Spherical_TetrahedronToEquilibrium)
|
||||
// ── Steps 1–3 ─────────────────────────────────────────────────────────
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// ── Step 4: solve ─────────────────────────────────────────────────────
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.2);
|
||||
@@ -178,7 +178,7 @@ TEST(Pipeline, HyperIdeal_TriangleRoundTrip)
|
||||
// ── Steps 1–3 ─────────────────────────────────────────────────────────
|
||||
auto mesh = make_triangle();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
|
||||
// ── Step 4: natural targets (equilibrium at b=1.0, a=0.5) ────────────
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
@@ -274,7 +274,7 @@ TEST(Pipeline, AllThreeGeometries_QuadStrip)
|
||||
{
|
||||
auto mesh = make_quad_strip();
|
||||
auto maps = setup_hyper_ideal_maps(mesh);
|
||||
int n = assign_all_dof_indices(mesh, maps);
|
||||
int n = assign_hyper_ideal_all_dof_indices(mesh, maps);
|
||||
auto xbase = set_natural_hyper_ideal_targets(mesh, maps, n);
|
||||
std::vector<double> x0 = xbase;
|
||||
for (auto& v : x0) v += 0.1;
|
||||
@@ -286,8 +286,8 @@ TEST(Pipeline, AllThreeGeometries_QuadStrip)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
std::vector<double> x0(static_cast<std::size_t>(n), -0.1);
|
||||
auto res = newton_spherical(mesh, x0, maps);
|
||||
EXPECT_TRUE(res.converged) << "Spherical: tetrahedron should converge";
|
||||
|
||||
@@ -52,8 +52,8 @@ TEST(SphericalFunctional, GradientCheck_Hessian)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.2);
|
||||
|
||||
@@ -122,8 +122,8 @@ TEST(SphericalFunctional, GradientCheck_OctaFaceVertex)
|
||||
{
|
||||
auto mesh = make_octahedron_face();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// Small uniform conformal factor: shrink the triangle slightly.
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.3);
|
||||
@@ -143,8 +143,8 @@ TEST(SphericalFunctional, GradientCheck_SpherTetVertex)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.2);
|
||||
|
||||
@@ -163,8 +163,8 @@ TEST(SphericalFunctional, GradientCheck_SpherTetAllDofs)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_all_spherical_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_all_dof_indices(mesh, maps);
|
||||
|
||||
// Replacement parameterization (Finding 3): when an edge carries a DOF its
|
||||
// value *replaces* λ°_ij + u_i + u_j entirely, so Λ_ij = λ_e. Here the edge
|
||||
@@ -208,8 +208,8 @@ TEST(SphericalFunctional, EdgeGradient_RegularTetClosedForm)
|
||||
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_all_spherical_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_all_dof_indices(mesh, maps);
|
||||
|
||||
// Edge DOF = λ⁰ → Λ_ij = λ⁰ → reproduces the arccos(−1/3) tetrahedron.
|
||||
// Vertex DOFs stay at 0 (ignored by the replacement convention for DOF edges).
|
||||
@@ -245,8 +245,8 @@ TEST(SphericalFunctional, AnglesFiniteAtKnownPoint)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// u_i = -1.5: contracts the triangle heavily but stays non-degenerate.
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -1.5);
|
||||
@@ -287,8 +287,8 @@ TEST(SphericalFunctional, GradientCheck_SpherFan4Vertex)
|
||||
mesh.add_face(center, rim[i], rim[(i + 1) % n_rim]);
|
||||
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int ndof = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int ndof = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(ndof), -0.3);
|
||||
|
||||
@@ -307,7 +307,7 @@ TEST(SphericalFunctional, GradientCheck_MixedPinnedVertices)
|
||||
{
|
||||
auto mesh = make_octahedron_face();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
|
||||
// Pin v0, make v1 and v2 variable.
|
||||
auto vit = mesh.vertices().begin();
|
||||
@@ -340,8 +340,8 @@ TEST(SphericalFunctional, GaugeFix_SpherTetVertexZerosSumGv)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// Off-gauge starting point: all u_i = -0.5
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.5);
|
||||
@@ -384,8 +384,8 @@ TEST(SphericalFunctional, GaugeFix_ApplyInPlace)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// x = -0.3: compressed but inside the valid spherical domain.
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.3);
|
||||
@@ -409,8 +409,8 @@ TEST(SphericalFunctional, GaugeFix_AlreadyAtGaugeReturnsTNearZero)
|
||||
// at the gauge maximum (by symmetry, ΣG_v = 0).
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), 0.0);
|
||||
double t = spherical_gauge_shift(mesh, x, maps);
|
||||
@@ -489,7 +489,7 @@ TEST(SphericalGoldenJava, AngleBetaEnergyFromLengths)
|
||||
// Setup parity (UnwrapUtility.prepareInvariantDataHyperbolicAndSpherical, scale):
|
||||
// closed mesh, ALL 4 vertices variable, Θ_v = 2π, no edge DOFs,
|
||||
// λ°_e = 2·log(SCALE·|p_i − p_j|) (Java uses chord length × scale, whereas the
|
||||
// C++ compute_lambda0_from_mesh helper assumes unit-sphere vertices and uses
|
||||
// C++ compute_spherical_lambda0_from_mesh helper assumes unit-sphere vertices and uses
|
||||
// ARC length — so we set λ° directly here to match Java exactly),
|
||||
// per-vertex u(P) = 0.10·X − 0.07·Y + 0.13·Z, SCALE = 0.2.
|
||||
//
|
||||
|
||||
@@ -80,8 +80,8 @@ TEST(SphericalHessian, HessianIsSymmetric)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.2);
|
||||
auto H = spherical_hessian(mesh, x, maps);
|
||||
@@ -106,8 +106,8 @@ TEST(SphericalHessian, ConstantVectorNotInNullSpace)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.2);
|
||||
auto H = spherical_hessian(mesh, x, maps);
|
||||
@@ -133,8 +133,8 @@ TEST(SphericalHessian, HessianIsNegativeSemiDefiniteAtEquilibrium)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
// x = 0 is the equilibrium for the regular spherical tetrahedron.
|
||||
std::vector<double> x(static_cast<std::size_t>(n), 0.0);
|
||||
@@ -156,8 +156,8 @@ TEST(SphericalHessian, FDCheck_OctaFaceVertex)
|
||||
{
|
||||
auto mesh = make_octahedron_face();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.3);
|
||||
|
||||
@@ -173,8 +173,8 @@ TEST(SphericalHessian, FDCheck_SpherTetVertex)
|
||||
{
|
||||
auto mesh = make_spherical_tetrahedron();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_vertex_dof_indices(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
int n = assign_spherical_vertex_dof_indices(mesh, maps);
|
||||
|
||||
std::vector<double> x(static_cast<std::size_t>(n), -0.2);
|
||||
|
||||
@@ -190,7 +190,7 @@ TEST(SphericalHessian, FDCheck_MixedPinnedVertices)
|
||||
{
|
||||
auto mesh = make_octahedron_face();
|
||||
auto maps = setup_spherical_maps(mesh);
|
||||
compute_lambda0_from_mesh(mesh, maps);
|
||||
compute_spherical_lambda0_from_mesh(mesh, maps);
|
||||
|
||||
auto vit = mesh.vertices().begin();
|
||||
Vertex_index v0 = *vit++;
|
||||
|
||||
Reference in New Issue
Block a user