From 2b15e7211c7363223cc8393fb2c8045709c5f74e Mon Sep 17 00:00:00 2001 From: stellamit Date: Sun, 10 Jun 2012 02:07:59 +0000 Subject: [PATCH] incremental development for sameAs inference support --- .../vitro/webapp/reasoner/SimpleReasoner.java | 221 +++++++++++------- .../SimpleReasonerInversePropertyTest.java | 2 +- .../reasoner/SimpleReasonerSameAsTest.java | 151 ++++++++++-- 3 files changed, 262 insertions(+), 112 deletions(-) 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 0d0ffed27..5fa989c4f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -427,6 +428,8 @@ public class SimpleReasoner extends StatementListener { Resource subject = null; Resource object = null; + //System.out.println("\n\naddedABoxSameAsAssertion called for this statement: " + stmtString(stmt)); + if (stmt.getSubject().isResource()) { subject = stmt.getSubject().asResource(); if (tboxModel.containsResource(subject) || subject.isAnon()) { @@ -449,18 +452,6 @@ public class SimpleReasoner extends StatementListener { 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(); - addInference(infStmt,inferenceModel,false); - } - inferenceModel.enterCriticalSection(Lock.WRITE); try { if (inferenceModel.contains(stmt)) { @@ -469,35 +460,103 @@ public class SimpleReasoner extends StatementListener { } finally { inferenceModel.leaveCriticalSection(); } - } - - /* - * 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(); + Statement opposite = ResourceFactory.createStatement(object, OWL.sameAs, subject); + addInference(opposite,inferenceModel,true); + + generateSameAsInferences(subject, object, inferenceModel); + generateSameAsInferences(object, subject, inferenceModel); + } + + /* + * 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; + } + + Set sameIndividuals = new HashSet(); + + inferenceModel.enterCriticalSection(Lock.READ); + try { + Iterator iter1 = inferenceModel.listStatements(subject, OWL.sameAs, (RDFNode) null); + while (iter1.hasNext()) { + Statement sameStmt = iter1.next(); + if (sameStmt.getObject() == null || !sameStmt.getObject().isResource()) continue; + sameIndividuals.add(sameStmt.getObject().asResource()); + } + + Iterator iter2 = inferenceModel.listStatements(object, OWL.sameAs, (RDFNode) null); + while (iter2.hasNext()) { + Statement sameStmt = iter2.next(); + if (sameStmt.getObject() == null || !sameStmt.getObject().isResource()) continue; + sameIndividuals.add(sameStmt.getObject().asResource()); + } + } finally { + inferenceModel.leaveCriticalSection(); + } + + + Iterator sIter1 = sameIndividuals.iterator(); + while (sIter1.hasNext()) { + removeInferencesForIndividual(sIter1.next(), inferenceModel); + } + + Iterator sIter2 = sameIndividuals.iterator(); + while (sIter2.hasNext()) { + computeInferencesForIndividual(sIter2.next(), inferenceModel); + } + } + + public void generateSameAsInferences(Resource ind1, Resource ind2, Model inferenceModel) { + + //System.out.println("\n\tgenerateSameAsInferences. ind1= " + ind1.getLocalName() + " ind2= " + ind2.getLocalName()); 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()); + aboxModel.enterCriticalSection(Lock.READ); + try { + Iterator iter = unionModel.listStatements(ind1, (Property) null, (RDFNode) null); + while (iter.hasNext()) { + Statement stmt = iter.next(); + //System.out.println("\tIn loop. stmt = " + stmtString(stmt)); + if (stmt.getObject() == null) continue; + Statement infStmt = ResourceFactory.createStatement(ind2,stmt.getPredicate(),stmt.getObject()); + addInference(infStmt, inferenceModel,true); + } + } finally { + aboxModel.leaveCriticalSection(); } - } finally { - aboxModel.leaveCriticalSection(); - } - return inferences; + return; } /* @@ -532,71 +591,38 @@ public class SimpleReasoner extends StatementListener { } /* - * 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 + * Remove inferences for individual */ - //TODO - I think I need to handle sameAs chains here - public void removedABoxSameAsAssertion(Statement stmt, Model inferenceModel) { + public void removeInferencesForIndividual(Resource ind, 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; - } - - Statement infStmt = ResourceFactory.createStatement(object,OWL.sameAs,subject); - removeInference(infStmt,inferenceModel,false); - recomputeInferencesForIndividual(subject, inferenceModel); - recomputeInferencesForIndividual(object, inferenceModel); - } - - /* - * Recompute inferences for individual - */ - public void recomputeInferencesForIndividual(Resource ind, Model inferenceModel) { - - Model inferencesToRemove = ModelFactory.createDefaultModel(); + Model individualInferences = ModelFactory.createDefaultModel(); inferenceModel.enterCriticalSection(Lock.READ); try { Iterator iter = inferenceModel.listStatements(ind, (Property) null, (RDFNode) null); while (iter.hasNext()) { - inferencesToRemove.add(iter.next()); + individualInferences.add(iter.next()); } } finally { inferenceModel.leaveCriticalSection(); } - + inferenceModel.enterCriticalSection(Lock.WRITE); try { - inferenceModel.remove(inferencesToRemove); + inferenceModel.remove(individualInferences); } finally { inferenceModel.leaveCriticalSection(); } + return; + } + + /* + * compute inferences for individual + */ + public void computeInferencesForIndividual(Resource ind, Model inferenceModel) { + Iterator iter = null; aboxModel.enterCriticalSection(Lock.WRITE); try { @@ -606,12 +632,14 @@ public class SimpleReasoner extends StatementListener { } while (iter.hasNext()) { - addedStatement(iter.next()); + Statement stmt = iter.next(); + //System.out.println("calling addedStatement for: " + stmtString(stmt)); + addedStatement(stmt); } return; } - + /* * Performs incremental property-based reasoning. * @@ -624,6 +652,7 @@ public class SimpleReasoner extends StatementListener { * */ public void addedABoxAssertion(Statement stmt, Model inferenceModel) { + List inverseProperties = getInverseProperties(stmt); Iterator inverseIter = inverseProperties.iterator(); @@ -1082,6 +1111,10 @@ public class SimpleReasoner extends StatementListener { */ protected void removeInference(Statement infStmt, Model inferenceModel, boolean handleSameAs) { + //TODO - add to Abox here if it's entailed? + + //System.out.println("\nremoveInference called for this statement: " + stmtString(infStmt)); + inferenceModel.enterCriticalSection(Lock.WRITE); try { if ( !entailedStatement(infStmt) && inferenceModel.contains(infStmt)) { @@ -1100,13 +1133,14 @@ public class SimpleReasoner extends StatementListener { while (sameIter.hasNext()) { Statement infStmtSame = ResourceFactory.createStatement(sameIter.next(), infStmt.getPredicate(), infStmt.getObject()); if (!entailedStatement(infStmtSame) && inferenceModel.contains(infStmtSame)) { + //System.out.println("\tsameAs processing: removing this from the inference model: " + stmtString(infStmtSame)); inferenceModel.remove(infStmtSame); } } } finally { inferenceModel.leaveCriticalSection(); } - } + } } /* @@ -1117,11 +1151,14 @@ public class SimpleReasoner extends StatementListener { */ protected void addInference(Statement infStmt, Model inferenceModel, boolean handleSameAs) { + //System.out.println("\taddInference called for this statement: " + stmtString(infStmt)); + aboxModel.enterCriticalSection(Lock.READ); try { inferenceModel.enterCriticalSection(Lock.WRITE); try { if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { + //System.out.println("\t\tadding this to the inference model: " + stmtString(infStmt)); inferenceModel.add(infStmt); } @@ -1130,8 +1167,16 @@ public class SimpleReasoner extends StatementListener { 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()); + + Statement sameStmt = ResourceFactory.createStatement(subject,infStmt.getPredicate(),infStmt.getObject()); + if (subject.equals(infStmt.getObject()) && OWL.sameAs.equals(infStmt.getPredicate())) { + //System.out.println("\t\tsameAS processing: skipping adding this statement to the inference model: " + stmtString(sameStmt)); + continue; + } + + if (!inferenceModel.contains(sameStmt) && !aboxModel.contains(sameStmt)) { + //System.out.println("\t\tsameAs processing: adding this to the inference model: " + stmtString(sameStmt)); + inferenceModel.add(sameStmt); } } } @@ -1143,11 +1188,11 @@ public class SimpleReasoner extends StatementListener { } /* - System.out.println("hello!!! ONE"); + //System.out.println("hello!!! ONE"); if (handleSameAs) { - System.out.println("hello!!! TWO"); + //System.out.println("hello!!! TWO"); aboxModel.enterCriticalSection(Lock.READ); - System.out.println("hello!!! TRES"); + //System.out.println("hello!!! TRES"); try { List sameIndividuals = getSameIndividuals(infStmt.getSubject().asResource(), inferenceModel); Iterator sameIter = sameIndividuals.iterator(); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java index 4c61fcb73..2d23b3782 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java @@ -24,7 +24,7 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { @Before public void suppressErrorOutput() { - suppressSyserr(); + //suppressSyserr(); //Turn off log messages to console setLoggerLevel(SimpleReasoner.class, Level.OFF); setLoggerLevel(SimpleReasonerTBoxListener.class, Level.OFF); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java index f0b167c59..3e589969e 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java @@ -28,7 +28,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { @Before public void suppressErrorOutput() { - suppressSyserr(); + //suppressSyserr(); //Turn off log messages to console setLoggerLevel(SimpleReasoner.class, Level.OFF); setLoggerLevel(SimpleReasonerTBoxListener.class, Level.OFF); @@ -90,7 +90,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } /* - * basic scenario of removing an abox sameAs assertion + * basic scenario of removing an abox sameAs assertion */ @Test public void removeSameAsABoxAssertion1() { @@ -103,10 +103,10 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { OntProperty Q = tBox.createObjectProperty("http://test.vivo/Q"); Q.setLabel("property Q", "en-US"); - OntProperty S = tBox.createDatatypeProperty("http://test.vivo/"); + OntProperty S = tBox.createDatatypeProperty("http://test.vivo/data1"); S.setLabel("property S", "en-US"); - OntProperty T = tBox.createDatatypeProperty("http://test.vivo/"); + OntProperty T = tBox.createDatatypeProperty("http://test.vivo/data2"); T.setLabel("property T", "en-US"); Literal literal1 = tBox.createLiteral("Literal value 1"); @@ -138,7 +138,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { 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)); @@ -147,8 +147,7 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } /* - * basic scenario of adding an abox assertion for - * an individual is sameAs another. + * adding abox assertion for individual in sameAs chain. */ @Test public void addABoxAssertion1() { @@ -182,10 +181,23 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { Resource b = aBox.createResource("http://test.vivo/b"); Resource c = aBox.createResource("http://test.vivo/c"); Resource d = aBox.createResource("http://test.vivo/d"); + Resource e = aBox.createResource("http://test.vivo/e"); + Resource f = aBox.createResource("http://test.vivo/f"); aBox.add(a,OWL.sameAs,b); + aBox.add(b,OWL.sameAs,e); + aBox.add(e,OWL.sameAs,f); Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(e,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(e,OWL.sameAs,b)); + Assert.assertTrue(inf.contains(a,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,b)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,a)); + Assert.assertTrue(inf.contains(b,OWL.sameAs,f)); + Assert.assertTrue(inf.contains(a,OWL.sameAs,f)); + aBox.add(a,P,c); aBox.add(a,S,literal1); @@ -196,24 +208,48 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { Assert.assertTrue(inf.contains(b,S,literal1)); Assert.assertTrue(inf.contains(a,Q,d)); Assert.assertTrue(inf.contains(a,T,literal2)); + Assert.assertTrue(inf.contains(e,P,c)); + Assert.assertTrue(inf.contains(e,S,literal1)); + Assert.assertTrue(inf.contains(e,Q,d)); + Assert.assertTrue(inf.contains(e,T,literal2)); + Assert.assertTrue(inf.contains(f,P,c)); + Assert.assertTrue(inf.contains(f,S,literal1)); + Assert.assertTrue(inf.contains(f,Q,d)); + Assert.assertTrue(inf.contains(f,T,literal2)); + + aBox.remove(b,OWL.sameAs,e); + + Assert.assertTrue(inf.contains(b,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(e,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(e,OWL.sameAs,b)); + Assert.assertFalse(inf.contains(a,OWL.sameAs,e)); + Assert.assertTrue(inf.contains(f,OWL.sameAs,e)); + Assert.assertFalse(inf.contains(f,OWL.sameAs,b)); + Assert.assertFalse(inf.contains(f,OWL.sameAs,a)); + Assert.assertFalse(inf.contains(b,OWL.sameAs,f)); + Assert.assertFalse(inf.contains(a,OWL.sameAs,f)); + + 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(inf.contains(e,P,c)); + Assert.assertFalse(inf.contains(e,S,literal1)); + Assert.assertFalse(inf.contains(e,Q,d)); + Assert.assertFalse(inf.contains(e,T,literal2)); + Assert.assertFalse(inf.contains(f,P,c)); + Assert.assertFalse(inf.contains(f,S,literal1)); + Assert.assertFalse(inf.contains(f,Q,d)); + Assert.assertFalse(inf.contains(f,T,literal2)); } /* - * adding abox assertion for individuals that are sameAs - * each other. + * sameAs with datatype properties */ @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"); @@ -230,18 +266,14 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { // 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)); } /* @@ -361,6 +393,79 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { } + /* + * adding and removing a type assertion for an individual who has + * a sameAs individual. + */ + //@Test + public void tBoxTypeAssertion1() throws InterruptedException { + + // Create a Tbox with a simple class hierarchy. B is a subclass of A. + // Pellet will compute TBox inferences + OntModel tBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC); + + 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); + + // 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)); + + Resource x = aBox.createResource("http://test.vivo/x"); + Resource y = aBox.createResource("http://test.vivo/y"); + Resource z = aBox.createResource("http://test.vivo/z"); + + aBox.add(x,OWL.sameAs,y); + aBox.add(y,OWL.sameAs,z); + aBox.add(x,RDF.type,classB); + + Assert.assertTrue(inf.contains(y,RDF.type,classB)); + Assert.assertTrue(inf.contains(y,RDF.type,classA)); +// Assert.assertTrue(inf.contains(z,RDF.type,classB)); +// Assert.assertTrue(inf.contains(z,RDF.type,classA)); + + aBox.remove(x,RDF.type,classB); + Assert.assertFalse(inf.contains(y,RDF.type,classB)); + Assert.assertFalse(inf.contains(y,RDF.type,classA)); + } + + + /* + * adding and removing subclass assertion when there is an + * individual member who has a sameAs individual. + */ + //@Test + public void tBoxSubclassAssertion1() throws InterruptedException { + + } + + /* + * test that mostSpecificType inferences propagate to sameAs + * individuals + */ + //@Test + public void mostSpecificTypeTest1() throws InterruptedException { + + } + + /* + * there is a sameAs chain and one sameAs statement is removed. + * + */ + //@Test + public void sameAsChain1() throws InterruptedException { + + } + + /* * Basic scenario around recomputing the ABox inferences */