// Souffle - A Datalog Compiler
// Copyright (c) 2016, The Souffle Developers. All rights reserved
// Licensed under the Universal Permissive License v 1.0 as shown at:
// - https://opensource.org/licenses/UPL
// - <souffle root>/licenses/SOUFFLE-UPL.txt

// Topological Ordering

// Gives a topological ordering over the vertices of an input graph. Note that is works only on input graph is acyclic.

// Graph

// Vertices
.decl vertices(v:symbol)
.input vertices()
.decl vertex(v:symbol)
.output vertex()
vertex(v) :- vertices(v).

// Edges
.decl edges(v1:symbol, v2:symbol)
.input edges()
.decl edge(v1:symbol, v2:symbol)
.output edge()
edge(v1, v2) :- vertex(v1), vertex(v2), edges(v1, v2).

// Tests if vertex v1 proceeds vertex v2 in the ordering.
.decl is_before(v1:symbol, v2:symbol)
.output is_before()

// Tests if vertex v1 succeeds vertex v2 in the ordering.
.decl is_after(v1:symbol, v2:symbol)
.output is_after()

// Gives the possible indices of the vertices in the ordering.
.decl indices(v:symbol, i:number)
.output indices()

// Gives the exact index of the vertex in the ordering.
.decl index(v:symbol, i:number)
.output index()

// Vertex x is before vertex y if the graph has an edge from x to y.
is_before(x, y) :-
    edge(x, y).

// Vertex x is before vertex y if some vertex z is before x and z is before y.
is_before(x, y) :-
    is_before(x, z),
    is_before(z, y).

// Vertex x is after vertex y if the graph has an edge from y to x.
is_after(x, y) :-
    edge(y, x).

// Vertex x is after vertex y if some vertex z is after x and y is after z.
is_after(x, y) :-
    is_after(z, x),
    is_after(y, z).

// The index of a vertex x is 0 if it has no inbound or outbound edges.
indices(x, 0) :-
    vertex(x),
    !edge(_, x),
    !edge(x, _).

// The index of a vertex x is 1 if it has no inbound but only outbound edges.
indices(x, 1) :-
    vertex(x),
    !edge(_, x),
    edge(x, _).

// The possible indices of a vertex x are 1 more than the index of some vertex y if that vertex y is before x but not after x.
indices(x, i+1) :-
    is_before(y, x),
    !is_before(x, y),
    is_after(x, y),
    indices(y, i).

// The exact index of a vertex is the maximum of its possible indices.
index(x, i) :-
    indices(x, i),
    !indices(x, i+1).
