I'm trying to "reverse" an inorder traversal by turning the inorder list back into BSTs.
BSTs has the predicate form node(Value,Left,Right)
or leaf
, so the empty tree is just leaf
, a tree with one node is node(_,leaf,leaf)
.
Given the predicate enumerate_bst(Elems,Bst)
, the goal is to match Bst
to all possibilities of the inorder list Elems
. For example (note setof/3):
?- setof(Bst,enumerate_bst([],Bst),Enum).
Enum = [leaf].
?- setof(Bst,enumerate_bst([1,2],Bst),Enum).
Enum = [
node(1, leaf, node(2, leaf, leaf)),
node(2, node(1, leaf, leaf), leaf)
].
?- setof(Bst,enumerate_bst([1,2,3],Bst),Enum).
Enum = [
node(1, leaf, node(2, leaf, node(3, leaf, leaf))),
node(1, leaf, node(3, node(2, leaf, leaf), leaf)),
node(2, node(1, leaf, leaf), node(3, leaf, leaf)),
node(3, node(1, leaf, node(2, leaf, leaf)), leaf),
node(3, node(2, node(1, leaf, leaf), leaf), leaf)
].
What I tried to do:
I already have a predicate that matches a given BST to it's inorder list:
inorder(leaf,[]).
inorder(node(X,L,R),Elems) :-
inorder(L,Elems_L),
inorder(R,Elems_R),
append(Elems_L,[X],Tmp),
append(Tmp,Elems_R,Elems).
I tried to use it in reverse by putting in a list instead, but this only returned one result, I'm not exactly sure why.
What I'm currently trying to do
I'm trying to use the native predicate append/3 in reverse, but can't fully decide how this will be done.
Any ideas as to the best way to do this? Thanks!
In reverse, your program does not terminate. Consider:
?- inorder(Tree, []).
Tree = leaf
; loops.
We would expect that it just shows this only solution and then stops.
The actual reason is the following fragment of your program - a failure-slice. No need to look any further than that. In other words, no need to understand append/3
at all.
?- inorder(Tree, []), false.inorder(leaf,[]) :- false. inorder(node(X,L,R),Elems) :- inorder(L,Elems_L), false.inorder(R,Elems_R),append(Elems_L,[X],Tmp),append(Tmp,Elems_R,Elems).
First, this fragment needs to terminate (and fail). Only then you may consider termination of the entire program. Within this fragment, the second argument (Elems
) is completely ignored! The first goal that would be interested in it is the very last one (append(Tmp,Elems_R,Elems)
).
A naive way out would be to reorder the goals, putting the two append/3
goals first. That works (that is, it terminates for a ground second argument), but it is quite unsatisfying, as the program is now devoted to distributing elements of a list into trees only.
Here is a version that works both ways as indicated by the termination condition:
inorder(A,B)terminates_if b(A);b(B).
which states that inorder/2
terminates if the first or the second argument is ground.
inorder(Tree, Xs) :-
phrase(inorder(Tree, Xs,[]), Xs).
inorder(leaf, Vs,Vs) -->
[].
inorder(node(X,L,R), [_|Vs0],Vs) -->
inorder(L, Vs0,Vs1),
[X],
inorder(R, Vs1,Vs).