Alternative to \+ in Prolog? - prolog

I have a program that returns true if an integer is prime, and else false.
However I used the built-in predicate '\ +' which it turns out I am not allowed to use, how could I get around not using it?
is_prime(2).
is_prime(3).
is_prime(P) :- P > 3, P mod 2 =\= 0, \+ has_factor(P,3).
has_factor(N,L) :- N mod L =:= 0.
has_factor(N,L) :- L * L < N, L2 is L + 2, has_factor(N,L2).
Any help would be much appreciated!

not/1 in Prolog is implemented with the combination cut-fail (so called NAF - negation by failure).
Code should be (untested)
...
is_prime(P) :- P > 3, P mod 2 =\= 0, has_factor(P,3), !, fail.
is_prime(P) :- P > 3, P mod 2 =\= 0.

Related

How to use an fd solver to determine which elements of a list can sum to a given number?

Given a list of possible summands I want to determine which, if any, can form a given sum. For example, with [1,2,3,4,5] I can make the sum of 9 with [4,5], [5,3,1], and [4,3,2].
I am using GNU Prolog and have something like the following which does not work
numbers([1,2,3,4,5]).
all_unique(_, []).
all_unique(L, [V|T]) :-
fd_exactly(1, L, V),
all_unique(L, T).
fd_sum([], Sum).
fd_sum([H|T], Sum):-
S = Sum + H,
fd_sum(T, S).
sum_clp(N, Summands):-
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
fd_domain(Y, [N]),
all_unique(S, Numbers),
fd_sum(S, Sum),
Sum #= Y,
fd_labeling(S).
I think the main problem is that I am not representing the constraint on the sum properly? Or maybe it is something else?
Just in case you're really interested in CLP(FD), here is your corrected program.
numbers([1,2,3,4,5]).
% note: use builtins where available, both for efficiency and correctness
%all_unique(_, []).
%all_unique(L, [V|T]) :-
% fd_exactly(1, L, V),
% all_unique(L, T).
fd_sum([], 0). % sum_fd_SO.pl:8: warning: singleton variables [Sum] for fd_sum/2
fd_sum([H|T], Sum):-
% note: use CLP(FD) operators and the correct operands
Sum #= S + H,
fd_sum(T, S).
sum_clp(N, S):- % sum_fd_SO.pl:13-23: warning: singleton variables [Summands] for sum_clp/2
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
%fd_domain(Y, [N]),
%all_unique(S, Numbers),
fd_all_different(S),
fd_sum(S, N),
%Sum #= Y,
fd_labeling(S).
test
?- sum_clp(3,L).
L = [3] ? ;
L = [1,2] ? ;
L = [2,1] ? ;
no
I think mixing the code for sublist into clp code is causing some confusion. GNU-Prolog has a sublist/2 predicate, you can use that.
You seem to be building the arithmetic expression with fd_sum but it is incorrectly implemented.
sum_exp([], 0).
sum_exp([X|Xs], X+Xse) :-
sum_exp(Xs, Xse).
sum_c(X, N, Xsub) :-
sublist(Xsub, X),
sum_exp(Xsub, Xe),
N #= Xe.
| ?- sum_exp([A, B, C, D], X).
X = A+(B+(C+(D+0)))
yes
| ?- sum_c([1, 2, 3, 4, 5], 9, X).
X = [4,5] ? ;
X = [2,3,4] ? ;
X = [1,3,5] ? ;
(1 ms) no
| ?- length(X, 4), sum_c(X, 4, [A, B]), member(A, [1, 2, 3]).
A = 1
B = 3
X = [_,_,1,3] ? ;
A = 2
B = 2
X = [_,_,2,2] ? ;
A = 3
B = 1
X = [_,_,3,1] ?
yes

Finding prime factors in Prolog

prime_factors(N, [_:_]) :- prime_factors(N, [_:_], 2).
prime_factors(N, [_:_], D) :- N mod D == 0, N1 is N div D,
prime_factors(N1, [_:D], D).
prime_factors(N, [_:_], D) :- N mod D =\= 0, D1 is D+1, prime_factors(N, [_:_], D1).
This is my proposed solution to find the prime factors of an input N.
When I try to run it I am getting an error about such a predicate/2 not existing - is my syntax somehow wrong with the extended predicate/3?
Using a second parameter that only seems to unify in the second case, does not seem to make much sense. Furthermore this is not the way you construct a list in Prolog anyway, since:
the "cons" has syntax [H|T], so then it should be [_|_];
by using underscores the predicates are not interested in the values, you each time pass other parameters; and
in Prolog one typically does not construct lists with answers, typically backtracking is used. One can use findall/3 to later construct a list. This is usually better since that means that we can also query like prime_factor(1425, 3) to check if 3 is a prime factor of 1425.
We can thus construct a predicate that looks like:
prime_factor(N, D) :-
find_prime_factor(N, 2, D).
find_prime_factor(N, D, D) :-
0 is N mod D.
find_prime_factor(N, D, R) :-
D < N,
(0 is N mod D
-> (N1 is N/D, find_prime_factor(N1, D, R))
; (D1 is D + 1, find_prime_factor(N, D1, R))
).
For example:
?- prime_factor(1425, R).
R = 3 ;
R = 5 ;
R = 5 ;
R = 19 ;
false.
?- prime_factor(1724, R).
R = 2 ;
R = 2 ;
R = 431 ;
false.
If we want a list of all prime factors, we can use findall/3 for that:
prime_factors(N, L) :-
findall(D, prime_factor(N, D), L).
For example:
?- prime_factors(1425, R).
R = [3, 5, 5, 19].
?- prime_factors(1724, R).
R = [2, 2, 431].
?- prime_factors(14, R).
R = [2, 7].
?- prime_factors(13, R).
R = [13].

Tail-recursive program in prolog which outputs odd numbers in a list

I've written a tail-recursive predicate in Prolog which outputs the integers between A and B in a list K. I've used "reverse" to bring the numbers into the right order:
numbers(A,B,K) :- numbers(A,B,[],K).
numbers(Y,Y,X,K) :- !, reverse([Y|X],K).
numbers(A,B,X,K) :- A<B, C is A+1, numbers(C,B,[A|X],K).
Query:
?- numbers(3,6, K).
K=[3,4,5,6]
All works fine. What I now want to do is that I only want to have odd numbers of the range between A and B in the list K. How can I do that? Thanks in advance!
Firstly, I would try to avoid using reverse/2. If you have such a solution, it's often an indicator that there's a better way to get the answer forwards more directly. Not always, but most often. reverse/2 is probably the 2nd favorite band-aid in Prolog right behind use of the cut. :)
In many problems, an auxiliary accumulator is needed. In this particular case, it is not. Also, I would tend to use CLP(FD) operations when involving integers since it's the more relational approach to reasoning over integers. But you can use the solution below with is/2, etc, if you wish. It just won't be as general.
numbers(S, E, []) :- S #> E. % null case
numbers(X, X, [X]).
numbers(S, E, [S|T]) :-
S #< E,
S1 #= S + 1,
numbers(S1, E, T).
| ?- numbers(3, 8, L).
L = [3,4,5,6,7,8] ? ;
no
| ?- numbers(A, B, [2,3,4,5]).
A = 2
B = 5 ? ;
no
| ?-
This solution avoids reverse/2 and is tail recursive.
To update it for odd integers, the first thought is that we can easily modify the above to do every other number by just adding 2 instead of 1:
every_other_number(S, E, []) :- S #> E.
every_other_number(X, X, [X]).
every_other_number(S, E, [S|T]) :-
S #< E,
S1 #= S + 2,
every_other_number(S1, E, T).
| ?- every_other_number(3, 7, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(3, 8, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(4, 8, L).
L = [4,6,8] ? ;
no
| ?-
Then we can do odd numbers by creating an initial predicate to ensure the condition that the first value is odd and calling every_other_number/3:
odd_numbers(S, E, L) :-
S rem 2 #= 1,
every_other_number(S, E, L).
odd_numbers(S, E, L) :-
S rem 2 #= 0,
S1 #= S + 1,
every_other_number(S1, E, L).
| ?- odd_numbers(2, 8, L).
L = [3,5,7] ? ;
no
| ?- odd_numbers(2, 9, L).
L = [3,5,7,9] ? ;
no
| ?- odd_numbers(3, 8, L).
L = [3,5,7] ? ;
no
| ?-
This could be a solution, using mod/2 operator.
numbers(A,B,K) :-
B1 is B+1,
numbers(A,B1,[],K).
numbers(Y,Y1,X,K) :-
Y = Y1,
reverse(X,K).
numbers(A,B,X,K) :-
A<B,
C is A+1,
C1 is mod(C,2),
(C1 = 0 ->
numbers(C,B,[A|X],K)
; numbers(C,B,X,K)).
Another possibility is to use DCG :
numbers(A,B,K) :-
phrase(odd(A,B), K).
odd(A,B) --> {A > B, !}, [].
odd(A,B) --> {A mod2 =:= 0, !, C is A+1}, odd(C,B).
odd(A,B) --> {C is A+2}, [A], odd(C, B).

Goldbach’s Conjecture in prolog

Goldbach’s Conjecture : Every positive even number greater than 2 is the sum of two prime numbers. Eg 28 (5,23 and 11,17)
I want Prolog code to print below (all combinations) :
?- goldbach(28, L).
Output :
L = [5,23];
L = [11, 17];
I have a code which prints single combination[5,23], but not the next [11,17].
is_prime(2).
is_prime(3).
is_prime(P) :- integer(P), P > 3, P mod 2 =\= 0, \+ has_factor(P,3).
has_factor(N,L) :- N mod L =:= 0.
has_factor(N,L) :- L * L < N, L2 is L + 2, has_factor(N,L2).
goldbach(4,[2,2]) :- !.
goldbach(N,L) :- N mod 2 =:= 0, N > 4, goldbach(N,L,3).
goldbach(N,[P,Q],P) :- Q is N - P, is_prime(Q), !.
goldbach(N,L,P) :- P < N, next_prime(P,P1), goldbach(N,L,P1).
next_prime(P,P1) :- P1 is P + 2, is_prime(P1), !.
next_prime(P,P1) :- P2 is P + 2, next_prime(P2,P1).
Drop the cuts (and add a condition to avoid duplicate answers).
goldbach(4,[2,2]).
goldbach(N,L) :-
N mod 2 =:= 0,
N > 4,
goldbach(N,L,3).
goldbach(N,[P,Q],P) :-
Q is N - P,
is_prime(Q), P < Q.
goldbach(N,L,P) :-
P < N,
next_prime(P,P1),
goldbach(N,L,P1).

what is the mean of \+ in the below code

I am analyzing the code of whether a number is prime or not i am not able to get the meaning of operator "\+" in prolog.(I am naive in prolog).
is_prime(2). is_prime(3).
is_prime(P) :- integer(P), P > 3, P mod 2 =\= 0, \+ has_factor(P,3).
has_factor(N,L) :- N mod L =:= 0.
has_factor(N,L) :- L * L < N, L2 is L + 2, has_factor(N,L2).
I have understand the other thing but not able to understand the meaning of "\+" in second line.
can anyone explain me the above?
It means "not provable". So \+ Thing succeeds if Thing can't be proven.
There's a useful dictionary of Prolog. The negation section is what you're after.

Resources