NIHVIVO-3293 add inverse property reasoning to SimpleReasoner
This commit is contained in:
parent
a31b91bddd
commit
20b04e3e8e
2 changed files with 897 additions and 49 deletions
|
@ -14,6 +14,7 @@ import com.hp.hpl.jena.ontology.AnnotationProperty;
|
||||||
import com.hp.hpl.jena.ontology.OntClass;
|
import com.hp.hpl.jena.ontology.OntClass;
|
||||||
import com.hp.hpl.jena.ontology.OntModel;
|
import com.hp.hpl.jena.ontology.OntModel;
|
||||||
import com.hp.hpl.jena.ontology.OntModelSpec;
|
import com.hp.hpl.jena.ontology.OntModelSpec;
|
||||||
|
import com.hp.hpl.jena.ontology.OntProperty;
|
||||||
import com.hp.hpl.jena.query.Query;
|
import com.hp.hpl.jena.query.Query;
|
||||||
import com.hp.hpl.jena.query.QueryExecution;
|
import com.hp.hpl.jena.query.QueryExecution;
|
||||||
import com.hp.hpl.jena.query.QueryExecutionFactory;
|
import com.hp.hpl.jena.query.QueryExecutionFactory;
|
||||||
|
@ -25,6 +26,7 @@ import com.hp.hpl.jena.rdf.listeners.StatementListener;
|
||||||
import com.hp.hpl.jena.rdf.model.Literal;
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
import com.hp.hpl.jena.rdf.model.Model;
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Property;
|
||||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
import com.hp.hpl.jena.rdf.model.Resource;
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||||
|
@ -32,6 +34,7 @@ import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||||
import com.hp.hpl.jena.shared.JenaException;
|
import com.hp.hpl.jena.shared.JenaException;
|
||||||
import com.hp.hpl.jena.shared.Lock;
|
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.OWL;
|
||||||
import com.hp.hpl.jena.vocabulary.RDF;
|
import com.hp.hpl.jena.vocabulary.RDF;
|
||||||
import com.hp.hpl.jena.vocabulary.RDFS;
|
import com.hp.hpl.jena.vocabulary.RDFS;
|
||||||
|
@ -126,11 +129,12 @@ public class SimpleReasoner extends StatementListener {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addedStatement(Statement stmt) {
|
public void addedStatement(Statement stmt) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (stmt.getPredicate().equals(RDF.type)) {
|
if (stmt.getPredicate().equals(RDF.type)) {
|
||||||
addedABoxTypeAssertion(stmt, inferenceModel, new HashSet<String>());
|
addedABoxTypeAssertion(stmt, inferenceModel, new HashSet<String>());
|
||||||
setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet<String>());
|
setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet<String>());
|
||||||
|
} else {
|
||||||
|
addedABoxAssertion(stmt, inferenceModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
doPlugins(ModelUpdate.Operation.ADD,stmt);
|
doPlugins(ModelUpdate.Operation.ADD,stmt);
|
||||||
|
@ -150,8 +154,9 @@ public class SimpleReasoner extends StatementListener {
|
||||||
public void removedStatement(Statement stmt) {
|
public void removedStatement(Statement stmt) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isInterestedInRemovedStatement(stmt)) { return; }
|
// if (!isInterestedInRemovedStatement(stmt)) { return; }
|
||||||
|
// interested in all of them now that we are doing inverse
|
||||||
|
// property reasoning
|
||||||
handleRemovedStatement(stmt);
|
handleRemovedStatement(stmt);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -160,7 +165,6 @@ public class SimpleReasoner extends StatementListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Synchronized part of removedStatement. Interacts
|
* Synchronized part of removedStatement. Interacts
|
||||||
* with DeltaComputer.
|
* with DeltaComputer.
|
||||||
|
@ -175,6 +179,8 @@ public class SimpleReasoner extends StatementListener {
|
||||||
if (stmt.getPredicate().equals(RDF.type)) {
|
if (stmt.getPredicate().equals(RDF.type)) {
|
||||||
removedABoxTypeAssertion(stmt, inferenceModel);
|
removedABoxTypeAssertion(stmt, inferenceModel);
|
||||||
setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet<String>());
|
setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet<String>());
|
||||||
|
} else {
|
||||||
|
removedABoxAssertion(stmt, inferenceModel);
|
||||||
}
|
}
|
||||||
doPlugins(ModelUpdate.Operation.RETRACT,stmt);
|
doPlugins(ModelUpdate.Operation.RETRACT,stmt);
|
||||||
}
|
}
|
||||||
|
@ -184,19 +190,16 @@ public class SimpleReasoner extends StatementListener {
|
||||||
* Performs incremental ABox reasoning based
|
* Performs incremental ABox reasoning based
|
||||||
* on changes to the class hierarchy.
|
* on changes to the class hierarchy.
|
||||||
*
|
*
|
||||||
* Handles rdfs:subclassOf, owl:equivalentClass,
|
* Handles rdfs:subclassOf, owl:equivalentClass, and owl:inverseOf
|
||||||
*/
|
*/
|
||||||
public void addedTBoxStatement(Statement stmt) {
|
public void addedTBoxStatement(Statement stmt) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.debug("added TBox assertion = " + stmt.toString());
|
if (!(stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) || stmt.getPredicate().equals(OWL.inverseOf))) {
|
||||||
|
|
||||||
if ( stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) ) {
|
|
||||||
// ignore anonymous classes
|
|
||||||
if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("added TBox assertion = " + stmt.toString());
|
||||||
|
|
||||||
if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) {
|
if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) {
|
||||||
log.warn("The object of this assertion has a null URI: " + stmtString(stmt));
|
log.warn("The object of this assertion has a null URI: " + stmtString(stmt));
|
||||||
return;
|
return;
|
||||||
|
@ -207,6 +210,12 @@ public class SimpleReasoner extends StatementListener {
|
||||||
return;
|
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 subject = tboxModel.getOntClass((stmt.getSubject()).getURI());
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI());
|
log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI());
|
||||||
|
@ -226,6 +235,20 @@ public class SimpleReasoner extends StatementListener {
|
||||||
addedSubClass(subject,object,inferenceModel);
|
addedSubClass(subject,object,inferenceModel);
|
||||||
addedSubClass(object,subject,inferenceModel);
|
addedSubClass(object,subject,inferenceModel);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI());
|
||||||
|
if (prop1 == null) {
|
||||||
|
log.debug("didn't find subject property in the tbox: " + (stmt.getSubject()).getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OntProperty prop2 = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI());
|
||||||
|
if (prop2 == null) {
|
||||||
|
log.debug("didn't find object property in the tbox: " + ((Resource)stmt.getObject()).getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addedInverseProperty(prop1, prop2, inferenceModel);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// don't stop the edit if there's an exception
|
// don't stop the edit if there's an exception
|
||||||
|
@ -237,19 +260,16 @@ public class SimpleReasoner extends StatementListener {
|
||||||
* Performs incremental ABox reasoning based
|
* Performs incremental ABox reasoning based
|
||||||
* on changes to the class hierarchy.
|
* on changes to the class hierarchy.
|
||||||
*
|
*
|
||||||
* Handles rdfs:subclassOf, owl:equivalentClass,
|
* Handles rdfs:subclassOf, owl:equivalentClass, and owl:inverseOf
|
||||||
*/
|
*/
|
||||||
public void removedTBoxStatement(Statement stmt) {
|
public void removedTBoxStatement(Statement stmt) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.debug("removed TBox assertion = " + stmt.toString());
|
if (!(stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) || stmt.getPredicate().equals(OWL.inverseOf))) {
|
||||||
|
|
||||||
if ( stmt.getPredicate().equals(RDFS.subClassOf) || stmt.getPredicate().equals(OWL.equivalentClass) ) {
|
|
||||||
// ignore anonymous classes
|
|
||||||
if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.debug("removed TBox assertion = " + stmt.toString());
|
||||||
|
|
||||||
if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) {
|
if ( stmt.getObject().isResource() && (stmt.getObject().asResource()).getURI() == null ) {
|
||||||
log.warn("The object of this assertion has a null URI: " + stmtString(stmt));
|
log.warn("The object of this assertion has a null URI: " + stmtString(stmt));
|
||||||
return;
|
return;
|
||||||
|
@ -260,6 +280,13 @@ public class SimpleReasoner extends StatementListener {
|
||||||
return;
|
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 subject = tboxModel.getOntClass((stmt.getSubject()).getURI());
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI());
|
log.debug("didn't find subject class in the tbox: " + (stmt.getSubject()).getURI());
|
||||||
|
@ -279,6 +306,20 @@ public class SimpleReasoner extends StatementListener {
|
||||||
removedSubClass(subject,object,inferenceModel);
|
removedSubClass(subject,object,inferenceModel);
|
||||||
removedSubClass(object,subject,inferenceModel);
|
removedSubClass(object,subject,inferenceModel);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI());
|
||||||
|
if (prop1 == null) {
|
||||||
|
log.debug("didn't find subject property in the tbox: " + (stmt.getSubject()).getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OntProperty prop2 = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI());
|
||||||
|
if (prop2 == null) {
|
||||||
|
log.debug("didn't find object property in the tbox: " + ((Resource)stmt.getObject()).getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
removedInverseProperty(prop1, prop2, inferenceModel);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// don't stop the edit if there's an exception
|
// don't stop the edit if there's an exception
|
||||||
|
@ -376,6 +417,45 @@ public class SimpleReasoner extends StatementListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs incremental property-based reasoning.
|
||||||
|
*
|
||||||
|
* Materializes inferences based on the owl:inverseOf relationship.
|
||||||
|
*
|
||||||
|
* If it is added that x prop1 y, and prop2 is an inverseOf prop1
|
||||||
|
* then add y prop2 x to the inference graph, if it is not already in
|
||||||
|
* the assertions graph.
|
||||||
|
*/
|
||||||
|
public void addedABoxAssertion(Statement stmt, Model inferenceModel) {
|
||||||
|
|
||||||
|
List<OntProperty> inverseProperties = getInverseProperties(stmt);
|
||||||
|
Iterator<OntProperty> inverseIter = inverseProperties.iterator();
|
||||||
|
|
||||||
|
while (inverseIter.hasNext()) {
|
||||||
|
Property inverseProp = inverseIter.next();
|
||||||
|
|
||||||
|
Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject());
|
||||||
|
|
||||||
|
aboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
inferenceModel.enterCriticalSection(Lock.WRITE);
|
||||||
|
try {
|
||||||
|
if (inferenceModel.contains(stmt)) {
|
||||||
|
inferenceModel.remove(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt) ) {
|
||||||
|
inferenceModel.add(infStmt);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inferenceModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
aboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it is removed that B is of type A, then for each superclass of A remove
|
* 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
|
* the inferred statement that B is of that type UNLESS it is otherwise entailed
|
||||||
|
@ -387,7 +467,6 @@ public class SimpleReasoner extends StatementListener {
|
||||||
tboxModel.enterCriticalSection(Lock.READ);
|
tboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
OntClass cls = null;
|
OntClass cls = null;
|
||||||
|
|
||||||
if ( (stmt.getObject().asResource()).getURI() != null ) {
|
if ( (stmt.getObject().asResource()).getURI() != null ) {
|
||||||
|
@ -453,11 +532,48 @@ public class SimpleReasoner extends StatementListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs incremental property-based reasoning.
|
||||||
|
*
|
||||||
|
* Retracts inferences based on the owl:inverseOf relationship.
|
||||||
|
*
|
||||||
|
* If it is removed that x prop1 y, and prop2 is an inverseOf prop1
|
||||||
|
* then remove y prop2 x from the inference graph, unless it is
|
||||||
|
* otherwise entailed by the assertions graph independently of
|
||||||
|
* this removed statement.
|
||||||
|
*/
|
||||||
|
public void removedABoxAssertion(Statement stmt, Model inferenceModel) {
|
||||||
|
List<OntProperty> inverseProperties = getInverseProperties(stmt);
|
||||||
|
Iterator<OntProperty> inverseIter = inverseProperties.iterator();
|
||||||
|
|
||||||
|
while (inverseIter.hasNext()) {
|
||||||
|
OntProperty inverseProp = inverseIter.next();
|
||||||
|
|
||||||
|
Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject());
|
||||||
|
|
||||||
|
inferenceModel.enterCriticalSection(Lock.WRITE);
|
||||||
|
try {
|
||||||
|
if (!entailedInverseStmt(infStmt) && inferenceModel.contains(infStmt)) {
|
||||||
|
inferenceModel.remove(infStmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a statement has been removed that is otherwise entailed,
|
||||||
|
// add it to the inference graph.
|
||||||
|
if (entailedInverseStmt(stmt) && !inferenceModel.contains(stmt)) {
|
||||||
|
inferenceModel.add(stmt);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inferenceModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if it is entailed by class subsumption that
|
// Returns true if it is entailed by class subsumption that
|
||||||
// subject is of type cls; otherwise returns false.
|
// subject is of type cls; otherwise returns false.
|
||||||
protected boolean entailedType(Resource subject, OntClass cls) {
|
protected boolean entailedType(Resource subject, OntClass cls) {
|
||||||
aboxModel.enterCriticalSection(Lock.READ);
|
|
||||||
tboxModel.enterCriticalSection(Lock.READ);
|
tboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
aboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<OntClass> subclasses = null;
|
List<OntClass> subclasses = null;
|
||||||
|
@ -483,6 +599,95 @@ public class SimpleReasoner extends StatementListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the triple is entailed by inverse property
|
||||||
|
// reasoning; otherwise returns false.
|
||||||
|
protected boolean entailedInverseStmt(Statement stmt) {
|
||||||
|
ExtendedIterator <? extends OntProperty> iter = null;
|
||||||
|
|
||||||
|
tboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().asResource().getURI());
|
||||||
|
iter = prop.listInverse();
|
||||||
|
} finally {
|
||||||
|
tboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
aboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Property invProp = iter.next();
|
||||||
|
|
||||||
|
// not reasoning on properties in the OWL, RDF or RDFS namespace
|
||||||
|
if ((invProp.getNameSpace()).equals(OWL.NS) ||
|
||||||
|
(invProp.getNameSpace()).equals(RDFS.getURI()) ||
|
||||||
|
(invProp.getNameSpace()).equals(RDF.getURI())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement invStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), invProp, stmt.getSubject());
|
||||||
|
if (aboxModel.contains(invStmt)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
aboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a list of properties that are inverses of the property
|
||||||
|
* in the given statement.
|
||||||
|
*/
|
||||||
|
protected List<OntProperty> getInverseProperties(Statement stmt) {
|
||||||
|
|
||||||
|
List<OntProperty> inverses = new ArrayList<OntProperty>();
|
||||||
|
|
||||||
|
if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) {
|
||||||
|
return inverses;
|
||||||
|
}
|
||||||
|
|
||||||
|
tboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
|
||||||
|
OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().getURI());
|
||||||
|
|
||||||
|
if (prop != null) {
|
||||||
|
if (!prop.isObjectProperty()) {
|
||||||
|
return inverses;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stmt.getObject().isResource()) {
|
||||||
|
log.warn("The predicate of this statement is an object property, but the object is not a resource.");
|
||||||
|
return inverses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not reasoning on properties in the OWL, RDF or RDFS namespace
|
||||||
|
if ((prop.getNameSpace()).equals(OWL.NS) ||
|
||||||
|
(prop.getNameSpace()).equals(RDFS.getURI()) ||
|
||||||
|
(prop.getNameSpace()).equals(RDF.getURI())) {
|
||||||
|
return inverses;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedIterator <? extends OntProperty> iter = prop.listInverse();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
OntProperty invProp = iter.next();
|
||||||
|
|
||||||
|
if ((invProp.getNameSpace()).equals(OWL.NS) ||
|
||||||
|
(invProp.getNameSpace()).equals(RDFS.getURI()) ||
|
||||||
|
(invProp.getNameSpace()).equals(RDF.getURI())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
inverses.add(invProp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
tboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return inverses;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* If it is added that B is a subClass of A, then for each
|
* 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
|
* individual that is typed as B, either in the ABox or in the
|
||||||
|
@ -566,6 +771,112 @@ public class SimpleReasoner extends StatementListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it is added that P is an inverse of Q, then:
|
||||||
|
* 1. For each statement involving predicate P in
|
||||||
|
* the assertions model add the inverse statement
|
||||||
|
* to the inference model if that inverse is
|
||||||
|
* in the assertions model.
|
||||||
|
*
|
||||||
|
* 2. Repeat the same for predicate Q.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void addedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) {
|
||||||
|
|
||||||
|
if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) {
|
||||||
|
log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model inferences = ModelFactory.createDefaultModel();
|
||||||
|
inferences.add(generateInverseInferences(prop1, prop2));
|
||||||
|
inferences.add(generateInverseInferences(prop2, prop1));
|
||||||
|
|
||||||
|
if (inferences.isEmpty()) return;
|
||||||
|
|
||||||
|
aboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
StmtIterator iter = inferences.listStatements();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Statement infStmt = iter.next();
|
||||||
|
|
||||||
|
inferenceModel.enterCriticalSection(Lock.WRITE);
|
||||||
|
try {
|
||||||
|
if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) {
|
||||||
|
inferenceModel.add(infStmt);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inferenceModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
aboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Model generateInverseInferences(OntProperty prop, OntProperty inverseProp) {
|
||||||
|
Model inferences = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
aboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
StmtIterator iter = aboxModel.listStatements((Resource) null, prop, (RDFNode) null);
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Statement stmt = iter.next();
|
||||||
|
if (!stmt.getObject().isResource()) continue;
|
||||||
|
Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject());
|
||||||
|
inferences.add(infStmt);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
aboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return inferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it is removed that P is an inverse of Q, then:
|
||||||
|
* 1. For each statement involving predicate P in
|
||||||
|
* the abox assertions model remove the inverse
|
||||||
|
* statement from the inference model unless
|
||||||
|
* that statement is otherwise entailed.
|
||||||
|
*
|
||||||
|
* 2. Repeat the same for predicate Q.
|
||||||
|
*/
|
||||||
|
public void removedInverseProperty(OntProperty prop1, OntProperty prop2, Model inferenceModel) {
|
||||||
|
|
||||||
|
if ( !prop1.isObjectProperty() || !prop2.isObjectProperty() ) {
|
||||||
|
log.warn("The subject and object of the inverseOf statement are not both object properties. No inferencing will be performed. property 1: " + prop1.getURI() + " property 2:" + prop2.getURI());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model inferences = ModelFactory.createDefaultModel();
|
||||||
|
inferences.add(generateInverseInferences(prop1, prop2));
|
||||||
|
inferences.add(generateInverseInferences(prop2, prop1));
|
||||||
|
|
||||||
|
if (inferences.isEmpty()) return;
|
||||||
|
|
||||||
|
StmtIterator iter = inferences.listStatements();
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Statement infStmt = iter.next();
|
||||||
|
|
||||||
|
if (entailedInverseStmt(infStmt)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
inferenceModel.enterCriticalSection(Lock.WRITE);
|
||||||
|
try {
|
||||||
|
if (inferenceModel.contains(infStmt)) {
|
||||||
|
inferenceModel.remove(infStmt);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inferenceModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the most specific types (classes) of an individual and
|
* Find the most specific types (classes) of an individual and
|
||||||
* indicate them for the individual with the mostSpecificType
|
* indicate them for the individual with the mostSpecificType
|
||||||
|
@ -740,13 +1051,12 @@ public class SimpleReasoner extends StatementListener {
|
||||||
* inference models.
|
* inference models.
|
||||||
*/
|
*/
|
||||||
protected synchronized void recomputeABox() {
|
protected synchronized void recomputeABox() {
|
||||||
|
|
||||||
HashSet<String> unknownTypes = new HashSet<String>();
|
HashSet<String> unknownTypes = new HashSet<String>();
|
||||||
|
|
||||||
// recompute the inferences
|
// recompute the inferences
|
||||||
inferenceRebuildModel.enterCriticalSection(Lock.WRITE);
|
inferenceRebuildModel.enterCriticalSection(Lock.WRITE);
|
||||||
try {
|
try {
|
||||||
log.info("Computing class-based ABox inferences.");
|
log.info("Computing ABox inferences.");
|
||||||
inferenceRebuildModel.removeAll();
|
inferenceRebuildModel.removeAll();
|
||||||
|
|
||||||
int numStmts = 0;
|
int numStmts = 0;
|
||||||
|
@ -784,6 +1094,57 @@ public class SimpleReasoner extends StatementListener {
|
||||||
log.info("Still computing class-based ABox inferences...");
|
log.info("Still computing class-based ABox inferences...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stopRequested) {
|
||||||
|
log.info("a stopRequested signal was received during recomputeABox. Halting Processing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Finished computing class-based ABox inferences");
|
||||||
|
|
||||||
|
Iterator<Statement> invStatements = null;
|
||||||
|
tboxModel.enterCriticalSection(Lock.READ);
|
||||||
|
try {
|
||||||
|
invStatements = tboxModel.listStatements((Resource) null, OWL.inverseOf, (Resource) null);
|
||||||
|
} finally {
|
||||||
|
tboxModel.leaveCriticalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (invStatements.hasNext()) {
|
||||||
|
Statement stmt = invStatements.next();
|
||||||
|
|
||||||
|
try {
|
||||||
|
OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI());
|
||||||
|
if (prop1 == null) {
|
||||||
|
log.debug("didn't find subject property in the tbox: " + (stmt.getSubject()).getURI());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OntProperty prop2 = tboxModel.getOntProperty(((Resource)stmt.getObject()).getURI());
|
||||||
|
if (prop2 == null) {
|
||||||
|
log.debug("didn't find object property in the tbox: " + ((Resource)stmt.getObject()).getURI());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addedInverseProperty(prop1, prop2, inferenceRebuildModel);
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation.");
|
||||||
|
return;
|
||||||
|
} catch (JenaException je) {
|
||||||
|
if (je.getMessage().equals("Statement models must no be null")) {
|
||||||
|
log.error("Exception while recomputing ABox inference model. Halting inference computation.", je);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.error("Exception while recomputing ABox inference model: ", je);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception while recomputing ABox inference model: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
numStmts++;
|
||||||
|
if ((numStmts % 10000) == 0) {
|
||||||
|
log.info("Still computing property-based ABox inferences...");
|
||||||
|
}
|
||||||
|
|
||||||
if (stopRequested) {
|
if (stopRequested) {
|
||||||
log.info("a stopRequested signal was received during recomputeABox. Halting Processing.");
|
log.info("a stopRequested signal was received during recomputeABox. Halting Processing.");
|
||||||
return;
|
return;
|
||||||
|
@ -798,7 +1159,7 @@ public class SimpleReasoner extends StatementListener {
|
||||||
inferenceRebuildModel.leaveCriticalSection();
|
inferenceRebuildModel.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Finished computing class-based ABox inferences");
|
log.info("Finished computing property-based ABox inferences");
|
||||||
|
|
||||||
// reflect the recomputed inferences into the application
|
// reflect the recomputed inferences into the application
|
||||||
// inference model.
|
// inference model.
|
||||||
|
|
|
@ -0,0 +1,487 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.reasoner;
|
||||||
|
|
||||||
|
import org.apache.log4j.Level;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mindswap.pellet.jena.PelletReasonerFactory;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread;
|
||||||
|
|
||||||
|
public class SimpleReasonerPropertyTest extends AbstractTestClass {
|
||||||
|
|
||||||
|
long delay = 50;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void suppressErrorOutput() {
|
||||||
|
suppressSyserr();
|
||||||
|
//Turn off log messages to console
|
||||||
|
setLoggerLevel(SimpleReasoner.class, Level.OFF);
|
||||||
|
setLoggerLevel(SimpleReasonerTBoxListener.class, Level.OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* basic scenarios around adding abox data
|
||||||
|
*
|
||||||
|
* Create a Tbox with property P inverseOf property Q.
|
||||||
|
* Pellet will compute TBox inferences. Add a statement
|
||||||
|
* a P b, and verify that b Q a is inferred.
|
||||||
|
* Add a statement c Q d and verify that d Q c
|
||||||
|
* is inferred.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void addABoxAssertion1() {
|
||||||
|
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register the SimpleReasoner listener with it
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// b Q a is inferred from a P b
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
|
||||||
|
// d P c is inferred from c Q d.
|
||||||
|
aBox.add(c,Q,d);
|
||||||
|
Assert.assertTrue(inf.contains(d,P,c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't infer if it's already in the abox
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void addABoxAssertion2() {
|
||||||
|
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and add statement b Q a
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
aBox.add(b,Q,a);
|
||||||
|
|
||||||
|
// register SimpleReasoner
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// b Q a is inferred from a P b, but it is already in the abox
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
Assert.assertFalse(inf.contains(b,Q,a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't infer if it's already in the abox
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void addABoxAssertion3() {
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register SimpleReasoner
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
|
||||||
|
// b Q a is inferred from a P b, but it is already in the abox
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
aBox.add(b,Q,a);
|
||||||
|
Assert.assertFalse(inf.contains(b,Q,a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* adding abox data where the property has an inverse and
|
||||||
|
* and equivalent property.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void addABoxAssertion4() {
|
||||||
|
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty R = tBox.createOntProperty("http://test.vivo/R");
|
||||||
|
R.setLabel("property R", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
|
||||||
|
R.addEquivalentProperty(P);
|
||||||
|
P.addEquivalentProperty(R);
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register the SimpleReasoner listener with it
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// b Q a is inferred from a R b.
|
||||||
|
aBox.add(a,R,b);
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
|
||||||
|
// d P c is inferred from c Q d.
|
||||||
|
aBox.add(c,Q,d);
|
||||||
|
Assert.assertTrue(inf.contains(d,P,c));
|
||||||
|
Assert.assertTrue(inf.contains(d,R,c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* basic scenarios around removing abox data
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void removedABoxAssertion1() {
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
OntProperty T = tBox.createOntProperty("http://test.vivo/T");
|
||||||
|
Q.setLabel("property T", "en-US");
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
P.addInverseOf(T);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register the SimpleReasoner listener with it
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// b Q a is inferred from a P b.
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
|
||||||
|
// d P c is inferred from c Q d and from c T d
|
||||||
|
aBox.add(c,Q,d);
|
||||||
|
aBox.add(c,T,d);
|
||||||
|
Assert.assertTrue(inf.contains(d,P,c));
|
||||||
|
|
||||||
|
aBox.remove(a,P,b);
|
||||||
|
Assert.assertFalse(inf.contains(b,Q,a));
|
||||||
|
|
||||||
|
aBox.remove(c,Q,d);
|
||||||
|
Assert.assertTrue(inf.contains(d,P,c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* removing abox data with equivalent and inverse properties
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void removedABoxAssertion2() {
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
OntProperty T = tBox.createOntProperty("http://test.vivo/T");
|
||||||
|
Q.setLabel("property T", "en-US");
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
Q.addInverseOf(P);
|
||||||
|
P.addEquivalentProperty(T);
|
||||||
|
T.addEquivalentProperty(P);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register the SimpleReasoner listener with it
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
|
||||||
|
// b Q a is inferred from a P b and a T b.
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
aBox.add(a,T,b);
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
Assert.assertFalse(inf.contains(a,P,b));
|
||||||
|
|
||||||
|
aBox.remove(a,P,b);
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* removing abox data with equivalent and inverse properties
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void removedABoxAssertion3() {
|
||||||
|
OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
P.addInverseOf(Q);
|
||||||
|
|
||||||
|
// this is the model to receive inferences
|
||||||
|
Model inf = ModelFactory.createDefaultModel();
|
||||||
|
|
||||||
|
// create an ABox and register the SimpleReasoner listener with it
|
||||||
|
OntModel aBox = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
|
||||||
|
aBox.register(new SimpleReasoner(tBox, aBox, inf));
|
||||||
|
|
||||||
|
aBox.add(b,Q,a);
|
||||||
|
|
||||||
|
Assert.assertFalse(inf.contains(b,Q,a));
|
||||||
|
Assert.assertFalse(inf.contains(a,P,b));
|
||||||
|
|
||||||
|
aBox.remove(a,P,b);
|
||||||
|
Assert.assertTrue(inf.contains(a,P,b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic scenario around adding an inverseOf assertion to the
|
||||||
|
* TBox
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void addTBoxInverseAssertion1() throws InterruptedException {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner);
|
||||||
|
tBox.register(simpleReasonerTBoxListener);
|
||||||
|
|
||||||
|
// set up TBox and Abox
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/P");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/Q");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// abox statements
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
aBox.add(c,P,d);
|
||||||
|
aBox.add(b,Q,a);
|
||||||
|
|
||||||
|
// Assert P and Q as inverses and wait for SimpleReasoner TBox
|
||||||
|
// thread to end
|
||||||
|
|
||||||
|
Q.addInverseOf(P);
|
||||||
|
|
||||||
|
while (!VitroBackgroundThread.getLivingThreads().isEmpty()) {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify inferences
|
||||||
|
Assert.assertTrue(inf.contains(d,Q,c));
|
||||||
|
Assert.assertFalse(inf.contains(b,Q,a));
|
||||||
|
|
||||||
|
simpleReasonerTBoxListener.setStopRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic scenario around removing an inverseOf assertion to the
|
||||||
|
* TBox
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void removeTBoxInverseAssertion1() throws InterruptedException {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner);
|
||||||
|
tBox.register(simpleReasonerTBoxListener);
|
||||||
|
|
||||||
|
// set up TBox and Abox
|
||||||
|
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/propP");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/propQ");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
|
||||||
|
Q.addInverseOf(P);
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// abox statements
|
||||||
|
aBox.add(c,P,d);
|
||||||
|
|
||||||
|
Assert.assertTrue(inf.contains(d,Q,c));
|
||||||
|
|
||||||
|
// Remove P and Q inverse relationship and wait for
|
||||||
|
// SimpleReasoner TBox thread to end.
|
||||||
|
|
||||||
|
Q.removeInverseProperty(P);
|
||||||
|
|
||||||
|
Thread.sleep(delay);
|
||||||
|
while (!VitroBackgroundThread.getLivingThreads().isEmpty()) {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify inferences
|
||||||
|
Assert.assertFalse(inf.contains(d,Q,c));
|
||||||
|
|
||||||
|
simpleReasonerTBoxListener.setStopRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic scenario around recomputing the ABox inferences
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void recomputeABox1() throws InterruptedException {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner);
|
||||||
|
tBox.register(simpleReasonerTBoxListener);
|
||||||
|
|
||||||
|
// set up TBox and Abox
|
||||||
|
OntProperty P = tBox.createOntProperty("http://test.vivo/propP");
|
||||||
|
P.setLabel("property P", "en-US");
|
||||||
|
OntProperty Q = tBox.createOntProperty("http://test.vivo/propQ");
|
||||||
|
Q.setLabel("property Q", "en-US");
|
||||||
|
Q.addInverseOf(P);
|
||||||
|
|
||||||
|
OntProperty X = tBox.createOntProperty("http://test.vivo/propX");
|
||||||
|
P.setLabel("property X", "en-US");
|
||||||
|
OntProperty Y = tBox.createOntProperty("http://test.vivo/propY");
|
||||||
|
Q.setLabel("property Y", "en-US");
|
||||||
|
X.addInverseOf(Y);
|
||||||
|
|
||||||
|
Thread.sleep(delay*3);
|
||||||
|
|
||||||
|
// Individuals a, b, c and d
|
||||||
|
Resource a = aBox.createResource("http://test.vivo/a");
|
||||||
|
Resource b = aBox.createResource("http://test.vivo/b");
|
||||||
|
Resource c = aBox.createResource("http://test.vivo/c");
|
||||||
|
Resource d = aBox.createResource("http://test.vivo/d");
|
||||||
|
|
||||||
|
// abox statements
|
||||||
|
aBox.add(a,P,b);
|
||||||
|
aBox.add(c,X,d);
|
||||||
|
|
||||||
|
simpleReasoner.recompute();
|
||||||
|
|
||||||
|
Thread.sleep(delay);
|
||||||
|
while (!VitroBackgroundThread.getLivingThreads().isEmpty() || simpleReasoner.isRecomputing()) {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify inferences
|
||||||
|
Assert.assertTrue(inf.contains(b,Q,a));
|
||||||
|
Assert.assertTrue(inf.contains(d,Y,c));
|
||||||
|
|
||||||
|
simpleReasonerTBoxListener.setStopRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==================================== Utility methods ====================
|
||||||
|
SimpleReasonerTBoxListener getTBoxListener(SimpleReasoner simpleReasoner) {
|
||||||
|
return new SimpleReasonerTBoxListener(simpleReasoner, new Exception().getStackTrace()[1].getMethodName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// To help in debugging the unit test
|
||||||
|
void printModel(Model model, String modelName) {
|
||||||
|
|
||||||
|
System.out.println("\nThe " + modelName + " model has " + model.size() + " statements:");
|
||||||
|
System.out.println("---------------------------------------------------------------------");
|
||||||
|
model.write(System.out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// To help in debugging the unit test
|
||||||
|
void printModel(OntModel ontModel, String modelName) {
|
||||||
|
|
||||||
|
System.out.println("\nThe " + modelName + " model has " + ontModel.size() + " statements:");
|
||||||
|
System.out.println("---------------------------------------------------------------------");
|
||||||
|
ontModel.writeAll(System.out,"N3",null);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue