How to tell if an edge is on some path - algorithm

Given an undirected graph G=V,E, 2 vertices: x, y and an edge e,
I would like to check if there is a path from x to y that contains the given edge e.
What I thought: Solve this by defining a network flow where x and y are source and sink and check if the flow in e is more than 0 it means that there is a path.
BUT there are 2 problems:
I don't know how to direct to edges
What would be the capacity of every edge?
So I'm guessing it's not the right approach... If someone can give an idea it'd be great.

One approach could be the following:
Remove the edge e = (u,v) from E(G).
If any x-y path contains e then the path will either be one of the two following forms: (1) x *-> u -> v *-> y or (2) x *-> v -> u *-> y where *-> means reachable. Use this fact to check if either of the following cases holds true
2.1. x is reachable from u and y is reachable from v.
2.2. x is reachable from v and y is reachable from u.
We can use BFS to find reachablility.

Related

Prolog, give a path from point x to the goal

This is my code:
% A The first link as a predicate
link(1,2).
link(2,3).
link(3,4).
link(3,6).
link(6,7).
link(6,5).
So what we did with the path predicate is check from a given starting point check if there exists a path from that point to the goal (which is defined at the top). This gives the correct outcome for all possible values.
What I need to do now is, I know there is a valid path from 1 to the goal, my path() predicate told me so, now i need to return a list of nodes that shows the that path to the goal, so with using path(L), path([2,3,6,5]) is true.
If I understand your problem statement, you
Have a directed graph (a digraph) defined by link(From,To).
Wish to be able to traverse that digraph from some origin node to some destination node and identify the path[s] between the 2 nodes.
This is a pretty straightforward problem that doesn't require assert/1 or retract/1.
A common pattern in Prolog programming is the use of helper predicates that carry extra arguments that track the persistent state required to accomplish the task at hand.
Graph traversal, as an algorithm, is pretty easy (and nicely recursive):
You can travel from node A to node B if nodes A and B are directly connected, or
You can travel from node A to node B if node A is connected to some other node X such that you can travel from node X to node B.
The trick here is that you need to track what nodes you've visited (and their order), and you'd want to do that anyway, so that you can detect cycles in the graph. Trying to traverse a cyclic graph like this::
a → b → c → b
leads to infinite recursion unless you check to see whether or not you've already visited node b.
That leads pretty direction to an implementation like this:
A traverse/3 predicate, traverse(Origin, Destination,Path), and,
A traverse/4 helper predicate, traverse(Origin,Destination,Visited,Path).
You can fiddle with it at https://swish.swi-prolog.org/p/oZUomEcK.pl
link(1,2).
link(2,3).
link(3,4).
link(3,6).
link(6,7).
link(6,5).
% ---------------------------------------------------------------------------
%
% traverse( Origin, Destination, ReversePath )
%
% traverse/3 traverses a directed graph defined by link(From,To).
% The path taken is listed in reverse order:
% [Destination, N3, N2, N1 , Origin]
%
% ---------------------------------------------------------------------------
traverse(A,B,P) :- % to traverse a graph
traverse(A,B, [], P) % - invoke the helper, seeding the visited list with the empty list
. %
% ---------------------------------------------------------------------------
% traverse( Origin, Destination, Visited, ReversePath )
% ---------------------------------------------------------------------------
traverse( A , B , V , [B,A|V] ) :- % Traversal of a graph from A to B,
link(A,B) % - succeeds if there exists an edge between A and B.
. %
traverse( A , B , V , P ) :- % otherwise, we can get from A to B if...
link(A,X) , % - an edge exists between A and some node X
\+ member(X,V) , % - that we have not yet visited,
traverse(X,B,[A|V],P) % - and we can get from X to B (adding A to the list of visited nodes
. %
Once you have that, invoking traverse/3 with all arguments unbound
?- traverse(A,B,P) .
results in finding all paths in the graph via backtracking.
If you want to know all the paths in the graph, beginning at a specific origin node, invoke it with the origin argument bound:
?- traverse(1,B,P) .
And if you want to know if two specific nodes are connected, invoke it with both origin and destination bound:
?- traverse(1,5,P) .
Note: because we're building the list of visited nodes by prepending them to the list of visited nodes, the path thus build is in reverse (destination-first) order. If you want the path in proper (origin-first) order, just use reverse/2 in the main predicate:
traverse(A,B,P) :- traverse(A,B, [], RP ), reverse(RP,P) .

Algorithm for allowing concurrent walk of a graph

In a directed acyclic graph describing a set of tasks to process, i need to find all tasks that can be processed concurrently. The graph has no loops and is quite small (~1000 nodes, ~2000 edges), performance is not a primary concern.
Examples with desired result:
[] is a group. All tasks in a group must be processed before continuing
[x & y] means x and y can be processed concurrently (x and y in parallel)
x -> y means x and y must be processed sequentially (x before y)
1
a -> [b & c] -> c
2
[a & e] -> b -> c -> [d & f]
3
[ [a -> b] & [e -> f] ] -> [ [c -> d] & g ]
I do not want to actually execute the graph, but rather build a data structure that is as parallel as possible, while maintaining the order. The nomenclature and names of algorithms is not that familiar to me, so i'm having a hard time trying to find similar problems/solutions online.
Mathematically, I would frame this problem as finding a minimally defined series-parallel partial order extending the given partial order.
I would start by transitively reducing the graph and repeatedly applying two heuristics.
If x has one dependent y, and y has one dependency x, merge them into a new node z = [x → y].
If x and y have the same dependencies and dependents, merge them into a new node z = [x & y].
Now, if the input is already series-parallel, the result will be one node. In general, however, this will leave a graph that embeds an N-shaped structure like b → c, b → g, f → g from the last example in the question. This structure must be addressed by adding one or more of b → f, c → f, c → g, f → b, f → c, g → c. But in a different instance, this act would in turn create new N-shaped structures. There's no obvious notion of a closure, which is why this problem feels hard to me.
Some of these choices seem worse than others. For example, c → f forces the sequence b → c → f → g, whereas f → c is the only choice that doesn't increase the length of the critical path.
I guess what I'd try is,
If heuristics 1 and 2 have no targets, form a graph with edges x--y if and only if x and y have either a common dependent or a common dependency, compute the connected components of this graph, and &-merge the smallest component that isn't a singleton, followed by another transitive reduction.
Here's a solution i came up with (pseudocode):
sequence = []
for each (node, depth) in depthFirstSearch(graph)
sequence[depth].push(node)
return sequence
The sequence defines the order to process the graph. If an item in it contains more than one node, they can be processed concurrently.
While this allows for some concurrency, it does not advance as fast as it could. For example, f in the 3rd example in the question would require a to be completed first (as it will be at depth 1, when a and e are depth 0). Ideally work on f could start when e is done.

Efficient way of generating graphs from source nodes

Let's say I have a graph G, and around each node I have a few source nodes xs. I have to create a new graph G' using xs=[[a, b, c], [d, e], [f]] nodes such that they won't conflict with grey donuts as shown in the figure below.
Expected output G' is [[a, d, f], [a, e, f], [b, e, f]]; all others are conflicting a gray donut.
I currently solved it by taking all permutation and combination of nodes xs. This works for smaller numbers of nodes, but as my number of nodes xs increases with bigger graph G, it soon becomes 100s of thousands of combination to try.
I am looking for an efficient algorithm which will help me speed things up and get me all the non-conflicting graphs with a minimum number of iterations.
You have a fairly obvious minimum set of edges for each stage of your path. They are both necessary and sufficient for your solution. For notational convenience, I'll label the original graph X--Y--Z. Your corresponding G' nodes are
X a b c
Y d f
Z f
You do this in two steps:
For each edge in G, you must test for validity each possible edge in G`. This consists of
X--Y [a, b, c] X [d, e]
a total of 6 edges; 3 qualify: set XY = [a--d, a--e, b--d]
Y--Z [d, e] X [f]
a total of 2 edges; 2 qualify: set YZ = [d--f, e--f]
Now, you need only generate all combinations of XY x YZ where the Y nodes match. If you sort the lists by the "inner" node, you can do this very quickly as
[a--d, b--d] x [d--f]
[a--e] x [e--f]
Most current languages have modules to perform combinations for you, so the code will be short enough.
Does that get you going?

graph recursion in prolog

The graph is shown in the figure below. I have to tell whether there is path between the two nodes and print the path also. For instance: my query is path(a,c). then it will return True. Now when i am giving the query as path(g,f), Ist and 2nd results are True and after that instead of terminating, its starts looping around. I am a novice in prolog. Please suggest some solution for stopping the recursion after getting the correct number of paths
These are the facts
arc(a,b).
arc(b,c).
arc(c,d).
arc(d,b).
arc(b,g).
arc(g,b).
arc(d,g).
arc(g,d).
arc(f,d).
arc(a,e).
arc(f,e).
arc(a,d).
arc(f,g).
arc(c,f).
path(X,Y):- arc(X,Y).
path(X,Y):- arc(X,Z),path(Z,Y).
You are traversing a directed graph. Assuming that it is acyclic, this should enumerate all the possible paths:
path(X,Y) :- % a path exists from X to Y
arc(X,Y) % IF an edge exists *from* X *to* Y
. %
path(X,Y) :- % Otherwise, a path exists from X to Y
arc(X,Z) , % IF an outbound path from X exists
Z \== Y , % whose destination (Z) is NOT Y, and
path(X,Y) % a path exists from Z to Y
. % Easy!
We're using \==/2 here because this predicate might be invoked with unbound argument(s).
Another way to write it might be:
path(X,Y) :- % A path exists from X to Y
arc(X,Z) , % IF an outbound path from X exists,
( % AND
Z = Y % Y is that destination (Z)
; % OR
path(Z,Y) % Y can be reached from Z.
) .
If your graph is cyclic, you'll need to build and carry along with you as you go a list of visited nodes, so you can skip visiting nodes you've already seen, lest you go down the rabbit hole of infinite recursion.

undirected graph

How can I find all way to go end in undirected graph ?
Graph :
Node : S, Y, F, T visualization : S ----- Y ---- T
Edge : S --- Y \ /
Y --- F \ /
S --- F \ /
Y --- T F
Assume that
Start S
Finish F
after run go
result will be :
S F
S Y F
I do not want visit one node more than once. If I visit, this problem become one of NP problems.
EDIT:
input can be any form
example:
edge (S,Y). OR edge (Y,S).
edge (Y,F). edge (F,Y).
edge (S,F). edge (F,S).
edge (Y,T). edge (T,Y).
BUT OUTPUT MUST BE SAME
Keep a trace of the visited nodes and exclude those when adding the possible destinations in the next step.
I changed a few edges and added one, to make sure it also works when edges are listed in the 'wrong' order for going from S to F.
edge('S','Y'). visualization: S -- Y -- T
edge('F','Y'). / \ /
edge('S','F'). / \/
edge('Y','T'). A --- F
edge('A','S').
edge('F','A').
In prolog this should roughly look like this:
pathBetween(A,A,_):- !, fail.
pathBetween(S,F,Visited) :- (edge(S,F) ; edge(F,S)),
append(Visited,[S,F],L),
write(L).
pathBetween(S,F,Visited) :-
( edge(S,A) ; edge(A,S) ),
not(member(A,Visited)),
pathBetween(A,F,[S|Visited]).
You can use ; to manually find all the solutions, or findall.
?- findall(Visited, pathBetween('S', 'F', []), _).
[S,F][S,Y,F][S,A,F]
true.

Resources