Related
For some practise; I'm trying to create a program that simulates a maze and shows every possible route between entry and exit. The code creates one of the lists, however it doesn't show both and doesn't stop when it's found them (route 1: entry,a,b,e,f,exit and route 2: entry,a,b,c,d,e,f,exit), and continuously loops into bigger and bigger routes.
% length(X, _), route(entry,exit, X).
%Facts, indicating an adjacent link between one room and another.
link(entry, a).
link(a, b).
link(b, c).
link(c, d).
link(d, e).
link(b, e).
link(e, f).
link(f, c).
link(f, exit).
%Searches for the path in an increasing order of length 'route'.
route(X, Y, [X, Y]) :- link(X,Y).
route(X, Y, [X | TY]) :- link(X, T), route(T, Y, TY).
Example from console:
| ?- route(entry, exit, A).
A = [entry,a,b,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,c,d,e,f,c,d,e,f,exit]
Can anyone help me?
The simplest way to make this iterative deepening path search stop from looking for further successes after the first one is to cut at the end of the goal:
?- length(X, _), route(entry,exit, X), !.
X = [entry,a,b,e,f,exit].
Once success brings Prolog's "finger" past the !, any attempt to redo and move the finger back leftwards is disallowed. So Prolog stops after the first success.
For multiple solutions: hopefully there is something like library(solution_sequences) around.
There we have limit(+Count,:Goal):
?- limit(2,route(entry, exit, A)).
A = [entry,a,b,c,d,e,f,exit] ;
A = [entry,a,b,c,d,e,f,c,d,e,f,exit].
The source code for limit, which is written in Prolog. It uses state-changing predicates, but can it be written without those?
1. First path predicate is the base case.
2. Second path predicate searches all possible routes for the given Start and End Node.
link(entry, a).
link(a, b).
link(b, c).
link(c, d).
link(d, e).
link(b, e).
link(e, f).
%link(f, c).
link(f, exit).
path(Node,Node,[Node]):-!.
path(StartN,EndN,[StartN|List]):-
link(StartN,NextN),
path(NextN,EndN,List).
Example:
?-path(entry,exit,Route).
Route = [entry, a, b, c, d, e, f, exit]
Route = [entry, a, b, e, f, exit]
?-path(entry,a,Route).
Route = [entry, a]
?-path(entry,b,Route).
Route = [entry, a, b]
?-path(entry,c,Route).
Route = [entry, a, b, c]
false
?-path(entry,d,Route).
Route = [entry, a, b, c, d]
false
?-path(entry,e,Route).
Route = [entry, a, b, c, d, e]
Route = [entry, a, b, e]
?-path(entry,f,Route).
Route = [entry, a, b, c, d, e, f]
Route = [entry, a, b, e, f]
Note: I had to comment link(f,c) to get the correct route for exit or else it'll give you stack limit exceeded, I'm not sure why.
I am currently working on implementing a source-removal topological sorting algorithm for a directed graph. Basically the algorithm goes like this:
Find a node in a graph with no incoming edges
Remove that node and all edges coming out from it and write its value down
Repeat 1 and 2 until you eliminate all nodes
So, for example, the graph
would have a topological sort of a,e,b,f,c,g,d,h. (Note: topological sorts aren't unique and thus there can be a different topological sort as well)
I am currently working on a Prolog implementation of this with the graph being represented in list form as follows:
[ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]],
[g,[h]], [h,[]] ]
Where the [a, [b,e,f] ] term for example represents the edges going from a to b, e, and f respectively, and the [b, [f,g] ] term represents the edges going from b to f and g. In other words, the first item in the array "tuple" is the "from" node and the following array contains the destinations of edges coming from the "from" node.
I am also operating under assumption that there is one unique name for each vertex and thus when I find it, I can delete it without worrying about any potential duplicates.
I wrote the following code
% depends_on shows that D is adjacent to A, i.e. I travel from A to D on the graph
% returns true if A ----> D
depends_on(G,A,D) :- member([A,Ns],G), member(D,Ns).
% doesnt_depend_on shows that node D doesnt have paths leading to it
doesnt_depend_on(G, D) :- \+ depends_on(G, _, D).
% removes node from a graph with the given value
remove_graph_node([ [D,_] | T], D, T). % base case -- FOUND IT return the tail only since we already popped it
remove_graph_node([ [H,Ns] | T], D, R) :- \+ H=D,remove_graph_node( T, D, TailReturn), append([[H,Ns]], TailReturn, R).
%----------------------------------------------------
source_removal([], []]). % Second parameter is empty list due to risk of a cycle
source_removal(G,Toposort):-member([D,_], G),
doesnt_depend_on(G,D),
remove_graph_node(G,D,SubG),
source_removal(SubG, SubTopoSort),
append([D], SubTopoSort, AppendResult),
Toposort is AppendResult.
And I tested the depends_on, doesnt_depend_on, and remove_graph_node by hand using the graph [ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]], [g,[h]], [h,[]] ] and manually changing the parameter variables (especially when it comes to node names like a, b, c and etc). I can vouch after extensive testing that they work.
However, my issue is debugging the source_removal command. In it, I repeatedly remove a node with no directed edge pointing towards it along with its outgoing edges and then try to add the node's name to the Toposort list I am building.
At the end of the function's running, I expect to get an array of output like [a,e,b,f,c,g,d,h] for its Toposort parameter. Instead, I got
?- source_removal([ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]], [g,[h]], [h,[]] ], Result).
false.
I got false as an output instead of the list I am trying to build.
I have spent hours trying to debug the source_removal function but failed to come up with anything. I would greatly appreciate it if anyone would be willing to take a look at this with a different pair of eyes and help me figure out what the issue in the source_removal function is. I would greatly appreciate it.
Thanks for the time spent reading this post and in advance.
The first clause for source_removal/2 contained a typo (one superfluous closing square bracket).
The last line for the second clause in your code says Toposort is AppendResult. Note that is is used in Prolog to denote the evaluation of an arithmetic expression, e.g., X is 3+4 yields X = 7 (instead of just unifying variable X with the term 3+4). When I change that line to use = (assignment, more precisely unification) instead of is (arithmetic evaluation) like so
source_removal([], []). % Second parameter is empty list due to risk of a cycle
source_removal(G,Toposort):-member([D,_], G),
doesnt_depend_on(G,D),
remove_graph_node(G,D,SubG),
source_removal(SubG, SubTopoSort),
append([D], SubTopoSort, AppendResult),
Toposort = AppendResult.
I get the following result:
?- source_removal([ [a,[b,e,f]], [b,[f,g]], [c,[g,d]], [d,[h]], [e,[f]], [f,[]], [g,[h]], [h,[]] ], Result).
Result = [a, b, c, d, e, f, g, h] ;
Result = [a, b, c, d, e, g, f, h] ;
Result = [a, b, c, d, e, g, h, f] ;
Result = [a, b, c, d, g, e, f, h] ;
Result = [a, b, c, d, g, e, h, f] ;
Result = [a, b, c, d, g, h, e, f] ;
Result = [a, b, c, e, d, f, g, h] ;
Result = [a, b, c, e, d, g, f, h] ;
Result = [a, b, c, e, d, g, h, f] ;
Result = [a, b, c, e, f, d, g, h] ;
Result = [a, b, c, e, f, g, d, h] ;
...
Result = [c, d, a, e, b, g, h, f] ;
false.
(Shortened, it shows 140 solutions in total.)
Edit: I didn't check all the solutions, but among the ones it finds is the one you gave in your example ([a,e,b,f,c,g,d,h]), and they look plausible in the sense that each either starts with a or with c.
This is my code:
sentence([['o'],['m','e','n','i','n','o'],['a','l','e','g','r','e']]).
lastWord(X,[X]).
lastWord(X,[_|Z]) :- lastWord(X,Z).
If I try lastWord(X,[1,2,3]). or even lastWord(X,[['o'],['m','e','n','i','n','o'],['a','l','e','g','r','e']]). I get what I want (which is, of course, the last element of the list (in the examples, 3 and ['a','l','e','g','r','e'].
But if I try lastWord(X, sentence). or lastWord(X, sentence(Y)). I get false.
How can I "call" the defined list (in this case, 'sentence') in lastWord?
Prolog is not a functional language. Thus, in goals such as lastWord(X, sentence) or lastWord(X, sentence(Y)) is not going to replace sentence or sentence(Y) by the argument of the sentence/1 predicate. Try instead:
?- sentence(List), lastWord(Last, List).
List = [[o], [m, e, n, i, n, o], [a, l, e, g, r, e]],
Last = [a, l, e, g, r, e] ;
false.
Note there's a spurious choice point left for the query. You can eliminate it by rewriting the definition of the predicate lastWord/2. A similar predicate, usually named last/2, is often available from libraries:
last([Head| Tail], Last) :-
last(Tail, Head, Last).
last([], Last, Last).
last([Head| Tail], _, Last) :-
last(Tail, Head, Last).
Note the different argument order (Prolog coding guidelines suggest to have input arguments preceding output arguments). Using this predicate instead:
?- sentence(List), last(List, Last).
List = [[o], [m, e, n, i, n, o], [a, l, e, g, r, e]],
Last = [a, l, e, g, r, e].
I have some data declared in a Prolog file that looks like the following:
gen1(grass).
gen1(poison).
gen1(psychic).
gen1(bug).
gen1(rock).
...
gen1((poison, flying)).
gen1((ghost, poison)).
gen1((water, ice)).
...
weak1(grass, poison).
weak1(grass, bug).
weak1(poison, rock).
strong1(grass, rock).
strong1(poison, grass).
strong1(bug, grass).
strong1(poison, bug).
strong1(psychic, poison).
strong1(bug, poison).
strong1(bug, psychic).
strong1(rock, bug).
Note that the data does not define strong1 or weak1 for compound gen1(...). Those are determined by rules which do not contribute to the minimal working example. I mention them because it might be useful to know they exist.
I am trying to find relations between these terms that form a cycle. Here's one sample function:
triangle1(A, B, C) :-
setof(A-B-C, (
gen1(A), gen1(B), gen1(C), A \= B, A \= C, B \= C,
strong1(A, B), strong1(B, C), strong1(C, A)
), Tris),
member(A-B-C, Tris).
This setup does remove duplicates where A, B, and C are in the same order. However, it doesn't remove duplicates in different orders. For example:
?- triangle1(A, B, C),
member(A, [bug, grass, rock]),
member(B, [bug, rock, grass]),
member(C, [bug, rock, grass]).
A = bug,
B = grass,
C = rock ;
A = grass,
B = rock,
C = bug ;
A = rock,
B = bug,
C = grass ;
false.
That query should only return one set of [A, B, C].
I've thought about using sort/2, but there are cases where simply sorting changes the meaning of the answer:
?- triangle1(A, B, C),
sort([A, B, C], [D, E, F]),
\+member([D, E, F], [[A, B, C], [B, C, A], [C, A, B]]).
A = D, D = bug,
B = F, F = psychic,
C = E, E = poison .
I also tried < and >, but those don't work on atoms, apparently.
Any thoughts?
(I looked at the similar questions, but have no idea how what I'm doing here compares to what other people are doing)
EDIT: As per comment about minimal working example.
You can try sorting inside the setof/3 call. So you should avoid the generation of triples in wrong order.
I mean: calling setof/3, instead of
A \= B, A \= C, B \= C,
try with
A #< B, A #< C, B \= C,
This way you impose that A is lower than B and lower than C, you avoid duplicates and maintain correct solutions.
The full triangle1/3
triangle1(A, B, C) :-
setof(A-B-C, (
gen1(A), gen1(B), gen1(C), A #< B, A #< C, B \= C,
strong1(A, B), strong1(B, C), strong1(C, A)
), Tris),
member(A-B-C, Tris).
Say I have a predicate pred containing several facts.
pred(a, b, c).
pred(a, d, f).
pred(x, y, z).
Can I use findall/3 to get a list of all facts which can be pattern matched?
for example, if I have
pred(a, _, _)
I would like to obtain
[pred(a, b, c), pred(a, d, f)]
Just summing up what #mbratch said in the comment section:
Yes, but you have to make sure that you either use named variables or construct a simple helper predicate that does that for you:
Named variables:
findall(pred(a,X,Y),pred(a,X,Y),List).
Helper predicate:
special_findall(X,List):-findall(X,X,List).
?-special_findall(pred(a,_,_),List).
List = [pred(a, b, c), pred(a, d, f)].
Note that this doesn't work:
findall(pred(a,_,_),pred(a,_,_),List).
Because it is equivalent to
findall(pred(a,A,B),pred(a,C,D),List).
And thus doesn't unify the Variables of Template with those of Goal.