I am writing a Souffle query that operates on family relationships:
.decl Parent(x: symbol, y: symbol)
.input Parent
.decl Descendant(x: symbol, y: symbol)
.output Descendant
.printsize Descendant
Descendant(x, y) :- Parent(x, y).
Descendant(x, y) :- Parent(z, y), Descendant(x, z).
.decl Qslow(x: symbol)
.output Qslow
.printsize Qslow
Qslow(x) :- Descendant("Alice", x).
I have some facts in a TSV file Parent.facts:
"Alice" "john"
"john" "mary"
"mary" "elizabeth"
"Bob" "charles"
And running souffle seems to generate the right output for the Descendant relation (three descendants for "Alice"):
hickory% souffle -F. -D. descendants.dl
Descendant 7
Qslow 0
hickory%
However, Qslow produces zero results. I would instead expect three results. This makes me suspicious of the definition of Qslow, but I am not sure what the issue is. Am I doing something weird with symbol syntax? It looks like I am using the same syntax as in the docs.
If I try adding another clause to the conjunction, I still get zero results:
Qslow(x) :- Descendant(y, x), y="Alice".
Related
Here's the code in prolog:
son(blake, john).
son(blake, katey).
son(toney, john).
son(toney, katey).
son(flory, john).
son(flory, katey).
son(charlie, stark).
son(charlie, shrek).
son(valenti, stark).
son(valenti, shrek).
age(blake, 13).
age(toney, 15).
age(flory, 19).
age(charlie, 48).
age(valenti, 49).
The definition of predicate and rules are:
son(X, Y) means X is the son of Y
age(M, N) means age of M is N
siblings(P, Q) means P and Q are siblings
My question is how to make a rule, let it be named oldestSon(X) that true if X is the oldestSon of a family?
When the query is oldestSon(flory) and oldestSon(valenti) it returns true or yes, and when the query is oldest(toney) it returns false or no.
I give it a try by writing these lines of code:
oldestSon(X) :-
son(X, _),
son(Y, _),
siblings(X, Y),
age(X, ageX),
age(Y, ageY),
ageX >= ageY.
But, when I try to input a query, in any of the case, when the query is oldestSon(blake). It returns like this:
false ? ;
false ? ;
false ? ;
...
How to make it only make only one output without using any external library or making another rule?
Your code is not working because:
it doesn't correctly describe the conditions for someone to be the oldest son in a family, and
it uses constants (ageX and ageY) where it should be using variables (AgeX and AgeY).
Assuming that "the oldest son in a family is the one who has no older sibling", you can code:
oldestSon(X) :-
age(X, AgeX),
not( ( siblings(X, Y),
age(Y, AgeY),
AgeY > AgeX ) ).
I am also assuming that the predicate siblings/2 is already defined as:
siblings(X, Y) :-
son(X, Z),
son(Y, Z),
X \= Y.
Hi I am working on a PROLOG family tree question, and this is what I have so far:
/*1. Write Prolog clauses to express the following three relationships,
* given the parent/2 relationship: grandparent/2, sibling/2, cousin/2.*/
% clauses
parent(jill, amy).
parent(jill, tim).
parent(jill, john).
parent(amy, grace).
parent(amy, anna).
parent(tim, sam).
parent(tim, joel).
parent(tim, ben).
% rules
grandparent(X,Y) :-
parent(Z,Y),
parent(X,Z).
sibling(X, Y) :-
parent(Z, X),
parent(Z, Y).
cousin(X,Y) :-
parent(P, X),
parent(S, Y),
sibling(P, S).
When I put:
?- sibling(X, tim).
the output gives:
X = amy
but both john and amy are tim's sibling. The same problem happens with:
?- cousin(ben, X).
which gives:
X = grace
when both grace and anna are ben's cousins.
What changes do I need to make in order for the code to output all of tim's siblings and ben's cousins?
Thanks. :)
First of all, you've got a little bug over there.
You should correct the sibling rule - just a small hint here, try to use the rule as so
sibling(grace,grace)
and back to your issue, after you're getting first response click the ; or any of these ; n r space TAB keys, as the result you see is the first correct response. If you want to see the next correct result you need to use one of the keys above.
You can also try to use findall predicate to see all the results in the list
?- findall(X, cousin(grace, X),Z).
Z = [sam, joel, ben].
I have the following prolog predicate:
processWords([hello, my, name, is, Simon], Result).
I need to know how I could get:
Result = [bye, my, name, is, Ben]
How would I recurse through the list and return a string that replaces "hello" with "bye" and "Simon" with "Ben", using Prolog?
Any help is greatly appreciated, thanks!
First of all, this cannot be done, since "Simon" and "Ben" in your example are variables. But supposing you are fine with "simon" and "ben", here is an answer:
processWords([], []).
processWords([H|T], [H2|T2]) :-
translate(H, H2),
processWords(T, T2).
translate(hello, bye):-!.
translate(simon, ben):-!.
translate(X, X). % catch-all clause for all words not to be translated
Alternatively, you could use maplist/3:
processWords(L,L2):-maplist(translate, L, L2).
translate(hello, bye):- !.
translate(simon, ben):- !.
translate(X, X). % catch-all clause for all words not to be translated
I tried to run this code:
eq(mul(a,b),mul(c,b)).
eq(X,Y) :- eq(mul(X,Z),mul(Y,Z))
with the query: eq (X, Y)
I expected the results:
X=mul(a,b),Y=(mul(c,b)) and X=a,Y=c
But I just got the first one.
I think you want:
eq(mul(a, b), mul(c, b)).
equal(X,Y) :-
eq(mul(X, Z), mul(Y, Z)).
Note that I have used different predicate names, to prevent a common mistake of infinite recursion/looping if a predicate (e.g. "eq") is calling itself.
Result in swi-prolog:
?- equal(X, Y).
X = a,
Y = c.
This rule would be wrong:
eq(X,Y) :- eq(mul(X,Z),mul(Y,Z)).
because X cannot be simultaneously mul(something) and part of the same something inside the mul(). Also, it falls into the trap of infinite recursion/looping.
I have a function that allows the user to enter a single quoted string (A), then searches a list of sublists (X) for the string and returns the sublist that contains the string:
process(6, X) :-
nl, write('\tEnter student name or ID: '),
read(A),
% FIRST WE CHECK FOR A in the ID SLOT
member( [A,B,C] , X)
% IF TRUE, DISPLAY DATA THEN PASS X back to menu
-> write('\tID="'), write(A), write('", Name="'), write(B), write('", Grade='), write(C),nl,nl, menu(X)
% ELSE, WE CHECK FOR A in the NAME SLOT
; write(A), write(' not found in ID slot'), nl, checkNAME(A, X).
checkNAME(A,X) :-
member( [B,A,C] , X )
% IF TRUE (A in NAME SLOT)
-> blah blah
% ELSE
; blah blah
My issue is when i use variable A in the ELSE clause, i get junk data "L1_233" or w/e and this prevents the ELSE clause from working properly. I tried to create a copy of A and use it in the ELSE clause, but all it does is create a copy of junk data. Why does variable A work in the IF CLAUSE but not the ELSE? thanks
You're having an operator precedence issue.
In Prolog, "AND" (the comma) has a higher precedence than ->. So the nl, write(...), read(A) is all considered part of the first half (antecedent) of ->. If the antecedent fails, then Prolog will backtrack to a point before read(A) and A won't be instantiated if the "else" path is taken. You need to parenthesize:
process(6, X) :-
nl, write('\tEnter student name or ID: '),
read(A),
% FIRST WE CHECK FOR A in the ID SLOT
( member( [A,B,C] , X)
% IF TRUE, DISPLAY DATA THEN PASS X back to menu
-> write('\tID="'), write(A),
write('", Name="'), write(B),
write('", Grade='), write(C),
nl,nl, menu(X)
% ELSE, WE CHECK FOR A in the NAME SLOT
; write(A), write(' not found in ID slot'),
nl, checkNAME(A, X)
).
"AND" (comma) is also higher precedence than "OR" (semicolon) so parenthetical grouping isn't needed for the consequent and else AND sequences.