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