I think this function falls into the same category as edge(), which I'm starting to believe is exactly like iterator operations
distance(), advance(), next() and prev(). Not part of a concept, not a full-fledged algorithm, but nonetheless an operation that
can be implemented for every graph, with varying degrees of efficiency.

I agree.  Should vertex() by default just be vertex(i, g) = {vertex_iterator it = vertices(g).first; advance(it, i); return *it;}?  I don't think we can guarantee that matches the vertex_index map, though.

Does that mean that mean that we minimally require VertexListGraph<G> (in what I will not refer to as C?? syntax).

I know of only one adaptor that doesn't model VertexListGraph (edge_list), but that's just a weird data structure anyway. Actually Michael Lopez (SoC09, function graphs) has cases where a function does not model this concept, but that's a weird data structure too.

Maybe vertex is more like swap(), where we have a general algorithm with lots of specializations?
 
For edge(), I imagine we should have a trait for whether the out edges of a vertex are sorted, and then we can use logarithmic or linear-time algorithms.  Particular graphs can specialize it for their own types (such as for adjacency_matrix's constant-time version).  The edge_range() function should be the same thing, except that it requires that the edges are sorted in some way so that parallel edges are together (or we can use a filtered_iterator which would be a lot slower).

Logically that sounds about right. The following is purely hypothetical.

template <EdgeListGraph G>
pair<Edge, bool>edge(Vertex u, Vertex v, G const& g)
{ for(...) { if source(e, g) == u && target(e, g) == v) return {e, true}; } }

template <AdajcencyMatrix G>
pair<Edge, bool> edge(Vertex u, Vertex v, G const& g)
{ return g(u, v); }

template <IncidenceGraph G>
  requires Range<G::out_edge_range>
pair<Edge,  bool> edge(Vertex u, Vertex v, G const& g)
{ /* linear search in out_edges */ }

template <IncidenceGraph G>
  requires SortedRange<G::out_edge_range>
pair<Edge, bool> edge(Vertex u, Vertex v, G const& g)
{ /* binary search in out_edges */ }

template <IncidenceGraph G>
  requires AssociativeContainer<G::out_edge_range>
pair<Edge, bool> edge(Vertex u, Vertex v, G const& g)
{ /* use x.find() */ }

We can map these back to tag dispatch with a little bit of work.

The biggest problem I see here is that the BGL doesn't let us easily reason about the internal properties of out edge lists for adjacency list-like data structures or adaptors. It would be one thing to return the a legitimate range or reference to a container, but that's not where we are right now.

One might require member functions for efficient edge queries like my theoretical adjacency_matrix () overload. That would certainly reduce the requirements on overloads, but leaves us more or less where we are now (maybe?)

I wonder if this also admits the existence of an AdjacencyList concept.

Andrew Sutton
andrew.n.sutton@gmail.com