// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GRAPH_DIRECTED_GRAPH_HPP
#define BOOST_GRAPH_DIRECTED_GRAPH_HPP

#include <boost/utility.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>

namespace boost
{
struct directed_graph_tag { };

/**
 * The directed_graph class template is a simplified version of the BGL
 * adjacency list. This class is provided for ease of use, but may not
 * perform as well as custom-defined adjacency list classes. Instances of
 * this template model the BidirectionalGraph, VertexIndexGraph, and
 * EdgeIndexGraph concepts. The graph is also fully mutable, supporting
 * both insertions and removals of vertices and edges.
 *
 * @note Special care must be taken when removing vertices or edges since
 * those operations can invalidate the numbering of vertices.
 */
template <
    typename VertexProp = no_property,
    typename EdgeProp= no_property,
    typename GraphProp= no_property>
class directed_graph
{
public:
    typedef typename graph_detail::vertex_prop<VertexProp>::type vertex_property_type;
    typedef typename graph_detail::vertex_prop<VertexProp>::bundle vertex_bundled;
    typedef typename graph_detail::edge_prop<EdgeProp>::type edge_property_type;
    typedef typename graph_detail::edge_prop<EdgeProp>::bundle edge_bundled;

private:
    // Wrap the user-specified properties with an index.
    typedef property<vertex_index_t, unsigned, vertex_property_type> vertex_property;
    typedef property<edge_index_t, unsigned, edge_property_type> edge_property;

public:
    typedef adjacency_list<
        listS, listS, bidirectionalS,
        vertex_property, edge_property, GraphProp,
        listS
    > graph_type;

private:
    // storage selectors
    typedef typename graph_type::vertex_list_selector vertex_list_selector;
    typedef typename graph_type::edge_list_selector edge_list_selector;
    typedef typename graph_type::out_edge_list_selector out_edge_list_selector;
    typedef typename graph_type::directed_selector directed_selector;

public:
    typedef directed_graph_tag graph_tag;
    typedef typename graph_type::graph_property_type graph_property_type;

    // more commonly used graph types
    typedef typename graph_type::stored_vertex stored_vertex;
    typedef typename graph_type::vertices_size_type vertices_size_type;
    typedef typename graph_type::edges_size_type edges_size_type;
    typedef typename graph_type::degree_size_type degree_size_type;
    typedef typename graph_type::vertex_descriptor vertex_descriptor;
    typedef typename graph_type::edge_descriptor edge_descriptor;

    // iterator types
    typedef typename graph_type::vertex_iterator vertex_iterator;
    typedef typename graph_type::edge_iterator edge_iterator;
    typedef typename graph_type::out_edge_iterator out_edge_iterator;
    typedef typename graph_type::in_edge_iterator in_edge_iterator;
    typedef typename graph_type::adjacency_iterator adjacency_iterator;

    // miscellaneous types
    typedef typename graph_type::directed_category directed_category;
    typedef typename graph_type::edge_parallel_category edge_parallel_category;
    typedef typename graph_type::traversal_category traversal_category;

    typedef unsigned vertex_index_type;
    typedef unsigned edge_index_type;

    directed_graph(GraphProp const& p = GraphProp())
        : m_graph(p), m_num_vertices(0), m_num_edges(0), m_max_vertex_index(0)
        , m_max_edge_index(0)
    { }

    directed_graph(directed_graph const& x)
        : m_graph(x), m_num_vertices(x.m_num_vertices), m_num_edges(x.m_num_edges)
        , m_max_vertex_index(x.m_max_vertex_index), m_max_edge_index(x.m_max_edge_index)
    { }

    directed_graph(vertices_size_type n, GraphProp const& p = GraphProp())
        : m_graph(n, p), m_num_vertices(n), m_num_edges(0), m_max_vertex_index(n)
        , m_max_edge_index(0)
    { renumber_vertex_indices(); }

    template <typename EdgeIterator>
    directed_graph(EdgeIterator f,
                   EdgeIterator l,
                   vertices_size_type n,
                   edges_size_type m = 0,
                   GraphProp const& p = GraphProp())
        : m_graph(f, l, n, m, p), m_num_vertices(n), m_num_edges(0)
        , m_max_vertex_index(n), m_max_edge_index(0)
    {
        // Unfortunately, we have to renumber the entire graph.
        renumber_indices();

        // Can't always guarantee that the number of edges is actually
        // m if distance(f, l) != m (or is undefined).
        m_num_edges = m_max_edge_index = boost::num_edges(m_graph);
    }

    directed_graph& operator=(directed_graph const& g) {
        if(&g != this) {
            m_graph = g.m_graph;
            m_num_vertices = g.m_num_vertices;
            m_num_edges = g.m_num_edges;
            m_max_vertex_index = g.m_max_vertex_index;
            m_max_edge_index = g.m_max_edge_index;
        }
        return *this;
    }

    // The impl_() methods are not part of the public interface.
    graph_type& impl()
    { return m_graph; }

    graph_type const& impl() const
    { return m_graph; }

    // The following methods are not part of the public interface
    vertices_size_type num_vertices() const
    { return m_num_vertices; }

private:
    // This helper function manages the attribution of vertex indices.
    vertex_descriptor make_index(vertex_descriptor v) {
        boost::put(vertex_index, m_graph, v, m_max_vertex_index);
        m_num_vertices++;
        m_max_vertex_index++;
        return v;
    }
public:
    vertex_descriptor add_vertex()
    { return make_index(boost::add_vertex(m_graph)); }

    vertex_descriptor add_vertex(vertex_property_type const& p)
    { return make_index(boost::add_vertex(vertex_property(0u, p), m_graph)); }

    void clear_vertex(vertex_descriptor v)
    {
        m_num_edges -= boost::degree(v, m_graph);
        boost::clear_vertex(v, m_graph);
    }

    void remove_vertex(vertex_descriptor v)
    {
        boost::remove_vertex(v, m_graph);
        --m_num_vertices;
    }

    edges_size_type num_edges() const
    { return m_num_edges; }

private:
    // A helper fucntion for managing edge index attributes.
    std::pair<edge_descriptor, bool> const&
    make_index(std::pair<edge_descriptor, bool> const& x)
    {
        if(x.second) {
            boost::put(edge_index, m_graph, x.first, m_max_edge_index);
            ++m_num_edges;
            ++m_max_edge_index;
        }
        return x;
    }
public:
    std::pair<edge_descriptor, bool>
    add_edge(vertex_descriptor u, vertex_descriptor v)
    { return make_index(boost::add_edge(u, v, m_graph)); }

    std::pair<edge_descriptor, bool>
    add_edge(vertex_descriptor u, vertex_descriptor v, edge_property_type const& p)
    { return make_index(boost::add_edge(u, v, edge_property(0u, p), m_graph)); }

    void remove_edge(vertex_descriptor u, vertex_descriptor v)
    {
        // find all edges, (u, v)
        std::vector<edge_descriptor> edges;
        out_edge_iterator i, i_end;
        for(tie(i, i_end) = boost::out_edges(u, m_graph); i != i_end; ++i) {
            if(boost::target(*i, m_graph) == v) {
                edges.push_back(*i);
            }
        }
        // remove all edges, (u, v)
        typename std::vector<edge_descriptor>::iterator
        j = edges.begin(), j_end = edges.end();
        for( ; j != j_end; ++j) {
            remove_edge(*j);
        }
    }

    void remove_edge(edge_iterator i)
    {
        remove_edge(*i);
    }

    void remove_edge(edge_descriptor e)
    {
        boost::remove_edge(e, m_graph);
        --m_num_edges;
    }

    vertex_index_type max_vertex_index() const
    { return m_max_vertex_index; }

    void
    renumber_vertex_indices()
    {
        vertex_iterator i, end;
        tie(i, end) = vertices(m_graph);
        m_max_vertex_index = renumber_vertex_indices(i, end, 0);
    }

    void
    remove_vertex_and_renumber_indices(vertex_iterator i)
    {
        vertex_iterator j = next(i), end = vertices(m_graph).second;
        vertex_index_type n = get(vertex_index, m_graph, *i);

        // remove the offending vertex and renumber everything after
        remove_vertex(*i);
        m_max_vertex_index = renumber_vertex_indices(j, end, n);
    }

    edge_index_type
    max_edge_index() const
    { return m_max_edge_index; }

    void
    renumber_edge_indices()
    {
        edge_iterator i, end;
        tie(i, end) = edges(m_graph);
        m_max_edge_index = renumber_edge_indices(i, end, 0);
    }

    void
    remove_edge_and_renumber_indices(edge_iterator i)
    {
        edge_iterator j = next(i), end = edges(m_graph).second;
        edge_index_type n = get(edge_index, m_graph, *i);

        // remove the offending edge and renumber everything after
        remove_edge(*i);
        m_max_edge_index = renumber_edge_indices(j, end, n);
    }

    void
    renumber_indices()
    {
        renumber_vertex_indices();
        renumber_edge_indices();
    }

    // bundled property support
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
    vertex_bundled& operator[](vertex_descriptor v)
    { return m_graph[v]; }

    vertex_bundled const& operator[](vertex_descriptor v) const
    { return m_graph[v]; }

    edge_bundled& operator[](edge_descriptor e)
    { return m_graph[e]; }

    edge_bundled const& operator[](edge_descriptor e) const
    { return m_graph[e]; }
#endif

    // Graph concepts
    static vertex_descriptor null_vertex()
    { return graph_type::null_vertex(); }

    void clear()
    {
        m_graph.clear();
        m_num_vertices = m_max_vertex_index = 0;
        m_num_edges = m_max_edge_index = 0;
    }

    void swap(directed_graph& g)
    {
        m_graph.swap(g);
        std::swap(m_num_vertices, g.m_num_vertices);
        std::swap(m_max_vertex_index, g.m_max_vertex_index);
        std::swap(m_num_edges, g.m_num_edges);
        std::swap(m_max_edge_index, g.m_max_edge_index);
    }

private:
    vertices_size_type
    renumber_vertex_indices(vertex_iterator i,
                            vertex_iterator end,
                            vertices_size_type n)
    {
        typedef typename property_map<graph_type, vertex_index_t>::type IndexMap;
        IndexMap indices = get(vertex_index, m_graph);
        for( ; i != end; ++i) {
            indices[*i] = n++;
        }
        return n;
    }

    vertices_size_type
    renumber_edge_indices(edge_iterator i,
                        edge_iterator end,
                        vertices_size_type n)
    {
        typedef typename property_map<graph_type, edge_index_t>::type IndexMap;
        IndexMap indices = get(edge_index, m_graph);
        for( ; i != end; ++i) {
            indices[*i] = n++;
        }
        return n;
    }

    graph_type m_graph;
    vertices_size_type m_num_vertices;
    edges_size_type m_num_edges;
    vertex_index_type m_max_vertex_index;
    edge_index_type m_max_edge_index;
};

#define DIRECTED_GRAPH_PARAMS typename VP, typename EP, typename GP
#define DIRECTED_GRAPH directed_graph<VP,EP,GP>

// IncidenceGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
source(typename DIRECTED_GRAPH::edge_descriptor e,
    DIRECTED_GRAPH const& g)
{ return source(e, g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
target(typename DIRECTED_GRAPH::edge_descriptor e,
    DIRECTED_GRAPH const& g)
{ return target(e, g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
out_degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return out_degree(v, g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
    typename DIRECTED_GRAPH::out_edge_iterator,
    typename DIRECTED_GRAPH::out_edge_iterator
>
out_edges(typename DIRECTED_GRAPH::vertex_descriptor v,
        DIRECTED_GRAPH const& g)
{ return out_edges(v, g.impl()); }

// BidirectionalGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
in_degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return in_degree(v, g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
    typename DIRECTED_GRAPH::in_edge_iterator,
    typename DIRECTED_GRAPH::in_edge_iterator
>
in_edges(typename DIRECTED_GRAPH::vertex_descriptor v,
        DIRECTED_GRAPH const& g)
{ return in_edges(v, g.impl()); }


template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return degree(v, g.impl()); }

// AdjacencyGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
    typename DIRECTED_GRAPH::adjacency_iterator,
    typename DIRECTED_GRAPH::adjacency_iterator
    >
adjacent_vertices(typename DIRECTED_GRAPH::vertex_descriptor v,
                  DIRECTED_GRAPH const& g)
{ return adjacent_vertices(v, g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::vertex_descriptor
vertex(typename DIRECTED_GRAPH::vertices_size_type n,
       DIRECTED_GRAPH const& g)
{ return vertex(g.impl()); }

template <DIRECTED_GRAPH_PARAMS>
std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
edge(typename DIRECTED_GRAPH::vertex_descriptor u,
     typename DIRECTED_GRAPH::vertex_descriptor v,
     DIRECTED_GRAPH const& g)
{ return edge(u, v, g.impl()); }

// VertexListGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertices_size_type
num_vertices(DIRECTED_GRAPH const& g)
{ return g.num_vertices(); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
    typename DIRECTED_GRAPH::vertex_iterator,
    typename DIRECTED_GRAPH::vertex_iterator
>
vertices(DIRECTED_GRAPH const& g)
{ return vertices(g.impl()); }

// EdgeListGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::edges_size_type
num_edges(DIRECTED_GRAPH const& g)
{ return g.num_edges(); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
    typename DIRECTED_GRAPH::edge_iterator,
    typename DIRECTED_GRAPH::edge_iterator
>
edges(DIRECTED_GRAPH const& g)
{ return edges(g.impl()); }

// MutableGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
add_vertex(DIRECTED_GRAPH& g)
{ return g.add_vertex(); }

template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
add_vertex(typename DIRECTED_GRAPH::vertex_property_type const& p,
           DIRECTED_GRAPH& g)
{ return g.add_vertex(p); }

template <DIRECTED_GRAPH_PARAMS>
inline void
clear_vertex(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH& g)
{ return g.clear_vertex(v); }

template <DIRECTED_GRAPH_PARAMS>
inline void
remove_vertex(typename DIRECTED_GRAPH::vertex_descriptor v,
              DIRECTED_GRAPH& g)
{ return g.remove_vertex(v); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
add_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
         typename DIRECTED_GRAPH::vertex_descriptor v,
         DIRECTED_GRAPH& g)
{ return g.add_edge(u, v); }

template <DIRECTED_GRAPH_PARAMS>
inline std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
add_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
         typename DIRECTED_GRAPH::vertex_descriptor v,
         typename DIRECTED_GRAPH::edge_property_type const& p,
         DIRECTED_GRAPH& g)
{ return g.add_edge(u, v, p); }

template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
                        typename DIRECTED_GRAPH::vertex_descriptor v,
                        DIRECTED_GRAPH& g)
{ return g.remove_edge(u, v); }


template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH& g)
{ return g.remove_edge(e); }

template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::edge_iterator i, DIRECTED_GRAPH& g)
{ return g.remove_edge(i); }

template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void remove_edge_if(Predicate pred, DIRECTED_GRAPH& g)
{ return remove_edge_if(pred, g.impl()); }

template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void
remove_out_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v,
                   Predicate pred,
                   DIRECTED_GRAPH& g)
{ return remove_out_edge_if(v, pred, g.impl()); }

template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void
remove_in_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v,
                Predicate pred,
                DIRECTED_GRAPH& g)
{ return remove_in_edge_if(v, pred, g.impl()); }

// Helper code for working with property maps
namespace detail
{
    struct directed_graph_vertex_property_selector {
        template <class DirectedGraph, class Property, class Tag>
        struct bind_ {
            typedef typename DirectedGraph::graph_type Graph;
            typedef property_map<Graph, Tag> PropertyMap;
            typedef typename PropertyMap::type type;
            typedef typename PropertyMap::const_type const_type;
        };
    };

    struct directed_graph_edge_property_selector {
        template <class DirectedGraph, class Property, class Tag>
        struct bind_ {
            typedef typename DirectedGraph::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<directed_graph_tag>
{ typedef detail::directed_graph_vertex_property_selector type; };

template <>
struct edge_property_selector<directed_graph_tag>
{ typedef detail::directed_graph_edge_property_selector type; };

// PropertyGraph concepts
template <DIRECTED_GRAPH_PARAMS, typename Property>
inline typename property_map<DIRECTED_GRAPH, Property>::type
get(Property p, DIRECTED_GRAPH& g)
{ return get(p, g.impl()); }

template <DIRECTED_GRAPH_PARAMS, typename Property>
inline typename property_map<DIRECTED_GRAPH, Property>::const_type
get(Property p, DIRECTED_GRAPH const& g)
{ return get(p, g.impl()); }

template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key>
inline typename property_traits<
    typename property_map<
        typename DIRECTED_GRAPH::graph_type, Property
    >::const_type
>::value_type
get(Property p, DIRECTED_GRAPH const& g, Key const& k)
{ return get(p, g.impl(), k); }

template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value>
inline void put(Property p, DIRECTED_GRAPH& g, Key const& k, Value const& v)
{ put(p, g.impl(), k, v); }

template <DIRECTED_GRAPH_PARAMS, class Property>
typename graph_property<DIRECTED_GRAPH, Property>::type&
get_property(DIRECTED_GRAPH& g, Property p)
{ return get_property(g.impl(), p); }

template <DIRECTED_GRAPH_PARAMS, class Property>
typename graph_property<DIRECTED_GRAPH, Property>::type const&
get_property(DIRECTED_GRAPH const& g, Property p)
{ return get_property(g.impl(), p); }

template <DIRECTED_GRAPH_PARAMS, class Property, class Value>
void
set_property(DIRECTED_GRAPH& g, Property p, Value v)
{ return set_property(g.impl(), p, v); }

#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES

template <DIRECTED_GRAPH_PARAMS, typename Type, typename Bundle>
inline typename property_map<DIRECTED_GRAPH, Type Bundle::*>::type
get(Type Bundle::* p, DIRECTED_GRAPH& g) {
    typedef typename property_map<
        DIRECTED_GRAPH, Type Bundle::*
    >::type return_type;
    return return_type(&g, p);
}

template <DIRECTED_GRAPH_PARAMS, typename Type, typename Bundle>
inline typename property_map<DIRECTED_GRAPH, Type Bundle::*>::const_type
get(Type Bundle::* p, DIRECTED_GRAPH const& g) {
    typedef typename property_map<
        DIRECTED_GRAPH, Type Bundle::*
    >::const_type return_type;
    return return_type(&g, p);
}

template <DIRECTED_GRAPH_PARAMS, typename Type, typename Bundle, typename Key>
inline Type get(Type Bundle::* p, DIRECTED_GRAPH const& g, Key const& k)
{ return get(p, g.impl(), k); }

template <DIRECTED_GRAPH_PARAMS, typename Type, typename Bundle, typename Key, typename Value>
inline void put(Type Bundle::* p, DIRECTED_GRAPH& g, Key const& k, Value const& v)
{ put(p, g.impl(), k, v); }
#endif

// Vertex index management

template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_index_type
get_vertex_index(typename DIRECTED_GRAPH::vertex_descriptor v,
                DIRECTED_GRAPH const& g)
{ return get(vertex_index, g, v); }

template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::vertex_index_type
max_vertex_index(DIRECTED_GRAPH const& g)
{ return g.max_vertex_index(); }

template <DIRECTED_GRAPH_PARAMS>
inline void
renumber_vertex_indices(DIRECTED_GRAPH& g)
{ g.renumber_vertex_indices(); }

template <DIRECTED_GRAPH_PARAMS>
inline void
remove_vertex_and_renumber_indices(typename DIRECTED_GRAPH::vertex_iterator i,
                                DIRECTED_GRAPH& g)
{ g.remove_vertex_and_renumber_indices(i); }

// Edge index management
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::edge_index_type
get_edge_index(typename DIRECTED_GRAPH::edge_descriptor v, DIRECTED_GRAPH const& g)
{ return get(edge_index, g, v); }

template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::edge_index_type
max_edge_index(DIRECTED_GRAPH const& g)
{ return g.max_edge_index(); }

template <DIRECTED_GRAPH_PARAMS>
inline void renumber_edge_indices(DIRECTED_GRAPH& g)
{ g.renumber_edge_indices(); }

template <DIRECTED_GRAPH_PARAMS>
inline void
remove_edge_and_renumber_indices(typename DIRECTED_GRAPH::edge_iterator i,
                                 DIRECTED_GRAPH& g)
{ g.remove_edge_and_renumber_indices(i); }

// Index management
template <DIRECTED_GRAPH_PARAMS>
inline void
renumber_indices(DIRECTED_GRAPH& g)
{ g.renumber_indices(); }

// Mutability Traits
template <DIRECTED_GRAPH_PARAMS>
struct graph_mutability_traits<DIRECTED_GRAPH> {
    typedef mutable_property_graph_tag category;
};

#undef DIRECTED_GRAPH_PARAMS
#undef DIRECTED_GRAPH

} /* namespace boost */

#endif
