I need to find the factors of a given number , e.g :
?- divisors2(40,R).
R = [40,20,10,8,5,4,2,1].
The code :
% get all the numbers between 1-X
range(I,I,[I]).
range(I,K,[I|L]) :- I < K, I1 is I + 1, range(I1,K,L).
% calc the modulo of each element with the given number :
% any x%y=0 would be considered as part of the answer
divisors1([],[],_).
divisors1([H|T],S,X):-divisors1(T,W,X),Z is X mod H,Z==0,S=[H|W].
divisors1([_|T],S,X):-divisors1(T,S,X).
divisors2(X,Result) :-range(1,X,Result1),divisors1(Result1,Result,X).
But when I run divisors2(40,RR).
I get infinite loop and nothing is presented to the screen.
Why ?
Regards
You have a bug here
If Z is Zero then S = [H|W] else S = W.
If you correct your range (use a cut for the end-of-recursion clause), you will get it sort of working. You do not immediately succeed upon finding all divisors though.
A solution using your general idea, but also built-ins between/3 and bagof/3 (to make typing a bit easier):
Please note that this solution returns the divisors in increasing order.
You are asking why you get an infinite loop for the query
divisors2(40,R)
. I almost wanted to explain this to you using a failure-slice. Alas ...... the answer is: No, you don't get an infinite loop! And your program also finds an answer. It's
which looks reasonable to me. They are in ascending order, and you wanted a descending list, but apart from that, that is a perfect answer. No kidding. However, I suspect that you were not patient enough to get the answer. For 36 I needed:
Quite unusual ... for a list with at most 36 meager integers Prolog needed 10 744 901 605 inferences, that is less than 234. Does this ring a bell? In any case, there are problems with your program. In fact, there are two quite independent problems. How can we find them?
Maybe we are looking at the wrong side. Just go back to the query. Our first error was how we used Prolog's toplevel. We were very impressed to get an answer. But Prolog offered us further answers! In fact:
This gets too tedious. Maybe a tiny example suffices?
More than enough! Maybe we stick to the minimal example
[]
and restate it:Clearly, that's not what we expected. We wanted this to fail. How to localize the problem? There is one general debugging strategy in Prolog:
We can specialize the program by adding further goals such that above query still succeeds. I will add
false
and some(=)/2
goals.false
is particularly interesting because it wipes out an entire clause:Somewhere in the remaining part something is too general! In fact the recursive rule of
divisors1/3
is too general. This new modified program of yours is called a slice that is a specialization of our original program.Several ways to fix this, the most naive way is to add the corresponding condition like so:
However, the performance of the program did not improve. To see this, I will again specialize this program:
Thus: No matter what is there behind the
false
, this program will try at least3 * 2^N
inferences for a list of lengthN
.By putting the recursive goals last we can avoid this.