10b57cec5SDimitry Andric //===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // PBQP Graph class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LLVM_CODEGEN_PBQP_GRAPH_H 140b57cec5SDimitry Andric #define LLVM_CODEGEN_PBQP_GRAPH_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 170b57cec5SDimitry Andric #include <algorithm> 180b57cec5SDimitry Andric #include <cassert> 190b57cec5SDimitry Andric #include <iterator> 200b57cec5SDimitry Andric #include <limits> 210b57cec5SDimitry Andric #include <vector> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace llvm { 240b57cec5SDimitry Andric namespace PBQP { 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric class GraphBase { 270b57cec5SDimitry Andric public: 280b57cec5SDimitry Andric using NodeId = unsigned; 290b57cec5SDimitry Andric using EdgeId = unsigned; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric /// Returns a value representing an invalid (non-existent) node. invalidNodeId()320b57cec5SDimitry Andric static NodeId invalidNodeId() { 330b57cec5SDimitry Andric return std::numeric_limits<NodeId>::max(); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric /// Returns a value representing an invalid (non-existent) edge. invalidEdgeId()370b57cec5SDimitry Andric static EdgeId invalidEdgeId() { 380b57cec5SDimitry Andric return std::numeric_limits<EdgeId>::max(); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric }; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// PBQP Graph class. 430b57cec5SDimitry Andric /// Instances of this class describe PBQP problems. 440b57cec5SDimitry Andric /// 450b57cec5SDimitry Andric template <typename SolverT> 460b57cec5SDimitry Andric class Graph : public GraphBase { 470b57cec5SDimitry Andric private: 480b57cec5SDimitry Andric using CostAllocator = typename SolverT::CostAllocator; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric public: 510b57cec5SDimitry Andric using RawVector = typename SolverT::RawVector; 520b57cec5SDimitry Andric using RawMatrix = typename SolverT::RawMatrix; 530b57cec5SDimitry Andric using Vector = typename SolverT::Vector; 540b57cec5SDimitry Andric using Matrix = typename SolverT::Matrix; 550b57cec5SDimitry Andric using VectorPtr = typename CostAllocator::VectorPtr; 560b57cec5SDimitry Andric using MatrixPtr = typename CostAllocator::MatrixPtr; 570b57cec5SDimitry Andric using NodeMetadata = typename SolverT::NodeMetadata; 580b57cec5SDimitry Andric using EdgeMetadata = typename SolverT::EdgeMetadata; 590b57cec5SDimitry Andric using GraphMetadata = typename SolverT::GraphMetadata; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric private: 620b57cec5SDimitry Andric class NodeEntry { 630b57cec5SDimitry Andric public: 640b57cec5SDimitry Andric using AdjEdgeList = std::vector<EdgeId>; 650b57cec5SDimitry Andric using AdjEdgeIdx = AdjEdgeList::size_type; 660b57cec5SDimitry Andric using AdjEdgeItr = AdjEdgeList::const_iterator; 670b57cec5SDimitry Andric NodeEntry(VectorPtr Costs)680b57cec5SDimitry Andric NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {} 690b57cec5SDimitry Andric getInvalidAdjEdgeIdx()700b57cec5SDimitry Andric static AdjEdgeIdx getInvalidAdjEdgeIdx() { 710b57cec5SDimitry Andric return std::numeric_limits<AdjEdgeIdx>::max(); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric addAdjEdgeId(EdgeId EId)740b57cec5SDimitry Andric AdjEdgeIdx addAdjEdgeId(EdgeId EId) { 750b57cec5SDimitry Andric AdjEdgeIdx Idx = AdjEdgeIds.size(); 760b57cec5SDimitry Andric AdjEdgeIds.push_back(EId); 770b57cec5SDimitry Andric return Idx; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric removeAdjEdgeId(Graph & G,NodeId ThisNId,AdjEdgeIdx Idx)800b57cec5SDimitry Andric void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) { 810b57cec5SDimitry Andric // Swap-and-pop for fast removal. 820b57cec5SDimitry Andric // 1) Update the adj index of the edge currently at back(). 830b57cec5SDimitry Andric // 2) Move last Edge down to Idx. 840b57cec5SDimitry Andric // 3) pop_back() 850b57cec5SDimitry Andric // If Idx == size() - 1 then the setAdjEdgeIdx and swap are 860b57cec5SDimitry Andric // redundant, but both operations are cheap. 870b57cec5SDimitry Andric G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx); 880b57cec5SDimitry Andric AdjEdgeIds[Idx] = AdjEdgeIds.back(); 890b57cec5SDimitry Andric AdjEdgeIds.pop_back(); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric getAdjEdgeIds()920b57cec5SDimitry Andric const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric VectorPtr Costs; 950b57cec5SDimitry Andric NodeMetadata Metadata; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric private: 980b57cec5SDimitry Andric AdjEdgeList AdjEdgeIds; 990b57cec5SDimitry Andric }; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric class EdgeEntry { 1020b57cec5SDimitry Andric public: EdgeEntry(NodeId N1Id,NodeId N2Id,MatrixPtr Costs)1030b57cec5SDimitry Andric EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs) 1040b57cec5SDimitry Andric : Costs(std::move(Costs)) { 1050b57cec5SDimitry Andric NIds[0] = N1Id; 1060b57cec5SDimitry Andric NIds[1] = N2Id; 1070b57cec5SDimitry Andric ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx(); 1080b57cec5SDimitry Andric ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx(); 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric connectToN(Graph & G,EdgeId ThisEdgeId,unsigned NIdx)1110b57cec5SDimitry Andric void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) { 1120b57cec5SDimitry Andric assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() && 1130b57cec5SDimitry Andric "Edge already connected to NIds[NIdx]."); 1140b57cec5SDimitry Andric NodeEntry &N = G.getNode(NIds[NIdx]); 1150b57cec5SDimitry Andric ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric connect(Graph & G,EdgeId ThisEdgeId)1180b57cec5SDimitry Andric void connect(Graph &G, EdgeId ThisEdgeId) { 1190b57cec5SDimitry Andric connectToN(G, ThisEdgeId, 0); 1200b57cec5SDimitry Andric connectToN(G, ThisEdgeId, 1); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric setAdjEdgeIdx(NodeId NId,typename NodeEntry::AdjEdgeIdx NewIdx)1230b57cec5SDimitry Andric void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) { 1240b57cec5SDimitry Andric if (NId == NIds[0]) 1250b57cec5SDimitry Andric ThisEdgeAdjIdxs[0] = NewIdx; 1260b57cec5SDimitry Andric else { 1270b57cec5SDimitry Andric assert(NId == NIds[1] && "Edge not connected to NId"); 1280b57cec5SDimitry Andric ThisEdgeAdjIdxs[1] = NewIdx; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric disconnectFromN(Graph & G,unsigned NIdx)1320b57cec5SDimitry Andric void disconnectFromN(Graph &G, unsigned NIdx) { 1330b57cec5SDimitry Andric assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() && 1340b57cec5SDimitry Andric "Edge not connected to NIds[NIdx]."); 1350b57cec5SDimitry Andric NodeEntry &N = G.getNode(NIds[NIdx]); 1360b57cec5SDimitry Andric N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]); 1370b57cec5SDimitry Andric ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx(); 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric disconnectFrom(Graph & G,NodeId NId)1400b57cec5SDimitry Andric void disconnectFrom(Graph &G, NodeId NId) { 1410b57cec5SDimitry Andric if (NId == NIds[0]) 1420b57cec5SDimitry Andric disconnectFromN(G, 0); 1430b57cec5SDimitry Andric else { 1440b57cec5SDimitry Andric assert(NId == NIds[1] && "Edge does not connect NId"); 1450b57cec5SDimitry Andric disconnectFromN(G, 1); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric getN1Id()1490b57cec5SDimitry Andric NodeId getN1Id() const { return NIds[0]; } getN2Id()1500b57cec5SDimitry Andric NodeId getN2Id() const { return NIds[1]; } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric MatrixPtr Costs; 1530b57cec5SDimitry Andric EdgeMetadata Metadata; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric private: 1560b57cec5SDimitry Andric NodeId NIds[2]; 1570b57cec5SDimitry Andric typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2]; 1580b57cec5SDimitry Andric }; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // ----- MEMBERS ----- 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric GraphMetadata Metadata; 1630b57cec5SDimitry Andric CostAllocator CostAlloc; 1640b57cec5SDimitry Andric SolverT *Solver = nullptr; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric using NodeVector = std::vector<NodeEntry>; 1670b57cec5SDimitry Andric using FreeNodeVector = std::vector<NodeId>; 1680b57cec5SDimitry Andric NodeVector Nodes; 1690b57cec5SDimitry Andric FreeNodeVector FreeNodeIds; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric using EdgeVector = std::vector<EdgeEntry>; 1720b57cec5SDimitry Andric using FreeEdgeVector = std::vector<EdgeId>; 1730b57cec5SDimitry Andric EdgeVector Edges; 1740b57cec5SDimitry Andric FreeEdgeVector FreeEdgeIds; 1750b57cec5SDimitry Andric Graph(const Graph & Other)1760b57cec5SDimitry Andric Graph(const Graph &Other) {} 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // ----- INTERNAL METHODS ----- 1790b57cec5SDimitry Andric getNode(NodeId NId)1800b57cec5SDimitry Andric NodeEntry &getNode(NodeId NId) { 1810b57cec5SDimitry Andric assert(NId < Nodes.size() && "Out of bound NodeId"); 1820b57cec5SDimitry Andric return Nodes[NId]; 1830b57cec5SDimitry Andric } getNode(NodeId NId)1840b57cec5SDimitry Andric const NodeEntry &getNode(NodeId NId) const { 1850b57cec5SDimitry Andric assert(NId < Nodes.size() && "Out of bound NodeId"); 1860b57cec5SDimitry Andric return Nodes[NId]; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric getEdge(EdgeId EId)1890b57cec5SDimitry Andric EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; } getEdge(EdgeId EId)1900b57cec5SDimitry Andric const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; } 1910b57cec5SDimitry Andric addConstructedNode(NodeEntry N)1920b57cec5SDimitry Andric NodeId addConstructedNode(NodeEntry N) { 1930b57cec5SDimitry Andric NodeId NId = 0; 1940b57cec5SDimitry Andric if (!FreeNodeIds.empty()) { 1950b57cec5SDimitry Andric NId = FreeNodeIds.back(); 1960b57cec5SDimitry Andric FreeNodeIds.pop_back(); 1970b57cec5SDimitry Andric Nodes[NId] = std::move(N); 1980b57cec5SDimitry Andric } else { 1990b57cec5SDimitry Andric NId = Nodes.size(); 2000b57cec5SDimitry Andric Nodes.push_back(std::move(N)); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric return NId; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric addConstructedEdge(EdgeEntry E)2050b57cec5SDimitry Andric EdgeId addConstructedEdge(EdgeEntry E) { 2060b57cec5SDimitry Andric assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() && 2070b57cec5SDimitry Andric "Attempt to add duplicate edge."); 2080b57cec5SDimitry Andric EdgeId EId = 0; 2090b57cec5SDimitry Andric if (!FreeEdgeIds.empty()) { 2100b57cec5SDimitry Andric EId = FreeEdgeIds.back(); 2110b57cec5SDimitry Andric FreeEdgeIds.pop_back(); 2120b57cec5SDimitry Andric Edges[EId] = std::move(E); 2130b57cec5SDimitry Andric } else { 2140b57cec5SDimitry Andric EId = Edges.size(); 2150b57cec5SDimitry Andric Edges.push_back(std::move(E)); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric EdgeEntry &NE = getEdge(EId); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric // Add the edge to the adjacency sets of its nodes. 2210b57cec5SDimitry Andric NE.connect(*this, EId); 2220b57cec5SDimitry Andric return EId; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void operator=(const Graph &Other) {} 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric public: 2280b57cec5SDimitry Andric using AdjEdgeItr = typename NodeEntry::AdjEdgeItr; 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric class NodeItr { 2310b57cec5SDimitry Andric public: 2320b57cec5SDimitry Andric using iterator_category = std::forward_iterator_tag; 2330b57cec5SDimitry Andric using value_type = NodeId; 2340b57cec5SDimitry Andric using difference_type = int; 2350b57cec5SDimitry Andric using pointer = NodeId *; 2360b57cec5SDimitry Andric using reference = NodeId &; 2370b57cec5SDimitry Andric NodeItr(NodeId CurNId,const Graph & G)2380b57cec5SDimitry Andric NodeItr(NodeId CurNId, const Graph &G) 2390b57cec5SDimitry Andric : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) { 2400b57cec5SDimitry Andric this->CurNId = findNextInUse(CurNId); // Move to first in-use node id 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; } 2440b57cec5SDimitry Andric bool operator!=(const NodeItr &O) const { return !(*this == O); } 2450b57cec5SDimitry Andric NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; } 2460b57cec5SDimitry Andric NodeId operator*() const { return CurNId; } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric private: findNextInUse(NodeId NId)2490b57cec5SDimitry Andric NodeId findNextInUse(NodeId NId) const { 2500b57cec5SDimitry Andric while (NId < EndNId && is_contained(FreeNodeIds, NId)) { 2510b57cec5SDimitry Andric ++NId; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric return NId; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric NodeId CurNId, EndNId; 2570b57cec5SDimitry Andric const FreeNodeVector &FreeNodeIds; 2580b57cec5SDimitry Andric }; 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric class EdgeItr { 2610b57cec5SDimitry Andric public: EdgeItr(EdgeId CurEId,const Graph & G)2620b57cec5SDimitry Andric EdgeItr(EdgeId CurEId, const Graph &G) 2630b57cec5SDimitry Andric : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) { 2640b57cec5SDimitry Andric this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; } 2680b57cec5SDimitry Andric bool operator!=(const EdgeItr &O) const { return !(*this == O); } 2690b57cec5SDimitry Andric EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; } 2700b57cec5SDimitry Andric EdgeId operator*() const { return CurEId; } 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric private: findNextInUse(EdgeId EId)2730b57cec5SDimitry Andric EdgeId findNextInUse(EdgeId EId) const { 2740b57cec5SDimitry Andric while (EId < EndEId && is_contained(FreeEdgeIds, EId)) { 2750b57cec5SDimitry Andric ++EId; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric return EId; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric EdgeId CurEId, EndEId; 2810b57cec5SDimitry Andric const FreeEdgeVector &FreeEdgeIds; 2820b57cec5SDimitry Andric }; 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric class NodeIdSet { 2850b57cec5SDimitry Andric public: NodeIdSet(const Graph & G)2860b57cec5SDimitry Andric NodeIdSet(const Graph &G) : G(G) {} 2870b57cec5SDimitry Andric begin()2880b57cec5SDimitry Andric NodeItr begin() const { return NodeItr(0, G); } end()2890b57cec5SDimitry Andric NodeItr end() const { return NodeItr(G.Nodes.size(), G); } 2900b57cec5SDimitry Andric empty()2910b57cec5SDimitry Andric bool empty() const { return G.Nodes.empty(); } 2920b57cec5SDimitry Andric size()2930b57cec5SDimitry Andric typename NodeVector::size_type size() const { 2940b57cec5SDimitry Andric return G.Nodes.size() - G.FreeNodeIds.size(); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric private: 2980b57cec5SDimitry Andric const Graph& G; 2990b57cec5SDimitry Andric }; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric class EdgeIdSet { 3020b57cec5SDimitry Andric public: EdgeIdSet(const Graph & G)3030b57cec5SDimitry Andric EdgeIdSet(const Graph &G) : G(G) {} 3040b57cec5SDimitry Andric begin()3050b57cec5SDimitry Andric EdgeItr begin() const { return EdgeItr(0, G); } end()3060b57cec5SDimitry Andric EdgeItr end() const { return EdgeItr(G.Edges.size(), G); } 3070b57cec5SDimitry Andric empty()3080b57cec5SDimitry Andric bool empty() const { return G.Edges.empty(); } 3090b57cec5SDimitry Andric size()3100b57cec5SDimitry Andric typename NodeVector::size_type size() const { 3110b57cec5SDimitry Andric return G.Edges.size() - G.FreeEdgeIds.size(); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric private: 3150b57cec5SDimitry Andric const Graph& G; 3160b57cec5SDimitry Andric }; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric class AdjEdgeIdSet { 3190b57cec5SDimitry Andric public: AdjEdgeIdSet(const NodeEntry & NE)3200b57cec5SDimitry Andric AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {} 3210b57cec5SDimitry Andric begin()3220b57cec5SDimitry Andric typename NodeEntry::AdjEdgeItr begin() const { 3230b57cec5SDimitry Andric return NE.getAdjEdgeIds().begin(); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric end()3260b57cec5SDimitry Andric typename NodeEntry::AdjEdgeItr end() const { 3270b57cec5SDimitry Andric return NE.getAdjEdgeIds().end(); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric empty()3300b57cec5SDimitry Andric bool empty() const { return NE.getAdjEdgeIds().empty(); } 3310b57cec5SDimitry Andric size()3320b57cec5SDimitry Andric typename NodeEntry::AdjEdgeList::size_type size() const { 3330b57cec5SDimitry Andric return NE.getAdjEdgeIds().size(); 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric private: 3370b57cec5SDimitry Andric const NodeEntry &NE; 3380b57cec5SDimitry Andric }; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric /// Construct an empty PBQP graph. 3410b57cec5SDimitry Andric Graph() = default; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric /// Construct an empty PBQP graph with the given graph metadata. Graph(GraphMetadata Metadata)3440b57cec5SDimitry Andric Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {} 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric /// Get a reference to the graph metadata. getMetadata()3470b57cec5SDimitry Andric GraphMetadata& getMetadata() { return Metadata; } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric /// Get a const-reference to the graph metadata. getMetadata()3500b57cec5SDimitry Andric const GraphMetadata& getMetadata() const { return Metadata; } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric /// Lock this graph to the given solver instance in preparation 3530b57cec5SDimitry Andric /// for running the solver. This method will call solver.handleAddNode for 3540b57cec5SDimitry Andric /// each node in the graph, and handleAddEdge for each edge, to give the 3550b57cec5SDimitry Andric /// solver an opportunity to set up any requried metadata. setSolver(SolverT & S)3560b57cec5SDimitry Andric void setSolver(SolverT &S) { 3570b57cec5SDimitry Andric assert(!Solver && "Solver already set. Call unsetSolver()."); 3580b57cec5SDimitry Andric Solver = &S; 3590b57cec5SDimitry Andric for (auto NId : nodeIds()) 3600b57cec5SDimitry Andric Solver->handleAddNode(NId); 3610b57cec5SDimitry Andric for (auto EId : edgeIds()) 3620b57cec5SDimitry Andric Solver->handleAddEdge(EId); 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric /// Release from solver instance. unsetSolver()3660b57cec5SDimitry Andric void unsetSolver() { 3670b57cec5SDimitry Andric assert(Solver && "Solver not set."); 3680b57cec5SDimitry Andric Solver = nullptr; 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric /// Add a node with the given costs. 3720b57cec5SDimitry Andric /// @param Costs Cost vector for the new node. 3730b57cec5SDimitry Andric /// @return Node iterator for the added node. 3740b57cec5SDimitry Andric template <typename OtherVectorT> addNode(OtherVectorT Costs)3750b57cec5SDimitry Andric NodeId addNode(OtherVectorT Costs) { 3760b57cec5SDimitry Andric // Get cost vector from the problem domain 3770b57cec5SDimitry Andric VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 3780b57cec5SDimitry Andric NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts)); 3790b57cec5SDimitry Andric if (Solver) 3800b57cec5SDimitry Andric Solver->handleAddNode(NId); 3810b57cec5SDimitry Andric return NId; 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric /// Add a node bypassing the cost allocator. 3850b57cec5SDimitry Andric /// @param Costs Cost vector ptr for the new node (must be convertible to 3860b57cec5SDimitry Andric /// VectorPtr). 3870b57cec5SDimitry Andric /// @return Node iterator for the added node. 3880b57cec5SDimitry Andric /// 3890b57cec5SDimitry Andric /// This method allows for fast addition of a node whose costs don't need 3900b57cec5SDimitry Andric /// to be passed through the cost allocator. The most common use case for 3910b57cec5SDimitry Andric /// this is when duplicating costs from an existing node (when using a 3920b57cec5SDimitry Andric /// pooling allocator). These have already been uniqued, so we can avoid 3930b57cec5SDimitry Andric /// re-constructing and re-uniquing them by attaching them directly to the 3940b57cec5SDimitry Andric /// new node. 3950b57cec5SDimitry Andric template <typename OtherVectorPtrT> addNodeBypassingCostAllocator(OtherVectorPtrT Costs)3960b57cec5SDimitry Andric NodeId addNodeBypassingCostAllocator(OtherVectorPtrT Costs) { 3970b57cec5SDimitry Andric NodeId NId = addConstructedNode(NodeEntry(Costs)); 3980b57cec5SDimitry Andric if (Solver) 3990b57cec5SDimitry Andric Solver->handleAddNode(NId); 4000b57cec5SDimitry Andric return NId; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric /// Add an edge between the given nodes with the given costs. 4040b57cec5SDimitry Andric /// @param N1Id First node. 4050b57cec5SDimitry Andric /// @param N2Id Second node. 4060b57cec5SDimitry Andric /// @param Costs Cost matrix for new edge. 4070b57cec5SDimitry Andric /// @return Edge iterator for the added edge. 4080b57cec5SDimitry Andric template <typename OtherVectorT> addEdge(NodeId N1Id,NodeId N2Id,OtherVectorT Costs)4090b57cec5SDimitry Andric EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) { 4100b57cec5SDimitry Andric assert(getNodeCosts(N1Id).getLength() == Costs.getRows() && 4110b57cec5SDimitry Andric getNodeCosts(N2Id).getLength() == Costs.getCols() && 4120b57cec5SDimitry Andric "Matrix dimensions mismatch."); 4130b57cec5SDimitry Andric // Get cost matrix from the problem domain. 4140b57cec5SDimitry Andric MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 4150b57cec5SDimitry Andric EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts)); 4160b57cec5SDimitry Andric if (Solver) 4170b57cec5SDimitry Andric Solver->handleAddEdge(EId); 4180b57cec5SDimitry Andric return EId; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric /// Add an edge bypassing the cost allocator. 4220b57cec5SDimitry Andric /// @param N1Id First node. 4230b57cec5SDimitry Andric /// @param N2Id Second node. 4240b57cec5SDimitry Andric /// @param Costs Cost matrix for new edge. 4250b57cec5SDimitry Andric /// @return Edge iterator for the added edge. 4260b57cec5SDimitry Andric /// 4270b57cec5SDimitry Andric /// This method allows for fast addition of an edge whose costs don't need 4280b57cec5SDimitry Andric /// to be passed through the cost allocator. The most common use case for 4290b57cec5SDimitry Andric /// this is when duplicating costs from an existing edge (when using a 4300b57cec5SDimitry Andric /// pooling allocator). These have already been uniqued, so we can avoid 4310b57cec5SDimitry Andric /// re-constructing and re-uniquing them by attaching them directly to the 4320b57cec5SDimitry Andric /// new edge. 4330b57cec5SDimitry Andric template <typename OtherMatrixPtrT> addEdgeBypassingCostAllocator(NodeId N1Id,NodeId N2Id,OtherMatrixPtrT Costs)4340b57cec5SDimitry Andric NodeId addEdgeBypassingCostAllocator(NodeId N1Id, NodeId N2Id, 4350b57cec5SDimitry Andric OtherMatrixPtrT Costs) { 4360b57cec5SDimitry Andric assert(getNodeCosts(N1Id).getLength() == Costs->getRows() && 4370b57cec5SDimitry Andric getNodeCosts(N2Id).getLength() == Costs->getCols() && 4380b57cec5SDimitry Andric "Matrix dimensions mismatch."); 4390b57cec5SDimitry Andric // Get cost matrix from the problem domain. 4400b57cec5SDimitry Andric EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs)); 4410b57cec5SDimitry Andric if (Solver) 4420b57cec5SDimitry Andric Solver->handleAddEdge(EId); 4430b57cec5SDimitry Andric return EId; 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric /// Returns true if the graph is empty. empty()4470b57cec5SDimitry Andric bool empty() const { return NodeIdSet(*this).empty(); } 4480b57cec5SDimitry Andric nodeIds()4490b57cec5SDimitry Andric NodeIdSet nodeIds() const { return NodeIdSet(*this); } edgeIds()4500b57cec5SDimitry Andric EdgeIdSet edgeIds() const { return EdgeIdSet(*this); } 4510b57cec5SDimitry Andric adjEdgeIds(NodeId NId)4520b57cec5SDimitry Andric AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); } 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric /// Get the number of nodes in the graph. 4550b57cec5SDimitry Andric /// @return Number of nodes in the graph. getNumNodes()4560b57cec5SDimitry Andric unsigned getNumNodes() const { return NodeIdSet(*this).size(); } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric /// Get the number of edges in the graph. 4590b57cec5SDimitry Andric /// @return Number of edges in the graph. getNumEdges()4600b57cec5SDimitry Andric unsigned getNumEdges() const { return EdgeIdSet(*this).size(); } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric /// Set a node's cost vector. 4630b57cec5SDimitry Andric /// @param NId Node to update. 4640b57cec5SDimitry Andric /// @param Costs New costs to set. 4650b57cec5SDimitry Andric template <typename OtherVectorT> setNodeCosts(NodeId NId,OtherVectorT Costs)4660b57cec5SDimitry Andric void setNodeCosts(NodeId NId, OtherVectorT Costs) { 4670b57cec5SDimitry Andric VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 4680b57cec5SDimitry Andric if (Solver) 4690b57cec5SDimitry Andric Solver->handleSetNodeCosts(NId, *AllocatedCosts); 4700b57cec5SDimitry Andric getNode(NId).Costs = AllocatedCosts; 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric /// Get a VectorPtr to a node's cost vector. Rarely useful - use 4740b57cec5SDimitry Andric /// getNodeCosts where possible. 4750b57cec5SDimitry Andric /// @param NId Node id. 4760b57cec5SDimitry Andric /// @return VectorPtr to node cost vector. 4770b57cec5SDimitry Andric /// 4780b57cec5SDimitry Andric /// This method is primarily useful for duplicating costs quickly by 4790b57cec5SDimitry Andric /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer 4800b57cec5SDimitry Andric /// getNodeCosts when dealing with node cost values. getNodeCostsPtr(NodeId NId)4810b57cec5SDimitry Andric const VectorPtr& getNodeCostsPtr(NodeId NId) const { 4820b57cec5SDimitry Andric return getNode(NId).Costs; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric /// Get a node's cost vector. 4860b57cec5SDimitry Andric /// @param NId Node id. 4870b57cec5SDimitry Andric /// @return Node cost vector. getNodeCosts(NodeId NId)4880b57cec5SDimitry Andric const Vector& getNodeCosts(NodeId NId) const { 4890b57cec5SDimitry Andric return *getNodeCostsPtr(NId); 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric getNodeMetadata(NodeId NId)4920b57cec5SDimitry Andric NodeMetadata& getNodeMetadata(NodeId NId) { 4930b57cec5SDimitry Andric return getNode(NId).Metadata; 4940b57cec5SDimitry Andric } 4950b57cec5SDimitry Andric getNodeMetadata(NodeId NId)4960b57cec5SDimitry Andric const NodeMetadata& getNodeMetadata(NodeId NId) const { 4970b57cec5SDimitry Andric return getNode(NId).Metadata; 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric getNodeDegree(NodeId NId)5000b57cec5SDimitry Andric typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const { 5010b57cec5SDimitry Andric return getNode(NId).getAdjEdgeIds().size(); 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric /// Update an edge's cost matrix. 5050b57cec5SDimitry Andric /// @param EId Edge id. 5060b57cec5SDimitry Andric /// @param Costs New cost matrix. 5070b57cec5SDimitry Andric template <typename OtherMatrixT> updateEdgeCosts(EdgeId EId,OtherMatrixT Costs)5080b57cec5SDimitry Andric void updateEdgeCosts(EdgeId EId, OtherMatrixT Costs) { 5090b57cec5SDimitry Andric MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 5100b57cec5SDimitry Andric if (Solver) 5110b57cec5SDimitry Andric Solver->handleUpdateCosts(EId, *AllocatedCosts); 5120b57cec5SDimitry Andric getEdge(EId).Costs = AllocatedCosts; 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric /// Get a MatrixPtr to a node's cost matrix. Rarely useful - use 5160b57cec5SDimitry Andric /// getEdgeCosts where possible. 5170b57cec5SDimitry Andric /// @param EId Edge id. 5180b57cec5SDimitry Andric /// @return MatrixPtr to edge cost matrix. 5190b57cec5SDimitry Andric /// 5200b57cec5SDimitry Andric /// This method is primarily useful for duplicating costs quickly by 5210b57cec5SDimitry Andric /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer 5220b57cec5SDimitry Andric /// getEdgeCosts when dealing with edge cost values. getEdgeCostsPtr(EdgeId EId)5230b57cec5SDimitry Andric const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const { 5240b57cec5SDimitry Andric return getEdge(EId).Costs; 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric /// Get an edge's cost matrix. 5280b57cec5SDimitry Andric /// @param EId Edge id. 5290b57cec5SDimitry Andric /// @return Edge cost matrix. getEdgeCosts(EdgeId EId)5300b57cec5SDimitry Andric const Matrix& getEdgeCosts(EdgeId EId) const { 5310b57cec5SDimitry Andric return *getEdge(EId).Costs; 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric getEdgeMetadata(EdgeId EId)5340b57cec5SDimitry Andric EdgeMetadata& getEdgeMetadata(EdgeId EId) { 5350b57cec5SDimitry Andric return getEdge(EId).Metadata; 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric getEdgeMetadata(EdgeId EId)5380b57cec5SDimitry Andric const EdgeMetadata& getEdgeMetadata(EdgeId EId) const { 5390b57cec5SDimitry Andric return getEdge(EId).Metadata; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /// Get the first node connected to this edge. 5430b57cec5SDimitry Andric /// @param EId Edge id. 5440b57cec5SDimitry Andric /// @return The first node connected to the given edge. getEdgeNode1Id(EdgeId EId)5450b57cec5SDimitry Andric NodeId getEdgeNode1Id(EdgeId EId) const { 5460b57cec5SDimitry Andric return getEdge(EId).getN1Id(); 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric /// Get the second node connected to this edge. 5500b57cec5SDimitry Andric /// @param EId Edge id. 5510b57cec5SDimitry Andric /// @return The second node connected to the given edge. getEdgeNode2Id(EdgeId EId)5520b57cec5SDimitry Andric NodeId getEdgeNode2Id(EdgeId EId) const { 5530b57cec5SDimitry Andric return getEdge(EId).getN2Id(); 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric /// Get the "other" node connected to this edge. 5570b57cec5SDimitry Andric /// @param EId Edge id. 5580b57cec5SDimitry Andric /// @param NId Node id for the "given" node. 5590b57cec5SDimitry Andric /// @return The iterator for the "other" node connected to this edge. getEdgeOtherNodeId(EdgeId EId,NodeId NId)5600b57cec5SDimitry Andric NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) { 5610b57cec5SDimitry Andric EdgeEntry &E = getEdge(EId); 5620b57cec5SDimitry Andric if (E.getN1Id() == NId) { 5630b57cec5SDimitry Andric return E.getN2Id(); 5640b57cec5SDimitry Andric } // else 5650b57cec5SDimitry Andric return E.getN1Id(); 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric /// Get the edge connecting two nodes. 5690b57cec5SDimitry Andric /// @param N1Id First node id. 5700b57cec5SDimitry Andric /// @param N2Id Second node id. 5710b57cec5SDimitry Andric /// @return An id for edge (N1Id, N2Id) if such an edge exists, 5720b57cec5SDimitry Andric /// otherwise returns an invalid edge id. findEdge(NodeId N1Id,NodeId N2Id)5730b57cec5SDimitry Andric EdgeId findEdge(NodeId N1Id, NodeId N2Id) { 5740b57cec5SDimitry Andric for (auto AEId : adjEdgeIds(N1Id)) { 5750b57cec5SDimitry Andric if ((getEdgeNode1Id(AEId) == N2Id) || 5760b57cec5SDimitry Andric (getEdgeNode2Id(AEId) == N2Id)) { 5770b57cec5SDimitry Andric return AEId; 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric return invalidEdgeId(); 5810b57cec5SDimitry Andric } 5820b57cec5SDimitry Andric 5830b57cec5SDimitry Andric /// Remove a node from the graph. 5840b57cec5SDimitry Andric /// @param NId Node id. removeNode(NodeId NId)5850b57cec5SDimitry Andric void removeNode(NodeId NId) { 5860b57cec5SDimitry Andric if (Solver) 5870b57cec5SDimitry Andric Solver->handleRemoveNode(NId); 5880b57cec5SDimitry Andric NodeEntry &N = getNode(NId); 5890b57cec5SDimitry Andric // TODO: Can this be for-each'd? 5900b57cec5SDimitry Andric for (AdjEdgeItr AEItr = N.adjEdgesBegin(), 5910b57cec5SDimitry Andric AEEnd = N.adjEdgesEnd(); 5920b57cec5SDimitry Andric AEItr != AEEnd;) { 5930b57cec5SDimitry Andric EdgeId EId = *AEItr; 5940b57cec5SDimitry Andric ++AEItr; 5950b57cec5SDimitry Andric removeEdge(EId); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric FreeNodeIds.push_back(NId); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric /// Disconnect an edge from the given node. 6010b57cec5SDimitry Andric /// 6020b57cec5SDimitry Andric /// Removes the given edge from the adjacency list of the given node. 6030b57cec5SDimitry Andric /// This operation leaves the edge in an 'asymmetric' state: It will no 6040b57cec5SDimitry Andric /// longer appear in an iteration over the given node's (NId's) edges, but 6050b57cec5SDimitry Andric /// will appear in an iteration over the 'other', unnamed node's edges. 6060b57cec5SDimitry Andric /// 6070b57cec5SDimitry Andric /// This does not correspond to any normal graph operation, but exists to 6080b57cec5SDimitry Andric /// support efficient PBQP graph-reduction based solvers. It is used to 6090b57cec5SDimitry Andric /// 'effectively' remove the unnamed node from the graph while the solver 6100b57cec5SDimitry Andric /// is performing the reduction. The solver will later call reconnectNode 6110b57cec5SDimitry Andric /// to restore the edge in the named node's adjacency list. 6120b57cec5SDimitry Andric /// 6130b57cec5SDimitry Andric /// Since the degree of a node is the number of connected edges, 6140b57cec5SDimitry Andric /// disconnecting an edge from a node 'u' will cause the degree of 'u' to 6150b57cec5SDimitry Andric /// drop by 1. 6160b57cec5SDimitry Andric /// 6170b57cec5SDimitry Andric /// A disconnected edge WILL still appear in an iteration over the graph 6180b57cec5SDimitry Andric /// edges. 6190b57cec5SDimitry Andric /// 6200b57cec5SDimitry Andric /// A disconnected edge should not be removed from the graph, it should be 6210b57cec5SDimitry Andric /// reconnected first. 6220b57cec5SDimitry Andric /// 6230b57cec5SDimitry Andric /// A disconnected edge can be reconnected by calling the reconnectEdge 6240b57cec5SDimitry Andric /// method. disconnectEdge(EdgeId EId,NodeId NId)6250b57cec5SDimitry Andric void disconnectEdge(EdgeId EId, NodeId NId) { 6260b57cec5SDimitry Andric if (Solver) 6270b57cec5SDimitry Andric Solver->handleDisconnectEdge(EId, NId); 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric EdgeEntry &E = getEdge(EId); 6300b57cec5SDimitry Andric E.disconnectFrom(*this, NId); 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric /// Convenience method to disconnect all neighbours from the given 6340b57cec5SDimitry Andric /// node. disconnectAllNeighborsFromNode(NodeId NId)6350b57cec5SDimitry Andric void disconnectAllNeighborsFromNode(NodeId NId) { 6360b57cec5SDimitry Andric for (auto AEId : adjEdgeIds(NId)) 6370b57cec5SDimitry Andric disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId)); 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric /// Re-attach an edge to its nodes. 6410b57cec5SDimitry Andric /// 6420b57cec5SDimitry Andric /// Adds an edge that had been previously disconnected back into the 6430b57cec5SDimitry Andric /// adjacency set of the nodes that the edge connects. reconnectEdge(EdgeId EId,NodeId NId)6440b57cec5SDimitry Andric void reconnectEdge(EdgeId EId, NodeId NId) { 6450b57cec5SDimitry Andric EdgeEntry &E = getEdge(EId); 6460b57cec5SDimitry Andric E.connectTo(*this, EId, NId); 6470b57cec5SDimitry Andric if (Solver) 6480b57cec5SDimitry Andric Solver->handleReconnectEdge(EId, NId); 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric 6510b57cec5SDimitry Andric /// Remove an edge from the graph. 6520b57cec5SDimitry Andric /// @param EId Edge id. removeEdge(EdgeId EId)6530b57cec5SDimitry Andric void removeEdge(EdgeId EId) { 6540b57cec5SDimitry Andric if (Solver) 6550b57cec5SDimitry Andric Solver->handleRemoveEdge(EId); 6560b57cec5SDimitry Andric EdgeEntry &E = getEdge(EId); 6570b57cec5SDimitry Andric E.disconnect(); 6580b57cec5SDimitry Andric FreeEdgeIds.push_back(EId); 6590b57cec5SDimitry Andric Edges[EId].invalidate(); 6600b57cec5SDimitry Andric } 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric /// Remove all nodes and edges from the graph. clear()6630b57cec5SDimitry Andric void clear() { 6640b57cec5SDimitry Andric Nodes.clear(); 6650b57cec5SDimitry Andric FreeNodeIds.clear(); 6660b57cec5SDimitry Andric Edges.clear(); 6670b57cec5SDimitry Andric FreeEdgeIds.clear(); 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric }; 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric } // end namespace PBQP 6720b57cec5SDimitry Andric } // end namespace llvm 6730b57cec5SDimitry Andric 674*fe6060f1SDimitry Andric #endif // LLVM_CODEGEN_PBQP_GRAPH_H 675