Related
I have understood the theory part of Recursion. I have seen exercises but I get confused. I've tried to solve some, some I understand and some I don't. This exercise is confusing me. I can't understand why, so I use comments to show you my weak points. I should have power (X,N,P) so P=X^N.
Some examples:
?- power(3,5,X).
X = 243
?- power(4,3,X).
X = 64
?- power(2,4,X).
X = 16
The solution of this exercise is: (See comments too)
power(X,0,1). % I know how works recursion,but those numbers 0 or 1 why?
power(X,1,X). % X,1,X i can't get it.
power(X,N,P) :- % X,N,P if only
N1 is N-1, % N1=N-1 ..ok i understand
power(X,N1,P1), % P1 is used to reach the the P
P is P1*X. % P = P1*X
What I know recursion, I use a different my example
related(X, Y) :-
parent(X, Z),
related(Z, Y).
Compare my example with the exercise. I could say that my first line, what I think. Please help me out with it is a lot of confusing.
related(X, Y) :- is similar to power(X,N,P) :- . Second sentence of my example parent(X, Z), is similar to N1 is N-1, and the third sentence is related(Z, Y). similar to power(X,N1,P1), and P is P1*X..
Let's go over the definition of the predicate step by step. First you have the fact...
power(X,0,1).
... that states: The 0th power of any X is 1. Then there is the fact...
power(X,1,X).
... that states: The 1st power of any X is X itself. Finally, you have a recursive rule that reads:
power(X,N,P) :- % P is the Nth power of X if
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Possibly your confusion is due to the two base cases that are expressed by the two facts (one of those is actually superfluous). Let's consider the following queries:
?- power(5,0,X).
X = 1 ;
ERROR: Out of local stack
The answer 1 is certainly what we expect, but then the predicate loops until it runs out of stack. That's certainly not desirable. And this query...
?- power(5,1,X).
X = 5 ;
X = 5 ;
ERROR: Out of local stack
... yields the correct answer twice before running out of stack. The reason for the redundant answer is that the recursive rule can reduce any given N to zero and to one thus yielding the same answer twice. If you look at the structure of your recursive rule, it is obvious that the first base case is sufficient, so let's remove the second. The reason for looping out of stack is that, after N becomes zero, the recursive rule will search for other solutions (for N=-1, N=-2, N=-3,...) that do not exist. To avoid that, you can add a goal that prevents the recursive rule from further search, if N is equal to or smaller than zero. That leaves you with following definition:
power(X,0,1). % the 0th power of any X is 1
power(X,N,P) :- % P is the Nth power of X if
N > 0, % N > 0 and
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Now the predicate works as expected:
?- power(5,0,X).
X = 1 ;
false.
?- power(5,1,X).
X = 5 ;
false.
?- power(5,3,X).
X = 125 ;
false.
I hope this alleviates some of your confusions.
I'm new to Prolog and I'm trying to write fully working magic square program, but to say the truth I don't really know how to do, I have started but I feel that I'm doing it wrong. I'm sharing my code and I hope someone will help me, now when numbers are good I get true, but when they are not I get like out of stack error... (here is only checking rows and columns I know about obliquely check)
thanks for your attention!
:- use_module(library(clpfd)).
:- use_module(library(lists)).
magicSq(List, N) :-
Number is N * N,
belongs(Number ,List), % check if numbers are correct.
all_different(List), % check if numbers not occur.
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma), % check column
checkR(List,1,N,Suma). % check row
belongs(0, _).
belongs(N, List) :- member(N,List) , Index is N - 1 , belongs(Index, List).
consecutiveSum(_, 0 , _,0).
consecutiveSum(List, HowMuch , From,Sum):-
Index is HowMuch - 1,
From1 is From +1,
nth1(From, List,Element),
consecutiveSum(List,Index,From1,Z),
Sum is Z + Element,!.
sumObliCol(0,_, [], _,_). % sums by columns or obliquely
sumObliCol(X,Number, [H|T], Ind, Residue) :-
Index is Ind + 1,
Y is mod(Index,Number),
Y =:= Residue,
sumObliCol(Z,Number, T, Index,Residue),
X is Z + H, !.
sumObliCol(X,Number, [_|T], Ind,Residue) :-
Index is Ind + 1,
sumObliCol(X,Number, T, Index,Residue).
checkC(_,0,_,_). % check column
checkC(List,N, Number,Answ):-
N1 is N-1,
checkC(List,N1, Number,Answ),
sumObliCol(Ats,Number,List,0,N1),Ats is Answ,!.
checkR(_,N,Number,_):- N>(Number*Number). % check row
checkR(List,N,Number,Answ):-
consecutiveSum(List,Number,N,Sum), Sum is Answ,
N1 is N + Number,
checkR(List,N1, Number,Answ),!.
In programming one often assumes that
everything is deeply intertwingled ... since the cross-connections among the myriad topics of this world/program simply cannot be divided up neatly.1
But in Prolog, sometimes, we can divide things up much more neatly. In particular, if you concentrate on a single property like non-termination. So let's consider magic squares of size one — very magic indeed! Like so using a failure-slice:
?- magicSq(Xs,1), false.
magicSq(List, N) :-
Number is N * N,
belongs(Number ,List), false,
all_different(List),
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma),
checkR(List,1,N,Suma).
belongs(0, _) :- false.
belongs(N1, List) :-
member(N1,List), false,
N2 is N1 - 1,
belongs(N2, List).
That's all you need to understand! Evidently, the List is unconstrained and thus the goal member(N1, List) cannot terminate. That's easy to fix, adding a goal length(List, Number). And still, the program does not terminate but in a different area:
?- magicSq(Xs,1), false.
magicSq(List, N) :-
Number is N * N,
length(List, Number),
belongs(Number ,List), false,
all_different(List),
Suma is N*(N*N + 1)/2,
checkC(List,N,N,Suma),
checkR(List,1,N,Suma).
belongs(0, _) :- false.
belongs(N1, List) :-
member(N1,List),
N2 is N1 - 1,
belongs(N2, List), false.
Now this does not terminate, for N1 may be negative, too. We need to improve that adding N1 > 0.
Now, considering the program with a false in front of all_different/1, I get:
?- time(magicSq(List, 3)).
% 8,571,007 inferences
That looks like an awful lot of inferences! In fact, what you are doing is to enumerate all possible configurations first. Thus, you do not use the powers of constraint programming. Please go through tutorials on this. Start here.
However, the problems do not stop here! There is much more to it, but the remaining program is very difficult to understand, for you are using the ! in completely unrelated places.
I want to write a predicate that determines if a number is prime or not. I am doing this by a brute force O(sqrt(n)) algorithm:
1) If number is 2, return true and do not check any more predicates.
2) If the number is even, return false and do no more checking predicates.
3) If the number is not even, check the divisors of the number up to the square root. Note that
we need only to check the odd divisors starting at 3 since if we get to this part of
the program the number is not even. Evens were eliminated in step 2.
4) If we find an even divisor, return false and do not check anything else.
5) If the divisor we are checking is larger than the square root of the number,
return true, we found no divisors. Do no more predicate checking.
Here is the code I have:
oddp(N) :- M is N mod 2, M = 1.
evenp(N) :- not(oddp(N)).
prime(2) :- !.
prime(X) :- X < 2, write_ln('case 1'), false, !.
prime(X) :- evenp(X), write_ln('case 2'), false, !.
prime(X) :- not(evenp(X)), write_ln('calling helper'),
prime_helper(X,3).
prime_helper(X, Divisor) :- K is X mod Divisor, K = 0,
write_ln('case 3'), false, !.
prime_helper(X, Divisor) :- Divisor > sqrt(X),
write_ln('case 4'), !.
prime_helper(X, Divisor) :- write_ln('case 5'),
Temp is Divisor + 2, prime_helper(X,Temp).
I am running into problems though. For example, if I query prime(1). the program is still checking the divisors. I thought that adding '!' would make the program stop checking if the prior conditions were true. Can someone tell me why the program is doing this? Keep in mind I am new at this and I know the code can be simplified. However, any tips would be appreciated!
#Paulo cited the key issues with the program that cause it to behave improperly and a couple of good tips. I'll add a few more tips on this particular program.
When writing a predicate, the focus should be on what's true. If your
predicate properly defines successful cases, then you don't need to explicitly
define the failure cases since they'll fail by default. This means your statements #2 and #4 don't need to be specifically defined as clauses.
You're using a lot of cuts which is usually a sign that your program
isn't defined efficiently or properly.
When writing the predicates, it's helpful to first state the purpose in logical language form (which you have done in your statements 1 through 5, but I'll rephrase here):
A number is prime if it is 2 (your statement #1), or if it is odd and it is not divisible by an odd divisor 3 or higher (your statement #3). If we write this out in Prolog, we get:
prime(X) :- % X is prime if...
oddp(X), % X is odd, AND
no_odd_divisors(X). % X has no odd divisors
prime(2). % 2 is prime
A number X is odd if X module 2 evaluates to 1.
oddp(X) :- X mod 2 =:= 1. % X is odd if X module 2 evaluates to 1
Note that rather than create a helper which essentially fails when I want success, I'm going to create a helper which succeeds when I want it to. no_odd_divisors will succeeds if X doesn't have any odd divisors >= 3.
A number X has no odd divisors if it is not divisible by 3, and if it's not divisible by any number 3+2k up to sqrt(X) (your statement #5).
no_odd_divisors(X) :- % X has no odd divisors if...
no_odd_divisors(X, 3). % X has no odd divisors 3 or above
no_odd_divisors(X, D) :- % X has no odd divisors D or above if...
D > sqrt(X), !. % D is greater than sqrt(X)
no_odd_divisors(X, D) :- % X has no odd divisors D or above if...
X mod D =\= 0, % X is not divisible by D, AND
D1 is D + 2, % X has no odd divisors D+2 or above
no_odd_divisors(X, D1).
Note the one cut above. This indicates that when we reach more than sqrt(X), we've made the final decision and we don't need to backtrack to other options for "no odd divisor" (corresponding to, Do no more predicate checking. in your statement #5).
This will yield the following behavior:
| ?- prime(2).
yes
| ?- prime(3).
(1 ms) yes
| ?- prime(6).
(1 ms) no
| ?- prime(7).
yes
| ?-
Note that I did define the prime(2) clause second above. In this case, prime(2) will first fail prime(X) with X = 2, then succeed prime(2) with nowhere else to backtrack. If I had defined prime(2) first, as your first statement (If number is 2, return true and do not check any more predicates.) indicates:
prime(2). % 2 is prime
prime(X) :- % X is prime if...
oddp(X), % X is odd, AND
no_odd_divisors(X). % X has no odd divisors
Then you'd see:
| ?- prime(2).
true ? a
no
| ?-
This would be perfectly valid since Prolog first succeeded on prime(2), then knew there was another clause to backtrack to in an effort to find other ways to make prime(2) succeed. It then fails on that second attempt and returns "no". That "no" sometimes confuses Prolog newcomers. You could also prevent the backtrack on the prime(2) case, regardless of clause order, by defining the clause as:
prime(2) :- !.
Which method you choose depends ultimately on the purpose of your predicate relations. The danger in using cuts is that you might unintentionally prevent alternate solutions you may actually want. So it should be used very thoughtfully and not as a quick patch to reduce outputs.
There are several issues on your program:
Writing a cut, !/0, after a call to false/0 is useless and as the cut will never be reached. Try exchanging the order of these two calls.
The first clause can be simplified to oddp(N) :- N mod 2 =:= 1. You can also apply this simplification in other clauses.
The predicate not/1 is better considered deprecated. Write instead evenp(N) :- \+ oddp(N).. The (\+)/1 is the standard operator/control construct for negation as failure.
We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).
So here it is : I'm trying to calculate the sum of all primes below two millions (for this problem), but my program is very slow. I do know that the algorithm in itself is terribly bad and a brute force one, but it seems way slower than it should to me.
Here I limit the search to 20,000 so that the result isn't waited too long.
I don't think that this predicate is difficult to understand but I'll explain it anyway : I calculate the list of all the primes below 20,000 and then sum them. The sum part is fine, the primes part is really slow.
problem_010(R) :-
p010(3, [], Primes),
sumlist([2|Primes], R).
p010(20001, Primes, Primes) :- !.
p010(Current, Primes, Result) :-
(
prime(Current, Primes)
-> append([Primes, [Current]], NewPrimes)
; NewPrimes = Primes
),
NewCurrent is Current + 2,
p010(NewCurrent, NewPrimes, Result).
prime(_, []) :- !.
prime(N, [Prime|_Primes]) :- 0 is N mod Prime, !, fail.
prime(ToTest, [_|Primes]) :- prime(ToTest, Primes).
I'd like some insight about why it is so slow. Is it a good implementation of the stupid brute force algorithm, or is there some reason that makes Prolog fall?
EDIT : I already found something, by appending new primes instead of letting them in the head of the list, I have primes that occur more often at start so it's ~3 times faster. Still need some insight though :)
First, Prolog does not fail here.
There are very smart ways how to generate prime numbers. But as a cheap start simply accumulate the primes in reversed order! (7.9s -> 2.6s) In this manner the smaller ones are tested sooner. Then, consider to test only against primes up to 141. Larger primes cannot be a factor.
Then, instead of stepping only through numbers not divisible by 2, you might add 3, 5, 7.
There are people writing papers on this "problem". See, for example this paper, although it's a bit of a sophistic discussion what the "genuine" algorithm actually was, 22 centuries ago when the latest release of the abacus was celebrated as Salamis tablets.
Consider using for example a sieve method ("Sieve of Eratosthenes"): First create a list [2,3,4,5,6,....N], using for example numlist/3. The first number in the list is a prime, keep it. Eliminate its multiples from the rest of the list. The next number in the remaining list is again a prime. Again eliminate its multiples. And so on. The list will shrink quite rapidly, and you end up with only primes remaining.
First of all, appending at the end of a list using append/3 is quite slow. If you must, then use difference lists instead. (Personally, I try to avoid append/3 as much as possible)
Secondly, your prime/2 always iterates over the whole list when checking a prime. This is unnecessarily slow. You can instead just check id you can find an integral factor up to the square root of the number you want to check.
problem_010(R) :-
p010(3, 2, R).
p010(2000001, Primes, Primes) :- !.
p010(Current, In, Result) :-
( prime(Current) -> Out is In+Current ; Out=In ),
NewCurrent is Current + 2,
p010(NewCurrent, Out, Result).
prime(2).
prime(3).
prime(X) :-
integer(X),
X > 3,
X mod 2 =\= 0,
\+is_composite(X, 3). % was: has_factor(X, 3)
is_composite(X, F) :- % was: has_factor(X, F)
X mod F =:= 0, !.
is_composite(X, F) :-
F * F < X,
F2 is F + 2,
is_composite(X, F2).
Disclaimer: I found this implementation of prime/1 and has_factor/2 by googling.
This code gives:
?- problem_010(R).
R = 142913828922
Yes (12.87s cpu)
Here is even faster code:
problem_010(R) :-
Max = 2000001,
functor(Bools, [], Max),
Sqrt is integer(floor(sqrt(Max))),
remove_multiples(2, Sqrt, Max, Bools),
compute_sum(2, Max, 0, R, Bools).
% up to square root of Max, remove multiples by setting bool to 0
remove_multiples(I, Sqrt, _, _) :- I > Sqrt, !.
remove_multiples(I, Sqrt, Max, Bools) :-
arg(I, Bools, B),
(
B == 0
->
true % already removed: do nothing
;
J is 2*I, % start at next multiple of I
remove(J, I, Max, Bools)
),
I1 is I+1,
remove_multiples(I1, Sqrt, Max, Bools).
remove(I, _, Max, _) :- I > Max, !.
remove(I, Add, Max, Bools) :-
arg(I, Bools, 0), % remove multiple by setting bool to 0
J is I+Add,
remove(J, Add, Max, Bools).
% sum up places that are not zero
compute_sum(Max, Max, R, R, _) :- !.
compute_sum(I, Max, RI, R, Bools) :-
arg(I, Bools, B),
(B == 0 -> RO = RI ; RO is RI + I ),
I1 is I+1,
compute_sum(I1, Max, RO, R, Bools).
This runs an order of magnitude faster than the code I gave above:
?- problem_010(R).
R = 142913828922
Yes (0.82s cpu)
OK, before the edit the problem was just the algorithm (imho).
As you noticed, it's more efficient to check if the number is divided by the smaller primes first; in a finite set, there are more numbers divisible by 3 than by 32147.
Another algorithm improvement is to stop checking when the primes are greater than the square root of the number.
Now, after your change there are indeed some prolog issues:
you use append/3. append/3 is quite slow since you have to traverse the whole list to place the element at the end.
Instead, you should use difference lists, which makes placing the element at the tail really fast.
Now, what is a difference list? Instead of creating a normal list [1,2,3] you create this one [1,2,3|T]. Notice that we leave the tail uninstantiated. Then, if we want to add one element (or more) at the end of the list we can simply say T=[4|NT]. awesome?
The following solution (accumulate primes in reverse order, stop when prime>sqrt(N), difference lists to append) takes 0.063 for 20k primes and 17sec for 2m primes while your original code took 3.7sec for 20k and the append/3 version 1.3sec.
problem_010(R) :-
p010(3, Primes, Primes),
sumlist([2|Primes], R).
p010(2000001, _Primes,[]) :- !. %checking for primes till 2mil
p010(Current, Primes,PrimesTail) :-
R is sqrt(Current),
(
prime(R,Current, Primes)
-> PrimesTail = [Current|NewPrimesTail]
; NewPrimesTail = PrimesTail
),
NewCurrent is Current + 2,
p010(NewCurrent, Primes,NewPrimesTail).
prime(_,_, Tail) :- var(Tail),!.
prime(R,_N, [Prime|_Primes]):-
Prime>R.
prime(_R,N, [Prime|_Primes]) :-0 is N mod Prime, !, fail.
prime(R,ToTest, [_|Primes]) :- prime(R,ToTest, Primes).
also, considering adding the numbers while you generate them to avoid the extra o(n) because of sumlist/2
in the end, you can always implement the AKS algorithm that runs in polynomial time (XD)