Breadth First Search code won't output BFS result












1














This is the code I found, and it was fixed in another post I made.



s(a, b).
s(a, c).
s(b, g).
s(b, f).
s(c, r).
s(c, e).
goal(g).

solve( Start, Solution) :-
breadthfirst( [ [Start] ], Solution).

breadthfirst( [ [Node | Path] |_], [Node | Path] ) :-
goal( Node).

breadthfirst( [ [N | Path] | Paths], Solution) :-
bagof([M,N|Path],
( s( N, M), + member( M, [N | Path] ) ), NewPaths),
%conc( Paths, NewPaths, Pathsl), !,
append(Paths, NewPaths, Pathsl), !,
breadthfirst( Pathsl, Solution);
breadthfirst( Paths, Solution).


However, I found that the output is :



?- solve(a,S).
S = [g, b, a] ;


I took all the facts and draw a tree to represent them, and in the tree, we have a gives b and c which are at the same level, at level 1. Therefore they should be visited first. And then after, g will be visited in the 2nd level through b.



So the output should be :



?- solve(a,S).
S = [g, c, b, a] ;


But it isn't giving me that output and I don't know why.



Now, there's also a problem of reversing the output, I would appreciate it if that is solved too.










share|improve this question




















  • 1




    If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
    – gusbro
    Nov 23 '18 at 16:28
















1














This is the code I found, and it was fixed in another post I made.



s(a, b).
s(a, c).
s(b, g).
s(b, f).
s(c, r).
s(c, e).
goal(g).

solve( Start, Solution) :-
breadthfirst( [ [Start] ], Solution).

breadthfirst( [ [Node | Path] |_], [Node | Path] ) :-
goal( Node).

breadthfirst( [ [N | Path] | Paths], Solution) :-
bagof([M,N|Path],
( s( N, M), + member( M, [N | Path] ) ), NewPaths),
%conc( Paths, NewPaths, Pathsl), !,
append(Paths, NewPaths, Pathsl), !,
breadthfirst( Pathsl, Solution);
breadthfirst( Paths, Solution).


However, I found that the output is :



?- solve(a,S).
S = [g, b, a] ;


I took all the facts and draw a tree to represent them, and in the tree, we have a gives b and c which are at the same level, at level 1. Therefore they should be visited first. And then after, g will be visited in the 2nd level through b.



So the output should be :



?- solve(a,S).
S = [g, c, b, a] ;


But it isn't giving me that output and I don't know why.



Now, there's also a problem of reversing the output, I would appreciate it if that is solved too.










share|improve this question




















  • 1




    If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
    – gusbro
    Nov 23 '18 at 16:28














1












1








1







This is the code I found, and it was fixed in another post I made.



s(a, b).
s(a, c).
s(b, g).
s(b, f).
s(c, r).
s(c, e).
goal(g).

solve( Start, Solution) :-
breadthfirst( [ [Start] ], Solution).

breadthfirst( [ [Node | Path] |_], [Node | Path] ) :-
goal( Node).

breadthfirst( [ [N | Path] | Paths], Solution) :-
bagof([M,N|Path],
( s( N, M), + member( M, [N | Path] ) ), NewPaths),
%conc( Paths, NewPaths, Pathsl), !,
append(Paths, NewPaths, Pathsl), !,
breadthfirst( Pathsl, Solution);
breadthfirst( Paths, Solution).


However, I found that the output is :



?- solve(a,S).
S = [g, b, a] ;


I took all the facts and draw a tree to represent them, and in the tree, we have a gives b and c which are at the same level, at level 1. Therefore they should be visited first. And then after, g will be visited in the 2nd level through b.



So the output should be :



?- solve(a,S).
S = [g, c, b, a] ;


But it isn't giving me that output and I don't know why.



Now, there's also a problem of reversing the output, I would appreciate it if that is solved too.










share|improve this question















This is the code I found, and it was fixed in another post I made.



s(a, b).
s(a, c).
s(b, g).
s(b, f).
s(c, r).
s(c, e).
goal(g).

solve( Start, Solution) :-
breadthfirst( [ [Start] ], Solution).

breadthfirst( [ [Node | Path] |_], [Node | Path] ) :-
goal( Node).

breadthfirst( [ [N | Path] | Paths], Solution) :-
bagof([M,N|Path],
( s( N, M), + member( M, [N | Path] ) ), NewPaths),
%conc( Paths, NewPaths, Pathsl), !,
append(Paths, NewPaths, Pathsl), !,
breadthfirst( Pathsl, Solution);
breadthfirst( Paths, Solution).


However, I found that the output is :



?- solve(a,S).
S = [g, b, a] ;


I took all the facts and draw a tree to represent them, and in the tree, we have a gives b and c which are at the same level, at level 1. Therefore they should be visited first. And then after, g will be visited in the 2nd level through b.



So the output should be :



?- solve(a,S).
S = [g, c, b, a] ;


But it isn't giving me that output and I don't know why.



Now, there's also a problem of reversing the output, I would appreciate it if that is solved too.







prolog breadth-first-search






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 '18 at 15:49









false

11.1k770143




11.1k770143










asked Nov 23 '18 at 15:38









John Sall

816




816








  • 1




    If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
    – gusbro
    Nov 23 '18 at 16:28














  • 1




    If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
    – gusbro
    Nov 23 '18 at 16:28








1




1




If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
– gusbro
Nov 23 '18 at 16:28




If the desired output is a path from source to goal (well, in your case a reversed path), then the output is ok as the path should not go through c.
– gusbro
Nov 23 '18 at 16:28












1 Answer
1






active

oldest

votes


















3















It isn't giving me that output and I don't know why.




Your code is giving the correct answer as noted in my earlier answer.



?- solve(a,S).
S = [g, b, a] ;


The problem is not the answer the code gives, but I believe in your understanding of either how the algorithm works or the layout of the graph from the facts.



Using paper and pen to work on a problem before converting it to code is a wise decision.



Here is the graph in a visual form with the root (a) at the top.



        a               Level 0
/
b c Level 1
/ /
g f r e Level 2


Notice that the shortest path from a to g is a,b,g and not a,b,c,g as you expect. Even though c is connected to a, it is not on the path from a to g and so is not part of the solution.



You are correct in that with Breadth First Search (BFS) you start at Level 0 then process ALL the nodes connected to it, which are shown at Level 1. Then do the same for each node in Level 1 creating Level 2 before repeating again for each new level.



In processing each node, BFS just looks for any node connected to that current node that it has not visited already and records any information it needs in a table or other data structure. If your example included weights on each vertex then the cost to get to the current node being processed would be recorded with the current node in the data structure. Visiting a node for processing a node is not the same as visiting a node as part of the shortest path from one node to another.



Another way to think about this is that both BFS and Depth First Search (DFS) should both give the same answers, the difference is in the algorithm. If you use DFS on this you will get the same answer of a,b, and g, without c.



dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).

?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.




From comment:




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.




I would not agree with that.



In running the query with trace on in SWI-Prolog



line   1   [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), +member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append(, [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append(, [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), +member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), +member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), +member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), +member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), +member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), +member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), +member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), +member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), +member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), +member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), +member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1(, _12870)
line 94 Fail: (16) breadthfirst_1(, _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.


At



line   7   ^  Call: (10) bagof([_13076, a],  (s(a, _13076), +member(_13076, [a])), _13134)


it shows the result of visiting the start node a which is just the path a and in a list of known paths is [a].



at



line  16   ^  Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])


for path [a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [a] and using the item at the head of the list a visit one of its neighbors s(a,b) and add that new path into a new list, [[b,a]].



with with path [a] and using the item at the head of the list a visit one of its neighbors s(a, c). and add that new path into a new list, [[b,a],[c,a]].



at



line  32   ^  Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])


for path [b, a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, g). and add that new path into a new list, [[g, b, a]].



with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, f). and add that new path into a new list, [[g, b, a], [f, b, a]].



Notice that the answer [g, b, a] is now in the new list but it does not have c in the path.



At



line  50     Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])


all of the paths have been created



[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]


by using all of the s/2 facts and still the path with the answer [g, b, a] has no c in it.






Why the change from conc/3 to append/3 ?




Even though it is not one of your questions I need to answer it for others that read this question, especially people learning Prolog on their own for the first time.



This is my version of the events related to conc/3 and append/3 if there is another story about it do tell; I will even ask it as a posted question if need be.



One of the best if not the best books for introductory learning/teaching Prolog is "Prolog Programming for Artificial Intelligence" By Ivan Bratko. (WorldCat) (Amazon).



When first learning Prolog, people tend to spend their life in the list data structure and get a healthy diet of append/3 but in the book he chose to have the students create their own version of append/3 and named it conc/3. So through out the book is the use of conc/3 and hardly any use of append/3. Now those people are use to conc/3 and start writing code with it, posting it, etc. and it is very infectious, and you happen to have caught it. So I gave your code the remedy.






Problem of reversing the output.




When recursion is used to solve a problem it typically stores the intermediate result on the stack. Depending on the order on the stack the results are in the correct order, or in a reversed order.



There are a few ways to get the results to be returned from recursion in the correct order.



For most beginners it is to get the results and than if need be just reverse the results. For Prolog if the result is a list then reverse/2 works.



?- reverse([g, b, a],R).
R = [a, b, g].


The predicates for reverse/2



?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, , B, B).

true.

?- listing(reverse/4).
lists:reverse(, A, A, ).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).

true.


When you get into larger problems constantly reversing the result even between different predicate calls starts to add up time. This is especially true in functional programming.



Another way is by passing an accumulator. To demonstrate this I will use this simpler version of reverse.



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).
accumulator_reverse(,A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


The first clause initializes the accumulator to an empty list for use with accumulator_reverse/3



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).


The other two clauses just recursively process a list with this clause being the base case



accumulator_reverse(,A,A).


which is when the input list is empty () and



this clause



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


to take the list apart [H|T] (AKA deconstruct) and append the head H to the accumulator [H|A] (AKA construct).



As the list is processed through



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


the original list gets smaller and smaller because the head is always being removed from the list and the accumulator grows because the head from the list is always being added to the accumulator. Since the order in which list is deconstructed, (front to back) and the accumulator is constructed (back to front) the list becomes reversed.



Normally when you look at refactored Prolog code if you see recursion and a base case that looks like



base(,A,A) 


where one of the arguments is an empty list or bottom, and two other parameters are the same, but one is bound when the call is made and the other is unbound when the call is made, look to see if accumulator passing has been factored into the code.






share|improve this answer























  • Of interest: Quick Prolog
    – Guy Coder
    Nov 23 '18 at 20:55










  • Of interest: Ways to reverse a list in Haskell
    – Guy Coder
    Nov 23 '18 at 20:56










  • Of interest: Recursion Best Practices
    – Guy Coder
    Nov 23 '18 at 21:40










  • Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
    – John Sall
    Nov 24 '18 at 9:46










  • @sosscs See updated answer based on your comment.
    – Guy Coder
    Nov 24 '18 at 15:20











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449457%2fbreadth-first-search-code-wont-output-bfs-result%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









3















It isn't giving me that output and I don't know why.




Your code is giving the correct answer as noted in my earlier answer.



?- solve(a,S).
S = [g, b, a] ;


The problem is not the answer the code gives, but I believe in your understanding of either how the algorithm works or the layout of the graph from the facts.



Using paper and pen to work on a problem before converting it to code is a wise decision.



Here is the graph in a visual form with the root (a) at the top.



        a               Level 0
/
b c Level 1
/ /
g f r e Level 2


Notice that the shortest path from a to g is a,b,g and not a,b,c,g as you expect. Even though c is connected to a, it is not on the path from a to g and so is not part of the solution.



You are correct in that with Breadth First Search (BFS) you start at Level 0 then process ALL the nodes connected to it, which are shown at Level 1. Then do the same for each node in Level 1 creating Level 2 before repeating again for each new level.



In processing each node, BFS just looks for any node connected to that current node that it has not visited already and records any information it needs in a table or other data structure. If your example included weights on each vertex then the cost to get to the current node being processed would be recorded with the current node in the data structure. Visiting a node for processing a node is not the same as visiting a node as part of the shortest path from one node to another.



Another way to think about this is that both BFS and Depth First Search (DFS) should both give the same answers, the difference is in the algorithm. If you use DFS on this you will get the same answer of a,b, and g, without c.



dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).

?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.




From comment:




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.




I would not agree with that.



In running the query with trace on in SWI-Prolog



line   1   [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), +member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append(, [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append(, [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), +member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), +member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), +member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), +member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), +member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), +member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), +member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), +member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), +member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), +member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), +member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1(, _12870)
line 94 Fail: (16) breadthfirst_1(, _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.


At



line   7   ^  Call: (10) bagof([_13076, a],  (s(a, _13076), +member(_13076, [a])), _13134)


it shows the result of visiting the start node a which is just the path a and in a list of known paths is [a].



at



line  16   ^  Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])


for path [a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [a] and using the item at the head of the list a visit one of its neighbors s(a,b) and add that new path into a new list, [[b,a]].



with with path [a] and using the item at the head of the list a visit one of its neighbors s(a, c). and add that new path into a new list, [[b,a],[c,a]].



at



line  32   ^  Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])


for path [b, a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, g). and add that new path into a new list, [[g, b, a]].



with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, f). and add that new path into a new list, [[g, b, a], [f, b, a]].



Notice that the answer [g, b, a] is now in the new list but it does not have c in the path.



At



line  50     Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])


all of the paths have been created



[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]


by using all of the s/2 facts and still the path with the answer [g, b, a] has no c in it.






Why the change from conc/3 to append/3 ?




Even though it is not one of your questions I need to answer it for others that read this question, especially people learning Prolog on their own for the first time.



This is my version of the events related to conc/3 and append/3 if there is another story about it do tell; I will even ask it as a posted question if need be.



One of the best if not the best books for introductory learning/teaching Prolog is "Prolog Programming for Artificial Intelligence" By Ivan Bratko. (WorldCat) (Amazon).



When first learning Prolog, people tend to spend their life in the list data structure and get a healthy diet of append/3 but in the book he chose to have the students create their own version of append/3 and named it conc/3. So through out the book is the use of conc/3 and hardly any use of append/3. Now those people are use to conc/3 and start writing code with it, posting it, etc. and it is very infectious, and you happen to have caught it. So I gave your code the remedy.






Problem of reversing the output.




When recursion is used to solve a problem it typically stores the intermediate result on the stack. Depending on the order on the stack the results are in the correct order, or in a reversed order.



There are a few ways to get the results to be returned from recursion in the correct order.



For most beginners it is to get the results and than if need be just reverse the results. For Prolog if the result is a list then reverse/2 works.



?- reverse([g, b, a],R).
R = [a, b, g].


The predicates for reverse/2



?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, , B, B).

true.

?- listing(reverse/4).
lists:reverse(, A, A, ).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).

true.


When you get into larger problems constantly reversing the result even between different predicate calls starts to add up time. This is especially true in functional programming.



Another way is by passing an accumulator. To demonstrate this I will use this simpler version of reverse.



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).
accumulator_reverse(,A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


The first clause initializes the accumulator to an empty list for use with accumulator_reverse/3



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).


The other two clauses just recursively process a list with this clause being the base case



accumulator_reverse(,A,A).


which is when the input list is empty () and



this clause



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


to take the list apart [H|T] (AKA deconstruct) and append the head H to the accumulator [H|A] (AKA construct).



As the list is processed through



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


the original list gets smaller and smaller because the head is always being removed from the list and the accumulator grows because the head from the list is always being added to the accumulator. Since the order in which list is deconstructed, (front to back) and the accumulator is constructed (back to front) the list becomes reversed.



Normally when you look at refactored Prolog code if you see recursion and a base case that looks like



base(,A,A) 


where one of the arguments is an empty list or bottom, and two other parameters are the same, but one is bound when the call is made and the other is unbound when the call is made, look to see if accumulator passing has been factored into the code.






share|improve this answer























  • Of interest: Quick Prolog
    – Guy Coder
    Nov 23 '18 at 20:55










  • Of interest: Ways to reverse a list in Haskell
    – Guy Coder
    Nov 23 '18 at 20:56










  • Of interest: Recursion Best Practices
    – Guy Coder
    Nov 23 '18 at 21:40










  • Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
    – John Sall
    Nov 24 '18 at 9:46










  • @sosscs See updated answer based on your comment.
    – Guy Coder
    Nov 24 '18 at 15:20
















3















It isn't giving me that output and I don't know why.




Your code is giving the correct answer as noted in my earlier answer.



?- solve(a,S).
S = [g, b, a] ;


The problem is not the answer the code gives, but I believe in your understanding of either how the algorithm works or the layout of the graph from the facts.



Using paper and pen to work on a problem before converting it to code is a wise decision.



Here is the graph in a visual form with the root (a) at the top.



        a               Level 0
/
b c Level 1
/ /
g f r e Level 2


Notice that the shortest path from a to g is a,b,g and not a,b,c,g as you expect. Even though c is connected to a, it is not on the path from a to g and so is not part of the solution.



You are correct in that with Breadth First Search (BFS) you start at Level 0 then process ALL the nodes connected to it, which are shown at Level 1. Then do the same for each node in Level 1 creating Level 2 before repeating again for each new level.



In processing each node, BFS just looks for any node connected to that current node that it has not visited already and records any information it needs in a table or other data structure. If your example included weights on each vertex then the cost to get to the current node being processed would be recorded with the current node in the data structure. Visiting a node for processing a node is not the same as visiting a node as part of the shortest path from one node to another.



Another way to think about this is that both BFS and Depth First Search (DFS) should both give the same answers, the difference is in the algorithm. If you use DFS on this you will get the same answer of a,b, and g, without c.



dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).

?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.




From comment:




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.




I would not agree with that.



In running the query with trace on in SWI-Prolog



line   1   [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), +member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append(, [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append(, [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), +member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), +member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), +member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), +member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), +member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), +member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), +member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), +member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), +member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), +member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), +member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1(, _12870)
line 94 Fail: (16) breadthfirst_1(, _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.


At



line   7   ^  Call: (10) bagof([_13076, a],  (s(a, _13076), +member(_13076, [a])), _13134)


it shows the result of visiting the start node a which is just the path a and in a list of known paths is [a].



at



line  16   ^  Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])


for path [a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [a] and using the item at the head of the list a visit one of its neighbors s(a,b) and add that new path into a new list, [[b,a]].



with with path [a] and using the item at the head of the list a visit one of its neighbors s(a, c). and add that new path into a new list, [[b,a],[c,a]].



at



line  32   ^  Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])


for path [b, a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, g). and add that new path into a new list, [[g, b, a]].



with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, f). and add that new path into a new list, [[g, b, a], [f, b, a]].



Notice that the answer [g, b, a] is now in the new list but it does not have c in the path.



At



line  50     Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])


all of the paths have been created



[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]


by using all of the s/2 facts and still the path with the answer [g, b, a] has no c in it.






Why the change from conc/3 to append/3 ?




Even though it is not one of your questions I need to answer it for others that read this question, especially people learning Prolog on their own for the first time.



This is my version of the events related to conc/3 and append/3 if there is another story about it do tell; I will even ask it as a posted question if need be.



One of the best if not the best books for introductory learning/teaching Prolog is "Prolog Programming for Artificial Intelligence" By Ivan Bratko. (WorldCat) (Amazon).



When first learning Prolog, people tend to spend their life in the list data structure and get a healthy diet of append/3 but in the book he chose to have the students create their own version of append/3 and named it conc/3. So through out the book is the use of conc/3 and hardly any use of append/3. Now those people are use to conc/3 and start writing code with it, posting it, etc. and it is very infectious, and you happen to have caught it. So I gave your code the remedy.






Problem of reversing the output.




When recursion is used to solve a problem it typically stores the intermediate result on the stack. Depending on the order on the stack the results are in the correct order, or in a reversed order.



There are a few ways to get the results to be returned from recursion in the correct order.



For most beginners it is to get the results and than if need be just reverse the results. For Prolog if the result is a list then reverse/2 works.



?- reverse([g, b, a],R).
R = [a, b, g].


The predicates for reverse/2



?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, , B, B).

true.

?- listing(reverse/4).
lists:reverse(, A, A, ).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).

true.


When you get into larger problems constantly reversing the result even between different predicate calls starts to add up time. This is especially true in functional programming.



Another way is by passing an accumulator. To demonstrate this I will use this simpler version of reverse.



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).
accumulator_reverse(,A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


The first clause initializes the accumulator to an empty list for use with accumulator_reverse/3



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).


The other two clauses just recursively process a list with this clause being the base case



accumulator_reverse(,A,A).


which is when the input list is empty () and



this clause



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


to take the list apart [H|T] (AKA deconstruct) and append the head H to the accumulator [H|A] (AKA construct).



As the list is processed through



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


the original list gets smaller and smaller because the head is always being removed from the list and the accumulator grows because the head from the list is always being added to the accumulator. Since the order in which list is deconstructed, (front to back) and the accumulator is constructed (back to front) the list becomes reversed.



Normally when you look at refactored Prolog code if you see recursion and a base case that looks like



base(,A,A) 


where one of the arguments is an empty list or bottom, and two other parameters are the same, but one is bound when the call is made and the other is unbound when the call is made, look to see if accumulator passing has been factored into the code.






share|improve this answer























  • Of interest: Quick Prolog
    – Guy Coder
    Nov 23 '18 at 20:55










  • Of interest: Ways to reverse a list in Haskell
    – Guy Coder
    Nov 23 '18 at 20:56










  • Of interest: Recursion Best Practices
    – Guy Coder
    Nov 23 '18 at 21:40










  • Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
    – John Sall
    Nov 24 '18 at 9:46










  • @sosscs See updated answer based on your comment.
    – Guy Coder
    Nov 24 '18 at 15:20














3












3








3







It isn't giving me that output and I don't know why.




Your code is giving the correct answer as noted in my earlier answer.



?- solve(a,S).
S = [g, b, a] ;


The problem is not the answer the code gives, but I believe in your understanding of either how the algorithm works or the layout of the graph from the facts.



Using paper and pen to work on a problem before converting it to code is a wise decision.



Here is the graph in a visual form with the root (a) at the top.



        a               Level 0
/
b c Level 1
/ /
g f r e Level 2


Notice that the shortest path from a to g is a,b,g and not a,b,c,g as you expect. Even though c is connected to a, it is not on the path from a to g and so is not part of the solution.



You are correct in that with Breadth First Search (BFS) you start at Level 0 then process ALL the nodes connected to it, which are shown at Level 1. Then do the same for each node in Level 1 creating Level 2 before repeating again for each new level.



In processing each node, BFS just looks for any node connected to that current node that it has not visited already and records any information it needs in a table or other data structure. If your example included weights on each vertex then the cost to get to the current node being processed would be recorded with the current node in the data structure. Visiting a node for processing a node is not the same as visiting a node as part of the shortest path from one node to another.



Another way to think about this is that both BFS and Depth First Search (DFS) should both give the same answers, the difference is in the algorithm. If you use DFS on this you will get the same answer of a,b, and g, without c.



dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).

?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.




From comment:




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.




I would not agree with that.



In running the query with trace on in SWI-Prolog



line   1   [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), +member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append(, [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append(, [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), +member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), +member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), +member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), +member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), +member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), +member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), +member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), +member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), +member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), +member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), +member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1(, _12870)
line 94 Fail: (16) breadthfirst_1(, _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.


At



line   7   ^  Call: (10) bagof([_13076, a],  (s(a, _13076), +member(_13076, [a])), _13134)


it shows the result of visiting the start node a which is just the path a and in a list of known paths is [a].



at



line  16   ^  Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])


for path [a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [a] and using the item at the head of the list a visit one of its neighbors s(a,b) and add that new path into a new list, [[b,a]].



with with path [a] and using the item at the head of the list a visit one of its neighbors s(a, c). and add that new path into a new list, [[b,a],[c,a]].



at



line  32   ^  Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])


for path [b, a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, g). and add that new path into a new list, [[g, b, a]].



with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, f). and add that new path into a new list, [[g, b, a], [f, b, a]].



Notice that the answer [g, b, a] is now in the new list but it does not have c in the path.



At



line  50     Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])


all of the paths have been created



[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]


by using all of the s/2 facts and still the path with the answer [g, b, a] has no c in it.






Why the change from conc/3 to append/3 ?




Even though it is not one of your questions I need to answer it for others that read this question, especially people learning Prolog on their own for the first time.



This is my version of the events related to conc/3 and append/3 if there is another story about it do tell; I will even ask it as a posted question if need be.



One of the best if not the best books for introductory learning/teaching Prolog is "Prolog Programming for Artificial Intelligence" By Ivan Bratko. (WorldCat) (Amazon).



When first learning Prolog, people tend to spend their life in the list data structure and get a healthy diet of append/3 but in the book he chose to have the students create their own version of append/3 and named it conc/3. So through out the book is the use of conc/3 and hardly any use of append/3. Now those people are use to conc/3 and start writing code with it, posting it, etc. and it is very infectious, and you happen to have caught it. So I gave your code the remedy.






Problem of reversing the output.




When recursion is used to solve a problem it typically stores the intermediate result on the stack. Depending on the order on the stack the results are in the correct order, or in a reversed order.



There are a few ways to get the results to be returned from recursion in the correct order.



For most beginners it is to get the results and than if need be just reverse the results. For Prolog if the result is a list then reverse/2 works.



?- reverse([g, b, a],R).
R = [a, b, g].


The predicates for reverse/2



?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, , B, B).

true.

?- listing(reverse/4).
lists:reverse(, A, A, ).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).

true.


When you get into larger problems constantly reversing the result even between different predicate calls starts to add up time. This is especially true in functional programming.



Another way is by passing an accumulator. To demonstrate this I will use this simpler version of reverse.



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).
accumulator_reverse(,A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


The first clause initializes the accumulator to an empty list for use with accumulator_reverse/3



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).


The other two clauses just recursively process a list with this clause being the base case



accumulator_reverse(,A,A).


which is when the input list is empty () and



this clause



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


to take the list apart [H|T] (AKA deconstruct) and append the head H to the accumulator [H|A] (AKA construct).



As the list is processed through



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


the original list gets smaller and smaller because the head is always being removed from the list and the accumulator grows because the head from the list is always being added to the accumulator. Since the order in which list is deconstructed, (front to back) and the accumulator is constructed (back to front) the list becomes reversed.



Normally when you look at refactored Prolog code if you see recursion and a base case that looks like



base(,A,A) 


where one of the arguments is an empty list or bottom, and two other parameters are the same, but one is bound when the call is made and the other is unbound when the call is made, look to see if accumulator passing has been factored into the code.






share|improve this answer















It isn't giving me that output and I don't know why.




Your code is giving the correct answer as noted in my earlier answer.



?- solve(a,S).
S = [g, b, a] ;


The problem is not the answer the code gives, but I believe in your understanding of either how the algorithm works or the layout of the graph from the facts.



Using paper and pen to work on a problem before converting it to code is a wise decision.



Here is the graph in a visual form with the root (a) at the top.



        a               Level 0
/
b c Level 1
/ /
g f r e Level 2


Notice that the shortest path from a to g is a,b,g and not a,b,c,g as you expect. Even though c is connected to a, it is not on the path from a to g and so is not part of the solution.



You are correct in that with Breadth First Search (BFS) you start at Level 0 then process ALL the nodes connected to it, which are shown at Level 1. Then do the same for each node in Level 1 creating Level 2 before repeating again for each new level.



In processing each node, BFS just looks for any node connected to that current node that it has not visited already and records any information it needs in a table or other data structure. If your example included weights on each vertex then the cost to get to the current node being processed would be recorded with the current node in the data structure. Visiting a node for processing a node is not the same as visiting a node as part of the shortest path from one node to another.



Another way to think about this is that both BFS and Depth First Search (DFS) should both give the same answers, the difference is in the algorithm. If you use DFS on this you will get the same answer of a,b, and g, without c.



dfs_1(N,N,[N]).
dfs_1(Start,End,[Start|Rest] ) :-
s(Start,Next),
dfs_1(Next,End,Rest).

?- dfs_1(a,g,Path).
Path = [a, b, g] ;
false.




From comment:




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.




I would not agree with that.



In running the query with trace on in SWI-Prolog



line   1   [trace] 133 ?- solve_1(a,S).
line 2 Call: (8) solve_1(a, _12870)
line 3 Call: (9) breadthfirst_1([[a]], _12870)
line 4 Call: (10) goal_1(a)
line 5 Fail: (10) goal_1(a)
line 6 Redo: (9) breadthfirst_1([[a]], _12870)
line 7 ^ Call: (10) bagof([_13076, a], (s(a, _13076), +member(_13076, [a])), _13134)
line 8 Call: (17) s(a, _13076)
line 9 Exit: (17) s(a, b)
line 10 Call: (17) lists:member(b, [a])
line 11 Fail: (17) lists:member(b, [a])
line 12 Redo: (17) s(a, _13076)
line 13 Exit: (17) s(a, c)
line 14 Call: (17) lists:member(c, [a])
line 15 Fail: (17) lists:member(c, [a])
line 16 ^ Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])
line 17 Call: (10) lists:append(, [[b, a], [c, a]], _13216)
line 18 Exit: (10) lists:append(, [[b, a], [c, a]], [[b, a], [c, a]])
line 19 Call: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 20 Call: (11) goal_1(b)
line 21 Fail: (11) goal_1(b)
line 22 Redo: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 23 ^ Call: (11) bagof([_13198, b, a], (s(b, _13198), +member(_13198, [b, a])), _13256)
line 24 Call: (18) s(b, _13198)
line 25 Exit: (18) s(b, g)
line 26 Call: (18) lists:member(g, [b, a])
line 27 Fail: (18) lists:member(g, [b, a])
line 28 Redo: (18) s(b, _13198)
line 29 Exit: (18) s(b, f)
line 30 Call: (18) lists:member(f, [b, a])
line 31 Fail: (18) lists:member(f, [b, a])
line 32 ^ Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])
line 33 Call: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], _13350)
line 34 Exit: (11) lists:append([[c, a]], [[g, b, a], [f, b, a]], [[c, a], [g, b, a], [f, b, a]])
line 35 Call: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 36 Call: (12) goal_1(c)
line 37 Fail: (12) goal_1(c)
line 38 Redo: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 39 ^ Call: (12) bagof([_13338, c, a], (s(c, _13338), +member(_13338, [c, a])), _13396)
line 40 Call: (19) s(c, _13338)
line 41 Exit: (19) s(c, r)
line 42 Call: (19) lists:member(r, [c, a])
line 43 Fail: (19) lists:member(r, [c, a])
line 44 Redo: (19) s(c, _13338)
line 45 Exit: (19) s(c, e)
line 46 Call: (19) lists:member(e, [c, a])
line 47 Fail: (19) lists:member(e, [c, a])
line 48 ^ Exit: (12) bagof([_13338, c, a], user:(s(c, _13338), +member(_13338, [c, a])), [[r, c, a], [e, c, a]])
line 49 Call: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], _13490)
line 50 Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])
line 51 Call: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 52 Call: (13) goal_1(g)
line 53 Exit: (13) goal_1(g)
line 54 Exit: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], [g, b, a])
line 55 Exit: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], [g, b, a])
line 56 Exit: (10) breadthfirst_1([[b, a], [c, a]], [g, b, a])
line 57 Exit: (9) breadthfirst_1([[a]], [g, b, a])
line 58 Exit: (8) solve_1(a, [g, b, a])
line 59 S = [g, b, a] ;
line 60 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 61 ^ Call: (13) bagof([_13484, g, b, a], (s(g, _13484), +member(_13484, [g, b, a])), _13542)
line 62 Call: (20) s(g, _13484)
line 63 Fail: (20) s(g, _13484)
line 64 ^ Fail: (13) bagof([_13484, g, b, a], user:(s(g, _13484), +member(_13484, [g, b, a])), _13548)
line 65 Redo: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 66 Call: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 67 Call: (14) goal_1(f)
line 68 Fail: (14) goal_1(f)
line 69 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 70 ^ Call: (14) bagof([_13484, f, b, a], (s(f, _13484), +member(_13484, [f, b, a])), _13542)
line 71 Call: (21) s(f, _13484)
line 72 Fail: (21) s(f, _13484)
line 73 ^ Fail: (14) bagof([_13484, f, b, a], user:(s(f, _13484), +member(_13484, [f, b, a])), _13548)
line 74 Redo: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 75 Call: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 76 Call: (15) goal_1(r)
line 77 Fail: (15) goal_1(r)
line 78 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 79 ^ Call: (15) bagof([_13484, r, c, a], (s(r, _13484), +member(_13484, [r, c, a])), _13542)
line 80 Call: (22) s(r, _13484)
line 81 Fail: (22) s(r, _13484)
line 82 ^ Fail: (15) bagof([_13484, r, c, a], user:(s(r, _13484), +member(_13484, [r, c, a])), _13548)
line 83 Redo: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 84 Call: (15) breadthfirst_1([[e, c, a]], _12870)
line 85 Call: (16) goal_1(e)
line 86 Fail: (16) goal_1(e)
line 87 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 88 ^ Call: (16) bagof([_13484, e, c, a], (s(e, _13484), +member(_13484, [e, c, a])), _13542)
line 89 Call: (23) s(e, _13484)
line 90 Fail: (23) s(e, _13484)
line 91 ^ Fail: (16) bagof([_13484, e, c, a], user:(s(e, _13484), +member(_13484, [e, c, a])), _13548)
line 92 Redo: (15) breadthfirst_1([[e, c, a]], _12870)
line 93 Call: (16) breadthfirst_1(, _12870)
line 94 Fail: (16) breadthfirst_1(, _12870)
line 95 Fail: (15) breadthfirst_1([[e, c, a]], _12870)
line 96 Fail: (14) breadthfirst_1([[r, c, a], [e, c, a]], _12870)
line 97 Fail: (13) breadthfirst_1([[f, b, a], [r, c, a], [e, c, a]], _12870)
line 98 Fail: (12) breadthfirst_1([[g, b, a], [f, b, a], [r, c, a], [e, c, a]], _12870)
line 99 Fail: (11) breadthfirst_1([[c, a], [g, b, a], [f, b, a]], _12870)
line 100 Fail: (10) breadthfirst_1([[b, a], [c, a]], _12870)
line 101 Fail: (9) breadthfirst_1([[a]], _12870)
line 102 Fail: (8) solve_1(a, _12870)
line 103 false.


At



line   7   ^  Call: (10) bagof([_13076, a],  (s(a, _13076), +member(_13076, [a])), _13134)


it shows the result of visiting the start node a which is just the path a and in a list of known paths is [a].



at



line  16   ^  Exit: (10) bagof([_13076, a], user:(s(a, _13076), +member(_13076, [a])), [[b, a], [c, a]])


for path [a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [a] and using the item at the head of the list a visit one of its neighbors s(a,b) and add that new path into a new list, [[b,a]].



with with path [a] and using the item at the head of the list a visit one of its neighbors s(a, c). and add that new path into a new list, [[b,a],[c,a]].



at



line  32   ^  Exit: (11) bagof([_13198, b, a], user:(s(b, _13198), +member(_13198, [b, a])), [[g, b, a], [f, b, a]])


for path [b, a] a new list is created by using the item at the head of the list and visiting one of it's neighbors that have not been visited and adding that new path into a new list.



So
with with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, g). and add that new path into a new list, [[g, b, a]].



with path [b, a] and using the item at the head of the list b visit one of its neighbors s(b, f). and add that new path into a new list, [[g, b, a], [f, b, a]].



Notice that the answer [g, b, a] is now in the new list but it does not have c in the path.



At



line  50     Exit: (12) lists:append([[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]])


all of the paths have been created



[[g, b, a], [f, b, a]], [[r, c, a], [e, c, a]], [[g, b, a], [f, b, a], [r, c, a], [e, c, a]]


by using all of the s/2 facts and still the path with the answer [g, b, a] has no c in it.






Why the change from conc/3 to append/3 ?




Even though it is not one of your questions I need to answer it for others that read this question, especially people learning Prolog on their own for the first time.



This is my version of the events related to conc/3 and append/3 if there is another story about it do tell; I will even ask it as a posted question if need be.



One of the best if not the best books for introductory learning/teaching Prolog is "Prolog Programming for Artificial Intelligence" By Ivan Bratko. (WorldCat) (Amazon).



When first learning Prolog, people tend to spend their life in the list data structure and get a healthy diet of append/3 but in the book he chose to have the students create their own version of append/3 and named it conc/3. So through out the book is the use of conc/3 and hardly any use of append/3. Now those people are use to conc/3 and start writing code with it, posting it, etc. and it is very infectious, and you happen to have caught it. So I gave your code the remedy.






Problem of reversing the output.




When recursion is used to solve a problem it typically stores the intermediate result on the stack. Depending on the order on the stack the results are in the correct order, or in a reversed order.



There are a few ways to get the results to be returned from recursion in the correct order.



For most beginners it is to get the results and than if need be just reverse the results. For Prolog if the result is a list then reverse/2 works.



?- reverse([g, b, a],R).
R = [a, b, g].


The predicates for reverse/2



?- listing(reverse/2).
lists:reverse(A, B) :-
reverse(A, , B, B).

true.

?- listing(reverse/4).
lists:reverse(, A, A, ).
lists:reverse([B|A], C, D, [_|E]) :-
reverse(A, [B|C], D, E).

true.


When you get into larger problems constantly reversing the result even between different predicate calls starts to add up time. This is especially true in functional programming.



Another way is by passing an accumulator. To demonstrate this I will use this simpler version of reverse.



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).
accumulator_reverse(,A,A).
accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


The first clause initializes the accumulator to an empty list for use with accumulator_reverse/3



reverse_2(L,Result) :-
accumulator_reverse(L,,Result).


The other two clauses just recursively process a list with this clause being the base case



accumulator_reverse(,A,A).


which is when the input list is empty () and



this clause



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


to take the list apart [H|T] (AKA deconstruct) and append the head H to the accumulator [H|A] (AKA construct).



As the list is processed through



accumulator_reverse([H|T],A,Result) :-
accumulator_reverse(T,[H|A],Result).


the original list gets smaller and smaller because the head is always being removed from the list and the accumulator grows because the head from the list is always being added to the accumulator. Since the order in which list is deconstructed, (front to back) and the accumulator is constructed (back to front) the list becomes reversed.



Normally when you look at refactored Prolog code if you see recursion and a base case that looks like



base(,A,A) 


where one of the arguments is an empty list or bottom, and two other parameters are the same, but one is bound when the call is made and the other is unbound when the call is made, look to see if accumulator passing has been factored into the code.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 25 '18 at 10:33

























answered Nov 23 '18 at 16:28









Guy Coder

14.9k43982




14.9k43982












  • Of interest: Quick Prolog
    – Guy Coder
    Nov 23 '18 at 20:55










  • Of interest: Ways to reverse a list in Haskell
    – Guy Coder
    Nov 23 '18 at 20:56










  • Of interest: Recursion Best Practices
    – Guy Coder
    Nov 23 '18 at 21:40










  • Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
    – John Sall
    Nov 24 '18 at 9:46










  • @sosscs See updated answer based on your comment.
    – Guy Coder
    Nov 24 '18 at 15:20


















  • Of interest: Quick Prolog
    – Guy Coder
    Nov 23 '18 at 20:55










  • Of interest: Ways to reverse a list in Haskell
    – Guy Coder
    Nov 23 '18 at 20:56










  • Of interest: Recursion Best Practices
    – Guy Coder
    Nov 23 '18 at 21:40










  • Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
    – John Sall
    Nov 24 '18 at 9:46










  • @sosscs See updated answer based on your comment.
    – Guy Coder
    Nov 24 '18 at 15:20
















Of interest: Quick Prolog
– Guy Coder
Nov 23 '18 at 20:55




Of interest: Quick Prolog
– Guy Coder
Nov 23 '18 at 20:55












Of interest: Ways to reverse a list in Haskell
– Guy Coder
Nov 23 '18 at 20:56




Of interest: Ways to reverse a list in Haskell
– Guy Coder
Nov 23 '18 at 20:56












Of interest: Recursion Best Practices
– Guy Coder
Nov 23 '18 at 21:40




Of interest: Recursion Best Practices
– Guy Coder
Nov 23 '18 at 21:40












Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
– John Sall
Nov 24 '18 at 9:46




Okay, I see, so the actual working of the algorithm is as I printed it including c, but then when it wants to print the final path, it will exclude c since it's not on the path.
– John Sall
Nov 24 '18 at 9:46












@sosscs See updated answer based on your comment.
– Guy Coder
Nov 24 '18 at 15:20




@sosscs See updated answer based on your comment.
– Guy Coder
Nov 24 '18 at 15:20


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53449457%2fbreadth-first-search-code-wont-output-bfs-result%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)