Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// PBQP Graph class.
10
//
11
//===----------------------------------------------------------------------===//
12
 
13
#ifndef LLVM_CODEGEN_PBQP_GRAPH_H
14
#define LLVM_CODEGEN_PBQP_GRAPH_H
15
 
16
#include "llvm/ADT/STLExtras.h"
17
#include <algorithm>
18
#include <cassert>
19
#include <iterator>
20
#include <limits>
21
#include <vector>
22
 
23
namespace llvm {
24
namespace PBQP {
25
 
26
  class GraphBase {
27
  public:
28
    using NodeId = unsigned;
29
    using EdgeId = unsigned;
30
 
31
    /// Returns a value representing an invalid (non-existent) node.
32
    static NodeId invalidNodeId() {
33
      return std::numeric_limits<NodeId>::max();
34
    }
35
 
36
    /// Returns a value representing an invalid (non-existent) edge.
37
    static EdgeId invalidEdgeId() {
38
      return std::numeric_limits<EdgeId>::max();
39
    }
40
  };
41
 
42
  /// PBQP Graph class.
43
  /// Instances of this class describe PBQP problems.
44
  ///
45
  template <typename SolverT>
46
  class Graph : public GraphBase {
47
  private:
48
    using CostAllocator = typename SolverT::CostAllocator;
49
 
50
  public:
51
    using RawVector = typename SolverT::RawVector;
52
    using RawMatrix = typename SolverT::RawMatrix;
53
    using Vector = typename SolverT::Vector;
54
    using Matrix = typename SolverT::Matrix;
55
    using VectorPtr = typename CostAllocator::VectorPtr;
56
    using MatrixPtr = typename CostAllocator::MatrixPtr;
57
    using NodeMetadata = typename SolverT::NodeMetadata;
58
    using EdgeMetadata = typename SolverT::EdgeMetadata;
59
    using GraphMetadata = typename SolverT::GraphMetadata;
60
 
61
  private:
62
    class NodeEntry {
63
    public:
64
      using AdjEdgeList = std::vector<EdgeId>;
65
      using AdjEdgeIdx = AdjEdgeList::size_type;
66
      using AdjEdgeItr = AdjEdgeList::const_iterator;
67
 
68
      NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
69
 
70
      static AdjEdgeIdx getInvalidAdjEdgeIdx() {
71
        return std::numeric_limits<AdjEdgeIdx>::max();
72
      }
73
 
74
      AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
75
        AdjEdgeIdx Idx = AdjEdgeIds.size();
76
        AdjEdgeIds.push_back(EId);
77
        return Idx;
78
      }
79
 
80
      void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) {
81
        // Swap-and-pop for fast removal.
82
        //   1) Update the adj index of the edge currently at back().
83
        //   2) Move last Edge down to Idx.
84
        //   3) pop_back()
85
        // If Idx == size() - 1 then the setAdjEdgeIdx and swap are
86
        // redundant, but both operations are cheap.
87
        G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx);
88
        AdjEdgeIds[Idx] = AdjEdgeIds.back();
89
        AdjEdgeIds.pop_back();
90
      }
91
 
92
      const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; }
93
 
94
      VectorPtr Costs;
95
      NodeMetadata Metadata;
96
 
97
    private:
98
      AdjEdgeList AdjEdgeIds;
99
    };
100
 
101
    class EdgeEntry {
102
    public:
103
      EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs)
104
          : Costs(std::move(Costs)) {
105
        NIds[0] = N1Id;
106
        NIds[1] = N2Id;
107
        ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx();
108
        ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx();
109
      }
110
 
111
      void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) {
112
        assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() &&
113
               "Edge already connected to NIds[NIdx].");
114
        NodeEntry &N = G.getNode(NIds[NIdx]);
115
        ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId);
116
      }
117
 
118
      void connect(Graph &G, EdgeId ThisEdgeId) {
119
        connectToN(G, ThisEdgeId, 0);
120
        connectToN(G, ThisEdgeId, 1);
121
      }
122
 
123
      void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) {
124
        if (NId == NIds[0])
125
          ThisEdgeAdjIdxs[0] = NewIdx;
126
        else {
127
          assert(NId == NIds[1] && "Edge not connected to NId");
128
          ThisEdgeAdjIdxs[1] = NewIdx;
129
        }
130
      }
131
 
132
      void disconnectFromN(Graph &G, unsigned NIdx) {
133
        assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() &&
134
               "Edge not connected to NIds[NIdx].");
135
        NodeEntry &N = G.getNode(NIds[NIdx]);
136
        N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]);
137
        ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx();
138
      }
139
 
140
      void disconnectFrom(Graph &G, NodeId NId) {
141
        if (NId == NIds[0])
142
          disconnectFromN(G, 0);
143
        else {
144
          assert(NId == NIds[1] && "Edge does not connect NId");
145
          disconnectFromN(G, 1);
146
        }
147
      }
148
 
149
      NodeId getN1Id() const { return NIds[0]; }
150
      NodeId getN2Id() const { return NIds[1]; }
151
 
152
      MatrixPtr Costs;
153
      EdgeMetadata Metadata;
154
 
155
    private:
156
      NodeId NIds[2];
157
      typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
158
    };
159
 
160
    // ----- MEMBERS -----
161
 
162
    GraphMetadata Metadata;
163
    CostAllocator CostAlloc;
164
    SolverT *Solver = nullptr;
165
 
166
    using NodeVector = std::vector<NodeEntry>;
167
    using FreeNodeVector = std::vector<NodeId>;
168
    NodeVector Nodes;
169
    FreeNodeVector FreeNodeIds;
170
 
171
    using EdgeVector = std::vector<EdgeEntry>;
172
    using FreeEdgeVector = std::vector<EdgeId>;
173
    EdgeVector Edges;
174
    FreeEdgeVector FreeEdgeIds;
175
 
176
    Graph(const Graph &Other) {}
177
 
178
    // ----- INTERNAL METHODS -----
179
 
180
    NodeEntry &getNode(NodeId NId) {
181
      assert(NId < Nodes.size() && "Out of bound NodeId");
182
      return Nodes[NId];
183
    }
184
    const NodeEntry &getNode(NodeId NId) const {
185
      assert(NId < Nodes.size() && "Out of bound NodeId");
186
      return Nodes[NId];
187
    }
188
 
189
    EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
190
    const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
191
 
192
    NodeId addConstructedNode(NodeEntry N) {
193
      NodeId NId = 0;
194
      if (!FreeNodeIds.empty()) {
195
        NId = FreeNodeIds.back();
196
        FreeNodeIds.pop_back();
197
        Nodes[NId] = std::move(N);
198
      } else {
199
        NId = Nodes.size();
200
        Nodes.push_back(std::move(N));
201
      }
202
      return NId;
203
    }
204
 
205
    EdgeId addConstructedEdge(EdgeEntry E) {
206
      assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
207
             "Attempt to add duplicate edge.");
208
      EdgeId EId = 0;
209
      if (!FreeEdgeIds.empty()) {
210
        EId = FreeEdgeIds.back();
211
        FreeEdgeIds.pop_back();
212
        Edges[EId] = std::move(E);
213
      } else {
214
        EId = Edges.size();
215
        Edges.push_back(std::move(E));
216
      }
217
 
218
      EdgeEntry &NE = getEdge(EId);
219
 
220
      // Add the edge to the adjacency sets of its nodes.
221
      NE.connect(*this, EId);
222
      return EId;
223
    }
224
 
225
    void operator=(const Graph &Other) {}
226
 
227
  public:
228
    using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
229
 
230
    class NodeItr {
231
    public:
232
      using iterator_category = std::forward_iterator_tag;
233
      using value_type = NodeId;
234
      using difference_type = int;
235
      using pointer = NodeId *;
236
      using reference = NodeId &;
237
 
238
      NodeItr(NodeId CurNId, const Graph &G)
239
        : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
240
        this->CurNId = findNextInUse(CurNId); // Move to first in-use node id
241
      }
242
 
243
      bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; }
244
      bool operator!=(const NodeItr &O) const { return !(*this == O); }
245
      NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; }
246
      NodeId operator*() const { return CurNId; }
247
 
248
    private:
249
      NodeId findNextInUse(NodeId NId) const {
250
        while (NId < EndNId && is_contained(FreeNodeIds, NId)) {
251
          ++NId;
252
        }
253
        return NId;
254
      }
255
 
256
      NodeId CurNId, EndNId;
257
      const FreeNodeVector &FreeNodeIds;
258
    };
259
 
260
    class EdgeItr {
261
    public:
262
      EdgeItr(EdgeId CurEId, const Graph &G)
263
        : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) {
264
        this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id
265
      }
266
 
267
      bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; }
268
      bool operator!=(const EdgeItr &O) const { return !(*this == O); }
269
      EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; }
270
      EdgeId operator*() const { return CurEId; }
271
 
272
    private:
273
      EdgeId findNextInUse(EdgeId EId) const {
274
        while (EId < EndEId && is_contained(FreeEdgeIds, EId)) {
275
          ++EId;
276
        }
277
        return EId;
278
      }
279
 
280
      EdgeId CurEId, EndEId;
281
      const FreeEdgeVector &FreeEdgeIds;
282
    };
283
 
284
    class NodeIdSet {
285
    public:
286
      NodeIdSet(const Graph &G) : G(G) {}
287
 
288
      NodeItr begin() const { return NodeItr(0, G); }
289
      NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
290
 
291
      bool empty() const { return G.Nodes.empty(); }
292
 
293
      typename NodeVector::size_type size() const {
294
        return G.Nodes.size() - G.FreeNodeIds.size();
295
      }
296
 
297
    private:
298
      const Graph& G;
299
    };
300
 
301
    class EdgeIdSet {
302
    public:
303
      EdgeIdSet(const Graph &G) : G(G) {}
304
 
305
      EdgeItr begin() const { return EdgeItr(0, G); }
306
      EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
307
 
308
      bool empty() const { return G.Edges.empty(); }
309
 
310
      typename NodeVector::size_type size() const {
311
        return G.Edges.size() - G.FreeEdgeIds.size();
312
      }
313
 
314
    private:
315
      const Graph& G;
316
    };
317
 
318
    class AdjEdgeIdSet {
319
    public:
320
      AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
321
 
322
      typename NodeEntry::AdjEdgeItr begin() const {
323
        return NE.getAdjEdgeIds().begin();
324
      }
325
 
326
      typename NodeEntry::AdjEdgeItr end() const {
327
        return NE.getAdjEdgeIds().end();
328
      }
329
 
330
      bool empty() const { return NE.getAdjEdgeIds().empty(); }
331
 
332
      typename NodeEntry::AdjEdgeList::size_type size() const {
333
        return NE.getAdjEdgeIds().size();
334
      }
335
 
336
    private:
337
      const NodeEntry &NE;
338
    };
339
 
340
    /// Construct an empty PBQP graph.
341
    Graph() = default;
342
 
343
    /// Construct an empty PBQP graph with the given graph metadata.
344
    Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
345
 
346
    /// Get a reference to the graph metadata.
347
    GraphMetadata& getMetadata() { return Metadata; }
348
 
349
    /// Get a const-reference to the graph metadata.
350
    const GraphMetadata& getMetadata() const { return Metadata; }
351
 
352
    /// Lock this graph to the given solver instance in preparation
353
    /// for running the solver. This method will call solver.handleAddNode for
354
    /// each node in the graph, and handleAddEdge for each edge, to give the
355
    /// solver an opportunity to set up any requried metadata.
356
    void setSolver(SolverT &S) {
357
      assert(!Solver && "Solver already set. Call unsetSolver().");
358
      Solver = &S;
359
      for (auto NId : nodeIds())
360
        Solver->handleAddNode(NId);
361
      for (auto EId : edgeIds())
362
        Solver->handleAddEdge(EId);
363
    }
364
 
365
    /// Release from solver instance.
366
    void unsetSolver() {
367
      assert(Solver && "Solver not set.");
368
      Solver = nullptr;
369
    }
370
 
371
    /// Add a node with the given costs.
372
    /// @param Costs Cost vector for the new node.
373
    /// @return Node iterator for the added node.
374
    template <typename OtherVectorT>
375
    NodeId addNode(OtherVectorT Costs) {
376
      // Get cost vector from the problem domain
377
      VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
378
      NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts));
379
      if (Solver)
380
        Solver->handleAddNode(NId);
381
      return NId;
382
    }
383
 
384
    /// Add a node bypassing the cost allocator.
385
    /// @param Costs Cost vector ptr for the new node (must be convertible to
386
    ///        VectorPtr).
387
    /// @return Node iterator for the added node.
388
    ///
389
    ///   This method allows for fast addition of a node whose costs don't need
390
    /// to be passed through the cost allocator. The most common use case for
391
    /// this is when duplicating costs from an existing node (when using a
392
    /// pooling allocator). These have already been uniqued, so we can avoid
393
    /// re-constructing and re-uniquing them by attaching them directly to the
394
    /// new node.
395
    template <typename OtherVectorPtrT>
396
    NodeId addNodeBypassingCostAllocator(OtherVectorPtrT Costs) {
397
      NodeId NId = addConstructedNode(NodeEntry(Costs));
398
      if (Solver)
399
        Solver->handleAddNode(NId);
400
      return NId;
401
    }
402
 
403
    /// Add an edge between the given nodes with the given costs.
404
    /// @param N1Id First node.
405
    /// @param N2Id Second node.
406
    /// @param Costs Cost matrix for new edge.
407
    /// @return Edge iterator for the added edge.
408
    template <typename OtherVectorT>
409
    EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
410
      assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
411
             getNodeCosts(N2Id).getLength() == Costs.getCols() &&
412
             "Matrix dimensions mismatch.");
413
      // Get cost matrix from the problem domain.
414
      MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
415
      EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts));
416
      if (Solver)
417
        Solver->handleAddEdge(EId);
418
      return EId;
419
    }
420
 
421
    /// Add an edge bypassing the cost allocator.
422
    /// @param N1Id First node.
423
    /// @param N2Id Second node.
424
    /// @param Costs Cost matrix for new edge.
425
    /// @return Edge iterator for the added edge.
426
    ///
427
    ///   This method allows for fast addition of an edge whose costs don't need
428
    /// to be passed through the cost allocator. The most common use case for
429
    /// this is when duplicating costs from an existing edge (when using a
430
    /// pooling allocator). These have already been uniqued, so we can avoid
431
    /// re-constructing and re-uniquing them by attaching them directly to the
432
    /// new edge.
433
    template <typename OtherMatrixPtrT>
434
    NodeId addEdgeBypassingCostAllocator(NodeId N1Id, NodeId N2Id,
435
                                         OtherMatrixPtrT Costs) {
436
      assert(getNodeCosts(N1Id).getLength() == Costs->getRows() &&
437
             getNodeCosts(N2Id).getLength() == Costs->getCols() &&
438
             "Matrix dimensions mismatch.");
439
      // Get cost matrix from the problem domain.
440
      EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs));
441
      if (Solver)
442
        Solver->handleAddEdge(EId);
443
      return EId;
444
    }
445
 
446
    /// Returns true if the graph is empty.
447
    bool empty() const { return NodeIdSet(*this).empty(); }
448
 
449
    NodeIdSet nodeIds() const { return NodeIdSet(*this); }
450
    EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
451
 
452
    AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
453
 
454
    /// Get the number of nodes in the graph.
455
    /// @return Number of nodes in the graph.
456
    unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
457
 
458
    /// Get the number of edges in the graph.
459
    /// @return Number of edges in the graph.
460
    unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
461
 
462
    /// Set a node's cost vector.
463
    /// @param NId Node to update.
464
    /// @param Costs New costs to set.
465
    template <typename OtherVectorT>
466
    void setNodeCosts(NodeId NId, OtherVectorT Costs) {
467
      VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
468
      if (Solver)
469
        Solver->handleSetNodeCosts(NId, *AllocatedCosts);
470
      getNode(NId).Costs = AllocatedCosts;
471
    }
472
 
473
    /// Get a VectorPtr to a node's cost vector. Rarely useful - use
474
    ///        getNodeCosts where possible.
475
    /// @param NId Node id.
476
    /// @return VectorPtr to node cost vector.
477
    ///
478
    ///   This method is primarily useful for duplicating costs quickly by
479
    /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
480
    /// getNodeCosts when dealing with node cost values.
481
    const VectorPtr& getNodeCostsPtr(NodeId NId) const {
482
      return getNode(NId).Costs;
483
    }
484
 
485
    /// Get a node's cost vector.
486
    /// @param NId Node id.
487
    /// @return Node cost vector.
488
    const Vector& getNodeCosts(NodeId NId) const {
489
      return *getNodeCostsPtr(NId);
490
    }
491
 
492
    NodeMetadata& getNodeMetadata(NodeId NId) {
493
      return getNode(NId).Metadata;
494
    }
495
 
496
    const NodeMetadata& getNodeMetadata(NodeId NId) const {
497
      return getNode(NId).Metadata;
498
    }
499
 
500
    typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
501
      return getNode(NId).getAdjEdgeIds().size();
502
    }
503
 
504
    /// Update an edge's cost matrix.
505
    /// @param EId Edge id.
506
    /// @param Costs New cost matrix.
507
    template <typename OtherMatrixT>
508
    void updateEdgeCosts(EdgeId EId, OtherMatrixT Costs) {
509
      MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
510
      if (Solver)
511
        Solver->handleUpdateCosts(EId, *AllocatedCosts);
512
      getEdge(EId).Costs = AllocatedCosts;
513
    }
514
 
515
    /// Get a MatrixPtr to a node's cost matrix. Rarely useful - use
516
    ///        getEdgeCosts where possible.
517
    /// @param EId Edge id.
518
    /// @return MatrixPtr to edge cost matrix.
519
    ///
520
    ///   This method is primarily useful for duplicating costs quickly by
521
    /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
522
    /// getEdgeCosts when dealing with edge cost values.
523
    const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const {
524
      return getEdge(EId).Costs;
525
    }
526
 
527
    /// Get an edge's cost matrix.
528
    /// @param EId Edge id.
529
    /// @return Edge cost matrix.
530
    const Matrix& getEdgeCosts(EdgeId EId) const {
531
      return *getEdge(EId).Costs;
532
    }
533
 
534
    EdgeMetadata& getEdgeMetadata(EdgeId EId) {
535
      return getEdge(EId).Metadata;
536
    }
537
 
538
    const EdgeMetadata& getEdgeMetadata(EdgeId EId) const {
539
      return getEdge(EId).Metadata;
540
    }
541
 
542
    /// Get the first node connected to this edge.
543
    /// @param EId Edge id.
544
    /// @return The first node connected to the given edge.
545
    NodeId getEdgeNode1Id(EdgeId EId) const {
546
      return getEdge(EId).getN1Id();
547
    }
548
 
549
    /// Get the second node connected to this edge.
550
    /// @param EId Edge id.
551
    /// @return The second node connected to the given edge.
552
    NodeId getEdgeNode2Id(EdgeId EId) const {
553
      return getEdge(EId).getN2Id();
554
    }
555
 
556
    /// Get the "other" node connected to this edge.
557
    /// @param EId Edge id.
558
    /// @param NId Node id for the "given" node.
559
    /// @return The iterator for the "other" node connected to this edge.
560
    NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
561
      EdgeEntry &E = getEdge(EId);
562
      if (E.getN1Id() == NId) {
563
        return E.getN2Id();
564
      } // else
565
      return E.getN1Id();
566
    }
567
 
568
    /// Get the edge connecting two nodes.
569
    /// @param N1Id First node id.
570
    /// @param N2Id Second node id.
571
    /// @return An id for edge (N1Id, N2Id) if such an edge exists,
572
    ///         otherwise returns an invalid edge id.
573
    EdgeId findEdge(NodeId N1Id, NodeId N2Id) {
574
      for (auto AEId : adjEdgeIds(N1Id)) {
575
        if ((getEdgeNode1Id(AEId) == N2Id) ||
576
            (getEdgeNode2Id(AEId) == N2Id)) {
577
          return AEId;
578
        }
579
      }
580
      return invalidEdgeId();
581
    }
582
 
583
    /// Remove a node from the graph.
584
    /// @param NId Node id.
585
    void removeNode(NodeId NId) {
586
      if (Solver)
587
        Solver->handleRemoveNode(NId);
588
      NodeEntry &N = getNode(NId);
589
      // TODO: Can this be for-each'd?
590
      for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
591
             AEEnd = N.adjEdgesEnd();
592
           AEItr != AEEnd;) {
593
        EdgeId EId = *AEItr;
594
        ++AEItr;
595
        removeEdge(EId);
596
      }
597
      FreeNodeIds.push_back(NId);
598
    }
599
 
600
    /// Disconnect an edge from the given node.
601
    ///
602
    /// Removes the given edge from the adjacency list of the given node.
603
    /// This operation leaves the edge in an 'asymmetric' state: It will no
604
    /// longer appear in an iteration over the given node's (NId's) edges, but
605
    /// will appear in an iteration over the 'other', unnamed node's edges.
606
    ///
607
    /// This does not correspond to any normal graph operation, but exists to
608
    /// support efficient PBQP graph-reduction based solvers. It is used to
609
    /// 'effectively' remove the unnamed node from the graph while the solver
610
    /// is performing the reduction. The solver will later call reconnectNode
611
    /// to restore the edge in the named node's adjacency list.
612
    ///
613
    /// Since the degree of a node is the number of connected edges,
614
    /// disconnecting an edge from a node 'u' will cause the degree of 'u' to
615
    /// drop by 1.
616
    ///
617
    /// A disconnected edge WILL still appear in an iteration over the graph
618
    /// edges.
619
    ///
620
    /// A disconnected edge should not be removed from the graph, it should be
621
    /// reconnected first.
622
    ///
623
    /// A disconnected edge can be reconnected by calling the reconnectEdge
624
    /// method.
625
    void disconnectEdge(EdgeId EId, NodeId NId) {
626
      if (Solver)
627
        Solver->handleDisconnectEdge(EId, NId);
628
 
629
      EdgeEntry &E = getEdge(EId);
630
      E.disconnectFrom(*this, NId);
631
    }
632
 
633
    /// Convenience method to disconnect all neighbours from the given
634
    ///        node.
635
    void disconnectAllNeighborsFromNode(NodeId NId) {
636
      for (auto AEId : adjEdgeIds(NId))
637
        disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
638
    }
639
 
640
    /// Re-attach an edge to its nodes.
641
    ///
642
    /// Adds an edge that had been previously disconnected back into the
643
    /// adjacency set of the nodes that the edge connects.
644
    void reconnectEdge(EdgeId EId, NodeId NId) {
645
      EdgeEntry &E = getEdge(EId);
646
      E.connectTo(*this, EId, NId);
647
      if (Solver)
648
        Solver->handleReconnectEdge(EId, NId);
649
    }
650
 
651
    /// Remove an edge from the graph.
652
    /// @param EId Edge id.
653
    void removeEdge(EdgeId EId) {
654
      if (Solver)
655
        Solver->handleRemoveEdge(EId);
656
      EdgeEntry &E = getEdge(EId);
657
      E.disconnect();
658
      FreeEdgeIds.push_back(EId);
659
      Edges[EId].invalidate();
660
    }
661
 
662
    /// Remove all nodes and edges from the graph.
663
    void clear() {
664
      Nodes.clear();
665
      FreeNodeIds.clear();
666
      Edges.clear();
667
      FreeEdgeIds.clear();
668
    }
669
  };
670
 
671
} // end namespace PBQP
672
} // end namespace llvm
673
 
674
#endif // LLVM_CODEGEN_PBQP_GRAPH_H