Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Richard
Hi!
Thank you so much for this awesome API bringing ontology work to the modern world in Python :)
I have an ontology (RDF/XML) built in Protege to the effect of:

----
Classes:
Thing
    Ingredient
        Kale <--- subClassOf: hasTaste some Bitter . EquivalentTo: {kale}
    Taste
        Bitter <--- EquivalentTo: {bitter}

Individuals:
    kale
    bitter

Object Properties:
    hasTaste

----------
Notice that I've closed/reified the Kale and Bitter classes to include exactly 1 individual each. When I run the following code:

from owlready2 import *
world = World()
onto = world.get_ontology('.../my/ontology/file.owl')

print(onto.Kale.instances()) # []
sync_reasoner(world)
print(onto.Kale.instances()) # [onto.kale]  GOOD!
print(onto.hasTaste[onto.kale]) # []  BAD; Expected: [onto.bitter]

Any ideas how to make this work? I've tried wrapping it in with onto: ... But that hasn't worked either.

Thanks in advance!

Reply | Threaded
Open this post in threaded view
|

Re: Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Jiba
Administrator
Hi,

Owlready was not taking into account the relation asserted at the class level.

In the devlopment version, I've modified the .indirect() method so as it takes into account class-level assertions, so you can now do:

list(onto.kale.hasTaste.indirect())

(it returns a generator you you need to convert it to a list for printing it)

Best regards,
Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Richard
Unfortunately this still returns []

print(list(onto.kale.hasTaste.indirect()))

It doesn't look like it would grab SuperClass "hasSomeValuesFrom" restrictions and infer it for individuals.
https://owlready2.readthedocs.io/en/latest/properties.html?highlight=.indirect()#obtaining-indirect-relations-considering-subproperty-transitivity-etc

Reply | Threaded
Open this post in threaded view
|

Re: Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Jiba
Administrator
I tested your example (its now test case prop_29 in test/regtest.py), as follows:

  def test_prop_29(self):
    world   = self.new_world()
    n       = world.get_ontology("http://www.semanticweb.org/test.owl")
   
    with n:
      class Ingredient(Thing): pass
      class Kale(Ingredient): pass
     
      class Taste(Thing): pass
      class Bitter(Taste): pass
     
      class has_taste(Ingredient >> Taste): pass
     
      bitter = Bitter()
      Kale.is_a.append(has_taste.some(Bitter))
     
      kale = Kale()
     
    print(kale.has_taste)
    print(set(kale.has_taste.indirect()))
    assert kale.has_taste == []
    assert set(kale.has_taste.indirect()) == { Bitter }
   

kale.has_taste.indirect() contains Bitter. It is not the instance but the class, because resolving singleton is not so simple (if you want to resolve all of them, you must take into account "same as" relations between individuals).

If you really need individuals, you can remove the class Bitter, create individual bitter as an instance of Taste, and assert that:  Kale.is_a.append(has_taste.value(bitter))

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Richard
Thank you for taking this time to address this problem. I can see how resolving relationships between individuals is hard. Would it help to assume these assertions?

    kale = Kale("kale")
    bitter = Bitter("bitter")
    Bitter.equivalent_to.append(OneOf([bitter]))
    Kale.equivalent_to.append(OneOf([kale]))
    AllDifferent([bitter, kale])

    Kale.is_a.append(has_taste.some(Bitter))

    close_world(Ingredient)

Unfortunately, even with this, I'm still getting an assertion error on:

    assert set(kale.has_taste.indirect()) == { Bitter }

We don't even want classes in triples, do we? That seems wrong. What is .indirect() really supposed to capture and what does it do that inference does not?




Reply | Threaded
Open this post in threaded view
|

Re: Inferring Object Properties for Individuals Based on Asserted SomeValuesFrom

Jiba
Administrator
Hi,

The equivalent_to relation is not sufficient to "replace" Bitter (class) by bitter (individual), because it does not prevent Bitter to be equivalent to another individual, e.g. bitter2, bitter3,...

If the property is asserted at the class level, I prefer to stay at that level -- changing level would require a true reasoning, but .indirect() does not do that, it just resolves transitive property and (now) gets the value asserted at the class level.

In my opinion, kale.has_taste should not be though as "triple" but rather as a Python attribute. In that sense, having classes in it is not a problem.


I tested the following program, and I obtain the expected results (= [t.Bitter]). Are you obtaining something else?

Best regards,
Jiba


----8<--------

from owlready2 import *

onto_path.append('/tmp')


onto = get_ontology('http://test.org/t.owl')
with onto:
  class Ingredient(Thing): pass
  class Kale(Ingredient): pass
  class Bitter(Ingredient): pass
  class has_taste(Thing >> Thing): pass
  kale = Kale("kale")
  bitter = Bitter("bitter")
  Bitter.equivalent_to.append(OneOf([bitter]))
  Kale.equivalent_to.append(OneOf([kale]))
  AllDifferent([bitter, kale])
 
  Kale.is_a.append(has_taste.some(Bitter))
 
  close_world(Ingredient)

print(list(kale.has_taste.indirect()))