10ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Ceres Solver - A fast non-linear least squares minimizer
20ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
30ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// http://code.google.com/p/ceres-solver/
40ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
50ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Redistribution and use in source and binary forms, with or without
60ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// modification, are permitted provided that the following conditions are met:
70ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
80ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions of source code must retain the above copyright notice,
90ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer.
100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Redistributions in binary form must reproduce the above copyright notice,
110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   this list of conditions and the following disclaimer in the documentation
120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   and/or other materials provided with the distribution.
130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// * Neither the name of Google Inc. nor the names of its contributors may be
140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   used to endorse or promote products derived from this software without
150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//   specific prior written permission.
160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// POSSIBILITY OF SUCH DAMAGE.
280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//
290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Author: David Gallup (dgallup@google.com)
300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong//         Sameer Agarwal (sameeragarwal@google.com)
310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
321d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#ifndef CERES_NO_SUITESPARSE
331d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/canonical_views_clustering.h"
350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/collections_port.h"
370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/graph.h"
380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/internal/macros.h"
390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "ceres/map_util.h"
400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong#include "glog/logging.h"
410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace ceres {
430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongnamespace internal {
440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtypedef HashMap<int, int> IntMap;
460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongtypedef HashSet<int> IntSet;
470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongclass CanonicalViewsClustering {
490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong public:
500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CanonicalViewsClustering() {}
510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Compute the canonical views clustering of the vertices of the
530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // graph. centers will contain the vertices that are the identified
540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // as the canonical views/cluster centers, and membership is a map
550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // from vertices to cluster_ids. The i^th cluster center corresponds
560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // to the i^th cluster. It is possible depending on the
570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // configuration of the clustering algorithm that some of the
580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // vertices may not be assigned to any cluster. In this case they
590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // are assigned to a cluster with id = kInvalidClusterId.
600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void ComputeClustering(const Graph<int>& graph,
610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                         const CanonicalViewsClusteringOptions& options,
620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                         vector<int>* centers,
630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                         IntMap* membership);
640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong private:
660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void FindValidViews(IntSet* valid_views) const;
670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double ComputeClusteringQualityDifference(const int candidate,
680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                            const vector<int>& centers) const;
690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void UpdateCanonicalViewAssignments(const int canonical_view);
700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  void ComputeClusterMembership(const vector<int>& centers,
710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong                                IntMap* membership) const;
720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CanonicalViewsClusteringOptions options_;
740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const Graph<int>* graph_;
750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Maps a view to its representative canonical view (its cluster
760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // center).
770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  IntMap view_to_canonical_view_;
780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Maps a view to its similarity to its current cluster center.
790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  HashMap<int, double> view_to_canonical_view_similarity_;
800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CERES_DISALLOW_COPY_AND_ASSIGN(CanonicalViewsClustering);
810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong};
820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid ComputeCanonicalViewsClustering(
840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const Graph<int>& graph,
850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const CanonicalViewsClusteringOptions& options,
860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    vector<int>* centers,
870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    IntMap* membership) {
880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  time_t start_time = time(NULL);
890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CanonicalViewsClustering cv;
900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  cv.ComputeClustering(graph, options, centers, membership);
910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  VLOG(2) << "Canonical views clustering time (secs): "
920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          << time(NULL) - start_time;
930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Implementation of CanonicalViewsClustering
960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid CanonicalViewsClustering::ComputeClustering(
970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const Graph<int>& graph,
980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const CanonicalViewsClusteringOptions& options,
990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    vector<int>* centers,
1000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    IntMap* membership) {
1010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  options_ = options;
1020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CHECK_NOTNULL(centers)->clear();
1030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CHECK_NOTNULL(membership)->clear();
1040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  graph_ = &graph;
1050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  IntSet valid_views;
1070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  FindValidViews(&valid_views);
1080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  while (valid_views.size() > 0) {
1090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Find the next best canonical view.
1100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    double best_difference = -std::numeric_limits<double>::max();
1110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    int best_view = 0;
1120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // TODO(sameeragarwal): Make this loop multi-threaded.
1140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    for (IntSet::const_iterator view = valid_views.begin();
1150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong         view != valid_views.end();
1160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong         ++view) {
1170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      const double difference =
1180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong          ComputeClusteringQualityDifference(*view, *centers);
1190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      if (difference > best_difference) {
1200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        best_difference = difference;
1210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        best_view = *view;
1220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      }
1230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    CHECK_GT(best_difference, -std::numeric_limits<double>::max());
1260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // Add canonical view if quality improves, or if minimum is not
1280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    // yet met, otherwise break.
1290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if ((best_difference <= 0) &&
1300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        (centers->size() >= options_.min_views)) {
1310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      break;
1320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    centers->push_back(best_view);
1350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    valid_views.erase(best_view);
1360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    UpdateCanonicalViewAssignments(best_view);
1370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  ComputeClusterMembership(*centers, membership);
1400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
1410ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1420ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Return the set of vertices of the graph which have valid vertex
1430ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// weights.
1440ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid CanonicalViewsClustering::FindValidViews(
1450ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    IntSet* valid_views) const {
1460ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const IntSet& views = graph_->vertices();
1470ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (IntSet::const_iterator view = views.begin();
1480ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       view != views.end();
1490ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       ++view) {
1500ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (graph_->VertexWeight(*view) != Graph<int>::InvalidWeight()) {
1510ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      valid_views->insert(*view);
1520ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1530ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1540ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
1550ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1560ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Computes the difference in the quality score if 'candidate' were
1570ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// added to the set of canonical views.
1580ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongdouble CanonicalViewsClustering::ComputeClusteringQualityDifference(
1590ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const int candidate,
1600ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const vector<int>& centers) const {
1610ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // View score.
1620ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  double difference =
1630ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      options_.view_score_weight * graph_->VertexWeight(candidate);
1640ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1650ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Compute how much the quality score changes if the candidate view
1660ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // was added to the list of canonical views and its nearest
1670ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // neighbors became members of its cluster.
1680ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const IntSet& neighbors = graph_->Neighbors(candidate);
1690ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (IntSet::const_iterator neighbor = neighbors.begin();
1700ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       neighbor != neighbors.end();
1710ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       ++neighbor) {
1720ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const double old_similarity =
1730ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        FindWithDefault(view_to_canonical_view_similarity_, *neighbor, 0.0);
1740ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const double new_similarity = graph_->EdgeWeight(*neighbor, candidate);
1750ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (new_similarity > old_similarity) {
1760ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      difference += new_similarity - old_similarity;
1770ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
1780ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1790ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1800ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Number of views penalty.
1810ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  difference -= options_.size_penalty_weight;
1820ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1830ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // Orthogonality.
1840ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (int i = 0; i < centers.size(); ++i) {
1850ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    difference -= options_.similarity_penalty_weight *
1860ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        graph_->EdgeWeight(centers[i], candidate);
1870ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
1880ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1890ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  return difference;
1900ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
1910ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
1920ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Reassign views if they're more similar to the new canonical view.
1930ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid CanonicalViewsClustering::UpdateCanonicalViewAssignments(
1940ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const int canonical_view) {
1950ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const IntSet& neighbors = graph_->Neighbors(canonical_view);
1960ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (IntSet::const_iterator neighbor = neighbors.begin();
1970ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       neighbor != neighbors.end();
1980ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       ++neighbor) {
1990ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const double old_similarity =
2000ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        FindWithDefault(view_to_canonical_view_similarity_, *neighbor, 0.0);
2010ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const double new_similarity =
2020ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        graph_->EdgeWeight(*neighbor, canonical_view);
2030ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (new_similarity > old_similarity) {
2040ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      view_to_canonical_view_[*neighbor] = canonical_view;
2050ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      view_to_canonical_view_similarity_[*neighbor] = new_similarity;
2060ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2070ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
2080ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
2090ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2100ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong// Assign a cluster id to each view.
2110ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kongvoid CanonicalViewsClustering::ComputeClusterMembership(
2120ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    const vector<int>& centers,
2130ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    IntMap* membership) const {
2140ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  CHECK_NOTNULL(membership)->clear();
2150ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2160ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  // The i^th cluster has cluster id i.
2170ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  IntMap center_to_cluster_id;
2180ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (int i = 0; i < centers.size(); ++i) {
2190ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    center_to_cluster_id[centers[i]] = i;
2200ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
2210ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2220ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  static const int kInvalidClusterId = -1;
2230ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2240ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  const IntSet& views = graph_->vertices();
2250ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  for (IntSet::const_iterator view = views.begin();
2260ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       view != views.end();
2270ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong       ++view) {
2280ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    IntMap::const_iterator it =
2290ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong        view_to_canonical_view_.find(*view);
2300ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    int cluster_id = kInvalidClusterId;
2310ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    if (it != view_to_canonical_view_.end()) {
2320ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong      cluster_id = FindOrDie(center_to_cluster_id, it->second);
2330ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    }
2340ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2350ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong    InsertOrDie(membership, *view, cluster_id);
2360ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong  }
2370ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}
2380ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong
2390ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace internal
2400ae28bd5885b5daa526898fcf7c323dc2c3e1963Angus Kong}  // namespace ceres
2411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
2421d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#endif  // CERES_NO_SUITESPARSE
243