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.
Related
I'm currently learning SWI-Prolog. I want to implement a function factorable(X) which is true if X can be written as X = n*b.
This is what I've gotten so far:
isTeiler(X,Y) :- Y mod X =:= 0.
hatTeiler(X,X) :- fail,!.
hatTeiler(X,Y) :- isTeiler(Y,X), !; Z is Y+1, hatTeiler(X,Z),!.
factorable(X) :- hatTeiler(X,2).
My problem is now that I don't understand how to end the recursion with a fail without backtracking. I thought the cut would do the job but after hatTeilerfails when both arguments are equal it jumps right to isTeiler which is of course true if both arguments are equal. I also tried using \+ but without success.
It looks like you add cuts to end a recursion but this is usually done by making rule heads more specific or adding guards to a clause.
E.g. a rule:
x_y_sum(X,succ(Y,1),succ(Z,1)) :-
x_y_sum(X,Y,Z).
will never be matched by x_y_sum(X,0,Y). A recursion just ends in this case.
Alternatively, a guard will prevent the application of a rule for invalid cases.
hatTeiler(X,X) :- fail,!.
I assume this rule should prevent matching of the rule below with equal arguments. It is much easier just to add the inequality of X and Y as a conditon:
hatTeiler(X,Y) :-
Y>X,
isTeiler(Y,X),
!;
Z is Y+1,
hatTeiler(X,Z),
!.
Then hatTeiler(5,5) fails automatically. (*)
You also have a disjunction operator ; that is much better written as two clauses (i drop the cuts or not all possibilities will be explored):
hatTeiler(X,Y) :- % (1)
Y > X,
isTeiler(Y,X).
hatTeiler(X,Y) :- % (2)
Y > X,
Z is Y+1,
hatTeiler(X,Z).
Now we can read the rules declaratively:
(1) if Y is larger than X and X divides Y without remainder, hatTeiler(X,Y) is true.
(2) if Y is larger than X and (roughly speaking) hatTeiler(X,Y+1) is true, then hatTeiler(X, Y) is also true.
Rule (1) sounds good, but (2) sounds fishy: for specific X and Y we get e.g.: hatTeiler(4,15) is true when hatTeiler(4,16) is true. If I understand correctly, this problem is about divisors so I would not expect this property to hold. Moreover, the backwards reasoning of prolog will then try to deduce hatTeiler(4,17), hatTeiler(4,18), etc. which leads to non-termination. I guess you want the cut to stop the recursion but it looks like you need a different property.
Coming from the original property, you want to check if X = N * B for some N and B. We know that 2 <= N <= X and X mod N = 0. For the first one there is even a built-in called between/2 that makes the whole thing a two-liner:
hT(X,B) :-
between(2, X, B),
0 is (X mod B).
?- hT(12,X).
X = 2 ;
X = 3 ;
X = 4 ;
X = 6 ;
X = 12.
Now you only need to write your own between and you're done - all without cuts.
(*) The more general hasTeiler(X,X) fails because is (and <) only works when the right hand side (both sides) is variable-free and contains only arithmetic terms (i.e. numbers, +, -, etc).
If you put cut before the fail, it will be freeze the backtracking.
The cut operation freeze the backtracking , if prolog cross it.
Actually when prolog have failed, it backtracks to last cut.
for example :
a:- b,
c,!,
d,
e,!,
f.
Here, if b or c have failed, backtrack do not freeze.
if d or f have failed, backtrack Immediately freeze, because before it is a cut
if e have failed , it can backtrack just on d
I hope it be useful
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.
Hello can anyone help me compute the sum of the first n numbers. For example n=4 => sum = 10.
So far I've wrote this
predicates
sum(integer,integer)
clauses
sum(0,0).
sum(N,R):-
N1=N-1,
sum(N1,R1),
R=R1+N.
This one works but I need another implementation. I don't have any ideas how I could make this differen . Please help
What #mbratch said.
What you're computing is a triangular number. If your homework is about triangular numbers and not about learning recursive thinking, you can simply compute it thus:
triangular_number(N,R) :- R is N * (N+1) / 2 .
If, as is more likely, you're learning recursive thought, try this:
sum(N,R) :- % to compute the triangular number n,
sum(N,1,0,R) % - invoke the worker predicate with its counter and accumulator properly seeded
.
sum(0,_,R,R). % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
sum(C,X,T,R) :- % otherwise,
C > 0 , % - assuming the count is greater than zero
T1 is T+X , % - increment the accumulator
X1 is X+1 , % - increment the current number
C1 is C-1 , % - decrement the count
sum(C1,X1,T1,R) % - recurse down
. % Easy!
Edited to add:
Or, if you prefer a count down approach:
sum(N,R) :- sum(N,0,R).
sum(0,R,R). % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
sum(N,T,R) :- % otherwise,
N > 0 , % - assuming the count is greater than zero
T1 is T+N , % - increment the accumulator
N1 is N-1 , % - decrement the count
sum(N1,T1,R) % - recurse down
. % Easy!
Both of these are tail-recursive, meaning that the prolog compiler can turn them into iteration (google "tail recursion optimization" for details).
If you want to eliminate the accumulator, you need to do something like this:
sum(0,0).
sum(N,R) :-
N > 0 ,
N1 is N-1 ,
sum(N1,R1) ,
R is R1+N
.
A little bit simpler, but each recursion consumes another stack frame: given a sufficiently large value for N, execution will fail with a stack overflow.
sum(N, Sum) :-
Sum is (N + 1) * N / 2 .
Since you already got plenty of advice about your code, let me throw in a snippet (a bit off-topic).
Counting, and more generally, aggregating, it's an area where Prolog doesn't shine when compared to other relational,declarative languages (read SQL). But some vendor specific library make it much more pleasant:
?- aggregate(sum(N),between(1,4,N),S).
S = 10.
This is the "heart" of your program:
sum(N,R):-
R=R+N,
N=N-1,
sum(N,R).
The =/2 predicate (note the /2 means it accepts 2 arguments) is the instantiation predicate, not an assignment, or logical equal. It attempts to unify its arguments to make them the same. So if N is anything but 0, then R=R+N will always fail because R can never be the same as R+N. Likewise for N=N-1: it will always fail because N and N-1 can never be the same.
In the case of =/2 (unification), expressions are not evaluated. They are just terms. So if Y = 1, then X = Y + 1 unifies X with 1+1 as a term (equivalently written +(1,1)).
Because of the above issues, sum will always fail.
Numerical assignment of an arithmetic expression is done in Prolog with the is/2 predicate. Like this:
X is Y + 1.
This operator unifies the value of X to be the same as the value of the evaluated expression Y+1. In this case, you also cannot have X is X+1 for the same reason given above: X cannot be made the same as X+1 and Prolog does not allow "re-instantiation" of a variable inside of a clause. So you would need something like, X1 is X + 1. Also note that for is/2 to work, everything in the expression on the right must be previously instantiated. If any variables in the expression on the right do not have a value, you will get an instantiation error or, in the case of Turbo Prolog, Free variable in expression....
So you need to use different variables for expression results, and organize the code so that, if using is/2, variables in the expression are instantiated.
EDIT
I understand from Sergey Dymchenko that Turbo Prolog, unlike GNU or SWI, evaluates expressions for =/2. So the = will work in the given problem. However, the error regarding instantiation (or "free variable") is still caused by the same issue I mentioned above.
sum(N, N, N).
sum(M, N, S):-
N>M,
X is M+1,
sum(X, N, T),
S is M+T.
?- sum(1,5,N).
N = 15 .
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).
I understand that I need to figure out my own homework, but seeing that noone in the class can figure it out, I need some help.
Write a Prolog program such that p(X)
is true if X is a list consisting of n
a's followed by n+1 b's, for any n >= 1.
I don't remember how to code this in Prolog, but the idea is this:
Rule 1:
If listsize is 1, return true if the element is a B.
Rule 2:
If listsize is 2, return false.
Rule 3:
Check if the first item in the list is an A and the last one is a B.
If this is true, return the solution for elements 2 to listsize-1.
If I understood your problem correctly that should be the perfect Prolog style solution.
Edit: I totally forgot about this. I edited the answer to consider the case of n = 1 and n = 2. Thanks to Heath Hunnicutt.
You should use a counter to keep track of what you have found so far. When you find an b, add one to the counter. When you find a a, subtract one. The final value of your counter after the whole list is traversed should be one, since you want the number of b's to be 1 more than the number of a's. Here's an example of how to write that in code:
% When we see an "a" at the head of a list, we decrement the counter.
validList([a|Tail], Counter) :-
NewCounter is Counter - 1,
validList(Tail, NewCounter).
% When we see an "b" at the head of a list, we increment the counter.
validList([b|Tail], Counter) :-
NewCounter is Counter + 1,
validList(Tail, NewCounter).
% When we have been through the whole list, the counter should be 1.
validList([], 1).
% Shortcut for calling the function with a single parameter.
p(X) :-
validList(X, 0).
Now, this will do almost what you want - it matches the rules for all n >= 0, while you want it for all n >= 1. In typical homework answer fashion, I've left that last bit for you to add yourself.
Here is my abstruse solution
:-use_module(library(clpfd)).
n(L, N) -->
[L],
{N1 #= N-1
},
!, n(L, N1).
n(_, 0) --> [], !.
ab -->
n(a, N),
{N1 is N + 1
},
n(b, N1).
p(X) :- phrase(ab, X).
test :-
p([b]),
p([a,b,b]),
p([a,a,b,b,b]),
p([a,a,a,b,b,b,b]),
\+ p([a]),
\+ p([a,b]),
\+ p([a,a,b,b]),
\+ p([a,b,b,c]).
testing:
?- [ab].
% ab compiled 0.00 sec, -36 bytes
true.
?- test.
true.