Gavin
Gavin

Reputation: 2824

Node has no descendant

I have a rule

% X is descendant of Y
descendant(X,Y) :-

I am trying to write a rule that will find out which node has no descendant. How do I tell prolog that I want to find every X that fails descendant(X,_).

I tried this it doesn't give the correct result.

nodescendants(X) :- \+(descendant(X, _)).

Edited to update my question. Actually what I am finding is more strict.

Given the following facts and rules.

cyborg(greatgrandparent).
cyborg(grandparent).

female(parent).

male(child).

cyborg(child2).

female(jr_child).

parent(greatgrandparent, grandparent).
parent(grandparent, parent).
parent(parent, child).
parent(parent, child2).
parent(child, jr_child).

% X is descendant of Y
descendant(X,Y) :-

% C is cyborg descendant of Y
cyborg_descendant(C,Y) :-

is_human_or_cyborg(X) :-
      human(X)
   ;  cyborg(X).

has_no_cyborg_descendants(X) :-
   is_human_or_cyborg(X),
   \+(cyborg_descendant(_, X)).

When I did a run to find all person(cyborg+ all humans) that do not have cyborg descendants, 'grandparent' got flagged as true, which should not be the case. As grandparent -> parent -> child2 which is a cyborg.

?- has_no_cyborg_descendants(X).
X = child ;
X = jr_child ;
X = grandparent ;
X = child2.

Upvotes: 0

Views: 444

Answers (3)

lurker
lurker

Reputation: 58244

You are saying that grandparent should have a cyborg descendant due to the descendancy: grandparent -> parent -> child2. However, the following query fails:

cyborg_descendant(child2, grandparent).

In fact, this query also fails:

cyborg_descendant(_, grandparent).

So clearly there's something wrong with the logic in cyborg_descendant/2. This is resulting in has_no_cyborg_descendants(grandparent) succeeding.

Additionally, you have an issue with splitting up your like facts. Prolog expects like facts (facts with the same functor name) to be grouped together, or some may be ignored. So the following:

cyborg(greatgrandparent).
cyborg(grandparent).

female(parent).

male(child).

cyborg(child2).

female(jr_child).

Can result in female(jr_child) and cyborg(child2) being ignored. The Prolog interpreter warns about this. You should rewrite this as:

cyborg(greatgrandparent).
cyborg(grandparent).
cyborg(child2).

female(parent).
female(jr_child).

male(child).

Upvotes: 2

tas
tas

Reputation: 8140

The way you wrote nondescendant/1 you are not describing anything to match only something not to match. If you want concrete answers specify what you are looking for. For example: if you had a predicate person/1 that describes all the known people and you want to know who of them is not a descendant, you could ask for a person that is not a descendant:

person(a).
person(b).
person(c).
person(d).

descendant(a,b).
descendant(b,c).
descendant(c,d).

nondescendant(X) :-
    person(X),
    \+(descendant(X,_)).


?- nondescendant(X).
X = d

Or stick with your definition of nondescendant/1 and use it in conjunction with another goal:

?- person(X), nondescendant(X).
X = d

Upvotes: 2

SQB
SQB

Reputation: 4078

Actually, your nodescendants/1 predicate works fine, when used for a specific node.

If you want to find all X, use findall/3. But the interpreter has to know which nodes to consider, so you need to account for that as well. You can't expect the interpreter to figure out all nodes by itself.

Upvotes: 0

Related Questions