From 9217040b7ed0eab97bd9fbc93b89dbf4baf8decf Mon Sep 17 00:00:00 2001 From: Constantin Pape Date: Tue, 12 Feb 2019 21:00:08 +0100 Subject: [PATCH 1/2] Remove andres multicut and lifted multicut solvers --- ...lifted_multicut_andres_greedy_additive.hxx | 214 ---------------- .../lifted_multicut_andres_kernighan_lin.hxx | 238 ------------------ .../graph/opt/multicut/multicut_andres.hxx | 201 --------------- .../nifty/graph/opt/multicut/multicut_mp.hxx | 4 +- .../graph/opt/lifted_multicut/CMakeLists.txt | 2 - .../opt/lifted_multicut/lifted_multicut.cxx | 4 - ...lifted_multicut_andres_greedy_additive.cxx | 61 ----- .../lifted_multicut_andres_kernighan_lin.cxx | 67 ----- .../lib/graph/opt/multicut/CMakeLists.txt | 3 +- .../lib/graph/opt/multicut/multicut.cxx | 2 - .../graph/opt/multicut/multicut_andres.cxx | 124 --------- .../graph/opt/lifted_multicut/__init__.py | 17 -- .../nifty/graph/opt/multicut/__init__.py | 59 ----- .../test_lifted_multicut_solvers.py | 11 +- 14 files changed, 9 insertions(+), 998 deletions(-) delete mode 100644 include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.hxx delete mode 100644 include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.hxx delete mode 100644 include/nifty/graph/opt/multicut/multicut_andres.hxx delete mode 100644 src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.cxx delete mode 100644 src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.cxx delete mode 100644 src/python/lib/graph/opt/multicut/multicut_andres.cxx diff --git a/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.hxx b/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.hxx deleted file mode 100644 index 92a9c10b2..000000000 --- a/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.hxx +++ /dev/null @@ -1,214 +0,0 @@ - -#pragma once - - -#include -#include -#include -#include -#include - -#include "nifty/tools/changable_priority_queue.hxx" - -#include "nifty/tools/runtime_check.hxx" -#include "nifty/ufd/ufd.hxx" -#include "nifty/graph/detail/adjacency.hxx" -#include "nifty/graph/opt/lifted_multicut/lifted_multicut_base.hxx" -#include "nifty/graph/edge_contraction_graph.hxx" -#include "nifty/graph/components.hxx" - - -#include "andres/graph/graph.hxx" -#include "andres/graph/multicut-lifted/greedy-additive.hxx" -#include "andres/graph/components.hxx" - - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace lifted_multicut{ - - - - - - - - - - - template - class LiftedMulticutAndresGreedyAdditive : public LiftedMulticutBase - { - public: - - typedef OBJECTIVE ObjectiveType; - typedef LiftedMulticutBase BaseType; - typedef typename ObjectiveType::GraphType GraphType; - typedef typename ObjectiveType::LiftedGraphType LiftedGraphType; - - typedef typename BaseType::VisitorBaseType VisitorBaseType; - typedef typename BaseType::VisitorProxyType VisitorProxyType; - typedef typename BaseType::NodeLabelsType NodeLabelsType; - - private: - - - - - public: - - struct SettingsType{ - }; - - - - virtual ~LiftedMulticutAndresGreedyAdditive(){} - LiftedMulticutAndresGreedyAdditive(const ObjectiveType & objective, const SettingsType & settings = SettingsType()); - virtual void optimize(NodeLabelsType & nodeLabels, VisitorBaseType * visitor); - virtual const ObjectiveType & objective() const; - - - - - - - - - virtual const NodeLabelsType & currentBestNodeLabels( ){ - return *currentBest_; - } - - virtual std::string name()const{ - return std::string("LiftedMulticutAndresGreedyAdditive"); - } - - - private: - - - - - const ObjectiveType & objective_; - SettingsType settings_; - const GraphType & graph_; - const LiftedGraphType & liftedGraph_; - NodeLabelsType * currentBest_; - - andres::graph::Graph<> aGraph_; - andres::graph::Graph<> aLiftedGraph_; - std::vector edgeCosts_; - }; - - - template - LiftedMulticutAndresGreedyAdditive:: - LiftedMulticutAndresGreedyAdditive( - const ObjectiveType & objective, - const SettingsType & settings - ) - : objective_(objective), - settings_(settings), - graph_(objective.graph()), - liftedGraph_(objective.liftedGraph()), - currentBest_(nullptr), - aGraph_(objective.graph().nodeIdUpperBound()+1), - aLiftedGraph_(objective.graph().nodeIdUpperBound()+1), - edgeCosts_(objective.liftedGraph().numberOfEdges(),0) - { - for(const auto edge : graph_.edges()){ - const auto uv = graph_.uv(edge); - aGraph_.insertEdge(uv.first, uv.second); - } - - auto c = 0; - for(const auto edge : liftedGraph_.edges()){ - const auto uv = liftedGraph_.uv(edge); - aLiftedGraph_.insertEdge(uv.first, uv.second); - edgeCosts_[c] = objective_.weights()[edge]; - ++c; - } - } - - template - void LiftedMulticutAndresGreedyAdditive:: - optimize( - NodeLabelsType & nodeLabels, VisitorBaseType * visitor - ){ - - currentBest_ = &nodeLabels; - - VisitorProxyType visitorProxy(visitor); - //visitorProxy.addLogNames({"violatedCycleConstraints","violatedCutConstraints"}); - visitorProxy.begin(this); - - typedef std::vector ELA; - - - - std::vector outLabels(aLiftedGraph_.numberOfEdges()); - std::vector edegInALiftedGraph(aGraph_.numberOfEdges()); - for (std::size_t i = 0; i < aGraph_.numberOfEdges(); ++i){ - const auto v0 = aGraph_.vertexOfEdge(i, 0); - const auto v1 = aGraph_.vertexOfEdge(i, 1); - edegInALiftedGraph[i] = aLiftedGraph_.findEdge(v0, v1).second; - } - - - //for (std::size_t i = 0; i < aLiftedGraph_.numberOfEdges(); ++i){ - // const auto v0 = aLiftedGraph_.vertexOfEdge(i, 0); - // const auto v1 = aLiftedGraph_.vertexOfEdge(i, 1); - // outLabels[i] = nodeLabels[v0] != nodeLabels[v1] ? 1 : 0; - //} - - - andres::graph::multicut_lifted::greedyAdditiveEdgeContraction( - aGraph_, - aLiftedGraph_, - edgeCosts_, - outLabels - ); - - - - struct SubgraphWithCut { // a subgraph with cut mask - SubgraphWithCut(const ELA& labels, std::vector const& edegInALiftedGraph) - : labels_(labels), edegInALiftedGraph_(edegInALiftedGraph) - {} - bool vertex(const std::size_t v) const - { return true; } - bool edge(const std::size_t e) const - { return labels_[edegInALiftedGraph_[e]] == 0; } - - std::vector const& edegInALiftedGraph_; - const ELA& labels_; - }; - - // build decomposition based on the current multicut - andres::graph::ComponentsByPartition > components; - components.build(aGraph_, SubgraphWithCut(outLabels, edegInALiftedGraph)); - - for(const auto node : graph_.nodes()){ - nodeLabels[node] = components.partition_.find(node); - } - - - visitorProxy.end(this); - } - - template - const typename LiftedMulticutAndresGreedyAdditive::ObjectiveType & - LiftedMulticutAndresGreedyAdditive:: - objective()const{ - return objective_; - } - - - - - -} // lifted_multicut -} // namespace nifty::graph::opt -} // namespace nifty::graph -} // namespace nifty - diff --git a/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.hxx b/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.hxx deleted file mode 100644 index b798efef1..000000000 --- a/include/nifty/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.hxx +++ /dev/null @@ -1,238 +0,0 @@ -// reimplementation of kerninhanlin in -// https://github.com/bjoern-andres/graph - -#pragma once - - -#include -#include -#include -#include -#include - -#include "nifty/tools/changable_priority_queue.hxx" - -#include "nifty/tools/runtime_check.hxx" -#include "nifty/ufd/ufd.hxx" -#include "nifty/graph/detail/adjacency.hxx" -#include "nifty/graph/opt/lifted_multicut/lifted_multicut_base.hxx" -#include "nifty/graph/edge_contraction_graph.hxx" -#include "nifty/graph/components.hxx" - - -#include "andres/graph/graph.hxx" -#include "andres/graph/components.hxx" -#include "andres/graph/multicut-lifted/kernighan-lin.hxx" - - - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace lifted_multicut{ - - - - - - - - - - - template - class LiftedMulticutAndresKernighanLin : public LiftedMulticutBase - { - public: - - typedef OBJECTIVE ObjectiveType; - typedef LiftedMulticutBase BaseType; - typedef typename ObjectiveType::GraphType GraphType; - typedef typename ObjectiveType::LiftedGraphType LiftedGraphType; - - typedef typename BaseType::VisitorBaseType VisitorBaseType; - typedef typename BaseType::VisitorProxyType VisitorProxy; - typedef typename BaseType::NodeLabelsType NodeLabelsType; - - private: - - - - - public: - - - struct SettingsType { - std::size_t numberOfInnerIterations { std::numeric_limits::max() }; - std::size_t numberOfOuterIterations { 100 }; - double epsilon { 1e-7 }; - }; - - - - - - virtual ~LiftedMulticutAndresKernighanLin(){} - LiftedMulticutAndresKernighanLin(const ObjectiveType & objective, const SettingsType & settings = SettingsType()); - virtual void optimize(NodeLabelsType & nodeLabels, VisitorBaseType * visitor); - virtual const ObjectiveType & objective() const; - - - - - - - - - virtual const NodeLabelsType & currentBestNodeLabels( ){ - return *currentBest_; - } - - virtual std::string name()const{ - return std::string("LiftedMulticutAndresKernighanLin"); - } - - - private: - - - - - const ObjectiveType & objective_; - SettingsType settings_; - const GraphType & graph_; - const LiftedGraphType & liftedGraph_; - NodeLabelsType * currentBest_; - - andres::graph::Graph<> aGraph_; - andres::graph::Graph<> aLiftedGraph_; - std::vector edgeCosts_; - }; - - - template - LiftedMulticutAndresKernighanLin:: - LiftedMulticutAndresKernighanLin( - const ObjectiveType & objective, - const SettingsType & settings - ) - : objective_(objective), - settings_(settings), - graph_(objective.graph()), - liftedGraph_(objective.liftedGraph()), - currentBest_(nullptr), - aGraph_(objective.graph().nodeIdUpperBound()+1), - aLiftedGraph_(objective.graph().nodeIdUpperBound()+1), - edgeCosts_(objective.liftedGraph().numberOfEdges(),0) - { - for(const auto edge : graph_.edges()){ - const auto uv = graph_.uv(edge); - aGraph_.insertEdge(uv.first, uv.second); - } - - auto c = 0; - for(const auto edge : liftedGraph_.edges()){ - const auto uv = liftedGraph_.uv(edge); - aLiftedGraph_.insertEdge(uv.first, uv.second); - edgeCosts_[c] = objective_.weights()[edge]; - ++c; - } - } - - template - void LiftedMulticutAndresKernighanLin:: - optimize( - NodeLabelsType & nodeLabels, VisitorBaseType * visitor - ){ - - currentBest_ = &nodeLabels; - - VisitorProxy visitorProxy(visitor); - //visitorProxy.addLogNames({"violatedCycleConstraints","violatedCutConstraints"}); - visitorProxy.begin(this); - - typedef std::vector ELA; - - - - std::vector ioLabels(aLiftedGraph_.numberOfEdges()); - - std::vector edegInALiftedGraph(aGraph_.numberOfEdges()); - - - - for (std::size_t i = 0; i < aGraph_.numberOfEdges(); ++i){ - const auto v0 = aGraph_.vertexOfEdge(i, 0); - const auto v1 = aGraph_.vertexOfEdge(i, 1); - edegInALiftedGraph[i] = aLiftedGraph_.findEdge(v0, v1).second; - } - - - for (std::size_t i = 0; i < aLiftedGraph_.numberOfEdges(); ++i){ - const auto v0 = aLiftedGraph_.vertexOfEdge(i, 0); - const auto v1 = aLiftedGraph_.vertexOfEdge(i, 1); - ioLabels[i] = nodeLabels[v0] != nodeLabels[v1] ? 1 : 0; - } - - - - - andres::graph::multicut_lifted::KernighanLinSettings klSettings_; - klSettings_.numberOfInnerIterations = settings_.numberOfInnerIterations; - klSettings_.numberOfOuterIterations = settings_.numberOfOuterIterations; - klSettings_.epsilon = settings_.epsilon; - klSettings_.verbose = false; - - - andres::graph::multicut_lifted::kernighanLin( - aGraph_, - aLiftedGraph_, - edgeCosts_, - ioLabels, - ioLabels, - klSettings_ - ); - - - - struct SubgraphWithCut { // a subgraph with cut mask - SubgraphWithCut(const ELA& labels, std::vector const& edegInALiftedGraph) - : labels_(labels), edegInALiftedGraph_(edegInALiftedGraph) - {} - bool vertex(const std::size_t v) const - { return true; } - bool edge(const std::size_t e) const - { return labels_[edegInALiftedGraph_[e]] == 0; } - - std::vector const& edegInALiftedGraph_; - const ELA& labels_; - }; - - // build decomposition based on the current multicut - andres::graph::ComponentsByPartition > components; - components.build(aGraph_, SubgraphWithCut(ioLabels, edegInALiftedGraph)); - - for(const auto node : graph_.nodes()){ - nodeLabels[node] = components.partition_.find(node); - } - - - visitorProxy.end(this); - } - - template - const typename LiftedMulticutAndresKernighanLin::ObjectiveType & - LiftedMulticutAndresKernighanLin:: - objective()const{ - return objective_; - } - - - - - -} // lifted_multicut -} // namespace nifty::graph::opt -} // namespace nifty::graph -} // namespace nifty - diff --git a/include/nifty/graph/opt/multicut/multicut_andres.hxx b/include/nifty/graph/opt/multicut/multicut_andres.hxx deleted file mode 100644 index c0faa2e30..000000000 --- a/include/nifty/graph/opt/multicut/multicut_andres.hxx +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "nifty/graph/opt/multicut/multicut_base.hxx" -#include "nifty/ufd/ufd.hxx" - -// andres::graph includes -#include "andres/graph/graph.hxx" -#include "andres/graph/multicut/kernighan-lin.hxx" -#include "andres/graph/multicut/greedy-additive.hxx" - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace multicut{ - - template - class MulticutAndres : public MulticutBase - { - public: - typedef OBJECTIVE ObjectiveType; - typedef typename ObjectiveType::GraphType GraphType; - typedef MulticutBase BaseType; - typedef typename BaseType::VisitorBaseType VisitorBaseType; - typedef typename BaseType::VisitorProxyType VisitorProxyType; - typedef typename BaseType::NodeLabelsType NodeLabelsType; - typedef andres::graph::Graph<> AGraphType; - - MulticutAndres(const ObjectiveType & objective); - - virtual void optimize(NodeLabelsType & nodelabels, VisitorBaseType * visitor){} - - virtual const ObjectiveType & objective() const {return objective_;} - virtual const NodeLabelsType & currentBestNodeLabels() {return *currentBest_;} - virtual std::string name() const {return "MulticutAndres";} - - protected: - void nodeLabelsToEdgeLabels(std::vector & edgeLabels); - void edgeLabelsToNodeLabels(const std::vector & edgeLabels); - NodeLabelsType * currentBest_; - AGraphType graph_; - - private: - void initGraph(); - const ObjectiveType & objective_; - ufd::Ufd ufd_; - }; - - - template - MulticutAndres::MulticutAndres( - const ObjectiveType & objective - ) : currentBest_(nullptr), - graph_(objective.graph().numberOfNodes()), - objective_(objective), - ufd_(graph_.numberOfVertices()) - { - initGraph(); - } - - - template - void MulticutAndres::initGraph(){ - const auto & objGraph = objective_.graph(); - for(auto e : objGraph.edges()){ - const auto & uv = objGraph.uv(e); - graph_.insertEdge(uv.first, uv.second); - } - } - - - template - void MulticutAndres::nodeLabelsToEdgeLabels(std::vector & edgeLabels) { - const auto & nodeLabels = *currentBest_; - for(auto edgeId = 0; edgeId < graph_.numberOfEdges(); ++edgeId) { - const auto u = graph_.vertexOfEdge(edgeId,0); - const auto v = graph_.vertexOfEdge(edgeId,1); - edgeLabels[edgeId] = nodeLabels[u] != nodeLabels[v]; - } - } - - - template - void MulticutAndres::edgeLabelsToNodeLabels(const std::vector & edgeLabels) { - for(auto edgeId = 0; edgeId < graph_.numberOfEdges(); ++edgeId) { - if(!edgeLabels[edgeId]){ - ufd_.merge( graph_.vertexOfEdge(edgeId,0), graph_.vertexOfEdge(edgeId,1) ); - } - } - ufd_.elementLabeling(currentBest_->begin()); - } - - - - template - class MulticutAndresGreedyAdditive : public MulticutAndres - { - public: - - typedef OBJECTIVE ObjectiveType; - typedef MulticutAndres Base; - typedef typename Base::NodeLabelsType NodeLabelsType; - typedef typename Base::VisitorBaseType VisitorBaseType; - - struct SettingsType {}; - MulticutAndresGreedyAdditive(const ObjectiveType & objective, const SettingsType & settings = SettingsType()); - - virtual void optimize(NodeLabelsType & nodeLabels, VisitorBaseType * visitor); - virtual const ObjectiveType & objective() const {return Base::objective();} - virtual const NodeLabelsType & currentBestNodeLabels() {return Base::currentBestNodeLabels();} - virtual std::string name() const {return "MulticutAndresGreedyAdditive";} - - }; - - template - MulticutAndresGreedyAdditive:: - MulticutAndresGreedyAdditive(const ObjectiveType & objective, const SettingsType &) - : Base(objective) - {} - - template - void MulticutAndresGreedyAdditive::optimize( - NodeLabelsType & nodeLabels, VisitorBaseType * visitor - ){ - //VisitorProxyType visitorProxy(visitor); - Base::currentBest_ = &nodeLabels; - - if(Base::graph_.numberOfEdges()>0){ - std::vector edgeLabels( Base::graph_.numberOfEdges() ); - Base::nodeLabelsToEdgeLabels(edgeLabels); - andres::graph::multicut::greedyAdditiveEdgeContraction(Base::graph_, objective().weights(), edgeLabels); - Base::edgeLabelsToNodeLabels(edgeLabels); - } - } - - - template - class MulticutAndresKernighanLin : public MulticutAndres - { - public: - - typedef OBJECTIVE ObjectiveType; - typedef MulticutAndres Base; - typedef typename Base::NodeLabelsType NodeLabelsType; - typedef typename Base::VisitorBaseType VisitorBaseType; - - typedef andres::graph::multicut::KernighanLinSettings KlSettings; - - struct SettingsType { - size_t numberOfInnerIterations { std::numeric_limits::max() }; - size_t numberOfOuterIterations { 100 }; - double epsilon { 1e-6 }; - bool verbose { false }; - bool greedyWarmstart{true}; - }; - - MulticutAndresKernighanLin(const ObjectiveType & objective, const SettingsType & settings = SettingsType()); - - virtual void optimize(NodeLabelsType & nodeLabels, VisitorBaseType * visitor); - virtual const ObjectiveType & objective() const {return Base::objective();} - virtual const NodeLabelsType & currentBestNodeLabels() {return Base::currentBestNodeLabels();} - virtual std::string name() const {return "MulticutAndresKernighanLin";} - - private: - SettingsType settings_; - KlSettings klSettings_; - }; - - template - MulticutAndresKernighanLin:: - MulticutAndresKernighanLin(const ObjectiveType & objective, const SettingsType & settings) - : Base(objective), - settings_(settings), - klSettings_() - { - klSettings_.numberOfInnerIterations = settings_.numberOfInnerIterations; - klSettings_.numberOfOuterIterations = settings_.numberOfOuterIterations; - klSettings_.epsilon = settings_.epsilon; - klSettings_.verbose = settings_.verbose; - } - - template - void MulticutAndresKernighanLin::optimize( - NodeLabelsType & nodeLabels, VisitorBaseType * visitor - ){ - //VisitorProxyType visitorProxy(visitor); - Base::currentBest_ = &nodeLabels; - - if(Base::graph_.numberOfEdges()>0){ - std::vector edgeLabels( Base::graph_.numberOfEdges() ); - Base::nodeLabelsToEdgeLabels(edgeLabels); - if(settings_.greedyWarmstart){ - andres::graph::multicut::greedyAdditiveEdgeContraction(Base::graph_, objective().weights(), edgeLabels); - } - andres::graph::multicut::kernighanLin(Base::graph_, objective().weights(), edgeLabels, edgeLabels, klSettings_); - Base::edgeLabelsToNodeLabels(edgeLabels); - } - } -} // namespace nifty::graph::opt::multicut -} // namespace nifty::graph::opt -} -} diff --git a/include/nifty/graph/opt/multicut/multicut_mp.hxx b/include/nifty/graph/opt/multicut/multicut_mp.hxx index 333d66bef..60f070631 100644 --- a/include/nifty/graph/opt/multicut/multicut_mp.hxx +++ b/include/nifty/graph/opt/multicut/multicut_mp.hxx @@ -6,7 +6,7 @@ #include "nifty/graph/opt/multicut/multicut_base.hxx" #include "nifty/graph/opt/common/solver_factory.hxx" #include "nifty/graph/opt/common/solver_factory_base.hxx" -#include "nifty/graph/opt/multicut/multicut_andres.hxx" +#include "nifty/graph/opt/multicut/kernighan_lin.hxx" #include "nifty/ufd/ufd.hxx" // LP_MP includes @@ -169,7 +169,7 @@ namespace multicut{ { // if we don't have a mc-factory, we use the LP_MP default rounder if(!bool(settings_.mcFactory)) { - typedef MulticutAndresKernighanLin DefaultSolver; + typedef KernighanLin DefaultSolver; typedef nifty::graph::opt::common::SolverFactory DefaultFactory; settings_.mcFactory = std::make_shared(); } diff --git a/src/python/lib/graph/opt/lifted_multicut/CMakeLists.txt b/src/python/lib/graph/opt/lifted_multicut/CMakeLists.txt index 66742e342..dd217d7fa 100644 --- a/src/python/lib/graph/opt/lifted_multicut/CMakeLists.txt +++ b/src/python/lib/graph/opt/lifted_multicut/CMakeLists.txt @@ -8,8 +8,6 @@ SET(MOD_SOURCES lifted_multicut_greedy_additive.cxx lifted_multicut_kernighan_lin.cxx lifted_multicut_ilp.cxx - lifted_multicut_andres_kernighan_lin.cxx - lifted_multicut_andres_greedy_additive.cxx fusion_move_based.cxx lifted_graph_features.cxx chained_solvers.cxx diff --git a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut.cxx b/src/python/lib/graph/opt/lifted_multicut/lifted_multicut.cxx index 41e504ffd..719cb623a 100644 --- a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut.cxx +++ b/src/python/lib/graph/opt/lifted_multicut/lifted_multicut.cxx @@ -23,8 +23,6 @@ namespace lifted_multicut{ void exportLiftedMulticutKernighanLin(py::module &); void exportLiftedMulticutIlp(py::module &); void exportLiftedMulticutMp(py::module &); - void exportLiftedMulticutAndresKernighanLin(py::module &); - void exportLiftedMulticutAndresGreedyAdditive(py::module &); void exportFusionMoveBased(py::module &); void exportLiftedGraphFeatures(py::module &); // void exportPixelWiseLmcStuff(py::module &); @@ -55,8 +53,6 @@ PYBIND11_MODULE(_lifted_multicut, liftedMulticutModule) { exportLiftedMulticutGreedyAdditive(liftedMulticutModule); exportLiftedMulticutKernighanLin(liftedMulticutModule); exportLiftedMulticutIlp(liftedMulticutModule); - exportLiftedMulticutAndresKernighanLin(liftedMulticutModule); - exportLiftedMulticutAndresGreedyAdditive(liftedMulticutModule); exportFusionMoveBased(liftedMulticutModule); exportLiftedGraphFeatures(liftedMulticutModule); // exportPixelWiseLmcStuff(liftedMulticutModule); diff --git a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.cxx b/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.cxx deleted file mode 100644 index cee7c4bb0..000000000 --- a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.cxx +++ /dev/null @@ -1,61 +0,0 @@ -#include - -#include "nifty/graph/opt/lifted_multicut/lifted_multicut_andres_greedy_additive.hxx" - -#include "nifty/python/converter.hxx" -#include "nifty/python/graph/undirected_grid_graph.hxx" -#include "nifty/python/graph/undirected_list_graph.hxx" -#include "nifty/python/graph/edge_contraction_graph.hxx" -#include "nifty/python/graph/opt/lifted_multicut/lifted_multicut_objective.hxx" -#include "nifty/python/graph/opt/lifted_multicut/export_lifted_multicut_solver.hxx" - -namespace py = pybind11; - -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace lifted_multicut{ - - - template - void exportLiftedMulticutAndresGreedyAdditiveT(py::module & liftedMulticutModule) { - - typedef OBJECTIVE ObjectiveType; - typedef LiftedMulticutAndresGreedyAdditive Solver; - typedef typename Solver::SettingsType SettingsType; - - exportLiftedMulticutSolver(liftedMulticutModule,"LiftedMulticutAndresGreedyAdditive") - .def(py::init<>()) - ; - - } - - void exportLiftedMulticutAndresGreedyAdditive(py::module & liftedMulticutModule) { - { - typedef PyUndirectedGraph GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresGreedyAdditiveT(liftedMulticutModule); - } - { - typedef nifty::graph::UndirectedGridGraph<2,true> GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresGreedyAdditiveT(liftedMulticutModule); - } - { - typedef nifty::graph::UndirectedGridGraph<3,true> GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresGreedyAdditiveT(liftedMulticutModule); - } - //{ - // typedef PyContractionGraph GraphType; - // typedef MulticutObjective ObjectiveType; - // exportLiftedMulticutAndresGreedyAdditiveT(liftedMulticutModule); - //} - } - -} -} // namespace nifty::graph::opt -} -} diff --git a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.cxx b/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.cxx deleted file mode 100644 index 4c8863423..000000000 --- a/src/python/lib/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.cxx +++ /dev/null @@ -1,67 +0,0 @@ -#include - -#include "nifty/graph/opt/lifted_multicut/lifted_multicut_andres_kernighan_lin.hxx" - -#include "nifty/python/converter.hxx" -#include "nifty/python/graph/undirected_grid_graph.hxx" -#include "nifty/python/graph/undirected_list_graph.hxx" -//#include "nifty/python/graph/edge_contraction_graph.hxx" -#include "nifty/python/graph/opt/lifted_multicut/lifted_multicut_objective.hxx" -#include "nifty/python/graph/opt/lifted_multicut/export_lifted_multicut_solver.hxx" - -namespace py = pybind11; - -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace lifted_multicut{ - - - template - void exportLiftedMulticutAndresKernighanLinT(py::module & liftedMulticutModule) { - - typedef OBJECTIVE ObjectiveType; - typedef LiftedMulticutAndresKernighanLin Solver; - typedef typename Solver::SettingsType SettingsType; - - exportLiftedMulticutSolver(liftedMulticutModule,"LiftedMulticutAndresKernighanLin") - .def(py::init<>()) - .def_readwrite("numberOfInnerIterations", &SettingsType::numberOfInnerIterations) - .def_readwrite("numberOfOuterIterations", &SettingsType::numberOfOuterIterations) - .def_readwrite("epsilon", &SettingsType::epsilon) - //.def_readwrite("numberOfOuterIterations", &SettingsType::numberOfOuterIterations) - - //.def_readwrite("verbose", &SettingsType::verbose) - ; - - } - - void exportLiftedMulticutAndresKernighanLin(py::module & liftedMulticutModule) { - { - typedef PyUndirectedGraph GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresKernighanLinT(liftedMulticutModule); - } - { - typedef nifty::graph::UndirectedGridGraph<2,true> GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresKernighanLinT(liftedMulticutModule); - } - { - typedef nifty::graph::UndirectedGridGraph<3,true> GraphType; - typedef LiftedMulticutObjective ObjectiveType; - exportLiftedMulticutAndresKernighanLinT(liftedMulticutModule); - } - //{ - // typedef PyContractionGraph GraphType; - // typedef MulticutObjective ObjectiveType; - // exportLiftedMulticutAndresKernighanLinT(liftedMulticutModule); - //} - } - -} -} // namespace nifty::graph::opt -} -} diff --git a/src/python/lib/graph/opt/multicut/CMakeLists.txt b/src/python/lib/graph/opt/multicut/CMakeLists.txt index 9c0a7dfd6..1cc19b86c 100644 --- a/src/python/lib/graph/opt/multicut/CMakeLists.txt +++ b/src/python/lib/graph/opt/multicut/CMakeLists.txt @@ -9,7 +9,6 @@ SET(MOD_SOURCES multicut_ilp.cxx multicut_decomposer.cxx multicut_greedy_additive.cxx - multicut_andres.cxx fusion_move_based.cxx cc_fusion_move_based.cxx perturb_and_map.cxx @@ -32,4 +31,4 @@ addPythonModule( ${MOD_LIBS} ) -target_link_libraries(_multicut PUBLIC ${MOD_LIBS} ) \ No newline at end of file +target_link_libraries(_multicut PUBLIC ${MOD_LIBS} ) diff --git a/src/python/lib/graph/opt/multicut/multicut.cxx b/src/python/lib/graph/opt/multicut/multicut.cxx index c8f23040c..6280e203c 100644 --- a/src/python/lib/graph/opt/multicut/multicut.cxx +++ b/src/python/lib/graph/opt/multicut/multicut.cxx @@ -27,7 +27,6 @@ namespace multicut{ void exportFusionMoveBased(py::module &); void exportPerturbAndMap(py::module &); void exportMulticutDecomposer(py::module &); - void exportMulticutAndres(py::module &); void exportChainedSolvers(py::module &); void exportMulticutCcFusionMoveBased(py::module &); void exportKernighanLin(py::module &); @@ -58,7 +57,6 @@ PYBIND11_MODULE(_multicut, multicutModule) { exportFusionMoveBased(multicutModule); exportPerturbAndMap(multicutModule); exportMulticutDecomposer(multicutModule); - exportMulticutAndres(multicutModule); exportChainedSolvers(multicutModule); exportMulticutCcFusionMoveBased(multicutModule); exportKernighanLin(multicutModule); diff --git a/src/python/lib/graph/opt/multicut/multicut_andres.cxx b/src/python/lib/graph/opt/multicut/multicut_andres.cxx deleted file mode 100644 index 29741027d..000000000 --- a/src/python/lib/graph/opt/multicut/multicut_andres.cxx +++ /dev/null @@ -1,124 +0,0 @@ -#include - -#include "nifty/graph/opt/multicut/multicut_andres.hxx" - -#include "nifty/python/graph/opt/multicut/multicut_objective.hxx" -#include "nifty/python/converter.hxx" -#include "nifty/python/graph/opt/multicut/export_multicut_solver.hxx" -#include "nifty/python/graph/undirected_list_graph.hxx" -#include "nifty/python/graph/edge_contraction_graph.hxx" - -namespace py = pybind11; - -PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); - -namespace nifty{ -namespace graph{ -namespace opt{ -namespace multicut{ - - template - void exportMulticutAndresT(py::module & multicutModule){ - - typedef OBJECTIVE ObjectiveType; - - const auto objName = MulticutObjectiveName::name(); - - // export greedy additive - { - - - /////////////////////////////////////////////////////////////// - // DOCSTRING HELPER - /////////////////////////////////////////////////////////////// - nifty::graph::opt::SolverDocstringHelper docHelper; - docHelper.objectiveName = - "multicut objective"; - docHelper.objectiveClsName = - MulticutObjectiveName::name(); - docHelper.name = - "greedy additive andres"; - docHelper.mainText = - "Find approximate solutions via\n" - "agglomerative clustering as in :cite:`beier_15_funsion`.\n"; - docHelper.cites.emplace_back("beier_15_funsion"); - docHelper.note = - "This solver should be used to\n" - "warm start other solvers with.\n" - "This solver is very fast but\n" - "yields rather suboptimal results.\n"; - docHelper.warning = - "This native nifty implementation as this implementation\n"; - "from andres which is just used for comparison\n"; - - - typedef MulticutAndresGreedyAdditive Solver; - typedef typename Solver::SettingsType SettingsType; - const auto solverName = std::string("MulticutAndresGreedyAdditive"); - // FIXME verbose has no effect yet - exportMulticutSolver(multicutModule, solverName.c_str(), docHelper) - .def(py::init<>()) - ; - } - - // export kernighan lin - { - - - - /////////////////////////////////////////////////////////////// - // DOCSTRING HELPER - /////////////////////////////////////////////////////////////// - nifty::graph::opt::SolverDocstringHelper docHelper; - docHelper.objectiveName = "multicut objective"; - docHelper.objectiveClsName = MulticutObjectiveName::name(); - docHelper.name = "Kernighan Lin"; - docHelper.mainText = - "KernighanLin Algorithm with joins for multicuts\n" - "As introduced in TODO"; - docHelper.cites.emplace_back("TODO"); - docHelper.note = "This solver should be warm started," - "otherwise results are very poor." - "Using :func:`greedyAdditiveFactory` to create " - "a solver for warm starting is suggested."; - - - - - typedef MulticutAndresKernighanLin Solver; - typedef typename Solver::SettingsType SettingsType; - const auto solverName = std::string("MulticutAndresKernighanLin"); - // FIXME verbose has no effect yet - exportMulticutSolver(multicutModule, solverName.c_str(), docHelper) - .def(py::init<>()) - .def_readwrite("numberOfInnerIterations", &SettingsType::numberOfInnerIterations) - .def_readwrite("numberOfOuterIterations", &SettingsType::numberOfOuterIterations) - .def_readwrite("epsilon", &SettingsType::epsilon) - .def_readwrite("verbose", &SettingsType::verbose) - .def_readwrite("greedyWarmstart", &SettingsType::greedyWarmstart) - ; - } - - } - - - void exportMulticutAndres(py::module & multicutModule){ - - { - typedef PyUndirectedGraph GraphType; - typedef MulticutObjective ObjectiveType; - exportMulticutAndresT(multicutModule); - } - // FIXME this doesn't compile - //{ - // typedef PyContractionGraph GraphType; - // typedef MulticutObjective ObjectiveType; - // exportMulticutMpT(multicutModule); - //} - - } - -} // namespace nifty::graph::opt::multicut -} // namespace nifty::graph::opt -} // namespace graph -} // namespace nifty diff --git a/src/python/module/nifty/graph/opt/lifted_multicut/__init__.py b/src/python/module/nifty/graph/opt/lifted_multicut/__init__.py index 34b3fd4bf..9e373352a 100644 --- a/src/python/module/nifty/graph/opt/lifted_multicut/__init__.py +++ b/src/python/module/nifty/graph/opt/lifted_multicut/__init__.py @@ -234,23 +234,6 @@ def liftedMulticutKernighanLinFactory(numberOfOuterIterations=1000000, O.liftedMulticutKernighanLinFactory = staticmethod(liftedMulticutKernighanLinFactory) - def liftedMulticutAndresKernighanLinFactory(numberOfOuterIterations=1000000, - numberOfInnerIterations=100, - epsilon=1e-7): - s,F = getSettingsAndFactoryCls("LiftedMulticutAndresKernighanLin") - s.numberOfOuterIterations = int(numberOfOuterIterations) - s.numberOfInnerIterations = int(numberOfInnerIterations) - s.epsilon = float(epsilon) - return F(s) - O.liftedMulticutAndresKernighanLinFactory = staticmethod(liftedMulticutAndresKernighanLinFactory) - - - def liftedMulticutAndresGreedyAdditiveFactory(): - s,F = getSettingsAndFactoryCls("LiftedMulticutAndresGreedyAdditive") - return F(s) - O.liftedMulticutAndresGreedyAdditiveFactory = staticmethod(liftedMulticutAndresGreedyAdditiveFactory) - - if Configuration.WITH_LP_MP: def liftedMulticutMpFactory( lmcFactory = None, diff --git a/src/python/module/nifty/graph/opt/multicut/__init__.py b/src/python/module/nifty/graph/opt/multicut/__init__.py index e846078e1..0a8c77297 100644 --- a/src/python/module/nifty/graph/opt/multicut/__init__.py +++ b/src/python/module/nifty/graph/opt/multicut/__init__.py @@ -273,27 +273,6 @@ def defaultMulticutFactory(): """%(factoryClsName("MulticutGreedyAdditive")) - - def multicutAndresGreedyAdditiveFactory(): - s, F = getSettingsAndFactoryCls("MulticutAndresGreedyAdditive") - return F(s) - O.multicutAndresGreedyAdditiveFactory = staticmethod(multicutAndresGreedyAdditiveFactory) - O.multicutAndresGreedyAdditiveFactory.__doc__ = """ create an instance of :class:`%s` - - Find approximate solutions via - agglomerative clustering as in :cite:`beier_15_funsion`. - - Note: - This is just for comparison since it implements the - same as :func:`greedyAddtiveFactory`. - - - Returns: - %s : multicut factory - """%tuple([factoryClsName("MulticutAndresGreedyAdditive")]*2) - - - @warmStartGreeedyDecorator def kernighanLinFactory( numberOfInnerIterations = sys.maxsize, @@ -323,43 +302,6 @@ def kernighanLinFactory( """%tuple([factoryClsName("KernighanLin")]*2) - - def multicutAndresKernighanLinFactory( - numberOfInnerIterations = sys.maxsize, - numberOfOuterIterations = 100, - epsilon = 1e-6, - verbose = False, - greedyWarmstart = False - ): - s, F = getSettingsAndFactoryCls("MulticutAndresKernighanLin") - s.numberOfInnerIterations = numberOfInnerIterations - s.numberOfOuterIterations = numberOfOuterIterations - s.epsilon = epsilon - s.verbose = verbose - s.greedyWarmstart = greedyWarmstart - return F(s) - O.multicutAndresKernighanLinFactory = staticmethod(multicutAndresKernighanLinFactory) - O.multicutAndresKernighanLinFactory.__doc__ = """ create an instance of :class:`%s` - - Find approximate solutions via - agglomerative clustering as in :cite:`TODO`. - - Note: - This is just for comparison since it implements the - same as :func:`greedyAddtiveFactory`. - - Args: - numberOfInnerIterations (int): number of inner iterations (default: {sys.maxsize}) - numberOfOuterIterations (int): number of outer iterations (default: {100}) - epsilon (float): epsilon (default: { 1e-6}) - verbose (bool): (default: {False}) - greedyWarmstart (bool): initialize with greedyAdditive (default: {True}) - - Returns: - %s : multicut factory - """%tuple([factoryClsName("MulticutAndresKernighanLin")]*2) - - def multicutDecomposerFactory(submodelFactory=None, fallthroughFactory=None): if submodelFactory is None: @@ -399,7 +341,6 @@ def multicutDecomposerFactory(submodelFactory=None, fallthroughFactory=None): """%(factoryClsName("MulticutDecomposer"),factoryClsName("MulticutDecomposer")) - def multicutIlpFactory(addThreeCyclesConstraints=True, addOnlyViolatedThreeCyclesConstraints=True, ilpSolverSettings=None, diff --git a/src/python/test/graph/lifted_multicut/test_lifted_multicut_solvers.py b/src/python/test/graph/lifted_multicut/test_lifted_multicut_solvers.py index c07349518..c1634ea86 100644 --- a/src/python/test/graph/lifted_multicut/test_lifted_multicut_solvers.py +++ b/src/python/test/graph/lifted_multicut/test_lifted_multicut_solvers.py @@ -60,12 +60,13 @@ def testLiftedMulticutGreedyAdditive(self): visitor = obj.verboseVisitor(100) argN = solver.optimize() - solverFactory = obj.liftedMulticutAndresGreedyAdditiveFactory() - solver = solverFactory.create(obj) - visitor = obj.verboseVisitor(100) - argA = solver.optimize() + if False: + solverFactory = obj.liftedMulticutAndresGreedyAdditiveFactory() + solver = solverFactory.create(obj) + visitor = obj.verboseVisitor(100) + argA = solver.optimize() - self.assertAlmostEqual(obj.evalNodeLabels(argA), obj.evalNodeLabels(argN)) + self.assertAlmostEqual(obj.evalNodeLabels(argA), obj.evalNodeLabels(argN)) def testLiftedMulticutKernighanLinSimple(self): G = nifty.graph.UndirectedGraph From 5b997069c123439afc7bcad89687c7dc377c5e48 Mon Sep 17 00:00:00 2001 From: Constantin Pape Date: Tue, 12 Feb 2019 21:39:02 +0100 Subject: [PATCH 2/2] Remove graph submodule; move necessary headers to nifty/graph/detail --- .gitmodules | 4 - CMakeLists.txt | 5 +- externals/graph | 1 - .../nifty/graph/detail/andres/adjacency.hxx | 187 +++ .../nifty/graph/detail/andres/grid-graph.hxx | 1423 +++++++++++++++++ include/nifty/graph/detail/andres/visitor.hxx | 71 + include/nifty/graph/undirected_grid_graph.hxx | 2 +- 7 files changed, 1685 insertions(+), 8 deletions(-) delete mode 160000 externals/graph create mode 100644 include/nifty/graph/detail/andres/adjacency.hxx create mode 100644 include/nifty/graph/detail/andres/grid-graph.hxx create mode 100644 include/nifty/graph/detail/andres/visitor.hxx diff --git a/.gitmodules b/.gitmodules index 5494dbac1..28a6deb94 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "externals/graph"] - path = externals/graph - url = https://github.com/bjoern-andres/graph - [submodule "externals/LP_MP"] path = externals/LP_MP url = https://github.com/pawelswoboda/LP_MP.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ef9c17db..c65710af9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,8 +140,9 @@ include_directories(${xtensor_INCLUDE_DIRS}) #------------------------------------------------------------------------------------------------------------------- # externals #------------------------------------------------------------------------------------------------------------------- -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/externals/maxflow") -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/externals/graph/include") +# FIXME external maxflow project doews not exist anymore +# was this removed accidentally? +# include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/externals/maxflow") diff --git a/externals/graph b/externals/graph deleted file mode 160000 index 951031bab..000000000 --- a/externals/graph +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 951031bab424e3c66002192536fc9de1994dbb00 diff --git a/include/nifty/graph/detail/andres/adjacency.hxx b/include/nifty/graph/detail/andres/adjacency.hxx new file mode 100644 index 000000000..a33dbede5 --- /dev/null +++ b/include/nifty/graph/detail/andres/adjacency.hxx @@ -0,0 +1,187 @@ +// This header was copied from https://github.com/bjoern-andres/graph. +// It comes with the following license: +/* +Copyright (c) by Bjoern Andres (bjoern@andres.sc). + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + The name of the author must not be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once +#ifndef ANDRES_GRAPH_ADJACENCY_HXX +#define ANDRES_GRAPH_ADJACENCY_HXX + +namespace andres { +namespace graph { + +/// The adjacency of a vertex consists of a vertex and a connecting edge. +template +class Adjacency { +public: + typedef T Value; + + Adjacency(const Value = T(), const Value = T()); + Value vertex() const; + Value& vertex(); + Value edge() const; + Value& edge(); + bool operator<(const Adjacency&) const; + bool operator<=(const Adjacency&) const; + bool operator>(const Adjacency&) const; + bool operator>=(const Adjacency&) const; + bool operator==(const Adjacency&) const; + bool operator!=(const Adjacency&) const; + +private: + Value vertex_; + Value edge_; +}; + +/// Construct an adjacency. +/// +/// \param vertex Vertex. +/// \param edge Edge. +/// +template +inline +Adjacency::Adjacency( + const Value vertex, + const Value edge +) +: vertex_(vertex), + edge_(edge) +{} + +/// Access the vertex. +/// +template +inline typename Adjacency::Value +Adjacency::vertex() const { + return vertex_; +} + +/// Access the vertex. +/// +template +inline typename Adjacency::Value& +Adjacency::vertex() { + return vertex_; +} + +/// Access the edge. +/// +template +inline typename Adjacency::Value +Adjacency::edge() const { + return edge_; +} + +/// Access the edge. +/// +template +inline typename Adjacency::Value& +Adjacency::edge() { + return edge_; +} + +/// Adjacencies are ordered first wrt the vertex, then wrt the edge. +/// +template +inline bool +Adjacency::operator<( + const Adjacency& in +) const { + if(vertex_ < in.vertex_) { + return true; + } + else if(vertex_ == in.vertex_) { + return edge_ < in.edge_; + } + else { + return false; + } +} + +/// Adjacencies are ordered first wrt the vertex, then wrt the edge. +/// +template +inline bool +Adjacency::operator<=( + const Adjacency& in +) const { + if(vertex_ < in.vertex_) { + return true; + } + else if(vertex_ == in.vertex_) { + return edge_ <= in.edge_; + } + else { + return false; + } +} + +/// Adjacencies are ordered first wrt the vertex, then wrt the edge. +/// +template +inline bool +Adjacency::operator>( + const Adjacency& in +) const { + if(vertex_ > in.vertex_) { + return true; + } + else if(vertex_ == in.vertex_) { + return edge_ > in.edge_; + } + else { + return false; + } +} + +/// Adjacencies are ordered first wrt the vertex, then wrt the edge. +/// +template +inline bool +Adjacency::operator>=( + const Adjacency& in +) const { + if(vertex_ > in.vertex_) { + return true; + } + else if(vertex_ == in.vertex_) { + return edge_ >= in.edge_; + } + else { + return false; + } +} + +/// Adjacencies are equal if both the vertex and the edge are equal. +/// +template +inline bool +Adjacency::operator==( + const Adjacency& in +) const { + return vertex_ == in.vertex_ && edge_ == in.edge_; +} + +/// Adjacencies are unequal if either the vertex or the edge are unqual. +/// +template +inline bool +Adjacency::operator!=( + const Adjacency& in +) const { + return !(*this == in); +} + +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_ADJACENCY_HXX diff --git a/include/nifty/graph/detail/andres/grid-graph.hxx b/include/nifty/graph/detail/andres/grid-graph.hxx new file mode 100644 index 000000000..815c56241 --- /dev/null +++ b/include/nifty/graph/detail/andres/grid-graph.hxx @@ -0,0 +1,1423 @@ +// This header was copied from https://github.com/bjoern-andres/graph. +// It comes with the following license: +/* +Copyright (c) by Bjoern Andres (bjoern@andres.sc). + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + The name of the author must not be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once +#ifndef ANDRES_GRAPH_GRID_GRAPH_HXX +#define ANDRES_GRAPH_GRID_GRAPH_HXX + +#include +#include +#include +#include +#include +#include + +#include "nifty/graph/detail/andres/adjacency.hxx" +#include "nifty/graph/detail/andres/visitor.hxx" + +namespace andres { + +namespace graph { + +/// D-dimensional grid graph. +template > +class GridGraph { +public: + typedef std::size_t size_type; + typedef VISITOR Visitor; + typedef andres::graph::Adjacency AdjacencyType; + + static const size_type DIMENSION = static_cast (D); + + typedef std::array VertexCoordinate; + + /// \class EdgeCoordinate + /// Describes an edge as the integer index of the minimum of the + /// two endpoints and the direction along which it is drawn. + struct EdgeCoordinate { + EdgeCoordinate(const VertexCoordinate&, const size_type, bool = false); + EdgeCoordinate(); + /// The minimum of the two endpoints of the edge is specified + /// as an integer and accessed by the \b pivot member. + /// This specifies the \e origin of the edge, in a direction + /// towards the positive orthant. + /// (i.e.: in specifying the pivot of an edge, an isSmaller + /// of false is implied.) + VertexCoordinate pivotCoordinate_; + /// The dimension along which the edge is drawn. + size_type dimension_; + }; + + /// AdjacencyIterator + // \cond SUPPRESS_DOXYGEN + class AdjacencyIterator + : public std::iterator < + std::random_access_iterator_tag, + const AdjacencyType + > { + public: + typedef GridGraph GraphType; + typedef std::iterator < + std::random_access_iterator_tag, + const AdjacencyType + > Base; + typedef typename Base::difference_type difference_type; + typedef typename Base::pointer pointer; + typedef typename Base::reference reference; + + AdjacencyIterator(); + AdjacencyIterator(const GraphType&); + AdjacencyIterator(const GraphType&, const size_type); + AdjacencyIterator(const GraphType&, const size_type, const size_type); + + // increment and decrement + AdjacencyIterator& operator+=(const difference_type); + AdjacencyIterator& operator-=(const difference_type); + AdjacencyIterator& operator++(); // prefix + AdjacencyIterator& operator--(); // prefix + AdjacencyIterator operator++(int); // postfix + AdjacencyIterator operator--(int); // postfix + AdjacencyIterator operator+(const difference_type) const; + AdjacencyIterator operator-(const difference_type) const; + difference_type operator-(const AdjacencyIterator&) const; + + // comparison + bool operator==(const AdjacencyIterator&) const; + bool operator!=(const AdjacencyIterator&) const; + bool operator<(const AdjacencyIterator&) const; + bool operator<=(const AdjacencyIterator&) const; + bool operator>(const AdjacencyIterator&) const; + bool operator>=(const AdjacencyIterator&) const; + + // access + reference operator*(); + pointer operator->(); + reference operator[](const difference_type); + + protected: + const GraphType* graph_; + size_type vertex_; + size_type adjacencyIndex_; + AdjacencyType adjacency_; + }; + + class VertexIterator + : public AdjacencyIterator { + public: + typedef GridGraph GraphType; + typedef AdjacencyIterator Base; + typedef const size_type value_type; + typedef typename Base::difference_type difference_type; + typedef value_type* pointer; + typedef value_type& reference; + + VertexIterator(); + VertexIterator(const VertexIterator&); + VertexIterator(const AdjacencyIterator&); + VertexIterator(const GraphType&); + VertexIterator(const GraphType&, const size_type); + VertexIterator(const GraphType&, const size_type, const size_type); + + // access + value_type operator*() const; + value_type operator[](const difference_type) const; + + void coordinate(VertexCoordinate&) const; + private: + pointer operator->() const; + }; + + class EdgeIterator + : public AdjacencyIterator { + public: + typedef GridGraph GraphType; + typedef AdjacencyIterator Base; + typedef const size_type value_type; + typedef typename Base::difference_type difference_type; + typedef value_type* pointer; + typedef value_type& reference; + + EdgeIterator(); + EdgeIterator(const EdgeIterator&); + EdgeIterator(const AdjacencyIterator&); + EdgeIterator(const GraphType&); + EdgeIterator(const GraphType&, const size_type); + EdgeIterator(const GraphType&, const size_type, const size_type); + + // access + value_type operator*() const; + value_type operator[](const difference_type) const; + private: + pointer operator->() const; + }; + // \endcond + + // construction + GridGraph(const Visitor& = Visitor()); + GridGraph(const VertexCoordinate&, const Visitor& = Visitor()); + GridGraph(const std::initializer_list, const Visitor& = Visitor()); + void assign(const Visitor& = Visitor()); + void assign(const VertexCoordinate&, const Visitor& = Visitor()); + + // iterator access (compatible with Digraph) + VertexIterator verticesFromVertexBegin(const size_type) const; + VertexIterator verticesFromVertexEnd(const size_type) const; + VertexIterator verticesToVertexBegin(const size_type) const; + VertexIterator verticesToVertexEnd(const size_type) const; + EdgeIterator edgesFromVertexBegin(const size_type) const; + EdgeIterator edgesFromVertexEnd(const size_type) const; + EdgeIterator edgesToVertexBegin(const size_type) const; + EdgeIterator edgesToVertexEnd(const size_type) const; + AdjacencyIterator adjacenciesFromVertexBegin(const size_type) const; + AdjacencyIterator adjacenciesFromVertexEnd(const size_type) const; + AdjacencyIterator adjacenciesToVertexBegin(const size_type) const; + AdjacencyIterator adjacenciesToVertexEnd(const size_type) const; + + // access (compatible with Digraph) + size_type numberOfVertices() const; + size_type numberOfEdges() const; + size_type numberOfEdgesFromVertex(const size_type) const; + size_type numberOfEdgesToVertex(const size_type) const; + size_type vertexOfEdge(const size_type, const size_type) const; + size_type edgeFromVertex(const size_type, const size_type) const; + size_type edgeToVertex(const size_type, const size_type) const; + size_type vertexFromVertex(const size_type, const size_type) const; + size_type vertexToVertex(const size_type, const size_type) const; + AdjacencyType adjacencyFromVertex(const size_type, const size_type) const; + AdjacencyType adjacencyToVertex(const size_type, const size_type) const; + std::pair findEdge(const size_type, const size_type) const; + bool multipleEdgesEnabled() const; + + size_type insertEdge(const size_type, const size_type) const; + + size_type shape(const size_type) const; + + size_type vertex(const VertexCoordinate&) const; + void vertex(size_type, VertexCoordinate&) const; + size_type edge(const EdgeCoordinate&) const; + void edge(size_type, EdgeCoordinate&) const; + +private: + size_type vertexFromVertex(const VertexCoordinate&, const size_type, size_type&, bool&) const; + void adjacencyFromVertex(const VertexCoordinate&, const size_type, size_type&, size_type&) const; + + // Member variables + VertexCoordinate shape_; + std::array edgeIndexOffsets_; + std::array vertexIndexOffsets_; + std::array edgeShapes_; + size_type numberOfVertices_; + const size_type& numberOfEdges_; + Visitor visitor_; +}; + +/// Construct an empty grid graph. +/// \tparam S the type of the indices used. It must be an unsigned type +/// (otherwise a compilation error is caused). Defaults to \c std::size_t . +/// \tparam VISITOR a visitor class to be used. Since this class is immutable +/// appart from resizing, this is a dummy variable meant for compatibility, +/// defaulting to \c andres::graph::IdgeGraphVisitor. +/// \param visitor Visitor to follow changes of integer indices of vertices +/// and edges. +template +inline +GridGraph::GridGraph( + const Visitor& visitor +) +: GridGraph(VertexCoordinate({}), visitor) // Chain-call Constructor +{} + +/// Construct a grid graph with a specified shape. +/// +/// \param shape the shape of the Grid Graph as an std::array. +/// \param visitor Visitor to follow changes of integer indices of vertices +/// and edges. +template +inline +GridGraph::GridGraph( + const VertexCoordinate& shape, + const Visitor& visitor +) + : numberOfEdges_ (edgeIndexOffsets_[DIMENSION - 1]) { + assign(shape, visitor); +} + +/// Construct a grid graph with a specified shape. +/// +/// \param shape the shape of the Grid Graph as an std::array. +/// \param visitor Visitor to follow changes of integer indices of vertices +/// and edges. +template +inline +GridGraph::GridGraph( + std::initializer_list shape, + const Visitor& visitor +) + : numberOfEdges_ (edgeIndexOffsets_[DIMENSION - 1]) { + assert(shape.size()==D); + VertexCoordinate vCoord; + std::copy(shape.begin(), shape.end(), vCoord.begin()); + assign(vCoord, visitor); +} + +/// Clear a grid graph. +/// +/// \param visitor Visitor to follow changes of integer indices of vertices +/// and edges. +/// +template +inline void +GridGraph::assign( + const Visitor& visitor +) { + VertexCoordinate shape; + std::fill(shape.begin(), shape.end(), 0); + assign(shape, visitor); +} + +/// Clear a grid graph and assign a new shape. +/// +/// \param shape the shape of the grid graph +/// \param visitor Visitor to follow changes of integer indices of vertices +/// and edges. +template +inline void +GridGraph::assign( + const VertexCoordinate& shape, + const Visitor& visitor +) { + shape_ = shape; + visitor_ = visitor; + + // Set vertex offsets for fast vertex indexing. + { + size_type cumprod = 1; + size_type i; + for(i = 0; i < DIMENSION; ++i) { + vertexIndexOffsets_[i] = cumprod; + cumprod *= shape_[i]; + } + numberOfVertices_ = cumprod; + } + { + size_type edgeIndexOffset = 0; // First edge is at offset 0 + for(size_type i = 0; i < DIMENSION; ++i) { + VertexCoordinate& edgeShape = edgeShapes_[i]; + edgeShape = shape_; // the i-th dimension of the edges along the i-th dimension is 1 less + if(edgeShape[i] > 0) { // If already zero, no need to reduce. + --edgeShape[i]; + } + { + // + size_type cumprod = edgeShape[0]; + for(size_type j = 1; j < DIMENSION; ++j) { + cumprod *= edgeShape[j]; + } + edgeIndexOffsets_[i] = (edgeIndexOffset += cumprod); + } + } + } +} + +/// Get an iterator to the beginning of the sequence of vertices reachable +/// from a given vertex via a single edge. +/// +/// \param vertex Integer index of the vertex. +/// \return VertexIterator. +/// +/// \sa verticesFromVertexEnd() +/// +template +inline typename GridGraph::VertexIterator +GridGraph::verticesFromVertexBegin( + const size_type vertex +) const { + return VertexIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of vertices reachable from +/// a given vertex via a single edge. +/// +/// \param vertex Integer index of the vertex. +/// \return VertexIterator. +/// +/// \sa verticesFromVertexBegin() +/// +template +inline typename GridGraph::VertexIterator +GridGraph::verticesFromVertexEnd( + const size_type vertex +) const { + return VertexIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get an iterator to the beginning of the sequence of vertices from which +/// a given vertex is reachable via a single edge. +/// +/// \param vertex Integer index of the vertex. +/// \return VertexIterator. +/// +/// \sa verticesToVertexEnd() +/// +template +inline typename GridGraph::VertexIterator +GridGraph::verticesToVertexBegin( + const size_type vertex +) const { + return VertexIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of vertices from which a +/// given vertex is reachable via a single edge. +/// +/// \param vertex Integer index of the vertex. +/// \return VertexIterator. +/// +/// \sa verticesToVertexBegin() +/// +template +inline typename GridGraph::VertexIterator +GridGraph::verticesToVertexEnd( + const size_type vertex +) const { + return VertexIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get an iterator to the beginning of the sequence of edges that originate +/// from a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return EdgeIterator. +/// +/// \sa edgesFromVertexEnd() +/// +template +inline typename GridGraph::EdgeIterator +GridGraph::edgesFromVertexBegin( + const size_type vertex +) const { + return EdgeIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of edges that originate from +/// a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return EdgeIterator. +/// +/// \sa edgesFromVertexBegin() +/// +template +inline typename GridGraph::EdgeIterator +GridGraph::edgesFromVertexEnd( + const size_type vertex +) const { + return EdgeIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get an iterator to the beginning of the sequence of edges that are +/// incident to a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return EdgeIterator. +/// +/// \sa edgesToVertexEnd() +/// +template +inline typename GridGraph::EdgeIterator +GridGraph::edgesToVertexBegin( + const size_type vertex +) const { + return EdgeIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of edges that are incident +/// to a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return EdgeIterator. +/// +/// \sa edgesToVertexBegin() +/// +template +inline typename GridGraph::EdgeIterator +GridGraph::edgesToVertexEnd( + const size_type vertex +) const { + return EdgeIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get an iterator to the beginning of the sequence of adjacencies that +/// originate from a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return AdjacencyIterator. +/// +/// \sa adjacenciesFromVertexEnd() +/// +template +inline typename GridGraph::AdjacencyIterator +GridGraph::adjacenciesFromVertexBegin( + const size_type vertex +) const { + return AdjacencyIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of adjacencies that originate +/// from a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return AdjacencyIterator. +/// +/// \sa adjacenciesFromVertexBegin() +/// +template +inline typename GridGraph::AdjacencyIterator +GridGraph::adjacenciesFromVertexEnd( + const size_type vertex +) const { + return AdjacencyIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get an iterator to the beginning of the sequence of adjacencies incident +/// to a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return AdjacencyIterator. +/// +/// \sa adjacenciesToVertexEnd() +/// +template +inline typename GridGraph::AdjacencyIterator +GridGraph::adjacenciesToVertexBegin( + const size_type vertex +) const { + return AdjacencyIterator(*this, vertex, 0); +} + +/// Get an iterator to the end of the sequence of adjacencies incident to +/// a given vertex. +/// +/// \param vertex Integer index of the vertex. +/// \return AdjacencyIterator. +/// +/// \sa adjacenciesToVertexBegin() +/// +template +inline typename GridGraph::AdjacencyIterator +GridGraph::adjacenciesToVertexEnd( + const size_type vertex +) const { + return AdjacencyIterator(*this, vertex, numberOfEdgesFromVertex(vertex)); +} + +/// Get the number of vertices. +/// +template +inline typename GridGraph::size_type +GridGraph::numberOfVertices() const { + return numberOfVertices_; +} + +/// Get the number of edges. +/// +template +inline typename GridGraph::size_type +GridGraph::numberOfEdges() const { + return numberOfEdges_; +} + +/// Get the number of edges that originate from a given vertex. +/// +/// \param vertex Integer index of a vertex. +/// +/// \sa edgeFromVertex() +/// +template +inline typename GridGraph::size_type +GridGraph::numberOfEdgesFromVertex( + const size_type vertex +) const { + assert(vertex < numberOfVertices()); + VertexCoordinate edgeCoordinate; + this->vertex(vertex, edgeCoordinate); + size_type numEdgesFromVertex = 0; + for(size_type i = 0; i < DIMENSION; ++i) { + const size_type& coordinate = edgeCoordinate[i]; + if(coordinate > 0) { + ++numEdgesFromVertex; + } + if(coordinate < (shape_[i] - 1)) { + ++numEdgesFromVertex; + } + } + return numEdgesFromVertex; +} + +/// Get the number of edges that are incident to a given vertex. +/// +/// \param vertex Integer index of a vertex. +/// +/// \sa edgeToVertex() +/// +template +inline typename GridGraph::size_type +GridGraph::numberOfEdgesToVertex( + const size_type vertex +) const { + return numberOfEdgesFromVertex(vertex); +} + +/// Get the integer index of a vertex of an edge. +/// +/// \param edge Integer index of an edge. +/// \param j Number of the vertex in the edge; either 0 or 1. +/// +template +inline typename GridGraph::size_type +GridGraph::vertexOfEdge( + const size_type edge, + const size_type j +) const { + assert(edge < numberOfEdges()); + assert(j < 2); + EdgeCoordinate edgeCoordinate; + this->edge(edge, edgeCoordinate); + size_type pivotIndex = vertex(edgeCoordinate.pivotCoordinate_); + if(j == 0) { + return pivotIndex; + } + else { + return pivotIndex + vertexIndexOffsets_[edgeCoordinate.dimension_]; + } +} + +/// Get the integer index of an edge that originates from a given vertex. +/// +/// \param vertex Integer index of a vertex. +/// \param j Number of the edge; between 0 and numberOfEdgesFromVertex(vertex) +/// - 1. +/// +/// \sa numberOfEdgesFromVertex()exFi +/// +template +inline typename GridGraph::size_type +GridGraph::edgeFromVertex( + const size_type vertex, + const size_type j +) const { + assert(j < numberOfEdgesFromVertex(vertex)); + VertexCoordinate vertexCoordinate; + this->vertex(vertex, vertexCoordinate); + size_type direction; + bool isSmaller; + vertexFromVertex(vertexCoordinate, j, direction, isSmaller); + if(isSmaller) { + VertexCoordinate pivotVertexCoordinate = vertexCoordinate; + --pivotVertexCoordinate[direction]; + return edge(EdgeCoordinate(pivotVertexCoordinate, direction)); + } + else { + return edge(EdgeCoordinate(vertexCoordinate, direction)); + } +} + +/// Get the integer index of an edge that is incident to a given vertex. +/// +/// \param vertex Integer index of a vertex. +/// \param j Number of the edge; between 0 and numberOfEdgesFromVertex(vertex) +/// - 1. +/// +/// \sa numberOfEdgesToVertex() +/// +template +inline typename GridGraph::size_type +GridGraph::edgeToVertex( + const size_type vertex, + const size_type j +) const { + assert(j < numberOfEdgesToVertex(vertex)); + return edgeFromVertex(vertex, j); +} + +/// Get the integer index of a vertex from which a given vertex is reachable +/// via a single edge. +/// +/// \param vertex Integer index of a vertex. +/// \param j Number of the vertex; between 0 and +/// numberOfEdgesFromVertex(vertex) - 1. +/// +/// \sa numberOfEdgesFromVertex() +/// +template +inline typename GridGraph::size_type +GridGraph::vertexFromVertex( + const size_type vertex, + const size_type j +) const { + assert(j < numberOfEdgesToVertex(vertex)); + VertexCoordinate vertexCoordinate; + this->vertex(vertex, vertexCoordinate); + size_type direction; + bool isSmaller; + return vertexFromVertex(vertexCoordinate, j, direction, isSmaller); +} + + +/// Get the integer index of a vertex to which a given vertex has a single +/// edge. +/// +/// \param vertex Integer index of a vertex. +/// \param j Number of the vertex; between 0 and +/// numberOfEdgesFromVertex(vertex) - 1. +/// +/// \sa numberOfEdgesFromVertex() +/// +template +inline typename GridGraph::size_type +GridGraph::vertexToVertex( + const size_type vertex, + const size_type j +) const { + assert(j < numberOfEdgesToVertex(vertex)); + return vertexFromVertex(vertex, j); +} + +/// Get the j-th adjacency from a vertex. +/// +/// \param vertex Vertex. +/// \param j Number of the adjacency. +template +inline typename GridGraph::AdjacencyType +GridGraph::adjacencyFromVertex( + const size_type vertex, + const size_type j +) const { + assert(j < numberOfEdgesToVertex(vertex)); + size_type direction; + size_type adjacentEdgeIndex; + size_type adjacentVertexIndex; + + { + VertexCoordinate vertexCoordinate; + this->vertex(vertex, vertexCoordinate); + + adjacencyFromVertex(vertexCoordinate, j, adjacentVertexIndex, adjacentEdgeIndex); + } + return AdjacencyType(adjacentVertexIndex, adjacentEdgeIndex); +} + + +/// Get the j-th adjacency to a vertex. +/// +/// \param vertex Vertex. +/// \param j Number of the adjacency. +/// +template +inline typename GridGraph::AdjacencyType +GridGraph::adjacencyToVertex( + const size_type vertex, + const size_type j +) const { + return adjacencyFromVertex(vertex, j); +} + +/// Search for an edge (in constant time). +/// +/// \param vertex0 first vertex of the edge. +/// \param vertex1 second vertex of the edge. +/// \retval pair an \c std::pair. If an edge from \b vertex0 to \b vertex1 +/// exists, \c pair.first is \c true +/// and \c pair.second is the index of such an edge. If no edge from \b +/// vertex0 to \b vertex1 exists, \c pair.first is \c false +/// and \c pair.second is undefined. +template +inline std::pair::size_type> +GridGraph::findEdge( + const size_type vertex0, + const size_type vertex1 +) const { + assert(vertex0 < numberOfVertices()); + assert(vertex1 < numberOfVertices()); + if(vertex0 < vertex1) { + size_type offset = vertex1 - vertex0; + size_type i; + for(i = 0; i < DIMENSION - 1; ++i) { + if(offset == vertexIndexOffsets_[i]) { // edge found unless offset runs across dimension + VertexCoordinate vertexCoordinate0; + vertex(vertex0, vertexCoordinate0); + if(vertexCoordinate0[i] != shape_[i] - 1) { // Check for boundary case + const EdgeCoordinate edgeCoordinate(vertexCoordinate0, i, false); + const size_type edgeIndex = edge(edgeCoordinate); + return std::make_pair(true, edgeIndex); + } + } + } + if(offset == vertexIndexOffsets_[i]) { // edge found + VertexCoordinate vertexCoordinate0; + vertex(vertex0, vertexCoordinate0); + const EdgeCoordinate edgeCoordinate(vertexCoordinate0, i, false); + const size_type edgeIndex = edge(edgeCoordinate); + return std::make_pair(true, edgeIndex); + } + } + else { // On expectation faster to ignore the equal case. (Assuming uniform input distribution) + size_type offset = vertex0 - vertex1; + size_type i; + for(i = 0; i < DIMENSION - 1; ++i) { + if(offset == vertexIndexOffsets_[i]) { // edge found unless offset runs across dimensions + VertexCoordinate vertexCoordinate1; + vertex(vertex1, vertexCoordinate1); + if(vertexCoordinate1[i] != shape_[i] - 1) { // Check for boundary case + const EdgeCoordinate edgeCoordinate(vertexCoordinate1, i, false); + const size_type edgeIndex = edge(edgeCoordinate); + return std::make_pair(true, edgeIndex); + } + } + } + if(offset == vertexIndexOffsets_[i]) { // edge found unless offset runs across dimensions + VertexCoordinate vertexCoordinate1; + vertex(vertex1, vertexCoordinate1); + const EdgeCoordinate edgeCoordinate(vertexCoordinate1, i, false); + const size_type edgeIndex = edge(edgeCoordinate); + return std::make_pair(true, edgeIndex); + } + } + return std::make_pair(false, 0); +} + +/// Indicate if multiple edges are enabled. +/// +/// \return false +/// +template +inline bool +GridGraph::multipleEdgesEnabled() const { + return false; +} + +/// Returns the edge between the specified vertices. +/// +/// \param vertexIndex0 Integer index of the first vertex in the edge. +/// \param vertexIndex1 Integer index of the second vertex in the edge. +/// \return Integer index of the newly inserted edge. +/// \throw runtime_error If the edge does not exist. +template +inline typename GridGraph::size_type +GridGraph::insertEdge( + const size_type vertexIndex0, + const size_type vertexIndex1 +) const { + assert(vertexIndex0 < numberOfVertices()); + assert(vertexIndex1 < numberOfVertices()); + + std::pair p = findEdge(vertexIndex0, vertexIndex1); + if(p.first == true) { + return p.second; + } else { + throw std::runtime_error("Edge not found."); + } +} + +/// Retrieve the specified vertex of the graph. +/// \param[in] vertexIndex the integer index of the requested vertex +/// \param[out] vertexCoordinate The coordinates of the vertex. +/// \warning For the sake of performance this function does not validate +/// its inputs. +template +void +GridGraph::vertex( + size_type vertexIndex, + VertexCoordinate& vertexCoordinate +) const { + assert(vertexIndex < numberOfVertices_); + size_type i; + for(i = 0; i < DIMENSION - 1; ++i) { + vertexCoordinate[i] = vertexIndex % shape_[i]; + vertexIndex = vertexIndex / shape_[i]; + } + vertexCoordinate[i] = vertexIndex; +} + +/// Get the size of a specific dimension of the grid graph. +/// \param dimension the index of the dimension index to retrieve. +/// \return the size of the specified dimension. +/// \see mapIndexToCoordinate mapVertexCoordinateToIndex +template +inline typename GridGraph::size_type +GridGraph::shape( + const size_type dimension +) const { + return shape_[dimension]; +} + +/// Retrieve the specified vertex of the graph. +/// \param vertexCoordinate the integer index of the requested vertex +/// \return The integer index of the specified vertex. +/// \warning For the sake of performance this function does not validate +/// its inputs. +template +typename GridGraph::size_type +GridGraph::vertex( + const VertexCoordinate& vertexCoordinate +) const { + size_type index = vertexCoordinate[DIMENSION - 1]; + for(size_type i = DIMENSION - 1; i > 0; --i) { + index = index * shape_[i - 1] + vertexCoordinate[i - 1]; + } + return index; +} + +/// Retrieve the specified edge of the graph. +/// \param edgeCoordinate the coordinates of the minimum endpoint (\e pivot) +/// and the direction of the requested edge. +/// \return The integer index of the specified edge. +/// \warning For the sake of performance this function does not validate +/// its inputs. +/// \sa hasEdge() +template +inline typename GridGraph::size_type +GridGraph::edge( + const EdgeCoordinate& edgeCoordinate +) const { + assert(edgeCoordinate.dimension_ < DIMENSION); + const size_type& dimension = edgeCoordinate.dimension_; + const VertexCoordinate& pivotCoordinate = edgeCoordinate.pivotCoordinate_; + const VertexCoordinate& edgeShape = edgeShapes_[dimension]; + + // size_type index = mapCoordinateToIndex(edgeCoordinate,edgeShape); + size_type index = pivotCoordinate[DIMENSION - 1]; + for(size_type i = DIMENSION - 1; i > 0; --i) { + index = index * edgeShape[i - 1] + pivotCoordinate[i - 1]; + } + if(dimension > 0) { + const size_type& offset = edgeIndexOffsets_[dimension - 1]; + index += offset; + } + return index; +} + +/// Retrieve the specified edge of the graph. +/// \param[in] edgeIndex the integer index of the requested edge. +/// \param[out] edgeCoordinate a GridGraph::EdgeCoordinate instance. \c +/// edgeCoordinate.pivot is the integer index +/// of the minimum of the two edge endpoints; \p edgeCoordinate.direction +/// is the dimension along which +/// the edge is drawn, with an assumed positive isSmaller. +/// \warning For the sake of performance this function does not validate +/// its inputs. +/// \sa GridGraph::bool +template +inline void +GridGraph::edge( + size_type edgeIndex, + EdgeCoordinate& edgeCoordinate +) const { + // WARNING: If the assertion does not hold, the code will scan until an unlikely condition. + assert(edgeIndex < numberOfEdges()); + size_type& direction = edgeCoordinate.dimension_; + // Find the direction as the last edge offset: + for(direction = 0; edgeIndex >= edgeIndexOffsets_[direction]; ++direction); + if(direction > 0) { // Not needed, but saves one memory lookup. + const size_type& offset = edgeIndexOffsets_[direction - 1]; + edgeIndex -= offset; + } + const VertexCoordinate& edgeShape = edgeShapes_[direction]; + // mapEdgeIndexToCoordinate + { + VertexCoordinate& pivotCoordinate = edgeCoordinate.pivotCoordinate_; + size_type i; + for(i = 0; i < DIMENSION - 1; ++i) { + pivotCoordinate[i] = edgeIndex % edgeShape[i]; + edgeIndex = edgeIndex / edgeShape[i]; + } + pivotCoordinate[i] = edgeIndex; + } +} + + +/// \internal +/// \brief Retrieve the direction and isSmaller of the j-th edge of +/// a vertex +/// \param vertexCoordinate the integer index of the vertex from which the +/// edges are originating +/// \param j the index within the set of adacent edges of the specified vertex +/// \param[out] direction the direction of the specified edge +/// \param[out] isSmaller the isSmaller of the specified edge +/// \retval found If the edge is found, a value of \c true is returned. +/// \remark This function attempts a fast imlementation that tries not +/// to waste any comparison operations and is meant for use as a building +/// block of the class. +/// \warning For the sake of performance this function does not validate +/// its inputs. +/// \sa directionOfEdgeFromVertex, edgeFromVertex +template +inline typename GridGraph::size_type +GridGraph::vertexFromVertex( + const VertexCoordinate& vertexCoordinate, + const size_type j, + size_type& direction, + bool& isSmaller +) const { + assert(vertex(vertexCoordinate) < numberOfVertices()); + VertexCoordinate modifieableVertexCoordinate = vertexCoordinate; + size_type cur_j = 0; + for(size_type i = DIMENSION; i > 0; --i) { + if(vertexCoordinate[i - 1] > 0) { // edge exists + if(cur_j == j) { + direction = i - 1; + isSmaller = true; + --modifieableVertexCoordinate[i - 1]; + const size_type vertexIndex = vertex(modifieableVertexCoordinate); + return vertexIndex; + } + ++cur_j; + } + } + for(size_type i = 0; i < DIMENSION; ++i) { + if(vertexCoordinate[i] < shape_[i] - 1) { // edge exists + if(cur_j == j) { + direction = i; + isSmaller = false; + ++modifieableVertexCoordinate[i]; + const size_type vertexIndex = vertex(modifieableVertexCoordinate); + return vertexIndex; + } + ++cur_j; + } + } + throw std::out_of_range("vertex neighbor index out of range."); +} + +template +inline void +GridGraph::adjacencyFromVertex( + const VertexCoordinate& vertexCoordinate, + const size_type j, + size_type& adjacentVertexIndex, + size_type& adjacentEdgeIndex +) const { + assert(vertex(vertexCoordinate) < numberOfVertices()); + size_type direction; + bool isSmaller; + adjacentVertexIndex = vertexFromVertex(vertexCoordinate, j, direction, isSmaller); + if(isSmaller) { + VertexCoordinate pivotVertexCoordinate = vertexCoordinate; + --pivotVertexCoordinate[direction]; + adjacentEdgeIndex = edge(EdgeCoordinate(pivotVertexCoordinate, direction)); + } + else { + adjacentEdgeIndex = edge(EdgeCoordinate(vertexCoordinate, direction)); + } + +} + +/// Initialize an edge coordinate. +/// \param pivotCoordinate coordinate of the reference vertex. +/// \param dimension dimension along which the edge is drawn. +/// \param isSmaller relative position of specified endpoint.\n +/// A value of \c true results in an object corresponding to the edge +/// of which the smallest endpoint has a GridGraph::VertexCoordinate +/// equal to \b pivotCoordinate.\n +/// Similarly, a value of \c false results in an object corresponding +/// to the edge of which the largest endpoint has a +/// GridGraph::VertexCoordinate equal to \b pivotCoordinate. +template +inline GridGraph::EdgeCoordinate::EdgeCoordinate( + const VertexCoordinate& pivotCoordinate, + const size_type dimension, + const bool isSmaller +) + : pivotCoordinate_(pivotCoordinate), + dimension_(dimension) { + if(isSmaller) { + assert(pivotCoordinate_[dimension] > 0); + --pivotCoordinate_[dimension]; + } +} + +/// Default non-initializing constructor +/// \warning this constructor will \b NOT set the pivotCoordinate_ membr +/// variable to zero. +template +inline GridGraph::EdgeCoordinate::EdgeCoordinate() { +} + + +// \cond SUPPRESS_DOXYGEN + +// implementation of AdjacencyIterator + +template +inline +GridGraph::AdjacencyIterator::AdjacencyIterator() + : vertex_(0), + adjacencyIndex_(0), + adjacency_() +{} +template +inline +GridGraph::AdjacencyIterator::AdjacencyIterator( + const GraphType& graph +) + : graph_(&graph), + vertex_(0), + adjacencyIndex_(0), + adjacency_() +{} + +template +inline +GridGraph::AdjacencyIterator::AdjacencyIterator( + const GraphType& graph, + const size_type vertex +) + : graph_(&graph), + vertex_(vertex), + adjacencyIndex_(0), + adjacency_() { + assert(vertex < graph.numberOfVertices()); +} + +template +inline +GridGraph::AdjacencyIterator::AdjacencyIterator( + const GraphType& graph, + const size_type vertex, + const size_type adjacencyIndex +) + : graph_(&graph), + vertex_(vertex), + adjacencyIndex_(adjacencyIndex), + adjacency_() { + assert(vertex < graph.numberOfVertices()); + assert(adjacencyIndex <= graph.numberOfVertices()); +} + +template +inline typename GridGraph::AdjacencyIterator& +GridGraph::AdjacencyIterator::operator+=( + const difference_type d +) { + adjacencyIndex_ += d; + return *this; +} + +template +inline typename GridGraph::AdjacencyIterator& +GridGraph::AdjacencyIterator::operator-=( + const difference_type d +) { + adjacencyIndex_ -= d; + return *this; +} + +template +inline typename GridGraph::AdjacencyIterator& +GridGraph::AdjacencyIterator::operator++() { + ++adjacencyIndex_; + return *this; +} + +template +inline typename GridGraph::AdjacencyIterator& +GridGraph::AdjacencyIterator::operator--() { + --adjacencyIndex_; + return *this; +} + +template +inline typename GridGraph::AdjacencyIterator +GridGraph::AdjacencyIterator::operator++(int) { + AdjacencyIterator copy = *this; + ++adjacencyIndex_; + return copy; +} + +template +inline typename GridGraph::AdjacencyIterator +GridGraph::AdjacencyIterator::operator--(int) { + AdjacencyIterator copy = *this; + --adjacencyIndex_; + return copy; +} + +template +inline typename GridGraph::AdjacencyIterator +GridGraph::AdjacencyIterator::operator+( + const difference_type d +) const { + AdjacencyIterator copy = *this; + copy += d; + return copy; +} + +template +inline typename GridGraph::AdjacencyIterator +GridGraph::AdjacencyIterator::operator-( + const difference_type d +) const { + AdjacencyIterator copy = *this; + copy -= d; + return copy; +} + +template +inline typename GridGraph::AdjacencyIterator::difference_type +GridGraph::AdjacencyIterator::operator-( + const AdjacencyIterator& adjacencyIterator +) const { + return adjacencyIndex_ - adjacencyIterator.adjacencyIndex_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator==( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ == other.adjacencyIndex_ + && vertex_ == other.vertex_ + && graph_ == other.graph_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator!=( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ != other.adjacencyIndex_ + || vertex_ != other.vertex_ + || graph_ != other.graph_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator<( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ < other.adjacencyIndex_ + && vertex_ == other.vertex_ + && graph_ == other.graph_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator<=( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ <= other.adjacencyIndex_ + && vertex_ == other.vertex_ + && graph_ == other.graph_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator>( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ > other.adjacencyIndex_ + && vertex_ == other.vertex_ + && graph_ == other.graph_; +} + +template +inline bool +GridGraph::AdjacencyIterator::operator>=( + const AdjacencyIterator& other +) const { + return adjacencyIndex_ >= other.adjacencyIndex_ + && vertex_ == other.vertex_ + && graph_ == other.graph_; +} + +// Since the GridGraph has no backing storage for each of the Adjacency +// objects handled in the class, the AdjacencyIterator is limited to only +// one adjacency object per iterator instance. +// This should be sufficient for most normal usage scenarios, and is supported +// by the very lightweight copying of the AdjacencyType object itself. +// Note, however, that if you store a reference to the pointed object, +// then advance the iterator and subsequently dereference it again, +// the new reference will refer to the very same same adjacency object, +// unique for the AdjacencyIterator instance. +// This operation will therefore silently update all previous references to +// the adjacency object of the iterator. +template +inline typename GridGraph::AdjacencyIterator::reference +GridGraph::AdjacencyIterator::operator*() { + adjacency_ = graph_->adjacencyFromVertex(vertex_, adjacencyIndex_); + return adjacency_; +} + +template +inline typename GridGraph::AdjacencyIterator::pointer +GridGraph::AdjacencyIterator::operator->() { + adjacency_ = graph_->adjacencyFromVertex(vertex_, adjacencyIndex_); + return &adjacency_; +} + +template +inline typename GridGraph::AdjacencyIterator::reference +GridGraph::AdjacencyIterator::operator[]( + const difference_type j +) { + adjacency_ = graph_->adjacencyFromVertex(vertex_, adjacencyIndex_ + j); + return adjacency_; +} + +// implementation of VertexIterator + +template +inline +GridGraph::VertexIterator::VertexIterator() + : Base() +{} + +template +inline +GridGraph::VertexIterator::VertexIterator( + const GraphType& graph +) + : Base(graph) +{} + +template +inline +GridGraph::VertexIterator::VertexIterator( + const GraphType& graph, + const size_type vertex +) + : Base(graph, vertex) +{} + +template +inline +GridGraph::VertexIterator::VertexIterator( + const GraphType& graph, + const size_type vertex, + const size_type adjacencyIndex +) + : Base(graph, vertex, adjacencyIndex) +{} + +template +inline +GridGraph::VertexIterator::VertexIterator( + const VertexIterator& it +) + : Base(*(it.graph_), it.vertex_, it.adjacencyIndex_) +{} + +template +inline +GridGraph::VertexIterator::VertexIterator( + const AdjacencyIterator& it +) + : Base(it) +{} + +template +inline typename GridGraph::VertexIterator::value_type +GridGraph::VertexIterator::operator*() const { + return Base::graph_->vertexFromVertex(Base::vertex_, Base::adjacencyIndex_); +} + +template +inline typename GridGraph::VertexIterator::value_type +GridGraph::VertexIterator::operator[]( + const difference_type j +) const { + return Base::graph_->vertexFromVertex(Base::vertex_, Base::adjacencyIndex_ + j); +} + +template +inline void +GridGraph::VertexIterator::coordinate( + VertexCoordinate& vertexCoordinate +) const { + const size_type opposite = Base::graph_->vertexFromVertex(Base::vertex_, Base::adjacencyIndex_); + Base::graph_->vertex(opposite, vertexCoordinate); +} + +// implementation of EdgeIterator + +template +inline +GridGraph::EdgeIterator::EdgeIterator() + : Base() +{} + +template +inline +GridGraph::EdgeIterator::EdgeIterator( + const GraphType& graph +) + : Base(graph) +{} + +template +inline +GridGraph::EdgeIterator::EdgeIterator( + const GraphType& graph, + const size_type vertex +) + : Base(graph, vertex) +{} + +template +inline +GridGraph::EdgeIterator::EdgeIterator( + const GraphType& graph, + const size_type vertex, + const size_type adjacencyIndex +) + : Base(graph, vertex, adjacencyIndex) +{} + +template +inline +GridGraph::EdgeIterator::EdgeIterator( + const EdgeIterator& it +) + : Base(*(it.graph_), it.vertex_, it.adjacencyIndex_) +{} + +template +inline +GridGraph::EdgeIterator::EdgeIterator( + const AdjacencyIterator& it +) + : Base(it) +{} + +template +inline typename GridGraph::EdgeIterator::value_type +GridGraph::EdgeIterator::operator*() const { + return Base::graph_->edgeFromVertex(Base::vertex_, Base::adjacencyIndex_); +} + +template +inline typename GridGraph::EdgeIterator::value_type +GridGraph::EdgeIterator::operator[]( + const difference_type j +) const { + return Base::graph_->edgeFromVertex(Base::vertex_, Base::adjacencyIndex_ + j); +} + +// \endcond + + +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_GRID_GRAPH_HXX diff --git a/include/nifty/graph/detail/andres/visitor.hxx b/include/nifty/graph/detail/andres/visitor.hxx new file mode 100644 index 000000000..2607f7052 --- /dev/null +++ b/include/nifty/graph/detail/andres/visitor.hxx @@ -0,0 +1,71 @@ +// This header was copied from https://github.com/bjoern-andres/graph. +// It comes with the following license: +/* +Copyright (c) by Bjoern Andres (bjoern@andres.sc). + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + The name of the author must not be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once +#ifndef ANDRES_GRAPH_VISITOR_HXX +#define ANDRES_GRAPH_VISITOR_HXX + +#include +#include + +namespace andres { +namespace graph { + +/// Visitors can be used to follow the indices of vertices and edges. +/// +/// These indices change due to the insetion and removal of vertices and edges. +/// +template +struct IdleGraphVisitor { + typedef S size_type; + + IdleGraphVisitor() {} + void insertVertex(const size_type a) const {} + void insertVertices(const size_type a, const size_type n) const {} + void eraseVertex(const size_type a) const {} + void relabelVertex(const size_type a, const size_type b) const {} + void insertEdge(const size_type a) const {} + void eraseEdge(const size_type a) const {} + void relabelEdge(const size_type a, const size_type b) const {} +}; + +/// Visitors can be used to follow the indices of vertices and edges. +/// +/// These indices change due to the insetion and removal of vertices and edges. +/// +template +struct VerboseGraphVisitor { + typedef S size_type; + + VerboseGraphVisitor() {} + void insertVertex(const size_type a) const + { std::cout << "inserting vertex " << a << std::endl; } + void insertVertices(const size_type a, const size_type n) const + { std::cout << "inserting " << n << " vertices, starting from index " << a << std::endl; } + void eraseVertex(const size_type a) const + { std::cout << "removing vertex " << a << std::endl; } + void relabelVertex(const size_type a, const size_type b) const + { std::cout << "relabeling vertex " << a << ". new label is " << b << std::endl; } + void insertEdge(const size_type a) const + { std::cout << "inserting edge " << a << std::endl; } + void eraseEdge(const size_type a) const + { std::cout << "removing edge " << a << std::endl; } + void relabelEdge(const size_type a, const size_type b) const + { std::cout << "relabeling edge " << a << ". new label is " << b << std::endl; } +}; + +} // namespace graph +} // namespace andres + +#endif // #ifndef ANDRES_GRAPH_VISITOR_HXX diff --git a/include/nifty/graph/undirected_grid_graph.hxx b/include/nifty/graph/undirected_grid_graph.hxx index f4df32f29..d1f4dea22 100644 --- a/include/nifty/graph/undirected_grid_graph.hxx +++ b/include/nifty/graph/undirected_grid_graph.hxx @@ -5,7 +5,7 @@ #include #include -#include "andres/graph/grid-graph.hxx" +#include "nifty/graph/detail/andres/grid-graph.hxx" #include "nifty/tools/runtime_check.hxx" #include "nifty/tools/for_each_coordinate.hxx"