Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make this predicate enumerate trees fairly?

Tags:

prolog

We represent the empty tree by the atom 'nil' and the non-empty tree by the term t(X,L,R), where X denotes the root node and L and R denote the left and right subtree, respectively.

As such, a predicate that tests if a term represents a binary tree is as follows:

is_tree(nil).
is_tree(t(_, Left, Right)) :-
    is_tree(Left), is_tree(Right).

And it works great, for example:

% ?- is_tree(nil).
%@    true.
% ?- is_tree(t(a, nil, nil)).
%@    true.
% ?- is_tree(t(a, t(b, nil, nil), nil)).
%@    true.

However, when posed with a general query, it only seems to create right side nodes:

% ?- is_tree(X).
%@    X = nil
%@ ;  X = t(_A,nil,nil)
%@ ;  X = t(_A,nil,t(_B,nil,nil))
%@ ;  ... .

Now, if X was a list, I could have just prepended the query with length(X, _) to get iterative deepening. However, seeing as the argument is not a list, I am at a loss on how to get a fair enumeration.

I tried to make a predicate that calculates the depth of the tree:

tree_depth(nil, 0).
tree_depth(t(_, Left, Right), Depth) :-
    tree_depth(Left, D0), tree_depth(Right, D1),
    Depth #= max(D0, D1) + 1. 

And then tried to limit it with a constraint, but all I got was a nonterminating query, which, upon inspection, just keeps on generating deeper and deeper trees with only right hand subtrees:

% ?- Y #< 3, tree_depth(X, Y), is_tree(X).
%@    Y = 0, X = nil
%@ ;  Y = 1, X = t(_A,nil,nil)
%@ ;  Y = 2, X = t(_A,nil,t(_B,nil,nil))
%@ ;  *hangs*

At this point I am unsure what should I do, nor what am I doing wrong. I am using scryer prolog if it matters.

like image 997
Dizzar Avatar asked Oct 27 '25 15:10

Dizzar


1 Answers

The problem is the left recursion before the constraint. A predicate is left recursive and not tail recursive, if the first goal in a clause is the recursive call:

p :- p, ...

If you can stop the recursion before the left recursive call, you could be more lucky. The Depth parameter will give the max depth, and it will generate also smaller trees:

tree_enum(nil, _).
tree_enum(t(_,Left,Right), Depth) :-
   Depth > 0,    %%% stop condition
   Depth2 is Depth-1,
   tree_enum(Left, Depth2),
   tree_enum(Right, Depth2).

Here is an example run:

?- tree_enum(X, 2).
X = nil ;
X = t(_, nil, nil) ;
X = t(_, nil, t(_, nil, nil)) ;
X = t(_, t(_, nil, nil), nil) ;
X = t(_, t(_, nil, nil), t(_, nil, nil)) ;
false.
like image 92
Gottlob Frege Avatar answered Oct 29 '25 15:10

Gottlob Frege



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!