deba@948: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@948: * deba@948: * This file is a part of LEMON, a generic C++ optimization library. deba@948: * deba@948: * Copyright (C) 2003-2009 deba@948: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@948: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@948: * deba@948: * Permission to use, modify and distribute this software is granted deba@948: * provided that this copyright notice appears in all copies. For deba@948: * precise terms see the accompanying LICENSE file. deba@948: * deba@948: * This software is provided "AS IS" with no warranty of any kind, deba@948: * express or implied, and with no claim as to its suitability for any deba@948: * purpose. deba@948: * deba@948: */ deba@948: deba@948: #ifndef LEMON_FRACTIONAL_MATCHING_H deba@948: #define LEMON_FRACTIONAL_MATCHING_H deba@948: deba@948: #include deba@948: #include deba@948: #include deba@948: #include deba@948: deba@948: #include deba@948: #include deba@948: #include deba@948: #include deba@948: #include deba@948: #include deba@948: deba@948: ///\ingroup matching deba@948: ///\file deba@948: ///\brief Fractional matching algorithms in general graphs. deba@948: deba@948: namespace lemon { deba@948: deba@948: /// \brief Default traits class of MaxFractionalMatching class. deba@948: /// deba@948: /// Default traits class of MaxFractionalMatching class. deba@948: /// \tparam GR Graph type. deba@948: template deba@948: struct MaxFractionalMatchingDefaultTraits { deba@948: deba@948: /// \brief The type of the graph the algorithm runs on. deba@948: typedef GR Graph; deba@948: deba@948: /// \brief The type of the map that stores the matching. deba@948: /// deba@948: /// The type of the map that stores the matching arcs. deba@948: /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. deba@948: typedef typename Graph::template NodeMap MatchingMap; deba@948: deba@948: /// \brief Instantiates a MatchingMap. deba@948: /// deba@948: /// This function instantiates a \ref MatchingMap. deba@948: /// \param graph The graph for which we would like to define deba@948: /// the matching map. deba@948: static MatchingMap* createMatchingMap(const Graph& graph) { deba@948: return new MatchingMap(graph); deba@948: } deba@948: deba@948: /// \brief The elevator type used by MaxFractionalMatching algorithm. deba@948: /// deba@948: /// The elevator type used by MaxFractionalMatching algorithm. deba@948: /// deba@948: /// \sa Elevator deba@948: /// \sa LinkedElevator deba@948: typedef LinkedElevator Elevator; deba@948: deba@948: /// \brief Instantiates an Elevator. deba@948: /// deba@948: /// This function instantiates an \ref Elevator. deba@948: /// \param graph The graph for which we would like to define deba@948: /// the elevator. deba@948: /// \param max_level The maximum level of the elevator. deba@948: static Elevator* createElevator(const Graph& graph, int max_level) { deba@948: return new Elevator(graph, max_level); deba@948: } deba@948: }; deba@948: deba@948: /// \ingroup matching deba@948: /// deba@948: /// \brief Max cardinality fractional matching deba@948: /// deba@948: /// This class provides an implementation of fractional matching deba@948: /// algorithm based on push-relabel principle. deba@948: /// deba@948: /// The maximum cardinality fractional matching is a relaxation of the deba@948: /// maximum cardinality matching problem where the odd set constraints deba@948: /// are omitted. deba@948: /// It can be formulated with the following linear program. deba@948: /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] deba@948: /// \f[x_e \ge 0\quad \forall e\in E\f] deba@948: /// \f[\max \sum_{e\in E}x_e\f] deba@948: /// where \f$\delta(X)\f$ is the set of edges incident to a node in deba@948: /// \f$X\f$. The result can be represented as the union of a deba@948: /// matching with one value edges and a set of odd length cycles deba@948: /// with half value edges. deba@948: /// deba@948: /// The algorithm calculates an optimal fractional matching and a deba@948: /// barrier. The number of adjacents of any node set minus the size deba@948: /// of node set is a lower bound on the uncovered nodes in the deba@948: /// graph. For maximum matching a barrier is computed which deba@948: /// maximizes this difference. deba@948: /// deba@948: /// The algorithm can be executed with the run() function. After it deba@948: /// the matching (the primal solution) and the barrier (the dual deba@948: /// solution) can be obtained using the query functions. deba@948: /// deba@948: /// The primal solution is multiplied by deba@950: /// \ref MaxFractionalMatching::primalScale "2". deba@948: /// deba@948: /// \tparam GR The undirected graph type the algorithm runs on. deba@948: #ifdef DOXYGEN deba@948: template deba@948: #else deba@948: template > deba@948: #endif deba@948: class MaxFractionalMatching { deba@948: public: deba@948: deba@948: /// \brief The \ref MaxFractionalMatchingDefaultTraits "traits deba@948: /// class" of the algorithm. deba@948: typedef TR Traits; deba@948: /// The type of the graph the algorithm runs on. deba@948: typedef typename TR::Graph Graph; deba@948: /// The type of the matching map. deba@948: typedef typename TR::MatchingMap MatchingMap; deba@948: /// The type of the elevator. deba@948: typedef typename TR::Elevator Elevator; deba@948: deba@948: /// \brief Scaling factor for primal solution deba@948: /// deba@948: /// Scaling factor for primal solution. deba@948: static const int primalScale = 2; deba@948: deba@948: private: deba@948: deba@948: const Graph &_graph; deba@948: int _node_num; deba@948: bool _allow_loops; deba@948: int _empty_level; deba@948: deba@948: TEMPLATE_GRAPH_TYPEDEFS(Graph); deba@948: deba@948: bool _local_matching; deba@948: MatchingMap *_matching; deba@948: deba@948: bool _local_level; deba@948: Elevator *_level; deba@948: deba@948: typedef typename Graph::template NodeMap InDegMap; deba@948: InDegMap *_indeg; deba@948: deba@948: void createStructures() { deba@948: _node_num = countNodes(_graph); deba@948: deba@948: if (!_matching) { deba@948: _local_matching = true; deba@948: _matching = Traits::createMatchingMap(_graph); deba@948: } deba@948: if (!_level) { deba@948: _local_level = true; deba@948: _level = Traits::createElevator(_graph, _node_num); deba@948: } deba@948: if (!_indeg) { deba@948: _indeg = new InDegMap(_graph); deba@948: } deba@948: } deba@948: deba@948: void destroyStructures() { deba@948: if (_local_matching) { deba@948: delete _matching; deba@948: } deba@948: if (_local_level) { deba@948: delete _level; deba@948: } deba@948: if (_indeg) { deba@948: delete _indeg; deba@948: } deba@948: } deba@948: deba@948: void postprocessing() { deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_indeg)[n] != 0) continue; deba@948: _indeg->set(n, -1); deba@948: Node u = n; deba@948: while ((*_matching)[u] != INVALID) { deba@948: Node v = _graph.target((*_matching)[u]); deba@948: _indeg->set(v, -1); deba@948: Arc a = _graph.oppositeArc((*_matching)[u]); deba@948: u = _graph.target((*_matching)[v]); deba@948: _indeg->set(u, -1); deba@948: _matching->set(v, a); deba@948: } deba@948: } deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_indeg)[n] != 1) continue; deba@948: _indeg->set(n, -1); deba@948: deba@948: int num = 1; deba@948: Node u = _graph.target((*_matching)[n]); deba@948: while (u != n) { deba@948: _indeg->set(u, -1); deba@948: u = _graph.target((*_matching)[u]); deba@948: ++num; deba@948: } deba@948: if (num % 2 == 0 && num > 2) { deba@948: Arc prev = _graph.oppositeArc((*_matching)[n]); deba@948: Node v = _graph.target((*_matching)[n]); deba@948: u = _graph.target((*_matching)[v]); deba@948: _matching->set(v, prev); deba@948: while (u != n) { deba@948: prev = _graph.oppositeArc((*_matching)[u]); deba@948: v = _graph.target((*_matching)[u]); deba@948: u = _graph.target((*_matching)[v]); deba@948: _matching->set(v, prev); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: deba@948: public: deba@948: deba@948: typedef MaxFractionalMatching Create; deba@948: deba@948: ///\name Named Template Parameters deba@948: deba@948: ///@{ deba@948: deba@948: template deba@948: struct SetMatchingMapTraits : public Traits { deba@948: typedef T MatchingMap; deba@948: static MatchingMap *createMatchingMap(const Graph&) { deba@948: LEMON_ASSERT(false, "MatchingMap is not initialized"); deba@948: return 0; // ignore warnings deba@948: } deba@948: }; deba@948: deba@948: /// \brief \ref named-templ-param "Named parameter" for setting deba@948: /// MatchingMap type deba@948: /// deba@948: /// \ref named-templ-param "Named parameter" for setting MatchingMap deba@948: /// type. deba@948: template deba@948: struct SetMatchingMap deba@948: : public MaxFractionalMatching > { deba@948: typedef MaxFractionalMatching > Create; deba@948: }; deba@948: deba@948: template deba@948: struct SetElevatorTraits : public Traits { deba@948: typedef T Elevator; deba@948: static Elevator *createElevator(const Graph&, int) { deba@948: LEMON_ASSERT(false, "Elevator is not initialized"); deba@948: return 0; // ignore warnings deba@948: } deba@948: }; deba@948: deba@948: /// \brief \ref named-templ-param "Named parameter" for setting deba@948: /// Elevator type deba@948: /// deba@948: /// \ref named-templ-param "Named parameter" for setting Elevator deba@948: /// type. If this named parameter is used, then an external deba@948: /// elevator object must be passed to the algorithm using the deba@948: /// \ref elevator(Elevator&) "elevator()" function before calling deba@948: /// \ref run() or \ref init(). deba@948: /// \sa SetStandardElevator deba@948: template deba@948: struct SetElevator deba@948: : public MaxFractionalMatching > { deba@948: typedef MaxFractionalMatching > Create; deba@948: }; deba@948: deba@948: template deba@948: struct SetStandardElevatorTraits : public Traits { deba@948: typedef T Elevator; deba@948: static Elevator *createElevator(const Graph& graph, int max_level) { deba@948: return new Elevator(graph, max_level); deba@948: } deba@948: }; deba@948: deba@948: /// \brief \ref named-templ-param "Named parameter" for setting deba@948: /// Elevator type with automatic allocation deba@948: /// deba@948: /// \ref named-templ-param "Named parameter" for setting Elevator deba@948: /// type with automatic allocation. deba@948: /// The Elevator should have standard constructor interface to be deba@948: /// able to automatically created by the algorithm (i.e. the deba@948: /// graph and the maximum level should be passed to it). deba@948: /// However an external elevator object could also be passed to the deba@948: /// algorithm with the \ref elevator(Elevator&) "elevator()" function deba@948: /// before calling \ref run() or \ref init(). deba@948: /// \sa SetElevator deba@948: template deba@948: struct SetStandardElevator deba@948: : public MaxFractionalMatching > { deba@948: typedef MaxFractionalMatching > Create; deba@948: }; deba@948: deba@948: /// @} deba@948: deba@948: protected: deba@948: deba@948: MaxFractionalMatching() {} deba@948: deba@948: public: deba@948: deba@948: /// \brief Constructor deba@948: /// deba@948: /// Constructor. deba@948: /// deba@948: MaxFractionalMatching(const Graph &graph, bool allow_loops = true) deba@948: : _graph(graph), _allow_loops(allow_loops), deba@948: _local_matching(false), _matching(0), deba@948: _local_level(false), _level(0), _indeg(0) deba@948: {} deba@948: deba@948: ~MaxFractionalMatching() { deba@948: destroyStructures(); deba@948: } deba@948: deba@948: /// \brief Sets the matching map. deba@948: /// deba@948: /// Sets the matching map. deba@948: /// If you don't use this function before calling \ref run() or deba@948: /// \ref init(), an instance will be allocated automatically. deba@948: /// The destructor deallocates this automatically allocated map, deba@948: /// of course. deba@948: /// \return (*this) deba@948: MaxFractionalMatching& matchingMap(MatchingMap& map) { deba@948: if (_local_matching) { deba@948: delete _matching; deba@948: _local_matching = false; deba@948: } deba@948: _matching = ↦ deba@948: return *this; deba@948: } deba@948: deba@948: /// \brief Sets the elevator used by algorithm. deba@948: /// deba@948: /// Sets the elevator used by algorithm. deba@948: /// If you don't use this function before calling \ref run() or deba@948: /// \ref init(), an instance will be allocated automatically. deba@948: /// The destructor deallocates this automatically allocated elevator, deba@948: /// of course. deba@948: /// \return (*this) deba@948: MaxFractionalMatching& elevator(Elevator& elevator) { deba@948: if (_local_level) { deba@948: delete _level; deba@948: _local_level = false; deba@948: } deba@948: _level = &elevator; deba@948: return *this; deba@948: } deba@948: deba@948: /// \brief Returns a const reference to the elevator. deba@948: /// deba@948: /// Returns a const reference to the elevator. deba@948: /// deba@948: /// \pre Either \ref run() or \ref init() must be called before deba@948: /// using this function. deba@948: const Elevator& elevator() const { deba@948: return *_level; deba@948: } deba@948: deba@948: /// \name Execution control deba@948: /// The simplest way to execute the algorithm is to use one of the deba@948: /// member functions called \c run(). \n deba@948: /// If you need more control on the execution, first deba@948: /// you must call \ref init() and then one variant of the start() deba@948: /// member. deba@948: deba@948: /// @{ deba@948: deba@948: /// \brief Initializes the internal data structures. deba@948: /// deba@948: /// Initializes the internal data structures and sets the initial deba@948: /// matching. deba@948: void init() { deba@948: createStructures(); deba@948: deba@948: _level->initStart(); deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: _indeg->set(n, 0); deba@948: _matching->set(n, INVALID); deba@948: _level->initAddItem(n); deba@948: } deba@948: _level->initFinish(); deba@948: deba@948: _empty_level = _node_num; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: for (OutArcIt a(_graph, n); a != INVALID; ++a) { deba@948: if (_graph.target(a) == n && !_allow_loops) continue; deba@948: _matching->set(n, a); deba@948: Node v = _graph.target((*_matching)[n]); deba@948: _indeg->set(v, (*_indeg)[v] + 1); deba@948: break; deba@948: } deba@948: } deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_indeg)[n] == 0) { deba@948: _level->activate(n); deba@948: } deba@948: } deba@948: } deba@948: deba@948: /// \brief Starts the algorithm and computes a fractional matching deba@948: /// deba@948: /// The algorithm computes a maximum fractional matching. deba@948: /// deba@948: /// \param postprocess The algorithm computes first a matching deba@948: /// which is a union of a matching with one value edges, cycles deba@948: /// with half value edges and even length paths with half value deba@948: /// edges. If the parameter is true, then after the push-relabel deba@948: /// algorithm it postprocesses the matching to contain only deba@948: /// matching edges and half value odd cycles. deba@948: void start(bool postprocess = true) { deba@948: Node n; deba@948: while ((n = _level->highestActive()) != INVALID) { deba@948: int level = _level->highestActiveLevel(); deba@948: int new_level = _level->maxLevel(); deba@948: for (InArcIt a(_graph, n); a != INVALID; ++a) { deba@948: Node u = _graph.source(a); deba@948: if (n == u && !_allow_loops) continue; deba@948: Node v = _graph.target((*_matching)[u]); deba@948: if ((*_level)[v] < level) { deba@948: _indeg->set(v, (*_indeg)[v] - 1); deba@948: if ((*_indeg)[v] == 0) { deba@948: _level->activate(v); deba@948: } deba@948: _matching->set(u, a); deba@948: _indeg->set(n, (*_indeg)[n] + 1); deba@948: _level->deactivate(n); deba@948: goto no_more_push; deba@948: } else if (new_level > (*_level)[v]) { deba@948: new_level = (*_level)[v]; deba@948: } deba@948: } deba@948: deba@948: if (new_level + 1 < _level->maxLevel()) { deba@948: _level->liftHighestActive(new_level + 1); deba@948: } else { deba@948: _level->liftHighestActiveToTop(); deba@948: } deba@948: if (_level->emptyLevel(level)) { deba@948: _level->liftToTop(level); deba@948: } deba@948: no_more_push: deba@948: ; deba@948: } deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] == INVALID) continue; deba@948: Node u = _graph.target((*_matching)[n]); deba@948: if ((*_indeg)[u] > 1) { deba@948: _indeg->set(u, (*_indeg)[u] - 1); deba@948: _matching->set(n, INVALID); deba@948: } deba@948: } deba@948: if (postprocess) { deba@948: postprocessing(); deba@948: } deba@948: } deba@948: deba@948: /// \brief Starts the algorithm and computes a perfect fractional deba@948: /// matching deba@948: /// deba@948: /// The algorithm computes a perfect fractional matching. If it deba@948: /// does not exists, then the algorithm returns false and the deba@948: /// matching is undefined and the barrier. deba@948: /// deba@948: /// \param postprocess The algorithm computes first a matching deba@948: /// which is a union of a matching with one value edges, cycles deba@948: /// with half value edges and even length paths with half value deba@948: /// edges. If the parameter is true, then after the push-relabel deba@948: /// algorithm it postprocesses the matching to contain only deba@948: /// matching edges and half value odd cycles. deba@948: bool startPerfect(bool postprocess = true) { deba@948: Node n; deba@948: while ((n = _level->highestActive()) != INVALID) { deba@948: int level = _level->highestActiveLevel(); deba@948: int new_level = _level->maxLevel(); deba@948: for (InArcIt a(_graph, n); a != INVALID; ++a) { deba@948: Node u = _graph.source(a); deba@948: if (n == u && !_allow_loops) continue; deba@948: Node v = _graph.target((*_matching)[u]); deba@948: if ((*_level)[v] < level) { deba@948: _indeg->set(v, (*_indeg)[v] - 1); deba@948: if ((*_indeg)[v] == 0) { deba@948: _level->activate(v); deba@948: } deba@948: _matching->set(u, a); deba@948: _indeg->set(n, (*_indeg)[n] + 1); deba@948: _level->deactivate(n); deba@948: goto no_more_push; deba@948: } else if (new_level > (*_level)[v]) { deba@948: new_level = (*_level)[v]; deba@948: } deba@948: } deba@948: deba@948: if (new_level + 1 < _level->maxLevel()) { deba@948: _level->liftHighestActive(new_level + 1); deba@948: } else { deba@948: _level->liftHighestActiveToTop(); deba@948: _empty_level = _level->maxLevel() - 1; deba@948: return false; deba@948: } deba@948: if (_level->emptyLevel(level)) { deba@948: _level->liftToTop(level); deba@948: _empty_level = level; deba@948: return false; deba@948: } deba@948: no_more_push: deba@948: ; deba@948: } deba@948: if (postprocess) { deba@948: postprocessing(); deba@948: } deba@948: return true; deba@948: } deba@948: deba@948: /// \brief Runs the algorithm deba@948: /// deba@948: /// Just a shortcut for the next code: deba@948: ///\code deba@948: /// init(); deba@948: /// start(); deba@948: ///\endcode deba@948: void run(bool postprocess = true) { deba@948: init(); deba@948: start(postprocess); deba@948: } deba@948: deba@948: /// \brief Runs the algorithm to find a perfect fractional matching deba@948: /// deba@948: /// Just a shortcut for the next code: deba@948: ///\code deba@948: /// init(); deba@948: /// startPerfect(); deba@948: ///\endcode deba@948: bool runPerfect(bool postprocess = true) { deba@948: init(); deba@948: return startPerfect(postprocess); deba@948: } deba@948: deba@948: ///@} deba@948: deba@948: /// \name Query Functions deba@948: /// The result of the %Matching algorithm can be obtained using these deba@948: /// functions.\n deba@948: /// Before the use of these functions, deba@948: /// either run() or start() must be called. deba@948: ///@{ deba@948: deba@948: deba@948: /// \brief Return the number of covered nodes in the matching. deba@948: /// deba@948: /// This function returns the number of covered nodes in the matching. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: int matchingSize() const { deba@948: int num = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] != INVALID) { deba@948: ++num; deba@948: } deba@948: } deba@948: return num; deba@948: } deba@948: deba@948: /// \brief Returns a const reference to the matching map. deba@948: /// deba@948: /// Returns a const reference to the node map storing the found deba@948: /// fractional matching. This method can be called after deba@948: /// running the algorithm. deba@948: /// deba@948: /// \pre Either \ref run() or \ref init() must be called before deba@948: /// using this function. deba@948: const MatchingMap& matchingMap() const { deba@948: return *_matching; deba@948: } deba@948: deba@948: /// \brief Return \c true if the given edge is in the matching. deba@948: /// deba@948: /// This function returns \c true if the given edge is in the deba@948: /// found matching. The result is scaled by \ref primalScale deba@948: /// "primal scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: int matching(const Edge& edge) const { deba@948: return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + deba@948: (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); deba@948: } deba@948: deba@948: /// \brief Return the fractional matching arc (or edge) incident deba@948: /// to the given node. deba@948: /// deba@948: /// This function returns one of the fractional matching arc (or deba@948: /// edge) incident to the given node in the found matching or \c deba@948: /// INVALID if the node is not covered by the matching or if the deba@948: /// node is on an odd length cycle then it is the successor edge deba@948: /// on the cycle. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Arc matching(const Node& node) const { deba@948: return (*_matching)[node]; deba@948: } deba@948: deba@948: /// \brief Returns true if the node is in the barrier deba@948: /// deba@948: /// The barrier is a subset of the nodes. If the nodes in the deba@948: /// barrier have less adjacent nodes than the size of the barrier, deba@948: /// then at least as much nodes cannot be covered as the deba@948: /// difference of the two subsets. deba@948: bool barrier(const Node& node) const { deba@948: return (*_level)[node] >= _empty_level; deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: }; deba@948: deba@948: /// \ingroup matching deba@948: /// deba@948: /// \brief Weighted fractional matching in general graphs deba@948: /// deba@948: /// This class provides an efficient implementation of fractional deba@950: /// matching algorithm. The implementation uses priority queues and deba@950: /// provides \f$O(nm\log n)\f$ time complexity. deba@948: /// deba@948: /// The maximum weighted fractional matching is a relaxation of the deba@948: /// maximum weighted matching problem where the odd set constraints deba@948: /// are omitted. deba@948: /// It can be formulated with the following linear program. deba@948: /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] deba@948: /// \f[x_e \ge 0\quad \forall e\in E\f] deba@948: /// \f[\max \sum_{e\in E}x_ew_e\f] deba@948: /// where \f$\delta(X)\f$ is the set of edges incident to a node in deba@948: /// \f$X\f$. The result must be the union of a matching with one deba@948: /// value edges and a set of odd length cycles with half value edges. deba@948: /// deba@948: /// The algorithm calculates an optimal fractional matching and a deba@948: /// proof of the optimality. The solution of the dual problem can be deba@948: /// used to check the result of the algorithm. The dual linear deba@948: /// problem is the following. deba@948: /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] deba@948: /// \f[y_u \ge 0 \quad \forall u \in V\f] deba@950: /// \f[\min \sum_{u \in V}y_u \f] deba@948: /// deba@948: /// The algorithm can be executed with the run() function. deba@948: /// After it the matching (the primal solution) and the dual solution deba@948: /// can be obtained using the query functions. deba@948: /// deba@948: /// If the value type is integer, then the primal and the dual deba@948: /// solutions are multiplied by deba@950: /// \ref MaxWeightedFractionalMatching::primalScale "2" and deba@950: /// \ref MaxWeightedFractionalMatching::dualScale "4" respectively. deba@948: /// deba@948: /// \tparam GR The undirected graph type the algorithm runs on. deba@948: /// \tparam WM The type edge weight map. The default type is deba@948: /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". deba@948: #ifdef DOXYGEN deba@948: template deba@948: #else deba@948: template > deba@948: #endif deba@948: class MaxWeightedFractionalMatching { deba@948: public: deba@948: deba@948: /// The graph type of the algorithm deba@948: typedef GR Graph; deba@948: /// The type of the edge weight map deba@948: typedef WM WeightMap; deba@948: /// The value type of the edge weights deba@948: typedef typename WeightMap::Value Value; deba@948: deba@948: /// The type of the matching map deba@948: typedef typename Graph::template NodeMap deba@948: MatchingMap; deba@948: deba@948: /// \brief Scaling factor for primal solution deba@948: /// deba@948: /// Scaling factor for primal solution. It is equal to 2 or 1 deba@948: /// according to the value type. deba@948: static const int primalScale = deba@948: std::numeric_limits::is_integer ? 2 : 1; deba@948: deba@948: /// \brief Scaling factor for dual solution deba@948: /// deba@948: /// Scaling factor for dual solution. It is equal to 4 or 1 deba@948: /// according to the value type. deba@948: static const int dualScale = deba@948: std::numeric_limits::is_integer ? 4 : 1; deba@948: deba@948: private: deba@948: deba@948: TEMPLATE_GRAPH_TYPEDEFS(Graph); deba@948: deba@948: typedef typename Graph::template NodeMap NodePotential; deba@948: deba@948: const Graph& _graph; deba@948: const WeightMap& _weight; deba@948: deba@948: MatchingMap* _matching; deba@948: NodePotential* _node_potential; deba@948: deba@948: int _node_num; deba@948: bool _allow_loops; deba@948: deba@948: enum Status { deba@948: EVEN = -1, MATCHED = 0, ODD = 1 deba@948: }; deba@948: deba@948: typedef typename Graph::template NodeMap StatusMap; deba@948: StatusMap* _status; deba@948: deba@948: typedef typename Graph::template NodeMap PredMap; deba@948: PredMap* _pred; deba@948: deba@948: typedef ExtendFindEnum TreeSet; deba@948: deba@948: IntNodeMap *_tree_set_index; deba@948: TreeSet *_tree_set; deba@948: deba@948: IntNodeMap *_delta1_index; deba@948: BinHeap *_delta1; deba@948: deba@948: IntNodeMap *_delta2_index; deba@948: BinHeap *_delta2; deba@948: deba@948: IntEdgeMap *_delta3_index; deba@948: BinHeap *_delta3; deba@948: deba@948: Value _delta_sum; deba@948: deba@948: void createStructures() { deba@948: _node_num = countNodes(_graph); deba@948: deba@948: if (!_matching) { deba@948: _matching = new MatchingMap(_graph); deba@948: } deba@948: if (!_node_potential) { deba@948: _node_potential = new NodePotential(_graph); deba@948: } deba@948: if (!_status) { deba@948: _status = new StatusMap(_graph); deba@948: } deba@948: if (!_pred) { deba@948: _pred = new PredMap(_graph); deba@948: } deba@948: if (!_tree_set) { deba@948: _tree_set_index = new IntNodeMap(_graph); deba@948: _tree_set = new TreeSet(*_tree_set_index); deba@948: } deba@948: if (!_delta1) { deba@948: _delta1_index = new IntNodeMap(_graph); deba@948: _delta1 = new BinHeap(*_delta1_index); deba@948: } deba@948: if (!_delta2) { deba@948: _delta2_index = new IntNodeMap(_graph); deba@948: _delta2 = new BinHeap(*_delta2_index); deba@948: } deba@948: if (!_delta3) { deba@948: _delta3_index = new IntEdgeMap(_graph); deba@948: _delta3 = new BinHeap(*_delta3_index); deba@948: } deba@948: } deba@948: deba@948: void destroyStructures() { deba@948: if (_matching) { deba@948: delete _matching; deba@948: } deba@948: if (_node_potential) { deba@948: delete _node_potential; deba@948: } deba@948: if (_status) { deba@948: delete _status; deba@948: } deba@948: if (_pred) { deba@948: delete _pred; deba@948: } deba@948: if (_tree_set) { deba@948: delete _tree_set_index; deba@948: delete _tree_set; deba@948: } deba@948: if (_delta1) { deba@948: delete _delta1_index; deba@948: delete _delta1; deba@948: } deba@948: if (_delta2) { deba@948: delete _delta2_index; deba@948: delete _delta2; deba@948: } deba@948: if (_delta3) { deba@948: delete _delta3_index; deba@948: delete _delta3; deba@948: } deba@948: } deba@948: deba@948: void matchedToEven(Node node, int tree) { deba@948: _tree_set->insert(node, tree); deba@948: _node_potential->set(node, (*_node_potential)[node] + _delta_sum); deba@948: _delta1->push(node, (*_node_potential)[node]); deba@948: deba@948: if (_delta2->state(node) == _delta2->IN_HEAP) { deba@948: _delta2->erase(node); deba@948: } deba@948: deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: if (node == v) { deba@948: if (_allow_loops && _graph.direction(a)) { deba@948: _delta3->push(a, rw / 2); deba@948: } deba@948: } else if ((*_status)[v] == EVEN) { deba@948: _delta3->push(a, rw / 2); deba@948: } else if ((*_status)[v] == MATCHED) { deba@948: if (_delta2->state(v) != _delta2->IN_HEAP) { deba@948: _pred->set(v, a); deba@948: _delta2->push(v, rw); deba@948: } else if ((*_delta2)[v] > rw) { deba@948: _pred->set(v, a); deba@948: _delta2->decrease(v, rw); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: deba@948: void matchedToOdd(Node node, int tree) { deba@948: _tree_set->insert(node, tree); deba@948: _node_potential->set(node, (*_node_potential)[node] - _delta_sum); deba@948: deba@948: if (_delta2->state(node) == _delta2->IN_HEAP) { deba@948: _delta2->erase(node); deba@948: } deba@948: } deba@948: deba@948: void evenToMatched(Node node, int tree) { deba@948: _delta1->erase(node); deba@948: _node_potential->set(node, (*_node_potential)[node] - _delta_sum); deba@948: Arc min = INVALID; deba@948: Value minrw = std::numeric_limits::max(); deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: deba@948: if (node == v) { deba@948: if (_allow_loops && _graph.direction(a)) { deba@948: _delta3->erase(a); deba@948: } deba@948: } else if ((*_status)[v] == EVEN) { deba@948: _delta3->erase(a); deba@948: if (minrw > rw) { deba@948: min = _graph.oppositeArc(a); deba@948: minrw = rw; deba@948: } deba@948: } else if ((*_status)[v] == MATCHED) { deba@948: if ((*_pred)[v] == a) { deba@948: Arc mina = INVALID; deba@948: Value minrwa = std::numeric_limits::max(); deba@948: for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { deba@948: Node va = _graph.target(aa); deba@948: if ((*_status)[va] != EVEN || deba@948: _tree_set->find(va) == tree) continue; deba@948: Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - deba@948: dualScale * _weight[aa]; deba@948: if (minrwa > rwa) { deba@948: minrwa = rwa; deba@948: mina = aa; deba@948: } deba@948: } deba@948: if (mina != INVALID) { deba@948: _pred->set(v, mina); deba@948: _delta2->increase(v, minrwa); deba@948: } else { deba@948: _pred->set(v, INVALID); deba@948: _delta2->erase(v); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: if (min != INVALID) { deba@948: _pred->set(node, min); deba@948: _delta2->push(node, minrw); deba@948: } else { deba@948: _pred->set(node, INVALID); deba@948: } deba@948: } deba@948: deba@948: void oddToMatched(Node node) { deba@948: _node_potential->set(node, (*_node_potential)[node] + _delta_sum); deba@948: Arc min = INVALID; deba@948: Value minrw = std::numeric_limits::max(); deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: if ((*_status)[v] != EVEN) continue; deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: deba@948: if (minrw > rw) { deba@948: min = _graph.oppositeArc(a); deba@948: minrw = rw; deba@948: } deba@948: } deba@948: if (min != INVALID) { deba@948: _pred->set(node, min); deba@948: _delta2->push(node, minrw); deba@948: } else { deba@948: _pred->set(node, INVALID); deba@948: } deba@948: } deba@948: deba@948: void alternatePath(Node even, int tree) { deba@948: Node odd; deba@948: deba@948: _status->set(even, MATCHED); deba@948: evenToMatched(even, tree); deba@948: deba@948: Arc prev = (*_matching)[even]; deba@948: while (prev != INVALID) { deba@948: odd = _graph.target(prev); deba@948: even = _graph.target((*_pred)[odd]); deba@948: _matching->set(odd, (*_pred)[odd]); deba@948: _status->set(odd, MATCHED); deba@948: oddToMatched(odd); deba@948: deba@948: prev = (*_matching)[even]; deba@948: _status->set(even, MATCHED); deba@948: _matching->set(even, _graph.oppositeArc((*_matching)[odd])); deba@948: evenToMatched(even, tree); deba@948: } deba@948: } deba@948: deba@948: void destroyTree(int tree) { deba@948: for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { deba@948: if ((*_status)[n] == EVEN) { deba@948: _status->set(n, MATCHED); deba@948: evenToMatched(n, tree); deba@948: } else if ((*_status)[n] == ODD) { deba@948: _status->set(n, MATCHED); deba@948: oddToMatched(n); deba@948: } deba@948: } deba@948: _tree_set->eraseClass(tree); deba@948: } deba@948: deba@948: deba@948: void unmatchNode(const Node& node) { deba@948: int tree = _tree_set->find(node); deba@948: deba@948: alternatePath(node, tree); deba@948: destroyTree(tree); deba@948: deba@948: _matching->set(node, INVALID); deba@948: } deba@948: deba@948: deba@948: void augmentOnEdge(const Edge& edge) { deba@948: Node left = _graph.u(edge); deba@948: int left_tree = _tree_set->find(left); deba@948: deba@948: alternatePath(left, left_tree); deba@948: destroyTree(left_tree); deba@948: _matching->set(left, _graph.direct(edge, true)); deba@948: deba@948: Node right = _graph.v(edge); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.direct(edge, false)); deba@948: } deba@948: deba@948: void augmentOnArc(const Arc& arc) { deba@948: Node left = _graph.source(arc); deba@948: _status->set(left, MATCHED); deba@948: _matching->set(left, arc); deba@948: _pred->set(left, arc); deba@948: deba@948: Node right = _graph.target(arc); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.oppositeArc(arc)); deba@948: } deba@948: deba@948: void extendOnArc(const Arc& arc) { deba@948: Node base = _graph.target(arc); deba@948: int tree = _tree_set->find(base); deba@948: deba@948: Node odd = _graph.source(arc); deba@948: _tree_set->insert(odd, tree); deba@948: _status->set(odd, ODD); deba@948: matchedToOdd(odd, tree); deba@948: _pred->set(odd, arc); deba@948: deba@948: Node even = _graph.target((*_matching)[odd]); deba@948: _tree_set->insert(even, tree); deba@948: _status->set(even, EVEN); deba@948: matchedToEven(even, tree); deba@948: } deba@948: deba@948: void cycleOnEdge(const Edge& edge, int tree) { deba@948: Node nca = INVALID; deba@948: std::vector left_path, right_path; deba@948: deba@948: { deba@948: std::set left_set, right_set; deba@948: Node left = _graph.u(edge); deba@948: left_path.push_back(left); deba@948: left_set.insert(left); deba@948: deba@948: Node right = _graph.v(edge); deba@948: right_path.push_back(right); deba@948: right_set.insert(right); deba@948: deba@948: while (true) { deba@948: deba@948: if (left_set.find(right) != left_set.end()) { deba@948: nca = right; deba@948: break; deba@948: } deba@948: deba@948: if ((*_matching)[left] == INVALID) break; deba@948: deba@948: left = _graph.target((*_matching)[left]); deba@948: left_path.push_back(left); deba@948: left = _graph.target((*_pred)[left]); deba@948: left_path.push_back(left); deba@948: deba@948: left_set.insert(left); deba@948: deba@948: if (right_set.find(left) != right_set.end()) { deba@948: nca = left; deba@948: break; deba@948: } deba@948: deba@948: if ((*_matching)[right] == INVALID) break; deba@948: deba@948: right = _graph.target((*_matching)[right]); deba@948: right_path.push_back(right); deba@948: right = _graph.target((*_pred)[right]); deba@948: right_path.push_back(right); deba@948: deba@948: right_set.insert(right); deba@948: deba@948: } deba@948: deba@948: if (nca == INVALID) { deba@948: if ((*_matching)[left] == INVALID) { deba@948: nca = right; deba@948: while (left_set.find(nca) == left_set.end()) { deba@948: nca = _graph.target((*_matching)[nca]); deba@948: right_path.push_back(nca); deba@948: nca = _graph.target((*_pred)[nca]); deba@948: right_path.push_back(nca); deba@948: } deba@948: } else { deba@948: nca = left; deba@948: while (right_set.find(nca) == right_set.end()) { deba@948: nca = _graph.target((*_matching)[nca]); deba@948: left_path.push_back(nca); deba@948: nca = _graph.target((*_pred)[nca]); deba@948: left_path.push_back(nca); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: deba@948: alternatePath(nca, tree); deba@948: Arc prev; deba@948: deba@948: prev = _graph.direct(edge, true); deba@948: for (int i = 0; left_path[i] != nca; i += 2) { deba@948: _matching->set(left_path[i], prev); deba@948: _status->set(left_path[i], MATCHED); deba@948: evenToMatched(left_path[i], tree); deba@948: deba@948: prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); deba@948: _status->set(left_path[i + 1], MATCHED); deba@948: oddToMatched(left_path[i + 1]); deba@948: } deba@948: _matching->set(nca, prev); deba@948: deba@948: for (int i = 0; right_path[i] != nca; i += 2) { deba@948: _status->set(right_path[i], MATCHED); deba@948: evenToMatched(right_path[i], tree); deba@948: deba@948: _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); deba@948: _status->set(right_path[i + 1], MATCHED); deba@948: oddToMatched(right_path[i + 1]); deba@948: } deba@948: deba@948: destroyTree(tree); deba@948: } deba@948: deba@948: void extractCycle(const Arc &arc) { deba@948: Node left = _graph.source(arc); deba@948: Node odd = _graph.target((*_matching)[left]); deba@948: Arc prev; deba@948: while (odd != left) { deba@948: Node even = _graph.target((*_matching)[odd]); deba@948: prev = (*_matching)[odd]; deba@948: odd = _graph.target((*_matching)[even]); deba@948: _matching->set(even, _graph.oppositeArc(prev)); deba@948: } deba@948: _matching->set(left, arc); deba@948: deba@948: Node right = _graph.target(arc); deba@948: int right_tree = _tree_set->find(right); deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.oppositeArc(arc)); deba@948: } deba@948: deba@948: public: deba@948: deba@948: /// \brief Constructor deba@948: /// deba@948: /// Constructor. deba@948: MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight, deba@948: bool allow_loops = true) deba@948: : _graph(graph), _weight(weight), _matching(0), deba@948: _node_potential(0), _node_num(0), _allow_loops(allow_loops), deba@948: _status(0), _pred(0), deba@948: _tree_set_index(0), _tree_set(0), deba@948: deba@948: _delta1_index(0), _delta1(0), deba@948: _delta2_index(0), _delta2(0), deba@948: _delta3_index(0), _delta3(0), deba@948: deba@948: _delta_sum() {} deba@948: deba@948: ~MaxWeightedFractionalMatching() { deba@948: destroyStructures(); deba@948: } deba@948: deba@948: /// \name Execution Control deba@948: /// The simplest way to execute the algorithm is to use the deba@948: /// \ref run() member function. deba@948: deba@948: ///@{ deba@948: deba@948: /// \brief Initialize the algorithm deba@948: /// deba@948: /// This function initializes the algorithm. deba@948: void init() { deba@948: createStructures(); deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: (*_delta1_index)[n] = _delta1->PRE_HEAP; deba@948: (*_delta2_index)[n] = _delta2->PRE_HEAP; deba@948: } deba@948: for (EdgeIt e(_graph); e != INVALID; ++e) { deba@948: (*_delta3_index)[e] = _delta3->PRE_HEAP; deba@948: } deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: Value max = 0; deba@948: for (OutArcIt e(_graph, n); e != INVALID; ++e) { deba@948: if (_graph.target(e) == n && !_allow_loops) continue; deba@948: if ((dualScale * _weight[e]) / 2 > max) { deba@948: max = (dualScale * _weight[e]) / 2; deba@948: } deba@948: } deba@948: _node_potential->set(n, max); deba@948: _delta1->push(n, max); deba@948: deba@948: _tree_set->insert(n); deba@948: deba@948: _matching->set(n, INVALID); deba@948: _status->set(n, EVEN); deba@948: } deba@948: deba@948: for (EdgeIt e(_graph); e != INVALID; ++e) { deba@948: Node left = _graph.u(e); deba@948: Node right = _graph.v(e); deba@948: if (left == right && !_allow_loops) continue; deba@948: _delta3->push(e, ((*_node_potential)[left] + deba@948: (*_node_potential)[right] - deba@948: dualScale * _weight[e]) / 2); deba@948: } deba@948: } deba@948: deba@948: /// \brief Start the algorithm deba@948: /// deba@948: /// This function starts the algorithm. deba@948: /// deba@948: /// \pre \ref init() must be called before using this function. deba@948: void start() { deba@948: enum OpType { deba@948: D1, D2, D3 deba@948: }; deba@948: deba@948: int unmatched = _node_num; deba@948: while (unmatched > 0) { deba@948: Value d1 = !_delta1->empty() ? deba@948: _delta1->prio() : std::numeric_limits::max(); deba@948: deba@948: Value d2 = !_delta2->empty() ? deba@948: _delta2->prio() : std::numeric_limits::max(); deba@948: deba@948: Value d3 = !_delta3->empty() ? deba@948: _delta3->prio() : std::numeric_limits::max(); deba@948: deba@948: _delta_sum = d3; OpType ot = D3; deba@948: if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } deba@948: if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } deba@948: deba@948: switch (ot) { deba@948: case D1: deba@948: { deba@948: Node n = _delta1->top(); deba@948: unmatchNode(n); deba@948: --unmatched; deba@948: } deba@948: break; deba@948: case D2: deba@948: { deba@948: Node n = _delta2->top(); deba@948: Arc a = (*_pred)[n]; deba@948: if ((*_matching)[n] == INVALID) { deba@948: augmentOnArc(a); deba@948: --unmatched; deba@948: } else { deba@948: Node v = _graph.target((*_matching)[n]); deba@948: if ((*_matching)[n] != deba@948: _graph.oppositeArc((*_matching)[v])) { deba@948: extractCycle(a); deba@948: --unmatched; deba@948: } else { deba@948: extendOnArc(a); deba@948: } deba@948: } deba@948: } break; deba@948: case D3: deba@948: { deba@948: Edge e = _delta3->top(); deba@948: deba@948: Node left = _graph.u(e); deba@948: Node right = _graph.v(e); deba@948: deba@948: int left_tree = _tree_set->find(left); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: if (left_tree == right_tree) { deba@948: cycleOnEdge(e, left_tree); deba@948: --unmatched; deba@948: } else { deba@948: augmentOnEdge(e); deba@948: unmatched -= 2; deba@948: } deba@948: } break; deba@948: } deba@948: } deba@948: } deba@948: deba@948: /// \brief Run the algorithm. deba@948: /// deba@950: /// This method runs the \c %MaxWeightedFractionalMatching algorithm. deba@948: /// deba@948: /// \note mwfm.run() is just a shortcut of the following code. deba@948: /// \code deba@948: /// mwfm.init(); deba@948: /// mwfm.start(); deba@948: /// \endcode deba@948: void run() { deba@948: init(); deba@948: start(); deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: /// \name Primal Solution deba@948: /// Functions to get the primal solution, i.e. the maximum weighted deba@948: /// matching.\n deba@948: /// Either \ref run() or \ref start() function should be called before deba@948: /// using them. deba@948: deba@948: /// @{ deba@948: deba@948: /// \brief Return the weight of the matching. deba@948: /// deba@948: /// This function returns the weight of the found matching. This deba@948: /// value is scaled by \ref primalScale "primal scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value matchingWeight() const { deba@948: Value sum = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] != INVALID) { deba@948: sum += _weight[(*_matching)[n]]; deba@948: } deba@948: } deba@948: return sum * primalScale / 2; deba@948: } deba@948: deba@948: /// \brief Return the number of covered nodes in the matching. deba@948: /// deba@948: /// This function returns the number of covered nodes in the matching. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: int matchingSize() const { deba@948: int num = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] != INVALID) { deba@948: ++num; deba@948: } deba@948: } deba@948: return num; deba@948: } deba@948: deba@948: /// \brief Return \c true if the given edge is in the matching. deba@948: /// deba@948: /// This function returns \c true if the given edge is in the deba@948: /// found matching. The result is scaled by \ref primalScale deba@948: /// "primal scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value matching(const Edge& edge) const { deba@948: return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0) deba@948: * primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0) deba@948: * primalScale / 2; deba@948: } deba@948: deba@948: /// \brief Return the fractional matching arc (or edge) incident deba@948: /// to the given node. deba@948: /// deba@948: /// This function returns one of the fractional matching arc (or deba@948: /// edge) incident to the given node in the found matching or \c deba@948: /// INVALID if the node is not covered by the matching or if the deba@948: /// node is on an odd length cycle then it is the successor edge deba@948: /// on the cycle. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Arc matching(const Node& node) const { deba@948: return (*_matching)[node]; deba@948: } deba@948: deba@948: /// \brief Return a const reference to the matching map. deba@948: /// deba@948: /// This function returns a const reference to a node map that stores deba@948: /// the matching arc (or edge) incident to each node. deba@948: const MatchingMap& matchingMap() const { deba@948: return *_matching; deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: /// \name Dual Solution deba@948: /// Functions to get the dual solution.\n deba@948: /// Either \ref run() or \ref start() function should be called before deba@948: /// using them. deba@948: deba@948: /// @{ deba@948: deba@948: /// \brief Return the value of the dual solution. deba@948: /// deba@948: /// This function returns the value of the dual solution. deba@948: /// It should be equal to the primal value scaled by \ref dualScale deba@948: /// "dual scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value dualValue() const { deba@948: Value sum = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: sum += nodeValue(n); deba@948: } deba@948: return sum; deba@948: } deba@948: deba@948: /// \brief Return the dual value (potential) of the given node. deba@948: /// deba@948: /// This function returns the dual value (potential) of the given node. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value nodeValue(const Node& n) const { deba@948: return (*_node_potential)[n]; deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: }; deba@948: deba@948: /// \ingroup matching deba@948: /// deba@948: /// \brief Weighted fractional perfect matching in general graphs deba@948: /// deba@948: /// This class provides an efficient implementation of fractional deba@950: /// matching algorithm. The implementation uses priority queues and deba@950: /// provides \f$O(nm\log n)\f$ time complexity. deba@948: /// deba@948: /// The maximum weighted fractional perfect matching is a relaxation deba@948: /// of the maximum weighted perfect matching problem where the odd deba@948: /// set constraints are omitted. deba@948: /// It can be formulated with the following linear program. deba@948: /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] deba@948: /// \f[x_e \ge 0\quad \forall e\in E\f] deba@948: /// \f[\max \sum_{e\in E}x_ew_e\f] deba@948: /// where \f$\delta(X)\f$ is the set of edges incident to a node in deba@948: /// \f$X\f$. The result must be the union of a matching with one deba@948: /// value edges and a set of odd length cycles with half value edges. deba@948: /// deba@948: /// The algorithm calculates an optimal fractional matching and a deba@948: /// proof of the optimality. The solution of the dual problem can be deba@948: /// used to check the result of the algorithm. The dual linear deba@948: /// problem is the following. deba@948: /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] deba@950: /// \f[\min \sum_{u \in V}y_u \f] deba@948: /// deba@948: /// The algorithm can be executed with the run() function. deba@948: /// After it the matching (the primal solution) and the dual solution deba@948: /// can be obtained using the query functions. deba@948: deba@948: /// If the value type is integer, then the primal and the dual deba@948: /// solutions are multiplied by deba@950: /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2" and deba@950: /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4" respectively. deba@948: /// deba@948: /// \tparam GR The undirected graph type the algorithm runs on. deba@948: /// \tparam WM The type edge weight map. The default type is deba@948: /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". deba@948: #ifdef DOXYGEN deba@948: template deba@948: #else deba@948: template > deba@948: #endif deba@948: class MaxWeightedPerfectFractionalMatching { deba@948: public: deba@948: deba@948: /// The graph type of the algorithm deba@948: typedef GR Graph; deba@948: /// The type of the edge weight map deba@948: typedef WM WeightMap; deba@948: /// The value type of the edge weights deba@948: typedef typename WeightMap::Value Value; deba@948: deba@948: /// The type of the matching map deba@948: typedef typename Graph::template NodeMap deba@948: MatchingMap; deba@948: deba@948: /// \brief Scaling factor for primal solution deba@948: /// deba@948: /// Scaling factor for primal solution. It is equal to 2 or 1 deba@948: /// according to the value type. deba@948: static const int primalScale = deba@948: std::numeric_limits::is_integer ? 2 : 1; deba@948: deba@948: /// \brief Scaling factor for dual solution deba@948: /// deba@948: /// Scaling factor for dual solution. It is equal to 4 or 1 deba@948: /// according to the value type. deba@948: static const int dualScale = deba@948: std::numeric_limits::is_integer ? 4 : 1; deba@948: deba@948: private: deba@948: deba@948: TEMPLATE_GRAPH_TYPEDEFS(Graph); deba@948: deba@948: typedef typename Graph::template NodeMap NodePotential; deba@948: deba@948: const Graph& _graph; deba@948: const WeightMap& _weight; deba@948: deba@948: MatchingMap* _matching; deba@948: NodePotential* _node_potential; deba@948: deba@948: int _node_num; deba@948: bool _allow_loops; deba@948: deba@948: enum Status { deba@948: EVEN = -1, MATCHED = 0, ODD = 1 deba@948: }; deba@948: deba@948: typedef typename Graph::template NodeMap StatusMap; deba@948: StatusMap* _status; deba@948: deba@948: typedef typename Graph::template NodeMap PredMap; deba@948: PredMap* _pred; deba@948: deba@948: typedef ExtendFindEnum TreeSet; deba@948: deba@948: IntNodeMap *_tree_set_index; deba@948: TreeSet *_tree_set; deba@948: deba@948: IntNodeMap *_delta2_index; deba@948: BinHeap *_delta2; deba@948: deba@948: IntEdgeMap *_delta3_index; deba@948: BinHeap *_delta3; deba@948: deba@948: Value _delta_sum; deba@948: deba@948: void createStructures() { deba@948: _node_num = countNodes(_graph); deba@948: deba@948: if (!_matching) { deba@948: _matching = new MatchingMap(_graph); deba@948: } deba@948: if (!_node_potential) { deba@948: _node_potential = new NodePotential(_graph); deba@948: } deba@948: if (!_status) { deba@948: _status = new StatusMap(_graph); deba@948: } deba@948: if (!_pred) { deba@948: _pred = new PredMap(_graph); deba@948: } deba@948: if (!_tree_set) { deba@948: _tree_set_index = new IntNodeMap(_graph); deba@948: _tree_set = new TreeSet(*_tree_set_index); deba@948: } deba@948: if (!_delta2) { deba@948: _delta2_index = new IntNodeMap(_graph); deba@948: _delta2 = new BinHeap(*_delta2_index); deba@948: } deba@948: if (!_delta3) { deba@948: _delta3_index = new IntEdgeMap(_graph); deba@948: _delta3 = new BinHeap(*_delta3_index); deba@948: } deba@948: } deba@948: deba@948: void destroyStructures() { deba@948: if (_matching) { deba@948: delete _matching; deba@948: } deba@948: if (_node_potential) { deba@948: delete _node_potential; deba@948: } deba@948: if (_status) { deba@948: delete _status; deba@948: } deba@948: if (_pred) { deba@948: delete _pred; deba@948: } deba@948: if (_tree_set) { deba@948: delete _tree_set_index; deba@948: delete _tree_set; deba@948: } deba@948: if (_delta2) { deba@948: delete _delta2_index; deba@948: delete _delta2; deba@948: } deba@948: if (_delta3) { deba@948: delete _delta3_index; deba@948: delete _delta3; deba@948: } deba@948: } deba@948: deba@948: void matchedToEven(Node node, int tree) { deba@948: _tree_set->insert(node, tree); deba@948: _node_potential->set(node, (*_node_potential)[node] + _delta_sum); deba@948: deba@948: if (_delta2->state(node) == _delta2->IN_HEAP) { deba@948: _delta2->erase(node); deba@948: } deba@948: deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: if (node == v) { deba@948: if (_allow_loops && _graph.direction(a)) { deba@948: _delta3->push(a, rw / 2); deba@948: } deba@948: } else if ((*_status)[v] == EVEN) { deba@948: _delta3->push(a, rw / 2); deba@948: } else if ((*_status)[v] == MATCHED) { deba@948: if (_delta2->state(v) != _delta2->IN_HEAP) { deba@948: _pred->set(v, a); deba@948: _delta2->push(v, rw); deba@948: } else if ((*_delta2)[v] > rw) { deba@948: _pred->set(v, a); deba@948: _delta2->decrease(v, rw); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: deba@948: void matchedToOdd(Node node, int tree) { deba@948: _tree_set->insert(node, tree); deba@948: _node_potential->set(node, (*_node_potential)[node] - _delta_sum); deba@948: deba@948: if (_delta2->state(node) == _delta2->IN_HEAP) { deba@948: _delta2->erase(node); deba@948: } deba@948: } deba@948: deba@948: void evenToMatched(Node node, int tree) { deba@948: _node_potential->set(node, (*_node_potential)[node] - _delta_sum); deba@948: Arc min = INVALID; deba@948: Value minrw = std::numeric_limits::max(); deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: deba@948: if (node == v) { deba@948: if (_allow_loops && _graph.direction(a)) { deba@948: _delta3->erase(a); deba@948: } deba@948: } else if ((*_status)[v] == EVEN) { deba@948: _delta3->erase(a); deba@948: if (minrw > rw) { deba@948: min = _graph.oppositeArc(a); deba@948: minrw = rw; deba@948: } deba@948: } else if ((*_status)[v] == MATCHED) { deba@948: if ((*_pred)[v] == a) { deba@948: Arc mina = INVALID; deba@948: Value minrwa = std::numeric_limits::max(); deba@948: for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { deba@948: Node va = _graph.target(aa); deba@948: if ((*_status)[va] != EVEN || deba@948: _tree_set->find(va) == tree) continue; deba@948: Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - deba@948: dualScale * _weight[aa]; deba@948: if (minrwa > rwa) { deba@948: minrwa = rwa; deba@948: mina = aa; deba@948: } deba@948: } deba@948: if (mina != INVALID) { deba@948: _pred->set(v, mina); deba@948: _delta2->increase(v, minrwa); deba@948: } else { deba@948: _pred->set(v, INVALID); deba@948: _delta2->erase(v); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: if (min != INVALID) { deba@948: _pred->set(node, min); deba@948: _delta2->push(node, minrw); deba@948: } else { deba@948: _pred->set(node, INVALID); deba@948: } deba@948: } deba@948: deba@948: void oddToMatched(Node node) { deba@948: _node_potential->set(node, (*_node_potential)[node] + _delta_sum); deba@948: Arc min = INVALID; deba@948: Value minrw = std::numeric_limits::max(); deba@948: for (InArcIt a(_graph, node); a != INVALID; ++a) { deba@948: Node v = _graph.source(a); deba@948: if ((*_status)[v] != EVEN) continue; deba@948: Value rw = (*_node_potential)[node] + (*_node_potential)[v] - deba@948: dualScale * _weight[a]; deba@948: deba@948: if (minrw > rw) { deba@948: min = _graph.oppositeArc(a); deba@948: minrw = rw; deba@948: } deba@948: } deba@948: if (min != INVALID) { deba@948: _pred->set(node, min); deba@948: _delta2->push(node, minrw); deba@948: } else { deba@948: _pred->set(node, INVALID); deba@948: } deba@948: } deba@948: deba@948: void alternatePath(Node even, int tree) { deba@948: Node odd; deba@948: deba@948: _status->set(even, MATCHED); deba@948: evenToMatched(even, tree); deba@948: deba@948: Arc prev = (*_matching)[even]; deba@948: while (prev != INVALID) { deba@948: odd = _graph.target(prev); deba@948: even = _graph.target((*_pred)[odd]); deba@948: _matching->set(odd, (*_pred)[odd]); deba@948: _status->set(odd, MATCHED); deba@948: oddToMatched(odd); deba@948: deba@948: prev = (*_matching)[even]; deba@948: _status->set(even, MATCHED); deba@948: _matching->set(even, _graph.oppositeArc((*_matching)[odd])); deba@948: evenToMatched(even, tree); deba@948: } deba@948: } deba@948: deba@948: void destroyTree(int tree) { deba@948: for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { deba@948: if ((*_status)[n] == EVEN) { deba@948: _status->set(n, MATCHED); deba@948: evenToMatched(n, tree); deba@948: } else if ((*_status)[n] == ODD) { deba@948: _status->set(n, MATCHED); deba@948: oddToMatched(n); deba@948: } deba@948: } deba@948: _tree_set->eraseClass(tree); deba@948: } deba@948: deba@948: void augmentOnEdge(const Edge& edge) { deba@948: Node left = _graph.u(edge); deba@948: int left_tree = _tree_set->find(left); deba@948: deba@948: alternatePath(left, left_tree); deba@948: destroyTree(left_tree); deba@948: _matching->set(left, _graph.direct(edge, true)); deba@948: deba@948: Node right = _graph.v(edge); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.direct(edge, false)); deba@948: } deba@948: deba@948: void augmentOnArc(const Arc& arc) { deba@948: Node left = _graph.source(arc); deba@948: _status->set(left, MATCHED); deba@948: _matching->set(left, arc); deba@948: _pred->set(left, arc); deba@948: deba@948: Node right = _graph.target(arc); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.oppositeArc(arc)); deba@948: } deba@948: deba@948: void extendOnArc(const Arc& arc) { deba@948: Node base = _graph.target(arc); deba@948: int tree = _tree_set->find(base); deba@948: deba@948: Node odd = _graph.source(arc); deba@948: _tree_set->insert(odd, tree); deba@948: _status->set(odd, ODD); deba@948: matchedToOdd(odd, tree); deba@948: _pred->set(odd, arc); deba@948: deba@948: Node even = _graph.target((*_matching)[odd]); deba@948: _tree_set->insert(even, tree); deba@948: _status->set(even, EVEN); deba@948: matchedToEven(even, tree); deba@948: } deba@948: deba@948: void cycleOnEdge(const Edge& edge, int tree) { deba@948: Node nca = INVALID; deba@948: std::vector left_path, right_path; deba@948: deba@948: { deba@948: std::set left_set, right_set; deba@948: Node left = _graph.u(edge); deba@948: left_path.push_back(left); deba@948: left_set.insert(left); deba@948: deba@948: Node right = _graph.v(edge); deba@948: right_path.push_back(right); deba@948: right_set.insert(right); deba@948: deba@948: while (true) { deba@948: deba@948: if (left_set.find(right) != left_set.end()) { deba@948: nca = right; deba@948: break; deba@948: } deba@948: deba@948: if ((*_matching)[left] == INVALID) break; deba@948: deba@948: left = _graph.target((*_matching)[left]); deba@948: left_path.push_back(left); deba@948: left = _graph.target((*_pred)[left]); deba@948: left_path.push_back(left); deba@948: deba@948: left_set.insert(left); deba@948: deba@948: if (right_set.find(left) != right_set.end()) { deba@948: nca = left; deba@948: break; deba@948: } deba@948: deba@948: if ((*_matching)[right] == INVALID) break; deba@948: deba@948: right = _graph.target((*_matching)[right]); deba@948: right_path.push_back(right); deba@948: right = _graph.target((*_pred)[right]); deba@948: right_path.push_back(right); deba@948: deba@948: right_set.insert(right); deba@948: deba@948: } deba@948: deba@948: if (nca == INVALID) { deba@948: if ((*_matching)[left] == INVALID) { deba@948: nca = right; deba@948: while (left_set.find(nca) == left_set.end()) { deba@948: nca = _graph.target((*_matching)[nca]); deba@948: right_path.push_back(nca); deba@948: nca = _graph.target((*_pred)[nca]); deba@948: right_path.push_back(nca); deba@948: } deba@948: } else { deba@948: nca = left; deba@948: while (right_set.find(nca) == right_set.end()) { deba@948: nca = _graph.target((*_matching)[nca]); deba@948: left_path.push_back(nca); deba@948: nca = _graph.target((*_pred)[nca]); deba@948: left_path.push_back(nca); deba@948: } deba@948: } deba@948: } deba@948: } deba@948: deba@948: alternatePath(nca, tree); deba@948: Arc prev; deba@948: deba@948: prev = _graph.direct(edge, true); deba@948: for (int i = 0; left_path[i] != nca; i += 2) { deba@948: _matching->set(left_path[i], prev); deba@948: _status->set(left_path[i], MATCHED); deba@948: evenToMatched(left_path[i], tree); deba@948: deba@948: prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); deba@948: _status->set(left_path[i + 1], MATCHED); deba@948: oddToMatched(left_path[i + 1]); deba@948: } deba@948: _matching->set(nca, prev); deba@948: deba@948: for (int i = 0; right_path[i] != nca; i += 2) { deba@948: _status->set(right_path[i], MATCHED); deba@948: evenToMatched(right_path[i], tree); deba@948: deba@948: _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); deba@948: _status->set(right_path[i + 1], MATCHED); deba@948: oddToMatched(right_path[i + 1]); deba@948: } deba@948: deba@948: destroyTree(tree); deba@948: } deba@948: deba@948: void extractCycle(const Arc &arc) { deba@948: Node left = _graph.source(arc); deba@948: Node odd = _graph.target((*_matching)[left]); deba@948: Arc prev; deba@948: while (odd != left) { deba@948: Node even = _graph.target((*_matching)[odd]); deba@948: prev = (*_matching)[odd]; deba@948: odd = _graph.target((*_matching)[even]); deba@948: _matching->set(even, _graph.oppositeArc(prev)); deba@948: } deba@948: _matching->set(left, arc); deba@948: deba@948: Node right = _graph.target(arc); deba@948: int right_tree = _tree_set->find(right); deba@948: alternatePath(right, right_tree); deba@948: destroyTree(right_tree); deba@948: _matching->set(right, _graph.oppositeArc(arc)); deba@948: } deba@948: deba@948: public: deba@948: deba@948: /// \brief Constructor deba@948: /// deba@948: /// Constructor. deba@948: MaxWeightedPerfectFractionalMatching(const Graph& graph, deba@948: const WeightMap& weight, deba@948: bool allow_loops = true) deba@948: : _graph(graph), _weight(weight), _matching(0), deba@948: _node_potential(0), _node_num(0), _allow_loops(allow_loops), deba@948: _status(0), _pred(0), deba@948: _tree_set_index(0), _tree_set(0), deba@948: deba@948: _delta2_index(0), _delta2(0), deba@948: _delta3_index(0), _delta3(0), deba@948: deba@948: _delta_sum() {} deba@948: deba@948: ~MaxWeightedPerfectFractionalMatching() { deba@948: destroyStructures(); deba@948: } deba@948: deba@948: /// \name Execution Control deba@948: /// The simplest way to execute the algorithm is to use the deba@948: /// \ref run() member function. deba@948: deba@948: ///@{ deba@948: deba@948: /// \brief Initialize the algorithm deba@948: /// deba@948: /// This function initializes the algorithm. deba@948: void init() { deba@948: createStructures(); deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: (*_delta2_index)[n] = _delta2->PRE_HEAP; deba@948: } deba@948: for (EdgeIt e(_graph); e != INVALID; ++e) { deba@948: (*_delta3_index)[e] = _delta3->PRE_HEAP; deba@948: } deba@948: deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: Value max = - std::numeric_limits::max(); deba@948: for (OutArcIt e(_graph, n); e != INVALID; ++e) { deba@948: if (_graph.target(e) == n && !_allow_loops) continue; deba@948: if ((dualScale * _weight[e]) / 2 > max) { deba@948: max = (dualScale * _weight[e]) / 2; deba@948: } deba@948: } deba@948: _node_potential->set(n, max); deba@948: deba@948: _tree_set->insert(n); deba@948: deba@948: _matching->set(n, INVALID); deba@948: _status->set(n, EVEN); deba@948: } deba@948: deba@948: for (EdgeIt e(_graph); e != INVALID; ++e) { deba@948: Node left = _graph.u(e); deba@948: Node right = _graph.v(e); deba@948: if (left == right && !_allow_loops) continue; deba@948: _delta3->push(e, ((*_node_potential)[left] + deba@948: (*_node_potential)[right] - deba@948: dualScale * _weight[e]) / 2); deba@948: } deba@948: } deba@948: deba@948: /// \brief Start the algorithm deba@948: /// deba@948: /// This function starts the algorithm. deba@948: /// deba@948: /// \pre \ref init() must be called before using this function. deba@948: bool start() { deba@948: enum OpType { deba@948: D2, D3 deba@948: }; deba@948: deba@948: int unmatched = _node_num; deba@948: while (unmatched > 0) { deba@948: Value d2 = !_delta2->empty() ? deba@948: _delta2->prio() : std::numeric_limits::max(); deba@948: deba@948: Value d3 = !_delta3->empty() ? deba@948: _delta3->prio() : std::numeric_limits::max(); deba@948: deba@948: _delta_sum = d3; OpType ot = D3; deba@948: if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } deba@948: deba@948: if (_delta_sum == std::numeric_limits::max()) { deba@948: return false; deba@948: } deba@948: deba@948: switch (ot) { deba@948: case D2: deba@948: { deba@948: Node n = _delta2->top(); deba@948: Arc a = (*_pred)[n]; deba@948: if ((*_matching)[n] == INVALID) { deba@948: augmentOnArc(a); deba@948: --unmatched; deba@948: } else { deba@948: Node v = _graph.target((*_matching)[n]); deba@948: if ((*_matching)[n] != deba@948: _graph.oppositeArc((*_matching)[v])) { deba@948: extractCycle(a); deba@948: --unmatched; deba@948: } else { deba@948: extendOnArc(a); deba@948: } deba@948: } deba@948: } break; deba@948: case D3: deba@948: { deba@948: Edge e = _delta3->top(); deba@948: deba@948: Node left = _graph.u(e); deba@948: Node right = _graph.v(e); deba@948: deba@948: int left_tree = _tree_set->find(left); deba@948: int right_tree = _tree_set->find(right); deba@948: deba@948: if (left_tree == right_tree) { deba@948: cycleOnEdge(e, left_tree); deba@948: --unmatched; deba@948: } else { deba@948: augmentOnEdge(e); deba@948: unmatched -= 2; deba@948: } deba@948: } break; deba@948: } deba@948: } deba@948: return true; deba@948: } deba@948: deba@948: /// \brief Run the algorithm. deba@948: /// deba@950: /// This method runs the \c %MaxWeightedPerfectFractionalMatching deba@950: /// algorithm. deba@948: /// deba@948: /// \note mwfm.run() is just a shortcut of the following code. deba@948: /// \code deba@948: /// mwpfm.init(); deba@948: /// mwpfm.start(); deba@948: /// \endcode deba@948: bool run() { deba@948: init(); deba@948: return start(); deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: /// \name Primal Solution deba@948: /// Functions to get the primal solution, i.e. the maximum weighted deba@948: /// matching.\n deba@948: /// Either \ref run() or \ref start() function should be called before deba@948: /// using them. deba@948: deba@948: /// @{ deba@948: deba@948: /// \brief Return the weight of the matching. deba@948: /// deba@948: /// This function returns the weight of the found matching. This deba@948: /// value is scaled by \ref primalScale "primal scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value matchingWeight() const { deba@948: Value sum = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] != INVALID) { deba@948: sum += _weight[(*_matching)[n]]; deba@948: } deba@948: } deba@948: return sum * primalScale / 2; deba@948: } deba@948: deba@948: /// \brief Return the number of covered nodes in the matching. deba@948: /// deba@948: /// This function returns the number of covered nodes in the matching. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: int matchingSize() const { deba@948: int num = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: if ((*_matching)[n] != INVALID) { deba@948: ++num; deba@948: } deba@948: } deba@948: return num; deba@948: } deba@948: deba@948: /// \brief Return \c true if the given edge is in the matching. deba@948: /// deba@948: /// This function returns \c true if the given edge is in the deba@948: /// found matching. The result is scaled by \ref primalScale deba@948: /// "primal scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value matching(const Edge& edge) const { deba@948: return Value(edge == (*_matching)[_graph.u(edge)] ? 1 : 0) deba@948: * primalScale / 2 + Value(edge == (*_matching)[_graph.v(edge)] ? 1 : 0) deba@948: * primalScale / 2; deba@948: } deba@948: deba@948: /// \brief Return the fractional matching arc (or edge) incident deba@948: /// to the given node. deba@948: /// deba@948: /// This function returns one of the fractional matching arc (or deba@948: /// edge) incident to the given node in the found matching or \c deba@948: /// INVALID if the node is not covered by the matching or if the deba@948: /// node is on an odd length cycle then it is the successor edge deba@948: /// on the cycle. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Arc matching(const Node& node) const { deba@948: return (*_matching)[node]; deba@948: } deba@948: deba@948: /// \brief Return a const reference to the matching map. deba@948: /// deba@948: /// This function returns a const reference to a node map that stores deba@948: /// the matching arc (or edge) incident to each node. deba@948: const MatchingMap& matchingMap() const { deba@948: return *_matching; deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: /// \name Dual Solution deba@948: /// Functions to get the dual solution.\n deba@948: /// Either \ref run() or \ref start() function should be called before deba@948: /// using them. deba@948: deba@948: /// @{ deba@948: deba@948: /// \brief Return the value of the dual solution. deba@948: /// deba@948: /// This function returns the value of the dual solution. deba@948: /// It should be equal to the primal value scaled by \ref dualScale deba@948: /// "dual scale". deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value dualValue() const { deba@948: Value sum = 0; deba@948: for (NodeIt n(_graph); n != INVALID; ++n) { deba@948: sum += nodeValue(n); deba@948: } deba@948: return sum; deba@948: } deba@948: deba@948: /// \brief Return the dual value (potential) of the given node. deba@948: /// deba@948: /// This function returns the dual value (potential) of the given node. deba@948: /// deba@948: /// \pre Either run() or start() must be called before using this function. deba@948: Value nodeValue(const Node& n) const { deba@948: return (*_node_potential)[n]; deba@948: } deba@948: deba@948: /// @} deba@948: deba@948: }; deba@948: deba@948: } //END OF NAMESPACE LEMON deba@948: deba@948: #endif //LEMON_FRACTIONAL_MATCHING_H