diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index 2949d5f25..b2f0390f8 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -2,6 +2,7 @@ package edu.cornell.mannlib.vitro.webapp.reasoner; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -35,8 +36,7 @@ import com.hp.hpl.jena.vocabulary.RDFS; /** * Allows for real-time incremental materialization or retraction of RDFS- * style class and property subsumption based ABox inferences as statements - * are added to or removed from the (ABox or TBox) knowledge base. - * + * are added to or removed from the (ABox or TBox) knowledge base. */ public class SimpleReasoner extends StatementListener { @@ -101,6 +101,7 @@ public class SimpleReasoner extends StatementListener { try { if (stmt.getPredicate().equals(RDF.type)) { addedABoxTypeAssertion(stmt, inferenceModel); + setMostSpecificTypes(stmt.getSubject(), inferenceModel); } else { addedABoxAssertion(stmt,inferenceModel); } @@ -121,6 +122,7 @@ public class SimpleReasoner extends StatementListener { try { if (stmt.getPredicate().equals(RDF.type)) { removedABoxTypeAssertion(stmt, inferenceModel); + setMostSpecificTypes(stmt.getSubject(), inferenceModel); } else { removedABoxAssertion(stmt, inferenceModel); } @@ -156,22 +158,22 @@ public class SimpleReasoner extends StatementListener { OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); if (stmt.getPredicate().equals(RDFS.subClassOf)) { - addedSubClass(subject,object); + addedSubClass(subject,object,inferenceModel); } else { // equivalent class is the same as subclass in both directions - addedSubClass(subject,object); - addedSubClass(object,subject); + addedSubClass(subject,object,inferenceModel); + addedSubClass(object,subject,inferenceModel); } } else if (stmt.getPredicate().equals(RDFS.subPropertyOf) || stmt.getPredicate().equals(OWL.equivalentProperty)) { OntProperty subject = tboxModel.getOntProperty((stmt.getSubject()).getURI()); OntProperty object = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI()); if (stmt.getPredicate().equals(RDFS.subPropertyOf)) { - addedSubProperty(subject, object, inferenceModel); + addedSubProperty(subject,object,inferenceModel); } else { // equivalent property is the same as subProperty in both directions - addedSubProperty(subject, object, inferenceModel); - addedSubProperty(object, subject, inferenceModel); + addedSubProperty(subject,object,inferenceModel); + addedSubProperty(object,subject,inferenceModel); } } } catch (Exception e) { @@ -202,11 +204,11 @@ public class SimpleReasoner extends StatementListener { OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); if (stmt.getPredicate().equals(RDFS.subClassOf)) { - removedSubClass(subject,object); + removedSubClass(subject,object,inferenceModel); } else { // equivalent class is the same as subclass in both directions - removedSubClass(subject,object); - removedSubClass(object,subject); + removedSubClass(subject,object,inferenceModel); + removedSubClass(object,subject,inferenceModel); } } else if (stmt.getPredicate().equals(RDFS.subPropertyOf) || stmt.getPredicate().equals(OWL.equivalentProperty)) { OntProperty subject = tboxModel.getOntProperty((stmt.getSubject()).getURI()); @@ -494,11 +496,11 @@ public class SimpleReasoner extends StatementListener { * individual that is typed as B, either in the ABox or in the * inferred model, assert that it is of type A. */ - public void addedSubClass(OntClass subClass, OntClass superClass) { + public void addedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { log.debug("subClass = " + subClass.getURI() + " superClass = " + superClass.getURI()); - aboxModel.enterCriticalSection(Lock.READ); + aboxModel.enterCriticalSection(Lock.WRITE); inferenceModel.enterCriticalSection(Lock.WRITE); try { @@ -517,6 +519,7 @@ public class SimpleReasoner extends StatementListener { if (!inferenceModel.contains(infStmt)) { inferenceModel.add(infStmt); + setMostSpecificTypes(infStmt.getSubject(), inferenceModel); } } } finally { @@ -532,11 +535,11 @@ public class SimpleReasoner extends StatementListener { * UNLESS the individual is of some type C that is a subClass * of A (including A itself) */ - public void removedSubClass(OntClass subClass, OntClass superClass) { + public void removedSubClass(OntClass subClass, OntClass superClass, Model inferenceModel) { log.debug("subClass = " + subClass.getURI() + ". superClass = " + superClass.getURI()); - aboxModel.enterCriticalSection(Lock.READ); + aboxModel.enterCriticalSection(Lock.WRITE); inferenceModel.enterCriticalSection(Lock.WRITE); try { @@ -559,6 +562,7 @@ public class SimpleReasoner extends StatementListener { if (inferenceModel.contains(infStmt)) { inferenceModel.remove(infStmt); + setMostSpecificTypes(infStmt.getSubject(), inferenceModel); } } } finally { @@ -661,9 +665,9 @@ public class SimpleReasoner extends StatementListener { * indicate them for the individual with the core:mostSpecificType * annotation. */ - public void setMostSpecificTypes(Resource individual) { + public void setMostSpecificTypes(Resource individual, Model inferenceModel) { - aboxModel.enterCriticalSection(Lock.READ); + aboxModel.enterCriticalSection(Lock.WRITE); inferenceModel.enterCriticalSection(Lock.READ); tboxModel.enterCriticalSection(Lock.READ); @@ -672,12 +676,13 @@ public class SimpleReasoner extends StatementListener { unionModel.addSubModel(aboxModel); unionModel.addSubModel(inferenceModel); - HashSet typeURIs = new HashSet(); - StmtIterator iter = unionModel.listStatements((Resource) null, RDF.type, (RDFNode) null); + List types = new ArrayList(); + + StmtIterator stmtIter = unionModel.listStatements(individual, RDF.type, (RDFNode) null); - while (iter.hasNext()) { + while (stmtIter.hasNext()) { - Statement stmt = iter.next(); + Statement stmt = stmtIter.next(); if ( !stmt.getObject().isResource() ) { log.warn("The object of this rdf:type assertion is expected to be a resource: " + stmtString(stmt)); @@ -692,21 +697,48 @@ public class SimpleReasoner extends StatementListener { } if (ontClass.isAnon()) continue; - - if (ontClass.hasSubClass()) continue; - - typeURIs.add(ontClass.getURI()); - - Iterator eIter = ontClass.listEquivalentClasses(); - - while (eIter.hasNext()) { - OntClass equivClass = eIter.next(); - if (equivClass.isAnon()) continue; - typeURIs.add(equivClass.getURI()); - } + + types.add(ontClass); } + + HashSet typeURIs = new HashSet(); + List types2 = new ArrayList(); + types2.addAll(types); - setMostSpecificTypes(individual, typeURIs); + Iterator typeIter = types.iterator(); + + while (typeIter.hasNext()) { + OntClass type = typeIter.next(); + + boolean add = true; + Iterator typeIter2 = types2.iterator(); + while (typeIter2.hasNext()) { + OntClass type2 = typeIter2.next(); + + if (type.equals(type2)) { + continue; + } + + if (type.hasSubClass(type2, false) && !type2.hasSubClass(type, false)) { + add = false; + break; + } + } + + if (add) { + typeURIs.add(type.getURI()); + + Iterator eIter = type.listEquivalentClasses(); + + while (eIter.hasNext()) { + OntClass equivClass = eIter.next(); + if (equivClass.isAnon()) continue; + typeURIs.add(equivClass.getURI()); + } + } + } + + setMostSpecificTypes(individual, typeURIs, inferenceModel); } finally { aboxModel.leaveCriticalSection(); @@ -717,27 +749,30 @@ public class SimpleReasoner extends StatementListener { return; } - public void setMostSpecificTypes(Resource individual, HashSet typeURIs) { + public void setMostSpecificTypes(Resource individual, HashSet typeURIs, Model inferenceModel) { aboxModel.enterCriticalSection(Lock.WRITE); try { + Model retractions = ModelFactory.createDefaultModel(); // remove obsolete most-specific-type assertions - StmtIterator iter = aboxModel.listStatements((Resource) null, mostSpecificType, (RDFNode) null); + StmtIterator iter = aboxModel.listStatements(individual, mostSpecificType, (RDFNode) null); while (iter.hasNext()) { Statement stmt = iter.next(); - + if ( !stmt.getObject().isLiteral() ) { log.warn("The object of this assertion is expected to be a literal: " + stmtString(stmt)); continue; } - + if (!typeURIs.contains(stmt.getObject().asLiteral().getLexicalForm())) { - aboxModel.remove(stmt); + retractions.add(stmt); } } + aboxModel.remove(retractions); + // add new most-specific-type assertions Iterator typeIter = typeURIs.iterator(); @@ -746,6 +781,7 @@ public class SimpleReasoner extends StatementListener { Literal uriLiteral = ResourceFactory.createTypedLiteral(typeURI, XSDDatatype.XSDanyURI); if (!aboxModel.contains(individual, mostSpecificType, uriLiteral)) { + Statement toAdd = ResourceFactory.createStatement(individual, mostSpecificType, uriLiteral); aboxModel.add(individual, mostSpecificType, uriLiteral); } } @@ -791,7 +827,7 @@ public class SimpleReasoner extends StatementListener { // recompute the inferences inferenceRebuildModel.enterCriticalSection(Lock.WRITE); - aboxModel.enterCriticalSection(Lock.READ); + aboxModel.enterCriticalSection(Lock.WRITE); tboxModel.enterCriticalSection(Lock.READ); try { @@ -802,6 +838,7 @@ public class SimpleReasoner extends StatementListener { while (iter.hasNext()) { Statement stmt = iter.next(); addedABoxTypeAssertion(stmt, inferenceRebuildModel); + setMostSpecificTypes(stmt.getSubject(), inferenceRebuildModel); } log.info("Computing property-based ABox inferences"); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java index 444052f7a..fd7474f5a 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java @@ -9,15 +9,20 @@ import org.junit.Before; import org.junit.Test; import org.mindswap.pellet.jena.PelletReasonerFactory; +import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; +import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; +import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; @@ -28,6 +33,7 @@ public class SimpleReasonerTest extends AbstractTestClass { private Resource objectProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#ObjectProperty"); + private static final String mostSpecificTypePropertyURI = "http://vivoweb.org/ontology/core#mostSpecificType"; @Before public void suppressErrorOutput() { @@ -35,7 +41,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Turn off log messages to console setLoggerLevel(SimpleReasoner.class, Level.OFF); } - + /* * Test that when an individual is asserted to be of a type, * its asserted type is not added to the inference graph @@ -46,6 +52,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Create a Tbox with a simple class hierarchy. B is a subclass of A. // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -84,6 +91,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Create a Tbox with a simple class hierarchy. D and E are subclasses // of C. B and C are subclasses of A. Pellet will compute TBox inferences. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -137,6 +145,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -184,6 +193,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -223,6 +233,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -271,6 +282,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // and B is a subclass of A. Pellet will compute TBox inferences. OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntClass classA = tBox.createClass("http://test.vivo/A"); classA.setLabel("class A", "en-US"); @@ -336,6 +348,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -403,6 +416,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -462,6 +476,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -547,6 +562,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -589,6 +605,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -630,6 +647,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -684,6 +702,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -726,6 +745,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -782,6 +802,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -849,6 +870,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // Pellet will compute TBox inferences OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); Model inf = ModelFactory.createDefaultModel(); @@ -933,6 +955,209 @@ public class SimpleReasonerTest extends AbstractTestClass { } + @Test + /* + * Test computation of mostSpecificType annotations in response + * to an added/removed ABox type assertion. + */ + public void mstTest1(){ + // Create TBox, ABox and Inference models and register + // the ABox reasoner listeners with the ABox and TBox + // Pellet will compute TBox inferences + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + Model inf = ModelFactory.createDefaultModel(); + + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + + // Set up the Tbox with a class hierarchy. C is a subclass of A + // and Y. D and E are subclasses C. B is a subclass of D. + // Pellet will compute TBox inferences. + + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); + + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + + OntClass classB = tBox.createClass("http://test.vivo/B"); + classB.setLabel("class B", "en-US"); + + OntClass classC = tBox.createClass("http://test.vivo/C"); + classC.setLabel("class C", "en-US"); + + OntClass classD = tBox.createClass("http://test.vivo/D"); + classD.setLabel("class D", "en-US"); + + OntClass classE = tBox.createClass("http://test.vivo/E"); + classE.setLabel("class E", "en-US"); + + OntClass classY = tBox.createClass("http://test.vivo/Y"); + classE.setLabel("class Y", "en-US"); + + classY.addSubClass(classC); + classA.addSubClass(classC); + + classC.addSubClass(classD); + classC.addSubClass(classE); + + classD.addSubClass(classB); + + // Add the statement individual x is of type Y to the ABox + Resource ind_x = aBox.createResource("http://test.vivo/x"); + aBox.add(ind_x, RDF.type, classD); + + // Verify ind_x mostSpecificType annotation for D + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + + // Verify ind_x doesn't have a mostSpecificType annotation for + // A, Y, C, E or B. + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classA.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classY.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classC.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classE.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classB.getURI(), XSDDatatype.XSDanyURI))); + + aBox.remove(ind_x, RDF.type, classD); // retract assertion that x is of type D. + // Verify that D is not longer the most specific type + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + } + + @Test + /* + * Test computation of mostSpecificType annotations in response + * to an added ABox type assertion. + */ + public void mstTest2(){ + // Create TBox, ABox and Inference models and register + // the ABox reasoner listeners with the ABox and TBox + // Pellet will compute TBox inferences + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + Model inf = ModelFactory.createDefaultModel(); + + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + + // Set up the Tbox with a class hierarchy. B is a subclass of A, + // C is a subclass of B, and A is a subclass of C. + // Pellet should infer these three classes to be equivalent. + + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); + + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + + OntClass classB = tBox.createClass("http://test.vivo/B"); + classB.setLabel("class B", "en-US"); + + OntClass classC = tBox.createClass("http://test.vivo/C"); + classC.setLabel("class C", "en-US"); + + classA.addSubClass(classB); + classB.addSubClass(classC); + classC.addSubClass(classA); + + // Add the statement individual x is of type B to the ABox + Resource ind_x = aBox.createResource("http://test.vivo/x"); + aBox.add(ind_x, RDF.type, classB); + + StmtIterator stmtIterator = aBox.listStatements(ind_x, mostSpecificType, (RDFNode)null); + + // Verify ind_x mostSpecificType annotation for A, B and C + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classA.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classB.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classC.getURI(), XSDDatatype.XSDanyURI))); + } + + @Test + /* + * Test computation of mostSpecificType annotations in response + * to an added/removed TBox assertions. + */ + public void mstTest3(){ + // Create TBox, ABox and Inference models and register + // the ABox reasoner listeners with the ABox and TBox + // Pellet will compute TBox inferences + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + Model inf = ModelFactory.createDefaultModel(); + + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); + + OntClass OWL_THING = tBox.createClass(OWL.Thing.getURI()); + AnnotationProperty mostSpecificType = tBox.createAnnotationProperty(mostSpecificTypePropertyURI); + + // Set up the Tbox with classes A, B, C, D, + // E, F and G + + OntClass classA = tBox.createClass("http://test.vivo/A"); + classA.setLabel("class A", "en-US"); + + OntClass classB = tBox.createClass("http://test.vivo/B"); + classB.setLabel("class B", "en-US"); + + OntClass classC = tBox.createClass("http://test.vivo/C"); + classC.setLabel("class C", "en-US"); + + OntClass classD = tBox.createClass("http://test.vivo/D"); + classD.setLabel("class D", "en-US"); + + OntClass classE = tBox.createClass("http://test.vivo/E"); + classE.setLabel("class E", "en-US"); + + OntClass classF = tBox.createClass("http://test.vivo/F"); + classE.setLabel("class F", "en-US"); + + OntClass classG = tBox.createClass("http://test.vivo/G"); + classE.setLabel("class G", "en-US"); + + // add individuals x, y and z to the aBox + Resource ind_x = aBox.createResource("http://test.vivo/x"); + Resource ind_y = aBox.createResource("http://test.vivo/y"); + + aBox.add(ind_x, RDF.type, OWL_THING); + aBox.add(ind_y, RDF.type, classD); + + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(OWL.Thing.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + + aBox.add(ind_x, RDF.type, classC); + aBox.add(ind_y, RDF.type, classF); + + Assert.assertFalse(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(OWL.Thing.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_x, mostSpecificType, ResourceFactory.createTypedLiteral(classC.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classF.getURI(), XSDDatatype.XSDanyURI))); + + // Set up a class hierarchy. + // Pellet will compute TBox inferences. + + classA.addSubClass(classB); + classA.addSubClass(classC); + classA.addSubClass(classD); + + classC.addSubClass(classE); + + classD.addSubClass(classF); + classD.addSubClass(classG); + + Assert.assertFalse(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + Assert.assertTrue(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classF.getURI(), XSDDatatype.XSDanyURI))); + + // If F is removed as a subclass of D, then D should once again be a most specific type + // for y. + classD.removeSubClass(classF); + Assert.assertTrue(aBox.contains(ind_y, mostSpecificType, ResourceFactory.createTypedLiteral(classD.getURI(), XSDDatatype.XSDanyURI))); + + } // To help in debugging the unit test void printModels(OntModel ontModel) {