Boost logo

Boost :

From: Jens Müller (jens.mueller_at_[hidden])
Date: 2007-08-21 03:44:01


Jens Müller wrote:
>
> Sorry, forgot that (was quite busy the last month). So, I'll see if I
> can turn my "make bidirected" adapter into an undirected adapter. Should
> be quite the same, except that the both directions are equal, and edge
> indices don't need to get adapted, and probably some other small stuff ...

Something like the attached one, if someone wanna take a look ...

Nothing fancy, and probably with some bugs ...

Jens


//
//=======================================================================
// Copyright 2007 University of Karlsruhe
// Author: Jens Mueller
//
// Based on boost/graph/reverse_graph.hpp
// (C) Copyright David Abrahams 2000.
// 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 undirected_graph_HPP_893441
#define undirected_graph_HPP_893441

#include <boost/type_traits/is_convertible.hpp>
#include <boost/graph/properties.hpp>

namespace boost {

  /**
    This is a tag to distinguish the undirected graph adapter adapter from
    other graph implementations.
  
    It is used for tag dispatching purposes.
  */
  struct undirected_graph_tag {};
  
  namespace detail {
    /**
      This template provides the edge iterator for the class (through the bind_ member template).
    
    \param isEdgeList Is the graph an EdgeListGraph? If not, no edge iterator is defined.
    */
    template<bool isEdgeList> struct choose_undi_edge_iter {};
    template<> struct choose_undi_edge_iter<true> {
      template<class Self> struct bind_ {
        class edge_iterator
          : public boost::iterator_facade<edge_iterator,
                                  typename Self::edge_descriptor const,
                                  boost::forward_traversal_tag,
                                  typename Self::edge_descriptor const>
          {
          public:
            edge_iterator(typename boost::graph_traits<typename Self::base_type>::edge_iterator iter,
                          bool reverse_direction)
              : m_iter(iter), m_reverse_direction(reverse_direction) {}
            edge_iterator() {}
            
          private:
            typename Self::edge_descriptor dereference() const
              // { return std::make_pair(*m_iter, m_reverse_direction); }
              { return typename Self::edge_descriptor(*m_iter, m_reverse_direction); }
            bool equal(const edge_iterator& other) const
              { return // (m_reverse_direction == other.m_reverse_direction) &&
                     (m_iter == other.m_iter); }
            
            /* void increment() {
              if (m_reverse_direction==false)
                m_reverse_direction = true;
              else {
                ++m_iter;
                m_reverse_direction=false;
              }
            } */
            void increment() {
              ++m_iter;
            }
            
            
            typename boost::graph_traits<typename Self::base_type>::edge_iterator
                m_iter;
            bool m_reverse_direction;
            friend class boost::iterator_core_access;
          };
        
        typedef edge_iterator type;
      };
    };
    
    template<> struct choose_undi_edge_iter<false> {
      template<class Self> struct bind_ {
        typedef void type;
      };
    };
    
    /**
      The out edge iterator class for the undirected graph adapter
    
    \param Self the undirected_graph for which this iterator class is used.
    */
    template<class Self>
    class undirected_out_edge_iterator
      : public boost::iterator_facade<undirected_out_edge_iterator<Self>,
                                  typename Self::edge_descriptor const,
                                  boost::forward_traversal_tag,
                                  typename Self::edge_descriptor const>
    {
      public:
        /**
         Constructs the iterator.
        \param cur_out The current out edge the iterator points at
        \param cur_in The current in edge the iterator points at
        \param in_begin The first in edge - used to switch to after the last out edge
        \param out_end The end iterator for out edges - switch to in edges after it
        \param out_p Is the iterator currently iterating over out edges?
        */
        undirected_out_edge_iterator(
          typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            cur_out,
          typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            cur_in,
          typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            in_begin,
          typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            out_end,
          bool out_p)
        : m_cur_out(cur_out), m_cur_in(cur_in), m_in_begin(in_begin),
        m_out_end(out_end), m_out_p(out_p)
        {
          if (m_out_p) {
            if (m_cur_out==m_out_end)
            {
              m_out_p = false;
              m_cur_in = m_in_begin;
            }
          }
        } // constructor
                    
                    
        /**
         Copy constructor
        */
        undirected_out_edge_iterator(const undirected_out_edge_iterator<Self> & other)
        : m_cur_out(other.m_cur_out), m_cur_in(other.m_cur_in),
                    m_in_begin(other.m_in_begin),
                    m_out_end(other.m_out_end), m_out_p(other.m_out_p) { }
                    
        
        /**
         Default constructor. Does nothing useful, but is required.
        */
        undirected_out_edge_iterator() {}
      private:
        /**
         Dereferences the iterator
        
        \return edge descriptor at which the iterator is pointing
        */
        typename Self::edge_descriptor dereference() const
        {
          if (m_out_p)
            return typename Self::edge_descriptor(*m_cur_out, false);
          else
            return typename Self::edge_descriptor(*m_cur_in, true);
        }
        
        /**
        Compares the iterator to another iterator.
        
        \param other The other iterator
        */
        bool equal (const undirected_out_edge_iterator& other) const
        {
          if (m_out_p != other.m_out_p)
          { return false; }
            
          
          if (m_out_p)
          { return m_cur_out==other.m_cur_out; }
          else
          { return m_cur_in==other.m_cur_in; }
        }
        
        /**
         Increments the iterator.
        */
        void increment()
        {
          if (m_out_p) {
            ++m_cur_out;
            if (m_cur_out==m_out_end)
            {
              m_out_p = false;
              m_cur_in = m_in_begin;
            }
          } else {
            ++m_cur_in;
          }
        }
        
        typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            m_cur_out; /// current out edge
        typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            m_cur_in; /// current in edge
        typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            m_in_begin; /// first in edge
        typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            m_out_end; /// end iterator for out edges
        bool m_out_p; /// true, if the iterator is currently pointing at an out edge
        
        friend class boost::iterator_core_access;
    }; // class undirected_out_edge_iterator
    
    /**
    The in edge iterator class for the bidirected graph adapter.
    
    Everything is the same as for the out edge iterator.
    
    \param Self the bidirected_graph for which this iterator class is used.
     */
    template<class Self>
    class undirected_in_edge_iterator
      : public boost::iterator_facade<bidirected_in_edge_iterator<Self>,
                                  typename Self::edge_descriptor const,
                                  boost::forward_traversal_tag,
                                  typename Self::edge_descriptor const>
    {
      public:
        undirected_in_edge_iterator(
          typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            cur_out,
          typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            cur_in,
          typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            in_begin,
          typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            out_end,
          bool out_p)
        : m_cur_out(cur_out), m_cur_in(cur_in), m_in_begin(in_begin),
                    m_out_end(out_end), m_out_p(out_p)
        {
          if (m_out_p) {
            if (m_cur_out==m_out_end)
            {
              m_out_p = false;
              m_cur_in = m_in_begin;
            }
          }
        }
      private:
        typename Self::edge_descriptor dereference() const
        {
          if (m_out_p)
            return typename Self::edge_descriptor(*m_cur_out, true); // reverse from oe iter
          else
            return typename Self::edge_descriptor(*m_cur_in, false); // reverse from oe iter
        }
        
        bool equal (const undirected_in_edge_iterator& other) const
        {
          if (m_out_p != other.m_out_p)
            return false;
          
          if (m_out_p)
            return m_cur_out==other.m_cur_out;
          else
            return m_cur_in==other.m_cur_in;
        }
        
        void increment()
        {
          if (m_out_p) {
            ++m_cur_out;
            if (m_cur_out==m_out_end)
            {
              m_out_p = false;
              m_cur_in = m_in_begin;
            }
          } else {
            ++m_cur_in;
          }
        }
        
        typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            m_cur_out;
        typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            m_cur_in;
        typename boost::graph_traits<typename Self::base_type>::in_edge_iterator
            m_in_begin;
        typename boost::graph_traits<typename Self::base_type>::out_edge_iterator
            m_out_end;
        bool m_out_p;
        
        friend class boost::iterator_core_access;
    };
  }; // namespace detail

  namespace detail {
    template<class Self> // Self: the corresponding bidirected_graph
    class undi_graph_vertex_descriptor
    {
    public: // hmpf ...
      typename boost::graph_traits<typename Self::base_type>::vertex_descriptor
          m_vertex;
      
    public:
      undi_graph_vertex_descriptor
        (const typename boost::graph_traits<typename Self::base_type>::vertex_descriptor v)
        : m_vertex(v) {}
      
      undi_graph_vertex_descriptor() {}
      
      operator typename boost::graph_traits<typename Self::base_type>::vertex_descriptor () const
      { return m_vertex; }
      
      bool operator==(undi_graph_vertex_descriptor<Self> other)
      {
        return (m_vertex == other.m_vertex);
      }
    }; // class undi_graph_vertex_descriptor
    
    template<class Self> // Self: the corresponding bidirected_graph
    class undi_graph_edge_descriptor
    {
    public: // hmpf ...
      typename boost::graph_traits<typename Self::base_type>::edge_descriptor
          first;
      bool second;
      
    public:
      undi_graph_edge_descriptor
        (const typename boost::graph_traits<typename Self::base_type>::edge_descriptor e,
         bool reverse)
        : first(e), second(reverse) {}
      
      undi_graph_edge_descriptor() {}
      
      bool operator==(undi_graph_edge_descriptor<Self> other)
      {
        return (first == other.first);
      }
      
      bool operator!=(undi_graph_edge_descriptor<Self> other)
      {
        return (first != other.first);
      }
    }; // class undi_graph_edge_descriptor
    
    
    template<class Self, class PMap>
    typename boost::property_traits<PMap>::value_type
    get(PMap p, undi_graph_vertex_descriptor<Self> u) {
      return get(p, u.m_vertex);
    }
    
    template<class Self> // Self: the corresponding undirected_graph
    class undi_graph_vertex_iterator
      : public boost::iterator_facade<undi_graph_vertex_iterator<Self>,
                              typename Self::vertex_descriptor const,
                              boost::forward_traversal_tag,
                              typename Self::vertex_descriptor const>
    {
    public:
      undi_graph_vertex_iterator
          (typename boost::graph_traits<typename Self::base_type>::vertex_iterator iter)
        : m_iter(iter) {}
      undi_graph_vertex_iterator() {}
      
    private:
      typename Self::vertex_descriptor dereference() const
        { return *m_iter; }
      
      bool equal(const undi_graph_vertex_iterator& other) const
        { return (m_iter == other.m_iter); }
      
      void increment() {
        ++m_iter;
      }
      
      typename boost::graph_traits<typename Self::base_type>::vertex_iterator
          m_iter;
      friend class boost::iterator_core_access;
    }; // class undi_graph_vertex_iterator
    
  }; //namespace detail
  
  
  
  
  
  
  
  
  
  
  
  
  /**
   Adapter class to make a bidirectional graph (edges accessible in both directions) undirected,
   as required e.g. by BFS algorithms.
  
  \param BidirectionalGraph Type of the underlying bidirectional graph.
  \param GraphRef Type of the reference to the underlying graph.
  */
  template<class BidirectionalGraph, class GraphRef = /* const */ BidirectionalGraph&>
  class undirected_graph {
      typedef undirected_graph<BidirectionalGraph, GraphRef> Self;
      typedef boost::graph_traits<BidirectionalGraph> Traits;
    public:
      typedef BidirectionalGraph base_type;
      
      /**
      Constructs a undirected_graph from a given base graph.
      \param g a reference to the base graph
      */
      undirected_graph(GraphRef g) : m_g(g) {}
      
      // Graph requirements
      //typedef typename Traits::vertex_descriptor vertex_descriptor;
      typedef detail::undi_graph_vertex_descriptor<Self> vertex_descriptor;
      
      // /// \todo
      // typedef std::pair<typename Traits::edge_descriptor, bool>
      // edge_descriptor; // bool: original direction = true, reversed = false;
      typedef detail::undi_graph_edge_descriptor<Self> edge_descriptor;
      
      
      typedef boost::undirected_tag directed_category;
      typedef boost::allow_parallel_edge_tag edge_parallel_category;
      typedef typename Traits::traversal_category traversal_category;
      /// \todo maybe something better is needed here ...
      
      // IncidenceGraph requirements
      typedef typename detail::undirected_out_edge_iterator<Self>
          out_edge_iterator;
      typedef typename Traits::degree_size_type degree_size_type;
      
      // BidirectionalGraph requirements
      typedef typename detail::undirected_in_edge_iterator<Self>
          in_edge_iterator;
      
      
      // AdjacencyGraph requirements
      /// \todo
      typedef void adjacency_iterator;
      
      //VertexListGraph requirements
      //typedef typename Traits::vertex_iterator vertex_iterator;
      typedef detail::undi_graph_vertex_iterator<Self> vertex_iterator;
      typedef typename Traits::vertices_size_type vertices_size_type;
      
      
      // EdgeListGraph requirements
      enum { is_edge_list = boost::is_convertible<traversal_category,
        edge_list_graph_tag>::value };
      typedef detail::choose_undi_edge_iter<is_edge_list> ChooseEdgeIter;
      typedef typename ChooseEdgeIter::
          template bind_<Self>::type edge_iterator;
      typedef typename Traits::edges_size_type edges_size_type;
      
      // properties ...
      
      typedef undirected_graph_tag graph_tag;
      
      // Bundled properties support - TODO
      
      static vertex_descriptor null_vertex()
      { return Traits::null_vertex(); }
      
      // private:
      GraphRef m_g;
  };
  
  /*
  template<typename Graph, typename GraphRef>
  struct boost::vertex_bundle_type<bidirected_graph<Graph, GraphRef> >
    : boost::vertex_bundle_type<Graph> { };

  template<typename Graph, typename GraphRef>
  struct boost::edge_bundle_type<bidirected_graph<Graph, GraphRef> >
   : boost::edge_bundle_type<Graph> { };
  */
  
  /**
  Helper function to create an undirected_graph.
  \param BidirectionalGraph Type of the underlying graph. Normally gets inferred.
  \param g The underlying graph.
  \return An undirected graph adapter for the given graph.
  */
  template<class BidirectionalGraph>
  inline undirected_graph<BidirectionalGraph>
  make_undirected_graph(const BidirectionalGraph& g)
  {
    return undirected_graph<BidirectionalGraph>(g);
  }
  
  
  template<class BidirectionalGraph>
  inline undirected_graph<BidirectionalGraph, BidirectionalGraph&>
  make_undirected_graph(BidirectionalGraph& g)
  {
    return undirected_graph<BidirectionalGraph, BidirectionalGraph&>(g);
  }
  
  
  /**
   Get the vertices of the undirected graph
  \param g The undirected graph
  \return a pair of iterators for the vertices of the graph.
  */
  template<class BidirectionalGraph, class GRef>
  std::pair<typename undirected_graph<BidirectionalGraph, GRef>::vertex_iterator,
            typename undirected_graph<BidirectionalGraph, GRef>::vertex_iterator>
  vertices(const undirected_graph<BidirectionalGraph,GRef>& g)
  {
    return vertices(g.m_g);
  }
  
  /**
  Get the edges of the undirected graph
  \param g The bidirected graph
  \return a pair of iterators for the edges of the graph. Each edge of the underlying graph
    occurs just once, in its original direction.
   */
  template <class BidirectionalGraph, class GRef>
  std::pair<typename undirected_graph<BidirectionalGraph, GRef>::edge_iterator,
            typename undirected_graph<BidirectionalGraph, GRef>::edge_iterator>
  edges(const undirected_graph<BidirectionalGraph,GRef>& g)
  {
    return std::make_pair(
        typename undirected_graph<BidirectionalGraph,GRef>::edge_iterator(
          edges(g.m_g).first, false),
        typename undirected_graph<BidirectionalGraph,GRef>::edge_iterator(
          edges(g.m_g).second, false));
  }
  
  /**
  Get the out edges of a specific vertex
  \param g The undirected graph
  \param u The vertex
  \return a pair of iterators for the out edges of u. These contain the out edges in
  their original direction and the in edges in reversed direction.
   */
  template <class BidirectionalGraph, class GRef>
  std::pair<typename undirected_graph<BidirectionalGraph>::out_edge_iterator,
            typename undirected_graph<BidirectionalGraph>::out_edge_iterator>
  // out_edges(const typename BidirectionalGraph::vertex_descriptor u,
  // const bidirected_graph<BidirectionalGraph,GRef>& g)
  out_edges(const detail::undi_graph_vertex_descriptor<
                   boost::undirected_graph<BidirectionalGraph, GRef> > u,
            const undirected_graph<BidirectionalGraph,GRef>& g)
  {
    return std::make_pair(
        typename undirected_graph<BidirectionalGraph,GRef>::out_edge_iterator(
          out_edges(u.m_vertex, g.m_g).first,
          in_edges(u.m_vertex, g.m_g).first, // dummy
          in_edges(u.m_vertex, g.m_g).first,
          out_edges(u.m_vertex, g.m_g).second,
          true),
        typename undirected_graph<BidirectionalGraph,GRef>::out_edge_iterator(
          out_edges(u.m_vertex, g.m_g).second, // dummy
          in_edges(u.m_vertex, g.m_g).second, // cur_in == end
          in_edges(u.m_vertex, g.m_g).first, // not needed ...
          out_edges(u.m_vertex, g.m_g).second, // not needed ...
          false)
        );
  }
  
  /**
  Get the in edges of a specific vertex
  \param g The undirected graph
  \param u The vertex
  \return a pair of iterators for the out edges of u. These contain the in edges in
  their original direction and the out edges in reversed direction.
     */
  template <class BidirectionalGraph, class GRef>
  std::pair<typename undirected_graph<BidirectionalGraph>::in_edge_iterator,
            typename undirected_graph<BidirectionalGraph>::in_edge_iterator>
  in_edges(const typename BidirectionalGraph::vertex_descriptor u,
            const undirected_graph<BidirectionalGraph,GRef>& g)
  {
    return std::make_pair(
        typename undirected_graph<BidirectionalGraph,GRef>::in_edge_iterator(
          out_edges(u, g.m_g).first,
          in_edges(u, g.m_g).first, // dummy
          in_edges(u, g.m_g).first,
          out_edges(u, g.m_g).second,
          true),
        typename undirected_graph<BidirectionalGraph,GRef>::in_edge_iterator(
          out_edges(u, g.m_g).second, // dummy
          in_edges(u, g.m_g).second, // cur_in == end
          in_edges(u, g.m_g).first, // not needed ...
          out_edges(u, g.m_g).second, // not needed ...
          false)
        );
  }
  
  template <class BidirectionalGraph, class GRef>
  inline typename undirected_graph<BidirectionalGraph, GRef>::vertices_size_type
  num_vertices(const undirected_graph<BidirectionalGraph,GRef>& g)
  {
      return num_vertices(g.m_g);
  }
  
  /**
   Get the number of edges. This is the number of edges of the underlying graph.
  */
  template <class BidirectionalGraph, class GRef>
  inline typename undirected_graph<BidirectionalGraph, GRef>::edges_size_type
  num_edges(const undirected_graph<BidirectionalGraph, GRef>& g)
  {
      return num_edges(g.m_g);
  }
  
  template <class BidirectionalGraph, class GRef>
  inline typename undirected_graph<BidirectionalGraph, GRef>::degree_size_type
  out_degree(const typename undirected_graph<BidirectionalGraph, GRef>::vertex_descriptor u,
            const undirected_graph<BidirectionalGraph, GRef>& g)
  {
      return in_degree(u, g.m_g)+out_degree(u, g.m_g);
  }
  
  template <class BidirectionalGraph, class GRef>
  inline typename undirected_graph<BidirectionalGraph, GRef>::vertex_descriptor
  source(const typename undirected_graph<BidirectionalGraph, GRef>::edge_descriptor e,
         const undirected_graph<BidirectionalGraph, GRef>& g)
  {
    return e.second ? target(e.first, g.m_g) : source(e.first, g.m_g);
  }
  
  template <class BidirectionalGraph, class GRef>
  inline typename undirected_graph<BidirectionalGraph, GRef>::vertex_descriptor
  target(const typename undirected_graph<BidirectionalGraph, GRef>::edge_descriptor e,
         const undirected_graph<BidirectionalGraph, GRef>& g)
  {
    return e.second ? source(e.first, g.m_g) : target(e.first, g.m_g);
  }
  
  
  template <class BidirectionalGraph, class GRef>
  inline std::pair<typename undirected_graph<BidirectionalGraph, GRef>::edge_descriptor, bool>
  edge(const typename BidirectionalGraph::vertex_descriptor u,
      const typename BidirectionalGraph::vertex_descriptor v,
      const undirected_graph<BidirectionalGraph,GRef>& g)
  {
    std::pair<typename BidirectionalGraph::edge_descriptor, bool> normal
        = edge(u, v, g.m_g);
    if (normal.second)
      return std::make_pair(typename undirected_graph<BidirectionalGraph, GRef>::edge_descriptor(normal.first, true), true);
    
    std::pair<typename BidirectionalGraph::edge_descriptor, bool> reverse
        = edge(v, u, g.m_g);
    // if (reverse.second)
      return std::make_pair(typename undirected_graph<BidirectionalGraph, GRef>::edge_descriptor(reverse.first, false), reverse.second);
     
      /* in case no edge is found, just return *anything* with false as second */
  }
  
  
  
  
  
  
  namespace detail {
    template<class BidiGraph>
    class undi_graph_edge_index_map {
      typedef typename BidiGraph::base_type Graph;
      typedef typename property_map<Graph, edge_index_t>::type PMap;

      PMap pm_;
    public:
      typedef typename BidiGraph::edge_descriptor key_type;
      typedef typename property_traits<PMap>::value_type value_type;
      typedef typename property_traits<PMap>::reference reference;
      typedef boost::readable_property_map_tag category;
        
      value_type get_(key_type key)
      {
        value_type original_value = get(pm_, key.first);
        // return original_value + (key.second ? 0 : 1);
        return original_value;
      }

      undi_graph_edge_index_map(PMap pm) : pm_(pm) {}
    }; // class
    
    template<class BidiGraph>
    typename undi_graph_edge_index_map<BidiGraph>::value_type
    get(undi_graph_edge_index_map<BidiGraph> pm,
        typename undi_graph_edge_index_map<BidiGraph>::key_type key)
    { return pm.get_(key); }
  
    template<class BidiGraph, class Tag>
    class undi_graph_edge_property_map {
      typedef typename BidiGraph::base_type Graph;
      typedef typename property_map<Graph, Tag>::type PMap;

      PMap pm_;
    public:
      typedef typename BidiGraph::edge_descriptor key_type;
      typedef typename property_traits<PMap>::value_type value_type;
      typedef typename property_traits<PMap>::reference reference;
      typedef boost::readable_property_map_tag category;

      value_type get_(key_type key) { return get(pm_, key.first); }
      
      undi_graph_edge_property_map(PMap pm) : pm_(pm) {}
    }; // class

    template<class BidiGraph, class Tag>
    typename undi_graph_edge_property_map<BidiGraph, Tag>::value_type
    get(undi_graph_edge_property_map<BidiGraph, Tag> pm,
        typename undi_graph_edge_property_map<BidiGraph, Tag>::key_type key)
    { return pm.get_(key); }
    
    struct undirected_graph_edge_property_selector {
      template <class BidiGraph, class PropertyTag>
      struct bind_ {
        typedef typename BidiGraph::base_type Graph;
        typedef undi_graph_edge_property_map<BidiGraph, PropertyTag> PMap;
        typedef PMap type;
        typedef PMap const_type;
      };
      
      template <class BidiGraph>
      struct bind_<BidiGraph, edge_index_t> {
        typedef typename BidiGraph::base_type Graph;
        typedef undi_graph_edge_index_map<BidiGraph> PMap;
        typedef PMap type;
        typedef PMap const_type;
      };
    }; // struct undirected_graph_edge_property_selector

    struct undirected_graph_vertex_property_selector {
      template <class BidiGraph, class PropertyTag>
          struct bind_ {
            typedef typename BidiGraph::base_type Graph;
            typedef property_map<Graph, PropertyTag> PMap;
            typedef typename PMap::type type;
            typedef typename PMap::const_type const_type;
          };
    };

    template <class Graph, class PropertyTag>
    struct undi_vertex_property_map {
      typedef undirected_graph_vertex_property_selector Selector;
      typedef Selector::template bind_<Graph, PropertyTag> Bind;
      typedef typename Bind::type type;
      typedef typename Bind::const_type const_type;
    };

    template <class Graph, class PropertyTag>
    struct undi_edge_property_map {
      typedef undirected_graph_edge_property_selector Selector;
      typedef Selector::template bind_<Graph, PropertyTag> Bind;
      typedef typename Bind::type type;
      typedef typename Bind::const_type const_type;
    };

    struct undi_choose_vertex_pm {
      template <class Graph, class Property> // Graph is an undirected_graph!
      struct bind_ {
        typedef undi_vertex_property_map<Graph, Property> type;
      };
    };
    struct undi_choose_edge_pm {
      template <class Graph, class Property> // Graph is an undirected_graph!
          struct bind_ {
            typedef undi_edge_property_map<Graph, Property> type;
          };
    };
    
    template<class Kind>
    struct undi_pm_kind_selector { };
    
    template <> struct undi_pm_kind_selector<vertex_property_tag> {
      typedef undi_choose_vertex_pm type;
    };
    template <> struct undi_pm_kind_selector<edge_property_tag> {
      typedef undi_choose_edge_pm type;
    };
  } // namespace detail
  
  template <class BidirectionalGraph, class GRef, class Property>
  struct property_map<undirected_graph<BidirectionalGraph, GRef>, Property>{
  private:
    typedef undirected_graph<BidirectionalGraph, GRef> Graph;
    typedef typename property_kind<Property>::type Kind;
    typedef typename detail::undi_pm_kind_selector<Kind>::type Selector;
    typedef typename Selector::template bind_<Graph, Property> Bind;
    typedef typename Bind::type Map;
  public:
    typedef typename Map::type type;
    typedef typename Map::const_type const_type;
  };

  namespace detail {
    template <class BidirGraph, class GRef, class Property>
    typename property_map<BidirGraph, Property>::type
    undirected_graph_get_pmap_dispatch(Property p,
            const undirected_graph<BidirGraph,GRef>& g, vertex_property_tag)
    {
      return get(p, g.m_g);
    }
    
    template <class BidirGraph, class GRef, class Property>
    typename property_map<BidirGraph, Property>::type
    undirected_graph_get_pmap_dispatch(Property p,
            const undirected_graph<BidirGraph,GRef>& g, edge_property_tag)
    {
      return undi_graph_edge_property_map<BidirGraph, Property>
          (get(p, g.m_g));
    }
  } // namespace detail
  
  template <class BidirGraph, class GRef, class Property>
  typename property_map<BidirGraph, Property>::type
  get(Property p, const undirected_graph<BidirGraph,GRef>& g) {
    return detail::undirected_graph_get_pmap_dispatch(p, g,
        typename property_kind<Property>::type());
  }
  
  template <class BidirGraph, class GRef>
  typename property_map<undirected_graph<BidirGraph,GRef>, edge_index_t>::type
  get(edge_index_t p, const undirected_graph<BidirGraph,GRef>& g) {
    return detail::undi_graph_edge_index_map<undirected_graph<BidirGraph,GRef> >(get(p, g.m_g));
  }
  
  
 
} // namespace boost
#endif


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk