/* -*- 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_FREDMAN_TARJAN_H #define LEMON_FREDMAN_TARJAN_H ///\ingroup spantree ///\file ///\brief FredmanTarjan algorithm to compute minimum spanning forest. #include #include #include #include #include #include #include #include #include #include #include #include namespace lemon { ///Default traits class of FredmanTarjan class. ///Default traits class of FredmanTarjan class. ///\param GR Graph type. ///\param LM Type of cost map. template struct FredmanTarjanDefaultTraits{ ///The graph type the algorithm runs on. typedef GR UGraph; ///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 concept::ReadMap "ReadMap" concept. typedef LM CostMap; //The type of the cost of the edges. typedef typename LM::Value Value; ///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. ///It must meet the \ref concept::ReadWriteMap "ReadWriteMap" concept. ///By default it is a BoolEdgeMap. typedef typename UGraph::template UEdgeMap TreeMap; ///Instantiates a TreeMap. ///This function instantiates a \ref TreeMap. ///\param _graph is the graph, to which ///we would like to define the \ref TreeMap static TreeMap *createTreeMap(const GR &_graph){ return new TreeMap(_graph); } }; ///%FredmanTarjan algorithm class to find a minimum spanning tree. /// \ingroup spantree ///This class provides an efficient implementation of %FredmanTarjan algorithm ///whitch is sometimes a bit quicker than the Prim algorithm on larger graphs. ///Due to the structure of the algorithm, it has less controll functions than ///Prim. /// ///The running time is O(e*B(e,n)) where e is the number of edges, n is the ///number of nodes in the graph and B(e,n) is min { i | log^(i) n <= e/n} ///( log^(i+1) n = log(log^(i)) n ) /// ///The edge costs are passed to the algorithm using a ///\ref concept::ReadMap "ReadMap", ///so it is easy to change it to any kind of cost. /// ///The type of the cost is determined by the ///\ref concept::ReadMap::Value "Value" of the cost map. /// ///\param GR The graph type the algorithm runs on. The default value ///is \ref ListUGraph. The value of GR is not used directly by ///FredmanTarjan, it is only passed to \ref FredmanTarjanDefaultTraits. /// ///\param LM This read-only UEdgeMap determines the costs of the ///edges. It is read once for each edge, so the map may involve in ///relatively time consuming process to compute the edge cost if ///it is necessary. The default map type is \ref ///concept::UGraph::UEdgeMap "UGraph::UEdgeMap". The value ///of LM is not used directly by FredmanTarjan, it is only passed to \ref ///FredmanTarjanDefaultTraits. /// ///\param TR Traits class to set ///various data types used by the algorithm. The default traits ///class is \ref FredmanTarjanDefaultTraits ///"FredmanTarjanDefaultTraits". See \ref ///FredmanTarjanDefaultTraits for the documentation of a FredmanTarjan traits ///class. /// ///\author Balazs Attila Mihaly #ifdef DOXYGEN template #else template , typename TR=FredmanTarjanDefaultTraits > #endif class FredmanTarjan { public: /** * \brief \ref Exception for uninitialized parameters. * * This error represents problems in the initialization * of the parameters of the algorithms. */ class UninitializedParameter : public lemon::UninitializedParameter { public: virtual const char* exceptionName() const { return "lemon::FredmanTarjan::UninitializedParameter"; } }; typedef GR Graph; typedef TR Traits; ///The type of the underlying graph. typedef typename TR::UGraph UGraph; ///\e typedef typename UGraph::Node Node; ///\e typedef typename UGraph::NodeIt NodeIt; ///\e typedef typename UGraph::UEdge UEdge; ///\e typedef typename UGraph::UEdgeIt UEdgeIt; ///\e typedef typename UGraph::IncEdgeIt IncEdgeIt; ///The type of the cost of the edges. typedef typename TR::CostMap::Value Value; ///The type of the map that stores the edge costs. typedef typename TR::CostMap CostMap; ///Edges of the spanning tree. typedef typename TR::TreeMap TreeMap; private: ///Pointer to the underlying graph. const UGraph *graph; ///Pointer to the cost map const CostMap *cost; ///Pointer to the map of tree edges. TreeMap *_tree; ///Indicates if \ref _tree is locally allocated (\c true) or not. bool local_tree; ///Creates the maps if necessary. void create_maps(){ if(!_tree){ local_tree=true; _tree=Traits::createTreeMap(*graph); } } public : typedef FredmanTarjan Create; ///\name Named template parameters ///@{ template struct DefTreeMapTraits : public Traits { typedef TM TreeMap; static TreeMap *createTreeMap(const UGraph &) { throw UninitializedParameter(); } }; ///\ref named-templ-param "Named parameter" for setting TreeMap ///\ref named-templ-param "Named parameter" for setting TreeMap /// template struct DefTreeMap : public FredmanTarjan< UGraph, CostMap, DefTreeMapTraits > { typedef FredmanTarjan< UGraph, CostMap, DefTreeMapTraits > Create; }; ///@} protected: FredmanTarjan() {} private: template void processNextTree(const SrcGraph& graph,const OrigMap& orig,Heap &heap, ProcessedMap& processed,PredMap& pred,int& tree_counter,const int limit){ std::vector tree_nodes; int tree_index=tree_counter; bool stop=false; while(!heap.empty() && !stop){ typename SrcGraph::Node v=heap.top(); heap.pop(); if(processed[v]!=-1){ heap.state(v,Heap::PRE_HEAP); tree_index=processed[v]; _tree->set(orig[pred[v]],true); stop=true; break; } tree_nodes.push_back(v); for(typename SrcGraph::IncEdgeIt e(graph,v);e!=INVALID;++e){ typename SrcGraph::Node w=graph.oppositeNode(v,e); switch(heap.state(w)){ case Heap::PRE_HEAP: if(heap.size()>=limit){ stop=true; } else{ heap.push(w,(*cost)[orig[e]]); pred.set(w,e); } break; case Heap::IN_HEAP: if ((*cost)[orig[e]]set(orig[pred[tree_nodes[i]]],true); processed.set(tree_nodes[i],tree_index); heap.state(tree_nodes[i], Heap::PRE_HEAP); } processed.set(tree_nodes[0],tree_index); heap.state(tree_nodes[0],Heap::PRE_HEAP); while (!heap.empty()) { typename SrcGraph::Node v=heap.top(); heap.pop(); heap.state(v,Heap::PRE_HEAP); } if(!stop)++tree_counter; } template void createTrees(const SrcGraph& graph,const OrigMap& orig, ProcessedMap& processed, int edgenum,int& tree_counter){ typedef typename SrcGraph::Node Node; typedef typename SrcGraph::UEdge UEdge; typedef typename SrcGraph::NodeIt NodeIt; typedef typename SrcGraph::template NodeMap HeapCrossRef; typedef typename SrcGraph::template NodeMap PredMap; HeapCrossRef crossref(graph,-1); FibHeap heap(crossref); PredMap pred(graph,INVALID); int rate=2*edgenum/countNodes(graph); int limit=(rate>std::numeric_limits::digits)?std::numeric_limits::max():(1< void collect(const SrcGraph& srcgraph,const SrcOrigMap& srcorig,DestGraph& destgraph, DestOrigMap& destorig,const ProcessedMap& processed,const int tree_counter){ typedef typename SrcGraph::Node Node; typedef typename DestGraph::Node DNode; typedef typename SrcGraph::UEdge UEdge; typedef typename DestGraph::UEdge DUEdge; typedef typename SrcGraph::Edge Edge; typedef typename SrcGraph::EdgeIt EdgeIt; std::vector edges; std::vector nodes(tree_counter, INVALID); for(EdgeIt i(srcgraph);i!=INVALID;++i){ if(processed[srcgraph.source(i)](*cost)[srcorig[edges[i+1]]]) { minval=(*cost)[srcorig[edges[i+1]]]; minpos=edges[i+1]; } ++i; } destorig[destgraph.addEdge(nodes[srcproc],nodes[trgproc])]=srcorig[minpos]; } } template void phase(const SrcGraph& graph,const OrigMap& orig,int edgenum){ int tree_counter = 0; typename SrcGraph::template NodeMap processed(graph,-1); SmartUGraph destgraph; SmartUGraph::UEdgeMap destorig(destgraph); createTrees(graph,orig,processed,edgenum,tree_counter); collect(graph,orig,destgraph,destorig,processed,tree_counter); if (countNodes(destgraph)>1) { phase(destgraph,destorig,edgenum); } } public: ///Constructor. ///\param _graph the graph the algorithm will run on. ///\param _cost the cost map used by the algorithm. FredmanTarjan(const UGraph& _graph, const CostMap& _cost) : graph(&_graph), cost(&_cost), _tree(0), local_tree(false) { checkConcept(); } ///Destructor. ~FredmanTarjan(){ if(local_tree) delete _tree; } ///Sets the cost map. ///Sets the cost map. ///\return (*this) FredmanTarjan &costMap(const CostMap &m){ cost = &m; return *this; } ///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. ///By default this is a BoolEdgeMap. ///\return (*this) FredmanTarjan &treeMap(TreeMap &m){ if(local_tree) { delete _tree; local_tree=false; } _tree = &m; return *this; } public: ///\name Execution control ///The simplest way to execute the algorithm is to use ///one of the member functions called \c run(...). ///@{ ///Initializes the internal data structures. ///Initializes the internal data structures. /// void init(){ create_maps(); for(typename Graph::UEdgeIt i(*graph);i!=INVALID;++i){ _tree->set(i,false); } } ///Executes the algorithm. ///Executes the algorithm. /// ///\pre init() must be called and at least one node should be added ///with addSource() before using this function. /// ///This method runs the %FredmanTarjan algorithm from the node(s) ///in order to compute the ///minimum spanning tree. void start(){ phase(*graph,identityMap(),countEdges(*graph)); } ///Runs %FredmanTarjan algorithm. ///This method runs the %FredmanTarjan algorithm ///in order to compute the minimum spanning forest. /// ///\note ft.run() is just a shortcut of the following code. ///\code /// ft.init(); /// ft.start(); ///\endcode void run() { init(); start(); } ///@} ///\name Query Functions ///The result of the %FredmanTarjan algorithm can be obtained using these ///functions.\n ///Before the use of these functions, ///either run() or start() must be called. ///@{ ///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. /// ///\pre \ref run() or \ref start() must be called before using this ///function. const TreeMap &treeMap() const { return *_tree;} ///Sets the tree edges map. ///Sets the TreeMap of the edges of the minimum spanning tree. ///The map values belonging to the edges of the minimum ///spanning tree are set to \c tree_edge_value or \c true by default ///while the edge values not belonging to the minimum spanning tree are ///set to ///\c tree_default_value or \c false by default. /// ///\pre \ref run() or \ref start() must be called before using this ///function. template void treeEdges( TreeMap& tree, const typename TreeMap::Value& tree_edge_value=true, const typename TreeMap::Value& tree_default_value=false) const { for(typename UGraph::UEdgeIt i(*graph);i!=INVALID;++i){ (*_tree)[i]?tree.set(i,tree_edge_value):tree.set(i,tree_default_value); } } ///\brief Checks if an edge is in the spanning tree or not. ///Checks if an edge is in the spanning tree or not. ///\param e is the edge that will be checked ///\return \c true if e is in the spanning tree, \c false otherwise bool tree(UEdge e){ return (*_tree)[e]; } ///@} }; /// \ingroup spantree /// /// \brief Function type interface for FredmanTarjan algorithm. /// /// Function type interface for FredmanTarjan algorithm. /// \param graph the UGraph that the algorithm runs on /// \param cost the CostMap of the edges /// \retval tree the EdgeMap that contains whether an edge is in the /// spanning tree or not /// /// \sa Prim template void fredmanTarjan(const Graph& graph, const CostMap& cost,TreeMap& tree){ typename FredmanTarjan::template DefTreeMap:: Create ft(graph,cost); ft.treeMap(tree); ft.run(); } } //END OF NAMESPACE LEMON #endif