I am working with Prolog sample list programs and triying to do some operations on them. However, I am stuck at a point and couldn't find any solution or sample.
I want to write a function which takes two lists of integers and return a float value. The two lists size are equal. The float value is the result of comparison divided by list size.
The function should compare every elemen of first list to every elemen of the second list. A pair (i, j) is that i is the location of element in first list and j is the location of the element in second list. If element i greater than element j, result of comparison is incremented by 1. If element i less than element j, result of comparison decremented by 1. If equal, nothing happen. At the end of the above operation, we return the float value described above.
Example:
retVal([4,5,3], [8,2,1], Result).
should return Result = (-1+1+1-1+1+1-1+1+1) / 3 = 0.33
In object oriented language, it is as simple as printing something on the console. However, I don't have any idea in Prolog. Thank you in advance.
What you describe by words could be this snippet
retVal(L1,L2, Result) :-
findall(S, (member(X1,L1), member(X2,L2), (X1 < X2 -> S = -1 ; S = 1)), L),
sum_list(L, Sum),
length(L1, Len),
Result is Sum / Len.
Alas, the test outcome doesn't match your expectation
?- retVal([4,5,3], [8,2,1], X).
X = 1.
As liori noted in his comment, your manual calculation is incorrect...
I think this should work:
sgn(X, Y, -1) :- X<Y.
sgn(X, Y, 1) :- X>Y.
sgn(X, X, 0).
ssapd(L, R, O) :- ssapd(L, R, R, 0, 0, O).
ssapd([LI | LR], RL, [RPI | RPL], ACC, ACCL, O) :-
sgn(LI, RPI, SGN), !,
ACC1 is ACC + SGN,
ssapd([LI | LR], RL, RPL, ACC1, ACCL, O).
ssapd([_ | LR], RL, [], ACC, ACCL, O) :-
ACCL1 is ACCL + 1,
ssapd(LR, RL, RL, ACC, ACCL1, O).
ssapd([], _, _, ACC, ACCL, Result) :-
Result is ACC / ACCL.
It's a nice implementation with tail recursion done by using two accumulators, O(n²) time complexity and constant memory (except for the size of input). To execute it, try:
ssapd([4,5,3], [8,2,1], Result).
This is a tail-recursive approach:
compare_list( Xs , Ys , Z ) :-
compare_list( Xs, Ys, 0 , 0 , S , L ) ,
Z is float(S)/float(L)
.
compare_list( [] , [] , S , L , S , L ) .
compare_list( [X|Xs] , [Y|Ys] , A , B , S , L ) :-
A1 is A + sign(X-V) ,
B1 is B + 1 ,
compare_list(Xs,Ys,A1,B1,S,L)
.
Another approach, this time "head recursive":
compare_list( Xs , Ys , Z ) :-
compare_list( Xs , Ys , S , L ) ,
Z is float(S)/float(L)
.
compare_list( [] , [] , 0 , 0 ) .
compare_list( [X|Xs] , [Y|Ys] , S , L ) :-
compare_list(Xs,Ys,S1,L1) ,
S is S1 + sign(X-Y) ,
L is L1 + 1
.
The former implementation won't overflow the stack on long lists as it gets optimized away into [effectively] iteration, but requires accumulators; the latter implementation doesn't require accumulators, but will blow the stack if the list(s) are of sufficient length.
Related
Basically, I have an assignment where i need to compare sizes of every pair of elements in a List. The tricky part is:
The second element has to be larger than the first one,
The third element has to be smaller than the second one,
The fourth element has to be larger than the third one,
And so on an so forth alternating until the end od the list.
If this all checks out, then it returns yes, otherwise returns no.
Any ideas?
I know how to compare 2 elements in a list, but i can't wrap my head around comparing each consecutive one. I'm guessing it's supposed to be a recursion where I compare the first element to the second one, then remove the Head and do the same thing until the end, while keeping some kind of flag that tells me if it should be a bigger or a smaller number than the head.
Problem is i'm really new to prolog and i have no idea how to even start writing this properly.
I think this suits a grammar describing a list where you take the first element, look to step up from that to a larger element, then down from that to a smaller element, repeated until you get to the empty list (the end):
updown --> [A], up_from(A).
up_from(A) --> [B], {A<B}, (down_from(B) ; []), !.
down_from(A) --> [B], {A>B}, (up_from(B) ; []), !.
?- phrase(updown, [1,10,5,20]).
true
?- phrase(updown, [1,10,5,2]).
false
Like most recursive problems, there's one general, recursive case, and a few special cases that terminate the recursion.
Let's start with the general case: lists of length 3 or more, [X,Y,Z|Rest] succeeds if X < Y > Z, in which case we discard the first 2 elements, X and Y, and recurse down on the remainder:
alternating_values( [X,Y,Z|Ns] ) :- X < Y , Y > Z , alternating_values([Z|Ns]) .
The special, non-recursive, terminating cases deal with lists of lengths < 3:
The empty list ([]): this succeeds because there's nothing to compare:
alternating_values( [] ) .
Lists of length 1 ([X]): This likewise succeeds because there's nothing to which the single item can be compared, and if the original list was of length 3 or more, it was compared to item immediately preceding it in list in the previous iteration.
alternating_values( [_] ) .
Lists of length 2 ([X,Y]): This succeeds if X < Y.
alternating_values( [X,Y] ) :- X < Y .
Putting it all together, you get this, which you can fiddle with at SWI Prolog's Swish sandbox:
alternating_values( [] ) .
alternating_values( [_] ) .
alternating_values( [X,Y] ) :- X < Y .
alternating_values( [X,Y,Z|Ns] ) :- X < Y , Y > Z , alternating_values([Z|Ns]) .
Another approach might be to use a helper predicate that carries an additional bit of state. This eliminates the need to deals with lists of length 2, since we're only removing one element at a time:
alternating_values( Xs ) :- alternating_values( Xs , lt ) .
alternating_values( [] , _ ) .
alternating_values( [_] , _ ) .
alternating_values( [X,Y|Zs] , lt ) :- cmp(CC,X,Y,CC1), alternating_values([Y|Zs],CC1) .
alternating_values( [X,Y|Zs] , gt ) :- cmp(CC,X,Y,CC1), alternating_values([Y|Zs],CC1) .
cmp( lt , X , Y , gt ) :- X < Y .
cmp( gt , X , Y , lt ) :- X > Y .
But I like the first approach better. It's simpler and more straightforward.
% Allow list to terminate here
lower_higher_alternating([]).
lower_higher_alternating([H|T]) :-
lower_higher_alternating_(T, H).
lower_higher_alternating_([], _).
% P = previous element, H = head, T = tail
lower_higher_alternating_([H|T], P) :-
% Compare using "standard order"
P #< H,
higher_lower_alternating_(T, H).
higher_lower_alternating_([], _).
higher_lower_alternating_([H|T], P) :-
% Other comparison
P #> H,
% Check next 2 elements
lower_higher_alternating([H|T]).
Results in swi-prolog:
?- lower_higher_alternating([1,5,3,4,2]).
true.
?- lower_higher_alternating([1,0,3,4,2]).
false.
Alternative method, with same results:
lower_higher_alternating([]).
lower_higher_alternating([H|T]) :-
lower_higher_alternating_(T, H, <).
lower_higher_alternating_([], _, _).
% P = previous element, H = head, T = tail
lower_higher_alternating_([H|T], P, C) :-
compare(C, P, H),
next_comp(C, C1),
lower_higher_alternating_(T, H, C1).
next_comp(<, >).
next_comp(>, <).
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].
`three Sum([1,2,3,4,5,6,7,8,9],12,Output).
Output=[1,2,9];
Output=[1,3,8];
Output=[1,4,7];
Output=[1,5,6];
Output=[2,3,7];
Output=[2,4,6];
Output=[3,4,5]`
we should make result = summation 3 elements sorted ascendingly from list
This is fundamentally a matter of finding all the combinations of n things taken k at a time. To do that is pretty simple:
combination( 0 , _ , [] ) :- !.
combination( N , L , [C|Cs] ) :-
N > 0,
N1 is N-1,
select(L,C,L1),
combination(N1, L1, Cs).
select( [H|T] , H, T ) .
select( [_|T] , H, R ) :- select(T,H,R) .
once you have that, then it is a matter of wrapping it up nicely:
combination_sum( Xs, K, V, Ys ) :-
sort(Xs,X0), % orders the list, making it a proper set by removing duplicates
length(Xs,L),
between(1,L,K), % ensures K has a sensible value (and allows K to be unbound
combination(K,X0,Ys),
sum_of(Ys,V).
sum_of( Xs , S ) :- sum_of(Xs,0,S).
sum_of( [] , S , S ).
sum_of( [X|Xs] , T , S ) :- T1 is T+X, sum_of(Xs,T1,S) .
That gives you the generic, flexible solution: you can solve the problem for any given sized subset.
Note also that you may, should you choose, leave K or V unbound (or both, for that matter), and it will return all solutions for the given constraints:
combination_sum( [1..n], K, V, L ) yields all combinations of any length and their sum
combination_sum( [1..n], K, 12, L ) yields all combinations of any length that sum to 12.
combination_sum( [1..n], 3, V, L ) yields all combinations of length 3 that sum to any value.
combination_sum( [1...n], 3, 12, L ) yields all combinations of length 3 that sum to 12.
Then, just wrap that for your specialized use case:
sum_three(Xs,V,Ys) :- combination_sum(Xs,3,V,Ys).
three_sum(Lst, Total, [One, Two, Three]) :-
% Using msort, to sort without removing duplicates
msort(Lst, LstSorted),
select_remainder(One, LstSorted, Lst1),
select_remainder(Two, Lst1, Lst2),
select_remainder(Three, Lst2, _),
Total is One + Two + Three.
select_remainder(Elem, [H|T], RemainderForward) :-
select_remainder_(T, H, Elem, RemainderForward).
select_remainder_(T, H, H, T).
select_remainder_([H|T], _, Elem, R) :-
select_remainder_(T, H, Elem, R).
Result in swi-prolog:
?- time(findall(Lst, three_sum([1,2,3,4,5,6,7,8,9], 12, Lst), Lsts)).
% 278 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 1220471 Lips)
Lsts = [[1,2,9],[1,3,8],[1,4,7],[1,5,6],[2,3,7],[2,4,6],[3,4,5]].
I have a list of numbers, I need to calculate the sum of the even numbers of the list and the product of the odd numbers of the same list. I'm new in Prolog, and my searches so far weren't successful. Can anyone help me solve it ?
l_odd_even([]).
l_odd_even([H|T], Odd, [H|Etail]) :-
H rem 2 =:=0,
split(T, Odd, Etail).
l_odd_even([H|T], [H|Otail], Even) :-
H rem 2 =:=1,
split(T, Otail, Even).
Here is a suggestion for the sum of the even numbers from a list:
even(X) :-
Y is mod(X,2), % using "is" to evaluate to number
Y =:= 0.
odd(X) :- % using even
Y is X + 1,
even(Y).
sum_even(0, []). % empty list has zero sum
sum_even(X, [H|T]) :-
even(H),
sum_even(Y, T),
X is Y+H.
sum_even(X, [H|T]) :-
odd(H),
sum_even(X, T). % ignore the odd numbers
Note: My Prolog has oxidized, so there might be better solutions. :-)
Note: Holy cow! There seems to be no Prolog support for syntax highlighting (see here), so I used Erlang syntax.
Ha, it really works. :-)
Running some queries in GNU Prolog, I get:
| ?- sum_even(X,[]).
X = 0 ?
yes
| ?- sum_even(X,[2]).
X = 2 ?
yes
| ?- sum_even(X,[3]).
X = 0 ?
yes
| ?- sum_even(X,[5,4,3,2,1,0]).
X = 6 ?
yes
The ideas applied here should enable you to come up with the needed product.
Use clpfd!
:- use_module(library(clpfd)).
Building on meta-predicate foldl/4, we only need to define what a single folding step is:
sumprod_(Z,S0,S) :-
M #= Z mod 2,
rem_sumprod_(M,Z,S0,S).
rem_sumprod_(0,Z,S0-P,S-P) :-
S0 + Z #= S.
rem_sumprod_(1,Z,S-P0,S-P) :-
P0 * Z #= P.
Let's fold sumprod_/3 over the list!
l_odd_even(Zs,ProductOfOdds,SumOfEvens) :-
foldl(sumprod_,Zs,0-1,SumOfEvens-ProductOfOdds).
Sample query:
?- l_odd_even([1,2,3,4,5,6,7],Odd,Even).
Odd = 105,
Even = 12.
Alternatively, we can define sumprod_/3 even more concisely by using if_/3 and zeven_t/3:
sumprod_(Z,S0-P0,S-P) :-
if_(zeven_t(Z), (S0+Z #= S, P0=P),
(P0*Z #= P, S0=S)).
untested!
sum_odd_product_even([], S, P, S, P).
sum_odd_product_even([H|T], S0, P0, S, P) :-
S1 is S0 + H,
sum_even_product_odd(T, S1, P0, S, P).
sum_even_product_odd([], S, P, S, P).
sum_even_product_odd([H|T], S0, P0, S, P) :-
P1 is P0 * H,
sum_odd_product_even(T, S0, P1, S, P).
sum_odd_product_even(L, S, P) :-
sum_odd_product_even(L, 0, 1, S, P).
sum_even_product_odd(L, S, P) :-
sum_even_product_odd(L, 0, 1, S, P).
It shouldn't get much simpler than
%
% invoke the worker predicate with the accumulators seeded appropriately.
%
odds_and_evens( [O] , P , S ) :- odds_and_evens( [] , O , 0 , P , S ) .
odds_and_evens( [O,E|Ns] , P , S ) :- odds_and_evens( Ns , O , E , P , S ) .
odds_and_evens( [] , P , S , P , S ) . % if the list is exhausted, we're done.
odds_and_evens( [O] , X , X , P , S ) :- % if it's a single element list, we've only an odd element...
P is X*O , % - compute it's product
. % - and we're done.
odds_and_evens( [O,E|Ns] , X , Y , P , S ) :- % if the list is at least two elements in length'e both an odd and an even:
X1 is X*O , % - increment the odd accumulator
Y1 is Y+E , % - increment the even accumulator
odds_and_evens( Ns , X1 , Y1 , P , S ) % - recurse down (until it coalesces into one of the two special cases)
. % Easy!
How to write a predicate minmax(L, X, Y) to find out min value of X and max value of Y in list of integer L.
Example:
?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10, Y = 7.
Let's define list_minnum_maxnum/3 like list_minnum/2:
list_minnum_maxnum([E|Es],Min,Max) :-
V is E,
list_minnum0_minnum_maxnum0_maxnum(Es,V,Min,V,Max).
list_minnum0_minnum_maxnum0_maxnum([] ,Min ,Min,Max ,Max).
list_minnum0_minnum_maxnum0_maxnum([E|Es],Min0,Min,Max0,Max) :-
V is E,
Min1 is min(Min0,V),
Max1 is max(Max0,V),
list_minnum0_minnum_maxnum0_maxnum(Es,Min1,Min,Max1,Max).
Sample query as given by the OP:
?- list_minnum_maxnum([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
Note that this implementation of list_minnum_maxnum/3 works with all kinds of numbers.
?- list_minnum_maxnum([1,-10,1,0,7.2,7,7], Min,Max).
Min = -10,
Max = 7.2.
If you only care about handling integers, use clpfd!
:- use_module(library(clpfd)).
We define list_zmin_zmax/3 as follows:
list_zmin_zmax([E|Es],Min,Max) :-
V #= E,
list_zmin0_zmin_zmax0_zmax(Es,V,Min,V,Max).
list_zmin0_zmin_zmax0_zmax([] ,Min ,Min,Max ,Max).
list_zmin0_zmin_zmax0_zmax([E|Es],Min0,Min,Max0,Max) :-
V #= E,
Min1 #= min(Min0,V),
Max1 #= max(Max0,V),
list_zmin0_zmin_zmax0_zmax(Es,Min1,Min,Max1,Max).
Same sample use as before:
?- list_zmin_zmax([1,-10,1,0,7,7], Min,Max).
Min = -10,
Max = 7.
OK! What about support for non-integer numbers?
?- list_zmin_zmax([1,-10,1,0,7.2,7,7], Min,Max).
ERROR: Domain error: `clpfd_expression' expected, found `7.2'
We expected getting an error, we got an error...
Note that thanks to clpfd, we can run more general queries, too!
?- list_zmin_zmax([A,B], Min,Max).
A #>= Min, Max #>= A, Min #= min(A,B),
B #>= Min, Max #>= B, Max #= max(A,B).
As noted, you need to iterate over the list, accumulating the min and max values as you go. So, assuming that you have to write this from scratch, the first thing you need to do is decompose the problem into simple steps:
You need a means of comparing two objects and determine which is the lower or higher.
You need a means of iterating over the loop and tracking the min and max values seen as you go.
That leads to a min/3 and max/3, thus:
min(X,X,X).
min(X,Y,X) :- X < Y .
min(X,Y,Y) :- X > Y .
max(X,X,X).
max(X,Y,X) :- X > Y .
max(X,Y,Y) :- X < Y .
For your purposes here, one could even combine them into a single predicate, if you liked:
rank( X , X , X , X ) .
rank( X , Y , X , Y ) :- X < Y .
rank( X , Y , Y , X ) :- X > Y .
A pretty typical programming pattern in Prolog is to have a simple public API predicate that invokes a private "worker" predicate that does the actual work. Often the worker predicate will carry temporary "accumulator" variables that simplify the job. Your public predicate might look like:
minmax([X|Xs],Min,Max) :- minmax_scan( Xs , X , X , Min , Max ).
Here, your public API predicate accepts a non-empty list, seeding the min/max accumulators the worker predicate uses with the head of the list, then calling the worker predicate with the tail of the list.
Your worker predicate then might look like this:
% if the list is empty, we've solved the puzzle, right?
minmax_scan( [] , Min , Max , Min , Max ) .
% if the list is non-empty, we need to compare its head to
% the current value for min/max to determine the new values for min/max
% (which might be the same), and then recurse down on the tail of the list
minmax_scan( [X|Xs] , CurrMin , CurrMax , Min , Max ) :-
min( X , CurrMin , NextMin ) ,
max( X , CurrMax , NextMax ) ,
minmax_scan( Xs , NextMin , NextMax , Min , Max )
.
Easy!
Here's something convoluted and a bit complex.
is_minmax(A,B-D,C-E) :-
D is min(...),
E is max(...) .
pair(A,B,A-B).
minmax(L,MIN,MAX) :-
L=[A|_], length(L,N), N2 is N-1,
length(L2,N2), append(L2,[MIN],L22),
length(L3,N2), append(L3,[MAX],L33),
maplist(pair, [A|L2], L22, KL2),
maplist(pair, [A|L3], L33, KL3),
maplist(is_minmax, L, KL2, KL3).
(works in SWI Prolog). Try to figure out what to write in place of dots ....
take the first value from the list, then examine each other element of the list, selecting lower/higher values as temporary min/max.
When at the end of list, you have both...
minmax([First|Rest], Min, Max) :-
minmax(Rest, First, First, Min, Max).
minmax([], Min, Max, Min, Max).
minmax([Value|Ns], MinCurr, MaxCurr, Min, Max) :-
....
minmax(Ns, MinNext, MaxNext, Min, Max).
I'll let you write the tests before the recursive call (i.e. fill the dots!)
edit just to point out library(aggregate), available in several Prolog systems:
1 ?- [user].
minmax(L, X, Y) :- aggregate( (min(E), max(E)), member(E, L), (X, Y) ).
|:
true.
2 ?- minmax([1, -10, 1, 0, 7, 7], X, Y).
X = -10,
Y = 7.