summaryrefslogtreecommitdiff
path: root/geom_bottleneck/include/bottleneck_detail.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'geom_bottleneck/include/bottleneck_detail.hpp')
-rw-r--r--geom_bottleneck/include/bottleneck_detail.hpp200
1 files changed, 121 insertions, 79 deletions
diff --git a/geom_bottleneck/include/bottleneck_detail.hpp b/geom_bottleneck/include/bottleneck_detail.hpp
index ad6c882..8ec9c68 100644
--- a/geom_bottleneck/include/bottleneck_detail.hpp
+++ b/geom_bottleneck/include/bottleneck_detail.hpp
@@ -40,6 +40,7 @@ derivative works thereof, in binary and source code form.
#include <sstream>
#include <string>
#include <cctype>
+#include <set>
#include "bottleneck_detail.h"
@@ -106,31 +107,35 @@ namespace hera {
distMax = std::max(distMax, infinityCost);
}
- template<class Real>
- inline Real getOneDimensionalCost(std::vector<Real>& set_A, std::vector<Real>& set_B)
- {
- if (set_A.size() != set_B.size()) {
- return std::numeric_limits<Real>::infinity();
- }
-
- if (set_A.empty()) {
- return Real(0.0);
- }
-
- std::sort(set_A.begin(), set_A.end());
- std::sort(set_B.begin(), set_B.end());
-
- Real result = 0.0;
- for (size_t i = 0; i < set_A.size(); ++i) {
- result = std::max(result, (std::fabs(set_A[i] - set_B[i])));
- }
-
- return result;
- }
+ // template<class Real>
+ // inline Real getOneDimensionalCost(std::vector<Real>& set_A, std::vector<Real>& set_B)
+ // {
+ // if (set_A.size() != set_B.size()) {
+ // return std::numeric_limits<Real>::infinity();
+ // }
+ //
+ // if (set_A.empty()) {
+ // return Real(0.0);
+ // }
+ //
+ // std::sort(set_A.begin(), set_A.end());
+ // std::sort(set_B.begin(), set_B.end());
+ //
+ // Real result = 0.0;
+ // for (size_t i = 0; i < set_A.size(); ++i) {
+ // result = std::max(result, (std::fabs(set_A[i] - set_B[i])));
+ // }
+ //
+ // return result;
+ // }
template<class Real>
- using CostEdgePair = std::pair<Real, typename hera::bt::MatchingEdge<Real>>;
+ struct CostEdgePair
+ {
+ Real cost;
+ typename hera::bt::MatchingEdge<Real> edge;
+ };
template<class Real>
using CoordPointPair = std::pair<Real, typename hera::bt::DiagramPoint<Real>>;
@@ -148,27 +153,31 @@ namespace hera {
};
template<class Real>
- inline typename hera::bt::CostEdgePair<Real> getOneDimensionalCost(typename hera::bt::CoordPointVector<Real>& set_A, typename hera::bt::CoordPointVector<Real>& set_B)
+ inline typename hera::bt::CostEdgePair<Real>
+ getOneDimensionalCost(typename hera::bt::CoordPointVector<Real>& set_A,
+ typename hera::bt::CoordPointVector<Real>& set_B)
{
using MatchingEdgeR = hera::bt::MatchingEdge<Real>;
+ using CostEdgePairR = CostEdgePair<Real>;
+
if (set_A.size() != set_B.size()) {
- return std::make_pair(std::numeric_limits<Real>::infinity(), MatchingEdgeR());
+ return CostEdgePairR { std::numeric_limits<Real>::infinity(), MatchingEdgeR() };
}
if (set_A.empty()) {
- return std::make_pair(Real(0.0), MatchingEdgeR());
+ return CostEdgePairR { Real(0.0), MatchingEdgeR() };
}
std::sort(set_A.begin(), set_A.end(), CoordPointPairComparator<Real>());
std::sort(set_B.begin(), set_B.end(), CoordPointPairComparator<Real>());
- CostEdgePair<Real> result(-1.0, MatchingEdgeR());
+ CostEdgePairR result { -1.0, MatchingEdgeR() };
for (size_t i = 0; i < set_A.size(); ++i) {
Real curr_cost = std::fabs(set_A[i].first - set_B[i].first);
- if (curr_cost > result.first) {
- result.first = curr_cost;
- result.second = MatchingEdgeR(set_A[i].second, set_B[i].second);
+ if (curr_cost > result.cost) {
+ result.cost = curr_cost;
+ result.edge = MatchingEdgeR(set_A[i].second, set_B[i].second);
}
}
return result;
@@ -176,23 +185,26 @@ namespace hera {
template<class Real>
- inline Real getInfinityCost(const DiagramPointSet <Real>& A, const DiagramPointSet <Real>& B,
- bool compute_longest_edge = false)
+ inline CostEdgePair<Real> getInfinityCost(const DiagramPointSet <Real>& A, const DiagramPointSet <Real>& B,
+ bool compute_longest_edge = false)
{
- std::vector<Real> x_plus_A, x_minus_A, y_plus_A, y_minus_A;
- std::vector<Real> x_plus_B, x_minus_B, y_plus_B, y_minus_B;
+ using CostEdgePairR = CostEdgePair<Real>;
+ using CoordPointVectorR = CoordPointVector<Real>;
+
+ CoordPointVectorR x_plus_A, x_minus_A, y_plus_A, y_minus_A;
+ CoordPointVectorR x_plus_B, x_minus_B, y_plus_B, y_minus_B;
for (auto iter_A = A.cbegin(); iter_A != A.cend(); ++iter_A) {
Real x = iter_A->getRealX();
Real y = iter_A->getRealY();
if (x == std::numeric_limits<Real>::infinity()) {
- y_plus_A.push_back(y);
+ y_plus_A.emplace_back(y, *iter_A);
} else if (x == -std::numeric_limits<Real>::infinity()) {
- y_minus_A.push_back(y);
+ y_minus_A.emplace_back(y, *iter_A);
} else if (y == std::numeric_limits<Real>::infinity()) {
- x_plus_A.push_back(x);
+ x_plus_A.emplace_back(x, *iter_A);
} else if (y == -std::numeric_limits<Real>::infinity()) {
- x_minus_A.push_back(x);
+ x_minus_A.emplace_back(x, *iter_A);
}
}
@@ -200,45 +212,60 @@ namespace hera {
Real x = iter_B->getRealX();
Real y = iter_B->getRealY();
if (x == std::numeric_limits<Real>::infinity()) {
- y_plus_B.push_back(y);
+ y_plus_B.emplace_back(y, *iter_B);
} else if (x == -std::numeric_limits<Real>::infinity()) {
- y_minus_B.push_back(y);
+ y_minus_B.emplace_back(y, *iter_B);
} else if (y == std::numeric_limits<Real>::infinity()) {
- x_plus_B.push_back(x);
+ x_plus_B.emplace_back(x, *iter_B);
} else if (y == -std::numeric_limits<Real>::infinity()) {
- x_minus_B.push_back(x);
+ x_minus_B.emplace_back(x, *iter_B);
}
}
- Real infinity_cost = getOneDimensionalCost(x_plus_A, x_plus_B);
- infinity_cost = std::max(infinity_cost, getOneDimensionalCost(x_minus_A, x_minus_B));
- infinity_cost = std::max(infinity_cost, getOneDimensionalCost(y_plus_A, y_plus_B));
- infinity_cost = std::max(infinity_cost, getOneDimensionalCost(y_minus_A, y_minus_B));
+ CostEdgePairR result = getOneDimensionalCost(x_plus_A, x_plus_B);
- return infinity_cost;
+ CostEdgePairR next_cost_edge = getOneDimensionalCost(x_minus_A, x_minus_B);
+ if (next_cost_edge.cost > result.cost) {
+ result = next_cost_edge;
+ }
+
+ next_cost_edge = getOneDimensionalCost(y_plus_A, y_plus_B);
+ if (next_cost_edge.cost > result.cost) {
+ result = next_cost_edge;
+ }
+
+ next_cost_edge = getOneDimensionalCost(y_minus_A, y_minus_B);
+ if (next_cost_edge.cost > result.cost) {
+ result = next_cost_edge;
+ }
+
+ return result;
}
-// return the interval (distMin, distMax) such that:
-// a) actual bottleneck distance between A and B is contained in the interval
-// b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
+ // return the interval (distMin, distMax) such that:
+ // a) actual bottleneck distance between A and B is contained in the interval
+ // b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
template<class Real>
inline std::pair<Real, Real>
- bottleneckDistApproxInterval(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B, const Real epsilon,
- MatchingEdge <Real>& edge, bool compute_longest_edge)
+ bottleneckDistApproxInterval(DiagramPointSet<Real>& A, DiagramPointSet<Real>& B, const Real epsilon,
+ MatchingEdge<Real>& edge, bool compute_longest_edge)
{
+ using MatchingEdgeR = MatchingEdge<Real>;
+ using CostEdgePairR = CostEdgePair<Real>;
+
+ edge = MatchingEdgeR();
// empty diagrams are not considered as error
if (A.empty() and B.empty()) {
return std::make_pair(0.0, 0.0);
}
- if (compute_longest_edge) {
- auto inf_cost_edge = getInfinityCost(A, B, true);
- } else {
- }
+ CostEdgePairR inf_cost_edge = getInfinityCost(A, B, true);
- Real infinity_cost = getInfinityCost(A, B);
+ Real infinity_cost = inf_cost_edge.cost;
if (infinity_cost == std::numeric_limits<Real>::infinity()) {
return std::make_pair(infinity_cost, infinity_cost);
+ } else {
+ edge = inf_cost_edge.edge;
}
// link diagrams A and B by adding projections
@@ -254,15 +281,20 @@ namespace hera {
BoundMatchOracle<Real> oracle(A, B, epsThreshold, useRangeSearch);
// check for distance = 0
if (oracle.isMatchLess(2 * epsThreshold)) {
- result.first = std::max(result.first, infinity_cost);
- result.second = std::max(result.first, infinity_cost);
+ if (infinity_cost > epsThreshold) {
+ result.first = infinity_cost;
+ result.second = infinity_cost;
+ edge = inf_cost_edge.edge;
+ }
return result;
}
// get a 3-approximation of maximal distance between A and B
// as a starting value for probe distance
Real distProbe { getFurthestDistance3Approx<Real, DiagramPointSet<Real>>(A, B) };
binarySearch(epsilon, result, oracle, infinity_cost, false, distProbe);
- if (compute_longest_edge) {
+ // to compute longest edge a perfect matching is needed
+ if (compute_longest_edge and result.first > infinity_cost) {
+ oracle.isMatchLess(result.second);
edge = oracle.get_longest_edge();
}
return result;
@@ -318,9 +350,9 @@ namespace hera {
}
-// return the interval (distMin, distMax) such that:
-// a) actual bottleneck distance between A and B is contained in the interval
-// b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
+ // return the interval (distMin, distMax) such that:
+ // a) actual bottleneck distance between A and B is contained in the interval
+ // b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
template<class Real>
std::pair<Real, Real>
bottleneckDistApproxIntervalWithInitial(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B,
@@ -378,10 +410,10 @@ namespace hera {
return result;
}
-// return the interval (distMin, distMax) such that:
-// a) actual bottleneck distance between A and B is contained in the interval
-// b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
-// use heuristic: initial estimate on sampled diagrams
+ // return the interval (distMin, distMax) such that:
+ // a) actual bottleneck distance between A and B is contained in the interval
+ // b) if the interval is not (0,0), then (distMax - distMin) / distMin < epsilon
+ // use heuristic: initial estimate on sampled diagrams
template<class Real>
std::pair<Real, Real>
bottleneckDistApproxIntervalHeur(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B, const Real epsilon,
@@ -410,13 +442,13 @@ namespace hera {
}
-// get approximate distance,
-// see bottleneckDistApproxInterval
+ // get approximate distance,
+ // see bottleneckDistApproxInterval
template<class Real>
Real bottleneckDistApprox(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B, const Real epsilon,
MatchingEdge <Real>& longest_edge, bool compute_longest_edge)
{
- auto interval = bottleneckDistApproxInterval<Real>(A, B, epsilon, longest_edge);
+ auto interval = bottleneckDistApproxInterval<Real>(A, B, epsilon, longest_edge, compute_longest_edge);
return interval.second;
}
@@ -444,7 +476,7 @@ namespace hera {
distEpsilon = diff;
}
}
- distEpsilon /= 3.0;
+ distEpsilon = std::min(diffThreshold, distEpsilon / 3.0);
BoundMatchOracle<Real> oracle(A, B, distEpsilon, useRangeSearch);
// binary search
@@ -462,16 +494,19 @@ namespace hera {
}
}
idxMid = static_cast<size_t>(floor(idxMin + idxMax) / 2.0);
+ Real result = pairwiseDist[idxMid];
if (compute_longest_edge) {
+ oracle.isMatchLess(result + distEpsilon / 2.0);
longest_edge = oracle.get_longest_edge();
}
- return pairwiseDist[idxMid];
+ return result;
}
template<class Real>
- Real bottleneckDistExact(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B, MatchingEdge <Real>& longest_edge,
- bool compute_longest_edge)
+ Real
+ bottleneckDistExact(DiagramPointSet <Real>& A, DiagramPointSet <Real>& B, MatchingEdge <Real>& longest_edge,
+ bool compute_longest_edge)
{
return bottleneckDistExact(A, B, 14, longest_edge, compute_longest_edge);
}
@@ -483,7 +518,10 @@ namespace hera {
using DgmPoint = DiagramPoint<Real>;
constexpr Real epsilon = 0.001;
- auto interval = bottleneckDistApproxInterval(A, B, epsilon, longest_edge);
+ auto interval = bottleneckDistApproxInterval(A, B, epsilon, longest_edge, true);
+ // if the longest edge is on infinity, the answer is already exact
+ // this will be detected here and all the code after if
+ // may assume that the longest edge is on finite points
if (interval.first == interval.second) {
return interval.first;
}
@@ -504,7 +542,7 @@ namespace hera {
// in this vector we store the distances between the points
// that are candidates to realize
- std::vector<Real> pairwiseDist;
+ std::set<Real> pairwiseDist;
{
// vector to store centers of vertical stripes
// two for each point in A and the id of the corresponding point
@@ -540,7 +578,7 @@ namespace hera {
// check if distance fits into the interval we've found
Real pwDist = distLInf(iterA->second, ptB);
if (pwDist >= minDist and pwDist <= maxDist) {
- pairwiseDist.push_back(pwDist);
+ pairwiseDist.insert(pwDist);
}
}
}
@@ -577,15 +615,19 @@ namespace hera {
}
Real pwDist = distLInf(iterA->second, ptB);
if (pwDist >= minDist and pwDist <= maxDist) {
- pairwiseDist.push_back(pwDist);
+ pairwiseDist.insert(pwDist);
}
}
}
}
- std::sort(pairwiseDist.begin(), pairwiseDist.end());
+ std::vector<Real> pw_dists;
+ pw_dists.reserve(pairwiseDist.size());
+ for(Real d : pairwiseDist) {
+ pw_dists.push_back(d);
+ }
- return bottleneckDistExactFromSortedPwDist(A, B, pairwiseDist, decPrecision, longest_edge,
+ return bottleneckDistExactFromSortedPwDist(A, B, pw_dists, decPrecision, longest_edge,
compute_longest_edge);
}