# HG changeset patch # User Antal Nemes # Date 2010-11-15 22:23:35 # Node ID 70bee017b584c6c4e3dd4013e37a4d875dbbe0f0 # Parent 1937b6455b7d0cff4f1e21bdd7c5a66b4c1af1cf Port max. card. search alg. from svn -r3512 (#397) and (#56) diff --git a/lemon/Makefile.am b/lemon/Makefile.am --- a/lemon/Makefile.am +++ b/lemon/Makefile.am @@ -107,6 +107,7 @@ lemon/matching.h \ lemon/math.h \ lemon/min_cost_arborescence.h \ + lemon/max_cardinality_search.h \ lemon/nauty_reader.h \ lemon/network_simplex.h \ lemon/pairing_heap.h \ diff --git a/lemon/max_cardinality_search.h b/lemon/max_cardinality_search.h new file mode 100644 --- /dev/null +++ b/lemon/max_cardinality_search.h @@ -0,0 +1,786 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2010 + * 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_MAX_CARDINALITY_SEARCH_H +#define LEMON_MAX_CARDINALITY_SEARCH_H + + +/// \ingroup search +/// \file +/// \brief Maximum cardinality search in undirected digraphs. + +#include +#include + +#include +#include + +#include + +namespace lemon { + + /// \brief Default traits class of MaxCardinalitySearch class. + /// + /// Default traits class of MaxCardinalitySearch class. + /// \param Digraph Digraph type. + /// \param CapacityMap Type of capacity map. + template + struct MaxCardinalitySearchDefaultTraits { + /// The digraph type the algorithm runs on. + typedef GR Digraph; + + template + struct CapMapSelector { + + typedef CM CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph& g) { + return new CapacityMap(g); + } + }; + + template + struct CapMapSelector > > { + + typedef ConstMap > CapacityMap; + + static CapacityMap *createCapacityMap(const Digraph&) { + return new CapacityMap; + } + }; + + /// \brief The type of the map that stores the arc capacities. + /// + /// The type of the map that stores the arc capacities. + /// It must meet the \ref concepts::ReadMap "ReadMap" concept. + typedef typename CapMapSelector::CapacityMap CapacityMap; + + /// \brief The type of the capacity of the arcs. + typedef typename CapacityMap::Value Value; + + /// \brief Instantiates a CapacityMap. + /// + /// This function instantiates a \ref CapacityMap. + /// \param digraph is the digraph, to which we would like to define + /// the CapacityMap. + static CapacityMap *createCapacityMap(const Digraph& digraph) { + return CapMapSelector::createCapacityMap(digraph); + } + + /// \brief The cross reference type used by heap. + /// + /// The cross reference type used by heap. + /// Usually it is \c Digraph::NodeMap. + typedef typename Digraph::template NodeMap HeapCrossRef; + + /// \brief Instantiates a HeapCrossRef. + /// + /// This function instantiates a \ref HeapCrossRef. + /// \param digraph is the digraph, to which we would like to define the + /// HeapCrossRef. + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + + template + struct HeapSelector { + template + struct Selector { + typedef BinHeap > Heap; + }; + }; + + template + struct HeapSelector > > { + template + struct Selector { + typedef BucketHeap Heap; + }; + }; + + /// \brief The heap type used by MaxCardinalitySearch algorithm. + /// + /// The heap type used by MaxCardinalitySearch algorithm. It should + /// maximalize the priorities. The default heap type is + /// the \ref BinHeap, but it is specialized when the + /// CapacityMap is ConstMap > + /// to BucketHeap. + /// + /// \sa MaxCardinalitySearch + typedef typename HeapSelector + ::template Selector + ::Heap Heap; + + /// \brief Instantiates a Heap. + /// + /// This function instantiates a \ref Heap. + /// \param crossref The cross reference of the heap. + static Heap *createHeap(HeapCrossRef& crossref) { + return new Heap(crossref); + } + + /// \brief The type of the map that stores whether a node is processed. + /// + /// The type of the map that stores whether a node is processed. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + /// By default it is a NullMap. + typedef NullMap ProcessedMap; + + /// \brief Instantiates a ProcessedMap. + /// + /// This function instantiates a \ref ProcessedMap. + /// \param digraph is the digraph, to which + /// we would like to define the \ref ProcessedMap +#ifdef DOXYGEN + static ProcessedMap *createProcessedMap(const Digraph &digraph) +#else + static ProcessedMap *createProcessedMap(const Digraph &) +#endif + { + return new ProcessedMap(); + } + + /// \brief The type of the map that stores the cardinalities of the nodes. + /// + /// The type of the map that stores the cardinalities of the nodes. + /// It must meet the \ref concepts::WriteMap "WriteMap" concept. + typedef typename Digraph::template NodeMap CardinalityMap; + + /// \brief Instantiates a CardinalityMap. + /// + /// This function instantiates a \ref CardinalityMap. + /// \param digraph is the digraph, to which we would like to define the \ref + /// CardinalityMap + static CardinalityMap *createCardinalityMap(const Digraph &digraph) { + return new CardinalityMap(digraph); + } + + + }; + + /// \ingroup search + /// + /// \brief Maximum Cardinality Search algorithm class. + /// + /// This class provides an efficient implementation of Maximum Cardinality + /// Search algorithm. The maximum cardinality search first chooses any + /// node of the digraph. Then every time it chooses one unprocessed node + /// with maximum cardinality, i.e the sum of capacities on out arcs to the nodes + /// which were previusly processed. + /// If there is a cut in the digraph the algorithm should choose + /// again any unprocessed node of the digraph. + + /// The arc capacities are passed to the algorithm using a + /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any + /// kind of capacity. + /// + /// The type of the capacity is determined by the \ref + /// concepts::ReadMap::Value "Value" of the capacity map. + /// + /// It is also possible to change the underlying priority heap. + /// + /// + /// \param GR The digraph type the algorithm runs on. The value of + /// Digraph is not used directly by the search algorithm, it + /// is only passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param CAP This read-only ArcMap determines the capacities of + /// the arcs. It is read once for each arc, so the map may involve in + /// relatively time consuming process to compute the arc capacity if + /// it is necessary. The default map type is \ref + /// ConstMap "ConstMap >". The value + /// of CapacityMap is not used directly by search algorithm, it is only + /// passed to \ref MaxCardinalitySearchDefaultTraits. + /// \param TR Traits class to set various data types used by the + /// algorithm. The default traits class is + /// \ref MaxCardinalitySearchDefaultTraits + /// "MaxCardinalitySearchDefaultTraits". + /// See \ref MaxCardinalitySearchDefaultTraits + /// for the documentation of a MaxCardinalitySearch traits class. + +#ifdef DOXYGEN + template +#else + template >, + typename TR = + MaxCardinalitySearchDefaultTraits > +#endif + class MaxCardinalitySearch { + public: + + typedef TR Traits; + ///The type of the underlying digraph. + typedef typename Traits::Digraph Digraph; + + ///The type of the capacity of the arcs. + typedef typename Traits::CapacityMap::Value Value; + ///The type of the map that stores the arc capacities. + typedef typename Traits::CapacityMap CapacityMap; + ///The type of the map indicating if a node is processed. + typedef typename Traits::ProcessedMap ProcessedMap; + ///The type of the map that stores the cardinalities of the nodes. + typedef typename Traits::CardinalityMap CardinalityMap; + ///The cross reference type used for the current heap. + typedef typename Traits::HeapCrossRef HeapCrossRef; + ///The heap type used by the algorithm. It maximizes the priorities. + typedef typename Traits::Heap Heap; + private: + // Pointer to the underlying digraph. + const Digraph *_graph; + // Pointer to the capacity map + const CapacityMap *_capacity; + // Indicates if \ref _capacity is locally allocated (\c true) or not. + bool local_capacity; + // Pointer to the map of cardinality. + CardinalityMap *_cardinality; + // Indicates if \ref _cardinality is locally allocated (\c true) or not. + bool local_cardinality; + // Pointer to the map of processed status of the nodes. + ProcessedMap *_processed; + // Indicates if \ref _processed is locally allocated (\c true) or not. + bool local_processed; + // Pointer to the heap cross references. + HeapCrossRef *_heap_cross_ref; + // Indicates if \ref _heap_cross_ref is locally allocated (\c true) or not. + bool local_heap_cross_ref; + // Pointer to the heap. + Heap *_heap; + // Indicates if \ref _heap is locally allocated (\c true) or not. + bool local_heap; + + public : + + typedef MaxCardinalitySearch Create; + + ///\name Named template parameters + + ///@{ + + template + struct DefCapacityMapTraits : public Traits { + typedef T CapacityMap; + static CapacityMap *createCapacityMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CapacityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CapacityMap type + /// for the algorithm. + template + struct SetCapacityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefCardinalityMapTraits : public Traits { + typedef T CardinalityMap; + static CardinalityMap *createCardinalityMap(const Digraph &) + { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// CardinalityMap type + /// + /// \ref named-templ-param "Named parameter" for setting CardinalityMap + /// type for the algorithm. + template + struct SetCardinalityMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefProcessedMapTraits : public Traits { + typedef T ProcessedMap; + static ProcessedMap *createProcessedMap(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting + /// ProcessedMap type + /// + /// \ref named-templ-param "Named parameter" for setting ProcessedMap type + /// for the algorithm. + template + struct SetProcessedMap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > Create; + }; + + template + struct DefHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + static Heap *createHeap(HeapCrossRef &) { + LEMON_ASSERT(false,"Uninitialized parameter."); + return 0; + } + }; + /// \brief \ref named-templ-param "Named parameter" for setting heap + /// and cross reference type + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type for the algorithm. + template > + struct SetHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch< Digraph, CapacityMap, + DefHeapTraits > Create; + }; + + template + struct DefStandardHeapTraits : public Traits { + typedef CR HeapCrossRef; + typedef H Heap; + static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { + return new HeapCrossRef(digraph); + } + static Heap *createHeap(HeapCrossRef &crossref) { + return new Heap(crossref); + } + }; + + /// \brief \ref named-templ-param "Named parameter" for setting heap and + /// cross reference type with automatic allocation + /// + /// \ref named-templ-param "Named parameter" for setting heap and cross + /// reference type. It can allocate the heap and the cross reference + /// object if the cross reference's constructor waits for the digraph as + /// parameter and the heap's constructor waits for the cross reference. + template > + struct SetStandardHeap + : public MaxCardinalitySearch > { + typedef MaxCardinalitySearch > + Create; + }; + + ///@} + + + protected: + + MaxCardinalitySearch() {} + + public: + + /// \brief Constructor. + /// + ///\param digraph the digraph the algorithm will run on. + ///\param capacity the capacity map used by the algorithm. + ///When no capacity map given, a constant 1 capacity map will + ///be allocated. +#ifdef DOXYGEN + MaxCardinalitySearch(const Digraph& digraph, + const CapacityMap& capacity=0 ) : +#else + MaxCardinalitySearch(const Digraph& digraph, + const CapacityMap& capacity=*static_cast(0) ) : +#endif + _graph(&digraph), + _capacity(&capacity), local_capacity(false), + _cardinality(0), local_cardinality(false), + _processed(0), local_processed(false), + _heap_cross_ref(0), local_heap_cross_ref(false), + _heap(0), local_heap(false) + { } + + /// \brief Destructor. + ~MaxCardinalitySearch() { + if(local_capacity) delete _capacity; + if(local_cardinality) delete _cardinality; + if(local_processed) delete _processed; + if(local_heap_cross_ref) delete _heap_cross_ref; + if(local_heap) delete _heap; + } + + /// \brief Sets the capacity map. + /// + /// Sets the capacity map. + /// \return (*this) + MaxCardinalitySearch &capacityMap(const CapacityMap &m) { + if (local_capacity) { + delete _capacity; + local_capacity=false; + } + _capacity=&m; + return *this; + } + + /// \brief Returns a const reference to the capacity map. + /// + /// Returns a const reference to the capacity map used by + /// the algorithm. + const CapacityMap &capacityMap() const { + return *_capacity; + } + + /// \brief Sets the map storing the cardinalities calculated by the + /// algorithm. + /// + /// Sets the map storing the cardinalities calculated by the algorithm. + /// 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 (*this) + MaxCardinalitySearch &cardinalityMap(CardinalityMap &m) { + if(local_cardinality) { + delete _cardinality; + local_cardinality=false; + } + _cardinality = &m; + return *this; + } + + /// \brief Sets the map storing the processed nodes. + /// + /// Sets the map storing the processed nodes. + /// 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 (*this) + MaxCardinalitySearch &processedMap(ProcessedMap &m) + { + if(local_processed) { + delete _processed; + local_processed=false; + } + _processed = &m; + return *this; + } + + /// \brief Returns a const reference to the cardinality map. + /// + /// Returns a const reference to the cardinality map used by + /// the algorithm. + const ProcessedMap &processedMap() const { + return *_processed; + } + + /// \brief Sets the heap and the cross reference used by algorithm. + /// + /// Sets the heap and the cross reference used by algorithm. + /// 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 (*this) + MaxCardinalitySearch &heap(Heap& hp, HeapCrossRef &cr) { + if(local_heap_cross_ref) { + delete _heap_cross_ref; + local_heap_cross_ref = false; + } + _heap_cross_ref = &cr; + if(local_heap) { + delete _heap; + local_heap = false; + } + _heap = &hp; + return *this; + } + + /// \brief Returns a const reference to the heap. + /// + /// Returns a const reference to the heap used by + /// the algorithm. + const Heap &heap() const { + return *_heap; + } + + /// \brief Returns a const reference to the cross reference. + /// + /// Returns a const reference to the cross reference + /// of the heap. + const HeapCrossRef &heapCrossRef() const { + return *_heap_cross_ref; + } + + private: + + typedef typename Digraph::Node Node; + typedef typename Digraph::NodeIt NodeIt; + typedef typename Digraph::Arc Arc; + typedef typename Digraph::InArcIt InArcIt; + + void create_maps() { + if(!_capacity) { + local_capacity = true; + _capacity = Traits::createCapacityMap(*_graph); + } + if(!_cardinality) { + local_cardinality = true; + _cardinality = Traits::createCardinalityMap(*_graph); + } + if(!_processed) { + local_processed = true; + _processed = Traits::createProcessedMap(*_graph); + } + if (!_heap_cross_ref) { + local_heap_cross_ref = true; + _heap_cross_ref = Traits::createHeapCrossRef(*_graph); + } + if (!_heap) { + local_heap = true; + _heap = Traits::createHeap(*_heap_cross_ref); + } + } + + void finalizeNodeData(Node node, Value capacity) { + _processed->set(node, true); + _cardinality->set(node, capacity); + } + + public: + /// \name Execution control + /// The simplest way to execute the algorithm is to use + /// one of the member functions called \ref run(). + /// \n + /// If you need more control on the execution, + /// first you must call \ref init(), then you can add several source nodes + /// with \ref addSource(). + /// Finally \ref start() will perform the computation. + + ///@{ + + /// \brief Initializes the internal data structures. + /// + /// Initializes the internal data structures, and clears the heap. + void init() { + create_maps(); + _heap->clear(); + for (NodeIt it(*_graph) ; it != INVALID ; ++it) { + _processed->set(it, false); + _heap_cross_ref->set(it, Heap::PRE_HEAP); + } + } + + /// \brief Adds a new source node. + /// + /// Adds a new source node to the priority heap. + /// + /// It checks if the node has not yet been added to the heap. + void addSource(Node source, Value capacity = 0) { + if(_heap->state(source) == Heap::PRE_HEAP) { + _heap->push(source, capacity); + } + } + + /// \brief Processes the next node in the priority heap + /// + /// Processes the next node in the priority heap. + /// + /// \return The processed node. + /// + /// \warning The priority heap must not be empty! + Node processNextNode() { + Node node = _heap->top(); + finalizeNodeData(node, _heap->prio()); + _heap->pop(); + + for (InArcIt it(*_graph, node); it != INVALID; ++it) { + Node source = _graph->source(it); + switch (_heap->state(source)) { + case Heap::PRE_HEAP: + _heap->push(source, (*_capacity)[it]); + break; + case Heap::IN_HEAP: + _heap->decrease(source, (*_heap)[source] + (*_capacity)[it]); + break; + case Heap::POST_HEAP: + break; + } + } + return node; + } + + /// \brief Next node to be processed. + /// + /// Next node to be processed. + /// + /// \return The next node to be processed or INVALID if the + /// priority heap is empty. + Node nextNode() { + return !_heap->empty() ? _heap->top() : INVALID; + } + + /// \brief Returns \c false if there are nodes + /// to be processed in the priority heap + /// + /// Returns \c false if there are nodes + /// to be processed in the priority heap + bool emptyQueue() { return _heap->empty(); } + /// \brief Returns the number of the nodes to be processed + /// in the priority heap + /// + /// Returns the number of the nodes to be processed in the priority heap + int emptySize() { return _heap->size(); } + + /// \brief 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 Maximum Cardinality Search algorithm from the + /// source node(s). + void start() { + while ( !_heap->empty() ) processNextNode(); + } + + /// \brief Executes the algorithm until \c dest is reached. + /// + /// Executes the algorithm until \c dest is reached. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// This method runs the %MaxCardinalitySearch algorithm from the source + /// nodes. + void start(Node dest) { + while ( !_heap->empty() && _heap->top()!=dest ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(), _heap->prio()); + } + + /// \brief Executes the algorithm until a condition is met. + /// + /// Executes the algorithm until a condition is met. + /// + /// \pre init() must be called and at least one node should be added + /// with addSource() before using this function. + /// + /// \param nm must be a bool (or convertible) node map. The algorithm + /// will stop when it reaches a node \c v with nm[v]==true. + template + void start(const NodeBoolMap &nm) { + while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); + if ( !_heap->empty() ) finalizeNodeData(_heap->top(),_heap->prio()); + } + + /// \brief Runs the maximum cardinality search algorithm from node \c s. + /// + /// This method runs the %MaxCardinalitySearch algorithm from a root + /// node \c s. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// d.addSource(s); + /// d.start(); + ///\endcode + void run(Node s) { + init(); + addSource(s); + start(); + } + + /// \brief Runs the maximum cardinality search algorithm for the + /// whole digraph. + /// + /// This method runs the %MaxCardinalitySearch algorithm from all + /// unprocessed node of the digraph. + /// + ///\note d.run(s) is just a shortcut of the following code. + ///\code + /// d.init(); + /// for (NodeIt it(digraph); it != INVALID; ++it) { + /// if (!d.reached(it)) { + /// d.addSource(s); + /// d.start(); + /// } + /// } + ///\endcode + void run() { + init(); + for (NodeIt it(*_graph); it != INVALID; ++it) { + if (!reached(it)) { + addSource(it); + start(); + } + } + } + + ///@} + + /// \name Query Functions + /// The results of the maximum cardinality search algorithm can be + /// obtained using these functions. + /// \n + /// Before the use of these functions, either run() or start() must be + /// called. + + ///@{ + + /// \brief The cardinality of a node. + /// + /// Returns the cardinality of a node. + /// \pre \ref run() must be called before using this function. + /// \warning If node \c v in unreachable from the root the return value + /// of this funcion is undefined. + Value cardinality(Node node) const { return (*_cardinality)[node]; } + + /// \brief The current cardinality of a node. + /// + /// Returns the current cardinality of a node. + /// \pre the given node should be reached but not processed + Value currentCardinality(Node node) const { return (*_heap)[node]; } + + /// \brief Returns a reference to the NodeMap of cardinalities. + /// + /// Returns a reference to the NodeMap of cardinalities. \pre \ref run() + /// must be called before using this function. + const CardinalityMap &cardinalityMap() const { return *_cardinality;} + + /// \brief Checks if a node is reachable from the root. + /// + /// Returns \c true if \c v is reachable from the root. + /// \warning The source nodes are initated as unreached. + /// \pre \ref run() must be called before using this function. + bool reached(Node v) { return (*_heap_cross_ref)[v] != Heap::PRE_HEAP; } + + /// \brief Checks if a node is processed. + /// + /// Returns \c true if \c v is processed, i.e. the shortest + /// path to \c v has already found. + /// \pre \ref run() must be called before using this function. + bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } + + ///@} + }; + +} + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,6 +31,7 @@ kruskal_test maps_test matching_test + max_cardinality_search_test max_clique_test min_cost_arborescence_test min_cost_flow_test diff --git a/test/Makefile.am b/test/Makefile.am --- a/test/Makefile.am +++ b/test/Makefile.am @@ -33,6 +33,7 @@ test/kruskal_test \ test/maps_test \ test/matching_test \ + test/max_cardinality_search_test \ test/max_clique_test \ test/min_cost_arborescence_test \ test/min_cost_flow_test \ @@ -85,6 +86,7 @@ test_maps_test_SOURCES = test/maps_test.cc test_mip_test_SOURCES = test/mip_test.cc test_matching_test_SOURCES = test/matching_test.cc +test_max_cardinality_search_test_SOURCES = test/max_cardinality_search_test.cc test_max_clique_test_SOURCES = test/max_clique_test.cc test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc diff --git a/test/max_cardinality_search_test.cc b/test/max_cardinality_search_test.cc new file mode 100644 --- /dev/null +++ b/test/max_cardinality_search_test.cc @@ -0,0 +1,162 @@ +/* -*- mode: C++; indent-tabs-mode: nil; -*- + * + * This file is a part of LEMON, a generic C++ optimization library. + * + * Copyright (C) 2003-2010 + * 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. + * + */ + +#include + +#include "test_tools.h" +#include +#include +#include +#include +#include +#include + +using namespace lemon; +using namespace std; + +char test_lgf[] = + "@nodes\n" + "label\n" + "0\n" + "1\n" + "2\n" + "3\n" + "@arcs\n" + " label capacity\n" + "0 1 0 2\n" + "1 0 1 2\n" + "2 1 2 1\n" + "2 3 3 3\n" + "3 2 4 3\n" + "3 1 5 5\n" + "@attributes\n" + "s 0\n" + "x 1\n" + "y 2\n" + "z 3\n"; + +void checkMaxCardSearchCompile() { + + typedef concepts::Digraph Digraph; + typedef int Value; + typedef Digraph::Node Node; + typedef Digraph::Arc Arc; + typedef concepts::ReadMap CapMap; + typedef concepts::ReadWriteMap CardMap; + typedef concepts::ReadWriteMap ProcMap; + typedef Digraph::NodeMap HeapCrossRef; + + Digraph g; + Node n,s; + CapMap cap; + CardMap card; + ProcMap proc; + HeapCrossRef crossref(g); + + typedef MaxCardinalitySearch + ::SetCapacityMap + ::SetCardinalityMap + ::SetProcessedMap + ::SetStandardHeap > + ::Create MaxCardType; + + MaxCardType maxcard(g,cap); + const MaxCardType& const_maxcard = maxcard; + + const MaxCardType::Heap& heap_const = const_maxcard.heap(); + MaxCardType::Heap& heap = const_cast(heap_const); + maxcard.heap(heap,crossref); + + maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc); + + maxcard.init(); + maxcard.addSource(s); + n = maxcard.nextNode(); + maxcard.processNextNode(); + maxcard.start(); + maxcard.run(s); + maxcard.run(); + } + + void checkWithIntMap( std::istringstream& input) + { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + typedef Digraph::ArcMap CapMap; + + Digraph g; + Node s,x,y,z,a; + CapMap cap(g); + + DigraphReader(g,input). + arcMap("capacity", cap). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g,cap); + + maxcard.init(); + maxcard.addSource(s); + maxcard.start(x); + + check(maxcard.processed(s) and !maxcard.processed(x) and + !maxcard.processed(y), "Wrong processed()!"); + + a=maxcard.nextNode(); + check(maxcard.processNextNode()==a, + "Wrong nextNode() or processNextNode() return value!"); + + check(maxcard.processed(a), "Wrong processNextNode()!"); + + maxcard.start(); + check(maxcard.cardinality(x)==2 and maxcard.cardinality(y)>=4, + "Wrong cardinalities!"); + } + + void checkWithConst1Map(std::istringstream &input) { + typedef SmartDigraph Digraph; + typedef Digraph::Node Node; + + Digraph g; + Node s,x,y,z; + + DigraphReader(g,input). + node("s",s). + node("x",x). + node("y",y). + node("z",z). + run(); + + MaxCardinalitySearch maxcard(g); + maxcard.run(s); + check(maxcard.cardinality(x)==1 && + maxcard.cardinality(y)+maxcard.cardinality(z)==3, + "Wrong cardinalities!"); +} + +int main() { + + std::istringstream input1(test_lgf); + checkWithIntMap(input1); + + std::istringstream input2(test_lgf); + checkWithConst1Map(input2); +}