Python NLTK ResolutionProver finds a solution when in fact there

ghz 昨天 ⋅ 4 views

Python NLTK ResolutionProver finds a solution when in fact there is no

I have this rule of format "if A&B then C": if b is_man and s is sister_of b, then b is brother_of s

I add the fact that is_man(luc) and I request if there is any 'b' for brother_of(b,leia)

I expect the answer to be negative because it is not said that leia is sister_of luc, so in my rule "if A&B then C" the B part is not true, but ResolutionProver surprisingly answers 'luc' ??!?

import nltk.inference
rexp = nltk.sem.Expression.fromstring
p1 = rexp('is_man(luc)')
p2 = rexp('(is_man(b) & sister_of(s,b)) -> brother_of(b,s)')
answer = rexp('brother_of(b,leia) -> ANSWER(b)')
tp = nltk.ResolutionProverCommand(None, [p1,p2,answer])
if list(tp.find_answers()): 
    for ans in list(tp.find_answers()): print(ans,end=' ')
else: print('No answer')

It should not answer Luc but False, how can I get False ? And get 'luc' only in case I'd declare in addition sister_of(leia,luc). Thank you !

PS: for info, here is the proof:

[1] {is_man(luc)}                                                  A  (that is p1)
[2] {-is_man(z368), -sister_of(z369,z368), brother_of(z368,z369)}  A  (that is p2)
[3] {-brother_of(z370,leia), ANSWER(z370)}                         A  (that is answer)
[4] {-sister_of(z369,luc), brother_of(luc,z369)}                   (1, 2)  (combination of 1 & 2)
[5] {ANSWER(z370), -is_man(z370), -sister_of(leia,z370)}           (2, 3) 
[6] {-sister_of(leia,luc), ANSWER(luc)}                            (1, 5) 
[7] {-sister_of(leia,luc), ANSWER(luc)}                            (3, 4) 

Answer

The issue you're encountering stems from the way ResolutionProverCommand in NLTK works, and how it processes logical expressions and rules. In your case, you're using the rule:

(is_man(b) & sister_of(s,b)) -> brother_of(b,s)

This means that if b is a man and s is a sister of b, then b is a brother of s. However, in your query, you're asking whether there is any b such that brother_of(b, leia) holds, without specifying that leia is a sister of anyone.

Here's the core issue: ResolutionProverCommand is inferring the possible values of b based on the rules you provided, and in this case, it's making an inference based on the is_man(luc) fact. Since the rule is a conditional (if-then) statement, and there's no specific clause saying sister_of(leia, luc) or similar, the solver still concludes that the condition could be true for luc due to the way logical resolution works.

Why does the prover answer 'luc'?

Looking at the proof:

  1. is_man(luc) is provided as a fact.
  2. The rule (is_man(b) & sister_of(s,b)) -> brother_of(b,s) says that if b is a man and s is a sister of b, then b is a brother of s. For this rule to apply to luc, the prover attempts to satisfy the condition sister_of(leia, luc) for luc and leia. Since this is not explicitly given in the facts, the prover may use the assumption that the condition could hold (which is an issue in this specific setup).
  3. The prover concludes that luc could potentially be the b for which brother_of(b, leia) holds because it infers that the rule could apply if leia were a sister of luc.

How to ensure 'luc' is returned only when sister_of(leia,luc) is given?

To get the correct behavior (i.e., not return luc unless it's explicitly stated that leia is a sister of luc), you need to make sure the system does not assume implicit relationships.

To fix this, you should add an explicit check for sister_of(leia, luc) before running the query for brother_of(b, leia). Only if this relationship is explicitly stated will the inference process correctly apply the rule.

Solution: Add the sister_of(leia, luc) fact

You can achieve this by explicitly adding the fact sister_of(leia, luc) if you want the inference to correctly return luc as the brother of leia. Here's the updated code:

import nltk.inference
rexp = nltk.sem.Expression.fromstring

# Facts
p1 = rexp('is_man(luc)')
p2 = rexp('(is_man(b) & sister_of(s,b)) -> brother_of(b,s)')
p3 = rexp('sister_of(leia, luc)')  # Add the explicit sister relationship

# Answer query
answer = rexp('brother_of(b,leia) -> ANSWER(b)')

# Running the prover
tp = nltk.ResolutionProverCommand(None, [p1,p2,p3,answer])
if list(tp.find_answers()): 
    for ans in list(tp.find_answers()): print(ans,end=' ')
else: 
    print('No answer')

What happens now?

With the additional fact sister_of(leia, luc), the rule (is_man(b) & sister_of(s,b)) -> brother_of(b,s) will apply because the conditions for b being a brother of leia are now satisfied (since luc is a man and leia is a sister of luc). Therefore, the prover will return luc.

If you do not add the fact sister_of(leia, luc), the prover will not return any answer because the condition for applying the rule is not satisfied.

Conclusion:

The key to getting the expected behavior is to ensure that the conditions for applying the rule are explicitly stated. The prover is working correctly by returning luc in the case where the rule applies, but if you want to avoid this, make sure that relationships like sister_of(leia, luc) are explicitly defined when querying for brother_of(b, leia).