Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Code Issue on implementing Inference in Frames with Prolog

Tags:

prolog

This is a code sample took from Ivan Bratko's book "Prolog Programming for Artificial Intelligence - 3rd edition - pg 377". It works perfectly for the query ?-value(kiwi, active_at, night). by giving the result as true.

But it also gives the result as true for the query ?- value(kiwi, active_at, daylight). and it should be false.

How should I modify it, or am I missing something?

%--------Define frames
bird(a_kind_of, animal).
bird(active_at, daylight).

albatross(a_kind_of, bird).
albatross(colour, black).
albatross(size, 10).

kiwi(a_kind_of, bird).
kiwi(active_at, night).
kiwi(colour, brown).
kiwi(size, 24).

albert(instance_of, albatross).
albert(size, 10).

%--------Inference in Frames
value(Frame, Slot, Value):-
    Query =.. [Frame, Slot, Value],
    call(Query), !.     %Value is directly retrieved
value(Frame, Slot, Value):-
    parent(Frame, ParentName),
    value(ParentName, Slot, Value).     % More general rule

parent(Frame, ParentName):-
    (Query =.. [Frame, a_kind_of, ParentName];
    Query =.. [Frame, instance_of, ParentName]),
    call(Query).
like image 800
Upekha Vandebona Avatar asked Nov 24 '17 07:11

Upekha Vandebona


2 Answers

First let's take a look at the queries in question. Your first query...

?- value(kiwi, active_at, night).
true.

... succeeds with the first rule of value/3. You can see that if you try the goals manually. The query...

?- Query =.. [kiwi, active_at, night].

... succeeds and unifies the variable Query with kiwi(active_at, night):

?- Query =.. [kiwi, active_at, night].
Query = kiwi(active_at, night).

The next goal calls Query...

?- call(kiwi(active_at, night)).
true.

... and succeeds since you have a fact kiwi(active_at, night).. The next goal ! prevents Prolog from backtracking and searching for further solutions therefore the query ?- value(kiwi, active_at, night). succeeds deterministically (you don't have to press ; after the first solution). Now let's take a look at your second query...

?- value(kiwi, active_at, daylight).
true ;
false.

... that succeeds as well. The first rule of value/3 unifies Query with kiwi(active_at, daylight) and subsequently calls it:

?- call(kiwi(active_at, daylight)).
false.

This call fails since you don't have a suitable fact. Note that at this point the rule can't succeed, so Prolog doesn't bother with the last goal and moves on to the second rule of value/3. Here the first goal

?- parent(kiwi,ParentName).
ParentName = bird ;
false.

... succeeds and is unifying ParentName with bird due to the first argument of the disjunction...

?- Query =.. [kiwi, a_kind_of, ParentName].
Query = kiwi(a_kind_of, ParentName).

... and the subsequent call/1 in parent/2:

?- call(kiwi(a_kind_of, ParentName)).
ParentName = bird.

Now the second goal of the second rule of value/3 calls itself, starting with the first rule again:

?- value(bird, active_at, daylight).
true.

This succeeds and therefore the query...

?- value(kiwi, active_at, daylight).
true

... succeeds as well. Note that Prolog is waiting for input after answering true and if you press ; it is searching for further solutions:

?- value(kiwi, active_at, daylight).
true ;

Although the goal value(bird, active_at, daylight) succeeded deterministically due to the cut in the first rule of value/3, the first goal (parent(kiwi,ParentName)) of the calling predicate (the second rule of value/3) left a choice point open (see the query above) and now Prolog is backtracking there to search for other solutions. But there are none so Prolog answers:

?- value(kiwi, active_at, daylight).
true ;
false.

However, if you ask at what time kiwis are active Prolog will answer:

?- value(kiwi, active_at, X).
X = night.

The reason why daylight is not derived here is again the cut. After the first rule of value/3 succeeds for X = night it prevents Prolog from searching for other solutions. From a logical point of view this behaviour is outright incorrect: Either kiwis are active at day and night, then the last query should yield both solutions, or they are nocturnal, then the query ?- value(kiwi, active_at, daylight). should fail. I don't want to speculate on the intended behaviour of the predicate value/3, so I will refer to the Wikipedia entry on kiwi instead which states: Kiwi are shy and usually nocturnal. Their mostly nocturnal habits may be a result of habitat intrusion by predators, including humans. In areas of New Zealand where introduced predators have been removed, such as sanctuaries, kiwi are often seen in daylight.

If you want to have both solutions I would suggest to add some facts iscallable/1 (don't call it callable/1 though, since there's already a built-in with that name) that cover your facts, add it in value/3 and parent/2 and remove the cut like so:

iscallable(bird).                                 % <- new fact
iscallable(albatross).                            % <- new fact
iscallable(kiwi).                                 % <- new fact
iscallable(albert).                               % <- new fact

value(Frame, Slot, Value):-
    iscallable(Frame),                            % <- new goal iscallable/1
    Query =.. [Frame, Slot, Value],
    call(Query).                                  % <- removed cut here
value(Frame, Slot, Value):-
    parent(Frame, ParentName),
    value(ParentName, Slot, Value).

parent(Frame, ParentName):-
    iscallable(Frame),                            % <- new goal iscallable/1
    (Query =.. [Frame, a_kind_of, ParentName];
     Query =.. [Frame, instance_of, ParentName]),
    call(Query).

With these alterations you'll consistently get both solutions:

?- value(kiwi, active_at,X).
X = night ;
X = daylight ;
false.

?- value(kiwi, active_at,night).
true ;
false.

?- value(kiwi, active_at,daylight).
true ;
false.

To see why you need something like iscallable/1 in rule 1 of value/3, remove it and consider the following query:

?- value(kiwi, active_at, X).
X = night ;
X = daylight ;
ERROR: value/3: Undefined procedure: animal/2
   Exception: (9) animal(active_at, _G4462) ? creep
   Exception: (8) value(animal, active_at, _G4462) ? creep

The predicate value/3 is trying to call a predicate animal/2 that does not exist. To see why you need something like iscallable/1 in parent/2, remove it and consider the following query:

?- value(kiwi, active_at,X).
X = night ;
X = daylight ;
ERROR: parent/2: Undefined procedure: animal/2
   Exception: (10) animal(a_kind_of, _G4558) ? creep

On the other hand, if you opt for the night solution only, you can define a fact nocturnalbird/2 that describes activity at night time and alter the facts kiwi/2 accordingly:

nocturnalbird(active_at, night).  % <- new fact

%kiwi(a_kind_of, bird).           % <- remove fact
kiwi(a_kind_of, nocturnalbird).   % <- new fact
%kiwi(active_at, night).          % <- remove fact
kiwi(colour, brown).
kiwi(size, 24).

This yields the desired results:

?- value(kiwi, active_at,X).
X = night ;
false.

?- value(kiwi, active_at,night).
true ;
false.

?- value(kiwi, active_at,daylight).
false.

If you plan to extend this example to include animal properties for nocturnal birds as well, you'll need to add a fact nocturnalbird(a_kind_of, animal). as well as include iscallable/1 in value/3 and parent/2 like above.

EDIT:

In fact, you don't need =../2 here at all, as pointed out by @false in the comments. You can simply use call/N instead:

value(Frame, Slot, Value):-
    iscallable(Frame),               
    call(Frame, Slot, Value).                    % <- here
value(Frame, Slot, Value):-
    parent(Frame, ParentName),
    value(ParentName, Slot, Value).

parent(Frame, ParentName):-
    iscallable(Frame),
    (call(Frame, a_kind_of, ParentName);         % <- here
     call(Frame, instance_of, ParentName)).      % <- here
like image 72
tas Avatar answered Nov 15 '22 12:11

tas


I came across this very late, but another way of handling this is to change the first clause of value to:

value(Frame, Slot, Value):-
    call(Frame, Slot, V), !,    % Value is directly retrieved
    V = Value.                  % Slot might already inherit value so check
like image 1
CAS Avatar answered Nov 15 '22 14:11

CAS