1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS-IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 
16 // Author: ericv@google.com (Eric Veach)
17 
18 #include "s2/s2builder_graph.h"
19 
20 #include <algorithm>
21 #include <limits>
22 #include <memory>
23 #include <numeric>
24 #include <vector>
25 #include "s2/base/logging.h"
26 #include "absl/container/btree_map.h"
27 #include "s2/id_set_lexicon.h"
28 #include "s2/s2builder.h"
29 #include "s2/s2error.h"
30 #include "s2/s2predicates.h"
31 
32 using std::make_pair;
33 using std::max;
34 using std::min;
35 using std::pair;
36 using std::vector;
37 
38 using Graph = S2Builder::Graph;
39 using GraphOptions = S2Builder::GraphOptions;
40 using DegenerateEdges = GraphOptions::DegenerateEdges;
41 using DuplicateEdges = GraphOptions::DuplicateEdges;
42 using SiblingPairs = GraphOptions::SiblingPairs;
43 
Graph(const GraphOptions & options,const vector<S2Point> * vertices,const vector<Edge> * edges,const vector<InputEdgeIdSetId> * input_edge_id_set_ids,const IdSetLexicon * input_edge_id_set_lexicon,const vector<LabelSetId> * label_set_ids,const IdSetLexicon * label_set_lexicon,IsFullPolygonPredicate is_full_polygon_predicate)44 Graph::Graph(const GraphOptions& options,
45              const vector<S2Point>* vertices,
46              const vector<Edge>* edges,
47              const vector<InputEdgeIdSetId>* input_edge_id_set_ids,
48              const IdSetLexicon* input_edge_id_set_lexicon,
49              const vector<LabelSetId>* label_set_ids,
50              const IdSetLexicon* label_set_lexicon,
51              IsFullPolygonPredicate is_full_polygon_predicate)
52     : options_(options), num_vertices_(vertices->size()), vertices_(vertices),
53       edges_(edges), input_edge_id_set_ids_(input_edge_id_set_ids),
54       input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
55       label_set_ids_(label_set_ids),
56       label_set_lexicon_(label_set_lexicon),
57       is_full_polygon_predicate_(std::move(is_full_polygon_predicate)) {
58   S2_DCHECK(std::is_sorted(edges->begin(), edges->end()));
59   S2_DCHECK_EQ(edges->size(), input_edge_id_set_ids->size());
60 }
61 
GetInEdgeIds() const62 vector<Graph::EdgeId> Graph::GetInEdgeIds() const {
63   vector<EdgeId> in_edge_ids(num_edges());
64   std::iota(in_edge_ids.begin(), in_edge_ids.end(), 0);
65   std::sort(in_edge_ids.begin(), in_edge_ids.end(),
66             [this](EdgeId ai, EdgeId bi) {
67       return StableLessThan(reverse(edge(ai)), reverse(edge(bi)), ai, bi);
68     });
69   return in_edge_ids;
70 }
71 
GetSiblingMap() const72 vector<Graph::EdgeId> Graph::GetSiblingMap() const {
73   vector<EdgeId> in_edge_ids = GetInEdgeIds();
74   MakeSiblingMap(&in_edge_ids);
75   return in_edge_ids;
76 }
77 
MakeSiblingMap(vector<Graph::EdgeId> * in_edge_ids) const78 void Graph::MakeSiblingMap(vector<Graph::EdgeId>* in_edge_ids) const {
79   S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
80          options_.sibling_pairs() == SiblingPairs::CREATE ||
81          options_.edge_type() == EdgeType::UNDIRECTED);
82   for (EdgeId e = 0; e < num_edges(); ++e) {
83     S2_DCHECK(edge(e) == reverse(edge((*in_edge_ids)[e])));
84   }
85   if (options_.edge_type() == EdgeType::DIRECTED) return;
86   if (options_.degenerate_edges() == DegenerateEdges::DISCARD) return;
87 
88   for (EdgeId e = 0; e < num_edges(); ++e) {
89     VertexId v = edge(e).first;
90     if (edge(e).second == v) {
91       S2_DCHECK_LT(e + 1, num_edges());
92       S2_DCHECK_EQ(edge(e + 1).first, v);
93       S2_DCHECK_EQ(edge(e + 1).second, v);
94       S2_DCHECK_EQ((*in_edge_ids)[e], e);
95       S2_DCHECK_EQ((*in_edge_ids)[e + 1], e + 1);
96       (*in_edge_ids)[e] = e + 1;
97       (*in_edge_ids)[e + 1] = e;
98       ++e;
99     }
100   }
101 }
102 
Init(const Graph & g)103 void Graph::VertexOutMap::Init(const Graph& g) {
104   edges_ = &g.edges();
105   edge_begins_.reserve(g.num_vertices() + 1);
106   EdgeId e = 0;
107   for (VertexId v = 0; v <= g.num_vertices(); ++v) {
108     while (e < g.num_edges() && g.edge(e).first < v) ++e;
109     edge_begins_.push_back(e);
110   }
111 }
112 
Init(const Graph & g)113 void Graph::VertexInMap::Init(const Graph& g) {
114   in_edge_ids_ = g.GetInEdgeIds();
115   in_edge_begins_.reserve(g.num_vertices() + 1);
116   EdgeId e = 0;
117   for (VertexId v = 0; v <= g.num_vertices(); ++v) {
118     while (e < g.num_edges() && g.edge(in_edge_ids_[e]).second < v) ++e;
119     in_edge_begins_.push_back(e);
120   }
121 }
122 
Init(const Graph & g,S2Builder::EdgeType edge_type)123 void Graph::LabelFetcher::Init(const Graph& g, S2Builder::EdgeType edge_type) {
124   g_ = &g;
125   edge_type_ = edge_type;
126   if (edge_type == EdgeType::UNDIRECTED) sibling_map_ = g.GetSiblingMap();
127 }
128 
Fetch(EdgeId e,vector<S2Builder::Label> * labels)129 void Graph::LabelFetcher::Fetch(EdgeId e, vector<S2Builder::Label>* labels) {
130   labels->clear();
131   for (InputEdgeId input_edge_id : g_->input_edge_ids(e)) {
132     for (Label label : g_->labels(input_edge_id)) {
133       labels->push_back(label);
134     }
135   }
136   if (edge_type_ == EdgeType::UNDIRECTED) {
137     for (InputEdgeId input_edge_id : g_->input_edge_ids(sibling_map_[e])) {
138       for (Label label : g_->labels(input_edge_id)) {
139         labels->push_back(label);
140       }
141     }
142   }
143   if (labels->size() > 1) {
144     std::sort(labels->begin(), labels->end());
145     labels->erase(std::unique(labels->begin(), labels->end()), labels->end());
146   }
147 }
148 
min_input_edge_id(EdgeId e) const149 S2Builder::InputEdgeId Graph::min_input_edge_id(EdgeId e) const {
150   IdSetLexicon::IdSet id_set = input_edge_ids(e);
151   return (id_set.size() == 0) ? kNoInputEdgeId : *id_set.begin();
152 }
153 
GetMinInputEdgeIds() const154 vector<S2Builder::InputEdgeId> Graph::GetMinInputEdgeIds() const {
155   vector<InputEdgeId> min_input_ids(num_edges());
156   for (EdgeId e = 0; e < num_edges(); ++e) {
157     min_input_ids[e] = min_input_edge_id(e);
158   }
159   return min_input_ids;
160 }
161 
GetInputEdgeOrder(const vector<InputEdgeId> & input_ids) const162 vector<Graph::EdgeId> Graph::GetInputEdgeOrder(
163     const vector<InputEdgeId>& input_ids) const {
164   vector<EdgeId> order(input_ids.size());
165   std::iota(order.begin(), order.end(), 0);
166   std::sort(order.begin(), order.end(), [&input_ids](EdgeId a, EdgeId b) {
167       // Comparison function ensures sort is stable.
168       return make_pair(input_ids[a], a) < make_pair(input_ids[b], b);
169     });
170   return order;
171 }
172 
173 // A struct for sorting the incoming and outgoing edges around a vertex "v0".
174 struct VertexEdge {
VertexEdgeVertexEdge175   VertexEdge(bool _incoming, Graph::EdgeId _index,
176              Graph::VertexId _endpoint, int32 _rank)
177       : incoming(_incoming), index(_index),
178         endpoint(_endpoint), rank(_rank) {
179   }
180   bool incoming;             // Is this an incoming edge to "v0"?
181   Graph::EdgeId index;       // Index of this edge in "edges_" or "in_edge_ids"
182   Graph::VertexId endpoint;  // The other (not "v0") endpoint of this edge
183   int32 rank;                // Secondary key for edges with the same endpoint
184 };
185 
186 // Given a set of duplicate outgoing edges (v0, v1) and a set of duplicate
187 // incoming edges (v1, v0), this method assigns each edge an integer "rank" so
188 // that the edges are sorted in a consistent order with respect to their
189 // orderings around "v0" and "v1".  Usually there is just one edge, in which
190 // case this is easy.  Sometimes there is one edge in each direction, in which
191 // case the outgoing edge is always ordered before the incoming edge.
192 //
193 // In general, we allow any number of duplicate edges in each direction, in
194 // which case outgoing edges are interleaved with incoming edges so as to
195 // create as many degenerate (two-edge) loops as possible.  In order to get a
196 // consistent ordering around "v0" and "v1", we move forwards through the list
197 // of outgoing edges and backwards through the list of incoming edges.  If
198 // there are more incoming edges, they go at the beginning of the ordering,
199 // while if there are more outgoing edges then they go at the end.
200 //
201 // For example, suppose there are 2 edges "a,b" from "v0" to "v1", and 4 edges
202 // "w,x,y,z" from "v1" to "v0".  Using lower/upper case letters to represent
203 // incoming/outgoing edges, the clockwise ordering around v0 would be zyAxBw,
204 // and the clockwise ordering around v1 would be WbXaYZ.  (Try making a
205 // diagram with each edge as a separate arc.)
AddVertexEdges(Graph::EdgeId out_begin,Graph::EdgeId out_end,Graph::EdgeId in_begin,Graph::EdgeId in_end,Graph::VertexId v1,vector<VertexEdge> * v0_edges)206 static void AddVertexEdges(Graph::EdgeId out_begin, Graph::EdgeId out_end,
207                            Graph::EdgeId in_begin, Graph::EdgeId in_end,
208                            Graph::VertexId v1, vector<VertexEdge>* v0_edges) {
209   int rank = 0;
210   // Any extra incoming edges go at the beginning of the ordering.
211   while (in_end - in_begin > out_end - out_begin) {
212     v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
213   }
214   // Next we interleave as many outgoing and incoming edges as possible.
215   while (in_end > in_begin) {
216     v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
217     v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
218   }
219   // Any extra outgoing edges to at the end of the ordering.
220   while (out_end > out_begin) {
221     v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
222   }
223 }
224 
GetLeftTurnMap(const vector<EdgeId> & in_edge_ids,vector<EdgeId> * left_turn_map,S2Error * error) const225 bool Graph::GetLeftTurnMap(const vector<EdgeId>& in_edge_ids,
226                            vector<EdgeId>* left_turn_map,
227                            S2Error* error) const {
228   left_turn_map->assign(num_edges(), -1);
229   if (num_edges() == 0) return true;
230 
231   // Declare vectors outside the loop to avoid reallocating them each time.
232   vector<VertexEdge> v0_edges;
233   vector<EdgeId> e_in, e_out;
234 
235   // Walk through the two sorted arrays of edges (outgoing and incoming) and
236   // gather all the edges incident to each vertex.  Then we sort those edges
237   // and add an entry to the left turn map from each incoming edge to the
238   // immediately following outgoing edge in clockwise order.
239   int out = 0, in = 0;
240   const Edge* out_edge = &edge(out);
241   const Edge* in_edge = &edge(in_edge_ids[in]);
242   Edge sentinel(num_vertices(), num_vertices());
243   Edge min_edge = min(*out_edge, reverse(*in_edge));
244   while (min_edge != sentinel) {
245     // Gather all incoming and outgoing edges around vertex "v0".
246     VertexId v0 = min_edge.first;
247     for (; min_edge.first == v0; min_edge = min(*out_edge, reverse(*in_edge))) {
248       VertexId v1 = min_edge.second;
249       // Count the number of copies of "min_edge" in each direction.
250       int out_begin = out, in_begin = in;
251       while (*out_edge == min_edge) {
252         out_edge = (++out == num_edges()) ? &sentinel : &edge(out);
253       }
254       while (reverse(*in_edge) == min_edge) {
255         in_edge = (++in == num_edges()) ? &sentinel : &edge(in_edge_ids[in]);
256       }
257       if (v0 != v1) {
258         AddVertexEdges(out_begin, out, in_begin, in, v1, &v0_edges);
259       } else {
260         // Each degenerate edge becomes its own loop.
261         for (; in_begin < in; ++in_begin) {
262           (*left_turn_map)[in_begin] = in_begin;
263         }
264       }
265     }
266     if (v0_edges.empty()) continue;
267 
268     // Sort the edges in clockwise order around "v0".
269     VertexId min_endpoint = v0_edges.front().endpoint;
270     std::sort(v0_edges.begin() + 1, v0_edges.end(),
271               [v0, min_endpoint, this](const VertexEdge& a,
272                                        const VertexEdge& b) {
273         if (a.endpoint == b.endpoint) return a.rank < b.rank;
274         if (a.endpoint == min_endpoint) return true;
275         if (b.endpoint == min_endpoint) return false;
276         return !s2pred::OrderedCCW(vertex(a.endpoint), vertex(b.endpoint),
277                                    vertex(min_endpoint), vertex(v0));
278       });
279     // Match incoming with outgoing edges.  We do this by keeping a stack of
280     // unmatched incoming edges.  We also keep a stack of outgoing edges with
281     // no previous incoming edge, and match these at the end by wrapping
282     // around circularly to the start of the edge ordering.
283     for (const VertexEdge& e : v0_edges) {
284       if (e.incoming) {
285         e_in.push_back(in_edge_ids[e.index]);
286       } else if (!e_in.empty()) {
287         (*left_turn_map)[e_in.back()] = e.index;
288         e_in.pop_back();
289       } else {
290         e_out.push_back(e.index);  // Matched below.
291       }
292     }
293     // Pair up additional edges using the fact that the ordering is circular.
294     std::reverse(e_out.begin(), e_out.end());
295     for (; !e_out.empty() && !e_in.empty(); e_out.pop_back(), e_in.pop_back()) {
296       (*left_turn_map)[e_in.back()] = e_out.back();
297     }
298     // We only need to process unmatched incoming edges, since we are only
299     // responsible for creating left turn map entries for those edges.
300     if (!e_in.empty() && error->ok()) {
301       error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
302                   "Given edges do not form loops (indegree != outdegree)");
303     }
304     e_in.clear();
305     e_out.clear();
306     v0_edges.clear();
307   }
308   return error->ok();
309 }
310 
CanonicalizeLoopOrder(const vector<InputEdgeId> & min_input_ids,vector<EdgeId> * loop)311 void Graph::CanonicalizeLoopOrder(const vector<InputEdgeId>& min_input_ids,
312                                   vector<EdgeId>* loop) {
313   if (loop->empty()) return;
314   // Find the position of the element with the highest input edge id.  If
315   // there are multiple such elements together (i.e., the edge was split
316   // into several pieces by snapping it to several vertices), then we choose
317   // the last such position in cyclic order (this attempts to preserve the
318   // original loop order even when new vertices are added).  For example, if
319   // the input edge id sequence is (7, 7, 4, 5, 6, 7) then we would rotate
320   // it to obtain (4, 5, 6, 7, 7, 7).
321 
322   // The reason that we put the highest-numbered edge last, rather than the
323   // lowest-numbered edge first, is that S2Loop::Invert() reverses the loop
324   // edge order *except* for the last edge.  For example, the loop ABCD (with
325   // edges AB, BC, CD, DA) becomes DCBA (with edges DC, CB, BA, AD).  Note
326   // that the last edge is the same except for its direction (DA vs. AD).
327   // This has the advantage that if an undirected loop is assembled with the
328   // wrong orientation and later inverted (e.g. by S2Polygon::InitOriented),
329   // we still end up preserving the original cyclic vertex order.
330   int pos = 0;
331   bool saw_gap = false;
332   for (int i = 1; i < loop->size(); ++i) {
333     int cmp = min_input_ids[(*loop)[i]] - min_input_ids[(*loop)[pos]];
334     if (cmp < 0) {
335       saw_gap = true;
336     } else if (cmp > 0 || !saw_gap) {
337       pos = i;
338       saw_gap = false;
339     }
340   }
341   if (++pos == loop->size()) pos = 0;  // Convert loop end to loop start.
342   std::rotate(loop->begin(), loop->begin() + pos, loop->end());
343 }
344 
CanonicalizeVectorOrder(const vector<InputEdgeId> & min_input_ids,vector<vector<EdgeId>> * chains)345 void Graph::CanonicalizeVectorOrder(const vector<InputEdgeId>& min_input_ids,
346                                     vector<vector<EdgeId>>* chains) {
347   std::sort(chains->begin(), chains->end(),
348     [&min_input_ids](const vector<EdgeId>& a, const vector<EdgeId>& b) {
349       return min_input_ids[a[0]] < min_input_ids[b[0]];
350     });
351 }
352 
GetDirectedLoops(LoopType loop_type,vector<EdgeLoop> * loops,S2Error * error) const353 bool Graph::GetDirectedLoops(LoopType loop_type, vector<EdgeLoop>* loops,
354                              S2Error* error) const {
355   S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
356          options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
357   S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);
358 
359   vector<EdgeId> left_turn_map;
360   if (!GetLeftTurnMap(GetInEdgeIds(), &left_turn_map, error)) return false;
361   vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
362 
363   // If we are breaking loops at repeated vertices, we maintain a map from
364   // VertexId to its position in "path".
365   vector<int> path_index;
366   if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
367 
368   // Visit edges in arbitrary order, and try to build a loop from each edge.
369   vector<EdgeId> path;
370   for (EdgeId start = 0; start < num_edges(); ++start) {
371     if (left_turn_map[start] < 0) continue;
372 
373     // Build a loop by making left turns at each vertex until we return to
374     // "start".  We use "left_turn_map" to keep track of which edges have
375     // already been visited by setting its entries to -1 as we go along.  If
376     // we are building vertex cycles, then whenever we encounter a vertex that
377     // is already part of the path, we "peel off" a loop by removing those
378     // edges from the path so far.
379     for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
380       path.push_back(e);
381       next = left_turn_map[e];
382       left_turn_map[e] = -1;
383       if (loop_type == LoopType::SIMPLE) {
384         path_index[edge(e).first] = path.size() - 1;
385         int loop_start = path_index[edge(e).second];
386         if (loop_start < 0) continue;
387         // Peel off a loop from the path.
388         vector<EdgeId> loop(path.begin() + loop_start, path.end());
389         path.erase(path.begin() + loop_start, path.end());
390         for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
391         CanonicalizeLoopOrder(min_input_ids, &loop);
392         loops->push_back(std::move(loop));
393       }
394     }
395     if (loop_type == LoopType::SIMPLE) {
396       S2_DCHECK(path.empty());  // Invariant.
397     } else {
398       CanonicalizeLoopOrder(min_input_ids, &path);
399       loops->push_back(std::move(path));
400       path.clear();
401     }
402   }
403   CanonicalizeVectorOrder(min_input_ids, loops);
404   return true;
405 }
406 
GetDirectedComponents(DegenerateBoundaries degenerate_boundaries,vector<DirectedComponent> * components,S2Error * error) const407 bool Graph::GetDirectedComponents(
408     DegenerateBoundaries degenerate_boundaries,
409     vector<DirectedComponent>* components, S2Error* error) const {
410   S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
411          (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
412           degenerate_boundaries == DegenerateBoundaries::KEEP));
413   S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
414          options_.sibling_pairs() == SiblingPairs::CREATE);
415   S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);  // Implied by above.
416 
417   vector<EdgeId> sibling_map = GetInEdgeIds();
418   vector<EdgeId> left_turn_map;
419   if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
420   MakeSiblingMap(&sibling_map);
421   vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
422   vector<EdgeId> frontier;  // Unexplored sibling edges.
423 
424   // A map from EdgeId to the position of that edge in "path".  Only needed if
425   // degenerate boundaries are being discarded.
426   vector<int> path_index;
427   if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
428     path_index.assign(num_edges(), -1);
429   }
430   for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
431     if (left_turn_map[min_start] < 0) continue;  // Already used.
432 
433     // Build a connected component by keeping a stack of unexplored siblings
434     // of the edges used so far.
435     DirectedComponent component;
436     frontier.push_back(min_start);
437     while (!frontier.empty()) {
438       EdgeId start = frontier.back();
439       frontier.pop_back();
440       if (left_turn_map[start] < 0) continue;  // Already used.
441 
442       // Build a path by making left turns at each vertex until we return to
443       // "start".  Whenever we encounter an edge that is a sibling of an edge
444       // that is already on the path, we "peel off" a loop consisting of any
445       // edges that were between these two edges.
446       vector<EdgeId> path;
447       for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
448         path.push_back(e);
449         next = left_turn_map[e];
450         left_turn_map[e] = -1;
451         // If the sibling hasn't been visited yet, add it to the frontier.
452         EdgeId sibling = sibling_map[e];
453         if (left_turn_map[sibling] >= 0) {
454           frontier.push_back(sibling);
455         }
456         if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
457           path_index[e] = path.size() - 1;
458           int sibling_index = path_index[sibling];
459           if (sibling_index < 0) continue;
460 
461           // Common special case: the edge and its sibling are adjacent, in
462           // which case we can simply remove them from the path and continue.
463           if (sibling_index == path.size() - 2) {
464             path.resize(sibling_index);
465             // We don't need to update "path_index" for these two edges
466             // because both edges of the sibling pair have now been used.
467             continue;
468           }
469           // Peel off a loop from the path.
470           vector<EdgeId> loop(path.begin() + sibling_index + 1, path.end() - 1);
471           path.erase(path.begin() + sibling_index, path.end());
472           // Mark the edges that are no longer part of the path.
473           for (EdgeId e2 : loop) path_index[e2] = -1;
474           CanonicalizeLoopOrder(min_input_ids, &loop);
475           component.push_back(std::move(loop));
476         }
477       }
478       // Mark the edges that are no longer part of the path.
479       if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
480         for (EdgeId e2 : path) path_index[e2] = -1;
481       }
482       CanonicalizeLoopOrder(min_input_ids, &path);
483       component.push_back(std::move(path));
484     }
485     CanonicalizeVectorOrder(min_input_ids, &component);
486     components->push_back(std::move(component));
487   }
488   // Sort the components to correspond to the input edge ordering.
489   std::sort(components->begin(), components->end(),
490             [&min_input_ids](const DirectedComponent& a,
491                              const DirectedComponent& b) {
492       return min_input_ids[a[0][0]] < min_input_ids[b[0][0]];
493     });
494   return true;
495 }
496 
497 // Encodes the index of one of the two complements of each component
498 // (a.k.a. the "slot", either 0 or 1) as a negative EdgeId.
MarkEdgeUsed(int slot)499 inline static Graph::EdgeId MarkEdgeUsed(int slot) { return -1 - slot; }
500 
GetUndirectedComponents(LoopType loop_type,vector<UndirectedComponent> * components,S2Error * error) const501 bool Graph::GetUndirectedComponents(LoopType loop_type,
502                                     vector<UndirectedComponent>* components,
503                                     S2Error* error) const {
504   S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
505          options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
506   S2_DCHECK(options_.edge_type() == EdgeType::UNDIRECTED);
507 
508   vector<EdgeId> sibling_map = GetInEdgeIds();
509   vector<EdgeId> left_turn_map;
510   if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
511   MakeSiblingMap(&sibling_map);
512   vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
513 
514   // A stack of unexplored sibling edges.  Each sibling edge has a "slot"
515   // (0 or 1) that indicates which of the two complements it belongs to.
516   vector<pair<EdgeId, int>> frontier;
517 
518   // If we are breaking loops at repeated vertices, we maintain a map from
519   // VertexId to its position in "path".
520   vector<int> path_index;
521   if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
522 
523   for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
524     if (left_turn_map[min_start] < 0) continue;  // Already used.
525 
526     // Build a connected component by keeping a stack of unexplored siblings
527     // of the edges used so far.
528     UndirectedComponent component;
529     frontier.push_back(make_pair(min_start, 0));
530     while (!frontier.empty()) {
531       EdgeId start = frontier.back().first;
532       int slot = frontier.back().second;
533       frontier.pop_back();
534       if (left_turn_map[start] < 0) continue;  // Already used.
535 
536       // Build a path by making left turns at each vertex until we return to
537       // "start".  We use "left_turn_map" to keep track of which edges have
538       // already been visited, and which complement they were assigned to, by
539       // setting its entries to negative values as we go along.
540       vector<EdgeId> path;
541       for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
542         path.push_back(e);
543         next = left_turn_map[e];
544         left_turn_map[e] = MarkEdgeUsed(slot);
545         // If the sibling hasn't been visited yet, add it to the frontier.
546         EdgeId sibling = sibling_map[e];
547         if (left_turn_map[sibling] >= 0) {
548           frontier.push_back(make_pair(sibling, 1 - slot));
549         } else if (left_turn_map[sibling] != MarkEdgeUsed(1 - slot)) {
550           // Two siblings edges can only belong the same complement if the
551           // given undirected edges do not form loops.
552           error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
553                       "Given undirected edges do not form loops");
554           return false;
555         }
556         if (loop_type == LoopType::SIMPLE) {
557           // Whenever we encounter a vertex that is already part of the path,
558           // we "peel off" a loop by removing those edges from the path.
559           path_index[edge(e).first] = path.size() - 1;
560           int loop_start = path_index[edge(e).second];
561           if (loop_start < 0) continue;
562           vector<EdgeId> loop(path.begin() + loop_start, path.end());
563           path.erase(path.begin() + loop_start, path.end());
564           // Mark the vertices that are no longer part of the path.
565           for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
566           CanonicalizeLoopOrder(min_input_ids, &loop);
567           component[slot].push_back(std::move(loop));
568         }
569       }
570       if (loop_type == LoopType::SIMPLE) {
571         S2_DCHECK(path.empty());  // Invariant.
572       } else {
573         CanonicalizeLoopOrder(min_input_ids, &path);
574         component[slot].push_back(std::move(path));
575       }
576     }
577     CanonicalizeVectorOrder(min_input_ids, &component[0]);
578     CanonicalizeVectorOrder(min_input_ids, &component[1]);
579     // To save some work in S2PolygonLayer, we swap the two loop sets of the
580     // component so that the loop set whose first loop most closely follows
581     // the input edge ordering is first.  (If the input was a valid S2Polygon,
582     // then this component will contain normalized loops.)
583     if (min_input_ids[component[0][0][0]] > min_input_ids[component[1][0][0]]) {
584       component[0].swap(component[1]);
585     }
586     components->push_back(std::move(component));
587   }
588   // Sort the components to correspond to the input edge ordering.
589   std::sort(components->begin(), components->end(),
590        [&min_input_ids](const UndirectedComponent& a,
591                         const UndirectedComponent& b) {
592       return min_input_ids[a[0][0][0]] < min_input_ids[b[0][0][0]];
593     });
594   return true;
595 }
596 
597 class Graph::PolylineBuilder {
598  public:
599   explicit PolylineBuilder(const Graph& g);
600   vector<EdgePolyline> BuildPaths();
601   vector<EdgePolyline> BuildWalks();
602 
603  private:
604   bool is_interior(VertexId v);
605   int excess_degree(VertexId v);
606   EdgePolyline BuildPath(EdgeId e);
607   EdgePolyline BuildWalk(VertexId v);
608   void MaximizeWalk(EdgePolyline* polyline);
609 
610   const Graph& g_;
611   Graph::VertexInMap in_;
612   Graph::VertexOutMap out_;
613   vector<EdgeId> sibling_map_;
614   vector<InputEdgeId> min_input_ids_;
615   bool directed_;
616   int edges_left_;
617   vector<bool> used_;
618   // A map of (outdegree(v) - indegree(v)) considering used edges only.
619   absl::btree_map<VertexId, int> excess_used_;
620 };
621 
GetPolylines(PolylineType polyline_type) const622 vector<Graph::EdgePolyline> Graph::GetPolylines(
623     PolylineType polyline_type) const {
624   S2_DCHECK(options_.sibling_pairs() == SiblingPairs::DISCARD ||
625          options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS ||
626          options_.sibling_pairs() == SiblingPairs::KEEP);
627   PolylineBuilder builder(*this);
628   if (polyline_type == PolylineType::PATH) {
629     return builder.BuildPaths();
630   } else {
631     return builder.BuildWalks();
632   }
633 }
634 
PolylineBuilder(const Graph & g)635 Graph::PolylineBuilder::PolylineBuilder(const Graph& g)
636     : g_(g), in_(g), out_(g),
637       min_input_ids_(g.GetMinInputEdgeIds()),
638       directed_(g_.options().edge_type() == EdgeType::DIRECTED),
639       edges_left_(g.num_edges() / (directed_ ? 1 : 2)),
640       used_(g.num_edges(), false) {
641   if (!directed_) {
642     sibling_map_ = in_.in_edge_ids();
643     g.MakeSiblingMap(&sibling_map_);
644   }
645 }
646 
is_interior(VertexId v)647 inline bool Graph::PolylineBuilder::is_interior(VertexId v) {
648   if (directed_) {
649     return in_.degree(v) == 1 && out_.degree(v) == 1;
650   } else {
651     return out_.degree(v) == 2;
652   }
653 }
654 
excess_degree(VertexId v)655 inline int Graph::PolylineBuilder::excess_degree(VertexId v) {
656   return directed_ ? out_.degree(v) - in_.degree(v) : out_.degree(v) % 2;
657 }
658 
BuildPaths()659 vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildPaths() {
660   // First build polylines starting at all the vertices that cannot be in the
661   // polyline interior (i.e., indegree != 1 or outdegree != 1 for directed
662   // edges, or degree != 2 for undirected edges).  We consider the possible
663   // starting edges in input edge id order so that we preserve the input path
664   // direction even when undirected edges are used.  (Undirected edges are
665   // represented by sibling pairs where only the edge in the input direction
666   // is labeled with an input edge id.)
667   vector<EdgePolyline> polylines;
668   vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
669   for (EdgeId e : edges) {
670     if (!used_[e] && !is_interior(g_.edge(e).first)) {
671       polylines.push_back(BuildPath(e));
672     }
673   }
674   // If there are any edges left, they form non-intersecting loops.  We build
675   // each loop and then canonicalize its edge order.  We consider candidate
676   // starting edges in input edge id order in order to preserve the input
677   // direction of undirected loops.  Even so, we still need to canonicalize
678   // the edge order to ensure that when an input edge is split into an edge
679   // chain, the loop does not start in the middle of such a chain.
680   for (EdgeId e : edges) {
681     if (edges_left_ == 0) break;
682     if (used_[e]) continue;
683     EdgePolyline polyline = BuildPath(e);
684     CanonicalizeLoopOrder(min_input_ids_, &polyline);
685     polylines.push_back(std::move(polyline));
686   }
687   S2_DCHECK_EQ(0, edges_left_);
688 
689   // Sort the polylines to correspond to the input order (if possible).
690   CanonicalizeVectorOrder(min_input_ids_, &polylines);
691   return polylines;
692 }
693 
BuildPath(EdgeId e)694 Graph::EdgePolyline Graph::PolylineBuilder::BuildPath(EdgeId e) {
695   // We simply follow edges until either we reach a vertex where there is a
696   // choice about which way to go (where is_interior(v) is false), or we
697   // return to the starting vertex (if the polyline is actually a loop).
698   EdgePolyline polyline;
699   VertexId start = g_.edge(e).first;
700   for (;;) {
701     polyline.push_back(e);
702     S2_DCHECK(!used_[e]);
703     used_[e] = true;
704     if (!directed_) used_[sibling_map_[e]] = true;
705     --edges_left_;
706     VertexId v = g_.edge(e).second;
707     if (!is_interior(v) || v == start) break;
708     if (directed_) {
709       S2_DCHECK_EQ(1, out_.degree(v));
710       e = *out_.edge_ids(v).begin();
711     } else {
712       S2_DCHECK_EQ(2, out_.degree(v));
713       for (EdgeId e2 : out_.edge_ids(v)) if (!used_[e2]) e = e2;
714     }
715   }
716   return polyline;
717 }
718 
BuildWalks()719 vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildWalks() {
720   // Note that some of this code is worst-case quadratic in the maximum vertex
721   // degree.  This could be fixed with a few extra arrays, but it should not
722   // be a problem in practice.
723 
724   // First, build polylines from all vertices where outdegree > indegree (or
725   // for undirected edges, vertices whose degree is odd).  We consider the
726   // possible starting edges in input edge id order, for idempotency in the
727   // case where multiple input polylines share vertices or edges.
728   vector<EdgePolyline> polylines;
729   vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
730   for (EdgeId e : edges) {
731     if (used_[e]) continue;
732     VertexId v = g_.edge(e).first;
733     int excess = excess_degree(v);
734     if (excess <= 0) continue;
735     excess -= excess_used_[v];
736     if (directed_ ? (excess <= 0) : (excess % 2 == 0)) continue;
737     ++excess_used_[v];
738     polylines.push_back(BuildWalk(v));
739     --excess_used_[g_.edge(polylines.back().back()).second];
740   }
741   // Now all vertices have outdegree == indegree (or even degree if undirected
742   // edges are being used).  Therefore all remaining edges can be assembled
743   // into loops.  We first try to expand the existing polylines if possible by
744   // adding loops to them.
745   if (edges_left_ > 0) {
746     for (EdgePolyline& polyline : polylines) {
747       MaximizeWalk(&polyline);
748     }
749   }
750   // Finally, if there are still unused edges then we build loops.  If the
751   // input is a polyline that forms a loop, then for idempotency we need to
752   // start from the edge with minimum input edge id.  If the minimal input
753   // edge was split into several edges, then we start from the first edge of
754   // the chain.
755   for (int i = 0; i < edges.size() && edges_left_ > 0; ++i) {
756     EdgeId e = edges[i];
757     if (used_[e]) continue;
758 
759     // Determine whether the origin of this edge is the start of an edge
760     // chain.  To do this, we test whether (outdegree - indegree == 1) for the
761     // origin, considering only unused edges with the same minimum input edge
762     // id.  (Undirected edges have input edge ids in one direction only.)
763     VertexId v = g_.edge(e).first;
764     InputEdgeId id = min_input_ids_[e];
765     int excess = 0;
766     for (int j = i; j < edges.size() && min_input_ids_[edges[j]] == id; ++j) {
767       EdgeId e2 = edges[j];
768       if (used_[e2]) continue;
769       if (g_.edge(e2).first == v) ++excess;
770       if (g_.edge(e2).second == v) --excess;
771     }
772     // It is also acceptable to start a polyline from any degenerate edge.
773     if (excess == 1 || g_.edge(e).second == v) {
774       EdgePolyline polyline = BuildWalk(v);
775       MaximizeWalk(&polyline);
776       polylines.push_back(std::move(polyline));
777     }
778   }
779   S2_DCHECK_EQ(0, edges_left_);
780 
781   // Sort the polylines to correspond to the input order (if possible).
782   CanonicalizeVectorOrder(min_input_ids_, &polylines);
783   return polylines;
784 }
785 
BuildWalk(VertexId v)786 Graph::EdgePolyline Graph::PolylineBuilder::BuildWalk(VertexId v) {
787   EdgePolyline polyline;
788   for (;;) {
789     // Follow the edge with the smallest input edge id.
790     EdgeId best_edge = -1;
791     InputEdgeId best_out_id = std::numeric_limits<InputEdgeId>::max();
792     for (EdgeId e : out_.edge_ids(v)) {
793       if (used_[e] || min_input_ids_[e] >= best_out_id) continue;
794       best_out_id = min_input_ids_[e];
795       best_edge = e;
796     }
797     if (best_edge < 0) return polyline;
798     // For idempotency when there are multiple input polylines, we stop the
799     // walk early if "best_edge" might be a continuation of a different
800     // incoming edge.
801     int excess = excess_degree(v) - excess_used_[v];
802     if (directed_ ? (excess < 0) : (excess % 2) == 1) {
803       for (EdgeId e : in_.edge_ids(v)) {
804         if (!used_[e] && min_input_ids_[e] <= best_out_id) {
805           return polyline;
806         }
807       }
808     }
809     polyline.push_back(best_edge);
810     used_[best_edge] = true;
811     if (!directed_) used_[sibling_map_[best_edge]] = true;
812     --edges_left_;
813     v = g_.edge(best_edge).second;
814   }
815 }
816 
MaximizeWalk(EdgePolyline * polyline)817 void Graph::PolylineBuilder::MaximizeWalk(EdgePolyline* polyline) {
818   // Examine all vertices of the polyline and check whether there are any
819   // unused outgoing edges.  If so, then build a loop starting at that vertex
820   // and insert it into the polyline.  (The walk is guaranteed to be a loop
821   // because this method is only called when all vertices have equal numbers
822   // of unused incoming and outgoing edges.)
823   for (int i = 0; i <= polyline->size(); ++i) {
824     VertexId v = (i == 0 ? g_.edge((*polyline)[i]).first
825                   : g_.edge((*polyline)[i - 1]).second);
826     for (EdgeId e : out_.edge_ids(v)) {
827       if (!used_[e]) {
828         EdgePolyline loop = BuildWalk(v);
829         S2_DCHECK_EQ(v, g_.edge(loop.back()).second);
830         polyline->insert(polyline->begin() + i, loop.begin(), loop.end());
831         S2_DCHECK(used_[e]);  // All outgoing edges from "v" are now used.
832         break;
833       }
834     }
835   }
836 }
837 
838 class Graph::EdgeProcessor {
839  public:
840   EdgeProcessor(const GraphOptions& options,
841                 vector<Edge>* edges,
842                 vector<InputEdgeIdSetId>* input_ids,
843                 IdSetLexicon* id_set_lexicon);
844   void Run(S2Error* error);
845 
846  private:
847   void AddEdge(const Edge& edge, InputEdgeIdSetId input_edge_id_set_id);
848   void AddEdges(int num_edges, const Edge& edge,
849                 InputEdgeIdSetId input_edge_id_set_id);
850   void CopyEdges(int out_begin, int out_end);
851   InputEdgeIdSetId MergeInputIds(int out_begin, int out_end);
852 
853   GraphOptions options_;
854   vector<Edge>& edges_;
855   vector<InputEdgeIdSetId>& input_ids_;
856   IdSetLexicon* id_set_lexicon_;
857   vector<EdgeId> out_edges_;
858   vector<EdgeId> in_edges_;
859 
860   vector<Edge> new_edges_;
861   vector<InputEdgeIdSetId> new_input_ids_;
862 
863   vector<InputEdgeId> tmp_ids_;
864 };
865 
ProcessEdges(GraphOptions * options,std::vector<Edge> * edges,std::vector<InputEdgeIdSetId> * input_ids,IdSetLexicon * id_set_lexicon,S2Error * error)866 void Graph::ProcessEdges(
867     GraphOptions* options, std::vector<Edge>* edges,
868     std::vector<InputEdgeIdSetId>* input_ids, IdSetLexicon* id_set_lexicon,
869     S2Error* error) {
870   EdgeProcessor processor(*options, edges, input_ids, id_set_lexicon);
871   processor.Run(error);
872   // Certain values of sibling_pairs() discard half of the edges and change
873   // the edge_type() to DIRECTED (see the description of GraphOptions).
874   if (options->sibling_pairs() == SiblingPairs::REQUIRE ||
875       options->sibling_pairs() == SiblingPairs::CREATE) {
876     options->set_edge_type(EdgeType::DIRECTED);
877   }
878 }
879 
EdgeProcessor(const GraphOptions & options,vector<Edge> * edges,vector<InputEdgeIdSetId> * input_ids,IdSetLexicon * id_set_lexicon)880 Graph::EdgeProcessor::EdgeProcessor(const GraphOptions& options,
881                                     vector<Edge>* edges,
882                                     vector<InputEdgeIdSetId>* input_ids,
883                                     IdSetLexicon* id_set_lexicon)
884     : options_(options), edges_(*edges),
885       input_ids_(*input_ids), id_set_lexicon_(id_set_lexicon),
886       out_edges_(edges_.size()), in_edges_(edges_.size()) {
887   // Sort the outgoing and incoming edges in lexigraphic order.  We use a
888   // stable sort to ensure that each undirected edge becomes a sibling pair,
889   // even if there are multiple identical input edges.
890   std::iota(out_edges_.begin(), out_edges_.end(), 0);
891   std::sort(out_edges_.begin(), out_edges_.end(), [this](EdgeId a, EdgeId b) {
892       return StableLessThan(edges_[a], edges_[b], a, b);
893     });
894   std::iota(in_edges_.begin(), in_edges_.end(), 0);
895   std::sort(in_edges_.begin(), in_edges_.end(), [this](EdgeId a, EdgeId b) {
896       return StableLessThan(reverse(edges_[a]), reverse(edges_[b]), a, b);
897     });
898   new_edges_.reserve(edges_.size());
899   new_input_ids_.reserve(edges_.size());
900 }
901 
AddEdge(const Edge & edge,InputEdgeIdSetId input_edge_id_set_id)902 inline void Graph::EdgeProcessor::AddEdge(
903     const Edge& edge, InputEdgeIdSetId input_edge_id_set_id) {
904   new_edges_.push_back(edge);
905   new_input_ids_.push_back(input_edge_id_set_id);
906 }
907 
AddEdges(int num_edges,const Edge & edge,InputEdgeIdSetId input_edge_id_set_id)908 void Graph::EdgeProcessor::AddEdges(int num_edges, const Edge& edge,
909                                     InputEdgeIdSetId input_edge_id_set_id) {
910   for (int i = 0; i < num_edges; ++i) {
911     AddEdge(edge, input_edge_id_set_id);
912   }
913 }
914 
CopyEdges(int out_begin,int out_end)915 void Graph::EdgeProcessor::CopyEdges(int out_begin, int out_end) {
916   for (int i = out_begin; i < out_end; ++i) {
917     AddEdge(edges_[out_edges_[i]], input_ids_[out_edges_[i]]);
918   }
919 }
920 
MergeInputIds(int out_begin,int out_end)921 S2Builder::InputEdgeIdSetId Graph::EdgeProcessor::MergeInputIds(
922     int out_begin, int out_end) {
923   if (out_end - out_begin == 1) {
924     return input_ids_[out_edges_[out_begin]];
925   }
926   tmp_ids_.clear();
927   for (int i = out_begin; i < out_end; ++i) {
928     for (auto id : id_set_lexicon_->id_set(input_ids_[out_edges_[i]])) {
929       tmp_ids_.push_back(id);
930     }
931   }
932   return id_set_lexicon_->Add(tmp_ids_);
933 }
934 
Run(S2Error * error)935 void Graph::EdgeProcessor::Run(S2Error* error) {
936   int num_edges = edges_.size();
937   if (num_edges == 0) return;
938 
939   // Walk through the two sorted arrays performing a merge join.  For each
940   // edge, gather all the duplicate copies of the edge in both directions
941   // (outgoing and incoming).  Then decide what to do based on "options_" and
942   // how many copies of the edge there are in each direction.
943   int out = 0, in = 0;
944   const Edge* out_edge = &edges_[out_edges_[out]];
945   const Edge* in_edge = &edges_[in_edges_[in]];
946   Edge sentinel(std::numeric_limits<VertexId>::max(),
947                 std::numeric_limits<VertexId>::max());
948   for (;;) {
949     Edge edge = min(*out_edge, reverse(*in_edge));
950     if (edge == sentinel) break;
951 
952     int out_begin = out, in_begin = in;
953     while (*out_edge == edge) {
954       out_edge = (++out == num_edges) ? &sentinel : &edges_[out_edges_[out]];
955     }
956     while (reverse(*in_edge) == edge) {
957       in_edge = (++in == num_edges) ? &sentinel : &edges_[in_edges_[in]];
958     }
959     int n_out = out - out_begin;
960     int n_in = in - in_begin;
961     if (edge.first == edge.second) {
962       S2_DCHECK_EQ(n_out, n_in);
963       if (options_.degenerate_edges() == DegenerateEdges::DISCARD) {
964         continue;
965       }
966       if (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
967           ((out_begin > 0 &&
968             edges_[out_edges_[out_begin - 1]].first == edge.first) ||
969            (out < num_edges && edges_[out_edges_[out]].first == edge.first) ||
970            (in_begin > 0 &&
971             edges_[in_edges_[in_begin - 1]].second == edge.first) ||
972            (in < num_edges && edges_[in_edges_[in]].second == edge.first))) {
973         continue;  // There were non-degenerate incident edges, so discard.
974       }
975       if (options_.edge_type() == EdgeType::UNDIRECTED &&
976           (options_.sibling_pairs() == SiblingPairs::REQUIRE ||
977            options_.sibling_pairs() == SiblingPairs::CREATE)) {
978         // When we have undirected edges and are guaranteed to have siblings,
979         // we cut the number of edges in half (see s2builder.h).
980         S2_DCHECK_EQ(0, n_out & 1);  // Number of edges is always even.
981         AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
982                  1 : (n_out / 2), edge, MergeInputIds(out_begin, out));
983       } else if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
984         AddEdges(options_.edge_type() == EdgeType::UNDIRECTED ? 2 : 1,
985                  edge, MergeInputIds(out_begin, out));
986       } else if (options_.sibling_pairs() == SiblingPairs::DISCARD ||
987                  options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
988         // Any SiblingPair option that discards edges causes the labels of all
989         // duplicate edges to be merged together (see s2builder.h).
990         AddEdges(n_out, edge, MergeInputIds(out_begin, out));
991       } else {
992         CopyEdges(out_begin, out);
993       }
994     } else if (options_.sibling_pairs() == SiblingPairs::KEEP) {
995       if (n_out > 1 && options_.duplicate_edges() == DuplicateEdges::MERGE) {
996         AddEdge(edge, MergeInputIds(out_begin, out));
997       } else {
998         CopyEdges(out_begin, out);
999       }
1000     } else if (options_.sibling_pairs() == SiblingPairs::DISCARD) {
1001       if (options_.edge_type() == EdgeType::DIRECTED) {
1002         // If n_out == n_in: balanced sibling pairs
1003         // If n_out < n_in:  unbalanced siblings, in the form AB, BA, BA
1004         // If n_out > n_in:  unbalanced siblings, in the form AB, AB, BA
1005         if (n_out <= n_in) continue;
1006         // Any option that discards edges causes the labels of all duplicate
1007         // edges to be merged together (see s2builder.h).
1008         AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
1009                  1 : (n_out - n_in), edge, MergeInputIds(out_begin, out));
1010       } else {
1011         if ((n_out & 1) == 0) continue;
1012         AddEdge(edge, MergeInputIds(out_begin, out));
1013       }
1014     } else if (options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
1015       if (options_.edge_type() == EdgeType::DIRECTED) {
1016         // See comments above.  The only difference is that if there are
1017         // balanced sibling pairs, we want to keep one such pair.
1018         if (n_out < n_in) continue;
1019         AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
1020                  1 : max(1, n_out - n_in), edge, MergeInputIds(out_begin, out));
1021       } else {
1022         AddEdges((n_out & 1) ? 1 : 2, edge, MergeInputIds(out_begin, out));
1023       }
1024     } else {
1025       S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
1026              options_.sibling_pairs() == SiblingPairs::CREATE);
1027       if (error->ok() && options_.sibling_pairs() == SiblingPairs::REQUIRE &&
1028           (options_.edge_type() == EdgeType::DIRECTED ? (n_out != n_in)
1029                                                       : ((n_out & 1) != 0))) {
1030         error->Init(S2Error::BUILDER_MISSING_EXPECTED_SIBLING_EDGES,
1031                     "Expected all input edges to have siblings, "
1032                     "but some were missing");
1033       }
1034       if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
1035         AddEdge(edge, MergeInputIds(out_begin, out));
1036       } else if (options_.edge_type() == EdgeType::UNDIRECTED) {
1037         // Convert graph to use directed edges instead (see documentation of
1038         // REQUIRE/CREATE for undirected edges).
1039         AddEdges((n_out + 1) / 2, edge, MergeInputIds(out_begin, out));
1040       } else {
1041         CopyEdges(out_begin, out);
1042         if (n_in > n_out) {
1043           // Automatically created edges have no input edge ids or labels.
1044           AddEdges(n_in - n_out, edge, IdSetLexicon::EmptySetId());
1045         }
1046       }
1047     }
1048   }
1049   edges_.swap(new_edges_);
1050   edges_.shrink_to_fit();
1051   input_ids_.swap(new_input_ids_);
1052   input_ids_.shrink_to_fit();
1053 }
1054 
FilterVertices(const vector<S2Point> & vertices,std::vector<Edge> * edges,vector<VertexId> * tmp)1055 vector<S2Point> Graph::FilterVertices(const vector<S2Point>& vertices,
1056                                       std::vector<Edge>* edges,
1057                                       vector<VertexId>* tmp) {
1058   // Gather the vertices that are actually used.
1059   vector<VertexId> used;
1060   used.reserve(2 * edges->size());
1061   for (const Edge& e : *edges) {
1062     used.push_back(e.first);
1063     used.push_back(e.second);
1064   }
1065   // Sort the vertices and find the distinct ones.
1066   std::sort(used.begin(), used.end());
1067   used.erase(std::unique(used.begin(), used.end()), used.end());
1068 
1069   // Build the list of new vertices, and generate a map from old vertex id to
1070   // new vertex id.
1071   vector<VertexId>& vmap = *tmp;
1072   vmap.resize(vertices.size());
1073   vector<S2Point> new_vertices(used.size());
1074   for (int i = 0; i < used.size(); ++i) {
1075     new_vertices[i] = vertices[used[i]];
1076     vmap[used[i]] = i;
1077   }
1078   // Update the edges.
1079   for (Edge& e : *edges) {
1080     e.first = vmap[e.first];
1081     e.second = vmap[e.second];
1082   }
1083   return new_vertices;
1084 }
1085