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.
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).
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
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.
Related
I am developing a path finding algorithm in Prolog, giving all nodes accessible by a path from a starting node. To avoid duplicate paths, visited nodes are kept in a list.
Nodes and neighbors are defined as below:
node(a).
node(b).
node(c).
node(d).
node(e).
edge(a,b).
edge(b,c).
edge(c,d).
edge(b,d).
neighbor(X,Y) :- edge(X,Y).
neighbor(X,Y) :- edge(Y,X).
The original algorithm below works fine:
path2(X,Y) :-
pathHelper(X,Y,[X]).
pathHelper(X,Y,L) :-
neighbor(X,Y),
\+ member(Y,L).
pathHelper(X,Y,H) :-
neighbor(X,Z),
\+ member(Z,H),
pathHelper(Z,Y,[Z|H]).
This works fine
[debug] ?- path2(a,X).
X = b ;
X = c ;
X = d ;
X = d ;
X = c ;
false.
however, when changing the order of the two clauses in the second definition, such as below
pathHelper(X,Y,L) :-
\+ member(Y,L),
neighbor(X,Y).
When trying the same here, swipl returns the following:
[debug] ?- path2(a,X).
false.
The query doesn't work anymore, and only returns false. I have tried to understand this through the tracecommand, but still can't make sense of what exactly is wrong.
In other words, I am failing to understand why the order of neighbor(X,Y)and \+ member(Y,L)is crucial here. It makes sense to have neighbor(X,Y) first in terms of efficiency, but not in terms of correctness to me.
You are now encountering the not so clean-cut borders of pure Prolog and its illogical surroundings. Welcome to the real world.
Or rather, not welcome! Instead, let's try to improve your definition. The key problem is
\+ member(Y, [a]), Y = b.
which fails while
Y = b, \+ member(Y,[a]).
succeeds. There is no logic to justify this. It's just the operational mechanism of Prolog's built-in (\+)/1.
Happily, we can improve upon this. Enter non_member/2.
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
Now,
?- non_member(Y, [a]).
dif(Y,a).
Mark this answer, it says: Yes, Y is not an element of [a], provided Y is different from a. Think of the many solutions this answer includes, like Y = 42, or Y = b and infinitely many more such solutions that are not a. Infinitely many solutions captured in nine characters!
Now, both non_member(Y, [a]), Y = b and Y = b, non_member(Y, [a]) succeed. So exchanging them has only influence on runtime and space consumption. If we are at it, note that you check for non-memberness in two clauses. You can factor this out. For a generic solution to this, see closure/3. With it, you simply say: closure(neighbor, A,B).
Also consider the case where you have only edge(a,a). Your definition fails here for path2(a,X). But shouldn't this rather succeed?
And the name path2/2 is not that fitting, rather reserve this word for an actual path.
The doubt you have is related to how prolog handle negation. Prolog uses negation as failure. This means that, if prolog has to negate a goal g (indicate it with not(g)), it tries to prove g by executing it and then, if the g fails, not(g) (or \+ g, i.e. the negation of g) succeeds and viceversa.
Keep in mind also that, after the execution of not(g), if the goal has variables, they will not be instantiated. This because prolog should instantiate the variables with all the terms that makes g fail, and this is likely an infinite set (for example for a list, not(member(A,[a]) should instantiate the variable A with all the elements that are not in the list).
Let's see an example. Consider this simple program:
test:-
L = [a,b,c],
\+member(A,L),
writeln(A).
and run it with ?- trace, test. First of all you get a Singleton variable in \+: A warning for the reason i explained before, but let's ignore it and see what happens.
Call:test
Call:_5204=[a, b]
Exit:[a, b]=[a, b]
Call:lists:member(_5204, [a, b])
Exit:lists:member(a, [a, b]) % <-----
Fail:test
false
You see at the highlighted line that the variable A is instantiated to a and so member/2 succeeds and so \+ member(A,L) is false.
So, in your code, if you write pathHelper(X,Y,L) :- \+ member(Y,L), neighbor(X,Y)., this clause will always fail because Y is not sufficiently instantiated. If you swap the two terms, Y will be ground and so member/2 can fail (and \+member succeeds).
we have a list of list think an example ?- solve([[40,A,B],[30,B],[60,A,B,C]]),label([A,B,C]). will succeed with replacing B=30,A=10 and C=20.
The constraint with this example is A+B=40, A+B+C=60 and generally every variable are in between 0 and 100. Every list must begin with a constant and it includes at least one variable.
:- use_module(library(clpfd)).
sum([],0). % if the list is empty.
sum([X|XS],Z) :-
sum(XS,Z1),
X in 0..100,
Z #= X+Z1.
solveOne([Const|Var]) :-
sum(Var,Const).
solve([]). % if the list of list is also empty
solve([First|Others]) :-
solveOne(First),
solve(Others).
I am a bit skeptic the idea of base case,facts. Because every list must include at list one variable according to constraints, on the other hand we think about the "empty list" situation.?
First, the obvious problem: you define both a solve/2 and a solve/1 predicate (solve([],0)). The ",0" is probably unwanted.
Apart from that, if you have only a constant, like [X], then solveOne succeeds only if X is zero; otherwise, it fails according to sum([],0). So, in a sense, you indirectly check that you can have at least one variable if you assume your sum is always strictly positive.
In order to explicitely check that there is effectively at least one variable, then you can modify solveOne as follows:
solveOne([Const,V1|Vars]) :-
sum([V1|Vars], Const).
#coredump answer should put you on right track. If you are interested in writing lean code, consider this more succint definition (tested in SWI-Prolog)
solve(L) :- maplist(solveOne, L).
solveOne([C|Vs]) :- Vs ins 0..100, sum(Vs, #=, C).
?- solve([[40,A,B],[30,B],[60,A,B,C]]).
A = 10,
B = 30,
C = 20.
I've got a rule in my Prolog program called blanket(X,Y) which checks if X is in a certain kind of set of Y which consists of:
Y's parents
Y's children
Y's coparents
I've defined it as follows :
blanket(Y,X) :- different(Y,X),parent(Y,X);child(Y,X);coparent(Y,X).
However, this doesn't work as I expect. It correctly identifies X's parents, children, and coparents (if any) but it lists itself as both a parent and a coparent, which I do not want. Is it possible to set some kind of order, so that the different(Y,X) evaluates first and independently? I tried something like : different(Y,X),(parent(Y,X);child(Y,X);coparent(Y,X))., of course, but that yields a syntax error as I"m still quite unfamiliar with the language.
Any suggestions would be greatly appreciated.
EDIT: Here are the child, different, and coparent relations:
child(X,Y) :- parent(Y,X).
different(X,Y) :- not(X == Y).
coparent(Y,X) :- parent(Y,Z),parent(X,Z).
For completeness.
blanket(Y,X) :- different(Y,X), parent(Y,X).
blanket(Y,X) :- different(Y,X), child(Y,X).
blanket(Y,X) :- different(Y,X), coparent(Y,X).
The problen is your definition of coparent. It is the statement that allows return itself as a valid result.
I suggest you redefine it, by example as:
coparent(Y,X) :- parent(Y,Z),parent(X,Z), X \= Y.
in this way, you can simply:
blanket(Y,X) :-parent(Y,X);child(Y,X);coparent(Y,X).
Of course, you can keep definition of "coparent" and only modify blanket as:
blanket(Y,X) :-parent(Y,X);child(Y,X);(coparent(Y,X), X\=Y).
I have this simple program that checks if an X element belongs to a list:
member2(X, [X|_]).
member2(X,[_|T]):- member2(X,T).
I'm trying to write it in an extended form (because in the previous way the behavior is not so clear). So I have write it in the following way:
member2(X, [X|_]).
member2(X,Y):- Y = [_|T],
member2(X,T).
So the meaning is more clear:
I have one fact that represent the base case (the X element belongs to the list if it is in the head of the list).
The rule say that I have to prove two things:
1) Y = [_|T]. This is true because the anonymous variable _ unifies with anything.
2) It recursively search the element X in the tail list.
Ok, I think my reasoning is correct but this second version of the program don't work! I think that maybe the problem could be in the Y = [_|T] section
your program is fine, in both forms. Here yet another way to (re)write it
member2(X, [Y|Ys]) :-
X = Y ; member2(X, Ys).
I guess the textbook example of checking for a member is:
member_check(X, [X|Tail]). % or [X|_] to avoid the warning
member_check(X, [Y|Tail]) :- X \= Y, member_check(X, Tail).
which would probably be clearer than your second attempt?
I am trying to write a Prolog program that will print out the male successors of British Royalty in order. My attempt so far:
son(elizabeth, charles).
son(charles, william).
son(charles, henry).
son(elizabeth, andrew).
son(elizabeth, edward).
son(edward, severn).
successor(X, Y) :- son(X, Y).
successor(X, Y) :- son(X, C), successor(C, Y).
The successor function doesn't quite do what I want: the current output is this:
successor(elizabeth, Y).
Y = charles ;
Y = andrew ;
Y = edward ;
Y = william ;
Y = henry ;
Y = severn ;
false.
The first rule makes all three immediate children print out, then the second rule prints out all the descendants. But the descendants of the first child should come before the second immediate child, like this:
successor(elizabeth, Y).
Y = charles ;
Y = william ; % william and henry should come before andrew
Y = henry ;
Y = andrew ;
Y = edward ;
Y = severn ;
false.
This is my first Prolog program, and I am at a loss for how to express the right relationship. Can anyone give me an idea or pointers to resources that would be helpful to me?
As rati noted above, Prolog queries are resolved by choosing a rule, recursively evaluating it using depth-first search, then choosing the next rule and repeating the process. However, the particular rules you're starting with actually result in a breadth-first search of the family tree, which, as you noted, does not give output that matches the actual line of succession. Instead, you want to do a depth-first traversal of the royal family tree. This version gives the result you're looking for:
successor(X, Y) :- son(X, Z), (Y = Z; successor(Z, Y)).
Using this rule, Prolog resolves the query successor(X, Y) roughly as follows:
For each Z who is a son of X:
Bind Y to Z, giving Z as a solution.
The ; operator functions as a logical OR, so now Y is unbound and successor/2 is called recursively to get the successors who are sons of Z.
And yes, please do try to get a copy of the Art of Prolog. It's not the easiest programming book to read, but I found it extremely helpful in my (ongoing) attempt to understand logic programming. There seem to have been some cheap hardcover copies of the 1994 edition floating around eBay lately.
You said:
The first rule makes all three immediate children print out, then the second rule prints out all the descendants.
For any given predicate (such as successor/2), PROLOG will generally evaluate all the possible solutions for the 1st clause, then the next, etc. up to the last clause, in that order. Therefore, PROLOG will behave exactly as you've suggested above - solutions to immediate children will be found first, as the first clause of successor/2 does just that, and the second clause finds the descendants. If you were after a different order, try re-ordering the clauses (i.e.);
successor(X, Y) :- son(X, C), successor(C, Y).
successor(X, Y) :- son(X, Y).
This will cause PROLOG to evaluate to:
?- successor(elizabeth, Y).
Y = william ;
Y = henry ;
Y = severn ;
Y = charles ;
Y = andrew ;
Y = edward.
i.e., all descentants before immediate children.
The ordering you've suggested as wanting, however, can't be achieved through a simple reordering of these subgoals. Instead, consider the various tree traversal methods; i.e., in-order, pre-order and post-order. You could write a (simple) program which is capable of walking the tree structure in various different ways, instead of the default evaluation order for PROLOG. For example, consider the following new definition of successor/2:
successor(Parent, [Son|SonDescendents]) :-
son(Parent, Son),
successor(Son, SonDescendents).
This clause seeks to depth-first populate a list of children under a son, and will backtrack to find all solutions.
successor(NonParent, []) :-
\+ son(NonParent, _).
This next clause takes care of the base-case whereby the given individual does not have any sons, therefore no descendants enter the result list (empty).
Evaluating this gives:
?- successor(elizabeth, S).
S = [charles, william] ;
S = [charles, henry] ;
S = [andrew] ;
S = [edward, severn] ;
false.
ps. I highly recommend the following texts for learning PROLOG:
The Art of Prolog, by Leon Sterling and Ehud Shapiro
The Craft of Prolog, by Richard O'Keefe
Programming in Prolog, by Clocksin and Mellish
Your rule set looks good to me, it's giving you the right results, it's just printing them as it deduces them, which makes the order seem incorrect. Work through the results on paper and you will likely get a similar result.