ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
graph_cut_test.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #define TEST_NAME "base/graph_cut"
33 #include "util/testing.h"
34 
35 #include "base/graph_cut.h"
36 
37 using namespace colmap;
38 
39 BOOST_AUTO_TEST_CASE(TestComputeMinGraphCutStoerWagner) {
40  const std::vector<std::pair<int, int>> edges = {
41  {3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, {0, 5},
42  {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}};
43  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1,
44  8, 1, 1, 80, 2, 1, 1, 4};
45  int cut_weight;
46  std::vector<char> cut_labels;
47  ComputeMinGraphCutStoerWagner(edges, weights, &cut_weight, &cut_labels);
48  BOOST_CHECK_EQUAL(cut_weight, 7);
49  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
50  for (const auto& label : cut_labels) {
51  BOOST_CHECK_GE(label, 0);
52  BOOST_CHECK_LT(label, 2);
53  }
54 }
55 
56 BOOST_AUTO_TEST_CASE(TestComputeMinGraphCutStoerWagnerDuplicateEdge) {
57  const std::vector<std::pair<int, int>> edges = {
58  {3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, {0, 5}, {0, 2},
59  {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}, {3, 4}};
60  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1, 8,
61  1, 1, 80, 2, 1, 1, 4, 4};
62  int cut_weight;
63  std::vector<char> cut_labels;
64  ComputeMinGraphCutStoerWagner(edges, weights, &cut_weight, &cut_labels);
65  BOOST_CHECK_EQUAL(cut_weight, 7);
66  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
67  for (const auto& label : cut_labels) {
68  BOOST_CHECK_GE(label, 0);
69  BOOST_CHECK_LT(label, 2);
70  }
71 }
72 
73 BOOST_AUTO_TEST_CASE(TestComputeMinGraphCutStoerWagnerMissingVertex) {
74  const std::vector<std::pair<int, int>> edges = {
75  {3, 4}, {3, 6}, {3, 5}, {0, 1}, {0, 6}, {0, 7}, {0, 5},
76  {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}};
77  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1};
78  int cut_weight;
79  std::vector<char> cut_labels;
80  ComputeMinGraphCutStoerWagner(edges, weights, &cut_weight, &cut_labels);
81  BOOST_CHECK_EQUAL(cut_weight, 2);
82  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
83  for (const auto& label : cut_labels) {
84  BOOST_CHECK_GE(label, 0);
85  BOOST_CHECK_LT(label, 2);
86  }
87 }
88 
89 BOOST_AUTO_TEST_CASE(TestComputeMinGraphCutStoerWagnerDisconnected) {
90  const std::vector<std::pair<int, int>> edges = {{0, 1}, {1, 2}, {3, 4}};
91  const std::vector<int> weights = {1, 3, 1};
92  int cut_weight;
93  std::vector<char> cut_labels;
94  ComputeMinGraphCutStoerWagner(edges, weights, &cut_weight, &cut_labels);
95  BOOST_CHECK_EQUAL(cut_weight, 0);
96  BOOST_CHECK_EQUAL(cut_labels.size(), 5);
97  for (const auto& label : cut_labels) {
98  BOOST_CHECK_GE(label, 0);
99  BOOST_CHECK_LT(label, 2);
100  }
101 }
102 
103 BOOST_AUTO_TEST_CASE(TestComputeNormalizedMinGraphCut) {
104  const std::vector<std::pair<int, int>> edges = {
105  {3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, {0, 5},
106  {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}};
107  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1,
108  8, 1, 1, 80, 2, 1, 1, 4};
109  const auto cut_labels = ComputeNormalizedMinGraphCut(edges, weights, 2);
110  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
111  for (const auto& label : cut_labels) {
112  BOOST_CHECK_GE(label.second, 0);
113  BOOST_CHECK_LT(label.second, 2);
114  }
115 }
116 
117 BOOST_AUTO_TEST_CASE(TestComputeNormalizedMinGraphCutDuplicateEdge) {
118  const std::vector<std::pair<int, int>> edges = {
119  {3, 4}, {3, 6}, {3, 5}, {0, 4}, {0, 1}, {0, 6}, {0, 7}, {0, 5}, {0, 2},
120  {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}, {3, 4}, {3, 4}};
121  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1, 8,
122  1, 1, 80, 2, 1, 1, 4, 4};
123  const auto cut_labels = ComputeNormalizedMinGraphCut(edges, weights, 2);
124  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
125  for (const auto& label : cut_labels) {
126  BOOST_CHECK_GE(label.second, 0);
127  BOOST_CHECK_LT(label.second, 2);
128  }
129 }
130 
131 BOOST_AUTO_TEST_CASE(TestComputeNormalizedMinGraphCutMissingVertex) {
132  const std::vector<std::pair<int, int>> edges = {
133  {3, 4}, {3, 6}, {3, 5}, {0, 1}, {0, 6}, {0, 7}, {0, 5},
134  {0, 2}, {4, 1}, {1, 6}, {1, 5}, {6, 7}, {7, 5}, {5, 2}};
135  const std::vector<int> weights = {0, 3, 1, 3, 1, 2, 6, 1, 8, 1, 1, 80, 2, 1};
136  const auto cut_labels = ComputeNormalizedMinGraphCut(edges, weights, 2);
137  BOOST_CHECK_EQUAL(cut_labels.size(), 8);
138  for (const auto& label : cut_labels) {
139  BOOST_CHECK_GE(label.second, 0);
140  BOOST_CHECK_LT(label.second, 2);
141  }
142 }
143 
144 BOOST_AUTO_TEST_CASE(TestComputeNormalizedMinGraphCutDisconnected) {
145  const std::vector<std::pair<int, int>> edges = {{0, 1}, {1, 2}, {3, 4}};
146  const std::vector<int> weights = {1, 3, 1};
147  const auto cut_labels = ComputeNormalizedMinGraphCut(edges, weights, 2);
148  BOOST_CHECK_EQUAL(cut_labels.size(), 5);
149  for (const auto& label : cut_labels) {
150  BOOST_CHECK_GE(label.second, 0);
151  BOOST_CHECK_LT(label.second, 2);
152  }
153 }
154 
155 BOOST_AUTO_TEST_CASE(TestMinSTGraphCut1) {
156  MinSTGraphCut<int, int> graph(2);
157  BOOST_CHECK_EQUAL(graph.NumNodes(), 2);
158  BOOST_CHECK_EQUAL(graph.NumEdges(), 0);
159  graph.AddNode(0, 5, 1);
160  graph.AddNode(1, 2, 6);
161  graph.AddEdge(0, 1, 3, 4);
162  BOOST_CHECK_EQUAL(graph.NumEdges(), 10);
163  BOOST_CHECK_EQUAL(graph.Compute(), 6);
164  BOOST_CHECK(graph.IsConnectedToSource(0));
165  BOOST_CHECK(graph.IsConnectedToSink(1));
166 }
167 
168 BOOST_AUTO_TEST_CASE(TestMinSTGraphCut2) {
169  MinSTGraphCut<int, int> graph(2);
170  graph.AddNode(0, 1, 5);
171  graph.AddNode(1, 2, 6);
172  graph.AddEdge(0, 1, 3, 4);
173  BOOST_CHECK_EQUAL(graph.NumEdges(), 10);
174  BOOST_CHECK_EQUAL(graph.Compute(), 3);
175  BOOST_CHECK(graph.IsConnectedToSink(0));
176  BOOST_CHECK(graph.IsConnectedToSink(1));
177 }
178 
179 BOOST_AUTO_TEST_CASE(TestMinSTGraphCut3) {
180  MinSTGraphCut<int, int> graph(3);
181  graph.AddNode(0, 6, 4);
182  graph.AddNode(2, 3, 6);
183  graph.AddEdge(0, 1, 2, 4);
184  graph.AddEdge(1, 2, 3, 5);
185  BOOST_CHECK_EQUAL(graph.NumEdges(), 12);
186  BOOST_CHECK_EQUAL(graph.Compute(), 9);
187  BOOST_CHECK(graph.IsConnectedToSource(0));
188  BOOST_CHECK(graph.IsConnectedToSink(1));
189  BOOST_CHECK(graph.IsConnectedToSink(2));
190 }
bool IsConnectedToSource(const node_t node_idx) const
Definition: graph_cut.h:180
void AddNode(const node_t node_idx, const value_t source_capacity, const value_t sink_capacity)
Definition: graph_cut.h:112
size_t NumNodes() const
Definition: graph_cut.h:102
size_t NumEdges() const
Definition: graph_cut.h:107
bool IsConnectedToSink(const node_t node_idx) const
Definition: graph_cut.h:186
void AddEdge(const node_t node_idx1, const node_t node_idx2, const value_t capacity, const value_t reverse_capacity)
Definition: graph_cut.h:142
BOOST_AUTO_TEST_CASE(TestComputeMinGraphCutStoerWagner)
std::unordered_map< int, int > ComputeNormalizedMinGraphCut(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, const int num_parts)
Definition: graph_cut.cc:186
void ComputeMinGraphCutStoerWagner(const std::vector< std::pair< int, int >> &edges, const std::vector< int > &weights, int *cut_weight, std::vector< char > *cut_labels)
Definition: graph_cut.cc:150