Prolog: Find positve numbers in a given list - prolog

I would like to know how to find a sublist of positive numbers in a given list L, example:
L = [-1, 5, 3, -7, 10]
Sublist = [5, 3, 10]
I tried:
pos_sublist([], []).
pos_sublist(H|L, LO) :- H>=0, pos_sublist(L, H|LO).
How could I implement the recursion part?

You need to read up on list notation (for which, see my answer to the question "https://stackoverflow.com/questions/24043039/accessing-list-elements-in-a-list-of-lists-in-prolog-to-operate-on".
Since you are omitting the [...] square brackets, you no longer have lists: you just have the [nested] data structure '|'/2.
The easiest way to select non-negative (positive meaning 'greater than zero', as zero does not have a sign) values from a list is a combination of member/2 and findall/3:
positive_nums(Xs,Ps) :- findall(P, (member(P,Xs), P >= 0), Ps ) .
Rolling your own, though, isn't much more complex:
positive_nums( [] , [] ) .
positive_nums( [X|Xs] , [X|Ys] ) :- X >= 0, !, positive_nums(Xs,Ys) .
positive_nums( [_|Xs] , Ys ) :- positive_nums(Xs,Ys) .

Related

Impossible for me to solve: Simple recursion does not take integers for indexing a list....source_sink does not exist?

This recursion should slice IL to IR out of the list Lin and hand result LOut...
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut].
slice(Lin,IL,IR,LOut) :-
nth0(IL,Lin,X),
append(LOut,[X],LOut2),
IK is IL + 1,
slice(Lin,IK,IR,LOut2).
Input / Output:
?- slice([1,2,3,4],2,3,X).
ERROR: source_sink `'3'' does not exist
ERROR: source_sink `'4'' does not exist
X = [] .
I m also new to Prolog, but I think this recursion must somehow work. Also I'm not really known to the error codes in Prolog, but after checking multiple times I just have to give up... I hope you guys can help me.
slice(_,IL,IR,LOut) :-
IR<IL,
[LOut]. % <-- this line causes source_sink error.
That syntax [name] tries to load the file name.pl as Prolog source code. By the time your code gets there, LOut is [3,4] so it tries to load the files 3.pl and 4.pl, and they don't exist (thankfully, or else who knows what they could do).
I think this recursion must somehow work
It won't; you are appending to a list as you go down into the recursion, which means you will never see the result.
The following might be a close version which works, at least one way:
slice(_,IL,IR,[]) :-
IR < IL.
slice(Lin,IL,IR,[X|LOut]) :-
IR >= IL,
nth0(IL,Lin,X),
IK is IL + 1,
slice(Lin,IK,IR,LOut).
?- slice([0,1,2,3,4,5,6,7,8,9], 2, 5, X).
X = [2, 3, 4, 5]
See how [X|LOut] in the second rule's header puts X in the result that you get, and append/3 is not needed, and LOut finishes down in the recursion eventually as [] the empty list from the first rule, and all the X's are prepended on the front of it to make the result on the way down into the recursion, which is tail recursion, so it doesn't need to go back up, only forward, since there's nothing left to be done after the recursive call.
Since the "cons" is done before the recursion, this is known as "tail recursion modulo cons" in other languages, but in Prolog it is just tail, and the list is being built top-down on the way forward, as opposed to being built bottom up on the way back:
Lin=[0,1,2,3,4,5,6,7,8,9], slice( Lin, 2, 5, R)
:-
nth0(2,Lin,X2), R=[X2|R2], slice( Lin, 3, 5, R2)
:-
nth0(3,Lin,X3), R2=[X3|R3], slice( Lin, 4, 5, R3)
:-
nth0(4,Lin,X4), R3=[X4|R4], slice( Lin, 5, 5, R4)
:-
nth0(5,Lin,X5), R4=[X5|R5], slice( Lin, 6, 5, R5)
:-
R5 = [].
I think findall/3 provides a readable readable solution for your problem:
slice(Lin,IL,IR,LOut) :-
findall(E,(nth0(P,Lin,E),between(IL,IR,P)),LOut).
yields
?- slice([1,2,3,4],2,3,X).
X = [3, 4].
If you expect a different outcome, use standard arithmetic comparison operators (=<,>=) instead of between/3.
I think you want:
list_elems_slice(Start, End, Lst, Slice) :-
list_elems_slice_(Lst, 1, Start, End, Slice).
list_elems_slice_([H|T], N, N, End, [H|Slice]) :-
list_elems_slice_capture_(T, N, End, Slice).
list_elems_slice_([_|T], N, Start, End, Slice) :-
N1 is N + 1,
list_elems_slice_(T, N1, Start, End, Slice).
list_elems_slice_capture_(_, N, N, []).
list_elems_slice_capture_([H|T], N, End, [H|Slice]) :-
N1 is N + 1,
list_elems_slice_capture_(T, N1, End, Slice).
Result in swi-prolog:
?- list_elems_slice(S, E, [a,b,c], Slice).
S = E, E = 1,
Slice = [a] ;
S = 1,
E = 2,
Slice = [a, b] ;
S = 1,
E = 3,
Slice = [a, b, c] ;
S = E, E = 2,
Slice = [b] ;
S = 2,
E = 3,
Slice = [b, c] ;
S = E, E = 3,
Slice = [c] ;
false.
Assuming that the point of this exercise is to teach you to think recursively, I would approach the problem as follows.
To get what you want is essentially two separate operations:
You first must discard some number of items from the beginning of the list, and then
Take some number of items from what's left over
That gives us discard/3:
discard( Xs , 0 , Xs ) .
discard( [_|Xs] , N , Ys ) :- N > 0 , N1 is N-1, discard(Xs,N1,Ys) .
and take/3, very nearly the same operation:
take( _ , 0 , [] ) .
take( [X|Xs] , N , [Y|Ys] ) :- N > 0 , N1 is N-1, take(Xs,N1,Ys) .
Once you have those two simple predicates, slice/4 itself is pretty trivial:
%
% slice( List , Left, Right, Sublist )
%
slice( Xs, L, R, Ys ) :- % to slice a list,
L =< R, % - the left offset must first be less than or equal to the right offset
N is R-L, % - compute the number of items required, and then
discard(Xs,L,X1), % - discard the first L items, and
take(X1,N,Ys). % - take the next N items
. % Easy!
Another approach would be to use append/3:
slice( Xs , L, R, Ys ) :-
length(Pfx,L), % - construct of list of the length to be discarded
append(Pfx,Sfx,Xs), % - use append to split Xs
N is R-L, % - compute the number of items required
length(Ys,N), % - ensure Ys is the required length
append(Ys,_,Sfx) % - use append to split off Ys
. % Easy!

Prolog binary counter

i'm trying to do a program that counts the sequence of binary numbers, let me give an example
the input is [0,0,0,1,1,0,0,0,1,1,1,1]
The output should be [0(the first number),3(number of 0 in sequence),2 (number of 1 in sequence),3,4]
the input size is infinite and it needs to be a list, so far what I have done is this:
list([H|T],[X|Y]):-
T = [], X is H, Y is 1.
list([H|T],[X|Y]):-
T \= [], X is H,X1 is 1, contlist([H|T],[X1,Y]).
contlist([H|T],[X,_]):-
T \= [],
H =:= [T|_},
T1 i
contlist([H|T],[X,_]):-
X1 is X+1.
I don't know how to compare the head with the head of the tail and how to continue from there, maybe someone can help me?
This is a special case of Run-length encoding suitable for binary sequences.
You begin noting the first bit and start counting either 1s or 0s, when the bit flips you "output" the number and start counting the other bit value. Every time the sequence flips bits you output the number and start counting again until the whole sequence is processed. Note this procedure is not reversible. To make it reversible you would probably want to use clp(FD).
rle_binary([B|Seq], [B|BRLE]):-
binary(B),
rle_binary(Seq, B, 1, BRLE).
rle_binary([], _, N, [N]).
rle_binary([B|Seq], B, N, BRLE):-
succ(N, N1),
rle_binary(Seq, B, N1, BRLE).
rle_binary([B1|Seq], B, N, [N|BRLE1]):-
binary(B1),
B \= B1,
rle_binary(Seq, B1, 1, BRLE1).
binary(0).
binary(1).
Sample run:
?- rle_binary( [0,0,0,1,1,0,0,0,1,1,1,1], BRLE).
BRLE = [0, 3, 2, 3, 4] ;
false.
What you're talking about is Run-Length Encoding.
It's easy to implement. Executing the below code as
?- run_length_encoding( [a,b,b,c,c,c] , Rs ) .
Yields
Rs = [ a:1, b:2, c:3 ]
[The code doesn't care what the list contains (outside of perhaps unbound variables)]
You can fiddle with it at: https://swish.swi-prolog.org/p/PrtWEfZx.pl
run_length_encoding( Xs, Ys ) :- nonvar(Xs), ! , rle_encode(Xs,Ys) .
run_length_encoding( Xs, Ys ) :- nonvar(Ys), rle_decode(Ys,Xs) .
rle_encode( [] , [] ) .
rle_encode( [X|Xs] , Rs ) :- rle_encode(Xs,X:1,Rs) .
rle_encode( [X|Xs] , Y:N , [Y:N|Rs] ) :- X \= Y , ! , rle_encode(Xs,X:1,Rs) .
rle_encode( [X|Xs] , X:N , Rs ) :- M is N+1 , ! , rle_encode(Xs,X:M,Rs) .
rle_encode( [] , X:N , [X:N] ) .
rle_decode( [] , [] ) .
rle_decode( [X:N|Xs] , [X|Ys] ) :- N > 0, !, M is N-1, rle_decode([X:M|Xs],Ys) .
rle_decode( [_:0|Xs] , Ys ) :- rle_decode(Xs,Ys) .
Using SWI-Prolog predicates clumped/2 and pairs_values/2:
rle([X|Xs], [X|V]) :-
clumped([X|Xs], P),
pairs_values(P, V).
Example:
?- rle([0,0,0,1,1,0,0,0,1,1,1,1], L).
L = [0, 3, 2, 3, 4].

using greedy algorithm search in lists

Given a list of positive integer Items whose elements are guaranteed to be in sorted ascending order, and a positive integer Goal, and Output is a list of three elements [A,B,C] taken from items that together add up to goal. The Output must occur inside the items list in that order (ascending order).
ex:
?- threeSum([3,8,9,10,12,14],27,Output).
Output=[8,9,10];
Output=[3,10,14].
someone helped me to reach this to this code
but it gives me singleton variables:[Input,Items] ,it didnt work
although iam not quite sure if this is a greedy algorithm search or not ?
threeSum(Input,Goal,[A,B,C]):-
permutation(Items, [A,B,C|Rest]),
msort([A,B,C],[A,B,C]),
msort(Rest,Rest),
sum_list([A,B,C],Goal).
A clpfd approach:
:- use_module(library(clpfd)).
threeSum(Input, Goal, [A,B,C]) :-
Input = [First|Rest],
foldl([N,M,T]>>(T = N\/M), Rest, First, Domain),
[A,B,C] ins Domain,
all_different([A,B,C]),
chain([A,B,C], #>=),
Goal #= A + B + C,
labeling([max(A), max(B), max(C)], [A,B,C]).
Which has a bit of wrangling to turn the list of numbers into a domain, then says [A,B,C] must be in the list of numbers, must be different numbers, must be in descending order, must sum to the goal, and the clpfd solver should strive to maximise the values of A then B then C. (This probably won't work if the list can contain multiple of the same value like [5,5,5,3,2]).
e.g.
?- threeSum([3,8,9,10,12,14], 27, Output).
Output = [14, 10, 3] ;
Output = [10, 9, 8]
nums_goal_answer(Input, Goal, [A,B,C]) :-
length(Input, InputLen),
reverse(Input, RInput), % 'greedy' interpreted as 'prefer larger values first'.
% and larger values are at the end.
between( 1, InputLen, N1),
between(N1, InputLen, N2), % three nested for-loops equivalent.
between(N2, InputLen, N3),
\+ N1 = N2, % can't pick the same thing more than once.
\+ N2 = N3,
nth1(N1, RInput, A, _),
nth1(N2, RInput, B, _),
nth1(N3, RInput, C, _),
sum_list([A,B,C], Goal).
someone helped me to reach this to this code but it gives me singleton variables:[Input,Items], it didnt work
The warning is because the code never looks at the numbers in the Input list. Without doing that, how could it ever work?
although iam not quite sure if this is a greedy algorithm
is it taking the biggest things first? I don't think permutation will do that.
Using DCG:
:- use_module(library(dcg/basics)).
three_sum_as_dcg(Total, Lst, LstThree) :-
phrase(three_sum_dcg(3, Total), Lst, LstThree).
% When finished, remove the remainder, rather than add to LstThree
three_sum_dcg(0, 0) --> remainder(_).
three_sum_dcg(NumsLeft, Total), [N] -->
% Use this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N),
succ(NumsLeft0, NumsLeft),
Total0 is Total - N
},
three_sum_dcg(NumsLeft0, Total0).
three_sum_dcg(NumsLeft, Total) -->
% Skip this element
[N],
{ three_sum_informed_search(NumsLeft, Total, N) },
three_sum_dcg(NumsLeft, Total).
three_sum_informed_search(NumsLeft, Total, N) :-
NumsLeft > 0,
% "Informed" search calc due to list nums not decreasing
Total >= (N * NumsLeft).
Result in swi-prolog (note the efficiency):
?- numlist(1, 1000000, L), time(findall(L3, three_sum_as_dcg(12, L, L3), L3s)).
% 546 inferences, 0.000 CPU in 0.000 seconds (97% CPU, 4740036 Lips)
L3s = [[1,2,9],[1,3,8],[1,4,7],[1,5,6],[2,3,7],[2,4,6],[3,4,5]].
Restating the problem statement:
Given that I have
A [source] list of positive integers, whose elements are guaranteed to be sorted in ascending order, and
a positive integer indicating the target value.
I want to find
an ordered subset of elements of the source list that sum to the target value
The simplest way is often the easiest (and the most general):
sum_of( _ , 0 , [] ) . % nothing adds up to nothing.
sum_of( [X|Xs] , S , [X|Ys] ) :- % otherwise...
S > 0 , % - if the target sum S is positive,
X =< S , % - and the head of the list is less than or equal to the target sum
S1 is S-X , % - remove that amount from the target sum, and
sum_of(Xs,S1,Ys) . % - recurse down with the new target sum
sum_of( [_|Xs] , S , Ys ) :- % then, on backtracking...
S > 0 , % - assuming that the target sum is positive,
sum_of(Xs,S,Ys). % - recurse down again, discarding the head of the list
This will find whatever combinations of however many list elements sum to the target value. It will find them from left to right, so
sum_of( [1,2,3,4,5,6,7,8,9], 10, L ).
will, on backtracking successively find
L = [ 1, 2, 3, 4 ]
L = [ 1, 2, 7 ]
L = [ 1, 3, 6 ]
L = [ 1, 4, 5 ]
L = [ 1, 9 ]
L = [ 2, 3, 5 ]
L = [ 2, 8 ]
L = [ 3, 7 ]
L = [ 4, 6 ]
If you want to change the order so it finds the largest values first, simply reverse the order of clauses 2 and 3 in sum_of/3:
sum_of( _ , 0 , [] ) .
sum_of( [_|Xs] , S , Ys ) :-
S > 0 ,
sum_of(Xs,S,Ys) .
sum_of( [X|Xs] , S , [X|Ys] ) :-
S > 0 ,
X =< S ,
S1 is S-X ,
sum_of(Xs,S1,Ys) .
Now it will return the same set of solutions, just in the reverse order, starting with [4,6] and finishing with [1,2,3,4].
Once you have solved the general problem, it's a simple matter of restricting it to a specified number of elements, for instance:
sum_of_n_elements(Xs,N,S,Ys) :- length(Ys,N), sum_of(Xs,S,Ys).
And to get just the 3-element subsets that sum to the target value:
sum_of_3_elements(Xs,S,Ys) :- sum_of_n_elements(Xs,3,S,Ys) .
https://swish.swi-prolog.org/p/XKjdstla.pl

Prolog list exercise

Here is my exercise: define a predicate in prolog which, applied to a list L of integers, gives as a result the list of the successors of the even elements present in L.
The code i wrote work only if one element is even , can someone help me figure out where I'm wrong?
even(X):- 0 is mod(X,2).
odd(X):- 1 is mod(X,2).
list_even([],[]).
list_even([T|C],K):- even(T), E is T+1, list_even(C,K1), append(K1,E,X), K is X.
list_even([T|C],K):- odd(T),list_even(C,K).
Some flaws in your code are:
append(K1, E, X): This goal should append two lists to generate a third list; however, E is just an element, not a list. So you need to write append(K1, [E], X).
K is X: This goal evaluates the arithmetic expression represented by the variable X and unifies its value with variable K; however, X is a list, not an arithmetic expression. So you need to remove it.
So the correct code would be as follows:
list_even([], []).
list_even([T|C], K):- even(T), E is T+1, list_even(C, K1), append(K1, [E], K).
list_even([T|C], K):- odd(T), list_even(C, K).
Example:
?- list_even([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [9, 41, 21] ;
false.
Note that in the obtained answer, the successors appear in reverse order (the first even element in the input list is 20, but its successor 21 is the last element in the output list).
So a better code is as follows:
even_number_successors([], []).
even_number_successors([X|Xs], Successors) :-
( X mod 2 =:= 0
-> Y is X + 1,
Successors = [Y|Ys]
; Successors = Ys ),
even_number_successors(Xs, Ys).
Example:
?- even_number_successors([1, 20, 3, 40, 5, 7, 8], Successors).
Successors = [21, 41, 9].
From your problem statement,
define a predicate in prolog which, applied to a list L of integers, gives as a result the list of the successors of the even elements present in L.
On the face of things, you don't need odd/1: that which is not even is odd.
Why use append/3? You're just iterating/filtering a list and constructing a new one, right? Instead, you can construct the list in order by leaving the list incomplete, with an unbound tail. As we recurse down, we build out the tail of the list, either by unifying it with a new list, or at the end, unifying it with the empty list, the atom []).
I would do something like this:
list_even( [] , [] ) . % empty list? All done.
list_even( [X|Xs] , [Y|Ys] ) :- % non-empty?
even(X), % - is X even? if so...
!, % - eliminate the choice point
Y is X+1, % - get the successor of X
list_even(Xs,Ys) % - recurse down
. %
list_even( [_|Xs] , Ys ) :- % Otherwise, the head of the list is odd: discard the head, and...
list_even(Xs,Ys) % - recurse down
. % Easy!
even(X) :- 0 =:= X .

Sort predicate in Prolog

I am trying to figure out how sort/2 is implemented in Prolog. I would like to see how it works but I cannot find the code for it anywhere. Does somebody know how it is implemented?
In SWI-Prolog, sort/2 is a "built-in", so it's in C.
The file seems to be src/pl-lists.c of the distribution.
Here it is:
https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-list.c
At line 543:
static
PRED_IMPL("sort", 2, sort, PL_FA_ISO)
{ PRED_LD
return pl_nat_sort(A1, A2,
TRUE, SORT_ASC,
0, NULL, FALSE PASS_LD);
}
pl_nat_sort is in the same file
The comment is historically interesting:
Natural merge sort. Code contributed by Richard O'Keefe and integrated
into SWI-Prolog by Jan Wielemaker. The nice point about this code is
that it uses no extra space and is pretty stable in performance.
Richards claim it that many qsort() implementations in libc are very
slow. This isn't the case for glibc 2.2, where this performs about the
same as the previous qsort() based implementation.
Presumably Richard O'Keefe notes:
I've been using a variant of this code in a sorting utility since about
1988. It leaves the UNIX sort(1) program in the dust. As you may know,
sort(1) breaks the input into blocks that fit in memory, sorts the
blocks using qsort(), and writes the blocks out to disc, then merges the
blocks. For files that fit into memory, the variant of this code runs
about twice as fast as sort(1). Part of that is better I/O, but part is
just plain not using qsort().
Dayum. That brings back memories of writing sorting algorithms in '89.
If you just are seaching for any sorting algorithm you can always use bubblesort *cough*. It is one of the most simple and inefficient ways to sort a list, but - depending on the implementation - will run through an already sorted list in linear time. Bubblesort does not remove duplicates. This implementation does descending order:
bubblesort(List, SortedList) :-
bubbleit(List, List1),
! ,
bubblesort(List1, SortedList) .
bubblesort(List, List).
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X < Y,
! .
bubbleit([Z|Rest], [Z|Rest1]) :-
bubbleit(Rest, Rest1).
?- bubblesort([1,2,5,4,7,3,2,4,1,5,3],L).
L = [7, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1].
If you want to sort for the second element in a list [_,E|] change the the first bubbleit rule to
bubbleit([X,Y|Rest], [Y,X|Rest]) :-
X = [_,XX|_],
Y = [_,YY|_],
XX < YY,
! .
?- bubblesort([[a,3],[b,5],[c,1],[d,4]],L).
L = [[b, 5], [d, 4], [a, 3], [c, 1]].
Try searching quicksort.
Here is one link: https://www.codepoc.io/blog/prolog/4934/prolog-program-to-sort-a-list-using-quick-sort
Here is another example:-
quicksort([], []).
quicksort([X | Tail], Sorted):-
split(X, Tail, Small, Big),
quicksort(Small, SortedSmall),
quicksort(Big, SortedBig),
concatenate(SortedSmall, [X| SortedBig], Sorted).
split(X, [], [], []).
split(X, [Y| Tail], [Y | Small], Big):-
X > Y, !,
split(X, Tail, Small, Big).
split(X, [Y| Tail], Small, [Y | Big]):-
split(X, Tail, Small, Big).
concatenate([],List,List).
concatenate([Item|List1],List2,[Item|List3]) :-
concatenate(List1,List2,List3).
?-quicksort([1,7,4,3,6,5,9,8,12,1],L).
L = [1, 1, 3, 4, 5, 6, 7, 8, 9, 12]
false
The merge sort algorithm is a natural fit for Prolog. Not to mention trivial to implement in a language with recursion and lists as fundamental.
Here's a SWI Playground: https://swish.swi-prolog.org/p/swi-prolog-merge-sort.pl
merge_sort( [], [] ). % The empty list is by definition ordered
merge_sort( [X], [X] ). % So is a list of length one
merge_sort( Unsorted, Sorted ) :- % otherwise...
partition( Unsorted, L, R ) , % partition the list into 2 halves
merge_sort(L,L1), % recursively sort the left half
merge_sort(R,R1), % recursively sort the right half
merge(L1,R1,Sorted) % merge the newly-sorted halves
. % See? simple!
partition( [] , [] , [] ). % the empty list gets partitioned into two empty lists
partition( [X] , [X] , [] ). % a left of length 1 gets partitioned into itself and an empty list
partition( [X,Y|L] , [X|Xs] , [Y|Ys] ) :- % list of length 2 or more gets popped and divided between left and right halves
partition(L,Xs,Ys) % with the remainder being recursively partitioned.
. % Easy!
merge( [] , [] , [] ). % merging to empty lists is trivial
merge( [] , [Y|Ys] , [Y|Ys] ). % merging an empty list and a non-empty list is easy
merge( [X|Xs] , [] , [X|Xs] ). % merging a non-empty list and an empty list is easy
merge( [X|Xs] , [Y|Ys] , [Lo,Hi|Zs] ) :- % otherwise...
compare(X,Y,Lo,Hi), % compare the two terms, put them in collating sequence
merge(Xs,Ys,Zs) % and recursively merge the tails
. % Easy!
compare( X , Y , X, Y ) :- X #=< Y. % if X <= Y, X is Lo, and Y is Hi
compare( X , Y , Y, X ) :- X #> Y. % if X > Y, Y is Lo, and X is Hi

Resources