convert list of adjacencies to recursive format - prolog

Given a binary tree in a format of list of adjacencies such as [1-8,1-2,...]
The elements in the list are not in any particular order.
Given the root of the tree the list needs to be converted to a recursive format t(L,Root,R). Where L and R are trees themselves or nil.
This is what I have tried:
% convert binary tree from adjacencies list to recursive term format.
% make_tree(AdjList, Root, Tree)
make_tree([],Root,t(nil,Root,nil)):-!.
make_tree([Root-X],Root,t(X,Root,nil)).
make_tree([Root-X],Root,t(nil,Root,X)):-!.
make_tree(_,nil,nil):-!.
make_tree(N,Root,t(L,Root,R)):-
find_kids(N,Root,C,S),
reorder(C,[C1,C2]),
make_tree(S,C1,L), make_tree(S,C2,R).
% reorder 2 out of 2
reorder([X,Y],[Y,X]).
reorder([X,Y],[X,Y]).
% find children and remove them from list of nodes
find_kids(L,Root,[C1,C2],R):-
find_children(L,Root,[C1,C2|_],R).
find_children([Root-Y|Xs],Root,[Y|T],Acc):-
find_children(Xs,Root,T,Acc).
find_children([X-Y|Xs],Root,R,[X-Y|Acc]):-
X \= Root,
find_children(Xs,Root,R,Acc).
find_children([],_,[nil,nil],[]).

Consider the following binary tree and an arbitrary adjacency list for it:
% 0
% / \
% 1 2
% / \ / \
% 3 4 5 6
% / \ \
% 7 8 9
adj_list([1-3,0-2,1-4,5-9,3-7,2-5,2-6,3-8,0-1]).
To get the children of a node, you can use the following predicate:
find_children(Root, List, Children, Rest) :-
partition({Root}/[X-_]>>(X=Root), List, Children0, Rest),
maplist([Root-Child, Child]>>true, Children0, Children).
Examples:
?- adj_list(List), find_children(3, List, Children, Rest).
List = [1-3, 0-2, 1-4, 5-9, 3-7, 2-5, 2-6, 3-8, ... - ...],
Children = [7, 8],
Rest = [1-3, 0-2, 1-4, 5-9, 2-5, 2-6, 0-1].
?- adj_list(List), find_children(5, List, Children, Rest).
List = [1-3, 0-2, 1-4, 5-9, 3-7, 2-5, 2-6, 3-8, ... - ...],
Children = [9],
Rest = [1-3, 0-2, 1-4, 3-7, 2-5, 2-6, 3-8, 0-1].
?- adj_list(List), find_children(4, List, Children, Rest).
List = Rest, Rest = [1-3, 0-2, 1-4, 5-9, 3-7, 2-5, 2-6, 3-8, ... - ...],
Children = [].
To build all possible binary trees from a given root, you can use the following code:
% trees(+Root, -Tree)
trees(Root, Tree) :-
adj_list(List),
make_tree(Root, List, _Rest, Tree).
% make_tree(+Root, +List, -Rest, -Tree)
make_tree(Root, List, Rest, Tree) :-
find_children(Root, List, Children, Rest0),
make_tree(Children, Root, Rest0, Rest, Tree).
make_tree([], Root, List, List, t(nil, Root, nil)).
make_tree([X], Root, List, Rest, Tree) :-
make_tree(X, List, Rest, Subtree),
( Tree = t(Subtree, Root, nil)
; Tree = t(nil, Root, Subtree) ).
make_tree([X,Y], Root, List, Rest, Tree) :-
make_tree(X, List, Rest0, Subtree1),
make_tree(Y, Rest0, Rest, Subtree2),
( Tree = t(Subtree1, Root, Subtree2)
; Tree = t(Subtree2, Root, Subtree1) ).
Examples:
?- trees(4, T).
T = t(nil, 4, nil).
?- trees(3, T).
T = t(t(nil, 7, nil), 3, t(nil, 8, nil)) ;
T = t(t(nil, 8, nil), 3, t(nil, 7, nil)).
?- trees(5, T).
T = t(t(nil, 9, nil), 5, nil) ;
T = t(nil, 5, t(nil, 9, nil)) ;
false.
?- trees(2, T).
T = t(t(t(nil, 9, nil), 5, nil), 2, t(nil, 6, nil)) ;
T = t(t(nil, 6, nil), 2, t(t(nil, 9, nil), 5, nil)) ;
T = t(t(nil, 5, t(nil, 9, nil)), 2, t(nil, 6, nil)) ;
T = t(t(nil, 6, nil), 2, t(nil, 5, t(nil, 9, nil))) ;
false.

Related

How to search for a member in a 2-3 tree

The code below successfully finds a member in a binary tree. Except that now I want to find a member in a 2-3 tree. (Similar to the tree shown in https://www.youtube.com/watch?v=vSbBB4MRzp4.) The last line below is an attempt to do this. But I am unsure what to use for the items marked TBD (and other parts of this line could be wrong). Any help on how to do this? Thanks!
bTree(L,X,R).
member(X, bTree(L,Y,_)) :-
X #< Y,
member(X,L).
member(X, bTree(_,X,_)).
member(X, bTree(_,Y,R)) :-
X #> Y,
member(X,R).
member(X, bTree(L,Y,R)) :-
X #> TBD, X #< TBD
member(X,TBD).
In a 2–3-tree, each node can be a:
2-node, say t(Left,Key,Right), that has one key and two children, or
3-node, say t(Left,Key1,Middle,Key2,Right), that has two keys and three children.
Thus, the 2-3-tree:
can be represented as:
mytree(
t(t(t(nil,1,nil),
4,
t(nil,5,nil,7,nil),
13,
t(nil,15,nil)),
16,
t(t(nil,17,nil,19,nil),
20,
t(nil,22,nil),
24,
t(nil,29,nil)))
).
To search this tree, you can use the following predicate:
:- use_module(library(clpfd)).
% search 2-nodes: t(Left, Key, Right)
has(t(L,X,_), K) :- K #< X, has(L, K).
has(t(_,K,_), K).
has(t(_,X,R), K) :- K #> X, has(R, K).
% search 3-nodes: t(Left, Key1, Middle, Key2, Right)
has(t(L,X,_,_,_), K) :- K #< X, has(L, K).
has(t(_,K,_,_,_), K).
has(t(_,X,M,Y,_), K) :- K #> X, K #< Y, has(M, K).
has(t(_,_,_,K,_), K).
has(t(_,_,_,Y,R), K) :- K #> Y, has(R, K).
Examples:
?- mytree(T), has(T, 51).
false.
?- mytree(T), has(T, 16).
T = t(t(t(nil, 1, nil), 4, t(nil, 5, nil, 7, nil), 13, t(nil, 15, nil)), 16, t(t(nil, 17, nil, 19, nil), 20, t(nil, 22, nil), 24, t(nil, 29, nil))) .
?- mytree(T), forall(has(T,X), writeln(X)).
1
4
5
7
13
15
16
17
19
20
22
24
29
T = t(t(t(nil, 1, nil), 4, t(nil, 5, nil, 7, nil), 13, t(nil, 15, nil)), 16, t(t(nil, 17, nil, 19, nil), 20, t(nil, 22, nil), 24, t(nil, 29, nil))).

Creating Binary Tree in Prolog

I'm a beginner in Prolog, and my first assignment is to implement a function construct(), that builds a binary tree from a list. I know there is something wrong or missing in my code, but I can't put my finger on it. I also think a helper method may be necessary, but I can't think of how to go about that.
Here is my code so far:
construct([],nil).
construct(E, tree(E,nil,nil)).
construct([H|T], tree(H, construct(T,R), nil)):-
T>H.
construct([H|T], tree(H, construct(T,R), nil)):-
T<H.
First: there are no functions in Prolog, just predicates. So, if you write tree(H, construct(T,R), nil) (from your 2nd clause), then you've created a structure (or "term") that looks like this:
tree
/ | \
/ | \
H construct nil
/ \
/ \
T R
which is not what you want.
Instead, you should write something like this (although this won't do what you want either -- see below):
construct([H|T], tree(H, Tree, nil)):-
T>H,
construct(T, R, Tree).
Second: you should have an easy way to distinguish a value from a non-value. You've chosen nil for non-value, so you could have something like value(V) for storing a value.
Now, think about what a node looks like. It's got 2 parts (left and right), each of which can be either nil, a value or a node. For example, you'd want [1,2,3] to produce a tree that looks something like
node(node(value(1),
value(2)),
value(3))
As for an auxiliary predicate (not "function"), an obvious one is a predicate that inserts a single value to a tree. So, just list out all the possibilities:
insert_value(X, node(nil, nil), node(value(X), nil)). % insert into an empty node
insert_value(X, node(value(Y), nil), node(value(X), value(Y))) :- X < Y.
insert_value(X, node(value(Y), nil), node(value(Y), value(X))) :- X > Y.
insert_value(X, node(node(A,B), value(Y)), node(T1, value(Y))) :-
X < Y,
insert_value(X, node(A,B), T1).
etc.
If you do this, you'll find that this isn't the best representation for a tree, but I'll leave it to you to come up with a better representation. (Incidentally, there's no need for all the node functors to have 2 elements; it's ok to have node - contains nothing; node(X) - contains a single item; node(X,Y) - contains 2 items).
Also, you'll need to decide what to do wwhen inserting a value that's already in the tree -- does insert_value/3 fail, does it just do nothing, or does it allow multiple identical values?
Once you've got this working, then you can write a predicate to insert a list of values:
insert_values([], Tree, Tree).
insert_values([X|Xs], Tree0, Tree) :-
insert_value(X, Tree0, Tree1),
insert_values(Xs, Tree1, Tree).
This is a very common pattern; the general form of it is called "foldl".
And finally, get the whole thing going with an initial value of an empty node:
insert_values(Values, Tree) :-
insert_values(Values, node(nil,nil), Tree).
It's also very common in Prolog to define predicates with different numbers of arguments; in this case, insert_values/2 uses insert_values/3 with an initial value of an empty node (node(nil,nil)).
In Prolog, we can use:
the atom nil to represent an empty binary tree, and
a term of the form t(Left, Root, Right) to represent a non-empty binary tree, where Root is the value at the root of the tree, and Left and Right are also terms representing binary trees.
To make the binary trees easier to see, you can use the following predicate:
show(T) :-
show(T, 0).
show(nil, _).
show(t(Left, Root, Right), Indent) :-
Indent1 is Indent + 3,
show(Right, Indent1),
format('~*c~w\n', [Indent, 32, Root]),
show(Left, Indent1).
Example:
?- show( t(t(nil,1,nil), 2, t(nil,3,nil)) ).
3
2
1
true.
Let List be a list denoting the in-order traversal of an arbitrary binary tree, as illustrated bellow:
Then, since different binary trees can have the same in-order traversal, a binary tree corresponding to such list can be described as follows:
% convert from in-order traversal list to binary tree
list_to_bt(List, Tree) :-
( List = []
-> Tree = nil
; Tree = t(Left, Root, Right),
append(Prefix, [Root|Suffix], List),
list_to_bt(Prefix, Left),
list_to_bt(Suffix, Right) ).
Example:
?- list_to_bt([1,2,3], T), show(T).
3
2
1
T = t(nil, 1, t(nil, 2, t(nil, 3, nil))) ;
3
2
1
T = t(nil, 1, t(t(nil, 2, nil), 3, nil)) ;
3
2
1
T = t(t(nil, 1, nil), 2, t(nil, 3, nil))
...
false.
If you want to obtain only balanced binary trees (e.g., trees such that, for each node, the absolute difference in the sizes of the right and left subtrees is at most 1), then you can include this constraint as follows:
% convert from in-order traversal list to balanced binary tree (bbt)
list_to_bbt(List, Tree) :-
( List = []
-> Tree = nil
; Tree = t(Left, Root, Right),
append(Prefix, [Root|Suffix], List),
length(Prefix, Size1),
length(Suffix, Size2),
abs(Size1 - Size2) =< 1,
list_to_bbt(Prefix, Left),
list_to_bbt(Suffix, Right) ).
Example:
?- list_to_bbt([1,2,3], T), show(T).
3
2
1
T = t(t(nil, 1, nil), 2, t(nil, 3, nil)) ;
false.
If you want only balanced binary search trees from an arbitrary list, then you must sort this list before creating the balanced binary tree:
% convert from arbitrary list to balanced binary search tree (bbst)
list_to_bbst(List, Tree) :-
sort(List, Sorted),
list_to_bbt(Sorted, Tree).
Examples:
?- list_to_bbst([3,1,7,5,4,2,6], T), show(T).
7
6
5
4
3
2
1
T = t(t(t(nil, 1, nil), 2, t(nil, 3, nil)), 4, t(t(nil, 5, nil), 6, t(nil, 7, nil))) ;
false.
?- list_to_bbst([3,1,4,2], T), show(T).
4
3
2
1
T = t(t(nil, 1, nil), 2, t(nil, 3, t(nil, 4, nil))) ;
4
3
2
1
T = t(t(nil, 1, nil), 2, t(t(nil, 3, nil), 4, nil)) ;
4
3
2
1
T = t(t(nil, 1, t(nil, 2, nil)), 3, t(nil, 4, nil)) ;
4
3
2
1
T = t(t(t(nil, 1, nil), 2, nil), 3, t(nil, 4, nil)) ;
false.

Prolog insert into a list

I would advice about this exercise:
Write a method insert, which has 3 parameters, the first an ordered
list, the second an int and the third an ordered list without repeated
values equal as the first one but containing the second parameter.
Example:
> insert([5, 6, 30, 60, 90], 40, L)
L = [5, 6, 30, 40, 60, 90]
> insert([5, 6, 30, 60, 90], 30, L)
L = [5, 6, 30, 60, 90]
I would do:
insert([],_,[_]).
insert([H],_,Result) :-
Result < H,
insert([],[],[Result|H]).
insert([H],_,Result) :-
Result > H,
insert([],[],[H|Result]).
insert([H,Y|Rest], _, Result):-
_ < Y,
insert([X|Rest], [], Result).
insert([H,Y|Rest], _, Result):-
_ > Y,
insert([Y|Rest], [], Result).
But I think base case when there is only one element is redundant and not needed because of we have the general recursive case and the empty list one. I need some suggest to improve or better explanations to polish the code.
Thank you for your time.
Try with compare:
:- use_module(library(clpfd)).
insert([], X, [X]).
insert([X|Xs], New, Ys) :-
zcompare(Order, X, New),
insert(Order, X, New, Xs, Ys).
insert(>, X, New, Xs, [New,X|Xs]).
insert(=, X, _, Xs, [X|Xs]).
insert(<, X, New, Xs, [X|Ys]) :-
insert(Xs, New, Ys).
but maybe you need explanation? It is strange, because you could also just read documentation as I did and find why this is good enough implementation, but of course maybe it is good to explain more, just in case.
insert([], X, [X]).
When first argument is empty list, second argument is the only element of the result list.
insert([X|Xs], New, Ys) :-
zcompare(Order, X, New), ...
When first argument is list with at least one element, take head element and compare it to New element. After compare or zcompare first argument Order is either > or = or < (but what do these mean? maybe guess or maybe even read documentation if it is not too much work).
insert(Order, X, New, Xs, Ys).
After comparing take the Order and the rest of the variables and....
insert(>, X, New, Xs, [New,X|Xs]).
Element at head of list is larger than New element. This means that result list should be New element followed by head followed by rest of list.
insert(=, X, _, Xs, [X|Xs]).
Element at head of list is exactly the same as New element. We are done, no need to insert anything just keep original list as result.
insert(<, X, New, Xs, [X|Ys]) :-
insert(Xs, New, Ys).
Element at head of list is smaller than New element: New element must come after this element in result. So we put current element back in list and search for place of New element in rest of list.
So much text, but is it now easier to understand what code says? Maybe or maybe not?
there
?- insert([5, 6, 30, 60, 90], 40, L).
L = [5, 6, 30, 40, 60, 90].
?- insert([5, 6, 30, 60, 90], 6, L).
L = [5, 6, 30, 60, 90].
?- insert([5, 6, 30, 60, 90], 100, L).
L = [5, 6, 30, 60, 90, 100].
?- insert([5, 6, 30, 60, 90], 0, L).
L = [0, 5, 6, 30, 60, 90].
but there are more interesting things to do with this solution because it uses a predicate like zcompare/3 which looks a bit like compare/3 but it knows integer constraints so it is possible to query:
What integers can be inserted in list [1,3,4]?
?- insert([1,3,4], X, R).
R = [X, 1, 3, 4],
X in inf..0 ;
X = 1,
R = [1, 3, 4] ;
X = 2,
R = [1, 2, 3, 4] ;
X = 3,
R = [1, 3, 4] ;
X = 4,
R = [1, 3, 4] ;
R = [1, 3, 4, X],
X in 5..sup.
So you can insert any integer < 1 at front, or you can "insert" 1 that was there, or you can insert 2 between 1 and 3, or you can "insert" 3 or 4, or you can insert 5 or anything larger at the end of list.
Another way :
% First element of the list is smaller than V
% we keep on wth the rest of the list
insert([H | T], V, [H|V1]) :-
H < V, !, % remove choice points
insert(T, V, V1).
% First element of the list is equal than V
% insert([V | T] , V, [V|T]).
% corrected after **enoy** remark
insert([V | T] , V, [V|T]):- !.
% First element of the list is greater than V, found the place of V
insert([H | T] , V, [V,H|T]).
% insert V in an empty list (V is greater than all elements of the list)
insert([], V, [V]).
with the same results as the Users9213 answer.
EDIT A way to avoid cut is
% First element of the list is smaller than V
% we keep on with the rest of the list
insert([H | T], V, [H|V1]) :-
H < V,
insert(T, V, V1).
% First element of the list is equal than V
insert([V | T] , V, [V|T]).
% First element of the list is greater than V, found the place of V
insert([H | T] , V, [V,H|T]):-
H > V.
% insert V in an empty list (V is greater than all elements of the list)
insert([], V, [V]).

How to add a leaves to a tree in Prolog

I am studying binary tree in Prolog and I have some problem to add leaves to a specific b-tree.
I have the following predicates that add a single leaf to a b-tree:
addLeaf(nil, X, t(nil, X, nil)).
addLeaf(t(Left, X, Right), X, t(Left, X, Right)).
addLeaf(t(Left, Root, Right), X, t(Left1, Root, Right)) :-
gt(Root, X), addLeaf(Left, X, Left1).
addLeaf(t(Left, Root, Right), X, t(Left, Root, Right1)) :-
gt(X, Root), addLeaf(Right, X, Right1).
gt(Element1, Element2) :- Element1 #> Element2.
This is pretty simple and I think that I have not problem with it.
My problem is related about to use it to perform query that add more then a single leaf to a bin tree,
For example if, in the Prolog shell, I perform the following statement:
[debug] ?- addLeaf(nil, 6, Tree).
Tree = t(nil, 6, nil).
the original tree is nil (there is no tree), so add a new leaf is equivalent to create a new tree (called Tree) that have the element 6 as root.
Now my problem is: "I have create a new tree, that corresponds to the Tree variable, what have I to do to add others leaves to this tree?"
Because, if now I try to perform the following statement:
[debug] ?- addLeaf(Tree, 6, NewTree).
Tree = nil,
NewTree = t(nil, 6, nil)
I obtain that Tree = nill (also if I had just created it in the previous statement. Evidently the Tree variable (in the two statement) are independent of each other, evidently the variables are independent of each other.
So I try to perform:
[debug] ?- addLeaf(nil, 6, Tree), addLeaf(Tree, 8, NewTree).
Tree = t(nil, 6, nil),
NewTree = t(nil, 6, t(nil, 8, nil)).
and it work fine adding the 8 element as the right child of 6 (according to the b-tree rules)
But, I am asking if, in the Prolog shell, is it possible do something this:
create new tree.
add a leaf.
add another leaf.
add another leaf.
...
...
without declare all the operation in an unique statement, some idea about it?
?- addLeaf(nil, 6, Tree).
Tree = t(nil, 6, nil).
?- addLeaf($Tree, 7, NewTree).
NewTree = t(nil, 6, t(nil, 7, nil)).
?- addLeaf($NewTree, 4, NewTree2).
NewTree2 = (t(nil, 4, nil), 6, t(nil, 7, nil)) .
this sample uses top level variables (a feature of SWI-Prolog). Judging from NewTree2, it seems you have a typo in your code.
You can reuse top-level bindings in SWI Prolog:
6 ?- X = a(_).
X = a(_G236)
7 ?- Z = $X.
Z = a(_G269)

Sort a list of cards prolog

I have a list of card structures such as:
[card(ace, spades), card(10, diamonds), card(king, clubs)]
can anyone help me understand how to sort these according to face value?
I have this:
bubblesort(L, L1) :-
( bubble(L, L2)
-> bubblesort(L2, L1)
; L = L1 ).
bubble([card(A,A2), card(B,B2)|T], L) :-
( A > B
-> L = [card(B,B2), card(A,A2)|T]
; L = [card(A,A2) | L1],
bubble([card(B,B2)|T], L1)).
which works well (its bubble sort) except when you have card(ace, spades) or alike because ace is not a number
You can use predsort/3
It's like sort/2, but determines the order of the terms by calling the comparison predicate you fed it. So we only need to write a compare_values/3 predicate that compares the face values of your cards. My try:
compare_values(D, card(A,_), card(B,_)) :-
nth0(X, [ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king], A),
nth0(Y, [ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king], B),
compare(D, X, Y).
sort_cards(L, R) :-
predsort(compare_values, L, R).
Explanation of the compare_values/3 predicate:
We need to define an ordering over the following list:
[ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, jack, queen, king]
how? Given two values A and B, we simply use nth0/3 to search for A and B in the list. nth0/3 will give us the position of the element we are searching for. So now:
X = position of the element A in the ordered list
Y = position of the element B in the ordered list
but now X and Y are guaranteed to be numbers! And we can compare them with the built-in predicate compare/3. If X < Y the card A comes before the card B, and vice-versa.
compare/3 will compare X and Y, and return one of (>), (<), (=).
An example:
?- compare_values(D, card(ace, clubs), card(7, spades)).
nth0 search for ace and 7 in the list of ordered values.
Now X = 0 and Y = 6 (the indexes of ace and 7 in the list)
compare(D, 0, 6) unifies with D = (<)
Finally: the predsort/3 predicate uses compare_values to sort the list accordingly to the order defined by compare_values/3
A query:
?- sort_cards([card(king, spades), card(ace,spades), card(3, clubs), card(7,diamonds), card(jack,clubs)], X).
X = [card(ace, spades), card(3, clubs), card(7, diamonds), card(jack, clubs), card(king, spades)].

Resources