/* Strongly connected components of a directed graph, by Andrew Beers.
 *
 * Algorithm:
 *   Let verts = the vertex set of the graph
 *   Let edges = the edge set of the graph
 *   Let v = some vertex on the graph
 *   Let F = the set of vertices reachable from v, travelling along edges in
 *           the proper direction.
 *   Let B = the set of vertices reachable from v, travelling along edges
 *           in the reverse direction.
 *
 * Then, S = intersect(F,B) is a strongly connected subcomponent containing
 * v.  The remaining components can be found by repeating this process on the
 * graph G' with vertex set verts-S, starting with some vertex u that is in G'.
*/

mode none.

closure allreach/2, reach/2, breach/2, ballreach/2.

top equals scc(verts,edges).

	scc({X\T},E) equals scc1(int(reach(X,E),breach(X,E)), {X\T}, E).

	scc1(S,_,_) contains {S}.
	scc1(S,T,E) contains scc(diff(T,S),E).

% Returns the set of vertices reachable from X when traversing edges in the
% forward direction.

	reach(X,_) contains {X}.
	reach(X,E) contains allreach(dadj(X,E),E).

	allreach({X\_},E) contains reach(X,E).

		dadj(X,{[X|Y]\_}) contains {Y}.

% Returns the set of vertices reachable from X when traversing edges in the
% reverse direction.

	breach(X,_) contains {X}.
	breach(X,E) contains ballreach(badj(X,E),E).

	ballreach({X\_},E) contains breach(X,E).

		badj(X,{[Y|X]\_}) contains {Y}.


/**** Helper functions ****/

	int({X\_},{X\_}) contains {X}.

	diff({X\_}, S) contains if member(X,S) then phi else {X}.

	member(X,{X\_}) equals true.
	member(_, _)    equals false.


/**** Directed graph ****/

% Graph courtesy Cormen, Leiserson, and Rivest, p. 489

verts equals {a,b,c,d,e,f,g,h}.

edges equals { [a|b], [b|e], [b|f], [b|c], [c|g], [c|d], [d|c], [d|h],
               [e|a], [e|f], [f|g], [g|f], [g|h], [h|h] }.

