Graph.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // PBQP Graph class.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_CODEGEN_PBQP_GRAPH_H
  18. #define LLVM_CODEGEN_PBQP_GRAPH_H
  19. #include "llvm/ADT/STLExtras.h"
  20. #include <algorithm>
  21. #include <cassert>
  22. #include <iterator>
  23. #include <limits>
  24. #include <vector>
  25. namespace llvm {
  26. namespace PBQP {
  27. class GraphBase {
  28. public:
  29. using NodeId = unsigned;
  30. using EdgeId = unsigned;
  31. /// Returns a value representing an invalid (non-existent) node.
  32. static NodeId invalidNodeId() {
  33. return std::numeric_limits<NodeId>::max();
  34. }
  35. /// Returns a value representing an invalid (non-existent) edge.
  36. static EdgeId invalidEdgeId() {
  37. return std::numeric_limits<EdgeId>::max();
  38. }
  39. };
  40. /// PBQP Graph class.
  41. /// Instances of this class describe PBQP problems.
  42. ///
  43. template <typename SolverT>
  44. class Graph : public GraphBase {
  45. private:
  46. using CostAllocator = typename SolverT::CostAllocator;
  47. public:
  48. using RawVector = typename SolverT::RawVector;
  49. using RawMatrix = typename SolverT::RawMatrix;
  50. using Vector = typename SolverT::Vector;
  51. using Matrix = typename SolverT::Matrix;
  52. using VectorPtr = typename CostAllocator::VectorPtr;
  53. using MatrixPtr = typename CostAllocator::MatrixPtr;
  54. using NodeMetadata = typename SolverT::NodeMetadata;
  55. using EdgeMetadata = typename SolverT::EdgeMetadata;
  56. using GraphMetadata = typename SolverT::GraphMetadata;
  57. private:
  58. class NodeEntry {
  59. public:
  60. using AdjEdgeList = std::vector<EdgeId>;
  61. using AdjEdgeIdx = AdjEdgeList::size_type;
  62. using AdjEdgeItr = AdjEdgeList::const_iterator;
  63. NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
  64. static AdjEdgeIdx getInvalidAdjEdgeIdx() {
  65. return std::numeric_limits<AdjEdgeIdx>::max();
  66. }
  67. AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
  68. AdjEdgeIdx Idx = AdjEdgeIds.size();
  69. AdjEdgeIds.push_back(EId);
  70. return Idx;
  71. }
  72. void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) {
  73. // Swap-and-pop for fast removal.
  74. // 1) Update the adj index of the edge currently at back().
  75. // 2) Move last Edge down to Idx.
  76. // 3) pop_back()
  77. // If Idx == size() - 1 then the setAdjEdgeIdx and swap are
  78. // redundant, but both operations are cheap.
  79. G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx);
  80. AdjEdgeIds[Idx] = AdjEdgeIds.back();
  81. AdjEdgeIds.pop_back();
  82. }
  83. const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; }
  84. VectorPtr Costs;
  85. NodeMetadata Metadata;
  86. private:
  87. AdjEdgeList AdjEdgeIds;
  88. };
  89. class EdgeEntry {
  90. public:
  91. EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs)
  92. : Costs(std::move(Costs)) {
  93. NIds[0] = N1Id;
  94. NIds[1] = N2Id;
  95. ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx();
  96. ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx();
  97. }
  98. void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) {
  99. assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() &&
  100. "Edge already connected to NIds[NIdx].");
  101. NodeEntry &N = G.getNode(NIds[NIdx]);
  102. ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId);
  103. }
  104. void connect(Graph &G, EdgeId ThisEdgeId) {
  105. connectToN(G, ThisEdgeId, 0);
  106. connectToN(G, ThisEdgeId, 1);
  107. }
  108. void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) {
  109. if (NId == NIds[0])
  110. ThisEdgeAdjIdxs[0] = NewIdx;
  111. else {
  112. assert(NId == NIds[1] && "Edge not connected to NId");
  113. ThisEdgeAdjIdxs[1] = NewIdx;
  114. }
  115. }
  116. void disconnectFromN(Graph &G, unsigned NIdx) {
  117. assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() &&
  118. "Edge not connected to NIds[NIdx].");
  119. NodeEntry &N = G.getNode(NIds[NIdx]);
  120. N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]);
  121. ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx();
  122. }
  123. void disconnectFrom(Graph &G, NodeId NId) {
  124. if (NId == NIds[0])
  125. disconnectFromN(G, 0);
  126. else {
  127. assert(NId == NIds[1] && "Edge does not connect NId");
  128. disconnectFromN(G, 1);
  129. }
  130. }
  131. NodeId getN1Id() const { return NIds[0]; }
  132. NodeId getN2Id() const { return NIds[1]; }
  133. MatrixPtr Costs;
  134. EdgeMetadata Metadata;
  135. private:
  136. NodeId NIds[2];
  137. typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
  138. };
  139. // ----- MEMBERS -----
  140. GraphMetadata Metadata;
  141. CostAllocator CostAlloc;
  142. SolverT *Solver = nullptr;
  143. using NodeVector = std::vector<NodeEntry>;
  144. using FreeNodeVector = std::vector<NodeId>;
  145. NodeVector Nodes;
  146. FreeNodeVector FreeNodeIds;
  147. using EdgeVector = std::vector<EdgeEntry>;
  148. using FreeEdgeVector = std::vector<EdgeId>;
  149. EdgeVector Edges;
  150. FreeEdgeVector FreeEdgeIds;
  151. Graph(const Graph &Other) {}
  152. // ----- INTERNAL METHODS -----
  153. NodeEntry &getNode(NodeId NId) {
  154. assert(NId < Nodes.size() && "Out of bound NodeId");
  155. return Nodes[NId];
  156. }
  157. const NodeEntry &getNode(NodeId NId) const {
  158. assert(NId < Nodes.size() && "Out of bound NodeId");
  159. return Nodes[NId];
  160. }
  161. EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
  162. const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
  163. NodeId addConstructedNode(NodeEntry N) {
  164. NodeId NId = 0;
  165. if (!FreeNodeIds.empty()) {
  166. NId = FreeNodeIds.back();
  167. FreeNodeIds.pop_back();
  168. Nodes[NId] = std::move(N);
  169. } else {
  170. NId = Nodes.size();
  171. Nodes.push_back(std::move(N));
  172. }
  173. return NId;
  174. }
  175. EdgeId addConstructedEdge(EdgeEntry E) {
  176. assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
  177. "Attempt to add duplicate edge.");
  178. EdgeId EId = 0;
  179. if (!FreeEdgeIds.empty()) {
  180. EId = FreeEdgeIds.back();
  181. FreeEdgeIds.pop_back();
  182. Edges[EId] = std::move(E);
  183. } else {
  184. EId = Edges.size();
  185. Edges.push_back(std::move(E));
  186. }
  187. EdgeEntry &NE = getEdge(EId);
  188. // Add the edge to the adjacency sets of its nodes.
  189. NE.connect(*this, EId);
  190. return EId;
  191. }
  192. void operator=(const Graph &Other) {}
  193. public:
  194. using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
  195. class NodeItr {
  196. public:
  197. using iterator_category = std::forward_iterator_tag;
  198. using value_type = NodeId;
  199. using difference_type = int;
  200. using pointer = NodeId *;
  201. using reference = NodeId &;
  202. NodeItr(NodeId CurNId, const Graph &G)
  203. : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
  204. this->CurNId = findNextInUse(CurNId); // Move to first in-use node id
  205. }
  206. bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; }
  207. bool operator!=(const NodeItr &O) const { return !(*this == O); }
  208. NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; }
  209. NodeId operator*() const { return CurNId; }
  210. private:
  211. NodeId findNextInUse(NodeId NId) const {
  212. while (NId < EndNId && is_contained(FreeNodeIds, NId)) {
  213. ++NId;
  214. }
  215. return NId;
  216. }
  217. NodeId CurNId, EndNId;
  218. const FreeNodeVector &FreeNodeIds;
  219. };
  220. class EdgeItr {
  221. public:
  222. EdgeItr(EdgeId CurEId, const Graph &G)
  223. : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) {
  224. this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id
  225. }
  226. bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; }
  227. bool operator!=(const EdgeItr &O) const { return !(*this == O); }
  228. EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; }
  229. EdgeId operator*() const { return CurEId; }
  230. private:
  231. EdgeId findNextInUse(EdgeId EId) const {
  232. while (EId < EndEId && is_contained(FreeEdgeIds, EId)) {
  233. ++EId;
  234. }
  235. return EId;
  236. }
  237. EdgeId CurEId, EndEId;
  238. const FreeEdgeVector &FreeEdgeIds;
  239. };
  240. class NodeIdSet {
  241. public:
  242. NodeIdSet(const Graph &G) : G(G) {}
  243. NodeItr begin() const { return NodeItr(0, G); }
  244. NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
  245. bool empty() const { return G.Nodes.empty(); }
  246. typename NodeVector::size_type size() const {
  247. return G.Nodes.size() - G.FreeNodeIds.size();
  248. }
  249. private:
  250. const Graph& G;
  251. };
  252. class EdgeIdSet {
  253. public:
  254. EdgeIdSet(const Graph &G) : G(G) {}
  255. EdgeItr begin() const { return EdgeItr(0, G); }
  256. EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
  257. bool empty() const { return G.Edges.empty(); }
  258. typename NodeVector::size_type size() const {
  259. return G.Edges.size() - G.FreeEdgeIds.size();
  260. }
  261. private:
  262. const Graph& G;
  263. };
  264. class AdjEdgeIdSet {
  265. public:
  266. AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
  267. typename NodeEntry::AdjEdgeItr begin() const {
  268. return NE.getAdjEdgeIds().begin();
  269. }
  270. typename NodeEntry::AdjEdgeItr end() const {
  271. return NE.getAdjEdgeIds().end();
  272. }
  273. bool empty() const { return NE.getAdjEdgeIds().empty(); }
  274. typename NodeEntry::AdjEdgeList::size_type size() const {
  275. return NE.getAdjEdgeIds().size();
  276. }
  277. private:
  278. const NodeEntry &NE;
  279. };
  280. /// Construct an empty PBQP graph.
  281. Graph() = default;
  282. /// Construct an empty PBQP graph with the given graph metadata.
  283. Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
  284. /// Get a reference to the graph metadata.
  285. GraphMetadata& getMetadata() { return Metadata; }
  286. /// Get a const-reference to the graph metadata.
  287. const GraphMetadata& getMetadata() const { return Metadata; }
  288. /// Lock this graph to the given solver instance in preparation
  289. /// for running the solver. This method will call solver.handleAddNode for
  290. /// each node in the graph, and handleAddEdge for each edge, to give the
  291. /// solver an opportunity to set up any requried metadata.
  292. void setSolver(SolverT &S) {
  293. assert(!Solver && "Solver already set. Call unsetSolver().");
  294. Solver = &S;
  295. for (auto NId : nodeIds())
  296. Solver->handleAddNode(NId);
  297. for (auto EId : edgeIds())
  298. Solver->handleAddEdge(EId);
  299. }
  300. /// Release from solver instance.
  301. void unsetSolver() {
  302. assert(Solver && "Solver not set.");
  303. Solver = nullptr;
  304. }
  305. /// Add a node with the given costs.
  306. /// @param Costs Cost vector for the new node.
  307. /// @return Node iterator for the added node.
  308. template <typename OtherVectorT>
  309. NodeId addNode(OtherVectorT Costs) {
  310. // Get cost vector from the problem domain
  311. VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
  312. NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts));
  313. if (Solver)
  314. Solver->handleAddNode(NId);
  315. return NId;
  316. }
  317. /// Add a node bypassing the cost allocator.
  318. /// @param Costs Cost vector ptr for the new node (must be convertible to
  319. /// VectorPtr).
  320. /// @return Node iterator for the added node.
  321. ///
  322. /// This method allows for fast addition of a node whose costs don't need
  323. /// to be passed through the cost allocator. The most common use case for
  324. /// this is when duplicating costs from an existing node (when using a
  325. /// pooling allocator). These have already been uniqued, so we can avoid
  326. /// re-constructing and re-uniquing them by attaching them directly to the
  327. /// new node.
  328. template <typename OtherVectorPtrT>
  329. NodeId addNodeBypassingCostAllocator(OtherVectorPtrT Costs) {
  330. NodeId NId = addConstructedNode(NodeEntry(Costs));
  331. if (Solver)
  332. Solver->handleAddNode(NId);
  333. return NId;
  334. }
  335. /// Add an edge between the given nodes with the given costs.
  336. /// @param N1Id First node.
  337. /// @param N2Id Second node.
  338. /// @param Costs Cost matrix for new edge.
  339. /// @return Edge iterator for the added edge.
  340. template <typename OtherVectorT>
  341. EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
  342. assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
  343. getNodeCosts(N2Id).getLength() == Costs.getCols() &&
  344. "Matrix dimensions mismatch.");
  345. // Get cost matrix from the problem domain.
  346. MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
  347. EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts));
  348. if (Solver)
  349. Solver->handleAddEdge(EId);
  350. return EId;
  351. }
  352. /// Add an edge bypassing the cost allocator.
  353. /// @param N1Id First node.
  354. /// @param N2Id Second node.
  355. /// @param Costs Cost matrix for new edge.
  356. /// @return Edge iterator for the added edge.
  357. ///
  358. /// This method allows for fast addition of an edge whose costs don't need
  359. /// to be passed through the cost allocator. The most common use case for
  360. /// this is when duplicating costs from an existing edge (when using a
  361. /// pooling allocator). These have already been uniqued, so we can avoid
  362. /// re-constructing and re-uniquing them by attaching them directly to the
  363. /// new edge.
  364. template <typename OtherMatrixPtrT>
  365. NodeId addEdgeBypassingCostAllocator(NodeId N1Id, NodeId N2Id,
  366. OtherMatrixPtrT Costs) {
  367. assert(getNodeCosts(N1Id).getLength() == Costs->getRows() &&
  368. getNodeCosts(N2Id).getLength() == Costs->getCols() &&
  369. "Matrix dimensions mismatch.");
  370. // Get cost matrix from the problem domain.
  371. EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, Costs));
  372. if (Solver)
  373. Solver->handleAddEdge(EId);
  374. return EId;
  375. }
  376. /// Returns true if the graph is empty.
  377. bool empty() const { return NodeIdSet(*this).empty(); }
  378. NodeIdSet nodeIds() const { return NodeIdSet(*this); }
  379. EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
  380. AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
  381. /// Get the number of nodes in the graph.
  382. /// @return Number of nodes in the graph.
  383. unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
  384. /// Get the number of edges in the graph.
  385. /// @return Number of edges in the graph.
  386. unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
  387. /// Set a node's cost vector.
  388. /// @param NId Node to update.
  389. /// @param Costs New costs to set.
  390. template <typename OtherVectorT>
  391. void setNodeCosts(NodeId NId, OtherVectorT Costs) {
  392. VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
  393. if (Solver)
  394. Solver->handleSetNodeCosts(NId, *AllocatedCosts);
  395. getNode(NId).Costs = AllocatedCosts;
  396. }
  397. /// Get a VectorPtr to a node's cost vector. Rarely useful - use
  398. /// getNodeCosts where possible.
  399. /// @param NId Node id.
  400. /// @return VectorPtr to node cost vector.
  401. ///
  402. /// This method is primarily useful for duplicating costs quickly by
  403. /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
  404. /// getNodeCosts when dealing with node cost values.
  405. const VectorPtr& getNodeCostsPtr(NodeId NId) const {
  406. return getNode(NId).Costs;
  407. }
  408. /// Get a node's cost vector.
  409. /// @param NId Node id.
  410. /// @return Node cost vector.
  411. const Vector& getNodeCosts(NodeId NId) const {
  412. return *getNodeCostsPtr(NId);
  413. }
  414. NodeMetadata& getNodeMetadata(NodeId NId) {
  415. return getNode(NId).Metadata;
  416. }
  417. const NodeMetadata& getNodeMetadata(NodeId NId) const {
  418. return getNode(NId).Metadata;
  419. }
  420. typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
  421. return getNode(NId).getAdjEdgeIds().size();
  422. }
  423. /// Update an edge's cost matrix.
  424. /// @param EId Edge id.
  425. /// @param Costs New cost matrix.
  426. template <typename OtherMatrixT>
  427. void updateEdgeCosts(EdgeId EId, OtherMatrixT Costs) {
  428. MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
  429. if (Solver)
  430. Solver->handleUpdateCosts(EId, *AllocatedCosts);
  431. getEdge(EId).Costs = AllocatedCosts;
  432. }
  433. /// Get a MatrixPtr to a node's cost matrix. Rarely useful - use
  434. /// getEdgeCosts where possible.
  435. /// @param EId Edge id.
  436. /// @return MatrixPtr to edge cost matrix.
  437. ///
  438. /// This method is primarily useful for duplicating costs quickly by
  439. /// bypassing the cost allocator. See addNodeBypassingCostAllocator. Prefer
  440. /// getEdgeCosts when dealing with edge cost values.
  441. const MatrixPtr& getEdgeCostsPtr(EdgeId EId) const {
  442. return getEdge(EId).Costs;
  443. }
  444. /// Get an edge's cost matrix.
  445. /// @param EId Edge id.
  446. /// @return Edge cost matrix.
  447. const Matrix& getEdgeCosts(EdgeId EId) const {
  448. return *getEdge(EId).Costs;
  449. }
  450. EdgeMetadata& getEdgeMetadata(EdgeId EId) {
  451. return getEdge(EId).Metadata;
  452. }
  453. const EdgeMetadata& getEdgeMetadata(EdgeId EId) const {
  454. return getEdge(EId).Metadata;
  455. }
  456. /// Get the first node connected to this edge.
  457. /// @param EId Edge id.
  458. /// @return The first node connected to the given edge.
  459. NodeId getEdgeNode1Id(EdgeId EId) const {
  460. return getEdge(EId).getN1Id();
  461. }
  462. /// Get the second node connected to this edge.
  463. /// @param EId Edge id.
  464. /// @return The second node connected to the given edge.
  465. NodeId getEdgeNode2Id(EdgeId EId) const {
  466. return getEdge(EId).getN2Id();
  467. }
  468. /// Get the "other" node connected to this edge.
  469. /// @param EId Edge id.
  470. /// @param NId Node id for the "given" node.
  471. /// @return The iterator for the "other" node connected to this edge.
  472. NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
  473. EdgeEntry &E = getEdge(EId);
  474. if (E.getN1Id() == NId) {
  475. return E.getN2Id();
  476. } // else
  477. return E.getN1Id();
  478. }
  479. /// Get the edge connecting two nodes.
  480. /// @param N1Id First node id.
  481. /// @param N2Id Second node id.
  482. /// @return An id for edge (N1Id, N2Id) if such an edge exists,
  483. /// otherwise returns an invalid edge id.
  484. EdgeId findEdge(NodeId N1Id, NodeId N2Id) {
  485. for (auto AEId : adjEdgeIds(N1Id)) {
  486. if ((getEdgeNode1Id(AEId) == N2Id) ||
  487. (getEdgeNode2Id(AEId) == N2Id)) {
  488. return AEId;
  489. }
  490. }
  491. return invalidEdgeId();
  492. }
  493. /// Remove a node from the graph.
  494. /// @param NId Node id.
  495. void removeNode(NodeId NId) {
  496. if (Solver)
  497. Solver->handleRemoveNode(NId);
  498. NodeEntry &N = getNode(NId);
  499. // TODO: Can this be for-each'd?
  500. for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
  501. AEEnd = N.adjEdgesEnd();
  502. AEItr != AEEnd;) {
  503. EdgeId EId = *AEItr;
  504. ++AEItr;
  505. removeEdge(EId);
  506. }
  507. FreeNodeIds.push_back(NId);
  508. }
  509. /// Disconnect an edge from the given node.
  510. ///
  511. /// Removes the given edge from the adjacency list of the given node.
  512. /// This operation leaves the edge in an 'asymmetric' state: It will no
  513. /// longer appear in an iteration over the given node's (NId's) edges, but
  514. /// will appear in an iteration over the 'other', unnamed node's edges.
  515. ///
  516. /// This does not correspond to any normal graph operation, but exists to
  517. /// support efficient PBQP graph-reduction based solvers. It is used to
  518. /// 'effectively' remove the unnamed node from the graph while the solver
  519. /// is performing the reduction. The solver will later call reconnectNode
  520. /// to restore the edge in the named node's adjacency list.
  521. ///
  522. /// Since the degree of a node is the number of connected edges,
  523. /// disconnecting an edge from a node 'u' will cause the degree of 'u' to
  524. /// drop by 1.
  525. ///
  526. /// A disconnected edge WILL still appear in an iteration over the graph
  527. /// edges.
  528. ///
  529. /// A disconnected edge should not be removed from the graph, it should be
  530. /// reconnected first.
  531. ///
  532. /// A disconnected edge can be reconnected by calling the reconnectEdge
  533. /// method.
  534. void disconnectEdge(EdgeId EId, NodeId NId) {
  535. if (Solver)
  536. Solver->handleDisconnectEdge(EId, NId);
  537. EdgeEntry &E = getEdge(EId);
  538. E.disconnectFrom(*this, NId);
  539. }
  540. /// Convenience method to disconnect all neighbours from the given
  541. /// node.
  542. void disconnectAllNeighborsFromNode(NodeId NId) {
  543. for (auto AEId : adjEdgeIds(NId))
  544. disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
  545. }
  546. /// Re-attach an edge to its nodes.
  547. ///
  548. /// Adds an edge that had been previously disconnected back into the
  549. /// adjacency set of the nodes that the edge connects.
  550. void reconnectEdge(EdgeId EId, NodeId NId) {
  551. EdgeEntry &E = getEdge(EId);
  552. E.connectTo(*this, EId, NId);
  553. if (Solver)
  554. Solver->handleReconnectEdge(EId, NId);
  555. }
  556. /// Remove an edge from the graph.
  557. /// @param EId Edge id.
  558. void removeEdge(EdgeId EId) {
  559. if (Solver)
  560. Solver->handleRemoveEdge(EId);
  561. EdgeEntry &E = getEdge(EId);
  562. E.disconnect();
  563. FreeEdgeIds.push_back(EId);
  564. Edges[EId].invalidate();
  565. }
  566. /// Remove all nodes and edges from the graph.
  567. void clear() {
  568. Nodes.clear();
  569. FreeNodeIds.clear();
  570. Edges.clear();
  571. FreeEdgeIds.clear();
  572. }
  573. };
  574. } // end namespace PBQP
  575. } // end namespace llvm
  576. #endif // LLVM_CODEGEN_PBQP_GRAPH_H
  577. #ifdef __GNUC__
  578. #pragma GCC diagnostic pop
  579. #endif