Uncle or Aunt without sibling fact - prolog

I'm wondering how would I be able to call a nephew or niece in a family tree without using a sibling fact for prolog. I can't figure out a way to do it by calling the uncle directly.
For example:
parent(elli, lisa).
parent(kelly, lisa).
parent(ben, claire).
parent(lisa, claire).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
Since ellie or kelly is ben's niece, I have the rule that when called by grandparent(X, claire). will give elli and kelly as the grandchild of claire. How would I make a rule to be able to call niece(ben, X). so it'll list all of ben's niece. I can't figure out a way to do it with only the parent fact, the only way of doing it would be to include a sibling fact but is there a way to do it without making a sibling fact?
I'm very new to prolog, literally like a week ago so please excuse me if I don't understand it that well.

brother(X, Y) :- male(X), parent(X, Z), parent(Y, Z), X \= Y.
uncle(X, Y) :- brother(X, Z), parent(Y, Z).

Related

prolog family tree locating cousins

The Cousin Explainer
Write a program that when given a person of reference and a degree the program can tell me all of the nth degree cousins that person has. I've started by writing my facts: male/1 female/1 and child/2 these are populated with the names of my family members. I then began writing rules for cousins I figured id write a different rule for every degree so only up to the third cousins. The problems I'm having are as follows.
firstCousin_of(X,Y):-child(X,Z1),child(Y,Z2),child(Z1,Z),child(Z2,Z). I have this to find a first cousin but the 2nd cousin is more complicated which makes me think there has gotta be a way to do this recursively.
I need the rule, all_cousins(Person, Degree, ListOfCousins), which after figuring out all of the nth degree cousins edits a list of all cousins to only include those specific nth degree cousins. I'm used to imperative languages and all i can think about with this is how do I even convey to the rule which people to remove from the list from one rule to another.
lastly I have a rule, all_cousinsRemoved(Person, Degree, removed(Number, Direction), ListOfCousins) that I don't even know where to start with but ill need the all_cousins rule for this one because it does the same thing but also only includes cousins in the edited lists w=that were removed nth times either up or down.
The best solutions is make a several rules that call other rules, here an example
male(dicky).
male(randy).
male(mike).
male(don).
male(elmer).
female(anne).
female(rosie).
female(esther).
female(mildred).
female(greatgramma).
male(blair).
male(god).
female(god).
parent(don,randy).
parent(don,mike).
parent(don,anne).
parent(rosie,randy).
parent(rosie,mike).
parent(rosie,anne).
parent(elmer,don).
parent(mildred,don).
parent(esther,rosie).
parent(esther,dicky).
parent(greatgramma,esther).
parent(randy,blair).
male(mel).
male(teo).
parent(melsr,mel).
parent(melsr,teo).
american(anne).
american(X) :- ancestor(X,anne).
american(X) :- ancestor(anne,X).
relation(X,Y) :- ancestor(A,X), ancestor(A,Y).
father(X,Y) :- male(X),parent(X,Y).
father(god, _) :- male(god).
mother(X,Y) :- female(X),parent(X,Y).
son(X,Y) :- male(X),parent(Y,X).
daughter(X,Y) :- female(X),parent(Y,X).
grandfather(X,Y) :- male(X),parent(X,Somebody),parent(Somebody,Y).
aunt(X,Y) :- female(X),sister(X,Mom),mother(Mom,Y).
aunt(X,Y) :- female(X),sister(X,Dad),father(Dad,Y).
sister(X,Y) :- female(X),parent(Par,X),parent(Par,Y), X \= Y.
uncle(X,Y) :- brother(X,Par),parent(Par,Y).
cousin(X,Y) :- uncle(Unc , X),father(Unc,Y).
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,Somebody),ancestor(Somebody,Y).
brother(X,Y) :- male(X),parent(Somebody,X),parent(Somebody,Y), X \= Y.
Retrived from this repository

In prolog, why doesn't adding "edge(X, Y) :- edge(Y, X)." alone work for converting a directed graph definition to an undirected graph

I'm just learning Prolog, and I'm reviewing lecture notes and all the notes say is that:
given the following definition for directed graphs:
path(X, Y) :- edge(X, Y).
path(X, Y) :- edge(X, Z), path(Z, Y).
If we wanted to make this an undirected graph, defining
edge(X, Y) :- edge(Y, X). alone doesn't work, and I can't figure out why.
X to Y has an edge if Y to X has an edge. Seems to make sense to me.
The notes don't really clarify why not, but it does define that the proper solution would be:
edge1(X, Y) :- edge(X, Y).
edge1(X, Y) :- edge(Y, X).
to what we already had.
Can anyone explain this to me, please and thanks? <3
There are several potential sources of non-termination in your program.
First, with the rule edge(X, Y) :- edge(Y, X). your program will never terminate. Regardless of where you add this rule to your program.
What is often quite irritating is that your program will still produce many answers which somewhat suggests that it works. However, it will never stop.
The best way to understand this, is to consider a slightly modified program, called a failure-slice. This modified program will share many properties with your program. Not all of them, but some. We will add goals false into your program. If the resulting program loops, the original program will loop as well.
path(X, Y) :- edge(X, Y), false.
path(X, Y) :- false, edge(X, Z), path(Z, Y).
edge(a, b) :- false.
edge(X, Y) :- edge(Y, X).
Second, there is another source of non-termination in your improved program. Here is the related failure-slice:
path(X, Y) :- false, edge1(X, Y).
path(X, Y) :- edge1(X, Z), path(Z, Y), false.
edge1(X, Y) :- edge(X, Y).
edge1(X, Y) :- edge(Y, X).
edge(a, b).
edge1/2 now always contains cycles, so this fragment will loop for path(a, Y). and more generally also path(X, Y), false.
To solve this problem, you will have to rewrite path/2.
You can rewrite this in a generic manner by using closure0/3 and path/4!
So path/2 can be defined as:
path(X, Y) :-
closure(edge, X, Y).
Because rules don't work the same as facts, and you are spiraling off into an infinite loop if you use the same predicate.
Let's take the example ?-edge(5,2). We will end up calling --
edge(5,2) :- edge(2,5).
Ok, what happens when we call edge(2,5)?
edge(2,5) :- edge(5,2).
... Uh oh. Logic circle.
When using edge1, you are simply creating a wrapper for your predicate to escape the recursive definition.

writing rules in prolog

I am learning Prolog and would just like to check myself:
I think this question is very basic but I am just beginning.
father(X,Y)
mother(X,Y)
male(X)
female(X)
parent(X,Y)
diff(X,Y)
To write a clause for is_mother(X) is this correct?
is_mother(X):- female(X), parent(X,Y).
Thank you
is_mother(X) :- female(X), parent(X,Y).
This is technically correct in that it says, X is a mother if X is female, and X is the parent of someone (Y). In this definition, Prolog will give you a warning about Y being a "singleton" variable since you don't use its value. To avoid that warning, you can use _ or a name that starts with _ to indicate a variable whose value you don't care about and Prolog won't warn that you're not using:
is_mother(X) :- female(X), parent(X,_).
The terms female(X) and parent(X,_) assume that you have either predicates female(X) and parent(X,Y) or you have facts, such as (for example) female(sally). where sally is an "atom" (a constant in Prolog), and/or parent(sally, tom).

How to negate in Prolog

I'm new to PROLOG and am at the very beginning of the exercises on this page. Given the rules parent(X, Y) and male(X), I'm trying to define a rule mother(X, Y) as
mother(X, Y) :-
not(male(X)),
parent(X, Y).
However, in GNU Prolog I get the following error:
| ?- mother(lina, julia).
uncaught exception: error(existence_error(procedure,not/1),mother/2)
| ?-
\+/1 is the ISO Prolog predicate to "negate". Note that "negate" means here not provable at that point.
You can refer to this excellent answer by #false for more on the subject
The solution is actually in the exercise file on that page:
female(X) :- \+ male(X).
As #Mog said, negation is the unary \+ operator.

Getting all the solutions to a predicate in Prolog

I'm writing a text adventure game in Prolog, and I am printing out room exits. I have code that does:
exits_from(Room) :-
connected(Room, X),
write(X), write(' ').
where connected/2 is:
connected(X, Y) :- path(X, Y).
connected(X, Y) :- path(Y, X).
and path is:
path(room, hallway).
path(hallway, foyer).
and so on.
When I am printing the exits for a room though, it gets the first, then wants a ';' to say that I want another solution. Is there anyway to force a predicate to compute the result entirely, so that the player wouldn't have to keep asking for more exits?
one way is to do something like
print_all_solutions :-
solution(Sol),
write(Sol),
fail. % this causes backtracking
print_all_solutions. % succed
another is to use special predicate forall, like follows:
forall(solution(Sol), write(Sol))

Resources