Lets say I've got the following predicates:
father(aaron, chloe).
father(aaron, dan).
father(aaron, emily).
father(frank, george).
mother(beth, chloe).
mother(beth, dan).
mother(beth, emily).
mother(emily, george).
sibling(X,Y) :-...
parents(X,Y) :-...
I want to find the shortest route (distance) between two members of the family tree.
The distance between parents for instance is 2, and between brothers (siblings) is one.
I've tried the following (but it didn't work):
parent(X,Y) :-
father(X,Y);
mother(X,Y).
sibling(X,Y):-
parent(Z,X), !, parent(Z,Y),
not(X=Y).
not_in_list(_,[]).
not_in_list(X,[Y|L]):-
not(X=Y),
not_in_list(X,L).
edge(X,Y):-
(parent(X,Y);
parent(Y,X);
sibling(X,Y)).
list_length(0,[]).
list_length(N,[_|Ys]):-
list_length(N1,Ys),
N is N1+1.
travel_graph(X,X,_).
travel_graph(From,To,[From|Path]):-
edge(From,Next),
not_in_list(Next,Path),
travel_graph(Next,To,Path).
degree(X,Y,N):-
travel_graph(X,Y,L),
list_length(N,L).
In general when you want shortest paths you want a breadth-first search. There's some discussion here: Breadth-First in Prolog
Prolog is going to try to find solutions depth first, so it's going to see just how far a particular line of reasoning can take it. When you want the shortest path, you would rather Prolog try all the first options, then iterate outward one from each of those, until you find a solution. This way, the first solution you find will be the shortest. It's the only way to go if you might have infinite solutions (such as walking a maze where you can back up and retrace your steps).
Unfortunately there's no magic switch you can flip to get breadth-first search, so you'll have to implement it. O'Keefe explains this very lucidly in The Craft of Prolog, by explaining first how to convert a normal Prolog search into an explicit depth-first search with an "open set" of things yet-to-be-tried, and then how to change the order of the list representing the open set to get breadth-first behavior instead.
Related
I'm working with this code. I'm struggling with the prolog logic paradigm. I have these two questions.
Is there a way to change the path predicate to not only get the "best" path, but to get all the paths that lead to that node/location in order?
How can I make the path predicate more "user friendly" and just insert the two locations I want to calculate, e.g. path(london, manchester)
Is there a way to change the path predicate to not only get the "best" path, but to get all the paths that lead to that node/location in order?
The given code is rather specialized to the Dijkstra algorithm and for finding shortest paths only. I don't see a simple way to modify it to give what you ask. (Initially I thought it might suffice to just remove some cuts, but I haven't had success with that. Comments welcome!)
If you want all paths between two nodes, you don't need the complexity of the Dijkstra algorithm. Here is a mostly reasonable answer defining a predicate that enumerates all paths: https://stackoverflow.com/a/27194523/4391743 ("Mostly" reasonable because the formatting isn't pretty, and because the unvisited/2 predicate would better be expressed using a generic non_member/2 predicate such as the one given here: https://stackoverflow.com/a/10322639/4391743)
There are many other Prolog path-finding questions here, but I haven't yet found one that has the best beginner-friendly answer.
Edit: Forgot to add that the predicate given above computes all paths, but does not yield them "in order". Enumerating all paths ordered by length isn't very easy. Here the best way might be to enumerate all paths and their lengths, use findall/3 to compute a single list of all these paths, and to sort that list by length.
How can I make the path predicate more "user friendly" and just insert the two locations I want to calculate, e.g. path(london, manchester)
If your predicate has too many arguments, just define another one that hides some of them:
path(Start, End) :-
path(Start, End, _Path, _Distance).
This will simply succeed or fail but not tell you anything more:
?- path(london, manchester).
true.
In Prolog it is normal to overload predicate names with different arities like this, which is why references to predicates often include the arity. In the definition above, we define path/2 in terms of path/4.
I'm trying to re-familiarize myself with Prolog and I thought this could be the type of problem with an elegant solution in Prolog.
I'm following along this example:
http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/hierarchical.html
I've tried a variety of data formats:
dist('BA','FI',662).
dist(0,'BA','FI',662).
dist(['BA'],['FI'],662).
but I haven't found any particular one most suitable.
Here's all the data in the first format:
%% Graph distances
dist('BA','FI',662).
dist('BA','MI',877).
dist('BA','NA',255).
dist('BA','RM',412).
dist('BA','TO',996).
dist('FI','MI',295).
dist('FI','NA',468).
dist('FI','RM',268).
dist('FI','TO',400).
dist('MI','NA',754).
dist('MI','RM',564).
dist('MI','TO',138).
dist('NA','RM',219).
dist('NA','TO',869).
dist('RM','TO',669).
Now, there seems to be some awesome structure to this problem to exploit, but I'm really struggling to get a grasp of it. I think I've got the first cluster here (thought it may not be the most elegant way of doing it ;)
minDist(A,B,D) :- dist(A,B,D), dist(X,Y,Z), A \= X, A \= Y, B \= X, B \= Y, D < Z.
min(A,B,B) :- B < A
min(A,B,A) :- A < B
dist([A,B],C, D) :- minDist(A,B,D), dist(A,C,Q), dist(B,C,W), min(Q,W,D)
The problem I have here is the concept of "replacing" the dist statements involving A and B with the cluster.
This just quickly become a brainteaser for me and I'm stuck. Any ideas on how to formulate this? Or is this perhaps just not the kind of problem elegantly solved with Prolog?
Your table is actually perfect! The problem is that you don't have an intermediate data structure. I'm guessing you'll find the following code pretty surprising. In Prolog, you can simply use whatever structures you want, and it will actually work. First let's get the preliminary we need for calculating distance without regard for argument order:
distance(X, Y, Dist) :- dist(X, Y, Dist) ; dist(Y, X, Dist).
This just swaps the order if it doesn't get a distance on the first try.
Another utility we'll need: the list of cities:
all_cities(['BA','FI','MI','NA','RM','TO']).
This is just helpful; we could compute it, but it would be tedious and weird looking.
OK, so the end of the linked article makes it clear that what is actually being created is a tree structure. The article doesn't show you the tree at all until you get to the end, so it isn't obvious that's what's going on in the merges. In Prolog, we can simply use the structure we want and there it is, and it will work. To demonstrate, let's enumerate the items in a tree with something like member/2 for lists:
% Our clustering forms a tree. So we need to be able to do some basic
% operations on the tree, like get all of the cities in the tree. This
% predicate shows how that is done, and shows what the structure of
% the cluster is going to look like.
cluster_member(X, leaf(X)).
cluster_member(X, cluster(Left, Right)) :-
cluster_member(X, Left) ; cluster_member(X, Right).
So you can see we're going to be making use of trees using leaf('FI') for instance, to represent a leaf-node, a cluster of N=1, and cluster(X,Y) to represent a cluster tree with two branches. The code above lets you enumerate all the cities within a cluster, which we'll need to compute the minimum distance between them.
% To calculate the minimum distance between two cluster positions we
% need to basically pair up each city from each side of the cluster
% and find the minimum.
cluster_distance(X, Y, Distance) :-
setof(D,
XCity^YCity^(
cluster_member(XCity, X),
cluster_member(YCity, Y),
distance(XCity, YCity, D)),
[Distance|_]).
This probably looks pretty weird. I'm cheating here. The setof/3 metapredicate finds solutions for a particular goal. The calling pattern is something like setof(Template, Goal, Result) where the Result will become a list of Template for each Goal success. This is just like bagof/3 except that setof/3 gives you unique results. How does it do that? By sorting! My third argument is [Distance|_], saying just give me the first item in the result list. Because the result is sorted, the first item in the list will be the smallest. It's a big cheat!
The XCity^YCity^ notation says to setof/3: I don't care what these variables actually are. It marks them as "existential variables." This means Prolog will not provide multiple solutions for each city combination; they will all be thrown together and sorted once.
This is all we need to perform the clustering!
From the article, the base case is when you have two clusters left: just combine them:
% OK, the base case for clustering is that we have two items left, so
% we cluster them together.
cluster([Left,Right], cluster(Left,Right)).
The inductive case takes the list of results and finds the two which are nearest and combines them. Hold on!
% The inductive case is: pair up each cluster and find the minimum distance.
cluster(CityClusters, FinalCityClusters) :-
CityClusters = [_,_,_|_], % ensure we have >2 clusters
setof(result(D, cluster(N1,N2), CC2),
CC1^(select(N1, CityClusters, CC1),
select(N2, CC1, CC2),
cluster_distance(N1, N2, D)),
[result(_, NewCluster, Remainder)|_]),
cluster([NewCluster|Remainder], FinalCityClusters).
Prolog's built-in sorting is to sort a structure on the first argument. We cheat again here by creating a new structure, result/3, which will contain the distance, the cluster with that distance, and the remaining items to be considered. select/3 is extremely handy. It works by pulling an item out of the list and then giving you back the list without that item. We use it twice here to select two items from the list (I don't have to worry about comparing a place to itself as a result!). CC1 is marked as a free variable. The result structures will be created for considering each possible cluster with the items we were given. Again, setof/3 will sort the list to make it unique, so the first item in the list will happen to be the one with the shortest distance. It's a lot of work for one setof/3 call, but I like to cheat!
The last line says, take the new cluster and append it to the remaining items, and forward it on recursively to ourself. The result of that invocation will eventually be the base case.
Now does it work? Let's make a quick-n-dirty main procedure to test it:
main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
Line one is a cheesy way to construct the initial conditions (all cities in their own cluster of one). Line two calls our predicate to cluster things. Then we write it out. What do we get? (Output manually indented for readability.)
cluster(
cluster(
leaf(FI),
cluster(
leaf(BA),
cluster(
leaf(NA),
leaf(RM)))),
cluster(
leaf(MI),
leaf(TO)))
The order is slightly different, but the result is the same!
If you're perplexed by my use of setof/3 (I would be!) then consider rewriting those predicates using the aggregate library or with simple recursive procedures that aggregate and find the minimum by hand.
When programming in Prolog I often write predicates whose behavior should be semi-deterministic when called with all arguments instantiated (and whose behavior should be non-deterministic otherwise).
A concrete use case for this is my predicate walk/3, which implements graph walks. Since multiple paths can exist between two vertices, the instantiation (+,+) gives multiple choicepoints after true. These are, however, quite useless. Calling code must explicitly use once/1 for performance reasons.
%! walk(+Graph:ugraph, +StartVertex, +EndVertex) is semidet.
%! walk(+Graph:ugraph, -StartVertex, +EndVertex) is nondet.
%! walk(+Graph:ugraph, +StartVertex, -EndVertex) is nondet.
%! walk(+Graph:ugraph, -StartVertex, -EndVertex) is nondet.
Semi-determinism can be forced by the use of once/1 in the calling context, but I want to implement semi-determinism as a property of the predicate walk/3, and not as something that has to be treated specially every time it is called.
In addition to concerns over code aesthetics, the calling context need not always know whether its call to walk/3 is semi-deterministic or not. For example:
%! cycle(+Graph:ugraph, +Vertex) is semidet.
%! cycle(+Graph:ugraph, -Vertex) is nondet.
cycle(Graph, Vertex):-
walk(Graph, Vertex, Vertex).
I have come up with the following solution, which does produce the correct behavior.
walk_wrapper(Graph, Start, End):-
call_ground_as_semidet(walk(Graph, Start, End)).
:- meta_predicate(call_ground_as_semidet(0)).
call_ground_as_semidet(Goal):-
ground(Goal), !,
Goal, !.
call_ground_as_semidet(Goal):-
Goal.
However, this solution has deficiencies:
It's not generic enough, e.g. sometimes ground should be nonvar.
It is not stylistic, requiring an extra predicate wrapper every time it is used.
It may also be slightly inefficient.
My question is: are there other ways in which often-occurring patterns of (non-)determinism, like the one described here, can be generically/efficiently/stylistically programmed in Prolog?
You should experiment with double negation as failure. Yes a ground goal can only be true or false, so it should not leave any choice points. Lets assume we have an acyclic graph, to make matters simple:
If I use this code:
edge(a, b). edge(a, c).
edge(a, d). edge(b, c).
edge(c, d). edge(c, e).
edge(d, e).
path(X,X).
path(X,Y) :- edge(X,Z), path(Z,Y).
The Prolog system will now leave choice points for closed queries:
?- path(a, e).
true ;
true ;
true ;
true ;
true ;
false.
In my opinion the recommended approach, to eliminate these
choice points and nevertheless have a multi-moded predicate,
is to use so called meta-programming in Prolog.
meta-programming is also sometimes derogeratively called
non-logical programming, since it is based on non-logical
predicates such as ground/1, !/0 or (+)/1. But lets call
it meta-programming when declarativity is not impacted.
You could write a wrapper smart/1 as follows, doing the
same as your call_ground_as_semidet/1, but with a small nuance:
smart(G) :- ground(G), !, \+ \+ G.
smart(G) :- G.
The Prolog system will not anymore leave a choice point for closed queries:
?- smart(path(a,e)).
true.
The advantage of \+ \+ over once, is that the former does
not only leave no choice points, but also removes the trail. It
is sometimes called the garbage collection meta-predicate of Prolog.
Not an answer but too long for a comment. Keep in mind I am not sure I understand exactly, so I want to re-state your question first.
To take your graph example. You want to be able to ask the following questions using the same call of the same predicate.
Given a graph,
Question 1: is vertex B reachable from vertex A (somehow)? - yes or no
Question 2: which vertices are reachable from A? - enumerate by backtracking
Question 3: from which vertices is B reachable? - enumerate by backtracking
Question 4: which A and B exist for which B is reachable from A? - enumerate by backtracking
And I might be wrong here, but it seems that answering Question 1 and Question 2 might employ a different search strategy than answering Question 3?
More generally, you want to have a way of saying: if I have a yes-or-no question, succeed or fail. Otherwise, enumerate answers.
Here comes my trouble: what are you going to do with the two different types of answers? And what are the situations in which you don't know in advance which type of answer you need? (If you do know in advance, you can use once(goal), as you said yourself.)
PS:
There is obviously setof/3, which will fail if there are no answers, or collect all answers. Are there situations in which you want to know some of the answers but you don't want to collect all of them? Is this an efficiency concern because of the size and number of the answers?
Not an answer but an advice.
Maybe I missunderstood your question. I think you are trying to address performance issues by forcing a predicate to be non-deterministic. That question is pointless: if p(X) is non-deterministic (multiple solutions), then p(X),! is deterministic (first solution only).
You should not address performance issues by altering program logic or predicate reversibility. I suggest a different approach:
First, take advantage of prolog indexing. For example:
cycle(+Graph:ugraph, +Vertex)
is NOT the same (in terms of performance) as:
cycle(+Vertex, +Graph:ugraph)
You should find documentation on prolog indexing (and performance impact) on the Web.
Second, write multiple implementations for the same problem. Each one will optimize performance for a different case. Then, write a predicate that chooses the best implementation for each case.
I want to make a predicate that check if a node can reach another node in graph in prolog. e.g Connected(1,X,[[1,3],[3,4],[2,5]]) The first argument is the node I want to start the second is the node I want to reach and the third is a list of edges. So far I have managed to do it but I get an infinite loop when I try to get all the nodes I reach by using findall/3.
Is there any way to stop the infinite loop or I should thing the problem from the beggining?
Here is my code so far:
match([X,Y],List):- member([X,Y], List).
match([X,Y],List):- member([Y,X], List).
go(X,Y,List):-match([X,Y],List).
go(X,Y,List):-match([X,Z],List),go(Z,Y,List).
goes(X,List,List2):-findall(Y,go(X,Y,List),List2).
I am new in Prolog and I cannot figure out what I am doing wrong.
a possible correction to your code
match([X,Y], List, Rest):- select([X,Y], List, Rest).
match([X,Y], List, Rest):- select([Y,X], List, Rest).
go(X,Y,List) :- match([X,Y],List,_).
go(X,Y,List) :- match([X,Z],List,Rest), go(Z,Y,Rest).
goes(X,List,List2) :- findall(Y, go(X,Y,List), List2).
now match 'consumes' an edge, then avoid infinite looping
Have a look at what ?- gtrace, goes(1,[[1,3],[3,4],[2,5]], X). Does.
For all recursions go :- go you need a condition when it stops.
In you case I recommend to add an argument Traversed which is a list of all nodes(or edges) you have visited. Then you do not go over nodes again if you have visited them already.
So you get less and less elements to recursively look at and the recorsion ends at some point.
Many recursions use the predicate !. Have a look at it.
I want to program this algorithms in Prolog, and first I need to create a matrix from a list of graphs. I've done this before (also with help of some of you, guys), but now I don't know how to store it inside a list of lists (which I suppose it's the best approach in prolog's case). I think I can be able to continue from there (with the triple for loop in each of the algorithms). The logic of the program is not difficult for me, but how to work with data. Sorry for being a bother and thanks in advance!
My matrix generator:
graph(a,b).
graph(a,a).
graph(b,c).
graph(b,d).
graph(c,d).
graph(a,e).
graph(e,f).
matrix :- allnodes(X),printmatrix(X).
node(X) :- graph(X,_).
node(X) :- graph(_,X).
allnodes(Nodes) :- setof(X, node(X), Nodes).
printedge(X,Y) :- graph(Y,X), write('1 ').
printedge(X,Y) :- \+ graph(Y,X), write('0 ').
printmatrix(List):- member(Y, List),nl,member(X, List),printedge(X,Y),fail.
Your previous question Adjacency Matrix in prolog dealt with the visual display (row over row) of the adjacency matrix of a graph. Here we address how to realize/represent the adjacency matrix as a Prolog term. In particular we will adopt as given the allnodes/1 predicate shown above as a means of getting a list of all nodes.
Prolog lacks any native "matrix" data type, so the approach taken here will be to use a list of lists to represent the adjacency matrix. Entries are organized by "row" in 0's and 1's that denote the adjacency of the node corresponding to a row with that node corresponding to a column.
Looking at your example graph/2 facts, I see that you've included one self-edge (from a to a). I'm not sure if you intend the graph to be directed or undirected, so I'll assume a directed graph was intended and note where a small change would be needed if otherwise an undirected graph was meant.
There is a "design pattern" here that defines a list by applying a rule to each item in a list. Here we do this one way to construct each row of the "matrix" and also (taking that as our rule) to construct the whole list of lists.
/* construct adjacency matrix for directed graph (allow self-edges) */
adjacency(AdjM) :-
allnodes(L),
adjMatrix(L,L,AdjM).
adjMatrix([ ],_,[ ]).
adjMatrix([H|T],L,[Row|Rows]) :-
row_AdjM(H,L,Row),
adjMatrix(T,L,Rows).
row_AdjM(_,[ ],[ ]).
row_AdjM(X,[Y|Ys],[C|Cs]) :-
( graph(X,Y)
-> C = 1
; C = 0
),
row_AdjM(X,Ys,Cs).
If an undirected graph were meant, then the call to graph(X,Y) should be replaced with an alternative ( graph(X,Y); graph(Y,X) ) that allows an edge to be considered in either direction.