Comparing the number of nodes at a given depth in Prolog - prolog

Given two binary trees T1 and T2 having the same height, I would like to know how to check if the number of nodes of T1 is equal to the number of nodes in T2, for each value of depth D.
I wrote a predicate numberOfNodesatD(T, N, D) which calculates the number of nodes at a depth D, but I am not able to define in Prolog the equality between the number of nodes if N1 == N2.

Riffing off my answer to your earlier question, Prolog - Find the depth of an element in a binary tree,
We can use
visit(T,P,D) :- visit(T,0,P,D) .
visit( t(_,L,_) , N, P, D ) :- N1 is N+1, visit(L,N1,P,D) .
visit( t(P,_,_) , D, P, D ) .
visit( t(_,_,R) , N, P, D ) :- N1 is N+1, visit(R,N1,P,D) .
and do something like this:
node_count_by_depth(T,D,N) :-
findall( D, visit(T,_,D), Ds ) ,
msort(Ds,Ss)l ,
groups(Ss,Fs) .
groups( [] , [] ) .
groups( [X|Xs] , Ys ) :- groups(Xs, X:1, Ys ).
groups( [] , Y:N , [Y:N] ) . % the end of the source list is a sequence break.
groups( [X|Xs] , X:N , Ys ) :- % if we haven't hit a sequence break...
N1 is N+1 , % - increment the count
groups(Xs,X:N1,Ys) . % - and recurse down
groups( [X|Xs] , Y:N , [Y:N|Ys] ) :- % otherwise...
X \= Y , % - we have hit a sequence break,
groups(Xs,X:1,Ys) % - recurse down, having moved the tuple to the result list
. % Easy!
And once you have that, then it's a matter of:
same_number_of_nodes_at_depth(T1,T2,D,N) :-
node_count_by_depth(T1,L1),
node_count_by_depth(T2,L2),
member( D:N, L1 ),
member( D:N, L2 ).

Related

Removing duplicates from a list in prolog

I'm trying to implement a simple predicate, that would simply remove items that occur more than once in a list.
For instace, for,
unique([a,b,a,b,c,c,a], R)
should be R = [a,b,c]
unique([], []).
unique([X], [X]).
unique([H|T], [H|R]) :-
not_contains(H, R),
unique(T, R).
unique([H|T], R) :-
contains(H, R),
unique(T, R).
contains(_, []).
contains(X, [X|T]).
not_contains(_, []).
not_contains(X, [H|T]) :-
X \= H,
not_contains(X, T).
I am unsure what I'm doing wrong. If the item is not contained within R, add to it and repeat, and if is, don't add it and proceed with iteration.
A fun way to do it that I just thought of:
nub(L,R):- maplist( p(R), L), length(R,_), !.
p(R,E):- memberchk(E,R).
nub(L,R) makes a unique list R out of an input list L. It assumes R is a non-instantiated variable before the call is made, and L is a fully ground list.
This uses the result list as its own uniqueness accumulator while it is being built!
Testing:
6 ?- nub([a,b,a,b,c,c,a], R).
R = [a, b, c].
The easiest way to make a list unique is just use the built-in sort/2:
unique(Xs,Ys) :- sort(Xs,Ys).
so unique( [c,a,b,a] , Rs ) yields Rs = [a,b,c].
If you want to maintain order, you need to decide on the strategy you want to use — in case of duplicates, which duplicate "wins": First or last?
The "last wins" strategy is the simplest to implement:
unique( [] , [] ) . % the empty list is itself a unique set
unique( [X|Xs] , Ys ) :- % A non-empty list is unique if . . .
contains(X,Xs), % - X is contained within the source list's tail,
!, - and (eliminating the choice point)
unique( Xs, Ys ) . - omitting X, the remainder of the list is (recursively) unique
unique( [X|Xs] , Ys ) :- % Otherwise, the non-empty list is unique if . . .
unique( Xs,[X|Ys] ) . % - adding X to the results, the remainder of the list is (recursively) unique .
Here, unique( [a,b,a,c,a], Rs ) yields Rs = [b,c,a].
If you want to use the "first wins" strategy, you'll be wanting to use a helper predicate with an accumulator that grows the result list in reverse order, which is then reversed. That gives us something like this:
unique( Xs , Ys ) :- unique(Xs,[],Zs), reverse(Zs,Ys) .
unique( [] , Ys , Ys ) . % Source list exhausted? we're done.
unique( [X|Xs] , Ts , Ys ) :- % Otherwise . . .
contains(X,Ts) , % - if X is found in the accumulator,
!, % - eliminate the choice point, and
unique(Xs,Ts,Ys) . % - recurse down, discarding X
unique( [X|Xs] , Ts , Ys ) :- % Otherwise (X is unique) . . .
unique(Xs,[X|Ts],Ys) . % - recurse down, prepending X to the accumulator
And here, unique( [a,b,a,c,a], Rs ) yields Rs = [a,b,c].
You can avoid the use of reverse/2 here, by building the 2 lists (accumulator and final set) in parallel. A trade-off, though: memory for speed:
unique( Xs , Ys ) :- unique(Xs,[],Ys) .
unique( [] , _ , [] ) .
unique( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts), !, unique( Xs, Ts , Ys ) .
unique( [X|Xs] , Ts , [X|Ys] ) :- unique( Xs, [X|Ts] , Ys ) .
You don't really need a contains/2 predicate: the in-built member/2 and memberchk/2 do exactly what you want. member/2 is non-deterministic and will succeed once for every time the item is found in the list; memberchk/2 is non-deterministic and will succeed at most once.
Since this is testing for uniqueness, memberchk/2 is what you'd want, giving you this:
contains(X,Ys) :- memberchk(X,Ys) .
Or you can roll you own (it's trivial):
contains( X , [X|Ys] ) :- ! .
contains( X , [_|Ys] ) :- contains(X,Ys) .
Or even simpler, just a one-liner:
contains( X , [Y|Ys] ) :- X = Y -> true ; contains(X,Ys) .

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

Find substrings of certain length

I'm a beginner at prolog and I'm having trouble getting started with the following problem:
Define the predicate partstr/3, where the first argument is a list, that generates a list A of length L that you find consecutive in the first list.
You should be able to present all answers with backtracking.
E.g.:
?- partstr([1, 2 , 3], L, A).
If L = 2 then A = [1,2] and [2,3],
or if L = 2 then F=[1,2] and [2,3].
and so on...
I feel like you would use recursion to solve it, but I'm not sure where to start. I would really appreciate some tips on how to solve this because I feel like I'm getting nowhere.
The core of this problem is that you need a way to pull all the sublist of length N from a list, correct?
So...
Consider that append/3 can concatenate two lists: append( [a,b,c], [1,2,3], L) returns L as [a,b,c,1,2,3]. But it can also decompose a list into a prefix and a suffix, so
append( Pfx, Sfx, [a,b,c])
will, on backtracking, successively yield:
Pfx
Sfx
[]
[a,b,c]
[a]
[b,c]
[a,b]
[c]
[a,b,c]
[]
...and... length/2 can not only tell you the length of a list, but
can generate lists of a specified length populated with unique,
unbound variables, so length(L,3) returns [V1,V2,V3].
You can combine those to get the behavior you want:
partstr( Xs, N, SL ) :- % To get all the contiguous sublists of length N from Xs...
append(_,Sfx,Xs) , % - repeatedly get all possible suffixes of Xs, and...
length(SL,N) , % - construct an empty, unbound list of the desired length (N), and...
append(SL,_,Sfx) % - pull that prefix off the suffix
. % Easy!
That's one approach. I imagine that this is coursework and that your instructor likely would like you to roll your own solution from scratch.
To do that, we first need a predicate that will yield the source list, and on backtracking remove the head of the list. Something like:
suffix( Xs , Xs ) .
suffix( [_|Xs] , Sfx ) :- suffix(Xs,Sfx).
Then we need a way to grab the 1st n elements from a list, something like this:
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N1 is N-1 , take(Xs,N1,Sfx) .
Given those two...
partstr( Xs, N , SL ) :-
suffix(Xs,Sfx),
take(Sfx,N, SL )
.
You can even dispense with the suffix/2 predicate, thus, rolling its functionality into partstr/3 itself:
partstr( Xs , N , SL ) :- take(Xs,N,SL).
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL).
And that, I think, is the sweet spot: it is hard to beat 4 lines of code —
partstr( Xs , N , SL ) :- take(Xs,N,SL) .
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL) .
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N > 0 , N1 is N-1 , take(Xs,N1,Sfx) .\

Prolog iterating over list

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.

Sum and square root list elements

So I am currently trying to compute a formula using Prolog. I currently have part of the formula done, but I am having trouble implementing the next part where I need to add the elements of the list and then square root the sum. Not sure how I would do that.
What I currently have:
formula([], [], []).
formula([], [H2|T2], [L|Ls]) :-
L = H2,
formula([], T2, Ls).
formula([H1|T1], [], [L|Ls]) :-
L = H1,
formula(T1, [], Ls).
formula([H1|T1], [H2|T2], [L|Ls]) :-
L is (H1 - H2)*(H1 - H2),
formula(T1, T2, Ls).
Your original formula
formula([], [], []).
formula([], [H2|T2], [L|Ls]) :-
L = H2,
formula([], T2, Ls).
formula([H1|T1], [], [L|Ls]) :-
L = H1,
formula(T1, [], Ls).
formula([H1|T1], [H2|T2], [L|Ls]) :-
L is (H1 - H2)*(H1 - H2),
formula(T1, T2, Ls).
can be simplified to make the pattern matching more explicit:
formula( [] , [] , [] ) .
formula( [] , [Y|Ys] , [Y|Zs] ) :- formula( [] , Ys , Zs ) .
formula( [X|Xs] , [] , [X|Zs] ) :- formula( Xs , [] , Zs ) .
formula( [X|Xs] , [Y|Ys] , [Z|Zs] ) :-
L is ( X - Y ) * ( X - Y ) ,
formula(Xs,Ys,Zs)
.
I assume your instructor wants you to roll your own here and learn about recursion rather than using a built-in predicate. So, ... You could sum the elements of a list like this (the naive implementation):
sum_of( [] , 0 ) . % the sum of the empty list is zero.
sum_of( [X|Xs] , S ) :- % the sum of an empty list is computed by
sum(Xs,T) , % - computing the sum of the tail of the list
S is T+X % - and adding that to the value of the head of the list.
. %
But that will fail with a stack overflow once the list gets sufficiently long as each recursive call pushes a new frame onto the stack. Prolog has an nifty optimization (tail recursion optimization) that effectively converts recursion into iteration by recognizing when it can reuse the stack frame. To do that, the recurive call must be the very last thing done.
This introduces a common pattern in prolog programming:
a public interface predicate (here, sum_of/2),
that invokes a "private" tail-recursize worker predicate (here, sum_of/3) that uses an accumulator argument to build up its result.
Using that pattern, we get this implementation:
sum_of(Xs,Sum) :- sum_of(Xs,0,Sum) .
sum_of( [] , S , S ) . % the sum of the empty list is 0.
sum_of( [X|Xs] , T , S ) :- % the sum of a non-empty list is computed by
T1 is T+X , % incrementing the accumulator by the value of the head of the list, and
sum_of( Xs , T1 , S ) % recursing down on the tail.
. % Easy!
This will work for lists of any length.
Using the SWI-Prolog library predicate sum_list/2:
list_summed_and_square_rooted(List, Value) :-
sum_list(List, Sum),
Value is sqrt(Sum).
You probably don't need to write a separate predicate for relating a list to the square root of the sum of its elements, unless you'll be needing to use that particular relation often. Your formula/3 makes one list out of two, but ultimately you seem to be after a numerical value, so you probably do want another predicate to describe the relation between two lists and the resultant numerical value.
lists_processed_in_some_way(List1, List2, Value) :-
formula(List1, List2, CombinedList),
sum_list(CombinedList, Sum),
Value is sqrt(Sum).
By the way, you can simplify your formula/3 because you don't need L = H2:
formula([], [H2|T2], [H2|Ls]) :-
formula([], T2, Ls).
Also, it's generally good practice to name your predicates carefully, with something descriptive. It will help you reason about what your predicates do and help you communicate your programs to others.

Resources