Chaos
Chaos

Reputation: 113

OWLAPI and HermiT reasoner: non-asserted deleted individuals are still inferred

I am currently using OWLAPI jointly with HermiT reasoner and I am experiencing what appears to me as a bug. I defined several methods that update the ontology and during unit testing I reached several contradictory results.

My methods can add, remove and test the presence of an individual, let it belong to some specific class or let it belong to owl:Thing.

Here's an example of contradiction: a removed individual is still present as an instance of owl:Thing.

boolean added = ontology.addIndividualToClass("Person", login);
Assert.isTrue(added, "The individual must be present.");
ontology.think();

boolean exists = ontology.doesIndividualBelongToClass("Person", login);
Assert.isTrue(exists, "The individual must be found.");

boolean removed = ontology.removeIndividualFromClass("Person", login);
Assert.isTrue(removed, "The individual must be removed.");
ontology.think();

// The next assertions is satisfied.
exists = ontology.doesIndividualBelongToClass("Person", login);
Assert.isTrue(!exists, "The individual must not be found.");

// The next assertions will fire, interrupting the test.
exists = ontology.doesIndividualExist(login);
Assert.isTrue(!exists, "The individual must not be present.");

My methods operate in this way:

  1. the add method generates a new class assertion,
  2. the remove method finds and removes the corresponding class assertion in case it exist,
  3. finally, the test method checks both inferred and asserted individuals for name and possibly class.

All methods seem to operate correctly, but when an existing individual is removed it still appears as inferred. The method think() is basically the wrapping of flush() and forces the ontology to apply all pending changes. I am using HermiT in buffering mode and I noticed that switching to non-buffering does not solve the problem.

public boolean addIndividualToClass(String className, String login) {
    [...]  // Checks on parameters.
    OWLNamedIndividual individual = dataFactory.getOWLNamedIndividual(individualName, prefixManager);
    if (individual == null) throw new IllegalArgumentException("Could not get named individual.");
    OWLClassAssertionAxiom classAssertion = dataFactory.getOWLClassAssertionAxiom(clazz, individual);
    ChangeApplied changed = ontology.add(classAssertion);
    return changed.equals(ChangeApplied.SUCCESSFULLY) || changed.equals(ChangeApplied.NO_OPERATION);
}
public boolean removeIndividualFromClass(String clazz, String individualName) { 
    [...] // Checks on parameters.
    Optional<OWLClassAssertionAxiom> individualAssertionOpt =
            ontology
                    .getClassAssertionAxioms(clazz)
                    .stream()
                    .filter(
                            i -> i.getIndividual().asOWLNamedIndividual().getIRI().getRemainder().orElse("").matches(individualName)
                    )
                    .findFirst();

    if (!individualAssertionOpt.isPresent())
        return false;
    else {
        ChangeApplied changed = ontology.remove(individualAssertionOpt.get());

        return changed.equals(ChangeApplied.SUCCESSFULLY) || changed.equals(ChangeApplied.NO_OPERATION);
    }
}

I am experiencing problems with the following two methods:

public boolean doesIndividualBelongToClass(String className, String name) {
    [...] // Parameters tests and retrieval of 'clazz'.
    Set<OWLNamedIndividual> inferredIndividuals =
            reasoner
                    .getInstances(clazz, false)
                    .getFlattened()
                    .stream()
                    .filter(i -> i.getIRI().getRemainder().orElse("").equals(name))
                    .collect(Collectors.toSet());

    Set<OWLNamedIndividual> assertedIndividuals = ontology
            .individualsInSignature()
            .filter(i -> i.getIRI().getRemainder().orElse("").equals(name))
            .filter(
                    i -> reasoner
                            .getTypes(i)
                            .entities()
                            .filter(t -> t.getIRI().getRemainder().orElse("").equals(className))
                            .findFirst()
                            .isPresent()
            ).collect(Collectors.toSet());

    inferredIndividuals.addAll(assertedIndividuals);

    return inferredIndividuals
            .stream()
            .findFirst()
            .isPresent();
}
public boolean doesIndividualExist(String login)  {
    return doesIndividualBelongToClass("owl:Thing", login);
}

Once an individual has been removed doesIndividualExist() returns true, where doesIndividualBelongToClass() returns false. During debugging I noticed that removed individuals are still present as instances of the owl:Thing class.

I double checked and started asking DL queries through the method resoner.isSatisfiable(): the DL query {X} where X is a deleted individual name turns out to be satisfiable.

I made another test: I saved the ontology, browsed it with Protege and found that deleted individuals where not present, neither inferred.

Is someone aware of a workaround or an actual solution? Am I missing something?

Upvotes: 0

Views: 55

Answers (1)

Ignazio
Ignazio

Reputation: 10684

OWLReasoner instances can be buffering or non buffering - HermiT reasoners can be created with either setting. A buffering reasoner will see changes you make to the ontology but not apply these changes to its internal models until you call the flush() method on it. A non buffering reasoner will apply changes to its internal models immediately.

To confirm if this is the reason behind your issues, please show how you create the OWLReasoner instance. OWLReasonerFactory has methods for creating both buffering and non buffering reasoners.

Upvotes: 0

Related Questions