[Lemon-commits] deba: r3261 - in lemon/trunk: lemon test

Lemon SVN svn at lemon.cs.elte.hu
Thu Apr 19 17:11:58 CEST 2007


Author: deba
Date: Thu Apr 19 17:11:58 2007
New Revision: 3261

Modified:
   lemon/trunk/lemon/kruskal.h
   lemon/trunk/test/kruskal_test.cc

Log:
Redesigned Kruskal algorithm

The interface of function type implementation is not changed
Additional class type implementation 



Modified: lemon/trunk/lemon/kruskal.h
==============================================================================
--- lemon/trunk/lemon/kruskal.h	(original)
+++ lemon/trunk/lemon/kruskal.h	Thu Apr 19 17:11:58 2007
@@ -22,6 +22,11 @@
 #include <algorithm>
 #include <vector>
 #include <lemon/unionfind.h>
+#include <lemon/graph_utils.h>
+#include <lemon/maps.h>
+
+#include <lemon/radix_sort.h>
+
 #include <lemon/bits/utility.h>
 #include <lemon/bits/traits.h>
 
@@ -34,403 +39,638 @@
 
 namespace lemon {
 
-  /// \addtogroup spantree
-  /// @{
+  namespace _kruskal_bits {
 
-  /// Kruskal's algorithm to find a minimum cost tree of a graph.
+    template <typename Map, typename Comp>
+    struct MappedComp {
 
-  /// This function runs Kruskal's algorithm to find a minimum cost tree.
-  /// Due to hard C++ hacking, it accepts various input and output types.
-  ///
-  /// \param g The graph the algorithm runs on.
-  /// It can be either \ref concepts::Graph "directed" or 
-  /// \ref concepts::UGraph "undirected".
-  /// If the graph is directed, the algorithm consider it to be 
-  /// undirected by disregarding the direction of the edges.
+      typedef typename Map::Key Key;
+
+      const Map& map;
+      Comp comp;
+
+      MappedComp(const Map& _map) 
+        : map(_map), comp() {}
+
+      bool operator()(const Key& left, const Key& right) {
+        return comp(map[left], map[right]);
+      }
+
+    };
+  
+  }
+
+  /// \ingroup spantree
   ///
-  /// \param in This object is used to describe the edge costs. It can be one
-  /// of the following choices.
-  /// - An STL compatible 'Forward Container'
-  /// with <tt>std::pair<GR::Edge,X></tt> as its <tt>value_type</tt>,
-  /// where \c X is the type of the costs. The pairs indicates the edges along
-  /// with the assigned cost. <em>They must be in a
-  /// cost-ascending order.</em>
-  /// - Any readable Edge map. The values of the map indicate the edge costs.
+  /// \brief Default traits class of Kruskal class.
   ///
-  /// \retval out Here we also have a choise.
-  /// - It can be a writable \c bool edge map. 
-  /// After running the algorithm
-  /// this will contain the found minimum cost spanning tree: the value of an
-  /// edge will be set to \c true if it belongs to the tree, otherwise it will
-  /// be set to \c false. The value of each edge will be set exactly once.
-  /// - It can also be an iteraror of an STL Container with
-  /// <tt>GR::Edge</tt> as its <tt>value_type</tt>.
-  /// The algorithm copies the elements of the found tree into this sequence.
-  /// For example, if we know that the spanning tree of the graph \c g has
-  /// say 53 edges, then
-  /// we can put its edges into an STL vector \c tree with a code like this.
-  ///\code
-  /// std::vector<Edge> tree(53);
-  /// kruskal(g,cost,tree.begin());
-  ///\endcode
-  /// Or if we don't know in advance the size of the tree, we can write this.
-  ///\code
-  /// std::vector<Edge> tree;
-  /// kruskal(g,cost,std::back_inserter(tree));
-  ///\endcode
-  ///
-  /// \return The cost of the found tree.
+  /// Default traits class of Kruskal class.
+  /// \param _UGraph Undirected graph type.
+  /// \param _CostMap Type of cost map.
+  template <typename _UGraph, typename _CostMap>
+  struct KruskalDefaultTraits{
+
+    /// \brief The graph type the algorithm runs on. 
+    typedef _UGraph UGraph;
+
+    /// \brief The type of the map that stores the edge costs.
+    ///
+    /// The type of the map that stores the edge costs.
+    /// It must meet the \ref concepts::ReadMap "ReadMap" concept.
+    typedef _CostMap CostMap;
+
+    /// \brief The type of the cost of the edges.
+    typedef typename _CostMap::Value Value;
+
+    /// \brief The type of the map that stores whether an edge is in the
+    /// spanning tree or not.
+    ///
+    /// The type of the map that stores whether an edge is in the
+    /// spanning tree or not.
+    typedef typename _UGraph::template UEdgeMap<bool> TreeMap;
+
+    /// \brief Instantiates a TreeMap.
+    ///
+    /// This function instantiates a \ref TreeMap.
+    ///
+    /// The first parameter is the graph, to which
+    /// we would like to define the \ref TreeMap
+    static TreeMap *createTreeMap(const _UGraph& graph){
+      return new TreeMap(graph);
+    }
+
+    template <typename Iterator>
+    static void sort(Iterator begin, Iterator end, const CostMap& cost) {
+      _kruskal_bits::MappedComp<CostMap, std::less<Value> > comp(cost);
+      std::sort(begin, end, comp);
+    }
+
+  };
+
+  /// \brief Kruskal's algorithm to find a minimum cost tree of a graph.
   ///
-  /// \warning If kruskal runs on an
-  /// \ref lemon::concepts::UGraph "undirected graph", be sure that the
-  /// map storing the tree is also undirected
-  /// (e.g. ListUGraph::UEdgeMap<bool>, otherwise the values of the
-  /// half of the edges will not be set.
+  /// This class implements Kruskal's algorithm to find a minimum cost
+  /// spanning tree. The 
   ///
+  /// \param _UGraph Undirected graph type.
+  /// \param _CostMap Type of cost map.
+  template <typename _UGraph, typename _CostMap,
+            typename _Traits = KruskalDefaultTraits<_UGraph, _CostMap> >
+  class Kruskal {
+  public:
 
-#ifdef DOXYGEN
-  template <class GR, class IN, class OUT>
-  CostType
-  kruskal(GR const& g, IN const& in, 
-	  OUT& out)
-#else
-  template <class GR, class IN, class OUT>
-  typename IN::value_type::second_type
-  kruskal(GR const& g, IN const& in, 
-	  OUT& out,
-// 	  typename IN::value_type::first_type = typename GR::Edge()
-// 	  ,typename OUT::Key = OUT::Key()
-// 	  //,typename OUT::Key = typename GR::Edge()
-	  const typename IN::value_type::first_type * = 
-	  reinterpret_cast<const typename IN::value_type::first_type*>(0),
-	  const typename OUT::Key * = 
-          reinterpret_cast<const typename OUT::Key*>(0)
-	  )
-#endif
-  {
-    typedef typename IN::value_type::second_type EdgeCost;
-    typedef typename GR::template NodeMap<int> NodeIntMap;
-    typedef typename GR::Node Node;
-
-    NodeIntMap comp(g);
-    UnionFind<NodeIntMap> uf(comp);
-    for (typename GR::NodeIt it(g); it != INVALID; ++it) {
-      uf.insert(it);
-    }
-      
-    EdgeCost tot_cost = 0;
-    for (typename IN::const_iterator p = in.begin(); 
-	 p!=in.end(); ++p ) {
-      if ( uf.join(g.target((*p).first),
-		   g.source((*p).first)) ) {
-	out.set((*p).first, true);
-	tot_cost += (*p).second;
+    typedef _Traits Traits;
+
+    typedef typename _Traits::UGraph UGraph;
+    typedef typename _Traits::CostMap CostMap;
+
+    typedef typename _Traits::TreeMap TreeMap;
+
+    typedef typename _Traits::Value Value;
+
+    template <typename Comp>
+    struct DefSortCompareTraits : public Traits {
+      template <typename Iterator>
+      static void sort(Iterator begin, Iterator end, const CostMap& cost) {
+        _kruskal_bits::MappedComp<CostMap, Comp> comp(cost, Comp());
+        std::sort(begin, end, comp);
       }
-      else {
-	out.set((*p).first, false);
+    };
+
+    /// \brief \ref named-templ-param "Named parameter" for setting the
+    /// comparator object of the standard sort
+    ///
+    /// \ref named-templ-param "Named parameter" for setting the
+    /// comparator object of the standard sort
+    template <typename Comp>
+    struct DefSortCompare
+      : public Kruskal<UGraph, CostMap, DefSortCompareTraits<Comp> > {
+      typedef Kruskal<UGraph, CostMap, DefSortCompareTraits<Comp> > Create;
+    };    
+
+    struct DefRadixSortTraits : public Traits {
+      template <typename Iterator>
+      static void sort(Iterator begin, Iterator end, const CostMap& cost) {
+        radixSort(begin, end, cost);
       }
-    }
-    return tot_cost;
-  }
+    };
 
- 
-  /// @}
+    /// \brief \ref named-templ-param "Named parameter" for setting the
+    /// sort function to radix sort
+    ///
+    /// \brief \ref named-templ-param "Named parameter" for setting the
+    /// sort function to radix sort. The value type of the cost map should
+    /// be integral, of course. 
+    struct DefRadixSort
+      : public Kruskal<UGraph, CostMap, DefRadixSortTraits> {
+      typedef Kruskal<UGraph, CostMap, DefRadixSortTraits> Create;
+    };    
+
+    template <class TM>
+    struct DefTreeMapTraits : public Traits {
+      typedef TM TreeMap;
+      static TreeMap *createTreeMap(const UGraph &) {
+        throw UninitializedParameter();
+      }
+    };
 
-  
-  /* A work-around for running Kruskal with const-reference bool maps... */
+    /// \brief \ref named-templ-param "Named parameter" for setting
+    /// TreeMap
+    ///
+    /// \ref named-templ-param "Named parameter" for setting TreeMap
+    ///
+    template <class TM>
+    struct DefTreeMap
+      : public Kruskal< UGraph, CostMap, DefTreeMapTraits<TM> > {
+      typedef Kruskal< UGraph, CostMap, DefTreeMapTraits<TM> > Create;
+    };    
+    
 
-  /// Helper class for calling kruskal with "constant" output map.
+  private:
+
+    typedef typename UGraph::Node Node;
+    typedef typename UGraph::NodeIt NodeIt;
+
+    typedef typename UGraph::UEdge UEdge;
+    typedef typename UGraph::UEdgeIt UEdgeIt;
+
+    const UGraph& graph;
+    const CostMap& cost;
+    
+    std::vector<UEdge> edges;
+    
+    typedef typename UGraph::template NodeMap<int> UfIndex;
+    typedef UnionFind<UfIndex> Uf;
+    UfIndex *ufi;
+    Uf *uf;
+
+    int index;
+
+    void initStructures() {
+      if (!_tree) {
+        _tree = Traits::createTreeMap(graph);
+        local_tree = true;
+      }
+      if (!uf) {
+        ufi = new typename UGraph::template NodeMap<int>(graph);
+        uf = new UnionFind<typename UGraph::template NodeMap<int> >(*ufi);
+      }
+    }
+    
+    void initUnionFind() {
+      uf->clear();
+      for (NodeIt it(graph); it != INVALID; ++it) {
+        uf->insert(it);
+      }
+    }
+
+    bool local_tree;
+    TreeMap* _tree;
 
-  /// Helper class for calling kruskal with output maps constructed
-  /// on-the-fly.
-  ///
-  /// A typical examle is the following call:
-  /// <tt>kruskal(g, some_input, makeSequenceOutput(iterator))</tt>.
-  /// Here, the third argument is a temporary object (which wraps around an
-  /// iterator with a writable bool map interface), and thus by rules of C++
-  /// is a \c const object. To enable call like this exist this class and
-  /// the prototype of the \ref kruskal() function with <tt>const& OUT</tt>
-  /// third argument.
-  template<class Map>
-  class NonConstMapWr {
-    const Map &m;
   public:
-    typedef typename Map::Key Key;
-    typedef typename Map::Value Value;
 
-    NonConstMapWr(const Map &_m) : m(_m) {}
+    /// \brief Constructor
+    ///
+    /// Constructor of the algorithm.
+    Kruskal(const UGraph& _graph, const CostMap& _cost) 
+      : graph(_graph), cost(_cost),
+        ufi(0), uf(0), local_tree(false), _tree(0) {}
+
+    /// \brief Destructor
+    ///
+    /// Destructor
+    ~Kruskal() {
+      if (local_tree) {
+        delete _tree;
+      }
+      if (uf) {
+        delete uf;
+        delete ufi;
+      }
+    }
 
-    template<class Key>
-    void set(Key const& k, Value const &v) const { m.set(k,v); }
-  };
+    /// \brief Sets the map storing the tree edges.
+    ///
+    /// Sets the map storing the tree edges.
+    /// If you don't use this function before calling \ref run(),
+    /// it will allocate one. The destuctor deallocates this
+    /// automatically allocated map, of course.
+    /// \return \c *this </tt>
+    Kruskal& treeMap(TreeMap &m){
+      if (local_tree) {
+	delete _tree;
+	local_tree = false;
+      }
+      _tree = &m;
+      return *this;
+    }
 
-  template <class GR, class IN, class OUT>
-  inline
-  typename IN::value_type::second_type
-  kruskal(GR const& g, IN const& edges, OUT const& out_map,
-// 	  typename IN::value_type::first_type = typename GR::Edge(),
-// 	  typename OUT::Key = GR::Edge()
-	  const typename IN::value_type::first_type * = 
-	  reinterpret_cast<const typename IN::value_type::first_type*>(0),
-	  const typename OUT::Key * = 
-          reinterpret_cast<const typename OUT::Key*>(0)
-	  )
-  {
-    NonConstMapWr<OUT> map_wr(out_map);
-    return kruskal(g, edges, map_wr);
-  }  
+    /// \brief Initialize the algorithm
+    ///
+    /// This member function initializes the unionfind data structure
+    /// and sorts the edges into ascending order
+    void init() {
+      initStructures();
+      initUnionFind();
+      for (UEdgeIt e(graph); e != INVALID; ++e) {
+        edges.push_back(e);
+        _tree->set(e, false);
+      }      
+      Traits::sort(edges.begin(), edges.end(), cost); 
+      index = 0;
+    }
 
-  /* ** ** Input-objects ** ** */
 
-  /// Kruskal's input source.
- 
-  /// Kruskal's input source.
-  ///
-  /// In most cases you possibly want to use the \ref kruskal() instead.
-  ///
-  /// \sa makeKruskalMapInput()
-  ///
-  ///\param GR The type of the graph the algorithm runs on.
-  ///\param Map An edge map containing the cost of the edges.
-  ///\par
-  ///The cost type can be any type satisfying
-  ///the STL 'LessThan comparable'
-  ///concept if it also has an operator+() implemented. (It is necessary for
-  ///computing the total cost of the tree).
-  ///
-  template<class GR, class Map>
-  class KruskalMapInput
-    : public std::vector< std::pair<typename GR::Edge,
-				    typename Map::Value> > {
-    
-  public:
-    typedef std::vector< std::pair<typename GR::Edge,
-				   typename Map::Value> > Parent;
-    typedef typename Parent::value_type value_type;
+    /// \brief Initialize the algorithm
+    ///
+    /// This member function initializes the unionfind data structure
+    /// and sets the edge order to the given sequence. The given
+    /// sequence should be a valid STL range of undirected edges.
+    template <typename Iterator>
+    void initPresorted(Iterator begin, Iterator end) {
+      initStructures();
+      initUnionFind();
+      edges.clear();
+      std::copy(begin, end, std::back_inserter(edges));
+      index = 0;
+    }
 
-  private:
-    class comparePair {
-    public:
-      bool operator()(const value_type& a,
-		      const value_type& b) {
-	return a.second < b.second;
+    /// \brief Initialize the algorithm
+    ///
+    /// This member function initializes the unionfind data structure
+    /// and sets the edge order to the given sequence. The given
+    /// sequence should be a valid STL range of undirected edges.
+    void reinit() {
+      initStructures();
+      initUnionFind();
+      for (UEdgeIt e(graph); e != INVALID; ++e) {
+        _tree->set(e, false);
       }
-    };
+      index = 0;
+    }
 
-    template<class _GR>
-    typename enable_if<UndirectedTagIndicator<_GR>,void>::type
-    fillWithEdges(const _GR& g, const Map& m,dummy<0> = 0) 
-    {
-      for(typename GR::UEdgeIt e(g);e!=INVALID;++e) 
-	push_back(value_type(g.direct(e, true), m[e]));
+
+    /// \brief Executes the algorithm.
+    ///
+    /// Executes the algorithm.
+    ///
+    /// \pre init() must be called before using this function.
+    ///
+    /// This method runs the %Kruskal algorithm.
+    void start() {
+      while (index < int(edges.size())) {
+        if (uf->join(graph.target(edges[index]), graph.source(edges[index]))) {
+          _tree->set(edges[index], true);
+        }
+        ++index;
+      }
     }
 
-    template<class _GR>
-    typename disable_if<UndirectedTagIndicator<_GR>,void>::type
-    fillWithEdges(const _GR& g, const Map& m,dummy<1> = 1) 
-    {
-      for(typename GR::EdgeIt e(g);e!=INVALID;++e) 
-	push_back(value_type(e, m[e]));
+    /// \brief Runs the prim algorithm until it find a new tree edge
+    ///
+    /// Runs the prim algorithm until it find a new tree edge. If it
+    /// does not next tree edge in the sequence it gives back \c INVALID.
+    UEdge findNextTreeEdge() {
+      while (index < int(edges.size())) {
+        if (uf->join(graph.target(edges[index]), graph.source(edges[index]))) {
+          _tree->set(edges[index], true);
+          return edges[index++];
+        }        
+        ++index;
+      }
+      return INVALID;
+    }
+      
+    /// \brief Processes the next edge in the sequence
+    ///
+    /// Processes the next edge in the sequence.
+    ///
+    /// \return The prcocessed edge.
+    ///
+    /// \warning The sequence must not be empty!
+    UEdge processNextEdge() {
+      UEdge edge = edges[index++];
+      processEdge(edge);
+      return edge;
+    }
+
+    /// \brief Processes an arbitrary edge
+    ///
+    /// Processes the next edge in the sequence.
+    ///
+    /// \return True when the edge is a tree edge.
+    bool processEdge(const UEdge& edge) {
+      if (uf->join(graph.target(edge), graph.source(edge))) {
+        _tree->set(edge, true);
+        return true;
+      } else {
+        return false;
+      }    
+    }
+
+    /// \brief Returns \c false if there are edge to be processed in
+    /// sequence
+    ///
+    /// Returns \c false if there are nodes to be processed in the
+    /// sequence
+    bool emptyQueue() {
+      return index == int(edges.size());
     }
-    
-    
-  public:
 
-    void sort() {
-      std::sort(this->begin(), this->end(), comparePair());
+    /// \brief Returns the next edge to be processed
+    ///
+    /// Returns the next edge to be processed
+    ///
+    UEdge nextEdge() const {
+      return edges[index];
     }
 
-    KruskalMapInput(GR const& g, Map const& m) {
-      fillWithEdges(g,m); 
-      sort();
+    /// \brief Runs %Kruskal algorithm.
+    ///
+    /// This method runs the %Kruskal algorithm in order to compute the
+    /// minimum spanning tree (or minimum spanning forest).  The
+    /// method also works on graphs that has more than one components.
+    /// In this case it computes the minimum spanning forest.
+    void run() {
+      init();
+      start();
     }
+
+    /// \brief Returns a reference to the tree edges map
+    ///
+    /// Returns a reference to the TreeEdgeMap of the edges of the
+    /// minimum spanning tree. The value of the map is \c true only if
+    /// the edge is in the minimum spanning tree.
+    ///
+    const TreeMap &treeMap() const { return *_tree;}
+
+    /// \brief Returns the total cost of the tree
+    ///
+    /// Returns the total cost of the tree
+    Value treeValue() const {
+      Value value = 0;
+      for (UEdgeIt it(graph); it != INVALID; ++it) {
+        if ((*_tree)[it]) {
+          value += cost[it];
+        }
+      }
+      return value;
+    }
+
+    /// \brief Returns true when the given edge is tree edge
+    ///
+    /// Returns true when the given edge is tree edge
+    bool tree(UEdge e) const {
+      return (*_tree)[e];
+    }
+    
+    
   };
 
-  /// Creates a KruskalMapInput object for \ref kruskal()
 
-  /// It makes easier to use 
-  /// \ref KruskalMapInput by making it unnecessary 
-  /// to explicitly give the type of the parameters.
-  ///
-  /// In most cases you possibly
-  /// want to use \ref kruskal() instead.
-  ///
-  ///\param g The type of the graph the algorithm runs on.
-  ///\param m An edge map containing the cost of the edges.
-  ///\par
-  ///The cost type can be any type satisfying the
-  ///STL 'LessThan Comparable'
-  ///concept if it also has an operator+() implemented. (It is necessary for
-  ///computing the total cost of the tree).
-  ///
-  ///\return An appropriate input source for \ref kruskal().
-  ///
-  template<class GR, class Map>
-  inline
-  KruskalMapInput<GR,Map> makeKruskalMapInput(const GR &g,const Map &m)
-  {
-    return KruskalMapInput<GR,Map>(g,m);
-  }
-  
-  
+  namespace _kruskal_bits {
 
-  /* ** ** Output-objects: simple writable bool maps ** ** */
-  
+    template <typename Graph, typename In, typename Out>
+    typename In::value_type::second_type
+    kruskal(const Graph& graph, const In& in, Out& out) {
+      typedef typename In::value_type::second_type Value;
+      typedef typename Graph::template NodeMap<int> IndexMap;
+      typedef typename Graph::Node Node;
+      
+      IndexMap index(graph);
+      UnionFind<IndexMap> uf(index);
+      for (typename Graph::NodeIt it(graph); it != INVALID; ++it) {
+        uf.insert(it);
+      }
+      
+      Value tree_value = 0;
+      for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) {
+        if (uf.join(graph.target(it->first),graph.source(it->first))) {
+          out.set(it->first, true);
+          tree_value += it->second;
+        }
+        else {
+          out.set(it->first, false);
+        }
+      }
+      return tree_value;
+    }
 
 
-  /// A writable bool-map that makes a sequence of "true" keys
+    template <typename Sequence>
+    struct PairComp {
+      typedef typename Sequence::value_type Value;
+      bool operator()(const Value& left, const Value& right) {
+	return left.second < right.second;
+      }
+    };
 
-  /// A writable bool-map that creates a sequence out of keys that receives
-  /// the value "true".
-  ///
-  /// \sa makeKruskalSequenceOutput()
-  ///
-  /// Very often, when looking for a min cost spanning tree, we want as
-  /// output a container containing the edges of the found tree. For this
-  /// purpose exist this class that wraps around an STL iterator with a
-  /// writable bool map interface. When a key gets value "true" this key
-  /// is added to sequence pointed by the iterator.
-  ///
-  /// A typical usage:
-  ///\code
-  /// std::vector<Graph::Edge> v;
-  /// kruskal(g, input, makeKruskalSequenceOutput(back_inserter(v)));
-  ///\endcode
-  /// 
-  /// For the most common case, when the input is given by a simple edge
-  /// map and the output is a sequence of the tree edges, a special
-  /// wrapper function exists: \ref kruskalEdgeMap_IteratorOut().
-  ///
-  /// \warning Not a regular property map, as it doesn't know its Key
-
-  template<class Iterator>
-  class KruskalSequenceOutput {
-    mutable Iterator it;
+    template <typename In, typename Enable = void>
+    struct SequenceInputIndicator {
+      static const bool value = false;
+    };
 
-  public:
-    typedef typename std::iterator_traits<Iterator>::value_type Key;
-    typedef bool Value;
+    template <typename In>
+    struct SequenceInputIndicator<In, 
+      typename exists<typename In::value_type::first_type>::type> {
+      static const bool value = true;
+    };
 
-    KruskalSequenceOutput(Iterator const &_it) : it(_it) {}
+    template <typename In, typename Enable = void>
+    struct MapInputIndicator {
+      static const bool value = false;
+    };
 
-    template<typename Key>
-    void set(Key const& k, bool v) const { if(v) {*it=k; ++it;} }
-  };
+    template <typename In>
+    struct MapInputIndicator<In, 
+      typename exists<typename In::Value>::type> {
+      static const bool value = true;
+    };
 
-  template<class Iterator>
-  inline
-  KruskalSequenceOutput<Iterator>
-  makeKruskalSequenceOutput(Iterator it) {
-    return KruskalSequenceOutput<Iterator>(it);
-  }
+    template <typename In, typename Enable = void>
+    struct SequenceOutputIndicator {
+      static const bool value = false;
+    };
+ 
+    template <typename Out>
+    struct SequenceOutputIndicator<Out, 
+      typename exists<typename Out::value_type>::type> {
+      static const bool value = true;
+    };
 
+    template <typename Out, typename Enable = void>
+    struct MapOutputIndicator {
+      static const bool value = false;
+    };
 
+    template <typename Out>
+    struct MapOutputIndicator<Out, 
+      typename exists<typename Out::Value>::type> {
+      static const bool value = true;
+    };
 
-  /* ** ** Wrapper funtions ** ** */
+    template <typename In, typename InEnable = void>
+    struct KruskalValueSelector {};
+
+    template <typename In>
+    struct KruskalValueSelector<In,
+      typename enable_if<SequenceInputIndicator<In>, void>::type> 
+    {
+      typedef typename In::value_type::second_type Value;
+    };    
+
+    template <typename In>
+    struct KruskalValueSelector<In,
+      typename enable_if<MapInputIndicator<In>, void>::type> 
+    {
+      typedef typename In::Value Value;
+    };    
+    
+    template <typename Graph, typename In, typename Out,
+              typename InEnable = void>
+    struct KruskalInputSelector {};
+
+    template <typename Graph, typename In, typename Out,
+              typename InEnable = void>
+    struct KruskalOutputSelector {};
+    
+    template <typename Graph, typename In, typename Out>
+    struct KruskalInputSelector<Graph, In, Out,
+      typename enable_if<SequenceInputIndicator<In>, void>::type > 
+    {
+      typedef typename In::value_type::second_type Value;
+
+      static Value kruskal(const Graph& graph, const In& in, Out& out) {
+        return KruskalOutputSelector<Graph, In, Out>::
+          kruskal(graph, in, out);
+      }
+
+    };
+
+    template <typename Graph, typename In, typename Out>
+    struct KruskalInputSelector<Graph, In, Out,
+      typename enable_if<MapInputIndicator<In>, void>::type > 
+    {
+      typedef typename In::Value Value;
+      static Value kruskal(const Graph& graph, const In& in, Out& out) {
+        typedef typename In::Key MapEdge;
+        typedef typename In::Value Value;
+        typedef typename ItemSetTraits<Graph, MapEdge>::ItemIt MapEdgeIt;
+        typedef std::vector<std::pair<MapEdge, Value> > Sequence;
+        Sequence seq;
+        
+        for (MapEdgeIt it(graph); it != INVALID; ++it) {
+          seq.push_back(make_pair(it, in[it]));
+        }
+
+        std::sort(seq.begin(), seq.end(), PairComp<Sequence>());
+        return KruskalOutputSelector<Graph, Sequence, Out>::
+          kruskal(graph, seq, out);
+      }
+    };
+
+    template <typename Graph, typename In, typename Out>
+    struct KruskalOutputSelector<Graph, In, Out,
+      typename enable_if<SequenceOutputIndicator<Out>, void>::type > 
+    {
+      typedef typename In::value_type::second_type Value;
+
+      static Value kruskal(const Graph& graph, const In& in, Out& out) {
+        typedef StoreBoolMap<Out> Map;
+        Map map(out);
+        return _kruskal_bits::kruskal(graph, in, map);
+      }
+
+    };
+
+    template <typename Graph, typename In, typename Out>
+    struct KruskalOutputSelector<Graph, In, Out,
+      typename enable_if<MapOutputIndicator<Out>, void>::type > 
+    {
+      typedef typename In::value_type::second_type Value;
+
+      static Value kruskal(const Graph& graph, const In& in, Out& out) {
+        return _kruskal_bits::kruskal(graph, in, out);
+      }
+    };
 
-//   \brief Wrapper function to kruskal().
-//   Input is from an edge map, output is a plain bool map.
-//  
-//   Wrapper function to kruskal().
-//   Input is from an edge map, output is a plain bool map.
-//  
-//   \param g The type of the graph the algorithm runs on.
-//   \param in An edge map containing the cost of the edges.
-//   \par
-//   The cost type can be any type satisfying the
-//   STL 'LessThan Comparable'
-//   concept if it also has an operator+() implemented. (It is necessary for
-//   computing the total cost of the tree).
-//  
-//   \retval out This must be a writable \c bool edge map.
-//   After running the algorithm
-//   this will contain the found minimum cost spanning tree: the value of an
-//   edge will be set to \c true if it belongs to the tree, otherwise it will
-//   be set to \c false. The value of each edge will be set exactly once.
-//  
-//   \return The cost of the found tree.
-
-  template <class GR, class IN, class RET>
-  inline
-  typename IN::Value
-  kruskal(GR const& g,
-	  IN const& in,
-	  RET &out,
-	  //	  typename IN::Key = typename GR::Edge(),
-	  //typename IN::Key = typename IN::Key (),
-	  //	  typename RET::Key = typename GR::Edge()
-	  const typename IN::Key * = 
-          reinterpret_cast<const typename IN::Key*>(0),
-	  const typename RET::Key * = 
-          reinterpret_cast<const typename RET::Key*>(0)
-	  )
-  {
-    return kruskal(g,
-		   KruskalMapInput<GR,IN>(g,in),
-		   out);
   }
 
-//   \brief Wrapper function to kruskal().
-//   Input is from an edge map, output is an STL Sequence.
-//  
-//   Wrapper function to kruskal().
-//   Input is from an edge map, output is an STL Sequence.
-//  
-//   \param g The type of the graph the algorithm runs on.
-//   \param in An edge map containing the cost of the edges.
-//   \par
-//   The cost type can be any type satisfying the
-//   STL 'LessThan Comparable'
-//   concept if it also has an operator+() implemented. (It is necessary for
-//   computing the total cost of the tree).
-//  
-//   \retval out This must be an iteraror of an STL Container with
-//   <tt>GR::Edge</tt> as its <tt>value_type</tt>.
-//   The algorithm copies the elements of the found tree into this sequence.
-//   For example, if we know that the spanning tree of the graph \c g has
-//   say 53 edges, then
-//   we can put its edges into an STL vector \c tree with a code like this.
-//\code
-//   std::vector<Edge> tree(53);
-//   kruskal(g,cost,tree.begin());
-//\endcode
-//   Or if we don't know in advance the size of the tree, we can write this.
-//\code
-//   std::vector<Edge> tree;
-//   kruskal(g,cost,std::back_inserter(tree));
-//\endcode
-//  
-//   \return The cost of the found tree.
-//  
-//   \bug its name does not follow the coding style.
-
-  template <class GR, class IN, class RET>
-  inline
-  typename IN::Value
-  kruskal(const GR& g,
-	  const IN& in,
-	  RET out,
-	  const typename RET::value_type * = 
-	  reinterpret_cast<const typename RET::value_type*>(0)
-	  )
+  /// \ingroup spantree
+  ///
+  /// \brief Kruskal's algorithm to find a minimum cost tree of a graph.
+  ///
+  /// This function runs Kruskal's algorithm to find a minimum cost tree.
+  /// Due to hard C++ hacking, it accepts various input and output types.
+  ///
+  /// \param g The graph the algorithm runs on.
+  /// It can be either \ref concepts::Graph "directed" or 
+  /// \ref concepts::UGraph "undirected".
+  /// If the graph is directed, the algorithm consider it to be 
+  /// undirected by disregarding the direction of the edges.
+  ///
+  /// \param in This object is used to describe the edge costs. It can be one
+  /// of the following choices.
+  ///
+  /// - An STL compatible 'Forward Container' with
+  /// <tt>std::pair<GR::UEdge,X></tt> or
+  /// <tt>std::pair<GR::Edge,X></tt> as its <tt>value_type</tt>, where
+  /// \c X is the type of the costs. The pairs indicates the edges
+  /// along with the assigned cost. <em>They must be in a
+  /// cost-ascending order.</em>
+  /// - Any readable Edge map. The values of the map indicate the edge costs.
+  ///
+  /// \retval out Here we also have a choise.
+  /// - It can be a writable \c bool edge map.  After running the
+  /// algorithm this will contain the found minimum cost spanning
+  /// tree: the value of an edge will be set to \c true if it belongs
+  /// to the tree, otherwise it will be set to \c false. The value of
+  /// each edge will be set exactly once.
+  /// - It can also be an iteraror of an STL Container with
+  /// <tt>GR::UEdge</tt> or <tt>GR::Edge</tt> as its
+  /// <tt>value_type</tt>.  The algorithm copies the elements of the
+  /// found tree into this sequence.  For example, if we know that the
+  /// spanning tree of the graph \c g has say 53 edges, then we can
+  /// put its edges into an STL vector \c tree with a code like this.
+  ///\code
+  /// std::vector<Edge> tree(53);
+  /// kruskal(g,cost,tree.begin());
+  ///\endcode
+  /// Or if we don't know in advance the size of the tree, we can
+  /// write this.  
+  ///\code std::vector<Edge> tree;
+  /// kruskal(g,cost,std::back_inserter(tree)); 
+  ///\endcode
+  ///
+  /// \return The total cost of the found tree.
+  ///
+  /// \warning If kruskal runs on an be consistent of using the same
+  /// Edge type for input and output.
+  ///
+
+#ifdef DOXYGEN
+  template <class Graph, class In, class Out>
+  Value kruskal(GR const& g, const In& in, Out& out)
+#else 
+  template <class Graph, class In, class Out>
+  inline typename _kruskal_bits::KruskalValueSelector<In>::Value 
+  kruskal(const Graph& graph, const In& in, Out& out) 
+#endif
   {
-    KruskalSequenceOutput<RET> _out(out);
-    return kruskal(g, KruskalMapInput<GR,IN>(g, in), _out);
+    return _kruskal_bits::KruskalInputSelector<Graph, In, Out>::
+      kruskal(graph, in, out);
   }
+
  
-  template <class GR, class IN, class RET>
-  inline
-  typename IN::Value
-  kruskal(const GR& g,
-	  const IN& in,
-	  RET *out
-	  )
+  
+
+  template <class Graph, class In, class Out>
+  inline typename _kruskal_bits::KruskalValueSelector<In>::Value
+  kruskal(const Graph& graph, const In& in, const Out& out)
   {
-    KruskalSequenceOutput<RET*> _out(out);
-    return kruskal(g, KruskalMapInput<GR,IN>(g, in), _out);
-  }
- 
-  /// @}
+    return _kruskal_bits::KruskalInputSelector<Graph, In, const Out>::
+      kruskal(graph, in, out);
+  }  
 
 } //namespace lemon
 

Modified: lemon/trunk/test/kruskal_test.cc
==============================================================================
--- lemon/trunk/test/kruskal_test.cc	(original)
+++ lemon/trunk/test/kruskal_test.cc	Thu Apr 19 17:11:58 2007
@@ -23,8 +23,10 @@
 #include <lemon/maps.h>
 #include <lemon/kruskal.h>
 #include <lemon/list_graph.h>
+
 #include <lemon/concepts/maps.h>
 #include <lemon/concepts/graph.h>
+#include <lemon/concepts/ugraph.h>
 
 
 using namespace std;
@@ -33,21 +35,56 @@
 void checkCompileKruskal()
 {
   concepts::WriteMap<concepts::Graph::Edge,bool> w;
+  concepts::WriteMap<concepts::UGraph::UEdge,bool> uw;
+
+  concepts::ReadMap<concepts::Graph::Edge,int> r;
+  concepts::ReadMap<concepts::UGraph::UEdge,int> ur;
 
   concepts::Graph g;
-  kruskal(g,
-	  concepts::ReadMap<concepts::Graph::Edge,int>(),
-	  w);
+  concepts::UGraph ug;
+
+  kruskal(g, r, w);
+  kruskal(ug, ur, uw);
+
+  std::vector<std::pair<concepts::Graph::Edge, int> > rs;
+  std::vector<std::pair<concepts::UGraph::UEdge, int> > urs;
+
+  kruskal(g, rs, w);
+  kruskal(ug, urs, uw);
+
+  std::vector<concepts::Graph::Edge> ws;
+  std::vector<concepts::UGraph::UEdge> uws;
+
+  kruskal(g, r, ws.begin());
+  kruskal(ug, ur, uws.begin());
+
+  Kruskal<concepts::UGraph,concepts::ReadMap<concepts::UGraph::UEdge,int> >
+    alg(ug, ur);
+
+  alg.init();
+  alg.initPresorted(uws.begin(), uws.end());
+  alg.reinit();
+  
+  alg.emptyQueue();
+  
+  alg.nextEdge();
+  alg.processNextEdge();
+  alg.processEdge(concepts::UGraph::UEdge());
+
+  alg.run();
+  
+  alg.treeMap();
+  alg.tree(concepts::UGraph::UEdge());
 }
 
 int main() {
 
-  typedef ListGraph::Node Node;
-  typedef ListGraph::Edge Edge;
-  typedef ListGraph::NodeIt NodeIt;
-  typedef ListGraph::EdgeIt EdgeIt;
+  typedef ListUGraph::Node Node;
+  typedef ListUGraph::UEdge UEdge;
+  typedef ListUGraph::NodeIt NodeIt;
+  typedef ListUGraph::EdgeIt EdgeIt;
 
-  ListGraph G;
+  ListUGraph G;
 
   Node s=G.addNode();
   Node v1=G.addNode();
@@ -56,26 +93,26 @@
   Node v4=G.addNode();
   Node t=G.addNode();
   
-  Edge e1 = G.addEdge(s, v1);
-  Edge e2 = G.addEdge(s, v2);
-  Edge e3 = G.addEdge(v1, v2);
-  Edge e4 = G.addEdge(v2, v1);
-  Edge e5 = G.addEdge(v1, v3);
-  Edge e6 = G.addEdge(v3, v2);
-  Edge e7 = G.addEdge(v2, v4);
-  Edge e8 = G.addEdge(v4, v3);
-  Edge e9 = G.addEdge(v3, t);
-  Edge e10 = G.addEdge(v4, t);
+  UEdge e1 = G.addEdge(s, v1);
+  UEdge e2 = G.addEdge(s, v2);
+  UEdge e3 = G.addEdge(v1, v2);
+  UEdge e4 = G.addEdge(v2, v1);
+  UEdge e5 = G.addEdge(v1, v3);
+  UEdge e6 = G.addEdge(v3, v2);
+  UEdge e7 = G.addEdge(v2, v4);
+  UEdge e8 = G.addEdge(v4, v3);
+  UEdge e9 = G.addEdge(v3, t);
+  UEdge e10 = G.addEdge(v4, t);
 
-  typedef ListGraph::EdgeMap<int> ECostMap;
-  typedef ListGraph::EdgeMap<bool> EBoolMap;
+  typedef ListUGraph::UEdgeMap<int> ECostMap;
+  typedef ListUGraph::UEdgeMap<bool> EBoolMap;
 
   ECostMap edge_cost_map(G, 2);
   EBoolMap tree_map(G);
   
 
   //Test with const map.
-  check(kruskal(G, ConstMap<ListGraph::Edge,int>(2), tree_map)==10,
+  check(kruskal(G, ConstMap<ListUGraph::UEdge,int>(2), tree_map)==10,
 	"Total cost should be 10");
   //Test with a edge map (filled with uniform costs).
   check(kruskal(G, edge_cost_map, tree_map)==10,
@@ -92,7 +129,7 @@
   edge_cost_map.set(e9, -2);
   edge_cost_map.set(e10, -1);
 
-  vector<Edge> tree_edge_vec(5);
+  vector<UEdge> tree_edge_vec(5);
 
   //Test with a edge map and inserter.
   check(kruskal(G, edge_cost_map,
@@ -107,14 +144,14 @@
 	==-31,
 	"Total cost should be -31.");
   
-  tree_edge_vec.clear();
+//   tree_edge_vec.clear();
   
-  //The above test could also be coded like this:
-  check(kruskal(G,
-		makeKruskalMapInput(G, edge_cost_map),
-		makeKruskalSequenceOutput(back_inserter(tree_edge_vec)))
-	==-31,
-	"Total cost should be -31.");
+//   //The above test could also be coded like this:
+//   check(kruskal(G,
+// 		makeKruskalMapInput(G, edge_cost_map),
+// 		makeKruskalSequenceOutput(back_inserter(tree_edge_vec)))
+// 	==-31,
+// 	"Total cost should be -31.");
 
   check(tree_edge_vec.size()==5,"The tree should have 5 edges.");
 
@@ -125,5 +162,19 @@
 	tree_edge_vec[4]==e9,
 	"Wrong tree.");
 
+  Kruskal<ListUGraph, ECostMap> ka(G, edge_cost_map);
+  
+  ka.run();
+  
+  check(ka.tree(e1) && 
+        ka.tree(e2) &&
+        ka.tree(e5) &&
+        ka.tree(e7) &&
+        ka.tree(e9),
+        "Wrong tree.");
+
+  check(ka.treeValue() == -31,
+	"Total cost should be -31.");
+
   return 0;
 }



More information about the Lemon-commits mailing list