Get all possible binary trees using Prolog? - prolog
I'm aware there are lots of questions about defining a binary tree to check whether something is a binary tree or not,but i could not find a thread that tackled this question in the "opposite direction".
Why does your definition of binary tree not return all possible binary trees when called as "es_arbol(X)"? Explain in detail and try to implement a different definition that does return all possible binary tree structures.
Ok,so basically i'm stuck in this part of an assignment.After defining my binary-tree-validating function i noticed that when called with no arguments it just returns trees that "grow" through their right nodes,or at least that's how i interpret the output of swi-prolog.What i am not getting is,assuming my definition is correct,Prolog should be able to construct them in both ways.If not,i would like if someone could point me in the right direction to work out a more general definition of a binary tree,or maybe explain why is it that my definition is not sufficient.
This is my definition:
es_arbol(nil).
es_arbol(arbol(_,I,D)) :- es_arbol(I), es_arbol(D).
The reason that your predicate generates an infinite number of trees along one branch is because you have more than one recursion, and like any language, Prolog will continue making the first recursive call it finds until it returns, which in this case, never will. So you always recurse on one leg of the tree. In other words, you have at least two variables in each tree (the left and right subtrees) that have an infinite number of possibilities.
Binary trees have an infinite number of recursive possibilities along two dimensions. You need a way to order the trees using a single-dimensional metric. One such metric could be the count of nodes in the tree. If you order your trees by node count, starting with node count 0, then for each node count, there are a finite number of trees to enumerate. Here is the general way this would work:
Nodes is a valid number of nodes
nil is a valid binary tree with 0 nodes
arbol(_, TL, TR) is a valid binary tree with N nodes if NL and NR2 add up to N-1 and TL is a valid binary tree of NL nodes, and TR is a valid binary tree of NR nodes. Since Prolog will find all solutions from a given point before backtracking prior to that point, it will search for all of the trees with the given number of nodes first before backtracking to a new valid number of nodes.
In Prolog, it looks like this.
:- use_module(library(clpfd)).
es_arbol(Tree) :-
length(_, Nodes),
es_arbol(Tree, Nodes).
I'm using length/2 to "generate" Nodes values of 0, 1, 2, etc. es_arbol(Tree) will succeed with binary trees with successive node counts starting at 0. For a given node count, Nodes, it will find all the solutions to es_arbol(Tree, Nodes) before it finally fails and backtracks to length(_, Nodes) again which will succeed on the next value of Node.
es_arbol(nil, 0).
es_arbol(arbol(_,TreeL,TreeR), N) :-
N #> 0,
NL + NR #= N - 1,
NL #>= 0, NR #>= 0,
es_arbol(TreeL, NL),
es_arbol(TreeR, NR).
The base case is trivial. nil is the tree with 0 nodes. The recursive case says that arbol(_,L,R) is a binary tree with N nodes if N > 0, NL and NR are non-negative integers that add up to N, and TL and TR are binary trees with length NL and NR, respectively.
The results of running the above code are:
?- es_arbol(Tree).
Tree = nil ;
Tree = arbol(_G258, nil, nil) ;
Tree = arbol(_G17, nil, arbol(_G157, nil, nil)) ;
Tree = arbol(_G17, arbol(_G200, nil, nil), nil) ;
Tree = arbol(_G14, nil, arbol(_G154, nil, arbol(_G593, nil, nil))) ;
Tree = arbol(_G14, nil, arbol(_G154, arbol(_G603, nil, nil), nil)) ;
Tree = arbol(_G14, arbol(_G130, nil, nil), arbol(_G191, nil, nil)) ;
Tree = arbol(_G14, arbol(_G53, nil, arbol(_G193, nil, nil)), nil) ;
Tree = arbol(_G14, arbol(_G53, arbol(_G236, nil, nil), nil), nil) ;
Tree = arbol(_G14, nil, arbol(_G100, nil, arbol(_G214, nil, arbol(_G354, nil, nil)))) ;
Tree = arbol(_G14, nil, arbol(_G100, nil, arbol(_G214, arbol(_G397, nil, nil), nil))) ;
Tree = arbol(_G14, nil, arbol(_G100, arbol(_G216, nil, nil), arbol(_G277, nil, nil))) ;
Tree = arbol(_G14, nil, arbol(_G100, arbol(_G139, nil, arbol(_G279, nil, nil)), nil)) ;
Tree = arbol(_G14, nil, arbol(_G100, arbol(_G139, arbol(_G322, nil, nil), nil), nil)) ;
Tree = arbol(_G14, arbol(_G130, nil, nil), arbol(_G191, nil, arbol(_G664, nil, nil))) ;
Tree = arbol(_G14, arbol(_G130, nil, nil), arbol(_G191, arbol(_G674, nil, nil), nil)) ;
Tree = arbol(_G14, arbol(_G132, nil, arbol(_G272, nil, nil)), arbol(_G676, nil, nil)) .
...
As #false has pointed out in the comments, the use of CLP(FD) is not the most efficient way in this case of applying a enumerative constraint. An alternative, more efficient means would be to use between/3:
es_arbol(nil, 0).
es_arbol(arbol(_,TreeL,TreeR), N) :-
N > 0,
N1 is N - 1,
between(0, N1, NL),
NR is N1 - NL,
es_arbol(TreeL, NL),
es_arbol(TreeR, NR).
Lurker has already given a very nice general solution using CLP(FD) constraints.
I would like to augment the existing answer with an alternative way to constrain the depth of the search. Instead of integers, I am using a list to "count" in a symbolic way.
To reason about lists in Prolog, DCG notation (dcg) is often very convenient, also in this case:
es_arbol(nil) --> [].
es_arbol(arbol(_,I,D)) --> [_], es_arbol(I), es_arbol(D).
Declaratively, you can think about these rules as "consuming credit" to apply.
If I query naively, then I get an unfair enumeration:
?- phrase(es_arbol(A), Ls).
A = nil,
Ls = [] ;
A = arbol(_9016, nil, nil),
Ls = [_9024] ;
A = arbol(_9016, nil, arbol(_9030, nil, nil)),
Ls = [_9024, _9038] ;
A = arbol(_9016, nil, arbol(_9030, nil, arbol(_9044, nil, nil))),
Ls = [_9024, _9038, _9052] ;
A = arbol(_9016, nil, arbol(_9030, nil, arbol(_9044, nil, arbol(_9058, nil, nil)))),
Ls = [_9024, _9038, _9052, _9066] .
The point is that we can easily turn this into a fair enumeration by restricting the length of the list. For example, to get all trees with exactly two inner node, we can use:
?- phrase(es_arbol(A), [_,_]).
A = arbol(_10426, nil, arbol(_10434, nil, nil)) ;
A = arbol(_10426, arbol(_10434, nil, nil), nil) ;
false.
Building on this, we can use iterative deepening to fairly enumerate all tree shapes:
?- length(Ls, _), phrase(es_arbol(A), Ls).
Ls = [],
A = nil ;
Ls = [_7130],
A = arbol(_7142, nil, nil) ;
Ls = [_7130, _7136],
A = arbol(_7148, nil, arbol(_7156, nil, nil)) ;
Ls = [_7130, _7136],
A = arbol(_7148, arbol(_7156, nil, nil), nil) ;
Ls = [_7130, _7136, _7142],
A = arbol(_7154, nil, arbol(_7162, nil, arbol(_7170, nil, nil))) ;
Ls = [_7130, _7136, _7142],
A = arbol(_7154, nil, arbol(_7162, arbol(_7170, nil, nil), nil)) ;
Ls = [_7130, _7136, _7142],
A = arbol(_7154, arbol(_7162, nil, nil), arbol(_7170, nil, nil)) .
Thus, counting "symbolically" is sometimes a convenient alternative to using actual integers.
Related
Find binary search trees based on traversal in prolog
I am trying to write a Prolog predicate that gives a possible binary search tree for a given traversal. I chose to represent the tree like t(Root, Left Subtree, Right Subtree), leaves are simply t(Number) and when a subtree does not exist its value is nil. This is what I have so far (only for postorder traversal in this case): post(nil, []). post(t(X), [X]). post(t(N, L, R), T) :- post(L, TL), post(R, TR), append([TL, TR, [N]], T). This works nicely in one way, but hangs in the other direction: ?- post(t(8, t(5, t(2), nil), t(12, t(9), t(16))), Trav). Trav = [2, 5, 9, 16, 12, 8]. ?- post(Tree, [2, 5, 9, 16, 12, 8]). Tree = t(8, nil, t(12, nil, t(16, nil, t(9, nil, t(5, nil, t(2)))))) ; Tree = t(8, nil, t(12, nil, t(16, nil, t(9, nil, t(5, nil, t(2, nil, nil)))))) ; [execution hangs here] I realized that post does not require a binary search tree, ie there is no requirement for all nodes in the left subtree to be less than the root node and all nodes in the right subtree to be greater than the root node, so I also wrote this: tree(t(_)). tree(nil). tree(t(N, L, R)) :- tree(L), tree(R), ( L = t(NL, _, _) -> NL < N ; true ), ( R = t(NR, _, _) -> NR > N ; true ). I thought I could just do ?- post(Tree, [...]), tree(Tree). to make Prolog only return actual binary search trees. However, I seem to be stuck already at generating possible trees. How could I improve my code? Is this even doable?
My suggestion is to write different code for different directions. Here is the code to transform a list back into a tree. The main difference with the original code is that we deconstruct the list (with last/3 and append/3) before reconstructing the tree. Note that I added the code to check for a search tree in third clause (the two maplist/2calls) but those can be as well removed if you want to keep it separately. postlist_to_tree([],nil). postlist_to_tree([X],t(X)). postlist_to_tree(Xs,t(Last,LT,RT)):- last(Fore,Last,Xs), append(LL,RL,Fore), maplist('>='(Last),LL), maplist('=<'(Last),RL), postlist_to_tree(LL, LT), postlist_to_tree(RL, RT). Now to have it as a single predicate, I would suggest to do something like this, using a non-logical predicate (ground/1 in this example) to decide which version to call depending on the instantiation of the arguments at call time. post2(Tree,List):- ground(List), !, postlist_to_tree(List,Tree). post2(Tree,List):- post(Tree,List).
Trying to add siblings to every node in a binary tree with one child so that all nodes have 2 or zero children. In other words no nodes have 1 child
My prolog program is supposed take a binary tree and make a new tree that adds a child to any node that only has one child so that all nodes have 2 or zero children. The binary tree representation being used is along the lines of t(73,t(31,t(5,nil,nil),nil),t(101,t(83,nil,t(97,nil,nil)),nil)). The issue is that it only fixes the nodes that have a missing right child and its not working for nodes that are missing a left node. treeEx(X) :- X = t(73,t(31,t(5,nil,nil),nil),t(101,t(83,nil,t(97,nil,nil)),nil)). singleFill(t(_,nil,nil),_,_):-!. singleFill(t(Root,nil,Right),V,t(Root,t(V,nil,nil),Right)):- singleFill(Right,V,_). singleFill(t(Root,Left,nil),V,t(Root,Left,t(V,nil,nil))):- singleFill(Left,V,_). singleFill(t(Root,Left,Right),V,t(Root,LD,RD)):- singleFill(Left,V,LD), singleFill(Right,V,RD). When using the query treeEx(T),singleFill(T,0,L). it should produce the result: T = t(73, t(31, t(5, nil, nil), nil), t(101, t(83, nil, t(97, nil, nil)), nil)), L = t(73, t(31, t(5, nil, nil), t(0, nil, nil)), t(101, t(83, t(0, nil, nil), t(97, nil, nil)), t(0, nil, nil))) however mine produces: T = t(73, t(31, t(5, nil, nil), nil), t(101, t(83, nil, t(97, nil, nil)), nil)), L = t(73, t(31, t(5, nil, nil), t(0, nil, nil)), t(101, t(83, nil, t(97, nil, nil)), t(0, nil, nil))) . The problem is that the node with 83 has one child but its not adding the zero. When I traced it I noticed that it was because there are 2 separate reclusive calls that have 2 different forms of the tree so I think that only the nodes with right children are saving the changes to the new tree. However the changes to the left tree are not
So, right off the bat we have a few weird things about your code: ?- singleFill(t(1,nil,nil), 0, Y). true. It's weird to me that this is true but didn't bind anything on Y. This must be the behavior that you noticed. I think it may stem from this: ?- singleFill(nil, 0, Y). false. Namely, your code doesn't handle the base case of the recursion. This is why you seem to need so many cases. Always check your predicates with simple inputs close to the base cases, those are the ones that will help you see the problem. In actuality, you only need three cases: single_fill(nil, New, t(New, nil, nil)). single_fill(t(V, nil, nil), _, t(V, nil, nil)) :- !. single_fill(t(V, Left, Right), New, t(V, NewLeft, NewRight)) :- single_fill(Left, New, NewLeft), single_fill(Right, New, NewRight). Notice that I'm only ignoring one variable here, and it's the fill variable in the case where no filling happens. I still have a cut here, which I'm not happy about. Without the cut, the first solution matches your specification but you get several more, basically one for each case where there was nil in both branches in the tree. With the cut, this predicate will successfully "check" those inputs even though it wouldn't generate them, which is a violation of backwards correctness. This suggests to me that there may be a better way to write this that doesn't have this problem. But I couldn't think of it. I feel like it should be sufficient to say Left \= nil, Right \= nil instead but that didn't work.
treeMerge in swi-prolog
I am trying to build a predicate treeMerge(A,B,C) that returns true if C is the result of merging the two trees A and B. Any suggestions on how I can implement this? I have a rough idea, I am thinking of merging the root, then first child then second and so on, but I am fairly new to prolog.
The idea is to get the list of the nodes inside a tree then add each nodes in the other tree. I've developed a predicate merge/3 which merges the two tree as input in a third tree (insert all the nodes of the first tree into the second). A tree is represented as t(Node,Left,Right). Here is the code: getNodes(nil,[]). getNodes(t(E,L,R),[E|S]) :- append(SL,SR,S), getNodes(L,SL), getNodes(R,SR),!. insert(Node,nil,t(Node,nil,nil)). insert(Node,t(El,Left,Right),t(El,L,R)):- (Node > El -> insert(Node,Right,R), L = Left ; insert(Node,Left,L), R = Right). insertNodesList([],T,T). insertNodesList([H|T],Tree,M):- insert(H,Tree,T1), insertNodesList(T,T1,M). merge(T1,T2,Merged):- getNodes(T1,LNodesT1), insertNodesList(LNodesT1,T2,Merged). Query: ?-merge(t(3,t(2,t(1,nil,nil),nil),t(4,nil,t(7,nil,t(5,nil,nil)))),t(3,t(2,nil,nil),t(4,nil,t(7,nil,t(5,nil,nil)))),T). T = t(3, t(2, t(2, t(1, nil, nil), nil), t(3, nil, nil)), t(4, t(4, nil, nil), t(7, t(7, t(5, nil, nil), nil), t(5, nil, nil))))
Prolog, reconstruct BST trees from inorder list
We well know inorder implementation for BST tree. inorder(nil, []). inorder(t(Root, L, R), List) :- inorder(L, ListLeft), inorder(R, ListRight), append(ListLeft, [Root|ListRight], List). However, is it possible to do it for list ? I mean reconstruct all possible BST trees, for example: inorder(X, [1,2,3]). X = t(1, nil, t(2, nil, t(3, nil, nil)))); X = t(3, t(2, t(1, nil, nil), nil), nil), nil); X = t(2, t(1, nil, nil), t(3, nil, nil)); false. It seems to be impossible for me.
First, let us use a Definite Clause Grammar (dcg) for relating trees to lists: inorder(nil) --> []. inorder(t(Root, L, R)) --> inorder(L), [Root], inorder(R). The trick I will now apply is described in Ulrich Neumerkel's dissertation in Taming Left Recursion. "... we add another state for the number of tokens that can be used by newly encountered nonterminals. The number of tokens that will be read by the terminals within a single rule are therefore reserved in advance." In our case: inorder(nil, Es, Es) --> []. inorder(t(Root, L, R), [_|Es0], Es) --> inorder(L, Es0, Es1), [Root], inorder(R, Es1, Es). Sample query (Ls omitted): ?- Ls = [1,2,3], phrase(inorder(Tree, Ls, _), Ls). Tree = t(1, nil, t(2, nil, t(3, nil, nil))) ; Tree = t(1, nil, t(3, t(2, nil, nil), nil)) ; Tree = t(2, t(1, nil, nil), t(3, nil, nil)) ; Tree = t(3, t(1, nil, t(2, nil, nil)), nil) ; Tree = t(3, t(2, t(1, nil, nil), nil), nil) ; false. Another way to solve such issues is to use your Prolog system's tabling mechanism.
If you like the trick I've proposed here, the only change required could be :- use_module(carlo(snippets/when_)). inorder(t(Root, L, R), List) -:- ... and now ?- inorder(T,[1,2,3]). T = t(1, nil, t(2, nil, t(3, nil, nil))) ; T = t(1, nil, t(3, t(2, nil, nil), nil)) ; T = t(2, t(1, nil, nil), t(3, nil, nil)) ; T = t(3, t(1, nil, t(2, nil, nil)), nil) ; T = t(3, t(2, t(1, nil, nil), nil), nil) ; false.
Prolog binary search tree test - unwanted parents' parent node comparison
I'm a Prolog rookie, please keep that in mind. I try to write a predicate to determine if some given term is a binary search tree. I figured out this code: is_btree(nil). is_btree(node(N,L,R)) :- number(N), is_btree(L), is_btree(R), small(N, R), big(N, L). small(N, nil). small(N, node(M,L,R)) :- N < M, small(N, L), small(N, R). big(N, nil). big(N, node(M,L,R)) :- N > M, big(N, L), big(N, R). It works quite fine until I test a graph that has a node on the right side which passes the condition "higher than parent node", but it is higher or equal to parent node of the parent node. In this case Prolog reports failure. Here is a sample query which fails unexpectedly: ?- is_btree(node(9,node( 3,node( 2,nil,nil), node(10,nil,nil)), node(12,node( 8,nil,nil), node(15,nil,nil)))). false. A very similar problem arises when some node on the left side is higher than parent node of the parent node—a situation that is shown in the following illustration: How can I check node values only with the value of their immediate parent node, but not the values of parents' parents?
Here's a slightly different take on the problem you want to solve. dcg for collecting elements: in-order tree-traversal in_order(nil) --> []. in_order(node(X,L,R)) --> in_order(L), [X], in_order(R). clpfd for relating adjacent list elements (which are all finite-domain variables) chain(Zs, #<) Let's put it all together and define is_bintreeFD/1 like this: :- use_module(library(clpfd)). is_bintreeFD(T) :- phrase(in_order(T), Zs), chain(Zs, #<). Sample queries: ?- is_bintreeFD(node(9,node( 3,node(2,nil,nil),node(10,nil,nil)), node(12,node(8,nil,nil),node(15,nil,nil)))). false. ?- is_bintreeFD(node(9,node( 3,node( 2,nil,nil),node( 8,nil,nil)), node(12,node(10,nil,nil),node(15,nil,nil)))). true.
This answer directly follows up on this previous answer, particularly on a comment by #WillNess that suggested "[...] switch the two goals, so the traversal is stopped as soon as possible on failure [...] to have chain before the phrase [...]". lazy_chain/2 is like chain/2, but utilizes prolog-coroutining to wait for sufficient instantiation: :- use_module(library(clpfd)). lazy_chain(Zs, R_2) :- ( var(R_2) -> instantiation_error(R_2) ; clpfd:chain_relation(R_2) -> freeze(Zs, lazy_chain_aux(Zs,R_2)) ; otherwise -> domain_error(chain_relation, R_2) ). lazy_chain_aux([], _). lazy_chain_aux([Z0|Zs], R_2) :- freeze(Zs, lazy_chain_aux_(Zs,R_2,Z0)). lazy_chain_aux_([], _, _). lazy_chain_aux_([Z1|Zs], R_2, Z0) :- call(R_2, Z0, Z1), freeze(Zs, lazy_chain_aux_(Zs,R_2,Z1)). Based on lazy_chain/2 we define is_bintreeL/2 like this: is_bintreeL(T) :- lazy_chain(Zs, #<), phrase(in_order(T), Zs). So... what about "early failure"? ?- T = node(2, nil, node(1, nil, node(3, nil, node(4, nil, node(5, nil, node(6, nil, node(7, nil, node(8, nil, node(9, nil, node(10, nil, node(11, nil, node(12, nil, node(13, nil, node(14, nil, node(15, nil, node(16, nil, node(17, nil, node(18, nil, node(19, nil, node(20, nil, node(21, nil, node(22, nil, node(23, nil, node(24, nil, node(25, nil, node(26, nil, node(27, nil, node(28, nil, node(29, nil, node(30, nil, node(31, nil, node(32, nil, node(33, nil, node(34, nil, node(35, nil, node(36, nil, node(37, nil, node(38, nil, node(39, nil, node(40, nil, node(41, nil, node(42, nil, node(43, nil, node(44, nil, node(45, nil, node(46, nil, node(47, nil, node(48, nil, node(49, nil, node(50, nil, node(51, nil, node(52, nil, node(53, nil, node(54, nil, node(55, nil, node(56, nil, node(57, nil, node(58, nil, node(59, nil, node(60, nil, node(61, nil, node(62, nil, node(63, nil, node(64, nil, node(65, nil, node(66, nil, node(67, nil, node(68, nil, node(69, nil, node(70, nil, node(71, nil, node(72, nil, node(73, nil, node(74, nil, node(75, nil, node(76, nil, node(77, nil, node(78, nil, node(79, nil, node(80, nil, node(81, nil, node(82, nil, node(83, nil, node(84, nil, node(85, nil, node(86, nil, node(87, nil, node(88, nil, node(89, nil, node(90, nil, node(91, nil, node(92, nil, node(93, nil, node(94, nil, node(95, nil, node(96, nil, node(97, nil, node(98, nil, node(99, nil, node(100, nil, nil)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))), time((phrase(in_order(T),Zs),eager_chain(Zs,#<))). % 210 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 4100201 Lips) false. ?- T = node(2, nil, node(1, nil, node(3, nil, node(4, nil, node(5, nil, node(6, nil, node(7, nil, node(8, nil, node(9, nil, node(10, nil, node(11, nil, node(12, nil, node(13, nil, node(14, nil, node(15, nil, node(16, nil, node(17, nil, node(18, nil, node(19, nil, node(20, nil, node(21, nil, node(22, nil, node(23, nil, node(24, nil, node(25, nil, node(26, nil, node(27, nil, node(28, nil, node(29, nil, node(30, nil, node(31, nil, node(32, nil, node(33, nil, node(34, nil, node(35, nil, node(36, nil, node(37, nil, node(38, nil, node(39, nil, node(40, nil, node(41, nil, node(42, nil, node(43, nil, node(44, nil, node(45, nil, node(46, nil, node(47, nil, node(48, nil, node(49, nil, node(50, nil, node(51, nil, node(52, nil, node(53, nil, node(54, nil, node(55, nil, node(56, nil, node(57, nil, node(58, nil, node(59, nil, node(60, nil, node(61, nil, node(62, nil, node(63, nil, node(64, nil, node(65, nil, node(66, nil, node(67, nil, node(68, nil, node(69, nil, node(70, nil, node(71, nil, node(72, nil, node(73, nil, node(74, nil, node(75, nil, node(76, nil, node(77, nil, node(78, nil, node(79, nil, node(80, nil, node(81, nil, node(82, nil, node(83, nil, node(84, nil, node(85, nil, node(86, nil, node(87, nil, node(88, nil, node(89, nil, node(90, nil, node(91, nil, node(92, nil, node(93, nil, node(94, nil, node(95, nil, node(96, nil, node(97, nil, node(98, nil, node(99, nil, node(100, nil, nil)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))), time((lazy_chain(Zs,#<),phrase(in_order(T),Zs))). % 52 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 1225664 Lips) false. Laziness wins—at least in above case:) Note, however, that using lazy_chain/2 with dcg can lead to bugs that are hard to find! For a more robust solution, see this alternative answer... For the sake of completeness, here's the source code of eager_chain/2: eager_chain(Zs, R_2) :- ( var(R_2) -> instantiation_error(R_2) ; clpfd:chain_relation(R_2) -> eager_chain_aux(Zs, R_2) ; otherwise -> domain_error(chain_relation, R_2) ). eager_chain_aux([], _). eager_chain_aux([Z0|Zs], R_2) :- eager_chain_aux_(Zs, R_2, Z0). eager_chain_aux_([], _, _). eager_chain_aux_([Z1|Zs], R_2, Z0) :- call(R_2, Z0, Z1), eager_chain_aux_(Zs, R_2, Z1).
In this answer we use clpfd for declarative integer arithmetics. :- use_module(library(clpfd)). :- asserta(clpfd:full_answer). We define the predicates is_bintree/1 and bintree_in/2 like this: is_bintree(T) :- bintree_in(T, _). bintree_in(nil, LB-UB) :- % LB-UB denotes the open interval (LB,UB) LB #< UB. % that is all integers I suchthat LB<I<UB bintree_in(node(Mid,L,R), LB-UB) :- Mid #> LB, Mid #< UB, bintree_in(L, LB-Mid), bintree_in(R, Mid-UB). First, we test1,2 the tree given by the OP: | ?- bintree_in(node(9,node( 3,node(2,nil,nil),node(10,nil,nil)), node(12,node(8,nil,nil),node(15,nil,nil))), _). no Let's fix the tree and check again! | ?- bintree_in(node(9,node( 3,node( 2,nil,nil),node( 8,nil,nil)), node(12,node(10,nil,nil),node(15,nil,nil))), _). _A in inf..1, _B in 16..sup ? ; % (somewhat sloppy) no OK! Next up are a few corner cases: | ?- bintree_in(T, 0-0). % no solution (as expected) no | ?- bintree_in(T, 0-1). % empty tree T = nil ? ; no | ?- bintree_in(T, 0-2). % singleton tree T = nil ? ; T = node(1,nil,nil) ? ; no Note that while is_btree/1 can only "test", bintree_in/2 can both3 "test" and "generate"! So let's generate (all possible) binary trees of a certain size in a small domain: | ?- bintree_in(T, 0-3). % T has less than 3 elements T = nil ? ; T = node(_A,nil,nil), _A in 1..2 ? ; T = node(1,nil,node(2,nil,nil)) ? ; T = node(2,node(1,nil,nil),nil) ? ; no | ?- bintree_in(T, 0-4). % T has less than 4 elements T = nil ? ; T = node(_A,nil,nil), _A in 1..3 ? ; T = node(_A,nil,node(_B,nil,nil)), _A#=<_B+ -1, _B#>=_A+1, _B in 2..3, _A in 1..2 ? ; T = node(1,nil,node(2,nil,node(3,nil,nil))) ? ; T = node(1,nil,node(3,node(2,nil,nil),nil)) ? ; T = node(_A,node(_B,nil,nil),nil), _A#>=_B+1, _A in 2..3, _B in 1..2 ? ; T = node(2,node(1,nil,nil),node(3,nil,nil)) ? ; T = node(3,node(1,nil,node(2,nil,nil)),nil) ? ; T = node(3,node(2,node(1,nil,nil),nil),nil) ? ; no Last, we generate candidate solutions with bintree_in/2 and test these with is_btree/1! is_btree/1 needs sufficient instantiation; labeling/2 provides us with ground terms. | ?- call_time(( UB in 2..12, indomain(UB), bintree_in(T, 0-UB), term_variables(T, Zs), labeling([], Zs), \+ is_btree(T) ; true ), T_ms). T_ms = 6270 ? ; no Footnote 1: The code in this answer runs (at on sicstus-prolog and swi-prolog. Footnote 2: All prolog-toplevel output presented is that of SICStus Prolog 4.3.2 (64-bit). Footnote 3: Not just do both, but (almost) arbitrarily mix generate and test, as it can handle partially instantiated terms.
In a comment to this previous answer, #WillNess suggested adding "early-failure" as a feature. in_order_inf_sup//3 effectively combines in_order//1 and chain/2: :- use_module(library(clpfd)). in_order_inf_sup(nil, P, P) --> []. in_order_inf_sup(node(X,L,R), P0, P) --> in_order_inf_sup(L, P0, P1), [X], { P1 #< X }, in_order_inf_sup(R, X, P). Sample queries (same as in previous answer): ?- phrase(in_order_inf_sup(node(9,node( 3,node(2,nil,nil),node(10,nil,nil)), node(12,node(8,nil,nil),node(15,nil,nil))),_,_), Zs). false. ?- phrase(in_order_inf_sup(node(9,node( 3,node( 2,nil,nil),node( 8,nil,nil)), node(12,node(10,nil,nil),node(15,nil,nil))),_,_), Zs). Zs = [2,3,8,9,10,12,15].
But it should fail. That tree is an invalid BST and your predicate tests for valid BSTs. There is something to be done here though. Right now you perform two passes over a tree - first in is_btree, second, with small/big. The two can be fused into one, but an immediately apparent solution will do exactly what you want, and thus succeed on such invalid BSTs: is_bst(nil). is_bst(node(N,L,R)):- ( L = nil ; L = node(M,LL,LR), M < N, is_bst(L), .... ), ( R = nil ; ...... ). To fix it, we have to return one more result from the tree traversal — that is the tree's rightmost element — and use it in the comparisons for validation. (edit: missed that the leftmost element also needs to be returned)