LLVM API Documentation
00001 //===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // PBQP Graph class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 00015 #ifndef LLVM_CODEGEN_PBQP_GRAPH_H 00016 #define LLVM_CODEGEN_PBQP_GRAPH_H 00017 00018 #include "llvm/ADT/ilist.h" 00019 #include "llvm/ADT/ilist_node.h" 00020 #include "llvm/Support/Compiler.h" 00021 #include <list> 00022 #include <map> 00023 #include <set> 00024 00025 namespace PBQP { 00026 00027 class GraphBase { 00028 public: 00029 typedef unsigned NodeId; 00030 typedef unsigned EdgeId; 00031 00032 /// \brief Returns a value representing an invalid (non-existent) node. 00033 static NodeId invalidNodeId() { 00034 return std::numeric_limits<NodeId>::max(); 00035 } 00036 00037 /// \brief Returns a value representing an invalid (non-existent) edge. 00038 static EdgeId invalidEdgeId() { 00039 return std::numeric_limits<EdgeId>::max(); 00040 } 00041 }; 00042 00043 /// PBQP Graph class. 00044 /// Instances of this class describe PBQP problems. 00045 /// 00046 template <typename SolverT> 00047 class Graph : public GraphBase { 00048 private: 00049 typedef typename SolverT::CostAllocator CostAllocator; 00050 public: 00051 typedef typename SolverT::RawVector RawVector; 00052 typedef typename SolverT::RawMatrix RawMatrix; 00053 typedef typename SolverT::Vector Vector; 00054 typedef typename SolverT::Matrix Matrix; 00055 typedef typename CostAllocator::VectorPtr VectorPtr; 00056 typedef typename CostAllocator::MatrixPtr MatrixPtr; 00057 typedef typename SolverT::NodeMetadata NodeMetadata; 00058 typedef typename SolverT::EdgeMetadata EdgeMetadata; 00059 00060 private: 00061 00062 class NodeEntry { 00063 public: 00064 typedef std::vector<EdgeId> AdjEdgeList; 00065 typedef AdjEdgeList::size_type AdjEdgeIdx; 00066 typedef AdjEdgeList::const_iterator AdjEdgeItr; 00067 00068 static AdjEdgeIdx getInvalidAdjEdgeIdx() { 00069 return std::numeric_limits<AdjEdgeIdx>::max(); 00070 } 00071 00072 NodeEntry(VectorPtr Costs) : Costs(Costs) {} 00073 00074 AdjEdgeIdx addAdjEdgeId(EdgeId EId) { 00075 AdjEdgeIdx Idx = AdjEdgeIds.size(); 00076 AdjEdgeIds.push_back(EId); 00077 return Idx; 00078 } 00079 00080 void removeAdjEdgeId(Graph &G, NodeId ThisNId, AdjEdgeIdx Idx) { 00081 // Swap-and-pop for fast removal. 00082 // 1) Update the adj index of the edge currently at back(). 00083 // 2) Move last Edge down to Idx. 00084 // 3) pop_back() 00085 // If Idx == size() - 1 then the setAdjEdgeIdx and swap are 00086 // redundant, but both operations are cheap. 00087 G.getEdge(AdjEdgeIds.back()).setAdjEdgeIdx(ThisNId, Idx); 00088 AdjEdgeIds[Idx] = AdjEdgeIds.back(); 00089 AdjEdgeIds.pop_back(); 00090 } 00091 00092 const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; } 00093 00094 VectorPtr Costs; 00095 NodeMetadata Metadata; 00096 private: 00097 AdjEdgeList AdjEdgeIds; 00098 }; 00099 00100 class EdgeEntry { 00101 public: 00102 EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs) 00103 : Costs(Costs) { 00104 NIds[0] = N1Id; 00105 NIds[1] = N2Id; 00106 ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx(); 00107 ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx(); 00108 } 00109 00110 void invalidate() { 00111 NIds[0] = NIds[1] = Graph::invalidNodeId(); 00112 ThisEdgeAdjIdxs[0] = ThisEdgeAdjIdxs[1] = 00113 NodeEntry::getInvalidAdjEdgeIdx(); 00114 Costs = nullptr; 00115 } 00116 00117 void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) { 00118 assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() && 00119 "Edge already connected to NIds[NIdx]."); 00120 NodeEntry &N = G.getNode(NIds[NIdx]); 00121 ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId); 00122 } 00123 00124 void connectTo(Graph &G, EdgeId ThisEdgeId, NodeId NId) { 00125 if (NId == NIds[0]) 00126 connectToN(G, ThisEdgeId, 0); 00127 else { 00128 assert(NId == NIds[1] && "Edge does not connect NId."); 00129 connectToN(G, ThisEdgeId, 1); 00130 } 00131 } 00132 00133 void connect(Graph &G, EdgeId ThisEdgeId) { 00134 connectToN(G, ThisEdgeId, 0); 00135 connectToN(G, ThisEdgeId, 1); 00136 } 00137 00138 void setAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) { 00139 if (NId == NIds[0]) 00140 ThisEdgeAdjIdxs[0] = NewIdx; 00141 else { 00142 assert(NId == NIds[1] && "Edge not connected to NId"); 00143 ThisEdgeAdjIdxs[1] = NewIdx; 00144 } 00145 } 00146 00147 void disconnectFromN(Graph &G, unsigned NIdx) { 00148 assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() && 00149 "Edge not connected to NIds[NIdx]."); 00150 NodeEntry &N = G.getNode(NIds[NIdx]); 00151 N.removeAdjEdgeId(G, NIds[NIdx], ThisEdgeAdjIdxs[NIdx]); 00152 ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx(); 00153 } 00154 00155 void disconnectFrom(Graph &G, NodeId NId) { 00156 if (NId == NIds[0]) 00157 disconnectFromN(G, 0); 00158 else { 00159 assert(NId == NIds[1] && "Edge does not connect NId"); 00160 disconnectFromN(G, 1); 00161 } 00162 } 00163 00164 NodeId getN1Id() const { return NIds[0]; } 00165 NodeId getN2Id() const { return NIds[1]; } 00166 MatrixPtr Costs; 00167 EdgeMetadata Metadata; 00168 private: 00169 NodeId NIds[2]; 00170 typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2]; 00171 }; 00172 00173 // ----- MEMBERS ----- 00174 00175 CostAllocator CostAlloc; 00176 SolverT *Solver; 00177 00178 typedef std::vector<NodeEntry> NodeVector; 00179 typedef std::vector<NodeId> FreeNodeVector; 00180 NodeVector Nodes; 00181 FreeNodeVector FreeNodeIds; 00182 00183 typedef std::vector<EdgeEntry> EdgeVector; 00184 typedef std::vector<EdgeId> FreeEdgeVector; 00185 EdgeVector Edges; 00186 FreeEdgeVector FreeEdgeIds; 00187 00188 // ----- INTERNAL METHODS ----- 00189 00190 NodeEntry& getNode(NodeId NId) { return Nodes[NId]; } 00191 const NodeEntry& getNode(NodeId NId) const { return Nodes[NId]; } 00192 00193 EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; } 00194 const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; } 00195 00196 NodeId addConstructedNode(const NodeEntry &N) { 00197 NodeId NId = 0; 00198 if (!FreeNodeIds.empty()) { 00199 NId = FreeNodeIds.back(); 00200 FreeNodeIds.pop_back(); 00201 Nodes[NId] = std::move(N); 00202 } else { 00203 NId = Nodes.size(); 00204 Nodes.push_back(std::move(N)); 00205 } 00206 return NId; 00207 } 00208 00209 EdgeId addConstructedEdge(const EdgeEntry &E) { 00210 assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() && 00211 "Attempt to add duplicate edge."); 00212 EdgeId EId = 0; 00213 if (!FreeEdgeIds.empty()) { 00214 EId = FreeEdgeIds.back(); 00215 FreeEdgeIds.pop_back(); 00216 Edges[EId] = std::move(E); 00217 } else { 00218 EId = Edges.size(); 00219 Edges.push_back(std::move(E)); 00220 } 00221 00222 EdgeEntry &NE = getEdge(EId); 00223 00224 // Add the edge to the adjacency sets of its nodes. 00225 NE.connect(*this, EId); 00226 return EId; 00227 } 00228 00229 Graph(const Graph &Other) {} 00230 void operator=(const Graph &Other) {} 00231 00232 public: 00233 00234 typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr; 00235 00236 class NodeItr { 00237 public: 00238 NodeItr(NodeId CurNId, const Graph &G) 00239 : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) { 00240 this->CurNId = findNextInUse(CurNId); // Move to first in-use node id 00241 } 00242 00243 bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; } 00244 bool operator!=(const NodeItr &O) const { return !(*this == O); } 00245 NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; } 00246 NodeId operator*() const { return CurNId; } 00247 00248 private: 00249 NodeId findNextInUse(NodeId NId) const { 00250 while (NId < EndNId && 00251 std::find(FreeNodeIds.begin(), FreeNodeIds.end(), NId) != 00252 FreeNodeIds.end()) { 00253 ++NId; 00254 } 00255 return NId; 00256 } 00257 00258 NodeId CurNId, EndNId; 00259 const FreeNodeVector &FreeNodeIds; 00260 }; 00261 00262 class EdgeItr { 00263 public: 00264 EdgeItr(EdgeId CurEId, const Graph &G) 00265 : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) { 00266 this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id 00267 } 00268 00269 bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; } 00270 bool operator!=(const EdgeItr &O) const { return !(*this == O); } 00271 EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; } 00272 EdgeId operator*() const { return CurEId; } 00273 00274 private: 00275 EdgeId findNextInUse(EdgeId EId) const { 00276 while (EId < EndEId && 00277 std::find(FreeEdgeIds.begin(), FreeEdgeIds.end(), EId) != 00278 FreeEdgeIds.end()) { 00279 ++EId; 00280 } 00281 return EId; 00282 } 00283 00284 EdgeId CurEId, EndEId; 00285 const FreeEdgeVector &FreeEdgeIds; 00286 }; 00287 00288 class NodeIdSet { 00289 public: 00290 NodeIdSet(const Graph &G) : G(G) { } 00291 NodeItr begin() const { return NodeItr(0, G); } 00292 NodeItr end() const { return NodeItr(G.Nodes.size(), G); } 00293 bool empty() const { return G.Nodes.empty(); } 00294 typename NodeVector::size_type size() const { 00295 return G.Nodes.size() - G.FreeNodeIds.size(); 00296 } 00297 private: 00298 const Graph& G; 00299 }; 00300 00301 class EdgeIdSet { 00302 public: 00303 EdgeIdSet(const Graph &G) : G(G) { } 00304 EdgeItr begin() const { return EdgeItr(0, G); } 00305 EdgeItr end() const { return EdgeItr(G.Edges.size(), G); } 00306 bool empty() const { return G.Edges.empty(); } 00307 typename NodeVector::size_type size() const { 00308 return G.Edges.size() - G.FreeEdgeIds.size(); 00309 } 00310 private: 00311 const Graph& G; 00312 }; 00313 00314 class AdjEdgeIdSet { 00315 public: 00316 AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) { } 00317 typename NodeEntry::AdjEdgeItr begin() const { 00318 return NE.getAdjEdgeIds().begin(); 00319 } 00320 typename NodeEntry::AdjEdgeItr end() const { 00321 return NE.getAdjEdgeIds().end(); 00322 } 00323 bool empty() const { return NE.getAdjEdgeIds().empty(); } 00324 typename NodeEntry::AdjEdgeList::size_type size() const { 00325 return NE.getAdjEdgeIds().size(); 00326 } 00327 private: 00328 const NodeEntry &NE; 00329 }; 00330 00331 /// \brief Construct an empty PBQP graph. 00332 Graph() : Solver(nullptr) { } 00333 00334 /// \brief Lock this graph to the given solver instance in preparation 00335 /// for running the solver. This method will call solver.handleAddNode for 00336 /// each node in the graph, and handleAddEdge for each edge, to give the 00337 /// solver an opportunity to set up any requried metadata. 00338 void setSolver(SolverT &S) { 00339 assert(!Solver && "Solver already set. Call unsetSolver()."); 00340 Solver = &S; 00341 for (auto NId : nodeIds()) 00342 Solver->handleAddNode(NId); 00343 for (auto EId : edgeIds()) 00344 Solver->handleAddEdge(EId); 00345 } 00346 00347 /// \brief Release from solver instance. 00348 void unsetSolver() { 00349 assert(Solver && "Solver not set."); 00350 Solver = nullptr; 00351 } 00352 00353 /// \brief Add a node with the given costs. 00354 /// @param Costs Cost vector for the new node. 00355 /// @return Node iterator for the added node. 00356 template <typename OtherVectorT> 00357 NodeId addNode(OtherVectorT Costs) { 00358 // Get cost vector from the problem domain 00359 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 00360 NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts)); 00361 if (Solver) 00362 Solver->handleAddNode(NId); 00363 return NId; 00364 } 00365 00366 /// \brief Add an edge between the given nodes with the given costs. 00367 /// @param N1Id First node. 00368 /// @param N2Id Second node. 00369 /// @return Edge iterator for the added edge. 00370 template <typename OtherVectorT> 00371 EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) { 00372 assert(getNodeCosts(N1Id).getLength() == Costs.getRows() && 00373 getNodeCosts(N2Id).getLength() == Costs.getCols() && 00374 "Matrix dimensions mismatch."); 00375 // Get cost matrix from the problem domain. 00376 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 00377 EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts)); 00378 if (Solver) 00379 Solver->handleAddEdge(EId); 00380 return EId; 00381 } 00382 00383 /// \brief Returns true if the graph is empty. 00384 bool empty() const { return NodeIdSet(*this).empty(); } 00385 00386 NodeIdSet nodeIds() const { return NodeIdSet(*this); } 00387 EdgeIdSet edgeIds() const { return EdgeIdSet(*this); } 00388 00389 AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); } 00390 00391 /// \brief Get the number of nodes in the graph. 00392 /// @return Number of nodes in the graph. 00393 unsigned getNumNodes() const { return NodeIdSet(*this).size(); } 00394 00395 /// \brief Get the number of edges in the graph. 00396 /// @return Number of edges in the graph. 00397 unsigned getNumEdges() const { return EdgeIdSet(*this).size(); } 00398 00399 /// \brief Set a node's cost vector. 00400 /// @param NId Node to update. 00401 /// @param Costs New costs to set. 00402 template <typename OtherVectorT> 00403 void setNodeCosts(NodeId NId, OtherVectorT Costs) { 00404 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs)); 00405 if (Solver) 00406 Solver->handleSetNodeCosts(NId, *AllocatedCosts); 00407 getNode(NId).Costs = AllocatedCosts; 00408 } 00409 00410 /// \brief Get a node's cost vector (const version). 00411 /// @param NId Node id. 00412 /// @return Node cost vector. 00413 const Vector& getNodeCosts(NodeId NId) const { 00414 return *getNode(NId).Costs; 00415 } 00416 00417 NodeMetadata& getNodeMetadata(NodeId NId) { 00418 return getNode(NId).Metadata; 00419 } 00420 00421 const NodeMetadata& getNodeMetadata(NodeId NId) const { 00422 return getNode(NId).Metadata; 00423 } 00424 00425 typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const { 00426 return getNode(NId).getAdjEdgeIds().size(); 00427 } 00428 00429 /// \brief Set an edge's cost matrix. 00430 /// @param EId Edge id. 00431 /// @param Costs New cost matrix. 00432 template <typename OtherMatrixT> 00433 void setEdgeCosts(EdgeId EId, OtherMatrixT Costs) { 00434 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs)); 00435 if (Solver) 00436 Solver->handleSetEdgeCosts(EId, *AllocatedCosts); 00437 getEdge(EId).Costs = AllocatedCosts; 00438 } 00439 00440 /// \brief Get an edge's cost matrix (const version). 00441 /// @param EId Edge id. 00442 /// @return Edge cost matrix. 00443 const Matrix& getEdgeCosts(EdgeId EId) const { return *getEdge(EId).Costs; } 00444 00445 EdgeMetadata& getEdgeMetadata(EdgeId NId) { 00446 return getEdge(NId).Metadata; 00447 } 00448 00449 const EdgeMetadata& getEdgeMetadata(EdgeId NId) const { 00450 return getEdge(NId).Metadata; 00451 } 00452 00453 /// \brief Get the first node connected to this edge. 00454 /// @param EId Edge id. 00455 /// @return The first node connected to the given edge. 00456 NodeId getEdgeNode1Id(EdgeId EId) { 00457 return getEdge(EId).getN1Id(); 00458 } 00459 00460 /// \brief Get the second node connected to this edge. 00461 /// @param EId Edge id. 00462 /// @return The second node connected to the given edge. 00463 NodeId getEdgeNode2Id(EdgeId EId) { 00464 return getEdge(EId).getN2Id(); 00465 } 00466 00467 /// \brief Get the "other" node connected to this edge. 00468 /// @param EId Edge id. 00469 /// @param NId Node id for the "given" node. 00470 /// @return The iterator for the "other" node connected to this edge. 00471 NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) { 00472 EdgeEntry &E = getEdge(EId); 00473 if (E.getN1Id() == NId) { 00474 return E.getN2Id(); 00475 } // else 00476 return E.getN1Id(); 00477 } 00478 00479 /// \brief Get the edge connecting two nodes. 00480 /// @param N1Id First node id. 00481 /// @param N2Id Second node id. 00482 /// @return An id for edge (N1Id, N2Id) if such an edge exists, 00483 /// otherwise returns an invalid edge id. 00484 EdgeId findEdge(NodeId N1Id, NodeId N2Id) { 00485 for (auto AEId : adjEdgeIds(N1Id)) { 00486 if ((getEdgeNode1Id(AEId) == N2Id) || 00487 (getEdgeNode2Id(AEId) == N2Id)) { 00488 return AEId; 00489 } 00490 } 00491 return invalidEdgeId(); 00492 } 00493 00494 /// \brief Remove a node from the graph. 00495 /// @param NId Node id. 00496 void removeNode(NodeId NId) { 00497 if (Solver) 00498 Solver->handleRemoveNode(NId); 00499 NodeEntry &N = getNode(NId); 00500 // TODO: Can this be for-each'd? 00501 for (AdjEdgeItr AEItr = N.adjEdgesBegin(), 00502 AEEnd = N.adjEdgesEnd(); 00503 AEItr != AEEnd;) { 00504 EdgeId EId = *AEItr; 00505 ++AEItr; 00506 removeEdge(EId); 00507 } 00508 FreeNodeIds.push_back(NId); 00509 } 00510 00511 /// \brief Disconnect an edge from the given node. 00512 /// 00513 /// Removes the given edge from the adjacency list of the given node. 00514 /// This operation leaves the edge in an 'asymmetric' state: It will no 00515 /// longer appear in an iteration over the given node's (NId's) edges, but 00516 /// will appear in an iteration over the 'other', unnamed node's edges. 00517 /// 00518 /// This does not correspond to any normal graph operation, but exists to 00519 /// support efficient PBQP graph-reduction based solvers. It is used to 00520 /// 'effectively' remove the unnamed node from the graph while the solver 00521 /// is performing the reduction. The solver will later call reconnectNode 00522 /// to restore the edge in the named node's adjacency list. 00523 /// 00524 /// Since the degree of a node is the number of connected edges, 00525 /// disconnecting an edge from a node 'u' will cause the degree of 'u' to 00526 /// drop by 1. 00527 /// 00528 /// A disconnected edge WILL still appear in an iteration over the graph 00529 /// edges. 00530 /// 00531 /// A disconnected edge should not be removed from the graph, it should be 00532 /// reconnected first. 00533 /// 00534 /// A disconnected edge can be reconnected by calling the reconnectEdge 00535 /// method. 00536 void disconnectEdge(EdgeId EId, NodeId NId) { 00537 if (Solver) 00538 Solver->handleDisconnectEdge(EId, NId); 00539 00540 EdgeEntry &E = getEdge(EId); 00541 E.disconnectFrom(*this, NId); 00542 } 00543 00544 /// \brief Convenience method to disconnect all neighbours from the given 00545 /// node. 00546 void disconnectAllNeighborsFromNode(NodeId NId) { 00547 for (auto AEId : adjEdgeIds(NId)) 00548 disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId)); 00549 } 00550 00551 /// \brief Re-attach an edge to its nodes. 00552 /// 00553 /// Adds an edge that had been previously disconnected back into the 00554 /// adjacency set of the nodes that the edge connects. 00555 void reconnectEdge(EdgeId EId, NodeId NId) { 00556 EdgeEntry &E = getEdge(EId); 00557 E.connectTo(*this, EId, NId); 00558 if (Solver) 00559 Solver->handleReconnectEdge(EId, NId); 00560 } 00561 00562 /// \brief Remove an edge from the graph. 00563 /// @param EId Edge id. 00564 void removeEdge(EdgeId EId) { 00565 if (Solver) 00566 Solver->handleRemoveEdge(EId); 00567 EdgeEntry &E = getEdge(EId); 00568 E.disconnect(); 00569 FreeEdgeIds.push_back(EId); 00570 Edges[EId].invalidate(); 00571 } 00572 00573 /// \brief Remove all nodes and edges from the graph. 00574 void clear() { 00575 Nodes.clear(); 00576 FreeNodeIds.clear(); 00577 Edges.clear(); 00578 FreeEdgeIds.clear(); 00579 } 00580 00581 /// \brief Dump a graph to an output stream. 00582 template <typename OStream> 00583 void dump(OStream &OS) { 00584 OS << nodeIds().size() << " " << edgeIds().size() << "\n"; 00585 00586 for (auto NId : nodeIds()) { 00587 const Vector& V = getNodeCosts(NId); 00588 OS << "\n" << V.getLength() << "\n"; 00589 assert(V.getLength() != 0 && "Empty vector in graph."); 00590 OS << V[0]; 00591 for (unsigned i = 1; i < V.getLength(); ++i) { 00592 OS << " " << V[i]; 00593 } 00594 OS << "\n"; 00595 } 00596 00597 for (auto EId : edgeIds()) { 00598 NodeId N1Id = getEdgeNode1Id(EId); 00599 NodeId N2Id = getEdgeNode2Id(EId); 00600 assert(N1Id != N2Id && "PBQP graphs shound not have self-edges."); 00601 const Matrix& M = getEdgeCosts(EId); 00602 OS << "\n" << N1Id << " " << N2Id << "\n" 00603 << M.getRows() << " " << M.getCols() << "\n"; 00604 assert(M.getRows() != 0 && "No rows in matrix."); 00605 assert(M.getCols() != 0 && "No cols in matrix."); 00606 for (unsigned i = 0; i < M.getRows(); ++i) { 00607 OS << M[i][0]; 00608 for (unsigned j = 1; j < M.getCols(); ++j) { 00609 OS << " " << M[i][j]; 00610 } 00611 OS << "\n"; 00612 } 00613 } 00614 } 00615 00616 /// \brief Print a representation of this graph in DOT format. 00617 /// @param OS Output stream to print on. 00618 template <typename OStream> 00619 void printDot(OStream &OS) { 00620 OS << "graph {\n"; 00621 for (auto NId : nodeIds()) { 00622 OS << " node" << NId << " [ label=\"" 00623 << NId << ": " << getNodeCosts(NId) << "\" ]\n"; 00624 } 00625 OS << " edge [ len=" << nodeIds().size() << " ]\n"; 00626 for (auto EId : edgeIds()) { 00627 OS << " node" << getEdgeNode1Id(EId) 00628 << " -- node" << getEdgeNode2Id(EId) 00629 << " [ label=\""; 00630 const Matrix &EdgeCosts = getEdgeCosts(EId); 00631 for (unsigned i = 0; i < EdgeCosts.getRows(); ++i) { 00632 OS << EdgeCosts.getRowAsVector(i) << "\\n"; 00633 } 00634 OS << "\" ]\n"; 00635 } 00636 OS << "}\n"; 00637 } 00638 }; 00639 00640 } 00641 00642 #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP