{edge(X,Y)} :- node(X), node(Y).

:- edge(X, Y), X = Y. % can't have edge from X -> Y if X = Y
:- edge(X, Y), nedge(X, Y, T), varin(T, X), varin(T, Y). % no solution edge if no edge in one of the inputs
:- edge(X, Y), path(Y, X). % acyclicity

path(Y, X) :- edge(Y,X). % recursive definition of path: edge Y->X (base case)
path(Y, X) :- edge(Y, Z), path(Z, X). % recursion step

directed(X, Y, T) :- edge(X, Y), varin(T, Y). % directed edge X->Y relative to graph T
directed(X, Y, T) :- edge(X, Z), directed(Z, Y, T), not varin(T,Z). % want to allow unobserved multistep path from X -> Y

causalconn(X, Y, T) :- directed(X, Y, T). % directed edge
causalconn(X, Y, T) :- directed(Z, X, T), directed(Z, Y, T), not varin(T, Z). % unobserved common cause
bidirected(X, Y, T) :- causalconn(X, Y, T), not directed(X, Y, T).

:- nedge(X, Y, T), causalconn(X, Y, T), varin(T,X), varin(T, Y). % if in same graph, then no edge --> no causal connection
:- edge(X, Y, T), not directed(X, Y, T), varin(T, X), varin(T, Y). % if edge, means directed path

#show edge/2.
