Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:26

0001 //===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // PBQP Graph class.
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     /// Returns a value representing an invalid (non-existent) node.
0032     static NodeId invalidNodeId() {
0033       return std::numeric_limits<NodeId>::max();
0034     }
0035 
0036     /// Returns a value representing an invalid (non-existent) edge.
0037     static EdgeId invalidEdgeId() {
0038       return std::numeric_limits<EdgeId>::max();
0039     }
0040   };
0041 
0042   /// PBQP Graph class.
0043   /// Instances of this class describe PBQP problems.
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         // Swap-and-pop for fast removal.
0082         //   1) Update the adj index of the edge currently at back().
0083         //   2) Move last Edge down to Idx.
0084         //   3) pop_back()
0085         // If Idx == size() - 1 then the setAdjEdgeIdx and swap are
0086         // redundant, but both operations are cheap.
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     // ----- MEMBERS -----
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     // ----- INTERNAL METHODS -----
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       // Add the edge to the adjacency sets of its nodes.
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); // Move to first in-use node id
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); // Move to first in-use edge id
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     /// Construct an empty PBQP graph.
0341     Graph() = default;
0342 
0343     /// Construct an empty PBQP graph with the given graph metadata.
0344     Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
0345 
0346     /// Get a reference to the graph metadata.
0347     GraphMetadata& getMetadata() { return Metadata; }
0348 
0349     /// Get a const-reference to the graph metadata.
0350     const GraphMetadata& getMetadata() const { return Metadata; }
0351 
0352     /// Lock this graph to the given solver instance in preparation
0353     /// for running the solver. This method will call solver.handleAddNode for
0354     /// each node in the graph, and handleAddEdge for each edge, to give the
0355     /// solver an opportunity to set up any requried metadata.
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     /// Release from solver instance.
0366     void unsetSolver() {
0367       assert(Solver && "Solver not set.");
0368       Solver = nullptr;
0369     }
0370 
0371     /// Add a node with the given costs.
0372     /// @param Costs Cost vector for the new node.
0373     /// @return Node iterator for the added node.
0374     template <typename OtherVectorT>
0375     NodeId addNode(OtherVectorT Costs) {
0376       // Get cost vector from the problem domain
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     /// Add a node bypassing the cost allocator.
0385     /// @param Costs Cost vector ptr for the new node (must be convertible to
0386     ///        VectorPtr).
0387     /// @return Node iterator for the added node.
0388     ///
0389     ///   This method allows for fast addition of a node whose costs don't need
0390     /// to be passed through the cost allocator. The most common use case for
0391     /// this is when duplicating costs from an existing node (when using a
0392     /// pooling allocator). These have already been uniqued, so we can avoid
0393     /// re-constructing and re-uniquing them by attaching them directly to the
0394     /// new node.
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     /// Add an edge between the given nodes with the given costs.
0404     /// @param N1Id First node.
0405     /// @param N2Id Second node.
0406     /// @param Costs Cost matrix for new edge.
0407     /// @return Edge iterator for the added edge.
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       // Get cost matrix from the problem domain.
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     /// Add an edge bypassing the cost allocator.
0422     /// @param N1Id First node.
0423     /// @param N2Id Second node.
0424     /// @param Costs Cost matrix for new edge.
0425     /// @return Edge iterator for the added edge.
0426     ///
0427     ///   This method allows for fast addition of an edge whose costs don't need
0428     /// to be passed through the cost allocator. The most common use case for
0429     /// this is when duplicating costs from an existing edge (when using a
0430     /// pooling allocator). These have already been uniqued, so we can avoid
0431     /// re-constructing and re-uniquing them by attaching them directly to the
0432     /// new edge.
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       // Get cost matrix from the problem domain.
0440       EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs));
0441       if (Solver)
0442         Solver->handleAddEdge(EId);
0443       return EId;
0444     }
0445 
0446     /// Returns true if the graph is empty.
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     /// Get the number of nodes in the graph.
0455     /// @return Number of nodes in the graph.
0456     unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
0457 
0458     /// Get the number of edges in the graph.
0459     /// @return Number of edges in the graph.
0460     unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
0461 
0462     /// Set a node's cost vector.
0463     /// @param NId Node to update.
0464     /// @param Costs New costs to set.
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     /// Get a VectorPtr to a node's cost vector. Rarely useful - use
0474     ///        getNodeCosts where possible.
0475     /// @param NId Node id.
0476     /// @return VectorPtr to node cost vector.
0477     ///
0478     ///   This method is primarily useful for duplicating costs quickly by
0479     /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
0480     /// getNodeCosts when dealing with node cost values.
0481     const VectorPtr& getNodeCostsPtr(NodeId NId) const {
0482       return getNode(NId).Costs;
0483     }
0484 
0485     /// Get a node's cost vector.
0486     /// @param NId Node id.
0487     /// @return Node cost vector.
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     /// Update an edge's cost matrix.
0505     /// @param EId Edge id.
0506     /// @param Costs New cost matrix.
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     /// Get a MatrixPtr to a node's cost matrix. Rarely useful - use
0516     ///        getEdgeCosts where possible.
0517     /// @param EId Edge id.
0518     /// @return MatrixPtr to edge cost matrix.
0519     ///
0520     ///   This method is primarily useful for duplicating costs quickly by
0521     /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
0522     /// getEdgeCosts when dealing with edge cost values.
0523     const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const {
0524       return getEdge(EId).Costs;
0525     }
0526 
0527     /// Get an edge's cost matrix.
0528     /// @param EId Edge id.
0529     /// @return Edge cost matrix.
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     /// Get the first node connected to this edge.
0543     /// @param EId Edge id.
0544     /// @return The first node connected to the given edge.
0545     NodeId getEdgeNode1Id(EdgeId EId) const {
0546       return getEdge(EId).getN1Id();
0547     }
0548 
0549     /// Get the second node connected to this edge.
0550     /// @param EId Edge id.
0551     /// @return The second node connected to the given edge.
0552     NodeId getEdgeNode2Id(EdgeId EId) const {
0553       return getEdge(EId).getN2Id();
0554     }
0555 
0556     /// Get the "other" node connected to this edge.
0557     /// @param EId Edge id.
0558     /// @param NId Node id for the "given" node.
0559     /// @return The iterator for the "other" node connected to this edge.
0560     NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
0561       EdgeEntry &E = getEdge(EId);
0562       if (E.getN1Id() == NId) {
0563         return E.getN2Id();
0564       } // else
0565       return E.getN1Id();
0566     }
0567 
0568     /// Get the edge connecting two nodes.
0569     /// @param N1Id First node id.
0570     /// @param N2Id Second node id.
0571     /// @return An id for edge (N1Id, N2Id) if such an edge exists,
0572     ///         otherwise returns an invalid edge id.
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     /// Remove a node from the graph.
0584     /// @param NId Node id.
0585     void removeNode(NodeId NId) {
0586       if (Solver)
0587         Solver->handleRemoveNode(NId);
0588       NodeEntry &N = getNode(NId);
0589       // TODO: Can this be for-each'd?
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     /// Disconnect an edge from the given node.
0601     ///
0602     /// Removes the given edge from the adjacency list of the given node.
0603     /// This operation leaves the edge in an 'asymmetric' state: It will no
0604     /// longer appear in an iteration over the given node's (NId's) edges, but
0605     /// will appear in an iteration over the 'other', unnamed node's edges.
0606     ///
0607     /// This does not correspond to any normal graph operation, but exists to
0608     /// support efficient PBQP graph-reduction based solvers. It is used to
0609     /// 'effectively' remove the unnamed node from the graph while the solver
0610     /// is performing the reduction. The solver will later call reconnectNode
0611     /// to restore the edge in the named node's adjacency list.
0612     ///
0613     /// Since the degree of a node is the number of connected edges,
0614     /// disconnecting an edge from a node 'u' will cause the degree of 'u' to
0615     /// drop by 1.
0616     ///
0617     /// A disconnected edge WILL still appear in an iteration over the graph
0618     /// edges.
0619     ///
0620     /// A disconnected edge should not be removed from the graph, it should be
0621     /// reconnected first.
0622     ///
0623     /// A disconnected edge can be reconnected by calling the reconnectEdge
0624     /// method.
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     /// Convenience method to disconnect all neighbours from the given
0634     ///        node.
0635     void disconnectAllNeighborsFromNode(NodeId NId) {
0636       for (auto AEId : adjEdgeIds(NId))
0637         disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
0638     }
0639 
0640     /// Re-attach an edge to its nodes.
0641     ///
0642     /// Adds an edge that had been previously disconnected back into the
0643     /// adjacency set of the nodes that the edge connects.
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     /// Remove an edge from the graph.
0652     /// @param EId Edge id.
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     /// Remove all nodes and edges from the graph.
0663     void clear() {
0664       Nodes.clear();
0665       FreeNodeIds.clear();
0666       Edges.clear();
0667       FreeEdgeIds.clear();
0668     }
0669   };
0670 
0671 } // end namespace PBQP
0672 } // end namespace llvm
0673 
0674 #endif // LLVM_CODEGEN_PBQP_GRAPH_H