Deleting first N prime numbers from a list (Prolog) - 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).

Related

Prolog recursion code returning false, add in variables as input to recursive list parse

Im writing prolog to print out each element of a list, as long as a counter is > 0.
printLN([],_).
printLN(_,-1).
printLN([[x,y] | T], N) :-
write(x), write(y), nl,
N2 is N-1,
printLN(T, N2).
This should print the 3 pairs.
printLN([[1,2],[3,4],[5,6]], 2).
This should print the 3 pairs.
printLN([[1,2],[3,4],[5,6]], 8).
This should print first pair.
printLN([[1,2],[3,4],[5,6]], 0).
I keep getting false though. Anyone know why this may be the case?
As well, how could i execute something like:
getPartialList(N) :-
getList(LIST), printLN(LIST, N).
where getList returns a list of pairs like:
getList([[1,2],[3,4],[5,6]]).
I keep getting false though. Anyone know why this may be the case?
Two errors:
a) write(x) should be written write(X) where X is a logical variable (in capitals).
b) Your third clause keeps Calling recursively even if N < 0. To correct this, put a test N > 0 into this clause.
printLN([],_).
printLN(_, -1) :- !.
printLN([[X,Y] | T], N) :-
N > 0,
write(X), write(Y), nl,
N2 is N-1,
printLN(T, N2).

Separating a list into a list of fixed length sublists

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?

Finding the largest even number in list

The point of this program is supposed to be to find the largest even number inside a list. For example, the query:
? - evenmax([1, 3, 9, 16, 25, -5, 18], X]
X = 18.
The way I thought to do this is to separate the list into two, one with just odd numbers and one with just even numbers. However, after doing that, I legitimately have no idea how to take the even-number list specifically and find the maximum integer in that.
Here is what I currently have:
seperate_list([], [], []).
separate_list([X|Xs], [X|Even], Odd) :-
0 is X mod 2,
separate_list(Xs, Even, Odd).
separate_list([X|Xs], Even, [X|Odd]) :-
1 is X mod 2,
separate_list(Xs, Even, Odd).
find_max([X|Xs], A, Max).
X > A,
find_max(Xs,X,Max).
find_max([X|Xs],A,Max) :-
X =< A,
find_max(Xs,A,Max).
find_max([],A,A).
I am still a newcomer to Prolog, so please bear with me...and I appreciate the help.
You could do it in one go. You can find the first even number in the list, then use this as seed and find the largest even number in the rest of the list.
But if you don't insist on doing it in a single traversal through the list, you can first collect all even numbers, then sort descending and take the first element of the sorted list.
evenmax(List, M) :-
include(even, List, Even),
sort(Even, Sorted),
reverse(Sorted, [M|_]).
even(E) :-
E rem 2 =:= 0.
If you want to see how include/2 is implemented, you can look here. Basically, this is a generalized and optimized version of the separate_list/3 that you have already defined in your question. sort/2 is a built-in, and reverse/2 is a library predicate, implementation is here.
There are many other ways to achieve the same, but for starters this should be good enough. You should ask more specific questions if you want more specific answers, for example:
What if the list has free variables?
What if you want to sort in decreasing order instead of sorting and then reversing?
How to do it in a single go?
and so on.
Sorry but... if you need the maximum (even) value... why don't you simply scan the list, memorizing the maximum (even) value?
The real problem that I see is: wich value return when there aren't even values.
In the following example I've used -1000 as minumum value (in case of no even values)
evenmax([], -1000). % or a adeguate minimum value
evenmax([H | T], EM) :-
K is H mod 2,
K == 0,
evenmax(T, EM0),
EM is max(H, EM0).
evenmax([H | T], EM) :-
K is H mod 2,
K == 1,
evenmax(T, EM).
-- EDIT --
Boris is right: the preceding is a bad solution.
Following his suggestions (thanks!) I've completely rewritten my solution. A little longer but (IMHO) a much better
evenmaxH([], 1, EM, EM).
evenmaxH([H | T], 0, _, EM) :-
0 =:= H mod 2,
evenmaxH(T, 1, H, EM).
evenmaxH([H | T], 1, M0, EM) :-
0 =:= H mod 2,
M1 is max(M0, H),
evenmaxH(T, 1, M1, EM).
evenmaxH([H | T], Found, M, EM) :-
1 =:= H mod 2,
evenmaxH(T, Found, M, EM).
evenmax(L, EM) :-
evenmaxH(L, 0, 0, EM).
I define evenmax like there is no member of list L which is even and is greater than X:
memb([X|_], X).
memb([_|T], X) :- memb(T,X).
even(X) :- R is X mod 2, R == 0.
evenmax(L, X) :- memb(L, X), even(X), not((memb(L, Y), even(Y), Y > X)), !.
There are already a number of good answers, but none that actually answers this part of your question:
I legitimately have no idea how to take the even-number list
specifically and find the maximum integer in that
Given your predicate definitions, it would be simply this:
evenmax(List, EvenMax) :-
separate_list(List, Evens, _Odds),
find_max(Evens, EvenMax).
For this find_max/2 you also need to add a tiny definition:
find_max([X|Xs], Max) :-
find_max(Xs, X, Max).
Finally, you have some typos in your code above: seperate vs. separate, and a . instead of :- in a clause head.

Creating a predicate in Prolog that sums the squares of only the even numbers in a list

I'm trying to figure out how to create a predicate in prolog that sums the squares of only the even numbers in a given list.
Expected output:
?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
Sum = 120 ;
false.
What I know how to do is to remove all the odd numbers from a list:
sumsq_even([], []).
sumsq_even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
sumsq_even(Tail, Sum).
sumsq_even([Head | Tail], [Head | Sum]) :-
sumsq_even(Tail, Sum).
Which gives me:
Sum = [2, -4, 6, 8]
And I also know how to sum all the squares of the numbers in a list:
sumsq_even([], 0)
sumsq_even([Head | Tail], Sum) :-
sumsq_even(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
But I can't seem to figure out how to connect these two together. I'm thinking I may have gone the wrong way about it but I'm not sure how to define proper relationships to get it to make sense.
Thanks!
Split your problem into smaller parts. As you already said, you have two different functionalities that should be combined:
remove odd numbers from a list (even)
sum all the squares of the numbers in a list (sumsq)
So, in the first place, use different predicate names for different functionalities:
even([], []).
even([Head | Tail], Sum) :-
not(0 is Head mod 2),
!,
even(Tail, Sum).
even([Head | Tail], [Head | Sum]) :-
even(Tail, Sum).
sumsq([], 0).
sumsq([Head | Tail], Sum) :-
sumsq(Tail, Tail_Sum),
Sum is Head * Head + Tail_Sum.
In a third predicate you can now combine the two subsequent smaller steps:
sumsq_even(List, Sum) :-
even(List, Even_List),
sumsq(Even_List, Sum).
In this rule, first the (input) list is reduced to even elements (Even_List) and after that the sum of the squares are calculated.
This is the result for your example:
sumsq_even([1,3,5,2,-4,6,8,-7], Sum).
S = 120.
Using clpfd and Prolog lambda write:
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
zs_sumevensq(Zs, S) :-
maplist(\Z^X^(X #= Z*Z*(1-(Z mod 2))), Zs, Es),
sum(Es, #=, S).
Sample query as given by the OP:
?- zs_sumevensq([1,3,5,2,-4,6,8,-7], S).
S = 120.
You can actually do both tasks (filtering the even number and summing them up) at once:
:- use_module(library(clpfd)).
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
X mod 2 #= 0,
nums_evensumsq(Xs,S1),
S0 #= S1 + X * X.
nums_evensumsq([X|Xs],S) :-
X mod 2 #= 1,
nums_evensumsq(Xs,S).
Querying the predicate gives the desired result:
?- nums_evensumsq([1,3,5,2,-4,6,8,-7],S).
S = 120 ? ;
no
You can write it even shorter using if_/3 as defined here:
nums_evensumsq([],0).
nums_evensumsq([X|Xs],S0) :-
nums_evensumsq(Xs,S1),
Y #= X mod 2,
if_(Y = 0, S0 #= S1 + X * X, S0 #= S1).
Note that the comparison in the first argument of if_/3 is done with =/3 as defined here.
Once you mastered the basics, you could be interested to learn about builtins. Library aggregate, provides a simple way to handle lists, using member/2 as list elements 'accessor':
sumsq_even(Ints, Sum) :-
aggregate(sum(C), I^(member(I, Ints), (I mod 2 =:= 0 -> C is I*I ; C = 0)), Sum).

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).

Resources