I want to programmatically get explanations for inferred axioms in consistent ontologies, in a similar manner that one can do in the Protégé UI. I cannot find any straightforward way. I have found the owlexplanation repo, but I cannot for the life of me solve the dependency issues to set up the owlexplanation
environment. I have also browsed the javadoc of owlapi regarding explanations (to avoid the other repo altogether), but I don't see anything useful beyond what I can already see browsing the Java source code.
I have thought of simply negating the inferred axiom, to get explanations through inconsistencies, but I would prefer something cleaner, and I am not sure this approach is correct anyway.
Other (possibly) useful context:
owlexplanation
, following this example from the HermiT source code..jar
file for owlexplanation
, in order to add it in my JPype classpath. My plan went sideways when I couldn't get the Java project to build in the first place.I would appreciate any insight or tips.
UPDATE Jan 6, 2022:
I decided to try once more with the owlexplanation
code with a clean head so here is where I am at:
pom.xml
file I get these problems:
Plugin 'org.apache.maven.plugins:maven-gpg-plugin:1.5' not found
Plugin 'org.sonatype.plugins:nexus-staging-maven-plugin:1.6.6' not found
UPDATE Jan 8, 2022: (Trying @Ignazio's answer)
I created a new IntelliJ project, and added the Maven dependencies @Ignazio mentioned (plus some others like slf4j
etc) and I got a working example (I think). Moving to my main project (using JPype), I had to manually download some .jars to include in the classpath (as maven can't be used here). These are the ones downloaded so far:
caffeine-3.0.5.jar hppcrt-0.7.5.jar org.semanticweb.hermit-1.4.5.519.jar slf4j-api-1.7.32.jar
commons-rdf-api-0.5.0.jar javax.inject-1.jar owlapi-distribution-5.1.9.jar slf4j-nop-1.7.32.jar
google-collect-1.0.jar owlexplanation-5.0.0.jar
Next, a NullPointerException
is thrown when trying to use loadOntologyFromOntologyDocument()
. I have tried re-downloading the jars as proposed here, but the Exception remains. Could it be that some .jar is missing? I downloaded them based on the thrown NoClassDefFoundError
that would occur.
This occurs with a common pizza.owl
file that it is otherwise fully working.
EDIT: I used mvn dependency:copy-dependencies -DoutputDirectory=OUTPUT_DIR
to get the dependencies and by using OUTPUT_DIR as the classpath, the NullPointerException
is gone, so it seems I was indeed missing some .jar file.
For the record, I then got other issues (gen.getExplanations()
was throwing a NoSuchMethodError
error), but I have no more time for debugging this. I will ditch JPype, however convenient it is, and simply call Java from Python with subprocess
. These are (I guess) Jpype problems, so I am accepting Ignazio's answer as it solved my Java/OWL API/owlexplanation side of things.
You're not just using the projects but actually building them from scratch, which requires more setup than using the published artifacts.
Shortcut that uses Maven available jars (via Maven Central, although other public repositories should do just as well)
Java code:
import java.io.File;
import java.util.Set;
import java.util.function.Supplier;
import org.junit.Test;
import org.semanticweb.HermiT.ReasonerFactory;
import org.semanticweb.owl.explanation.api.Explanation;
import org.semanticweb.owl.explanation.api.ExplanationGenerator;
import org.semanticweb.owl.explanation.api.ExplanationGeneratorFactory;
import org.semanticweb.owl.explanation.api.ExplanationProgressMonitor;
import org.semanticweb.owl.explanation.impl.blackbox.Configuration;
import org.semanticweb.owl.explanation.impl.blackbox.DivideAndConquerContractionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.EntailmentCheckerFactory;
import org.semanticweb.owl.explanation.impl.blackbox.InitialEntailmentCheckStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.StructuralTypePriorityExpansionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.checker.BlackBoxExplanationGeneratorFactory;
import org.semanticweb.owl.explanation.impl.blackbox.checker.SatisfiabilityEntailmentCheckerFactory;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
public class CheckOntology {
@Test
public void should() throws Exception {
OWLOntologyManager m = OWLManager.createOWLOntologyManager();
OWLOntology o = m.loadOntologyFromOntologyDocument(new File("pizza.owl"));
OWLReasonerFactory rf = new ReasonerFactory(); // Get hold of a reasoner factory
// Create the explanation generator factory which uses reasoners provided by the specified
// reasoner factory
ExplanationGeneratorFactory<OWLAxiom> genFac =
createExplanationGeneratorFactory(rf, null, OWLManager::createOWLOntologyManager);
// Now create the actual explanation generator for our ontology
ExplanationGenerator<OWLAxiom> gen = genFac.createExplanationGenerator(o);
// Ask for explanations for some entailment
// Get a reference to the axiom that represents the entailment that we want explanation for
// this will just run the explanations for all axioms
o.logicalAxioms().forEach(e -> explain(e, gen));
}
void explain(OWLAxiom entailment, ExplanationGenerator<OWLAxiom> gen) {
// Get our explanations. Ask for a maximum of 5.
try {
Set<Explanation<OWLAxiom>> expl = gen.getExplanations(entailment, 5);
System.out.println("CheckOntology.explain() " + entailment);
expl.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}
}
// this method replicates code existing in the owlexplanation project; it's needed because the factories in owlexplanation do not set InitialEntailmentCheckStrategy correctly
public static ExplanationGeneratorFactory<OWLAxiom> createExplanationGeneratorFactory(
OWLReasonerFactory reasonerFactory, ExplanationProgressMonitor<OWLAxiom> progressMonitor,
Supplier<OWLOntologyManager> m) {
EntailmentCheckerFactory<OWLAxiom> checker =
new SatisfiabilityEntailmentCheckerFactory(reasonerFactory, m);
Configuration<OWLAxiom> config = new Configuration<>(checker,
new StructuralTypePriorityExpansionStrategy<OWLAxiom>(
InitialEntailmentCheckStrategy.PERFORM, m),
new DivideAndConquerContractionStrategy<OWLAxiom>(), progressMonitor, m);
return new BlackBoxExplanationGeneratorFactory<>(config);
}
}
Maven configuration:
4.0.0 blah blah 0.0.1-SNAPSHOT blah junit junit 4.12 net.sourceforge.owlapi org.semanticweb.hermit 1.4.5.519 net.sourceforge.owlapi owlexplanation 5.0.0
HermiT is available on Maven Central via release builds I've made - the patch version refers to the OWLAPI version it was built with. Here 1.4.5.519 means HermiT was built with OWLAPI 5.1.9. owlexplanation 5.0.0 was built with OWLAPI 5, so it's the same major OWLAPI version for the project.
This code sample doesn't do a lot because it just looks for explanations of asserted axioms. Often the explanation is just the axiom itself, as it's asserted. Varying the chosen axiom, or using axioms not asserted in the ontology, should give you the explanations you are after.