File indexing completed on 2026-05-10 08:43:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_CODEGEN_PBQP_GRAPH_H
0014 #define LLVM_CODEGEN_PBQP_GRAPH_H
0015
0016 #include "llvm/ADT/STLExtras.h"
0017 #include <algorithm>
0018 #include <cassert>
0019 #include <iterator>
0020 #include <limits>
0021 #include <vector>
0022
0023 namespace llvm {
0024 namespace PBQP {
0025
0026 class GraphBase {
0027 public:
0028 using NodeId = unsigned;
0029 using EdgeId = unsigned;
0030
0031
0032 static NodeId invalidNodeId() {
0033 return std::numeric_limits<NodeId>::max();
0034 }
0035
0036
0037 static EdgeId invalidEdgeId() {
0038 return std::numeric_limits<EdgeId>::max();
0039 }
0040 };
0041
0042
0043
0044
0045 template <typename SolverT>
0046 class Graph : public GraphBase {
0047 private:
0048 using CostAllocator = typename SolverT::CostAllocator;
0049
0050 public:
0051 using RawVector = typename SolverT::RawVector;
0052 using RawMatrix = typename SolverT::RawMatrix;
0053 using Vector = typename SolverT::Vector;
0054 using Matrix = typename SolverT::Matrix;
0055 using VectorPtr = typename CostAllocator::VectorPtr;
0056 using MatrixPtr = typename CostAllocator::MatrixPtr;
0057 using NodeMetadata = typename SolverT::NodeMetadata;
0058 using EdgeMetadata = typename SolverT::EdgeMetadata;
0059 using GraphMetadata = typename SolverT::GraphMetadata;
0060
0061 private:
0062 class NodeEntry {
0063 public:
0064 using AdjEdgeList = std::vector<EdgeId>;
0065 using AdjEdgeIdx = AdjEdgeList::size_type;
0066 using AdjEdgeItr = AdjEdgeList::const_iterator;
0067
0068 NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
0069
0070 static AdjEdgeIdx getInvalidAdjEdgeIdx() {
0071 return std::numeric_limits<AdjEdgeIdx>::max();
0072 }
0073
0074 AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
0075 AdjEdgeIdx Idx = AdjEdgeIds.size();
0076 AdjEdgeIds.push_back(EId);
0077 return Idx;
0078 }
0079
0080 void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) {
0081
0082
0083
0084
0085
0086
0087 G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx);
0088 AdjEdgeIds[Idx] = AdjEdgeIds.back();
0089 AdjEdgeIds.pop_back();
0090 }
0091
0092 const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; }
0093
0094 VectorPtr Costs;
0095 NodeMetadata Metadata;
0096
0097 private:
0098 AdjEdgeList AdjEdgeIds;
0099 };
0100
0101 class EdgeEntry {
0102 public:
0103 EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs)
0104 : Costs(std::move(Costs)) {
0105 NIds[0] = N1Id;
0106 NIds[1] = N2Id;
0107 ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx();
0108 ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx();
0109 }
0110
0111 void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) {
0112 assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() &&
0113 "Edge already connected to NIds[NIdx].");
0114 NodeEntry &N = G.getNode(NIds[NIdx]);
0115 ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId);
0116 }
0117
0118 void connect(Graph &G, EdgeId ThisEdgeId) {
0119 connectToN(G, ThisEdgeId, 0);
0120 connectToN(G, ThisEdgeId, 1);
0121 }
0122
0123 void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) {
0124 if (NId == NIds[0])
0125 ThisEdgeAdjIdxs[0] = NewIdx;
0126 else {
0127 assert(NId == NIds[1] && "Edge not connected to NId");
0128 ThisEdgeAdjIdxs[1] = NewIdx;
0129 }
0130 }
0131
0132 void disconnectFromN(Graph &G, unsigned NIdx) {
0133 assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() &&
0134 "Edge not connected to NIds[NIdx].");
0135 NodeEntry &N = G.getNode(NIds[NIdx]);
0136 N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]);
0137 ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx();
0138 }
0139
0140 void disconnectFrom(Graph &G, NodeId NId) {
0141 if (NId == NIds[0])
0142 disconnectFromN(G, 0);
0143 else {
0144 assert(NId == NIds[1] && "Edge does not connect NId");
0145 disconnectFromN(G, 1);
0146 }
0147 }
0148
0149 NodeId getN1Id() const { return NIds[0]; }
0150 NodeId getN2Id() const { return NIds[1]; }
0151
0152 MatrixPtr Costs;
0153 EdgeMetadata Metadata;
0154
0155 private:
0156 NodeId NIds[2];
0157 typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
0158 };
0159
0160
0161
0162 GraphMetadata Metadata;
0163 CostAllocator CostAlloc;
0164 SolverT *Solver = nullptr;
0165
0166 using NodeVector = std::vector<NodeEntry>;
0167 using FreeNodeVector = std::vector<NodeId>;
0168 NodeVector Nodes;
0169 FreeNodeVector FreeNodeIds;
0170
0171 using EdgeVector = std::vector<EdgeEntry>;
0172 using FreeEdgeVector = std::vector<EdgeId>;
0173 EdgeVector Edges;
0174 FreeEdgeVector FreeEdgeIds;
0175
0176 Graph(const Graph &Other) {}
0177
0178
0179
0180 NodeEntry &getNode(NodeId NId) {
0181 assert(NId < Nodes.size() && "Out of bound NodeId");
0182 return Nodes[NId];
0183 }
0184 const NodeEntry &getNode(NodeId NId) const {
0185 assert(NId < Nodes.size() && "Out of bound NodeId");
0186 return Nodes[NId];
0187 }
0188
0189 EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
0190 const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
0191
0192 NodeId addConstructedNode(NodeEntry N) {
0193 NodeId NId = 0;
0194 if (!FreeNodeIds.empty()) {
0195 NId = FreeNodeIds.back();
0196 FreeNodeIds.pop_back();
0197 Nodes[NId] = std::move(N);
0198 } else {
0199 NId = Nodes.size();
0200 Nodes.push_back(std::move(N));
0201 }
0202 return NId;
0203 }
0204
0205 EdgeId addConstructedEdge(EdgeEntry E) {
0206 assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
0207 "Attempt to add duplicate edge.");
0208 EdgeId EId = 0;
0209 if (!FreeEdgeIds.empty()) {
0210 EId = FreeEdgeIds.back();
0211 FreeEdgeIds.pop_back();
0212 Edges[EId] = std::move(E);
0213 } else {
0214 EId = Edges.size();
0215 Edges.push_back(std::move(E));
0216 }
0217
0218 EdgeEntry &NE = getEdge(EId);
0219
0220
0221 NE.connect(*this, EId);
0222 return EId;
0223 }
0224
0225 void operator=(const Graph &Other) {}
0226
0227 public:
0228 using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
0229
0230 class NodeItr {
0231 public:
0232 using iterator_category = std::forward_iterator_tag;
0233 using value_type = NodeId;
0234 using difference_type = int;
0235 using pointer = NodeId *;
0236 using reference = NodeId &;
0237
0238 NodeItr(NodeId CurNId, const Graph &G)
0239 : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
0240 this->CurNId = findNextInUse(CurNId);
0241 }
0242
0243 bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; }
0244 bool operator!=(const NodeItr &O) const { return !(*this == O); }
0245 NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; }
0246 NodeId operator*() const { return CurNId; }
0247
0248 private:
0249 NodeId findNextInUse(NodeId NId) const {
0250 while (NId < EndNId && is_contained(FreeNodeIds, NId)) {
0251 ++NId;
0252 }
0253 return NId;
0254 }
0255
0256 NodeId CurNId, EndNId;
0257 const FreeNodeVector &FreeNodeIds;
0258 };
0259
0260 class EdgeItr {
0261 public:
0262 EdgeItr(EdgeId CurEId, const Graph &G)
0263 : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) {
0264 this->CurEId = findNextInUse(CurEId);
0265 }
0266
0267 bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; }
0268 bool operator!=(const EdgeItr &O) const { return !(*this == O); }
0269 EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; }
0270 EdgeId operator*() const { return CurEId; }
0271
0272 private:
0273 EdgeId findNextInUse(EdgeId EId) const {
0274 while (EId < EndEId && is_contained(FreeEdgeIds, EId)) {
0275 ++EId;
0276 }
0277 return EId;
0278 }
0279
0280 EdgeId CurEId, EndEId;
0281 const FreeEdgeVector &FreeEdgeIds;
0282 };
0283
0284 class NodeIdSet {
0285 public:
0286 NodeIdSet(const Graph &G) : G(G) {}
0287
0288 NodeItr begin() const { return NodeItr(0, G); }
0289 NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
0290
0291 bool empty() const { return G.Nodes.empty(); }
0292
0293 typename NodeVector::size_type size() const {
0294 return G.Nodes.size() - G.FreeNodeIds.size();
0295 }
0296
0297 private:
0298 const Graph& G;
0299 };
0300
0301 class EdgeIdSet {
0302 public:
0303 EdgeIdSet(const Graph &G) : G(G) {}
0304
0305 EdgeItr begin() const { return EdgeItr(0, G); }
0306 EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
0307
0308 bool empty() const { return G.Edges.empty(); }
0309
0310 typename NodeVector::size_type size() const {
0311 return G.Edges.size() - G.FreeEdgeIds.size();
0312 }
0313
0314 private:
0315 const Graph& G;
0316 };
0317
0318 class AdjEdgeIdSet {
0319 public:
0320 AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
0321
0322 typename NodeEntry::AdjEdgeItr begin() const {
0323 return NE.getAdjEdgeIds().begin();
0324 }
0325
0326 typename NodeEntry::AdjEdgeItr end() const {
0327 return NE.getAdjEdgeIds().end();
0328 }
0329
0330 bool empty() const { return NE.getAdjEdgeIds().empty(); }
0331
0332 typename NodeEntry::AdjEdgeList::size_type size() const {
0333 return NE.getAdjEdgeIds().size();
0334 }
0335
0336 private:
0337 const NodeEntry &NE;
0338 };
0339
0340
0341 Graph() = default;
0342
0343
0344 Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
0345
0346
0347 GraphMetadata& getMetadata() { return Metadata; }
0348
0349
0350 const GraphMetadata& getMetadata() const { return Metadata; }
0351
0352
0353
0354
0355
0356 void setSolver(SolverT &S) {
0357 assert(!Solver && "Solver already set. Call unsetSolver().");
0358 Solver = &S;
0359 for (auto NId : nodeIds())
0360 Solver->handleAddNode(NId);
0361 for (auto EId : edgeIds())
0362 Solver->handleAddEdge(EId);
0363 }
0364
0365
0366 void unsetSolver() {
0367 assert(Solver && "Solver not set.");
0368 Solver = nullptr;
0369 }
0370
0371
0372
0373
0374 template <typename OtherVectorT>
0375 NodeId addNode(OtherVectorT Costs) {
0376
0377 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
0378 NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts));
0379 if (Solver)
0380 Solver->handleAddNode(NId);
0381 return NId;
0382 }
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395 template <typename OtherVectorPtrT>
0396 NodeId addNodeBypassingCostAllocator(OtherVectorPtrT Costs) {
0397 NodeId NId = addConstructedNode(NodeEntry(Costs));
0398 if (Solver)
0399 Solver->handleAddNode(NId);
0400 return NId;
0401 }
0402
0403
0404
0405
0406
0407
0408 template <typename OtherVectorT>
0409 EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
0410 assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
0411 getNodeCosts(N2Id).getLength() == Costs.getCols() &&
0412 "Matrix dimensions mismatch.");
0413
0414 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
0415 EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts));
0416 if (Solver)
0417 Solver->handleAddEdge(EId);
0418 return EId;
0419 }
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433 template <typename OtherMatrixPtrT>
0434 NodeId addEdgeBypassingCostAllocator(NodeId N1Id, NodeId N2Id,
0435 OtherMatrixPtrT Costs) {
0436 assert(getNodeCosts(N1Id).getLength() == Costs->getRows() &&
0437 getNodeCosts(N2Id).getLength() == Costs->getCols() &&
0438 "Matrix dimensions mismatch.");
0439
0440 EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs));
0441 if (Solver)
0442 Solver->handleAddEdge(EId);
0443 return EId;
0444 }
0445
0446
0447 bool empty() const { return NodeIdSet(*this).empty(); }
0448
0449 NodeIdSet nodeIds() const { return NodeIdSet(*this); }
0450 EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
0451
0452 AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
0453
0454
0455
0456 unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
0457
0458
0459
0460 unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
0461
0462
0463
0464
0465 template <typename OtherVectorT>
0466 void setNodeCosts(NodeId NId, OtherVectorT Costs) {
0467 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
0468 if (Solver)
0469 Solver->handleSetNodeCosts(NId, *AllocatedCosts);
0470 getNode(NId).Costs = AllocatedCosts;
0471 }
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 const VectorPtr& getNodeCostsPtr(NodeId NId) const {
0482 return getNode(NId).Costs;
0483 }
0484
0485
0486
0487
0488 const Vector& getNodeCosts(NodeId NId) const {
0489 return *getNodeCostsPtr(NId);
0490 }
0491
0492 NodeMetadata& getNodeMetadata(NodeId NId) {
0493 return getNode(NId).Metadata;
0494 }
0495
0496 const NodeMetadata& getNodeMetadata(NodeId NId) const {
0497 return getNode(NId).Metadata;
0498 }
0499
0500 typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
0501 return getNode(NId).getAdjEdgeIds().size();
0502 }
0503
0504
0505
0506
0507 template <typename OtherMatrixT>
0508 void updateEdgeCosts(EdgeId EId, OtherMatrixT Costs) {
0509 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
0510 if (Solver)
0511 Solver->handleUpdateCosts(EId, *AllocatedCosts);
0512 getEdge(EId).Costs = AllocatedCosts;
0513 }
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const {
0524 return getEdge(EId).Costs;
0525 }
0526
0527
0528
0529
0530 const Matrix& getEdgeCosts(EdgeId EId) const {
0531 return *getEdge(EId).Costs;
0532 }
0533
0534 EdgeMetadata& getEdgeMetadata(EdgeId EId) {
0535 return getEdge(EId).Metadata;
0536 }
0537
0538 const EdgeMetadata& getEdgeMetadata(EdgeId EId) const {
0539 return getEdge(EId).Metadata;
0540 }
0541
0542
0543
0544
0545 NodeId getEdgeNode1Id(EdgeId EId) const {
0546 return getEdge(EId).getN1Id();
0547 }
0548
0549
0550
0551
0552 NodeId getEdgeNode2Id(EdgeId EId) const {
0553 return getEdge(EId).getN2Id();
0554 }
0555
0556
0557
0558
0559
0560 NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
0561 EdgeEntry &E = getEdge(EId);
0562 if (E.getN1Id() == NId) {
0563 return E.getN2Id();
0564 }
0565 return E.getN1Id();
0566 }
0567
0568
0569
0570
0571
0572
0573 EdgeId findEdge(NodeId N1Id, NodeId N2Id) {
0574 for (auto AEId : adjEdgeIds(N1Id)) {
0575 if ((getEdgeNode1Id(AEId) == N2Id) ||
0576 (getEdgeNode2Id(AEId) == N2Id)) {
0577 return AEId;
0578 }
0579 }
0580 return invalidEdgeId();
0581 }
0582
0583
0584
0585 void removeNode(NodeId NId) {
0586 if (Solver)
0587 Solver->handleRemoveNode(NId);
0588 NodeEntry &N = getNode(NId);
0589
0590 for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
0591 AEEnd = N.adjEdgesEnd();
0592 AEItr != AEEnd;) {
0593 EdgeId EId = *AEItr;
0594 ++AEItr;
0595 removeEdge(EId);
0596 }
0597 FreeNodeIds.push_back(NId);
0598 }
0599
0600
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625 void disconnectEdge(EdgeId EId, NodeId NId) {
0626 if (Solver)
0627 Solver->handleDisconnectEdge(EId, NId);
0628
0629 EdgeEntry &E = getEdge(EId);
0630 E.disconnectFrom(*this, NId);
0631 }
0632
0633
0634
0635 void disconnectAllNeighborsFromNode(NodeId NId) {
0636 for (auto AEId : adjEdgeIds(NId))
0637 disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
0638 }
0639
0640
0641
0642
0643
0644 void reconnectEdge(EdgeId EId, NodeId NId) {
0645 EdgeEntry &E = getEdge(EId);
0646 E.connectTo(*this, EId, NId);
0647 if (Solver)
0648 Solver->handleReconnectEdge(EId, NId);
0649 }
0650
0651
0652
0653 void removeEdge(EdgeId EId) {
0654 if (Solver)
0655 Solver->handleRemoveEdge(EId);
0656 EdgeEntry &E = getEdge(EId);
0657 E.disconnect();
0658 FreeEdgeIds.push_back(EId);
0659 Edges[EId].invalidate();
0660 }
0661
0662
0663 void clear() {
0664 Nodes.clear();
0665 FreeNodeIds.clear();
0666 Edges.clear();
0667 FreeEdgeIds.clear();
0668 }
0669 };
0670
0671 }
0672 }
0673
0674 #endif