IBM / LNN

A `Neural = Symbolic` framework for sound and complete weighted real-value logic
https://IBM.github.io/LNN/
Apache License 2.0
226 stars 438 forks source link

Errors on usage. #68

Closed daisylab closed 1 year ago

daisylab commented 1 year ago

Hi. I'm a graduate student from korea, majoring computer science.

I think LNN is a great project what I'm looking for. I really appreciate it. Thanks.

However, I found some errors in the usage page.

https://ibm.github.io/LNN/education/examples/reasoning.html#more-complex-reasoning-example

from lnn import (Predicate, Variable, Join, And,
                 Exists, Implies, ForAll, Model, Fact, World)

model = Model()  # Instantiate a model.
x, y, z, w = map(Variable, ['x', 'y', 'z', 'w'])

# Define and add predicates to the model.
owns = model['owns'] = Predicate('owns', 2)  # binary predicate
missile = model['missile'] = Predicate('missile')
american = model['american'] = Predicate('american')
enemy = model['enemy'] = Predicate('enemy', 2)
hostile = model['hostile'] = Predicate('hostile')
criminal = model['criminal'] = Predicate('criminal')
weapon = model['weapon'] = Predicate('weapon')
sells = model['sells'] = Predicate('sells', 3)  # ternary predicate

which tells that

      5 x, y, z, w = map(Variable, ['x', 'y', 'z', 'w'])
      7 # Define and add predicates to the model.
----> 8 owns = model['owns'] = Predicate('owns', 2)  # binary predicate
      9 missile = model['missile'] = Predicate('missile')
     10 american = model['american'] = Predicate('american')

TypeError: 'Model' object does not support item assignment

I'm new to LNN, and not yet fully understand it. Can you please tell me how to fix this error? Thank you very much.

daisylab commented 1 year ago

A few comments.

So i deleted the item assignment from the code.

# Define and add predicates to the model.
owns = Predicate('owns', 2)  # binary predicate
missile = Predicate('missile')
american = Predicate('american')
enemy = Predicate('enemy', 2)
hostile = Predicate('hostile')
criminal = Predicate('criminal')
weapon = Predicate('weapon')
sells = Predicate('sells', 3)  # ternary predicate

It seems to work, however, I got another error message from that code.

# Define and add the background knowledge to  the model.
america_enemies = (
    ForAll(x, Implies(enemy(x, (y, 'America')), 
                      hostile(x),
                      join=Join.OUTER),
           join=Join.OUTER, 
           world=World.AXIOM)
    )
model.add_knowledge(america_enemies)

which gave me an error message:


File ~/home/lnn-homework/complex.py:19
     15 sells = Predicate('sells', 3)  # ternary predicate
     17 # Define and add the background knowledge to  the model.
     18 america_enemies = (
---> 19     ForAll(x, Implies(enemy(x, (y, 'America')), 
     20                       hostile(x),
     21                       join=Join.OUTER),
     22            join=Join.OUTER, 
     23            world=World.AXIOM)
     24     )
     25 model.add_knowledge(america_enemies)

File ~/.virtualenvs/lnn/lib/python3.10/site-packages/lnn/symbolic/logic/leaf_formula.py:92, in Predicate.__call__(self, *args, **kwds)
     75 def __call__(self, *args, **kwds):
     76     r"""A called first-order logic predicate
     77 
     78     This correctly instantiates a predicate with variables - which is required when
   (...)
     90     an ordered unique collection (list).
     91     """
---> 92     return super().__call__(*args, **kwds)

File ~/.virtualenvs/lnn/lib/python3.10/site-packages/lnn/symbolic/logic/formula.py:689, in Formula.__call__(self, bind, *variables)
    687     variable_objects.append(v)
    688 else:
--> 689     raise TypeError(f"expected variable, received {type(v)}")
    691 if v in bind:
    692     if isinstance(bind[v], str):  # a single binding

TypeError: expected variable, received <class 'tuple'>

In [3]: 
KyleErwin commented 1 year ago

Hi @daisylab. Nice to meet you. It is great to hear that you are using the LNN.

Thank you for pointing this out. I will try to replicate the issue. In the meantime, please see here for a working example of the same code. Let me know if you have any questions.

daisylab commented 1 year ago

Thank you for the working example. It runs smoothly without errors. It greatly helped me.

After testing the code you mentioned above, I myself tried to modify the example code, and I got the right result, a.k.a, {'West'}.

Below is my modification to the example code:

# The code snippet below shows the declaration of the model and all the
# predicates.

from lnn import (Predicate, Variable, And,
                 Exists, Implies, ForAll, Model, Fact)

model = Model()  # Instantiate a model.
x, y, z, w = map(Variable, ['x', 'y', 'z', 'w'])

# Define and add predicates to the model.
owns = Predicate('owns', 2)  # binary predicate
missile = Predicate('missile')
american = Predicate('american')
enemy = Predicate('enemy', 2)
hostile = Predicate('hostile')
criminal = Predicate('criminal')
weapon = Predicate('weapon')
sells = Predicate('sells', 3)  # ternary predicate

# The code snippet below shows an example of adding the background
# knowledge into the model. All the other rules can be added to the
# model similarly.

model.add_knowledge(
    ForAll(x, y,
           Implies(enemy(x, y, bind={y: 'America'}),
                   hostile(x))),
    ForAll(x, y, z,
           Implies(And(american(x), weapon(y), sells(x, y, z),
                       hostile(z)),
                   criminal(x))),
    ForAll(x, y, z,
           Implies(And(missile(x), owns(y, x, bind={y: 'Nono'})),
                   sells(z, x, y, bind={z: 'West', y: 'Nono'}))),
    ForAll(x,
           Implies(missile(x), weapon(x)))

)

# The code snippet below shows how to add the query into the model.

query = Exists(x, criminal(x))

# model.add_knowledge(query)
model.set_query(query)

# Finally, we can add facts into the model.

model.add_data({
    owns: {('Nono', 'M1'): Fact.TRUE},
    missile: {'M1': Fact.TRUE},
    american: {'West': Fact.TRUE},
    enemy: {('Nono', 'America'): Fact.TRUE},
})

# Then we are ready to perform inference and answer queries (aka
# theorem proving):

model.infer()

print(model[query].true_groundings)

Thank you for your advice.

NaweedAghmad commented 1 year ago

The above example API is outdated and covered in the unittest. I don't see a question or issue, so closing it off.