Index: lemon/full_graph.h
===================================================================
--- lemon/full_graph.h	(revision 1791)
+++ lemon/full_graph.h	(revision 1820)
@@ -403,4 +403,194 @@
   };
 
+
+  class FullUndirBipartiteGraphBase {
+  protected:
+
+    int _upperNodeNum;
+    int _lowerNodeNum;
+
+    int _edgeNum;
+
+  public:
+
+    class NodeSetError : public LogicError {
+      virtual const char* exceptionName() const { 
+	return "lemon::FullUndirBipartiteGraph::NodeSetError";
+      }
+    };
+  
+    class Node {
+      friend class FullUndirBipartiteGraphBase;
+    protected:
+      int id;
+
+      Node(int _id) : id(_id) {}
+    public:
+      Node() {}
+      Node(Invalid) { id = -1; }
+      bool operator==(const Node i) const {return id==i.id;}
+      bool operator!=(const Node i) const {return id!=i.id;}
+      bool operator<(const Node i) const {return id<i.id;}
+    };
+
+    class Edge {
+      friend class FullUndirBipartiteGraphBase;
+    protected:
+      int id;
+
+      Edge(int _id) { id = _id;}
+    public:
+      Edge() {}
+      Edge (Invalid) { id = -1; }
+      bool operator==(const Edge i) const {return id==i.id;}
+      bool operator!=(const Edge i) const {return id!=i.id;}
+      bool operator<(const Edge i) const {return id<i.id;}
+    };
+
+    void construct(int upperNodeNum, int lowerNodeNum) {
+      _upperNodeNum = upperNodeNum;
+      _lowerNodeNum = lowerNodeNum;
+      _edgeNum = upperNodeNum * lowerNodeNum;
+    }
+
+    void firstUpper(Node& node) const {
+      node.id = 2 * _upperNodeNum - 2;
+      if (node.id < 0) node.id = -1; 
+    }
+    void nextUpper(Node& node) const {
+      node.id -= 2;
+      if (node.id < 0) node.id = -1; 
+    }
+
+    void firstLower(Node& node) const {
+      node.id = 2 * _lowerNodeNum - 1;
+    }
+    void nextLower(Node& node) const {
+      node.id -= 2;
+    }
+
+    void first(Node& node) const {
+      if (_upperNodeNum > 0) {
+	node.id = 2 * _upperNodeNum - 2;
+      } else {
+	node.id = 2 * _lowerNodeNum - 1;
+      }
+    }
+    void next(Node& node) const {
+      node.id -= 2;
+      if (node.id == -2) {
+	node.id = 2 * _lowerNodeNum - 1;
+      }
+    }
+  
+    void first(Edge& edge) const {
+      edge.id = _edgeNum - 1;
+    }
+    void next(Edge& edge) const {
+      --edge.id;
+    }
+
+    void firstDown(Edge& edge, const Node& node) const {
+      LEMON_ASSERT((node.id & 1) == 0, NodeSetError());
+      edge.id = (node.id >> 1) * _lowerNodeNum;
+    }
+    void nextDown(Edge& edge) const {
+      ++(edge.id);
+      if (edge.id % _lowerNodeNum == 0) edge.id = -1;
+    }
+
+    void firstUp(Edge& edge, const Node& node) const {
+      LEMON_ASSERT((node.id & 1) == 1, NodeSetError());
+      edge.id = (node.id >> 1);
+    }
+    void nextUp(Edge& edge) const {
+      edge.id += _lowerNodeNum;
+      if (edge.id >= _edgeNum) edge.id = -1;
+    }
+
+    static int id(const Node& node) {
+      return node.id;
+    }
+    static Node nodeFromId(int id) {
+      return Node(id);
+    }
+    int maxNodeId() const {
+      return _upperNodeNum > _lowerNodeNum ? 
+	_upperNodeNum * 2 - 2 : _lowerNodeNum * 2 - 1;
+    }
+  
+    static int id(const Edge& edge) {
+      return edge.id;
+    }
+    static Edge edgeFromId(int id) {
+      return Edge(id);
+    }
+    int maxEdgeId() const {
+      return _edgeNum - 1;
+    }
+  
+    static int upperId(const Node& node) {
+      return node.id >> 1;
+    }
+    static Node fromUpperId(int id, Node) {
+      return Node(id << 1);
+    }
+    int maxUpperId() const {
+      return _upperNodeNum;
+    }
+
+    static int lowerId(const Node& node) {
+      return node.id >> 1;
+    }
+    static Node fromLowerId(int id) {
+      return Node((id << 1) + 1);
+    }
+    int maxLowerId() const {
+      return _lowerNodeNum;
+    }
+
+    Node upperNode(const Edge& edge) const {
+      return Node((edge.id / _lowerNodeNum) << 1);
+    }
+    Node lowerNode(const Edge& edge) const {
+      return Node(((edge.id % _lowerNodeNum) << 1) + 1);
+    }
+
+    static bool upper(const Node& node) {
+      return (node.id & 1) == 0;
+    }
+
+    static bool lower(const Node& node) {
+      return (node.id & 1) == 1;
+    }
+
+    static Node upperNode(int index) {
+      return Node(index << 1);
+    }
+
+    static Node lowerNode(int index) {
+      return Node((index << 1) + 1);
+    }
+
+  };
+
+
+  typedef MappableUndirBipartiteGraphExtender<
+    IterableUndirBipartiteGraphExtender<
+    AlterableUndirBipartiteGraphExtender<
+    UndirBipartiteGraphExtender <
+    FullUndirBipartiteGraphBase> > > >
+  ExtendedFullUndirBipartiteGraphBase;
+
+
+  class FullUndirBipartiteGraph : 
+    public ExtendedFullUndirBipartiteGraphBase {
+  public:
+    typedef ExtendedFullUndirBipartiteGraphBase Parent;
+    FullUndirBipartiteGraph(int upperNodeNum, int lowerNodeNum) {
+      Parent::construct(upperNodeNum, lowerNodeNum);
+    }
+  };
+
 } //namespace lemon
 
