From e6577f5034e5f1e80eff853d904053f1b571f60c Mon Sep 17 00:00:00 2001 From: stellamit Date: Fri, 8 Jun 2012 14:21:49 +0000 Subject: [PATCH] incremental development for sameAs reasoning --- .../vitro/webapp/reasoner/SimpleReasoner.java | 849 ++++++++++++------ ...=> SimpleReasonerInversePropertyTest.java} | 6 +- .../reasoner/SimpleReasonerSameAsTest.java | 430 +++++++++ 3 files changed, 1026 insertions(+), 259 deletions(-) rename webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/{SimpleReasonerPropertyTest.java => SimpleReasonerInversePropertyTest.java} (98%) create mode 100644 webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java 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 6a03d1a34..52a1b9085 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -131,10 +131,12 @@ public class SimpleReasoner extends StatementListener { public void addedStatement(Statement stmt) { try { if (stmt.getPredicate().equals(RDF.type)) { - addedABoxTypeAssertion(stmt, inferenceModel, new HashSet()); - setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); + addedABoxTypeAssertion(stmt, inferenceModel, new HashSet()); + setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); + } else if (stmt.getPredicate().equals(OWL.sameAs)) { + addedABoxSameAsAssertion(stmt, inferenceModel); } else { - addedABoxAssertion(stmt, inferenceModel); + addedABoxAssertion(stmt, inferenceModel); } doPlugins(ModelUpdate.Operation.ADD,stmt); @@ -179,6 +181,8 @@ public class SimpleReasoner extends StatementListener { if (stmt.getPredicate().equals(RDF.type)) { removedABoxTypeAssertion(stmt, inferenceModel); setMostSpecificTypes(stmt.getSubject(), inferenceModel, new HashSet()); + } else if (stmt.getPredicate().equals(OWL.sameAs)) { + removedABoxSameAsAssertion(stmt, inferenceModel); } else { removedABoxAssertion(stmt, inferenceModel); } @@ -358,13 +362,10 @@ public class SimpleReasoner extends StatementListener { * A assert that B is of that type. */ protected void addedABoxTypeAssertion(Statement stmt, Model inferenceModel, HashSet unknownTypes) { - - tboxModel.enterCriticalSection(Lock.READ); - + + tboxModel.enterCriticalSection(Lock.READ); try { - OntClass cls = null; - if ( (stmt.getObject().asResource()).getURI() != null ) { cls = tboxModel.getOntClass(stmt.getObject().asResource().getURI()); @@ -373,32 +374,43 @@ public class SimpleReasoner extends StatementListener { List parents = (cls.listSuperClasses(false)).toList(); parents.addAll((cls.listEquivalentClasses()).toList()); Iterator parentIt = parents.iterator(); - - while (parentIt.hasNext()) { - OntClass parentClass = parentIt.next(); - - // VIVO doesn't materialize statements that assert anonymous types - // for individuals. Also, sharing an identical anonymous node is - // not allowed in owl-dl. picklist population code looks at qualities - // of classes not individuals. - if (parentClass.isAnon()) continue; - - Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); - aboxModel.enterCriticalSection(Lock.READ); - try { - inferenceModel.enterCriticalSection(Lock.WRITE); + + if (parentIt.hasNext()) { + List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); + while (parentIt.hasNext()) { + OntClass parentClass = parentIt.next(); + + // VIVO doesn't materialize statements that assert anonymous types + // for individuals. Also, sharing an identical anonymous node is + // not allowed in owl-dl. picklist population code looks at qualities + // of classes not individuals. + if (parentClass.isAnon()) continue; + + Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); + aboxModel.enterCriticalSection(Lock.READ); try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { - //log.debug("Adding this inferred statement: " + infStmt.toString() ); - inferenceModel.add(infStmt); - } + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { + inferenceModel.add(infStmt); + } + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { + inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); + } + } + + } finally { + inferenceModel.leaveCriticalSection(); + } } finally { - inferenceModel.leaveCriticalSection(); - } - } finally { - aboxModel.leaveCriticalSection(); - } - } + aboxModel.leaveCriticalSection(); + } + } + } } else { if ( !(stmt.getObject().asResource().getNameSpace()).equals(OWL.NS)) { if (!unknownTypes.contains(stmt.getObject().asResource().getURI())) { @@ -416,28 +428,51 @@ public class SimpleReasoner extends StatementListener { tboxModel.leaveCriticalSection(); } } - + /* - * Performs incremental property-based reasoning. - * - * Materializes inferences based on the owl:inverseOf relationship. + * Materializes inferences based on the owl:sameAs 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. + * If it is added that x owl:sameAs y, then all asserted and inferred + * statements about x will become inferred about y if they are not already + * asserted about y, and vice versa. */ - public void addedABoxAssertion(Statement stmt, Model inferenceModel) { - - List inverseProperties = getInverseProperties(stmt); - Iterator inverseIter = inverseProperties.iterator(); + public void addedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { + Resource subject = null; + Resource object = null; - while (inverseIter.hasNext()) { - Property inverseProp = inverseIter.next(); - - Statement infStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), inverseProp, stmt.getSubject()); - + if (stmt.getSubject().isResource()) { + subject = stmt.getSubject().asResource(); + if (tboxModel.containsResource(subject) || subject.isAnon()) { + log.debug("the subject of this sameAs statement is either in the tbox or an anonymous node, no reasoning will be done: " + stmtString(stmt)); + return; + } + } else { + log.warn("the subject of this sameAs statement is not a resource, no reasoning will be done: " + stmtString(stmt)); + return; + } + + if (stmt.getObject().isResource()) { + object = stmt.getObject().asResource(); + if (tboxModel.containsResource(object) || object.isAnon()) { + log.debug("the object of this sameAs statement is either in the tbox or an anonymous node, no reasoning will be done: " + stmtString(stmt)); + return; + } + } else { + log.warn("the object of this sameAs statement is not a resource, no reasoning will be done: " + stmtString(stmt)); + return; + } + + Model inferences = ModelFactory.createDefaultModel(); + inferences.add(generateSameAsInferences(subject, object, inferenceModel)); + inferences.add(generateSameAsInferences(object, subject, inferenceModel)); + inferences.add(object, OWL.sameAs, subject); + + Iterator infIter = inferences.listStatements(); + + while (infIter.hasNext()) { + Statement infStmt = infIter.next(); aboxModel.enterCriticalSection(Lock.READ); - try { + try { inferenceModel.enterCriticalSection(Lock.WRITE); try { if (inferenceModel.contains(stmt)) { @@ -455,6 +490,214 @@ public class SimpleReasoner extends StatementListener { } } } + + /* + * Create a model that contains every assertion about indB as exists for + * indA in the Abox assertions or inference model + */ + public Model generateSameAsInferences(Resource indA, Resource indB, Model inferenceModel) { + + Model inferences = ModelFactory.createDefaultModel(); + + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + + aboxModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = unionModel.listStatements(indA, (Property) null, (RDFNode) null); + + while (iter.hasNext()) { + Statement stmt = iter.next(); + if (stmt.getObject() == null) continue; + if (OWL.sameAs.equals(stmt.getPredicate()) && indB.equals(stmt.getObject())) continue; + inferences.add(indB, stmt.getPredicate(), stmt.getObject()); + } + } finally { + aboxModel.leaveCriticalSection(); + } + + return inferences; + } + + /* + * Get a list of individuals the same as the given individual + */ + public List getSameIndividuals(Resource ind, Model inferenceModel) { + + OntModel unionModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); + unionModel.addSubModel(aboxModel); + unionModel.addSubModel(inferenceModel); + + ArrayList sameIndividuals = new ArrayList(); + aboxModel.enterCriticalSection(Lock.READ); + inferenceModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = unionModel.listStatements(ind, OWL.sameAs, (RDFNode) null); + + while (iter.hasNext()) { + Statement stmt = iter.next(); + if (stmt.getObject() == null || !stmt.getObject().isResource() || stmt.getObject().asResource().getURI() == null) continue; + sameIndividuals.add(stmt.getObject().asResource()); + } + } finally { + inferenceModel.leaveCriticalSection(); + aboxModel.leaveCriticalSection(); + } + + return sameIndividuals; + } + + /* + * Materializes inferences based on the owl:sameAs relationship. + * + * If it is removed that x is sameAs y, then remove y sameAs x from + * the inference graph and then recompute the inferences for x and + * y based on their respective assertions. that x owl:sameAs y, then all asserted and inferred + */ + public void removedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { + + Resource subject = null; + Resource object = null; + + if (stmt.getSubject().isResource()) { + subject = stmt.getSubject().asResource(); + if (tboxModel.containsResource(subject) || subject.isAnon()) { + log.debug("the subject of this removed sameAs statement is either in the tbox or an anonymous node, no reasoning will be done: " + stmtString(stmt)); + return; + } + } else { + log.warn("the subject of this removed sameAs statement is not a resource, no reasoning will be done: " + stmtString(stmt)); + return; + } + + if (stmt.getObject().isResource()) { + object = stmt.getObject().asResource(); + if (tboxModel.containsResource(object) || object.isAnon()) { + log.debug("the object of this removed sameAs statement is either in the tbox or an anonymous node, no reasoning will be done: " + stmtString(stmt)); + return; + } + } else { + log.warn("the object of this removed sameAs statement is not a resource, no reasoning will be done: " + stmtString(stmt)); + return; + } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(stmt)) { + inferenceModel.remove(stmt); + } + + if (!inferenceModel.contains(object, OWL.sameAs, subject) && !aboxModel.contains(object, OWL.sameAs, subject) ) { + inferenceModel.add(object, OWL.sameAs, subject); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + recomputeInferencesForIndividual(subject, inferenceModel); + recomputeInferencesForIndividual(object, inferenceModel); + } + + /* + * Recompute inferences for individual + */ + public void recomputeInferencesForIndividual(Resource ind, Model inferenceModel) { + + Model inferencesToRemove = ModelFactory.createDefaultModel(); + + inferenceModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = inferenceModel.listStatements(ind, (Property) null, (RDFNode) null); + + while (iter.hasNext()) { + inferencesToRemove.add(iter.next()); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + inferenceModel.remove(inferencesToRemove); + } finally { + inferenceModel.leaveCriticalSection(); + } + + Iterator iter = null; + aboxModel.enterCriticalSection(Lock.WRITE); + try { + iter = aboxModel.listStatements(ind, (Property) null, (RDFNode) null); + } finally { + aboxModel.leaveCriticalSection(); + } + + while (iter.hasNext()) { + addedStatement(iter.next()); + } + + return; + } + + /* + * 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 sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); + List inverseProperties = getInverseProperties(stmt); + Iterator 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(infStmt) && !aboxModel.contains(infStmt) ) { + inferenceModel.add(infStmt); + } + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { + inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); + } + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } finally { + aboxModel.leaveCriticalSection(); + } + } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + if (inferenceModel.contains(stmt)) { + inferenceModel.remove(stmt); + } + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + if (!inferenceModel.contains(subject,stmt.getPredicate(),stmt.getObject()) && !aboxModel.contains(subject,stmt.getPredicate(),stmt.getObject())) { + inferenceModel.add(subject,stmt.getPredicate(),stmt.getObject()); + } + } + } finally { + inferenceModel.leaveCriticalSection(); + } + } /* * If it is removed that B is of type A, then for each superclass of A remove @@ -483,8 +726,7 @@ public class SimpleReasoner extends StatementListener { } } finally { inferenceModel.leaveCriticalSection(); - } - + } return; } @@ -542,30 +784,53 @@ public class SimpleReasoner extends StatementListener { * otherwise entailed by the assertions graph independently of * this removed statement. */ - public void removedABoxAssertion(Statement stmt, Model inferenceModel) { + public void removedABoxAssertion(Statement stmt, Model inferenceModel) { + + List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(), inferenceModel); List inverseProperties = getInverseProperties(stmt); Iterator 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)) { + if (!entailedStatement(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); - } + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Statement infStmtSame = ResourceFactory.createStatement(sameIter.next(), infStmt.getPredicate(), infStmt.getObject()); + if (!entailedStatement(infStmtSame) && inferenceModel.contains(infStmtSame)) { + inferenceModel.remove(infStmtSame); + } + } } finally { inferenceModel.leaveCriticalSection(); } } + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + // if a statement has been removed that is otherwise entailed, + // add it to the inference graph. + if (entailedStatement(stmt) && !inferenceModel.contains(stmt)) { + inferenceModel.add(stmt); + } + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Statement stmtSame = ResourceFactory.createStatement(sameIter.next(), stmt.getPredicate(), stmt.getObject()); + if (!entailedStatement(stmtSame) && inferenceModel.contains(stmtSame)) { + inferenceModel.remove(stmtSame); + } + } + } finally { + inferenceModel.leaveCriticalSection(); + } } // Returns true if it is entailed by class subsumption that @@ -600,39 +865,61 @@ 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 iter = null; - + // reasoning or sameAs reasoning; otherwise returns false. + protected boolean entailedStatement(Statement stmt) { + + List inverses = new ArrayList(); + tboxModel.enterCriticalSection(Lock.READ); try { OntProperty prop = tboxModel.getOntProperty(stmt.getPredicate().asResource().getURI()); - iter = prop.listInverse(); + inverses.addAll(prop.listInverse().toList()); } 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; + Iterator oIter = inverses.iterator(); + if (oIter.hasNext()) { + aboxModel.enterCriticalSection(Lock.READ); + try { + while (oIter.hasNext()) { + Property invProp = oIter.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; + } } - - Statement invStmt = ResourceFactory.createStatement(stmt.getObject().asResource(), invProp, stmt.getSubject()); - if (aboxModel.contains(invStmt)) { - return true; + } finally { + aboxModel.leaveCriticalSection(); + } + } + + List sameIndividuals = getSameIndividuals(stmt.getSubject().asResource(),inferenceModel); + Iterator rIter = sameIndividuals.iterator(); + if (rIter.hasNext()) { + aboxModel.enterCriticalSection(Lock.READ); + try { + while (rIter.hasNext()) { + Resource subject = rIter.next(); + + if (aboxModel.contains(subject, stmt.getPredicate(), stmt.getObject())) { + return true; + } } - } - return false; - } finally { - aboxModel.leaveCriticalSection(); - } + } finally { + aboxModel.leaveCriticalSection(); + } + } + + return false; } /* @@ -793,19 +1080,28 @@ public class SimpleReasoner extends StatementListener { 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(); + List sameIndividuals = getSameIndividuals(infStmt.getSubject().asResource(), inferenceModel); inferenceModel.enterCriticalSection(Lock.WRITE); try { if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { inferenceModel.add(infStmt); - } + } + + Iterator sameIter = sameIndividuals.iterator(); + while (sameIter.hasNext()) { + Resource subject = sameIter.next(); + if (!inferenceModel.contains(subject,infStmt.getPredicate(),infStmt.getObject()) && !aboxModel.contains(subject,infStmt.getPredicate(),infStmt.getObject())) { + inferenceModel.add(subject,infStmt.getPredicate(),infStmt.getObject()); + } + } } finally { inferenceModel.leaveCriticalSection(); } @@ -862,7 +1158,7 @@ public class SimpleReasoner extends StatementListener { while (iter.hasNext()) { Statement infStmt = iter.next(); - if (entailedInverseStmt(infStmt)) { + if (entailedStatement(infStmt)) { continue; } @@ -1051,19 +1347,18 @@ public class SimpleReasoner extends StatementListener { * inference models. */ protected synchronized void recomputeABox() { - HashSet unknownTypes = new HashSet(); - // recompute the inferences + // recompute class subsumption inferences inferenceRebuildModel.enterCriticalSection(Lock.WRITE); try { - log.info("Computing ABox inferences."); + HashSet unknownTypes = new HashSet(); inferenceRebuildModel.removeAll(); + log.info("Computing class subsumtion ABox inferences."); int numStmts = 0; ArrayList individuals = this.getAllIndividualURIs(); - for (String individualURI : individuals) { - + for (String individualURI : individuals) { Resource individual = ResourceFactory.createResource(individualURI); try { @@ -1077,8 +1372,8 @@ public class SimpleReasoner extends StatementListener { } } } catch (NullPointerException npe) { - log.error("a NullPointerException was received while recomputing the ABox inferences. Halting inference computation."); - return; + 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); @@ -1090,117 +1385,172 @@ public class SimpleReasoner extends StatementListener { } numStmts++; - if ((numStmts % 10000) == 0) { - log.info("Still computing class-based ABox inferences..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } + if ((numStmts % 10000) == 0) { + log.info("Still computing class subsumption 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 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(); - + log.info("Finished computing class subsumption ABox inferences"); + + log.info("Computing inverse property ABox inferences"); + Iterator invStatements = null; + tboxModel.enterCriticalSection(Lock.READ); 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); + invStatements = tboxModel.listStatements((Resource) null, OWL.inverseOf, (Resource) null); + } finally { + tboxModel.leaveCriticalSection(); } - numStmts++; - if ((numStmts % 10000) == 0) { - log.info("Still computing property-based ABox inferences..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } - } + numStmts = 0; + while (invStatements.hasNext()) { + Statement stmt = invStatements.next(); + + try { + OntProperty prop1 = tboxModel.getOntProperty((stmt.getSubject()).getURI()); + if (prop1 == null) { + //TODO make sure not to print out a million of these for the same property + 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) { + //TODO make sure not to print out a million of these for the same property + 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 inverse property ABox inferences..."); + } + + if (stopRequested) { + log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); + return; + } + } + + log.info("Finished computing inverse property ABox inferences"); + + log.info("Computing sameAs ABox inferences"); + + Iterator sameAsStatements = null; + aboxModel.enterCriticalSection(Lock.READ); + try { + sameAsStatements = aboxModel.listStatements((Resource) null, OWL.sameAs, (Resource) null); + } finally { + aboxModel.leaveCriticalSection(); + } + + numStmts = 0; + while (sameAsStatements.hasNext()) { + Statement stmt = sameAsStatements.next(); + + try { + addedABoxSameAsAssertion(stmt, 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 sameAs ABox inferences..."); + } + + if (stopRequested) { + log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); + return; + } + } + log.info("Finished computing sameAs ABox inferences"); + + try { + if (updateInferenceModel(inferenceRebuildModel)) { + log.info("a stopRequested signal was received during updateInferenceModel. Halting Processing."); + return; + } + } catch (Exception e) { + log.error("Exception while reconciling the current and recomputed ABox inference model for class subsumption inferences. Halting processing." , e); + inferenceRebuildModel.removeAll(); + return; + } } catch (Exception e) { - log.error("Exception while recomputing ABox inference model", e); - inferenceRebuildModel.removeAll(); // don't do this in the finally, it's needed in the case - // where there isn't an exception + log.error("Exception while recomputing ABox inferences. Halting processing.", e); + inferenceRebuildModel.removeAll(); return; } finally { inferenceRebuildModel.leaveCriticalSection(); - } - - log.info("Finished computing property-based ABox inferences"); - - // reflect the recomputed inferences into the application - // inference model. - log.info("Updating ABox inference model"); - StmtIterator iter = null; - - // Remove everything from the current inference model that is not - // in the recomputed inference model - int num = 0; - inferenceRebuildModel.enterCriticalSection(Lock.WRITE); - scratchpadModel.enterCriticalSection(Lock.WRITE); - try { - inferenceModel.enterCriticalSection(Lock.READ); - try { - scratchpadModel.removeAll(); - iter = inferenceModel.listStatements(); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - if (!inferenceRebuildModel.contains(stmt)) { - scratchpadModel.add(stmt); - } + } + } + + /* + * reconcile a set of inferences into the application inference model + */ + protected synchronized boolean updateInferenceModel(Model inferenceRebuildModel) { - num++; - if ((num % 10000) == 0) { - log.info("Still updating ABox inference model (removing outdated inferences)..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } - } - } catch (Exception e) { - log.error("Exception while reconciling the current and recomputed ABox inference models", e); - return; - } finally { - iter.close(); - inferenceModel.leaveCriticalSection(); - } + log.info("Updating ABox inference model"); + StmtIterator iter = null; + + // Remove everything from the current inference model that is not + // in the recomputed inference model + int num = 0; + scratchpadModel.enterCriticalSection(Lock.WRITE); + try { + inferenceModel.enterCriticalSection(Lock.READ); + try { + scratchpadModel.removeAll(); + iter = inferenceModel.listStatements(); + while (iter.hasNext()) { + Statement stmt = iter.next(); + if (!inferenceRebuildModel.contains(stmt)) { + scratchpadModel.add(stmt); + } + + num++; + if ((num % 10000) == 0) { + log.info("Still updating ABox inference model (removing outdated inferences)..."); + } + + if (stopRequested) { + return true; + } + } + } finally { + iter.close(); + inferenceModel.leaveCriticalSection(); + } + + try { iter = scratchpadModel.listStatements(); while (iter.hasNext()) { Statement stmt = iter.next(); @@ -1208,73 +1558,65 @@ public class SimpleReasoner extends StatementListener { inferenceModel.enterCriticalSection(Lock.WRITE); try { inferenceModel.remove(stmt); - } catch (Exception e) { - log.error("Exception while reconciling the current and recomputed ABox inference models", e); - } finally { - inferenceModel.leaveCriticalSection(); - } - } - - // Add everything from the recomputed inference model that is not already - // in the current inference model to the current inference model. - try { - scratchpadModel.removeAll(); - iter = inferenceRebuildModel.listStatements(); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - - inferenceModel.enterCriticalSection(Lock.READ); - try { - if (!inferenceModel.contains(stmt)) { - scratchpadModel.add(stmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - - num++; - if ((num % 10000) == 0) { - log.info("Still updating ABox inference model (adding new inferences)..."); - } - - if (stopRequested) { - log.info("a stopRequested signal was received during recomputeABox. Halting Processing."); - return; - } - } - } catch (Exception e) { - log.error("Exception while reconciling the current and recomputed ABox inference models", e); - return; - } finally { - iter.close(); - } - - iter = scratchpadModel.listStatements(); - while (iter.hasNext()) { - Statement stmt = iter.next(); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - inferenceModel.add(stmt); - } catch (Exception e) { - log.error("Exception while reconciling the current and recomputed ABox inference models", e); - return; } finally { inferenceModel.leaveCriticalSection(); } } } finally { iter.close(); - inferenceRebuildModel.removeAll(); - scratchpadModel.removeAll(); - inferenceRebuildModel.leaveCriticalSection(); - scratchpadModel.leaveCriticalSection(); } - - log.info("ABox inference model updated"); - } + + // Add everything from the recomputed inference model that is not already + // in the current inference model to the current inference model. + try { + scratchpadModel.removeAll(); + iter = inferenceRebuildModel.listStatements(); + while (iter.hasNext()) { + Statement stmt = iter.next(); + + inferenceModel.enterCriticalSection(Lock.READ); + try { + if (!inferenceModel.contains(stmt)) { + scratchpadModel.add(stmt); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + num++; + if ((num % 10000) == 0) { + log.info("Still updating ABox inference model (adding new inferences)..."); + } + + if (stopRequested) { + return true; + } + } + } finally { + iter.close(); + } + + iter = scratchpadModel.listStatements(); + while (iter.hasNext()) { + Statement stmt = iter.next(); + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + inferenceModel.add(stmt); + } finally { + inferenceModel.leaveCriticalSection(); + } + } + } finally { + iter.close(); + scratchpadModel.removeAll(); + scratchpadModel.leaveCriticalSection(); + } + + log.info("ABox inference model updated"); + return false; + } /* * Get the URIs for all individuals in the system */ @@ -1491,8 +1833,7 @@ public class SimpleReasoner extends StatementListener { try { log.info("started computing inferences for batch " + qualifier + " updates"); iter = retractions.listStatements(); - - + while (iter.hasNext() && !stopRequested) { Statement stmt = iter.next(); num++; diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java similarity index 98% rename from webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPropertyTest.java rename to webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java index 7276828f8..4c61fcb73 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerPropertyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java @@ -18,7 +18,7 @@ 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 { +public class SimpleReasonerInversePropertyTest extends AbstractTestClass { long delay = 50; @@ -439,8 +439,6 @@ public class SimpleReasonerPropertyTest extends AbstractTestClass { SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); aBox.register(simpleReasoner); - SimpleReasonerTBoxListener simpleReasonerTBoxListener = getTBoxListener(simpleReasoner); - tBox.register(simpleReasonerTBoxListener); // Individuals a, b, c and d Resource a = aBox.createResource("http://test.vivo/a"); Resource b = aBox.createResource("http://test.vivo/b"); @@ -460,8 +458,6 @@ public class SimpleReasonerPropertyTest extends AbstractTestClass { // Verify inferences Assert.assertTrue(inf.contains(b,Q,a)); Assert.assertTrue(inf.contains(d,Y,c)); - - simpleReasonerTBoxListener.setStopRequested(); } //==================================== Utility methods ==================== diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java new file mode 100644 index 000000000..41ceffee7 --- /dev/null +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java @@ -0,0 +1,430 @@ +/* $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.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.Literal; +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 com.hp.hpl.jena.vocabulary.OWL; +import com.hp.hpl.jena.vocabulary.RDF; + +import edu.cornell.mannlib.vitro.testing.AbstractTestClass; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; + +public class SimpleReasonerSameAsTest 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 scenario of adding an abox sameAs assertion + //*/ + @Test + public void addSameAsABoxAssertion1() { + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty P = tBox.createObjectProperty("http://test.vivo/P"); + P.setLabel("property P", "en-US"); + + OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); + Q.setLabel("property Q", "en-US"); + + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + S.setLabel("property S", "en-US"); + + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + T.setLabel("property T", "en-US"); + + Literal literal1 = tBox.createLiteral("Literal value 1"); + Literal literal2 = tBox.createLiteral("Literal value 2"); + + // 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"); + + aBox.add(a,P,c); + aBox.add(a,S,literal1); + aBox.add(b,Q,d); + aBox.add(b,T,literal2); + aBox.add(a,OWL.sameAs,b); + + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,P,c)); + Assert.assertTrue(inf.contains(b,S,literal1)); + Assert.assertTrue(inf.contains(a,Q,d)); + Assert.assertTrue(inf.contains(a,T,literal2)); + + Assert.assertFalse(aBox.contains(b,OWL.sameAs,a)); + Assert.assertFalse(aBox.contains(b,P,c)); + Assert.assertFalse(aBox.contains(b,S,literal1)); + Assert.assertFalse(aBox.contains(a,Q,d)); + Assert.assertFalse(aBox.contains(a,T,literal2)); + } + + /* + * basic scenario of removing an abox sameAs assertion + */ + @Test + public void removeSameAsABoxAssertion1() { + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty P = tBox.createObjectProperty("http://test.vivo/P"); + P.setLabel("property P", "en-US"); + + OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); + Q.setLabel("property Q", "en-US"); + + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + S.setLabel("property S", "en-US"); + + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + T.setLabel("property T", "en-US"); + + Literal literal1 = tBox.createLiteral("Literal value 1"); + Literal literal2 = tBox.createLiteral("Literal value 2"); + + // 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"); + + aBox.add(a,P,c); + aBox.add(a,S,literal1); + aBox.add(b,Q,d); + aBox.add(b,T,literal2); + aBox.add(a,OWL.sameAs,b); + + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,P,c)); + Assert.assertTrue(inf.contains(b,S,literal1)); + Assert.assertTrue(inf.contains(a,Q,d)); + Assert.assertTrue(inf.contains(a,T,literal2)); + + aBox.remove(a,OWL.sameAs,b); + + Assert.assertFalse(inf.contains(b,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(b,P,c)); + Assert.assertFalse(inf.contains(b,S,literal1)); + Assert.assertFalse(inf.contains(a,Q,d)); + Assert.assertFalse(inf.contains(a,T,literal2)); + } + + /* + * basic scenario of adding an abox assertion for + * an individual is sameAs another. + */ + @Test + public void addABoxAssertion1() { + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty P = tBox.createObjectProperty("http://test.vivo/P"); + P.setLabel("property P", "en-US"); + + OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); + Q.setLabel("property Q", "en-US"); + + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + S.setLabel("property S", "en-US"); + + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + T.setLabel("property T", "en-US"); + + Literal literal1 = tBox.createLiteral("Literal value 1"); + Literal literal2 = tBox.createLiteral("Literal value 2"); + + // 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"); + + aBox.add(a,OWL.sameAs,b); + + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + + aBox.add(a,P,c); + aBox.add(a,S,literal1); + aBox.add(b,Q,d); + aBox.add(b,T,literal2); + + Assert.assertTrue(inf.contains(b,P,c)); + Assert.assertTrue(inf.contains(b,S,literal1)); + Assert.assertTrue(inf.contains(a,Q,d)); + Assert.assertTrue(inf.contains(a,T,literal2)); + } + + /* + * adding abox assertion for individuals that are sameAs + * each other. + */ + @Test + public void addABoxAssertion2() { + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + 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.addSubClass(classB); + + OntProperty desc = tBox.createDatatypeProperty("http://test.vivo/desc"); + desc.setLabel("property desc", "en-US"); + + Literal desc1 = tBox.createLiteral("individual 1"); + Literal desc2 = tBox.createLiteral("individual 2"); + + // 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 and b + Resource a = aBox.createResource("http://test.vivo/a"); + Resource b = aBox.createResource("http://test.vivo/b"); + + aBox.add(a,desc,desc1); + aBox.add(b,desc,desc2); + aBox.add(a,OWL.sameAs,b); + aBox.add(a, RDF.type, classB); + + Assert.assertTrue(inf.contains(a,desc,desc2)); + Assert.assertTrue(inf.contains(a,RDF.type,classA)); + Assert.assertTrue(inf.contains(b,desc,desc1)); + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,RDF.type,classB)); + Assert.assertTrue(inf.contains(b,RDF.type,classA)); + } + + /* + * basic scenario of removing an abox assertion for + * an individual is sameAs another. + */ + @Test + public void removeABoxAssertion1() { + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty P = tBox.createObjectProperty("http://test.vivo/P"); + P.setLabel("property P", "en-US"); + + OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); + Q.setLabel("property Q", "en-US"); + + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + S.setLabel("property S", "en-US"); + + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + T.setLabel("property T", "en-US"); + + Literal literal1 = tBox.createLiteral("Literal value 1"); + Literal literal2 = tBox.createLiteral("Literal value 2"); + + // 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"); + + aBox.add(a,P,c); + aBox.add(a,S,literal1); + aBox.add(b,Q,d); + aBox.add(b,T,literal2); + aBox.add(a,OWL.sameAs,b); + + aBox.remove(a,P,c); + aBox.remove(a,S,literal1); + + Assert.assertFalse(inf.contains(b,P,c)); + Assert.assertFalse(inf.contains(b,S,literal1)); + } + + /* + * adding an inverseOf assertion for individuals who are sameAs + * each other. + */ + @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); + + 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"); + + 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); + + // Individuals a and b + Resource a = aBox.createResource("http://test.vivo/a"); + Resource b = aBox.createResource("http://test.vivo/b"); + + // abox statements + aBox.add(a,P,b); + aBox.add(a, OWL.sameAs,b); + + // Assert P and Q as inverses and wait for SimpleReasoner TBox + // thread to end + + Q.addInverseOf(P); + + tBox.rebind(); + tBox.prepare(); + + while (!VitroBackgroundThread.getLivingThreads().isEmpty()) { + Thread.sleep(delay); + } + + // Verify inferences + Assert.assertTrue(inf.contains(b,Q,a)); + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,P,b)); + Assert.assertTrue(inf.contains(a,Q,a)); + simpleReasonerTBoxListener.setStopRequested(); + } + + /* + * Basic scenario around recomputing the ABox inferences + */ + @Test + public void recomputeABox1() throws InterruptedException { + + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + OntProperty P = tBox.createObjectProperty("http://test.vivo/P"); + P.setLabel("property P", "en-US"); + + OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); + Q.setLabel("property Q", "en-US"); + + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + S.setLabel("property S", "en-US"); + + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + T.setLabel("property T", "en-US"); + + Literal literal1 = tBox.createLiteral("Literal value 1"); + Literal literal2 = tBox.createLiteral("Literal value 2"); + + // 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); + SimpleReasoner simpleReasoner = new SimpleReasoner(tBox, aBox, inf); + aBox.register(simpleReasoner); + + // 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.add(a,P,c); + aBox.add(a,S,literal1); + aBox.add(b,Q,d); + aBox.add(b,T,literal2); + aBox.add(a,OWL.sameAs,b); + + simpleReasoner.recompute(); + + while (simpleReasoner.isRecomputing()) { + Thread.sleep(delay); + } + + // Verify inferences + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,P,c)); + Assert.assertTrue(inf.contains(b,S,literal1)); + Assert.assertTrue(inf.contains(a,Q,d)); + Assert.assertTrue(inf.contains(a,T,literal2)); + } + + //==================================== 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); + + } +} \ No newline at end of file