How to model the "sister" relationship so that it implies the gender - prolog

How can you define mother/father/sister/brother relationships such that asserting sister(bart, maggie) makes ?- female(maggie) evaluate as true?
I'm working on a toy family relation problem. This is what I have:
parent(bart, homer).
parent(bart, marge).
parent(lisa, homer).
parent(lisa, marge).
male(homer).
male(bart).
female(marge).
female(lisa).
mother(X,Y) :- female(Y), parent(X,Y).
father(X,Y) :- male(Y), parent(X,Y).
sister(X,Y) :- female(Y), father(X,F), father(Y,F), mother(X,M), mother(Y,M), X/=Y.
I'd like to be able to do the following:
sister(bart, maggie).
?- female(maggie).
% expect yes
i.e. support the "common sense" definition where if you assert that maggie is bart's sister, we know that maggie is female, while still obtaining sister(bart, lisa) being true based on the parent/gender assertions I already have.

As it is, your system expects male/female and parent to be a fact and derives father/mother/brother/sister through rules
You could do this:
% X is female if it is somebody's sister.
female(X) :- sister(_,X).
But combined with the other rule, it probably won't terminate (X is female if she is sb's sister, she is sb.'s sister if she is female...)
You could set different facts and rules to reverse this way of doing it, e.g. decide that basic facts are sister, mother, son, daughter... But you need to decide what forms elementary information in your database, and what forms derived information. If you want anything to be derived from anything, while staying with simple rules, you quickly end up with a system that doesn't terminate, exploring more and more ways to derive information that is already known.
If you want to have a richer set of inference rules (e.g. if X implies Y and Y is false, then X is false), and make sure your process terminates, doesn't give you the result multiple times, etc, you need to write (or borrow) your own rule interpreter, that is, your own inference engine.

Common sense reasoning is in general way too complex to implement for any general purpose programming language. For this very limited domain, we can prototype in SWI-Prolog a simple minded metainterpreter that generalize the goal selection from rules body, and avoids loops by means of tabling:
:- autoload(library(tabling)).
:- table solve/1, rule/2.
solve(F) :-
rule(F,[]).
solve(H) :-
rule(H,B),
solve_b(B).
% allowed builtins
solve(X\=Y) :- X\=Y.
solve_b([]).
solve_b(B) :-
select(G,B,R),
solve(G),
solve_b(R).
rule(parent(bart, homer), []).
rule(parent(bart, marge), []).
rule(parent(lisa, homer), []).
rule(parent(lisa, marge), []).
rule(male(homer), []).
rule(male(bart), []).
rule(male(M), [father(_,M)]).
rule(male(M), [brother(_,M)]).
rule(female(marge), []).
rule(female(lisa), []).
rule(female(F), [mother(_,F)]).
rule(female(F), [sister(_,F)]).
rule(mother(X,Y), [female(Y), parent(X,Y)]).
rule(father(X,Y), [male(Y), parent(X,Y)]).
rule(sister(X,Y), [
female(Y),
sibling(X,Y)
]).
rule(brother(X,Y), [
male(Y),
sibling(X,Y)
]).
rule(sibling(X,Y), [
father(X,F),
father(Y,F),
mother(X,M),
mother(Y,M),
X\=Y
]).
rule(sister(bart,maggie), []).

Related

negation \+ and vanilla meta-interpreter

The following is the classic "textbook" vanilla meta-interpreter for prolog.
% simplest meta-interpreter
solve(true) :- !.
solve((A,B)):- !, solve(A), solve(B).
solve(A) :- clause(A,B), solve(B).
The following is simple program which establishes facts two relations which are "positive" and one relation which makes use of negation by failure \+.
% fruit
fruit(apple).
fruit(orange).
fruit(banana).
% colour
yellow(banana).
% Mary likes all fruit
likes(mary, X) :- fruit(X).
% James likes all fruit, as long as it is yellow
likes(james, X) :- fruit(X), yellow(X).
% Sally likes all fruit, except yellow fruit
likes(sally, X) :- fruit(X), \+ (yellow(X)).
The meta-interpeter can handle goals related to the first two relations ?-solve(likes(mary,X)) and ?- solve(likes(james,X)_.
However it fails with a goal related to the third relation ?- solve(likes(sally,X). The swi-prolog reports a stack limit being reached before the program crashes.
Question 1: What is causing the meta-interpreter to fail? Can it be easily adjusted to cope with the \+ negation? Is this related to the sometimes discussed issue of built-ins not being executed by the vanilla meta-interpreter?
Question 2: Where can I read about the need for those cuts in the vanilla meta-interpreter?
Tracing suggests the goal is being grown endlessly:
clause(\+call(call(call(call(yellow(apple))))),_5488)
Exit:clause(\+call(call(call(call(yellow(apple))))),\+call(call(call(call(call(yellow(apple)))))))
Call:solve(\+call(call(call(call(call(yellow(apple)))))))
Call:clause(\+call(call(call(call(call(yellow(apple)))))),_5508)
Exit:clause(\+call(call(call(call(call(yellow(apple)))))),\+call(call(call(call(call(call(yellow(apple))))))))
Call:solve(\+call(call(call(call(call(call(yellow(apple))))))))
Change solve(A) into:
solve(Goal) :-
writeln(Goal),
sleep(1),
clause(Goal, Body),
solve(Body).
... and we see:
?- solve_mi(likes(sally,X)).
likes(sally,_8636)
fruit(_8636)
\+yellow(apple)
\+call(yellow(apple))
\+call(call(yellow(apple)))
\+call(call(call(yellow(apple))))
...
clause/2 determines the body of \+yellow(apple) to be \+call(yellow(apple)), which is not a simplification.
Can use instead:
solve_mi(true) :-
!.
solve_mi((Goal1, Goal2)):-
!,
solve_mi(Goal1),
solve_mi(Goal2).
solve_mi(\+ Goal) :-
!,
\+ solve_mi(Goal).
solve_mi(Goal) :-
clause(Goal, Body),
solve_mi(Body).
Result in swi-prolog:
?- solve_mi(likes(sally,X)).
X = apple ;
X = orange ;
false.
I'm using solve_mi because solve conflicts with e.g. clpBNR, and I'm not using variable names A and B because they convey no meaning.
For understanding the cuts, I'd recommend gtrace, to see the unwanted unification with other goals that would otherwise take place.

How do I print dynamic/1 in Prolog

I want to print these all names under each dynamic/1. For example I want to print all names of male under one query for print all males in Prolog.
The easiest way to do this in swi-prolog (and also in gnu-prolog) is to use predicate listing/1:
?- listing(male/1).
:- dynamic male/1.
male(saad).
male(sohaib).
male(salman).
...
true.
If you want more control over display formatting, you can define your own predicate as:
list_facts(Name/Arity) :-
functor(Head, Name, Arity),
forall( clause(Head, true),
format('~w.\n', [Head]) ). % Adjust formatting here!
Example:
?- list_facts(female/1).
female(rida).
female(florida).
female(yasmeen).
...
true.
If you want to show just the names, try:
?- forall(female(Name), format('~w\n', [Name])).
rida
florida
yasmeen
...
true.
REMARK The swi-prolog built-in predicate forall/2is defined as:
forall(Cond, Action) :-
\+ (Cond, \+ Action).
The supplied code works with SWI-Prolog, don't know if this works with other Prolog systems but the basis of the code should be portable.
This is from actual code I use daily so it more production quality code than simple answer code but the basis is to use functor/3 to get a head and then use the head in forall/2 to get the rules (rule/2) and format/3 to output each rule. Normally a rule is a head and body but since this is outputting facts only the heads are output. To convert the rules to individual values =../2 is used. This uses library(options). This also uses current_predicate/1 to check if the predicate exists to avoid an exception if it does not. functor/3 could probably be used but somewhere I recall a corner case that it did now work. The rest should not need explaining.
I only entered 3 of the male facts. Would have used all of them if they were typed as text into the question as then they could have been easily copied.
If the facts are in a different module remember to change the name of the module when calling list_facts/N.
:- module(examples,
[
list_facts/1,
list_facts/2,
list_facts/3
]).
:- dynamic female/1.
:- dynamic male/1.
male(saad).
male(sohaib).
male(salman).
list_facts(Module:Name/Arity) :-
list_facts(user_output,Module:Name/Arity,[]).
list_facts(Output_stream,Module:Name/Arity) :-
list_facts(Output_stream,Module:Name/Arity,[]).
list_facts(Output_stream,Module:Name/Arity,Options) :-
(
current_predicate(Module:Name/Arity)
->
(
option(left_margin_size(Left_margin_size),Options)
->
atomic_list_concat(['~|~',Left_margin_size,'+~|~w'],Format)
;
Format = '~w'
),
(
option(title(Title),Options)
->
format(Output_stream,Format,[Title]),
format(Output_stream,'~n',[])
;
true
),
functor(Head,Name,Arity),
forall(
rule(Module:Head,Rule),
list_fact(Output_stream,Format,Rule)
)
;
format(Output_stream,'No facts found: ~w:~w/~w.~n',[Module,Name,Arity])
).
list_fact(Output_stream,Format,Fact) :-
Fact =.. Fact_values,
list_values(Output_stream,Format,false,Fact_values).
% Recursive case - functor name
list_values(Output_stream,Format,false,[_Value|Values]) :-
!,
list_values(Output_stream,Format,true,Values).
% Recursive case - fact arguments
list_values(Output_stream,Format,true,[Value|Values]) :-
!,
format(Output_stream,Format,[Value]),
list_values(Output_stream,Format,true,Values).
% Base case
list_values(Output_stream,_Format,_Functor_done,[]) :-
format(Output_stream,'~n',[]).
Example usage.
?- working_directory(_,'C:/Users/Groot').
true.
?- [examples].
true.
?- list_facts(examples:male/1).
saad
sohaib
salman
true.
?- list_facts(user_output,examples:male/1,[left_margin_size(3),title('male/1')]).
male/1
saad
sohaib
salman
true.

I have defined multiple predicates that seem to share a common form

All of these predicates are defined in pretty much the same way. The base case is defined for the empty list. For non-empty lists we unify in the head of the clause when a certain predicate holds, but do not unify if that predicate does not hold. These predicates look too similar for me to think it is a coincidence. Is there a name for this, or a defined abstraction?
intersect([],_,[]).
intersect(_,[],[]).
intersect([X|Xs],Ys,[X|Acc]) :-
member(X,Ys),
intersect(Xs,Ys,Acc).
intersect([X|Xs],Ys,Acc) :-
\+ member(X,Ys),
intersect(Xs,Ys,Acc).
without_duplicates([],[]).
without_duplicates([X|Xs],[X|Acc]) :-
\+ member(X,Acc),
without_duplicates(Xs,Acc).
without_duplicates([X|Xs],Acc) :-
member(X,Acc),
without_duplicates(Xs,Acc).
difference([],_,[]).
difference([X|Xs],Ys,[X|Acc]) :-
\+ member(X,Ys),
difference(Xs,Ys,Acc).
difference([X|Xs],Ys,Acc) :-
member(X,Ys),
difference(Xs,Ys,Acc).
delete(_,[],[]).
delete(E,[X|Xs],[X|Ans]) :-
E \= X,
delete(E,Xs,Ans).
delete(E,[X|Xs],Ans) :-
E = X,
delete(E,Xs,Ans).
There is an abstraction for "keep elements in list for which condition holds".
The names are inclide, exclude. There is a library for those in SWI-Prolog that you can use or copy. Your predicates intersect/3, difference/3, and delete/3 would look like this:
:- use_module(library(apply)).
intersect(L1, L2, L) :-
include(member_in(L1), L2, L).
difference(L1, L2, L) :-
exclude(member_in(L2), L1, L).
member_in(List, Member) :-
memberchk(Member, List).
delete(E, L1, L) :-
exclude(=(E), L1, L).
But please take a look at the implementation of include/3 and exclude/3, here:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3
Also in SWI-Prolog, in another library, there are versions of those predicates called intersection/3, subtract/3, delete/3:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#intersection/3
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#subtract/3
https://www.swi-prolog.org/pldoc/doc_for?object=delete/3
Those are similar in spirit to your solutions.
Your next predicate, without_duplicates, cannot be re-written like that with include/3 or exclude/3. Your implementation doesn't work, either. Try even something easy, like:
?- without_duplicates([a,b], L).
What happens?
But yeah, it is not the same as the others. To implement it correctly, depending on whether you need the original order or not.
If you don't need to keep the initial order, you can simply sort; this removes duplicates. Like this:
?- sort(List_with_duplicates, No_duplicates).
If you want to keep the original order, you need to pass the accumulated list to the recursive call.
without_duplicates([], []).
without_duplicates([H|T], [H|Result]) :-
without_duplicates_1(T, [H], Result).
without_duplicates_1([], _, []).
without_duplicates_1([H|T], Seen0, Result) :-
( memberchk(H, Seen0)
-> Seen = Seen0 , Result = Result0
; Seen = [H|Seen0], Result = [H|Result0]
),
without_duplicates_1(T, Seen, Result0).
You could get rid of one argument if you use a DCG:
without_duplicates([], []).
without_duplicates([H|T], [H|No_duplicates]) :-
phrase(no_dups(T, [H]), No_duplicates).
no_dups([], _) --> [].
no_dups([H|T], Seen) -->
{ memberchk(H, Seen) },
!,
no_dups(T, Seen).
no_dups([H|T], Seen) -->
[H],
no_dups(T, [H|Seen]).
Well, these are the "while loops" of Prolog on the one hand, and the inductive definitions of mathematical logic on the other hand (See also: Logic Programming, Functional Programming, and Inductive Definitions, Lawrence C. Paulson, Andrew W. Smith, 2001), so it's not surprising to find them multiple times in a program - syntactically similar, with slight deviations.
In this case, you just have a binary decision - whether something is the case or not - and you "branch" (or rather, decide to not fail the body and press on with the selected clause) on that. The "guard" (the test which supplements the head unification), in this case member(X,Ys) or \+ member(X,Ys) is a binary decision (it also is exhaustive, i.e. covers the whole space of possible X)
intersect([X|Xs],Ys,[X|Acc]) :- % if the head could unify with the goal
member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
intersect([X|Xs],Ys,Acc) :- % if the head could unify with the goal
\+ member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
Other applications may need the equivalent of a multiple-decision switch statement here, and so N>2 clauses may have to be written instead of 2.
foo(X) :-
member(X,Set1),
(...action...).
foo(X) :-
member(X,Set2),
(...action...).
foo(X) :-
member(X,Set3),
(...action...).
% inefficient pseudocode for the case where Set1, Set2, Set3
% do not cover the whole range of X. Such a predicate may or
% may not be necessary; the default behaviour would be "failure"
% of foo/1 if this clause does not exist:
foo(X) :-
\+ (member(X,Set1);member(X,Set2);member(X,Set3)),
(...action...).
Note:
Use memberchk/2 (which fails or succeeds-once) instead of member/2 (which fails or succeeds-and-then-tries-to-succeed-again-for-the-rest-of-the-set) to make the program deterministic in its decision whether member(X,L).
Similarly, "cut" after the clause guard to tell Prolog that if a guard of one clause succeeds, there is no point in trying the other clauses because they will all turn out false: member(X,Ys),!,...
Finally, use term comparison == and \== instead of unification = or unification failure \= for delete/3.

Mutually referential Prolog rules in family tree

I've seen various implementations of family trees in Prolog, but I haven't found one that does what I would like to do, which is to define child and parent by referring to each other.
I want to do this because sometimes I have a fact that someone is a child of someone, at other times I have the fact that someone is the parent of someone. From either of these kinds of facts, I'd like to be able to ask who are parents and who are children.
My attempt at coding this is :-
parent(mary, fred).
child(john, peter).
child(paul, peter).
parent(P, C).
parent(P, C) :- child(C, P).
child (C, P).
child(C, P) :- parent(P, C).
This seems to work ok except that it will continue to give me the same results duplicated over and over. Eg :-
[3] ?- parent(peter, X).
true ;
X = john ;
X = paul ;
true ;
X = john ;
X = paul ;
true
Is there a way I can get it to stop after it has given me the full set of results once ?
More generally, is this kind of definition a weird thing to want to do (because of the mutual recursion) ? I want to be able to have facts of either parent or child, as reported, but also to infer the "opposite" relationship from these.
Thanks !
The issue with your program is that you are merging predicates.
parent/2 and child/2 are facts, you should not name a rule like a fact that is already defined in your program.
Rename the rules and all will work. Also, the base clause in your rules should add a condition, that match the fact, something like this:
parent(mary, fred).
child(john, peter).
child(paul, peter).
isparent(P, C):- parent(P, C).
isparent(P, C):- child(C, P).
ischild(C, P):- child(C, P).
ischild(C, P) :- parent(P, C).
Now the query:
?- isparent(peter, X).
X = john
X = paul
Also, don't use the complement rule in your condition, that's not necessary and will avoid you the recursion

Prolog Predicate to return true when two people have same hobby

I want to write a Prolog predicate that returns true when two people have the same hobby, without using negation. I have the following database:
likes(john,movies).
likes(john,tennis).
likes(john,games).
likes(karl,music).
likes(karl,running).
likes(peter,swimming).
likes(peter,movies).
likes(jacob,art).
likes(jacob,studying).
likes(jacob,sleeping).
likes(mary,running).
likes(mary,sleeping).
likes(sam,art).
likes(sam,movies).
I came up with the following predicate:
same_hobby(X,Y) :-
likes(X,Z),
likes(Y,Z).
However, this predicate is also true when X equals Y and I do not want this to be the case. Can anyone help me find a solution? A small explanation would also be greatly appreciated.
You can simply use the predicate dif/2 , that is, dif(Term1, Term2) that means that Term1 have to differ from Term2, otherwise it will fail.
Your rule will become:
same_hobby(X,Y) :-
likes(X,Z),
likes(Y,Z),
dif(X,Y).
Cause dif/2 is a completely pure predicate, you can also write this as
same_hobby(X,Y) :-
dif(X,Y),
likes(X,Z),
likes(Y,Z).
That means that, if X differs from Y then reduce the goal likes(X,Z), likes(Y,Z), fail otherwise.
You can use the predicate dif/2 to state that X and Y must not be equal:
same_hobby(X, Y) :-
likes(X, Z),
likes(Y, Z),
dif(X, Y).
This makes it so the interpreter recognizes that X and Y need to be two different entities in order for the same_hobby/2 predicate to be true.

Resources