//=======================================================================
// Copyright (c) 2005 Aaron Windsor
//
// Distributed under the Boost Software License, Version 1.0. 
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
//=======================================================================

#ifndef BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP
#define BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP

#include <vector>
#include <list>
#include <deque>
#include <algorithm>                     // for std::sort and std::stable_sort
#include <utility>                       // for std::pair
#include <boost/property_map/property_map.hpp>
#include <boost/utility.hpp>             // for boost::tie
#include <boost/graph/graph_traits.hpp>  
#include <boost/graph/visitors.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/assert.hpp>


namespace boost
{
  namespace graph { namespace detail {
    enum { V_EVEN, V_ODD, V_UNREACHED };
  } } // end namespace graph::detail

  template <typename Graph, typename MateMap, typename VertexIndexMap>
  typename graph_traits<Graph>::vertices_size_type 
  matching_size(const Graph& g, MateMap mate, VertexIndexMap vm)
  {
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
    typedef typename graph_traits<Graph>::vertex_descriptor
      vertex_descriptor_t;
    typedef typename graph_traits<Graph>::vertices_size_type v_size_t;

    v_size_t size_of_matching = 0;
    vertex_iterator_t vi, vi_end;

    for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
      {
        vertex_descriptor_t v = *vi;
        if (get(mate,v) != graph_traits<Graph>::null_vertex() 
            && get(vm,v) < get(vm,get(mate,v)))
        ++size_of_matching;
      }
    return size_of_matching;
  }




  template <typename Graph, typename MateMap>
  inline typename graph_traits<Graph>::vertices_size_type
  matching_size(const Graph& g, MateMap mate)
  {
    return matching_size(g, mate, get(vertex_index,g));
  }




  template <typename Graph, typename MateMap, typename VertexIndexMap>
  bool is_a_matching(const Graph& g, MateMap mate, VertexIndexMap)
  {
    typedef typename graph_traits<Graph>::vertex_descriptor
      vertex_descriptor_t;
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;

    vertex_iterator_t vi, vi_end;
    for( boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
      {
        vertex_descriptor_t v = *vi;
        if (get(mate,v) != graph_traits<Graph>::null_vertex() 
            && v != get(mate,get(mate,v)))
        return false;
      }    
    return true;
  }




  template <typename Graph, typename MateMap>
  inline bool is_a_matching(const Graph& g, MateMap mate)
  {
    return is_a_matching(g, mate, get(vertex_index,g));
  }




  //***************************************************************************
  //***************************************************************************
  //               Maximum Cardinality Matching Functors 
  //***************************************************************************
  //***************************************************************************
  
  template <typename Graph, typename MateMap, 
            typename VertexIndexMap = dummy_property_map>
  struct no_augmenting_path_finder
  {
    no_augmenting_path_finder(const Graph&, MateMap, VertexIndexMap)
    { }

    inline bool augment_matching() { return false; }

    template <typename PropertyMap>
    void get_current_matching(PropertyMap) {}
  };




  template <typename Graph, typename MateMap, typename VertexIndexMap>
  class edmonds_augmenting_path_finder
  {
    // This implementation of Edmonds' matching algorithm closely
    // follows Tarjan's description of the algorithm in "Data
    // Structures and Network Algorithms."

  public:

    //generates the type of an iterator property map from vertices to type X
    template <typename X>
    struct map_vertex_to_ 
    { 
      typedef boost::iterator_property_map<typename std::vector<X>::iterator,
                                           VertexIndexMap> type; 
    };
    
    typedef typename graph_traits<Graph>::vertex_descriptor
      vertex_descriptor_t;
    typedef typename std::pair< vertex_descriptor_t, vertex_descriptor_t >
      vertex_pair_t;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor_t; 
    typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
    typedef typename graph_traits<Graph>::edges_size_type e_size_t;
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
    typedef typename graph_traits<Graph>::out_edge_iterator 
      out_edge_iterator_t;
    typedef typename std::deque<vertex_descriptor_t> vertex_list_t;
    typedef typename std::vector<edge_descriptor_t> edge_list_t;
    typedef typename map_vertex_to_<vertex_descriptor_t>::type 
      vertex_to_vertex_map_t;
    typedef typename map_vertex_to_<int>::type vertex_to_int_map_t;
    typedef typename map_vertex_to_<vertex_pair_t>::type 
      vertex_to_vertex_pair_map_t;
    typedef typename map_vertex_to_<v_size_t>::type vertex_to_vsize_map_t;
    typedef typename map_vertex_to_<e_size_t>::type vertex_to_esize_map_t;



    
    edmonds_augmenting_path_finder(const Graph& arg_g, MateMap arg_mate, 
                                   VertexIndexMap arg_vm) : 
      g(arg_g),
      vm(arg_vm),
      n_vertices(num_vertices(arg_g)),

      mate_vector(n_vertices),
      ancestor_of_v_vector(n_vertices),
      ancestor_of_w_vector(n_vertices),
      vertex_state_vector(n_vertices),
      origin_vector(n_vertices),
      pred_vector(n_vertices),
      bridge_vector(n_vertices),
      ds_parent_vector(n_vertices),
      ds_rank_vector(n_vertices),

      mate(mate_vector.begin(), vm),
      ancestor_of_v(ancestor_of_v_vector.begin(), vm),
      ancestor_of_w(ancestor_of_w_vector.begin(), vm),
      vertex_state(vertex_state_vector.begin(), vm),
      origin(origin_vector.begin(), vm),
      pred(pred_vector.begin(), vm),
      bridge(bridge_vector.begin(), vm),
      ds_parent_map(ds_parent_vector.begin(), vm),
      ds_rank_map(ds_rank_vector.begin(), vm),

      ds(ds_rank_map, ds_parent_map)
    {
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        mate[*vi] = get(arg_mate, *vi);
    }


    

    bool augment_matching()
    {
      //As an optimization, some of these values can be saved from one
      //iteration to the next instead of being re-initialized each
      //iteration, allowing for "lazy blossom expansion." This is not
      //currently implemented.
      
      e_size_t timestamp = 0;
      even_edges.clear();
      
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
      {
        vertex_descriptor_t u = *vi;
      
        origin[u] = u;
        pred[u] = u;
        ancestor_of_v[u] = 0;
        ancestor_of_w[u] = 0;
        ds.make_set(u);
      
        if (mate[u] == graph_traits<Graph>::null_vertex())
        {
          vertex_state[u] = graph::detail::V_EVEN;
          out_edge_iterator_t ei, ei_end;
          for(boost::tie(ei,ei_end) = out_edges(u,g); ei != ei_end; ++ei)
            even_edges.push_back( *ei );
        }
        else
          vertex_state[u] = graph::detail::V_UNREACHED;      
      }
    
      //end initializations
    
      vertex_descriptor_t v,w,w_free_ancestor,v_free_ancestor;
      w_free_ancestor = graph_traits<Graph>::null_vertex();
      v_free_ancestor = graph_traits<Graph>::null_vertex(); 
      bool found_alternating_path = false;
      
      while(!even_edges.empty() && !found_alternating_path)
      {
        // since we push even edges onto the back of the list as
        // they're discovered, taking them off the back will search
        // for augmenting paths depth-first.
        edge_descriptor_t current_edge = even_edges.back();
        even_edges.pop_back();

        v = source(current_edge,g);
        w = target(current_edge,g);
      
        vertex_descriptor_t v_prime = origin[ds.find_set(v)];
        vertex_descriptor_t w_prime = origin[ds.find_set(w)];
      
        // because of the way we put all of the edges on the queue,
        // v_prime should be labeled V_EVEN; the following is a
        // little paranoid but it could happen...
        if (vertex_state[v_prime] != graph::detail::V_EVEN)
        {
          std::swap(v_prime,w_prime);
          std::swap(v,w);
        }

        if (vertex_state[w_prime] == graph::detail::V_UNREACHED)
        {
          vertex_state[w_prime] = graph::detail::V_ODD;
          vertex_state[mate[w_prime]] = graph::detail::V_EVEN;
          out_edge_iterator_t ei, ei_end;
          for( boost::tie(ei,ei_end) = out_edges(mate[w_prime], g); ei != ei_end; ++ei)
            even_edges.push_back(*ei);
          pred[w_prime] = v;
        }
        
        //w_prime == v_prime can happen below if we get an edge that has been
        //shrunk into a blossom
        else if (vertex_state[w_prime] == graph::detail::V_EVEN && w_prime != v_prime) 
        {                                                             
          vertex_descriptor_t w_up = w_prime;
          vertex_descriptor_t v_up = v_prime;
          vertex_descriptor_t nearest_common_ancestor 
                = graph_traits<Graph>::null_vertex();
          w_free_ancestor = graph_traits<Graph>::null_vertex();
          v_free_ancestor = graph_traits<Graph>::null_vertex();
          
          // We now need to distinguish between the case that
          // w_prime and v_prime share an ancestor under the
          // "parent" relation, in which case we've found a
          // blossom and should shrink it, or the case that
          // w_prime and v_prime both have distinct ancestors that
          // are free, in which case we've found an alternating
          // path between those two ancestors.

          ++timestamp;

          while (nearest_common_ancestor == graph_traits<Graph>::null_vertex() && 
             (v_free_ancestor == graph_traits<Graph>::null_vertex() || 
              w_free_ancestor == graph_traits<Graph>::null_vertex()
              )
             )
          {
            ancestor_of_w[w_up] = timestamp;
            ancestor_of_v[v_up] = timestamp;

            if (w_free_ancestor == graph_traits<Graph>::null_vertex())
              w_up = parent(w_up);
            if (v_free_ancestor == graph_traits<Graph>::null_vertex())
              v_up = parent(v_up);
          
            if (mate[v_up] == graph_traits<Graph>::null_vertex())
              v_free_ancestor = v_up;
            if (mate[w_up] == graph_traits<Graph>::null_vertex())
              w_free_ancestor = w_up;
          
            if (ancestor_of_w[v_up] == timestamp)
              nearest_common_ancestor = v_up;
            else if (ancestor_of_v[w_up] == timestamp)
              nearest_common_ancestor = w_up;
            else if (v_free_ancestor == w_free_ancestor && 
              v_free_ancestor != graph_traits<Graph>::null_vertex())
            nearest_common_ancestor = v_up;
          }
          
          if (nearest_common_ancestor == graph_traits<Graph>::null_vertex())
            found_alternating_path = true; //to break out of the loop
          else
          {
            //shrink the blossom
            link_and_set_bridges(w_prime, nearest_common_ancestor, std::make_pair(w,v));
            link_and_set_bridges(v_prime, nearest_common_ancestor, std::make_pair(v,w));
          }
        }      
      }
      
      if (!found_alternating_path)
        return false;

      // retrieve the augmenting path and put it in aug_path
      reversed_retrieve_augmenting_path(v, v_free_ancestor);
      retrieve_augmenting_path(w, w_free_ancestor);

      // augment the matching along aug_path
      vertex_descriptor_t a,b;
      while (!aug_path.empty())
      {
        a = aug_path.front();
        aug_path.pop_front();
        b = aug_path.front();
        aug_path.pop_front();
        mate[a] = b;
        mate[b] = a;
      }
      
      return true;
      
    }




    template <typename PropertyMap>
    void get_current_matching(PropertyMap pm)
    {
      vertex_iterator_t vi,vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        put(pm, *vi, mate[*vi]);
    }




    template <typename PropertyMap>
    void get_vertex_state_map(PropertyMap pm)
    {
      vertex_iterator_t vi,vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        put(pm, *vi, vertex_state[origin[ds.find_set(*vi)]]);
    }




  private:    

    vertex_descriptor_t parent(vertex_descriptor_t x)
    {
      if (vertex_state[x] == graph::detail::V_EVEN 
          && mate[x] != graph_traits<Graph>::null_vertex())
        return mate[x];
      else if (vertex_state[x] == graph::detail::V_ODD)
        return origin[ds.find_set(pred[x])];
      else
        return x;
    }
    
    


    void link_and_set_bridges(vertex_descriptor_t x, 
                              vertex_descriptor_t stop_vertex, 
                  vertex_pair_t the_bridge)
    {
      for(vertex_descriptor_t v = x; v != stop_vertex; v = parent(v))
      {
        ds.union_set(v, stop_vertex);
        origin[ds.find_set(stop_vertex)] = stop_vertex;

        if (vertex_state[v] == graph::detail::V_ODD)
        {
          bridge[v] = the_bridge;
          out_edge_iterator_t oei, oei_end;
          for(boost::tie(oei, oei_end) = out_edges(v,g); oei != oei_end; ++oei)
            even_edges.push_back(*oei);
        }
      }
    }
    

    // Since none of the STL containers support both constant-time
    // concatenation and reversal, the process of expanding an
    // augmenting path once we know one exists is a little more
    // complicated than it has to be. If we know the path is from v to
    // w, then the augmenting path is recursively defined as:
    //
    // path(v,w) = [v], if v = w
    //           = concat([v, mate[v]], path(pred[mate[v]], w), 
    //                if v != w and vertex_state[v] == graph::detail::V_EVEN
    //           = concat([v], reverse(path(x,mate[v])), path(y,w)),
    //                if v != w, vertex_state[v] == graph::detail::V_ODD, and bridge[v] = (x,y)
    //
    // These next two mutually recursive functions implement this definition.
    
    void retrieve_augmenting_path(vertex_descriptor_t v, vertex_descriptor_t w)  
    {
      if (v == w)
        aug_path.push_back(v);
      else if (vertex_state[v] == graph::detail::V_EVEN)
      {
        aug_path.push_back(v);
        aug_path.push_back(mate[v]);
        retrieve_augmenting_path(pred[mate[v]], w);
      }
      else //vertex_state[v] == graph::detail::V_ODD 
      {
        aug_path.push_back(v);
        reversed_retrieve_augmenting_path(bridge[v].first, mate[v]);
        retrieve_augmenting_path(bridge[v].second, w);
      }
    }


    void reversed_retrieve_augmenting_path(vertex_descriptor_t v,
                                           vertex_descriptor_t w)  
    {

      if (v == w)
        aug_path.push_back(v);
      else if (vertex_state[v] == graph::detail::V_EVEN)
      {
        reversed_retrieve_augmenting_path(pred[mate[v]], w);
        aug_path.push_back(mate[v]);
        aug_path.push_back(v);
      }
      else //vertex_state[v] == graph::detail::V_ODD 
      {
        reversed_retrieve_augmenting_path(bridge[v].second, w);
        retrieve_augmenting_path(bridge[v].first, mate[v]);
        aug_path.push_back(v);
      }
    }

    


    //private data members
    
    const Graph& g;
    VertexIndexMap vm;
    v_size_t n_vertices;
    
    //storage for the property maps below
    std::vector<vertex_descriptor_t> mate_vector;
    std::vector<e_size_t> ancestor_of_v_vector;
    std::vector<e_size_t> ancestor_of_w_vector;
    std::vector<int> vertex_state_vector;
    std::vector<vertex_descriptor_t> origin_vector;
    std::vector<vertex_descriptor_t> pred_vector;
    std::vector<vertex_pair_t> bridge_vector;
    std::vector<vertex_descriptor_t> ds_parent_vector;
    std::vector<v_size_t> ds_rank_vector;

    //iterator property maps
    vertex_to_vertex_map_t mate;
    vertex_to_esize_map_t ancestor_of_v;
    vertex_to_esize_map_t ancestor_of_w;
    vertex_to_int_map_t vertex_state;
    vertex_to_vertex_map_t origin;
    vertex_to_vertex_map_t pred;
    vertex_to_vertex_pair_map_t bridge;
    vertex_to_vertex_map_t ds_parent_map;
    vertex_to_vsize_map_t ds_rank_map;

    vertex_list_t aug_path;
    edge_list_t even_edges;
    disjoint_sets< vertex_to_vsize_map_t, vertex_to_vertex_map_t > ds;

  };




  //***************************************************************************
  //***************************************************************************
  //               Initial Matching Functors
  //***************************************************************************
  //***************************************************************************
  
  template <typename Graph, typename MateMap>
  struct greedy_matching
  {
    typedef typename graph_traits< Graph >::vertex_descriptor vertex_descriptor_t;
    typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
    typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; 
    typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t;

    static void find_matching(const Graph& g, MateMap mate)
    {
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        put(mate, *vi, graph_traits<Graph>::null_vertex());
            
      edge_iterator_t ei, ei_end;
      for( boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
      {
        edge_descriptor_t e = *ei;
        vertex_descriptor_t u = source(e,g);
        vertex_descriptor_t v = target(e,g);
      
        if (get(mate,u) == get(mate,v))  
        //only way equality can hold is if
        //   mate[u] == mate[v] == null_vertex
        {
          put(mate,u,v);
          put(mate,v,u);
        }
      }    
    }
  };
  


  
  template <typename Graph, typename MateMap>
  struct extra_greedy_matching
  {
    // The "extra greedy matching" is formed by repeating the
    // following procedure as many times as possible: Choose the
    // unmatched vertex v of minimum non-zero degree.  Choose the
    // neighbor w of v which is unmatched and has minimum degree over
    // all of v's neighbors. Add (u,v) to the matching. Ties for
    // either choice are broken arbitrarily. This procedure takes time
    // O(m log n), where m is the number of edges in the graph and n
    // is the number of vertices.
    
    typedef typename graph_traits< Graph >::vertex_descriptor
      vertex_descriptor_t;
    typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
    typedef typename graph_traits< Graph >::edge_descriptor edge_descriptor_t; 
    typedef typename graph_traits< Graph >::edge_iterator edge_iterator_t;
    typedef std::pair<vertex_descriptor_t, vertex_descriptor_t> vertex_pair_t;
    
    struct select_first
    {
      inline static vertex_descriptor_t select_vertex(const vertex_pair_t p) 
      {return p.first;}
    };

    struct select_second
    {
      inline static vertex_descriptor_t select_vertex(const vertex_pair_t p) 
      {return p.second;}
    };

    template <class PairSelector>
    class less_than_by_degree
    {
    public:
      less_than_by_degree(const Graph& g): m_g(g) {}
      bool operator() (const vertex_pair_t x, const vertex_pair_t y)
      {
        return 
          out_degree(PairSelector::select_vertex(x), m_g) 
          < out_degree(PairSelector::select_vertex(y), m_g);
      }
    private:
      const Graph& m_g;
    };


    static void find_matching(const Graph& g, MateMap mate)
    {
      typedef std::vector<std::pair<vertex_descriptor_t, vertex_descriptor_t> >
        directed_edges_vector_t;
      
      directed_edges_vector_t edge_list;
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
        put(mate, *vi, graph_traits<Graph>::null_vertex());

      edge_iterator_t ei, ei_end;
      for(boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
      {
        edge_descriptor_t e = *ei;
        vertex_descriptor_t u = source(e,g);
        vertex_descriptor_t v = target(e,g);
        edge_list.push_back(std::make_pair(u,v));
        edge_list.push_back(std::make_pair(v,u));
      }
      
      //sort the edges by the degree of the target, then (using a
      //stable sort) by degree of the source
      std::sort(edge_list.begin(), edge_list.end(), 
                less_than_by_degree<select_second>(g));
      std::stable_sort(edge_list.begin(), edge_list.end(), 
                       less_than_by_degree<select_first>(g));
      
      //construct the extra greedy matching
      for(typename directed_edges_vector_t::const_iterator itr = edge_list.begin(); itr != edge_list.end(); ++itr)
      {
        if (get(mate,itr->first) == get(mate,itr->second)) 
        //only way equality can hold is if mate[itr->first] == mate[itr->second] == null_vertex
        {
          put(mate, itr->first, itr->second);
          put(mate, itr->second, itr->first);
        }
      }    
    }
  };


  

  template <typename Graph, typename MateMap>
  struct empty_matching
  { 
    typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;
    
    static void find_matching(const Graph& g, MateMap mate)
    {
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        put(mate, *vi, graph_traits<Graph>::null_vertex());
    }
  };
  



  //***************************************************************************
  //***************************************************************************
  //               Matching Verifiers
  //***************************************************************************
  //***************************************************************************

  namespace detail
  {

    template <typename SizeType>
    class odd_components_counter : public dfs_visitor<>
    // This depth-first search visitor will count the number of connected 
    // components with an odd number of vertices. It's used by 
    // maximum_matching_verifier.
    {
    public:
      odd_components_counter(SizeType& c_count):
        m_count(c_count)
      {
        m_count = 0;
      }
      
      template <class Vertex, class Graph>
      void start_vertex(Vertex, Graph&) 
      {
        m_parity = false; 
      }
      
      template <class Vertex, class Graph>
      void discover_vertex(Vertex, Graph&) 
      {
        m_parity = !m_parity;
        m_parity ? ++m_count : --m_count;
      }
      
    protected:
      SizeType& m_count;
      
    private:
      bool m_parity;
      
    };

  }//namespace detail




  template <typename Graph, typename MateMap, 
            typename VertexIndexMap = dummy_property_map>
  struct no_matching_verifier
  {
    inline static bool 
    verify_matching(const Graph&, MateMap, VertexIndexMap) 
    { return true;}
  };
  
  


  template <typename Graph, typename MateMap, typename VertexIndexMap>
  struct maximum_cardinality_matching_verifier
  {

    template <typename X>
    struct map_vertex_to_
    { 
      typedef boost::iterator_property_map<typename std::vector<X>::iterator,
                                           VertexIndexMap> type; 
    };

    typedef typename graph_traits<Graph>::vertex_descriptor 
      vertex_descriptor_t;
    typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
    typedef typename map_vertex_to_<int>::type vertex_to_int_map_t;
    typedef typename map_vertex_to_<vertex_descriptor_t>::type 
      vertex_to_vertex_map_t;


    template <typename VertexStateMap>
    struct non_odd_vertex {
      //this predicate is used to create a filtered graph that
      //excludes vertices labeled "graph::detail::V_ODD"
      non_odd_vertex() : vertex_state(0) { }
  
      non_odd_vertex(VertexStateMap* arg_vertex_state) 
        : vertex_state(arg_vertex_state) { }

      template <typename Vertex>
      bool operator()(const Vertex& v) const 
      {
        BOOST_ASSERT(vertex_state);
        return get(*vertex_state, v) != graph::detail::V_ODD;
      }

      VertexStateMap* vertex_state;
    };


    static bool verify_matching(const Graph& g, MateMap mate, VertexIndexMap vm)
    {
      //For any graph G, let o(G) be the number of connected
      //components in G of odd size. For a subset S of G's vertex set
      //V(G), let (G - S) represent the subgraph of G induced by
      //removing all vertices in S from G. Let M(G) be the size of the
      //maximum cardinality matching in G. Then the Tutte-Berge
      //formula guarantees that
      //
      //           2 * M(G) = min ( |V(G)| + |U| + o(G - U) )
      //
      //where the minimum is taken over all subsets U of
      //V(G). Edmonds' algorithm finds a set U that achieves the
      //minimum in the above formula, namely the vertices labeled
      //"ODD." This function runs one iteration of Edmonds' algorithm
      //to find U, then verifies that the size of the matching given
      //by mate satisfies the Tutte-Berge formula.

      //first, make sure it's a valid matching
      if (!is_a_matching(g,mate,vm))
        return false;

      //We'll try to augment the matching once. This serves two
      //purposes: first, if we find some augmenting path, the matching
      //is obviously non-maximum. Second, running edmonds' algorithm
      //on a graph with no augmenting path will create the
      //Edmonds-Gallai decomposition that we need as a certificate of
      //maximality - we can get it by looking at the vertex_state map
      //that results.
      edmonds_augmenting_path_finder<Graph,MateMap,VertexIndexMap>
        augmentor(g,mate,vm);
      if (augmentor.augment_matching())
        return false;

      std::vector<int> vertex_state_vector(num_vertices(g));
      vertex_to_int_map_t vertex_state(vertex_state_vector.begin(), vm);
      augmentor.get_vertex_state_map(vertex_state);
      
      //count the number of graph::detail::V_ODD vertices
      v_size_t num_odd_vertices = 0;
      vertex_iterator_t vi, vi_end;
      for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
        if (vertex_state[*vi] == graph::detail::V_ODD)
          ++num_odd_vertices;

      //count the number of connected components with odd cardinality
      //in the graph without graph::detail::V_ODD vertices
      non_odd_vertex<vertex_to_int_map_t> filter(&vertex_state);
      filtered_graph<Graph, keep_all, non_odd_vertex<vertex_to_int_map_t> > fg(g, keep_all(), filter);

      v_size_t num_odd_components;
      detail::odd_components_counter<v_size_t> occ(num_odd_components);
      depth_first_search(fg, visitor(occ).vertex_index_map(vm));

      if (2 * matching_size(g,mate,vm) == num_vertices(g) + num_odd_vertices - num_odd_components)
        return true;
      else
        return false;
    }
  };




  template <typename Graph, 
        typename MateMap,
        typename VertexIndexMap,
        template <typename, typename, typename> class AugmentingPathFinder, 
        template <typename, typename> class InitialMatchingFinder,
        template <typename, typename, typename> class MatchingVerifier>
  bool matching(const Graph& g, MateMap mate, VertexIndexMap vm)
  {
    
    InitialMatchingFinder<Graph,MateMap>::find_matching(g,mate);

    AugmentingPathFinder<Graph,MateMap,VertexIndexMap> augmentor(g,mate,vm);
    bool not_maximum_yet = true;
    while(not_maximum_yet)
      {
        not_maximum_yet = augmentor.augment_matching();
      }
    augmentor.get_current_matching(mate);

    return MatchingVerifier<Graph,MateMap,VertexIndexMap>::verify_matching(g,mate,vm);    
    
  }




  template <typename Graph, typename MateMap, typename VertexIndexMap>
  inline bool checked_edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate, VertexIndexMap vm)
  {
    return matching 
      < Graph, MateMap, VertexIndexMap,
        edmonds_augmenting_path_finder, extra_greedy_matching, maximum_cardinality_matching_verifier>
      (g, mate, vm);
  }




  template <typename Graph, typename MateMap>
  inline bool checked_edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate)
  {
    return checked_edmonds_maximum_cardinality_matching(g, mate, get(vertex_index,g));
  }




  template <typename Graph, typename MateMap, typename VertexIndexMap>
  inline void edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate, VertexIndexMap vm)
  {
    matching < Graph, MateMap, VertexIndexMap,
               edmonds_augmenting_path_finder, extra_greedy_matching, no_matching_verifier>
      (g, mate, vm);
  }




  template <typename Graph, typename MateMap>
  inline void edmonds_maximum_cardinality_matching(const Graph& g, MateMap mate)
  {
    edmonds_maximum_cardinality_matching(g, mate, get(vertex_index,g));
  }

}//namespace boost

#endif //BOOST_GRAPH_MAXIMUM_CARDINALITY_MATCHING_HPP
