deba@1567: /* -*- C++ -*- deba@1567: * lemon/matrix_graph.h - Part of LEMON, a generic C++ optimization library deba@1567: * deba@1567: * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1567: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@1567: * deba@1567: * Permission to use, modify and distribute this software is granted deba@1567: * provided that this copyright notice appears in all copies. For deba@1567: * precise terms see the accompanying LICENSE file. deba@1567: * deba@1567: * This software is provided "AS IS" with no warranty of any kind, deba@1567: * express or implied, and with no claim as to its suitability for any deba@1567: * purpose. deba@1567: * deba@1567: */ deba@1567: deba@1567: #ifndef MATRIX_GRAPH_H deba@1567: #define MATRIX_GRAPH_H deba@1567: deba@1567: #include deba@1567: #include deba@1567: #include deba@1567: deba@1567: #include deba@1567: #include deba@1567: #include deba@1567: deba@1567: #include deba@1567: deba@1567: namespace lemon { deba@1567: deba@1567: class MatrixGraphBase { deba@1567: deba@1567: public: deba@1567: deba@1567: typedef MatrixGraphBase Graph; deba@1567: deba@1567: class Node; deba@1567: class Edge; deba@1567: deba@1567: public: deba@1567: deba@1567: MatrixGraphBase() {} deba@1567: deba@1567: ///Creates a full graph with \c n nodes. deba@1567: void construct(int height, int width) { deba@1567: _height = height; _width = width; deba@1567: _nodeNum = height * width; _edgeNum = 2 * _nodeNum - width - height; deba@1567: _edgeLimit = _nodeNum - width; deba@1567: } deba@1567: deba@1567: Node operator()(int i, int j) const { deba@1567: return Node(i * _width + j); deba@1567: } deba@1567: deba@1567: int width() const { deba@1567: return _width; deba@1567: } deba@1567: deba@1567: int height() const { deba@1567: return _height; deba@1567: } deba@1567: deba@1567: typedef True NodeNumTag; deba@1567: typedef True EdgeNumTag; deba@1567: deba@1567: ///Number of nodes. deba@1567: int nodeNum() const { return _nodeNum; } deba@1567: ///Number of edges. deba@1567: int edgeNum() const { return _edgeNum; } deba@1567: deba@1567: /// Maximum node ID. deba@1567: deba@1567: /// Maximum node ID. deba@1567: ///\sa id(Node) deba@1567: int maxId(Node = INVALID) const { return nodeNum() - 1; } deba@1567: /// Maximum edge ID. deba@1567: deba@1567: /// Maximum edge ID. deba@1567: ///\sa id(Edge) deba@1567: int maxId(Edge = INVALID) const { return edgeNum() - 1; } deba@1567: deba@1567: Node source(Edge e) const { deba@1567: if (e.id < _edgeLimit) { deba@1567: return e.id; deba@1567: } else { deba@1567: return (e.id - _edgeLimit) % (_width - 1) + deba@1567: (e.id - _edgeLimit) / (_width - 1) * _width; deba@1567: } deba@1567: } deba@1567: deba@1567: Node target(Edge e) const { deba@1567: if (e.id < _edgeLimit) { deba@1567: return e.id + _width; deba@1567: } else { deba@1567: return (e.id - _edgeLimit) % (_width - 1) + deba@1567: (e.id - _edgeLimit) / (_width - 1) * _width + 1; deba@1567: } deba@1567: } deba@1567: deba@1567: /// Node ID. deba@1567: deba@1567: /// The ID of a valid Node is a nonnegative integer not greater than deba@1567: /// \ref maxNodeId(). The range of the ID's is not surely continuous deba@1567: /// and the greatest node ID can be actually less then \ref maxNodeId(). deba@1567: /// deba@1567: /// The ID of the \ref INVALID node is -1. deba@1567: ///\return The ID of the node \c v. deba@1567: deba@1567: static int id(Node v) { return v.id; } deba@1567: /// Edge ID. deba@1567: deba@1567: /// The ID of a valid Edge is a nonnegative integer not greater than deba@1567: /// \ref maxEdgeId(). The range of the ID's is not surely continuous deba@1567: /// and the greatest edge ID can be actually less then \ref maxEdgeId(). deba@1567: /// deba@1567: /// The ID of the \ref INVALID edge is -1. deba@1567: ///\return The ID of the edge \c e. deba@1567: static int id(Edge e) { return e.id; } deba@1567: deba@1567: static Node fromId(int id, Node) { return Node(id);} deba@1567: deba@1567: static Edge fromId(int id, Edge) { return Edge(id);} deba@1567: deba@1567: typedef True FindEdgeTag; deba@1567: deba@1567: /// Finds an edge between two nodes. deba@1567: deba@1567: /// Finds an edge from node \c u to node \c v. deba@1567: /// deba@1567: /// If \c prev is \ref INVALID (this is the default value), then deba@1567: /// It finds the first edge from \c u to \c v. Otherwise it looks for deba@1567: /// the next edge from \c u to \c v after \c prev. deba@1567: /// \return The found edge or INVALID if there is no such an edge. deba@1567: Edge findEdge(Node u, Node v, Edge prev = INVALID) { deba@1567: if (prev != INVALID) return INVALID; deba@1567: if (v.id - u.id == _width) return Edge(u.id); deba@1567: if (v.id - u.id == 1 && u.id % _width < _width - 1) { deba@1567: return Edge(u.id / _width * (_width - 1) + deba@1567: u.id % _width + _edgeLimit); deba@1567: } deba@1567: return INVALID; deba@1567: } deba@1567: deba@1567: deba@1567: class Node { deba@1567: friend class MatrixGraphBase; deba@1567: deba@1567: protected: deba@1567: int id; deba@1567: Node(int _id) { id = _id;} deba@1567: public: deba@1567: Node() {} deba@1567: Node (Invalid) { id = -1; } deba@1567: bool operator==(const Node node) const {return id == node.id;} deba@1567: bool operator!=(const Node node) const {return id != node.id;} deba@1567: bool operator<(const Node node) const {return id < node.id;} deba@1567: }; deba@1567: deba@1567: deba@1567: deba@1567: class Edge { deba@1567: friend class MatrixGraphBase; deba@1567: deba@1567: protected: deba@1567: int id; deba@1567: deba@1567: Edge(int _id) : id(_id) {} deba@1567: deba@1567: public: deba@1567: Edge() { } deba@1567: Edge (Invalid) { id = -1; } deba@1567: bool operator==(const Edge edge) const {return id == edge.id;} deba@1567: bool operator!=(const Edge edge) const {return id != edge.id;} deba@1567: bool operator<(const Edge edge) const {return id < edge.id;} deba@1567: }; deba@1567: deba@1567: void first(Node& node) const { deba@1567: node.id = nodeNum() - 1; deba@1567: } deba@1567: deba@1567: static void next(Node& node) { deba@1567: --node.id; deba@1567: } deba@1567: deba@1567: void first(Edge& edge) const { deba@1567: edge.id = edgeNum() - 1; deba@1567: } deba@1567: deba@1567: static void next(Edge& edge) { deba@1567: --edge.id; deba@1567: } deba@1567: deba@1567: void firstOut(Edge& edge, const Node& node) const { deba@1567: if (node.id < _nodeNum - _width) { deba@1567: edge.id = node.id; deba@1567: } else if (node.id % _width < _width - 1) { deba@1567: edge.id = _edgeLimit + node.id % _width + deba@1567: (node.id / _width) * (_width - 1); deba@1567: } else { deba@1567: edge.id = -1; deba@1567: } deba@1567: } deba@1567: deba@1567: void nextOut(Edge& edge) const { deba@1567: if (edge.id >= _edgeLimit) { deba@1567: edge.id = -1; deba@1567: } else if (edge.id % _width < _width - 1) { deba@1567: edge.id = _edgeLimit + edge.id % _width + deba@1567: (edge.id / _width) * (_width - 1); deba@1567: } else { deba@1567: edge.id = -1; deba@1567: } deba@1567: } deba@1567: deba@1567: void firstIn(Edge& edge, const Node& node) const { deba@1567: if (node.id >= _width) { deba@1567: edge.id = node.id - _width; deba@1567: } else if (node.id % _width > 0) { deba@1567: edge.id = _edgeLimit + node.id % _width + deba@1567: (node.id / _width) * (_width - 1) - 1; deba@1567: } else { deba@1567: edge.id = -1; deba@1567: } deba@1567: } deba@1567: deba@1567: void nextIn(Edge& edge) const { deba@1567: if (edge.id >= _edgeLimit) { deba@1567: edge.id = -1; deba@1567: } else if (edge.id % _width > 0) { deba@1567: edge.id = _edgeLimit + edge.id % _width + deba@1567: (edge.id / _width + 1) * (_width - 1) - 1; deba@1567: } else { deba@1567: edge.id = -1; deba@1567: } deba@1567: } deba@1567: deba@1567: private: deba@1567: int _width, _height; deba@1567: int _nodeNum, _edgeNum; deba@1567: int _edgeLimit; deba@1567: }; deba@1567: deba@1567: deba@1567: typedef UndirGraphExtender deba@1567: UndirMatrixGraphBase; deba@1567: typedef AlterableUndirGraphExtender deba@1567: AlterableMatrixGraphBase; deba@1567: typedef IterableUndirGraphExtender deba@1567: IterableMatrixGraphBase; deba@1567: typedef MappableUndirGraphExtender deba@1567: MappableMatrixGraphBase; deba@1567: deba@1567: /// \ingroup graphs deba@1567: /// deba@1567: /// \brief Matrix graph class deba@1567: /// deba@1567: /// This class implements a special graph type. The nodes of the deba@1567: /// graph can be indiced by two integer \c (i,j) value where \c i deba@1567: /// is in the \c [0,height) range and j is in the [0, width) range. deba@1567: /// Two nodes are connected in the graph if the indices differ only deba@1567: /// on one position and only one is the difference. deba@1567: /// alpar@1591: /// The graph can be indiced in the following way: deba@1567: /// \code deba@1567: /// MatrixGraph graph(h, w); deba@1567: /// MatrixGraph::NodeMap val(graph); deba@1567: /// for (int i = 0; i < graph.height(); ++i) { deba@1567: /// for (int j = 0; j < graph.width(); ++j) { deba@1567: /// val[graph(i, j)] = i + j; deba@1567: /// } deba@1567: /// } deba@1567: /// \endcode deba@1567: /// deba@1567: /// The graph type is fully conform to the \ref concept::UndirGraph deba@1567: /// "Undirected Graph" concept. deba@1567: /// deba@1567: /// \author Balazs Dezso deba@1567: class MatrixGraph : public MappableMatrixGraphBase { deba@1567: public: deba@1567: deba@1567: MatrixGraph(int m, int n) { construct(m, n); } deba@1567: }; deba@1567: } deba@1567: #endif