├── .gitignore ├── README.md ├── include ├── andres │ ├── graph │ │ ├── doxygen.hxx │ │ ├── subgraph.hxx │ │ ├── edge-value.hxx │ │ ├── visitor.hxx │ │ ├── hdf5 │ │ │ ├── complete-graph.hxx │ │ │ ├── grid-graph.hxx │ │ │ ├── graph.hxx │ │ │ └── digraph.hxx │ │ ├── triangles.hxx │ │ ├── multicut │ │ │ ├── mutex-watershed.hxx │ │ │ ├── greedy-additive.hxx │ │ │ ├── greedy-fixation.hxx │ │ │ └── cycle-packing.hxx │ │ ├── paths.hxx │ │ ├── adjacency.hxx │ │ ├── dfs.hxx │ │ ├── components.hxx │ │ ├── bfs.hxx │ │ └── detail │ │ │ └── graph.hxx │ └── functional.hxx └── nl-lmp │ ├── detail │ ├── compute-objective.hxx │ ├── call-multicut-solver.hxx │ └── update-class-labels.hxx │ ├── solution.hxx │ ├── greedy-additive.hxx │ └── solve-alternating.hxx ├── src ├── command-line-tools │ ├── solve-lmp.cxx │ ├── solve-mp.cxx │ ├── solve-mp-grid-graph.cxx │ ├── solve-mp-complete-graph.cxx │ ├── solve-lmp-grid-graph.cxx │ ├── Timer.hpp │ ├── utils.hxx │ ├── test-probabilistic-lifting.cxx │ ├── probabilistic-lifting.hxx │ ├── lift-mp.cxx │ └── lift-mp-grid-graph.cxx ├── andres │ └── graph │ │ ├── analysis │ │ └── erase-vertex.cxx │ │ └── unit-test │ │ ├── multicut │ │ ├── mutex-watershed.cxx │ │ ├── greedy-additive.cxx │ │ ├── preprocessing.cxx │ │ ├── kernighan-lin.cxx │ │ ├── ilp.cxx │ │ └── ilp-callback.cxx │ │ ├── triangles.cxx │ │ ├── paths.cxx │ │ ├── multicut-lifted │ │ ├── kernighan-lin.cxx │ │ ├── greedy-additive.cxx │ │ ├── ilp-callback.cxx │ │ └── ilp.cxx │ │ ├── minimum-spanning-tree.cxx │ │ ├── components.cxx │ │ ├── cut-vertices.cxx │ │ ├── bridges.cxx │ │ ├── dfs.cxx │ │ └── bfs.cxx └── tclap │ ├── Visitor.h │ ├── IgnoreRestVisitor.h │ ├── OptionalUnlabeledTracker.h │ ├── Constraint.h │ ├── CmdLineOutput.h │ ├── HelpVisitor.h │ ├── VersionVisitor.h │ ├── ArgTraits.h │ ├── ValuesConstraint.h │ ├── CmdLineInterface.h │ ├── XorHandler.h │ ├── StandardTraits.h │ ├── ArgException.h │ └── MultiSwitchArg.h └── cmake └── modules └── FindGUROBI.cmake /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | CMakeLists.txt.user 3 | *.autosave 4 | 5 | build/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Graphs and Graph Algorithms in C++ 2 | ============ 3 | 4 | http://www.andres.sc/graph.html 5 | -------------------------------------------------------------------------------- /include/andres/graph/doxygen.hxx: -------------------------------------------------------------------------------- 1 | /// \mainpage 2 | /// # Graphs and Graph Algorithms in C++ 3 | /// 4 | /// http://www.andres.sc/graph.html 5 | 6 | -------------------------------------------------------------------------------- /src/command-line-tools/solve-lmp.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "solve-lmp.hxx" 5 | 6 | int main(int argc, char** argv) 7 | try 8 | { 9 | Parameters parameters; 10 | 11 | parseCommandLine(argc, argv, parameters); 12 | solveLiftedMulticutProblem>(parameters); 13 | 14 | return 0; 15 | } 16 | catch (const std::runtime_error& error) 17 | { 18 | std::cerr << "error creating multicut problem: " << error.what() << std::endl; 19 | return 1; 20 | } -------------------------------------------------------------------------------- /include/andres/graph/subgraph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_SUBGRAPH_HXX 3 | #define ANDRES_GRAPH_SUBGRAPH_HXX 4 | 5 | namespace andres { 6 | namespace graph { 7 | 8 | /// An entire graph. 9 | template 10 | struct DefaultSubgraphMask { 11 | typedef T Value; 12 | 13 | bool vertex(const Value v) const 14 | { return true; } 15 | bool edge(const Value e) const 16 | { return true; } 17 | }; 18 | 19 | } // namespace graph 20 | } // namespace andres 21 | 22 | #endif // #ifndef ANDRES_GRAPH_SUBGRAPH_HXX 23 | -------------------------------------------------------------------------------- /src/command-line-tools/solve-mp.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "solve-mp.hxx" 7 | 8 | int main(int argc, char* argv[]) 9 | try 10 | { 11 | Parameters parameters; 12 | parseCommandLine(argc, argv, parameters); 13 | 14 | solveMulticutProblem>(parameters); 15 | 16 | return 0; 17 | } 18 | catch(const std::runtime_error& error) 19 | { 20 | std::cerr << "error creating multicut problem: " << error.what() << std::endl; 21 | return 1; 22 | } -------------------------------------------------------------------------------- /src/command-line-tools/solve-mp-grid-graph.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "solve-mp.hxx" 7 | 8 | int main(int argc, char* argv[]) 9 | try 10 | { 11 | Parameters parameters; 12 | parseCommandLine(argc, argv, parameters); 13 | 14 | solveMulticutProblem>(parameters); 15 | 16 | return 0; 17 | } 18 | catch(const std::runtime_error& error) 19 | { 20 | std::cerr << "error creating multicut problem: " << error.what() << std::endl; 21 | return 1; 22 | } -------------------------------------------------------------------------------- /src/command-line-tools/solve-mp-complete-graph.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "solve-mp.hxx" 7 | 8 | int main(int argc, char* argv[]) 9 | try 10 | { 11 | Parameters parameters; 12 | parseCommandLine(argc, argv, parameters); 13 | 14 | solveMulticutProblem>(parameters); 15 | 16 | return 0; 17 | } 18 | catch(const std::runtime_error& error) 19 | { 20 | std::cerr << "error creating multicut problem: " << error.what() << std::endl; 21 | return 1; 22 | } -------------------------------------------------------------------------------- /src/command-line-tools/solve-lmp-grid-graph.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "solve-lmp.hxx" 7 | 8 | int main(int argc, char** argv) 9 | try 10 | { 11 | Parameters parameters; 12 | 13 | parseCommandLine(argc, argv, parameters); 14 | solveLiftedMulticutProblem>(parameters); 15 | 16 | return 0; 17 | } 18 | catch (const std::runtime_error& error) 19 | { 20 | std::cerr << "error creating multicut problem: " << error.what() << std::endl; 21 | return 1; 22 | } -------------------------------------------------------------------------------- /include/andres/graph/edge-value.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_EDGE_VALUE_HXX 3 | #define ANDRES_GRAPH_EDGE_VALUE_HXX 4 | 5 | namespace andres { 6 | namespace graph { 7 | 8 | /// Return 1 for every edge. 9 | template 10 | struct UnitEdgeValueIterator { 11 | typedef std::ptrdiff_t difference_type; 12 | typedef T value_type; 13 | typedef value_type* pointer; 14 | typedef value_type& reference; 15 | typedef std::random_access_iterator_tag iterator_category; 16 | 17 | value_type operator[](const std::size_t) const 18 | { return 1; } 19 | }; 20 | 21 | } // namespace graph 22 | } // namespace andres 23 | 24 | #endif // #ifndef ANDRES_GRAPH_EDGE_VALUE_HXX 25 | -------------------------------------------------------------------------------- /cmake/modules/FindGUROBI.cmake: -------------------------------------------------------------------------------- 1 | set(GUROBI_ROOT_DIR "" CACHE PATH "GUROBI root directory.") 2 | 3 | STRING(REGEX MATCH "^[0-9]+" GUROBI_VERSION "${GUROBI_ROOT_DIR}") 4 | 5 | find_path(GUROBI_INCLUDE_DIR gurobi_c++.h HINTS "${GUROBI_ROOT_DIR}/include") 6 | find_library(GUROBI_LIBRARY libgurobi70.so HINTS ${GUROBI_ROOT_DIR}/lib) 7 | find_library(GUROBI_CPP_LIBRARY libgurobi_c++.a HINTS ${GUROBI_ROOT_DIR}/lib) 8 | 9 | include(FindPackageHandleStandardArgs) 10 | find_package_handle_standard_args(GUROBI DEFAULT_MSG GUROBI_LIBRARY GUROBI_CPP_LIBRARY GUROBI_INCLUDE_DIR) 11 | 12 | if(GUROBI_FOUND) 13 | set(GUROBI_INCLUDE_DIRS ${GUROBI_INCLUDE_DIR}) 14 | set(GUROBI_LIBRARIES ${GUROBI_CPP_LIBRARY} ${GUROBI_LIBRARY}) 15 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 16 | set(GUROBI_LIBRARIES "${GUROBI_LIBRARIES};m;pthread") 17 | endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") 18 | endif(GUROBI_FOUND) 19 | 20 | mark_as_advanced(GUROBI_LIBRARY GUROBI_CPP_LIBRARY GUROBI_INCLUDE_DIR) 21 | -------------------------------------------------------------------------------- /src/andres/graph/analysis/erase-vertex.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | int main() { 9 | // construct graph 10 | size_t const numberOfVertices = 1000; 11 | andres::graph::Graph<> graph(numberOfVertices); 12 | for(size_t j = 0; j < numberOfVertices; ++j) 13 | for(size_t k = 0; k < j; ++k) { 14 | graph.insertEdge(j, k); 15 | } 16 | 17 | // remove verices 18 | typedef std::chrono::high_resolution_clock Clock; 19 | std::default_random_engine randomEngine; 20 | auto const timeStart = Clock::now(); 21 | for(size_t j = 0; j < numberOfVertices; ++j) { 22 | std::uniform_int_distribution distribution(0, graph.numberOfVertices() - 1); 23 | size_t const index = distribution(randomEngine); 24 | graph.eraseVertex(index); 25 | } 26 | auto const timeStop = Clock::now(); 27 | auto const duration = std::chrono::duration(timeStop - timeStart); 28 | std::cout << "erasing " << numberOfVertices 29 | << " vertices has taken " << duration.count() 30 | << " ms." << std::endl; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /include/nl-lmp/detail/compute-objective.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_COMPUTE_OBJECTIVE_HXX 3 | #define NL_LMP_COMPUTE_OBJECTIVE_HXX 4 | 5 | #include "../problem.hxx" 6 | #include "../solution.hxx" 7 | 8 | 9 | 10 | namespace nl_lmp 11 | { 12 | 13 | namespace detail 14 | { 15 | 16 | template 17 | inline 18 | double compute_obj_value(Problem const& problem, Solution const& solution) 19 | { 20 | double obj_value = .0; 21 | 22 | for (size_t v = 0; v < problem.numberOfVertices(); ++v) 23 | obj_value += problem.getUnaryCost(v, solution[v].classIndex); 24 | 25 | for (size_t e = 0; e < problem.liftedGraph().numberOfEdges(); ++e) 26 | { 27 | auto const v0 = problem.liftedGraph().vertexOfEdge(e, 0); 28 | auto const v1 = problem.liftedGraph().vertexOfEdge(e, 1); 29 | 30 | if (solution[v0].clusterIndex != solution[v1].clusterIndex) 31 | obj_value += problem.getPairwiseCutCost(v0, v1, solution[v0].classIndex, solution[v1].classIndex); 32 | else 33 | obj_value += problem.getPairwiseJoinCost(v0, v1, solution[v0].classIndex, solution[v1].classIndex); 34 | } 35 | 36 | return obj_value; 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/nl-lmp/solution.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_SOLUTION_HXX 3 | #define NL_LMP_SOLUTION_HXX 4 | 5 | #include 6 | 7 | 8 | namespace nl_lmp 9 | { 10 | 11 | class Solution 12 | { 13 | public: 14 | struct element 15 | { 16 | size_t classIndex { 0 }; 17 | size_t clusterIndex { 0 }; 18 | }; 19 | 20 | explicit Solution(size_t n) : 21 | solution_(n) 22 | {} 23 | 24 | Solution(Solution const& other) 25 | { 26 | solution_ = other.solution_; 27 | } 28 | 29 | element const& operator[](size_t index) const 30 | { 31 | return solution_[index]; 32 | } 33 | 34 | std::vector::const_iterator begin() const 35 | { 36 | return solution_.cbegin(); 37 | } 38 | 39 | std::vector::const_iterator end() const 40 | { 41 | return solution_.cend(); 42 | } 43 | 44 | size_t size() const 45 | { 46 | return solution_.size(); 47 | } 48 | 49 | element& operator[](size_t index) 50 | { 51 | return solution_[index]; 52 | } 53 | 54 | std::vector::iterator begin() 55 | { 56 | return solution_.begin(); 57 | } 58 | 59 | std::vector::iterator end() 60 | { 61 | return solution_.end(); 62 | } 63 | 64 | private: 65 | std::vector solution_; 66 | }; 67 | 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/mutex-watershed.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/multicut/mutex-watershed.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testMutexWatershed() { 11 | // a simple weighted graph with a unique MWS solution 12 | 13 | andres::graph::Graph<> graph; 14 | graph.insertVertices(6); 15 | graph.insertEdge(0, 1); // 0 16 | graph.insertEdge(0, 3); // 1 17 | graph.insertEdge(1, 2); // 2 18 | graph.insertEdge(1, 4); // 3 19 | graph.insertEdge(2, 5); // 4 20 | graph.insertEdge(3, 4); // 5 21 | graph.insertEdge(4, 5); // 6 22 | 23 | std::vector weights(7); 24 | weights[0] = 5; 25 | weights[1] = -21; 26 | weights[2] = 4; 27 | weights[3] = 6; 28 | weights[4] = -20; 29 | weights[5] = 7; 30 | weights[6] = 8; 31 | 32 | std::vector edge_labels(graph.numberOfEdges()); 33 | andres::graph::multicut::mutexWatershed(graph, weights, edge_labels); 34 | 35 | test(edge_labels[0] == 1); 36 | test(edge_labels[1] == 1); 37 | test(edge_labels[2] == 1); 38 | test(edge_labels[3] == 0); 39 | test(edge_labels[4] == 1); 40 | test(edge_labels[5] == 0); 41 | test(edge_labels[6] == 0); 42 | } 43 | 44 | int main() 45 | { 46 | testMutexWatershed(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/greedy-additive.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/multicut/greedy-additive.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testMulticut() { 11 | // a simple weighted graph in which an optimal multicut is non-trivial 12 | 13 | andres::graph::Graph<> graph; 14 | graph.insertVertices(6); 15 | graph.insertEdge(0, 1); // 0 16 | graph.insertEdge(0, 3); // 1 17 | graph.insertEdge(1, 2); // 2 18 | graph.insertEdge(1, 4); // 3 19 | graph.insertEdge(2, 5); // 4 20 | graph.insertEdge(3, 4); // 5 21 | graph.insertEdge(4, 5); // 6 22 | 23 | std::vector weights(7); 24 | weights[0] = 5; 25 | weights[1] = -20; 26 | weights[2] = 5; 27 | weights[3] = 5; 28 | weights[4] = -20; 29 | weights[5] = 5; 30 | weights[6] = 5; 31 | 32 | std::vector edge_labels(graph.numberOfEdges()); 33 | andres::graph::multicut::greedyAdditiveEdgeContraction(graph, weights, edge_labels); 34 | 35 | test(edge_labels[0] == 0); 36 | test(edge_labels[1] == 1); 37 | test(edge_labels[2] == 0); 38 | test(edge_labels[3] == 1); 39 | test(edge_labels[4] == 1); 40 | test(edge_labels[5] == 0); 41 | test(edge_labels[6] == 0); 42 | } 43 | 44 | int main() 45 | { 46 | testMulticut(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/tclap/Visitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: Visitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reverved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | #ifndef TCLAP_VISITOR_H 24 | #define TCLAP_VISITOR_H 25 | 26 | namespace TCLAP { 27 | 28 | /** 29 | * A base class that defines the interface for visitors. 30 | */ 31 | class Visitor 32 | { 33 | public: 34 | 35 | /** 36 | * Constructor. Does nothing. 37 | */ 38 | Visitor() { } 39 | 40 | /** 41 | * Destructor. Does nothing. 42 | */ 43 | virtual ~Visitor() { } 44 | 45 | /** 46 | * Does nothing. Should be overridden by child. 47 | */ 48 | virtual void visit() { } 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/nl-lmp/greedy-additive.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_GREEDY_ADDITIVE_HXX 3 | #define NL_LMP_GREEDY_ADDITIVE_HXX 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include "problem.hxx" 10 | #include "solution.hxx" 11 | 12 | 13 | 14 | namespace nl_lmp 15 | { 16 | 17 | // this function computes only multicut, so it expects already initialized class labeling 18 | template 19 | inline 20 | Solution greedyAdditiveEdgeContraction(Problem const& problem, Solution const& input_labeling) 21 | { 22 | std::vector edge_weights(problem.liftedGraph().numberOfEdges()); 23 | for (size_t e = 0; e < problem.liftedGraph().numberOfEdges(); ++e) 24 | { 25 | auto const v0 = problem.liftedGraph().vertexOfEdge(e, 0); 26 | auto const v1 = problem.liftedGraph().vertexOfEdge(e, 1); 27 | 28 | edge_weights[e] = problem.getPairwiseCutCost(v0, v1, input_labeling[v0].classIndex, input_labeling[v1].classIndex, e) - problem.getPairwiseJoinCost(v0, v1, input_labeling[v0].classIndex, input_labeling[v1].classIndex, e); 29 | } 30 | 31 | auto vertex_cluster_labels = andres::graph::multicut_lifted::greedyAdditiveEdgeContraction(problem.originalGraph(), problem.liftedGraph(), edge_weights); 32 | 33 | Solution solution(problem.numberOfVertices()); 34 | for (size_t i = 0; i < problem.numberOfVertices(); ++i) 35 | solution[i].clusterIndex = vertex_cluster_labels[i]; 36 | 37 | return solution; 38 | } 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/tclap/IgnoreRestVisitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: IgnoreRestVisitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reverved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | #ifndef TCLAP_IGNORE_REST_VISITOR_H 24 | #define TCLAP_IGNORE_REST_VISITOR_H 25 | 26 | #include 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | /** 32 | * A Vistor that tells the CmdLine to begin ignoring arguments after 33 | * this one is parsed. 34 | */ 35 | class IgnoreRestVisitor: public Visitor 36 | { 37 | public: 38 | 39 | /** 40 | * Constructor. 41 | */ 42 | IgnoreRestVisitor() : Visitor() {} 43 | 44 | /** 45 | * Sets Arg::_ignoreRest. 46 | */ 47 | void visit() { Arg::beginIgnoring(); } 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/triangles.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include "andres/graph/graph.hxx" 3 | #include "andres/graph/triangles.hxx" 4 | 5 | 6 | inline void test(bool pred) 7 | { 8 | if(!pred) 9 | throw std::runtime_error("Test failed."); 10 | } 11 | 12 | using namespace andres::graph; 13 | 14 | void testTriangles() 15 | { 16 | andres::graph::Graph<> test_graph; 17 | test_graph.insertVertices(6); 18 | test_graph.insertEdge(0, 1); 19 | test_graph.insertEdge(0, 2); 20 | test_graph.insertEdge(1, 2); 21 | test_graph.insertEdge(1, 4); 22 | test_graph.insertEdge(1, 3); 23 | test_graph.insertEdge(3, 4); 24 | test_graph.insertEdge(2, 4); 25 | test_graph.insertEdge(4, 5); 26 | test_graph.insertEdge(3, 5); 27 | 28 | std::cout << "-- Test graph --" << std::endl; 29 | std::cout << "Number of vertices: " << test_graph.numberOfVertices() << std::endl; 30 | std::cout << "Edges:" << std::endl; 31 | for (size_t e = 0; e < test_graph.numberOfEdges(); e++) 32 | { 33 | auto v0 = test_graph.vertexOfEdge(e, 0); 34 | auto v1 = test_graph.vertexOfEdge(e, 1); 35 | std::cout << v0 << " - " << v1 << std::endl; 36 | } 37 | 38 | auto triangles = findTriangles(test_graph); 39 | 40 | test(triangles.size() == 4); 41 | 42 | std::cout << "Triangles found: " << std::endl; 43 | 44 | for (auto it = triangles.begin(); it != triangles.end(); it++) 45 | { 46 | auto triangle = *it; 47 | std::cout << triangle[0] << " - " << triangle[1] << " - " << triangle[2] << std::endl; 48 | } 49 | } 50 | 51 | int main() 52 | { 53 | testTriangles(); 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /src/andres/graph/unit-test/paths.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/paths.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | struct SubgraphMask { 11 | bool vertex(const size_t v) const { return true; } 12 | bool edge(const size_t e) const { return e != 7; } 13 | }; 14 | 15 | int main() { 16 | typedef andres::graph::Graph<> Graph; 17 | 18 | Graph graph(7); 19 | graph.insertEdge(0, 1); // 0 20 | graph.insertEdge(1, 2); // 1 21 | graph.insertEdge(2, 3); // 2 22 | graph.insertEdge(3, 4); // 3 23 | graph.insertEdge(4, 5); // 4 24 | graph.insertEdge(1, 6); // 5 25 | graph.insertEdge(6, 2); // 6 26 | graph.insertEdge(3, 5); // 7 27 | 28 | { 29 | size_t path[] = {0, 1, 2, 3, 4, 5}; 30 | 31 | std::pair p = andres::graph::findChord(graph, path, path + 6); 32 | test(p.first == true); 33 | test(p.second == 7); 34 | 35 | p = andres::graph::findChord(graph, path, path + 5); 36 | test(p.first == false); 37 | 38 | p = andres::graph::findChord(graph, path + 3, path + 6); 39 | test(p.first == true); 40 | test(p.second == 7); 41 | 42 | p = andres::graph::findChord(graph, SubgraphMask(), path + 3, path + 6, false); 43 | test(p.first == false); 44 | } 45 | { 46 | size_t path[] = {1, 6, 2}; 47 | 48 | std::pair p = andres::graph::findChord(graph, path, path + 3); 49 | test(p.first == true); 50 | test(p.second == 1); 51 | 52 | p = andres::graph::findChord(graph, path, path + 3, true); 53 | test(p.first == false); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /include/nl-lmp/solve-alternating.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_SOLVE_ALTERNATING_HXX 3 | #define NL_LMP_SOLVE_ALTERNATING_HXX 4 | 5 | #include "detail/update-class-labels.hxx" 6 | #include "detail/call-multicut-solver.hxx" 7 | 8 | 9 | 10 | namespace nl_lmp 11 | { 12 | 13 | template 14 | inline 15 | Solution solve_alternating(Problem const& problem, Solution const& input) 16 | { 17 | struct Visitor 18 | { 19 | void operator()(Solution const& solution) const 20 | {} 21 | } visitor; 22 | 23 | return solve_alternating(problem, input, visitor); 24 | } 25 | 26 | template 27 | inline 28 | Solution solve_alternating(Problem const& problem, Solution const& input, VISITOR& visitor) 29 | { 30 | double obj_value = detail::compute_obj_value(problem, input); 31 | 32 | Solution output(input); 33 | 34 | std::cout << "starting objective value: " << std::fixed << obj_value << std::endl; 35 | 36 | double gain_update_labels = .0; 37 | double gain_update_multicut = .0; 38 | do 39 | { 40 | gain_update_multicut = detail::update_multicut(problem, output, output); 41 | 42 | gain_update_labels = detail::update_class_labels(problem, output, output); 43 | 44 | visitor(output); 45 | 46 | if (gain_update_labels + gain_update_multicut > 1e-6) 47 | { 48 | obj_value -= gain_update_labels + gain_update_multicut; 49 | 50 | std::cout << "..gain from updating multicut: " << gain_update_multicut << std::endl; 51 | std::cout << "..gain from updating labels: " << gain_update_labels << std::endl; 52 | std::cout << "..new objective value: " << obj_value << std::endl; 53 | } 54 | } while (gain_update_labels + gain_update_multicut > 1e-6); 55 | 56 | return output; 57 | } 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/tclap/OptionalUnlabeledTracker.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | * 5 | * file: OptionalUnlabeledTracker.h 6 | * 7 | * Copyright (c) 2005, Michael E. Smoot . 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | 24 | #ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H 25 | #define TCLAP_OPTIONAL_UNLABELED_TRACKER_H 26 | 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | class OptionalUnlabeledTracker 32 | { 33 | 34 | public: 35 | 36 | static void check( bool req, const std::string& argName ); 37 | 38 | static void gotOptional() { alreadyOptionalRef() = true; } 39 | 40 | static bool& alreadyOptional() { return alreadyOptionalRef(); } 41 | 42 | private: 43 | 44 | static bool& alreadyOptionalRef() { static bool ct = false; return ct; } 45 | }; 46 | 47 | 48 | inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName ) 49 | { 50 | if ( OptionalUnlabeledTracker::alreadyOptional() ) 51 | throw( SpecificationException( 52 | "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", 53 | argName ) ); 54 | 55 | if ( !req ) 56 | OptionalUnlabeledTracker::gotOptional(); 57 | } 58 | 59 | 60 | } // namespace TCLAP 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/tclap/Constraint.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: Constraint.h 5 | * 6 | * Copyright (c) 2005, Michael E. Smoot 7 | * All rights reverved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | #ifndef TCLAP_CONSTRAINT_H 23 | #define TCLAP_CONSTRAINT_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace TCLAP { 33 | 34 | /** 35 | * The interface that defines the interaction between the Arg and Constraint. 36 | */ 37 | template 38 | class Constraint 39 | { 40 | 41 | public: 42 | /** 43 | * Returns a description of the Constraint. 44 | */ 45 | virtual std::string description() const =0; 46 | 47 | /** 48 | * Returns the short ID for the Constraint. 49 | */ 50 | virtual std::string shortID() const =0; 51 | 52 | /** 53 | * The method used to verify that the value parsed from the command 54 | * line meets the constraint. 55 | * \param value - The value that will be checked. 56 | */ 57 | virtual bool check(const T& value) const =0; 58 | 59 | /** 60 | * Destructor. 61 | * Silences warnings about Constraint being a base class with virtual 62 | * functions but without a virtual destructor. 63 | */ 64 | virtual ~Constraint() { ; } 65 | }; 66 | 67 | } //namespace TCLAP 68 | #endif 69 | -------------------------------------------------------------------------------- /src/command-line-tools/Timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef WITH_TBB 6 | #include "tbb/tbb.h" 7 | #else 8 | #include 9 | #endif //of WITH_TBB 10 | 11 | class Timer 12 | { 13 | public: 14 | Timer(); 15 | 16 | double get_elapsed_seconds() const; 17 | 18 | unsigned long long hours() const; 19 | 20 | unsigned long long minutes() const; 21 | 22 | void reset(); 23 | 24 | double seconds() const; 25 | 26 | void start(); 27 | 28 | void stop(); 29 | 30 | std::string to_string() const; 31 | 32 | private: 33 | double m_seconds; 34 | 35 | #ifdef WITH_TBB 36 | tbb::tick_count m_timeObject; 37 | #else 38 | decltype(std::chrono::high_resolution_clock::now()) m_timeObject; 39 | #endif //of WITH_TBB 40 | }; 41 | 42 | 43 | 44 | 45 | inline Timer::Timer() 46 | { 47 | reset(); 48 | } 49 | 50 | inline double Timer::get_elapsed_seconds() const 51 | { 52 | return m_seconds; 53 | } 54 | 55 | inline unsigned long long Timer::hours() const 56 | { 57 | return static_cast(m_seconds) / 3600ULL; 58 | } 59 | 60 | inline unsigned long long Timer::minutes() const 61 | { 62 | return (static_cast(m_seconds) - hours()*3600ULL) / 60ULL; 63 | } 64 | 65 | inline void Timer::reset() 66 | { 67 | m_seconds = .0; 68 | } 69 | 70 | inline double Timer::seconds() const 71 | { 72 | return m_seconds - 3600.0*hours() - 60.0*minutes(); 73 | } 74 | 75 | inline void Timer::start() 76 | { 77 | #ifdef WITH_TBB 78 | m_timeObject = tbb::tick_count::now(); 79 | #else 80 | m_timeObject = std::chrono::high_resolution_clock::now(); 81 | #endif //of WITH_TBB 82 | } 83 | 84 | inline void Timer::stop() 85 | { 86 | #ifdef WITH_TBB 87 | m_seconds += (tbb::tick_count::now() - m_timeObject).seconds(); 88 | #else 89 | m_seconds += std::chrono::duration_cast>(std::chrono::high_resolution_clock::now() - m_timeObject).count(); 90 | #endif //of WITH_TBB 91 | } 92 | 93 | inline std::string Timer::to_string() const 94 | { 95 | std::ostringstream s(std::ostringstream::out); 96 | 97 | s << hours() << "h " << minutes() << "m " << seconds() << "s"; 98 | 99 | return s.str(); 100 | } -------------------------------------------------------------------------------- /src/tclap/CmdLineOutput.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | * 5 | * file: CmdLineOutput.h 6 | * 7 | * Copyright (c) 2004, Michael E. Smoot 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef TCLAP_CMDLINEOUTPUT_H 24 | #define TCLAP_CMDLINEOUTPUT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace TCLAP { 34 | 35 | class CmdLineInterface; 36 | class ArgException; 37 | 38 | /** 39 | * The interface that any output object must implement. 40 | */ 41 | class CmdLineOutput 42 | { 43 | 44 | public: 45 | 46 | /** 47 | * Virtual destructor. 48 | */ 49 | virtual ~CmdLineOutput() {} 50 | 51 | /** 52 | * Generates some sort of output for the USAGE. 53 | * \param c - The CmdLine object the output is generated for. 54 | */ 55 | virtual void usage(CmdLineInterface& c)=0; 56 | 57 | /** 58 | * Generates some sort of output for the version. 59 | * \param c - The CmdLine object the output is generated for. 60 | */ 61 | virtual void version(CmdLineInterface& c)=0; 62 | 63 | /** 64 | * Generates some sort of output for a failure. 65 | * \param c - The CmdLine object the output is generated for. 66 | * \param e - The ArgException that caused the failure. 67 | */ 68 | virtual void failure( CmdLineInterface& c, 69 | ArgException& e )=0; 70 | 71 | }; 72 | 73 | } //namespace TCLAP 74 | #endif 75 | -------------------------------------------------------------------------------- /src/tclap/HelpVisitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: HelpVisitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reverved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | #ifndef TCLAP_HELP_VISITOR_H 23 | #define TCLAP_HELP_VISITOR_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | /** 32 | * A Visitor object that calls the usage method of the given CmdLineOutput 33 | * object for the specified CmdLine object. 34 | */ 35 | class HelpVisitor: public Visitor 36 | { 37 | private: 38 | /** 39 | * Prevent accidental copying. 40 | */ 41 | HelpVisitor(const HelpVisitor& rhs); 42 | HelpVisitor& operator=(const HelpVisitor& rhs); 43 | 44 | protected: 45 | 46 | /** 47 | * The CmdLine the output will be generated for. 48 | */ 49 | CmdLineInterface* _cmd; 50 | 51 | /** 52 | * The output object. 53 | */ 54 | CmdLineOutput** _out; 55 | 56 | public: 57 | 58 | /** 59 | * Constructor. 60 | * \param cmd - The CmdLine the output will be generated for. 61 | * \param out - The type of output. 62 | */ 63 | HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) 64 | : Visitor(), _cmd( cmd ), _out( out ) { } 65 | 66 | /** 67 | * Calls the usage method of the CmdLineOutput for the 68 | * specified CmdLine. 69 | */ 70 | void visit() { (*_out)->usage(*_cmd); throw ExitException(0); } 71 | 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut-lifted/kernighan-lin.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/complete-graph.hxx" 5 | #include "andres/graph/multicut-lifted/kernighan-lin.hxx" 6 | 7 | 8 | inline void test(bool pred) 9 | { 10 | if(!pred) 11 | throw std::runtime_error("Test failed."); 12 | } 13 | 14 | using namespace andres::graph; 15 | 16 | void testMulticutLifted() 17 | { 18 | Graph<> original_graph(5); 19 | original_graph.insertEdge(0, 1); // 0 20 | original_graph.insertEdge(0, 3); // 1 21 | original_graph.insertEdge(1, 2); // 2 22 | original_graph.insertEdge(1, 4); // 3 23 | original_graph.insertEdge(3, 4); // 4 24 | 25 | CompleteGraph<> lifted_graph(5); 26 | 27 | std::vector weights(10); 28 | weights[lifted_graph.findEdge(0, 1).second] = 10; 29 | weights[lifted_graph.findEdge(0, 2).second] = -1; 30 | weights[lifted_graph.findEdge(0, 3).second] = -1; 31 | weights[lifted_graph.findEdge(0, 4).second] = -1; 32 | weights[lifted_graph.findEdge(1, 2).second] = 10; 33 | weights[lifted_graph.findEdge(1, 3).second] = -1; 34 | weights[lifted_graph.findEdge(1, 4).second] = 4; 35 | weights[lifted_graph.findEdge(2, 3).second] = -1; 36 | weights[lifted_graph.findEdge(2, 4).second] = -1; 37 | weights[lifted_graph.findEdge(3, 4).second] = 10; 38 | 39 | std::vector edge_labels(lifted_graph.numberOfEdges(), 1); 40 | multicut_lifted::kernighanLin(original_graph, lifted_graph, weights, edge_labels, edge_labels); 41 | 42 | test(edge_labels[lifted_graph.findEdge(0, 1).second] == 0); 43 | test(edge_labels[lifted_graph.findEdge(0, 2).second] == 0); 44 | test(edge_labels[lifted_graph.findEdge(0, 3).second] == 1); 45 | test(edge_labels[lifted_graph.findEdge(0, 4).second] == 1); 46 | test(edge_labels[lifted_graph.findEdge(1, 2).second] == 0); 47 | test(edge_labels[lifted_graph.findEdge(1, 3).second] == 1); 48 | test(edge_labels[lifted_graph.findEdge(1, 4).second] == 1); 49 | test(edge_labels[lifted_graph.findEdge(2, 3).second] == 1); 50 | test(edge_labels[lifted_graph.findEdge(2, 4).second] == 1); 51 | test(edge_labels[lifted_graph.findEdge(3, 4).second] == 0); 52 | } 53 | 54 | int main() 55 | { 56 | testMulticutLifted(); 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /include/andres/graph/visitor.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_VISITOR_HXX 3 | #define ANDRES_GRAPH_VISITOR_HXX 4 | 5 | #include 6 | #include 7 | 8 | namespace andres { 9 | namespace graph { 10 | 11 | /// Visitors can be used to follow the indices of vertices and edges. 12 | /// 13 | /// These indices change due to the insetion and removal of vertices and edges. 14 | /// 15 | template 16 | struct IdleGraphVisitor { 17 | typedef S size_type; 18 | 19 | IdleGraphVisitor() {} 20 | void insertVertex(const size_type a) const {} 21 | void insertVertices(const size_type a, const size_type n) const {} 22 | void eraseVertex(const size_type a) const {} 23 | void relabelVertex(const size_type a, const size_type b) const {} 24 | void insertEdge(const size_type a) const {} 25 | void eraseEdge(const size_type a) const {} 26 | void relabelEdge(const size_type a, const size_type b) const {} 27 | }; 28 | 29 | /// Visitors can be used to follow the indices of vertices and edges. 30 | /// 31 | /// These indices change due to the insetion and removal of vertices and edges. 32 | /// 33 | template 34 | struct VerboseGraphVisitor { 35 | typedef S size_type; 36 | 37 | VerboseGraphVisitor() {} 38 | void insertVertex(const size_type a) const 39 | { std::cout << "inserting vertex " << a << std::endl; } 40 | void insertVertices(const size_type a, const size_type n) const 41 | { std::cout << "inserting " << n << " vertices, starting from index " << a << std::endl; } 42 | void eraseVertex(const size_type a) const 43 | { std::cout << "removing vertex " << a << std::endl; } 44 | void relabelVertex(const size_type a, const size_type b) const 45 | { std::cout << "relabeling vertex " << a << ". new label is " << b << std::endl; } 46 | void insertEdge(const size_type a) const 47 | { std::cout << "inserting edge " << a << std::endl; } 48 | void eraseEdge(const size_type a) const 49 | { std::cout << "removing edge " << a << std::endl; } 50 | void relabelEdge(const size_type a, const size_type b) const 51 | { std::cout << "relabeling edge " << a << ". new label is " << b << std::endl; } 52 | }; 53 | 54 | } // namespace graph 55 | } // namespace andres 56 | 57 | #endif // #ifndef ANDRES_GRAPH_VISITOR_HXX 58 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut-lifted/greedy-additive.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "andres/graph/graph.hxx" 5 | #include "andres/graph/complete-graph.hxx" 6 | #include "andres/graph/multicut-lifted/greedy-additive.hxx" 7 | 8 | 9 | inline void test(bool pred) 10 | { 11 | if(!pred) 12 | throw std::runtime_error("Test failed."); 13 | } 14 | 15 | using namespace andres::graph; 16 | 17 | void testMulticutLifted() 18 | { 19 | Graph<> original_graph(5); 20 | original_graph.insertEdge(0, 1); // 0 21 | original_graph.insertEdge(0, 3); // 1 22 | original_graph.insertEdge(1, 2); // 2 23 | original_graph.insertEdge(1, 4); // 3 24 | original_graph.insertEdge(3, 4); // 4 25 | 26 | CompleteGraph<> lifted_graph(5); 27 | 28 | std::vector weights(10); 29 | weights[lifted_graph.findEdge(0, 1).second] = 10; 30 | weights[lifted_graph.findEdge(0, 2).second] = -1; 31 | weights[lifted_graph.findEdge(0, 3).second] = -1; 32 | weights[lifted_graph.findEdge(0, 4).second] = -1; 33 | weights[lifted_graph.findEdge(1, 2).second] = 10; 34 | weights[lifted_graph.findEdge(1, 3).second] = -1; 35 | weights[lifted_graph.findEdge(1, 4).second] = 4; 36 | weights[lifted_graph.findEdge(2, 3).second] = -1; 37 | weights[lifted_graph.findEdge(2, 4).second] = -1; 38 | weights[lifted_graph.findEdge(3, 4).second] = 10; 39 | 40 | std::vector edge_labels(lifted_graph.numberOfEdges(), 1); 41 | multicut_lifted::greedyAdditiveEdgeContraction(original_graph, lifted_graph, weights, edge_labels); 42 | 43 | test(edge_labels[lifted_graph.findEdge(0, 1).second] == 0); 44 | test(edge_labels[lifted_graph.findEdge(0, 2).second] == 0); 45 | test(edge_labels[lifted_graph.findEdge(0, 3).second] == 1); 46 | test(edge_labels[lifted_graph.findEdge(0, 4).second] == 1); 47 | test(edge_labels[lifted_graph.findEdge(1, 2).second] == 0); 48 | test(edge_labels[lifted_graph.findEdge(1, 3).second] == 1); 49 | test(edge_labels[lifted_graph.findEdge(1, 4).second] == 1); 50 | test(edge_labels[lifted_graph.findEdge(2, 3).second] == 1); 51 | test(edge_labels[lifted_graph.findEdge(2, 4).second] == 1); 52 | test(edge_labels[lifted_graph.findEdge(3, 4).second] == 0); 53 | } 54 | 55 | int main() 56 | { 57 | testMulticutLifted(); 58 | 59 | return 0; 60 | } -------------------------------------------------------------------------------- /src/tclap/VersionVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: VersionVisitor.h 6 | * 7 | * Copyright (c) 2003, Michael E. Smoot . 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | 24 | #ifndef TCLAP_VERSION_VISITOR_H 25 | #define TCLAP_VERSION_VISITOR_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace TCLAP { 32 | 33 | /** 34 | * A Vistor that will call the version method of the given CmdLineOutput 35 | * for the specified CmdLine object and then exit. 36 | */ 37 | class VersionVisitor: public Visitor 38 | { 39 | private: 40 | /** 41 | * Prevent accidental copying 42 | */ 43 | VersionVisitor(const VersionVisitor& rhs); 44 | VersionVisitor& operator=(const VersionVisitor& rhs); 45 | 46 | protected: 47 | 48 | /** 49 | * The CmdLine of interest. 50 | */ 51 | CmdLineInterface* _cmd; 52 | 53 | /** 54 | * The output object. 55 | */ 56 | CmdLineOutput** _out; 57 | 58 | public: 59 | 60 | /** 61 | * Constructor. 62 | * \param cmd - The CmdLine the output is generated for. 63 | * \param out - The type of output. 64 | */ 65 | VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) 66 | : Visitor(), _cmd( cmd ), _out( out ) { } 67 | 68 | /** 69 | * Calls the version method of the output object using the 70 | * specified CmdLine. 71 | */ 72 | void visit() { 73 | (*_out)->version(*_cmd); 74 | throw ExitException(0); 75 | } 76 | 77 | }; 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/andres/functional.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_FUNCTIONAL_HXX 3 | #define ANDRES_FUNCTIONAL_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace andres { 10 | 11 | template 12 | struct Identity { 13 | typedef T argument_type; 14 | typedef T result_type; 15 | #ifndef _MSC_VER 16 | constexpr 17 | #endif 18 | result_type operator()(const argument_type& x) const 19 | { return x; } 20 | }; 21 | 22 | template 23 | struct NegativeLogProbabilityRatio { 24 | typedef T argument_type; 25 | typedef U result_type; 26 | 27 | NegativeLogProbabilityRatio(const argument_type epsilon = static_cast(1) / static_cast(255)) 28 | : epsilon_(epsilon), 29 | oneMinusEpsilon_(static_cast(1) - epsilon) 30 | { 31 | if(epsilon <= 0 || epsilon * 2 >= 1) { 32 | throw std::out_of_range("epsilon out of range (0, 0.5)."); 33 | } 34 | } 35 | result_type operator()(argument_type x) const 36 | { 37 | assert(0 <= x && x <= 1); 38 | if(x < epsilon_) { 39 | x = epsilon_; 40 | } 41 | else if(x > oneMinusEpsilon_) { 42 | x = oneMinusEpsilon_; 43 | } 44 | return std::log( (1-x)/x ); 45 | } 46 | 47 | private: 48 | const argument_type epsilon_; 49 | const argument_type oneMinusEpsilon_; 50 | }; 51 | 52 | template 53 | struct NegativeLogProbabilityToInverseProbability { 54 | typedef T argument_type; 55 | typedef U result_type; 56 | 57 | result_type operator()(argument_type x) const { 58 | return 1-::exp(-x ); 59 | } 60 | }; 61 | 62 | template 63 | struct ProbabilityToNegativeLogInverseProbability { 64 | typedef T argument_type; 65 | typedef U result_type; 66 | 67 | result_type operator()(argument_type x) const { 68 | return -::log( 1-x ); 69 | } 70 | }; 71 | 72 | template 73 | struct ProbabilityToLogit { 74 | typedef T argument_type; 75 | typedef U result_type; 76 | 77 | result_type operator()(argument_type x) const { 78 | return ::log( (1-x)/x ); 79 | } 80 | }; 81 | 82 | } // namespace andres 83 | 84 | #endif // #ifndef ANDRES_FUNCTIONAL_HXX 85 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/minimum-spanning-tree.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include "andres/graph/complete-graph.hxx" 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/minimum-spanning-tree.hxx" 5 | 6 | inline void test(bool pred) 7 | { 8 | if(!pred) 9 | throw std::runtime_error("Test failed."); 10 | } 11 | 12 | using namespace andres::graph; 13 | 14 | 15 | void testMST() 16 | { 17 | Graph<> graph; 18 | graph.insertVertices(6); 19 | graph.insertEdge(0, 1); // 0 20 | graph.insertEdge(0, 3); // 1 21 | graph.insertEdge(1, 2); // 2 22 | graph.insertEdge(1, 4); // 3 23 | graph.insertEdge(2, 5); // 4 24 | graph.insertEdge(3, 4); // 5 25 | graph.insertEdge(4, 5); // 6 26 | 27 | std::vector weights(7); 28 | weights[0] = 5; 29 | weights[1] = -20; 30 | weights[2] = 5; 31 | weights[3] = 5; 32 | weights[4] = -20; 33 | weights[5] = 5; 34 | weights[6] = 5; 35 | 36 | std::vector pred(graph.numberOfVertices()); 37 | auto mst_value = findMSTPrim(graph, weights, pred); 38 | 39 | test(mst_value == -25); 40 | 41 | struct mask 42 | { 43 | constexpr bool vertex(std::size_t i) const 44 | { return true; } 45 | 46 | bool edge(std::size_t i) const 47 | { return !(i == 1); } 48 | }; 49 | 50 | mst_value = findMSTPrim(graph, weights, mask(), pred); 51 | 52 | test(mst_value == 0); 53 | } 54 | 55 | void testMSTCompleteGraph() 56 | { 57 | CompleteGraph<> graph(5); 58 | 59 | std::vector weights(10); 60 | weights[graph.findEdge(0, 1).second] = 10; 61 | weights[graph.findEdge(0, 2).second] = -1; 62 | weights[graph.findEdge(0, 3).second] = -1; 63 | weights[graph.findEdge(0, 4).second] = -1; 64 | weights[graph.findEdge(1, 2).second] = 10; 65 | weights[graph.findEdge(1, 3).second] = -1; 66 | weights[graph.findEdge(1, 4).second] = 4; 67 | weights[graph.findEdge(2, 3).second] = -1; 68 | weights[graph.findEdge(2, 4).second] = -1; 69 | weights[graph.findEdge(3, 4).second] = 10; 70 | 71 | std::vector pred(graph.numberOfVertices()); 72 | auto mst_value = findMSTDynamicProgramming(graph, weights, pred); 73 | 74 | test(mst_value == -4); 75 | 76 | struct mask 77 | { 78 | constexpr bool vertex(std::size_t i) const 79 | { return true; } 80 | 81 | bool edge(std::size_t i) const 82 | { return !(i == 5); } 83 | }; 84 | 85 | mst_value = findMSTDynamicProgramming(graph, weights, mask(), pred); 86 | 87 | test(mst_value == 1); 88 | } 89 | 90 | int main() 91 | { 92 | testMST(); 93 | 94 | testMSTCompleteGraph(); 95 | 96 | return 0; 97 | } -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/preprocessing.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/multicut/preprocessing.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testPreprocessing() { 11 | 12 | andres::graph::Graph<> graph; 13 | graph.insertVertices(8); 14 | graph.insertEdge(0, 1); // 0 15 | graph.insertEdge(0, 2); // 1 16 | graph.insertEdge(1, 2); // 2 17 | graph.insertEdge(1, 4); // 3 18 | graph.insertEdge(1, 3); // 4 19 | graph.insertEdge(2, 4); // 5 20 | graph.insertEdge(3, 4); // 6 21 | graph.insertEdge(3, 5); // 7 22 | graph.insertEdge(4, 5); // 8 23 | graph.insertEdge(1, 5); // 9 24 | graph.insertEdge(2, 6); // 10 25 | graph.insertEdge(2, 7); // 11 26 | graph.insertEdge(4, 6); // 12 27 | graph.insertEdge(4, 7); // 13 28 | graph.insertEdge(6, 7); // 14 29 | 30 | std::vector weights(15); 31 | weights[0] = -2; 32 | weights[1] = 1; 33 | weights[2] = 2; 34 | weights[3] = 3; 35 | weights[4] = 3; 36 | weights[5] = -2; 37 | weights[6] = -2; 38 | weights[7] = 2; 39 | weights[8] = 3; 40 | weights[9] = 4; 41 | weights[10] = -2; 42 | weights[11] = -1; 43 | weights[12] = -3; 44 | weights[13] = -4; 45 | weights[14] = 2; 46 | 47 | std::cout << "Input graph:" << std::endl; 48 | std::cout << "|V| = " << graph.numberOfVertices() << ", Edges: " << std::endl; 49 | for (size_t e = 0; e < graph.numberOfEdges(); e++) 50 | std::cout << graph.vertexOfEdge(e, 0) << " - " << graph.vertexOfEdge(e, 1) << " : " << weights[e] << std::endl; 51 | 52 | std::cout << "-- Preprocessing -- " << std::endl; 53 | 54 | auto reduced_instance = andres::graph::multicut::preprocessing(graph, weights); 55 | 56 | auto constr = std::get<3>(reduced_instance); 57 | auto red_graph = std::get<0>(reduced_instance); 58 | auto red_costs = std::get<1>(reduced_instance); 59 | 60 | std::cout << "Contraints:" << std::endl; 61 | for (size_t i = 0; i < constr.size(); i++) 62 | std::cout << constr[i].first.first << " - " << constr[i].first.second << " : " << static_cast(constr[i].second) << std::endl; 63 | 64 | std::cout << "Reduced graph:" << std::endl; 65 | std::cout << "|V| = " << red_graph.numberOfVertices() << ", Edges: " << std::endl; 66 | for (size_t e = 0; e < red_graph.numberOfEdges(); e++) 67 | std::cout << red_graph.vertexOfEdge(e, 0) << " - " << red_graph.vertexOfEdge(e, 1) << " : " << red_costs[e] << std::endl; 68 | 69 | } 70 | 71 | int main() 72 | { 73 | testPreprocessing(); 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/components.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "andres/graph/graph.hxx" 5 | #include "andres/graph/components.hxx" 6 | 7 | inline void test(const bool& pred) { 8 | if(!pred) throw std::runtime_error("Test failed."); 9 | } 10 | 11 | struct SubgraphMask { 12 | bool vertex(const std::size_t v) const { return v != 3; } 13 | bool edge(const std::size_t e) const { return e != 0; } 14 | }; 15 | 16 | template 17 | void testComponents() { 18 | typedef COMPONENTS Components; 19 | typedef typename Components::Graph Graph; 20 | 21 | Graph graph(10); 22 | graph.insertEdge(0, 1); 23 | graph.insertEdge(2, 3); 24 | graph.insertEdge(3, 4); 25 | graph.insertEdge(5, 6); 26 | graph.insertEdge(5, 7); 27 | graph.insertEdge(6, 8); 28 | graph.insertEdge(7, 8); 29 | 30 | Components components; 31 | components.build(graph); 32 | 33 | test(components.areConnected(0, 1)); 34 | test(components.areConnected(2, 3)); 35 | test(components.areConnected(3, 4)); 36 | test(components.areConnected(5, 6)); 37 | test(components.areConnected(6, 7)); 38 | test(components.areConnected(7, 8)); 39 | test(!components.areConnected(0, 2)); 40 | test(!components.areConnected(0, 5)); 41 | test(!components.areConnected(0, 9)); 42 | test(!components.areConnected(2, 5)); 43 | test(!components.areConnected(2, 9)); 44 | test(!components.areConnected(5, 9)); 45 | 46 | components.build(graph, SubgraphMask()); 47 | 48 | test(components.areConnected(5, 6)); 49 | test(components.areConnected(6, 7)); 50 | test(components.areConnected(7, 8)); 51 | test(!components.areConnected(0, 1)); 52 | test(!components.areConnected(0, 2)); 53 | test(!components.areConnected(0, 4)); 54 | test(!components.areConnected(0, 5)); 55 | test(!components.areConnected(0, 9)); 56 | test(!components.areConnected(1, 2)); 57 | test(!components.areConnected(1, 4)); 58 | test(!components.areConnected(1, 5)); 59 | test(!components.areConnected(1, 9)); 60 | test(!components.areConnected(2, 4)); 61 | test(!components.areConnected(2, 5)); 62 | test(!components.areConnected(2, 9)); 63 | test(!components.areConnected(4, 5)); 64 | test(!components.areConnected(4, 9)); 65 | test(!components.areConnected(5, 9)); 66 | } 67 | 68 | int main() { 69 | typedef andres::graph::Graph<> Graph; 70 | typedef andres::graph::ComponentsBySearch ComponentsBySearch; 71 | typedef andres::graph::ComponentsByPartition ComponentsByPartition; 72 | 73 | testComponents(); 74 | testComponents(); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /include/nl-lmp/detail/call-multicut-solver.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_CALL_MULTICUT_SOLVER_HXX 3 | #define NL_LMP_CALL_MULTICUT_SOLVER_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "compute-objective.hxx" 10 | 11 | 12 | 13 | namespace nl_lmp 14 | { 15 | 16 | namespace detail 17 | { 18 | 19 | template 20 | inline 21 | std::vector call_kernighanLin(Problem const& problem, ECA const& edge_weights, VERTEXLABELS const& vertex_cluster_labels) 22 | { 23 | return andres::graph::multicut_lifted::kernighanLin(problem.originalGraph(), problem.liftedGraph(), edge_weights, vertex_cluster_labels); 24 | } 25 | 26 | template 27 | inline 28 | std::vector call_kernighanLin(Problem> const& problem, ECA const& edge_weights, VERTEXLABELS const& vertex_cluster_labels) 29 | { 30 | return andres::graph::multicut::kernighanLin(problem.originalGraph(), edge_weights, vertex_cluster_labels); 31 | } 32 | 33 | template 34 | inline 35 | double update_multicut(Problem const& problem, Solution const& input, Solution& output) 36 | { 37 | // given class labels frozen we're essentially optimizing the multicut objective 38 | // therefore, I just make use of existing Kernighan-Lin code 39 | // this is also much faster, because accessing 'edge_weights' is way faster 40 | 41 | auto energy = compute_obj_value(problem, input); 42 | 43 | std::vector vertex_cluster_labels(problem.numberOfVertices()); 44 | for (size_t v = 0; v < problem.numberOfVertices(); ++v) 45 | { 46 | vertex_cluster_labels[v] = input[v].clusterIndex; 47 | 48 | output[v].classIndex = input[v].classIndex; 49 | } 50 | 51 | std::vector edge_weights(problem.liftedGraph().numberOfEdges()); 52 | for (size_t e = 0; e < problem.liftedGraph().numberOfEdges(); ++e) 53 | { 54 | auto const v0 = problem.liftedGraph().vertexOfEdge(e, 0); 55 | auto const v1 = problem.liftedGraph().vertexOfEdge(e, 1); 56 | 57 | edge_weights[e] = problem.getPairwiseCutCost(v0, v1, input[v0].classIndex, input[v1].classIndex, e) - problem.getPairwiseJoinCost(v0, v1, input[v0].classIndex, input[v1].classIndex, e); 58 | } 59 | 60 | auto new_vertex_labels = call_kernighanLin(problem, edge_weights, vertex_cluster_labels); 61 | 62 | for (size_t v = 0; v < problem.numberOfVertices(); ++v) 63 | output[v].clusterIndex = new_vertex_labels[v]; 64 | 65 | double energy_after = compute_obj_value(problem, output); 66 | 67 | return energy - energy_after; 68 | } 69 | 70 | } 71 | 72 | } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/cut-vertices.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include "andres/graph/complete-graph.hxx" 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/cut-vertices.hxx" 5 | 6 | 7 | inline void test(bool pred) 8 | { 9 | if(!pred) 10 | throw std::runtime_error("Test failed."); 11 | } 12 | 13 | using namespace andres::graph; 14 | 15 | void test() 16 | { 17 | Graph<> graph(8); 18 | graph.insertEdge(0, 1); 19 | graph.insertEdge(0, 2); 20 | graph.insertEdge(1, 3); 21 | graph.insertEdge(2, 4); 22 | graph.insertEdge(2, 5); 23 | graph.insertEdge(4, 6); 24 | graph.insertEdge(5, 6); 25 | 26 | std::vector isCutVertex(graph.numberOfVertices()); 27 | findCutVertices(graph, isCutVertex); 28 | 29 | test(isCutVertex[0] == true); 30 | test(isCutVertex[1] == true); 31 | test(isCutVertex[2] == true); 32 | test(isCutVertex[3] == false); 33 | test(isCutVertex[4] == false); 34 | test(isCutVertex[5] == false); 35 | test(isCutVertex[6] == false); 36 | test(isCutVertex[7] == false); 37 | 38 | 39 | struct mask 40 | { 41 | bool vertex(std::size_t i) const 42 | { 43 | return !(i == 4 || i == 5 || i == 6); 44 | } 45 | 46 | bool edge(std::size_t i) const 47 | { 48 | return true; 49 | } 50 | }; 51 | 52 | findCutVertices(graph, mask(), isCutVertex); 53 | 54 | test(isCutVertex[0] == true); 55 | test(isCutVertex[1] == true); 56 | test(isCutVertex[2] == false); 57 | test(isCutVertex[3] == false); 58 | test(isCutVertex[4] == false); 59 | test(isCutVertex[5] == false); 60 | test(isCutVertex[6] == false); 61 | } 62 | 63 | void testCompleteGraph() 64 | { 65 | CompleteGraph<> graph(5); 66 | 67 | std::vector isCutVertex(graph.numberOfVertices()); 68 | findCutVertices(graph, isCutVertex); 69 | 70 | test(isCutVertex[0] == false); 71 | test(isCutVertex[1] == false); 72 | test(isCutVertex[2] == false); 73 | test(isCutVertex[3] == false); 74 | test(isCutVertex[4] == false); 75 | 76 | struct mask 77 | { 78 | bool vertex(std::size_t i) const 79 | { 80 | return true; 81 | } 82 | 83 | bool edge(std::size_t i) const 84 | { 85 | return !(i == 1 || i == 2 || i == 3 || i == 5 || i == 6); 86 | } 87 | }; 88 | 89 | findCutVertices(graph, mask(), isCutVertex); 90 | 91 | test(isCutVertex[0] == false); 92 | test(isCutVertex[1] == true); 93 | test(isCutVertex[2] == true); 94 | test(isCutVertex[3] == false); 95 | test(isCutVertex[4] == false); 96 | } 97 | 98 | int main() 99 | { 100 | test(); 101 | 102 | testCompleteGraph(); 103 | 104 | return 0; 105 | } -------------------------------------------------------------------------------- /include/andres/graph/hdf5/complete-graph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_COMPLETE_GRAPH_HDF5_HXX 3 | #define ANDRES_GRAPH_COMPLETE_GRAPH_HDF5_HXX 4 | 5 | #include 6 | #include 7 | 8 | #include "hdf5.hxx" 9 | #include "../complete-graph.hxx" 10 | 11 | namespace andres { 12 | namespace graph { 13 | namespace hdf5 { 14 | 15 | template 16 | struct GraphTraitsHDF5 > { 17 | static const int ID; 18 | }; 19 | template 20 | const int GraphTraitsHDF5 >::ID = 10002; 21 | 22 | template 23 | void save(const hid_t, const std::string&, const CompleteGraph& graph); 24 | 25 | template 26 | void load(const hid_t, const std::string&, CompleteGraph& graph); 27 | 28 | template 29 | void 30 | save( 31 | const hid_t parentHandle, 32 | const std::string& graphName, 33 | const CompleteGraph& graph 34 | ) { 35 | typedef CompleteGraph Graph; 36 | hdf5::HandleCheck handleCheck; 37 | hid_t groupHandle = openGroup(parentHandle, graphName, true); 38 | std::string sError; 39 | try { 40 | save(groupHandle, "number-of-vertices", graph.numberOfVertices()); 41 | int ID = GraphTraitsHDF5::ID; 42 | save(groupHandle, "graph-type-id", ID); 43 | } catch (std::exception& e) { 44 | sError = e.what(); 45 | } 46 | closeGroup(groupHandle); 47 | if(!sError.empty()) { 48 | throw std::runtime_error("error saving complete graph: " + sError); 49 | } 50 | } 51 | 52 | template 53 | void 54 | load( 55 | const hid_t parentHandle, 56 | const std::string& graphName, 57 | CompleteGraph& graph 58 | ) { 59 | typedef CompleteGraph CompleteGraph; 60 | hdf5::HandleCheck handleCheck; 61 | hid_t groupHandle = openGroup(parentHandle, graphName); 62 | std::string sError; 63 | try { 64 | { 65 | int ID; 66 | load(groupHandle, "graph-type-id", ID); 67 | if(ID != GraphTraitsHDF5::ID) { 68 | sError = "Stored graph type is not a CompleteGraph."; 69 | goto cleanup; 70 | } 71 | } 72 | std::size_t numberOfVertices; 73 | load(groupHandle, "number-of-vertices", numberOfVertices); 74 | graph.assign(numberOfVertices); 75 | } 76 | catch(std::exception& e) { 77 | sError = e.what(); 78 | } 79 | 80 | cleanup: 81 | closeGroup(groupHandle); 82 | if(!sError.empty()) { 83 | throw std::runtime_error("error loading complete graph: " + sError); 84 | } 85 | } 86 | 87 | } //namespace hdf 88 | } //namespace graph 89 | } //namespace andres 90 | 91 | #endif // #ifndef ANDRES_GRAPH_COMPLETE_GRAPH_HDF5_HXX 92 | -------------------------------------------------------------------------------- /include/andres/graph/triangles.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_TRIANGLES_HXX 3 | #define ANDRES_GRAPH_TRIANGLES_HXX 4 | 5 | namespace andres { 6 | namespace graph { 7 | 8 | // Efficiently list all triangles of a graph 9 | // with the "forward" algorithm from [1]. 10 | // 11 | // [1] Schank, Wagner. Finding, Counting and Listing all 12 | // Triangles in Large Graphs, An Experimental Study. 2005 13 | // 14 | // Implementation by Jan-Hendrik Lange (c) 2018 15 | // 16 | // Output: Vector of vertex triples 17 | // 18 | template 19 | std::vector> findTriangles(const GRAPH& graph) 20 | { 21 | std::vector> triangles; 22 | 23 | // get degrees of all vertices 24 | std::vector vertices(graph.numberOfVertices()); 25 | std::vector index(graph.numberOfVertices()); 26 | std::vector degrees(graph.numberOfVertices()); 27 | for (size_t v = 0; v < graph.numberOfVertices(); v++) 28 | { 29 | vertices[v] = v; 30 | degrees[v] = graph.numberOfEdgesFromVertex(v); 31 | } 32 | 33 | // sort vertices according to degrees 34 | std::sort(vertices.begin(), vertices.end(), [&] (const size_t& a, const size_t& b) {return (degrees[a] < degrees[b]);}); 35 | 36 | // determine mapping of vertices to indices 37 | for (size_t i = 0; i < graph.numberOfVertices(); i++) 38 | index[vertices[i]] = i; 39 | 40 | // dynamic adjacency data 41 | std::vector> adj(graph.numberOfVertices()); 42 | 43 | // MAIN LOOP 44 | for (size_t i = 0; i < graph.numberOfVertices(); i++) 45 | { 46 | auto u = vertices[i]; 47 | // iterate over neighbors 48 | for (auto it = graph.adjacenciesFromVertexBegin(u); it != graph.adjacenciesFromVertexEnd(u); it++) 49 | { 50 | auto v = it->vertex(); 51 | auto j = index[v]; 52 | 53 | // only consider smaller indices 54 | if (i < j) 55 | { 56 | // find intersection in adjacency lists 57 | auto it_u = adj[i].begin(); 58 | auto it_v = adj[j].begin(); 59 | 60 | while (it_u != adj[i].end() && it_v != adj[j].end()) 61 | { 62 | if (*it_u == *it_v) 63 | { 64 | auto k = *it_u; 65 | std::vector triangle{u,v,vertices[k]}; 66 | triangles.push_back(triangle); 67 | it_u++; 68 | it_v++; 69 | } 70 | else if (*it_u < *it_v) 71 | it_u++; 72 | else if (*it_v < *it_u) 73 | it_v++; 74 | } 75 | 76 | adj[j].push_back(i); 77 | } 78 | } 79 | } 80 | 81 | return triangles; 82 | } 83 | 84 | } 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/tclap/ArgTraits.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: ArgTraits.h 6 | * 7 | * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | // This is an internal tclap file, you should probably not have to 24 | // include this directly 25 | 26 | #ifndef TCLAP_ARGTRAITS_H 27 | #define TCLAP_ARGTRAITS_H 28 | 29 | namespace TCLAP { 30 | 31 | // We use two empty structs to get compile type specialization 32 | // function to work 33 | 34 | /** 35 | * A value like argument value type is a value that can be set using 36 | * operator>>. This is the default value type. 37 | */ 38 | struct ValueLike { 39 | typedef ValueLike ValueCategory; 40 | virtual ~ValueLike() {} 41 | }; 42 | 43 | /** 44 | * A string like argument value type is a value that can be set using 45 | * operator=(string). Usefull if the value type contains spaces which 46 | * will be broken up into individual tokens by operator>>. 47 | */ 48 | struct StringLike { 49 | virtual ~StringLike() {} 50 | }; 51 | 52 | /** 53 | * A class can inherit from this object to make it have string like 54 | * traits. This is a compile time thing and does not add any overhead 55 | * to the inherenting class. 56 | */ 57 | struct StringLikeTrait { 58 | typedef StringLike ValueCategory; 59 | virtual ~StringLikeTrait() {} 60 | }; 61 | 62 | /** 63 | * A class can inherit from this object to make it have value like 64 | * traits. This is a compile time thing and does not add any overhead 65 | * to the inherenting class. 66 | */ 67 | struct ValueLikeTrait { 68 | typedef ValueLike ValueCategory; 69 | virtual ~ValueLikeTrait() {} 70 | }; 71 | 72 | /** 73 | * Arg traits are used to get compile type specialization when parsing 74 | * argument values. Using an ArgTraits you can specify the way that 75 | * values gets assigned to any particular type during parsing. The two 76 | * supported types are StringLike and ValueLike. 77 | */ 78 | template 79 | struct ArgTraits { 80 | typedef typename T::ValueCategory ValueCategory; 81 | virtual ~ArgTraits() {} 82 | //typedef ValueLike ValueCategory; 83 | }; 84 | 85 | #endif 86 | 87 | } // namespace 88 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/kernighan-lin.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "andres/graph/multicut/kernighan-lin.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testMulticut() { 11 | // a simple weighted graph in which an optimal multicut is non-trivial 12 | 13 | andres::graph::Graph<> graph; 14 | graph.insertVertices(6); 15 | graph.insertEdge(0, 1); // 0 16 | graph.insertEdge(0, 3); // 1 17 | graph.insertEdge(1, 2); // 2 18 | graph.insertEdge(1, 4); // 3 19 | graph.insertEdge(2, 5); // 4 20 | graph.insertEdge(3, 4); // 5 21 | graph.insertEdge(4, 5); // 6 22 | 23 | std::vector weights(7); 24 | weights[0] = 5; 25 | weights[1] = -20; 26 | weights[2] = 5; 27 | weights[3] = 5; 28 | weights[4] = -20; 29 | weights[5] = 5; 30 | weights[6] = 5; 31 | 32 | std::vector edge_labels(graph.numberOfEdges()); 33 | andres::graph::multicut::kernighanLin(graph, weights, edge_labels, edge_labels); 34 | 35 | test(edge_labels[0] == 0); 36 | test(edge_labels[1] == 1); 37 | test(edge_labels[2] == 0); 38 | test(edge_labels[3] == 1); 39 | test(edge_labels[4] == 1); 40 | test(edge_labels[5] == 0); 41 | test(edge_labels[6] == 0); 42 | } 43 | 44 | void testMulticutCompleteGraph() { 45 | // a simple weighted complete graph in which an optimal multicut is non-trivial 46 | 47 | andres::graph::CompleteGraph<> graph(5); 48 | 49 | std::vector weights(10); 50 | weights[graph.findEdge(0, 1).second] = 10; 51 | weights[graph.findEdge(0, 2).second] = -1; 52 | weights[graph.findEdge(0, 3).second] = -1; 53 | weights[graph.findEdge(0, 4).second] = -1; 54 | weights[graph.findEdge(1, 2).second] = 10; 55 | weights[graph.findEdge(1, 3).second] = -1; 56 | weights[graph.findEdge(1, 4).second] = 4; 57 | weights[graph.findEdge(2, 3).second] = -1; 58 | weights[graph.findEdge(2, 4).second] = -1; 59 | weights[graph.findEdge(3, 4).second] = 10; 60 | 61 | std::vector edge_labels(graph.numberOfEdges(), 1); 62 | andres::graph::multicut::kernighanLin(graph, weights, edge_labels, edge_labels); 63 | 64 | test(edge_labels[graph.findEdge(0, 1).second] == 0); 65 | test(edge_labels[graph.findEdge(0, 2).second] == 0); 66 | test(edge_labels[graph.findEdge(0, 3).second] == 1); 67 | test(edge_labels[graph.findEdge(0, 4).second] == 1); 68 | test(edge_labels[graph.findEdge(1, 2).second] == 0); 69 | test(edge_labels[graph.findEdge(1, 3).second] == 1); 70 | test(edge_labels[graph.findEdge(1, 4).second] == 1); 71 | test(edge_labels[graph.findEdge(2, 3).second] == 1); 72 | test(edge_labels[graph.findEdge(2, 4).second] == 1); 73 | test(edge_labels[graph.findEdge(3, 4).second] == 0); 74 | } 75 | 76 | int main() 77 | { 78 | testMulticut(); 79 | 80 | testMulticutCompleteGraph(); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/ilp.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/ilp/gurobi.hxx" 4 | #include "andres/graph/multicut/ilp.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testMulticut() { 11 | // a simple weighted graph in which an optimal multicut is non-trivial 12 | 13 | andres::graph::Graph<> graph; 14 | graph.insertVertices(6); 15 | graph.insertEdge(0, 1); // 0 16 | graph.insertEdge(0, 3); // 1 17 | graph.insertEdge(1, 2); // 2 18 | graph.insertEdge(1, 4); // 3 19 | graph.insertEdge(2, 5); // 4 20 | graph.insertEdge(3, 4); // 5 21 | graph.insertEdge(4, 5); // 6 22 | 23 | std::vector weights(7); 24 | weights[0] = 5; 25 | weights[1] = -20; 26 | weights[2] = 5; 27 | weights[3] = 5; 28 | weights[4] = -20; 29 | weights[5] = 5; 30 | weights[6] = 5; 31 | 32 | std::vector edge_labels(graph.numberOfEdges(), 1); 33 | andres::graph::multicut::ilp(graph, weights, edge_labels, edge_labels); 34 | 35 | test(edge_labels[0] == 0); 36 | test(edge_labels[1] == 1); 37 | test(edge_labels[2] == 0); 38 | test(edge_labels[3] == 1); 39 | test(edge_labels[4] == 1); 40 | test(edge_labels[5] == 0); 41 | test(edge_labels[6] == 0); 42 | } 43 | 44 | void testMulticutCompleteGraph() { 45 | // a simple weighted complete graph in which an optimal multicut is non-trivial 46 | 47 | andres::graph::CompleteGraph<> graph(5); 48 | 49 | std::vector weights(10); 50 | weights[graph.findEdge(0, 1).second] = 10; 51 | weights[graph.findEdge(0, 2).second] = -1; 52 | weights[graph.findEdge(0, 3).second] = -1; 53 | weights[graph.findEdge(0, 4).second] = -1; 54 | weights[graph.findEdge(1, 2).second] = 10; 55 | weights[graph.findEdge(1, 3).second] = -1; 56 | weights[graph.findEdge(1, 4).second] = 4; 57 | weights[graph.findEdge(2, 3).second] = -1; 58 | weights[graph.findEdge(2, 4).second] = -1; 59 | weights[graph.findEdge(3, 4).second] = 10; 60 | 61 | std::vector edge_labels(graph.numberOfEdges(), 1); 62 | andres::graph::multicut::ilp(graph, weights, edge_labels, edge_labels); 63 | 64 | test(edge_labels[graph.findEdge(0, 1).second] == 0); 65 | test(edge_labels[graph.findEdge(0, 2).second] == 0); 66 | test(edge_labels[graph.findEdge(0, 3).second] == 1); 67 | test(edge_labels[graph.findEdge(0, 4).second] == 1); 68 | test(edge_labels[graph.findEdge(1, 2).second] == 0); 69 | test(edge_labels[graph.findEdge(1, 3).second] == 1); 70 | test(edge_labels[graph.findEdge(1, 4).second] == 1); 71 | test(edge_labels[graph.findEdge(2, 3).second] == 1); 72 | test(edge_labels[graph.findEdge(2, 4).second] == 1); 73 | test(edge_labels[graph.findEdge(3, 4).second] == 0); 74 | } 75 | 76 | int main() 77 | { 78 | testMulticut(); 79 | 80 | testMulticutCompleteGraph(); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut/ilp-callback.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/ilp/gurobi-callback.hxx" 4 | #include "andres/graph/multicut/ilp-callback.hxx" 5 | 6 | inline void test(const bool& pred) { 7 | if(!pred) throw std::runtime_error("Test failed."); 8 | } 9 | 10 | void testMulticut() { 11 | // a simple weighted graph in which an optimal multicut is non-trivial 12 | 13 | andres::graph::Graph<> graph; 14 | graph.insertVertices(6); 15 | graph.insertEdge(0, 1); // 0 16 | graph.insertEdge(0, 3); // 1 17 | graph.insertEdge(1, 2); // 2 18 | graph.insertEdge(1, 4); // 3 19 | graph.insertEdge(2, 5); // 4 20 | graph.insertEdge(3, 4); // 5 21 | graph.insertEdge(4, 5); // 6 22 | 23 | std::vector weights(7); 24 | weights[0] = 5; 25 | weights[1] = -20; 26 | weights[2] = 5; 27 | weights[3] = 5; 28 | weights[4] = -20; 29 | weights[5] = 5; 30 | weights[6] = 5; 31 | 32 | std::vector edge_labels(graph.numberOfEdges(), 1); 33 | andres::graph::multicut::ilp_callback(graph, weights, edge_labels, edge_labels); 34 | 35 | test(edge_labels[0] == 0); 36 | test(edge_labels[1] == 1); 37 | test(edge_labels[2] == 0); 38 | test(edge_labels[3] == 1); 39 | test(edge_labels[4] == 1); 40 | test(edge_labels[5] == 0); 41 | test(edge_labels[6] == 0); 42 | } 43 | 44 | void testMulticutCompleteGraph() { 45 | // a simple weighted complete graph in which an optimal multicut is non-trivial 46 | 47 | andres::graph::CompleteGraph<> graph(5); 48 | 49 | std::vector weights(10); 50 | weights[graph.findEdge(0, 1).second] = 10; 51 | weights[graph.findEdge(0, 2).second] = -1; 52 | weights[graph.findEdge(0, 3).second] = -1; 53 | weights[graph.findEdge(0, 4).second] = -1; 54 | weights[graph.findEdge(1, 2).second] = 10; 55 | weights[graph.findEdge(1, 3).second] = -1; 56 | weights[graph.findEdge(1, 4).second] = 4; 57 | weights[graph.findEdge(2, 3).second] = -1; 58 | weights[graph.findEdge(2, 4).second] = -1; 59 | weights[graph.findEdge(3, 4).second] = 10; 60 | 61 | std::vector edge_labels(graph.numberOfEdges(), 1); 62 | andres::graph::multicut::ilp_callback(graph, weights, edge_labels, edge_labels); 63 | 64 | test(edge_labels[graph.findEdge(0, 1).second] == 0); 65 | test(edge_labels[graph.findEdge(0, 2).second] == 0); 66 | test(edge_labels[graph.findEdge(0, 3).second] == 1); 67 | test(edge_labels[graph.findEdge(0, 4).second] == 1); 68 | test(edge_labels[graph.findEdge(1, 2).second] == 0); 69 | test(edge_labels[graph.findEdge(1, 3).second] == 1); 70 | test(edge_labels[graph.findEdge(1, 4).second] == 1); 71 | test(edge_labels[graph.findEdge(2, 3).second] == 1); 72 | test(edge_labels[graph.findEdge(2, 4).second] == 1); 73 | test(edge_labels[graph.findEdge(3, 4).second] == 0); 74 | } 75 | 76 | int main() 77 | { 78 | testMulticut(); 79 | 80 | testMulticutCompleteGraph(); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /include/andres/graph/hdf5/grid-graph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_GRID_GRAPH_HDF5_HXX 3 | #define ANDRES_GRAPH_GRID_GRAPH_HDF5_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "hdf5.hxx" 11 | #include "../grid-graph.hxx" 12 | 13 | namespace andres { 14 | namespace graph { 15 | namespace hdf5 { 16 | 17 | template 18 | struct GraphTraitsHDF5 > { 19 | static const int ID; 20 | }; 21 | template 22 | const int GraphTraitsHDF5 >::ID = 10003; 23 | 24 | template 25 | void save(const hid_t, const std::string&, const GridGraph&); 26 | 27 | template 28 | void load(const hid_t, const std::string&, GridGraph&); 29 | 30 | template 31 | void 32 | save( 33 | const hid_t parentHandle, 34 | const std::string& graphName, 35 | const GridGraph& graph 36 | ) { 37 | HandleCheck handleCheck; 38 | hid_t groupHandle = openGroup(parentHandle, graphName, true); 39 | 40 | std::string sError; 41 | try { 42 | save(groupHandle, "graph-type-id", GraphTraitsHDF5 >::ID); 43 | 44 | std::array shape; 45 | for(std::size_t i=0; i 59 | void 60 | load( 61 | const hid_t parentHandle, 62 | const std::string& graphName, 63 | GridGraph& graph 64 | ) { 65 | HandleCheck handleCheck; 66 | hid_t groupHandle = openGroup(parentHandle, graphName); 67 | 68 | std::string sError; 69 | try { 70 | int id; 71 | load(groupHandle, "graph-type-id", id); 72 | if(id != GraphTraitsHDF5 >::ID) { 73 | sError = "graph type id mismatch."; 74 | goto cleanup; 75 | } 76 | 77 | std::vector nDims; 78 | std::vector shape; 79 | load(groupHandle, "shape", nDims, shape); 80 | if(nDims.size() != 1 || nDims[0] != D) { 81 | sError = "shape mismatch."; 82 | goto cleanup; 83 | } 84 | 85 | typename GridGraph::VertexCoordinate vc; 86 | std::copy(shape.begin(), shape.end(), vc.begin()); 87 | graph.assign(vc); 88 | } catch(std::exception& e) { 89 | sError = "failed to load grid graph: " + std::string(e.what()); 90 | goto cleanup; 91 | } 92 | 93 | cleanup: 94 | closeGroup(groupHandle); 95 | if(!sError.empty()) { 96 | throw std::runtime_error("error loading grid graph: " + sError); 97 | } 98 | } 99 | 100 | } //namespace hdf 101 | } //namespace graph 102 | } //namespace andres 103 | 104 | #endif // #ifndef ANDRES_GRAPH_GRID_GRAPH_HDF5_HXX 105 | -------------------------------------------------------------------------------- /include/andres/graph/multicut/mutex-watershed.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_MULTICUT_MUTEX_WATERSHED_HXX 3 | #define ANDRES_GRAPH_MULTICUT_MUTEX_WATERSHED_HXX 4 | 5 | #include 6 | #include 7 | 8 | #include "andres/partition.hxx" 9 | 10 | namespace andres { 11 | namespace graph { 12 | namespace multicut { 13 | 14 | // Construct a heuristic solution for the Minimum Cost Multicut Problem 15 | // by the mutex watershed algorithm [1]. 16 | // 17 | // [1] "The Mutex Watershed: Efficient, Parameter-Free Image Partitioning" 18 | // S. Wolf, C. Pape, A. Bailoni, N. Rahaman, A. Kreshuk, U. Kothe, F. A. Hamprecht 19 | // The European Conference on Computer Vision (ECCV), 2018 20 | // 21 | // Modified implementation by Jan-Hendrik Lange (c) 2018 22 | // 23 | template 24 | void mutexWatershed(GRAPH const& graph, ECA const& edge_costs, ELA& output_labels) 25 | { 26 | // sort edges for decreasing absolute costs 27 | std::vector edges(graph.numberOfEdges()); 28 | std::iota(edges.begin(), edges.end(), 0); 29 | std::sort(edges.begin(), edges.end(), [&](const size_t a, const size_t b){ 30 | return std::abs(edge_costs[a]) > std::abs(edge_costs[b]); 31 | }); 32 | 33 | std::vector> mutexes(graph.numberOfVertices()); 34 | andres::Partition partition(graph.numberOfVertices()); 35 | 36 | /// MAIN LOOP 37 | for (auto const e : edges) 38 | { 39 | auto u = graph.vertexOfEdge(e, 0); 40 | auto v = graph.vertexOfEdge(e, 1); 41 | 42 | auto ru = partition.find(u); 43 | auto rv = partition.find(v); 44 | 45 | // if nodes are in the same component 46 | if (ru == rv) 47 | continue; 48 | 49 | // if mutex constraint is active 50 | if (mutexes[ru].find(rv) != mutexes[ru].end()) 51 | continue; 52 | 53 | // otherwise insert mutex constraint for negative edge 54 | if (edge_costs[e] < 0) 55 | { 56 | mutexes[ru].insert(rv); 57 | mutexes[rv].insert(ru); 58 | } 59 | // otherwise merge components for positive edge 60 | else 61 | { 62 | partition.merge(u, v); 63 | auto ruv = partition.find(ru); 64 | // update mutex representatives 65 | if (ruv != ru) 66 | { 67 | mutexes[ruv].insert(mutexes[ru].begin(), mutexes[ru].end()); 68 | for (auto & m : mutexes[ru]) 69 | { 70 | mutexes[m].erase(ru); 71 | mutexes[m].insert(ruv); 72 | } 73 | } 74 | if (ruv != rv) 75 | { 76 | mutexes[ruv].insert(mutexes[rv].begin(), mutexes[rv].end()); 77 | for (auto & m : mutexes[rv]) 78 | { 79 | mutexes[m].erase(rv); 80 | mutexes[m].insert(ruv); 81 | } 82 | } 83 | } 84 | } 85 | 86 | // determine output labels 87 | for (size_t e = 0; e < graph.numberOfEdges(); e++) 88 | output_labels[e] = partition.find(graph.vertexOfEdge(e, 0)) != partition.find(graph.vertexOfEdge(e, 1)); 89 | } 90 | 91 | } // namespace multicut 92 | } // namespace graph 93 | } // namespace andres 94 | 95 | #endif // #ifndef ANDRES_GRAPH_MULTICUT_MUTEX_WATERSHED_HXX -------------------------------------------------------------------------------- /src/command-line-tools/utils.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef UTILS_HXX 3 | #define UTILS_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | template 10 | inline 11 | void vertexToEdgeLabels(const GRAPH& graph, const VLA& vertex_labels, ELA& edge_labels) 12 | { 13 | for (std::size_t i = 0; i < graph.numberOfEdges(); ++i) 14 | { 15 | auto v0 = graph.vertexOfEdge(i, 0); 16 | auto v1 = graph.vertexOfEdge(i, 1); 17 | 18 | edge_labels[i] = vertex_labels[v0] == vertex_labels[v1] ? 0 : 1; 19 | } 20 | } 21 | 22 | template 23 | inline 24 | void vertexToEdgeLabels(const ORIGGRAPH& original_graph, const LIFTGRAPH& lifted_graph, const VLA& vertex_labels, ELA& edge_labels) 25 | { 26 | std::fill(edge_labels.begin(), edge_labels.end(), 1); 27 | 28 | std::stack S; 29 | std::vector visited(original_graph.numberOfVertices()); 30 | VLA new_labels(original_graph.numberOfVertices()); 31 | 32 | // coonectedness on the original graph 33 | for (std::size_t i = 0, cnt = 0; i < original_graph.numberOfVertices(); ++i) 34 | if (!visited[i]) 35 | { 36 | S.push(i); 37 | visited[i] = 1; 38 | 39 | auto label = vertex_labels[i]; 40 | 41 | new_labels[i] = cnt; 42 | 43 | while (!S.empty()) 44 | { 45 | auto v = S.top(); 46 | S.pop(); 47 | 48 | for (auto it = original_graph.adjacenciesFromVertexBegin(v); it != original_graph.adjacenciesFromVertexEnd(v); ++it) 49 | if (vertex_labels[it->vertex()] == label && !visited[it->vertex()]) 50 | { 51 | S.push(it->vertex()); 52 | visited[it->vertex()] = 1; 53 | new_labels[it->vertex()] = cnt; 54 | } 55 | } 56 | 57 | ++cnt; 58 | } 59 | 60 | vertexToEdgeLabels(lifted_graph, new_labels, edge_labels); 61 | } 62 | 63 | template 64 | inline 65 | void edgeToVertexLabels(const GRAPH& graph, const ELA& edge_labels, VLA& vertex_labels) 66 | { 67 | struct mask 68 | { 69 | mask(const ELA& edge_labels) : edge_labels_(edge_labels) 70 | {} 71 | bool vertex(std::size_t i) const 72 | { return true; } 73 | bool edge(std::size_t i) const 74 | { return !edge_labels_[i]; } 75 | 76 | const ELA& edge_labels_; 77 | }; 78 | 79 | andres::graph::DepthFirstSearchData<> dfs_data(graph.numberOfVertices()); 80 | 81 | for (std::size_t i = 0, label = 0; i < graph.numberOfVertices(); ++i) 82 | if (!dfs_data.visited(i)) 83 | { 84 | depthFirstSearch( 85 | graph, 86 | mask(edge_labels), 87 | i, 88 | [&](std::size_t v, bool& proceed, bool& add_neighbors) 89 | { 90 | vertex_labels[v] = label; 91 | proceed = true; 92 | add_neighbors = true; 93 | }, 94 | dfs_data); 95 | 96 | ++label; 97 | } 98 | } 99 | 100 | #endif // #ifndef UTILS_HXX 101 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/bridges.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include "andres/graph/complete-graph.hxx" 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/bridges.hxx" 5 | 6 | 7 | inline void test(bool pred) 8 | { 9 | if(!pred) 10 | throw std::runtime_error("Test failed."); 11 | } 12 | 13 | using namespace andres::graph; 14 | 15 | void test() 16 | { 17 | Graph<> graph(8); 18 | graph.insertEdge(0, 1); // 0 19 | graph.insertEdge(0, 2); // 1 20 | graph.insertEdge(1, 3); // 2 21 | graph.insertEdge(2, 4); // 3 22 | graph.insertEdge(2, 5); // 4 23 | graph.insertEdge(4, 6); // 5 24 | graph.insertEdge(5, 6); // 6 25 | 26 | std::vector isBridge(graph.numberOfEdges()); 27 | findBridges(graph, isBridge); 28 | 29 | test(isBridge[0] == true); 30 | test(isBridge[1] == true); 31 | test(isBridge[2] == true); 32 | test(isBridge[3] == false); 33 | test(isBridge[4] == false); 34 | test(isBridge[5] == false); 35 | test(isBridge[6] == false); 36 | 37 | 38 | struct mask 39 | { 40 | bool vertex(std::size_t i) const 41 | { 42 | return true; 43 | } 44 | 45 | bool edge(std::size_t i) const 46 | { 47 | return !(i == 3); 48 | } 49 | }; 50 | 51 | findBridges(graph, mask(), isBridge); 52 | 53 | test(isBridge[0] == true); 54 | test(isBridge[1] == true); 55 | test(isBridge[2] == true); 56 | test(isBridge[3] == false); 57 | test(isBridge[4] == true); 58 | test(isBridge[5] == true); 59 | test(isBridge[6] == true); 60 | } 61 | 62 | void testCompleteGraph() 63 | { 64 | CompleteGraph<> graph(5); 65 | 66 | std::vector isBridge(graph.numberOfEdges()); 67 | findBridges(graph, isBridge); 68 | 69 | test(isBridge[graph.findEdge(0, 1).second] == false); 70 | test(isBridge[graph.findEdge(0, 2).second] == false); 71 | test(isBridge[graph.findEdge(0, 3).second] == false); 72 | test(isBridge[graph.findEdge(0, 4).second] == false); 73 | test(isBridge[graph.findEdge(1, 2).second] == false); 74 | test(isBridge[graph.findEdge(1, 3).second] == false); 75 | test(isBridge[graph.findEdge(1, 4).second] == false); 76 | test(isBridge[graph.findEdge(2, 3).second] == false); 77 | test(isBridge[graph.findEdge(2, 4).second] == false); 78 | test(isBridge[graph.findEdge(3, 4).second] == false); 79 | 80 | struct mask 81 | { 82 | bool vertex(std::size_t i) const 83 | { 84 | return true; 85 | } 86 | 87 | bool edge(std::size_t i) const 88 | { 89 | return !(i == 1 || i == 2 || i == 3); 90 | } 91 | }; 92 | 93 | findBridges(graph, mask(), isBridge); 94 | 95 | test(isBridge[graph.findEdge(0, 1).second] == true); 96 | test(isBridge[graph.findEdge(0, 2).second] == false); 97 | test(isBridge[graph.findEdge(0, 3).second] == false); 98 | test(isBridge[graph.findEdge(0, 4).second] == false); 99 | test(isBridge[graph.findEdge(1, 2).second] == false); 100 | test(isBridge[graph.findEdge(1, 3).second] == false); 101 | test(isBridge[graph.findEdge(1, 4).second] == false); 102 | test(isBridge[graph.findEdge(2, 3).second] == false); 103 | test(isBridge[graph.findEdge(2, 4).second] == false); 104 | test(isBridge[graph.findEdge(3, 4).second] == false); 105 | } 106 | 107 | int main() 108 | { 109 | test(); 110 | 111 | testCompleteGraph(); 112 | 113 | return 0; 114 | } -------------------------------------------------------------------------------- /include/andres/graph/paths.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_PATHS_HXX 3 | #define ANDRES_GRAPH_PATHS_HXX 4 | 5 | #include 6 | #include // std::pair 7 | 8 | #include "andres/graph/graph.hxx" // DefaultSubgraphMask 9 | 10 | namespace andres { 11 | namespace graph { 12 | 13 | /// Search a path for a chord. 14 | /// 15 | /// \param graph Graph. 16 | /// \param begin Iterator to the beginning of the sequence of nodes on the path. 17 | /// \param end Iterator to the end of the sequence of nodes on the path. 18 | /// \param ignoreEdgeBetweenFirstAndLast Flag. 19 | /// 20 | template 21 | inline std::pair 22 | findChord( 23 | const GRAPH& graph, 24 | ITERATOR begin, 25 | ITERATOR end, 26 | const bool ignoreEdgeBetweenFirstAndLast = false 27 | ) { 28 | return findChord(graph, DefaultSubgraphMask<>(), begin, end, 29 | ignoreEdgeBetweenFirstAndLast); 30 | } 31 | 32 | /// Search a path for a chord. 33 | /// 34 | /// \param graph Graph. 35 | /// \param mask A subgraph mask such as DefaultSubgraphMask. 36 | /// \param begin Iterator to the beginning of the sequence of nodes on the path. 37 | /// \param end Iterator to the end of the sequence of nodes on the path. 38 | /// \param ignoreEdgeBetweenFirstAndLast Flag. 39 | /// 40 | template 41 | inline std::pair 42 | findChord( 43 | const GRAPH& graph, 44 | const SUBGRAPH_MASK& mask, 45 | ITERATOR begin, 46 | ITERATOR end, 47 | const bool ignoreEdgeBetweenFirstAndLast = false 48 | ) { 49 | for(ITERATOR it = begin; it != end - 1; ++it) 50 | for(ITERATOR it2 = it + 2; it2 != end; ++it2) { 51 | if(ignoreEdgeBetweenFirstAndLast && it == begin && it2 == end - 1) { 52 | continue; 53 | } 54 | std::pair p = graph.findEdge(*it, *it2); 55 | if(p.first && mask.edge(p.second)) { 56 | return p; 57 | } 58 | } 59 | return std::pair(false, 0); 60 | } 61 | 62 | /// Determine whether a path has a chord in time linear in the path length. 63 | /// 64 | /// \param graph Graph. 65 | /// \param begin Iterator to the beginning of the sequence of nodes on the path. 66 | /// \param end Iterator to the end of the sequence of nodes on the path. 67 | /// \param seen Vector of labels (should contain initially zeros) 68 | /// \param ignoreEdgeBetweenFirstAndLast Flag. 69 | /// 70 | template 71 | inline bool 72 | hasChord( 73 | const GRAPH& graph, 74 | ITERATOR begin, 75 | ITERATOR end, 76 | std::vector& seen, 77 | const bool ignoreEdgeBetweenFirstAndLast = false) 78 | { 79 | for (ITERATOR path_it = begin; path_it != end; path_it++) 80 | { 81 | if (seen[*path_it]) 82 | return true; 83 | 84 | for (auto adj_it = graph.adjacenciesFromVertexBegin(*path_it); adj_it != graph.adjacenciesFromVertexEnd(*path_it); adj_it++) 85 | { 86 | // exclude edge between first and last vertex in the path 87 | if (ignoreEdgeBetweenFirstAndLast && path_it == begin && adj_it->vertex() == *(end-1)) 88 | continue; 89 | 90 | if (adj_it->vertex() == *(path_it+1) ) 91 | continue; 92 | 93 | seen[adj_it->vertex()] = 1; 94 | } 95 | } 96 | return false; 97 | } 98 | 99 | } // namespace graph 100 | } // namespace andres 101 | 102 | #endif // #ifndef ANDRES_GRAPH_PATHS_HXX 103 | -------------------------------------------------------------------------------- /src/command-line-tools/test-probabilistic-lifting.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/lifting.hxx" 5 | 6 | #include 7 | 8 | inline void test(const bool condition) { 9 | if(!condition) throw std::logic_error("test failed."); 10 | } 11 | 12 | // difference modulo m 13 | template 14 | inline T diff(const T a, const T b, const T m) { 15 | const T d = a < b ? b - a : a - b; 16 | const T d2 = m - d; 17 | return d < d2 ? d : d2; 18 | } 19 | 20 | void testLiftEdgeValuesSPSP() { 21 | typedef std::size_t size_type; 22 | 23 | // build cycle 24 | const size_type numberOfVertices = 10; 25 | andres::graph::Graph<> graph; 26 | graph.insertVertices(numberOfVertices); 27 | for(size_type v = 0; v < graph.numberOfVertices(); ++v) 28 | { 29 | const int w = (v + 1) % graph.numberOfVertices(); 30 | graph.insertEdge(v, w); 31 | } 32 | 33 | // define (two unit) edge values 34 | std::vector edgeValues(graph.numberOfEdges(), 2); 35 | 36 | // lift graph 37 | const size_type distanceUpperBound = 4; 38 | andres::graph::Graph<> graphLifted; 39 | andres::graph::lift(graph, graphLifted, distanceUpperBound); 40 | 41 | // lift edge weights (by means of SPSP) 42 | std::vector edgeValuesLifted(graphLifted.numberOfEdges()); 43 | liftEdgeValues(graph, graphLifted, edgeValues.begin(), edgeValuesLifted.begin()); 44 | 45 | // test lifted edge values 46 | for(size_type e = 0; e < graphLifted.numberOfEdges(); ++e) 47 | { 48 | const size_type v = graphLifted.vertexOfEdge(e, 0); 49 | const size_type w = graphLifted.vertexOfEdge(e, 1); 50 | const size_type distance = diff(v, w, graph.numberOfVertices()); 51 | test(edgeValuesLifted[e] == distance * 2); 52 | } 53 | } 54 | 55 | void testLiftEdgeValuesFastMarching() { 56 | typedef std::size_t size_type; 57 | typedef andres::graph::GridGraph<2> GraphType; 58 | typedef GraphType::VertexCoordinate VertexCoordinate; 59 | typedef andres::graph::Graph<> LiftedGraphType; 60 | 61 | // build grid graph 62 | GraphType graph = {5, 4}; 63 | 64 | // define (two unit) edge values 65 | std::vector edgeValues(graph.numberOfEdges(), 2); 66 | 67 | // lift graph 68 | const size_type distanceUpperBound = 4; 69 | LiftedGraphType graphLifted; 70 | andres::graph::lift(graph, graphLifted, distanceUpperBound); 71 | 72 | // lift edge values (by menas of fast marching) 73 | const size_type interpolationOrder = 0; 74 | std::vector edgeValuesLiftedFM(graphLifted.numberOfEdges()); 75 | liftEdgeValues(graph, graphLifted, edgeValues.begin(), edgeValuesLiftedFM.begin(), interpolationOrder); 76 | 77 | // lift edge values (by menas of SPSP) 78 | std::vector edgeValuesLiftedSPSP(graphLifted.numberOfEdges()); 79 | liftEdgeValues< 80 | GraphType, 81 | LiftedGraphType, 82 | std::vector::const_iterator, 83 | std::vector::iterator 84 | >( 85 | graph, 86 | graphLifted, 87 | edgeValues.begin(), 88 | edgeValuesLiftedSPSP.begin() 89 | ); 90 | 91 | // test lifted edge values 92 | VertexCoordinate cv, cw; 93 | for(size_type e = 0; e < graphLifted.numberOfEdges(); ++e) 94 | test(edgeValuesLiftedFM[e] == edgeValuesLiftedSPSP[e]); 95 | } 96 | 97 | int main() { 98 | testLiftEdgeValuesSPSP(); 99 | testLiftEdgeValuesFastMarching(); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/tclap/ValuesConstraint.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | * 5 | * file: ValuesConstraint.h 6 | * 7 | * Copyright (c) 2005, Michael E. Smoot 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef TCLAP_VALUESCONSTRAINT_H 24 | #define TCLAP_VALUESCONSTRAINT_H 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef HAVE_CONFIG_H 31 | #include 32 | #else 33 | #define HAVE_SSTREAM 34 | #endif 35 | 36 | #if defined(HAVE_SSTREAM) 37 | #include 38 | #elif defined(HAVE_STRSTREAM) 39 | #include 40 | #else 41 | #error "Need a stringstream (sstream or strstream) to compile!" 42 | #endif 43 | 44 | namespace TCLAP { 45 | 46 | /** 47 | * A Constraint that constrains the Arg to only those values specified 48 | * in the constraint. 49 | */ 50 | template 51 | class ValuesConstraint : public Constraint 52 | { 53 | 54 | public: 55 | 56 | /** 57 | * Constructor. 58 | * \param allowed - vector of allowed values. 59 | */ 60 | ValuesConstraint(std::vector& allowed); 61 | 62 | /** 63 | * Virtual destructor. 64 | */ 65 | virtual ~ValuesConstraint() {} 66 | 67 | /** 68 | * Returns a description of the Constraint. 69 | */ 70 | virtual std::string description() const; 71 | 72 | /** 73 | * Returns the short ID for the Constraint. 74 | */ 75 | virtual std::string shortID() const; 76 | 77 | /** 78 | * The method used to verify that the value parsed from the command 79 | * line meets the constraint. 80 | * \param value - The value that will be checked. 81 | */ 82 | virtual bool check(const T& value) const; 83 | 84 | protected: 85 | 86 | /** 87 | * The list of valid values. 88 | */ 89 | std::vector _allowed; 90 | 91 | /** 92 | * The string used to describe the allowed values of this constraint. 93 | */ 94 | std::string _typeDesc; 95 | 96 | }; 97 | 98 | template 99 | ValuesConstraint::ValuesConstraint(std::vector& allowed) 100 | : _allowed(allowed), 101 | _typeDesc("") 102 | { 103 | for ( unsigned int i = 0; i < _allowed.size(); i++ ) 104 | { 105 | 106 | #if defined(HAVE_SSTREAM) 107 | std::ostringstream os; 108 | #elif defined(HAVE_STRSTREAM) 109 | std::ostrstream os; 110 | #else 111 | #error "Need a stringstream (sstream or strstream) to compile!" 112 | #endif 113 | 114 | os << _allowed[i]; 115 | 116 | std::string temp( os.str() ); 117 | 118 | if ( i > 0 ) 119 | _typeDesc += "|"; 120 | _typeDesc += temp; 121 | } 122 | } 123 | 124 | template 125 | bool ValuesConstraint::check( const T& val ) const 126 | { 127 | if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() ) 128 | return false; 129 | else 130 | return true; 131 | } 132 | 133 | template 134 | std::string ValuesConstraint::shortID() const 135 | { 136 | return _typeDesc; 137 | } 138 | 139 | template 140 | std::string ValuesConstraint::description() const 141 | { 142 | return _typeDesc; 143 | } 144 | 145 | 146 | } //namespace TCLAP 147 | #endif 148 | 149 | -------------------------------------------------------------------------------- /include/andres/graph/adjacency.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_ADJACENCY_HXX 3 | #define ANDRES_GRAPH_ADJACENCY_HXX 4 | 5 | namespace andres { 6 | namespace graph { 7 | 8 | /// The adjacency of a vertex consists of a vertex and a connecting edge. 9 | template 10 | class Adjacency { 11 | public: 12 | typedef T Value; 13 | 14 | Adjacency(const Value = T(), const Value = T()); 15 | Value vertex() const; 16 | Value& vertex(); 17 | Value edge() const; 18 | Value& edge(); 19 | bool operator<(const Adjacency&) const; 20 | bool operator<=(const Adjacency&) const; 21 | bool operator>(const Adjacency&) const; 22 | bool operator>=(const Adjacency&) const; 23 | bool operator==(const Adjacency&) const; 24 | bool operator!=(const Adjacency&) const; 25 | 26 | private: 27 | Value vertex_; 28 | Value edge_; 29 | }; 30 | 31 | /// Construct an adjacency. 32 | /// 33 | /// \param vertex Vertex. 34 | /// \param edge Edge. 35 | /// 36 | template 37 | inline 38 | Adjacency::Adjacency( 39 | const Value vertex, 40 | const Value edge 41 | ) 42 | : vertex_(vertex), 43 | edge_(edge) 44 | {} 45 | 46 | /// Access the vertex. 47 | /// 48 | template 49 | inline typename Adjacency::Value 50 | Adjacency::vertex() const { 51 | return vertex_; 52 | } 53 | 54 | /// Access the vertex. 55 | /// 56 | template 57 | inline typename Adjacency::Value& 58 | Adjacency::vertex() { 59 | return vertex_; 60 | } 61 | 62 | /// Access the edge. 63 | /// 64 | template 65 | inline typename Adjacency::Value 66 | Adjacency::edge() const { 67 | return edge_; 68 | } 69 | 70 | /// Access the edge. 71 | /// 72 | template 73 | inline typename Adjacency::Value& 74 | Adjacency::edge() { 75 | return edge_; 76 | } 77 | 78 | /// Adjacencies are ordered first wrt the vertex, then wrt the edge. 79 | /// 80 | template 81 | inline bool 82 | Adjacency::operator<( 83 | const Adjacency& in 84 | ) const { 85 | if(vertex_ < in.vertex_) { 86 | return true; 87 | } 88 | else if(vertex_ == in.vertex_) { 89 | return edge_ < in.edge_; 90 | } 91 | else { 92 | return false; 93 | } 94 | } 95 | 96 | /// Adjacencies are ordered first wrt the vertex, then wrt the edge. 97 | /// 98 | template 99 | inline bool 100 | Adjacency::operator<=( 101 | const Adjacency& in 102 | ) const { 103 | if(vertex_ < in.vertex_) { 104 | return true; 105 | } 106 | else if(vertex_ == in.vertex_) { 107 | return edge_ <= in.edge_; 108 | } 109 | else { 110 | return false; 111 | } 112 | } 113 | 114 | /// Adjacencies are ordered first wrt the vertex, then wrt the edge. 115 | /// 116 | template 117 | inline bool 118 | Adjacency::operator>( 119 | const Adjacency& in 120 | ) const { 121 | if(vertex_ > in.vertex_) { 122 | return true; 123 | } 124 | else if(vertex_ == in.vertex_) { 125 | return edge_ > in.edge_; 126 | } 127 | else { 128 | return false; 129 | } 130 | } 131 | 132 | /// Adjacencies are ordered first wrt the vertex, then wrt the edge. 133 | /// 134 | template 135 | inline bool 136 | Adjacency::operator>=( 137 | const Adjacency& in 138 | ) const { 139 | if(vertex_ > in.vertex_) { 140 | return true; 141 | } 142 | else if(vertex_ == in.vertex_) { 143 | return edge_ >= in.edge_; 144 | } 145 | else { 146 | return false; 147 | } 148 | } 149 | 150 | /// Adjacencies are equal if both the vertex and the edge are equal. 151 | /// 152 | template 153 | inline bool 154 | Adjacency::operator==( 155 | const Adjacency& in 156 | ) const { 157 | return vertex_ == in.vertex_ && edge_ == in.edge_; 158 | } 159 | 160 | /// Adjacencies are unequal if either the vertex or the edge are unqual. 161 | /// 162 | template 163 | inline bool 164 | Adjacency::operator!=( 165 | const Adjacency& in 166 | ) const { 167 | return !(*this == in); 168 | } 169 | 170 | } // namespace graph 171 | } // namespace andres 172 | 173 | #endif // #ifndef ANDRES_GRAPH_ADJACENCY_HXX 174 | -------------------------------------------------------------------------------- /src/tclap/CmdLineInterface.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: CmdLineInterface.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef TCLAP_COMMANDLINE_INTERFACE_H 24 | #define TCLAP_COMMANDLINE_INTERFACE_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | namespace TCLAP { 34 | 35 | class Arg; 36 | class CmdLineOutput; 37 | class XorHandler; 38 | 39 | /** 40 | * The base class that manages the command line definition and passes 41 | * along the parsing to the appropriate Arg classes. 42 | */ 43 | class CmdLineInterface 44 | { 45 | public: 46 | 47 | /** 48 | * Destructor 49 | */ 50 | virtual ~CmdLineInterface() {} 51 | 52 | /** 53 | * Adds an argument to the list of arguments to be parsed. 54 | * \param a - Argument to be added. 55 | */ 56 | virtual void add( Arg& a )=0; 57 | 58 | /** 59 | * An alternative add. Functionally identical. 60 | * \param a - Argument to be added. 61 | */ 62 | virtual void add( Arg* a )=0; 63 | 64 | /** 65 | * Add two Args that will be xor'd. 66 | * If this method is used, add does 67 | * not need to be called. 68 | * \param a - Argument to be added and xor'd. 69 | * \param b - Argument to be added and xor'd. 70 | */ 71 | virtual void xorAdd( Arg& a, Arg& b )=0; 72 | 73 | /** 74 | * Add a list of Args that will be xor'd. If this method is used, 75 | * add does not need to be called. 76 | * \param xors - List of Args to be added and xor'd. 77 | */ 78 | virtual void xorAdd( std::vector& xors )=0; 79 | 80 | /** 81 | * Parses the command line. 82 | * \param argc - Number of arguments. 83 | * \param argv - Array of arguments. 84 | */ 85 | virtual void parse(int argc, const char * const * argv)=0; 86 | 87 | /** 88 | * Parses the command line. 89 | * \param args - A vector of strings representing the args. 90 | * args[0] is still the program name. 91 | */ 92 | void parse(std::vector& args); 93 | 94 | /** 95 | * Returns the CmdLineOutput object. 96 | */ 97 | virtual CmdLineOutput* getOutput()=0; 98 | 99 | /** 100 | * \param co - CmdLineOutput object that we want to use instead. 101 | */ 102 | virtual void setOutput(CmdLineOutput* co)=0; 103 | 104 | /** 105 | * Returns the version string. 106 | */ 107 | virtual std::string& getVersion()=0; 108 | 109 | /** 110 | * Returns the program name string. 111 | */ 112 | virtual std::string& getProgramName()=0; 113 | 114 | /** 115 | * Returns the argList. 116 | */ 117 | virtual std::list& getArgList()=0; 118 | 119 | /** 120 | * Returns the XorHandler. 121 | */ 122 | virtual XorHandler& getXorHandler()=0; 123 | 124 | /** 125 | * Returns the delimiter string. 126 | */ 127 | virtual char getDelimiter()=0; 128 | 129 | /** 130 | * Returns the message string. 131 | */ 132 | virtual std::string& getMessage()=0; 133 | 134 | /** 135 | * Indicates whether or not the help and version switches were created 136 | * automatically. 137 | */ 138 | virtual bool hasHelpAndVersion()=0; 139 | 140 | /** 141 | * Resets the instance as if it had just been constructed so that the 142 | * instance can be reused. 143 | */ 144 | virtual void reset()=0; 145 | }; 146 | 147 | } //namespace 148 | 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/dfs.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/dfs.hxx" 5 | 6 | inline void test(const bool condition) { 7 | if(!condition) throw std::logic_error("test failed."); 8 | } 9 | 10 | struct SimpleCallback { 11 | SimpleCallback() 12 | : vertexIndices_() 13 | {} 14 | void operator()( 15 | const std::size_t v, 16 | bool& proceed, 17 | bool& addNeighbors 18 | ) { 19 | vertexIndices_.push_back(v); 20 | proceed = true; 21 | addNeighbors = true; 22 | } 23 | 24 | std::vector vertexIndices_; 25 | }; 26 | 27 | struct SearchCallback { 28 | SearchCallback(const std::size_t vertexIndex) 29 | : vertexIndex_(vertexIndex), 30 | vertexIndices_() 31 | {} 32 | void operator()( 33 | const std::size_t v, 34 | bool& proceed, 35 | bool& addNeighbors 36 | ) { 37 | vertexIndices_.push_back(v); 38 | proceed = (v != vertexIndex_); 39 | addNeighbors = true; 40 | } 41 | 42 | std::size_t vertexIndex_; 43 | std::vector vertexIndices_; 44 | }; 45 | 46 | struct BlockingCallback { 47 | BlockingCallback(const std::size_t vertexIndex) 48 | : vertexIndex_(vertexIndex), 49 | vertexIndices_() 50 | {} 51 | void operator()( 52 | const std::size_t v, 53 | bool& proceed, 54 | bool& addNeighbors 55 | ) { 56 | vertexIndices_.push_back(v); 57 | proceed = true; 58 | addNeighbors = (v != vertexIndex_); 59 | } 60 | 61 | std::size_t vertexIndex_; 62 | std::vector vertexIndices_; 63 | }; 64 | 65 | int main() { 66 | andres::graph::Graph<> g; 67 | g.insertVertices(7); 68 | g.insertEdge(0, 1); 69 | g.insertEdge(0, 2); 70 | g.insertEdge(0, 4); 71 | g.insertEdge(1, 3); 72 | g.insertEdge(1, 5); 73 | g.insertEdge(2, 6); 74 | g.insertEdge(4, 5); 75 | 76 | { 77 | SimpleCallback callback; 78 | andres::graph::depthFirstSearch(g, 0, callback); 79 | test(callback.vertexIndices_.size() == 7); 80 | test(callback.vertexIndices_[0] == 0); 81 | test(callback.vertexIndices_[1] == 4); 82 | test(callback.vertexIndices_[2] == 5); 83 | test(callback.vertexIndices_[3] == 1); 84 | test(callback.vertexIndices_[4] == 3); 85 | test(callback.vertexIndices_[5] == 2); 86 | test(callback.vertexIndices_[6] == 6); 87 | } 88 | 89 | { 90 | SearchCallback callback(2); 91 | andres::graph::depthFirstSearch(g, 0, callback); 92 | test(callback.vertexIndices_.size() == 6); 93 | test(callback.vertexIndices_[0] == 0); 94 | test(callback.vertexIndices_[1] == 4); 95 | test(callback.vertexIndices_[2] == 5); 96 | test(callback.vertexIndices_[3] == 1); 97 | test(callback.vertexIndices_[4] == 3); 98 | test(callback.vertexIndices_[5] == 2); 99 | } 100 | 101 | { 102 | BlockingCallback callback(2); 103 | andres::graph::depthFirstSearch(g, 0, callback); 104 | test(callback.vertexIndices_.size() == 6); 105 | test(callback.vertexIndices_[0] == 0); 106 | test(callback.vertexIndices_[1] == 4); 107 | test(callback.vertexIndices_[2] == 5); 108 | test(callback.vertexIndices_[3] == 1); 109 | test(callback.vertexIndices_[4] == 3); 110 | test(callback.vertexIndices_[5] == 2); 111 | } 112 | 113 | // disconnected graph 114 | g.insertVertices(2); 115 | g.insertEdge(7, 8); 116 | 117 | { 118 | SimpleCallback callback; 119 | andres::graph::depthFirstSearch(g, 0, callback); 120 | andres::graph::depthFirstSearch(g, 7, callback); 121 | test(callback.vertexIndices_.size() == 9); 122 | test(callback.vertexIndices_[0] == 0); 123 | test(callback.vertexIndices_[1] == 4); 124 | test(callback.vertexIndices_[2] == 5); 125 | test(callback.vertexIndices_[3] == 1); 126 | test(callback.vertexIndices_[4] == 3); 127 | test(callback.vertexIndices_[5] == 2); 128 | test(callback.vertexIndices_[6] == 6); 129 | test(callback.vertexIndices_[7] == 7); 130 | test(callback.vertexIndices_[8] == 8); 131 | } 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut-lifted/ilp-callback.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | inline void test(bool pred) { 11 | if(!pred) throw std::logic_error("test failed."); 12 | } 13 | 14 | void test_3() { 15 | andres::graph::Graph<> original_graph(3); 16 | original_graph.insertEdge(0, 1); 17 | original_graph.insertEdge(1, 2); 18 | 19 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 20 | lifted_graph.insertEdge(0, 1); 21 | lifted_graph.insertEdge(1, 2); 22 | lifted_graph.insertEdge(0, 2); 23 | 24 | std::vector edge_values(lifted_graph.numberOfEdges()); 25 | edge_values[0] = -10; 26 | edge_values[1] = -10; 27 | edge_values[2] = 10; 28 | 29 | std::vector edge_labels(lifted_graph.numberOfEdges()); 30 | andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 31 | 32 | test(edge_labels[0] == 1); 33 | test(edge_labels[1] == 1); 34 | test(edge_labels[2] == 1); 35 | } 36 | 37 | void test_4() { 38 | andres::graph::Graph<> original_graph(4); 39 | original_graph.insertEdge(0, 1); 40 | original_graph.insertEdge(0, 3); 41 | original_graph.insertEdge(1, 2); 42 | original_graph.insertEdge(2, 3); 43 | 44 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 45 | lifted_graph.insertEdge(0, 1); 46 | lifted_graph.insertEdge(0, 3); 47 | lifted_graph.insertEdge(1, 2); 48 | lifted_graph.insertEdge(2, 3); 49 | lifted_graph.insertEdge(0, 2); 50 | 51 | std::vector edge_values(lifted_graph.numberOfEdges()); 52 | edge_values[0] = -10; 53 | edge_values[1] = -2; 54 | edge_values[2] = -10; 55 | edge_values[3] = -4; 56 | edge_values[4] = 1; 57 | 58 | std::vector edge_labels(lifted_graph.numberOfEdges()); 59 | andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 60 | 61 | test(edge_labels[0] == 1); 62 | test(edge_labels[1] == 1); 63 | test(edge_labels[2] == 1); 64 | test(edge_labels[3] == 1); 65 | test(edge_labels[4] == 1); 66 | } 67 | 68 | void test_8() { 69 | andres::graph::Graph<> original_graph(8); 70 | original_graph.insertEdge(0, 1); 71 | original_graph.insertEdge(1, 2); 72 | original_graph.insertEdge(2, 3); 73 | original_graph.insertEdge(4, 5); 74 | original_graph.insertEdge(5, 6); 75 | original_graph.insertEdge(6, 7); 76 | original_graph.insertEdge(0, 4); 77 | original_graph.insertEdge(1, 5); 78 | original_graph.insertEdge(2, 6); 79 | original_graph.insertEdge(3, 7); 80 | 81 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 82 | lifted_graph.insertEdge(0, 1); 83 | lifted_graph.insertEdge(1, 2); 84 | lifted_graph.insertEdge(2, 3); 85 | lifted_graph.insertEdge(4, 5); 86 | lifted_graph.insertEdge(5, 6); 87 | lifted_graph.insertEdge(6, 7); 88 | lifted_graph.insertEdge(0, 4); 89 | lifted_graph.insertEdge(1, 5); 90 | lifted_graph.insertEdge(2, 6); 91 | lifted_graph.insertEdge(3, 7); 92 | lifted_graph.insertEdge(0, 7); 93 | 94 | std::vector edge_values(lifted_graph.numberOfEdges()); 95 | edge_values[0] = -5; 96 | edge_values[1] = -5; 97 | edge_values[2] = -5; 98 | edge_values[3] = 5; 99 | edge_values[4] = .5; 100 | edge_values[5] = 5; 101 | edge_values[6] = 1; 102 | edge_values[7] = -1; 103 | edge_values[8] = 1; 104 | edge_values[9] = .5; 105 | edge_values[10] = -4; 106 | 107 | std::vector edge_labels(lifted_graph.numberOfEdges()); 108 | andres::graph::multicut_lifted::ilp_callback(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 109 | 110 | test(edge_labels[0] == 1); 111 | test(edge_labels[1] == 1); 112 | test(edge_labels[2] == 1); 113 | test(edge_labels[3] == 0); 114 | test(edge_labels[4] == 1); 115 | test(edge_labels[5] == 0); 116 | test(edge_labels[6] == 0); 117 | test(edge_labels[7] == 1); 118 | test(edge_labels[8] == 0); 119 | test(edge_labels[9] == 1); 120 | test(edge_labels[10] == 1); 121 | } 122 | 123 | int main() { 124 | test_3(); 125 | test_4(); 126 | test_8(); 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /src/andres/graph/unit-test/multicut-lifted/ilp.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | inline void test(bool pred) 11 | { 12 | if(!pred) 13 | throw std::runtime_error("Test failed."); 14 | } 15 | 16 | void test_3() 17 | { 18 | andres::graph::Graph<> original_graph(3); 19 | 20 | original_graph.insertEdge(0, 1); 21 | original_graph.insertEdge(1, 2); 22 | 23 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 24 | 25 | lifted_graph.insertEdge(0, 1); 26 | lifted_graph.insertEdge(1, 2); 27 | lifted_graph.insertEdge(0, 2); 28 | 29 | std::vector edge_values(lifted_graph.numberOfEdges()); 30 | 31 | edge_values[0] = -10; 32 | edge_values[1] = -10; 33 | edge_values[2] = 10; 34 | 35 | std::vector edge_labels(lifted_graph.numberOfEdges()); 36 | andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 37 | 38 | test(edge_labels[0] == 1); 39 | test(edge_labels[1] == 1); 40 | test(edge_labels[2] == 1); 41 | } 42 | 43 | void test_4() 44 | { 45 | andres::graph::Graph<> original_graph(4); 46 | 47 | original_graph.insertEdge(0, 1); 48 | original_graph.insertEdge(0, 3); 49 | original_graph.insertEdge(1, 2); 50 | original_graph.insertEdge(2, 3); 51 | 52 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 53 | 54 | lifted_graph.insertEdge(0, 1); 55 | lifted_graph.insertEdge(0, 3); 56 | lifted_graph.insertEdge(1, 2); 57 | lifted_graph.insertEdge(2, 3); 58 | lifted_graph.insertEdge(0, 2); 59 | 60 | std::vector edge_values(lifted_graph.numberOfEdges()); 61 | 62 | edge_values[0] = -10; 63 | edge_values[1] = -2; 64 | edge_values[2] = -10; 65 | edge_values[3] = -4; 66 | edge_values[4] = 1; 67 | 68 | std::vector edge_labels(lifted_graph.numberOfEdges()); 69 | andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 70 | 71 | test(edge_labels[0] == 1); 72 | test(edge_labels[1] == 1); 73 | test(edge_labels[2] == 1); 74 | test(edge_labels[3] == 1); 75 | test(edge_labels[4] == 1); 76 | } 77 | 78 | void test_8() 79 | { 80 | andres::graph::Graph<> original_graph(8); 81 | 82 | original_graph.insertEdge(0, 1); 83 | original_graph.insertEdge(1, 2); 84 | original_graph.insertEdge(2, 3); 85 | original_graph.insertEdge(4, 5); 86 | original_graph.insertEdge(5, 6); 87 | original_graph.insertEdge(6, 7); 88 | original_graph.insertEdge(0, 4); 89 | original_graph.insertEdge(1, 5); 90 | original_graph.insertEdge(2, 6); 91 | original_graph.insertEdge(3, 7); 92 | 93 | andres::graph::Graph<> lifted_graph(original_graph.numberOfVertices()); 94 | 95 | lifted_graph.insertEdge(0, 1); 96 | lifted_graph.insertEdge(1, 2); 97 | lifted_graph.insertEdge(2, 3); 98 | lifted_graph.insertEdge(4, 5); 99 | lifted_graph.insertEdge(5, 6); 100 | lifted_graph.insertEdge(6, 7); 101 | lifted_graph.insertEdge(0, 4); 102 | lifted_graph.insertEdge(1, 5); 103 | lifted_graph.insertEdge(2, 6); 104 | lifted_graph.insertEdge(3, 7); 105 | 106 | lifted_graph.insertEdge(0, 7); 107 | 108 | std::vector edge_values(lifted_graph.numberOfEdges()); 109 | 110 | edge_values[0] = -5; 111 | edge_values[1] = -5; 112 | edge_values[2] = -5; 113 | edge_values[3] = 5; 114 | edge_values[4] = .5; 115 | edge_values[5] = 5; 116 | edge_values[6] = 1; 117 | edge_values[7] = -1; 118 | edge_values[8] = 1; 119 | edge_values[9] = .5; 120 | 121 | edge_values[10] = -4; 122 | 123 | std::vector edge_labels(lifted_graph.numberOfEdges()); 124 | andres::graph::multicut_lifted::ilp(original_graph, lifted_graph, edge_values, edge_labels, edge_labels); 125 | 126 | test(edge_labels[0] == 1); 127 | test(edge_labels[1] == 1); 128 | test(edge_labels[2] == 1); 129 | test(edge_labels[3] == 0); 130 | test(edge_labels[4] == 1); 131 | test(edge_labels[5] == 0); 132 | test(edge_labels[6] == 0); 133 | test(edge_labels[7] == 1); 134 | test(edge_labels[8] == 0); 135 | test(edge_labels[9] == 1); 136 | test(edge_labels[10] == 1); 137 | } 138 | 139 | int main() 140 | { 141 | test_3(); 142 | 143 | test_4(); 144 | 145 | test_8(); 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /include/andres/graph/multicut/greedy-additive.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_MULTICUT_GREEDY_ADDITIVE_HXX 3 | #define ANDRES_GRAPH_MULTICUT_GREEDY_ADDITIVE_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "andres/partition.hxx" 13 | 14 | 15 | namespace andres { 16 | namespace graph { 17 | namespace multicut { 18 | 19 | /// Greedy agglomerative decomposition of a graph. 20 | /// 21 | template 22 | void greedyAdditiveEdgeContraction( 23 | const GRAPH& graph, 24 | EVA const& edge_values, 25 | ELA& edge_labels 26 | ) 27 | { 28 | class DynamicGraph 29 | { 30 | public: 31 | DynamicGraph(size_t n) : 32 | vertices_(n) 33 | {} 34 | 35 | bool edgeExists(size_t a, size_t b) const 36 | { 37 | return !vertices_[a].empty() && vertices_[a].find(b) != vertices_[a].end(); 38 | } 39 | 40 | std::map const& getAdjacentVertices(size_t v) const 41 | { 42 | return vertices_[v]; 43 | } 44 | 45 | typename EVA::value_type getEdgeWeight(size_t a, size_t b) const 46 | { 47 | return vertices_[a].at(b); 48 | } 49 | 50 | void removeVertex(size_t v) 51 | { 52 | for (auto& p : vertices_[v]) 53 | vertices_[p.first].erase(v); 54 | 55 | vertices_[v].clear(); 56 | } 57 | 58 | void updateEdgeWeight(size_t a, size_t b, typename EVA::value_type w) 59 | { 60 | vertices_[a][b] += w; 61 | vertices_[b][a] += w; 62 | } 63 | 64 | private: 65 | std::vector> vertices_; 66 | }; 67 | 68 | struct Edge 69 | { 70 | Edge(size_t _a, size_t _b, typename EVA::value_type _w) 71 | { 72 | if (_a > _b) 73 | std::swap(_a, _b); 74 | 75 | a = _a; 76 | b = _b; 77 | 78 | w = _w; 79 | } 80 | 81 | size_t a; 82 | size_t b; 83 | size_t edition; 84 | typename EVA::value_type w; 85 | 86 | bool operator <(Edge const& other) const 87 | { 88 | return w < other.w; 89 | } 90 | }; 91 | 92 | std::vector> edge_editions(graph.numberOfVertices()); 93 | DynamicGraph original_graph_cp(graph.numberOfVertices()); 94 | std::priority_queue Q; 95 | 96 | for (size_t i = 0; i < graph.numberOfEdges(); ++i) 97 | { 98 | auto a = graph.vertexOfEdge(i, 0); 99 | auto b = graph.vertexOfEdge(i, 1); 100 | 101 | original_graph_cp.updateEdgeWeight(a, b, edge_values[i]); 102 | 103 | auto e = Edge(a, b, edge_values[i]); 104 | e.edition = ++edge_editions[e.a][e.b]; 105 | 106 | Q.push(e); 107 | } 108 | 109 | andres::Partition partition(graph.numberOfVertices()); 110 | 111 | while (!Q.empty()) 112 | { 113 | auto edge = Q.top(); 114 | Q.pop(); 115 | 116 | if (!original_graph_cp.edgeExists(edge.a, edge.b) || edge.edition < edge_editions[edge.a][edge.b]) 117 | continue; 118 | 119 | if (edge.w < typename EVA::value_type()) 120 | break; 121 | 122 | auto stable_vertex = edge.a; 123 | auto merge_vertex = edge.b; 124 | 125 | if (original_graph_cp.getAdjacentVertices(stable_vertex).size() < original_graph_cp.getAdjacentVertices(merge_vertex).size()) 126 | std::swap(stable_vertex, merge_vertex); 127 | 128 | partition.merge(stable_vertex, merge_vertex); 129 | 130 | for (auto& p : original_graph_cp.getAdjacentVertices(merge_vertex)) 131 | { 132 | if (p.first == stable_vertex) 133 | continue; 134 | 135 | original_graph_cp.updateEdgeWeight(stable_vertex, p.first, p.second); 136 | 137 | auto e = Edge(stable_vertex, p.first, original_graph_cp.getEdgeWeight(stable_vertex, p.first)); 138 | e.edition = ++edge_editions[e.a][e.b]; 139 | 140 | Q.push(e); 141 | } 142 | 143 | original_graph_cp.removeVertex(merge_vertex); 144 | } 145 | 146 | for (size_t i = 0; i < graph.numberOfEdges(); ++i) 147 | edge_labels[i] = partition.find(graph.vertexOfEdge(i, 0)) == partition.find(graph.vertexOfEdge(i, 1)) ? 0 : 1; 148 | } 149 | 150 | } // namespace multicut 151 | } // namespace graph 152 | } // namespace andres 153 | 154 | #endif // #ifndef ANDRES_GRAPH_MULTICUT_GREEDY_ADDITIVE_HXX 155 | -------------------------------------------------------------------------------- /include/andres/graph/hdf5/graph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_GRAPH_HDF5_HXX 3 | #define ANDRES_GRAPH_GRAPH_HDF5_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "hdf5.hxx" 10 | #include "../graph.hxx" 11 | 12 | namespace andres { 13 | namespace graph { 14 | namespace hdf5 { 15 | 16 | template 17 | struct GraphTraitsHDF5 > { 18 | static const int ID; 19 | }; 20 | template 21 | const int GraphTraitsHDF5 >::ID = 10000; 22 | 23 | template 24 | void save(const hid_t, const std::string&, const Graph&); 25 | 26 | template 27 | void load(const hid_t, const std::string&, Graph&); 28 | 29 | template 30 | void 31 | save( 32 | const hid_t parentHandle, 33 | const std::string& graphName, 34 | const Graph& graph 35 | ) { 36 | HandleCheck handleCheck; 37 | hid_t groupHandle = openGroup(parentHandle, graphName, true); 38 | 39 | try { 40 | save(groupHandle, "graph-type-id", GraphTraitsHDF5 >::ID); 41 | save(groupHandle, "multiple-edges-enabled", static_cast(graph.multipleEdgesEnabled())); 42 | save(groupHandle, "number-of-vertices", graph.numberOfVertices()); 43 | save(groupHandle, "number-of-edges", graph.numberOfEdges()); 44 | if(graph.numberOfEdges() != 0) { 45 | std::vector vecIJ; 46 | vecIJ.resize(2 * graph.numberOfEdges()); 47 | std::size_t *ptr = &vecIJ[0]; 48 | for(std::size_t e=0; e 63 | void 64 | load( 65 | const hid_t parentHandle, 66 | const std::string& graphName, 67 | Graph& graph 68 | ) { 69 | HandleCheck handleCheck; 70 | hid_t groupHandle = openGroup(parentHandle, graphName); 71 | 72 | std::string sError; 73 | 74 | try { 75 | int id = 0; 76 | load(groupHandle, "graph-type-id", id); 77 | if(id != GraphTraitsHDF5 >::ID) { 78 | sError = "graph type id mismatch."; 79 | goto cleanup; 80 | } 81 | 82 | std::size_t numberOfVertices = 0; 83 | load(groupHandle, "number-of-vertices", numberOfVertices); 84 | 85 | std::size_t numberOfEdges = 0; 86 | load(groupHandle, "number-of-edges", numberOfEdges); 87 | 88 | graph.assign(numberOfVertices); 89 | 90 | if(numberOfEdges != 0) { 91 | graph.reserveEdges(numberOfEdges); 92 | 93 | std::vector bufferIJ; 94 | { 95 | std::vector shape; 96 | load(groupHandle, "edges", shape, bufferIJ); 97 | if(shape.size() != 2) { 98 | sError = "edges dataset is not 2-dimensional."; 99 | goto cleanup; 100 | } 101 | if(shape[0] != numberOfEdges || shape[1] != 2) { 102 | sError = "edges dataset has incorrect shape."; 103 | goto cleanup; 104 | } 105 | assert(shape[0] * 2 == bufferIJ.size()); 106 | } 107 | std::size_t* ptr = &bufferIJ[0]; 108 | { 109 | unsigned char multipleEdgesEnabled; 110 | load(groupHandle, "multiple-edges-enabled", multipleEdgesEnabled); 111 | graph.multipleEdgesEnabled() = static_cast(multipleEdgesEnabled); 112 | } 113 | for(std::size_t i=0;i= numberOfVertices || t >= numberOfVertices) { 117 | sError = "vertex index out of bounds."; 118 | goto cleanup; 119 | } 120 | const std::size_t e = graph.insertEdge(s, t); 121 | } 122 | } 123 | } catch(std::exception& e) { 124 | sError = e.what(); 125 | } 126 | 127 | cleanup: 128 | closeGroup(groupHandle); 129 | if(!sError.empty()) { 130 | throw std::runtime_error("error loading graph: " + sError); 131 | } 132 | } 133 | 134 | } //namespace hdf 135 | } //namespace graph 136 | } //namespace andres 137 | 138 | 139 | #endif // #ifndef ANDRES_GRAPH_GRAPH_HDF5_HXX 140 | -------------------------------------------------------------------------------- /include/andres/graph/hdf5/digraph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_DIGRAPH_HDF5_HXX 3 | #define ANDRES_GRAPH_DIGRAPH_HDF5_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "hdf5.hxx" 10 | #include "../digraph.hxx" 11 | 12 | namespace andres { 13 | namespace graph { 14 | namespace hdf5 { 15 | 16 | template 17 | struct GraphTraitsHDF5 > { 18 | static const int ID; 19 | }; 20 | template 21 | const int GraphTraitsHDF5 >::ID = 10001; 22 | 23 | template 24 | void save(const hid_t, const std::string&, const Digraph&); 25 | 26 | template 27 | void load(const hid_t, const std::string&, Digraph&); 28 | 29 | template 30 | void 31 | save( 32 | const hid_t parentHandle, 33 | const std::string& graphName, 34 | const Digraph& graph 35 | ) { 36 | HandleCheck handleCheck; 37 | hid_t groupHandle = openGroup(parentHandle, graphName,true); 38 | 39 | try { 40 | save(groupHandle, "graph-type-id", GraphTraitsHDF5 >::ID); 41 | save(groupHandle, "multiple-edges-enabled", static_cast(graph.multipleEdgesEnabled())); 42 | save(groupHandle, "number-of-vertices", graph.numberOfVertices()); 43 | save(groupHandle, "number-of-edges", graph.numberOfEdges()); 44 | if(graph.numberOfEdges() != 0) { 45 | std::vector vecIJ; 46 | vecIJ.resize(2 * graph.numberOfEdges()); 47 | std::size_t *ptr = &vecIJ[0]; 48 | for(std::size_t e=0; e 63 | void 64 | load( 65 | const hid_t parentHandle, 66 | const std::string& graphName, 67 | Digraph& graph 68 | ) { 69 | HandleCheck handleCheck; 70 | hid_t groupHandle = openGroup(parentHandle, graphName); 71 | 72 | std::string sError; 73 | 74 | try { 75 | int id = 0; 76 | load(groupHandle, "graph-type-id", id); 77 | if(id != GraphTraitsHDF5 >::ID) { 78 | sError = "graph type id mismatch."; 79 | goto cleanup; 80 | } 81 | 82 | std::size_t numberOfVertices = 0; 83 | load(groupHandle, "number-of-vertices", numberOfVertices); 84 | 85 | std::size_t numberOfEdges = 0; 86 | load(groupHandle, "number-of-edges", numberOfEdges); 87 | 88 | graph.assign(numberOfVertices); 89 | 90 | if(numberOfEdges != 0) { 91 | graph.reserveEdges(numberOfEdges); 92 | 93 | std::vector bufferIJ; 94 | { 95 | std::vector shape; 96 | load(groupHandle, "edges", shape, bufferIJ); 97 | if(shape.size() != 2) { 98 | sError = "edges dataset is not 2-dimensional."; 99 | goto cleanup; 100 | } 101 | if(shape[0] != numberOfEdges || shape[1] != 2) { 102 | sError = "edges dataset has incorrect shape."; 103 | goto cleanup; 104 | } 105 | assert(shape[0] * 2 == bufferIJ.size()); 106 | } 107 | std::size_t* ptr = &bufferIJ[0]; 108 | { 109 | unsigned char multipleEdgesEnabled; 110 | load(groupHandle, "multiple-edges-enabled", multipleEdgesEnabled); 111 | graph.multipleEdgesEnabled() = static_cast(multipleEdgesEnabled); 112 | } 113 | for(std::size_t i=0;i= numberOfVertices || t >= numberOfVertices) { 117 | sError = "vertex index out of bounds."; 118 | goto cleanup; 119 | } 120 | const std::size_t e = graph.insertEdge(s, t); 121 | } 122 | } 123 | } catch(std::exception& e) { 124 | sError = e.what(); 125 | } 126 | 127 | cleanup: 128 | closeGroup(groupHandle); 129 | if(!sError.empty()) { 130 | throw std::runtime_error("error loading digraph: " + sError); 131 | } 132 | } 133 | 134 | } //namespace hdf 135 | } //namespace graph 136 | } //namespace andres 137 | 138 | #endif // #ifndef ANDRES_GRAPH_DIGRAPH_HDF5_HXX 139 | -------------------------------------------------------------------------------- /src/tclap/XorHandler.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: XorHandler.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef TCLAP_XORHANDLER_H 24 | #define TCLAP_XORHANDLER_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace TCLAP { 33 | 34 | /** 35 | * This class handles lists of Arg's that are to be XOR'd on the command 36 | * line. This is used by CmdLine and you shouldn't ever use it. 37 | */ 38 | class XorHandler 39 | { 40 | protected: 41 | 42 | /** 43 | * The list of of lists of Arg's to be or'd together. 44 | */ 45 | std::vector< std::vector > _orList; 46 | 47 | public: 48 | 49 | /** 50 | * Constructor. Does nothing. 51 | */ 52 | XorHandler( ) : _orList(std::vector< std::vector >()) {} 53 | 54 | /** 55 | * Add a list of Arg*'s that will be orred together. 56 | * \param ors - list of Arg* that will be xor'd. 57 | */ 58 | void add( std::vector& ors ); 59 | 60 | /** 61 | * Checks whether the specified Arg is in one of the xor lists and 62 | * if it does match one, returns the size of the xor list that the 63 | * Arg matched. If the Arg matches, then it also sets the rest of 64 | * the Arg's in the list. You shouldn't use this. 65 | * \param a - The Arg to be checked. 66 | */ 67 | int check( const Arg* a ); 68 | 69 | /** 70 | * Returns the XOR specific short usage. 71 | */ 72 | std::string shortUsage(); 73 | 74 | /** 75 | * Prints the XOR specific long usage. 76 | * \param os - Stream to print to. 77 | */ 78 | void printLongUsage(std::ostream& os); 79 | 80 | /** 81 | * Simply checks whether the Arg is contained in one of the arg 82 | * lists. 83 | * \param a - The Arg to be checked. 84 | */ 85 | bool contains( const Arg* a ); 86 | 87 | std::vector< std::vector >& getXorList(); 88 | 89 | }; 90 | 91 | 92 | ////////////////////////////////////////////////////////////////////// 93 | //BEGIN XOR.cpp 94 | ////////////////////////////////////////////////////////////////////// 95 | inline void XorHandler::add( std::vector& ors ) 96 | { 97 | _orList.push_back( ors ); 98 | } 99 | 100 | inline int XorHandler::check( const Arg* a ) 101 | { 102 | // iterate over each XOR list 103 | for ( int i = 0; static_cast(i) < _orList.size(); i++ ) 104 | { 105 | // if the XOR list contains the arg.. 106 | ArgVectorIterator ait = std::find( _orList[i].begin(), 107 | _orList[i].end(), a ); 108 | if ( ait != _orList[i].end() ) 109 | { 110 | // first check to see if a mutually exclusive switch 111 | // has not already been set 112 | for ( ArgVectorIterator it = _orList[i].begin(); 113 | it != _orList[i].end(); 114 | it++ ) 115 | if ( a != (*it) && (*it)->isSet() ) 116 | throw(CmdLineParseException( 117 | "Mutually exclusive argument already set!", 118 | (*it)->toString())); 119 | 120 | // go through and set each arg that is not a 121 | for ( ArgVectorIterator it = _orList[i].begin(); 122 | it != _orList[i].end(); 123 | it++ ) 124 | if ( a != (*it) ) 125 | (*it)->xorSet(); 126 | 127 | // return the number of required args that have now been set 128 | if ( (*ait)->allowMore() ) 129 | return 0; 130 | else 131 | return static_cast(_orList[i].size()); 132 | } 133 | } 134 | 135 | if ( a->isRequired() ) 136 | return 1; 137 | else 138 | return 0; 139 | } 140 | 141 | inline bool XorHandler::contains( const Arg* a ) 142 | { 143 | for ( int i = 0; static_cast(i) < _orList.size(); i++ ) 144 | for ( ArgVectorIterator it = _orList[i].begin(); 145 | it != _orList[i].end(); 146 | it++ ) 147 | if ( a == (*it) ) 148 | return true; 149 | 150 | return false; 151 | } 152 | 153 | inline std::vector< std::vector >& XorHandler::getXorList() 154 | { 155 | return _orList; 156 | } 157 | 158 | 159 | 160 | ////////////////////////////////////////////////////////////////////// 161 | //END XOR.cpp 162 | ////////////////////////////////////////////////////////////////////// 163 | 164 | } //namespace TCLAP 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /src/command-line-tools/probabilistic-lifting.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PROBABILISTIC_LIFTING 3 | #define PROBABILISTIC_LIFTING 4 | 5 | #include 6 | 7 | #include "fast-marching.hxx" 8 | 9 | /// Lift edge values from a source graph to a target graph. 10 | template 11 | void 12 | liftEdgeValues( 13 | const SOURCE_GRAPH& sourceGraph, 14 | const TARGET_GRAPH& targetGraph, 15 | const SOURCE_EDGE_VALUE_ITERATOR sit, 16 | TARGET_EDGE_VALUE_ITERATOR tit 17 | ) { 18 | typedef std::size_t size_type; 19 | typedef typename std::iterator_traits::value_type value_type; 20 | 21 | if(sourceGraph.numberOfVertices() != targetGraph.numberOfVertices()) 22 | throw std::runtime_error("number of vertices mismatch between source and target graph."); 23 | 24 | class SSSPVisitor 25 | { 26 | public: 27 | SSSPVisitor(std::vector& target_vertices, std::size_t number_of_target_vertices) : 28 | target_vertices_(target_vertices), vertices_left_(number_of_target_vertices) 29 | { } 30 | 31 | bool operator()(typename std::vector::iterator distances, typename std::vector::iterator parents, std::size_t v) 32 | { 33 | if (target_vertices_[v]) 34 | { 35 | target_vertices_[v] = 0; 36 | --vertices_left_; 37 | } 38 | 39 | return vertices_left_; 40 | } 41 | 42 | private: 43 | std::vector& target_vertices_; 44 | std::size_t vertices_left_ { 0 }; 45 | }; 46 | 47 | std::vector distances(sourceGraph.numberOfVertices()); 48 | std::vector parents(sourceGraph.numberOfVertices()); 49 | std::vector target_vertices(sourceGraph.numberOfVertices()); 50 | std::vector target_vertices_edges(sourceGraph.numberOfVertices()); 51 | 52 | #pragma omp parallel for firstprivate(distances, parents, target_vertices, target_vertices_edges) 53 | for(long int i = 0; i < targetGraph.numberOfVertices(); ++i) 54 | { 55 | std::fill(target_vertices.begin(), target_vertices.end(), char()); 56 | 57 | for (auto it = targetGraph.adjacenciesFromVertexBegin(i); it != targetGraph.adjacenciesFromVertexEnd(i); ++it) 58 | { 59 | target_vertices[it->vertex()] = 1; 60 | target_vertices_edges[it->vertex()] = it->edge(); 61 | } 62 | 63 | SSSPVisitor visitor(target_vertices, targetGraph.numberOfEdgesFromVertex(i)); 64 | 65 | andres::graph::sssp( 66 | sourceGraph, 67 | andres::graph::DefaultSubgraphMask<>(), 68 | i, 69 | sit, 70 | distances.begin(), // buffer 71 | parents.begin(), // buffer 72 | visitor 73 | ); 74 | 75 | #pragma omp critical 76 | { 77 | for (auto it = targetGraph.adjacenciesFromVertexBegin(i); it != targetGraph.adjacenciesFromVertexEnd(i); ++it) 78 | tit[it->edge()] = distances[it->vertex()]; 79 | } 80 | } 81 | 82 | // restore original edge weights 83 | for (std::size_t e = 0; e < sourceGraph.numberOfEdges(); ++e) 84 | { 85 | auto v0 = sourceGraph.vertexOfEdge(e, 0); 86 | auto v1 = sourceGraph.vertexOfEdge(e, 1); 87 | 88 | tit[targetGraph.findEdge(v0, v1).second] = sit[e]; 89 | } 90 | } 91 | 92 | /// Lift edge values from a 2-dimensional grid graph to a target graph. 93 | template 94 | void 95 | liftEdgeValues( 96 | const andres::graph::GridGraph<2, SOURCE_GRAPH_VISITOR>& sourceGraph, 97 | const TARGET_GRAPH& targetGraph, 98 | SOURCE_EDGE_VALUE_ITERATOR sit, 99 | TARGET_EDGE_VALUE_ITERATOR tit, 100 | const std::size_t interpolationOrder = 0 101 | ) { 102 | typedef std::size_t size_type; 103 | typedef typename std::iterator_traits::value_type target_value_type; 104 | 105 | if(sourceGraph.numberOfVertices() != targetGraph.numberOfVertices()) { 106 | throw std::runtime_error("number of vertices mismatch between source and target graph."); 107 | } 108 | 109 | std::size_t cnt = 0; 110 | FastMarchingBuffers buffers(sourceGraph.numberOfVertices()); 111 | 112 | #pragma omp parallel for firstprivate(buffers) 113 | for(size_type v = 0; v < targetGraph.numberOfVertices(); ++v) 114 | fastMarching( 115 | sourceGraph, 116 | sit, 117 | v, 118 | targetGraph, 119 | tit, 120 | interpolationOrder, 121 | buffers 122 | ); 123 | 124 | // restore original edge weights 125 | for (std::size_t e = 0; e < sourceGraph.numberOfEdges(); ++e) 126 | { 127 | auto v0 = sourceGraph.vertexOfEdge(e, 0); 128 | auto v1 = sourceGraph.vertexOfEdge(e, 1); 129 | 130 | tit[targetGraph.findEdge(v0, v1).second] = sit[e]; 131 | } 132 | } 133 | 134 | #endif -------------------------------------------------------------------------------- /include/nl-lmp/detail/update-class-labels.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef NL_LMP_UPDATE_CLASS_LABELS_HXX 3 | #define NL_LMP_UPDATE_CLASS_LABELS_HXX 4 | 5 | #include 6 | #include 7 | 8 | #include "../problem.hxx" 9 | #include "../solution.hxx" 10 | 11 | 12 | 13 | namespace nl_lmp 14 | { 15 | 16 | namespace detail 17 | { 18 | 19 | template 20 | inline 21 | double update_class_labels(Problem const& problem, Solution const& input, Solution& output) 22 | { 23 | struct entry 24 | { 25 | entry(double __gain, size_t __v, size_t __k, size_t __edition = 0) : 26 | gain(__gain), v(__v), k(__k), edition(__edition) 27 | {} 28 | 29 | bool operator <(entry const& other) const 30 | { 31 | return gain < other.gain; 32 | } 33 | 34 | double gain; 35 | size_t v; 36 | size_t k; 37 | size_t edition; 38 | }; 39 | 40 | auto const number_of_labels = problem.numberOfClasses(); 41 | 42 | output = input; 43 | 44 | std::priority_queue Q; 45 | std::vector gains(problem.numberOfVertices() * number_of_labels); 46 | 47 | for (size_t v = 0; v < problem.numberOfVertices(); ++v) 48 | { 49 | double best_gain = .0; 50 | size_t best_label = 0; 51 | 52 | auto const v_label = input[v].classIndex; 53 | 54 | for (size_t k = 0; k < number_of_labels; ++k) 55 | { 56 | auto gain = problem.getUnaryCost(v, v_label) - problem.getUnaryCost(v, k); 57 | 58 | for (auto it = problem.liftedGraph().adjacenciesFromVertexBegin(v); it != problem.liftedGraph().adjacenciesFromVertexEnd(v); ++it) 59 | { 60 | auto const e = it->edge(); 61 | auto const w = it->vertex(); 62 | 63 | auto const w_label = input[w].classIndex; 64 | 65 | if (input[v].clusterIndex == input[w].clusterIndex) 66 | gain += problem.getPairwiseJoinCost(v, w, v_label, w_label) - problem.getPairwiseJoinCost(v, w, k, w_label); 67 | else 68 | gain += problem.getPairwiseCutCost(v, w, v_label, w_label) - problem.getPairwiseCutCost(v, w, k, w_label); 69 | } 70 | 71 | if (gain > best_gain) 72 | { 73 | best_gain = gain; 74 | best_label = k; 75 | } 76 | 77 | gains[v*number_of_labels + k] = gain; 78 | } 79 | 80 | if (best_gain > 1e-6) 81 | Q.push(entry(best_gain, v, best_label)); 82 | } 83 | 84 | std::vector visited(problem.numberOfVertices()); 85 | std::vector vertex_editions(problem.numberOfVertices()); 86 | 87 | double total_gain = .0; 88 | while (!Q.empty()) 89 | { 90 | auto const ent = Q.top(); 91 | Q.pop(); 92 | 93 | if (visited[ent.v] || ent.edition < vertex_editions[ent.v]) 94 | continue; 95 | 96 | total_gain += ent.gain; 97 | 98 | auto const v_former_label = output[ent.v].classIndex; 99 | output[ent.v].classIndex = ent.k; 100 | visited[ent.v] = 1; 101 | 102 | for (auto it = problem.liftedGraph().adjacenciesFromVertexBegin(ent.v); it != problem.liftedGraph().adjacenciesFromVertexEnd(ent.v); ++it) 103 | { 104 | auto const w = it->vertex(); 105 | 106 | if (!visited[w]) 107 | { 108 | auto const e = it->edge(); 109 | auto const w_label = output[w].classIndex; 110 | 111 | double best_gain = .0; 112 | size_t best_label = 0; 113 | 114 | for (size_t k = 0; k < number_of_labels; ++k) 115 | { 116 | // cancel previous contribution and add the new one 117 | if (output[ent.v].clusterIndex == output[w].clusterIndex) 118 | { 119 | gains[w*number_of_labels + k] -= problem.getPairwiseJoinCost(w, ent.v, w_label, v_former_label, e) - problem.getPairwiseJoinCost(w, ent.v, k, v_former_label, e); 120 | gains[w*number_of_labels + k] += problem.getPairwiseJoinCost(w, ent.v, w_label, ent.k, e) - problem.getPairwiseJoinCost(w, ent.v, k, ent.k, e); 121 | } 122 | else 123 | { 124 | gains[w*number_of_labels + k] -= problem.getPairwiseCutCost(w, ent.v, w_label, v_former_label, e) - problem.getPairwiseCutCost(w, ent.v, k, v_former_label, e); 125 | gains[w*number_of_labels + k] += problem.getPairwiseCutCost(w, ent.v, w_label, ent.k, e) - problem.getPairwiseCutCost(w, ent.v, k, ent.k, e); 126 | } 127 | 128 | if (gains[w*number_of_labels + k] > best_gain) 129 | { 130 | best_gain = gains[w*number_of_labels + k]; 131 | best_label = k; 132 | } 133 | } 134 | 135 | ++vertex_editions[w]; 136 | 137 | if (best_gain > 1e-6) 138 | Q.push(entry(best_gain, w, best_label, vertex_editions[w])); 139 | } 140 | } 141 | } 142 | 143 | return total_gain; 144 | } 145 | 146 | } // of namespace detail 147 | 148 | } // of namespace nl_lmp 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /src/tclap/StandardTraits.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: StandardTraits.h 6 | * 7 | * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | // This is an internal tclap file, you should probably not have to 24 | // include this directly 25 | 26 | #ifndef TCLAP_STANDARD_TRAITS_H 27 | #define TCLAP_STANDARD_TRAITS_H 28 | 29 | #ifdef HAVE_CONFIG_H 30 | #include // To check for long long 31 | #endif 32 | 33 | // If Microsoft has already typedef'd wchar_t as an unsigned 34 | // short, then compiles will break because it's as if we're 35 | // creating ArgTraits twice for unsigned short. Thus... 36 | #ifdef _MSC_VER 37 | #ifndef _NATIVE_WCHAR_T_DEFINED 38 | #define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS 39 | #endif 40 | #endif 41 | 42 | namespace TCLAP { 43 | 44 | // ====================================================================== 45 | // Integer types 46 | // ====================================================================== 47 | 48 | /** 49 | * longs have value-like semantics. 50 | */ 51 | template<> 52 | struct ArgTraits { 53 | typedef ValueLike ValueCategory; 54 | }; 55 | 56 | /** 57 | * ints have value-like semantics. 58 | */ 59 | template<> 60 | struct ArgTraits { 61 | typedef ValueLike ValueCategory; 62 | }; 63 | 64 | /** 65 | * shorts have value-like semantics. 66 | */ 67 | template<> 68 | struct ArgTraits { 69 | typedef ValueLike ValueCategory; 70 | }; 71 | 72 | /** 73 | * chars have value-like semantics. 74 | */ 75 | template<> 76 | struct ArgTraits { 77 | typedef ValueLike ValueCategory; 78 | }; 79 | 80 | #ifdef HAVE_LONG_LONG 81 | /** 82 | * long longs have value-like semantics. 83 | */ 84 | template<> 85 | struct ArgTraits { 86 | typedef ValueLike ValueCategory; 87 | }; 88 | #endif 89 | 90 | // ====================================================================== 91 | // Unsigned integer types 92 | // ====================================================================== 93 | 94 | /** 95 | * unsigned longs have value-like semantics. 96 | */ 97 | template<> 98 | struct ArgTraits { 99 | typedef ValueLike ValueCategory; 100 | }; 101 | 102 | /** 103 | * unsigned ints have value-like semantics. 104 | */ 105 | template<> 106 | struct ArgTraits { 107 | typedef ValueLike ValueCategory; 108 | }; 109 | 110 | /** 111 | * unsigned shorts have value-like semantics. 112 | */ 113 | template<> 114 | struct ArgTraits { 115 | typedef ValueLike ValueCategory; 116 | }; 117 | 118 | /** 119 | * unsigned chars have value-like semantics. 120 | */ 121 | template<> 122 | struct ArgTraits { 123 | typedef ValueLike ValueCategory; 124 | }; 125 | 126 | // Microsoft implements size_t awkwardly. 127 | #if defined(_MSC_VER) && defined(_M_X64) 128 | /** 129 | * size_ts have value-like semantics. 130 | */ 131 | template<> 132 | struct ArgTraits { 133 | typedef ValueLike ValueCategory; 134 | }; 135 | #endif 136 | 137 | 138 | #ifdef HAVE_LONG_LONG 139 | /** 140 | * unsigned long longs have value-like semantics. 141 | */ 142 | template<> 143 | struct ArgTraits { 144 | typedef ValueLike ValueCategory; 145 | }; 146 | #endif 147 | 148 | // ====================================================================== 149 | // Float types 150 | // ====================================================================== 151 | 152 | /** 153 | * floats have value-like semantics. 154 | */ 155 | template<> 156 | struct ArgTraits { 157 | typedef ValueLike ValueCategory; 158 | }; 159 | 160 | /** 161 | * doubles have value-like semantics. 162 | */ 163 | template<> 164 | struct ArgTraits { 165 | typedef ValueLike ValueCategory; 166 | }; 167 | 168 | // ====================================================================== 169 | // Other types 170 | // ====================================================================== 171 | 172 | /** 173 | * bools have value-like semantics. 174 | */ 175 | template<> 176 | struct ArgTraits { 177 | typedef ValueLike ValueCategory; 178 | }; 179 | 180 | 181 | /** 182 | * wchar_ts have value-like semantics. 183 | */ 184 | #ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS 185 | template<> 186 | struct ArgTraits { 187 | typedef ValueLike ValueCategory; 188 | }; 189 | #endif 190 | 191 | /** 192 | * Strings have string like argument traits. 193 | */ 194 | template<> 195 | struct ArgTraits { 196 | typedef StringLike ValueCategory; 197 | }; 198 | 199 | template 200 | void SetString(T &dst, const std::string &src) 201 | { 202 | dst = src; 203 | } 204 | 205 | } // namespace 206 | 207 | #endif 208 | 209 | -------------------------------------------------------------------------------- /include/andres/graph/dfs.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_DFS_HXX 3 | #define ANDRES_GRAPH_DFS_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "subgraph.hxx" 12 | 13 | namespace andres { 14 | namespace graph { 15 | 16 | template 17 | class DepthFirstSearchData { 18 | public: 19 | typedef S size_type; 20 | 21 | DepthFirstSearchData(const size_type size) 22 | : visited_(size) 23 | {} 24 | template 25 | DepthFirstSearchData(const GRAPH& graph) 26 | : visited_(graph.numberOfVertices()) 27 | {} 28 | void add(const size_type v) 29 | { stack_.push(v); } 30 | void clearStack() 31 | { stack_ = std::stack(); } 32 | bool empty() const 33 | { return stack_.empty(); } 34 | void markAllNotvisited() 35 | { std::fill(visited_.begin(), visited_.end(), 0); } 36 | size_type next() 37 | { const size_type v = stack_.top(); stack_.pop(); return v; } 38 | unsigned char& visited(const size_type v) 39 | { return visited_[v]; } 40 | unsigned char visited(const size_type v) const 41 | { return visited_[v]; } 42 | 43 | private: 44 | std::vector visited_; 45 | std::stack stack_; 46 | }; 47 | 48 | template 49 | inline void 50 | depthFirstSearch( 51 | const GRAPH& g, 52 | const std::size_t start_vertex, 53 | CALLBACK& callback 54 | ) 55 | { 56 | DepthFirstSearchData data(g); 57 | depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 58 | } 59 | 60 | template::value>::type> 61 | inline void 62 | depthFirstSearch( 63 | const GRAPH& g, 64 | const std::size_t start_vertex, 65 | CALLBACK&& callback 66 | ) 67 | { 68 | DepthFirstSearchData data(g); 69 | depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 70 | } 71 | 72 | template 73 | inline void 74 | depthFirstSearch( 75 | const GRAPH& g, 76 | const std::size_t start_vertex, 77 | CALLBACK& callback, 78 | DepthFirstSearchData& data 79 | ) 80 | { 81 | depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 82 | } 83 | 84 | template::value>::type> 85 | inline void 86 | depthFirstSearch( 87 | const GRAPH& g, 88 | const std::size_t start_vertex, 89 | CALLBACK&& callback, 90 | DepthFirstSearchData& data 91 | ) 92 | { 93 | depthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 94 | } 95 | 96 | template 97 | inline void 98 | depthFirstSearch( 99 | const GRAPH& g, 100 | const SUBGRAPH& subgraph_mask, 101 | const std::size_t start_vertex, 102 | CALLBACK& callback 103 | ) 104 | { 105 | DepthFirstSearchData data(g); 106 | depthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 107 | } 108 | 109 | template::value>::type> 110 | inline void 111 | depthFirstSearch( 112 | const GRAPH& g, 113 | const SUBGRAPH& subgraph_mask, 114 | const std::size_t start_vertex, 115 | CALLBACK&& callback 116 | ) 117 | { 118 | DepthFirstSearchData data(g); 119 | depthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 120 | } 121 | 122 | template 123 | inline void 124 | depthFirstSearch( 125 | const GRAPH& g, 126 | const SUBGRAPH& subgraph_mask, 127 | const std::size_t start_vertex, 128 | CALLBACK& callback, 129 | DepthFirstSearchData& data 130 | ) 131 | { 132 | assert(start_vertex < g.numberOfVertices()); 133 | 134 | data.add(start_vertex); 135 | 136 | while(!data.empty()) 137 | { 138 | auto v = data.next(); 139 | 140 | if (!data.visited(v)) 141 | { 142 | data.visited(v) = 1; 143 | 144 | bool proceed; 145 | bool addNeighbors; 146 | 147 | callback(v, proceed, addNeighbors); 148 | 149 | if (!proceed) 150 | { 151 | data.clearStack(); 152 | return; 153 | } 154 | 155 | if (addNeighbors) 156 | { 157 | auto e_it = g.edgesFromVertexBegin(v); 158 | for(auto it = g.verticesFromVertexBegin(v); it != g.verticesFromVertexEnd(v); ++it, ++e_it) 159 | if (!data.visited(*it) && subgraph_mask.vertex(*it) && subgraph_mask.edge(*e_it)) 160 | data.add(*it); 161 | } 162 | } 163 | } 164 | } 165 | 166 | template::value>::type> 167 | inline void 168 | depthFirstSearch( 169 | const GRAPH& g, 170 | const SUBGRAPH& subgraph_mask, 171 | const std::size_t start_vertex, 172 | CALLBACK&& callback, 173 | DepthFirstSearchData& data 174 | ) 175 | { 176 | depthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 177 | } 178 | 179 | } // namespace graph 180 | } // namespace andres 181 | 182 | #endif 183 | -------------------------------------------------------------------------------- /src/command-line-tools/lift-mp.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include "Timer.hpp" 15 | #include "probabilistic-lifting.hxx" 16 | 17 | 18 | 19 | using namespace std; 20 | using namespace andres; 21 | using namespace andres::graph; 22 | 23 | typedef double value_type; 24 | typedef size_t size_type; 25 | typedef vector ValueMap; 26 | 27 | struct Parameters { 28 | string inputHDF5FileName_; 29 | string outputHDF5FileName_; 30 | size_type upperDistanceBound_ { 1 }; 31 | size_type lowerDistanceBound_ { 0 }; 32 | bool probabilistic_ { true }; 33 | }; 34 | 35 | inline void 36 | parseCommandLine( 37 | int argc, 38 | char** argv, 39 | Parameters& parameters 40 | ) 41 | try 42 | { 43 | TCLAP::CmdLine tclap("lift-multicut-problem", ' ', "1.0"); 44 | TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName_, "INPUT_HDF5_FILE",tclap); 45 | TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf5-file", "hdf file (output)", true, parameters.outputHDF5FileName_, "OUTPUT_HDF5_FILE",tclap); 46 | TCLAP::ValueArg argUpperDistanceBound("u", "distance-upper-bound", "upper distance bound (inclusive)", false, parameters.upperDistanceBound_, "DIST_UPPER",tclap); 47 | TCLAP::ValueArg argLowerDistanceBound("l", "distance-lower-bound", "lower distance bound (non-inclusive)", false, parameters.lowerDistanceBound_, "DIST_LOWER",tclap); 48 | TCLAP::SwitchArg argNonProbabilistic("p", "non-probabilistic", "Assume inputs are not probabilities. By default, all inputs are assumed to be Logistic Probabilities. (Default: disabled).",tclap); 49 | 50 | tclap.parse(argc, argv); 51 | 52 | parameters.inputHDF5FileName_ = argInputHDF5FileName.getValue(); 53 | parameters.outputHDF5FileName_ = argOutputHDF5FileName.getValue(); 54 | parameters.upperDistanceBound_ = argUpperDistanceBound.getValue(); 55 | parameters.probabilistic_ = !argNonProbabilistic.getValue(); 56 | parameters.lowerDistanceBound_ = argLowerDistanceBound.getValue(); 57 | parameters.upperDistanceBound_ = argUpperDistanceBound.getValue(); 58 | } 59 | catch(TCLAP::ArgException& e) { 60 | throw runtime_error(e.error()); 61 | } 62 | 63 | void liftMulticutProblem( 64 | const Parameters& parameters, 65 | ostream& stream = cerr 66 | ) { 67 | { 68 | stream << "Liftin using neighbourhood defined by bounds (" << parameters.lowerDistanceBound_ 69 | << ","; 70 | 71 | if (parameters.upperDistanceBound_ == numeric_limits::max()) 72 | stream << "MAX"; 73 | else 74 | stream << parameters.upperDistanceBound_; 75 | 76 | stream << ")" << endl; 77 | } 78 | stream << "assuming Graph input." << endl; 79 | 80 | Graph<> graph; 81 | ValueMap edgeCutProbabilities; 82 | 83 | stream << "loading multicut problem from file: " << parameters.inputHDF5FileName_ << endl; 84 | { 85 | auto fileHandle = hdf5::openFile(parameters.inputHDF5FileName_); 86 | 87 | hdf5::load(fileHandle, "graph", graph); 88 | 89 | vector shape; 90 | hdf5::load(fileHandle, "edge-cut-probabilities", shape, edgeCutProbabilities); 91 | 92 | hdf5::closeFile(fileHandle); 93 | 94 | assert(shape.size() == 1); 95 | assert(shape[0] == graph.numberOfEdges()); 96 | } 97 | 98 | Timer t; 99 | t.start(); 100 | 101 | Graph<> graphLifted; 102 | lift(graph, graphLifted, parameters.upperDistanceBound_, parameters.lowerDistanceBound_); 103 | 104 | ValueMap edgeSplitProbabilitiesLifted(graphLifted.numberOfEdges()); 105 | if (parameters.probabilistic_) 106 | transform( 107 | edgeCutProbabilities.begin(), 108 | edgeCutProbabilities.end(), 109 | edgeCutProbabilities.begin(), 110 | ProbabilityToNegativeLogInverseProbability() 111 | ); 112 | 113 | liftEdgeValues( 114 | graph, 115 | graphLifted, 116 | edgeCutProbabilities.begin(), 117 | edgeSplitProbabilitiesLifted.begin() 118 | ); 119 | 120 | if (parameters.probabilistic_) 121 | transform( 122 | edgeSplitProbabilitiesLifted.begin(), 123 | edgeSplitProbabilitiesLifted.end(), 124 | edgeSplitProbabilitiesLifted.begin(), 125 | NegativeLogProbabilityToInverseProbability() 126 | ); 127 | 128 | t.stop(); 129 | 130 | stream << "saving Lifted Multicut as HDF5 file: " << parameters.outputHDF5FileName_ << endl; 131 | auto file = hdf5::createFile(parameters.outputHDF5FileName_); 132 | hdf5::save(file, "graph", graph); 133 | hdf5::save(file, "graph-lifted", graphLifted); 134 | hdf5::save(file, "lifting-time", t.get_elapsed_seconds()); 135 | hdf5::save(file, "edge-cut-probabilities", { graphLifted.numberOfEdges() }, edgeSplitProbabilitiesLifted.data()); 136 | hdf5::closeFile(file); 137 | } 138 | 139 | int main(int argc, char** argv) 140 | try 141 | { 142 | Parameters parameters; 143 | 144 | parseCommandLine(argc, argv, parameters); 145 | liftMulticutProblem(parameters); 146 | 147 | return 0; 148 | } 149 | catch(const runtime_error& error) 150 | { 151 | cerr << "error creating multicut problem: " << error.what() << endl; 152 | return 1; 153 | } -------------------------------------------------------------------------------- /src/andres/graph/unit-test/bfs.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "andres/graph/graph.hxx" 4 | #include "andres/graph/bfs.hxx" 5 | 6 | inline void test(const bool condition) { 7 | if(!condition) throw std::logic_error("test failed."); 8 | } 9 | 10 | struct SimpleCallback { 11 | SimpleCallback() 12 | : vertexIndices_(), 13 | depths_() 14 | {} 15 | void operator()( 16 | const std::size_t v, 17 | const std::size_t depth, 18 | bool& proceed, 19 | bool& add 20 | ) { 21 | vertexIndices_.push_back(v); 22 | depths_.push_back(depth); 23 | proceed = true; 24 | add = true; 25 | } 26 | 27 | std::vector vertexIndices_; 28 | std::vector depths_; 29 | }; 30 | 31 | struct SearchCallback { 32 | SearchCallback(const std::size_t vertexIndex) 33 | : vertexIndex_(vertexIndex), 34 | vertexIndices_(), 35 | depths_() 36 | {} 37 | void operator()( 38 | const std::size_t v, 39 | const std::size_t depth, 40 | bool& proceed, 41 | bool& add 42 | ) { 43 | vertexIndices_.push_back(v); 44 | depths_.push_back(depth); 45 | proceed = (v != vertexIndex_); 46 | add = true; 47 | } 48 | 49 | std::size_t vertexIndex_; 50 | std::vector vertexIndices_; 51 | std::vector depths_; 52 | }; 53 | 54 | struct BlockingCallback { 55 | BlockingCallback(const std::size_t vertexIndex) 56 | : vertexIndex_(vertexIndex), 57 | vertexIndices_(), 58 | depths_() 59 | {} 60 | void operator()( 61 | const std::size_t v, 62 | const std::size_t depth, 63 | bool& proceed, 64 | bool& add 65 | ) { 66 | vertexIndices_.push_back(v); 67 | depths_.push_back(depth); 68 | proceed = true; 69 | add = (v != vertexIndex_); 70 | } 71 | 72 | std::size_t vertexIndex_; 73 | std::vector vertexIndices_; 74 | std::vector depths_; 75 | }; 76 | 77 | int main() { 78 | andres::graph::Graph<> g; 79 | g.insertVertices(7); 80 | g.insertEdge(0, 1); 81 | g.insertEdge(0, 2); 82 | g.insertEdge(0, 4); 83 | g.insertEdge(1, 3); 84 | g.insertEdge(1, 5); 85 | g.insertEdge(2, 6); 86 | g.insertEdge(4, 5); 87 | 88 | { 89 | SimpleCallback callback; 90 | andres::graph::breadthFirstSearch(g, 0, callback); 91 | test(callback.vertexIndices_.size() == 7); 92 | test(callback.vertexIndices_[0] == 0); 93 | test(callback.vertexIndices_[1] == 1); 94 | test(callback.vertexIndices_[2] == 2); 95 | test(callback.vertexIndices_[3] == 4); 96 | test(callback.vertexIndices_[4] == 3); 97 | test(callback.vertexIndices_[5] == 5); 98 | test(callback.vertexIndices_[6] == 6); 99 | test(callback.depths_[0] == 0); 100 | test(callback.depths_[1] == 1); 101 | test(callback.depths_[2] == 1); 102 | test(callback.depths_[3] == 1); 103 | test(callback.depths_[4] == 2); 104 | test(callback.depths_[5] == 2); 105 | test(callback.depths_[6] == 2); 106 | } 107 | 108 | { 109 | SearchCallback callback(2); 110 | andres::graph::breadthFirstSearch(g, 0, callback); 111 | test(callback.vertexIndices_.size() == 3); 112 | test(callback.vertexIndices_[0] == 0); 113 | test(callback.vertexIndices_[1] == 1); 114 | test(callback.vertexIndices_[2] == 2); 115 | test(callback.depths_[0] == 0); 116 | test(callback.depths_[1] == 1); 117 | test(callback.depths_[2] == 1); 118 | } 119 | 120 | { 121 | BlockingCallback callback(2); 122 | andres::graph::breadthFirstSearch(g, 0, callback); 123 | test(callback.vertexIndices_.size() == 6); 124 | test(callback.vertexIndices_[0] == 0); 125 | test(callback.vertexIndices_[1] == 1); 126 | test(callback.vertexIndices_[2] == 2); 127 | test(callback.vertexIndices_[3] == 4); 128 | test(callback.vertexIndices_[4] == 3); 129 | test(callback.vertexIndices_[5] == 5); 130 | test(callback.depths_[0] == 0); 131 | test(callback.depths_[1] == 1); 132 | test(callback.depths_[2] == 1); 133 | test(callback.depths_[3] == 1); 134 | test(callback.depths_[4] == 2); 135 | test(callback.depths_[5] == 2); 136 | } 137 | 138 | // disconnected graph 139 | g.insertVertices(2); 140 | g.insertEdge(7, 8); 141 | 142 | { 143 | SimpleCallback callback; 144 | andres::graph::breadthFirstSearch(g, 0, callback); 145 | andres::graph::breadthFirstSearch(g, 7, callback); 146 | test(callback.vertexIndices_.size() == 9); 147 | test(callback.vertexIndices_[0] == 0); 148 | test(callback.vertexIndices_[1] == 1); 149 | test(callback.vertexIndices_[2] == 2); 150 | test(callback.vertexIndices_[3] == 4); 151 | test(callback.vertexIndices_[4] == 3); 152 | test(callback.vertexIndices_[5] == 5); 153 | test(callback.vertexIndices_[6] == 6); 154 | test(callback.vertexIndices_[7] == 7); 155 | test(callback.vertexIndices_[8] == 8); 156 | test(callback.depths_[0] == 0); 157 | test(callback.depths_[1] == 1); 158 | test(callback.depths_[2] == 1); 159 | test(callback.depths_[3] == 1); 160 | test(callback.depths_[4] == 2); 161 | test(callback.depths_[5] == 2); 162 | test(callback.depths_[6] == 2); 163 | test(callback.depths_[7] == 0); 164 | test(callback.depths_[8] == 1); 165 | } 166 | 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /include/andres/graph/multicut/greedy-fixation.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "andres/partition.hxx" 14 | 15 | namespace andres { 16 | namespace graph { 17 | namespace multicut { 18 | 19 | /// Greedy agglomerative decomposition of a graph. 20 | /// 21 | template 22 | void greedyFixation( 23 | const GRAPH& graph, 24 | EVA const& edge_values, 25 | ELA& edge_labels 26 | ) 27 | { 28 | class DynamicGraph 29 | { 30 | public: 31 | DynamicGraph(size_t n) : 32 | vertices_(n), cut_edges_(n) 33 | {} 34 | 35 | bool edgeExists(size_t a, size_t b) const 36 | { 37 | return !vertices_[a].empty() && vertices_[a].find(b) != vertices_[a].end(); 38 | } 39 | 40 | std::unordered_map const& getAdjacentVertices(size_t v) const 41 | { 42 | return vertices_[v]; 43 | } 44 | 45 | typename EVA::value_type getEdgeWeight(size_t a, size_t b) const 46 | { 47 | return vertices_[a].at(b); 48 | } 49 | 50 | bool isCutEdge(size_t a, size_t b) const 51 | { 52 | return !cut_edges_[a].empty() && cut_edges_[a].find(b) != cut_edges_[a].end(); 53 | } 54 | 55 | void markEdgeCut(size_t a, size_t b) 56 | { 57 | cut_edges_[a].insert(b); 58 | cut_edges_[b].insert(a); 59 | } 60 | 61 | void removeVertex(size_t v) 62 | { 63 | for (auto& p : vertices_[v]) 64 | { 65 | vertices_[p.first].erase(v); 66 | cut_edges_[p.first].erase(v); 67 | } 68 | 69 | vertices_[v].clear(); 70 | cut_edges_[v].clear(); 71 | } 72 | 73 | void setEdgeWeight(size_t a, size_t b, typename EVA::value_type w) 74 | { 75 | vertices_[a][b] = w; 76 | vertices_[b][a] = w; 77 | } 78 | 79 | private: 80 | std::vector> cut_edges_; 81 | std::vector> vertices_; 82 | }; 83 | 84 | struct Edge 85 | { 86 | Edge(size_t _a, size_t _b, typename EVA::value_type _w) 87 | { 88 | if (_a > _b) 89 | std::swap(_a, _b); 90 | 91 | a = _a; 92 | b = _b; 93 | 94 | w = _w; 95 | } 96 | 97 | size_t a; 98 | size_t b; 99 | size_t edition; 100 | typename EVA::value_type w; 101 | 102 | bool operator <(Edge const& other) const 103 | { 104 | return std::abs(w) < std::abs(other.w); 105 | } 106 | }; 107 | 108 | std::vector> edge_editions(graph.numberOfVertices()); 109 | (graph.numberOfVertices()); 110 | 111 | DynamicGraph original_graph_cp(graph.numberOfVertices()); 112 | std::priority_queue Q; 113 | 114 | for (size_t i = 0; i < graph.numberOfEdges(); ++i) 115 | { 116 | auto a = graph.vertexOfEdge(i, 0); 117 | auto b = graph.vertexOfEdge(i, 1); 118 | 119 | original_graph_cp.setEdgeWeight(a, b, edge_values[i]); 120 | 121 | auto e = Edge(a, b, edge_values[i]); 122 | e.edition = ++edge_editions[e.a][e.b]; 123 | 124 | Q.push(e); 125 | } 126 | 127 | andres::Partition partition(graph.numberOfVertices()); 128 | 129 | while (!Q.empty()) 130 | { 131 | auto edge = Q.top(); 132 | Q.pop(); 133 | 134 | if (!original_graph_cp.edgeExists(edge.a, edge.b) || edge.edition < edge_editions[edge.a][edge.b]) 135 | continue; 136 | 137 | if (edge.w > typename EVA::value_type() && !original_graph_cp.isCutEdge(edge.a, edge.b)) 138 | { 139 | auto stable_vertex = edge.a; 140 | auto merge_vertex = edge.b; 141 | 142 | if (original_graph_cp.getAdjacentVertices(stable_vertex).size() < original_graph_cp.getAdjacentVertices(merge_vertex).size()) 143 | std::swap(stable_vertex, merge_vertex); 144 | 145 | partition.merge(stable_vertex, merge_vertex); 146 | 147 | for (auto& p : original_graph_cp.getAdjacentVertices(merge_vertex)) 148 | { 149 | if (p.first == stable_vertex) 150 | continue; 151 | 152 | typename EVA::value_type t = typename EVA::value_type(); 153 | 154 | if (original_graph_cp.edgeExists(stable_vertex, p.first)) 155 | t = original_graph_cp.getEdgeWeight(stable_vertex, p.first); 156 | 157 | if (original_graph_cp.isCutEdge(merge_vertex, p.first)) 158 | original_graph_cp.markEdgeCut(stable_vertex, p.first); 159 | 160 | original_graph_cp.setEdgeWeight(stable_vertex, p.first, p.second + t); 161 | 162 | auto e = Edge(stable_vertex, p.first, p.second + t); 163 | e.edition = ++edge_editions[e.a][e.b]; 164 | 165 | Q.push(e); 166 | } 167 | 168 | original_graph_cp.removeVertex(merge_vertex); 169 | } 170 | else if (edge.w < typename EVA::value_type()) 171 | original_graph_cp.markEdgeCut(edge.a, edge.b); 172 | } 173 | 174 | for (size_t i = 0; i < graph.numberOfEdges(); ++i) 175 | edge_labels[i] = partition.find(graph.vertexOfEdge(i, 0)) == partition.find(graph.vertexOfEdge(i, 1)) ? 0 : 1; 176 | } 177 | 178 | } // namespace multicut 179 | } // namespace graph 180 | } // namespace andres 181 | -------------------------------------------------------------------------------- /src/tclap/ArgException.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: ArgException.h 6 | * 7 | * Copyright (c) 2003, Michael E. Smoot . 8 | * All rights reverved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | 24 | #ifndef TCLAP_ARG_EXCEPTION_H 25 | #define TCLAP_ARG_EXCEPTION_H 26 | 27 | #include 28 | #include 29 | 30 | namespace TCLAP { 31 | 32 | /** 33 | * A simple class that defines and argument exception. Should be caught 34 | * whenever a CmdLine is created and parsed. 35 | */ 36 | class ArgException : public std::exception 37 | { 38 | public: 39 | 40 | /** 41 | * Constructor. 42 | * \param text - The text of the exception. 43 | * \param id - The text identifying the argument source. 44 | * \param td - Text describing the type of ArgException it is. 45 | * of the exception. 46 | */ 47 | ArgException( const std::string& text = "undefined exception", 48 | const std::string& id = "undefined", 49 | const std::string& td = "Generic ArgException") 50 | : std::exception(), 51 | _errorText(text), 52 | _argId( id ), 53 | _typeDescription(td) 54 | { } 55 | 56 | /** 57 | * Destructor. 58 | */ 59 | virtual ~ArgException() throw() { } 60 | 61 | /** 62 | * Returns the error text. 63 | */ 64 | std::string error() const { return ( _errorText ); } 65 | 66 | /** 67 | * Returns the argument id. 68 | */ 69 | std::string argId() const 70 | { 71 | if ( _argId == "undefined" ) 72 | return " "; 73 | else 74 | return ( "Argument: " + _argId ); 75 | } 76 | 77 | /** 78 | * Returns the arg id and error text. 79 | */ 80 | const char* what() const throw() 81 | { 82 | static std::string ex; 83 | ex = _argId + " -- " + _errorText; 84 | return ex.c_str(); 85 | } 86 | 87 | /** 88 | * Returns the type of the exception. Used to explain and distinguish 89 | * between different child exceptions. 90 | */ 91 | std::string typeDescription() const 92 | { 93 | return _typeDescription; 94 | } 95 | 96 | 97 | private: 98 | 99 | /** 100 | * The text of the exception message. 101 | */ 102 | std::string _errorText; 103 | 104 | /** 105 | * The argument related to this exception. 106 | */ 107 | std::string _argId; 108 | 109 | /** 110 | * Describes the type of the exception. Used to distinguish 111 | * between different child exceptions. 112 | */ 113 | std::string _typeDescription; 114 | 115 | }; 116 | 117 | /** 118 | * Thrown from within the child Arg classes when it fails to properly 119 | * parse the argument it has been passed. 120 | */ 121 | class ArgParseException : public ArgException 122 | { 123 | public: 124 | /** 125 | * Constructor. 126 | * \param text - The text of the exception. 127 | * \param id - The text identifying the argument source 128 | * of the exception. 129 | */ 130 | ArgParseException( const std::string& text = "undefined exception", 131 | const std::string& id = "undefined" ) 132 | : ArgException( text, 133 | id, 134 | std::string( "Exception found while parsing " ) + 135 | std::string( "the value the Arg has been passed." )) 136 | { } 137 | }; 138 | 139 | /** 140 | * Thrown from CmdLine when the arguments on the command line are not 141 | * properly specified, e.g. too many arguments, required argument missing, etc. 142 | */ 143 | class CmdLineParseException : public ArgException 144 | { 145 | public: 146 | /** 147 | * Constructor. 148 | * \param text - The text of the exception. 149 | * \param id - The text identifying the argument source 150 | * of the exception. 151 | */ 152 | CmdLineParseException( const std::string& text = "undefined exception", 153 | const std::string& id = "undefined" ) 154 | : ArgException( text, 155 | id, 156 | std::string( "Exception found when the values ") + 157 | std::string( "on the command line do not meet ") + 158 | std::string( "the requirements of the defined ") + 159 | std::string( "Args." )) 160 | { } 161 | }; 162 | 163 | /** 164 | * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. 165 | * same flag as another Arg, same name, etc. 166 | */ 167 | class SpecificationException : public ArgException 168 | { 169 | public: 170 | /** 171 | * Constructor. 172 | * \param text - The text of the exception. 173 | * \param id - The text identifying the argument source 174 | * of the exception. 175 | */ 176 | SpecificationException( const std::string& text = "undefined exception", 177 | const std::string& id = "undefined" ) 178 | : ArgException( text, 179 | id, 180 | std::string("Exception found when an Arg object ")+ 181 | std::string("is improperly defined by the ") + 182 | std::string("developer." )) 183 | { } 184 | 185 | }; 186 | 187 | class ExitException { 188 | public: 189 | ExitException(int estat) : _estat(estat) {} 190 | 191 | int getExitStatus() const { return _estat; } 192 | 193 | private: 194 | int _estat; 195 | }; 196 | 197 | } // namespace TCLAP 198 | 199 | #endif 200 | 201 | -------------------------------------------------------------------------------- /include/andres/graph/components.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_COMPONENTS_HXX 3 | #define ANDRES_GRAPH_COMPONENTS_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | #include // std::fill 9 | 10 | #include "andres/partition.hxx" 11 | 12 | #include "subgraph.hxx" 13 | 14 | namespace andres { 15 | namespace graph { 16 | 17 | /// Connected component labeling by breadth-first-search (labels start at 0). 18 | template 19 | struct ComponentsBySearch { 20 | typedef GRAPH Graph; 21 | 22 | ComponentsBySearch(); 23 | std::size_t build(const Graph&); 24 | template 25 | std::size_t build(const Graph&, const SUBGRAPH_MASK&); 26 | bool areConnected(const std::size_t, const std::size_t) const; 27 | 28 | std::vector labels_; 29 | }; 30 | 31 | /// Connected component labeling using disjoint sets (labels start at 0). 32 | template 33 | struct ComponentsByPartition { 34 | typedef GRAPH Graph; 35 | 36 | ComponentsByPartition(); 37 | std::size_t build(const Graph&); 38 | template 39 | std::size_t build(const Graph&, const SUBGRAPH_MASK&); 40 | bool areConnected(const std::size_t, const std::size_t) const; 41 | 42 | andres::Partition partition_; 43 | }; 44 | 45 | /// Connected component labeling by breadth-first-search (labels start at 0). 46 | /// 47 | /// \param graph Graph. 48 | /// \param labeling Random access iterator to a container that has as many 49 | /// entries as there are vertices in the graph; all entries need to 50 | /// be initialized as 0 51 | /// 52 | template 53 | inline std::size_t 54 | labelComponents( 55 | const GRAPH& graph, 56 | ITERATOR labeling 57 | ) { 58 | return labelComponents(graph, DefaultSubgraphMask<>(), labeling); 59 | } 60 | 61 | /// Connected component labeling by breadth-first-search (labels start at 0). 62 | /// 63 | /// \param graph Graph. 64 | /// \param mask A subgraph mask such as DefaultSubgraphMask. 65 | /// \param labeling Random access iterator to a container that has as many 66 | /// entries as there are vertices in the graph; all entries need to 67 | /// be initialized as 0 68 | /// 69 | template 70 | std::size_t 71 | labelComponents( 72 | const GRAPH& graph, 73 | const SUBGRAPH_MASK& mask, 74 | ITERATOR labeling 75 | ) { 76 | std::size_t label = 0; 77 | std::vector visited(graph.numberOfVertices()); 78 | std::queue queue; 79 | for(std::size_t v = 0; v < graph.numberOfVertices(); ++v) { 80 | if(mask.vertex(v)) { 81 | if(!visited[v]) { 82 | labeling[v] = label; // label 83 | queue.push(v); 84 | visited[v] = 1; 85 | while(!queue.empty()) { 86 | std::size_t w = queue.front(); 87 | queue.pop(); 88 | for(typename GRAPH::AdjacencyIterator it = graph.adjacenciesFromVertexBegin(w); 89 | it != graph.adjacenciesFromVertexEnd(w); ++it) { 90 | if(mask.edge(it->edge()) 91 | && mask.vertex(it->vertex()) 92 | && !visited[it->vertex()]) { 93 | labeling[it->vertex()] = label; // label 94 | queue.push(it->vertex()); 95 | visited[it->vertex()] = 1; 96 | } 97 | } 98 | } 99 | label++; 100 | } 101 | } 102 | else { 103 | labeling[v] = 0; 104 | } 105 | } 106 | return label; 107 | } 108 | 109 | template 110 | inline 111 | ComponentsBySearch::ComponentsBySearch() 112 | : labels_() 113 | {} 114 | 115 | template 116 | inline std::size_t 117 | ComponentsBySearch::build( 118 | const Graph& graph 119 | ) { 120 | return build(graph, DefaultSubgraphMask<>()); 121 | } 122 | 123 | template 124 | template 125 | inline std::size_t 126 | ComponentsBySearch::build( 127 | const Graph& graph, 128 | const SUBGRAPH_MASK& mask 129 | ) { 130 | labels_.resize(graph.numberOfVertices()); 131 | return labelComponents(graph, mask, labels_.begin()); 132 | } 133 | 134 | template 135 | inline bool 136 | ComponentsBySearch::areConnected( 137 | const std::size_t vertex0, 138 | const std::size_t vertex1 139 | ) const { 140 | return labels_[vertex0] == labels_[vertex1]; 141 | } 142 | 143 | template 144 | inline 145 | ComponentsByPartition::ComponentsByPartition() 146 | : partition_() 147 | {} 148 | 149 | template 150 | inline std::size_t 151 | ComponentsByPartition::build( 152 | const Graph& graph 153 | ) { 154 | return build(graph, DefaultSubgraphMask<>()); 155 | } 156 | 157 | template 158 | template 159 | inline std::size_t 160 | ComponentsByPartition::build( 161 | const Graph& graph, 162 | const SUBGRAPH_MASK& mask 163 | ) { 164 | partition_.assign(graph.numberOfVertices()); 165 | for(std::size_t edge = 0; edge < graph.numberOfEdges(); ++edge) { 166 | if(mask.edge(edge)) { 167 | const std::size_t v0 = graph.vertexOfEdge(edge, 0); 168 | const std::size_t v1 = graph.vertexOfEdge(edge, 1); 169 | if(mask.vertex(v0) && mask.vertex(v1)) { 170 | partition_.merge(v0, v1); 171 | } 172 | } 173 | } 174 | return partition_.numberOfSets(); 175 | } 176 | 177 | template 178 | inline bool 179 | ComponentsByPartition::areConnected( 180 | const std::size_t vertex0, 181 | const std::size_t vertex1 182 | ) const { 183 | return partition_.find(vertex0) == partition_.find(vertex1); 184 | } 185 | 186 | } // namespace graph 187 | } // namespace andres 188 | 189 | #endif // #ifndef ANDRES_GRAPH_COMPONENTS_HXX 190 | -------------------------------------------------------------------------------- /include/andres/graph/bfs.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_BFS_HXX 3 | #define ANDRES_GRAPH_BFS_HXX 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "subgraph.hxx" 13 | 14 | namespace andres { 15 | namespace graph { 16 | 17 | template 18 | class BreadthFirstSearchData { 19 | public: 20 | typedef S size_type; 21 | 22 | static const size_type NOT_VISITED; 23 | 24 | BreadthFirstSearchData(const size_type size) 25 | : depth_(size, NOT_VISITED) 26 | {} 27 | template 28 | BreadthFirstSearchData(const GRAPH& graph) 29 | : depth_(graph.numberOfVertices(), NOT_VISITED) 30 | {} 31 | void add(const size_type v, const size_type depth) 32 | { depth_[v] = depth; queue_.push(v); } 33 | void clearQueue() 34 | { queue_ = std::queue(); } 35 | bool empty() const 36 | { return queue_.empty(); } 37 | void markAllNotvisited() 38 | { std::fill(depth_.begin(), depth_.end(), NOT_VISITED); } 39 | size_type next() 40 | { const size_type v = queue_.front(); queue_.pop(); return v; } 41 | size_type depth(const size_type v) const 42 | { return depth_[v]; } 43 | size_type& depth(const size_type v) 44 | { return depth_[v]; } 45 | 46 | private: 47 | std::vector depth_; 48 | std::queue queue_; 49 | }; 50 | template 51 | const S BreadthFirstSearchData::NOT_VISITED = std::numeric_limits::max(); 52 | 53 | template 54 | inline void 55 | breadthFirstSearch( 56 | const GRAPH& g, 57 | const std::size_t start_vertex, 58 | CALLBACK& callback 59 | ) 60 | { 61 | BreadthFirstSearchData data(g); 62 | breadthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 63 | } 64 | 65 | template::value>::type> 66 | inline void 67 | breadthFirstSearch( 68 | const GRAPH& g, 69 | const std::size_t start_vertex, 70 | CALLBACK&& callback 71 | ) 72 | { 73 | BreadthFirstSearchData data(g); 74 | breadthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 75 | } 76 | 77 | template 78 | inline void 79 | breadthFirstSearch( 80 | const GRAPH& g, 81 | const std::size_t start_vertex, 82 | CALLBACK& callback, 83 | BreadthFirstSearchData& data 84 | ) 85 | { 86 | breadthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 87 | } 88 | 89 | template::value>::type> 90 | inline void 91 | breadthFirstSearch( 92 | const GRAPH& g, 93 | const std::size_t start_vertex, 94 | CALLBACK&& callback, 95 | BreadthFirstSearchData& data 96 | ) 97 | { 98 | breadthFirstSearch(g, DefaultSubgraphMask<>(), start_vertex, callback, data); 99 | } 100 | 101 | template 102 | inline void 103 | breadthFirstSearch( 104 | const GRAPH& g, 105 | const SUBGRAPH& subgraph_mask, 106 | const std::size_t start_vertex, 107 | CALLBACK& callback 108 | ) 109 | { 110 | BreadthFirstSearchData data(g); 111 | breadthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 112 | } 113 | 114 | template::value>::type> 115 | inline void 116 | breadthFirstSearch( 117 | const GRAPH& g, 118 | const SUBGRAPH& subgraph_mask, 119 | const std::size_t start_vertex, 120 | CALLBACK&& callback 121 | ) 122 | { 123 | BreadthFirstSearchData data(g); 124 | breadthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 125 | } 126 | 127 | template 128 | inline void 129 | breadthFirstSearch( 130 | const GRAPH& g, 131 | const SUBGRAPH& subgraph_mask, 132 | const std::size_t start_vertex, 133 | CALLBACK& callback, 134 | BreadthFirstSearchData& data 135 | ) 136 | { 137 | assert(start_vertex < g.numberOfVertices()); 138 | 139 | { 140 | bool proceed; 141 | bool add; 142 | callback(start_vertex, 0, proceed, add); 143 | if(!proceed) { 144 | return; 145 | } 146 | if(add) { 147 | data.add(start_vertex, 0); 148 | } 149 | } 150 | while(!data.empty()) { 151 | const auto v = data.next(); 152 | const auto depth = data.depth(v) + 1; 153 | 154 | auto e_it = g.edgesFromVertexBegin(v); 155 | for(auto it = g.verticesFromVertexBegin(v); it != g.verticesFromVertexEnd(v); ++it, ++e_it) 156 | if(data.depth(*it) == BreadthFirstSearchData::NOT_VISITED && 157 | subgraph_mask.vertex(*it) && 158 | subgraph_mask.edge(*e_it)) 159 | { 160 | bool proceed; 161 | bool add; 162 | 163 | callback(*it, depth, proceed, add); 164 | 165 | if(!proceed) 166 | { 167 | data.clearQueue(); 168 | return; 169 | } 170 | 171 | if(add) 172 | data.add(*it, depth); 173 | } 174 | } 175 | } 176 | 177 | template::value>::type> 178 | inline void 179 | breadthFirstSearch( 180 | const GRAPH& g, 181 | const SUBGRAPH& subgraph_mask, 182 | const std::size_t start_vertex, 183 | CALLBACK&& callback, 184 | BreadthFirstSearchData& data 185 | ) 186 | { 187 | breadthFirstSearch(g, subgraph_mask, start_vertex, callback, data); 188 | } 189 | 190 | } // namespace graph 191 | } // namespace andres 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /include/andres/graph/multicut/cycle-packing.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_MULTICUT_CYCLE_PACKING_HXX 3 | #define ANDRES_GRAPH_MULTICUT_CYCLE_PACKING_HXX 4 | 5 | #include 6 | #include 7 | 8 | #include "andres/graph/components.hxx" 9 | #include "andres/graph/shortest-paths.hxx" 10 | #include "andres/graph/graph.hxx" 11 | 12 | namespace andres { 13 | namespace graph { 14 | namespace multicut { 15 | 16 | 17 | // Copyright (c) Jan-Hendrik Lange 2018 18 | // 19 | // Heuristic algorithm that computes a dual lower bound 20 | // by iteratively packing conflicted cycles. 21 | // 22 | // OUTPUT: - dual lower bound 23 | // - reduced primal cost vector associated with heuristic dual solution 24 | // 25 | template 26 | std::tuple 27 | iterativeCyclePacking(GRAPH const& graph_orig, ECA const& edgeCosts, bool verbose = false, size_t max_cycle_length = 0) 28 | { 29 | std::vector edge_costs(edgeCosts); 30 | 31 | std::vector> repulsive_edges; 32 | 33 | double lower_bound = 0; 34 | double const tolerance = std::numeric_limits::epsilon(); 35 | 36 | // copy attraction subgraph 37 | andres::graph::Graph<> graph(graph_orig.numberOfVertices()); 38 | graph.reserveEdges(graph_orig.numberOfEdges()); 39 | 40 | for (size_t e = 0; e < graph_orig.numberOfEdges(); e++) 41 | { 42 | auto v0 = graph_orig.vertexOfEdge(e, 0); 43 | auto v1 = graph_orig.vertexOfEdge(e, 1); 44 | 45 | if (edge_costs[e] > tolerance) 46 | graph.insertEdge(v0,v1); 47 | if (edge_costs[e] < -tolerance) 48 | { 49 | repulsive_edges.emplace_back(v0, v1); 50 | lower_bound += edge_costs[e]; 51 | } 52 | } 53 | 54 | if (verbose) 55 | { 56 | std::cout << "Conflicted cycle packing.." << std::endl; 57 | double trivial_bound = lower_bound; 58 | std::cout << "Trivial bound: " << trivial_bound << std::endl; 59 | } 60 | 61 | ComponentsBySearch> components; 62 | 63 | std::deque path; 64 | std::vector parents(graph.numberOfVertices()); 65 | std::vector labels(graph.numberOfVertices()); 66 | size_t seen_label = 0; 67 | 68 | size_t nCycles = 0; 69 | 70 | // check optional cycle length parameter 71 | if (max_cycle_length < 3) 72 | max_cycle_length = graph.numberOfEdges(); 73 | 74 | // iterative length cycle search 75 | for (size_t cycle_length = 3; cycle_length <= max_cycle_length; cycle_length++) 76 | { 77 | if (verbose) 78 | std::cout << "Round " << cycle_length-3 << ", L = " << lower_bound << std::endl; 79 | 80 | // update component labeling 81 | components.build(graph); 82 | 83 | size_t progress = 0; 84 | 85 | // shuffling can give great speed-up if edges with similar indices are spatially close in the graph 86 | std::random_shuffle(repulsive_edges.begin(), repulsive_edges.end()); 87 | 88 | std::vector> rem_repuls_edges; 89 | rem_repuls_edges.reserve(repulsive_edges.size()); 90 | 91 | // iterate over repulsive edges 92 | for (auto p : repulsive_edges) 93 | { 94 | // periodically update component labeling for speed-up 95 | progress++; 96 | if (progress > 0.1 * repulsive_edges.size()) 97 | { 98 | components.build(graph); 99 | progress = 0; 100 | } 101 | 102 | auto v0 = p.first; 103 | auto v1 = p.second; 104 | size_t f = graph_orig.findEdge(v0, v1).second; 105 | 106 | // check if conflicted cycle exists 107 | if (!components.areConnected(v0, v1)) 108 | continue; 109 | 110 | // pack short cycles as long as available and positive weight left 111 | while (edge_costs[f] < -tolerance) 112 | { 113 | seen_label++; 114 | if (seen_label == 0) 115 | { 116 | std::fill(labels.begin(), labels.end(), 0); 117 | seen_label++; 118 | } 119 | if (!spsp(graph, DefaultSubgraphMask<>(), v0, v1, path, parents, labels, seen_label, cycle_length-1)) 120 | break; 121 | 122 | // find minimum weight edge in cycle 123 | double min_weight = -edge_costs[f]; 124 | for (size_t j = 0; j < path.size() - 1; ++j) 125 | { 126 | auto e = graph_orig.findEdge(path[j], path[j + 1]).second; 127 | if (edge_costs[e] < min_weight) 128 | min_weight = edge_costs[e]; 129 | } 130 | // subtract minimum weight and delete edges of negligible weight 131 | edge_costs[f] += min_weight; 132 | for (size_t j = 0; j < path.size() - 1; ++j) 133 | { 134 | auto e = graph_orig.findEdge(path[j], path[j + 1]).second; 135 | edge_costs[e] -= min_weight; 136 | if (edge_costs[e] < tolerance) 137 | graph.eraseEdge(graph.findEdge(path[j], path[j+1]).second); 138 | } 139 | // update lower bound 140 | lower_bound += min_weight; 141 | nCycles++; 142 | } 143 | 144 | if (edge_costs[f] < -tolerance) 145 | rem_repuls_edges.emplace_back(v0, v1); 146 | } 147 | 148 | repulsive_edges = rem_repuls_edges; 149 | if (repulsive_edges.empty()) 150 | break; 151 | } 152 | 153 | if (verbose) 154 | { 155 | std::cout << "Improved bound: " << lower_bound << std::endl; 156 | std::cout << "Packed " << nCycles << " conflicted cycles." << std::endl; 157 | } 158 | 159 | return std::make_tuple(lower_bound, edge_costs); 160 | } 161 | 162 | 163 | } 164 | } // namespace graph 165 | } // namespace andres 166 | 167 | #endif // #ifndef ANDRES_GRAPH_MULTICUT_CYCLE_PACKING_HXX 168 | -------------------------------------------------------------------------------- /src/tclap/MultiSwitchArg.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: MultiSwitchArg.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. 8 | * Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek. 9 | * All rights reverved. 10 | * 11 | * See the file COPYING in the top directory of this distribution for 12 | * more information. 13 | * 14 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | * 22 | *****************************************************************************/ 23 | 24 | 25 | #ifndef TCLAP_MULTI_SWITCH_ARG_H 26 | #define TCLAP_MULTI_SWITCH_ARG_H 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | namespace TCLAP { 34 | 35 | /** 36 | * A multiple switch argument. If the switch is set on the command line, then 37 | * the getValue method will return the number of times the switch appears. 38 | */ 39 | class MultiSwitchArg : public SwitchArg 40 | { 41 | protected: 42 | 43 | /** 44 | * The value of the switch. 45 | */ 46 | int _value; 47 | 48 | /** 49 | * Used to support the reset() method so that ValueArg can be 50 | * reset to their constructed value. 51 | */ 52 | int _default; 53 | 54 | public: 55 | 56 | /** 57 | * MultiSwitchArg constructor. 58 | * \param flag - The one character flag that identifies this 59 | * argument on the command line. 60 | * \param name - A one word name for the argument. Can be 61 | * used as a long flag on the command line. 62 | * \param desc - A description of what the argument is for or 63 | * does. 64 | * \param init - Optional. The initial/default value of this Arg. 65 | * Defaults to 0. 66 | * \param v - An optional visitor. You probably should not 67 | * use this unless you have a very good reason. 68 | */ 69 | MultiSwitchArg(const std::string& flag, 70 | const std::string& name, 71 | const std::string& desc, 72 | int init = 0, 73 | Visitor* v = NULL); 74 | 75 | 76 | /** 77 | * MultiSwitchArg constructor. 78 | * \param flag - The one character flag that identifies this 79 | * argument on the command line. 80 | * \param name - A one word name for the argument. Can be 81 | * used as a long flag on the command line. 82 | * \param desc - A description of what the argument is for or 83 | * does. 84 | * \param parser - A CmdLine parser object to add this Arg to 85 | * \param init - Optional. The initial/default value of this Arg. 86 | * Defaults to 0. 87 | * \param v - An optional visitor. You probably should not 88 | * use this unless you have a very good reason. 89 | */ 90 | MultiSwitchArg(const std::string& flag, 91 | const std::string& name, 92 | const std::string& desc, 93 | CmdLineInterface& parser, 94 | int init = 0, 95 | Visitor* v = NULL); 96 | 97 | 98 | /** 99 | * Handles the processing of the argument. 100 | * This re-implements the SwitchArg version of this method to set the 101 | * _value of the argument appropriately. 102 | * \param i - Pointer the the current argument in the list. 103 | * \param args - Mutable list of strings. Passed 104 | * in from main(). 105 | */ 106 | virtual bool processArg(int* i, std::vector& args); 107 | 108 | /** 109 | * Returns int, the number of times the switch has been set. 110 | */ 111 | int getValue(); 112 | 113 | /** 114 | * Returns the shortID for this Arg. 115 | */ 116 | std::string shortID(const std::string& val) const; 117 | 118 | /** 119 | * Returns the longID for this Arg. 120 | */ 121 | std::string longID(const std::string& val) const; 122 | 123 | void reset(); 124 | 125 | }; 126 | 127 | ////////////////////////////////////////////////////////////////////// 128 | //BEGIN MultiSwitchArg.cpp 129 | ////////////////////////////////////////////////////////////////////// 130 | inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, 131 | const std::string& name, 132 | const std::string& desc, 133 | int init, 134 | Visitor* v ) 135 | : SwitchArg(flag, name, desc, false, v), 136 | _value( init ), 137 | _default( init ) 138 | { } 139 | 140 | inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, 141 | const std::string& name, 142 | const std::string& desc, 143 | CmdLineInterface& parser, 144 | int init, 145 | Visitor* v ) 146 | : SwitchArg(flag, name, desc, false, v), 147 | _value( init ), 148 | _default( init ) 149 | { 150 | parser.add( this ); 151 | } 152 | 153 | inline int MultiSwitchArg::getValue() { return _value; } 154 | 155 | inline bool MultiSwitchArg::processArg(int *i, std::vector& args) 156 | { 157 | if ( _ignoreable && Arg::ignoreRest() ) 158 | return false; 159 | 160 | if ( argMatches( args[*i] )) 161 | { 162 | // so the isSet() method will work 163 | _alreadySet = true; 164 | 165 | // Matched argument: increment value. 166 | ++_value; 167 | 168 | _checkWithVisitor(); 169 | 170 | return true; 171 | } 172 | else if ( combinedSwitchesMatch( args[*i] ) ) 173 | { 174 | // so the isSet() method will work 175 | _alreadySet = true; 176 | 177 | // Matched argument: increment value. 178 | ++_value; 179 | 180 | // Check for more in argument and increment value. 181 | while ( combinedSwitchesMatch( args[*i] ) ) 182 | ++_value; 183 | 184 | _checkWithVisitor(); 185 | 186 | return false; 187 | } 188 | else 189 | return false; 190 | } 191 | 192 | inline std::string 193 | MultiSwitchArg::shortID(const std::string& val) const 194 | { 195 | return Arg::shortID(val) + " ... "; 196 | } 197 | 198 | inline std::string 199 | MultiSwitchArg::longID(const std::string& val) const 200 | { 201 | return Arg::longID(val) + " (accepted multiple times)"; 202 | } 203 | 204 | inline void 205 | MultiSwitchArg::reset() 206 | { 207 | MultiSwitchArg::_value = MultiSwitchArg::_default; 208 | } 209 | 210 | ////////////////////////////////////////////////////////////////////// 211 | //END MultiSwitchArg.cpp 212 | ////////////////////////////////////////////////////////////////////// 213 | 214 | } //namespace TCLAP 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /include/andres/graph/detail/graph.hxx: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ANDRES_GRAPH_DETAIL_GRAPH_HXX 3 | #define ANDRES_GRAPH_DETAIL_GRAPH_HXX 4 | 5 | #include 6 | #include 7 | 8 | namespace andres { 9 | namespace graph { 10 | // \cond SUPPRESS_DOXYGEN 11 | namespace detail { 12 | 13 | template 14 | class Edge { 15 | public: 16 | typedef T Value; 17 | 18 | Edge(const Value, const Value); 19 | Value operator[](const std::size_t) const; 20 | Value& operator[](const std::size_t); 21 | 22 | private: 23 | Value vertexIndices_[2]; 24 | }; 25 | 26 | typedef RandomAccessSet > Adjacencies; 27 | 28 | template 29 | class IteratorHelper 30 | : public Adjacencies::const_iterator 31 | { 32 | private: 33 | typedef typename Adjacencies::const_iterator Base; 34 | 35 | public: 36 | typedef typename Base::iterator_category iterator_category; 37 | typedef typename Base::difference_type difference_type; 38 | typedef const std::size_t value_type; 39 | typedef value_type* pointer; 40 | typedef value_type& reference; 41 | 42 | // construction and assignment 43 | IteratorHelper(); 44 | IteratorHelper(const Base&); 45 | IteratorHelper(const IteratorHelper&); 46 | IteratorHelper operator=(const Base&); 47 | IteratorHelper operator=(const IteratorHelper&); 48 | 49 | // increment and decrement 50 | IteratorHelper& operator+=(const difference_type); 51 | IteratorHelper& operator-=(const difference_type); 52 | IteratorHelper& operator++(); // prefix 53 | IteratorHelper& operator--(); // prefix 54 | IteratorHelper operator++(int); // postfix 55 | IteratorHelper operator--(int); // postfix 56 | IteratorHelper operator+(const difference_type) const; 57 | IteratorHelper operator-(const difference_type) const; 58 | #ifdef _MSC_VER 59 | difference_type operator-(const IteratorHelper&) const; 60 | #endif 61 | 62 | // access 63 | value_type operator*() const; 64 | value_type operator[](const std::size_t j) const; 65 | private: 66 | pointer operator->() const; 67 | }; 68 | 69 | typedef IteratorHelper VertexIterator; 70 | typedef IteratorHelper EdgeIterator; 71 | 72 | // implementation of Edge 73 | 74 | template 75 | inline 76 | Edge::Edge( 77 | const Value v0, 78 | const Value v1 79 | ) { 80 | if(DIRECTED) { // evaluated at compile time 81 | vertexIndices_[0] = v0; 82 | vertexIndices_[1] = v1; 83 | } 84 | else { 85 | if(v0 <= v1) { 86 | vertexIndices_[0] = v0; 87 | vertexIndices_[1] = v1; 88 | } 89 | else { 90 | vertexIndices_[0] = v1; 91 | vertexIndices_[1] = v0; 92 | } 93 | } 94 | } 95 | 96 | template 97 | inline typename Edge::Value 98 | Edge::operator[] 99 | ( 100 | const std::size_t j 101 | ) const { 102 | assert(j < 2); 103 | 104 | return vertexIndices_[j]; 105 | } 106 | 107 | template 108 | inline typename Edge::Value& 109 | Edge::operator[]( 110 | const std::size_t j 111 | ) { 112 | assert(j < 2); 113 | 114 | return vertexIndices_[j]; 115 | } 116 | 117 | // implementation of IteratorHelper 118 | 119 | template 120 | inline 121 | IteratorHelper::IteratorHelper() 122 | : Base() 123 | {} 124 | 125 | template 126 | inline 127 | IteratorHelper::IteratorHelper( 128 | const Base& it 129 | ) 130 | : Base(it) 131 | {} 132 | 133 | template 134 | inline 135 | IteratorHelper::IteratorHelper( 136 | const IteratorHelper& it 137 | ) 138 | : Base(it) 139 | {} 140 | 141 | template 142 | inline IteratorHelper 143 | IteratorHelper::operator=( 144 | const Base& it 145 | ) { 146 | Base::operator=(it); 147 | return *this; 148 | } 149 | 150 | template 151 | inline IteratorHelper 152 | IteratorHelper::operator=( 153 | const IteratorHelper& it 154 | ) { 155 | Base::operator=(it); 156 | return *this; 157 | } 158 | 159 | template 160 | inline typename IteratorHelper::value_type 161 | IteratorHelper::operator*() const { 162 | if(T) { // evaluated at compile time 163 | return Base::operator*().vertex(); 164 | } 165 | else { 166 | return Base::operator*().edge(); 167 | } 168 | } 169 | 170 | template 171 | inline typename IteratorHelper::value_type 172 | IteratorHelper::operator[]( 173 | const std::size_t j 174 | ) const { 175 | if(T) { // evaluated at compile time 176 | return Base::operator[](j).vertex(); 177 | } 178 | else { 179 | return Base::operator[](j).edge(); 180 | } 181 | } 182 | 183 | template 184 | inline IteratorHelper& 185 | IteratorHelper::operator+=( 186 | const difference_type d 187 | ) { 188 | Base::operator+=(d); 189 | return *this; 190 | } 191 | 192 | template 193 | inline IteratorHelper& 194 | IteratorHelper::operator-=( 195 | const difference_type d 196 | ) { 197 | Base::operator-=(d); 198 | return *this; 199 | } 200 | 201 | template 202 | inline IteratorHelper& 203 | IteratorHelper::operator++() { // prefix 204 | Base::operator++(); 205 | return *this; 206 | } 207 | 208 | template 209 | inline IteratorHelper& 210 | IteratorHelper::operator--() { // prefix 211 | Base::operator--(); 212 | return *this; 213 | } 214 | 215 | template 216 | inline IteratorHelper 217 | IteratorHelper::operator++(int) { // postfix 218 | return Base::operator++(int()); 219 | } 220 | 221 | template 222 | inline IteratorHelper 223 | IteratorHelper::operator--(int) { // postfix 224 | return Base::operator--(int()); 225 | } 226 | 227 | template 228 | inline IteratorHelper 229 | IteratorHelper::operator+( 230 | const difference_type d 231 | ) const { 232 | return Base::operator+(d); 233 | } 234 | 235 | template 236 | inline IteratorHelper 237 | IteratorHelper::operator-( 238 | const difference_type d 239 | ) const { 240 | return Base::operator-(d); 241 | } 242 | 243 | #ifdef _MSC_VER 244 | template 245 | inline typename IteratorHelper::difference_type 246 | IteratorHelper::operator-( 247 | const IteratorHelper& other 248 | ) const { 249 | return Base::operator-(other); 250 | } 251 | #endif 252 | 253 | } // namespace detail 254 | // \endcond 255 | } // namespace graph 256 | } // namespace andres 257 | 258 | #endif // #ifndef ANDRES_GRAPH_DETAIL_GRAPH_HXX 259 | -------------------------------------------------------------------------------- /src/command-line-tools/lift-mp-grid-graph.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #include "Timer.hpp" 17 | #include "probabilistic-lifting.hxx" 18 | 19 | using namespace std; 20 | using namespace andres; 21 | using namespace andres::graph; 22 | 23 | typedef double value_type; 24 | typedef size_t size_type; 25 | typedef vector ValueMap; 26 | 27 | struct Parameters { 28 | string inputHDF5FileName_; 29 | string outputHDF5FileName_; 30 | size_type upperDistanceBound_ { 1 }; 31 | size_type lowerDistanceBound_ { 0 }; 32 | bool probabilistic_ { true }; 33 | LiftingMetric liftingMetric_; 34 | size_type interpolationOrder_ { 1 }; 35 | }; 36 | 37 | inline void 38 | parseCommandLine( 39 | int argc, 40 | char** argv, 41 | Parameters& parameters 42 | ) 43 | try 44 | { 45 | TCLAP::CmdLine tclap("lift-multicut-problem-grid-graph", ' ', "1.0"); 46 | TCLAP::ValueArg argInputHDF5FileName("i", "input-hdf5-file", "File to load multicut problem from", true, parameters.inputHDF5FileName_, "INPUT_HDF5_FILE",tclap); 47 | TCLAP::ValueArg argOutputHDF5FileName("o", "output-hdf5-file", "hdf file (output)", true, parameters.outputHDF5FileName_, "OUTPUT_HDF5_FILE",tclap); 48 | TCLAP::ValueArg argUpperDistanceBound("u", "distance-upper-bound", "upper distance bound (inclusive)", false, parameters.upperDistanceBound_, "DIST_UPPER",tclap); 49 | TCLAP::ValueArg argLowerDistanceBound("l", "distance-lower-bound", "lower distance bound (non-inclusive)", false, parameters.lowerDistanceBound_, "DIST_LOWER",tclap); 50 | TCLAP::ValueArg argLiftingMetric("m", "lifting-metric", "metric to use for deciding neighbourhood (path-length, L2)", false, "path-length", "METRIC",tclap); 51 | TCLAP::ValueArg argInterpolationOrder("k", "interpolation-order", "interpolation order.", false, parameters.interpolationOrder_, "ORDER",tclap); 52 | TCLAP::SwitchArg argNonProbabilistic("p", "non-probabilistic", "Assume inputs are not probabilities. By default, all inputs are assumed to be Logistic Probabilities. (Default: disabled).",tclap); 53 | 54 | tclap.parse(argc, argv); 55 | 56 | parameters.inputHDF5FileName_ = argInputHDF5FileName.getValue(); 57 | parameters.outputHDF5FileName_ = argOutputHDF5FileName.getValue(); 58 | parameters.upperDistanceBound_ = argUpperDistanceBound.getValue(); 59 | parameters.probabilistic_ = !argNonProbabilistic.getValue(); 60 | parameters.lowerDistanceBound_ = argLowerDistanceBound.getValue(); 61 | parameters.upperDistanceBound_ = argUpperDistanceBound.getValue(); 62 | parameters.interpolationOrder_ = argInterpolationOrder.getValue(); 63 | 64 | if (argLiftingMetric.getValue() == "L2") 65 | parameters.liftingMetric_ = LiftingMetric::L2; 66 | else if (argLiftingMetric.getValue() == "path-length") 67 | parameters.liftingMetric_ = LiftingMetric::PathLength; 68 | else 69 | throw runtime_error("Invalid metric specified"); 70 | } 71 | catch(TCLAP::ArgException& e) { 72 | throw runtime_error(e.error()); 73 | } 74 | 75 | void liftMulticutProblem( 76 | const Parameters& parameters, 77 | ostream& stream = cerr 78 | ) { 79 | { 80 | string metricName; 81 | 82 | if(parameters.liftingMetric_ == LiftingMetric::L2) 83 | metricName = "L2"; 84 | else 85 | metricName = "Path Length"; 86 | 87 | stream << " using neighbourhood defined by metric " << metricName 88 | << " and bounds (" << parameters.lowerDistanceBound_ 89 | << ","; 90 | 91 | if (parameters.upperDistanceBound_ == numeric_limits::max()) 92 | stream << "MAX"; 93 | else 94 | stream << parameters.upperDistanceBound_; 95 | 96 | stream << "]" << endl; 97 | } 98 | 99 | stream << "assuming GridGraph input." << endl; 100 | 101 | GridGraph<2> graph; 102 | ValueMap edgeCutProbabilities; 103 | 104 | stream << "loading multicut problem from file: " << parameters.inputHDF5FileName_ << endl; 105 | { 106 | auto fileHandle = hdf5::openFile(parameters.inputHDF5FileName_); 107 | 108 | hdf5::load(fileHandle, "graph", graph); 109 | 110 | vector shape; 111 | hdf5::load(fileHandle, "edge-cut-probabilities", shape, edgeCutProbabilities); 112 | 113 | hdf5::closeFile(fileHandle); 114 | 115 | assert(shape.size() == 1); 116 | assert(shape[0] == graph.numberOfEdges()); 117 | } 118 | stream << "lifting graph " << endl; 119 | 120 | Timer t; 121 | t.start(); 122 | 123 | Graph<> graphLifted; 124 | lift(graph, graphLifted, parameters.upperDistanceBound_, parameters.lowerDistanceBound_, parameters.liftingMetric_); 125 | 126 | ValueMap edgeSplitProbabilitiesLifted(graphLifted.numberOfEdges()); 127 | if(parameters.probabilistic_) 128 | transform( 129 | edgeCutProbabilities.begin(), 130 | edgeCutProbabilities.end(), 131 | edgeCutProbabilities.begin(), 132 | ProbabilityToNegativeLogInverseProbability() 133 | ); 134 | 135 | stream << "lifting edge values " << endl; 136 | liftEdgeValues( 137 | graph, 138 | graphLifted, 139 | edgeCutProbabilities.begin(), 140 | edgeSplitProbabilitiesLifted.begin(), 141 | parameters.interpolationOrder_ 142 | ); 143 | 144 | if(parameters.probabilistic_) 145 | transform( 146 | edgeSplitProbabilitiesLifted.begin(), 147 | edgeSplitProbabilitiesLifted.end(), 148 | edgeSplitProbabilitiesLifted.begin(), 149 | NegativeLogProbabilityToInverseProbability() 150 | ); 151 | 152 | t.stop(); 153 | 154 | stream << "saving Lifted Multicut as HDF5 file: " << parameters.outputHDF5FileName_ << endl; 155 | auto file = hdf5::createFile(parameters.outputHDF5FileName_); 156 | hdf5::save(file, "graph", graph); 157 | hdf5::save(file, "graph-lifted", graphLifted); 158 | hdf5::save(file, "lifting-time", t.get_elapsed_seconds()); 159 | hdf5::save(file, "edge-cut-probabilities", { graphLifted.numberOfEdges() }, edgeSplitProbabilitiesLifted.data()); 160 | hdf5::closeFile(file); 161 | } 162 | 163 | int main(int argc, char** argv) 164 | try 165 | { 166 | Parameters parameters; 167 | 168 | parseCommandLine(argc, argv, parameters); 169 | liftMulticutProblem(parameters); 170 | 171 | return 0; 172 | } 173 | catch (const runtime_error& error) 174 | { 175 | cerr << "error creating multicut problem: " << error.what() << endl; 176 | return 1; 177 | } --------------------------------------------------------------------------------