Defining facts within prolog rules - prolog

I am trying to translate the following statement into prolog:
"For all X, if X has a child who has a sister then X has two children."
I have defined the following rule:
has_two_children(X) :-
parent(X,Y),
sister(Y,_Z).
when I run it, I get:
"procedure `sister(A,B)' does not exist
Reachable from:
has_two_children(A)"
I have defined a parent relation separately, but I have not defined a sister relation separately. But this is puzzling to me. I was expecting it to just say false. What if no one i'm interested in has a sister? In that case, there's nothing I can put for the sister relation. Must I define the sister relation outside the rule?

What if no one i'm interested in has a sister? In that case, there's nothing I can put for the sister relation.
You can put:
sister(_, _) :- false.

You need to define the sister relation in order for the has_two_children rule to work.

Related

forall/2 predicate query doesn’t return results

I have the following facts.
loves(ami, paul).
loves(lucy, paul).
female(ami).
artist(ami).
female(lucy).
artist(lucy).
canadian(paul).
lovesCanadianArtists(Person) :- forall(canadian(X), loves(Person, X)).
When I execute the query in SWI-Prolog:
?- lovesCanadianArtists(X).
The answer is true, and I don't get results.
Someone told me that the issue is the predicate isLovedByArtists(Person) is not inversible or invertible. So, I should add a condition on Person variable because it is not bound by the forall\2 predicate. Like:
lovesCanadianArtists(Person) :- female(Person), forall(canadian(X), loves(Person, X)).
So, my questions are:
Is this predicate invertibility documented anywhere ? I can't find it.
For me, the explanation given is wrong, and but I am not sure whether I should get results with my first rule. What's the underlying issue here ?
What's the underlying issue here ?
"forall/2 does not change any variable bindings. [...] If your intent is to create variable bindings, the forall/2 control structure is inadequate." - https://www.swi-prolog.org/pldoc/man?section=forall2
Perhaps one of foreach, findall, bagof or setof will do what you want, although it's not clear from the plural 'artists' and singular 'Person' exactly what that is; e.g. for a list of all People who love at least one Canadian artist, which may have duplicates if you add more Canadian artists:
lovesCanadianArtists(People) :-
findall(Person, (canadian(X), loves(Person, X)), People).

Representing truth regarding beliefs in prolog

How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).

is it possible to prove nested rule in prolog?

I'm trying to call a rule inside another rule my code is to fined the grandpa just like:
male(jack).
male(john).
male(mark).
parent(jack,john).
parent(john,mark).
father(X,Y):-male(X),parent(X,Y).
grandpa(X,Y):-father(X,father(F,Y)).
and the query in GNU Prolog is
grandpa(X,mark).
it just returns no
and when I tried to trace the call I noticed that it doesn't even call the nested rule.
So is there any way to do this in prolog?
Rules aren't functions (which is why they aren't called functions): you don't call them, you prove them. To do what you seem to be asking, you would write:
grandpa(X,Y) :- father(X,Z), father(Z,Y).
That is: X is Y's grandpa if there exists a Z such that X is Z's father and Z is Y's father.

Finding a person with no siblings in prolog

I'm trying to write Prolog code that calculates how the fortune of man divided between his family members based on Islamic inheritance rules.
One of the cases is that, if a daughter has no siblings from her father she has the right for half of his fortune.
So my question is how to set a rule that tests if the daughter has no siblings from her father.
half(X,Y) :-
father(Y,X),
female(X),
sibling(What to do here?),
read(N),F is N*0.5, write(F).
male(ahmed).
male(adel).
male(hamza).
male(marwan).
female(sara).
female(lobna).
female(ghada).
female(aisha).
female(noor).
parent(aisha,sara).
parent(aisha,hamza).
parent(aisha,ghada).
parent(adel,sara).
parent(adel,hamza).
parent(adel,ghada).
parent(adel,lobna).
parent(marwan,noor).
sibling(X,Y):-parent(Z,X), parent(Z,Y), X\=Y.
father(X,Y):-male(X), parent(X,Y).
mother(X,Y):-female(X), parent(X,Y).
brother(X,Y):-male(X), (sibling(X,Y);sibling(Y,X)).
sister(X,Y):-female(X), (sibling(X,Y); sibling(Y,X)).
half(X,Y):-father(Y,X),female(X),sibling(X,_),read(N),F is N*0.5, write(F).
Personally, I'd add a few more rules to make the intent clearer - e.g.:
daughter(D,P) :- parent(P,D), female(D).
And you can create a rule which specifically checks to see if someone has any siblings:
has_sibling(X) :- sibling(X,_).
You can then write a rule called, say, eligible_half\2 to check for eligibility --
eligible_half(D,F) :- father(F,D), daughter(D,F), \+ has_sibling(D).
It looks like you've done the opposite of this in your definition of half/2 at the bottom of your code, though - your definition requires that the daughter does have a sibling.
At any rate, this means you can write a definition of half\2 which doesn't itself define any logical rule, but just checks that eligible_half\2 holds and does some I/O:
half(D,F):-
eligible_half(D,F),
read(N), number(N), HalfN is N*0.5, write(HalfN).
And as #lurker noted, you don't need to have the symmetric calls to sibling\2 in your definition of brother\2 and sister\2. Hopefully that's of use.

set up a Parent son relationship in prolog

I'm trying to set up a parent son relationship in prolog such as this
James is the father of Fountain Push
This is how I got it setup
clue5(Solution) :- parent([_, james], [push , foutain], Solution).
in prolog but I keep getting an error ,
clue2/1: Undefined procedure: parent1/3
However, there are definitions for:
parent1/2
my parent definition is as follows :
parent(X, L)
Would like to know what I am doing wrong here . thanks .
Your parent(X, L) predicate only takes 2 variables, X and L, but you are trying to call it with 3. You need to either create or update a parent predicate to take 3 parameters, or you need to not pass Solution into parent.
Without seeing the rest of the code, we can't be sure which way is correct.

Resources