Setting some order for prolog expressions - prolog

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).

Related

Three Prolog questions include grandparent

This program will be tested using SWI Prolog.
Family.pl contains facts about family members, who is married to whom, sorts of things.
Rules must be added at the bottom and submit the modified file.
Write a motherInLaw(X,Y) predicate that means X is Y’s mother-in-law.
Write a grandParent(X,Y) predicate that means X is Y's Grandparent.
Write a grandMother(X,Y) predicate that means X is Y's Grandmother.
Thank you guys!
here are my own answers, could you please take a look and tell me if they are correct? Thanks
motherInLaw(X, Y) : mother(X, Z),couple(Z, Y)
grandParent(X, Y) : parent(X, Z),parent(Z, Y)
grandMother(Z, Y) : mother(X, Z),parent(Z, Y)
You need to write :- instead of : and . at the end of each clause
The grandmother/2 predicate looks very strange. Actually I think the head of the clause should be grandMother(X,Y).

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.
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.

CLP Prolog - Logic Programming

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.

Prolog notBetween function

I need some help here with Prolog.
So I have this function between that evaluates if an element is between other two.
What I need now is a function that evaluates if a member is not between other two, even if it is the same as one of them.
I tried it :
notBetween(X,Y,Z,List):-right(X,Y,List),right(Z,Y,List). // right means Z is right to Y and left the same for the left
notBetween(X,Y,Z,List):-left(X,Y,List),left(Z,Y,List).
notBetween(X,Y,Z,List):-Y is Z;Y is X.
I am starting with Prolog so maybe it is not even close to work, so I would appreciate some help!
When it come to negation, Prolog behaviour must be handled more carefully, because negation is 'embedded' in the proof engine (see SLD resolution to know a little more about abstract Prolog). In your case, you are listing 3 alternatives, then if one will not be true, Prolog will try the next. It's the opposite of what you need.
There is an operator (\+)/2, read not. The name has been chosen 'on purpose' different than not, to remember us that it's a bit different from the not we use so easily during speaking.
But in this case it will do the trick:
notBeetwen(X,Y,Z,List) :- \+ between(X,Y,Z,List).
Of course, to a Prolog programmer, will be clearer the direct use of \+, instead of a predicate that 'hides' it - and requires inspection.
A possibile definition of between/4 with basic lists builtins
between(X,Y,Z,List) :- append(_, [X,Y,Z|_], List) ; append(_, [Z,Y,X|_], List).
EDIT: a simpler, constructive definition (minimal?) could be:
notBetween(X,Y,Z, List) :-
nth1(A, List, X),
nth1(B, List, Y),
nth1(C, List, Z),
( B < A, B < C ; B > A, B > C ), !.
EDIT: (==)/2 works with lists, without side effects (it doesn't instance variables). Example
1 ?- [1,2,3] == [1,2,3].
true.
2 ?- [1,2,X] == [1,2,X].
true.
3 ?- [1,2,Y] == [1,2,X].
false.

How to say if an element belongs to a list in Prolog?

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?

Resources