arXiv:math/0603097 is Springborn 2008 ("A variational principle for weighted
Delaunay triangulations and hyperideal polyhedra"), not a Kolpakov-Mednykh paper.
The author pair Kolpakov & Mednykh has no joint publication from 2006; their
earliest collaboration is arXiv:1008.0312 (2010, on torus knots, unrelated).
The wrong author name was introduced during the Java→C++ port — the Java source
correctly links to math/0603097 without naming the authors; whoever ported it
invented "Kolpakov-Mednykh". The S1 citation audit (2026-05-31) then cemented
the error by adding the incorrect row to references.md.
Files corrected (7):
- code/include/hyper_ideal_utility.hpp
- code/include/hyper_ideal_functional.hpp
- code/tests/cgal/test_hyper_ideal_functional.cpp
- doc/math/references.md
- doc/roadmap/research-track.md
- doc/architecture/project-structure.md
- doc/api/tests.md
Also:
- doc/reviewer/math-derivation-citation-audit-2026-05-31.md: M1 post-correction noted
- doc/reviewer/finding-orchestration.md: lesson-learned section added (AI citation
audits can introduce plausible-but-wrong attributions; human expert review required
before CGAL submission)
- papers/MANUAL-DOWNLOAD.md: overview of papers requiring manual download (paywalled
journals, TU Berlin theses, books)
- .gitignore: papers/*.pdf excluded (downloaded arXiv PDFs, not tracked)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
3.7 KiB
C++
111 lines
3.7 KiB
C++
#pragma once
|
||
// Copyright (c) 2024-2026 Tarik Moussa.
|
||
// SPDX-License-Identifier: MIT
|
||
|
||
|
||
// Hyperbolic tetrahedron volume formulas.
|
||
// Ported from de.varylab.discreteconformal.functional.HyperIdealUtility (Java).
|
||
|
||
#include "clausen.hpp"
|
||
#include "constants.hpp"
|
||
|
||
#include <Eigen/Dense>
|
||
#include <cmath>
|
||
#include <complex>
|
||
|
||
namespace conformallab {
|
||
|
||
/// Volume of a generalized hyperbolic tetrahedron with dihedral
|
||
/// angles `A,…,F` via the Meyerhoff / Ushijima 2006 formula.
|
||
/// Same as Java `HyperIdealUtility.calculateTetrahedronVolume()`.
|
||
inline double calculateTetrahedronVolume(double A, double B, double C,
|
||
double D, double E, double F) {
|
||
// PI from constants.hpp (conformallab::PI)
|
||
|
||
// Degenerate if any angle equals pi.
|
||
if (A == PI || B == PI || C == PI || D == PI || E == PI || F == PI)
|
||
return 0.0;
|
||
|
||
const double sA = std::sin(A), sB = std::sin(B), sC = std::sin(C);
|
||
const double sD = std::sin(D), sE = std::sin(E), sF = std::sin(F);
|
||
const double cA = std::cos(A), cB = std::cos(B), cC = std::cos(C);
|
||
const double cD = std::cos(D), cE = std::cos(E), cF = std::cos(F);
|
||
|
||
// Unit complex numbers e^(i*angle).
|
||
using Cx = std::complex<double>;
|
||
auto polar = [](double angle) { return std::polar(1.0, angle); };
|
||
|
||
Cx ad = polar(A + D), be = polar(B + E), cf = polar(C + F);
|
||
Cx abc = polar(A + B + C), abf = polar(A + B + F);
|
||
Cx ace = polar(A + C + E), aef = polar(A + E + F);
|
||
Cx bcd = polar(B + C + D), bdf = polar(B + D + F);
|
||
Cx def = polar(D + E + F), cde = polar(C + D + E);
|
||
Cx abde = ad * be, acdf = ad * cf, bcef = be * cf;
|
||
Cx abcdef = abc * def;
|
||
|
||
Cx z = ad + be + cf + abf + ace + bcd + def + abcdef;
|
||
|
||
// Gram matrix of the tetrahedron.
|
||
Eigen::Matrix4d G;
|
||
G << 1.0, -cA, -cB, -cF,
|
||
-cA, 1.0, -cC, -cE,
|
||
-cB, -cC, 1.0, -cD,
|
||
-cF, -cE, -cD, 1.0;
|
||
|
||
Cx sqrtG = std::sqrt(Cx(G.determinant(), 0.0));
|
||
|
||
Cx f = Cx(sA*sD + sB*sE + sC*sF, 0.0);
|
||
Cx f1 = f - sqrtG;
|
||
Cx f2 = f + sqrtG;
|
||
Cx z1 = -2.0 * f1 / z;
|
||
Cx z2 = -2.0 * f2 / z;
|
||
|
||
auto U = [&](Cx zi) {
|
||
return 0.5 * (
|
||
+ ImLi2(zi)
|
||
+ ImLi2(abde * zi)
|
||
+ ImLi2(acdf * zi)
|
||
+ ImLi2(bcef * zi)
|
||
- ImLi2(-abc * zi)
|
||
- ImLi2(-aef * zi)
|
||
- ImLi2(-bdf * zi)
|
||
- ImLi2(-cde * zi)
|
||
);
|
||
};
|
||
|
||
return (U(z1) - U(z2)) / 2.0;
|
||
}
|
||
|
||
/// Volume of a hyperideal tetrahedron with one ideal vertex at γ via
|
||
/// the Springborn 2008 formula (arxiv math/0603097). Same as Java
|
||
/// `HyperIdealUtility.calculateTetrahedronVolumeWithIdealVertexAtGamma()`.
|
||
inline double calculateTetrahedronVolumeWithIdealVertexAtGamma(
|
||
double gamma1, double gamma2, double gamma3,
|
||
double alpha23, double alpha31, double alpha12)
|
||
{
|
||
// PI from constants.hpp (conformallab::PI)
|
||
auto L = [](double x) { return Lobachevsky(x); };
|
||
|
||
double result = L(gamma1) + L(gamma2) + L(gamma3);
|
||
|
||
result += L((PI + alpha31 - alpha12 - gamma1) / 2.0);
|
||
result += L((PI + alpha12 - alpha23 - gamma2) / 2.0);
|
||
result += L((PI + alpha23 - alpha31 - gamma3) / 2.0);
|
||
|
||
result += L((PI - alpha31 + alpha12 - gamma1) / 2.0);
|
||
result += L((PI - alpha12 + alpha23 - gamma2) / 2.0);
|
||
result += L((PI - alpha23 + alpha31 - gamma3) / 2.0);
|
||
|
||
result += L((PI + alpha31 + alpha12 - gamma1) / 2.0);
|
||
result += L((PI + alpha12 + alpha23 - gamma2) / 2.0);
|
||
result += L((PI + alpha23 + alpha31 - gamma3) / 2.0);
|
||
|
||
result += L((PI - alpha31 - alpha12 - gamma1) / 2.0);
|
||
result += L((PI - alpha12 - alpha23 - gamma2) / 2.0);
|
||
result += L((PI - alpha23 - alpha31 - gamma3) / 2.0);
|
||
|
||
return result / 2.0;
|
||
}
|
||
|
||
} // namespace conformallab
|