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 57d8be01d..4a71f917b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -24,11 +24,12 @@ import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.util.iterator.ExtendedIterator; +import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.RDF; import com.hp.hpl.jena.vocabulary.RDFS; /** - * Allows for instant incremental materialization or retraction of 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. * @@ -77,135 +78,151 @@ public class SimpleReasoner extends StatementListener { } /* - * Performs incremental selected ABox reasoning based - * on a new type assertion (assertion that an individual - * is of a certain type) added to the ABox. - * + * Performs selected incremental ABox reasoning based + * on the addition of a new statement (aka assertion) + * to the ABox. */ @Override public void addedStatement(Statement stmt) { try { - if (stmt.getPredicate().equals(RDF.type)) { - addedType(stmt, inferenceModel); + addedABoxTypeAssertion(stmt, inferenceModel); + } else { + addedABoxAssertion(stmt,inferenceModel); } - } catch (Exception e) { // don't stop the edit if there's an exception - log.error("Exception while adding incremental inferences: ", e); + log.error("Exception while adding inferences: ", e); } } /* - * Performs incremental selected ABox reasoning based - * on a removed type assertion (assertion that an individual - * is of a certain type) from the ABox. - * + * Performs selected incremental ABox reasoning based + * on the retraction of a statement (aka assertion) + * from the ABox. */ @Override public void removedStatement(Statement stmt) { try { - if (stmt.getPredicate().equals(RDF.type)) { - removedType(stmt); + removedABoxTypeAssertion(stmt, inferenceModel); + } else { + removedABoxAssertion(stmt, inferenceModel); } - } catch (Exception e) { // don't stop the edit if there's an exception log.error("Exception while retracting inferences: ", e); } } - + /* * Performs incremental selected ABox reasoning based - * on changes to the class hierarchy. - * - * Handles subclassOf and equivalentClass assertions + * on changes to the class or property hierarchy. * + * Handles rdfs:subclassOf, owl:equivalentClass, + * rdfs:subPropertyOf and owl:equivalentProperty assertions */ public void addedTBoxStatement(Statement stmt) { + addedTBoxStatement(stmt, inferenceModel); + } + + public void addedTBoxStatement(Statement stmt, Model inferenceModel) { try { + log.debug("added TBox assertion = " + stmt.toString()); - if ( !(stmt.getPredicate().equals(RDFS.subClassOf) - || stmt.getPredicate().equals(RDFS.subClassOf) ) ) { - return; + if ( stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) ) { + // ignore anonymous classes + if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { + return; + } + + OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); + OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + + if (stmt.getPredicate().equals(RDFS.subClassOf)) { + addedSubClass(subject,object); + } else { + // equivalent class is the same as subclass in both directions + addedSubClass(subject,object); + addedSubClass(object,subject); + } + } 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); + } else { + // equivalent property is the same as subProperty in both directions + addedSubProperty(subject, object, inferenceModel); + addedSubProperty(object, subject, inferenceModel); + } } - - // ignore anonymous classes - if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { - return; - } - - log.debug("stmt = " + stmt.toString()); - - OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); - OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); - - if (stmt.getPredicate().equals(RDFS.subClassOf)) { - addedSubClass(subject,object); - } else { - // equivalent class is the same as subclass in both directions - addedSubClass(subject,object); - addedSubClass(object,subject); - } - } catch (Exception e) { // don't stop the edit if there's an exception - log.error("Exception while adding incremental inferences: ", e); + log.error("Exception while adding inference(s): ", e); } } /* * Performs incremental selected ABox reasoning based - * on changes to the class hierarchy. - * - * Handles subclassOf and equivalentClass assertions + * on changes to the class or property hierarchy. * + * Handles rdfs:subclassOf, owl:equivalentClass, + * rdfs:subPropertyOf and owl:equivalentProperty assertions */ public void removedTBoxStatement(Statement stmt) { try { + log.debug("removed TBox assertion = " + stmt.toString()); - if ( !(stmt.getPredicate().equals(RDFS.subClassOf) - || stmt.getPredicate().equals(RDFS.subClassOf) ) ) { - return; + if ( stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) ) { + // ignore anonymous classes + if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { + return; + } + + OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); + OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); + + if (stmt.getPredicate().equals(RDFS.subClassOf)) { + removedSubClass(subject,object); + } else { + // equivalent class is the same as subclass in both directions + removedSubClass(subject,object); + removedSubClass(object,subject); + } + } 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)) { + removedSubProperty(subject,object); + } else { + // equivalent property is the same as subProperty in both directions + removedSubProperty(subject,object); + removedSubProperty(object,subject); + } } - - // ignore anonymous classes - if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { - return; - } - - log.debug("stmt = " + stmt.toString()); - - OntClass subject = tboxModel.getOntClass((stmt.getSubject()).getURI()); - OntClass object = tboxModel.getOntClass(((Resource)stmt.getObject()).getURI()); - - if (stmt.getPredicate().equals(RDFS.subClassOf)) { - removedSubClass(subject,object); - } else { - // equivalent class is the same as subclass in both directions - removedSubClass(subject,object); - removedSubClass(object,subject); - } - } catch (Exception e) { // don't stop the edit if there's an exception - log.error("Exception while removing incremental inferences: ", e); + log.error("Exception while removing inference(s): ", e); } } - + /* + * Performs incremental reasoning based on a new type assertion + * added to the ABox (assertion that an individual is of a certain + * type). + * * If it is added that B is of type A, then for each superclass of * A assert that B is of that type. * */ - public void addedType(Statement stmt, Model inferenceModel) { - - //log.debug("stmt = " + stmt.toString()); + public void addedABoxTypeAssertion(Statement stmt, Model inferenceModel) { tboxModel.enterCriticalSection(Lock.READ); @@ -215,8 +232,7 @@ public class SimpleReasoner extends StatementListener { if (cls != null) { List parents = (cls.listSuperClasses(false)).toList(); - parents.addAll((cls.listEquivalentClasses()).toList()); - + parents.addAll((cls.listEquivalentClasses()).toList()); Iterator parentIt = parents.iterator(); while (parentIt.hasNext()) { @@ -247,13 +263,61 @@ public class SimpleReasoner extends StatementListener { } } + /* + * Performs incremental property-based reasoning. + * + * Materializes inferences based on the rdfs:subPropertyOf relationship. + * If it is added that x propB y and propB is a sub-property of propA + * then add x propA y to the inference graph. + */ + public void addedABoxAssertion(Statement stmt, Model inferenceModel) { + + tboxModel.enterCriticalSection(Lock.READ); + + try { + OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); + + if (prop != null) { + + //TODO: have trouble parametizing the template with ? extends OntProperty + List superProperties = prop.listSuperProperties(false).toList(); + superProperties.addAll(prop.listEquivalentProperties().toList()); + Iterator superIt = superProperties.iterator(); + + while (superIt.hasNext()) { + OntProperty superProp = superIt.next(); + + if ( !((prop.isObjectProperty() && superProp.isObjectProperty()) || (prop.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { + log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + prop.getURI() + " super-property:" + superProp.getURI()); + return; + } + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (!inferenceModel.contains(infStmt) && !infStmt.equals(stmt) ) { + //log.debug("Adding this inferred statement: " + infStmt.toString() ); + inferenceModel.add(infStmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } else { + log.warn("Didn't find target property (the predicate of the added statement) in the TBox: " + stmt.getPredicate().getURI()); + } + } finally { + tboxModel.leaveCriticalSection(); + } + } + /* * If it is removed that B is of type A, then for each superclass of A remove * the inferred statement that B is of that type UNLESS it is otherwise entailed * that B is of that type. * */ - public void removedType(Statement stmt) { + public void removedABoxTypeAssertion(Statement stmt, Model inferenceModel) { //log.debug("stmt = " + stmt.toString()); @@ -266,7 +330,6 @@ public class SimpleReasoner extends StatementListener { List parents = (cls.listSuperClasses(false)).toList(); parents.addAll((cls.listEquivalentClasses()).toList()); - Iterator parentIt = parents.iterator(); while (parentIt.hasNext()) { @@ -301,9 +364,63 @@ public class SimpleReasoner extends StatementListener { tboxModel.leaveCriticalSection(); } } + + /* + * Performs incremental property-based reasoning. + * + * Retracts inferences based on the rdfs:subPropertyOf relationship. + * If it is removed that x propB y and propB is a sub-property of propA + * then remove x propA y from the inference graph UNLESS it that + * statement is otherwise entailed. + */ + public void removedABoxAssertion(Statement stmt, Model inferenceModel) { + + tboxModel.enterCriticalSection(Lock.READ); + + try { + OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); + + if (prop != null) { + + //TODO: trouble parameterizing these templates with "? extends OntProperty" + List superProperties = prop.listSuperProperties(false).toList(); + superProperties.addAll(prop.listEquivalentProperties().toList()); + Iterator superIt = superProperties.iterator(); + + while (superIt.hasNext()) { + OntProperty superProp = superIt.next(); + + if ( !((prop.isObjectProperty() && superProp.isObjectProperty()) || (prop.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { + log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + prop.getURI() + " super-property:" + superProp.getURI()); + return; + } - // Returns true if it is entailed by class subsumption that subject is - // of type cls; otherwise returns false. + // if the statement is still entailed without the removed + // statement then don't remove it from the inferences + if (entailedByPropertySubsumption(stmt.getSubject(), superProp, stmt.getObject())) continue; + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(infStmt)) { + //log.debug("Removing this inferred statement: " + infStmt.toString() + " - " + infStmt.getSubject().toString() + " - " + infStmt.getPredicate().toString() + " - " + infStmt.getObject().toString()); + inferenceModel.remove(infStmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } else { + log.debug("Didn't find target predicate (the predicate of the removed statement) in the TBox: " + stmt.getPredicate().getURI()); + } + } finally { + tboxModel.leaveCriticalSection(); + } + } + + // Returns true if it is entailed by class subsumption that + // subject is of type cls; otherwise returns false. public boolean entailedType(Resource subject, OntClass cls) { //log.debug("subject = " + subject.getURI() + " class = " + cls.getURI()); @@ -313,8 +430,8 @@ public class SimpleReasoner extends StatementListener { try { ExtendedIterator iter = cls.listSubClasses(false); - while (iter.hasNext()) { - + + while (iter.hasNext()) { OntClass childClass = iter.next(); Statement stmt = ResourceFactory.createStatement(subject, RDF.type, childClass); if (aboxModel.contains(stmt)) return true; @@ -327,10 +444,33 @@ public class SimpleReasoner extends StatementListener { } } + // Returns true if the statement is entailed by property subsumption + public boolean entailedByPropertySubsumption(Resource subject, OntProperty prop, RDFNode object) { + + aboxModel.enterCriticalSection(Lock.READ); + tboxModel.enterCriticalSection(Lock.READ); + + try { + + ExtendedIterator iter = prop.listSubProperties(false); + + while (iter.hasNext()) { + OntProperty subProp = iter.next(); + Statement stmt = ResourceFactory.createStatement(subject, subProp, object); + if (aboxModel.contains(stmt)) return true; + } + + return false; + } finally { + aboxModel.leaveCriticalSection(); + tboxModel.leaveCriticalSection(); + } + } + /* - * If added that B is a subclass of A, then find all individuals - * that are typed as B, either in the ABox or in the inferred model - * and assert that they are of type A. + * If it is added that B is a subClass of A, then for each + * 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) { @@ -366,11 +506,10 @@ public class SimpleReasoner extends StatementListener { /* * If removed that B is a subclass of A, then for each individual - * that is of type B, either inferred or in the ABox, then - * remove the inferred assertion that it is of type A, - * UNLESS the individual is of some type C that is - * a subClass of A (including A itself) - * + * that is of type B, either inferred or in the ABox, remove the + * assertion that it is of type A from the inferred model, + * UNLESS the individual is of some type C that is a subClass + * of A (including A itself) */ public void removedSubClass(OntClass subClass, OntClass superClass) { @@ -407,6 +546,97 @@ public class SimpleReasoner extends StatementListener { inferenceModel.leaveCriticalSection(); } } + + /* + * If it is added that B is a subProperty of A, then for each assertion + * involving predicate B, either in the ABox or in the inferred model + * assert the same relationship for predicate A + */ + public void addedSubProperty(OntProperty subProp, OntProperty superProp, Model inferenceModel) { + + log.debug("subProperty = " + subProp.getURI() + " superProperty = " + subProp.getURI()); + + if ( !((subProp.isObjectProperty() && superProp.isObjectProperty()) || (subProp.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { + log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + subProp.getURI() + " super-property:" + superProp.getURI()); + return; + } + + aboxModel.enterCriticalSection(Lock.READ); + inferenceModel.enterCriticalSection(Lock.WRITE); + + try { + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + + StmtIterator iter = unionModel.listStatements((Resource) null, subProp, (RDFNode) null); + + while (iter.hasNext()) { + + Statement stmt = iter.next(); + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); + + inferenceModel.enterCriticalSection(Lock.WRITE); + + if (!inferenceModel.contains(infStmt)) { + //log.debug("Adding this inferred statement: " + infStmt.toString() ); + inferenceModel.add(infStmt); + } + } + } finally { + aboxModel.leaveCriticalSection(); + inferenceModel.leaveCriticalSection(); + } + } + + /* + * If it is removed that B is a subProperty of A, then for each + * assertion involving predicate B, either in the ABox or in the + * inferred model, remove the same assertion involving predicate + * A from the inferred model, UNLESS the assertion is otherwise + * entailed by property subsumption. + */ + public void removedSubProperty(OntProperty subProp, OntProperty superProp) { + + log.debug("subProperty = " + subProp.getURI() + " superProperty = " + subProp.getURI()); + + if ( !((subProp.isObjectProperty() && superProp.isObjectProperty()) || (subProp.isDatatypeProperty() && superProp.isDatatypeProperty())) ) { + log.warn("sub-property and super-property do not have the same type. No inferencing will be performed. sub-property: " + subProp.getURI() + " super-property:" + superProp.getURI()); + return; + } + + aboxModel.enterCriticalSection(Lock.READ); + inferenceModel.enterCriticalSection(Lock.WRITE); + + try { + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + + StmtIterator iter = unionModel.listStatements((Resource) null, subProp, (RDFNode) null); + + while (iter.hasNext()) { + + Statement stmt = iter.next(); + + // if the statement is entailed without the removed subPropertyOf + // relationship then don't remove it from the inferences + if (entailedByPropertySubsumption(stmt.getSubject(), superProp, stmt.getObject())) continue; + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), superProp, stmt.getObject()); + + inferenceModel.enterCriticalSection(Lock.WRITE); + + if (inferenceModel.contains(infStmt)) { + //log.debug("Adding this inferred statement: " + infStmt.toString() ); + inferenceModel.remove(infStmt); + } + } + } finally { + aboxModel.leaveCriticalSection(); + inferenceModel.leaveCriticalSection(); + } + } private boolean recomputing = false; @@ -440,27 +670,54 @@ public class SimpleReasoner extends StatementListener { * inference models. */ public synchronized void recomputeABox() { - - // recompute the inferences + + // recompute the ABox inferences inferenceRebuildModel.enterCriticalSection(Lock.WRITE); aboxModel.enterCriticalSection(Lock.READ); + tboxModel.enterCriticalSection(Lock.READ); try { inferenceRebuildModel.removeAll(); + + // compute the class-based inferences + log.info("Computing class-based ABox inferences"); + StmtIterator iter = aboxModel.listStatements((Resource) null, RDF.type, (RDFNode) null); while (iter.hasNext()) { Statement stmt = iter.next(); - addedType(stmt, inferenceRebuildModel); + addedABoxTypeAssertion(stmt, inferenceRebuildModel); + } + + // compute the property-based inferences + log.info("Computing property-based ABox inferences"); + iter = tboxModel.listStatements((Resource) null, RDFS.subPropertyOf, (RDFNode) null); + int numStmts = 0; + + while (iter.hasNext()) { + numStmts++; + if ((numStmts % 400) == 0) { + log.info("Still computing property-based ABox inferences..."); + } + + Statement stmt = iter.next(); + addedTBoxStatement(stmt, inferenceRebuildModel); + } + + iter = tboxModel.listStatements((Resource) null, OWL.equivalentProperty, (RDFNode) null); + + while (iter.hasNext()) { + Statement stmt = iter.next(); + addedTBoxStatement(stmt, inferenceRebuildModel); } } catch (Exception e) { log.error("Exception while recomputing ABox inference model", e); } finally { - aboxModel.leaveCriticalSection(); - inferenceRebuildModel.leaveCriticalSection(); + aboxModel.leaveCriticalSection(); + tboxModel.leaveCriticalSection(); + inferenceRebuildModel.leaveCriticalSection(); } - // reflect the recomputed inferences into the application inference // model. inferenceRebuildModel.enterCriticalSection(Lock.READ); @@ -531,100 +788,7 @@ public class SimpleReasoner extends StatementListener { log.info("ABox inferences recomputed."); } - - // The following three methods aren't currently called; the default behavior of VIVO is to not materialize such inferences. - public void addedProperty(Statement stmt) { - - tboxModel.enterCriticalSection(Lock.READ); - - try { - OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); - - if (prop != null) { - ExtendedIterator superIt = prop.listSuperProperties(false); - - while (superIt.hasNext()) { - OntProperty parentProp = superIt.next(); - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), parentProp, stmt.getObject()); - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (!inferenceModel.contains(infStmt)) { - //log.debug("Adding inferred statement: " + infStmt.toString() + " - " + infStmt.getSubject().toString() + " - " + infStmt.getPredicate().toString() + " - " + infStmt.getObject().toString()); - inferenceModel.add(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } else { - log.debug("Didn't find predicate of the added statement in the TBox: " + stmt.getPredicate().getURI()); - } - } finally { - tboxModel.leaveCriticalSection(); - } - } - - public void removedProperty(Statement stmt) { - - tboxModel.enterCriticalSection(Lock.READ); - - try { - OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI()); - - if (prop != null) { - ExtendedIterator superIt = prop.listSuperProperties(false); - - while (superIt.hasNext()) { - OntProperty parentProp = superIt.next(); - - if (entailedStmt(stmt.getSubject(),parentProp,stmt.getObject() )) continue; // if the statement is still entailed - // don't remove it from the inference graph. - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), parentProp, stmt.getObject()); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - if (inferenceModel.contains(infStmt)) { - //log.debug("Removing inferred statement: " + infStmt.toString() + " - " + infStmt.getSubject().toString() + " - " + infStmt.getPredicate().toString() + " - " + infStmt.getObject().toString()); - inferenceModel.remove(infStmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - } - - } else { - log.debug("Didn't find predicate of the removed statement in the TBox: " + stmt.getPredicate().getURI()); - } - } finally { - tboxModel.leaveCriticalSection(); - } - } - - // Returns true if the statement is entailed by property subsumption - public boolean entailedStmt(Resource subject, OntProperty prop, RDFNode object) { - - aboxModel.enterCriticalSection(Lock.READ); - - try { - - ExtendedIterator iter = prop.listSubProperties(false); - - while (iter.hasNext()) { - - OntProperty childProp = iter.next(); - - Statement stmt = ResourceFactory.createStatement(subject, childProp, object); - if (aboxModel.contains(stmt)) return true; - } - - return false; - } finally { - aboxModel.leaveCriticalSection(); - } - } - public static SimpleReasoner getSimpleReasonerFromServletContext(ServletContext ctx) { Object simpleReasoner = ctx.getAttribute("simpleReasoner"); 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 a858320ca..55b84a235 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerTest.java @@ -11,6 +11,7 @@ import org.mindswap.pellet.jena.PelletReasonerFactory; 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.Resource; @@ -24,17 +25,21 @@ import edu.cornell.mannlib.vitro.webapp.reasoner.support.SimpleReasonerTBoxListe public class SimpleReasonerTest extends AbstractTestClass { + + private Resource objectProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#ObjectProperty"); + @Before public void suppressErrorOutput() { suppressSyserr(); } + /* + * Test that when an individual is asserted to be of a type, + * its asserted type is not added to the inference graph + */ @Test - public void addType(){ - - // Test that when a new instance is asserted, its asserted type is not added to the - // inference graph - + public void addABoxTypeAssertion1(){ + // 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); @@ -50,7 +55,7 @@ public class SimpleReasonerTest extends AbstractTestClass { // this is the model to receive inferences Model inf = ModelFactory.createDefaultModel(); - // create an Abox and register the SimpleReasoner listener with it + // create an ABox and register the SimpleReasoner listener with it OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); aBox.register(new SimpleReasoner(tBox, aBox, inf)); @@ -64,12 +69,17 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that "x is of type B" was not inferred Assert.assertFalse(inf.contains(xisb)); } - + + /* + * Test that when an individual is asserted have a type, + * that inferences are materialized that it has the types + * of its superclasses + */ @Test - public void addTypes(){ + public void addABoxTypeAssertion2(){ - // 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 + // 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); OntClass classA = tBox.createClass("http://test.vivo/A"); @@ -113,13 +123,150 @@ public class SimpleReasonerTest extends AbstractTestClass { Assert.assertTrue(inf.contains(xisa)); } - + /* + * Test inference based on class equivalence + */ @Test - public void removeTypes(){ - - // Create a Tbox with a simple class hierarchy. C is a subclass of B and B is a subclass of A. + public void addABoxTypeAssertion3(){ + + // 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)); + + // Add classes A, B and C to the TBox + // A is equivalent to B + // C is a subclass of A + + 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.addEquivalentClass(classB); + classA.addSubClass(classC); + + // Add a statement that individual x is of type C to the ABox + Resource ind_x = aBox.createResource("http://test.vivo/x"); + aBox.add(ind_x, RDF.type, classC); + + // Verify that "x is of type A" was inferred + Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); + Assert.assertTrue(inf.contains(xisa)); + + // Verify that "x is of type B" was inferred + Statement xisb = ResourceFactory.createStatement(ind_x, RDF.type, classB); + Assert.assertTrue(inf.contains(xisb)); + } + + /* + * Test inference based on class equivalence + */ + @Test + public void addABoxTypeAssertion4() { + + // 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)); + + // Add classes A and B to the TBox + // A is equivalent to B + + 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"); + + classA.addEquivalentClass(classB); + + // Add a statement that 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); + + // Verify that "x is of type A" was inferred + Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); + Assert.assertTrue(inf.contains(xisa)); + } + + + /* + * Test inference based on class equivalence + */ + @Test + public void addABoxTypeAssertion5() { + + // 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)); + + // Add classes classes A and B to the TBox + // A is equivalent to B + + 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"); + + classA.addEquivalentClass(classB); + + // Add a statement that 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); + + // Verify that "x is of type A" was inferred + Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); + Assert.assertTrue(inf.contains(xisa)); + + // Remove the statement that x is of type B from the ABox + aBox.remove(ind_x, RDF.type, classB); + + // Verify that "x is of type A" was removed from the inference graph + Assert.assertFalse(inf.contains(xisa)); + } + + /* + * Test that when it is retracted that an individual is of a type, + * that the inferences that it is of the type of all superclasses + * of the retracted type are retracted from the inference graph. + * However, any assertions that are otherwise entailed (by the + * TBox, ABox and inference graph minus the retracted type statement) + * should not be retracted. + */ + @Test + public void removeABoxTypeAssertion1(){ + + // Create a Tbox with a simple class hierarchy. C is a subclass of B + // and B is a subclass of A. Pellet will compute TBox inferences. + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); OntClass classA = tBox.createClass("http://test.vivo/A"); @@ -154,14 +301,32 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that the inference graph contains the statement that x is of type A. Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); Assert.assertTrue(inf.contains(xisa)); + + // Hopefully the assertion that x is b got removed from + // the inference graph + Statement xisb = ResourceFactory.createStatement(ind_x, RDF.type, classB); + Assert.assertFalse(inf.contains(xisb)); + } - - // This tests added TBox subClassOf and equivalentClass statements. - // The ABox data that will be the basis for the inference will - // be in the ABox graph. + /* + * Test the addition of a subClassOf statement to + * the TBox. The instance data that is the basis + * for the inference is in the ABox. The existing + * instance of the newly declared subclass should + * be inferred to have the type of the superclass. + * There are also a few checks that the instance + * is not inferred to have the types of some other + * random classes. + * + * Since the addition of an owl:equivalentClass + * statement is implemented as two calls to the + * method that handles the addition of an + * rdfs:subClassOf statement, this test serves + * as a test of equivalentClass statements also. + */ @Test - public void addSubClass1(){ + public void addTBoxSubClassAssertion1(){ // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -211,12 +376,24 @@ public class SimpleReasonerTest extends AbstractTestClass { } - - // this tests added TBox subClassOf and equivalentClass statements. - // The ABox data that is the basis for the inference will be - // in the inferred graph + /* + * Test the addition of a subClassOf statement to + * the TBox. The instance data that is the basis + * for the inference is in the ABox graph and the + * inference graph. The existing instance of the + * subclass of the newly added subclass should + * be inferred to have the type of the superclass + * of the newly added subclass. + * + * Since the addition of an owl:equivalentClass + * statement is implemented as two calls to the + * method that handles the addition of an + * rdfs:subClassOf statement, this test serves + * as some test of equivalentClass statements also. + * + */ @Test - public void addSubClass2(){ + public void addTBoxSubClassAssertion2() { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -260,9 +437,23 @@ public class SimpleReasonerTest extends AbstractTestClass { } @Test - // this tests incremental reasoning as a result of the removal of a subClassOf - // or equivalentClass statement from the TBox. - public void removeSubClass(){ + /* + * Test the removal of a subClassOf statement from + * the TBox. The instance data that is the basis + * for the inference is in the ABox graph and the + * inference graph. The existing instance of the + * subclass of the newly added subclass should + * be inferred to have the type of the superclass + * of the newly added subclass. + * + * Since the addition of an owl:equivalentClass + * statement is implemented as two calls to the + * method that handles the addition of an + * rdfs:subClassOf statement, this test serves + * as a test of equivalentClass assertions also. + * + */ + public void removeTBoxSubClassAssertion1(){ // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox // Pellet will compute TBox inferences @@ -323,7 +514,6 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that "x is of type A" is not in the inference graph Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); Assert.assertFalse(inf.contains(xisa)); - // Verify that "x is of type B" is in the inference graph Statement xisb = ResourceFactory.createStatement(ind_x, RDF.type, classB); @@ -340,13 +530,14 @@ public class SimpleReasonerTest extends AbstractTestClass { // Verify that "y is of type A" is in the inference graph Statement yisa = ResourceFactory.createStatement(ind_y, RDF.type, classA); Assert.assertTrue(inf.contains(yisa)); - } - // Test inference based on class equivalence - // + + /* + * tests rdfs:subPropertyOf materialization for object properties. + */ @Test - public void equivClass1(){ + public void addABoxAssertion1(){ // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -360,40 +551,130 @@ public class SimpleReasonerTest extends AbstractTestClass { aBox.register(simpleReasoner); tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - // Add classes classes A, B and C to the TBox + // Add object properties propA and propB to the TBox. + // propB is a sub-property of propA. + + OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("propA", "en-US"); + + OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("propB", "en-US"); + + propA.addSubProperty(propB); + + // Add the assertion that x propB y 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, propB, ind_y); + + // Verify that x propA y was inferred + Statement xay = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertTrue(inf.contains(xay)); + } + + /* + * Test that when a statement is asserted, that it not + * added to the inference graph. + */ + @Test + public void addABoxAssertion2(){ + + // 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)); + + // Add object properties propA and propB to the TBox. + // propB is a sub-property of propA. + + OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("propA", "en-US"); + + OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("propB", "en-US"); + + propA.addSubProperty(propB); + + // Add the assertion that x propB y 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, propB, ind_y); + + // Verify that x propA y was inferred + Statement xby = ResourceFactory.createStatement(ind_x, propB, ind_y); + Assert.assertFalse(inf.contains(xby)); + } + + /* + * Test inference based on property equivalence + */ + @Test + public void addABoxAssertion4(){ + + // 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)); + + // Add properties A, B and C to the TBox // A is equivalent to B // C is a subclass of A - OntClass classA = tBox.createClass("http://test.vivo/A"); - classA.setLabel("class A", "en-US"); + OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("property A", "en-US"); - OntClass classB = tBox.createClass("http://test.vivo/B"); - classB.setLabel("class B", "en-US"); + OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("property B", "en-US"); - OntClass classC = tBox.createClass("http://test.vivo/C"); - classC.setLabel("class C", "en-US"); + OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); + tBox.add(propC, RDF.type, objectProperty); + propC.setLabel("property C", "en-US"); - classA.addEquivalentClass(classB); - classA.addSubClass(classC); + propA.addEquivalentProperty(propB); + propA.addSubProperty(propC); // Add a statement that individual x is of type C to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); - aBox.add(ind_x, RDF.type, classC); - - // Verify that "x is of type A" was inferred - Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); - Assert.assertTrue(inf.contains(xisa)); + Resource ind_y = aBox.createResource("http://test.vivo/y"); - // Verify that "x is of type B" was inferred - Statement xisb = ResourceFactory.createStatement(ind_x, RDF.type, classB); - Assert.assertTrue(inf.contains(xisb)); - + aBox.add(ind_x, propC, ind_y); + + // Verify that "x A y" was inferred + Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertTrue(inf.contains(xAy)); + + // Verify that "x B y" was inferred + Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); + Assert.assertTrue(inf.contains(xBy)); } - // Test inference based on class equivalence - // + /* + * The sub-property is not of the same type as the super + * property so no inference should be materialized. + */ + @Test - public void equivClass2(){ + public void addABoxAssertion5(){ // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -407,31 +688,35 @@ public class SimpleReasonerTest extends AbstractTestClass { aBox.register(simpleReasoner); tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - // Add classes classes A and B to the TBox - // A is equivalent to B + // Add object properties propA and propB to the TBox. + // propB is a sub-property of propA. - 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"); - - classA.addEquivalentClass(classB); + OntProperty propA = tBox.createOntProperty("http://test.vivo/propA"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("propA", "en-US"); - // Add a statement that individual x is of type B to the ABox + OntProperty propB = tBox.createOntProperty("http://test.vivo/propB"); + Resource datatypeProperty = ResourceFactory.createResource("http://www.w3.org/2002/07/owl#DatatypeProperty"); + tBox.add(propB, RDF.type, datatypeProperty); + propB.setLabel("propB", "en-US"); + + propA.addSubProperty(propB); + + // Add the assertion that x propB y to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); - aBox.add(ind_x, RDF.type, classB); - - // Verify that "x is of type A" was inferred - Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); - Assert.assertTrue(inf.contains(xisa)); + Resource ind_y = aBox.createResource("http://test.vivo/y"); + aBox.add(ind_x, propB, ind_y); + + // Verify that x propA y was not inferred + Statement xay = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertFalse(inf.contains(xay)); } - - // Test inference based on class equivalence - // + /* + * Test inference based on property equivalence + */ @Test - public void equivClass3(){ + public void addABoxAssertion6() { // Create TBox, ABox and Inference models and register // the ABox reasoner listeners with the ABox and TBox @@ -445,31 +730,203 @@ public class SimpleReasonerTest extends AbstractTestClass { aBox.register(simpleReasoner); tBox.register(new SimpleReasonerTBoxListener(simpleReasoner)); - // Add classes classes A and B to the TBox + // Add properties A and B to the TBox // A is equivalent to B - OntClass classA = tBox.createClass("http://test.vivo/A"); - classA.setLabel("class A", "en-US"); + OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("property A", "en-US"); - OntClass classB = tBox.createClass("http://test.vivo/B"); - classB.setLabel("class B", "en-US"); + OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("property B", "en-US"); - classA.addEquivalentClass(classB); + propA.addEquivalentProperty(propB); - // Add a statement that individual x is of type B to the ABox + // Add the statement x B y to the ABox Resource ind_x = aBox.createResource("http://test.vivo/x"); - aBox.add(ind_x, RDF.type, classB); + Resource ind_y = aBox.createResource("http://test.vivo/y"); + aBox.add(ind_x, propB, ind_y); - // Verify that "x is of type A" was inferred - Statement xisa = ResourceFactory.createStatement(ind_x, RDF.type, classA); - Assert.assertTrue(inf.contains(xisa)); + // Verify that "x A y" was inferred + Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertTrue(inf.contains(xAy)); - // Remove the statement that x is of type B from the ABox - aBox.remove(ind_x, RDF.type, classB); + // Remove the statement that x B y from the ABox + aBox.remove(ind_x, propB, ind_y); // Verify that "x is of type A" was removed from the inference graph - Assert.assertFalse(inf.contains(xisa)); + Assert.assertFalse(inf.contains(xAy)); + } + + + /* + * Test the addition of a subPropertyOf statement to + * the TBox. The instance data that is the basis + * for the inference is in the ABox. + * + * Since the addition of an owl:equivalentProperty + * statement is implemented as two calls to the + * method that handles the addition of an + * rdfs:subPropetyOf statement, this test serves + * as a test of equivalentProperty assertions also. + */ + @Test + public void addTBoxSubPropertyAssertion1(){ + // 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)); + + // Add properties A, B, C and D to the TBox + OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("property A", "en-US"); + + OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("property B", "en-US"); + + OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); + tBox.add(propC, RDF.type, objectProperty); + propB.setLabel("property C", "en-US"); + + OntProperty propD = tBox.createOntProperty("http://test.vivo/D"); + tBox.add(propD, RDF.type, objectProperty); + propB.setLabel("property D", "en-US"); + + // Add the statement "x C y" 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, propC, ind_y); + + // Add a statement that C is a sub-property of A to the TBox + + propA.addSubProperty(propC); + + // Verify that "x A y" was inferred + Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertTrue(inf.contains(xAy)); + + // Verify that "x B y" was not inferred + Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); + Assert.assertFalse(inf.contains(xBy)); + + // Verify that "x D y" was not inferred + Statement xDy = ResourceFactory.createStatement(ind_x, propD, ind_y); + Assert.assertFalse(inf.contains(xDy)); + + } + + @Test + /* + * Test the removal of a subPropertyOf statement from + * the TBox. The instance data that is the basis + * for the inference is in the ABox graph and the + * inference graph. + * + * Since the addition of an owl:equivalentProperty + * statement is implemented as two calls to the + * method that handles the addition of an + * rdfs:subPropertyOf statement, this test serves + * as a test of equivalentProperty assertions also. + * + */ + public void removeTBoxSubPropertyAssertion1(){ + // 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)); + + // Add properties A, B, C, D, E, F, G and H to the TBox. + // B, C and D are subproperties of A. + // E is a subproperty of B. + // F and G are subproperties of C. + // H is a subproperty of D. + + OntProperty propA = tBox.createOntProperty("http://test.vivo/A"); + tBox.add(propA, RDF.type, objectProperty); + propA.setLabel("property A", "en-US"); + + OntProperty propB = tBox.createOntProperty("http://test.vivo/B"); + tBox.add(propB, RDF.type, objectProperty); + propB.setLabel("property B", "en-US"); + + OntProperty propC = tBox.createOntProperty("http://test.vivo/C"); + tBox.add(propC, RDF.type, objectProperty); + propB.setLabel("property C", "en-US"); + + OntProperty propD = tBox.createOntProperty("http://test.vivo/D"); + tBox.add(propD, RDF.type, objectProperty); + propB.setLabel("property D", "en-US"); + + OntProperty propE = tBox.createOntProperty("http://test.vivo/E"); + tBox.add(propE, RDF.type, objectProperty); + propB.setLabel("property E", "en-US"); + + OntProperty propF = tBox.createOntProperty("http://test.vivo/F"); + tBox.add(propF, RDF.type, objectProperty); + propB.setLabel("property F", "en-US"); + + OntProperty propG = tBox.createOntProperty("http://test.vivo/G"); + tBox.add(propG, RDF.type, objectProperty); + propB.setLabel("property G", "en-US"); + + OntProperty propH = tBox.createOntProperty("http://test.vivo/H"); + tBox.add(propH, RDF.type, objectProperty); + propB.setLabel("property H", "en-US"); + + propA.addSubProperty(propB); + propA.addSubProperty(propC); + propA.addSubProperty(propD); + propB.addSubProperty(propE); + propC.addSubProperty(propF); + propC.addSubProperty(propG); + propD.addSubProperty(propH); + + // Add the statement "x E y" 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, propE, ind_y); + + // Remove the statement that B is a subproperty of A from the TBox + propA.removeSubProperty(propB); + + // Verify that "x A y" is not in the inference graph + Statement xAy = ResourceFactory.createStatement(ind_x, propA, ind_y); + Assert.assertFalse(inf.contains(xAy)); + + // Verify that "x B y" is in the inference graph + Statement xBy = ResourceFactory.createStatement(ind_x, propB, ind_y); + Assert.assertTrue(inf.contains(xBy)); + + // Add statements "w F z" and "w H z" to the ABox + Resource ind_z = aBox.createResource("http://test.vivo/z"); + Resource ind_w = aBox.createResource("http://test.vivo/w"); + aBox.add(ind_w, propF, ind_z); + aBox.add(ind_w, propH, ind_z); + + // Remove the statement that C is a subproperty of A from the TBox + propA.removeSubProperty(propC); + + // Verify that "w A z" is in the inference graph + Statement wAz = ResourceFactory.createStatement(ind_w, propA, ind_z); + Assert.assertTrue(inf.contains(wAz)); } @@ -480,5 +937,5 @@ public class SimpleReasonerTest extends AbstractTestClass { System.out.println("---------------------------------------------------"); ontModel.writeAll(System.out,"N3",null); - } + } } \ No newline at end of file