Recursion Problems in Prolog - recursion

I'm having some difficulties in prolog, I'm trying to write a predicate that will return all paths between two cities, although at the moment it returns the first path it finds on an infinite loop. Not sure where I'm going wrong but I've been trying to figure this out all day and I'm getting nowhere.
Any help that could be offered would be appreciated.
go:-
repeat,
f([],0,lon,spa,OP,OD),
write(OP),
write(OD),
fail.
city(lon).
city(ath).
city(spa).
city(kol).
path(lon,1,ath).
path(ath,3,spa).
path(spa,2,kol).
path(lon,1,kol).
joined(X,Y,D):-
path(X,D,Y);path(Y,D,X).
f(Ci_Vi,Di,De,De,PaO,Di):-
append([De],Ci_Vi,PaO),
!.
f(Cities_Visited,Distance,Start,Destination,Output_Path,Output_Distance):-
repeat,
city(X),
joined(Start,X,D),
not_member(X,Cities_Visited),
New_Distance is Distance + D,
f([Start|Cities_Visited],New_Distance,X,Destination,Output_Path,Output_Distance).
not_member(X,List):-
member(X,List),
!,
fail.
not_member(X,List).
The output I'm expecting here is [spa,ath,lon]4 [spa,kol,lon]3.
Once again, any help would be appreciated.
Many thanks in advance.

Your solution is essentially correct. Type f([],0,lon,spa,OP,OD), and you get the first path as expected. The only error I can see is that you're using repeat within your search predicate, which is why you keep computing the same solution. repeat is almost never necessary within business logic - backtracking for solutions is already built into the REP loop. Take it out, and you'll get the second path as expected, and then (correctly) failure.

Related

Struggling with building an intuition for recursion

Though I have studied and able am able to understand some programs in recursion, I am still not able to intuitively obtain a solution using recursion as I do easily using Iteration. Is there any course or track available in order to build an intuition for recursion? How can one master the concept of recursion?
if you want to gain a thorough understanding of how recursion works, I highly recommend that you start with understanding mathematical induction, as the two are very closely related, if not arguably identical.
Recursion is a way of breaking down seemingly complicated problems into smaller bits. Consider the trivial example of the factorial function.
def factorial(n):
if n < 2:
return 1
return n * factorial(n - 1)
To calculate factorial(100), for example, all you need is to calculate factorial(99) and multiply 100. This follows from the familiar definition of the factorial.
Here are some tips for coming up with a recursive solution:
Assume you know the result returned by the immediately preceding recursive call (e.g. in calculating factorial(100), assume you already know the value of factorial(99). How do you go from there?)
Consider the base case (i.e. when should the recursion come to a halt?)
The first bullet point might seem rather abstract, but all it means is this: a large portion of the work has already been done. How do you go from there to complete the task? In the case of the factorial, factorial(99) constituted this large portion of work. In many cases, you will find that identifying this portion of work simply amounts to examining the argument to the function (e.g. n in factorial), and assuming that you already have the answer to func(n - 1).
Here's another example for concreteness. Let's say we want to reverse a string without using in-built functions. In using recursion, we might assume that string[:-1], or the substring until the very last character, has already been reversed. Then, all that is needed is to put the last remaining character in the front. Using this inspiration, we might come up with the following recursive solution:
def my_reverse(string):
if not string: # base case: empty string
return string # return empty string, nothing to reverse
return string[-1] + my_reverse(string[:-1])
With all of this said, recursion is built on mathematical induction, and these two are inseparable ideas. In fact, one can easily prove that recursive algorithms work using induction. I highly recommend that you checkout this lecture.

Recursive thinking

I would like to ask if it is really necessary to track every recursive call when writing it, because I am having troubles if recursive call is inside a loop or inside multiple for loops. I just get lost when I am trying to understand what is happening.
Do you have some advice how to approach recursive problems and how to imagine it. I have already read a lot about it but I havent found a perfect answer yet. I understand for example how factorial works or fibonacci recursion. I get lost for example when I am trying to print all combinations from 1 to 5 length of 3 or all the solutions for n-queen problem
I had a similar problem, try drawing a tree like structure that keeps track of each recursive call. Where a node is a function and every child node of that node is a recursive call made from that function.
Everyone may have a different mental approach towards towards modeling a recursive problem. If you can solve the n queens problem in a non-recursive way, then you are just fine. It is certainly helpful to grasp the concept of recursion to break down a problem, though. If you are up for the mental exercise, then I suggest a text book on PROLOG. It is fun and very much teaches recursion from the very beginning.
Attempting a bit of a brain dump on n-queens. It goes like "how would I do it manually" by try and error. For n-queens, I propose to in your mind call it 8-queens as a start, just to make it look more familiar and intuitive. "n" is not an iterator here but specifies the problem size.
you reckon that n-queens has a self-similarity which is that you place single queens on a board - that is your candidate recursive routine
for a given board you have a routine to test if the latest queen added is in conflict with the prior placed ones
for a given board you have a routine to find a position for the queen that you have not tested yet if that test is not successful for the current position
you print out all queen positions if the queen you just placed was the nth (last) queen
otherwise (if the current queen was validly placed) you position an additional queen
The above is your program. Your routine will pass a list of positions of earlier queens. The first invocation is with an empty list.

Prolog 'Out of Local Stack'

I am developing a program that solves a more complicated version of the infamous puzzle 'The farmer, the fox, the goose, and the grain', which has eight components instead of four. I've already determined the solution; additionally, I've written out just the necessary states to complete the problem, like this:
move([w,w,w,w,w,w,w,w],[e,w,w,e,w,w,w,w]).
move([e,w,w,e,w,w,w,w],[w,w,w,e,w,w,w,w]).
etc.
My goal now is to have this program follow those states, chaining from one to the next, until it reaches the ultimate goal of [e,e,e,e,e,e,e,e]. To accomplish this, I have defined predicates as such:
solution([e,e,e,e,e,e,e,e],[]).
solution(Start,End) :-
move(Start,NextConfig),
solution(NextConfig,End).
My query is solution([w,w,w,w,w,w,w,w],[e,e,e,e,e,e,e,e]). However, this results in apparently infinite recursion. What am I missing?
To avoid cycles, try closure0/3
solution(S) :-
closure0(move, S,[e,e,e,e,e,e,e,e]).

Product of range in Prolog

I need to write a program, which calculates product of product in range:
I written the following code:
mult(N,N,R,R).
mult(N,Nt,R,Rt):-N1=Nt+1,R1=Rt*(1/(log(Nt))),mult(N,N1,R,R1).
This should implement basic product from Nt to N of 1/ln(j). As far as I understand it's got to be stopped when Nt and N are equal. However, I can't get it working due to:
?- mult(10,2,R,1), write(R).
ERROR: Out of global stack
The following error. Is there any other way to implement loop not using default libraries of SWI-Prolog?
Your program never terminates! To see this consider the following failure-slice of your program:
mult(N,N,R,R) :- false.
mult(N,Nt,R,Rt):-
N1=Nt+1,
R1=Rt*(1/(log(Nt))),
mult(N,N1,R,R1), false.
This new program does never terminate, and thus the original program doesn't terminate. To see that this never terminates, consider the two (=)/2 goals. In the first, the new variable N1 is unified with something. This will always succeed. Similarly, the second goal with always succeed. There will never be a possibility for failure prior to the recursive goal. And thus, this program never terminates.
You need to add some goal, or to replace existing goals. in the visible part. Maybe add
N > Nt.
Further, it might be a good idea to replace the two (=)/2 goals by (is)/2. But this is not required for termination, strictly speaking.
Out of global stack means you entered a too-long chain of recursion, possibly an infinite one.
The problem stems from using = instead of is in your assignments.
mult(N,N,R,R).
mult(N,Nt,R,Rt):-N1 is Nt+1, R1 is Rt*(1/(log(Nt))), mult(N,N1,R,R1).
You might want to insert a cut in your first clause to avoid going on after getting an answer.
If you have a graphical debugger (like the one in SWI) try setting 'trace' and 'debug' on and running. You'll soon realize that performing N1 = Nt+1 giving Ntas 2 yields the term 2+1. Since 2+1+1+1+(...) will never unify with with 10, that's the problem right there.

Prolog recursion stopping

In the bottom i gave link to whole program (ciao) to make help easier.
I try to make in Prolog function that will be have list of questions like
questions([[[What, are,you,doing,?],[Where,am,I,Incorrect,?]]]).
answers([[Im,doing,exercise],[I,do,nothing]],[[You,are,incorrect,at,'..'],[i,dont,know]]]).
wordkeys([[[Incorrect,50],[doing,20]]]).
I know it look really messy but I really need help and will be grateful.
Main function is checking which answer is the best (having biggest sum of keywords points).
My problem is that all look fine(made some write() to see what happening) till it go to last function here :
count_pnt_keys()
Prolog checking all words if their equal but when is out from keywords should come back to function called it but its just 'no' . Maybe I should check if list is empty before I call again the same function with just Tail? How to do this?
rules:
count_pnt([],[],[]).
count_pnt([Ah|At],Keys,RList) :- %choose one answer from answer list and go further
count_pnt_word(Ah,Keys,Pnts), %return sum of points for one answer
count_ADD_POINT(RList,Pnts), %not important here
count_pnt(At,Keys,RList). %call again with next question
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
count_pnt_word([],[],0)
count_pnt_word([Ah|At],Keys,Pnts) :- %choose one WORD from answer and go further
count_pnt_keys(Ah,Keys,Pnts),
count_pnt_word(At,Keys,Pnts). %call recursion with next word from answer
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
count_pnt_keys([],[],0)
count_pnt_keys(AWord,[Kh|Kt],Pnts) :- %check word with all keys for first question
get_tail_h(Kh,KWORD,KPOINTS), %just return head and tail from first key
AWord==KWORD, %check if they are equal
/*counting points*/ !, %counting not important when end counting points go out to next
count_pnt_keys(AWord,Kt,Pnts). %call again if not equal and try with next key
and I call it:
test :-
write(AnswerFirst),
count_pnt(FirstPackOfAnswer,FirstPackofKeys,ReturnedListwithpoints),
write(ReturnedListwithpoints).
link to code (ciao)
http://wklej.org/id/754478/
You call count_pnt with three free arguments, which means that count_pnt will first unify all its arguments with an empty list. Upon backtracking the recursive count_pnt clause is called which leads to count_pnt_keys with again three free arguments, that will lead to Ah being unified with [] etc rather than a failure.
Do you really call count_pnt as suggested by the code for test?
count_pnts(_,_,[],_).
count_pnt_word(_,[],_).
count_pnt_keys([],_,_).
should look like this that was a problem

Resources