Search code examples
javaowlowl-api

OWL-API rename does not remove old owl:Thing subclass in reasoner


After renaming a class using OWL-API I'm not getting the list of subclasses I expect. I have created a small example to demonstrate.

The ontology contains 2 classes: Dog and Frisbee. I then rename Dog to Cat. After the rename, the list of owl:Thing subclasses contains both Dog and Cat.

Here is the rename-test.owl file:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns="http://example.org/owl-api/rename/"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <owl:Ontology rdf:about="http://example.org/owl-api/rename"/>
  <owl:Class rdf:about="http://example.org/owl-api/rename/Frisbee"/>
  <owl:Class rdf:about="http://example.org/owl-api/rename/Dog"/>
</rdf:RDF>

Here is the java test file:

package org.example;

import java.io.File;
import java.util.Collections;
import java.util.List;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.FileDocumentSource;
import org.semanticweb.owlapi.io.OWLOntologyDocumentSource;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory;
import org.semanticweb.owlapi.util.OWLEntityRenamer;

public class OwlapiRenameTest_main {
    
    public static void main(String[] args) {
        
        String owlPath = "c:\\owl-tests\\rename-test.owl";
        String oldUri = "http://example.org/owl-api/rename/Dog";
        String newUri = "http://example.org/owl-api/rename/Cat";
        runRenameTest(owlPath, oldUri, newUri);
    }
    
    static void runRenameTest(String owlPath, String oldUri, String newUri) {
        
        OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
        OWLOntologyDocumentSource owlFile = new FileDocumentSource(new File(owlPath));
        try {
            OWLOntology ontology = manager.loadOntologyFromOntologyDocument(owlFile);
            OWLReasoner reasoner = new StructuralReasonerFactory().createNonBufferingReasoner(ontology);
            
            dumpStmts(ontology);
            dumpSubclasses(ontology, reasoner);
            
            OWLEntityRenamer renamer = new OWLEntityRenamer(manager, Collections.singleton(ontology));
            List<? extends OWLOntologyChange> changes = renamer.changeIRI(
                    IRI.create(oldUri), 
                    IRI.create(newUri));
            manager.applyChanges(changes);
            
            System.out.println("** rename applied **");
            
            //does not help (which it shouldn't anyway for non-buffering reasoner)
            reasoner.flush();

            dumpStmts(ontology);
            dumpSubclasses(ontology, reasoner);
        } catch (OWLOntologyCreationException e) {
            e.printStackTrace();
        }
    }
    
    static void dumpStmts(OWLOntology ontology) {
        
        System.out.println("** dump all start **");
        ontology.axioms().forEach(axiom -> System.out.println("  axiom: " + axiom));
        System.out.println("** dump all end **");
    }
    
    static void dumpSubclasses(OWLOntology ontology, OWLReasoner reasoner) {
        
        System.out.println("** owl:Thing subclasses **");
        OWLClass thingClass = ontology.getOWLOntologyManager().getOWLDataFactory().getOWLClass(
                IRI.create("http://www.w3.org/2002/07/owl#Thing"));
        reasoner.getSubClasses(thingClass, true).entities().forEach(entity ->
                System.out.println("  " + entity.toString()));
    }
}

The output I get is as follows:

** dump all start **
  axiom: Declaration(Class(<http://example.org/owl-api/rename/Frisbee>))
  axiom: Declaration(Class(<http://example.org/owl-api/rename/Dog>))
** dump all end **
** owl:Thing subclasses **
  <http://example.org/owl-api/rename/Frisbee>
  <http://example.org/owl-api/rename/Dog>
** rename applied **
** dump all start **
  axiom: Declaration(Class(<http://example.org/owl-api/rename/Frisbee>))
  axiom: Declaration(Class(<http://example.org/owl-api/rename/Cat>))
** dump all end **
** owl:Thing subclasses **
  <http://example.org/owl-api/rename/Frisbee>
  <http://example.org/owl-api/rename/Dog>
  <http://example.org/owl-api/rename/Cat>

As you can see the Dog class is not in the list of axioms after renaming but the non-buffering reasoner thinks it is.

Do I need to tweak the code somehow? I tried using flush() on the reasoner which made no difference, which makes sense for a non-buffering reasoner. I can't find any other similar method to try. I don't want to save automatically as this is for an OWL editor that the user must manually save.


Solution

  • Do not use the Structural reasoner. It is not meant for real world use and is likely keeping caches it shouldn't. Just write out the axioms in the ontology, there are few enough in this ontology for that to work.