Goldbach’s Conjecture in prolog - 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).

Related

PROLOG : Given a number X, find all multiples of 4 less or equal than X

I have the following program:
list4(N, L) :-
list4(0, N, L).
list4(N, N, [N]).
list4(N0, N, [N0| List]) :-
N0 < N,
N1 is N0+1,
list4(N1, N, List).
When i change the line N1 is N0+1 to N1 is 4*N0 i get stack limit exceeded error.
My expected result is
list4(10,L).
L = [4,8]
Two problems with the 4*N0 version:
In list4/2 you initialize list4/3 with N0=0, which, multiplied with anything, always stays 0. That causes the infinite recursion. As you want multiples of four, you can just keep increasing N0 by one in each step and multiply it by 4 before putting it into the list.
The anchor relies on your count variable arriving at N exactly, but N0 * 4 overshoots. The first rule of list4/3 has to cover the rest of the cases with N0*4 > N as well. To also include the upper limit in the result, we can make the anchor stop at values larger than the limit and handle the upper bound itself in the second rule.
Expressed in code:
list4(N, L) :-
list4(1, N, L).
list4(N0, N, []) :- N4Times is N0*4,N4Times > N.
list4(N0, N, [N4Times| List]) :-
N4Times is N0*4,
N4Times =< N,
N1 is N0 + 1,
list4(N1, N, List).
Results in:
?- list4(10,L).
L = [4, 8] ;
false.
?- list4(8,L).
L = [4, 8] ;
false.
You can initialize the accumulator with 0 and increment it by 4 at each step.
% list4(+Upperbound, -MultiplesOfFour)
list4(U, M) :-
list4(0, U, M).
list4(A, U, L) :-
M is A+4,
( M =< U
-> L = [M|Ms],
list4(M, U, Ms)
; L = [] ).
Examples:
?- list4(10, L).
L = [4, 8].
?- list4(8, L).
L = [4, 8].
?- list4(20, L).
L = [4, 8, 12, 16, 20].
?- list4(30, L).
L = [4, 8, 12, 16, 20, 24, 28].
?- list4(3, L).
L = [].

How do I create a list with elements from 1 to N in prolog

I've tried to create a program that makes a list with elements from 1 to N.
increasing(L, N):-
increasing(L, N, 1).
increasing([X|L], N, X):-
X =< N,
X1 is X + 1,
increasing(L, N, X1).
But for some reason it doesn't work
The problem is that eventually, you will make a call to increasing/3 where X <= N is not satisfied, and then that predicate will fail, and thus "unwind" the entire call stack.
You thus need to make a predicate that will succeed if X > N, for example:
increasing(L, N):-
increasing(L, N, 1).
increasing([], N, X) :-
X > N,
!.
increasing([X|L], N, X):-
X =< N,
X1 is X + 1,
increasing(L, N, X1).
For example:
?- increasing(L, 5).
L = [1, 2, 3, 4, 5].

How can labeling/2 generate solutions starting from the midpoint of a domain?

Having a list with independent variables, whose domain is 1..N, how can we use labeling/2 so it starts producing solutions starting from the middle?
The flags i tried are [bisect], [enum], [max], [min], [ff], but no matter which i picked, i can't make it work.
My code is:
:-use_module(library(clpfd)).
combos(EMPLOYEES,POSTS,LIST):-
LIMIT is POSTS-EMPLOYEES+1,
length(LIST,EMPLOYEES),
LIST ins 1..LIMIT,
sum(LIST,#=,POSTS),
labeling([bisect],LIST).
after setting a query, for example:
?-combos(2,10,LIST).
i want it to return:
L = [5,5];
L = [4,6];
L = [6,4] ...
instead of:
L = [1,9];
L = [2,8];
L = [3,7] ...
As a rule of thumb, whenever you try to extend the functionality of clpfd, try to reuse as much as possible. It seems that you want solutions first whose sum of distances to the center is as small as possible.
combos2(EMPLOYEES,POSTS,LIST):-
LIMIT is POSTS-EMPLOYEES+1,
length(LIST,EMPLOYEES),
LIST ins 1..LIMIT,
sum(LIST,#=,POSTS),
Mid is (LIMIT+1) div 2, %%
maplist(dist(Mid), LIST, DISTS), %%
sum(DISTS,#=,Totaldist), %%
labeling([],[Totaldist|LIST]).
dist(Mid, E, D) :-
D #= abs(Mid-E).
?- combos2(2,10,L).
L = [5,5]
; L = [4,6]
; L = [6,4]
; L = [3,7]
; L = [7,3]
; ... .
Here you go!
combos(2,S,L) :- b2(S,L).
combos(C,S,[A|L]) :-
C > 2,
b2(S,[A,B]),
D is C-1,
combos(D,B,L).
b2(S,L) :- B is S-1, bisector(B,L).
bisector(Y,[A,B]) :-
odd(Y),
M is div(1+Y,2),
Z is M-1,
range(D,0,Z),
bisec1(D,M,A,B).
bisector(Y,[A,B]) :-
even(Y),
M is 1+Y,
Z is Y/2-1,
range(D,0,Z),
bisec2(D,M,A,B).
bisec1(0,M,M,M).
bisec1(D,M,A,B) :- D > 0, A is M + D, A > 0, B is M - D, B > 0.
bisec1(D,M,A,B) :- D > 0, A is M - D, A > 0, B is M + D, B > 0.
bisec2(D,M,A,B) :- A is (M+2*D+1)/2, A > 0, B is (M-2*D-1)/2, B > 0.
bisec2(D,M,A,B) :- A is (M-2*D-1)/2, A > 0, B is (M+2*D+1)/2, B > 0.
even(X) :- 0 is mod(X, 2).
odd(X) :- 1 is mod(X, 2).
range(M,M,_).
range(X,M,N) :- P is M + 1, P =< N, range(X,P,N).

Alternative to \+ in 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.

Prolog Find N prime numbers

I have a problem with the recursive function of Prolog. I believe I am not implementing it right and need help.
I need to generate the first N prime numbers and return it in a list. Generating the prime number is not an issue, but rather, generating it in a list is the issue I have.
This is the part of the relevant code:
genList(_, 0, _).
genList(X, N, PrimeList, PrimeList):-
N > 0,
isprime(X),
X1 is X +1,
N1 is N -1,
genList(X1,N1,[X|PrimeList], [X|PrimeList]),!.
genList(X, N, PrimeList, PrimeList):-
N>0,
\+isprime(X),
X1 is X + 1,
genList(X1,N,PrimeList, PrimeList).
This is what I type into the Prolog interpreter:
genList(1,N, [],L).
For the 1st line, how do I make the base case such that when N=0, I stop recursing? Is this correct?
As for the next 2 clauses, I am having difficulty in thinking in terms of logic programming. I definitely feel that this is not logic programming style.
I want to say that when isPrime(X) fails, we continue to the next number without saving anything, but when isPrime(X) is true, then we recurse and continue to the next number, saving X.
How do I do that in Prolog?
First of all, you shouldn't need 4 arguments to your main predicate if you only want two. Here you want the list of the first primes up to N. So an argument for N and an argument for the list should be enough:
primeList(N, L) :-
% eventually in the body a call to a worker predicate with more arguments
Now here, your logic is explained in those terms:
primeList(N, [N|L]) :-
% If we're not at the base case yet
N > 0,
% If N is a prime
isPrime(N),
NewN is N - 1,
% Let's recurse and unifie N as the head of our result list in the head
% of the predicate
primeList(NewN, L).
primeList(N, L) :-
% Same as above but no further unification in the head this time.
N > 0,
% Because N isn't a prime
\+ isPrime(N),
NewN is N - 1,
primeList(NewN, L).
To that you'd have to add the base case
primeList(0, []).
You could rewrite that with cuts as follows:
primeList(0, []) :- !.
primeList(N, [N|L]) :-
isPrime(N),
!,
NewN is N - 1,
primeList(NewN, L).
primeList(N, L) :-
NewN is N - 1,
primeList(NewN, L).
Here's what you meant to write:
genList(N, L) :- genList(2, N, L, []).
genList(X, N, L, Z):- % L-Z is the result: primes list of length N
N > 0 ->
( isprime(X) -> L=[X|T], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 1,
genList(X1,N1,T,Z)
;
L = Z.
The if-then-else construct embodies the cuts. And you're right, it's essentially a functional programming style.
We can introduce a little twist to it, disallowing requests for 0 primes (there's no point to it anyway), so that we also get back the last generated prime:
genList(1, [2], 2) :- !.
genList(N, [2|L], PN) :- N>1, L=[3|_], N2 is N-2, gen_list(N2, L, [PN]).
gen_list(N, L, Z) :- L=[P|_], X is P+2, gen_list(X, N, L, Z).
gen_list(X, N, L, Z) :- % get N more odd primes into L's tail
N > 0 ->
( isprime(X) -> L=[_|T], T=[X|_], N1 is N-1 ; L=T, N1 is N ),
X1 is X + 2,
gen_list(X1,N1,T,Z)
;
L = Z. % primes list's last node
Run it:
?- genList(8,L,P).
L = [2, 3, 5, 7, 11, 13, 17, 19]
P = 19
This also enables us to stop and continue the primes generation from the point where we stopped, instead of starting over from the beginning:
?- L = [3|_], gen_list(8, L, Z), Z=[P10|_], writeln([2|L]),
gen_list(10, Z, Z2), Z2=[P20], writeln(Z).
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29|_G1037]
[29,31,37,41,43,47,53,59,61,67,71]
P10 = 29
P20 = 71

Resources