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