//===-------------------- 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