summaryrefslogtreecommitdiff
path: root/geom_bottleneck/bottleneck/src/bound_match.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'geom_bottleneck/bottleneck/src/bound_match.cpp')
-rw-r--r--geom_bottleneck/bottleneck/src/bound_match.cpp566
1 files changed, 0 insertions, 566 deletions
diff --git a/geom_bottleneck/bottleneck/src/bound_match.cpp b/geom_bottleneck/bottleneck/src/bound_match.cpp
deleted file mode 100644
index 210bd81..0000000
--- a/geom_bottleneck/bottleneck/src/bound_match.cpp
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
-Copyrigth 2015, D. Morozov, M. Kerber, A. Nigmetov
-
-This file is part of GeomBottleneck.
-
-GeomBottleneck is free software: you can redistribute it and/or modify
-it under the terms of the Lesser GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-GeomBottleneck is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-Lesser GNU General Public License for more details.
-
-You should have received a copy of the Lesser GNU General Public License
-along with GeomBottleneck. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include <assert.h>
-#include "def_debug_bt.h"
-#include "bound_match.h"
-
-#ifdef VERBOSE_BOTTLENECK
-#include <chrono>
-#endif
-
-#ifndef FOR_R_TDA
-#include <iostream>
-#endif
-
-namespace geom_bt {
-/*static void printDebug(//bool isDebug, std::string s)*/
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s << std::endl;
- //}
-//#endif
-//}
-
-//static void printDebug(//bool isDebug, std::string s, const Matching& m)
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s << std::endl;
- //std::cout << m << std::endl;
- //}
-//#endif
-//}
-
-//static void printDebug(//bool isDebug, std::string s, const DiagramPoint& p)
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s << p << std::endl;
- //}
-//#endif
-//}
-
-//static void printDebug(//bool isDebug, std::string s, const double r)
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s << r << std::endl;
- //}
-//#endif
-//}
-
-//static void printDebug(//bool isDebug, std::string s, const Path p)
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s;
- //for(auto pt : p) {
- //std::cout << pt << "; ";
- //}
- //std::cout << std::endl;
- //}
-//#endif
-//}
-
-//static void printDebug(//bool isDebug, std::string s, const DiagramPointSet& dpSet)
-//{
-//#ifdef DEBUG_BOUND_MATCH
- //if (isDebug) {
- //std::cout << s << dpSet << std::endl;
- //}
-//#endif
-/*}*/
-
-#ifndef FOR_R_TDA
-std::ostream& operator<<(std::ostream& output, const Matching& m)
-{
- output << "Matching: " << m.AToB.size() << " pairs (";
- if (!m.isPerfect()) {
- output << "not";
- }
- output << " perfect)" << std::endl;
- for(auto atob : m.AToB) {
- output << atob.first << " <-> " << atob.second << " distance: " << distLInf(atob.first, atob.second) << std::endl;
- }
- return output;
-}
-#endif
-
-void Matching::sanityCheck() const
-{
-#ifdef DEBUG_MATCHING
- assert( AToB.size() == BToA.size() );
- for(auto aToBPair : AToB) {
- auto bToAPair = BToA.find(aToBPair.second);
- assert(bToAPair != BToA.end());
- if (aToBPair.first != bToAPair->second) {
-#ifndef FOR_R_TDA
- std::cerr << "failed assertion, in aToB " << aToBPair.first;
- std::cerr << ", in bToA " << bToAPair->second << std::endl;
-#endif
- assert(false);
- }
- assert( aToBPair.first == bToAPair->second);
- }
-#endif
-}
-
-bool Matching::isPerfect() const
-{
- //sanityCheck();
- return AToB.size() == A.size();
-}
-
-void Matching::matchVertices(const DiagramPoint& pA, const DiagramPoint& pB)
-{
- assert(A.hasElement(pA));
- assert(B.hasElement(pB));
- AToB.erase(pA);
- AToB.insert( {{ pA, pB }} );
- BToA.erase(pB);
- BToA.insert( {{ pB, pA }} );
-}
-
-bool Matching::getMatchedVertex(const DiagramPoint& p, DiagramPoint& result) const
-{
- sanityCheck();
- auto inA = AToB.find(p);
- if (inA != AToB.end()) {
- result = (*inA).second;
- return true;
- } else {
- auto inB = BToA.find(p);
- if (inB != BToA.end()) {
- result = (*inB).second;
- return true;
- }
- }
- return false;
-}
-
-
-void Matching::checkAugPath(const Path& augPath) const
-{
- assert(augPath.size() % 2 == 0);
- for(size_t idx = 0; idx < augPath.size(); ++idx) {
- bool mustBeExposed { idx == 0 or idx == augPath.size() - 1 };
- if (isExposed(augPath[idx]) != mustBeExposed) {
-#ifndef FOR_R_TDA
- std::cerr << "mustBeExposed = " << mustBeExposed << ", idx = " << idx << ", point " << augPath[idx] << std::endl;
-#endif
- }
- assert( isExposed(augPath[idx]) == mustBeExposed );
- DiagramPoint matchedVertex {0.0, 0.0, DiagramPoint::DIAG, 1};
- if ( idx % 2 == 0 ) {
- assert( A.hasElement(augPath[idx]));
- if (!mustBeExposed) {
- getMatchedVertex(augPath[idx], matchedVertex);
- assert(matchedVertex == augPath[idx - 1]);
- }
- } else {
- assert( B.hasElement(augPath[idx]));
- if (!mustBeExposed) {
- getMatchedVertex(augPath[idx], matchedVertex);
- assert(matchedVertex == augPath[idx + 1]);
- }
- }
- }
-}
-
-// use augmenting path to increase
-// the size of the matching
-void Matching::increase(const Path& augPath)
-{
- //bool isDebug {false};
- sanityCheck();
- // check that augPath is an augmenting path
- checkAugPath(augPath);
- for(size_t idx = 0; idx < augPath.size() - 1; idx += 2) {
- matchVertices( augPath[idx], augPath[idx + 1]);
- }
- //printDebug(isDebug, "", *this);
- sanityCheck();
-}
-
-DiagramPointSet Matching::getExposedVertices(bool forA) const
-{
- sanityCheck();
- DiagramPointSet result;
- const DiagramPointSet* setToSearch { forA ? &A : &B };
- const std::unordered_map<DiagramPoint, DiagramPoint, DiagramPointHash>* mapToSearch { forA ? &AToB : &BToA };
- for(auto it = setToSearch->cbegin(); it != setToSearch->cend(); ++it) {
- if (mapToSearch->find((*it)) == mapToSearch->cend()) {
- result.insert((*it));
- }
- }
- return result;
-}
-
-void Matching::getAllAdjacentVertices(const DiagramPointSet& setIn,
- DiagramPointSet& setOut,
- bool forA) const
-{
- sanityCheck();
- //bool isDebug {false};
- setOut.clear();
- const std::unordered_map<DiagramPoint, DiagramPoint, DiagramPointHash>* m;
- m = ( forA ) ? &BToA : &AToB;
- for(auto pit = setIn.cbegin(); pit != setIn.cend(); ++pit) {
- auto findRes = m->find(*pit);
- if (findRes != m->cend()) {
- setOut.insert((*findRes).second);
- }
- }
- //printDebug(isDebug, "got all adjacent vertices for ", setIn);
- //printDebug(isDebug, "the result is: ", setOut);
- sanityCheck();
-}
-
-bool Matching::isExposed(const DiagramPoint& p) const
-{
- return ( AToB.find(p) == AToB.end() ) && ( BToA.find(p) == BToA.end() );
-}
-
-
-BoundMatchOracle::BoundMatchOracle(DiagramPointSet psA, DiagramPointSet psB,
- double dEps, bool useRS) :
- A(psA), B(psB), M(A, B), distEpsilon(dEps), useRangeSearch(useRS), prevQueryValue(0.0)
-{
- neighbOracle = new NeighbOracle(psB, 0, distEpsilon);
-}
-
-bool BoundMatchOracle::isMatchLess(double r)
-{
-#ifdef VERBOSE_BOTTLENECK
- std::chrono::high_resolution_clock hrClock;
- std::chrono::time_point<std::chrono::high_resolution_clock> startMoment;
- startMoment = hrClock.now();
-#endif
- bool result = buildMatchingForThreshold(r);
-#ifdef VERBOSE_BOTTLENECK
- auto endMoment = hrClock.now();
- std::chrono::duration<double, std::milli> iterTime = endMoment - startMoment;
- std::cout << "isMatchLess for r = " << r << " finished in " << std::chrono::duration<double, std::milli>(iterTime).count() << " ms." << std::endl;
-#endif
- return result;
-
-}
-
-
-void BoundMatchOracle::removeFromLayer(const DiagramPoint& p, const int layerIdx) {
- //bool isDebug {false};
- //printDebug(isDebug, "entered removeFromLayer, layerIdx == " + std::to_string(layerIdx) + ", p = ", p);
- layerGraph[layerIdx].erase(p);
- if (layerOracles[layerIdx]) {
- layerOracles[layerIdx]->deletePoint(p);
- }
-}
-
-// return true, if there exists an augmenting path from startVertex
-// in this case the path is returned in result.
-// startVertex must be an exposed vertex from L_1 (layer[0])
-bool BoundMatchOracle::buildAugmentingPath(const DiagramPoint startVertex, Path& result)
-{
- //bool isDebug {false};
- //printDebug(isDebug, "Entered buildAugmentingPath, startVertex: ", startVertex);
- DiagramPoint prevVertexA = startVertex;
- result.clear();
- result.push_back(startVertex);
- size_t evenLayerIdx {1};
- while ( evenLayerIdx < layerGraph.size() ) {
- //for(size_t evenLayerIdx = 1; evenLayerIdx < layerGraph.size(); evenLayerIdx += 2) {
- DiagramPoint nextVertexB{0.0, 0.0, DiagramPoint::DIAG, 1}; // next vertex from even layer
- bool neighbFound = layerOracles[evenLayerIdx]->getNeighbour(prevVertexA, nextVertexB);
- //printDebug(isDebug, "Searched neighbours for ", prevVertexA);
- //printDebug(isDebug, "; the result is ", nextVertexB);
- if (neighbFound) {
- result.push_back(nextVertexB);
- if ( layerGraph.size() == evenLayerIdx + 1) {
- //printDebug(isDebug, "Last layer reached, stopping; the path: ", result);
- break;
- } else {
- // nextVertexB must be matched with some vertex from the next odd
- // layer
- DiagramPoint nextVertexA {0.0, 0.0, DiagramPoint::DIAG, 1};
- if (!M.getMatchedVertex(nextVertexB, nextVertexA)) {
-#ifndef FOR_R_TDA
- std::cerr << "Vertices in even layers must be matched! Unmatched: ";
- std::cerr << nextVertexB << std::endl;
- std::cerr << evenLayerIdx << "; " << layerGraph.size() << std::endl;
-#endif
- throw std::runtime_error("Unmatched vertex in even layer");
- } else {
- assert( ! (nextVertexA.getRealX() == 0 and nextVertexA.getRealY() == 0) );
- result.push_back(nextVertexA);
- //printDebug(isDebug, "Matched vertex from the even layer added to the path, result: ", result);
- prevVertexA = nextVertexA;
- evenLayerIdx += 2;
- continue;
- }
- }
- } else {
- // prevVertexA has no neighbours in the next layer,
- // backtrack
- if (evenLayerIdx == 1) {
- // startVertex is not connected to any vertices
- // in the next layer, augm. path doesn't exist
- //printDebug(isDebug, "startVertex is not connected to any vertices in the next layer, augm. path doesn't exist");
- removeFromLayer(startVertex, 0);
- return false;
- } else {
- assert(evenLayerIdx >= 3);
- assert(result.size() % 2 == 1);
- result.pop_back();
- DiagramPoint prevVertexB = result.back();
- result.pop_back();
- //printDebug(isDebug, "removing 2 previous vertices from layers, evenLayerIdx == ", evenLayerIdx);
- removeFromLayer(prevVertexA, evenLayerIdx-1);
- removeFromLayer(prevVertexB, evenLayerIdx-2);
- // we should proceed from the previous odd layer
- //printDebug(isDebug, "Here! res.size == ", result.size());
- assert(result.size() >= 1);
- prevVertexA = result.back();
- evenLayerIdx -= 2;
- continue;
- }
- }
- } // finished iterating over all layers
- // remove all vertices in the augmenting paths
- // the corresponding layers
- for(size_t layerIdx = 0; layerIdx < result.size(); ++layerIdx) {
- removeFromLayer(result[layerIdx], layerIdx);
- }
- return true;
-}
-
-
-// remove all edges whose length is > newThreshold
-void Matching::trimMatching(const double newThreshold)
-{
- //bool isDebug { false };
- sanityCheck();
- for(auto aToBIter = AToB.begin(); aToBIter != AToB.end(); ) {
- if ( distLInf(aToBIter->first, aToBIter->second) > newThreshold ) {
- // remove edge from AToB and BToA
- //printDebug(isDebug, "removing edge ", aToBIter->first);
- //printDebug(isDebug, " <-> ", aToBIter->second);
- BToA.erase(aToBIter->second);
- aToBIter = AToB.erase(aToBIter);
- } else {
- aToBIter++;
- }
- }
- sanityCheck();
-}
-
-bool BoundMatchOracle::buildMatchingForThreshold(const double r)
-{
- //bool isDebug {false};
- //printDebug(isDebug,"Entered buildMatchingForThreshold, r = " + std::to_string(r));
- if (prevQueryValue > r) {
- M.trimMatching(r);
- }
- prevQueryValue = r;
- while(true) {
- buildLayerGraph(r);
- //printDebug(isDebug,"Layer graph built");
- if (augPathExist) {
- std::vector<Path> augmentingPaths;
- DiagramPointSet copyLG0;
- for(DiagramPoint p : layerGraph[0]) {
- copyLG0.insert(p);
- }
- for(DiagramPoint exposedVertex : copyLG0) {
- Path augPath;
- if (buildAugmentingPath(exposedVertex, augPath)) {
- //printDebug(isDebug, "Augmenting path found", augPath);
- augmentingPaths.push_back(augPath);
- }
- /*
- else {
- printDebug(isDebug,"augmenting paths must exist, but were not found!", M);
- std::cerr << "augmenting paths must exist, but were not found!" << std::endl;
- std::cout.flush();
- std::cerr.flush();
- printLayerGraph();
- //throw "Something went wrong-1";
- //return M.isPerfect();
- // analyze: finished or no paths exist
- // can this actually happen?
- }
- */
-
- }
- if (augmentingPaths.empty()) {
- //printDebug(isDebug,"augmenting paths must exist, but were not found!", M);
-#ifndef FOR_R_TDA
- std::cerr << "augmenting paths must exist, but were not found!" << std::endl;
-#endif
- throw std::runtime_error("bad epsilon?");
- }
- // swap all augmenting paths with matching to increase it
- //printDebug(isDebug,"before increase with augmenting paths:", M);
- for(auto& augPath : augmentingPaths ) {
- //printDebug(isDebug, "Increasing with augm. path ", augPath);
- M.increase(augPath);
- }
- //printDebug(isDebug,"after increase with augmenting paths:", M);
- } else {
- //printDebug(isDebug,"no augmenting paths exist, matching returned is:", M);
- return M.isPerfect();
- }
- }
-}
-
-void BoundMatchOracle::printLayerGraph(void)
-{
-#ifdef DEBUG_BOUND_MATCH
-#ifndef FOR_R_TDA
- for(auto& layer : layerGraph) {
- std::cout << "{ ";
- for(auto& p : layer) {
- std::cout << p << "; ";
- }
- std::cout << "\b\b }" << std::endl;
- }
-#endif
-#endif
-}
-
-void BoundMatchOracle::buildLayerGraph(double r)
-{
-#ifdef VERBOSE_BOTTLENECK
- std::cout << "Entered buildLayerGraph, r = " << r << std::endl;
-#endif
- layerGraph.clear();
- DiagramPointSet L1 = M.getExposedVertices();
- //printDebug(isDebug,"Got exposed vertices");
- layerGraph.push_back(L1);
- neighbOracle->rebuild(B, r);
- //printDebug(isDebug,"Oracle rebuilt");
- size_t k = 0;
- DiagramPointSet layerNextEven;
- DiagramPointSet layerNextOdd;
- bool exposedVerticesFound {false};
- while(true) {
- //printDebug(isDebug, "k = ", k);
- layerNextEven.clear();
- for( auto p : layerGraph[k]) {
- //printDebug(isDebug,"looking for neighbours for ", p);
- bool neighbFound;
- DiagramPoint neighbour {0.0, 0.0, DiagramPoint::DIAG, 1};
- if (useRangeSearch) {
- std::vector<DiagramPoint> neighbVec;
- neighbOracle->getAllNeighbours(p, neighbVec);
- neighbFound = !neighbVec.empty();
- for(auto& neighbPt : neighbVec) {
- layerNextEven.insert(neighbPt);
- if (!exposedVerticesFound and M.isExposed(neighbPt))
- exposedVerticesFound = true;
- }
- } else {
- while(true) {
- neighbFound = neighbOracle->getNeighbour(p, neighbour);
- if (neighbFound) {
- //printDebug(isDebug,"neighbour found, ", neighbour);
- layerNextEven.insert(neighbour);
- neighbOracle->deletePoint(neighbour);
- //printDebug(isDebug,"is exposed: " + std::to_string(M.isExposed(neighbour)));
- if ((!exposedVerticesFound) && M.isExposed(neighbour)) {
- exposedVerticesFound = true;
- }
- } else {
- //printDebug(isDebug,"no neighbours found for r = ", r);
- break;
- }
- }
- } // without range search
- } // all vertices from previous odd layer processed
- //printDebug(isDebug,"Next even layer finished");
- if (layerNextEven.empty()) {
- //printDebug(isDebug,"Next even layer is empty, augPathExist = false");
- augPathExist = false;
- break;
- }
- if (exposedVerticesFound) {
- //printDebug(isDebug,"Exposed vertices found in the even layer, aug. paths exist");
- //printDebug(isDebug,"Deleting all non-exposed from the last layer (we do not need them).");
- for(auto it = layerNextEven.cbegin(); it != layerNextEven.cend(); ) {
- if ( ! M.isExposed(*it) ) {
- layerNextEven.erase(it++);
- } else {
- ++it;
- }
-
- }
- layerGraph.push_back(layerNextEven);
- augPathExist = true;
- break;
- }
- layerGraph.push_back(layerNextEven);
- M.getAllAdjacentVertices(layerNextEven, layerNextOdd);
- //printDebug(isDebug,"Next odd layer finished");
- layerGraph.push_back(layerNextOdd);
- k += 2;
- }
- buildLayerOracles(r);
- //printDebug(isDebug,"layer oracles built, layer graph:");
- printLayerGraph();
-#ifdef VERBOSE_BOTTLENECK
- std::cout << "Exit buildLayerGraph, r = " << r << std::endl;
-#endif
- }
-
-
-
-BoundMatchOracle::~BoundMatchOracle()
-{
- for(auto& oracle : layerOracles) {
- delete oracle;
- }
- delete neighbOracle;
-}
-
-// create geometric oracles for each even layer
-// odd layers have NULL in layerOracles
-void BoundMatchOracle::buildLayerOracles(double r)
-{
- //bool isDebug {false};
- //printDebug(isDebug,"entered buildLayerOracles");
- // free previously constructed oracles
- for(auto& oracle : layerOracles) {
- delete oracle;
- }
- layerOracles.clear();
- //printDebug(isDebug,"previous oracles deleted");
- for(size_t layerIdx = 0; layerIdx < layerGraph.size(); ++layerIdx) {
- if (layerIdx % 2 == 1) {
- // even layer, build actual oracle
- layerOracles.push_back(new NeighbOracle(layerGraph[layerIdx], r, distEpsilon));
- } else {
- // odd layer
- layerOracles.push_back(nullptr);
- }
- }
- //printDebug(isDebug,"exiting buildLayerOracles");
-}
-}