[Alignment][NFC] Migrate Instructions to Align
[llvm-core.git] / include / llvm / CodeGen / PBQP / Graph.h
blobc2cd6dadae5f8b46b2a317d73464ff7d070930fd
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.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CODEGEN_PBQP_GRAPH_H
14 #define LLVM_CODEGEN_PBQP_GRAPH_H
16 #include "llvm/ADT/STLExtras.h"
17 #include <algorithm>
18 #include <cassert>
19 #include <iterator>
20 #include <limits>
21 #include <vector>
23 namespace llvm {
24 namespace PBQP {
26 class GraphBase {
27 public:
28 using NodeId = unsigned;
29 using EdgeId = unsigned;
31 /// Returns a value representing an invalid (non-existent) node.
32 static NodeId invalidNodeId() {
33 return std::numeric_limits<NodeId>::max();
36 /// Returns a value representing an invalid (non-existent) edge.
37 static EdgeId invalidEdgeId() {
38 return std::numeric_limits<EdgeId>::max();
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;
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;
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;
68 NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
70 static AdjEdgeIdx getInvalidAdjEdgeIdx() {
71 return std::numeric_limits<AdjEdgeIdx>::max();
74 AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
75 AdjEdgeIdx Idx = AdjEdgeIds.size();
76 AdjEdgeIds.push_back(EId);
77 return Idx;
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();
92 const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; }
94 VectorPtr Costs;
95 NodeMetadata Metadata;
97 private:
98 AdjEdgeList AdjEdgeIds;
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();
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);
118 void connect(Graph &G, EdgeId ThisEdgeId) {
119 connectToN(G, ThisEdgeId, 0);
120 connectToN(G, ThisEdgeId, 1);
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;
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();
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);
149 NodeId getN1Id() const { return NIds[0]; }
150 NodeId getN2Id() const { return NIds[1]; }
152 MatrixPtr Costs;
153 EdgeMetadata Metadata;
155 private:
156 NodeId NIds[2];
157 typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
160 // ----- MEMBERS -----
162 GraphMetadata Metadata;
163 CostAllocator CostAlloc;
164 SolverT *Solver = nullptr;
166 using NodeVector = std::vector<NodeEntry>;
167 using FreeNodeVector = std::vector<NodeId>;
168 NodeVector Nodes;
169 FreeNodeVector FreeNodeIds;
171 using EdgeVector = std::vector<EdgeEntry>;
172 using FreeEdgeVector = std::vector<EdgeId>;
173 EdgeVector Edges;
174 FreeEdgeVector FreeEdgeIds;
176 Graph(const Graph &Other) {}
178 // ----- INTERNAL METHODS -----
180 NodeEntry &getNode(NodeId NId) {
181 assert(NId < Nodes.size() && "Out of bound NodeId");
182 return Nodes[NId];
184 const NodeEntry &getNode(NodeId NId) const {
185 assert(NId < Nodes.size() && "Out of bound NodeId");
186 return Nodes[NId];
189 EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
190 const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
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));
202 return NId;
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));
218 EdgeEntry &NE = getEdge(EId);
220 // Add the edge to the adjacency sets of its nodes.
221 NE.connect(*this, EId);
222 return EId;
225 void operator=(const Graph &Other) {}
227 public:
228 using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
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 &;
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
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; }
248 private:
249 NodeId findNextInUse(NodeId NId) const {
250 while (NId < EndNId && is_contained(FreeNodeIds, NId)) {
251 ++NId;
253 return NId;
256 NodeId CurNId, EndNId;
257 const FreeNodeVector &FreeNodeIds;
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
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; }
272 private:
273 EdgeId findNextInUse(EdgeId EId) const {
274 while (EId < EndEId && is_contained(FreeEdgeIds, EId)) {
275 ++EId;
277 return EId;
280 EdgeId CurEId, EndEId;
281 const FreeEdgeVector &FreeEdgeIds;
284 class NodeIdSet {
285 public:
286 NodeIdSet(const Graph &G) : G(G) {}
288 NodeItr begin() const { return NodeItr(0, G); }
289 NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
291 bool empty() const { return G.Nodes.empty(); }
293 typename NodeVector::size_type size() const {
294 return G.Nodes.size() - G.FreeNodeIds.size();
297 private:
298 const Graph& G;
301 class EdgeIdSet {
302 public:
303 EdgeIdSet(const Graph &G) : G(G) {}
305 EdgeItr begin() const { return EdgeItr(0, G); }
306 EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
308 bool empty() const { return G.Edges.empty(); }
310 typename NodeVector::size_type size() const {
311 return G.Edges.size() - G.FreeEdgeIds.size();
314 private:
315 const Graph& G;
318 class AdjEdgeIdSet {
319 public:
320 AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
322 typename NodeEntry::AdjEdgeItr begin() const {
323 return NE.getAdjEdgeIds().begin();
326 typename NodeEntry::AdjEdgeItr end() const {
327 return NE.getAdjEdgeIds().end();
330 bool empty() const { return NE.getAdjEdgeIds().empty(); }
332 typename NodeEntry::AdjEdgeList::size_type size() const {
333 return NE.getAdjEdgeIds().size();
336 private:
337 const NodeEntry &NE;
340 /// Construct an empty PBQP graph.
341 Graph() = default;
343 /// Construct an empty PBQP graph with the given graph metadata.
344 Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
346 /// Get a reference to the graph metadata.
347 GraphMetadata& getMetadata() { return Metadata; }
349 /// Get a const-reference to the graph metadata.
350 const GraphMetadata& getMetadata() const { return Metadata; }
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);
365 /// Release from solver instance.
366 void unsetSolver() {
367 assert(Solver && "Solver not set.");
368 Solver = nullptr;
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;
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.
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;
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;
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.
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;
446 /// Returns true if the graph is empty.
447 bool empty() const { return NodeIdSet(*this).empty(); }
449 NodeIdSet nodeIds() const { return NodeIdSet(*this); }
450 EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
452 AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
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(); }
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(); }
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;
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.
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;
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);
492 NodeMetadata& getNodeMetadata(NodeId NId) {
493 return getNode(NId).Metadata;
496 const NodeMetadata& getNodeMetadata(NodeId NId) const {
497 return getNode(NId).Metadata;
500 typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
501 return getNode(NId).getAdjEdgeIds().size();
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;
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.
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;
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;
534 EdgeMetadata& getEdgeMetadata(EdgeId EId) {
535 return getEdge(EId).Metadata;
538 const EdgeMetadata& getEdgeMetadata(EdgeId EId) const {
539 return getEdge(EId).Metadata;
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();
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();
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();
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;
580 return invalidEdgeId();
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);
597 FreeNodeIds.push_back(NId);
600 /// Disconnect an edge from the given node.
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.
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.
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.
617 /// A disconnected edge WILL still appear in an iteration over the graph
618 /// edges.
620 /// A disconnected edge should not be removed from the graph, it should be
621 /// reconnected first.
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);
629 EdgeEntry &E = getEdge(EId);
630 E.disconnectFrom(*this, NId);
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));
640 /// Re-attach an edge to its nodes.
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);
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();
662 /// Remove all nodes and edges from the graph.
663 void clear() {
664 Nodes.clear();
665 FreeNodeIds.clear();
666 Edges.clear();
667 FreeEdgeIds.clear();
671 } // end namespace PBQP
672 } // end namespace llvm
674 #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP