<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef BISPANNING_GRAPH_HEADER
#define BISPANNING_GRAPH_HEADER
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <map>
#include <ostream>
#include <queue>
#include <sstream>
#include <vector>
#include "debug.h"
template <class VertexData, class EdgeData,
bool _directed,
bool _allow_parallel,
bool _allow_loops,
bool _allow_deletes>
class GraphBase
{
public:
using id_type = unsigned int;
using vertex_data_type = VertexData;
using edge_data_type = EdgeData;
enum { ID_INVALID = id_type(-1) };
class Vertex
{
public:
std::vector<id_type> edgelist;
VertexData data;
explicit Vertex(const VertexData& d)
: data(d)
{ }
inline bool deleted() const
{
if (!allow_deletes) return false;
return (edgelist.size() == 1 && edgelist[0] == ID_INVALID);
}
inline bool remove_edge(const id_type& e)
{
std::vector<id_type>::iterator it
= std::find(edgelist.begin(), edgelist.end(), e);
if (it == edgelist.end()) return false;
edgelist.erase(it);
return true;
}
};
class Edge
{
public:
id_type tail, head;
EdgeData data;
Edge(const id_type& t, const id_type& h, const EdgeData& d)
: tail(t), head(h), data(d)
{ }
inline bool deleted() const
{
if (!allow_deletes) return false;
return (tail == ID_INVALID && head == ID_INVALID);
}
inline const id_type & other_id(const id_type& v) const
{
assert(!deleted());
assert(v == head || v == tail);
return (v == head) ? tail : head;
}
friend std::ostream& operator << (std::ostream& os, const Edge& e)
{
return os << "(" << e.tail << "," << e.head << ")";
}
};
public:
enum { is_directed = _directed };
enum { is_undirected = !_directed };
enum { allow_loops = _allow_loops };
enum { allow_parallel = _allow_parallel };
enum { allow_deletes = _allow_deletes };
protected:
std::vector<Vertex> m_vertex;
std::vector<Edge> m_edge;
size_t m_vertex_deleted;
size_t m_edge_deleted;
public:
class vertex_iterator;
class const_vertex_iterator;
class edge_iterator;
class const_edge_iterator;
class vertex_edge_iterator;
class const_vertex_edge_iterator;
class vertex_iterator_range;
class const_vertex_iterator_range;
class edge_iterator_range;
class const_edge_iterator_range;
class vertex_edge_iterator_range;
class const_vertex_edge_iterator_range;
public:
explicit GraphBase(const id_type& n = 0, const VertexData& vd = VertexData())
: m_vertex(n, Vertex(vd)),
m_vertex_deleted(0), m_edge_deleted(0)
{ }
size_t num_vertex() const
{
if (!allow_deletes) return total_vertex();
return m_vertex.size() - m_vertex_deleted;
}
size_t total_vertex() const
{
return m_vertex.size();
}
size_t num_edge() const
{
if (!allow_deletes) return total_edge();
return m_edge.size() - m_edge_deleted;
}
size_t total_edge() const
{
return m_edge.size();
}
bool has_deleted() const
{
return (m_vertex_deleted != 0) || (m_edge_deleted != 0);
}
size_t vertex_num_edge(const id_type& v) const
{
assert(v < m_vertex.size());
assert(!m_vertex[v].deleted());
return m_vertex[v].edgelist.size();
}
protected:
Vertex & vertex_data(const id_type& v)
{
assert(v < m_vertex.size());
return m_vertex[v];
}
const Vertex & vertex_data(const id_type& v) const
{
assert(v < m_vertex.size());
return m_vertex[v];
}
Edge & edge_data(const id_type& e)
{
assert(e < m_edge.size());
return m_edge[e];
}
const Edge & edge_data(const id_type& e) const
{
assert(e < m_edge.size());
return m_edge[e];
}
id_type vertex_edge_id(const id_type& v, const id_type& e) const
{
assert(v < m_vertex.size());
assert(e < m_vertex[v].edgelist.size());
return m_vertex[v].edgelist[e];
}
Edge & vertex_edge_data(const id_type& v, const id_type& e)
{
assert(v < m_vertex.size());
assert(e < m_vertex[v].edgelist.size());
return edge_data(m_vertex[v].edgelist[e]);
}
const Edge & vertex_edge_data(const id_type& v, const id_type& e) const
{
assert(v < m_vertex.size());
assert(e < m_vertex[v].edgelist.size());
return edge_data(m_vertex[v].edgelist[e]);
}
public:
class vertex_iterator
{
private:
GraphBase* m_graph;
id_type m_id;
public:
vertex_iterator(GraphBase* g, const id_type& v)
: m_graph(g), m_id(v)
{
skip_deleted();
}
const GraphBase * graph() const
{
return m_graph;
}
const id_type & vertex_id() const
{
return m_id;
}
bool deleted() const
{
return m_graph->vertex_data(m_id).deleted();
}
id_type degree() const
{
assert(!deleted());
return m_graph->vertex_num_edge(m_id);
}
vertex_iterator& operator ++ ()
{
++m_id;
return skip_deleted();
}
vertex_iterator & skip_deleted()
{
while (m_id < m_graph->total_vertex() && deleted())
++m_id;
return *this;
}
const VertexData& operator * () const
{
assert(!deleted());
return m_graph->vertex_data(m_id).data;
}
VertexData& operator * ()
{
assert(!deleted());
return m_graph->vertex_data(m_id).data;
}
const VertexData* operator -> () const
{
assert(!deleted());
return &m_graph->vertex_data(m_id).data;
}
VertexData* operator -> ()
{
assert(!deleted());
return &m_graph->vertex_data(m_id).data;
}
vertex_edge_iterator edge_begin() const
{
return m_graph->vertex_edge_begin(m_id);
}
vertex_edge_iterator edge_end() const
{
return m_graph->vertex_edge_end(m_id);
}
vertex_edge_iterator edge(id_type ei) const
{
return m_graph->vertex_edge(m_id, ei);
}
vertex_edge_iterator_range edge_list() const
{
return m_graph->vertex_edge_list(m_id);
}
bool operator == (const vertex_iterator& a) const
{
return (m_graph == a.m_graph) && (m_id == a.m_id);
}
bool operator != (const vertex_iterator& a) const
{
return (m_graph != a.m_graph) || (m_id != a.m_id);
}
bool operator < (const vertex_iterator& a) const
{
if (m_graph != a.m_graph) return (m_graph < a.m_graph);
return (m_id < a.m_id);
}
friend std::ostream& operator << (std::ostream& os, const vertex_iterator& vi)
{
return os << "(" << vi.vertex_id() << ")";
}
};
vertex_iterator vertex_begin()
{
return vertex_iterator(this, 0);
}
vertex_iterator vertex_end()
{
return vertex_iterator(this, total_vertex());
}
public:
class const_vertex_iterator
{
private:
const GraphBase* m_graph;
id_type m_id;
public:
const_vertex_iterator(const GraphBase* g, const id_type& v)
: m_graph(g), m_id(v)
{
skip_deleted();
}
const GraphBase * graph() const
{
return m_graph;
}
const_vertex_iterator(const vertex_iterator& vi)
: m_graph(vi.graph()), m_id(vi.vertex_id())
{ }
const id_type & vertex_id() const
{
return m_id;
}
bool deleted() const
{
return m_graph->vertex_data(m_id).deleted();
}
id_type degree() const
{
assert(!deleted());
return m_graph->vertex_num_edge(m_id);
}
const_vertex_iterator& operator ++ ()
{
++m_id;
return skip_deleted();
}
const_vertex_iterator & skip_deleted()
{
while (m_id < m_graph->total_vertex() && deleted())
++m_id;
return *this;
}
const VertexData& operator * () const
{
assert(!deleted());
return m_graph->vertex_data(m_id).data;
}
const VertexData* operator -> () const
{
assert(!deleted());
return &m_graph->vertex_data(m_id).data;
}
const_vertex_edge_iterator edge_begin() const
{
return m_graph->vertex_edge_begin(m_id);
}
const_vertex_edge_iterator edge_end() const
{
return m_graph->vertex_edge_end(m_id);
}
const_vertex_edge_iterator_range edge_list() const
{
return m_graph->vertex_edge_list(m_id);
}
const_vertex_edge_iterator edge(id_type ei) const
{
return m_graph->vertex_edge(m_id, ei);
}
bool operator == (const const_vertex_iterator& a) const
{
return (m_graph == a.m_graph) && (m_id == a.m_id);
}
bool operator != (const const_vertex_iterator& a) const
{
return (m_graph != a.m_graph) || (m_id != a.m_id);
}
bool operator < (const const_vertex_iterator& a) const
{
if (m_graph != a.m_graph) return (m_graph < a.m_graph);
return (m_id < a.m_id);
}
friend std::ostream& operator << (std::ostream& os, const const_vertex_iterator& vi)
{
return os << "(" << vi.vertex_id() << ")";
}
};
const_vertex_iterator vertex_begin() const
{
return const_vertex_iterator(this, 0);
}
const_vertex_iterator vertex_end() const
{
return const_vertex_iterator(this, total_vertex());
}
bool contains(const const_vertex_iterator& vi) const
{
return (vi.graph() == this);
}
public:
template <typename Iterator>
class iterator_proxy
{
public:
Iterator m_iter;
iterator_proxy(const Iterator& iter)
: m_iter(iter)
{ }
bool operator != (const iterator_proxy& i) const
{
return m_iter != i.m_iter;
}
iterator_proxy& operator ++ ()
{
++m_iter;
return *this;
}
Iterator& operator * ()
{
return m_iter;
}
};
class vertex_iterator_range
{
public:
GraphBase& m_graph;
using iterator_proxy_type = iterator_proxy<vertex_iterator>;
explicit vertex_iterator_range(GraphBase& graph)
: m_graph(graph)
{ }
iterator_proxy_type begin()
{
return m_graph.vertex_begin();
}
iterator_proxy_type end()
{
return m_graph.vertex_end();
}
};
class const_vertex_iterator_range
{
public:
const GraphBase& m_graph;
using iterator_proxy_type = iterator_proxy<const_vertex_iterator>;
explicit const_vertex_iterator_range(const GraphBase& graph)
: m_graph(graph)
{ }
iterator_proxy_type begin()
{
return m_graph.vertex_begin();
}
iterator_proxy_type end()
{
return m_graph.vertex_end();
}
};
vertex_iterator_range vertex_list()
{
return vertex_iterator_range(*this);
}
const_vertex_iterator_range vertex_list() const
{
return const_vertex_iterator_range(*this);
}
public:
class edge_iterator
{
private:
GraphBase* m_graph;
id_type m_id;
public:
edge_iterator(GraphBase* g, const id_type& e)
: m_graph(g), m_id(e)
{
skip_deleted();
}
edge_iterator(const vertex_edge_iterator& vei)
: m_graph(vei.graph()), m_id(vei.edge_id())
{ }
const GraphBase * graph() const
{
return m_graph;
}
const id_type & edge_id() const
{
return m_id;
}
bool deleted() const
{
return m_graph->edge_data(m_id).deleted();
}
edge_iterator& operator ++ ()
{
++m_id;
return skip_deleted();
}
edge_iterator & skip_deleted()
{
while (m_id < m_graph->total_edge() && deleted())
++m_id;
return *this;
}
const EdgeData& operator * () const
{
assert(!deleted());
return m_graph->edge_data(m_id).data;
}
EdgeData& operator * ()
{
assert(!deleted());
return m_graph->edge_data(m_id).data;
}
const EdgeData* operator -> () const
{
assert(!deleted());
return &m_graph->edge_data(m_id).data;
}
EdgeData* operator -> ()
{
assert(!deleted());
return &m_graph->edge_data(m_id).data;
}
const id_type & head_id() const
{
assert(!deleted());
return m_graph->edge_data(m_id).head;
}
const id_type & tail_id() const
{
assert(!deleted());
return m_graph->edge_data(m_id).tail;
}
vertex_iterator head() const
{
return m_graph->vertex(head_id());
}
vertex_iterator tail() const
{
return m_graph->vertex(tail_id());
}
const id_type & other_id(const id_type& v) const
{
assert(!deleted());
return m_graph->edge_data(m_id).other_id(v);
}
const id_type & other_id(const const_vertex_iterator& vi) const
{
return other_id(vi.vertex_id());
}
vertex_iterator other(const id_type& v) const
{
assert(v == head_id() || v == tail_id());
return m_graph->vertex(other_id(v));
}
vertex_iterator other(const const_vertex_iterator& vi) const
{
return other(vi.vertex_id());
}
bool operator == (const edge_iterator& a) const
{
return (m_graph == a.m_graph) && (m_id == a.m_id);
}
bool operator != (const edge_iterator& a) const
{
return (m_graph != a.m_graph) || (m_id != a.m_id);
}
bool operator < (const edge_iterator& a) const
{
assert(m_graph == a.m_graph);
return (m_id < a.m_id);
}
friend std::ostream& operator << (std::ostream& os, const edge_iterator& ei)
{
if (ei.graph()->is_directed)
return os << "(" << ei.edge_id() << "=(" << ei.head_id() << "," << ei.tail_id() << "))";
else
return os << "(" << ei.edge_id() << "={" << ei.head_id() << "," << ei.tail_id() << "})";
}
};
edge_iterator edge_begin()
{
return edge_iterator(this, 0);
}
edge_iterator edge_end()
{
return edge_iterator(this, total_edge());
}
public:
class const_edge_iterator
{
private:
const GraphBase* m_graph;
id_type m_id;
public:
const_edge_iterator(const GraphBase* g, const id_type& e)
: m_graph(g), m_id(e)
{
skip_deleted();
}
const_edge_iterator(const edge_iterator& ei)
: m_graph(ei.graph()), m_id(ei.edge_id())
{ }
const_edge_iterator(const const_vertex_edge_iterator& vei)
: m_graph(vei.graph()), m_id(vei.edge_id())
{ }
const GraphBase * graph() const
{
return m_graph;
}
const id_type & edge_id() const
{
return m_id;
}
bool deleted() const
{
return m_graph->edge_data(m_id).deleted();
}
const_edge_iterator& operator ++ ()
{
++m_id;
return skip_deleted();
}
const_edge_iterator & skip_deleted()
{
while (m_id < m_graph->total_edge() && deleted())
++m_id;
return *this;
}
const EdgeData& operator * () const
{
assert(!deleted());
return m_graph->edge_data(m_id).data;
}
const EdgeData* operator -> () const
{
assert(!deleted());
return &m_graph->edge_data(m_id).data;
}
const id_type & head_id() const
{
assert(!deleted());
return m_graph->edge_data(m_id).head;
}
const id_type & tail_id() const
{
assert(!deleted());
return m_graph->edge_data(m_id).tail;
}
const_vertex_iterator head() const
{
return m_graph->vertex(head_id());
}
const_vertex_iterator tail() const
{
return m_graph->vertex(tail_id());
}
const id_type & other_id(const id_type& v) const
{
assert(!deleted());
return m_graph->edge_data(m_id).other_id(v);
}
const id_type & other_id(const const_vertex_iterator& vi) const
{
return other_id(vi.vertex_id());
}
const_vertex_iterator other(const id_type& v) const
{
assert(v == head_id() || v == tail_id());
return m_graph->vertex(other_id(v));
}
const_vertex_iterator other(const const_vertex_iterator& vi) const
{
return other(vi.vertex_id());
}
bool operator == (const const_edge_iterator& a) const
{
return (m_graph == a.m_graph) && (m_id == a.m_id);
}
bool operator != (const const_edge_iterator& a) const
{
return (m_graph != a.m_graph) || (m_id != a.m_id);
}
bool operator < (const const_edge_iterator& a) const
{
assert(m_graph == a.m_graph);
return (m_id < a.m_id);
}
friend std::ostream& operator << (std::ostream& os, const const_edge_iterator& ei)
{
if (ei.graph()->is_directed)
return os << "(" << ei.edge_id() << "=(" << ei.head_id() << "," << ei.tail_id() << "))";
else
return os << "(" << ei.edge_id() << "={" << ei.head_id() << "," << ei.tail_id() << "})";
}
};
const_edge_iterator edge_begin() const
{
return const_edge_iterator(this, 0);
}
const_edge_iterator edge_end() const
{
return const_edge_iterator(this, total_edge());
}
bool contains(const const_edge_iterator& ei) const
{
return (ei.graph() == this);
}
public:
class edge_iterator_range
{
public:
GraphBase& m_graph;
using iterator_proxy_type = iterator_proxy<edge_iterator>;
explicit edge_iterator_range(GraphBase& graph)
: m_graph(graph)
{ }
iterator_proxy_type begin()
{
return m_graph.edge_begin();
}
iterator_proxy_type end()
{
return m_graph.edge_end();
}
};
class const_edge_iterator_range
{
public:
const GraphBase& m_graph;
using iterator_proxy_type = iterator_proxy<const_edge_iterator>;
explicit const_edge_iterator_range(const GraphBase& graph)
: m_graph(graph)
{ }
iterator_proxy_type begin()
{
return m_graph.edge_begin();
}
iterator_proxy_type end()
{
return m_graph.edge_end();
}
};
edge_iterator_range edge_list()
{
return edge_iterator_range(*this);
}
const_edge_iterator_range edge_list() const
{
return const_edge_iterator_range(*this);
}
public:
class vertex_edge_iterator
{
private:
GraphBase* m_graph;
id_type m_vertex;
id_type m_edge;
public:
vertex_edge_iterator(GraphBase* g, const id_type& v, const id_type& e)
: m_graph(g), m_vertex(v), m_edge(e)
{
assert(!g->vertex_deleted(v));
skip_deleted();
}
GraphBase * graph() const
{
return m_graph;
}
const id_type & vertex_id() const
{
return m_vertex;
}
const id_type & vertex_edge_id() const
{
return m_edge;
}
id_type edge_id() const
{
return m_graph->vertex_edge_id(m_vertex, m_edge);
}
bool deleted() const
{
return m_graph->vertex_edge_data(m_vertex, m_edge).deleted();
}
id_type degree() const
{
assert(!deleted());
return m_graph->vertex_num_edge(m_vertex);
}
vertex_edge_iterator& operator ++ ()
{
++m_edge;
return skip_deleted();
}
vertex_edge_iterator & skip_deleted()
{
while (m_edge < m_graph->vertex_num_edge(m_vertex) && deleted())
++m_edge;
return *this;
}
const EdgeData& operator * () const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
EdgeData& operator * ()
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
const EdgeData* operator -> () const
{
assert(!deleted());
return &m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
EdgeData* operator -> ()
{
assert(!deleted());
return &m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
const id_type & head_id() const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).head;
}
const id_type & tail_id() const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).tail;
}
vertex_iterator head() const
{
return m_graph->vertex(head_id());
}
vertex_iterator tail() const
{
return m_graph->vertex(tail_id());
}
const id_type & other_id(const id_type& v) const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).other_id(v);
}
const id_type & other_id(const const_vertex_iterator& vi) const
{
return other_id(vi.vertex_id());
}
vertex_iterator other(const id_type& v) const
{
assert(v == head_id() || v == tail_id());
return m_graph->vertex(other_id(v));
}
vertex_iterator other(const const_vertex_iterator& vi) const
{
return other(vi.vertex_id());
}
bool operator == (const vertex_edge_iterator& a) const
{
return (m_graph == a.m_graph) && (m_vertex == a.m_vertex) && (m_edge == a.m_edge);
}
bool operator != (const vertex_edge_iterator& a) const
{
return (m_graph != a.m_graph) || (m_vertex != a.m_vertex) || (m_edge != a.m_edge);
}
bool operator < (const vertex_edge_iterator& a) const
{
if (m_graph != a.m_graph) return (m_graph < a.m_graph);
if (m_vertex != a.m_vertex) return (m_vertex < a.m_vertex);
return (m_edge < a.m_edge);
}
operator edge_iterator () const
{
return edge_iterator(m_graph, edge_id());
}
friend std::ostream& operator << (std::ostream& os, const vertex_edge_iterator& ei)
{
if (ei.graph()->is_directed)
return os << "(" << ei.edge_id() << "=(" << ei.head_id() << "," << ei.tail_id() << "))";
else
return os << "(" << ei.edge_id() << "={" << ei.head_id() << "," << ei.tail_id() << "})";
}
};
vertex_edge_iterator vertex_edge_begin(const id_type& v)
{
return vertex_edge_iterator(this, v, 0);
}
vertex_edge_iterator vertex_edge_end(const id_type& v)
{
return vertex_edge_iterator(this, v, vertex_num_edge(v));
}
vertex_edge_iterator vertex_edge_begin(const const_vertex_iterator& vi)
{
return vertex_edge_begin(vi.vertex_id());
}
vertex_edge_iterator vertex_edge_end(const const_vertex_iterator& vi)
{
return vertex_edge_end(vi.vertex_id());
}
public:
class const_vertex_edge_iterator
{
private:
const GraphBase* m_graph;
id_type m_vertex;
id_type m_edge;
public:
const_vertex_edge_iterator(const GraphBase* g, const id_type& v, const id_type& ei)
: m_graph(g), m_vertex(v), m_edge(ei)
{
assert(!g->vertex_deleted(v));
skip_deleted();
}
const_vertex_edge_iterator(const vertex_edge_iterator& vi)
: m_graph(vi.graph()), m_vertex(vi.vertex_id()), m_edge(vi.vertex_edge_id())
{ }
const GraphBase * graph() const
{
return m_graph;
}
const id_type & vertex_id() const
{
return m_vertex;
}
id_type edge_id() const
{
return m_graph->vertex_edge_id(m_vertex, m_edge);
}
bool deleted() const
{
return m_graph->vertex_edge_data(m_vertex, m_edge).deleted();
}
id_type degree() const
{
assert(!deleted());
return m_graph->vertex_num_edge(m_vertex);
}
const_vertex_edge_iterator& operator ++ ()
{
++m_edge;
return skip_deleted();
}
const_vertex_edge_iterator & skip_deleted()
{
while (m_edge < m_graph->vertex_num_edge(m_vertex) && deleted())
++m_edge;
return *this;
}
const EdgeData& operator * () const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
const EdgeData* operator -> () const
{
assert(!deleted());
return &m_graph->vertex_edge_data(m_vertex, m_edge).data;
}
const id_type & head_id() const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).head;
}
const id_type & tail_id() const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).tail;
}
const_vertex_iterator head() const
{
return m_graph->vertex(head_id());
}
const_vertex_iterator tail() const
{
return m_graph->vertex(tail_id());
}
const id_type & other_id(const id_type& v) const
{
assert(!deleted());
return m_graph->vertex_edge_data(m_vertex, m_edge).other_id(v);
}
const id_type & other_id(const const_vertex_iterator& vi) const
{
return other_id(vi.vertex_id());
}
const_vertex_iterator other(const id_type& v) const
{
assert(v == head_id() || v == tail_id());
return m_graph->vertex(other_id(v));
}
const_vertex_iterator other(const const_vertex_iterator& vi) const
{
return other(vi.vertex_id());
}
bool operator == (const const_vertex_edge_iterator& a) const
{
return (m_graph == a.m_graph) && (m_vertex == a.m_vertex) && (m_edge == a.m_edge);
}
bool operator != (const const_vertex_edge_iterator& a) const
{
return (m_graph != a.m_graph) || (m_vertex != a.m_vertex) || (m_edge != a.m_edge);
}
operator const_edge_iterator () const
{
return const_edge_iterator(m_graph, edge_id());
}
friend std::ostream& operator << (std::ostream& os, const const_vertex_edge_iterator& e)
{
if (e.graph()->is_directed)
return os << "(" << e.edge_id() << "=(" << e.head_id() << "," << e.tail_id() << "))";
else
return os << "(" << e.edge_id() << "={" << e.head_id() << "," << e.tail_id() << "})";
}
};
const_vertex_edge_iterator vertex_edge_begin(const id_type& v) const
{
return const_vertex_edge_iterator(this, v, 0);
}
const_vertex_edge_iterator vertex_edge_end(const id_type& v) const
{
return const_vertex_edge_iterator(this, v, vertex_num_edge(v));
}
const_vertex_edge_iterator vertex_edge_begin(const const_vertex_iterator& vi) const
{
return vertex_edge_begin(vi.vertex_id());
}
const_vertex_edge_iterator vertex_edge_end(const const_vertex_iterator& vi) const
{
return vertex_edge_end(vi.vertex_id());
}
bool contains(const const_vertex_edge_iterator& vei) const
{
return (vei.graph() == this);
}
public:
class vertex_edge_iterator_range
{
public:
GraphBase& m_graph;
id_type m_v;
using iterator_proxy_type = iterator_proxy<vertex_edge_iterator>;
vertex_edge_iterator_range(GraphBase& graph, const id_type& v)
: m_graph(graph), m_v(v)
{ }
iterator_proxy_type begin()
{
return m_graph.vertex_edge_begin(m_v);
}
iterator_proxy_type end()
{
return m_graph.vertex_edge_end(m_v);
}
};
class const_vertex_edge_iterator_range
{
public:
const GraphBase& m_graph;
id_type m_v;
using iterator_proxy_type = iterator_proxy<const_vertex_edge_iterator>;
const_vertex_edge_iterator_range(const GraphBase& graph, const id_type& v)
: m_graph(graph), m_v(v)
{ }
iterator_proxy_type begin()
{
return m_graph.vertex_edge_begin(m_v);
}
iterator_proxy_type end()
{
return m_graph.vertex_edge_end(m_v);
}
};
vertex_edge_iterator_range vertex_edge_list(const id_type& v)
{
return vertex_edge_iterator_range(*this, v);
}
const_vertex_edge_iterator_range vertex_edge_list(const id_type& v) const
{
return const_vertex_edge_iterator_range(*this, v);
}
public:
bool vertex_deleted(const id_type& v) const
{
assert(v < m_vertex.size());
return m_vertex[v].deleted();
}
vertex_iterator vertex(const id_type& v)
{
assert(v < m_vertex.size());
assert(!m_vertex[v].deleted());
return vertex_iterator(this, v);
}
const_vertex_iterator vertex(const id_type& v) const
{
assert(v < m_vertex.size());
assert(!m_vertex[v].deleted());
return const_vertex_iterator(this, v);
}
bool edge_deleted(const id_type& e) const
{
assert(e < m_edge.size());
return m_edge[e].deleted();
}
edge_iterator edge(const id_type& e)
{
assert(e < m_edge.size());
assert(!m_edge[e].deleted());
return edge_iterator(this, e);
}
const_edge_iterator edge(const id_type& e) const
{
assert(e < m_edge.size());
assert(!m_edge[e].deleted());
return const_edge_iterator(this, e);
}
vertex_edge_iterator vertex_edge(const id_type& v, const id_type& e)
{
assert(v < m_vertex.size());
assert(e < m_vertex[v].edgelist.size());
assert(m_vertex[v].edgelist[e] < m_edge.size());
assert(!m_edge[m_vertex[v].edgelist[e]].deleted());
return vertex_edge_iterator(this, v, e);
}
const_vertex_edge_iterator vertex_edge(const id_type& v, const id_type& e) const
{
assert(v < m_vertex.size());
assert(e < m_vertex[v].edgelist.size());
assert(m_vertex[v].edgelist[e] < m_edge.size());
assert(!m_edge[m_vertex[v].edgelist[e]].deleted());
return const_vertex_edge_iterator(this, v, e);
}
vertex_edge_iterator vertex_edge(const const_vertex_iterator& vi, const id_type& e)
{
return vertex_edge(vi.vertex_id(), e);
}
const_vertex_edge_iterator vertex_edge(const const_vertex_iterator& vi, const id_type& e) const
{
return vertex_edge(vi.vertex_id(), e);
}
public:
vertex_iterator add_vertex(const VertexData& v = VertexData())
{
m_vertex.push_back(Vertex(v));
return vertex_iterator(this, total_vertex() - 1);
}
edge_iterator add_edge(const id_type& tail, const id_type& head, const EdgeData& e = EdgeData())
{
assert(tail < m_vertex.size());
assert(head < m_vertex.size());
assert(allow_loops || tail != head);
assert(allow_parallel || find_edge(tail, head) == edge_end());
assert(is_directed || allow_parallel || find_edge(head, tail) == edge_end());
assert(!vertex_deleted(tail));
assert(!vertex_deleted(head));
m_vertex[tail].edgelist.push_back(total_edge());
if (is_undirected)
m_vertex[head].edgelist.push_back(total_edge());
m_edge.push_back(Edge(tail, head, e));
return edge_iterator(this, total_edge() - 1);
}
edge_iterator add_edge(const const_vertex_iterator& tail,
const const_vertex_iterator& head,
const EdgeData& e = EdgeData())
{
assert(contains(tail) && contains(head));
return add_edge(tail.vertex_id(), head.vertex_id(), e);
}
public:
template <bool Directed, bool AllowParallel, bool AllowLoops, bool AllowDeletes>
static GraphBase
copy_from(const GraphBase<VertexData, EdgeData, Directed, AllowParallel,
AllowLoops, AllowDeletes>& g)
{
typedef GraphBase<VertexData, EdgeData,
Directed, AllowParallel,
AllowLoops, AllowDeletes> other_type;
std::vector<id_type> vmap(g.total_vertex());
GraphBase out;
for (typename other_type::const_vertex_iterator vi = g.vertex_begin();
vi != g.vertex_end(); ++vi)
{
vertex_iterator nv = out.add_vertex(*vi);
vmap[vi.vertex_id()] = nv.vertex_id();
}
for (typename other_type::const_edge_iterator ei = g.edge_begin();
ei != g.edge_end(); ++ei)
{
out.add_edge(vmap[ei.tail_id()], vmap[ei.head_id()], *ei);
}
return out;
}
public:
edge_iterator find_edge(const id_type& tail, const id_type& head, id_type num = 0)
{
assert(tail < m_vertex.size());
assert(head < m_vertex.size());
assert(!vertex_deleted(tail));
assert(!vertex_deleted(head));
Vertex& v = m_vertex[tail];
for (size_t ei = 0; ei < v.edgelist.size(); ++ei)
{
const Edge& e = m_edge[v.edgelist[ei]];
if (e.deleted()) continue;
if (is_directed)
{
assert(e.tail == tail);
if (e.tail == tail && e.head == head)
{
if (num == 0)
return edge_iterator(this, v.edgelist[ei]);
--num;
}
}
else
{
assert(e.tail == tail || e.head == tail);
if ((e.tail == tail && e.head == head) ||
(e.tail == head && e.head == tail))
{
if (num == 0)
return edge_iterator(this, v.edgelist[ei]);
--num;
}
}
}
return edge_end();
}
edge_iterator find_edge(const const_vertex_iterator& tail,
const const_vertex_iterator& head, id_type num = 0)
{
assert(contains(tail) && contains(head));
return find_edge(tail.vertex_id(), head.vertex_id(), num);
}
const_edge_iterator find_edge(const id_type& tail, const id_type& head, id_type num = 0) const
{
assert(tail < m_vertex.size());
assert(head < m_vertex.size());
assert(!vertex_deleted(tail));
assert(!vertex_deleted(head));
const Vertex& v = m_vertex[tail];
for (size_t ei = 0; ei < v.edgelist.size(); ++ei)
{
const Edge& e = m_edge[v.edgelist[ei]];
if (e.deleted()) continue;
if (is_directed)
{
assert(e.tail == tail);
if (e.tail == tail && e.head == head)
{
if (num == 0)
return const_edge_iterator(this, v.edgelist[ei]);
--num;
}
}
else
{
assert(e.tail == tail || e.head == tail);
if ((e.tail == tail && e.head == head) ||
(e.tail == head && e.head == tail))
{
if (num == 0)
return const_edge_iterator(this, v.edgelist[ei]);
--num;
}
}
}
return edge_end();
}
const_edge_iterator find_edge(const const_vertex_iterator& tail,
const const_vertex_iterator& head,
id_type num = 0) const
{
assert(contains(tail) && contains(head));
return find_edge(tail.vertex_id(), head.vertex_id(), num);
}
id_type count_edges(const id_type& tail, const id_type& head) const
{
assert(tail < m_vertex.size());
assert(head < m_vertex.size());
assert(!vertex_deleted(tail));
assert(!vertex_deleted(head));
const Vertex& v = m_vertex[tail];
id_type num = 0;
for (size_t ei = 0; ei < v.edgelist.size(); ++ei)
{
const Edge& e = m_edge[v.edgelist[ei]];
if (e.deleted()) continue;
if (is_directed)
{
assert(e.tail == tail);
if (e.tail == tail && e.head == head)
{
++num;
}
}
else
{
assert(e.tail == tail || e.head == tail);
if ((e.tail == tail && e.head == head) ||
(e.tail == head && e.head == tail))
{
++num;
}
}
}
return num;
}
id_type count_edges(const const_vertex_iterator& tail,
const const_vertex_iterator& head) const
{
assert(contains(tail) && contains(head));
return count_edges(tail.vertex_id(), head.vertex_id());
}
id_type count_edges(const const_edge_iterator& ei) const
{
assert(contains(ei));
return count_edges(ei.tail_id(), ei.head_id());
}
id_type count_edges(id_type e) const
{
return count_edges(edge(e));
}
public:
bool delete_edge_reorder(const id_type& e)
{
assert(allow_deletes);
assert(e < m_edge.size());
assert(!edge_deleted(e));
m_edge.erase(m_edge.begin() + e);
unsigned int delcount = 0;
for (size_t vi = 0; vi < m_vertex.size(); ++vi)
{
Vertex& v = m_vertex[vi];
if (v.deleted()) continue;
for (size_t i = 0; i < v.edgelist.size(); ++i)
{
if (v.edgelist[i] < e) {
}
else if (v.edgelist[i] == e) {
v.edgelist.erase(v.edgelist.begin() + i);
--i;
++delcount;
}
else {
v.edgelist[i]--;
}
}
}
assert(delcount == (is_directed ? 1 : 2));
return true;
}
bool delete_edge_reorder(const const_edge_iterator& ei)
{
assert(contains(ei));
return delete_edge_reorder(ei.edge_id());
}
public:
bool delete_vertex(const id_type& v)
{
assert(allow_deletes);
assert(v < m_vertex.size());
assert(!vertex_deleted(v));
for (edge_iterator ei = edge_begin(); ei != edge_end(); ++ei)
{
if (ei.tail_id() == v || ei.head_id() == v)
delete_edge(ei);
}
assert(m_vertex[v].edgelist.size() == 0);
m_vertex[v].edgelist.resize(1);
m_vertex[v].edgelist[0] = ID_INVALID;
++m_vertex_deleted;
return true;
}
bool delete_vertex(const const_vertex_iterator& vi)
{
assert(contains(vi));
return delete_vertex(vi.vertex_id());
}
public:
bool delete_edge(const id_type& e)
{
assert(allow_deletes);
assert(e < m_edge.size());
assert(!edge_deleted(e));
m_edge[e].tail = m_edge[e].head = ID_INVALID;
++m_edge_deleted;
unsigned int delcount = 0;
for (size_t vi = 0; vi < m_vertex.size(); ++vi)
{
Vertex& v = m_vertex[vi];
if (v.deleted()) continue;
for (std::vector<id_type>::iterator it = v.edgelist.begin();
it != v.edgelist.end(); )
{
if (*it == e) {
it = v.edgelist.erase(it);
++delcount;
}
else
++it;
}
}
assert(delcount == (is_directed ? 1 : 2));
return true;
}
bool delete_edge(const const_edge_iterator& ei)
{
assert(contains(ei));
return delete_edge(ei.edge_id());
}
bool delete_edge(const const_vertex_edge_iterator& ei)
{
assert(contains(ei));
return delete_edge(ei.edge_id());
}
void add_deleted_edge(const EdgeData& e = EdgeData())
{
assert(allow_deletes);
m_edge.push_back(Edge(ID_INVALID, ID_INVALID, e));
++m_edge_deleted;
}
public:
bool contract(id_type v1, id_type v2)
{
assert(allow_deletes);
assert(allow_parallel);
assert(!is_directed);
for (id_type e = 0; e < total_edge(); ++e)
{
if (edge_deleted(e)) continue;
if (m_edge[e].head == v2)
{
if (m_edge[e].tail == v1 && !allow_loops) {
delete_edge(e);
}
else {
m_edge[e].head = v1;
m_vertex[v2].remove_edge(e);
m_vertex[v1].edgelist.push_back(e);
}
}
else if (m_edge[e].tail == v2)
{
if (m_edge[e].head == v1 && !allow_loops) {
delete_edge(e);
}
else {
m_edge[e].tail = v1;
m_vertex[v2].remove_edge(e);
m_vertex[v1].edgelist.push_back(e);
}
}
}
delete_vertex(v2);
return true;
}
bool contract(const edge_iterator& ei)
{
assert(contains(ei));
return contract(ei.tail_id(), ei.head_id());
}
public:
friend std::ostream& operator << (std::ostream& os, const GraphBase& g)
{
os << (g.is_directed ? "digraph" : "graph") << " G {\n";
for (const_vertex_iterator v = g.vertex_begin(); v != g.vertex_end(); ++v)
{
os << " " << v.vertex_id() << ';' << std::endl;
}
for (const_edge_iterator e = g.edge_begin(); e != g.edge_end(); ++e)
{
os << " " << e.head_id()
<< (g.is_directed ? " -> " : " -- ")
<< e.tail_id() << ';' << std::endl;
}
os << '}';
return os;
}
public:
template <typename CloneType = GraphBase>
CloneType clone_reorder_degree() const
{
using vdegpair = std::pair<id_type, unsigned int>;
std::vector<vdegpair> vdeg;
vdeg.reserve(num_vertex());
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
vdeg.push_back(std::make_pair(vi.vertex_id(), vi.degree()));
}
std::sort(vdeg.begin(), vdeg.end(),
[](const vdegpair& a, const vdegpair& b) {
if (a.second == b.second) return a.first < b.first;
return a.second > b.second;
});
CloneType h;
std::vector<id_type> vmap(total_vertex(), ID_INVALID);
for (unsigned int i = 0; i < vdeg.size(); ++i)
{
vmap[vdeg[i].first] = i;
h.add_vertex(vertex_data(vdeg[i].first).data);
}
for (const_edge_iterator ei = edge_begin(); ei != edge_end(); ++ei)
{
h.add_edge(vmap[ei.tail_id()], vmap[ei.head_id()], *ei);
}
return h;
}
template <typename CloneType = GraphBase>
CloneType clone_reorder_degree(std::map<id_type, id_type>& _vmap,
std::map<id_type, id_type>& _emap) const
{
using vdegpair = std::pair<id_type, unsigned int>;
std::vector<vdegpair> vdeg;
vdeg.reserve(num_vertex());
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
vdeg.push_back(std::make_pair(vi.vertex_id(), vi.degree()));
}
std::sort(vdeg.begin(), vdeg.end(),
[](const vdegpair& a, const vdegpair& b) {
if (a.second == b.second) return a.first < b.first;
return b.second < a.second;
});
CloneType h;
std::vector<id_type> vmap(total_vertex(), ID_INVALID);
for (unsigned int i = 0; i < vdeg.size(); ++i)
{
vmap[vdeg[i].first] = i;
_vmap[vdeg[i].first] = i;
h.add_vertex(vertex_data(vdeg[i].first).data);
}
for (const_edge_iterator ei = edge_begin(); ei != edge_end(); ++ei)
{
typename CloneType::edge_iterator en =
h.add_edge(vmap[ei.tail_id()], vmap[ei.head_id()], *ei);
_emap[ei.edge_id()] = en.edge_id();
}
return h;
}
public:
int get_regularity() const
{
if (num_vertex() == 0) return 0;
const_vertex_iterator vi = vertex_begin();
int reg = vi.degree();
while (vi != vertex_end())
{
if (static_cast<int>(vi.degree()) != reg)
return -1;
++vi;
}
return reg;
}
unsigned int get_min_degree() const
{
if (num_vertex() == 0) return 0;
const_vertex_iterator vi = vertex_begin();
unsigned int mindeg = vi.degree();
while (vi != vertex_end())
{
if (vi.degree() < mindeg) {
mindeg = vi.degree();
}
++vi;
}
return mindeg;
}
unsigned int get_max_degree() const
{
if (num_vertex() == 0) return 0;
const_vertex_iterator vi = vertex_begin();
unsigned int maxdeg = vi.degree();
while (vi != vertex_end())
{
if (vi.degree() > maxdeg) {
maxdeg = vi.degree();
}
++vi;
}
return maxdeg;
}
double get_avg_degree() const
{
if (num_vertex() == 0) return 0;
const_vertex_iterator vi = vertex_begin();
unsigned int sumdeg = 0;
while (vi != vertex_end())
{
sumdeg += vi.degree();
++vi;
}
return sumdeg / static_cast<double>(num_vertex());
}
size_t count_degree(size_t deg) const
{
size_t count = 0;
for (const_vertex_iterator vi = vertex_begin();
vi != vertex_end(); ++vi)
{
if (vi.degree() == deg) ++count;
}
return count;
}
std::string get_degree_sequence() const
{
if (num_vertex() == 0) return "";
std::vector<id_type> deg;
deg.reserve(num_vertex());
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
deg.push_back(vi.degree());
}
std::sort(deg.begin(), deg.end(), std::greater<id_type>());
std::ostringstream oss;
for (size_t i = 0; i < deg.size(); ++i)
{
if (i != 0) oss << ',';
oss << deg[i];
}
return oss.str();
}
vertex_iterator find_vertex_degree(unsigned int deg)
{
for (vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
if (vi.degree() == deg) return vi;
}
return vertex_end();
}
const_vertex_iterator find_vertex_degree(unsigned int deg) const
{
for (const_vertex_iterator vi = vertex_begin();
vi != vertex_end(); ++vi)
{
if (vi.degree() == deg) return vi;
}
return vertex_end();
}
class DefaultFilter
{
public:
static bool filter_vertex(const const_vertex_iterator&)
{
return false;
}
static bool filter_edge(const const_edge_iterator&)
{
return false;
}
};
template <typename GraphFilter = DefaultFilter>
id_type get_num_components_undirected(GraphFilter gf = DefaultFilter()) const
{
std::vector<id_type> pred(total_vertex(), ID_INVALID);
id_type num_components = 0;
for (size_t i = 0; i < pred.size(); ++i)
pred[i] = i;
std::queue<id_type> queue;
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
if (gf.filter_vertex(vi)) continue;
id_type r = vi.vertex_id();
if (pred[r] != r) continue;
++num_components;
queue.push(r);
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (pred[w] != w || w == r)
continue;
queue.push(w);
pred[w] = v;
}
}
}
return num_components;
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type>
get_component_sizes_undirected(GraphFilter gf = DefaultFilter()) const
{
std::vector<id_type> pred(total_vertex(), ID_INVALID);
std::vector<id_type> num_vertices;
for (size_t i = 0; i < pred.size(); ++i)
pred[i] = i;
std::queue<id_type> queue;
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
if (gf.filter_vertex(vi)) continue;
id_type r = vi.vertex_id();
if (pred[r] != r) continue;
num_vertices.push_back(0);
queue.push(r);
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
num_vertices.back()++;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (pred[w] != w || w == r)
continue;
queue.push(w);
pred[w] = v;
}
}
}
return num_vertices;
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type>
get_component_id_undirected(GraphFilter gf = DefaultFilter()) const
{
std::vector<id_type> comp(total_vertex(), ID_INVALID);
unsigned int c = 0;
std::queue<id_type> queue;
for (const_vertex_iterator vi = vertex_begin(); vi != vertex_end(); ++vi)
{
if (gf.filter_vertex(vi)) continue;
id_type r = vi.vertex_id();
if (comp[r] != ID_INVALID) continue;
comp[r] = c;
queue.push(r);
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (comp[w] != ID_INVALID)
continue;
queue.push(w);
comp[w] = c;
}
}
c++;
}
return comp;
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type>
get_connected_undirected(id_type r, GraphFilter gf = DefaultFilter()) const
{
std::vector<id_type> vlist;
if (gf.filter_vertex(vertex(r))) return vlist;
std::vector<id_type> pred(total_vertex(), ID_INVALID);
for (size_t i = 0; i < pred.size(); ++i)
pred[i] = i;
std::queue<id_type> queue;
queue.push(r);
vlist.push_back(r);
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (pred[w] != w || w == r)
continue;
queue.push(w);
vlist.push_back(w);
pred[w] = v;
}
}
return vlist;
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type>
get_connected_undirected(const_vertex_iterator vi,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(vi));
return get_connected_undirected(vi.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
class AlgStrongConnectedComponents
{
public:
id_type num_components;
protected:
GraphBase m_g;
GraphFilter m_gf;
id_type m_dfs;
std::vector<id_type> m_index, m_lowlink;
std::vector<id_type> m_stack;
bool stack_contains(const id_type& v)
{
for (size_t i = 0; i < m_stack.size(); ++i) {
if (m_stack[i] == v) return true;
}
return false;
}
void strongconnect(const id_type& v)
{
m_index[v] = m_lowlink[v] = m_dfs++;
m_stack.push_back(v);
for (const_vertex_edge_iterator ei = m_g.vertex_edge_begin(v);
ei != m_g.vertex_edge_end(v); ++ei)
{
if (m_gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (m_gf.filter_vertex(m_g.vertex(w))) continue;
if (m_index[w] == ID_INVALID)
{
strongconnect(w);
m_lowlink[v] = std::min(m_lowlink[v], m_lowlink[w]);
}
else if (stack_contains(w))
{
m_lowlink[v] = std::min(m_lowlink[v], m_lowlink[w]);
}
}
if (m_lowlink[v] == m_index[v])
{
m_stack.clear();
++num_components;
}
}
public:
AlgStrongConnectedComponents(const GraphBase& g, GraphFilter gf)
: num_components(0),
m_g(g), m_gf(gf),
m_dfs(0),
m_index(g.total_vertex(), ID_INVALID),
m_lowlink(g.total_vertex(), ID_INVALID)
{
for (const_vertex_iterator vi = g.vertex_begin();
vi != g.vertex_end(); ++vi)
{
if (m_gf.filter_vertex(vi)) continue;
if (m_index[vi.vertex_id()] == ID_INVALID)
strongconnect(vi.vertex_id());
}
}
};
template <typename GraphFilter = DefaultFilter>
id_type get_num_components_directed(GraphFilter gf = DefaultFilter()) const
{
return AlgStrongConnectedComponents<GraphFilter>(*this, gf).num_components;
}
template <typename GraphFilter = DefaultFilter>
id_type get_num_components(GraphFilter gf = DefaultFilter()) const
{
if (is_undirected)
return get_num_components_undirected(gf);
else
return get_num_components_directed(gf);
}
template <typename GraphFilter = DefaultFilter>
bool is_connected(GraphFilter gf = DefaultFilter()) const
{
return (get_num_components(gf) == 1);
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type> get_bfs_distance(id_type root,
GraphFilter gf = DefaultFilter()) const
{
std::vector<id_type> pred(total_vertex(), ID_INVALID);
std::vector<id_type> dist(total_vertex(), ID_INVALID);
id_type num_components = 0;
for (size_t i = 0; i < pred.size(); ++i)
pred[i] = i;
std::queue<id_type> queue;
if (gf.filter_vertex(vertex(root))) return dist;
queue.push(root);
dist[root] = 0;
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (pred[w] != w || w == root)
continue;
queue.push(w);
pred[w] = v;
dist[w] = dist[v] + 1;
}
}
return dist;
}
template <typename GraphFilter = DefaultFilter>
std::vector<id_type> get_bfs_distance(const_vertex_iterator root,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(root));
return get_bfs_distance(root.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
bool is_acyclic_undirected(GraphFilter gf = DefaultFilter()) const
{
assert(is_undirected);
std::vector<id_type> pred(total_vertex());
for (size_t i = 0; i < pred.size(); ++i)
pred[i] = i;
std::queue<id_type> queue;
for (const_vertex_iterator vi = vertex_begin();
vi != vertex_end(); ++vi)
{
if (gf.filter_vertex(vi)) continue;
id_type r = vi.vertex_id();
if (pred[r] != r) continue;
queue.push(r);
while (!queue.empty())
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (gf.filter_vertex(vertex(w))) continue;
if (w == pred[v])
continue;
if (pred[w] != w)
return false;
queue.push(w);
pred[w] = v;
}
}
}
return true;
}
template <typename GraphFilter = DefaultFilter>
bool is_acyclic_directed(GraphFilter = DefaultFilter()) const
{
assert(is_directed);
abort();
}
template <typename GraphFilter = DefaultFilter>
bool is_acyclic(GraphFilter gf = DefaultFilter()) const
{
if (is_undirected)
return is_acyclic_undirected(gf);
else
return is_acyclic_directed(gf);
}
template <typename GraphFilter = DefaultFilter>
bool is_cyclic(GraphFilter gf = DefaultFilter()) const
{
return !is_acyclic(gf);
}
template <typename GraphFilter = DefaultFilter>
std::vector<const_edge_iterator>
find_path(const id_type& s, const id_type& t,
GraphFilter gf = DefaultFilter()) const
{
std::vector<const_edge_iterator> p;
if (s == t) return p;
std::vector<id_type> pred(total_vertex(), ID_INVALID);
std::queue<id_type> queue;
queue.push(s);
while (!queue.empty() && pred[t] == ID_INVALID)
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (gf.filter_vertex(vertex(w))) continue;
if (pred[w] != ID_INVALID)
continue;
queue.push(w);
pred[w] = ei.edge_id();
}
}
assert(pred[t] != ID_INVALID);
id_type c = t;
while (c != s)
{
p.push_back(edge(pred[c]));
c = edge(pred[c]).other_id(c);
}
std::reverse(p.begin(), p.end());
return p;
}
template <typename GraphFilter = DefaultFilter>
std::vector<const_edge_iterator>
find_path(const const_vertex_iterator& s, const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(s) && contains(t));
return find_path(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
std::vector<edge_iterator>
find_path(const id_type& s, const id_type& t, GraphFilter gf = DefaultFilter())
{
std::vector<edge_iterator> p;
if (s == t) return p;
std::vector<id_type> pred(total_vertex(), ID_INVALID);
std::queue<id_type> queue;
queue.push(s);
while (!queue.empty() && pred[t] == ID_INVALID)
{
id_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v);
ei != vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (gf.filter_vertex(vertex(w))) continue;
if (pred[w] != ID_INVALID)
continue;
queue.push(w);
pred[w] = ei.edge_id();
}
}
assert(pred[t] != ID_INVALID);
id_type c = t;
while (c != s)
{
p.push_back(edge(pred[c]));
c = edge(pred[c]).other_id(c);
}
std::reverse(p.begin(), p.end());
return p;
}
template <typename GraphFilter = DefaultFilter>
std::vector<edge_iterator>
find_path(const const_vertex_iterator& s, const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter())
{
assert(contains(s) && contains(t));
return find_path(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
id_type get_distance(const id_type& s, const id_type& t, GraphFilter gf = DefaultFilter()) const
{
if (s == t) return 0;
std::vector<id_type> seen(total_vertex(), 0);
using pair_type = std::pair<id_type, id_type>;
std::queue<pair_type> queue;
queue.push(pair_type(s, 0));
seen[s] = 1;
while (!queue.empty())
{
pair_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v.first))) continue;
for (const_vertex_edge_iterator ei = vertex_edge_begin(v.first);
ei != vertex_edge_end(v.first); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v.first);
if (seen[w])
continue;
if (w == t) return v.second + 1;
seen[w] = 1;
queue.push(pair_type(w, v.second + 1));
}
}
return ID_INVALID;
}
template <typename GraphFilter = DefaultFilter>
id_type get_distance(const const_vertex_iterator& s, const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(s) && contains(t));
return get_distance(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter,
typename GraphType, typename EdgeIterator>
class AlgAllShortestPaths
{
protected:
using edgelist_type = std::vector<EdgeIterator>;
GraphType& gr;
id_type src, tgt;
using idlist_type = std::vector<id_type>;
std::vector<idlist_type> pred;
void dfs_predtree(std::vector<edgelist_type>& pathlist,
id_type v, const edgelist_type& path) const
{
if (v == src) {
pathlist.push_back(
edgelist_type(path.rbegin(), path.rend()));
return;
}
for (idlist_type::const_iterator ui = pred[v].begin();
ui != pred[v].end(); ++ui)
{
edgelist_type p = path;
p.push_back(gr.edge(*ui));
dfs_predtree(pathlist, p.back().other_id(v), p);
}
}
public:
AlgAllShortestPaths(const id_type& s, const id_type& t,
GraphType g, GraphFilter gf)
: gr(g),
src(s), tgt(t),
pred(g.total_vertex())
{
if (src == tgt) return;
id_type d = 0;
std::vector<id_type> dist(gr.total_vertex(), ID_INVALID);
std::queue<id_type> queue1, queue2;
queue2.push(src);
dist[src] = d;
while (!queue2.empty() && dist[t] == ID_INVALID)
{
std::swap(queue1, queue2);
++d;
while (!queue1.empty())
{
id_type v = queue1.front();
queue1.pop();
if (gf.filter_vertex(gr.vertex(v))) continue;
for (const_vertex_edge_iterator ei = gr.vertex_edge_begin(v);
ei != gr.vertex_edge_end(v); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v);
if (gf.filter_vertex(gr.vertex(w))) continue;
if (dist[w] == ID_INVALID)
{
dist[w] = d;
queue2.push(w);
}
if (dist[w] == d) {
pred[w].push_back(ei.edge_id());
}
}
}
}
assert(dist[t] != ID_INVALID);
}
std::vector<edgelist_type> get_pathlist() const
{
std::vector<edgelist_type> pathlist;
edgelist_type path;
dfs_predtree(pathlist, tgt, path);
return pathlist;
}
GraphBase get_bfs_graph() const
{
std::vector<id_type> seen(gr.total_vertex(), 0);
std::queue<id_type> queue1, queue2;
queue2.push(tgt);
seen[tgt] = 1;
while (!queue2.empty() && seen[src] == 0)
{
std::swap(queue1, queue2);
while (!queue1.empty())
{
id_type v = queue1.front();
queue1.pop();
for (idlist_type::const_iterator pi = pred[v].begin();
pi != pred[v].end(); ++pi)
{
EdgeIterator w = gr.edge(*pi);
id_type wi = w.other_id(v);
if (seen[wi]) continue;
seen[wi] = 1;
queue2.push(wi);
}
}
}
GraphBase bfs;
for (id_type v = 0; v < gr.total_vertex(); ++v)
{
if (seen[v]) {
vertex_iterator vi = bfs.add_vertex(*gr.vertex(v));
seen[v] = vi.vertex_id();
}
else {
seen[v] = ID_INVALID;
}
}
for (std::vector<idlist_type>::const_iterator pli = pred.begin();
pli != pred.end(); ++pli)
{
for (idlist_type::const_iterator pi = pli->begin();
pi != pli->end(); ++pi)
{
EdgeIterator e = gr.edge(*pi);
if (seen[e.tail_id()] == ID_INVALID) continue;
if (seen[e.head_id()] == ID_INVALID) continue;
bfs.add_edge(seen[e.tail_id()],
seen[e.head_id()], *e);
}
}
return bfs;
}
};
template <typename GraphFilter = DefaultFilter>
std::vector<std::vector<edge_iterator> >
find_all_shortest_paths(const id_type& s, const id_type& t,
GraphFilter gf = DefaultFilter())
{
return AlgAllShortestPaths<GraphFilter, GraphBase&, edge_iterator>
(s, t, *this, gf).get_pathlist();
}
template <typename GraphFilter = DefaultFilter>
std::vector<std::vector<edge_iterator> >
find_all_shortest_paths(const const_vertex_iterator& s,
const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter())
{
assert(contains(s) && contains(t));
return find_all_shortest_paths(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
std::vector<std::vector<const_edge_iterator> >
find_all_shortest_paths(const id_type& s, const id_type& t,
GraphFilter gf = DefaultFilter()) const
{
return AlgAllShortestPaths<GraphFilter, const GraphBase&, const_edge_iterator>
(s, t, *this, gf).get_pathlist();
}
template <typename GraphFilter = DefaultFilter>
std::vector<std::vector<const_edge_iterator> >
find_all_shortest_paths(const const_vertex_iterator& s,
const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(s) && contains(t));
return find_all_shortest_paths(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
GraphBase
get_all_shortest_path_graph(const id_type& s, const id_type& t,
GraphFilter gf = DefaultFilter())
{
return AlgAllShortestPaths<GraphFilter, GraphBase&, edge_iterator>
(s, t, *this, gf).get_bfs_graph();
}
template <typename GraphFilter = DefaultFilter>
GraphBase
get_all_shortest_path_graph(const const_vertex_iterator& s,
const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter())
{
assert(contains(s) && contains(t));
return get_all_shortest_path_graph(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
GraphBase
get_all_shortest_path_graph(const id_type& s, const id_type& t,
GraphFilter gf = DefaultFilter()) const
{
return AlgAllShortestPaths<GraphFilter, const GraphBase&, const_edge_iterator>
(s, t, *this, gf).get_bfs_graph();
}
template <typename GraphFilter = DefaultFilter>
GraphBase
get_all_shortest_path_graph(const const_vertex_iterator& s,
const const_vertex_iterator& t,
GraphFilter gf = DefaultFilter()) const
{
assert(contains(s) && contains(t));
return get_all_shortest_path_graph(s.vertex_id(), t.vertex_id(), gf);
}
template <typename GraphFilter = DefaultFilter>
id_type get_diameter(const_vertex_iterator* vSource = nullptr,
const_vertex_iterator* vTarget = nullptr,
GraphFilter gf = DefaultFilter()) const
{
unsigned int diam = 0;
std::vector<id_type> seen(total_vertex(), 0);
id_type seen_key = 0;
for (const_vertex_iterator r = vertex_begin(); r != vertex_end(); ++r)
{
if (gf.filter_vertex(r)) continue;
using pair_type = std::pair<id_type, id_type>;
std::queue<pair_type> queue;
queue.push(pair_type(r.vertex_id(), 0));
seen[r.vertex_id()] = ++seen_key;
while (!queue.empty())
{
pair_type v = queue.front();
queue.pop();
if (gf.filter_vertex(vertex(v.first))) continue;
if (v.second > diam)
{
diam = v.second;
if (vSource) *vSource = r;
if (vTarget) *vTarget = vertex(v.first);
}
for (const_vertex_edge_iterator ei = vertex_edge_begin(v.first);
ei != vertex_edge_end(v.first); ++ei)
{
if (gf.filter_edge(ei)) continue;
id_type w = ei.other_id(v.first);
if (seen[w] == seen_key)
continue;
seen[w] = seen_key;
queue.push(pair_type(w, v.second + 1));
}
}
}
return diam;
}
template <typename GraphTypeA, typename GraphTypeB>
class AlgIsomorphic
{
protected:
bool m_result;
const GraphTypeA& m_g1;
const GraphTypeB& m_g2;
using id_type = typename GraphTypeA::id_type;
using vertexA_iterator = typename GraphTypeA::const_vertex_iterator;
using edgeA_iterator = typename GraphTypeA::const_edge_iterator;
using vertexB_iterator = typename GraphTypeA::const_vertex_iterator;
using edgeB_iterator = typename GraphTypeA::const_edge_iterator;
std::vector<id_type> m_biject;
public:
AlgIsomorphic(const GraphTypeA& g1, const GraphTypeB& g2)
: m_result(false),
m_g1(g1), m_g2(g2)
{
if (g1.num_vertex() != g2.num_vertex() ||
g1.num_edge() != g2.num_edge() ||
g1.get_degree_sequence() != g2.get_degree_sequence())
{
return;
}
m_biject.resize(g1.total_vertex());
rec_buildmap(0, 0);
}
protected:
bool rec_buildmap(id_type deg, id_type vcover)
{
if (vcover == m_g1.num_vertex())
return check_bijection();
std::vector<id_type> vdeg1, vdeg2;
for (vertexA_iterator v = m_g1.vertex_begin(); v != m_g1.vertex_end(); ++v)
{
if (v.degree() == deg) vdeg1.push_back(v.vertex_id());
}
for (vertexB_iterator v = m_g2.vertex_begin(); v != m_g2.vertex_end(); ++v)
{
if (v.degree() == deg) vdeg2.push_back(v.vertex_id());
}
assert(vdeg1.size() == vdeg2.size());
do {
for (size_t i = 0; i < vdeg1.size(); ++i)
{
m_biject[vdeg1[i]] = vdeg2[i];
}
if (rec_buildmap(deg + 1, vcover + vdeg1.size())) return true;
}
while (std::next_permutation(vdeg1.begin(), vdeg1.end()));
return false;
}
bool check_bijection()
{
for (id_type v = 0; v < m_g1.total_vertex(); ++v)
{
if (m_g1.vertex_deleted(v)) continue;
assert(!m_g2.vertex_deleted(m_biject[v]));
if (m_g1.vertex(v).degree() != m_g2.vertex(m_biject[v]).degree()) {
assert(!"should not happen with degree permutation mapping");
return false;
}
}
std::vector<char> emarks(m_g2.total_edge(), false);
for (edgeA_iterator e1 = m_g1.edge_begin(); e1 != m_g1.edge_end(); ++e1)
{
id_type e1t = m_biject[e1.tail_id()], e1h = m_biject[e1.head_id()];
for (id_type inst = 0; ; ++inst)
{
edgeB_iterator e2 = m_g2.find_edge(e1t, e1h, inst);
if (e2 == m_g2.edge_end()) return false;
if (!emarks[e2.edge_id()]) {
emarks[e2.edge_id()] = true;
break;
}
}
}
for (id_type e = 0; e < m_g2.total_edge(); ++e)
{
if (!emarks[e] != m_g2.edge_deleted(e)) return false;
}
m_result = true;
return true;
}
public:
bool result() const
{
return m_result;
}
};
template <typename GraphTypeA, typename GraphTypeB>
static bool isomorphic(const GraphTypeA& g1, const GraphTypeB& g2)
{
return AlgIsomorphic<GraphTypeA, GraphTypeB>(g1, g2).result();
}
template <typename GraphTypeB>
bool isomorphic(const GraphTypeB& g2) const
{
return AlgIsomorphic<GraphBase, GraphTypeB>(*this, g2).result();
}
class IsomorphismCheck
{
protected:
using graphmap_type = std::multimap<std::string, GraphBase>;
graphmap_type m_graphmap;
public:
inline bool operator () (const GraphBase& g)
{
std::string id = g.get_degree_sequence();
for (typename graphmap_type::const_iterator gi = m_graphmap.find(id);
gi != m_graphmap.end() && gi->first == id; ++gi)
{
if (g.isomorphic(gi->second)) return false;
}
m_graphmap.insert(std::make_pair(id, g));
return true;
}
};
public:
using triangle_type = std::array<const_edge_iterator, 3>;
std::vector<triangle_type> find_triangles() const
{
std::vector<triangle_type> triangles;
for (const_edge_iterator e1 = edge_begin(); e1 != edge_end(); ++e1)
{
const_vertex_iterator v1 = e1.head();
const_vertex_iterator v2 = e1.tail();
for (const_vertex_edge_iterator v1e = v1.edge_begin();
v1e != v1.edge_end(); ++v1e)
{
if (v1e.edge_id() <= e1.edge_id()) continue;
for (const_vertex_edge_iterator v2e = v2.edge_begin();
v2e != v2.edge_end(); ++v2e)
{
if (v2e.edge_id() <= e1.edge_id()) continue;
if (v1e.edge_id() <= v2e.edge_id()) continue;
const_vertex_iterator v1o = v1e.other(v1);
const_vertex_iterator v2o = v2e.other(v2);
if (v1o != v2o) continue;
triangles.push_back(triangle_type { e1, v1e, v2e });
}
}
}
return triangles;
}
using triangle_vertex_type = std::array<const_vertex_iterator, 3>;
static triangle_vertex_type get_triangle_vertices(const triangle_type& tri)
{
const_vertex_iterator v1 = tri[0].head();
const_vertex_iterator v2 = tri[0].tail();
if (tri[1].head() == v1) {
return triangle_vertex_type { v1, v2, tri[1].tail() };
}
else if (tri[1].head() == v2) {
return triangle_vertex_type { v1, v2, tri[1].tail() };
}
else if (tri[1].tail() == v1) {
return triangle_vertex_type { v1, v2, tri[1].head() };
}
else if (tri[1].tail() == v2) {
return triangle_vertex_type { v1, v2, tri[1].head() };
}
else {
abort();
}
}
public:
void add_copy(const GraphBase& from)
{
id_type vbase = total_vertex();
for (const_vertex_iterator vi = from.vertex_begin();
vi != from.vertex_end(); ++vi)
{
add_vertex(*vi);
}
for (const_edge_iterator ei = from.edge_begin();
ei != from.edge_end(); ++ei)
{
add_edge(vbase + ei.tail_id(), vbase + ei.head_id(), *ei);
}
}
public:
template <typename ProductType, typename GraphType1, typename GraphType2>
class ProductObjectDataFactory
{
public:
using id_type = typename GraphBase::id_type;
using vertex_data_type = typename ProductType::vertex_data_type;
using edge_data_type = typename ProductType::edge_data_type;
using const_vertex_iterator1 = typename GraphType1::const_vertex_iterator;
using const_vertex_iterator2 = typename GraphType2::const_vertex_iterator;
using const_edge_iterator1 = typename GraphType1::const_edge_iterator;
using const_edge_iterator2 = typename GraphType2::const_edge_iterator;
vertex_data_type vertex(const const_vertex_iterator1&,
const const_vertex_iterator2&)
{
return vertex_data_type();
}
edge_data_type edge(const const_edge_iterator1&,
const const_vertex_iterator2&)
{
return edge_data_type();
}
edge_data_type edge(const const_vertex_iterator1&,
const const_edge_iterator2&)
{
return edge_data_type();
}
};
class SelfProductObjectDataFactory : public ProductObjectDataFactory<GraphBase, GraphBase, GraphBase>
{ };
template <typename ProductType,
typename GraphType1, typename GraphType2,
typename DataFactoryType = ProductObjectDataFactory<ProductType, GraphType1, GraphType2> >
static ProductType product(const GraphType1& g1, const GraphType2& g2,
DataFactoryType factory = DataFactoryType())
{
assert(!g1.has_deleted() && !g2.has_deleted());
id_type n1 = g1.num_vertex(), n2 = g2.num_vertex();
ProductType p;
for (typename GraphType1::const_vertex_iterator v1 = g1.vertex_begin();
v1 != g1.vertex_end(); ++v1)
{
for (typename GraphType2::const_vertex_iterator v2 = g2.vertex_begin();
v2 != g2.vertex_end(); ++v2)
{
p.add_vertex(factory.vertex(v1, v2));
}
}
for (typename GraphType1::const_edge_iterator e1 = g1.edge_begin();
e1 != g1.edge_end(); ++e1)
{
for (typename GraphType2::const_vertex_iterator v2 = g2.vertex_begin();
v2 != g2.vertex_end(); ++v2)
{
p.add_edge(e1.tail_id() * n2 + v2.vertex_id(),
e1.head_id() * n2 + v2.vertex_id(),
factory.edge(e1, v2));
}
}
for (typename GraphType1::const_vertex_iterator v1 = g1.vertex_begin();
v1 != g1.vertex_end(); ++v1)
{
for (typename GraphType2::const_edge_iterator e2 = g2.edge_begin();
e2 != g2.edge_end(); ++e2)
{
p.add_edge(v1.vertex_id() * n2 + e2.tail_id(),
v1.vertex_id() * n2 + e2.head_id(),
factory.edge(v1, e2));
}
}
return p;
}
};
template <class VertexData, class EdgeData, bool AllowDeletes = true>
using Graph = GraphBase<VertexData, EdgeData, false, false, false, AllowDeletes>;
template <class VertexData, class EdgeData, bool AllowDeletes = true>
using Digraph = GraphBase<VertexData, EdgeData, true, false, false, AllowDeletes>;
template <typename GraphType>
bool generate_random_graph(GraphType& out, unsigned int num_vertex, unsigned int num_edge,
unsigned int* seed)
{
GraphType g(num_vertex);
if (!g.allow_parallel)
{
unsigned int maxedges =
g.is_directed && g.allow_loops ? (num_vertex * num_vertex) :
g.is_directed && !g.allow_loops ? (num_vertex * num_vertex - num_vertex) :
!g.is_directed && g.allow_loops ? (num_vertex * (num_vertex - 1) / 2 + num_vertex) :
!g.is_directed && !g.allow_loops ? (num_vertex * (num_vertex - 1) / 2) :
0;
if (num_edge > maxedges)
return false;
}
for (unsigned int en = 0; en < num_edge; ++en)
{
int v = rand_r(seed) % num_vertex,
w = rand_r(seed) % num_vertex;
if (!g.allow_loops && v == w) {
--en;
continue;
}
if (!g.allow_parallel)
{
if (g.find_edge(v, w) != g.edge_end()) {
--en;
continue;
}
if (g.find_edge(w, v) != g.edge_end() && g.is_undirected) {
--en;
continue;
}
}
g.add_edge(v, w);
}
assert(g.num_edge() == num_edge);
out = g;
return true;
}
template <typename GraphType>
class GraphDecorator
{
protected:
using id_type = typename GraphType::id_type;
using vertex_iterator = typename GraphType::const_vertex_iterator;
using edge_iterator = typename GraphType::const_edge_iterator;
public:
void graph(std::ostream&, const GraphType&) const
{ }
bool filter_vertex(const vertex_iterator&) const
{
return false;
}
void vertex_default(std::ostream&) const
{ }
bool vertex_short(const GraphType&) const
{
return false;
}
void vertex(std::ostream&, const vertex_iterator&) const
{ }
bool filter_edge(const edge_iterator&) const
{
return false;
}
void edge_default(std::ostream&) const
{ }
void edge(std::ostream&, const edge_iterator&) const
{ }
void extra(std::ostream&, const GraphType&) const
{ }
};
template <typename GraphType, typename GraphDecorator>
class GraphvizOutput
{
protected:
const GraphType& m_graph;
GraphDecorator m_graphdeco;
using vertex_iterator = typename GraphType::const_vertex_iterator;
using edge_iterator = typename GraphType::const_edge_iterator;
public:
explicit GraphvizOutput(const GraphType& g, GraphDecorator gd = GraphDecorator())
: m_graph(g), m_graphdeco(gd)
{ }
friend std::ostream& operator << (std::ostream& os, const GraphvizOutput& go)
{
const GraphType& g = go.m_graph;
const GraphDecorator& gd = go.m_graphdeco;
os << (g.is_directed ? "digraph" : "graph") << " G {\n";
os << " graph [";
gd.graph(os, g);
os << "]\n";
os << " node [";
gd.vertex_default(os);
os << "]\n";
os << " edge [";
gd.edge_default(os);
os << "]\n";
for (vertex_iterator v = g.vertex_begin(); v != g.vertex_end(); ++v)
{
if (gd.filter_vertex(v)) continue;
os << " " << v.vertex_id() << " [";
gd.vertex(os, v);
os << "];\n";
}
for (edge_iterator e = g.edge_begin(); e != g.edge_end(); ++e)
{
if (gd.filter_edge(e)) continue;
os << " " << e.tail_id()
<< (g.is_directed ? " -> " : " -- ")
<< e.head_id() << " [";
gd.edge(os, e);
os << "];\n";
}
gd.extra(os, g);
os << "}";
return os;
}
};
template <typename GraphType, typename GraphDecorator>
GraphvizOutput<GraphType, GraphDecorator> graphviz(const GraphType& g, GraphDecorator gd = GraphDecorator())
{
return GraphvizOutput<GraphType, GraphDecorator>(g, gd);
}
template <typename GraphType, typename GraphDecorator>
class GraphTikzOutput
{
protected:
const GraphType& m_graph;
GraphDecorator m_graphdeco;
using vertex_iterator = typename GraphType::const_vertex_iterator;
using edge_iterator = typename GraphType::const_edge_iterator;
public:
explicit GraphTikzOutput(const GraphType& g, GraphDecorator gd = GraphDecorator())
: m_graph(g), m_graphdeco(gd)
{ }
friend std::ostream& operator << (std::ostream& os, const GraphTikzOutput& go)
{
const GraphType& g = go.m_graph;
const GraphDecorator& gd = go.m_graphdeco;
os << "\\begin{tikzpicture}";
os << "[graphtheorie,";
gd.graph(os, g);
os << "]\n";
for (vertex_iterator v = g.vertex_begin(); v != g.vertex_end(); ++v)
{
if (gd.filter_vertex(v)) continue;
os << " \\node[";
gd.vertex(os, v);
os << "] (v" << v.vertex_id() << ")"
<< " at (";
gd.vertex_x(os, v);
os << ",";
gd.vertex_y(os, v);
os << ")"
<< " {";
gd.vertex_label(os, v);
os << "};\n";
}
for (edge_iterator e = g.edge_begin(); e != g.edge_end(); ++e)
{
if (gd.filter_edge(e)) continue;
os << " \\draw[";
gd.edge(os, e);
os << "] (v" << e.tail_id() << ") -- (v" << e.head_id() << ");\n";
}
gd.extra(os, g);
os << "\\end{tikzpicture}";
return os;
}
};
template <typename GraphType, typename GraphDecorator>
GraphTikzOutput<GraphType, GraphDecorator> graphtikz(const GraphType& g, GraphDecorator gd = GraphDecorator())
{
return GraphTikzOutput<GraphType, GraphDecorator>(g, gd);
}
template <typename GraphType, typename GraphDecorator>
class TrivialGraphOutput
{
protected:
const GraphType& m_graph;
GraphDecorator m_graphdeco;
using vertex_iterator = typename GraphType::const_vertex_iterator;
using edge_iterator = typename GraphType::const_edge_iterator;
public:
explicit TrivialGraphOutput(const GraphType& g, GraphDecorator gd = GraphDecorator())
: m_graph(g), m_graphdeco(gd)
{ }
friend std::ostream& operator << (std::ostream& os, const TrivialGraphOutput& go)
{
const GraphType& g = go.m_graph;
const GraphDecorator& gd = go.m_graphdeco;
for (vertex_iterator v = g.vertex_begin(); v != g.vertex_end(); ++v)
{
os << v.vertex_id() << " ";
gd.vertex_label(os, v);
os << "\n";
}
os << "#\n";
for (edge_iterator e = g.edge_begin(); e != g.edge_end(); ++e)
{
os << e.tail_id() << " " << e.head_id() << " ";
gd.edge_label(os, e);
os << "\n";
}
return os;
}
};
template <typename GraphType, typename GraphDecorator>
TrivialGraphOutput<GraphType, GraphDecorator> graphtgf(const GraphType& g, GraphDecorator gd = GraphDecorator())
{
return TrivialGraphOutput<GraphType, GraphDecorator>(g, gd);
}
template <typename GraphType, typename GraphDecorator>
class GraphStringOutput
{
protected:
const GraphType& m_graph;
GraphDecorator m_graphdeco;
using vertex_iterator = typename GraphType::const_vertex_iterator;
using edge_iterator = typename GraphType::const_edge_iterator;
public:
explicit GraphStringOutput(const GraphType& g, GraphDecorator gd = GraphDecorator())
: m_graph(g), m_graphdeco(gd)
{ }
friend std::ostream& operator << (std::ostream& os, const GraphStringOutput& gso)
{
const GraphType& g = gso.m_graph;
const GraphDecorator& gd = gso.m_graphdeco;
os << 'V' << g.num_vertex();
if (!gd.vertex_short(g))
{
os << ':';
for (vertex_iterator v = g.vertex_begin(); v != g.vertex_end(); ++v)
{
os << 'i' << v.vertex_id();
gd.vertex(os, v);
os << '/';
}
}
os << ';';
os << 'E' << g.num_edge() << ':';
for (edge_iterator e = g.edge_begin(); e != g.edge_end(); ++e)
{
os << 'i' << e.edge_id()
<< 't' << e.tail_id() << 'h' << e.head_id();
gd.edge(os, e);
os << '/';
}
os << ';';
return os;
}
};
template <typename GraphType, typename GraphDecorator>
GraphStringOutput<GraphType, GraphDecorator>
graphstring(const GraphType& g, GraphDecorator gd = GraphDecorator())
{
return GraphStringOutput<GraphType, GraphDecorator>(g, gd);
}
#endif