17ea69237SEugene Zelenko //===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===// 2cb1e1017SLang Hames // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6cb1e1017SLang Hames // 7cb1e1017SLang Hames //===----------------------------------------------------------------------===// 8cb1e1017SLang Hames // 9cb1e1017SLang Hames // PBQP Graph class. 10cb1e1017SLang Hames // 11cb1e1017SLang Hames //===----------------------------------------------------------------------===// 12cb1e1017SLang Hames 13cb1e1017SLang Hames #ifndef LLVM_CODEGEN_PBQP_GRAPH_H 14cb1e1017SLang Hames #define LLVM_CODEGEN_PBQP_GRAPH_H 15cb1e1017SLang Hames 1646d39604SRichard Smith #include "llvm/ADT/STLExtras.h" 1721858f21SVassil Vassilev #include <algorithm> 1821858f21SVassil Vassilev #include <cassert> 197ea69237SEugene Zelenko #include <iterator> 2021858f21SVassil Vassilev #include <limits> 2111960334SRichard Smith #include <vector> 22cb1e1017SLang Hames 238f31f448SLang Hames namespace llvm { 24cb1e1017SLang Hames namespace PBQP { 25cb1e1017SLang Hames 2618635828SLang Hames class GraphBase { 27cb1e1017SLang Hames public: 287ea69237SEugene Zelenko using NodeId = unsigned; 297ea69237SEugene Zelenko using EdgeId = unsigned; 30652b0a4fSLang Hames 314dfcc4a7SAdrian Prantl /// Returns a value representing an invalid (non-existent) node. invalidNodeId()32652b0a4fSLang Hames static NodeId invalidNodeId() { 33652b0a4fSLang Hames return std::numeric_limits<NodeId>::max(); 34652b0a4fSLang Hames } 35652b0a4fSLang Hames 364dfcc4a7SAdrian Prantl /// Returns a value representing an invalid (non-existent) edge. invalidEdgeId()37652b0a4fSLang Hames static EdgeId invalidEdgeId() { 38652b0a4fSLang Hames return std::numeric_limits<EdgeId>::max(); 39652b0a4fSLang Hames } 4018635828SLang Hames }; 41c083578aSLang Hames 4218635828SLang Hames /// PBQP Graph class. 4318635828SLang Hames /// Instances of this class describe PBQP problems. 4418635828SLang Hames /// 4518635828SLang Hames template <typename SolverT> 4618635828SLang Hames class Graph : public GraphBase { 47c083578aSLang Hames private: 487ea69237SEugene Zelenko using CostAllocator = typename SolverT::CostAllocator; 497ea69237SEugene Zelenko 50c083578aSLang Hames public: 517ea69237SEugene Zelenko using RawVector = typename SolverT::RawVector; 527ea69237SEugene Zelenko using RawMatrix = typename SolverT::RawMatrix; 537ea69237SEugene Zelenko using Vector = typename SolverT::Vector; 547ea69237SEugene Zelenko using Matrix = typename SolverT::Matrix; 557ea69237SEugene Zelenko using VectorPtr = typename CostAllocator::VectorPtr; 567ea69237SEugene Zelenko using MatrixPtr = typename CostAllocator::MatrixPtr; 577ea69237SEugene Zelenko using NodeMetadata = typename SolverT::NodeMetadata; 587ea69237SEugene Zelenko using EdgeMetadata = typename SolverT::EdgeMetadata; 597ea69237SEugene Zelenko using GraphMetadata = typename SolverT::GraphMetadata; 60cb1e1017SLang Hames 61cb1e1017SLang Hames private: 62fb82630aSLang Hames class NodeEntry { 63cb1e1017SLang Hames public: 647ea69237SEugene Zelenko using AdjEdgeList = std::vector<EdgeId>; 657ea69237SEugene Zelenko using AdjEdgeIdx = AdjEdgeList::size_type; 667ea69237SEugene Zelenko using AdjEdgeItr = AdjEdgeList::const_iterator; 677ea69237SEugene Zelenko NodeEntry(VectorPtr Costs)687ea69237SEugene Zelenko NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {} 69ff85ba12SLang Hames getInvalidAdjEdgeIdx()70ff85ba12SLang Hames static AdjEdgeIdx getInvalidAdjEdgeIdx() { 71ff85ba12SLang Hames return std::numeric_limits<AdjEdgeIdx>::max(); 72ff85ba12SLang Hames } 73ff85ba12SLang Hames addAdjEdgeId(EdgeId EId)74ff85ba12SLang Hames AdjEdgeIdx addAdjEdgeId(EdgeId EId) { 75ff85ba12SLang Hames AdjEdgeIdx Idx = AdjEdgeIds.size(); 76ff85ba12SLang Hames AdjEdgeIds.push_back(EId); 77ff85ba12SLang Hames return Idx; 78ff85ba12SLang Hames } 79ff85ba12SLang Hames removeAdjEdgeId(Graph & G,NodeId ThisNId,AdjEdgeIdx Idx)805391ac47SLang Hames void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) { 815391ac47SLang Hames // Swap-and-pop for fast removal. 825391ac47SLang Hames // 1) Update the adj index of the edge currently at back(). 83cacce82cSDavid Blaikie // 2) Move last Edge down to Idx. 845391ac47SLang Hames // 3) pop_back() 85cacce82cSDavid Blaikie // If Idx == size() - 1 then the setAdjEdgeIdx and swap are 865391ac47SLang Hames // redundant, but both operations are cheap. 87cacce82cSDavid Blaikie G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx); 88cacce82cSDavid Blaikie AdjEdgeIds[Idx] = AdjEdgeIds.back(); 89ff85ba12SLang Hames AdjEdgeIds.pop_back(); 90ff85ba12SLang Hames } 91ff85ba12SLang Hames getAdjEdgeIds()92ff85ba12SLang Hames const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; } 93ff85ba12SLang Hames 9418635828SLang Hames VectorPtr Costs; 9518635828SLang Hames NodeMetadata Metadata; 967ea69237SEugene Zelenko 97ff85ba12SLang Hames private: 9818635828SLang Hames AdjEdgeList AdjEdgeIds; 99cb1e1017SLang Hames }; 100cb1e1017SLang Hames 101fb82630aSLang Hames class EdgeEntry { 102c083578aSLang Hames public: EdgeEntry(NodeId N1Id,NodeId N2Id,MatrixPtr Costs)10318635828SLang Hames EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs) 10482de7d32SBenjamin Kramer : Costs(std::move(Costs)) { 105ff85ba12SLang Hames NIds[0] = N1Id; 106ff85ba12SLang Hames NIds[1] = N2Id; 107ff85ba12SLang Hames ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx(); 108ff85ba12SLang Hames ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx(); 109ff85ba12SLang Hames } 110ff85ba12SLang Hames connectToN(Graph & G,EdgeId ThisEdgeId,unsigned NIdx)111ff85ba12SLang Hames void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) { 112ff85ba12SLang Hames assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() && 113ff85ba12SLang Hames "Edge already connected to NIds[NIdx]."); 114ff85ba12SLang Hames NodeEntry &N = G.getNode(NIds[NIdx]); 115ff85ba12SLang Hames ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId); 116ff85ba12SLang Hames } 117ff85ba12SLang Hames connect(Graph & G,EdgeId ThisEdgeId)118ff85ba12SLang Hames void connect(Graph &G, EdgeId ThisEdgeId) { 119ff85ba12SLang Hames connectToN(G, ThisEdgeId, 0); 120ff85ba12SLang Hames connectToN(G, ThisEdgeId, 1); 121ff85ba12SLang Hames } 122ff85ba12SLang Hames setAdjEdgeIdx(NodeId NId,typename NodeEntry::AdjEdgeIdx NewIdx)123cacce82cSDavid Blaikie void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) { 124ff85ba12SLang Hames if (NId == NIds[0]) 125ff85ba12SLang Hames ThisEdgeAdjIdxs[0] = NewIdx; 126ff85ba12SLang Hames else { 127ff85ba12SLang Hames assert(NId == NIds[1] && "Edge not connected to NId"); 128ff85ba12SLang Hames ThisEdgeAdjIdxs[1] = NewIdx; 129ff85ba12SLang Hames } 130ff85ba12SLang Hames } 131ff85ba12SLang Hames disconnectFromN(Graph & G,unsigned NIdx)132ff85ba12SLang Hames void disconnectFromN(Graph &G, unsigned NIdx) { 133ff85ba12SLang Hames assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() && 134ff85ba12SLang Hames "Edge not connected to NIds[NIdx]."); 135ff85ba12SLang Hames NodeEntry &N = G.getNode(NIds[NIdx]); 1365391ac47SLang Hames N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]); 137ff85ba12SLang Hames ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx(); 138ff85ba12SLang Hames } 139ff85ba12SLang Hames disconnectFrom(Graph & G,NodeId NId)140ff85ba12SLang Hames void disconnectFrom(Graph &G, NodeId NId) { 141ff85ba12SLang Hames if (NId == NIds[0]) 142ff85ba12SLang Hames disconnectFromN(G, 0); 143ff85ba12SLang Hames else { 144ff85ba12SLang Hames assert(NId == NIds[1] && "Edge does not connect NId"); 145ff85ba12SLang Hames disconnectFromN(G, 1); 146ff85ba12SLang Hames } 147ff85ba12SLang Hames } 148ff85ba12SLang Hames getN1Id()149ff85ba12SLang Hames NodeId getN1Id() const { return NIds[0]; } getN2Id()150ff85ba12SLang Hames NodeId getN2Id() const { return NIds[1]; } 1517ea69237SEugene Zelenko 15218635828SLang Hames MatrixPtr Costs; 15318635828SLang Hames EdgeMetadata Metadata; 1547ea69237SEugene Zelenko 15518635828SLang Hames private: 156ff85ba12SLang Hames NodeId NIds[2]; 157ff85ba12SLang Hames typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2]; 158cb1e1017SLang Hames }; 159cb1e1017SLang Hames 160cb1e1017SLang Hames // ----- MEMBERS ----- 161cb1e1017SLang Hames 16257a28ce3SLang Hames GraphMetadata Metadata; 16318635828SLang Hames CostAllocator CostAlloc; 1647ea69237SEugene Zelenko SolverT *Solver = nullptr; 16518635828SLang Hames 1667ea69237SEugene Zelenko using NodeVector = std::vector<NodeEntry>; 1677ea69237SEugene Zelenko using FreeNodeVector = std::vector<NodeId>; 16818635828SLang Hames NodeVector Nodes; 16918635828SLang Hames FreeNodeVector FreeNodeIds; 170cb1e1017SLang Hames 1717ea69237SEugene Zelenko using EdgeVector = std::vector<EdgeEntry>; 1727ea69237SEugene Zelenko using FreeEdgeVector = std::vector<EdgeId>; 17318635828SLang Hames EdgeVector Edges; 17418635828SLang Hames FreeEdgeVector FreeEdgeIds; 175cb1e1017SLang Hames Graph(const Graph & Other)1767ea69237SEugene Zelenko Graph(const Graph &Other) {} 1777ea69237SEugene Zelenko 178cb1e1017SLang Hames // ----- INTERNAL METHODS ----- 179cb1e1017SLang Hames getNode(NodeId NId)1800dea74b0SArnaud A. de Grandmaison NodeEntry &getNode(NodeId NId) { 1810dea74b0SArnaud A. de Grandmaison assert(NId < Nodes.size() && "Out of bound NodeId"); 1820dea74b0SArnaud A. de Grandmaison return Nodes[NId]; 1830dea74b0SArnaud A. de Grandmaison } getNode(NodeId NId)1840dea74b0SArnaud A. de Grandmaison const NodeEntry &getNode(NodeId NId) const { 1850dea74b0SArnaud A. de Grandmaison assert(NId < Nodes.size() && "Out of bound NodeId"); 1860dea74b0SArnaud A. de Grandmaison return Nodes[NId]; 1870dea74b0SArnaud A. de Grandmaison } 188cb1e1017SLang Hames getEdge(EdgeId EId)18918635828SLang Hames EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; } getEdge(EdgeId EId)19018635828SLang Hames const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; } 191cb1e1017SLang Hames addConstructedNode(NodeEntry N)1928f31f448SLang Hames NodeId addConstructedNode(NodeEntry N) { 19318635828SLang Hames NodeId NId = 0; 19418635828SLang Hames if (!FreeNodeIds.empty()) { 19518635828SLang Hames NId = FreeNodeIds.back(); 19618635828SLang Hames FreeNodeIds.pop_back(); 19718635828SLang Hames Nodes[NId] = std::move(N); 198fb82630aSLang Hames } else { 19918635828SLang Hames NId = Nodes.size(); 20018635828SLang Hames Nodes.push_back(std::move(N)); 201fb82630aSLang Hames } 20218635828SLang Hames return NId; 203cb1e1017SLang Hames } 204cb1e1017SLang Hames addConstructedEdge(EdgeEntry E)2058f31f448SLang Hames EdgeId addConstructedEdge(EdgeEntry E) { 20618635828SLang Hames assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() && 207cb1e1017SLang Hames "Attempt to add duplicate edge."); 20818635828SLang Hames EdgeId EId = 0; 20918635828SLang Hames if (!FreeEdgeIds.empty()) { 21018635828SLang Hames EId = FreeEdgeIds.back(); 21118635828SLang Hames FreeEdgeIds.pop_back(); 21218635828SLang Hames Edges[EId] = std::move(E); 213fb82630aSLang Hames } else { 21418635828SLang Hames EId = Edges.size(); 21518635828SLang Hames Edges.push_back(std::move(E)); 216fb82630aSLang Hames } 217fb82630aSLang Hames 21818635828SLang Hames EdgeEntry &NE = getEdge(EId); 219fb82630aSLang Hames 220ff85ba12SLang Hames // Add the edge to the adjacency sets of its nodes. 221ff85ba12SLang Hames NE.connect(*this, EId); 22218635828SLang Hames return EId; 223cb1e1017SLang Hames } 224cb1e1017SLang Hames 22518635828SLang Hames void operator=(const Graph &Other) {} 226fb82630aSLang Hames 227cb1e1017SLang Hames public: 2287ea69237SEugene Zelenko using AdjEdgeItr = typename NodeEntry::AdjEdgeItr; 22918635828SLang Hames 230fb82630aSLang Hames class NodeItr { 231fb82630aSLang Hames public: 2327ea69237SEugene Zelenko using iterator_category = std::forward_iterator_tag; 2337ea69237SEugene Zelenko using value_type = NodeId; 2347ea69237SEugene Zelenko using difference_type = int; 2357ea69237SEugene Zelenko using pointer = NodeId *; 2367ea69237SEugene Zelenko using reference = NodeId &; 2378f31f448SLang Hames NodeItr(NodeId CurNId,const Graph & G)23818635828SLang Hames NodeItr(NodeId CurNId, const Graph &G) 23918635828SLang Hames : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) { 24018635828SLang Hames this->CurNId = findNextInUse(CurNId); // Move to first in-use node id 241fb82630aSLang Hames } 242fb82630aSLang Hames 24318635828SLang Hames bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; } 24418635828SLang Hames bool operator!=(const NodeItr &O) const { return !(*this == O); } 24518635828SLang Hames NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; } 24618635828SLang Hames NodeId operator*() const { return CurNId; } 247fb82630aSLang Hames 248fb82630aSLang Hames private: findNextInUse(NodeId NId)24918635828SLang Hames NodeId findNextInUse(NodeId NId) const { 2500d955d0bSDavid Majnemer while (NId < EndNId && is_contained(FreeNodeIds, NId)) { 25118635828SLang Hames ++NId; 252fb82630aSLang Hames } 25318635828SLang Hames return NId; 254fb82630aSLang Hames } 255fb82630aSLang Hames 25618635828SLang Hames NodeId CurNId, EndNId; 25718635828SLang Hames const FreeNodeVector &FreeNodeIds; 258fb82630aSLang Hames }; 259fb82630aSLang Hames 260fb82630aSLang Hames class EdgeItr { 261fb82630aSLang Hames public: EdgeItr(EdgeId CurEId,const Graph & G)26218635828SLang Hames EdgeItr(EdgeId CurEId, const Graph &G) 26318635828SLang Hames : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) { 26418635828SLang Hames this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id 265fb82630aSLang Hames } 266fb82630aSLang Hames 26718635828SLang Hames bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; } 26818635828SLang Hames bool operator!=(const EdgeItr &O) const { return !(*this == O); } 26918635828SLang Hames EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; } 27018635828SLang Hames EdgeId operator*() const { return CurEId; } 271fb82630aSLang Hames 272fb82630aSLang Hames private: findNextInUse(EdgeId EId)27318635828SLang Hames EdgeId findNextInUse(EdgeId EId) const { 2740d955d0bSDavid Majnemer while (EId < EndEId && is_contained(FreeEdgeIds, EId)) { 27518635828SLang Hames ++EId; 276fb82630aSLang Hames } 27718635828SLang Hames return EId; 278fb82630aSLang Hames } 279fb82630aSLang Hames 28018635828SLang Hames EdgeId CurEId, EndEId; 28118635828SLang Hames const FreeEdgeVector &FreeEdgeIds; 28218635828SLang Hames }; 28318635828SLang Hames 28418635828SLang Hames class NodeIdSet { 28518635828SLang Hames public: NodeIdSet(const Graph & G)28618635828SLang Hames NodeIdSet(const Graph &G) : G(G) {} 2877ea69237SEugene Zelenko begin()28818635828SLang Hames NodeItr begin() const { return NodeItr(0, G); } end()28918635828SLang Hames NodeItr end() const { return NodeItr(G.Nodes.size(), G); } 2907ea69237SEugene Zelenko empty()29118635828SLang Hames bool empty() const { return G.Nodes.empty(); } 2927ea69237SEugene Zelenko size()29318635828SLang Hames typename NodeVector::size_type size() const { 29418635828SLang Hames return G.Nodes.size() - G.FreeNodeIds.size(); 29518635828SLang Hames } 2967ea69237SEugene Zelenko 29718635828SLang Hames private: 29818635828SLang Hames const Graph& G; 29918635828SLang Hames }; 30018635828SLang Hames 30118635828SLang Hames class EdgeIdSet { 30218635828SLang Hames public: EdgeIdSet(const Graph & G)30318635828SLang Hames EdgeIdSet(const Graph &G) : G(G) {} 3047ea69237SEugene Zelenko begin()30518635828SLang Hames EdgeItr begin() const { return EdgeItr(0, G); } end()30618635828SLang Hames EdgeItr end() const { return EdgeItr(G.Edges.size(), G); } 3077ea69237SEugene Zelenko empty()30818635828SLang Hames bool empty() const { return G.Edges.empty(); } 3097ea69237SEugene Zelenko size()31018635828SLang Hames typename NodeVector::size_type size() const { 31118635828SLang Hames return G.Edges.size() - G.FreeEdgeIds.size(); 31218635828SLang Hames } 3137ea69237SEugene Zelenko 31418635828SLang Hames private: 31518635828SLang Hames const Graph& G; 31618635828SLang Hames }; 31718635828SLang Hames 31818635828SLang Hames class AdjEdgeIdSet { 31918635828SLang Hames public: AdjEdgeIdSet(const NodeEntry & NE)32018635828SLang Hames AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {} 3217ea69237SEugene Zelenko begin()32218635828SLang Hames typename NodeEntry::AdjEdgeItr begin() const { 323ff85ba12SLang Hames return NE.getAdjEdgeIds().begin(); 32418635828SLang Hames } 3257ea69237SEugene Zelenko end()32618635828SLang Hames typename NodeEntry::AdjEdgeItr end() const { 327ff85ba12SLang Hames return NE.getAdjEdgeIds().end(); 32818635828SLang Hames } 3297ea69237SEugene Zelenko empty()330ff85ba12SLang Hames bool empty() const { return NE.getAdjEdgeIds().empty(); } 3317ea69237SEugene Zelenko size()33218635828SLang Hames typename NodeEntry::AdjEdgeList::size_type size() const { 333ff85ba12SLang Hames return NE.getAdjEdgeIds().size(); 33418635828SLang Hames } 3357ea69237SEugene Zelenko 33618635828SLang Hames private: 33718635828SLang Hames const NodeEntry &NE; 338fb82630aSLang Hames }; 339fb82630aSLang Hames 3404dfcc4a7SAdrian Prantl /// Construct an empty PBQP graph. 3417ea69237SEugene Zelenko Graph() = default; 34218635828SLang Hames 3434dfcc4a7SAdrian Prantl /// Construct an empty PBQP graph with the given graph metadata. Graph(GraphMetadata Metadata)3447ea69237SEugene Zelenko Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {} 3458f31f448SLang Hames 3464dfcc4a7SAdrian Prantl /// Get a reference to the graph metadata. getMetadata()34757a28ce3SLang Hames GraphMetadata& getMetadata() { return Metadata; } 34857a28ce3SLang Hames 3494dfcc4a7SAdrian Prantl /// Get a const-reference to the graph metadata. getMetadata()35057a28ce3SLang Hames const GraphMetadata& getMetadata() const { return Metadata; } 35157a28ce3SLang Hames 3524dfcc4a7SAdrian Prantl /// Lock this graph to the given solver instance in preparation 35318635828SLang Hames /// for running the solver. This method will call solver.handleAddNode for 35418635828SLang Hames /// each node in the graph, and handleAddEdge for each edge, to give the 35518635828SLang Hames /// solver an opportunity to set up any requried metadata. setSolver(SolverT & S)35618635828SLang Hames void setSolver(SolverT &S) { 3578d399f87SCraig Topper assert(!Solver && "Solver already set. Call unsetSolver()."); 35818635828SLang Hames Solver = &S; 35918635828SLang Hames for (auto NId : nodeIds()) 36018635828SLang Hames Solver->handleAddNode(NId); 36118635828SLang Hames for (auto EId : edgeIds()) 36218635828SLang Hames Solver->handleAddEdge(EId); 36318635828SLang Hames } 36418635828SLang Hames 3654dfcc4a7SAdrian Prantl /// Release from solver instance. unsetSolver()36618635828SLang Hames void unsetSolver() { 3678d399f87SCraig Topper assert(Solver && "Solver not set."); 36818635828SLang Hames Solver = nullptr; 36918635828SLang Hames } 370cb1e1017SLang Hames 3714dfcc4a7SAdrian Prantl /// Add a node with the given costs. 37218635828SLang Hames /// @param Costs Cost vector for the new node. 373cb1e1017SLang Hames /// @return Node iterator for the added node. 37418635828SLang Hames template <typename OtherVectorT> addNode(OtherVectorT Costs)37518635828SLang Hames NodeId addNode(OtherVectorT Costs) { 37618635828SLang Hames // Get cost vector from the problem domain 37718635828SLang Hames VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 37818635828SLang Hames NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts)); 37918635828SLang Hames if (Solver) 38018635828SLang Hames Solver->handleAddNode(NId); 38118635828SLang Hames return NId; 382cb1e1017SLang Hames } 383cb1e1017SLang Hames 3844dfcc4a7SAdrian Prantl /// Add a node bypassing the cost allocator. 3855fe30ca5SLang Hames /// @param Costs Cost vector ptr for the new node (must be convertible to 3865fe30ca5SLang Hames /// VectorPtr). 3875fe30ca5SLang Hames /// @return Node iterator for the added node. 3885fe30ca5SLang Hames /// 3895fe30ca5SLang Hames /// This method allows for fast addition of a node whose costs don't need 3905fe30ca5SLang Hames /// to be passed through the cost allocator. The most common use case for 3915fe30ca5SLang Hames /// this is when duplicating costs from an existing node (when using a 3925fe30ca5SLang Hames /// pooling allocator). These have already been uniqued, so we can avoid 3935fe30ca5SLang Hames /// re-constructing and re-uniquing them by attaching them directly to the 3945fe30ca5SLang Hames /// new node. 3955fe30ca5SLang Hames template <typename OtherVectorPtrT> addNodeBypassingCostAllocator(OtherVectorPtrT Costs)3965fe30ca5SLang Hames NodeId addNodeBypassingCostAllocator(OtherVectorPtrT Costs) { 3975fe30ca5SLang Hames NodeId NId = addConstructedNode(NodeEntry(Costs)); 3985fe30ca5SLang Hames if (Solver) 3995fe30ca5SLang Hames Solver->handleAddNode(NId); 4005fe30ca5SLang Hames return NId; 4015fe30ca5SLang Hames } 4025fe30ca5SLang Hames 4034dfcc4a7SAdrian Prantl /// Add an edge between the given nodes with the given costs. 40418635828SLang Hames /// @param N1Id First node. 40518635828SLang Hames /// @param N2Id Second node. 4065fe30ca5SLang Hames /// @param Costs Cost matrix for new edge. 407cb1e1017SLang Hames /// @return Edge iterator for the added edge. 40818635828SLang Hames template <typename OtherVectorT> addEdge(NodeId N1Id,NodeId N2Id,OtherVectorT Costs)40918635828SLang Hames EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) { 41018635828SLang Hames assert(getNodeCosts(N1Id).getLength() == Costs.getRows() && 41118635828SLang Hames getNodeCosts(N2Id).getLength() == Costs.getCols() && 412cb1e1017SLang Hames "Matrix dimensions mismatch."); 41318635828SLang Hames // Get cost matrix from the problem domain. 41418635828SLang Hames MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 41518635828SLang Hames EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts)); 41618635828SLang Hames if (Solver) 41718635828SLang Hames Solver->handleAddEdge(EId); 41818635828SLang Hames return EId; 419cb1e1017SLang Hames } 420cb1e1017SLang Hames 4214dfcc4a7SAdrian Prantl /// Add an edge bypassing the cost allocator. 4225fe30ca5SLang Hames /// @param N1Id First node. 4235fe30ca5SLang Hames /// @param N2Id Second node. 4245fe30ca5SLang Hames /// @param Costs Cost matrix for new edge. 4255fe30ca5SLang Hames /// @return Edge iterator for the added edge. 4265fe30ca5SLang Hames /// 4275fe30ca5SLang Hames /// This method allows for fast addition of an edge whose costs don't need 4285fe30ca5SLang Hames /// to be passed through the cost allocator. The most common use case for 4295fe30ca5SLang Hames /// this is when duplicating costs from an existing edge (when using a 4305fe30ca5SLang Hames /// pooling allocator). These have already been uniqued, so we can avoid 4315fe30ca5SLang Hames /// re-constructing and re-uniquing them by attaching them directly to the 4325fe30ca5SLang Hames /// new edge. 4335fe30ca5SLang Hames template <typename OtherMatrixPtrT> addEdgeBypassingCostAllocator(NodeId N1Id,NodeId N2Id,OtherMatrixPtrT Costs)4345fe30ca5SLang Hames NodeId addEdgeBypassingCostAllocator(NodeId N1Id, NodeId N2Id, 4355fe30ca5SLang Hames OtherMatrixPtrT Costs) { 4365fe30ca5SLang Hames assert(getNodeCosts(N1Id).getLength() == Costs->getRows() && 4375fe30ca5SLang Hames getNodeCosts(N2Id).getLength() == Costs->getCols() && 4385fe30ca5SLang Hames "Matrix dimensions mismatch."); 4395fe30ca5SLang Hames // Get cost matrix from the problem domain. 4405fe30ca5SLang Hames EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs)); 4415fe30ca5SLang Hames if (Solver) 4425fe30ca5SLang Hames Solver->handleAddEdge(EId); 4435fe30ca5SLang Hames return EId; 4445fe30ca5SLang Hames } 4455fe30ca5SLang Hames 4464dfcc4a7SAdrian Prantl /// Returns true if the graph is empty. empty()44718635828SLang Hames bool empty() const { return NodeIdSet(*this).empty(); } 44818635828SLang Hames nodeIds()44918635828SLang Hames NodeIdSet nodeIds() const { return NodeIdSet(*this); } edgeIds()45018635828SLang Hames EdgeIdSet edgeIds() const { return EdgeIdSet(*this); } 45118635828SLang Hames adjEdgeIds(NodeId NId)45218635828SLang Hames AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); } 45318635828SLang Hames 4544dfcc4a7SAdrian Prantl /// Get the number of nodes in the graph. 455cb1e1017SLang Hames /// @return Number of nodes in the graph. getNumNodes()45618635828SLang Hames unsigned getNumNodes() const { return NodeIdSet(*this).size(); } 457cb1e1017SLang Hames 4584dfcc4a7SAdrian Prantl /// Get the number of edges in the graph. 459cb1e1017SLang Hames /// @return Number of edges in the graph. getNumEdges()46018635828SLang Hames unsigned getNumEdges() const { return EdgeIdSet(*this).size(); } 461cb1e1017SLang Hames 4624dfcc4a7SAdrian Prantl /// Set a node's cost vector. 46318635828SLang Hames /// @param NId Node to update. 46418635828SLang Hames /// @param Costs New costs to set. 46518635828SLang Hames template <typename OtherVectorT> setNodeCosts(NodeId NId,OtherVectorT Costs)46618635828SLang Hames void setNodeCosts(NodeId NId, OtherVectorT Costs) { 46718635828SLang Hames VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 46818635828SLang Hames if (Solver) 46918635828SLang Hames Solver->handleSetNodeCosts(NId, *AllocatedCosts); 47018635828SLang Hames getNode(NId).Costs = AllocatedCosts; 47118635828SLang Hames } 472cb1e1017SLang Hames 4734dfcc4a7SAdrian Prantl /// Get a VectorPtr to a node's cost vector. Rarely useful - use 4745fe30ca5SLang Hames /// getNodeCosts where possible. 4755fe30ca5SLang Hames /// @param NId Node id. 4765fe30ca5SLang Hames /// @return VectorPtr to node cost vector. 4775fe30ca5SLang Hames /// 4785fe30ca5SLang Hames /// This method is primarily useful for duplicating costs quickly by 4795fe30ca5SLang Hames /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer 4805fe30ca5SLang Hames /// getNodeCosts when dealing with node cost values. getNodeCostsPtr(NodeId NId)4815fe30ca5SLang Hames const VectorPtr& getNodeCostsPtr(NodeId NId) const { 4825fe30ca5SLang Hames return getNode(NId).Costs; 4835fe30ca5SLang Hames } 4845fe30ca5SLang Hames 4854dfcc4a7SAdrian Prantl /// Get a node's cost vector. 48618635828SLang Hames /// @param NId Node id. 487cb1e1017SLang Hames /// @return Node cost vector. getNodeCosts(NodeId NId)4885fe30ca5SLang Hames const Vector& getNodeCosts(NodeId NId) const { 4895fe30ca5SLang Hames return *getNodeCostsPtr(NId); 4905fe30ca5SLang Hames } 491cb1e1017SLang Hames getNodeMetadata(NodeId NId)49218635828SLang Hames NodeMetadata& getNodeMetadata(NodeId NId) { 49318635828SLang Hames return getNode(NId).Metadata; 49418635828SLang Hames } 495cb1e1017SLang Hames getNodeMetadata(NodeId NId)49618635828SLang Hames const NodeMetadata& getNodeMetadata(NodeId NId) const { 49718635828SLang Hames return getNode(NId).Metadata; 49818635828SLang Hames } 499cb1e1017SLang Hames getNodeDegree(NodeId NId)50018635828SLang Hames typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const { 501ff85ba12SLang Hames return getNode(NId).getAdjEdgeIds().size(); 50218635828SLang Hames } 50318635828SLang Hames 5044dfcc4a7SAdrian Prantl /// Update an edge's cost matrix. 50518635828SLang Hames /// @param EId Edge id. 50618635828SLang Hames /// @param Costs New cost matrix. 50718635828SLang Hames template <typename OtherMatrixT> updateEdgeCosts(EdgeId EId,OtherMatrixT Costs)508de79026dSArnaud A. de Grandmaison void updateEdgeCosts(EdgeId EId, OtherMatrixT Costs) { 50918635828SLang Hames MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 51018635828SLang Hames if (Solver) 511de79026dSArnaud A. de Grandmaison Solver->handleUpdateCosts(EId, *AllocatedCosts); 51218635828SLang Hames getEdge(EId).Costs = AllocatedCosts; 51318635828SLang Hames } 514cb1e1017SLang Hames 5154dfcc4a7SAdrian Prantl /// Get a MatrixPtr to a node's cost matrix. Rarely useful - use 5165fe30ca5SLang Hames /// getEdgeCosts where possible. 5175fe30ca5SLang Hames /// @param EId Edge id. 5185fe30ca5SLang Hames /// @return MatrixPtr to edge cost matrix. 5195fe30ca5SLang Hames /// 5205fe30ca5SLang Hames /// This method is primarily useful for duplicating costs quickly by 5215fe30ca5SLang Hames /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer 5225fe30ca5SLang Hames /// getEdgeCosts when dealing with edge cost values. getEdgeCostsPtr(EdgeId EId)5235fe30ca5SLang Hames const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const { 5245fe30ca5SLang Hames return getEdge(EId).Costs; 5255fe30ca5SLang Hames } 5265fe30ca5SLang Hames 5274dfcc4a7SAdrian Prantl /// Get an edge's cost matrix. 52818635828SLang Hames /// @param EId Edge id. 529cb1e1017SLang Hames /// @return Edge cost matrix. getEdgeCosts(EdgeId EId)5308f31f448SLang Hames const Matrix& getEdgeCosts(EdgeId EId) const { 5318f31f448SLang Hames return *getEdge(EId).Costs; 5328f31f448SLang Hames } 53318635828SLang Hames getEdgeMetadata(EdgeId EId)5345fe30ca5SLang Hames EdgeMetadata& getEdgeMetadata(EdgeId EId) { 5355fe30ca5SLang Hames return getEdge(EId).Metadata; 536cb1e1017SLang Hames } 537cb1e1017SLang Hames getEdgeMetadata(EdgeId EId)5385fe30ca5SLang Hames const EdgeMetadata& getEdgeMetadata(EdgeId EId) const { 5395fe30ca5SLang Hames return getEdge(EId).Metadata; 540cb1e1017SLang Hames } 541cb1e1017SLang Hames 5424dfcc4a7SAdrian Prantl /// Get the first node connected to this edge. 54318635828SLang Hames /// @param EId Edge id. 544cb1e1017SLang Hames /// @return The first node connected to the given edge. getEdgeNode1Id(EdgeId EId)5451f4448adSArnaud A. de Grandmaison NodeId getEdgeNode1Id(EdgeId EId) const { 54618635828SLang Hames return getEdge(EId).getN1Id(); 547cb1e1017SLang Hames } 548cb1e1017SLang Hames 5494dfcc4a7SAdrian Prantl /// Get the second node connected to this edge. 55018635828SLang Hames /// @param EId Edge id. 551cb1e1017SLang Hames /// @return The second node connected to the given edge. getEdgeNode2Id(EdgeId EId)5521f4448adSArnaud A. de Grandmaison NodeId getEdgeNode2Id(EdgeId EId) const { 55318635828SLang Hames return getEdge(EId).getN2Id(); 554cb1e1017SLang Hames } 555cb1e1017SLang Hames 5564dfcc4a7SAdrian Prantl /// Get the "other" node connected to this edge. 55718635828SLang Hames /// @param EId Edge id. 55818635828SLang Hames /// @param NId Node id for the "given" node. 559cb1e1017SLang Hames /// @return The iterator for the "other" node connected to this edge. getEdgeOtherNodeId(EdgeId EId,NodeId NId)56018635828SLang Hames NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) { 56118635828SLang Hames EdgeEntry &E = getEdge(EId); 56218635828SLang Hames if (E.getN1Id() == NId) { 56318635828SLang Hames return E.getN2Id(); 564cb1e1017SLang Hames } // else 56518635828SLang Hames return E.getN1Id(); 566cb1e1017SLang Hames } 567cb1e1017SLang Hames 5684dfcc4a7SAdrian Prantl /// Get the edge connecting two nodes. 56918635828SLang Hames /// @param N1Id First node id. 57018635828SLang Hames /// @param N2Id Second node id. 57118635828SLang Hames /// @return An id for edge (N1Id, N2Id) if such an edge exists, 572fb82630aSLang Hames /// otherwise returns an invalid edge id. findEdge(NodeId N1Id,NodeId N2Id)57318635828SLang Hames EdgeId findEdge(NodeId N1Id, NodeId N2Id) { 57418635828SLang Hames for (auto AEId : adjEdgeIds(N1Id)) { 57518635828SLang Hames if ((getEdgeNode1Id(AEId) == N2Id) || 57618635828SLang Hames (getEdgeNode2Id(AEId) == N2Id)) { 57718635828SLang Hames return AEId; 578cb1e1017SLang Hames } 579cb1e1017SLang Hames } 580fb82630aSLang Hames return invalidEdgeId(); 581cb1e1017SLang Hames } 582cb1e1017SLang Hames 5834dfcc4a7SAdrian Prantl /// Remove a node from the graph. 58418635828SLang Hames /// @param NId Node id. removeNode(NodeId NId)58518635828SLang Hames void removeNode(NodeId NId) { 58618635828SLang Hames if (Solver) 58718635828SLang Hames Solver->handleRemoveNode(NId); 58818635828SLang Hames NodeEntry &N = getNode(NId); 58918635828SLang Hames // TODO: Can this be for-each'd? 59018635828SLang Hames for (AdjEdgeItr AEItr = N.adjEdgesBegin(), 59118635828SLang Hames AEEnd = N.adjEdgesEnd(); 59218635828SLang Hames AEItr != AEEnd;) { 59318635828SLang Hames EdgeId EId = *AEItr; 59418635828SLang Hames ++AEItr; 59518635828SLang Hames removeEdge(EId); 596cb1e1017SLang Hames } 59718635828SLang Hames FreeNodeIds.push_back(NId); 59818635828SLang Hames } 59918635828SLang Hames 6004dfcc4a7SAdrian Prantl /// Disconnect an edge from the given node. 60118635828SLang Hames /// 60218635828SLang Hames /// Removes the given edge from the adjacency list of the given node. 60318635828SLang Hames /// This operation leaves the edge in an 'asymmetric' state: It will no 60418635828SLang Hames /// longer appear in an iteration over the given node's (NId's) edges, but 60518635828SLang Hames /// will appear in an iteration over the 'other', unnamed node's edges. 60618635828SLang Hames /// 60718635828SLang Hames /// This does not correspond to any normal graph operation, but exists to 60818635828SLang Hames /// support efficient PBQP graph-reduction based solvers. It is used to 60918635828SLang Hames /// 'effectively' remove the unnamed node from the graph while the solver 61018635828SLang Hames /// is performing the reduction. The solver will later call reconnectNode 61118635828SLang Hames /// to restore the edge in the named node's adjacency list. 61218635828SLang Hames /// 61318635828SLang Hames /// Since the degree of a node is the number of connected edges, 61418635828SLang Hames /// disconnecting an edge from a node 'u' will cause the degree of 'u' to 61518635828SLang Hames /// drop by 1. 61618635828SLang Hames /// 61718635828SLang Hames /// A disconnected edge WILL still appear in an iteration over the graph 61818635828SLang Hames /// edges. 61918635828SLang Hames /// 62018635828SLang Hames /// A disconnected edge should not be removed from the graph, it should be 62118635828SLang Hames /// reconnected first. 62218635828SLang Hames /// 62318635828SLang Hames /// A disconnected edge can be reconnected by calling the reconnectEdge 62418635828SLang Hames /// method. disconnectEdge(EdgeId EId,NodeId NId)62518635828SLang Hames void disconnectEdge(EdgeId EId, NodeId NId) { 62618635828SLang Hames if (Solver) 62718635828SLang Hames Solver->handleDisconnectEdge(EId, NId); 628ff85ba12SLang Hames 629ff85ba12SLang Hames EdgeEntry &E = getEdge(EId); 630ff85ba12SLang Hames E.disconnectFrom(*this, NId); 63118635828SLang Hames } 63218635828SLang Hames 6334dfcc4a7SAdrian Prantl /// Convenience method to disconnect all neighbours from the given 63418635828SLang Hames /// node. disconnectAllNeighborsFromNode(NodeId NId)63518635828SLang Hames void disconnectAllNeighborsFromNode(NodeId NId) { 63618635828SLang Hames for (auto AEId : adjEdgeIds(NId)) 63718635828SLang Hames disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId)); 63818635828SLang Hames } 63918635828SLang Hames 6404dfcc4a7SAdrian Prantl /// Re-attach an edge to its nodes. 64118635828SLang Hames /// 64218635828SLang Hames /// Adds an edge that had been previously disconnected back into the 64318635828SLang Hames /// adjacency set of the nodes that the edge connects. reconnectEdge(EdgeId EId,NodeId NId)64418635828SLang Hames void reconnectEdge(EdgeId EId, NodeId NId) { 645ff85ba12SLang Hames EdgeEntry &E = getEdge(EId); 646ff85ba12SLang Hames E.connectTo(*this, EId, NId); 64718635828SLang Hames if (Solver) 64818635828SLang Hames Solver->handleReconnectEdge(EId, NId); 649cb1e1017SLang Hames } 650cb1e1017SLang Hames 6514dfcc4a7SAdrian Prantl /// Remove an edge from the graph. 65218635828SLang Hames /// @param EId Edge id. removeEdge(EdgeId EId)65318635828SLang Hames void removeEdge(EdgeId EId) { 65418635828SLang Hames if (Solver) 65518635828SLang Hames Solver->handleRemoveEdge(EId); 65618635828SLang Hames EdgeEntry &E = getEdge(EId); 657ff85ba12SLang Hames E.disconnect(); 65818635828SLang Hames FreeEdgeIds.push_back(EId); 65918635828SLang Hames Edges[EId].invalidate(); 660cb1e1017SLang Hames } 661cb1e1017SLang Hames 6624dfcc4a7SAdrian Prantl /// Remove all nodes and edges from the graph. clear()663cb1e1017SLang Hames void clear() { 66418635828SLang Hames Nodes.clear(); 66518635828SLang Hames FreeNodeIds.clear(); 66618635828SLang Hames Edges.clear(); 66718635828SLang Hames FreeEdgeIds.clear(); 668cb1e1017SLang Hames } 669cb1e1017SLang Hames }; 670cb1e1017SLang Hames 6717ea69237SEugene Zelenko } // end namespace PBQP 6727ea69237SEugene Zelenko } // end namespace llvm 673cb1e1017SLang Hames 674*aa5c09beSKazu Hirata #endif // LLVM_CODEGEN_PBQP_GRAPH_H 675