From c025b09496f78ed607ced65850dc056b03d2cbfb Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Thu, 25 May 2023 11:52:50 +0200 Subject: [PATCH] Add support for GraphViz cgraph library Signed-off-by: Tobias Lorenz --- example/cgraph-example.cpp | 221 ++++++++ include/boost/graph/cgraph_graph.hpp | 758 +++++++++++++++++++++++++++ 2 files changed, 979 insertions(+) create mode 100644 example/cgraph-example.cpp create mode 100644 include/boost/graph/cgraph_graph.hpp diff --git a/example/cgraph-example.cpp b/example/cgraph-example.cpp new file mode 100644 index 000000000..11068b75a --- /dev/null +++ b/example/cgraph-example.cpp @@ -0,0 +1,221 @@ +/* C++ Standard Library */ +#include + +/* Boost Graph Library */ +#include +#include +#include + +/* Graphviz */ +#include + +void example_a() +{ + GVC_t * gvc = ::gvContext(); + + Agraph_t * g = ::agopen("g", Agdirected, nullptr); + Agnode_t * n = ::agnode(g, "n", 1); + Agnode_t * m = ::agnode(g, "m", 1); + Agedge_t * e = ::agedge(g, n, m, nullptr, 1); + ::agsafeset(n, "color", "red", ""); + + ::gvLayout(gvc, g, "dot"); + ::gvRender(gvc, g, "plain", stdout); + + ::gvFreeLayout(gvc, g); + ::agclose(g); + + ::gvFreeContext(gvc); +} + +void example_b() +{ + // create a typedef for the Graph type + typedef boost::cgraph_graph_ptr Graph; + typedef boost::property_map::type GraphNameMap; + typedef boost::property_map::type VertexIndexMap; + typedef boost::property_map::type VertexNameMap; + typedef boost::property_map::type EdgeIndexMap; + typedef boost::property_map::type EdgeNameMap; + + BOOST_CONCEPT_ASSERT((boost::MultiPassInputIteratorConcept)); + + /* graph concepts */ + BOOST_CONCEPT_ASSERT((boost::GraphConcept)); + BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::BidirectionalGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::AdjacencyGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::EdgeListGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::VertexAndEdgeListGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::EdgeMutableGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::VertexMutableGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::MutableGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::MutableIncidenceGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::MutableBidirectionalGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::MutableEdgeListGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::VertexMutablePropertyGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::EdgeMutablePropertyGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::AdjacencyMatrixConcept)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyGraphConcept::edge_descriptor, boost::edge_index_t>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyGraphConcept::vertex_descriptor, boost::vertex_index_t>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyGraphConcept)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyGraphConcept::edge_descriptor, boost::edge_name_t>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyGraphConcept::vertex_descriptor, boost::vertex_name_t>)); +// BOOST_CONCEPT_ASSERT((boost::PropertyGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::LvaluePropertyGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::VertexIndexGraphConcept)); +// BOOST_CONCEPT_ASSERT((boost::EdgeIndexGraphConcept)); + + /* utility concepts */ +// BOOST_CONCEPT_ASSERT((boost::ColorValueConcept)); +// BOOST_CONCEPT_ASSERT((boost::BasicMatrixConcept)); +// BOOST_CONCEPT_ASSERT((boost::NumericValueConcept)); +// BOOST_CONCEPT_ASSERT((boost::DegreeMeasureConcept)); +// BOOST_CONCEPT_ASSERT((boost::DistanceMeasureConcept)); + + /* iterator concepts */ + BOOST_CONCEPT_ASSERT((boost::InputIteratorConcept)); +// BOOST_CONCEPT_ASSERT((boost::OutputIteratorConcept)); + BOOST_CONCEPT_ASSERT((boost::Mutable_ForwardIteratorConcept)); + BOOST_CONCEPT_ASSERT((boost::BidirectionalIteratorConcept)); + BOOST_CONCEPT_ASSERT((boost::Mutable_BidirectionalIteratorConcept)); + BOOST_CONCEPT_ASSERT((boost::RandomAccessIteratorConcept)); + BOOST_CONCEPT_ASSERT((boost::Mutable_RandomAccessIteratorConcept)); + + /* property map concepts */ + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept::edge_descriptor>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept::vertex_descriptor>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept::edge_descriptor>)); + BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept::vertex_descriptor>)); +// BOOST_CONCEPT_ASSERT((boost::WritablePropertyMapConcept)); +// BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept)); +// BOOST_CONCEPT_ASSERT((boost::LvaluePropertyMapConcept)); +// BOOST_CONCEPT_ASSERT((boost::Mutable_LvaluePropertyMapConcept)); + + GVC_t * gvc = ::gvContext(); + + // declare a graph object + Graph g = ::agopen("g", Agdirected, nullptr); + + // add nodes + boost::graph_traits::vertex_descriptor A = boost::add_vertex("A", g); + boost::graph_traits::vertex_descriptor B = boost::add_vertex("B", g); + boost::graph_traits::vertex_descriptor C = boost::add_vertex("C", g); + boost::graph_traits::vertex_descriptor D = boost::add_vertex("D", g); + boost::graph_traits::vertex_descriptor E = boost::add_vertex("E", g); + + // add edges + std::pair::edge_descriptor, bool> AB = boost::add_edge(A, B, "AB", g); + std::pair::edge_descriptor, bool> AD = boost::add_edge(A, D, "AD", g); + std::pair::edge_descriptor, bool> CA = boost::add_edge(C, A, "CA", g); + std::pair::edge_descriptor, bool> DC = boost::add_edge(D, C, "DC", g); + std::pair::edge_descriptor, bool> CE = boost::add_edge(C, E, "CE", g); + std::pair::edge_descriptor, bool> BD = boost::add_edge(B, D, "BD", g); + std::pair::edge_descriptor, bool> DE = boost::add_edge(D, E, "DE", g); + + std::cout << "vertices(g) = "; + typedef boost::graph_traits::vertex_iterator vertex_iter; + VertexIndexMap vertexIndex = get(boost::vertex_index, g); + VertexNameMap vertexName = get(boost::vertex_name, g); + std::pair vp; + for (vp = vertices(g); vp.first != vp.second; ++vp.first) { + const boost::graph_traits::vertex_descriptor v = *vp.first; + std::cout << vertexIndex[v]; + if(vertexName[v]) { + std::cout << ':' << vertexName[v]; + } + std::cout << " "; + } + std::cout << std::endl; + + std::cout << "edges(g) = "; + boost::graph_traits::edge_iterator ei, ei_end; + EdgeIndexMap edgeIndex = get(boost::edge_index, g); + EdgeNameMap edgeName = get(boost::edge_name, g); + for (boost::tie(ei, ei_end) = boost::edges(g); ei != ei_end; ++ei) { + boost::graph_traits::vertex_descriptor src = source(*ei, g); + boost::graph_traits::vertex_descriptor trg = target(*ei, g); + std::cout << "("; + std::cout << edgeIndex[*ei]; + if(edgeName[*ei]) { + std::cout << ':' << edgeName[*ei]; + } + std::cout << ") "; + } + std::cout << std::endl; + + std::cout << "out-edges of A: "; + boost::graph_traits::out_edge_iterator out_i, out_end; + for (boost::tie(out_i, out_end) = out_edges(A, g); out_i != out_end; ++out_i) { + boost::graph_traits::vertex_descriptor src = source(*out_i, g); + boost::graph_traits::vertex_descriptor targ = target(*out_i, g); + std::cout << "("; + std::cout << edgeIndex[*out_i]; + if(edgeName[*out_i]) { + std::cout << ':' << edgeName[*out_i]; + } + std::cout << ") "; + } + std::cout << std::endl; + + std::cout << "in-edges of A: "; + boost::graph_traits::in_edge_iterator in_i, in_end; + for (boost::tie(in_i, in_end) = in_edges(A, g); in_i != in_end; ++in_i) { + boost::graph_traits::vertex_descriptor src = source(*in_i, g); + boost::graph_traits::vertex_descriptor targ = target(*in_i, g); + std::cout << "("; + std::cout << edgeIndex[*in_i]; + if(edgeName[*in_i]) { + std::cout << ':' << edgeName[*in_i]; + } + std::cout << ") "; + } + std::cout << std::endl; + + std::cout << "adjacent vertices of C: "; + boost::graph_traits::adjacency_iterator ai, ai_end; + for (boost::tie(ai, ai_end) = adjacent_vertices(C, g); ai != ai_end; ++ai) { + std::cout << "("; + std::cout << edgeIndex[*ai]; + if(edgeName[*ai]) { + std::cout << ':' << edgeName[*ai]; + } + std::cout << ") "; + } + std::cout << std::endl; + + // @todo the following terminates with + // terminate called after throwing an instance of 'boost::wrapexcept' + // what(): The graph must be a DAG. + typedef boost::graph_traits::vertex_descriptor Vertex; + typedef std::list container; + std::list c; + std::map vertex_colors; + boost::topological_sort(g, std::back_inserter(c), boost::color_map(boost::make_assoc_property_map(vertex_colors))); + std::cout << "A topological ordering: "; + for (container::reverse_iterator ii = c.rbegin(); ii != c.rend(); ++ii) { + std::cout << vertexIndex[*ii]; + if(vertexName[*ii]) { + std::cout << ':' << vertexName[*ii]; + } + } + std::cout << std::endl; + + ::gvLayout(gvc, g, "dot"); + ::gvRender(gvc, g, "plain", stdout); + + ::gvFreeLayout(gvc, g); + ::agclose(g); + + ::gvFreeContext(gvc); +} + +int main(int argc, char *argv[]) +{ + example_b(); + + return EXIT_SUCCESS; +} diff --git a/include/boost/graph/cgraph_graph.hpp b/include/boost/graph/cgraph_graph.hpp new file mode 100644 index 000000000..87c870cff --- /dev/null +++ b/include/boost/graph/cgraph_graph.hpp @@ -0,0 +1,758 @@ +/* + * Copyright (C) 2023 Tobias Lorenz + * + * Author: tobias.lorenz@gmx.net + * + * 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_CGRAPH_GRAPH_HPP +#define BOOST_GRAPH_CGRAPH_GRAPH_HPP + +/* C++ Standard Library */ +#include + +/* Boost Graph Library */ +#include +#include + +/* Graphviz */ +#include + +namespace boost { + +// @todo subgraphs are not handled yet + +typedef ::Agraph_t * cgraph_graph_ptr; + +#define cgraph_type Agdirected +//#define cgraph_type Agstrictdirected +//#define cgraph_type Agundirected +//#define cgraph_type Agstrictundirected + +template <> +struct graph_traits +{ + /* Graph */ + + typedef ::Agnode_t * vertex_descriptor; + typedef ::Agedge_t * edge_descriptor; + +// @todo How can this runtime setting be handled in the template? +#if cgraph_type == Agdirected + // Agdirected (digraph) + typedef bidirectional_tag directed_category; + typedef allow_parallel_edge_tag edge_parallel_category; +#elif cgraph_type == Agstrictdirected + // Agstrictdirected (strict digraph) + typedef bidirectional_tag directed_category; + typedef disallow_parallel_edge_tag edge_parallel_category; +#elif cgraph_type == Agundirected + // Agundirected (graph) + typedef undirected_tag directed_category; + typedef allow_parallel_edge_tag edge_parallel_category; +#elif cgraph_type == Agstrictundirected + // Agstrictundirected (strict graph) + typedef undirected_tag directed_category; + typedef disallow_parallel_edge_tag edge_parallel_category; +#endif + struct traversal_category: + //public virtual incidence_graph_tag, // included in bidirectional_graph_tag + public virtual adjacency_graph_tag, + public virtual bidirectional_graph_tag, + public virtual vertex_list_graph_tag, + public virtual edge_list_graph_tag + //public virtual adjacency_matrix_tag, => edge(u, v, g) + { + }; + + static constexpr vertex_descriptor null_vertex() + { + return nullptr; + } + + /* IncidenceGraph */ + + class out_edge_iterator: + public iterator_facade + { + public: + explicit out_edge_iterator(edge_descriptor edge = nullptr, cgraph_graph_ptr graph = nullptr): + edge(edge), + graph(graph) + { + } + + private: + reference dereference() const + { + return edge; + } + + bool equal(const out_edge_iterator & j) const + { + return edge == j.edge; + } + + void increment() + { + assert(graph); + assert(edge); + edge = ::agnxtout(graph, edge); + } + + edge_descriptor edge{nullptr}; + cgraph_graph_ptr graph{nullptr}; + + friend class iterator_core_access; + }; + + typedef int degree_size_type; + + /* BidirectionalGraph */ + + class in_edge_iterator: + public iterator_facade + { + public: + explicit in_edge_iterator(edge_descriptor edge = nullptr, cgraph_graph_ptr graph = nullptr): + edge(edge), + graph(graph) + { + } + + private: + reference dereference() const + { + return edge; + } + + bool equal(const in_edge_iterator & j) const + { + return edge == j.edge; + } + + void increment() + { + assert(graph); + assert(edge); + edge = ::agnxtin(graph, edge); + } + + edge_descriptor edge{nullptr}; + cgraph_graph_ptr graph{nullptr}; + + friend class iterator_core_access; + }; + + /* AdjacencyGraph */ + + class adjacency_iterator: + public iterator_facade + { + public: + explicit adjacency_iterator(vertex_descriptor node = nullptr, edge_descriptor edge = nullptr, cgraph_graph_ptr graph = nullptr): + node(node), + edge(edge), + graph(graph) + { + } + + private: + reference dereference() const + { + assert(edge); + return aghead(edge); + } + + bool equal(const adjacency_iterator & j) const + { + return (node == j.node) && (edge == j.edge); + } + + void increment() + { + assert(graph); + if (::agisdirected(graph)) { + assert(edge); + edge = ::agnxtout(graph, edge); + } + if (::agisundirected(graph)) { + assert(edge); + assert(node); + edge = ::agnxtedge(graph, edge, node); + } + } + + vertex_descriptor node{nullptr}; + edge_descriptor edge{nullptr}; + cgraph_graph_ptr graph{nullptr}; + + friend class iterator_core_access; + }; + + /* VertexListGraph */ + + class vertex_iterator: + public iterator_facade + { + public: + explicit vertex_iterator(vertex_descriptor node = nullptr, cgraph_graph_ptr graph = nullptr): + node(node), + graph(graph) + { + } + + private: + reference dereference() const + { + return node; + } + + bool equal(const vertex_iterator & j) const + { + return node == j.node; + } + + void increment() + { + assert(graph); + assert(node); + node = ::agnxtnode(graph, node); + } + + void decrement() + { + assert(graph); + assert(node); + node = ::agprvnode(graph, node); + } + +// void advance(difference_type n) +// { +// while (n > 0) { +// increment(); +// n--; +// } +// while (n < 0) { +// decrement(); +// n++; +// } +// } + +// difference_type distance_to(const vertex_iterator & j) const +// { +// difference_type n = 0; +// vertex_descriptor jnode = j.node; +// while(node != jnode) { +// jnode = ::agnxtnode(graph, jnode); +// n++; +// } +// return n; +// } + + vertex_descriptor node{nullptr}; + cgraph_graph_ptr graph{nullptr}; + + friend class iterator_core_access; + }; + + typedef int vertices_size_type; + + /* EdgeListGraph */ + + class edge_iterator: + public iterator_facade + { + public: + explicit edge_iterator(vertex_descriptor node = nullptr, edge_descriptor edge = nullptr, const cgraph_graph_ptr graph = nullptr): + node(node), + edge(edge), + graph(graph) + { + } + + private: + const edge_descriptor & dereference() const + { + return edge; + } + + bool equal(const edge_iterator & j) const + { + return edge == j.edge; + } + + void increment() + { + assert(graph); + if (::agisdirected(graph)) { + assert(edge); + edge = ::agnxtout(graph, edge); + if (!edge) { + node = ::agnxtnode(graph, node); + if (node) { + edge = ::agfstout(graph, node); + } + } + } + if (::agisundirected(graph)) { + assert(edge); + assert(node); + edge = ::agnxtedge(graph, edge, node); + if (!edge) { + node = ::agnxtnode(graph, node); + if (node) { + edge = ::agfstedge(graph, node); + } + } + } + } + + vertex_descriptor node{nullptr}; + edge_descriptor edge{nullptr}; + cgraph_graph_ptr graph{nullptr}; + + friend class iterator_core_access; + }; + + typedef int edges_size_type; + + /* MutablePropertyGraph */ + + // @todo the following typedefs are suffient to set the name, however std::map would allow all attributes to be set. + typedef char * edge_property_type; + typedef char * vertex_property_type; +}; + +/* IncidenceGraph */ + +graph_traits::vertex_descriptor source(graph_traits::edge_descriptor e, const cgraph_graph_ptr & g) +{ + assert(e); + assert(g); + return agtail(e); +} + +graph_traits::vertex_descriptor target(graph_traits::edge_descriptor e, const cgraph_graph_ptr & g) +{ + assert(e); + assert(g); + return aghead(e); +} + +inline std::pair::out_edge_iterator, graph_traits::out_edge_iterator> out_edges(graph_traits::vertex_descriptor v, const cgraph_graph_ptr & g) +{ + assert(v); + assert(g); + typedef graph_traits::out_edge_iterator Iter; + return std::make_pair(Iter(::agfstout(g, v), g), Iter(nullptr, g)); +} + +graph_traits::degree_size_type out_degree(graph_traits::vertex_descriptor v, const cgraph_graph_ptr & g) +{ + assert(v); + assert(g); + // @todo agdegree or agcountuniqedges ? + return ::agdegree(g, v, 0, 1); +} + +/* BidirectionalGraph */ + +inline std::pair::in_edge_iterator, graph_traits::in_edge_iterator> in_edges(graph_traits::vertex_descriptor v, const cgraph_graph_ptr & g) +{ + assert(v); + assert(g); + typedef graph_traits::in_edge_iterator Iter; + return std::make_pair(Iter(::agfstin(g, v), g), Iter(nullptr, g)); +} + +graph_traits::degree_size_type in_degree(graph_traits::vertex_descriptor v, const cgraph_graph_ptr & g) +{ + assert(v); + assert(g); + return ::agdegree(g, v, 1, 0); +} + +graph_traits::degree_size_type degree(graph_traits::vertex_descriptor u, const cgraph_graph_ptr & g) +{ + assert(u); + assert(g); + return ::agdegree(g, u, 1, 1); +} + +/* AdjacencyGraph */ + +inline std::pair::adjacency_iterator, graph_traits::adjacency_iterator> adjacent_vertices(graph_traits::vertex_descriptor v, const cgraph_graph_ptr & g) +{ + assert(v); + assert(g); + typedef graph_traits::adjacency_iterator Iter; + if (::agisdirected(g)) { + return std::make_pair(Iter(v, ::agfstout(g, v), g), Iter(v, nullptr, g)); + } + if (::agisundirected(g)) { + return std::make_pair(Iter(v, ::agfstedge(g, v), g), Iter(v, nullptr, g)); + } + return std::make_pair(Iter(v, nullptr, g), Iter(v, nullptr, g)); +} + +/* VertexListGraph */ + +inline std::pair::vertex_iterator, graph_traits::vertex_iterator> vertices(const cgraph_graph_ptr & g) +{ + assert(g); + typedef graph_traits::vertex_iterator Iter; + return std::make_pair(Iter(::agfstnode(g), g), Iter(nullptr, g)); +} + +graph_traits::vertices_size_type num_vertices(const cgraph_graph_ptr & g) +{ + assert(g); + return ::agnnodes(g); +} + +/* EdgeListGraph */ + +inline std::pair::edge_iterator, graph_traits::edge_iterator> edges(const cgraph_graph_ptr & g) +{ + assert(g); + typedef graph_traits::edge_iterator Iter; + graph_traits::vertex_descriptor n = ::agfstnode(g); + assert(n); + if (::agisdirected(g)) { + graph_traits::edge_descriptor e = ::agfstedge(g, n); + return std::make_pair(Iter(n, e, g), Iter(nullptr, nullptr, g)); + } + if (::agisundirected(g)) { + graph_traits::edge_descriptor e = ::agfstedge(g, n); + return std::make_pair(Iter(n, e, g), Iter(nullptr, nullptr, g)); + } + return std::make_pair(Iter(nullptr, nullptr, g), Iter(nullptr, nullptr, g)); +} + +graph_traits::edges_size_type num_edges(const cgraph_graph_ptr & g) +{ + assert(g); + return ::agnedges(g); +} + +// source(e, g) defines in IncidenceGraph +// target(e, g) defined in IncidenceGraph + +/* AdjancencyMatrix */ + +// edge(u, v, g) + +/* MutableGraph */ + +std::pair::edge_descriptor, bool> add_edge(graph_traits::vertex_descriptor u, graph_traits::vertex_descriptor v, cgraph_graph_ptr g) +{ + assert(u); + assert(v); + assert(g); + graph_traits::edge_descriptor edge = ::agedge(g, u, v, nullptr, 1); + return std::make_pair(edge, true); // @todo false if strict and edge exists already +} + +void remove_edge(graph_traits::vertex_descriptor u, graph_traits::vertex_descriptor v, cgraph_graph_ptr g) +{ + assert(u); + assert(v); + assert(g); + graph_traits::edge_descriptor edge = ::agedge(g, u, v, nullptr, 0); + if (edge) { + ::agdeledge(g, edge); + } +} + +void remove_edge(graph_traits::edge_descriptor e, cgraph_graph_ptr g) +{ + assert(e); + assert(g); + ::agdeledge(g, e); +} + +void remove_edge(graph_traits::out_edge_iterator iter, cgraph_graph_ptr g) +{ + assert(*iter); + assert(g); + ::agdeledge(g, *iter); +} + +template +void remove_edge_if(Predicate p, cgraph_graph_ptr g) +{ + // assert(p); + assert(g); + for (graph_traits::vertex_descriptor v = ::agfstnode(g); v; v = ::agnxtnode(g, v)) { + for (graph_traits::edge_descriptor e = ::agfstout(g, v); e; e = ::agnxtout(g, e)) { + if (p(e)) { + ::agdeledge(g, e); + } + } + } +} + +template +void remove_out_edge_if(graph_traits::vertex_descriptor u, Predicate p, cgraph_graph_ptr g) +{ + assert(u); + // assert(p); + assert(g); + for (graph_traits::edge_descriptor e = ::agfstout(g, u); e; e = ::agnxtout(g, e)) { + if (p(e)) { + ::agdeledge(g, e); + } + } +} + +template +void remove_in_edge_if(graph_traits::vertex_descriptor u, Predicate p, cgraph_graph_ptr g) +{ + assert(u); + // assert(p); + assert(g); + for (graph_traits::edge_descriptor e = ::agfstin(g, u); e; e = ::agnxtin(g, e)) { + if (p(e)) { + ::agdeledge(g, e); + } + } +} + +graph_traits::vertex_descriptor add_vertex(cgraph_graph_ptr g) +{ + assert(g); + return ::agnode(g, nullptr, 1); +} + +void clear_vertex(graph_traits::vertex_descriptor v, cgraph_graph_ptr g) +{ + assert(v); + assert(g); + for (graph_traits::edge_descriptor e = ::agfstout(g, v); e; e = ::agnxtout(g, e)) { + ::agdeledge(g, e); + } + for (graph_traits::edge_descriptor e = ::agfstin(g, v); e; e = ::agnxtin(g, e)) { + ::agdeledge(g, e); + } +} + +void remove_vertex(graph_traits::vertex_descriptor v, cgraph_graph_ptr g) +{ + assert(v); + assert(g); + ::agdelnode(g, v); +} + +/* PropertyGraph */ + +class cgraph_graph_id_map : + public put_get_helper<::IDTYPE, cgraph_graph_id_map> +{ +public: + typedef readable_property_map_tag category; + typedef ::IDTYPE value_type; + typedef ::IDTYPE reference; + typedef void * key_type; + + cgraph_graph_id_map() + { + } + + ::IDTYPE operator[](void * x) const + { + assert(x); + return AGID(x); + } +}; + +inline cgraph_graph_id_map get(edge_index_t /*p*/, const cgraph_graph_ptr & g) +{ + // assert(p); + assert(g); + return cgraph_graph_id_map(); +} + +inline ::IDTYPE get(edge_index_t p, const cgraph_graph_ptr & g, const graph_traits::edge_descriptor & x) +{ + // assert(p); + assert(g); + assert(x); + return get(get(p, g), x); +} + +inline cgraph_graph_id_map get(vertex_index_t /*p*/, const cgraph_graph_ptr & g) +{ + // assert(p); + assert(g); + return cgraph_graph_id_map(); +} + +inline ::IDTYPE get(vertex_index_t p, const cgraph_graph_ptr & g, const graph_traits::vertex_descriptor & x) +{ + // assert(p); + assert(g); + assert(x); + return get(get(p, g), x); +} + +template<> +struct property_map +{ + typedef cgraph_graph_id_map type; + typedef cgraph_graph_id_map const_type; +}; + +template<> +struct property_map +{ + typedef cgraph_graph_id_map type; + typedef cgraph_graph_id_map const_type; +}; + +class cgraph_graph_name_map : + public put_get_helper +{ +public: + typedef readable_property_map_tag category; + typedef char * value_type; + typedef char * reference; + typedef void * key_type; + + cgraph_graph_name_map() + { + } + + char * operator[](void * x) const + { + assert(x); + return ::agnameof(x); + } +}; + +inline cgraph_graph_name_map get(graph_name_t /*p*/, const cgraph_graph_ptr & g) +{ + // assert(p); + assert(g); + return cgraph_graph_name_map(); +} + +inline char * get(graph_name_t p, const cgraph_graph_ptr & g, const cgraph_graph_ptr & x) +{ + // assert(p); + assert(g); + assert(x); + return get(get(p, g), x); +} + +inline cgraph_graph_name_map get(edge_name_t /*p*/, const cgraph_graph_ptr & g) +{ + // assert(p); + assert(g); + return cgraph_graph_name_map(); +} + +inline char * get(edge_name_t p, const cgraph_graph_ptr & g, const graph_traits::edge_descriptor & x) +{ + // assert(p); + assert(g); + assert(x); + return get(get(p, g), x); +} + +inline cgraph_graph_name_map get(vertex_name_t /*p*/, const cgraph_graph_ptr & g) +{ + // assert(p); + assert(g); + return cgraph_graph_name_map(); +} + +inline char * get(vertex_name_t p, const cgraph_graph_ptr & g, const graph_traits::vertex_descriptor & x) +{ + // assert(p); + assert(g); + assert(x); + return get(get(p, g), x); +} + +template<> +struct property_map +{ + typedef cgraph_graph_name_map type; + typedef cgraph_graph_name_map const_type; +}; + +template<> +struct property_map +{ + typedef cgraph_graph_name_map type; + typedef cgraph_graph_name_map const_type; +}; + +template<> +struct property_map +{ + typedef cgraph_graph_name_map type; + typedef cgraph_graph_name_map const_type; +}; + +// @todo how are all the other graphviz properties be handled? + +/* MutablePropertyGraph */ + +template<> +struct edge_property_type +{ + typedef graph_traits::edge_property_type type; +}; + +std::pair::edge_descriptor, bool> add_edge(graph_traits::vertex_descriptor u, graph_traits::vertex_descriptor v, graph_traits::edge_property_type ep, cgraph_graph_ptr g) +{ + assert(u); + assert(v); + assert(ep); + assert(g); + graph_traits::edge_descriptor edge = ::agedge(g, u, v, ep, 1); + return std::make_pair(edge, true); // @todo false if strict and edge exists already +} + +template<> +struct vertex_property_type +{ + typedef graph_traits::vertex_property_type type; +}; + +graph_traits::vertex_descriptor add_vertex(graph_traits::vertex_property_type vp, cgraph_graph_ptr g) +{ + assert(vp); + assert(g); + return ::agnode(g, vp, 1); +} + +} // namespace boost + +/* @todo got concept check failures (fpermissive) without this... */ +using boost::out_edges; +using boost::source; +using boost::target; +using boost::out_degree; +using boost::in_edges; +using boost::in_degree; +using boost::degree; +using boost::adjacent_vertices; +using boost::vertices; +using boost::num_vertices; +using boost::edges; +using boost::num_edges; +using boost::add_vertex; +using boost::clear_vertex; +using boost::remove_vertex; +using boost::add_edge; +using boost::remove_edge; +using boost::get; +using boost::put; + +#endif // BOOST_GRAPH_CGRAPH_GRAPH_HPP