| package org.apache.rya.reasoning; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.eclipse.rdf4j.model.IRI; |
| import org.eclipse.rdf4j.model.Resource; |
| import org.eclipse.rdf4j.model.vocabulary.OWL; |
| import org.eclipse.rdf4j.model.vocabulary.RDF; |
| import org.eclipse.rdf4j.model.vocabulary.RDFS; |
| import org.eclipse.rdf4j.model.vocabulary.SKOS; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class LocalReasonerTest { |
| private LocalReasoner reasoner; |
| private Schema schema; |
| |
| /** |
| * Load in a small schema to use in instance reasoning |
| */ |
| @Before |
| public void loadSchema() { |
| schema = new Schema(); |
| reasoner = new LocalReasoner(TestUtils.NODE, schema, 1, 0); |
| } |
| |
| /** |
| * cax-sco |
| */ |
| @Test |
| public void testInferSuperclass() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("Professor"), |
| RDFS.SUBCLASSOF, TestUtils.uri("Faculty"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("Professor"))); |
| Assert.assertTrue("Type not derived from subclass", |
| reasoner.types.knownTypes.containsKey(TestUtils.uri("Faculty"))); |
| } |
| |
| /** |
| * prp-dom |
| */ |
| @Test |
| public void testInferDomain() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("hasAlumnus"), |
| RDFS.DOMAIN, TestUtils.uri("University"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasAlumnus"), TestUtils.uri("John Doe"))); |
| Assert.assertTrue("Type not derived from rdfs:domain", |
| reasoner.types.knownTypes.containsKey(TestUtils.uri("University"))); |
| } |
| |
| /** |
| * prp-rng |
| */ |
| @Test |
| public void testInferRange() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("advisor"), |
| RDFS.RANGE, TestUtils.uri("Professor"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("John Doe"), |
| TestUtils.uri("advisor"), TestUtils.NODE)); |
| Assert.assertTrue("Type not derived from rdfs:range", |
| reasoner.types.knownTypes.containsKey(TestUtils.uri("Professor"))); |
| } |
| |
| /** |
| * cls-nothing2 |
| */ |
| @Test |
| public void testNothingInconsistent() throws Exception { |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, OWL.NOTHING)); |
| Assert.assertTrue("rdf:type owl:Nothing should be inconsistent", |
| reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * prp-inv1 |
| */ |
| @Test |
| public void testInverseProperty1() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("memberOf"), |
| OWL.INVERSEOF, TestUtils.uri("member"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("memberOf"), TestUtils.NODE)); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(TestUtils.uri("member")) |
| && t.getObject().equals(TestUtils.uri("y"))) { |
| return; |
| } |
| } |
| Assert.fail("Should have derived inverse triple"); |
| } |
| |
| /** |
| * prp-inv2 |
| */ |
| @Test |
| public void testInverseProperty2() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("memberOf"), |
| OWL.INVERSEOF, TestUtils.uri("member"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("member"), TestUtils.NODE)); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(TestUtils.uri("memberOf")) |
| && t.getObject().equals(TestUtils.uri("y"))) { |
| return; |
| } |
| } |
| Assert.fail("Should have derived inverse triple"); |
| } |
| |
| /** |
| * prp-spo1 |
| */ |
| @Test |
| public void testInferSuperproperty() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("headOf"), |
| RDFS.SUBPROPERTYOF, TestUtils.uri("worksFor"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("headOf"), TestUtils.uri("org"))); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(TestUtils.uri("worksFor")) |
| && t.getObject().equals(TestUtils.uri("org"))) { |
| return; |
| } |
| } |
| Assert.fail("Superproperty not inferred from subproperty"); |
| } |
| |
| /** |
| * prp-symp |
| */ |
| @Test |
| public void testSymmetry() throws Exception { |
| schema.processTriple(TestUtils.statement(SKOS.RELATED, RDF.TYPE, |
| OWL.SYMMETRICPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), SKOS.RELATED, |
| TestUtils.NODE)); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(SKOS.RELATED) |
| && t.getObject().equals(TestUtils.uri("y"))) { |
| return; |
| } |
| } |
| Assert.fail("Symmetric property not inferred"); |
| } |
| |
| /** |
| * cls-com |
| */ |
| @Test |
| public void testComplementaryClasses() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("A"), |
| OWL.COMPLEMENTOF, TestUtils.uri("NotA"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("A"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("NotA"))); |
| Assert.assertTrue("Complementary class membership not detected", |
| reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * cax-dw |
| */ |
| @Test |
| public void testDisjointClasses() throws Exception { |
| schema.processTriple(TestUtils.statement(SKOS.CONCEPT, OWL.DISJOINTWITH, |
| SKOS.COLLECTION)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| SKOS.CONCEPT)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| SKOS.COLLECTION)); |
| Assert.assertTrue("Disjoint class membership not detected", |
| reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * prp-trp |
| */ |
| @Test |
| public void testTransitivePropertyIncomingOutgoing() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("subOrganizationOf"), |
| RDF.TYPE, OWL.TRANSITIVEPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("subOrganizationOf"), TestUtils.NODE)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("subOrganizationOf"), TestUtils.uri("z"))); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("y")) |
| && t.getPredicate().equals(TestUtils.uri("subOrganizationOf")) |
| && t.getObject().equals(TestUtils.uri("z"))) { |
| return; |
| } |
| } |
| Assert.fail("Transitive relation not inferred (received incoming edge first)"); |
| } |
| @Test |
| public void testTransitivePropertyOutgoingIncoming() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("subOrganizationOf"), |
| RDF.TYPE, OWL.TRANSITIVEPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("subOrganizationOf"), TestUtils.uri("z"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("subOrganizationOf"), TestUtils.NODE)); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("y")) |
| && t.getPredicate().equals(TestUtils.uri("subOrganizationOf")) |
| && t.getObject().equals(TestUtils.uri("z"))) { |
| Assert.fail("Transitive relation should not be inferred " |
| + "(received outgoing edge first)"); |
| } |
| } |
| } |
| |
| /** |
| * prp-irp |
| */ |
| @Test |
| public void testIrreflexiveProperty() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("hasParent"), |
| RDF.TYPE, OWL2.IRREFLEXIVEPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasParent"), TestUtils.NODE)); |
| Assert.assertTrue("Relation to self via irreflexive property not detected", |
| reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * prp-asyp |
| */ |
| @Test |
| public void testAsymmetricPropertyIncomingOutgoing() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("hasChild"), |
| RDF.TYPE, OWL2.ASYMMETRICPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("hasChild"), TestUtils.NODE)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasChild"), TestUtils.uri("y"))); |
| Assert.assertTrue("Symmetric relation with asymmetric property not detected" |
| + " (receiving incoming edge first)", reasoner.hasInconsistencies()); |
| } |
| @Test |
| public void testAsymmetricPropertyReverseOutgoingIncoming() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("hasChild"), RDF.TYPE, |
| OWL2.ASYMMETRICPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasChild"), TestUtils.uri("y"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("y"), |
| TestUtils.uri("hasChild"), TestUtils.NODE)); |
| Assert.assertFalse("Symmetric relation with asymmetric property should" |
| + " not be detected when receiving outgoing edge first", |
| reasoner.hasInconsistencies()); |
| } |
| @Test |
| public void testAsymmetricPropertyReflexive() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("hasChild"), |
| RDF.TYPE, OWL2.ASYMMETRICPROPERTY)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasChild"), TestUtils.NODE)); |
| Assert.assertTrue("Self-referential relation with asymmetric property" |
| + " not detected", reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * prp-pdw |
| */ |
| @Test |
| public void testDisjointProperties() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("p1"), |
| OWL2.PROPERTYDISJOINTWITH, TestUtils.uri("p2"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("p1"), TestUtils.uri("y"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("p2"), TestUtils.uri("y"))); |
| Assert.assertTrue("Disjoint property usage not detected (left-hand side" |
| + " of propertyDisjointWith received first)", reasoner.hasInconsistencies()); |
| } |
| @Test |
| public void testDisjointPropertiesReverse() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("p2"), |
| OWL2.PROPERTYDISJOINTWITH, TestUtils.uri("p1"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("p1"), TestUtils.uri("y"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("p2"), TestUtils.uri("y"))); |
| Assert.assertTrue("Disjoint property usage not detected (right-hand side" |
| + " of propertyDisjointWith received first)", reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * cls-svf1 |
| */ |
| @Test |
| public void testSomeValuesFromMembership() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.SOMEVALUESFROM, TestUtils.uri("Department"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("headOf"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("Department"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("John Doe"), |
| TestUtils.uri("headOf"), TestUtils.NODE)); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("John Doe")) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("x"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:someValuesFrom c]" |
| + " on property p; (z type c) then (y p z) should imply" |
| + " (y type x)."); |
| } |
| @Test |
| public void testSomeValuesFromMembershipReverse() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.SOMEVALUESFROM, TestUtils.uri("Department"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("headOf"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.uri("John Doe"), |
| TestUtils.uri("headOf"), TestUtils.NODE)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("Department"))); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("John Doe")) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("x"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:someValuesFrom c]" |
| + " on property p; (y p z) then (z type c) should imply" |
| + " (y type x)."); |
| } |
| |
| /** |
| * cls-svf2 |
| */ |
| @Test |
| public void testSomeValuesFromThing() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.SOMEVALUESFROM, OWL.THING)); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("foo"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("foo"), TestUtils.uri("bar"))); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("x"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:someValuesFrom owl:Thing]" |
| + " on property p; (y p z) should imply (y type x) for any z."); |
| } |
| |
| /** |
| * cls-hv1 |
| */ |
| @Test |
| public void testHasValueInferValue() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), OWL.HASVALUE, |
| TestUtils.uri("y"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("p"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("x"))); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(TestUtils.uri("p")) |
| && t.getObject().equals(TestUtils.uri("y"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:hasValue y]" |
| + " on property p; (u type x) should imply (u p y) for any u."); |
| } |
| |
| /** |
| * cls-hv2 |
| */ |
| @Test |
| public void testHasValueInferClass() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), OWL.HASVALUE, |
| TestUtils.uri("y"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("p"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("p"), TestUtils.uri("y"))); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.NODE) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("x"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:hasValue y]" |
| + " on property p; (u p y) should imply (u type x) for any u."); |
| } |
| |
| |
| /** |
| * cls-avf |
| */ |
| @Test |
| public void testAllValuesFrom() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ALLVALUESFROM, TestUtils.uri("Human"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("hasParent"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasParent"), TestUtils.uri("v"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("x"))); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("v")) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("Human"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:allValuesFrom c]" |
| + " on property p; (u p v) then (u type x) should imply (v type c)."); |
| } |
| @Test |
| public void testAllValuesFromReverse() throws Exception { |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ALLVALUESFROM, TestUtils.uri("Human"))); |
| schema.processTriple(TestUtils.statement(TestUtils.uri("x"), |
| OWL.ONPROPERTY, TestUtils.uri("hasParent"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, |
| TestUtils.uri("x"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, |
| TestUtils.uri("hasParent"), TestUtils.uri("v"))); |
| reasoner.getTypes(); |
| for (Fact t : reasoner.getFacts()) { |
| if (t.getSubject().equals(TestUtils.uri("v")) |
| && t.getPredicate().equals(RDF.TYPE) |
| && t.getObject().equals(TestUtils.uri("Human"))) { |
| return; |
| } |
| } |
| Assert.fail("If x is a property restriction [owl:allValuesFrom c]" |
| + " on property p; (u type x) then (u p v) should imply (v type c)."); |
| } |
| |
| /** |
| * cls-maxc1 |
| */ |
| @Test |
| public void testMaxCardinalityZero() throws Exception { |
| IRI r = TestUtils.uri("restriction"); |
| IRI p = TestUtils.uri("impossiblePredicate1"); |
| schema.processTriple(TestUtils.statement(r, OWL.MAXCARDINALITY, |
| TestUtils.intLiteral("0"))); |
| schema.processTriple(TestUtils.statement(r, OWL.ONPROPERTY, p)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, p, |
| TestUtils.uri("y"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, r)); |
| Assert.assertTrue("If p has maxCardinality of 0; then any (x p y)" |
| + " should be found inconsistent", reasoner.hasInconsistencies()); |
| } |
| |
| /** |
| * cls-maxqc2 |
| */ |
| @Test |
| public void testMaxQCardinalityZeroThings() throws Exception { |
| Resource r = TestUtils.bnode("restriction"); |
| IRI p = TestUtils.uri("impossiblePredicate2"); |
| schema.processTriple(TestUtils.statement(r, OWL2.MAXQUALIFIEDCARDINALITY, |
| TestUtils.intLiteral("0"))); |
| schema.processTriple(TestUtils.statement(r, OWL.ONPROPERTY, p)); |
| schema.processTriple(TestUtils.statement(r, OWL2.ONCLASS, OWL.THING)); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, p, |
| TestUtils.uri("y"))); |
| reasoner.processFact(TestUtils.fact(TestUtils.NODE, RDF.TYPE, r)); |
| Assert.assertTrue("If p has maxQualifiedCardinality of 0 on owl:Thing;" |
| + " then any (x p y) should be found inconsistent", |
| reasoner.hasInconsistencies()); |
| } |
| } |