Getting all nodes that have atleast 2 nodes connected to them - prolog

Having some issues with a Prolog question:
The following clauses represent a directed graph, where nodes are
atoms, and edges are denoted by the connected predicate. Given that
the following clauses are in the database, answer the two questions
below.
connected(a,b).
connected(b,d).
connected(b,e).
connected(b,f).
connected(a,c).
connected(c,f).
connected(c,g).
connected(h,c).
path(X,Y) :- connected(X,Y).
path(X,Z) :- connected(X,Y), path(Y,Z).
Show the Prolog query that returns all nodes having two or more
different incoming edges (i.e., at least two different nodes are
connected to it). Also, show the result of entering the query (asking
for every solution). Your query may return the same node multiple
times, and may printout the values of other variables in the query.
The variable denoting the node in question should be called DNode.
So far I have:
path(DNode,__) , path(__,DNode).
But that only give me b and c
I think the letters with more than one nodes are a, b, c, f.
I tried this to get a, b and c:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__).
But I got a, b, c and h.
I am assuming I'll have to like this to get all the letters I want:
path(__,DNode),path(DNode,__) ; path(DNode,__) , path(DNode,__) ; path(__,DNode) , path(__,DNode).
It gives me a, b, c, e, f, g and h though.
Any advice about how to get the 4 letters I want would be appreciated.

if you display your graph, perhaps with Graphviz
?- writeln('digraph G {'), forall(connected(A,B), writeln(A->B)), writeln('}').
you can see that only [c,f] have 2 incoming edges, and that you don't need path/2. It's sufficient a join on the second argument of connected/2, with a test that the first arguments are different (operator (\=)/2).

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) .

How to find direct path between two nodes in a graph in Prolog?

I am new to Prolog and I'm trying to write a predicate that takes two nodes and a graph as it's arguments and then checks whether there exists a direct path between these two nodes in the graph.
For example, there is a direct path from n(1) to n(4) in the graph below, that goes from n(1)
to n(3) and from n(3) to n(4):
g[n(1), n(4), g([n(1), n(2), n(3), n(4), n(5), n(6), n(7), n(8)],
[e(n(1), n(2)), e(n(1), n(3)), e(n(3), n(4)), e(n(4), n(5)), e(n(5), n(6)), e(n(5), n(7)), e(n(7), n(8))]))
In the end
?− dirPath(n(1), n(4), g[n(1), n(4), g([n(1), n(2), n(3), n(4), n(5), n(6), n(7), n(8)],
[e(n(1), n(2)), e(n(1), n(3)), e(n(3), n(4)), e(n(4), n(5)), e(n(5), n(6)), e(n(5), n(7)), e(n(7), n(8))]))
should return true.
My tentative code looks like this:
edge(n(1),n(2)).
edge(n(1),n(3)).
edge(n(3),n(4)).
edge(n(4),n(5)).
edge(n(5),n(6)).
edge(n(5),n(7)).
edge(n(7),n(8)).
dirPath(A,B, g) :- % - graph argument still missing.
move(A,B,[]) % - two nodes are connected,
. % - if one can move from one to the other,
move(A,B,V) :- % - and one can move from A to B
edge(A,X) , % - if A is connected to X, and
not(member(X,V)) , % - one hasn't yet reached X, and
( % - either
B = X % - X is the desired destination
; % OR
move(X,B,[A|V]) % - one can get to that destination from X
)
.
My main problem is that I can't figure out how make my dirPath predicate accepts a graph, as it's argument.
First of all, this:
g[n(1), n(4), g([n(1), n(2), n(3), n(4), n(5), n(6), n(7), n(8)],
[e(n(1), n(2)), e(n(1), n(3)), e(n(3), n(4)), e(n(4), n(5)), e(n(5), n(6)), e(n(5), n(7)), e(n(7), n(8))]))
is not valid syntax. A term cannot begin g[.... This should probably be g([... instead.
Second, the representation is not entirely intuitive. What are the special roles of n(1) and n(4)? Why is there an inner g(...) term?
Nevertheless, it's clear which part is supposed to be the edges. Let's define a predicate to access just the edges:
graph_edges(Graph, Edges) :-
Graph = g(_Something, _SomethingElse, g(_Nodes, Edges)).
Selection of one edge from the graph is then:
graph_edge(Graph, Edge) :-
graph_edges(Graph, Edges),
member(Edge, Edges).
You can then incorporate this into your predicate like this:
dirPath(A, B, Graph) :-
move(A, B, Graph, []).
move(A, B, Graph, Vs) :-
graph_edge(Graph, e(A, X)),
...
Note that I changed your variable V to Vs. Single-letter variable names are often not great in general (From and To would in my opinion be clearer than A and B). Single-letter variable names for lists are especially unusual; the common convention is to add s (as in the English plural, visited nodes) for lists. For graphs this is especially recommended, since a simple V could very well be interpreted as a single "vertex".
(Solution not tested.)

Run Dijkstra among all the pair of cities as (source, destination) and store the distances as facts

I have a data given in the form of an adjacency matrix signifying the edges, out of which I was able to create a edges.pl file containing all the edges between the cities. For reference see the image,
In the edges.pl file I have facts of the form edge(agartala, ahmedabad, 3305), edge(ahmedabad, agartala, 3305) to create a bidirectional graph.
There are 47 cities in total.
Now I want to create another file, where I want to create facts that give shortest distance between each pair of cities. That is, something like a 47x47 matrix where each city on row is a source and each city on column is a destination.
Basically, I want to implement loops so that I can run Dijkstra on each pair of cities and store dynamic facts like,
distance(city1, city2, shortest_distance).
I don't understand how to run these nested loops on these cities.
Since you want to find the shortest paths for all pairs of cities, isn't the Floyd-Warshall algorithm what you should be using instead of Dijkstra's? I will use Floyd-Warshall in this answer. What both algorithms have in common is that they need to make updates to some data structure. I will use the Prolog database for this, since you want to assert some dynamic facts anyway. However, the solution will be very "non-logical".
I will be using the following input graph from the Floyd-Warshall Wikipedia page:
node(1).
node(2).
node(3).
node(4).
edge(1, 3, -2).
edge(2, 1, 4).
edge(2, 3, 3).
edge(3, 4, 2).
edge(4, 2, -1).
As a commenter mentioned, a technique you can use here are failure-driven loops.
Here is what a failure-driven loop looks like:
visit_each_node :-
node(Node),
fail.
This doesn't seem to do anything:
?- visit_each_node.
false.
And indeed, logically it just fails. But procedurally it visits each node, it just doesn't do anything with it.
You can do things inside failure-driven loops, but only non-logical things like I/O, or modifications of the Prolog database. For example:
print_each_node :-
node(Node),
write('visiting '),
write(Node),
nl,
fail.
This will visit a node, print it, and come to the failure. The failure will force it to backtrack to find another node and print it. Then it will fail again, find another node, and so on, until all nodes have been visited, and finally the query fails:
?- print_each_node.
visiting 1
visiting 2
visiting 3
visiting 4
false.
We will usually want our loops to do something and then succeed. For this, we can just add another clause that succeeds:
print_each_node_and_succeed :-
node(Node),
write('visiting '),
write(Node),
nl,
fail.
print_each_node_and_succeed :-
% when we get here, all nodes have been visited
true.
This will do all of what I described above. Then, after the first clause has definitely failed, it will execute the second clause and will succeed:
?- print_each_node_and_succeed.
visiting 1
visiting 2
visiting 3
visiting 4
true.
In general, a failure-driven loop will consist of: (a) some goals that generate some data, (b) some goals that consume that data non-logically, (c) a fail, all in one clause, and (d) a second clause that succeeds:
generic_loop :-
% generate
some_x(X),
some_y(Y),
% consume
do_something_non_logical_with_x_and_y(X, Y),
% loop back
fail.
generic_loop :-
% nothing more to do
true.
Now, for the Floyd-Warshall algorithm. We'll populate the following dynamic predicate, using from_to_set_distance to encapsulate removing any old stored distance between two cities and storing a new one:
:- dynamic from_to_distance/3.
from_to_set_distance(From, To, Distance) :-
retractall(from_to_distance(From, To, _OldDistance)),
asserta(from_to_distance(From, To, Distance)).
The first step of the algorithm is to initialize all distances from given edges. This must visit all pairs of cities and do something non-logical, namely, update the Prolog database. A job for a failure-driven loop!
initialize_distances :-
retractall(from_to_distance(_From, _To, _Distance)),
node(U),
node(V),
( U = V
-> from_to_set_distance(U, U, 0)
; edge(U, V, Distance)
-> from_to_set_distance(U, V, Distance)
; Infinity = 999999,
from_to_set_distance(U, V, Infinity) ),
% failure-driven loop
fail.
initialize_distances :-
% when we get here, all pairs of nodes have been initialized
true.
The second step is to visit all triples of cities and do something non-logical: Update the stored distance if we found a shorter path than the one we had stored before. Again, a job for a failure-driven loop!
compute_pairwise_distances :-
node(K),
node(I),
node(J),
from_to_distance(I, J, DistIJ),
from_to_distance(I, K, DistIK),
from_to_distance(K, J, DistKJ),
( DistIJ > DistIK + DistKJ
-> DistIKJ is DistIK + DistKJ,
from_to_set_distance(I, J, DistIKJ)
; % nothing to do
true ),
% failure-driven loop
fail.
compute_pairwise_distances :-
% when we get here, all triples of nodes have been visited and all
% pairwise distances computed
true.
The entire Floyd-Warshall algorithm first does the initialization, then the computation of all pairwise distances:
floyd_warshall :-
initialize_distances,
compute_pairwise_distances.
When we run this, it will not produce anything visible:
?- floyd_warshall.
true.
But the database will have been updated. To see all the stored distances, we can visit all of them and do something non-logical, namely, print them. A job for... you guessed it: a failure-driven loop!
?- from_to_distance(From, To, Distance), write(from_to_distance(From, To, Distance)), nl, fail.
from_to_distance(3,2,1)
from_to_distance(3,1,5)
from_to_distance(1,2,-1)
from_to_distance(2,4,4)
from_to_distance(1,4,0)
from_to_distance(4,3,1)
from_to_distance(4,1,3)
from_to_distance(2,3,2)
from_to_distance(4,4,0)
from_to_distance(4,2,-1)
from_to_distance(3,4,2)
from_to_distance(3,3,0)
from_to_distance(2,2,0)
from_to_distance(2,1,4)
from_to_distance(1,3,-2)
from_to_distance(1,1,0)
false.

How can I know if all nodes have been visited in a graph before reaching the intended node?

I have a knowledge base of this type:
connect(a, b).
connect(a, d).
connect(a, e).
connect(b, a).
connect(b, c).
...
My objective is, given an origin and a destiny, to go through all the existing nodes once, before reaching the final node.
So far this is what I have got:
path(O, D, L):-
path(O, D, [O], L).
path(D, D, _, [D]).
path(O, D, A, [O|T]):-
connect(O, I),
\+ member(I, A),
path(I, D, [I|A], T).
In order to deal with the double connections e.g. connect(a, b). connect(b, a). I use a list that saves every node I go through and before going into the recursion call I make sure that the node I am going to does not belong in that list.
Now I need to make sure that I go through all the existing nodes before reaching the final one. I have absolutely no idea how to even approach this. How can I ever be sure that I visited all the other nodes before reaching the last one?
You can test it with your own code (not using findall), by making a small change. Instead of throwing away the list of visited nodes, keep it. So, change path/4 to path/5 as follows:
path(D, D, V, V, [D]).
path(O, D, A, V, [O|T]):-
connect(O, I),
\+ member(I, A),
path(I, D, [I|A], V, T).
Now you can query path(a,c,[a], Visited, Path) and test if any connect node exists that is not a member of Visited.
You have defined a network as a list of edges. A quick-and-dirty way to collect all nodes would be, for example:
findall(X, ( connect(X, _) ; connect(_, X) ), Xs),
sort(Xs, Nodes)
This will first collect all "from"s and "to"s you have listed in your connect/2, then make a set out of it by sorting and removing duplicates.
At that point you can just compare this set to the path you found (after making a set out of it, too).
Obviously, it is important that your predicate fails there is no path that visits all nodes in the network defined by connect/2.

get all combinations of elements and elements can be repeat many times in single combination

I have a problem to get all combinations of elements, and elements can be repeat and reuse for many times, even in a single combination.
For example, I have a box with 100 cm2, then i have below objects:
1) Object A: 20cm2
2) Object B: 50cm2
The expected combinations would be: (A), (A, A), (A, A, A), (A, A, A, A), (A, A, A, A, A), (A, B), (A, B, A), (A, B, A, A) .....
Any combination are allowed, as long as they can fit into the box. Objects can be repeat many times in single combination. However, repeated pattern is not needed e.g. (A, B) is equal to (B, A).
I not sure what is the keyword to search for this question, do let me know if this is a repeated question.
Seems to me like a recursive algo would do the job: fit the first object then add all combinations of the next objects (including the one you just included) in the box with a reduced size.
Then do the same with the second object, always using combinations with the next objects in line, not the previous ones (can't have an A after a B).
With your example, you would have:
(A)
(A,A)
(A,A,A)
(A,A,A,A)
(A,A,A,A,A)
(A,A,A,A,B) does not work
(A,A,A,B) does not work
(A,A,B)
(A,B)
(A,B,B) does not work
(B)
(B,B)

Resources