[Lemon-commits] [lemon_svn] alpar: r2978 - in hugo/trunk: benchmark lemon

Lemon SVN svn at lemon.cs.elte.hu
Mon Nov 6 21:51:36 CET 2006


Author: alpar
Date: Thu Oct 12 12:53:25 2006
New Revision: 2978

Added:
   hugo/trunk/benchmark/edge_lookup.cc
   hugo/trunk/benchmark/edge_lookup_test   (contents, props changed)
   hugo/trunk/benchmark/edge_lookup_test.h
Modified:
   hugo/trunk/benchmark/Makefile.am
   hugo/trunk/lemon/graph_utils.h

Log:
EdgeLookUp and AllEdgeLookUp added.


Modified: hugo/trunk/benchmark/Makefile.am
==============================================================================
--- hugo/trunk/benchmark/Makefile.am	(original)
+++ hugo/trunk/benchmark/Makefile.am	Thu Oct 12 12:53:25 2006
@@ -1,5 +1,6 @@
 EXTRA_DIST += \
 	benchmark/Makefile
+	benchmark/edge_lookup_test
 
 noinst_HEADERS += benchmark/bench_tools.h
 
@@ -11,7 +12,8 @@
 	benchmark/swap_bipartite_bench \
 	benchmark/bfs-bench \
 	benchmark/radix_sort-bench \
-	benchmark/swap_bipartite_bench
+	benchmark/swap_bipartite_bench \
+	benchmark/edge_lookup
 
 endif WANT_BENCHMARK
 
@@ -24,3 +26,5 @@
 benchmark_radix_sort_bench_SOURCES = benchmark/radix_sort-bench.cc
 
 benchmark_swap_bipartite_bench_SOURCES = benchmark/swap_bipartite_bench.cc
+
+benchmark_edge_lookup_SOURCES = benchmark/edge_lookup.cc

Added: hugo/trunk/benchmark/edge_lookup.cc
==============================================================================
--- (empty file)
+++ hugo/trunk/benchmark/edge_lookup.cc	Thu Oct 12 12:53:25 2006
@@ -0,0 +1,137 @@
+// #include<lemon/edge_lookup.h>
+#include<lemon/edge_lookup_test.h>
+#include<lemon/smart_graph.h>
+#include<vector>
+#include<lemon/time_measure.h>
+
+using namespace lemon;
+
+GRAPH_TYPEDEFS(SmartGraph)
+typedef SmartGraph Graph;
+
+class FE 
+{
+public:
+  Graph &_g;
+  FE(Graph &g) :_g(g) {}
+  void operator()() 
+  {
+    Edge e;
+    
+    for(NodeIt v(_g);v!=INVALID;++v)
+      for(NodeIt u(_g);u!=INVALID;++u)
+	e=findEdge(_g,u,v);
+  }
+  
+};
+
+class EL 
+{
+public:
+  Graph &_g;
+  EdgeLookUp<Graph> _el;
+  EL(Graph &g) :_g(g), _el(g) {}
+  void operator()() 
+  {
+    Edge e;
+    
+    for(NodeIt v(_g);v!=INVALID;++v)
+      for(NodeIt u(_g);u!=INVALID;++u)
+	e=_el(u,v);
+  }
+  
+};
+class EL2
+{
+public:
+  Graph &_g;
+  EdgeLookUp2<Graph> _el;
+  EL2(Graph &g) :_g(g), _el(g) {}
+  void operator()() 
+  {
+    Edge e;
+    
+    for(NodeIt v(_g);v!=INVALID;++v)
+      for(NodeIt u(_g);u!=INVALID;++u)
+	e=_el(u,v);
+  }
+  
+};
+
+class EL3
+{
+public:
+  Graph &_g;
+  EdgeLookUp3<Graph> _el;
+  EL3(Graph &g) :_g(g), _el(g) {}
+  void operator()() 
+  {
+    Edge e;
+    
+    for(NodeIt v(_g);v!=INVALID;++v)
+      for(NodeIt u(_g);u!=INVALID;++u)
+	e=_el(u,v);
+  }
+  
+};
+
+class EL4
+{
+public:
+  Graph &_g;
+  EdgeLookUp4<Graph> _el;
+  EL4(Graph &g) :_g(g), _el(g) {}
+  void operator()() 
+  {
+    Edge e;
+    
+    for(NodeIt v(_g);v!=INVALID;++v)
+      for(NodeIt u(_g);u!=INVALID;++u)
+	e=_el(u,v);
+  }
+  
+};
+
+int main(int argc, char**argv)
+{
+  int N=atoi(argv[1]);
+  int M=int(N*atof(argv[2]));
+  
+  Graph g;
+  
+  std::vector<Node> v;
+  for(int i=0;i<N;i++) v.push_back(g.addNode());
+  for(int i=0;i<M;i++) g.addEdge(v[int(drand48()*N)],v[int(drand48()*N)]);
+
+//   {
+//     Edge e;
+    
+//     TimeReport t("findEdge: ");
+//     for(NodeIt u(g);u!=INVALID;++u)
+//       for(NodeIt v(g);v!=INVALID;++v)
+// 	e=findEdge(g,u,v);
+//   }
+//   {
+//     Edge e;
+//     EdgeLookUp<Graph> el(g);
+    
+//     TimeReport t("EdgeLookUp: ");
+//     for(NodeIt u(g);u!=INVALID;++u)
+//       for(NodeIt v(g);v!=INVALID;++v)
+// 	e=el(u,v);
+//   }
+
+
+  TimeStamp t1 = runningTimeTest(FE(g),1);
+  TimeStamp t2 = runningTimeTest(EL(g),1);
+  TimeStamp t3 = runningTimeTest(EL2(g),1);
+  TimeStamp t4 = runningTimeTest(EL3(g),1);
+  TimeStamp t5 = runningTimeTest(EL4(g),1);
+
+  std::cout << t1.userTime()/N/N << ' ' 
+	    << t2.userTime()/N/N << ' '
+	    << t3.userTime()/N/N << ' '
+	    << t4.userTime()/N/N << ' '
+	    << t5.userTime()/N/N << std::endl;
+}
+

Added: hugo/trunk/benchmark/edge_lookup_test
==============================================================================
--- (empty file)
+++ hugo/trunk/benchmark/edge_lookup_test	Thu Oct 12 12:53:25 2006
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for((i=1;i<50;i++))
+do
+    echo -n $i ''
+    edge_lookup 100 $i
+done

Added: hugo/trunk/benchmark/edge_lookup_test.h
==============================================================================
--- (empty file)
+++ hugo/trunk/benchmark/edge_lookup_test.h	Thu Oct 12 12:53:25 2006
@@ -0,0 +1,281 @@
+/* -*- C++ -*-
+ *
+ * This file is a part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2003-2006
+ * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+#ifndef LEMON_EDGE_LOOKUP_H
+#define LEMON_EDGE_LOOKUP_H
+
+#include<lemon/graph_utils.h>
+#include<algorithm>
+#include<vector>
+
+namespace lemon {
+  template<class G>
+  class EdgeLookUp2
+  {
+  public:
+    GRAPH_TYPEDEFS(typename G)
+    typedef G Graph;
+
+  private:
+    const Graph &_g;
+    typename Graph::template NodeMap<int> _start;
+    typename Graph::template NodeMap<int> _end;
+    std::vector<Edge> _edges;
+    
+    class EdgeLess {
+      const Graph &g;
+    public:
+      EdgeLess(const Graph &_g) : g(_g) {}
+      bool operator()(Edge a,Edge b) const 
+      {
+	return g.target(a)<g.target(b);
+      }
+    };
+    
+  public:
+    
+    ///Constructor
+    EdgeLookUp2(const Graph &g) :_g(g),_start(g),_end(g) {refresh();}
+    
+  public:
+    ///Refresh the data structure at a node.
+    void refresh(Node n) 
+    {
+      const int bi = _start[n] = _edges.size();
+      for(OutEdgeIt e(_g,n);e!=INVALID;++e) _edges.push_back(e);
+      const typename std::vector<Edge>::iterator ei=_edges.end();
+      _end[n]=_edges.size();
+      std::sort(_edges.begin()+bi,ei,EdgeLess(_g));
+    }
+    ///Refresh the full data structure.
+    void refresh() 
+    {
+      _edges.clear();
+      for(NodeIt n(_g);n!=INVALID;++n) refresh(n);
+    }
+    
+    ///Find an edge between two nodes.
+    
+    ///Find an edge between two nodes.
+    ///\param s The source node
+    ///\param t The target node
+    ///\return An edge from \c s to \c t if there exists,
+    ///\ref INVALID otherwise.
+
+    Edge operator()(Node s, Node t) 
+    {
+      int a=_start[s];
+      int b=_end[s];
+      while(a<b) 
+	{
+	  int n=(a+b)/2;
+	  Node tt = _g.target(_edges[n]);
+	  if(tt==t) return _edges[n];
+	  else if(tt<t) a=n+1;
+	  else b=n;
+	}
+      return INVALID;
+    }
+
+    ///Find the next edge
+      
+      ///\warning This function is unimplemented.
+    Edge operator()(Node s, Node t, Edge prev) 
+    {
+      return prev==INVALID?(*this)(s,t):INVALID;
+    }
+      
+  };
+
+  template<class G>
+  class EdgeLookUp3
+  {
+  public:
+    GRAPH_TYPEDEFS(typename G)
+    typedef G Graph;
+
+  private:
+    const Graph &_g;
+    typename Graph::template NodeMap<Edge*> _start;
+    typename Graph::template NodeMap<Edge*> _end;
+    std::vector<Edge> _edges;
+    
+    class EdgeLess {
+      const Graph &g;
+    public:
+      EdgeLess(const Graph &_g) : g(_g) {}
+      bool operator()(Edge a,Edge b) const 
+      {
+	return g.target(a)<g.target(b);
+      }
+    };
+    
+  public:
+    
+    ///Constructor
+    EdgeLookUp3(const Graph &g) :_g(g),_start(g),_end(g) {refresh();}
+    
+  public:
+    ///Refresh the data structure at a node.
+    void refresh(Node n) 
+    {
+      const int bi = _start[n] = _edges.size();
+      for(OutEdgeIt e(_g,n);e!=INVALID;++e) _edges.push_back(e);
+      const typename std::vector<Edge>::iterator ei=_edges.end();
+      _end[n]=_edges.size();
+      std::sort(_edges.begin()+bi,ei,EdgeLess(_g));
+    }
+    ///Refresh the full data structure.
+    void refresh() 
+    {
+      _edges.resize(countEdges(_g));
+      int l=0;
+      for(NodeIt n(_g);n!=INVALID;++n)
+	{
+	  int ls = l;
+	  _start[n]=&(_edges[l]);	
+	  for(OutEdgeIt e(_g,n);e!=INVALID;++e) _edges[l++]=e;
+	  _end[n]=&(_edges[l]);
+	  std::sort(_edges.begin()+ls,_edges.begin()+l,EdgeLess(_g));
+	}
+      
+    }
+    
+    ///Find an edge between two nodes.
+    
+    ///Find an edge between two nodes.
+    ///\param s The source node
+    ///\param t The target node
+    ///\return An edge from \c s to \c t if there exists,
+    ///\ref INVALID otherwise.
+
+    Edge operator()(Node s, Node t) 
+    {
+      Edge *a=_start[s];
+      Edge *b=_end[s];
+      while(a!=b) 
+	{
+ 	  Edge *m=a+((b-a)/2);
+	  Node tt = _g.target(*m);
+	  if(tt==t) return *m;
+	  else if(tt<t) a=m+1;
+	  else b=m;
+	}
+      return INVALID;
+    }
+
+    ///Find the next edge
+      
+      ///\warning This function is unimplemented.
+    Edge operator()(Node s, Node t, Edge prev) 
+    {
+      return prev==INVALID?(*this)(s,t):INVALID;
+    }
+      
+  };
+
+  template<class G>
+  class EdgeLookUp4
+  {
+  public:
+    GRAPH_TYPEDEFS(typename G)
+    typedef G Graph;
+
+  private:
+    const Graph &_g;
+    typename Graph::template NodeMap<Edge*> _start;
+    typename Graph::template NodeMap<Edge*> _end;
+    std::vector<Edge> _edges;
+    
+    class EdgeLess {
+      const Graph &g;
+    public:
+      EdgeLess(const Graph &_g) : g(_g) {}
+      bool operator()(Edge a,Edge b) const 
+      {
+	return g.target(a)<g.target(b);
+      }
+    };
+    
+  public:
+    
+    ///Constructor
+    EdgeLookUp4(const Graph &g) :_g(g),_start(g),_end(g) {refresh();}
+    
+  public:
+    ///Refresh the data structure at a node.
+    void refresh(Node n) 
+    {
+      const int bi = _start[n] = _edges.size();
+      for(OutEdgeIt e(_g,n);e!=INVALID;++e) _edges.push_back(e);
+      const typename std::vector<Edge>::iterator ei=_edges.end();
+      _end[n]=_edges.size();
+      std::sort(_edges.begin()+bi,ei,EdgeLess(_g));
+    }
+    ///Refresh the full data structure.
+    void refresh() 
+    {
+      _edges.resize(countEdges(_g));
+      int l=0;
+      for(NodeIt n(_g);n!=INVALID;++n)
+	{
+	  int ls = l;
+	  _start[n]=&(_edges[l]);	
+	  for(OutEdgeIt e(_g,n);e!=INVALID;++e) _edges[l++]=e;
+	  _end[n]=&(_edges[l]);
+	  std::sort(_edges.begin()+ls,_edges.begin()+l,EdgeLess(_g));
+	}
+      
+    }
+    
+    ///Find an edge between two nodes.
+    
+    ///Find an edge between two nodes.
+    ///\param s The source node
+    ///\param t The target node
+    ///\return An edge from \c s to \c t if there exists,
+    ///\ref INVALID otherwise.
+
+    Edge operator()(Node s, Node t) 
+    {
+      Edge *a=_start[s];
+      Edge *b=_end[s];
+      while(a!=b) 
+	{
+	  Edge *m=(Edge*)(((unsigned int)a+(unsigned int)b)/2 & 0xfffffffc);
+	  Node tt = _g.target(*m);
+	  if(tt==t) return *m;
+	  else if(tt<t) a=m+1;
+	  else b=m;
+	}
+      return INVALID;
+    }
+
+    ///Find the next edge
+      
+      ///\warning This function is unimplemented.
+    Edge operator()(Node s, Node t, Edge prev) 
+    {
+      return prev==INVALID?(*this)(s,t):INVALID;
+    }
+      
+  };
+
+}
+
+#endif

Modified: hugo/trunk/lemon/graph_utils.h
==============================================================================
--- hugo/trunk/lemon/graph_utils.h	(original)
+++ hugo/trunk/lemon/graph_utils.h	Thu Oct 12 12:53:25 2006
@@ -23,6 +23,7 @@
 #include <vector>
 #include <map>
 #include <cmath>
+#include <algorithm>
 
 #include <lemon/bits/invalid.h>
 #include <lemon/bits/utility.h>
@@ -374,6 +375,8 @@
   /// }
   ///\endcode
   ///
+  ///\sa EdgeLookUp
+  ///\se AllEdgeLookup
   ///\sa ConEdgeIt
   template <typename Graph>
   inline typename Graph::Edge findEdge(const Graph &g,
@@ -395,6 +398,8 @@
   ///\endcode
   /// 
   ///\sa findEdge()
+  ///\sa EdgeLookUp
+  ///\se AllEdgeLookup
   ///
   /// \author Balazs Dezso 
   template <typename _Graph>
@@ -1838,6 +1843,242 @@
   };
 
 
+  ///Fast edge look up between given endpoints.
+  
+  ///\ingroup gutils
+  ///Using this class, you can find an edge in a graph from a given
+  ///source to a given target in time <em>O(log d)</em>,
+  ///where <em>d</em> is the out-degree of the source node.
+  ///
+  ///It is not possible to find \e all parallel edges between two nodes.
+  ///Use \ref AllEdgeLookUp for this purpose.
+  ///
+  ///\warning This class is static, so you should refresh() (or at least
+  ///refresh(Node)) this data structure
+  ///whenever the graph changes. This is a time consuming (superlinearly
+  ///proportional (<em>O(m</em>log<em>m)</em>) to the number of edges).
+  ///
+  ///\param G The type of the underlying graph.
+  ///
+  ///\sa AllEdgeLookUp  
+  template<class G>
+  class EdgeLookUp 
+  {
+  public:
+    GRAPH_TYPEDEFS(typename G)
+    typedef G Graph;
+
+  protected:
+    const Graph &_g;
+    typename Graph::template NodeMap<Edge> _head;
+    typename Graph::template EdgeMap<Edge> _left;
+    typename Graph::template EdgeMap<Edge> _right;
+    
+    class EdgeLess {
+      const Graph &g;
+    public:
+      EdgeLess(const Graph &_g) : g(_g) {}
+      bool operator()(Edge a,Edge b) const 
+      {
+	return g.target(a)<g.target(b);
+      }
+    };
+    
+  public:
+    
+    ///Constructor
+
+    ///Constructor.
+    ///
+    ///It builds up the search database, which remains valid until the graph
+    ///changes.
+    EdgeLookUp(const Graph &g) :_g(g),_head(g),_left(g),_right(g) {refresh();}
+    
+  private:
+    Edge refresh_rec(std::vector<Edge> &v,int a,int b) 
+    {
+      int m=(a+b)/2;
+      Edge me=v[m];
+      _left[me] = a<m?refresh_rec(v,a,m-1):INVALID;
+      _right[me] = m<b?refresh_rec(v,m+1,b):INVALID;
+      return me;
+    }
+  public:
+    ///Refresh the data structure at a node.
+
+    ///Build up the search database of node \c n.
+    ///
+    ///It runs in time <em>O(d</em>log<em>d)</em>, where <em>d</em> is
+    ///the number of the outgoing edges of \c n.
+    void refresh(Node n) 
+    {
+      std::vector<Edge> v;
+      for(OutEdgeIt e(_g,n);e!=INVALID;++e) v.push_back(e);
+      if(v.size()) {
+	std::sort(v.begin(),v.end(),EdgeLess(_g));
+	_head[n]=refresh_rec(v,0,v.size()-1);
+      }
+      else _head[n]=INVALID;
+    }
+    ///Refresh the full data structure.
+
+    ///Build up the full search database. In fact, it simply calls
+    ///\ref refresh(Node) "refresh(n)" for each node \c n.
+    ///
+    ///It runs in time <em>O(m</em>log<em>D)</em>, where <em>m</em> is
+    ///the number of the edges of \c n and <em>D</em> is the maximum
+    ///out-degree of the graph.
+
+    void refresh() 
+    {
+      for(NodeIt n(_g);n!=INVALID;++n) refresh(n);
+    }
+    
+    ///Find an edge between two nodes.
+    
+    ///Find an edge between two nodes in time <em>O(</em>log<em>d)</em>, where
+    /// <em>d</em> is the number of outgoing edges of \c s.
+    ///\param s The source node
+    ///\param t The target node
+    ///\return An edge from \c s to \c t if there exists,
+    ///\ref INVALID otherwise.
+    ///
+    ///\warning If you change the graph, refresh() must be called before using
+    ///this operator. If you change the outgoing edges of
+    ///a single node \c n, then
+    ///\ref refresh(Node) "refresh(n)" is enough.
+    ///
+    Edge operator()(Node s, Node t) const
+    {
+      Edge e;
+      for(e=_head[s];
+	  e!=INVALID&&_g.target(e)!=t;
+	  e = t < _g.target(e)?_left[e]:_right[e]) ;
+      return e;
+    }
+
+  };
+
+  ///Fast look up of all edges between given endpoints.
+  
+  ///\ingroup gutils
+  ///This class is the same as \ref EdgeLookUp, with the addition
+  ///that it makes it possible to find all edges between given endpoints.
+  ///
+  ///\warning This class is static, so you should refresh() (or at least
+  ///refresh(Node)) this data structure
+  ///whenever the graph changes. This is a time consuming (superlinearly
+  ///proportional (<em>O(m</em>log<em>m)</em>) to the number of edges).
+  ///
+  ///\param G The type of the underlying graph.
+  ///
+  ///\sa EdgeLookUp  
+  template<class G>
+  class AllEdgeLookUp : public EdgeLookUp<G>
+  {
+    using EdgeLookUp<G>::_g;
+    using EdgeLookUp<G>::_right;
+    using EdgeLookUp<G>::_left;
+    using EdgeLookUp<G>::_head;
+
+    GRAPH_TYPEDEFS(typename G)
+    typedef G Graph;
+    
+    typename Graph::template EdgeMap<Edge> _next;
+    
+    Edge refreshNext(Edge head,Edge next=INVALID)
+    {
+      if(head==INVALID) return next;
+      else {
+	next=refreshNext(_right[head],next);
+// 	_next[head]=next;
+	_next[head]=( next!=INVALID && _g.target(next)==_g.target(head))
+	  ? next : INVALID;
+	return refreshNext(_left[head],head);
+      }
+    }
+    
+    void refreshNext()
+    {
+      for(NodeIt n(_g);n!=INVALID;++n) refreshNext(_head[n]);
+    }
+    
+  public:
+    ///Constructor
+
+    ///Constructor.
+    ///
+    ///It builds up the search database, which remains valid until the graph
+    ///changes.
+    AllEdgeLookUp(const Graph &g) : EdgeLookUp<G>(g), _next(g) {refreshNext();}
+
+    ///Refresh the data structure at a node.
+
+    ///Build up the search database of node \c n.
+    ///
+    ///It runs in time <em>O(d</em>log<em>d)</em>, where <em>d</em> is
+    ///the number of the outgoing edges of \c n.
+    
+    void refresh(Node n) 
+    {
+      EdgeLookUp<G>::refresh(n);
+      refreshNext(_head[n]);
+    }
+    
+    ///Refresh the full data structure.
+
+    ///Build up the full search database. In fact, it simply calls
+    ///\ref refresh(Node) "refresh(n)" for each node \c n.
+    ///
+    ///It runs in time <em>O(m</em>log<em>D)</em>, where <em>m</em> is
+    ///the number of the edges of \c n and <em>D</em> is the maximum
+    ///out-degree of the graph.
+
+    void refresh() 
+    {
+      for(NodeIt n(_g);n!=INVALID;++n) refresh(_head[n]);
+    }
+    
+    ///Find an edge between two nodes.
+    
+    ///Find an edge between two nodes.
+    ///\param s The source node
+    ///\param t The target node
+    ///\param prev The previous edge between \c s and \c t. It it is INVALID or
+    ///not given, the operator finds the first appropriate edge.
+    ///\return An edge from \c s to \c t after \prev or
+    ///\ref INVALID if there is no more.
+    ///
+    ///For example, you can count the number of edges from \c u to \c v in the
+    ///following way.
+    ///\code
+    ///AllEdgeLookUp<ListGraph> ae(g);
+    ///...
+    ///int n=0;
+    ///for(Edge e=ae(u,v);e!=INVALID;e=ae(u,v,e)) n++;
+    ///\endcode
+    ///
+    ///Finding the first edge take <em>O(</em>log<em>d)</em> time, where
+    /// <em>d</em> is the number of outgoing edges of \c s. Then, the
+    ///consecutive edges are found in constant time.
+    ///
+    ///\warning If you change the graph, refresh() must be called before using
+    ///this operator. If you change the outgoing edges of
+    ///a single node \c n, then
+    ///\ref refresh(Node) "refresh(n)" is enough.
+    ///
+#ifdef DOXYGEN
+    Edge operator()(Node s, Node t, Edge prev=INVALID) const {}
+#else
+    using EdgeLookUp<G>::operator() ;
+    Edge operator()(Node s, Node t, Edge prev) const
+    {
+      return prev==INVALID?(*this)(s,t):_next[prev];
+    }
+#endif
+      
+  };
+
   /// @}
 
 } //END OF NAMESPACE LEMON



More information about the Lemon-commits mailing list