//===-- GraphBase.h - Abstract Base PBQP Graph ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Base class for PBQP Graphs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_PBQP_GRAPHBASE_H #define LLVM_CODEGEN_PBQP_GRAPHBASE_H #include "PBQPMath.h" #include #include namespace PBQP { // UGLY, but I'm not sure there's a good way around this: We need to be able to // look up a Node's "adjacent edge list" structure type before the Node type is // fully constructed. We can enable this by pushing the choice of data type // out into this traits class. template class NodeBaseTraits { public: typedef std::list AdjEdgeList; typedef typename AdjEdgeList::iterator AdjEdgeIterator; typedef typename AdjEdgeList::const_iterator ConstAdjEdgeIterator; }; /// \brief Base for concrete graph classes. Provides a basic set of graph /// operations which are useful for PBQP solvers. template class GraphBase { private: typedef GraphBase ThisGraphT; typedef std::list NodeList; typedef std::list EdgeList; NodeList nodeList; unsigned nodeListSize; EdgeList edgeList; unsigned edgeListSize; GraphBase(const ThisGraphT &other) { abort(); } void operator=(const ThisGraphT &other) { abort(); } public: /// \brief Iterates over the nodes of a graph. typedef typename NodeList::iterator NodeIterator; /// \brief Iterates over the nodes of a const graph. typedef typename NodeList::const_iterator ConstNodeIterator; /// \brief Iterates over the edges of a graph. typedef typename EdgeList::iterator EdgeIterator; /// \brief Iterates over the edges of a const graph. typedef typename EdgeList::const_iterator ConstEdgeIterator; /// \brief Iterates over the edges attached to a node. typedef typename NodeBaseTraits::AdjEdgeIterator AdjEdgeIterator; /// \brief Iterates over the edges attached to a node in a const graph. typedef typename NodeBaseTraits::ConstAdjEdgeIterator ConstAdjEdgeIterator; private: typedef std::vector IDToNodeMap; IDToNodeMap idToNodeMap; bool nodeIDsValid; void invalidateNodeIDs() { if (nodeIDsValid) { idToNodeMap.clear(); nodeIDsValid = false; } } template bool iteratorInRange(ItrT itr, const ItrT &begin, const ItrT &end) { for (ItrT t = begin; t != end; ++t) { if (itr == t) return true; } return false; } protected: GraphBase() : nodeListSize(0), edgeListSize(0), nodeIDsValid(false) {} NodeEntry& getNodeEntry(const NodeIterator &nodeItr) { return *nodeItr; } const NodeEntry& getNodeEntry(const ConstNodeIterator &nodeItr) const { return *nodeItr; } EdgeEntry& getEdgeEntry(const EdgeIterator &edgeItr) { return *edgeItr; } const EdgeEntry& getEdgeEntry(const ConstEdgeIterator &edgeItr) const { return *edgeItr; } NodeIterator addConstructedNode(const NodeEntry &nodeEntry) { ++nodeListSize; invalidateNodeIDs(); NodeIterator newNodeItr = nodeList.insert(nodeList.end(), nodeEntry); return newNodeItr; } EdgeIterator addConstructedEdge(const EdgeEntry &edgeEntry) { assert((findEdge(edgeEntry.getNode1Itr(), edgeEntry.getNode2Itr()) == edgeList.end()) && "Attempt to add duplicate edge."); ++edgeListSize; // Add the edge to the graph. EdgeIterator edgeItr = edgeList.insert(edgeList.end(), edgeEntry); // Get a reference to the version in the graph. EdgeEntry &newEdgeEntry = getEdgeEntry(edgeItr); // Node entries: NodeEntry &node1Entry = getNodeEntry(newEdgeEntry.getNode1Itr()), &node2Entry = getNodeEntry(newEdgeEntry.getNode2Itr()); // Sanity check on matrix dimensions. assert((node1Entry.getCosts().getLength() == newEdgeEntry.getCosts().getRows()) && (node2Entry.getCosts().getLength() == newEdgeEntry.getCosts().getCols()) && "Matrix dimensions do not match cost vector dimensions."); // Create links between nodes and edges. newEdgeEntry.setNode1ThisEdgeItr( node1Entry.addAdjEdge(edgeItr)); newEdgeEntry.setNode2ThisEdgeItr( node2Entry.addAdjEdge(edgeItr)); return edgeItr; } public: /// \brief Returns the number of nodes in this graph. unsigned getNumNodes() const { return nodeListSize; } /// \brief Returns the number of edges in this graph. unsigned getNumEdges() const { return edgeListSize; } /// \brief Return the cost vector for the given node. Vector& getNodeCosts(const NodeIterator &nodeItr) { return getNodeEntry(nodeItr).getCosts(); } /// \brief Return the cost vector for the give node. const Vector& getNodeCosts(const ConstNodeIterator &nodeItr) const { return getNodeEntry(nodeItr).getCosts(); } /// \brief Return the degree of the given node. unsigned getNodeDegree(const NodeIterator &nodeItr) const { return getNodeEntry(nodeItr).getDegree(); } /// \brief Assigns sequential IDs to the nodes, starting at 0, which /// remain valid until the next addition or removal of a node. void assignNodeIDs() { unsigned curID = 0; idToNodeMap.resize(getNumNodes()); for (NodeIterator nodeItr = nodesBegin(), nodeEnd = nodesEnd(); nodeItr != nodeEnd; ++nodeItr, ++curID) { getNodeEntry(nodeItr).setID(curID); idToNodeMap[curID] = nodeItr; } nodeIDsValid = true; } /// \brief Assigns sequential IDs to the nodes using the ordering of the /// given vector. void assignNodeIDs(const std::vector &nodeOrdering) { assert((getNumNodes() == nodeOrdering.size()) && "Wrong number of nodes in node ordering."); idToNodeMap = nodeOrdering; for (unsigned nodeID = 0; nodeID < idToNodeMap.size(); ++nodeID) { getNodeEntry(idToNodeMap[nodeID]).setID(nodeID); } nodeIDsValid = true; } /// \brief Returns true if valid node IDs are assigned, false otherwise. bool areNodeIDsValid() const { return nodeIDsValid; } /// \brief Return the numeric ID of the given node. /// /// Calls to this method will result in an assertion failure if there have /// been any node additions or removals since the last call to /// assignNodeIDs(). unsigned getNodeID(const ConstNodeIterator &nodeItr) const { assert(nodeIDsValid && "Attempt to retrieve invalid ID."); return getNodeEntry(nodeItr).getID(); } /// \brief Returns the iterator associated with the given node ID. NodeIterator getNodeItr(unsigned nodeID) { assert(nodeIDsValid && "Attempt to retrieve iterator with invalid ID."); return idToNodeMap[nodeID]; } /// \brief Returns the iterator associated with the given node ID. ConstNodeIterator getNodeItr(unsigned nodeID) const { assert(nodeIDsValid && "Attempt to retrieve iterator with invalid ID."); return idToNodeMap[nodeID]; } /// \brief Removes the given node (and all attached edges) from the graph. void removeNode(const NodeIterator &nodeItr) { assert(iteratorInRange(nodeItr, nodeList.begin(), nodeList.end()) && "Iterator does not belong to this graph!"); invalidateNodeIDs(); NodeEntry &nodeEntry = getNodeEntry(nodeItr); // We need to copy this out because it will be destroyed as the edges are // removed. typedef std::vector AdjEdgeList; typedef typename AdjEdgeList::iterator AdjEdgeListItr; AdjEdgeList adjEdges; adjEdges.reserve(nodeEntry.getDegree()); std::copy(nodeEntry.adjEdgesBegin(), nodeEntry.adjEdgesEnd(), std::back_inserter(adjEdges)); // Iterate over the copied out edges and remove them from the graph. for (AdjEdgeListItr itr = adjEdges.begin(), end = adjEdges.end(); itr != end; ++itr) { removeEdge(*itr); } // Erase the node from the nodelist. nodeList.erase(nodeItr); --nodeListSize; } NodeIterator nodesBegin() { return nodeList.begin(); } ConstNodeIterator nodesBegin() const { return nodeList.begin(); } NodeIterator nodesEnd() { return nodeList.end(); } ConstNodeIterator nodesEnd() const { return nodeList.end(); } AdjEdgeIterator adjEdgesBegin(const NodeIterator &nodeItr) { return getNodeEntry(nodeItr).adjEdgesBegin(); } ConstAdjEdgeIterator adjEdgesBegin(const ConstNodeIterator &nodeItr) const { return getNodeEntry(nodeItr).adjEdgesBegin(); } AdjEdgeIterator adjEdgesEnd(const NodeIterator &nodeItr) { return getNodeEntry(nodeItr).adjEdgesEnd(); } ConstAdjEdgeIterator adjEdgesEnd(const ConstNodeIterator &nodeItr) const { getNodeEntry(nodeItr).adjEdgesEnd(); } EdgeIterator findEdge(const NodeIterator &node1Itr, const NodeIterator &node2Itr) { for (AdjEdgeIterator adjEdgeItr = adjEdgesBegin(node1Itr), adjEdgeEnd = adjEdgesEnd(node1Itr); adjEdgeItr != adjEdgeEnd; ++adjEdgeItr) { if ((getEdgeNode1Itr(*adjEdgeItr) == node2Itr) || (getEdgeNode2Itr(*adjEdgeItr) == node2Itr)) { return *adjEdgeItr; } } return edgeList.end(); } ConstEdgeIterator findEdge(const ConstNodeIterator &node1Itr, const ConstNodeIterator &node2Itr) const { for (ConstAdjEdgeIterator adjEdgeItr = adjEdgesBegin(node1Itr), adjEdgeEnd = adjEdgesEnd(node1Itr); adjEdgeItr != adjEdgeEnd; ++adjEdgeItr) { if ((getEdgeNode1Itr(*adjEdgeItr) == node2Itr) || (getEdgeNode2Itr(*adjEdgeItr) == node2Itr)) { return *adjEdgeItr; } } return edgeList.end(); } Matrix& getEdgeCosts(const EdgeIterator &edgeItr) { return getEdgeEntry(edgeItr).getCosts(); } const Matrix& getEdgeCosts(const ConstEdgeIterator &edgeItr) const { return getEdgeEntry(edgeItr).getCosts(); } NodeIterator getEdgeNode1Itr(const EdgeIterator &edgeItr) { return getEdgeEntry(edgeItr).getNode1Itr(); } ConstNodeIterator getEdgeNode1Itr(const ConstEdgeIterator &edgeItr) const { return getEdgeEntry(edgeItr).getNode1Itr(); } NodeIterator getEdgeNode2Itr(const EdgeIterator &edgeItr) { return getEdgeEntry(edgeItr).getNode2Itr(); } ConstNodeIterator getEdgeNode2Itr(const ConstEdgeIterator &edgeItr) const { return getEdgeEntry(edgeItr).getNode2Itr(); } NodeIterator getEdgeOtherNode(const EdgeIterator &edgeItr, const NodeIterator &nodeItr) { EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); if (nodeItr == edgeEntry.getNode1Itr()) { return edgeEntry.getNode2Itr(); } //else return edgeEntry.getNode1Itr(); } ConstNodeIterator getEdgeOtherNode(const ConstEdgeIterator &edgeItr, const ConstNodeIterator &nodeItr) const { const EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); if (nodeItr == edgeEntry.getNode1Itr()) { return edgeEntry.getNode2Itr(); } //else return edgeEntry.getNode1Itr(); } void removeEdge(const EdgeIterator &edgeItr) { assert(iteratorInRange(edgeItr, edgeList.begin(), edgeList.end()) && "Iterator does not belong to this graph!"); --edgeListSize; // Get the edge entry. EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); // Get the nodes entry. NodeEntry &node1Entry(getNodeEntry(edgeEntry.getNode1Itr())), &node2Entry(getNodeEntry(edgeEntry.getNode2Itr())); // Disconnect the edge from the nodes. node1Entry.removeAdjEdge(edgeEntry.getNode1ThisEdgeItr()); node2Entry.removeAdjEdge(edgeEntry.getNode2ThisEdgeItr()); // Remove the edge from the graph. edgeList.erase(edgeItr); } EdgeIterator edgesBegin() { return edgeList.begin(); } ConstEdgeIterator edgesBegin() const { return edgeList.begin(); } EdgeIterator edgesEnd() { return edgeList.end(); } ConstEdgeIterator edgesEnd() const { return edgeList.end(); } void clear() { nodeList.clear(); nodeListSize = 0; edgeList.clear(); edgeListSize = 0; idToNodeMap.clear(); } template void printDot(OStream &os) const { assert(areNodeIDsValid() && "Cannot print a .dot of a graph unless IDs have been assigned."); os << "graph {\n"; for (ConstNodeIterator nodeItr = nodesBegin(), nodeEnd = nodesEnd(); nodeItr != nodeEnd; ++nodeItr) { os << " node" << getNodeID(nodeItr) << " [ label=\"" << getNodeID(nodeItr) << ": " << getNodeCosts(nodeItr) << "\" ]\n"; } os << " edge [ len=" << getNumNodes() << " ]\n"; for (ConstEdgeIterator edgeItr = edgesBegin(), edgeEnd = edgesEnd(); edgeItr != edgeEnd; ++edgeItr) { os << " node" << getNodeID(getEdgeNode1Itr(edgeItr)) << " -- node" << getNodeID(getEdgeNode2Itr(edgeItr)) << " [ label=\""; const Matrix &edgeCosts = getEdgeCosts(edgeItr); for (unsigned i = 0; i < edgeCosts.getRows(); ++i) { os << edgeCosts.getRowAsVector(i) << "\\n"; } os << "\" ]\n"; } os << "}\n"; } template void printDot(OStream &os) { if (!areNodeIDsValid()) { assignNodeIDs(); } const_cast(this)->printDot(os); } template void dumpTo(OStream &os) const { typedef ConstNodeIterator ConstNodeID; assert(areNodeIDsValid() && "Cannot dump a graph unless IDs have been assigned."); for (ConstNodeIterator nItr = nodesBegin(), nEnd = nodesEnd(); nItr != nEnd; ++nItr) { os << getNodeID(nItr) << "\n"; } unsigned edgeNumber = 1; for (ConstEdgeIterator eItr = edgesBegin(), eEnd = edgesEnd(); eItr != eEnd; ++eItr) { os << edgeNumber++ << ": { " << getNodeID(getEdgeNode1Itr(eItr)) << ", " << getNodeID(getEdgeNode2Itr(eItr)) << " }\n"; } } template void dumpTo(OStream &os) { if (!areNodeIDsValid()) { assignNodeIDs(); } const_cast(this)->dumpTo(os); } }; /// \brief Provides a base from which to derive nodes for GraphBase. template class NodeBase { private: typedef GraphBase GraphBaseT; typedef NodeBaseTraits ThisNodeBaseTraits; public: typedef typename GraphBaseT::EdgeIterator EdgeIterator; private: typedef typename ThisNodeBaseTraits::AdjEdgeList AdjEdgeList; unsigned degree, id; Vector costs; AdjEdgeList adjEdges; void operator=(const NodeBase& other) { assert(false && "Can't assign NodeEntrys."); } public: typedef typename ThisNodeBaseTraits::AdjEdgeIterator AdjEdgeIterator; typedef typename ThisNodeBaseTraits::ConstAdjEdgeIterator ConstAdjEdgeIterator; NodeBase(const Vector &costs) : degree(0), costs(costs) { assert((costs.getLength() > 0) && "Can't have zero-length cost vector."); } Vector& getCosts() { return costs; } const Vector& getCosts() const { return costs; } unsigned getDegree() const { return degree; } void setID(unsigned id) { this->id = id; } unsigned getID() const { return id; } AdjEdgeIterator addAdjEdge(const EdgeIterator &edgeItr) { ++degree; return adjEdges.insert(adjEdges.end(), edgeItr); } void removeAdjEdge(const AdjEdgeIterator &adjEdgeItr) { --degree; adjEdges.erase(adjEdgeItr); } AdjEdgeIterator adjEdgesBegin() { return adjEdges.begin(); } ConstAdjEdgeIterator adjEdgesBegin() const { return adjEdges.begin(); } AdjEdgeIterator adjEdgesEnd() { return adjEdges.end(); } ConstAdjEdgeIterator adjEdgesEnd() const { return adjEdges.end(); } }; template class EdgeBase { public: typedef typename GraphBase::NodeIterator NodeIterator; typedef typename GraphBase::EdgeIterator EdgeIterator; typedef typename NodeImpl::AdjEdgeIterator NodeAdjEdgeIterator; private: NodeIterator node1Itr, node2Itr; NodeAdjEdgeIterator node1ThisEdgeItr, node2ThisEdgeItr; Matrix costs; void operator=(const EdgeBase &other) { assert(false && "Can't assign EdgeEntrys."); } public: EdgeBase(const NodeIterator &node1Itr, const NodeIterator &node2Itr, const Matrix &costs) : node1Itr(node1Itr), node2Itr(node2Itr), costs(costs) { assert((costs.getRows() > 0) && (costs.getCols() > 0) && "Can't have zero-dimensioned cost matrices"); } Matrix& getCosts() { return costs; } const Matrix& getCosts() const { return costs; } const NodeIterator& getNode1Itr() const { return node1Itr; } const NodeIterator& getNode2Itr() const { return node2Itr; } void setNode1ThisEdgeItr(const NodeAdjEdgeIterator &node1ThisEdgeItr) { this->node1ThisEdgeItr = node1ThisEdgeItr; } const NodeAdjEdgeIterator& getNode1ThisEdgeItr() const { return node1ThisEdgeItr; } void setNode2ThisEdgeItr(const NodeAdjEdgeIterator &node2ThisEdgeItr) { this->node2ThisEdgeItr = node2ThisEdgeItr; } const NodeAdjEdgeIterator& getNode2ThisEdgeItr() const { return node2ThisEdgeItr; } }; } #endif // LLVM_CODEGEN_PBQP_GRAPHBASE_HPP