Separating a list into a list of fixed length sublists - prolog

Given a list L, for instance, [1,2,3,4,5,6,7] and a number N, for instance 3, I would like to make a predicate that would separate the elements of L into lists of size N.
So, the result will be: [[1,2,3], [4,5,6], [7]] in our case.
What I have tried:
% List containing the first N elements of given list.
takeN([X|Xs], 0, []) :- !.
takeN([X|Xs], N, [X|Ys]) :- N1 is N-1, takeN(Xs, N1, Ys).
% Given list without the first N elements.
dropN(R, 0, R) :- !.
dropN([X|Xs], N, R) :- N1 is N-1, dropN(Xs, N1, R).
% size of list.
sizeL([], 0) :- !.
sizeL([X|Xs], N) :- sizeL(Xs, N1), N is N1+1.
blockify(R, N, [R|[]]) :- sizeL(R, N1), N1 < N, !.
blockify([X|Xs], N, [Y|Ys]) :- sizeL(R, N1), N1 >= N, takeN([X|Xs], N, Y),
dropN([X|Xs], N, Res), blockify(Res, N, Ys).
It doesn't work (blockify([1,2,3], 2, R) for example returns false, instead of [[1,2], [3]]).
I can't find where I'm mistaken, though. What's wrong with this?

I think you are making thinks a bit overcomplicated. First of all let's exclude the case where we want to blockify/3 the empty list:
blockify([],_,[]).
Now in the case there are elements in the original list, we simply make use of two accumulators:
- some kind of difference list that stores the running sequence; and
- an accumulator that counts down and look whether we reached zero, in which case we append the running difference list and construct a new one.
So this would be something like:
blockify([H|T],N,R) :-
N1 is N-1,
blockify(T,N1,N1,[H|D],D,R).
Now the blockify/5 has some important cases:
we reach the end of the list: in that case we close the difference list and append it to the running R:
blockify([],_,_,D,[],[D]).
we reach the bottom of the current counter, we add the difference list to R and we intialize a new difference list with an updated counter:
blockify([H|T],N,0,D,[],[D|TR]) :-
blockify(T,N,N,[H|D2],D2,TR).
none of these cases, we simply append the element to the running difference decrement the accumulator and continue:
blockify([H|T],N,M,D,[H|D2],TR) :-
M > 0,
M1 is M-1,
blockify(T,N,M1,D,D2,TR).
Or putting it all together:
blockify([],_,[]).
blockify([H|T],N,R) :-
N1 is N-1,
blockify(T,N1,N1,[H|D],D,R).
blockify([],_,_,D,[],[D]).
blockify([H|T],N,0,D,[],[D|TR]) :-
blockify(T,N,N,[H|D2],D2,TR).
blockify([H|T],N,M,D,[H|D2],TR) :-
M > 0,
M1 is M-1,
blockify(T,N,M1,D,D2,TR).
Since in each recursive call all clauses run in O(1) and we do the recursion O(n) deep with n the number of elements in the original list, this program runs in O(n).

if your Prolog provides length/2, a compact solution could be:
blockify(R, N, [B|Bs]) :-
length(B, N),
append(B, T, R),
!, blockify(T, N, Bs).
blockify(R, _N, [R]).

Let me teach you how to debug a Prolog query:
1) blockify([1,2,3], 2, R)
2) does it match blockify(R, N, [R|[]]) ? oh yes,
it can be bound to blockify([1, 2, 3], 2, [[1, 2, 3]])
3) let's evaluate the body: sizeL(R, N1), N1 < N, !.
Replace R and N, we get: sizeL([1, 2, 3], N1), N1 < 2, !.
4) evaluate sizeL([1, 2, 3], N1): for brevity, since it's a common
list count predicate, the result should be obvious: N1 = 3
5) evaluate N1 < N: 3 < 2 => false
6) since the rest are all , (and operator) a single false
is enough to make the whole body to evaluate to false
7) there you go, the predicate is false
See where your mistake is?

Related

Prolog query: how does addition matter for recursive queries

I'm trying to write a predicate to find the nth element of a list.
Initially I wrote something like this:
nth([X|_], 0, X).
nth([_|T],N,Z):- N > 0, nth(T, M, Z), N is M + 1.
It works for queries such as nth([1, 2, 3, 4, 5], 0, X). but for queries such as nth([1, 2, 3, 4, 5], N, 1)., I get an "arguments insufficiently instantiated error" after I enter ";" after getting the answer. I know that there will be only 1 ans in this case, but for the sake of completeness, I want to know why.
I read on stack overflow here that the following is a better solution:
nth([X|_], 0, X) :- !.
nth([_|Y], N, Z) :- N > 0, M is N-1, nth(Y, M, Z).
I want to understand why M is N-1, nth(Y, M, Z). makes a difference as against the nth(T, M, Z), N is M + 1 in my answer.
PS: I think the question title can be improved, but I'm not sure of how. If you have suggestions, please let me know!
is/2 is not a complete constraint solver. So N is M + 1 and M is N - 1 look to be equivalent but they are not. The first only succeeds when M is instantiated and second when N is instantiated. Have you tried your solution with indices other zero? They will not work. You can use plus(1, M, N) instead of either of them to get it to work. Also clause ordering matters so plus(1, M, N) should be before the recursive call to nth.
nth([X|_], 0, X).
nth([_|T],N,Z):- N > 0, plus(1, M, N), nth(T, M, Z).
If N > 0, nth(T, M, Z), plus(1, M, N) is your clause ordering, your program will try to satisfy nth(T, M, Z) first and cause an uninstantiated error at N > 0 since M is not already instantiated.
Also neither program will work in the generative case.

Deleting first N prime numbers from a list (Prolog)

Basically I want to remove the first N numbers from a list, the function that checks whether a number is prime or not seems to work well but the program itself doesn't
For example for input [2,4,5,7,6,9,11] and N = 3 I should get [4, 6, 9, 11] but I get only [4, 6, 9].
divisible(X,Y) :-
0 is X mod Y, !.
divisible(X,Y) :-
X > Y+1,
divisible(X, Y+1).
%isPrime function check whether or not the argument is a prime number
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
%delFunction (input_list, N, output_list)
delFunction([],_,_).
delFunction(_,0,_).
delFunction([H|T], N, [H|Res]):-
not(isPrime(H)), !,
delFunction(T, N, Res).
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
delFunction([2,4,5,7,6,9,11],3,X) -> [4,6,9] (which is not the correct answer)
Honestly, I don't know where I went wrong, the implementation idea seems pretty easy and straight forward, so is the code.
Also, when I run it it stops at [4] and I have to keep on clicking next to get me to the end of the execution (thus the result). Any idea how to fix it? I'm thinking maybe I need some cuts but not sure where.
P.S: I'd rather not use built-in functions (if there are any that would help in this scenario)
Fists of all, instead of
delFunction([],_,_).
you should write
delFunction([],_,[]).
because when the input list (the left one) is empty, you have to construct the base for the output list: an empty list; with delFunction([], _, _) you don't unify the output list with the empty list so the result end with an not unified variable.
Second. Instead of
delFunction(_,0,_).
you should write
delFunction(L,0,L).
The problem is the same: when number is zero you can "copy" the input in the output; that is, you can unify they; that is delFunction(L,0,L). With delFunction(_,0,_) you don't unify and the result ends with a not unified variable.
Third. In the is-prime clause
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
you should check that N is greater than zero
delFunction([_|T], N, Res):-
N > 0,
N1 is N-1,
delFunction(T,N1,Res).
or, if you prefer, you should add a cut (!) in the zero clause
delFunction(L,0,L) :- !.
Just to avoid that Prolog, via backtracking, can give multiple undesired answers.
--- EDIT ---
As Guy Coder, I avoid cuts like a plague; so I propose the following solution to avoid unwanted repetitions.
delFunction([], _, []).
delFunction([H | T], 0, [H | T]).
delFunction([H | T], N, [H | Res]) :-
N > 0,
not(isPrime(H)),
delFunction(T, N, Res).
delFunction([H | T], N, Res):-
N > 0,
isPrime(H),
N1 is N-1,
delFunction(T, N1, Res).

SWI ProLog / ProbLog: Check if exactly one element in a list is true

I'm trying to make a function in ProbLog (extension of ProLog) that checks if only one of the inputs is True. As input the function will take a list of variables as argument. An XOR is not good enough in this case, because I am working with more than two arguments and I want the function to be true if and only if one of the elements in the list is True.
So for example:
function([X|Xs) :- code that checks if only (exactly) one element in the list is true
I don't know about the Problog extension, but maybe you can simply count the true elements and check if the count is one? Perhaps using this as a starting point:
length(List, N) :-
length(List, 0, N).
length([], N, N). % Second argument is the accumulator.
length([H|T], L, N) :-
L1 is L + 1,
length(T, L1, N).
You would then add a case where L is not incremented if H is not true, and in the end check if N is one.
hasOneTrueElement(List) :-
countTrueElements(List, 1).
countTrueElements(List, N) :-
countTrueElements(List, 0, N).
countTrueElements([], N, N).
countTrueElements([H|T], L, N) :-
call(H),
L1 is L + 1,
countTrueElements(T, L1, N).
countTrueElements([H|T], L, N) :-
\+ H,
countTrueElements(T, L, N).
this should work
list_unique(List, Unique) :-
select(Unique, List, Rest), \+ memberchk(Unique, Rest).

Traverse a list in Prolog

I have a problem like this: find all elements in a list such that all element(s) immediately besides it is/are odd numbers.
For example
?- find([20,1,2,3,4,5,6,7,8,10], L).
L = [20, 2, 4, 6]
Normally in other languages I would traverse the list and check the condition, but I don't know how to "think" in Prolog in this scenario. How should I approach this?
visit the list considering the pair of head elements:
find([A,B|R], [A|T]) :-
is_odd(B),
... etc etc
You'll need to add obviously the base recursion case and the case when A must be discarded.
EDIT: a better solution based on CapelliCs suggestion (this uses the isodd predicate from below):
% if N0 and N2 are odd, cut, add N1 to the result and recurse
ff([N0,N1,N2|T], [N1|R]) :- isodd(N0), isodd(N2), !, ff([N1,N2|T], R).
% for any other case where the list has at least three members, cut and recurse
ff([_,N1,N2|T], R) :- !, ff([N1,N2|T], R).
% this is reached if the list has less that three members - we're done
ff(_, []).
% append and prepend '1' to the list to deal with the edges, call ff.
find(L, R) :- append(L, [1], L1), ff([1|L], R).
My old solution which keept track of the two previous values with extra arguments:
% isodd(+N)
% helper predicate that succeds for odd numbers.
isodd(N) :- mod(N, 2) =:= 1.
% find(+I, +N1, +N2, +R, -L)
% find/5 is the predicate doing the actual work.
% I is the input list, N1 and N2 are the numbers before the current one,
% R is the intermediate result list and L the result.
% we're done if the input list is empty
find([], _, _, R, R) :- !.
% check if N0 and N2 are odd to see if N1 should be appended to the list.
% if yes, do a cut, append N1 to the result and recurse.
find([N0|T], N1, N2, R, L) :-
isodd(N0), isodd(N2), !,
append(R, [N1], R1), find(T, N0, N1, R1, L).
% if N0 and N2 are not odd (and thus the cut in the previous clause isn't
% reached) just continue the recursion.
find([N0|T], N1, _, R, L) :- find(T, N0, N1, R, L).
% find(+I, -L)
% this predicate is the entry point - initialize the result list and the first
% values for N1 and N2, and append 1 to the input list so we don't need an extra
% predicate for dealing with the last item.
find(I, L) :- append(I, [1], I1), find(I1, 1, 0, [], L).

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