Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 1 | // Ceres Solver - A fast non-linear least squares minimizer |
| 2 | // Copyright 2010, 2011, 2012 Google Inc. All rights reserved. |
| 3 | // http://code.google.com/p/ceres-solver/ |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are met: |
| 7 | // |
| 8 | // * Redistributions of source code must retain the above copyright notice, |
| 9 | // this list of conditions and the following disclaimer. |
| 10 | // * Redistributions in binary form must reproduce the above copyright notice, |
| 11 | // this list of conditions and the following disclaimer in the documentation |
| 12 | // and/or other materials provided with the distribution. |
| 13 | // * Neither the name of Google Inc. nor the names of its contributors may be |
| 14 | // used to endorse or promote products derived from this software without |
| 15 | // specific prior written permission. |
| 16 | // |
| 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 27 | // POSSIBILITY OF SUCH DAMAGE. |
| 28 | // |
| 29 | // Author: sameeragarwal@google.com (Sameer Agarwal) |
| 30 | // |
| 31 | // Various algorithms that operate on undirected graphs. |
| 32 | |
| 33 | #ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_ |
| 34 | #define CERES_INTERNAL_GRAPH_ALGORITHMS_H_ |
| 35 | |
Sameer Agarwal | 509f68c | 2013-02-20 01:39:03 -0800 | [diff] [blame] | 36 | #include <algorithm> |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 37 | #include <vector> |
Sameer Agarwal | 509f68c | 2013-02-20 01:39:03 -0800 | [diff] [blame] | 38 | #include <utility> |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 39 | #include "ceres/collections_port.h" |
| 40 | #include "ceres/graph.h" |
Sameer Agarwal | 509f68c | 2013-02-20 01:39:03 -0800 | [diff] [blame] | 41 | #include "glog/logging.h" |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 42 | |
| 43 | namespace ceres { |
| 44 | namespace internal { |
| 45 | |
Sameer Agarwal | 096d593 | 2013-05-20 08:49:09 -0700 | [diff] [blame] | 46 | // Compare two vertices of a graph by their degrees, if the degrees |
| 47 | // are equal then order them by their ids. |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 48 | template <typename Vertex> |
Sameer Agarwal | 36c73c2 | 2013-05-17 22:52:21 -0700 | [diff] [blame] | 49 | class VertexTotalOrdering { |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 50 | public: |
Sameer Agarwal | 36c73c2 | 2013-05-17 22:52:21 -0700 | [diff] [blame] | 51 | explicit VertexTotalOrdering(const Graph<Vertex>& graph) |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 52 | : graph_(graph) {} |
| 53 | |
| 54 | bool operator()(const Vertex& lhs, const Vertex& rhs) const { |
Sameer Agarwal | 887b156 | 2012-05-06 15:14:47 -0700 | [diff] [blame] | 55 | if (graph_.Neighbors(lhs).size() == graph_.Neighbors(rhs).size()) { |
Sameer Agarwal | 3faa08b | 2012-05-06 16:08:22 -0700 | [diff] [blame] | 56 | return lhs < rhs; |
Sameer Agarwal | 887b156 | 2012-05-06 15:14:47 -0700 | [diff] [blame] | 57 | } |
Sameer Agarwal | 3faa08b | 2012-05-06 16:08:22 -0700 | [diff] [blame] | 58 | return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size(); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | private: |
| 62 | const Graph<Vertex>& graph_; |
| 63 | }; |
| 64 | |
Sameer Agarwal | 36c73c2 | 2013-05-17 22:52:21 -0700 | [diff] [blame] | 65 | template <typename Vertex> |
| 66 | class VertexDegreeLessThan { |
| 67 | public: |
| 68 | explicit VertexDegreeLessThan(const Graph<Vertex>& graph) |
| 69 | : graph_(graph) {} |
| 70 | |
| 71 | bool operator()(const Vertex& lhs, const Vertex& rhs) const { |
| 72 | return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size(); |
| 73 | } |
| 74 | |
| 75 | private: |
| 76 | const Graph<Vertex>& graph_; |
| 77 | }; |
| 78 | |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 79 | // Order the vertices of a graph using its (approximately) largest |
| 80 | // independent set, where an independent set of a graph is a set of |
| 81 | // vertices that have no edges connecting them. The maximum |
| 82 | // independent set problem is NP-Hard, but there are effective |
| 83 | // approximation algorithms available. The implementation here uses a |
| 84 | // breadth first search that explores the vertices in order of |
| 85 | // increasing degree. The same idea is used by Saad & Li in "MIQR: A |
| 86 | // multilevel incomplete QR preconditioner for large sparse |
| 87 | // least-squares problems", SIMAX, 2007. |
| 88 | // |
| 89 | // Given a undirected graph G(V,E), the algorithm is a greedy BFS |
| 90 | // search where the vertices are explored in increasing order of their |
| 91 | // degree. The output vector ordering contains elements of S in |
| 92 | // increasing order of their degree, followed by elements of V - S in |
| 93 | // increasing order of degree. The return value of the function is the |
| 94 | // cardinality of S. |
| 95 | template <typename Vertex> |
| 96 | int IndependentSetOrdering(const Graph<Vertex>& graph, |
| 97 | vector<Vertex>* ordering) { |
| 98 | const HashSet<Vertex>& vertices = graph.vertices(); |
| 99 | const int num_vertices = vertices.size(); |
| 100 | |
| 101 | CHECK_NOTNULL(ordering); |
| 102 | ordering->clear(); |
| 103 | ordering->reserve(num_vertices); |
| 104 | |
| 105 | // Colors for labeling the graph during the BFS. |
| 106 | const char kWhite = 0; |
| 107 | const char kGrey = 1; |
| 108 | const char kBlack = 2; |
| 109 | |
| 110 | // Mark all vertices white. |
| 111 | HashMap<Vertex, char> vertex_color; |
| 112 | vector<Vertex> vertex_queue; |
| 113 | for (typename HashSet<Vertex>::const_iterator it = vertices.begin(); |
| 114 | it != vertices.end(); |
| 115 | ++it) { |
| 116 | vertex_color[*it] = kWhite; |
| 117 | vertex_queue.push_back(*it); |
| 118 | } |
| 119 | |
| 120 | |
| 121 | sort(vertex_queue.begin(), vertex_queue.end(), |
Sameer Agarwal | 36c73c2 | 2013-05-17 22:52:21 -0700 | [diff] [blame] | 122 | VertexTotalOrdering<Vertex>(graph)); |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 123 | |
| 124 | // Iterate over vertex_queue. Pick the first white vertex, add it |
| 125 | // to the independent set. Mark it black and its neighbors grey. |
| 126 | for (int i = 0; i < vertex_queue.size(); ++i) { |
| 127 | const Vertex& vertex = vertex_queue[i]; |
| 128 | if (vertex_color[vertex] != kWhite) { |
| 129 | continue; |
| 130 | } |
| 131 | |
| 132 | ordering->push_back(vertex); |
| 133 | vertex_color[vertex] = kBlack; |
| 134 | const HashSet<Vertex>& neighbors = graph.Neighbors(vertex); |
| 135 | for (typename HashSet<Vertex>::const_iterator it = neighbors.begin(); |
| 136 | it != neighbors.end(); |
| 137 | ++it) { |
| 138 | vertex_color[*it] = kGrey; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | int independent_set_size = ordering->size(); |
| 143 | |
| 144 | // Iterate over the vertices and add all the grey vertices to the |
| 145 | // ordering. At this stage there should only be black or grey |
| 146 | // vertices in the graph. |
| 147 | for (typename vector<Vertex>::const_iterator it = vertex_queue.begin(); |
| 148 | it != vertex_queue.end(); |
| 149 | ++it) { |
| 150 | const Vertex vertex = *it; |
| 151 | DCHECK(vertex_color[vertex] != kWhite); |
| 152 | if (vertex_color[vertex] != kBlack) { |
| 153 | ordering->push_back(vertex); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | CHECK_EQ(ordering->size(), num_vertices); |
| 158 | return independent_set_size; |
| 159 | } |
| 160 | |
Sameer Agarwal | 36c73c2 | 2013-05-17 22:52:21 -0700 | [diff] [blame] | 161 | // Same as above with one important difference. The ordering parameter |
| 162 | // is an input/output parameter which carries an initial ordering of |
| 163 | // the vertices of the graph. The greedy independent set algorithm |
| 164 | // starts by sorting the vertices in increasing order of their |
| 165 | // degree. The input ordering is used to stabilize this sort, i.e., if |
| 166 | // two vertices have the same degree then they are ordered in the same |
| 167 | // order in which they occur in "ordering". |
| 168 | // |
| 169 | // This is useful in eliminating non-determinism from the Schur |
| 170 | // ordering algorithm over all. |
| 171 | template <typename Vertex> |
| 172 | int StableIndependentSetOrdering(const Graph<Vertex>& graph, |
| 173 | vector<Vertex>* ordering) { |
| 174 | CHECK_NOTNULL(ordering); |
| 175 | const HashSet<Vertex>& vertices = graph.vertices(); |
| 176 | const int num_vertices = vertices.size(); |
| 177 | CHECK_EQ(vertices.size(), ordering->size()); |
| 178 | |
| 179 | // Colors for labeling the graph during the BFS. |
| 180 | const char kWhite = 0; |
| 181 | const char kGrey = 1; |
| 182 | const char kBlack = 2; |
| 183 | |
| 184 | vector<Vertex> vertex_queue(*ordering); |
| 185 | |
| 186 | stable_sort(vertex_queue.begin(), vertex_queue.end(), |
| 187 | VertexDegreeLessThan<Vertex>(graph)); |
| 188 | |
| 189 | // Mark all vertices white. |
| 190 | HashMap<Vertex, char> vertex_color; |
| 191 | for (typename HashSet<Vertex>::const_iterator it = vertices.begin(); |
| 192 | it != vertices.end(); |
| 193 | ++it) { |
| 194 | vertex_color[*it] = kWhite; |
| 195 | } |
| 196 | |
| 197 | ordering->clear(); |
| 198 | ordering->reserve(num_vertices); |
| 199 | // Iterate over vertex_queue. Pick the first white vertex, add it |
| 200 | // to the independent set. Mark it black and its neighbors grey. |
| 201 | for (int i = 0; i < vertex_queue.size(); ++i) { |
| 202 | const Vertex& vertex = vertex_queue[i]; |
| 203 | if (vertex_color[vertex] != kWhite) { |
| 204 | continue; |
| 205 | } |
| 206 | |
| 207 | ordering->push_back(vertex); |
| 208 | vertex_color[vertex] = kBlack; |
| 209 | const HashSet<Vertex>& neighbors = graph.Neighbors(vertex); |
| 210 | for (typename HashSet<Vertex>::const_iterator it = neighbors.begin(); |
| 211 | it != neighbors.end(); |
| 212 | ++it) { |
| 213 | vertex_color[*it] = kGrey; |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | int independent_set_size = ordering->size(); |
| 218 | |
| 219 | // Iterate over the vertices and add all the grey vertices to the |
| 220 | // ordering. At this stage there should only be black or grey |
| 221 | // vertices in the graph. |
| 222 | for (typename vector<Vertex>::const_iterator it = vertex_queue.begin(); |
| 223 | it != vertex_queue.end(); |
| 224 | ++it) { |
| 225 | const Vertex vertex = *it; |
| 226 | DCHECK(vertex_color[vertex] != kWhite); |
| 227 | if (vertex_color[vertex] != kBlack) { |
| 228 | ordering->push_back(vertex); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | CHECK_EQ(ordering->size(), num_vertices); |
| 233 | return independent_set_size; |
| 234 | } |
| 235 | |
Keir Mierle | 8ebb073 | 2012-04-30 23:09:08 -0700 | [diff] [blame] | 236 | // Find the connected component for a vertex implemented using the |
| 237 | // find and update operation for disjoint-set. Recursively traverse |
| 238 | // the disjoint set structure till you reach a vertex whose connected |
| 239 | // component has the same id as the vertex itself. Along the way |
| 240 | // update the connected components of all the vertices. This updating |
| 241 | // is what gives this data structure its efficiency. |
| 242 | template <typename Vertex> |
| 243 | Vertex FindConnectedComponent(const Vertex& vertex, |
| 244 | HashMap<Vertex, Vertex>* union_find) { |
| 245 | typename HashMap<Vertex, Vertex>::iterator it = union_find->find(vertex); |
| 246 | DCHECK(it != union_find->end()); |
| 247 | if (it->second != vertex) { |
| 248 | it->second = FindConnectedComponent(it->second, union_find); |
| 249 | } |
| 250 | |
| 251 | return it->second; |
| 252 | } |
| 253 | |
| 254 | // Compute a degree two constrained Maximum Spanning Tree/forest of |
| 255 | // the input graph. Caller owns the result. |
| 256 | // |
| 257 | // Finding degree 2 spanning tree of a graph is not always |
| 258 | // possible. For example a star graph, i.e. a graph with n-nodes |
| 259 | // where one node is connected to the other n-1 nodes does not have |
| 260 | // a any spanning trees of degree less than n-1.Even if such a tree |
| 261 | // exists, finding such a tree is NP-Hard. |
| 262 | |
| 263 | // We get around both of these problems by using a greedy, degree |
| 264 | // constrained variant of Kruskal's algorithm. We start with a graph |
| 265 | // G_T with the same vertex set V as the input graph G(V,E) but an |
| 266 | // empty edge set. We then iterate over the edges of G in decreasing |
| 267 | // order of weight, adding them to G_T if doing so does not create a |
| 268 | // cycle in G_T} and the degree of all the vertices in G_T remains |
| 269 | // bounded by two. This O(|E|) algorithm results in a degree-2 |
| 270 | // spanning forest, or a collection of linear paths that span the |
| 271 | // graph G. |
| 272 | template <typename Vertex> |
| 273 | Graph<Vertex>* |
| 274 | Degree2MaximumSpanningForest(const Graph<Vertex>& graph) { |
| 275 | // Array of edges sorted in decreasing order of their weights. |
| 276 | vector<pair<double, pair<Vertex, Vertex> > > weighted_edges; |
| 277 | Graph<Vertex>* forest = new Graph<Vertex>(); |
| 278 | |
| 279 | // Disjoint-set to keep track of the connected components in the |
| 280 | // maximum spanning tree. |
| 281 | HashMap<Vertex, Vertex> disjoint_set; |
| 282 | |
| 283 | // Sort of the edges in the graph in decreasing order of their |
| 284 | // weight. Also add the vertices of the graph to the Maximum |
| 285 | // Spanning Tree graph and set each vertex to be its own connected |
| 286 | // component in the disjoint_set structure. |
| 287 | const HashSet<Vertex>& vertices = graph.vertices(); |
| 288 | for (typename HashSet<Vertex>::const_iterator it = vertices.begin(); |
| 289 | it != vertices.end(); |
| 290 | ++it) { |
| 291 | const Vertex vertex1 = *it; |
| 292 | forest->AddVertex(vertex1, graph.VertexWeight(vertex1)); |
| 293 | disjoint_set[vertex1] = vertex1; |
| 294 | |
| 295 | const HashSet<Vertex>& neighbors = graph.Neighbors(vertex1); |
| 296 | for (typename HashSet<Vertex>::const_iterator it2 = neighbors.begin(); |
| 297 | it2 != neighbors.end(); |
| 298 | ++it2) { |
| 299 | const Vertex vertex2 = *it2; |
| 300 | if (vertex1 >= vertex2) { |
| 301 | continue; |
| 302 | } |
| 303 | const double weight = graph.EdgeWeight(vertex1, vertex2); |
| 304 | weighted_edges.push_back(make_pair(weight, make_pair(vertex1, vertex2))); |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | // The elements of this vector, are pairs<edge_weight, |
| 309 | // edge>. Sorting it using the reverse iterators gives us the edges |
| 310 | // in decreasing order of edges. |
| 311 | sort(weighted_edges.rbegin(), weighted_edges.rend()); |
| 312 | |
| 313 | // Greedily add edges to the spanning tree/forest as long as they do |
| 314 | // not violate the degree/cycle constraint. |
| 315 | for (int i =0; i < weighted_edges.size(); ++i) { |
| 316 | const pair<Vertex, Vertex>& edge = weighted_edges[i].second; |
| 317 | const Vertex vertex1 = edge.first; |
| 318 | const Vertex vertex2 = edge.second; |
| 319 | |
| 320 | // Check if either of the vertices are of degree 2 already, in |
| 321 | // which case adding this edge will violate the degree 2 |
| 322 | // constraint. |
| 323 | if ((forest->Neighbors(vertex1).size() == 2) || |
| 324 | (forest->Neighbors(vertex2).size() == 2)) { |
| 325 | continue; |
| 326 | } |
| 327 | |
| 328 | // Find the id of the connected component to which the two |
| 329 | // vertices belong to. If the id is the same, it means that the |
| 330 | // two of them are already connected to each other via some other |
| 331 | // vertex, and adding this edge will create a cycle. |
| 332 | Vertex root1 = FindConnectedComponent(vertex1, &disjoint_set); |
| 333 | Vertex root2 = FindConnectedComponent(vertex2, &disjoint_set); |
| 334 | |
| 335 | if (root1 == root2) { |
| 336 | continue; |
| 337 | } |
| 338 | |
| 339 | // This edge can be added, add an edge in either direction with |
| 340 | // the same weight as the original graph. |
| 341 | const double edge_weight = graph.EdgeWeight(vertex1, vertex2); |
| 342 | forest->AddEdge(vertex1, vertex2, edge_weight); |
| 343 | forest->AddEdge(vertex2, vertex1, edge_weight); |
| 344 | |
| 345 | // Connected the two connected components by updating the |
| 346 | // disjoint_set structure. Always connect the connected component |
| 347 | // with the greater index with the connected component with the |
| 348 | // smaller index. This should ensure shallower trees, for quicker |
| 349 | // lookup. |
| 350 | if (root2 < root1) { |
| 351 | std::swap(root1, root2); |
| 352 | }; |
| 353 | |
| 354 | disjoint_set[root2] = root1; |
| 355 | } |
| 356 | return forest; |
| 357 | } |
| 358 | |
| 359 | } // namespace internal |
| 360 | } // namespace ceres |
| 361 | |
| 362 | #endif // CERES_INTERNAL_GRAPH_ALGORITHMS_H_ |