| //===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // PBQP Graph class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_CODEGEN_PBQP_GRAPH_H | |
| #define LLVM_CODEGEN_PBQP_GRAPH_H | |
| #include "Math.h" | |
| #include <list> | |
| #include <map> | |
| namespace PBQP { | |
| /// PBQP Graph class. | |
| /// Instances of this class describe PBQP problems. | |
| class Graph { | |
| private: | |
| // ----- TYPEDEFS ----- | |
| class NodeEntry; | |
| class EdgeEntry; | |
| typedef std::list<NodeEntry> NodeList; | |
| typedef std::list<EdgeEntry> EdgeList; | |
| public: | |
| typedef NodeList::iterator NodeItr; | |
| typedef NodeList::const_iterator ConstNodeItr; | |
| typedef EdgeList::iterator EdgeItr; | |
| typedef EdgeList::const_iterator ConstEdgeItr; | |
| private: | |
| typedef std::list<EdgeItr> AdjEdgeList; | |
| public: | |
| typedef AdjEdgeList::iterator AdjEdgeItr; | |
| private: | |
| class NodeEntry { | |
| private: | |
| Vector costs; | |
| AdjEdgeList adjEdges; | |
| unsigned degree; | |
| void *data; | |
| public: | |
| NodeEntry(const Vector &costs) : costs(costs), degree(0) {} | |
| Vector& getCosts() { return costs; } | |
| const Vector& getCosts() const { return costs; } | |
| unsigned getDegree() const { return degree; } | |
| AdjEdgeItr edgesBegin() { return adjEdges.begin(); } | |
| AdjEdgeItr edgesEnd() { return adjEdges.end(); } | |
| AdjEdgeItr addEdge(EdgeItr e) { | |
| ++degree; | |
| return adjEdges.insert(adjEdges.end(), e); | |
| } | |
| void removeEdge(AdjEdgeItr ae) { | |
| --degree; | |
| adjEdges.erase(ae); | |
| } | |
| void setData(void *data) { this->data = data; } | |
| void* getData() { return data; } | |
| }; | |
| class EdgeEntry { | |
| private: | |
| NodeItr node1, node2; | |
| Matrix costs; | |
| AdjEdgeItr node1AEItr, node2AEItr; | |
| void *data; | |
| public: | |
| EdgeEntry(NodeItr node1, NodeItr node2, const Matrix &costs) | |
| : node1(node1), node2(node2), costs(costs) {} | |
| NodeItr getNode1() const { return node1; } | |
| NodeItr getNode2() const { return node2; } | |
| Matrix& getCosts() { return costs; } | |
| const Matrix& getCosts() const { return costs; } | |
| void setNode1AEItr(AdjEdgeItr ae) { node1AEItr = ae; } | |
| AdjEdgeItr getNode1AEItr() { return node1AEItr; } | |
| void setNode2AEItr(AdjEdgeItr ae) { node2AEItr = ae; } | |
| AdjEdgeItr getNode2AEItr() { return node2AEItr; } | |
| void setData(void *data) { this->data = data; } | |
| void *getData() { return data; } | |
| }; | |
| // ----- MEMBERS ----- | |
| NodeList nodes; | |
| unsigned numNodes; | |
| EdgeList edges; | |
| unsigned numEdges; | |
| // ----- INTERNAL METHODS ----- | |
| NodeEntry& getNode(NodeItr nItr) { return *nItr; } | |
| const NodeEntry& getNode(ConstNodeItr nItr) const { return *nItr; } | |
| EdgeEntry& getEdge(EdgeItr eItr) { return *eItr; } | |
| const EdgeEntry& getEdge(ConstEdgeItr eItr) const { return *eItr; } | |
| NodeItr addConstructedNode(const NodeEntry &n) { | |
| ++numNodes; | |
| return nodes.insert(nodes.end(), n); | |
| } | |
| EdgeItr addConstructedEdge(const EdgeEntry &e) { | |
| assert(findEdge(e.getNode1(), e.getNode2()) == edges.end() && | |
| "Attempt to add duplicate edge."); | |
| ++numEdges; | |
| EdgeItr edgeItr = edges.insert(edges.end(), e); | |
| EdgeEntry &ne = getEdge(edgeItr); | |
| NodeEntry &n1 = getNode(ne.getNode1()); | |
| NodeEntry &n2 = getNode(ne.getNode2()); | |
| // Sanity check on matrix dimensions: | |
| assert((n1.getCosts().getLength() == ne.getCosts().getRows()) && | |
| (n2.getCosts().getLength() == ne.getCosts().getCols()) && | |
| "Edge cost dimensions do not match node costs dimensions."); | |
| ne.setNode1AEItr(n1.addEdge(edgeItr)); | |
| ne.setNode2AEItr(n2.addEdge(edgeItr)); | |
| return edgeItr; | |
| } | |
| inline void copyFrom(const Graph &other); | |
| public: | |
| /// \brief Construct an empty PBQP graph. | |
| Graph() : numNodes(0), numEdges(0) {} | |
| /// \brief Copy construct this graph from "other". Note: Does not copy node | |
| /// and edge data, only graph structure and costs. | |
| /// @param other Source graph to copy from. | |
| Graph(const Graph &other) : numNodes(0), numEdges(0) { | |
| copyFrom(other); | |
| } | |
| /// \brief Make this graph a copy of "other". Note: Does not copy node and | |
| /// edge data, only graph structure and costs. | |
| /// @param other The graph to copy from. | |
| /// @return A reference to this graph. | |
| /// | |
| /// This will clear the current graph, erasing any nodes and edges added, | |
| /// before copying from other. | |
| Graph& operator=(const Graph &other) { | |
| clear(); | |
| copyFrom(other); | |
| return *this; | |
| } | |
| /// \brief Add a node with the given costs. | |
| /// @param costs Cost vector for the new node. | |
| /// @return Node iterator for the added node. | |
| NodeItr addNode(const Vector &costs) { | |
| return addConstructedNode(NodeEntry(costs)); | |
| } | |
| /// \brief Add an edge between the given nodes with the given costs. | |
| /// @param n1Itr First node. | |
| /// @param n2Itr Second node. | |
| /// @return Edge iterator for the added edge. | |
| EdgeItr addEdge(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr, | |
| const Matrix &costs) { | |
| assert(getNodeCosts(n1Itr).getLength() == costs.getRows() && | |
| getNodeCosts(n2Itr).getLength() == costs.getCols() && | |
| "Matrix dimensions mismatch."); | |
| return addConstructedEdge(EdgeEntry(n1Itr, n2Itr, costs)); | |
| } | |
| /// \brief Get the number of nodes in the graph. | |
| /// @return Number of nodes in the graph. | |
| unsigned getNumNodes() const { return numNodes; } | |
| /// \brief Get the number of edges in the graph. | |
| /// @return Number of edges in the graph. | |
| unsigned getNumEdges() const { return numEdges; } | |
| /// \brief Get a node's cost vector. | |
| /// @param nItr Node iterator. | |
| /// @return Node cost vector. | |
| Vector& getNodeCosts(NodeItr nItr) { return getNode(nItr).getCosts(); } | |
| /// \brief Get a node's cost vector (const version). | |
| /// @param nItr Node iterator. | |
| /// @return Node cost vector. | |
| const Vector& getNodeCosts(ConstNodeItr nItr) const { | |
| return getNode(nItr).getCosts(); | |
| } | |
| /// \brief Set a node's data pointer. | |
| /// @param nItr Node iterator. | |
| /// @param data Pointer to node data. | |
| /// | |
| /// Typically used by a PBQP solver to attach data to aid in solution. | |
| void setNodeData(NodeItr nItr, void *data) { getNode(nItr).setData(data); } | |
| /// \brief Get the node's data pointer. | |
| /// @param nItr Node iterator. | |
| /// @return Pointer to node data. | |
| void* getNodeData(NodeItr nItr) { return getNode(nItr).getData(); } | |
| /// \brief Get an edge's cost matrix. | |
| /// @param eItr Edge iterator. | |
| /// @return Edge cost matrix. | |
| Matrix& getEdgeCosts(EdgeItr eItr) { return getEdge(eItr).getCosts(); } | |
| /// \brief Get an edge's cost matrix (const version). | |
| /// @param eItr Edge iterator. | |
| /// @return Edge cost matrix. | |
| const Matrix& getEdgeCosts(ConstEdgeItr eItr) const { | |
| return getEdge(eItr).getCosts(); | |
| } | |
| /// \brief Set an edge's data pointer. | |
| /// @param eItr Edge iterator. | |
| /// @param data Pointer to edge data. | |
| /// | |
| /// Typically used by a PBQP solver to attach data to aid in solution. | |
| void setEdgeData(EdgeItr eItr, void *data) { getEdge(eItr).setData(data); } | |
| /// \brief Get an edge's data pointer. | |
| /// @param eItr Edge iterator. | |
| /// @return Pointer to edge data. | |
| void* getEdgeData(EdgeItr eItr) { return getEdge(eItr).getData(); } | |
| /// \brief Get a node's degree. | |
| /// @param nItr Node iterator. | |
| /// @return The degree of the node. | |
| unsigned getNodeDegree(NodeItr nItr) const { | |
| return getNode(nItr).getDegree(); | |
| } | |
| /// \brief Begin iterator for node set. | |
| NodeItr nodesBegin() { return nodes.begin(); } | |
| /// \brief Begin const iterator for node set. | |
| ConstNodeItr nodesBegin() const { return nodes.begin(); } | |
| /// \brief End iterator for node set. | |
| NodeItr nodesEnd() { return nodes.end(); } | |
| /// \brief End const iterator for node set. | |
| ConstNodeItr nodesEnd() const { return nodes.end(); } | |
| /// \brief Begin iterator for edge set. | |
| EdgeItr edgesBegin() { return edges.begin(); } | |
| /// \brief End iterator for edge set. | |
| EdgeItr edgesEnd() { return edges.end(); } | |
| /// \brief Get begin iterator for adjacent edge set. | |
| /// @param nItr Node iterator. | |
| /// @return Begin iterator for the set of edges connected to the given node. | |
| AdjEdgeItr adjEdgesBegin(NodeItr nItr) { | |
| return getNode(nItr).edgesBegin(); | |
| } | |
| /// \brief Get end iterator for adjacent edge set. | |
| /// @param nItr Node iterator. | |
| /// @return End iterator for the set of edges connected to the given node. | |
| AdjEdgeItr adjEdgesEnd(NodeItr nItr) { | |
| return getNode(nItr).edgesEnd(); | |
| } | |
| /// \brief Get the first node connected to this edge. | |
| /// @param eItr Edge iterator. | |
| /// @return The first node connected to the given edge. | |
| NodeItr getEdgeNode1(EdgeItr eItr) { | |
| return getEdge(eItr).getNode1(); | |
| } | |
| /// \brief Get the second node connected to this edge. | |
| /// @param eItr Edge iterator. | |
| /// @return The second node connected to the given edge. | |
| NodeItr getEdgeNode2(EdgeItr eItr) { | |
| return getEdge(eItr).getNode2(); | |
| } | |
| /// \brief Get the "other" node connected to this edge. | |
| /// @param eItr Edge iterator. | |
| /// @param nItr Node iterator for the "given" node. | |
| /// @return The iterator for the "other" node connected to this edge. | |
| NodeItr getEdgeOtherNode(EdgeItr eItr, NodeItr nItr) { | |
| EdgeEntry &e = getEdge(eItr); | |
| if (e.getNode1() == nItr) { | |
| return e.getNode2(); | |
| } // else | |
| return e.getNode1(); | |
| } | |
| /// \brief Get the edge connecting two nodes. | |
| /// @param n1Itr First node iterator. | |
| /// @param n2Itr Second node iterator. | |
| /// @return An iterator for edge (n1Itr, n2Itr) if such an edge exists, | |
| /// otherwise returns edgesEnd(). | |
| EdgeItr findEdge(NodeItr n1Itr, NodeItr n2Itr) { | |
| for (AdjEdgeItr aeItr = adjEdgesBegin(n1Itr), aeEnd = adjEdgesEnd(n1Itr); | |
| aeItr != aeEnd; ++aeItr) { | |
| if ((getEdgeNode1(*aeItr) == n2Itr) || | |
| (getEdgeNode2(*aeItr) == n2Itr)) { | |
| return *aeItr; | |
| } | |
| } | |
| return edges.end(); | |
| } | |
| /// \brief Remove a node from the graph. | |
| /// @param nItr Node iterator. | |
| void removeNode(NodeItr nItr) { | |
| NodeEntry &n = getNode(nItr); | |
| for (AdjEdgeItr itr = n.edgesBegin(), end = n.edgesEnd(); itr != end;) { | |
| EdgeItr eItr = *itr; | |
| ++itr; | |
| removeEdge(eItr); | |
| } | |
| nodes.erase(nItr); | |
| --numNodes; | |
| } | |
| /// \brief Remove an edge from the graph. | |
| /// @param eItr Edge iterator. | |
| void removeEdge(EdgeItr eItr) { | |
| EdgeEntry &e = getEdge(eItr); | |
| NodeEntry &n1 = getNode(e.getNode1()); | |
| NodeEntry &n2 = getNode(e.getNode2()); | |
| n1.removeEdge(e.getNode1AEItr()); | |
| n2.removeEdge(e.getNode2AEItr()); | |
| edges.erase(eItr); | |
| --numEdges; | |
| } | |
| /// \brief Remove all nodes and edges from the graph. | |
| void clear() { | |
| nodes.clear(); | |
| edges.clear(); | |
| numNodes = numEdges = 0; | |
| } | |
| /// \brief Print a representation of this graph in DOT format. | |
| /// @param os Output stream to print on. | |
| template <typename OStream> | |
| void printDot(OStream &os) { | |
| os << "graph {\n"; | |
| for (NodeItr nodeItr = nodesBegin(), nodeEnd = nodesEnd(); | |
| nodeItr != nodeEnd; ++nodeItr) { | |
| os << " node" << nodeItr << " [ label=\"" | |
| << nodeItr << ": " << getNodeCosts(nodeItr) << "\" ]\n"; | |
| } | |
| os << " edge [ len=" << getNumNodes() << " ]\n"; | |
| for (EdgeItr edgeItr = edgesBegin(), edgeEnd = edgesEnd(); | |
| edgeItr != edgeEnd; ++edgeItr) { | |
| os << " node" << getEdgeNode1(edgeItr) | |
| << " -- node" << getEdgeNode2(edgeItr) | |
| << " [ label=\""; | |
| const Matrix &edgeCosts = getEdgeCosts(edgeItr); | |
| for (unsigned i = 0; i < edgeCosts.getRows(); ++i) { | |
| os << edgeCosts.getRowAsVector(i) << "\\n"; | |
| } | |
| os << "\" ]\n"; | |
| } | |
| os << "}\n"; | |
| } | |
| }; | |
| class NodeItrComparator { | |
| public: | |
| bool operator()(Graph::NodeItr n1, Graph::NodeItr n2) const { | |
| return &*n1 < &*n2; | |
| } | |
| bool operator()(Graph::ConstNodeItr n1, Graph::ConstNodeItr n2) const { | |
| return &*n1 < &*n2; | |
| } | |
| }; | |
| class EdgeItrCompartor { | |
| public: | |
| bool operator()(Graph::EdgeItr e1, Graph::EdgeItr e2) const { | |
| return &*e1 < &*e2; | |
| } | |
| bool operator()(Graph::ConstEdgeItr e1, Graph::ConstEdgeItr e2) const { | |
| return &*e1 < &*e2; | |
| } | |
| }; | |
| void Graph::copyFrom(const Graph &other) { | |
| std::map<Graph::ConstNodeItr, Graph::NodeItr, | |
| NodeItrComparator> nodeMap; | |
| for (Graph::ConstNodeItr nItr = other.nodesBegin(), | |
| nEnd = other.nodesEnd(); | |
| nItr != nEnd; ++nItr) { | |
| nodeMap[nItr] = addNode(other.getNodeCosts(nItr)); | |
| } | |
| } | |
| } | |
| #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP |