Galigator / openllet

Openllet is an OWL 2 reasoner in Java, build on top of Pellet.
https://www.w3.org/TR/owl2-primer/
Other
96 stars 26 forks source link

getInstances for Class Expressions using Complement doesn't work correctly #59

Closed TortugaAttack closed 3 years ago

TortugaAttack commented 3 years ago

If I use the OpenlletReasoner and want to retrieve any Instances for any Class Expression containing Owl Complements, it either yields no result even though they are definitely Individuals fitting or some bot not all.

I created a small Ontology and code for reproducing that, and it turns out that the getInstances always returned 0 elements for the ClassExpressions containing a complement. However using https://github.com/SmartDataAnalytics/SML-Bench/blob/updates/learningtasks/carcinogenesis/owl/data/carcinogenesis.owl and f.e. not carcinogenesis:Bond-2 contains 13055 Instances, so it is not always empty, but it should be way more.

Small Ontology file for reproducing:

@prefix : <http://example.com#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@base <http://example.com#> .

<http://example.com> rdf:type owl:Ontology .

:Carbon rdf:type owl:Class .
:Oxygen rdf:type owl:Class .
Parser parser = new Parser("test2.ttl");
:Oxygen-40 rdf:type owl:Class ;
           rdfs:subClassOf :Oxygen .
:Oxygen-10 rdf:type owl:Class ;
           rdfs:subClassOf :Oxygen .

:Carbon-10 rdf:type owl:Class ;
        rdfs:subClassOf :Carbon .

:hasOxygen rdf:type owl:ObjectProperty ;
         rdfs:domain :Carbon ;
         rdfs:range :Oxygen .

:Individual-40 rdf:type :Oxygen-40 .

:Individual-10 rdf:type :Oxygen-10 .

:Individual-Carbon-10 rdf:type :Carbon-10 ;
        :hasOxygen :Individual-10 .

:Individual-Carbon-10-2 rdf:type :Carbon-10 ;
        :hasOxygen :Individual-40 .

Code which shows the problem:

public void test() throws OWLOntologyCreationException {
        OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
        ontology = manager.loadOntologyFromOntologyDocument(new File("ontology.ttl"));
        OpenlletReasoner res =  OpenlletReasonerFactory.getInstance().createReasoner(ontology);
        res.prepareReasoner();

        OWLClass carbon10 = new OWLClassImpl(IRI.create("http://example.com#Carbon-10"));
        OWLClass oxygen40 = new OWLClassImpl(IRI.create("http://example.com#Oxygen-40"));
        OWLClass oxygen10 = new OWLClassImpl(IRI.create("http://example.com#Oxygen-10"));
        OWLClass oxygenBase = new OWLClassImpl(IRI.create("http://example.com#Oxygen"));

        Set<OWLNamedIndividual> notCarbon10 = res.getInstances(new OWLObjectComplementOfImpl(carbon10), false).getFlattened();
        Set<OWLNamedIndividual> notOxygen40 = res.getInstances(new OWLObjectComplementOfImpl(oxygen40)).getFlattened();
        Set<OWLNamedIndividual> notOxygen10 = res.getInstances(new OWLObjectComplementOfImpl(oxygen10)).getFlattened();
        Set<OWLNamedIndividual> notOxygenBase = res.getInstances(new OWLObjectComplementOfImpl(oxygenBase)).getFlattened();

        Set<OWLNamedIndividual> carbon10Individuals = res.getInstances(carbon10).getFlattened();
        Set<OWLNamedIndividual> oxygen40Individuals = res.getInstances(oxygen40).getFlattened();
        Set<OWLNamedIndividual> oxygen10Individuals = res.getInstances(oxygen10).getFlattened();
        Set<OWLNamedIndividual> oxygenBaseIndividuals = res.getInstances(oxygenBase).getFlattened();

        System.out.println("Carbon-10 Individuals: "+carbon10Individuals);
        System.out.println("Oxygen-40 Individuals: "+oxygen40Individuals);
        System.out.println("Oxygen-10 Individuals: "+oxygen10Individuals);
        System.out.println("Oxygen Individuals: "+oxygenBaseIndividuals);

        if(notCarbon10.isEmpty()){
            System.err.println("(not Carbon-10): Should contain :Individual-10, :Individual-40");
        }
        if(notOxygen40.isEmpty()){
            System.err.println("(not Oxygen-40): Should contain :Individual-10, :Individual-Carbon-10, :Individual-Carbon-10-2");
        }
        if(notOxygen10.isEmpty()){
            System.err.println("(not Oxygen-10): Should contain :Individual-40, :Individual-Carbon-10, :Individual-Carbon-10-2");
        }

        if(notOxygenBase.isEmpty()){
            System.err.println("(not Oxygen): Should contain :Individual-Carbon-10, :Individual-Carbon-10-2");
        }

        OWLObjectProperty hasOxygen = new OWLObjectPropertyImpl(IRI.create("http://example.com#:hasOxygen"));
        OWLClassExpression hasOxygenSomeOxygen10 = new OWLObjectSomeValuesFromImpl(hasOxygen, oxygen10);

        // Carbon-10 and (hasOxygen only (not Oxygen-10)) -> only Individual is Individual-Carbon-10-2
        OWLClassExpression carbon10AndhasOxygenOnlyNotOxygen10 = new OWLObjectIntersectionOfImpl(Lists.newArrayList(carbon10, hasOxygenSomeOxygen10.getComplementNNF()));
        Set<OWLNamedIndividual> carbon10hasOxygen40 = res.getInstances(carbon10AndhasOxygenOnlyNotOxygen10).getFlattened();
        if(carbon10hasOxygen40.isEmpty()){
            System.err.println("(Carbon-10 and (hasOxygen only (not Oxygen-10))): Should contain :Individual-Carbon-10-2");
        }
    }
ignazio1977 commented 3 years ago

Is that the whole ontology? I cannot spot any axioms what would allow inference of individuals belonging to complements of those classes in there (no classes declared as disjoint, no individuals declared as different).

TortugaAttack commented 3 years ago

Ah sorry my fault, I was thinking/arguing from a Closed World assumption. I guess it is not configurable in Openllet to use a Closed World assumption?