blob: 2e6eec0e6d8494a85ed45f913930b79a14e1cf20 [file] [log] [blame]
Keir Mierle8ebb0732012-04-30 23:09:08 -07001// 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 Agarwal509f68c2013-02-20 01:39:03 -080036#include <algorithm>
Keir Mierle8ebb0732012-04-30 23:09:08 -070037#include <vector>
Sameer Agarwal509f68c2013-02-20 01:39:03 -080038#include <utility>
Keir Mierle8ebb0732012-04-30 23:09:08 -070039#include "ceres/collections_port.h"
40#include "ceres/graph.h"
Sameer Agarwal509f68c2013-02-20 01:39:03 -080041#include "glog/logging.h"
Keir Mierle8ebb0732012-04-30 23:09:08 -070042
43namespace ceres {
44namespace internal {
45
46// Compare two vertices of a graph by their degrees.
47template <typename Vertex>
48class VertexDegreeLessThan {
49 public:
50 explicit VertexDegreeLessThan(const Graph<Vertex>& graph)
51 : graph_(graph) {}
52
53 bool operator()(const Vertex& lhs, const Vertex& rhs) const {
Sameer Agarwal887b1562012-05-06 15:14:47 -070054 if (graph_.Neighbors(lhs).size() == graph_.Neighbors(rhs).size()) {
Sameer Agarwal3faa08b2012-05-06 16:08:22 -070055 return lhs < rhs;
Sameer Agarwal887b1562012-05-06 15:14:47 -070056 }
Sameer Agarwal3faa08b2012-05-06 16:08:22 -070057 return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size();
Keir Mierle8ebb0732012-04-30 23:09:08 -070058 }
59
60 private:
61 const Graph<Vertex>& graph_;
62};
63
64// Order the vertices of a graph using its (approximately) largest
65// independent set, where an independent set of a graph is a set of
66// vertices that have no edges connecting them. The maximum
67// independent set problem is NP-Hard, but there are effective
68// approximation algorithms available. The implementation here uses a
69// breadth first search that explores the vertices in order of
70// increasing degree. The same idea is used by Saad & Li in "MIQR: A
71// multilevel incomplete QR preconditioner for large sparse
72// least-squares problems", SIMAX, 2007.
73//
74// Given a undirected graph G(V,E), the algorithm is a greedy BFS
75// search where the vertices are explored in increasing order of their
76// degree. The output vector ordering contains elements of S in
77// increasing order of their degree, followed by elements of V - S in
78// increasing order of degree. The return value of the function is the
79// cardinality of S.
80template <typename Vertex>
81int IndependentSetOrdering(const Graph<Vertex>& graph,
82 vector<Vertex>* ordering) {
83 const HashSet<Vertex>& vertices = graph.vertices();
84 const int num_vertices = vertices.size();
85
86 CHECK_NOTNULL(ordering);
87 ordering->clear();
88 ordering->reserve(num_vertices);
89
90 // Colors for labeling the graph during the BFS.
91 const char kWhite = 0;
92 const char kGrey = 1;
93 const char kBlack = 2;
94
95 // Mark all vertices white.
96 HashMap<Vertex, char> vertex_color;
97 vector<Vertex> vertex_queue;
98 for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
99 it != vertices.end();
100 ++it) {
101 vertex_color[*it] = kWhite;
102 vertex_queue.push_back(*it);
103 }
104
105
106 sort(vertex_queue.begin(), vertex_queue.end(),
107 VertexDegreeLessThan<Vertex>(graph));
108
109 // Iterate over vertex_queue. Pick the first white vertex, add it
110 // to the independent set. Mark it black and its neighbors grey.
111 for (int i = 0; i < vertex_queue.size(); ++i) {
112 const Vertex& vertex = vertex_queue[i];
113 if (vertex_color[vertex] != kWhite) {
114 continue;
115 }
116
117 ordering->push_back(vertex);
118 vertex_color[vertex] = kBlack;
119 const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
120 for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
121 it != neighbors.end();
122 ++it) {
123 vertex_color[*it] = kGrey;
124 }
125 }
126
127 int independent_set_size = ordering->size();
128
129 // Iterate over the vertices and add all the grey vertices to the
130 // ordering. At this stage there should only be black or grey
131 // vertices in the graph.
132 for (typename vector<Vertex>::const_iterator it = vertex_queue.begin();
133 it != vertex_queue.end();
134 ++it) {
135 const Vertex vertex = *it;
136 DCHECK(vertex_color[vertex] != kWhite);
137 if (vertex_color[vertex] != kBlack) {
138 ordering->push_back(vertex);
139 }
140 }
141
142 CHECK_EQ(ordering->size(), num_vertices);
143 return independent_set_size;
144}
145
146// Find the connected component for a vertex implemented using the
147// find and update operation for disjoint-set. Recursively traverse
148// the disjoint set structure till you reach a vertex whose connected
149// component has the same id as the vertex itself. Along the way
150// update the connected components of all the vertices. This updating
151// is what gives this data structure its efficiency.
152template <typename Vertex>
153Vertex FindConnectedComponent(const Vertex& vertex,
154 HashMap<Vertex, Vertex>* union_find) {
155 typename HashMap<Vertex, Vertex>::iterator it = union_find->find(vertex);
156 DCHECK(it != union_find->end());
157 if (it->second != vertex) {
158 it->second = FindConnectedComponent(it->second, union_find);
159 }
160
161 return it->second;
162}
163
164// Compute a degree two constrained Maximum Spanning Tree/forest of
165// the input graph. Caller owns the result.
166//
167// Finding degree 2 spanning tree of a graph is not always
168// possible. For example a star graph, i.e. a graph with n-nodes
169// where one node is connected to the other n-1 nodes does not have
170// a any spanning trees of degree less than n-1.Even if such a tree
171// exists, finding such a tree is NP-Hard.
172
173// We get around both of these problems by using a greedy, degree
174// constrained variant of Kruskal's algorithm. We start with a graph
175// G_T with the same vertex set V as the input graph G(V,E) but an
176// empty edge set. We then iterate over the edges of G in decreasing
177// order of weight, adding them to G_T if doing so does not create a
178// cycle in G_T} and the degree of all the vertices in G_T remains
179// bounded by two. This O(|E|) algorithm results in a degree-2
180// spanning forest, or a collection of linear paths that span the
181// graph G.
182template <typename Vertex>
183Graph<Vertex>*
184Degree2MaximumSpanningForest(const Graph<Vertex>& graph) {
185 // Array of edges sorted in decreasing order of their weights.
186 vector<pair<double, pair<Vertex, Vertex> > > weighted_edges;
187 Graph<Vertex>* forest = new Graph<Vertex>();
188
189 // Disjoint-set to keep track of the connected components in the
190 // maximum spanning tree.
191 HashMap<Vertex, Vertex> disjoint_set;
192
193 // Sort of the edges in the graph in decreasing order of their
194 // weight. Also add the vertices of the graph to the Maximum
195 // Spanning Tree graph and set each vertex to be its own connected
196 // component in the disjoint_set structure.
197 const HashSet<Vertex>& vertices = graph.vertices();
198 for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
199 it != vertices.end();
200 ++it) {
201 const Vertex vertex1 = *it;
202 forest->AddVertex(vertex1, graph.VertexWeight(vertex1));
203 disjoint_set[vertex1] = vertex1;
204
205 const HashSet<Vertex>& neighbors = graph.Neighbors(vertex1);
206 for (typename HashSet<Vertex>::const_iterator it2 = neighbors.begin();
207 it2 != neighbors.end();
208 ++it2) {
209 const Vertex vertex2 = *it2;
210 if (vertex1 >= vertex2) {
211 continue;
212 }
213 const double weight = graph.EdgeWeight(vertex1, vertex2);
214 weighted_edges.push_back(make_pair(weight, make_pair(vertex1, vertex2)));
215 }
216 }
217
218 // The elements of this vector, are pairs<edge_weight,
219 // edge>. Sorting it using the reverse iterators gives us the edges
220 // in decreasing order of edges.
221 sort(weighted_edges.rbegin(), weighted_edges.rend());
222
223 // Greedily add edges to the spanning tree/forest as long as they do
224 // not violate the degree/cycle constraint.
225 for (int i =0; i < weighted_edges.size(); ++i) {
226 const pair<Vertex, Vertex>& edge = weighted_edges[i].second;
227 const Vertex vertex1 = edge.first;
228 const Vertex vertex2 = edge.second;
229
230 // Check if either of the vertices are of degree 2 already, in
231 // which case adding this edge will violate the degree 2
232 // constraint.
233 if ((forest->Neighbors(vertex1).size() == 2) ||
234 (forest->Neighbors(vertex2).size() == 2)) {
235 continue;
236 }
237
238 // Find the id of the connected component to which the two
239 // vertices belong to. If the id is the same, it means that the
240 // two of them are already connected to each other via some other
241 // vertex, and adding this edge will create a cycle.
242 Vertex root1 = FindConnectedComponent(vertex1, &disjoint_set);
243 Vertex root2 = FindConnectedComponent(vertex2, &disjoint_set);
244
245 if (root1 == root2) {
246 continue;
247 }
248
249 // This edge can be added, add an edge in either direction with
250 // the same weight as the original graph.
251 const double edge_weight = graph.EdgeWeight(vertex1, vertex2);
252 forest->AddEdge(vertex1, vertex2, edge_weight);
253 forest->AddEdge(vertex2, vertex1, edge_weight);
254
255 // Connected the two connected components by updating the
256 // disjoint_set structure. Always connect the connected component
257 // with the greater index with the connected component with the
258 // smaller index. This should ensure shallower trees, for quicker
259 // lookup.
260 if (root2 < root1) {
261 std::swap(root1, root2);
262 };
263
264 disjoint_set[root2] = root1;
265 }
266 return forest;
267}
268
269} // namespace internal
270} // namespace ceres
271
272#endif // CERES_INTERNAL_GRAPH_ALGORITHMS_H_