Add an unweighted graph.

Rename Graph -> WeightedGraph.
Add a new Graph class, which is cheaper to construct and
work with if the weights are not needed.

This cuts down the cost of building the Hessian graph
significantly.

Change-Id: Id0cfc81dd2c0bb5ff8f63a1b55aa133c53c0c869
diff --git a/internal/ceres/canonical_views_clustering.cc b/internal/ceres/canonical_views_clustering.cc
index 2f032e6..9bbab4b 100644
--- a/internal/ceres/canonical_views_clustering.cc
+++ b/internal/ceres/canonical_views_clustering.cc
@@ -61,7 +61,7 @@
   // vertices may not be assigned to any cluster. In this case they
   // are assigned to a cluster with id = kInvalidClusterId.
   void ComputeClustering(const CanonicalViewsClusteringOptions& options,
-                         const Graph<int>& graph,
+                         const WeightedGraph<int>& graph,
                          vector<int>* centers,
                          IntMap* membership);
 
@@ -74,7 +74,7 @@
                                 IntMap* membership) const;
 
   CanonicalViewsClusteringOptions options_;
-  const Graph<int>* graph_;
+  const WeightedGraph<int>* graph_;
   // Maps a view to its representative canonical view (its cluster
   // center).
   IntMap view_to_canonical_view_;
@@ -85,7 +85,7 @@
 
 void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     IntMap* membership) {
   time_t start_time = time(NULL);
@@ -98,7 +98,7 @@
 // Implementation of CanonicalViewsClustering
 void CanonicalViewsClustering::ComputeClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     IntMap* membership) {
   options_ = options;
@@ -150,7 +150,7 @@
   for (IntSet::const_iterator view = views.begin();
        view != views.end();
        ++view) {
-    if (graph_->VertexWeight(*view) != Graph<int>::InvalidWeight()) {
+    if (graph_->VertexWeight(*view) != WeightedGraph<int>::InvalidWeight()) {
       valid_views->insert(*view);
     }
   }
diff --git a/internal/ceres/canonical_views_clustering.h b/internal/ceres/canonical_views_clustering.h
index 1b4c4ee..d3fa572 100644
--- a/internal/ceres/canonical_views_clustering.h
+++ b/internal/ceres/canonical_views_clustering.h
@@ -101,7 +101,7 @@
 // cluster. In this case they are assigned to a cluster with id = -1;
 void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     vector<int>* centers,
     HashMap<int, int>* membership);
 
diff --git a/internal/ceres/canonical_views_clustering_test.cc b/internal/ceres/canonical_views_clustering_test.cc
index f86084a..006b2dd 100644
--- a/internal/ceres/canonical_views_clustering_test.cc
+++ b/internal/ceres/canonical_views_clustering_test.cc
@@ -75,7 +75,7 @@
     ComputeCanonicalViewsClustering(options_, graph_, &centers_, &membership_);
   }
 
-  Graph<int> graph_;
+  WeightedGraph<int> graph_;
 
   CanonicalViewsClusteringOptions options_;
   vector<int> centers_;
diff --git a/internal/ceres/graph.h b/internal/ceres/graph.h
index 5f92d4d..38fdae3 100644
--- a/internal/ceres/graph.h
+++ b/internal/ceres/graph.h
@@ -43,13 +43,75 @@
 namespace ceres {
 namespace internal {
 
-// A weighted undirected graph templated over the vertex ids. Vertex
+// A unweighted undirected graph templated over the vertex ids. Vertex
 // should be hashable and comparable.
 template <typename Vertex>
 class Graph {
  public:
   Graph() {}
 
+  // Add a vertex.
+  void AddVertex(const Vertex& vertex) {
+    if (vertices_.insert(vertex).second) {
+      edges_[vertex] = HashSet<Vertex>();
+    }
+  }
+
+  bool RemoveVertex(const Vertex& vertex) {
+    if (vertices_.find(vertex) == vertices_.end()) {
+      return false;
+    }
+
+    vertices_.erase(vertex);
+    const HashSet<Vertex>& sinks = edges_[vertex];
+    for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
+         it != sinks.end(); ++it) {
+      edges_[*it].erase(vertex);
+    }
+
+    edges_.erase(vertex);
+    return true;
+  }
+
+  // Add an edge between the vertex1 and vertex2. Calling AddEdge on a
+  // pair of vertices which do not exist in the graph yet will result
+  // in undefined behavior.
+  //
+  // It is legal to call this method repeatedly for the same set of
+  // vertices.
+  void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
+    DCHECK(vertices_.find(vertex1) != vertices_.end());
+    DCHECK(vertices_.find(vertex2) != vertices_.end());
+
+    if (edges_[vertex1].insert(vertex2).second) {
+      edges_[vertex2].insert(vertex1);
+    }
+  }
+
+  // Calling Neighbors on a vertex not in the graph will result in
+  // undefined behaviour.
+  const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+    return FindOrDie(edges_, vertex);
+  }
+
+  const HashSet<Vertex>& vertices() const {
+    return vertices_;
+  }
+
+ private:
+  HashSet<Vertex> vertices_;
+  HashMap<Vertex, HashSet<Vertex> > edges_;
+
+  CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+};
+
+// A weighted undirected graph templated over the vertex ids. Vertex
+// should be hashable and comparable.
+template <typename Vertex>
+class WeightedGraph {
+ public:
+  WeightedGraph() {}
+
   // Add a weighted vertex. If the vertex already exists in the graph,
   // its weight is set to the new weight.
   void AddVertex(const Vertex& vertex, double weight) {
@@ -152,7 +214,7 @@
   HashMap<Vertex, HashSet<Vertex> > edges_;
   HashMap<pair<Vertex, Vertex>, double> edge_weights_;
 
-  CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+  CERES_DISALLOW_COPY_AND_ASSIGN(WeightedGraph);
 };
 
 }  // namespace internal
diff --git a/internal/ceres/graph_algorithms.h b/internal/ceres/graph_algorithms.h
index ca3a2fe..46a37c5 100644
--- a/internal/ceres/graph_algorithms.h
+++ b/internal/ceres/graph_algorithms.h
@@ -38,6 +38,7 @@
 #include <utility>
 #include "ceres/collections_port.h"
 #include "ceres/graph.h"
+#include "ceres/wall_time.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -171,6 +172,8 @@
 template <typename Vertex>
 int StableIndependentSetOrdering(const Graph<Vertex>& graph,
                                  vector<Vertex>* ordering) {
+  EventLogger event_logger("StableIndependentSetOrdering");
+
   CHECK_NOTNULL(ordering);
   const HashSet<Vertex>& vertices = graph.vertices();
   const int num_vertices = vertices.size();
@@ -185,6 +188,7 @@
 
   stable_sort(vertex_queue.begin(), vertex_queue.end(),
               VertexDegreeLessThan<Vertex>(graph));
+  event_logger.AddEvent("StableSort");
 
   // Mark all vertices white.
   HashMap<Vertex, char> vertex_color;
@@ -193,6 +197,7 @@
        ++it) {
     vertex_color[*it] = kWhite;
   }
+  event_logger.AddEvent("MarkWhite");
 
   ordering->clear();
   ordering->reserve(num_vertices);
@@ -213,6 +218,7 @@
       vertex_color[*it] = kGrey;
     }
   }
+  event_logger.AddEvent("IndependentVertices");
 
   int independent_set_size = ordering->size();
 
@@ -228,6 +234,7 @@
       ordering->push_back(vertex);
     }
   }
+  event_logger.AddEvent("DependentVertices");
 
   CHECK_EQ(ordering->size(), num_vertices);
   return independent_set_size;
@@ -270,11 +277,11 @@
 // spanning forest, or a collection of linear paths that span the
 // graph G.
 template <typename Vertex>
-Graph<Vertex>*
-Degree2MaximumSpanningForest(const Graph<Vertex>& graph) {
+WeightedGraph<Vertex>*
+Degree2MaximumSpanningForest(const WeightedGraph<Vertex>& graph) {
   // Array of edges sorted in decreasing order of their weights.
   vector<pair<double, pair<Vertex, Vertex> > > weighted_edges;
-  Graph<Vertex>* forest = new Graph<Vertex>();
+  WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
 
   // Disjoint-set to keep track of the connected components in the
   // maximum spanning tree.
diff --git a/internal/ceres/graph_algorithms_test.cc b/internal/ceres/graph_algorithms_test.cc
index 7c24476..bbb1e0d 100644
--- a/internal/ceres/graph_algorithms_test.cc
+++ b/internal/ceres/graph_algorithms_test.cc
@@ -102,13 +102,13 @@
 }
 
 TEST(Degree2MaximumSpanningForest, PreserveWeights) {
-  Graph<int> graph;
+  WeightedGraph<int> graph;
   graph.AddVertex(0, 1.0);
   graph.AddVertex(1, 2.0);
   graph.AddEdge(0, 1, 0.5);
   graph.AddEdge(1, 0, 0.5);
 
-  scoped_ptr<Graph<int> > forest(Degree2MaximumSpanningForest(graph));
+  scoped_ptr<WeightedGraph<int> > forest(Degree2MaximumSpanningForest(graph));
 
   const HashSet<int>& vertices = forest->vertices();
   EXPECT_EQ(vertices.size(), 2);
@@ -119,7 +119,7 @@
 }
 
 TEST(Degree2MaximumSpanningForest, StarGraph) {
-  Graph<int> graph;
+  WeightedGraph<int> graph;
   graph.AddVertex(0);
   graph.AddVertex(1);
   graph.AddVertex(2);
@@ -131,7 +131,7 @@
   graph.AddEdge(0, 3, 3.0);
   graph.AddEdge(0, 4, 4.0);
 
-  scoped_ptr<Graph<int> > forest(Degree2MaximumSpanningForest(graph));
+  scoped_ptr<WeightedGraph<int> > forest(Degree2MaximumSpanningForest(graph));
   const HashSet<int>& vertices = forest->vertices();
   EXPECT_EQ(vertices.size(), 5);
 
@@ -176,8 +176,8 @@
   //   |
   // 2-3
   // 0,1 and 2 have degree 1 and 3 has degree 2.
-  graph.AddEdge(0, 1, 1.0);
-  graph.AddEdge(2, 3, 1.0);
+  graph.AddEdge(0, 1);
+  graph.AddEdge(2, 3);
   VertexTotalOrdering<int> less_than(graph);
 
   for (int i = 0; i < 4; ++i) {
diff --git a/internal/ceres/graph_test.cc b/internal/ceres/graph_test.cc
index 85b80bf..a1521d8 100644
--- a/internal/ceres/graph_test.cc
+++ b/internal/ceres/graph_test.cc
@@ -44,6 +44,51 @@
 
 TEST(Graph, AddVertexAndEdge) {
   Graph<int> graph;
+  graph.AddVertex(0);
+  graph.AddVertex(1);
+  graph.AddEdge(0, 1);
+
+  const HashSet<int>& vertices = graph.vertices();
+  EXPECT_EQ(vertices.size(), 2);
+  EXPECT_EQ(graph.Neighbors(0).size(), 1);
+  EXPECT_EQ(graph.Neighbors(1).size(), 1);
+}
+
+TEST(Graph, AddVertexIdempotence) {
+  Graph<int> graph;
+  graph.AddVertex(0);
+  graph.AddVertex(1);
+  graph.AddEdge(0, 1)
+
+  const HashSet<int>& vertices = graph.vertices();
+
+  EXPECT_EQ(vertices.size(), 2);
+
+  // Try adding the vertex again with a new weight.
+  graph.AddVertex(0, 3.0);
+  EXPECT_EQ(vertices.size(), 2);
+
+  // Rest of the graph remains the same.
+  EXPECT_EQ(graph.Neighbors(0).size(), 1);
+  EXPECT_EQ(graph.Neighbors(1).size(), 1);
+}
+
+TEST(Graph, DieOnNonExistentVertex) {
+  Graph<int> graph;
+  graph.AddVertex(0);
+  graph.AddVertex(1);
+  graph.AddEdge(0, 1);
+
+  EXPECT_DEATH_IF_SUPPORTED(graph.Neighbors(2), "key not found");
+}
+
+TEST(WeightedGraph, EmptyGraph) {
+  WeightedGraph<int> graph;
+  EXPECT_EQ(graph.vertices().size(), 0);
+}
+
+TEST(WeightedGraph, AddVertexAndEdge) {
+  WeightedGraph<int> graph;
   graph.AddVertex(0, 1.0);
   graph.AddVertex(1, 2.0);
   graph.AddEdge(0, 1, 0.5);
@@ -58,8 +103,8 @@
   EXPECT_EQ(graph.EdgeWeight(1, 0), 0.5);
 }
 
-TEST(Graph, AddVertexIdempotence) {
-  Graph<int> graph;
+TEST(WeightedGraph, AddVertexIdempotence) {
+  WeightedGraph<int> graph;
   graph.AddVertex(0, 1.0);
   graph.AddVertex(1, 2.0);
   graph.AddEdge(0, 1, 0.5);
@@ -83,8 +128,8 @@
   EXPECT_EQ(graph.EdgeWeight(1, 0), 0.5);
 }
 
-TEST(Graph, DieOnNonExistentVertex) {
-  Graph<int> graph;
+TEST(WeightedGraph, DieOnNonExistentVertex) {
+  WeightedGraph<int> graph;
   graph.AddVertex(0, 1.0);
   graph.AddVertex(1, 2.0);
   graph.AddEdge(0, 1, 0.5);
@@ -93,8 +138,8 @@
   EXPECT_DEATH_IF_SUPPORTED(graph.Neighbors(2), "key not found");
 }
 
-TEST(Graph, NonExistentEdge) {
-  Graph<int> graph;
+TEST(WeightedGraph, NonExistentEdge) {
+  WeightedGraph<int> graph;
   graph.AddVertex(0, 1.0);
   graph.AddVertex(1, 2.0);
   graph.AddEdge(0, 1, 0.5);
diff --git a/internal/ceres/parameter_block_ordering.cc b/internal/ceres/parameter_block_ordering.cc
index 3032329..1525de9 100644
--- a/internal/ceres/parameter_block_ordering.cc
+++ b/internal/ceres/parameter_block_ordering.cc
@@ -37,6 +37,7 @@
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
+#include "ceres/wall_time.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -45,8 +46,10 @@
 int ComputeStableSchurOrdering(const Program& program,
                          vector<ParameterBlock*>* ordering) {
   CHECK_NOTNULL(ordering)->clear();
-
+  EventLogger event_logger("ComputeStableSchurOrdering");
   scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+  event_logger.AddEvent("CreateHessianGraph");
+
   const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
   const HashSet<ParameterBlock*>& vertices = graph->vertices();
   for (int i = 0; i < parameter_blocks.size(); ++i) {
@@ -54,8 +57,10 @@
       ordering->push_back(parameter_blocks[i]);
     }
   }
+  event_logger.AddEvent("Preordering");
 
   int independent_set_size = StableIndependentSetOrdering(*graph, ordering);
+  event_logger.AddEvent("StableIndependentSet");
 
   // Add the excluded blocks to back of the ordering vector.
   for (int i = 0; i < parameter_blocks.size(); ++i) {
@@ -64,6 +69,7 @@
       ordering->push_back(parameter_block);
     }
   }
+  event_logger.AddEvent("ConstantParameterBlocks");
 
   return independent_set_size;
 }
@@ -109,8 +115,7 @@
   }
 }
 
-Graph<ParameterBlock*>*
-CreateHessianGraph(const Program& program) {
+Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
   Graph<ParameterBlock*>* graph = CHECK_NOTNULL(new Graph<ParameterBlock*>);
   const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
   for (int i = 0; i < parameter_blocks.size(); ++i) {
diff --git a/internal/ceres/single_linkage_clustering.cc b/internal/ceres/single_linkage_clustering.cc
index 0a8b20c..f0f7e0e 100644
--- a/internal/ceres/single_linkage_clustering.cc
+++ b/internal/ceres/single_linkage_clustering.cc
@@ -44,7 +44,7 @@
 
 int ComputeSingleLinkageClustering(
     const SingleLinkageClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     HashMap<int, int>* membership) {
   CHECK_NOTNULL(membership)->clear();
 
diff --git a/internal/ceres/single_linkage_clustering.h b/internal/ceres/single_linkage_clustering.h
index e6fdeab..79c4da1 100644
--- a/internal/ceres/single_linkage_clustering.h
+++ b/internal/ceres/single_linkage_clustering.h
@@ -64,7 +64,7 @@
 // identified by the algorithm.
 int ComputeSingleLinkageClustering(
     const SingleLinkageClusteringOptions& options,
-    const Graph<int>& graph,
+    const WeightedGraph<int>& graph,
     HashMap<int, int>* membership);
 
 }  // namespace internal
diff --git a/internal/ceres/single_linkage_clustering_test.cc b/internal/ceres/single_linkage_clustering_test.cc
index 1cbc5be..1d4efd2 100644
--- a/internal/ceres/single_linkage_clustering_test.cc
+++ b/internal/ceres/single_linkage_clustering_test.cc
@@ -43,7 +43,7 @@
 namespace internal {
 
 TEST(SingleLinkageClustering, GraphHasTwoComponents) {
-  Graph<int> graph;
+  WeightedGraph<int> graph;
   const int kNumVertices = 6;
   for (int i = 0; i < kNumVertices; ++i) {
     graph.AddVertex(i);
@@ -61,8 +61,7 @@
   ComputeSingleLinkageClustering(options, graph, &membership);
   EXPECT_EQ(membership.size(), kNumVertices);
 
-  EXPECT_EQ(membership[1], membership[0]);
-  EXPECT_EQ(membership[2], membership[0]);
+  EXPECT_EQ(membership[1], membership[0]); EXPECT_EQ(membership[2], membership[0]);
   EXPECT_EQ(membership[3], membership[0]);
   EXPECT_NE(membership[4], membership[0]);
   EXPECT_NE(membership[5], membership[0]);
@@ -70,7 +69,7 @@
 }
 
 TEST(SingleLinkageClustering, ComponentWithWeakLink) {
-  Graph<int> graph;
+  WeightedGraph<int> graph;
   const int kNumVertices = 6;
   for (int i = 0; i < kNumVertices; ++i) {
     graph.AddVertex(i);
@@ -99,7 +98,7 @@
 }
 
 TEST(SingleLinkageClustering, ComponentWithWeakLinkAndStrongLink) {
-  Graph<int> graph;
+  WeightedGraph<int> graph;
   const int kNumVertices = 6;
   for (int i = 0; i < kNumVertices; ++i) {
     graph.AddVertex(i);
diff --git a/internal/ceres/visibility.cc b/internal/ceres/visibility.cc
index b3ee185..e46421c 100644
--- a/internal/ceres/visibility.cc
+++ b/internal/ceres/visibility.cc
@@ -76,7 +76,7 @@
   }
 }
 
-Graph<int>* CreateSchurComplementGraph(const vector<set<int> >& visibility) {
+WeightedGraph<int>* CreateSchurComplementGraph(const vector<set<int> >& visibility) {
   const time_t start_time = time(NULL);
   // Compute the number of e_blocks/point blocks. Since the visibility
   // set for each e_block/camera contains the set of e_blocks/points
@@ -122,7 +122,7 @@
     }
   }
 
-  Graph<int>* graph = new Graph<int>();
+  WeightedGraph<int>* graph = new WeightedGraph<int>();
 
   // Add vertices and initialize the pairs for self edges so that self
   // edges are guaranteed. This is needed for the Canonical views
diff --git a/internal/ceres/visibility.h b/internal/ceres/visibility.h
index 5ddd3a5..62d4f0f 100644
--- a/internal/ceres/visibility.h
+++ b/internal/ceres/visibility.h
@@ -72,9 +72,9 @@
 // matrix/Schur complement matrix obtained by eliminating the e_blocks
 // from the normal equations.
 //
-// Caller acquires ownership of the returned Graph pointer
+// Caller acquires ownership of the returned WeightedGraph pointer
 // (heap-allocated).
-Graph<int>* CreateSchurComplementGraph(const vector<set<int> >& visibility);
+WeightedGraph<int>* CreateSchurComplementGraph(const vector<set<int> >& visibility);
 
 }  // namespace internal
 }  // namespace ceres
diff --git a/internal/ceres/visibility_based_preconditioner.cc b/internal/ceres/visibility_based_preconditioner.cc
index 695eedc..c7ed049 100644
--- a/internal/ceres/visibility_based_preconditioner.cc
+++ b/internal/ceres/visibility_based_preconditioner.cc
@@ -167,9 +167,9 @@
   // maximum spanning forest of this graph.
   vector<set<int> > cluster_visibility;
   ComputeClusterVisibility(visibility, &cluster_visibility);
-  scoped_ptr<Graph<int> > cluster_graph(
+  scoped_ptr<WeightedGraph<int> > cluster_graph(
       CHECK_NOTNULL(CreateClusterGraph(cluster_visibility)));
-  scoped_ptr<Graph<int> > forest(
+  scoped_ptr<WeightedGraph<int> > forest(
       CHECK_NOTNULL(Degree2MaximumSpanningForest(*cluster_graph)));
   ForestToClusterPairs(*forest, &cluster_pairs_);
 }
@@ -189,7 +189,7 @@
 // memberships for each camera block.
 void VisibilityBasedPreconditioner::ClusterCameras(
     const vector<set<int> >& visibility) {
-  scoped_ptr<Graph<int> > schur_complement_graph(
+  scoped_ptr<WeightedGraph<int> > schur_complement_graph(
       CHECK_NOTNULL(CreateSchurComplementGraph(visibility)));
 
   HashMap<int, int> membership;
@@ -498,7 +498,7 @@
 // Convert a graph into a list of edges that includes self edges for
 // each vertex.
 void VisibilityBasedPreconditioner::ForestToClusterPairs(
-    const Graph<int>& forest,
+    const WeightedGraph<int>& forest,
     HashSet<pair<int, int> >* cluster_pairs) const {
   CHECK_NOTNULL(cluster_pairs)->clear();
   const HashSet<int>& vertices = forest.vertices();
@@ -541,9 +541,9 @@
 // Construct a graph whose vertices are the clusters, and the edge
 // weights are the number of 3D points visible to cameras in both the
 // vertices.
-Graph<int>* VisibilityBasedPreconditioner::CreateClusterGraph(
+WeightedGraph<int>* VisibilityBasedPreconditioner::CreateClusterGraph(
     const vector<set<int> >& cluster_visibility) const {
-  Graph<int>* cluster_graph = new Graph<int>;
+  WeightedGraph<int>* cluster_graph = new WeightedGraph<int>;
 
   for (int i = 0; i < num_clusters_; ++i) {
     cluster_graph->AddVertex(i);
diff --git a/internal/ceres/visibility_based_preconditioner.h b/internal/ceres/visibility_based_preconditioner.h
index 70cea83..7e0b51b 100644
--- a/internal/ceres/visibility_based_preconditioner.h
+++ b/internal/ceres/visibility_based_preconditioner.h
@@ -156,8 +156,8 @@
                             vector<int>* membership_vector) const;
   void ComputeClusterVisibility(const vector<set<int> >& visibility,
                                 vector<set<int> >* cluster_visibility) const;
-  Graph<int>* CreateClusterGraph(const vector<set<int> >& visibility) const;
-  void ForestToClusterPairs(const Graph<int>& forest,
+  WeightedGraph<int>* CreateClusterGraph(const vector<set<int> >& visibility) const;
+  void ForestToClusterPairs(const WeightedGraph<int>& forest,
                             HashSet<pair<int, int> >* cluster_pairs) const;
   void ComputeBlockPairsInPreconditioner(const CompressedRowBlockStructure& bs);
   bool IsBlockPairInPreconditioner(int block1, int block2) const;
diff --git a/internal/ceres/visibility_test.cc b/internal/ceres/visibility_test.cc
index 0e22f88..01f2bdf 100644
--- a/internal/ceres/visibility_test.cc
+++ b/internal/ceres/visibility_test.cc
@@ -108,7 +108,7 @@
     ASSERT_EQ(visibility[i].size(), 1);
   }
 
-  scoped_ptr<Graph<int> > graph(CreateSchurComplementGraph(visibility));
+  scoped_ptr<WeightedGraph<int> > graph(CreateSchurComplementGraph(visibility));
   EXPECT_EQ(graph->vertices().size(), visibility.size());
   for (int i = 0; i < visibility.size(); ++i) {
     EXPECT_EQ(graph->VertexWeight(i), 1.0);
@@ -184,7 +184,7 @@
     ASSERT_EQ(visibility[i].size(), 0);
   }
 
-  scoped_ptr<Graph<int> > graph(CreateSchurComplementGraph(visibility));
+  scoped_ptr<WeightedGraph<int> > graph(CreateSchurComplementGraph(visibility));
   EXPECT_EQ(graph->vertices().size(), visibility.size());
   for (int i = 0; i < visibility.size(); ++i) {
     EXPECT_EQ(graph->VertexWeight(i), 1.0);