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