Remove PBQP-cost dimension sanity assertion in PBQP::Graph::addConstructedEdge.
[oota-llvm.git] / include / llvm / CodeGen / PBQP / Graph.h
1 //===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // PBQP Graph class.
11 //
12 //===----------------------------------------------------------------------===//
13
14
15 #ifndef LLVM_CODEGEN_PBQP_GRAPH_H
16 #define LLVM_CODEGEN_PBQP_GRAPH_H
17
18 #include "llvm/ADT/ilist.h"
19 #include "llvm/ADT/ilist_node.h"
20 #include "llvm/Support/Compiler.h"
21 #include <list>
22 #include <map>
23 #include <set>
24
25 namespace PBQP {
26
27   class GraphBase {
28   public:
29     typedef unsigned NodeId;
30     typedef unsigned EdgeId;
31   };
32
33   /// PBQP Graph class.
34   /// Instances of this class describe PBQP problems.
35   ///
36   template <typename SolverT>
37   class Graph : public GraphBase {
38   private:
39     typedef typename SolverT::CostAllocator CostAllocator;
40   public:
41     typedef typename SolverT::RawVector RawVector;
42     typedef typename SolverT::RawMatrix RawMatrix;
43     typedef typename SolverT::Vector Vector;
44     typedef typename SolverT::Matrix Matrix;
45     typedef typename CostAllocator::VectorPtr VectorPtr;
46     typedef typename CostAllocator::MatrixPtr MatrixPtr;
47     typedef typename SolverT::NodeMetadata NodeMetadata;
48     typedef typename SolverT::EdgeMetadata EdgeMetadata;
49
50   private:
51
52     class NodeEntry {
53     public:
54       typedef std::vector<EdgeId> AdjEdgeList;
55       typedef AdjEdgeList::size_type AdjEdgeIdx;
56       typedef AdjEdgeList::const_iterator AdjEdgeItr;
57
58       static AdjEdgeIdx getInvalidAdjEdgeIdx() {
59         return std::numeric_limits<AdjEdgeIdx>::max();
60       }
61
62       NodeEntry(VectorPtr Costs) : Costs(Costs) {}
63
64       AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
65         AdjEdgeIdx Idx = AdjEdgeIds.size();
66         AdjEdgeIds.push_back(EId);
67         return Idx;
68       }
69
70       // If a swap is performed, returns the new EdgeId that must be
71       // updated, otherwise returns invalidEdgeId().
72       EdgeId removeAdjEdgeId(AdjEdgeIdx Idx) {
73         EdgeId EIdToUpdate = Graph::invalidEdgeId();
74         if (Idx < AdjEdgeIds.size() - 1) {
75           std::swap(AdjEdgeIds[Idx], AdjEdgeIds.back());
76           EIdToUpdate = AdjEdgeIds[Idx];
77         }
78         AdjEdgeIds.pop_back();
79         return EIdToUpdate;
80       }
81
82       const AdjEdgeList& getAdjEdgeIds() const { return AdjEdgeIds; }
83
84       VectorPtr Costs;
85       NodeMetadata Metadata;
86     private:
87       AdjEdgeList AdjEdgeIds;
88     };
89
90     class EdgeEntry {
91     public:
92       EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs)
93         : Costs(Costs) {
94         NIds[0] = N1Id;
95         NIds[1] = N2Id;
96         ThisEdgeAdjIdxs[0] = NodeEntry::getInvalidAdjEdgeIdx();
97         ThisEdgeAdjIdxs[1] = NodeEntry::getInvalidAdjEdgeIdx();
98       }
99
100       void invalidate() {
101         NIds[0] = NIds[1] = Graph::invalidNodeId();
102         ThisEdgeAdjIdxs[0] = ThisEdgeAdjIdxs[1] =
103           NodeEntry::getInvalidAdjEdgeIdx();
104         Costs = nullptr;
105       }
106
107       void connectToN(Graph &G, EdgeId ThisEdgeId, unsigned NIdx) {
108         assert(ThisEdgeAdjIdxs[NIdx] == NodeEntry::getInvalidAdjEdgeIdx() &&
109                "Edge already connected to NIds[NIdx].");
110         NodeEntry &N = G.getNode(NIds[NIdx]);
111         ThisEdgeAdjIdxs[NIdx] = N.addAdjEdgeId(ThisEdgeId);
112       }
113
114       void connectTo(Graph &G, EdgeId ThisEdgeId, NodeId NId) {
115         if (NId == NIds[0])
116           connectToN(G, ThisEdgeId, 0);
117         else {
118           assert(NId == NIds[1] && "Edge does not connect NId.");
119           connectToN(G, ThisEdgeId, 1);
120         }
121       }
122
123       void connect(Graph &G, EdgeId ThisEdgeId) {
124         connectToN(G, ThisEdgeId, 0);
125         connectToN(G, ThisEdgeId, 1);
126       }
127
128       void updateAdjEdgeIdx(NodeId NId, typename NodeEntry::AdjEdgeIdx NewIdx) {
129         if (NId == NIds[0])
130           ThisEdgeAdjIdxs[0] = NewIdx;
131         else {
132           assert(NId == NIds[1] && "Edge not connected to NId");
133           ThisEdgeAdjIdxs[1] = NewIdx;
134         }
135       }
136
137       void disconnectFromN(Graph &G, unsigned NIdx) {
138         assert(ThisEdgeAdjIdxs[NIdx] != NodeEntry::getInvalidAdjEdgeIdx() &&
139                "Edge not connected to NIds[NIdx].");
140         NodeEntry &N = G.getNode(NIds[NIdx]);
141         EdgeId EIdToUpdate = N.removeAdjEdgeId(ThisEdgeAdjIdxs[NIdx]);
142         if (EIdToUpdate != Graph::invalidEdgeId())
143           G.getEdge(EIdToUpdate).updateAdjEdgeIdx(NIds[NIdx], ThisEdgeAdjIdxs[NIdx]);
144         ThisEdgeAdjIdxs[NIdx] = NodeEntry::getInvalidAdjEdgeIdx();
145       }
146
147       void disconnectFrom(Graph &G, NodeId NId) {
148         if (NId == NIds[0])
149           disconnectFromN(G, 0);
150         else {
151           assert(NId == NIds[1] && "Edge does not connect NId");
152           disconnectFromN(G, 1);
153         }
154       }
155
156       NodeId getN1Id() const { return NIds[0]; }
157       NodeId getN2Id() const { return NIds[1]; }
158       MatrixPtr Costs;
159       EdgeMetadata Metadata;
160     private:
161       NodeId NIds[2];
162       typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
163     };
164
165     // ----- MEMBERS -----
166
167     CostAllocator CostAlloc;
168     SolverT *Solver;
169
170     typedef std::vector<NodeEntry> NodeVector;
171     typedef std::vector<NodeId> FreeNodeVector;
172     NodeVector Nodes;
173     FreeNodeVector FreeNodeIds;
174
175     typedef std::vector<EdgeEntry> EdgeVector;
176     typedef std::vector<EdgeId> FreeEdgeVector;
177     EdgeVector Edges;
178     FreeEdgeVector FreeEdgeIds;
179
180     // ----- INTERNAL METHODS -----
181
182     NodeEntry& getNode(NodeId NId) { return Nodes[NId]; }
183     const NodeEntry& getNode(NodeId NId) const { return Nodes[NId]; }
184
185     EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
186     const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
187
188     NodeId addConstructedNode(const NodeEntry &N) {
189       NodeId NId = 0;
190       if (!FreeNodeIds.empty()) {
191         NId = FreeNodeIds.back();
192         FreeNodeIds.pop_back();
193         Nodes[NId] = std::move(N);
194       } else {
195         NId = Nodes.size();
196         Nodes.push_back(std::move(N));
197       }
198       return NId;
199     }
200
201     EdgeId addConstructedEdge(const EdgeEntry &E) {
202       assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
203              "Attempt to add duplicate edge.");
204       EdgeId EId = 0;
205       if (!FreeEdgeIds.empty()) {
206         EId = FreeEdgeIds.back();
207         FreeEdgeIds.pop_back();
208         Edges[EId] = std::move(E);
209       } else {
210         EId = Edges.size();
211         Edges.push_back(std::move(E));
212       }
213
214       EdgeEntry &NE = getEdge(EId);
215
216       // Add the edge to the adjacency sets of its nodes.
217       NE.connect(*this, EId);
218       return EId;
219     }
220
221     Graph(const Graph &Other) {}
222     void operator=(const Graph &Other) {}
223
224   public:
225
226     typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr;
227
228     class NodeItr {
229     public:
230       NodeItr(NodeId CurNId, const Graph &G)
231         : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
232         this->CurNId = findNextInUse(CurNId); // Move to first in-use node id
233       }
234
235       bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; }
236       bool operator!=(const NodeItr &O) const { return !(*this == O); }
237       NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; }
238       NodeId operator*() const { return CurNId; }
239
240     private:
241       NodeId findNextInUse(NodeId NId) const {
242         while (NId < EndNId &&
243                std::find(FreeNodeIds.begin(), FreeNodeIds.end(), NId) !=
244                  FreeNodeIds.end()) {
245           ++NId;
246         }
247         return NId;
248       }
249
250       NodeId CurNId, EndNId;
251       const FreeNodeVector &FreeNodeIds;
252     };
253
254     class EdgeItr {
255     public:
256       EdgeItr(EdgeId CurEId, const Graph &G)
257         : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) {
258         this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id
259       }
260
261       bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; }
262       bool operator!=(const EdgeItr &O) const { return !(*this == O); }
263       EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; }
264       EdgeId operator*() const { return CurEId; }
265
266     private:
267       EdgeId findNextInUse(EdgeId EId) const {
268         while (EId < EndEId &&
269                std::find(FreeEdgeIds.begin(), FreeEdgeIds.end(), EId) !=
270                FreeEdgeIds.end()) {
271           ++EId;
272         }
273         return EId;
274       }
275
276       EdgeId CurEId, EndEId;
277       const FreeEdgeVector &FreeEdgeIds;
278     };
279
280     class NodeIdSet {
281     public:
282       NodeIdSet(const Graph &G) : G(G) { }
283       NodeItr begin() const { return NodeItr(0, G); }
284       NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
285       bool empty() const { return G.Nodes.empty(); }
286       typename NodeVector::size_type size() const {
287         return G.Nodes.size() - G.FreeNodeIds.size();
288       }
289     private:
290       const Graph& G;
291     };
292
293     class EdgeIdSet {
294     public:
295       EdgeIdSet(const Graph &G) : G(G) { }
296       EdgeItr begin() const { return EdgeItr(0, G); }
297       EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
298       bool empty() const { return G.Edges.empty(); }
299       typename NodeVector::size_type size() const {
300         return G.Edges.size() - G.FreeEdgeIds.size();
301       }
302     private:
303       const Graph& G;
304     };
305
306     class AdjEdgeIdSet {
307     public:
308       AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) { }
309       typename NodeEntry::AdjEdgeItr begin() const {
310         return NE.getAdjEdgeIds().begin();
311       }
312       typename NodeEntry::AdjEdgeItr end() const {
313         return NE.getAdjEdgeIds().end();
314       }
315       bool empty() const { return NE.getAdjEdgeIds().empty(); }
316       typename NodeEntry::AdjEdgeList::size_type size() const {
317         return NE.getAdjEdgeIds().size();
318       }
319     private:
320       const NodeEntry &NE;
321     };
322
323     /// \brief Construct an empty PBQP graph.
324     Graph() : Solver(nullptr) { }
325
326     /// \brief Lock this graph to the given solver instance in preparation
327     /// for running the solver. This method will call solver.handleAddNode for
328     /// each node in the graph, and handleAddEdge for each edge, to give the
329     /// solver an opportunity to set up any requried metadata.
330     void setSolver(SolverT &S) {
331       assert(Solver == nullptr && "Solver already set. Call unsetSolver().");
332       Solver = &S;
333       for (auto NId : nodeIds())
334         Solver->handleAddNode(NId);
335       for (auto EId : edgeIds())
336         Solver->handleAddEdge(EId);
337     }
338
339     /// \brief Release from solver instance.
340     void unsetSolver() {
341       assert(Solver != nullptr && "Solver not set.");
342       Solver = nullptr;
343     }
344
345     /// \brief Add a node with the given costs.
346     /// @param Costs Cost vector for the new node.
347     /// @return Node iterator for the added node.
348     template <typename OtherVectorT>
349     NodeId addNode(OtherVectorT Costs) {
350       // Get cost vector from the problem domain
351       VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
352       NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts));
353       if (Solver)
354         Solver->handleAddNode(NId);
355       return NId;
356     }
357
358     /// \brief Add an edge between the given nodes with the given costs.
359     /// @param N1Id First node.
360     /// @param N2Id Second node.
361     /// @return Edge iterator for the added edge.
362     template <typename OtherVectorT>
363     EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
364       assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
365              getNodeCosts(N2Id).getLength() == Costs.getCols() &&
366              "Matrix dimensions mismatch.");
367       // Get cost matrix from the problem domain.
368       MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
369       EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts));
370       if (Solver)
371         Solver->handleAddEdge(EId);
372       return EId;
373     }
374
375     /// \brief Returns true if the graph is empty.
376     bool empty() const { return NodeIdSet(*this).empty(); }
377
378     NodeIdSet nodeIds() const { return NodeIdSet(*this); }
379     EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
380
381     AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
382
383     /// \brief Get the number of nodes in the graph.
384     /// @return Number of nodes in the graph.
385     unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
386
387     /// \brief Get the number of edges in the graph.
388     /// @return Number of edges in the graph.
389     unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
390
391     /// \brief Set a node's cost vector.
392     /// @param NId Node to update.
393     /// @param Costs New costs to set.
394     template <typename OtherVectorT>
395     void setNodeCosts(NodeId NId, OtherVectorT Costs) {
396       VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
397       if (Solver)
398         Solver->handleSetNodeCosts(NId, *AllocatedCosts);
399       getNode(NId).Costs = AllocatedCosts;
400     }
401
402     /// \brief Get a node's cost vector (const version).
403     /// @param NId Node id.
404     /// @return Node cost vector.
405     const Vector& getNodeCosts(NodeId NId) const {
406       return *getNode(NId).Costs;
407     }
408
409     NodeMetadata& getNodeMetadata(NodeId NId) {
410       return getNode(NId).Metadata;
411     }
412
413     const NodeMetadata& getNodeMetadata(NodeId NId) const {
414       return getNode(NId).Metadata;
415     }
416
417     typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
418       return getNode(NId).getAdjEdgeIds().size();
419     }
420
421     /// \brief Set an edge's cost matrix.
422     /// @param EId Edge id.
423     /// @param Costs New cost matrix.
424     template <typename OtherMatrixT>
425     void setEdgeCosts(EdgeId EId, OtherMatrixT Costs) {
426       MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
427       if (Solver)
428         Solver->handleSetEdgeCosts(EId, *AllocatedCosts);
429       getEdge(EId).Costs = AllocatedCosts;
430     }
431
432     /// \brief Get an edge's cost matrix (const version).
433     /// @param EId Edge id.
434     /// @return Edge cost matrix.
435     const Matrix& getEdgeCosts(EdgeId EId) const { return *getEdge(EId).Costs; }
436
437     EdgeMetadata& getEdgeMetadata(EdgeId NId) {
438       return getEdge(NId).Metadata;
439     }
440
441     const EdgeMetadata& getEdgeMetadata(EdgeId NId) const {
442       return getEdge(NId).Metadata;
443     }
444
445     /// \brief Get the first node connected to this edge.
446     /// @param EId Edge id.
447     /// @return The first node connected to the given edge.
448     NodeId getEdgeNode1Id(EdgeId EId) {
449       return getEdge(EId).getN1Id();
450     }
451
452     /// \brief Get the second node connected to this edge.
453     /// @param EId Edge id.
454     /// @return The second node connected to the given edge.
455     NodeId getEdgeNode2Id(EdgeId EId) {
456       return getEdge(EId).getN2Id();
457     }
458
459     /// \brief Get the "other" node connected to this edge.
460     /// @param EId Edge id.
461     /// @param NId Node id for the "given" node.
462     /// @return The iterator for the "other" node connected to this edge.
463     NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
464       EdgeEntry &E = getEdge(EId);
465       if (E.getN1Id() == NId) {
466         return E.getN2Id();
467       } // else
468       return E.getN1Id();
469     }
470
471     /// \brief Returns a value representing an invalid (non-existant) node.
472     static NodeId invalidNodeId() {
473       return std::numeric_limits<NodeId>::max();
474     }
475
476     /// \brief Returns a value representing an invalid (non-existant) edge.
477     static EdgeId invalidEdgeId() {
478       return std::numeric_limits<EdgeId>::max();
479     }
480
481     /// \brief Get the edge connecting two nodes.
482     /// @param N1Id First node id.
483     /// @param N2Id Second node id.
484     /// @return An id for edge (N1Id, N2Id) if such an edge exists,
485     ///         otherwise returns an invalid edge id.
486     EdgeId findEdge(NodeId N1Id, NodeId N2Id) {
487       for (auto AEId : adjEdgeIds(N1Id)) {
488         if ((getEdgeNode1Id(AEId) == N2Id) ||
489             (getEdgeNode2Id(AEId) == N2Id)) {
490           return AEId;
491         }
492       }
493       return invalidEdgeId();
494     }
495
496     /// \brief Remove a node from the graph.
497     /// @param NId Node id.
498     void removeNode(NodeId NId) {
499       if (Solver)
500         Solver->handleRemoveNode(NId);
501       NodeEntry &N = getNode(NId);
502       // TODO: Can this be for-each'd?
503       for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
504                       AEEnd = N.adjEdgesEnd();
505            AEItr != AEEnd;) {
506         EdgeId EId = *AEItr;
507         ++AEItr;
508         removeEdge(EId);
509       }
510       FreeNodeIds.push_back(NId);
511     }
512
513     /// \brief Disconnect an edge from the given node.
514     ///
515     /// Removes the given edge from the adjacency list of the given node.
516     /// This operation leaves the edge in an 'asymmetric' state: It will no
517     /// longer appear in an iteration over the given node's (NId's) edges, but
518     /// will appear in an iteration over the 'other', unnamed node's edges.
519     ///
520     /// This does not correspond to any normal graph operation, but exists to
521     /// support efficient PBQP graph-reduction based solvers. It is used to
522     /// 'effectively' remove the unnamed node from the graph while the solver
523     /// is performing the reduction. The solver will later call reconnectNode
524     /// to restore the edge in the named node's adjacency list.
525     ///
526     /// Since the degree of a node is the number of connected edges,
527     /// disconnecting an edge from a node 'u' will cause the degree of 'u' to
528     /// drop by 1.
529     ///
530     /// A disconnected edge WILL still appear in an iteration over the graph
531     /// edges.
532     ///
533     /// A disconnected edge should not be removed from the graph, it should be
534     /// reconnected first.
535     ///
536     /// A disconnected edge can be reconnected by calling the reconnectEdge
537     /// method.
538     void disconnectEdge(EdgeId EId, NodeId NId) {
539       if (Solver)
540         Solver->handleDisconnectEdge(EId, NId);
541
542       EdgeEntry &E = getEdge(EId);
543       E.disconnectFrom(*this, NId);
544     }
545
546     /// \brief Convenience method to disconnect all neighbours from the given
547     ///        node.
548     void disconnectAllNeighborsFromNode(NodeId NId) {
549       for (auto AEId : adjEdgeIds(NId))
550         disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
551     }
552
553     /// \brief Re-attach an edge to its nodes.
554     ///
555     /// Adds an edge that had been previously disconnected back into the
556     /// adjacency set of the nodes that the edge connects.
557     void reconnectEdge(EdgeId EId, NodeId NId) {
558       EdgeEntry &E = getEdge(EId);
559       E.connectTo(*this, EId, NId);
560       if (Solver)
561         Solver->handleReconnectEdge(EId, NId);
562     }
563
564     /// \brief Remove an edge from the graph.
565     /// @param EId Edge id.
566     void removeEdge(EdgeId EId) {
567       if (Solver)
568         Solver->handleRemoveEdge(EId);
569       EdgeEntry &E = getEdge(EId);
570       E.disconnect();
571       FreeEdgeIds.push_back(EId);
572       Edges[EId].invalidate();
573     }
574
575     /// \brief Remove all nodes and edges from the graph.
576     void clear() {
577       Nodes.clear();
578       FreeNodeIds.clear();
579       Edges.clear();
580       FreeEdgeIds.clear();
581     }
582
583     /// \brief Dump a graph to an output stream.
584     template <typename OStream>
585     void dump(OStream &OS) {
586       OS << nodeIds().size() << " " << edgeIds().size() << "\n";
587
588       for (auto NId : nodeIds()) {
589         const Vector& V = getNodeCosts(NId);
590         OS << "\n" << V.getLength() << "\n";
591         assert(V.getLength() != 0 && "Empty vector in graph.");
592         OS << V[0];
593         for (unsigned i = 1; i < V.getLength(); ++i) {
594           OS << " " << V[i];
595         }
596         OS << "\n";
597       }
598
599       for (auto EId : edgeIds()) {
600         NodeId N1Id = getEdgeNode1Id(EId);
601         NodeId N2Id = getEdgeNode2Id(EId);
602         assert(N1Id != N2Id && "PBQP graphs shound not have self-edges.");
603         const Matrix& M = getEdgeCosts(EId);
604         OS << "\n" << N1Id << " " << N2Id << "\n"
605            << M.getRows() << " " << M.getCols() << "\n";
606         assert(M.getRows() != 0 && "No rows in matrix.");
607         assert(M.getCols() != 0 && "No cols in matrix.");
608         for (unsigned i = 0; i < M.getRows(); ++i) {
609           OS << M[i][0];
610           for (unsigned j = 1; j < M.getCols(); ++j) {
611             OS << " " << M[i][j];
612           }
613           OS << "\n";
614         }
615       }
616     }
617
618     /// \brief Print a representation of this graph in DOT format.
619     /// @param OS Output stream to print on.
620     template <typename OStream>
621     void printDot(OStream &OS) {
622       OS << "graph {\n";
623       for (auto NId : nodeIds()) {
624         OS << "  node" << NId << " [ label=\""
625            << NId << ": " << getNodeCosts(NId) << "\" ]\n";
626       }
627       OS << "  edge [ len=" << nodeIds().size() << " ]\n";
628       for (auto EId : edgeIds()) {
629         OS << "  node" << getEdgeNode1Id(EId)
630            << " -- node" << getEdgeNode2Id(EId)
631            << " [ label=\"";
632         const Matrix &EdgeCosts = getEdgeCosts(EId);
633         for (unsigned i = 0; i < EdgeCosts.getRows(); ++i) {
634           OS << EdgeCosts.getRowAsVector(i) << "\\n";
635         }
636         OS << "\" ]\n";
637       }
638       OS << "}\n";
639     }
640   };
641
642 }
643
644 #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP