text: // Copyright (C) 2009 Andrew Sutton
  
  // Use, modification and distribution is subject to 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_LABELED_GRAPH_HPP
  #define BOOST_GRAPH_LABELED_GRAPH_HPP
  
  #include <boost/config.hpp>
  #include <vector>
  #include <map>
  
  #include <boost/static_assert.hpp>
  #include <boost/mpl/if.hpp>
  #include <boost/mpl/bool.hpp>
  #include <boost/unordered_map.hpp>
  #include <boost/type_traits/is_same.hpp>
  #include <boost/type_traits/is_unsigned.hpp>
  #include <boost/pending/container_traits.hpp>
  #include <boost/graph/graph_traits.hpp>
  
  // This file implements a utility for creating mappings from arbitrary
  // identifiers to the vertices of a graph.
  
  namespace boost {
  
  // A type selector that denotes the use of some default value.
  struct defaultS { };
  
  /** @internal */
  namespace graph_detail {
      /** Returns true if the selector is the default selector. */
      template <typename Selector>
      struct is_default
          : mpl::bool_<is_same<Selector, defaultS>::value>
      { };
  
      /**
       * Choose the default map instance. If Label is an unsigned integral type
       * the we can use a vector to store the information.
       */
      template <typename Label, typename Vertex>
      struct choose_default_map {
          typedef typename mpl::if_<
              is_unsigned<Label>,
              std::vector<Vertex>,
              std::map<Label, Vertex> // TODO: Should use unordered_map?
          >::type type;
      };
  
      /**
       * @name Generate Label Map
       * These type generators are responsible for instantiating an associative
       * container for the the labeled graph. Note that the Selector must be
       * select a pair associative container or a vecS, which is only valid if
       * Label is an integral type.
       */
      //@{
      template <typename Selector, typename Label, typename Vertex>
      struct generate_label_map { };
  
      template <typename Label, typename Vertex>
      struct generate_label_map<vecS, Label, Vertex>
      { typedef std::vector<Vertex> type; };
  
      template <typename Label, typename Vertex>
      struct generate_label_map<mapS, Label, Vertex>
      { typedef std::map<Label, Vertex> type; };
  
      template <typename Label, typename Vertex>
      struct generate_label_map<multimapS, Label, Vertex>
      { typedef std::multimap<Label, Vertex> type; };
  
      template <typename Label, typename Vertex>
      struct generate_label_map<hash_mapS, Label, Vertex>
      { typedef boost::unordered_map<Label, Vertex> type; };
  
      template <typename Label, typename Vertex>
      struct generate_label_map<hash_multimapS, Label, Vertex>
      { typedef boost::unordered_multimap<Label, Vertex> type; };
  
      template <typename Selector, typename Label, typename Vertex>
      struct choose_custom_map {
          typedef typename generate_label_map<Selector, Label, Vertex>::type type;
      };
      //@}
  
      /**
       * Choose and instantiate an "associative" container. Note that this can
       * also choose vector.
       */
      template <typename Selector, typename Label, typename Vertex>
      struct choose_map {
          typedef typename mpl::eval_if<
              is_default<Selector>,
              choose_default_map<Label, Vertex>,
              choose_custom_map<Selector, Label, Vertex>
          >::type type;
      };
  
      /** @name Insert Labeled Vertex */
      //@{
      // Tag dispatch on random access containers (i.e., vectors). This function
      // basically requires a) that Container is vector<Label> and that Label
      // is an unsigned integral value. Note that this will resize the vector
      // to accommodate indices.
      template <typename Container, typename Graph, typename Label, typename Prop>
      std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
      insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p,
                            random_access_container_tag)
      {
          typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
  
          // If the label is out of bounds, resize the vector to accommodate.
          // Resize by 2x the index so we don't cause quadratic insertions over
          // time.
          if(l >= c.size()) {
              c.resize((l + 1) * 2);
          }
          Vertex v = add_vertex(p, g);
          c[l] = v;
          return std::make_pair(c[l], true);
      }
  
      // Tag dispatch on multi associative containers (i.e. multimaps).
      template <typename Container, typename Graph, typename Label, typename Prop>
      std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
      insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p,
                            multiple_associative_container_tag const&)
      {
          // Note that insertion always succeeds so we can add the vertex first
          // and then the mapping to the label.
          typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
          Vertex v = add_vertex(g);
          c.insert(std::make_pair(l, v));
          return std::make_pair(v, true);
      }
  
      // Tag dispatch on unique associative containers (i.e. maps).
      template <typename Container, typename Graph, typename Label, typename Prop>
      std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
      insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p,
                            unique_associative_container_tag)
      {
          // Here, we actually have to try the insertion first, and only add
          // the vertex if we get a new element.
          typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
          typedef typename Container::iterator Iterator;
          std::pair<Iterator, bool> x = c.insert(std::make_pair(l, Vertex()));
          if(x.second) {
              x.first->second = add_vertex(g);
              put(boost::vertex_all, g, x.first->second, p);
          }
          return std::make_pair(x.first->second, x.second);
      }
  
      // Dispatcher
      template <typename Container, typename Graph, typename Label, typename Prop>
      std::pair<typename graph_traits<Graph>::vertex_descriptor, bool>
      insert_labeled_vertex(Container& c, Graph& g, Label const& l, Prop const& p)
      { return insert_labeled_vertex(c, g, l, p, container_category(c)); }
      //@}
  
      /** @name Find Labeled Vertex */
      //@{
      // Tag dispatch for sequential maps (i.e., vectors).
      template <typename Container, typename Graph, typename Label>
      typename graph_traits<Graph>::vertex_descriptor
      find_labeled_vertex(Container const& c, Graph const&, Label const& l,
                          random_access_container_tag)
      { return l < c.size() ? c[l] : graph_traits<Graph>::null_vertex(); }
  
      // Tag dispatch for pair associative maps (more or less).
      template <typename Container, typename Graph, typename Label>
      typename graph_traits<Graph>::vertex_descriptor
      find_labeled_vertex(Container const& c, Graph const&, Label const& l,
                          associative_container_tag)
      {
          typename Container::const_iterator i = c.find(l);
          return i != c.end() ? i->second : graph_traits<Graph>::null_vertex();
      }
  
      // Dispatcher
      template <typename Container, typename Graph, typename Label>
      typename graph_traits<Graph>::vertex_descriptor
      find_labeled_vertex(Container const& c, Graph const& g, Label const& l)
      { return find_labeled_vertex(c, g, l, container_category(c)); }
      //@}
  
      /** @name Put Vertex Label */
      //@{
      // Tag dispatch on vectors.
      template <typename Container, typename Label, typename Graph, typename Vertex>
      bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v,
                            random_access_container_tag)
      {
          // If the element is already occupied, then we probably don't want to
          // overwrite it.
          if(c[l] == graph_traits<Graph>::null_vertex()) return false;
          c[l] = v;
          return true;
      }
  
      // Attempt the insertion and return its result.
      template <typename Container, typename Label, typename Graph, typename Vertex>
      bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v,
                            unique_associative_container_tag)
      { return c.insert(std::make_pair(l, v)).second; }
  
      // Insert the pair and return true.
      template <typename Container, typename Label, typename Graph, typename Vertex>
      bool put_vertex_label(Container& c, Graph const&, Label const& l, Vertex v,
                            multiple_associative_container_tag)
      {
          c.insert(std::make_pair(l, v));
          return true;
      }
  
      // Dispatcher
      template <typename Container, typename Label, typename Graph, typename Vertex>
      bool put_vertex_label(Container& c, Graph const& g, Label const& l, Vertex v)
      { return put_vertex_label(c, g, l, v, container_category(c)); }
      //@}
  
  } // namespace detail
  
  struct labeled_graph_class_tag { };
  
  /** @internal
   * This class is responsible for the deduction and declaration of type names
   * for the labeled_graph class template.
   */
  template <typename Graph, typename Label, typename Selector>
  struct labeled_graph_types {
      typedef Graph graph_type;
  
      // Label and maps
      typedef Label label_type;
      typedef typename graph_detail::choose_map<
          Selector, Label, typename graph_traits<Graph>::vertex_descriptor
      >::type map_type;
  };
  
  /**
   * The labeled_graph class is a graph adaptor that maintains a mapping between
   * vertex labels and vertex descriptors.
   *
   * @todo This class is somewhat redundant for adjacency_list<*, vecS>  if
   * the intended label is an unsigned int (and perhaps some other cases), but
   * it does avoid some weird ambiguities (i.e. adding a vertex with a label that
   * does not match its target index).
   *
   * @todo This needs to be reconciled with the named_graph, but since there is
   * no documentation or examples, its not going to happen.
   */
  template <typename Graph, typename Label, typename Selector = defaultS>
  class labeled_graph
      : protected labeled_graph_types<Graph, Label, Selector>
  {
      typedef labeled_graph_types<Graph, Label, Selector> Base;
  public:
      typedef labeled_graph_class_tag graph_tag;
  
      typedef typename Base::graph_type graph_type;
      typedef typename graph_traits<graph_type>::vertex_descriptor vertex_descriptor;
      typedef typename graph_traits<graph_type>::edge_descriptor edge_descriptor;
      typedef typename graph_traits<graph_type>::directed_category directed_category;
      typedef typename graph_traits<graph_type>::edge_parallel_category edge_parallel_category;
      typedef typename graph_traits<graph_type>::traversal_category traversal_category;
  
      typedef typename graph_traits<graph_type>::out_edge_iterator out_edge_iterator;
      typedef typename graph_traits<graph_type>::in_edge_iterator in_edge_iterator;
      typedef typename graph_traits<graph_type>::adjacency_iterator adjacency_iterator;
      typedef typename graph_traits<graph_type>::degree_size_type degree_size_type;
  
      typedef typename graph_traits<graph_type>::vertex_iterator vertex_iterator;
      typedef typename graph_traits<graph_type>::vertices_size_type vertices_size_type;
      typedef typename graph_traits<graph_type>::edge_iterator edge_iterator;
      typedef typename graph_traits<graph_type>::edges_size_type edges_size_type;
  
      typedef typename graph_type::graph_property_type graph_property_type;
      typedef typename graph_type::graph_bundled graph_bundled;
  
      typedef typename graph_type::vertex_property_type vertex_property_type;
      typedef typename graph_type::vertex_bundled vertex_bundled;
  
      typedef typename graph_type::edge_property_type edge_property_type;
      typedef typename graph_type::edge_bundled edge_bundled;
  
      typedef typename Base::label_type label_type;
      typedef typename Base::map_type map_type;
  
  public:
      labeled_graph(graph_property_type const& gp = graph_property_type())
          : _graph(gp), _map()
      { }
  
      labeled_graph(labeled_graph const& x)
          : _graph(x._graph), _map(x._map)
      { }
  
      // This constructor can only be used if map_type supports positional
      // range insertion (i.e. its a vector). This is the only case where we can
      // try to guess the intended labels for graph.
      labeled_graph(vertices_size_type n,
                    graph_property_type const& gp = graph_property_type())
          : _graph(n, gp), _map()
      {
          std::pair<vertex_iterator, vertex_iterator> rng = vertices(_graph);
          _map.insert(_map.end(), rng.first, rng.second);
      }
  
      // Construct a graph over n vertices, each of which receives a label from
      // the range [l, l + n). Note that the graph is not directly constructed
      // over the n vertices, but added sequentially. This constructor is
      // necessarily slower than the underlying counterpart.
      template <typename LabelIter>
      labeled_graph(vertices_size_type n, LabelIter l,
                    graph_property_type const& gp = graph_property_type())
          : _graph(gp)
      { while(n-- >= 0) add_vertex(*l++); }
  
      // Construct the graph over n vertices each of which has a label in the
      // range [l, l + n) and a property in the range [p, p + n).
      template <typename LabelIter, typename PropIter>
      labeled_graph(vertices_size_type n, LabelIter l, PropIter p,
                    graph_property_type const& gp = graph_property_type())
      { while(n-- >= 0) add_vertex(*l++, *p++); }
  
      labeled_graph& operator=(labeled_graph const& x) {
          _graph = x._graph;
          _map = x._map;
          return *this;
      }
  
      /** @name Graph Accessors */
      //@{
      graph_type& graph() { return _graph; }
      graph_type const& graph() const { return _graph; }
      //@}
  
      /**
       * Create a new label for the given vertex, returning false, if the label
       * cannot be created.
       */
      bool label_vertex(vertex_descriptor v, Label const& l)
      { return graph_detail::put_vertex_label(_map, _graph, l, v); }
  
      /** @name Add Vertex
       * Add a vertex to the graph, returning the descriptor. If the vertices
       * are uniquely labeled and the label already exists within the graph,
       * then no vertex is added, and the returned descriptor refers to the
       * existing vertex. A vertex property can be given as a parameter, if
       * needed.
       */
      //@{
      vertex_descriptor add_vertex(Label const& l) {
          return graph_detail::insert_labeled_vertex(
              _map, _graph, l, vertex_property_type()
              ).first;
      }
  
      vertex_descriptor add_vertex(Label const& l, vertex_property_type const& p)
      { return graph_detail::insert_labeled_vertex(_map, _graph, l, p).first; }
      //@}
  
      /** @name Insert Vertex
       * Insert a vertex into the graph, returning a pair containing the
       * descriptor of a vertex and a boolean value that describes whether or not
       * a new vertex was inserted. If vertices are not uniquely labeled, then
       * insertion will always succeed.
       */
      //@{
      std::pair<vertex_descriptor, bool> insert_vertex(Label const& l) {
          return graph_detail::insert_labeled_vertex(
              _map, _graph, l, vertex_property_type()
          );
      }
  
      std::pair<vertex_descriptor, bool>
      insert_vertex(Label const& l, vertex_property_type const& p)
      { return graph_detail::insert_labeled_vertex(_map, _graph, l, p); }
      //@}
  
      /** Remove the vertex with the given label. */
      void remove_vertex(Label const& l)
      { return boost::remove_vertex(vertex(l), _graph); }
  
      /** Return a descriptor for the given label. */
      vertex_descriptor vertex(Label const& l) const
      { return graph_detail::find_labeled_vertex(_map, _graph, l); }
  
  #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
      /** @name Bundled Properties */
      //@{
      // Lookup the requested vertex and return the bundle.
      vertex_bundled& operator[](Label const& l)
      { return _graph[vertex(l)]; }
  
      vertex_bundled const& operator[](Label const& l) const
      { return _graph[vertex(l)]; }
  
      // Delegate edge lookup to the underlying graph.
      edge_bundled& operator[](edge_descriptor e)
      { return _graph[e]; }
  
      edge_bundled const& operator[](edge_descriptor e) const
      { return _graph[e]; }
      //@}
  #endif
  
      /** Return a null descriptor */
      static vertex_descriptor null_vertex()
      { return graph_traits<graph_type>::null_vertex(); }
  
  private:
      graph_type _graph;
      map_type _map;
  };
  
  /**
   * The partial specialization over graph pointers allows the construction
   * of temporary labeled graph objects. In this case, the labels are destructed
   * when the wrapper goes out of scope.
   */
  template <typename Graph, typename Label, typename Selector>
  class labeled_graph<Graph*, Label, Selector>
      : protected labeled_graph_types<Graph, Label, Selector>
  {
      typedef labeled_graph_types<Graph, Label, Selector> Base;
  public:
      typedef labeled_graph_class_tag graph_tag;
  
      typedef typename Base::graph_type graph_type;
      typedef typename graph_traits<graph_type>::vertex_descriptor vertex_descriptor;
      typedef typename graph_traits<graph_type>::edge_descriptor edge_descriptor;
      typedef typename graph_traits<graph_type>::directed_category directed_category;
      typedef typename graph_traits<graph_type>::edge_parallel_category edge_parallel_category;
      typedef typename graph_traits<graph_type>::traversal_category traversal_category;
  
      typedef typename graph_traits<graph_type>::out_edge_iterator out_edge_iterator;
      typedef typename graph_traits<graph_type>::in_edge_iterator in_edge_iterator;
      typedef typename graph_traits<graph_type>::adjacency_iterator adjacency_iterator;
      typedef typename graph_traits<graph_type>::degree_size_type degree_size_type;
  
      typedef typename graph_traits<graph_type>::vertex_iterator vertex_iterator;
      typedef typename graph_traits<graph_type>::vertices_size_type vertices_size_type;
      typedef typename graph_traits<graph_type>::edge_iterator edge_iterator;
      typedef typename graph_traits<graph_type>::edges_size_type edges_size_type;
  
      typedef typename graph_type::vertex_property_type vertex_property_type;
      typedef typename graph_type::edge_property_type edge_property_type;
      typedef typename graph_type::graph_property_type graph_property_type;
      typedef typename graph_type::vertex_bundled vertex_bundled;
      typedef typename graph_type::edge_bundled edge_bundled;
  
      typedef typename Base::label_type label_type;
      typedef typename Base::map_type map_type;
  
      labeled_graph(graph_type* g)
          : _graph(g)
      { }
  
      /** @name Graph Access */
      //@{
      graph_type& graph() { return *_graph; }
      graph_type const& graph() const { return *_graph; }
      //@}
  
      /**
       * Create a new label for the given vertex, returning false, if the label
       * cannot be created.
       */
      bool label_vertex(vertex_descriptor v, Label const& l)
      { return graph_detail::put_vertex_label(_map, *_graph, l, v); }
  
      /** @name Add Vertex */
      //@{
      vertex_descriptor add_vertex(Label const& l) {
          return graph_detail::insert_labeled_vertex(
              _map, *_graph, l, vertex_property_type()
              ).first;
      }
  
      vertex_descriptor add_vertex(Label const& l, vertex_property_type const& p)
      { return graph_detail::insert_labeled_vertex(_map, *_graph, l, p).first; }
  
      std::pair<vertex_descriptor, bool> insert_vertex(Label const& l) {
          return graph_detail::insert_labeled_vertex(
              _map, *_graph, l, vertex_property_type()
          );
      }
      //@}
  
      /** Try to insert a vertex with the given label. */
      std::pair<vertex_descriptor, bool>
      insert_vertex(Label const& l, vertex_property_type const& p)
      { return graph_detail::insert_labeled_vertex(_map, *_graph, l, p); }
  
      /** Remove the vertex with the given label. */
      void remove_vertex(Label const& l)
      { return boost::remove_vertex(vertex(l), *_graph); }
  
      /** Return a descriptor for the given label. */
      vertex_descriptor vertex(Label const& l) const
      { return graph_detail::find_labeled_vertex(_map, *_graph, l); }
  
  #ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
      /** @name Bundled Properties */
      //@{
      // Lookup the requested vertex and return the bundle.
      vertex_bundled& operator[](Label const& l)
      { return (*_graph)[vertex(l)]; }
  
      vertex_bundled const& operator[](Label const& l) const
      { return (*_graph)[vertex(l)]; }
  
      // Delegate edge lookup to the underlying graph.
      edge_bundled& operator[](edge_descriptor e)
      { return (*_graph)[e]; }
  
      edge_bundled const& operator[](edge_descriptor e) const
      { return (*_graph)[e]; }
      //@}
  #endif
  
      static vertex_descriptor null_vertex()
      { return graph_traits<graph_type>::null_vertex(); }
  
  private:
      graph_type* _graph;
      map_type _map;
  };
  
  #define LABELED_GRAPH_PARAMS typename G, typename L, typename S
  #define LABELED_GRAPH labeled_graph<G,L,S>
  
  /** @name Labeled Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline bool label_vertex(typename LABELED_GRAPH::vertex_descriptor v,
                           typename LABELED_GRAPH::label_type const l,
                           LABELED_GRAPH& g)
  { return g.label_vertex(v, l); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertex_descriptor
  vertex_by_label(typename LABELED_GRAPH::label_type const l,
                  LABELED_GRAPH& g)
  { return g.vertex(l); }
  //@}
  
  /** @name Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  edge(typename LABELED_GRAPH::vertex_descriptor const& u,
       typename LABELED_GRAPH::vertex_descriptor const& v,
       LABELED_GRAPH const& g)
  { return edge(u, v, g.graph()); }
  
  // Labeled Extensions
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  edge_by_label(typename LABELED_GRAPH::label_type const& u,
                typename LABELED_GRAPH::label_type const& v,
                LABELED_GRAPH const& g)
  { return edge(g.vertex(u), g.vertex(v), g); }
  //@}
  
  /** @name Incidence Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<
      typename LABELED_GRAPH::out_edge_iterator,
      typename LABELED_GRAPH::out_edge_iterator>
  out_edges(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return out_edges(v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::degree_size_type
  out_degree(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return out_degree(v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertex_descriptor
  source(typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH const& g)
  { return source(e, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertex_descriptor
  target(typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH const& g)
  { return target(e, g.graph()); }
  //@}
  
  /** @name Bidirectional Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<
      typename LABELED_GRAPH::in_edge_iterator,
      typename LABELED_GRAPH::in_edge_iterator>
  in_edges(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return in_edges(v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::degree_size_type
  in_degree(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return in_degree(v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::degree_size_type
  degree(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return degree(v, g.graph()); }
  //@}
  
  /** @name Adjacency Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<
      typename LABELED_GRAPH::adjacency_iterator,
      typename LABELED_GRAPH::adjacency_iterator>
  adjacenct_vertices(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH const& g)
  { return adjacent_vertices(v, g.graph()); }
  //@}
  
  /** @name VertexListGraph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<
      typename LABELED_GRAPH::vertex_iterator,
      typename LABELED_GRAPH::vertex_iterator>
  vertices(LABELED_GRAPH const& g)
  { return vertices(g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertices_size_type
  num_vertices(LABELED_GRAPH const& g)
  { return num_vertices(g.graph()); }
  //@}
  
  /** @name EdgeListGraph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<
      typename LABELED_GRAPH::edge_iterator,
      typename LABELED_GRAPH::edge_iterator>
  edges(LABELED_GRAPH const& g)
  { return edges(g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::edges_size_type
  num_edges(LABELED_GRAPH const& g)
  { return num_edges(g.graph()); }
  //@}
  
  /** @internal @name Property Lookup */
  //@{
  namespace graph_detail {
      struct labeled_graph_vertex_property_selector {
          template <class LabeledGraph, class Property, class Tag>
          struct bind_ {
              typedef typename LabeledGraph::graph_type Graph;
              typedef property_map<Graph, Tag> PropertyMap;
              typedef typename PropertyMap::type type;
              typedef typename PropertyMap::const_type const_type;
          };
      };
  
      struct labeled_graph_edge_property_selector {
          template <class LabeledGraph, class Property, class Tag>
          struct bind_ {
              typedef typename LabeledGraph::graph_type Graph;
              typedef property_map<Graph, Tag> PropertyMap;
              typedef typename PropertyMap::type type;
              typedef typename PropertyMap::const_type const_type;
          };
      };
  }
  
  template <>
  struct vertex_property_selector<labeled_graph_class_tag> {
      typedef graph_detail::labeled_graph_vertex_property_selector type;
  };
  
  template <>
  struct edge_property_selector<labeled_graph_class_tag> {
      typedef graph_detail::labeled_graph_edge_property_selector type;
  };
  //@}
  
  /** @name Property Graph */
  //@{
  template <LABELED_GRAPH_PARAMS, typename Prop>
  inline typename property_map<LABELED_GRAPH, Prop>::type
  get(Prop p, LABELED_GRAPH& g)
  { return get(p, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS, typename Prop>
  inline typename property_map<LABELED_GRAPH, Prop>::const_type
  get(Prop p, LABELED_GRAPH const& g)
  { return get(p, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS, typename Prop, typename Key>
  inline typename property_traits<
      typename property_map<typename LABELED_GRAPH::graph_type, Prop>::const_type
  >::value_type
  get(Prop p, LABELED_GRAPH const& g, const Key& k)
  { return get(p, g.graph(), k); }
  
  template <LABELED_GRAPH_PARAMS, typename Prop, typename Key, typename Value>
  inline void
  put(Prop p, LABELED_GRAPH& g, Key const& k, Value const& v)
  { put(p, g.graph(), k, v); }
  //@}
  
  /** @name Mutable Graph */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  add_edge(typename LABELED_GRAPH::vertex_descriptor const& u,
           typename LABELED_GRAPH::vertex_descriptor const& v,
           LABELED_GRAPH& g)
  { return add_edge(u, v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  add_edge(typename LABELED_GRAPH::vertex_descriptor const& u,
           typename LABELED_GRAPH::vertex_descriptor const& v,
           typename LABELED_GRAPH::edge_property_type const& p,
           LABELED_GRAPH& g)
  { return add_edge(u, v, p, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  clear_vertex(typename LABELED_GRAPH::vertex_descriptor v, LABELED_GRAPH& g)
  { return clear_vertex(v, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  remove_edge(typename LABELED_GRAPH::edge_descriptor e, LABELED_GRAPH& g)
  { return remove_edge(e, g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  remove_edge(typename LABELED_GRAPH::vertex_descriptor u,
              typename LABELED_GRAPH::vertex_descriptor v,
              LABELED_GRAPH& g)
  { return remove_edge(u, v, g.graph()); }
  
  // Labeled extensions
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  add_edge_by_label(typename LABELED_GRAPH::label_type const& u,
                    typename LABELED_GRAPH::label_type const& v,
                    LABELED_GRAPH& g)
  { return add_edge(g.vertex(u), g.vertex(v), g); }
  
  template <LABELED_GRAPH_PARAMS>
  inline std::pair<typename LABELED_GRAPH::edge_descriptor, bool>
  add_edge_by_label(typename LABELED_GRAPH::label_type const& u,
                    typename LABELED_GRAPH::label_type const& v,
                    typename LABELED_GRAPH::edge_property_type const& p,
                    LABELED_GRAPH& g)
  { return add_edge(g.vertex(u), g.vertex(v), p, g); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  clear_vertex_by_label(typename LABELED_GRAPH::label_type const& l, LABELED_GRAPH& g)
  { clear_vertex(g.vertex(l), g.graph()); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  remove_edge_by_label(typename LABELED_GRAPH::label_type const& u,
                       typename LABELED_GRAPH::label_type const& v,
                       LABELED_GRAPH& g)
  { remove_edge(g.vertex(u), g.vertex(v), g.graph()); }
  //@}
  
  /** @name Labeled Mutable Graph
   * The labeled mutable graph hides the add_ and remove_ vertex functions from
   * the mutable graph concept. Note that the remove_vertex is hidden because
   * removing the vertex without its key could leave a dangling reference in
   * the map.
   */
  //@{
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertex_descriptor
  add_vertex(typename LABELED_GRAPH::label_type const& l,
             LABELED_GRAPH& g)
  { return g.add_vertex(l); }
  
  // MutableLabeledPropertyGraph::add_vertex(l, vp, g)
  template <LABELED_GRAPH_PARAMS>
  inline typename LABELED_GRAPH::vertex_descriptor
  add_vertex(typename LABELED_GRAPH::label_type const& l,
             typename LABELED_GRAPH::vertex_property_type const& p,
             LABELED_GRAPH& g)
  { return g.add_vertex(l, p); }
  
  template <LABELED_GRAPH_PARAMS>
  inline void
  remove_vertex(typename LABELED_GRAPH::label_type const& l, LABELED_GRAPH& g)
  { g.remove_vertex(l); }
  //@}
  
  #undef LABELED_GRAPH_PARAMS
  #undef LABELED_GRAPH
  
  } // namespace boost
  
  // Pull the labeled graph traits
  #include <boost/graph/detail/labeled_graph_traits.hpp>
  
  #endif // BOOST_GRAPH_LABELED_GRAPH_HPP
  