Coverage Report

Created: 2025-11-15 06:18

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