From 232362e1715649c7e6ba2d52149ce4dec5f19b08 Mon Sep 17 00:00:00 2001 From: Simon Spero Date: Wed, 30 Apr 2014 20:22:50 -0400 Subject: [PATCH 1/5] Add class + tests for langRange pattern matching --- .../datatypes/types/text/LangRange.java | 128 ++++++++++++++++++ .../pellet/datatypes/test/LangRangeTests.java | 51 +++++++ 2 files changed, 179 insertions(+) create mode 100644 core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/LangRange.java create mode 100644 test/src/test/java/com/clarkparsia/pellet/datatypes/test/LangRangeTests.java diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/LangRange.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/LangRange.java new file mode 100644 index 000000000..08eeb31e2 --- /dev/null +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/LangRange.java @@ -0,0 +1,128 @@ +package com.clarkparsia.pellet.datatypes.types.text; + +/** + * Extended language range patterns as defined in RFC 4647 + */ +public class LangRange { + + private static final String[] EMPTY_SUBTAG_LIST = new String[0]; + private final String rangeString; + private String[] rangeSubtags; + + /** + * @param range An extended language pattern as defined in RFC 4647 + */ + public LangRange(String range) { + if (range == null) { + range = ""; + } + this.rangeString = range; + if (range.length() == 0) { + rangeSubtags = EMPTY_SUBTAG_LIST; + } else { + rangeSubtags = range.split("-"); + } + } + + /** + * Match a language according to the extended filtering rules of RFC 4647 sec 3.3.2 + * + * @param tag language tag to match + * @return true if tag is in the specified range + */ + public boolean match(String tag) { + // empty tag only matches empty range + if (tag == null || tag.length() == 0) { + return rangeSubtags.length == 0; + } + // empty range only matches empty tag + if (rangeSubtags.length == 0) { + return false; + } + + /* + 1. Split both the extended language range and the language tag being + compared into a list of subtags by dividing on the hyphen (%x2D) + character. Two subtags match if either they are the same when + compared case-insensitively or the language range's subtag is the + wildcard '*'. + */ + + String tagSubtags[] = tag.split("-"); + + /* + 2. Begin with the first subtag in each list. If the first subtag in + the range does not match the first subtag in the tag, the overall + match fails. Otherwise, move to the next subtag in both the + range and the tag. + */ + int tagIndex = 0; + int rangeIndex = 0; + + String rangeSubTag = rangeSubtags[rangeIndex++]; + String tagSubTag = tagSubtags[tagIndex++]; + + if (!rangeSubTag.equals("*") && !rangeSubTag.equalsIgnoreCase(tagSubTag)) { + return false; + } + /* + 3. While there are more subtags left in the language range's list: + */ + while (rangeIndex < rangeSubtags.length) { + rangeSubTag = rangeSubtags[rangeIndex]; + + /* A. If the subtag currently being examined in the range is the + wildcard ('*'), move to the next subtag in the range and + continue with the loop. + */ + if (rangeSubTag.equals("*")) { + rangeIndex++; + continue; + } + /* B. Else, if there are no more subtags in the language tag's + list, the match fails. + */ + if (tagIndex >= tagSubtags.length) { + return false; + } + /* C. Else, if the current subtag in the range's list matches the + current subtag in the language tag's list, move to the next + subtag in both lists and continue with the loop. + */ + tagSubTag = tagSubtags[tagIndex]; + if (rangeSubTag.equalsIgnoreCase(tagSubTag)) { + tagIndex++; + rangeIndex++; + continue; + } + /* D. Else, if the language tag's subtag is a "singleton" (a single + letter or digit, which includes the private-use subtag 'x') + the match fails. + */ + if (tagSubTag.length() == 1) { + return false; + } + /* E. Else, move to the next subtag in the language tag's list and + continue with the loop. + */ + tagIndex++; + } + return true; + } + + + @Override + public boolean equals(Object o) { + return this == o || o instanceof LangRange && rangeString.equals(((LangRange) o).rangeString); + } + + @Override + public int hashCode() { + return rangeString.hashCode(); + } + + @Override + public String toString() { + return rangeString; + } +} diff --git a/test/src/test/java/com/clarkparsia/pellet/datatypes/test/LangRangeTests.java b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/LangRangeTests.java new file mode 100644 index 000000000..795f84fc2 --- /dev/null +++ b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/LangRangeTests.java @@ -0,0 +1,51 @@ +package com.clarkparsia.pellet.datatypes.test; + +import com.clarkparsia.pellet.datatypes.types.text.LangRange; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Created by ses on 4/30/14. + */ +public class LangRangeTests { + + @Test + public void testLangEmptyRange() { + LangRange emptyRange = new LangRange(""); + assertTrue("empty matches empty", emptyRange.match("")); + assertTrue("empty matches empty", emptyRange.match(null)); + assertFalse("empty does not match en", emptyRange.match("en")); + } + + @Test + public void testUniversalRange() { + LangRange any = new LangRange("*"); + assertTrue("any mathches en", any.match("en")); + assertFalse("any doesn't match empty", any.match("")); + assertFalse("any doesn't match empty", any.match(null)); + } + + @Test + public void testRFC4647TestCases() { + matchAllAgainstRange("de-*-DE", true, + "de-DE", "de-de", "de-Latn-DE", "de-Latf-DE", "de-DE-x-goethe", "de-Latn-DE-1996", "de-Deva-DE"); + + matchAllAgainstRange("de-DE", true, + "de-DE", "de-de", "de-Latn-DE", "de-Latf-DE", "de-DE-x-goethe", "de-Latn-DE-1996", "de-Deva-DE"); + + matchAllAgainstRange("de-*-DE", false, + "de", "de-x-DE", "de-Deva"); + matchAllAgainstRange("de-DE", false, + "de", "de-x-DE", "de-Deva"); + } + + private void matchAllAgainstRange(String rangeString, boolean expected, String... tags) { + LangRange range = new LangRange(rangeString); + for (String tag : tags) { + assertEquals("match " + rangeString + " against " + tag, expected, range.match(tag)); + } + } +} From 34e7f8b37ca0e6651bd1f4a27cfc5305dc4b02c5 Mon Sep 17 00:00:00 2001 From: Simon Spero Date: Wed, 30 Apr 2014 20:24:08 -0400 Subject: [PATCH 2/5] Add support for rdf:langRange facet on rdf:PlainLiteral --- .../clarkparsia/pellet/datatypes/Facet.java | 20 +- .../types/text/RestrictedTextDatatype.java | 359 ++++++++++-------- .../test/DatatypeRestrictionTests.java | 340 ++++++++++------- 3 files changed, 420 insertions(+), 299 deletions(-) diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/Facet.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/Facet.java index 79e2d7e5a..e1b49f57f 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/Facet.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/Facet.java @@ -37,7 +37,11 @@ public static class Registry { for( Facet f : XSD.values() ) { map.put( f.getName(), f ); } - } + for( Facet f : RDF.values() ) { + map.put( f.getName(), f ); + } + + } /** * Get a Facet for a URI @@ -73,4 +77,18 @@ public ATermAppl getName() { } } + + public static enum RDF implements Facet { + LANG_RANGE("langRange"); + + private final ATermAppl name; + + private RDF(String localName) { + name = ATermUtils.makeTermAppl( Namespaces.RDF + localName ); + } + + public ATermAppl getName() { + return name; + } + } } diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java index a00925d86..860140adf 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java @@ -1,5 +1,14 @@ package com.clarkparsia.pellet.datatypes.types.text; +import aterm.ATerm; +import aterm.ATermAppl; +import com.clarkparsia.pellet.datatypes.Datatype; +import com.clarkparsia.pellet.datatypes.Facet; +import com.clarkparsia.pellet.datatypes.RestrictedDatatype; +import com.clarkparsia.pellet.datatypes.exceptions.InvalidConstrainingFacetException; +import org.mindswap.pellet.utils.ATermUtils; +import org.mindswap.pellet.utils.SetUtils; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -10,15 +19,6 @@ import java.util.Set; import java.util.regex.Pattern; -import org.mindswap.pellet.utils.ATermUtils; -import org.mindswap.pellet.utils.SetUtils; - -import aterm.ATermAppl; - -import com.clarkparsia.pellet.datatypes.Datatype; -import com.clarkparsia.pellet.datatypes.RestrictedDatatype; -import com.clarkparsia.pellet.datatypes.exceptions.InvalidConstrainingFacetException; - /** *

* Title: Restricted Text Datatype @@ -32,175 +32,206 @@ *

* Company: Clark & Parsia, LLC. *

- * + * * @author Mike Smith */ public class RestrictedTextDatatype implements RestrictedDatatype { - private static final String NCNAMESTARTCHAR = "[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]"; - private static final String NCNAMECHAR = NCNAMESTARTCHAR + "|-|\\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]"; - protected static final String NCNAME = "(" + NCNAMESTARTCHAR + ")(" + NCNAMECHAR + ")*"; - - private static final String NAMESTARTCHAR = ":|" + NCNAMESTARTCHAR; - private static final String NAMECHAR = NAMESTARTCHAR + "|-|\\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]"; - protected static final String NAME = "(" + NAMESTARTCHAR + ")(" + NAMECHAR + ")*"; - - protected static final String NMTOKEN = "(" + NAMECHAR + ")+"; - - protected static final String TOKEN = "([^\\s])(\\s([^\\s])|([^\\s]))*"; - - protected static final String LANGUAGE = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"; - - protected static final String NORMALIZED_STRING = "([^\\r\\n\\t])*"; - - private static final Set permittedDts; - - private final Set excludedValues; - private final Set patterns; - - static { - permittedDts = new HashSet( Arrays.asList( ATermUtils.EMPTY ) ); - } - - /* - * TODO: This is awkward. - */ - public static boolean addPermittedDatatype(ATermAppl dt) { - return permittedDts.add( dt ); - } - - private final boolean allowLang; - private final Datatype dt; - - public RestrictedTextDatatype(Datatype dt, boolean allowLang) { - this(dt, Collections.emptySet(), allowLang, Collections.emptySet()); - } - - public RestrictedTextDatatype(Datatype dt, String pattern) { - this(dt, Collections.singleton(Pattern.compile(pattern)), false, Collections.emptySet()); - } - - private RestrictedTextDatatype(Datatype dt, Set patterns, boolean allowLang, Set excludedValues) { - this.dt = dt; - this.allowLang = allowLang; - this.excludedValues = excludedValues; - this.patterns = patterns; - } - - public RestrictedDatatype applyConstrainingFacet(ATermAppl facet, Object value) - throws InvalidConstrainingFacetException { - // TODO: support facets - throw new UnsupportedOperationException(); - } - - public boolean contains(Object value) { - if( value instanceof ATermAppl ) { - final ATermAppl a = (ATermAppl) value; - - if (excludedValues.contains(a)) { - return false; - } - - if( ATermUtils.isLiteral( a ) - && permittedDts.contains( a.getArgument( ATermUtils.LIT_URI_INDEX ) ) ) { - if( !allowLang - && !ATermUtils.EMPTY.equals( a.getArgument( ATermUtils.LIT_LANG_INDEX ) ) ) { - return false; - } - - if (!patterns.isEmpty()) { - String litValue = ((ATermAppl) a.getArgument(ATermUtils.LIT_VAL_INDEX)).getName(); - for (Pattern pattern : patterns) { - if( !pattern.matcher(litValue).matches() ) - return false; - } - } - - return true; - } - } - return false; - } - - public boolean containsAtLeast(int n) { - return true; - } - - public RestrictedDatatype exclude(Collection values) { - Set newExcludedValues = new HashSet(values); - newExcludedValues.addAll(excludedValues); - return new RestrictedTextDatatype(dt, patterns, allowLang, newExcludedValues); - } - - public Datatype getDatatype() { - return dt; - } - - public ATermAppl getValue(int i) { - throw new UnsupportedOperationException(); - } - - protected List concatLists(List l1, List l2) { - if( l1.isEmpty() ) - return l2; - if( l2.isEmpty() ) - return l1; - - List newList = new ArrayList(l1.size() + l2.size()); - newList.addAll(l1); - newList.addAll(l2); - - return newList; - } - - public RestrictedDatatype intersect(RestrictedDatatype other, boolean negated) { - if( other instanceof RestrictedTextDatatype ) { - RestrictedTextDatatype that = (RestrictedTextDatatype) other; - - return new RestrictedTextDatatype(dt, SetUtils.union(this.patterns, that.patterns), this.allowLang - && that.allowLang, - SetUtils.union(this.excludedValues, that.excludedValues)); - } - else { - throw new IllegalArgumentException(); + private static final String NCNAMESTARTCHAR = "[A-Z]|_|[a-z]|[\u00C0-\u00D6]|[\u00D8-\u00F6]|[\u00F8-\u02FF]|[\u0370-\u037D]|[\u037F-\u1FFF]|[\u200C-\u200D]|[\u2070-\u218F]|[\u2C00-\u2FEF]|[\u3001-\uD7FF]|[\uF900-\uFDCF]|[\uFDF0-\uFFFD]"; + private static final String NCNAMECHAR = NCNAMESTARTCHAR + "|-|\\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]"; + protected static final String NCNAME = "(" + NCNAMESTARTCHAR + ")(" + NCNAMECHAR + ")*"; + + private static final String NAMESTARTCHAR = ":|" + NCNAMESTARTCHAR; + private static final String NAMECHAR = NAMESTARTCHAR + "|-|\\.|[0-9]|\u00B7|[\u0300-\u036F]|[\u203F-\u2040]"; + protected static final String NAME = "(" + NAMESTARTCHAR + ")(" + NAMECHAR + ")*"; + + protected static final String NMTOKEN = "(" + NAMECHAR + ")+"; + + protected static final String TOKEN = "([^\\s])(\\s([^\\s])|([^\\s]))*"; + + protected static final String LANGUAGE = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"; + + protected static final String NORMALIZED_STRING = "([^\\r\\n\\t])*"; + + private static final Set permittedDts; + + private final Set excludedValues; + private final Set patterns; + private final Set langRanges; + + static { + permittedDts = new HashSet(Arrays.asList(ATermUtils.EMPTY)); + } + + /* + * TODO: This is awkward. + */ + public static boolean addPermittedDatatype(ATermAppl dt) { + return permittedDts.add(dt); + } + + private final boolean allowLang; + private final Datatype dt; + + public RestrictedTextDatatype(Datatype dt, boolean allowLang) { + this(Collections.emptySet(), allowLang, Collections.emptySet(), dt, Collections.emptySet()); + } + + public RestrictedTextDatatype(Datatype dt, String pattern) { + this(Collections.singleton(Pattern.compile(pattern)), false, Collections.emptySet(), dt, Collections.emptySet()); + } + + private RestrictedTextDatatype(Set patterns, boolean allowLang, Set excludedValues, Datatype dt, Set langRanges) { + this.dt = dt; + this.allowLang = allowLang; + this.excludedValues = excludedValues; + this.patterns = patterns; + this.langRanges = langRanges; + } + + public RestrictedDatatype applyConstrainingFacet(ATermAppl facet, Object value) + throws InvalidConstrainingFacetException { + // TODO: support moar facets + + if (facet.equals(Facet.RDF.LANG_RANGE.getName())) { + return applyLangRangFacet(facet, value); + } else { + throw new InvalidConstrainingFacetException(facet, value); } - } + } - public boolean isEmpty() { - return false; - } + private RestrictedDatatype applyLangRangFacet(ATermAppl facet, Object value) throws InvalidConstrainingFacetException { + if (!(value instanceof ATermAppl)) { + throw new InvalidConstrainingFacetException("Invalid java type for value", facet, value); + } - public boolean isEnumerable() { - return false; - } + String rangePattern = ATermUtils.getLiteralValue((ATermAppl) value); + if (!allowLang && !rangePattern.equals("")) { + throw new InvalidConstrainingFacetException("can't add langRange facet to type that doesn't allow languages:" + this.dt.getName(), facet, value); + } + Set newRanges = new HashSet(); + newRanges.addAll(langRanges); + newRanges.add(new LangRange(rangePattern)); + return new RestrictedTextDatatype(patterns, allowLang, excludedValues, dt, newRanges); + } + + public boolean contains(Object value) { + if (value instanceof ATermAppl) { + final ATermAppl a = (ATermAppl) value; + + if (excludedValues.contains(a)) { + return false; + } - public boolean isFinite() { - return false; - } + if (ATermUtils.isLiteral(a) + && permittedDts.contains(a.getArgument(ATermUtils.LIT_URI_INDEX))) { - public int size() { - throw new IllegalStateException(); - } + boolean hasLangTag = !ATermUtils.EMPTY.equals(a.getArgument(ATermUtils.LIT_LANG_INDEX)); + if (!allowLang && hasLangTag) { + return false; + } + String langTag = hasLangTag ? ATermUtils.getLiteralLang(a) : ""; + for (LangRange range : langRanges) { + if(!range.match(langTag)) { + return false; + } + } + if (!patterns.isEmpty()) { + String litValue = ((ATermAppl) a.getArgument(ATermUtils.LIT_VAL_INDEX)).getName(); + for (Pattern pattern : patterns) { + if (!pattern.matcher(litValue).matches()) + return false; + } + } - public RestrictedDatatype union(RestrictedDatatype other) { - if( other instanceof RestrictedTextDatatype ) { - if (!patterns.isEmpty() || !((RestrictedTextDatatype) other).patterns.isEmpty()) { - throw new UnsupportedOperationException(); - } + return true; + } + } + return false; + } + + public boolean containsAtLeast(int n) { + return true; + } + + public RestrictedDatatype exclude(Collection values) { + Set newExcludedValues = new HashSet(values); + newExcludedValues.addAll(excludedValues); + return new RestrictedTextDatatype(patterns, allowLang, newExcludedValues, dt, langRanges); + } + + public Datatype getDatatype() { + return dt; + } + + public ATermAppl getValue(int i) { + throw new UnsupportedOperationException(); + } + + protected List concatLists(List l1, List l2) { + if (l1.isEmpty()) + return l2; + if (l2.isEmpty()) + return l1; + + List newList = new ArrayList(l1.size() + l2.size()); + newList.addAll(l1); + newList.addAll(l2); + + return newList; + } + + public RestrictedDatatype intersect(RestrictedDatatype other, boolean negated) { + if (other instanceof RestrictedTextDatatype) { + RestrictedTextDatatype that = (RestrictedTextDatatype) other; + + return new RestrictedTextDatatype(SetUtils.union(this.patterns, that.patterns), + this.allowLang && that.allowLang, + SetUtils.union(this.excludedValues, that.excludedValues), + dt, + SetUtils.union(this.langRanges, that.langRanges) + ); + } else { + throw new IllegalArgumentException(); + } + } + + public boolean isEmpty() { + return false; + } + + public boolean isEnumerable() { + return false; + } + + public boolean isFinite() { + return false; + } + + public int size() { + throw new IllegalStateException(); + } + + public RestrictedDatatype union(RestrictedDatatype other) { + if (other instanceof RestrictedTextDatatype) { + if (!patterns.isEmpty() || !((RestrictedTextDatatype) other).patterns.isEmpty() + || !langRanges.isEmpty() || !((RestrictedTextDatatype) other).langRanges.isEmpty()) { + //TODO support unions with patterns or langRanges + throw new UnsupportedOperationException("union of restricted text types with patterns or langRanges not yet done"); + } - if( this.allowLang ) { - return this; + if (this.allowLang) { + return this; } - return (RestrictedTextDatatype) other; - } - else { - throw new IllegalArgumentException(); + return (RestrictedTextDatatype) other; + } else { + throw new IllegalArgumentException(); } - } + } - public Iterator valueIterator() { - throw new IllegalStateException(); - } + public Iterator valueIterator() { + throw new IllegalStateException(); + } } diff --git a/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java index 28acc1d54..e6e3a2a00 100644 --- a/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java +++ b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java @@ -1,6 +1,15 @@ package com.clarkparsia.pellet.datatypes.test; +import aterm.ATermAppl; +import com.clarkparsia.pellet.datatypes.Facet; +import junit.framework.JUnit4TestAdapter; +import org.junit.Test; +import org.mindswap.pellet.PelletOptions; +import org.mindswap.pellet.test.AbstractKBTests; +import org.mindswap.pellet.utils.ATermUtils; + import static com.clarkparsia.pellet.datatypes.Datatypes.INTEGER; +import static com.clarkparsia.pellet.datatypes.Datatypes.PLAIN_LITERAL; import static com.clarkparsia.pellet.datatypes.Datatypes.POSITIVE_INTEGER; import static com.clarkparsia.pellet.utils.TermFactory.list; import static com.clarkparsia.pellet.utils.TermFactory.literal; @@ -14,148 +23,211 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; -import junit.framework.JUnit4TestAdapter; -import org.junit.Ignore; -import org.junit.Test; -import org.mindswap.pellet.PelletOptions; -import org.mindswap.pellet.test.AbstractKBTests; +public class DatatypeRestrictionTests extends AbstractKBTests { + public static junit.framework.Test suite() { + return new JUnit4TestAdapter(DatatypeRestrictionTests.class); + } + + @Test + public void simpleRestriction() { + classes(C); + dataProperties(p); + individuals(a, b); + + kb.addDatatypeDefinition(D, restrict(INTEGER, minInclusive(literal(1)))); + kb.addEquivalentClass(C, some(p, D)); + kb.addPropertyValue(p, a, literal(2)); + kb.addPropertyValue(p, b, literal(3)); -import aterm.ATermAppl; + assertTrue(kb.isType(a, C)); + assertTrue(kb.isType(b, C)); + } -public class DatatypeRestrictionTests extends AbstractKBTests { - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(DatatypeRestrictionTests.class); - } - - @Test - public void simpleRestriction() { - classes(C); - dataProperties(p); - individuals(a, b); - - kb.addDatatypeDefinition(D, restrict(INTEGER, minInclusive(literal(1)))); - kb.addEquivalentClass(C, some(p, D)); - kb.addPropertyValue(p, a, literal(2)); - kb.addPropertyValue(p, b, literal(3)); - - assertTrue(kb.isType(a, C)); - assertTrue(kb.isType(b, C)); - } - - @Test - public void nestedRestriction() { - classes(C); - dataProperties(p); - individuals(a, b); - - kb.addDatatypeDefinition(E, restrict(INTEGER, maxInclusive(literal(2)))); - kb.addDatatypeDefinition(D, restrict(E, minInclusive(literal(1)))); - kb.addEquivalentClass(C, some(p, D)); - kb.addPropertyValue(p, a, literal(2)); - kb.addPropertyValue(p, b, literal(3)); - - assertTrue(kb.isType(a, C)); - assertFalse(kb.isType(b, C)); - } - - @Test(expected = RuntimeException.class) - public void invalidRestriction() { - classes(C); - dataProperties(p); - individuals(a, b); - - kb.addDatatypeDefinition(E, oneOf(literal(1), literal(2), literal(3))); - kb.addDatatypeDefinition(D, restrict(E, minInclusive(literal(1)))); - kb.addEquivalentClass(C, some(p, D)); - kb.addPropertyValue(p, a, literal(2)); - kb.addPropertyValue(p, b, literal(3)); - - assertTrue(kb.isType(a, C)); - assertFalse(kb.isType(b, C)); - } - - @Test - public void invalidLiteralBuiltInDatatype() { - dataProperties(p); - individuals(a); - - kb.addRange(p, INTEGER); - kb.addPropertyValue(p, a, literal("-1", POSITIVE_INTEGER)); - - assertFalse(kb.isConsistent()); - } - - @Test - public void invalidLiteralRestrictedDatatype() { - dataProperties(p); - individuals(a); - - ATermAppl uri = term("http//example.com/datatype"); - - kb.addRange(p, INTEGER); - kb.addDatatypeDefinition(uri, restrict(INTEGER, minExclusive(literal(0)))); - kb.addPropertyValue(p, a, literal("-1", uri)); - - assertFalse(kb.isConsistent()); - } - - @Test - public void validLiteralRestrictedDatatype() { - dataProperties(p); - individuals(a); - - ATermAppl uri = term("http//example.com/datatype"); - - kb.addRange(p, INTEGER); - kb.addDatatypeDefinition(uri, restrict(INTEGER, minExclusive(literal(0)))); - kb.addPropertyValue(p, a, literal("1", uri)); - - assertTrue(kb.isConsistent()); - } - - @Test - public void validLiteralStringRestriction1() { - dataProperties(p); - individuals(a); - - ATermAppl uri = term("http//example.com/datatype"); - - kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); - kb.addRange(p, uri); - kb.addPropertyValue(p, a, literal("a")); - - assertTrue(kb.isConsistent()); - } + @Test + public void nestedRestriction() { + classes(C); + dataProperties(p); + individuals(a, b); + + kb.addDatatypeDefinition(E, restrict(INTEGER, maxInclusive(literal(2)))); + kb.addDatatypeDefinition(D, restrict(E, minInclusive(literal(1)))); + kb.addEquivalentClass(C, some(p, D)); + kb.addPropertyValue(p, a, literal(2)); + kb.addPropertyValue(p, b, literal(3)); + + assertTrue(kb.isType(a, C)); + assertFalse(kb.isType(b, C)); + } + + @Test(expected = RuntimeException.class) + public void invalidRestriction() { + classes(C); + dataProperties(p); + individuals(a, b); + + kb.addDatatypeDefinition(E, oneOf(literal(1), literal(2), literal(3))); + kb.addDatatypeDefinition(D, restrict(E, minInclusive(literal(1)))); + kb.addEquivalentClass(C, some(p, D)); + kb.addPropertyValue(p, a, literal(2)); + kb.addPropertyValue(p, b, literal(3)); + + assertTrue(kb.isType(a, C)); + assertFalse(kb.isType(b, C)); + } + + @Test + public void invalidLiteralBuiltInDatatype() { + dataProperties(p); + individuals(a); + + kb.addRange(p, INTEGER); + kb.addPropertyValue(p, a, literal("-1", POSITIVE_INTEGER)); + + assertFalse(kb.isConsistent()); + } + + @Test + public void invalidLiteralRestrictedDatatype() { + dataProperties(p); + individuals(a); + + ATermAppl uri = term("http//example.com/datatype"); + + kb.addRange(p, INTEGER); + kb.addDatatypeDefinition(uri, restrict(INTEGER, minExclusive(literal(0)))); + kb.addPropertyValue(p, a, literal("-1", uri)); + + assertFalse(kb.isConsistent()); + } + + @Test + public void validLiteralRestrictedDatatype() { + dataProperties(p); + individuals(a); + + ATermAppl uri = term("http//example.com/datatype"); + + kb.addRange(p, INTEGER); + kb.addDatatypeDefinition(uri, restrict(INTEGER, minExclusive(literal(0)))); + kb.addPropertyValue(p, a, literal("1", uri)); + + assertTrue(kb.isConsistent()); + } + + @Test + public void validLiteralStringRestriction1() { + dataProperties(p); + individuals(a); + + ATermAppl uri = term("http//example.com/datatype"); + + kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); + kb.addRange(p, uri); + kb.addPropertyValue(p, a, literal("a")); + + assertTrue(kb.isConsistent()); + } + + @Test + public void invalidLiteralStringRestriction() { + assumeTrue(PelletOptions.INVALID_LITERAL_AS_INCONSISTENCY); + + dataProperties(p); + individuals(a); + + ATermAppl uri = term("http//example.com/datatype"); + + kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); + kb.addRange(p, uri); + kb.addPropertyValue(p, a, literal("a", uri)); + + assertFalse(kb.isConsistent()); + } + + @Test + public void validLiteralStringRestriction2() { + dataProperties(p); + individuals(a, b, c); + + ATermAppl uri = term("http//example.com/datatype"); + + kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); + kb.addRange(p, uri); + kb.addPropertyValue(p, a, literal("c")); + kb.addAllDifferent(list(a, b, c)); + + assertFalse(kb.isConsistent()); + } + + @Test + public void testEmptyLangRangeRestriction() { + classes(C); + dataProperties(p); + individuals(a, b); + kb.addDatatypeDefinition(D, restrict(PLAIN_LITERAL, ATermUtils.makeFacetRestriction(Facet.RDF.LANG_RANGE.getName(), literal("")))); + kb.addEquivalentClass(C, some(p, D)); + kb.addPropertyValue(p, a, literal("no lang tag")); + kb.addPropertyValue(p, b, literal("english string", "en")); + + assertTrue(kb.isType(a, C)); + assertFalse(kb.isType(b, C)); + + + } + + @Test + public void testAnyLangRangeRestriction() { + classes(C); + dataProperties(p); + individuals(a, b); + kb.addDatatypeDefinition(E, restrict(PLAIN_LITERAL, ATermUtils.makeFacetRestriction(Facet.RDF.LANG_RANGE.getName(), literal("*")))); + kb.addEquivalentClass(C, some(p, E)); + kb.addPropertyValue(p, a, literal("no lang tag")); + kb.addPropertyValue(p, b, literal("english string", "en")); + + assertTrue(kb.isType(b, C)); + assertFalse(kb.isType(a, C)); + + + } + + @Test + public void testEnglishLangRangeRestriction() { + classes(C); + dataProperties(p); + individuals(a, b, c); + kb.addDatatypeDefinition(D, restrict(PLAIN_LITERAL, ATermUtils.makeFacetRestriction(Facet.RDF.LANG_RANGE.getName(), literal("en")))); + kb.addEquivalentClass(C, some(p, D)); + kb.addPropertyValue(p, a, literal("no lang tag")); + kb.addPropertyValue(p, b, literal("english string", "en")); + kb.addPropertyValue(p, c, literal("american english string", "en-US")); + + assertFalse(kb.isType(a, C)); + assertTrue(kb.isType(b, C)); + assertTrue(kb.isType(c, C)); - @Test - public void invalidLiteralStringRestriction() { - assumeTrue(PelletOptions.INVALID_LITERAL_AS_INCONSISTENCY); - - dataProperties(p); - individuals(a); - - ATermAppl uri = term("http//example.com/datatype"); - kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); - kb.addRange(p, uri); - kb.addPropertyValue(p, a, literal("a", uri)); + } - assertFalse(kb.isConsistent()); - } + @Test + public void testUSEnglishLangRangeRestriction() { + classes(C); + dataProperties(p); + individuals(a, b, c); + kb.addDatatypeDefinition(D, restrict(PLAIN_LITERAL, ATermUtils.makeFacetRestriction(Facet.RDF.LANG_RANGE.getName(), literal("en")))); + ATermAppl literal = literal("en-US"); + kb.addDatatypeDefinition(E, restrict(D, ATermUtils.makeFacetRestriction(Facet.RDF.LANG_RANGE.getName(), literal))); + kb.addEquivalentClass(C, some(p, E)); + kb.addPropertyValue(p, a, literal("no lang tag")); + kb.addPropertyValue(p, b, literal("english string", "en")); + kb.addPropertyValue(p, c, literal("american english string", "en-US")); - @Test - public void validLiteralStringRestriction2() { - dataProperties(p); - individuals(a, b, c); + assertFalse(kb.isType(a, C)); + assertFalse(kb.isType(b, C)); + assertTrue(kb.isType(c, C)); - ATermAppl uri = term("http//example.com/datatype"); - kb.addDatatypeDefinition(uri, oneOf(literal("a"), literal("b"))); - kb.addRange(p, uri); - kb.addPropertyValue(p, a, literal("c")); - kb.addAllDifferent(list(a, b, c)); + } - assertFalse(kb.isConsistent()); - } } From 31868c7f70a33a7c485da7f19870e6dcb0842128 Mon Sep 17 00:00:00 2001 From: Simon Spero Date: Wed, 30 Apr 2014 20:26:35 -0400 Subject: [PATCH 3/5] Add caching for data ranges. Adds dependency on google guava --- core/pom.xml | 5 + .../datatypes/DatatypeReasonerImpl.java | 1904 ++++++++--------- 2 files changed, 953 insertions(+), 956 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 2b79e7383..74c171af5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,6 +18,11 @@ org.jgrapht jgrapht-jdk1.5 + + com.google.guava + guava + 16.0.1 + xerces xercesImpl diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java index c4f9fc9d3..f98538ce4 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java @@ -1,27 +1,7 @@ package com.clarkparsia.pellet.datatypes; -import static java.lang.String.format; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.mindswap.pellet.Literal; -import org.mindswap.pellet.PelletOptions; -import org.mindswap.pellet.utils.ATermUtils; - import aterm.ATermAppl; import aterm.ATermList; - import com.clarkparsia.pellet.datatypes.exceptions.InvalidConstrainingFacetException; import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException; import com.clarkparsia.pellet.datatypes.exceptions.UnrecognizedDatatypeException; @@ -38,22 +18,10 @@ import com.clarkparsia.pellet.datatypes.types.duration.XSDDuration; import com.clarkparsia.pellet.datatypes.types.floating.XSDDouble; import com.clarkparsia.pellet.datatypes.types.floating.XSDFloat; -import com.clarkparsia.pellet.datatypes.types.real.OWLRational; -import com.clarkparsia.pellet.datatypes.types.real.OWLReal; -import com.clarkparsia.pellet.datatypes.types.real.XSDByte; +import com.clarkparsia.pellet.datatypes.types.real.*; import com.clarkparsia.pellet.datatypes.types.real.XSDDecimal; -import com.clarkparsia.pellet.datatypes.types.real.XSDInt; import com.clarkparsia.pellet.datatypes.types.real.XSDInteger; import com.clarkparsia.pellet.datatypes.types.real.XSDLong; -import com.clarkparsia.pellet.datatypes.types.real.XSDNegativeInteger; -import com.clarkparsia.pellet.datatypes.types.real.XSDNonNegativeInteger; -import com.clarkparsia.pellet.datatypes.types.real.XSDNonPositiveInteger; -import com.clarkparsia.pellet.datatypes.types.real.XSDPositiveInteger; -import com.clarkparsia.pellet.datatypes.types.real.XSDShort; -import com.clarkparsia.pellet.datatypes.types.real.XSDUnsignedByte; -import com.clarkparsia.pellet.datatypes.types.real.XSDUnsignedInt; -import com.clarkparsia.pellet.datatypes.types.real.XSDUnsignedLong; -import com.clarkparsia.pellet.datatypes.types.real.XSDUnsignedShort; import com.clarkparsia.pellet.datatypes.types.text.RDFPlainLiteral; import com.clarkparsia.pellet.datatypes.types.text.XSDLanguage; import com.clarkparsia.pellet.datatypes.types.text.XSDNCName; @@ -63,6 +31,20 @@ import com.clarkparsia.pellet.datatypes.types.text.XSDString; import com.clarkparsia.pellet.datatypes.types.text.XSDToken; import com.clarkparsia.pellet.datatypes.types.uri.XSDAnyURI; +import com.google.common.base.Optional; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import org.mindswap.pellet.Literal; +import org.mindswap.pellet.PelletOptions; +import org.mindswap.pellet.utils.ATermUtils; + +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static java.lang.String.format; /** *

@@ -77,769 +59,789 @@ *

* Company: Clark & Parsia, LLC. *

- * + * * @author Mike Smith */ public class DatatypeReasonerImpl implements DatatypeReasoner { - private static final Map> coreDatatypes; - private static final DataRange EMPTY_RANGE; - private static final Logger log; - private static final DataRange TRIVIALLY_SATISFIABLE; - - static { - log = Logger.getLogger(DatatypeReasonerImpl.class.getCanonicalName()); - - coreDatatypes = new HashMap>(); - - { - coreDatatypes.put(RDFPlainLiteral.getInstance().getName(), RDFPlainLiteral.getInstance()); - coreDatatypes.put(XSDString.getInstance().getName(), XSDString.getInstance()); - coreDatatypes.put(XSDNormalizedString.getInstance().getName(), XSDNormalizedString.getInstance()); - coreDatatypes.put(XSDToken.getInstance().getName(), XSDToken.getInstance()); - coreDatatypes.put(XSDLanguage.getInstance().getName(), XSDLanguage.getInstance()); - coreDatatypes.put(XSDNMToken.getInstance().getName(), XSDNMToken.getInstance()); - coreDatatypes.put(XSDName.getInstance().getName(), XSDName.getInstance()); - coreDatatypes.put(XSDNCName.getInstance().getName(), XSDNCName.getInstance()); - } - - coreDatatypes.put(XSDBoolean.getInstance().getName(), XSDBoolean.getInstance()); - - { - coreDatatypes.put(OWLReal.getInstance().getName(), OWLReal.getInstance()); - coreDatatypes.put(OWLRational.getInstance().getName(), OWLRational.getInstance()); - coreDatatypes.put(XSDDecimal.getInstance().getName(), XSDDecimal.getInstance()); - coreDatatypes.put(XSDInteger.getInstance().getName(), XSDInteger.getInstance()); - coreDatatypes.put(XSDLong.getInstance().getName(), XSDLong.getInstance()); - coreDatatypes.put(XSDInt.getInstance().getName(), XSDInt.getInstance()); - coreDatatypes.put(XSDShort.getInstance().getName(), XSDShort.getInstance()); - coreDatatypes.put(XSDByte.getInstance().getName(), XSDByte.getInstance()); - coreDatatypes.put(XSDNonNegativeInteger.getInstance().getName(), XSDNonNegativeInteger.getInstance()); - coreDatatypes.put(XSDNonPositiveInteger.getInstance().getName(), XSDNonPositiveInteger.getInstance()); - coreDatatypes.put(XSDNegativeInteger.getInstance().getName(), XSDNegativeInteger.getInstance()); - coreDatatypes.put(XSDPositiveInteger.getInstance().getName(), XSDPositiveInteger.getInstance()); - coreDatatypes.put(XSDUnsignedLong.getInstance().getName(), XSDUnsignedLong.getInstance()); - coreDatatypes.put(XSDUnsignedInt.getInstance().getName(), XSDUnsignedInt.getInstance()); - coreDatatypes.put(XSDUnsignedShort.getInstance().getName(), XSDUnsignedShort.getInstance()); - coreDatatypes.put(XSDUnsignedByte.getInstance().getName(), XSDUnsignedByte.getInstance()); - } - - coreDatatypes.put(XSDDouble.getInstance().getName(), XSDDouble.getInstance()); - - coreDatatypes.put(XSDFloat.getInstance().getName(), XSDFloat.getInstance()); - - { - coreDatatypes.put(XSDDateTime.getInstance().getName(), XSDDateTime.getInstance()); - coreDatatypes.put(XSDDateTimeStamp.getInstance().getName(), XSDDateTimeStamp.getInstance()); - } - { - coreDatatypes.put(XSDDate.getInstance().getName(), XSDDate.getInstance()); - coreDatatypes.put(XSDGYearMonth.getInstance().getName(), XSDGYearMonth.getInstance()); - coreDatatypes.put(XSDGMonthDay.getInstance().getName(), XSDGMonthDay.getInstance()); - coreDatatypes.put(XSDGYear.getInstance().getName(), XSDGYear.getInstance()); - coreDatatypes.put(XSDGMonth.getInstance().getName(), XSDGMonth.getInstance()); - coreDatatypes.put(XSDGDay.getInstance().getName(), XSDGDay.getInstance()); - coreDatatypes.put(XSDTime.getInstance().getName(), XSDTime.getInstance()); - } - - coreDatatypes.put(XSDDuration.getInstance().getName(), XSDDuration.getInstance()); - - coreDatatypes.put(XSDAnyURI.getInstance().getName(), XSDAnyURI.getInstance()); - } - - static { - EMPTY_RANGE = new EmptyDataRange(); - - TRIVIALLY_SATISFIABLE = new DataRange() { - - public boolean contains(Object value) { - return true; - } - - public boolean containsAtLeast(int n) { - return true; - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - - public Object getValue(int i) { - throw new UnsupportedOperationException(); - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - public boolean isEmpty() { - return false; - } - - public boolean isEnumerable() { - return false; - } - - public boolean isFinite() { - return false; - } - - public int size() { - throw new UnsupportedOperationException(); - } - - public Iterator valueIterator() { - throw new UnsupportedOperationException(); - } - - }; - } - - private static DataValueEnumeration findSmallestEnumeration( - Collection> ranges) { - DataValueEnumeration ret = null; - int best = Integer.MAX_VALUE; - for (DataValueEnumeration r : ranges) { - final DataValueEnumeration e = r; - final int s = e.size(); - if (s < best) { - ret = e; - best = s; - } - } - return ret; - } - - private static final ATermAppl getDatatypeName(ATermAppl literal) { - if (!ATermUtils.isLiteral(literal)) { - final String msg = "Method expected an ATermAppl literal as an argument"; - log.severe(msg); - throw new IllegalArgumentException(msg); - } - - final ATermAppl dtName = (ATermAppl) literal.getArgument(ATermUtils.LIT_URI_INDEX); - if (ATermUtils.EMPTY.equals(dtName)) { - final String msg = "Untyped literals not supported by this datatype reasoner"; - log.severe(msg); - throw new IllegalArgumentException(msg); - } - - return dtName; - } - - private static int inequalityCount(Set[] nes, int xIndex) { - - final Set others = nes[xIndex]; - return others == null ? 0 : others.size(); - } - - private static void partitionDConjunction(Collection> dconjunction, - Set> positiveEnumerations, - Set> negativeEnumerations, - Set> positiveRestrictions, - Set> negativeRestrictions) { - for (DataRange dr : dconjunction) { - if (dr instanceof DataValueEnumeration) { - positiveEnumerations.add((DataValueEnumeration) dr); - } - else if (dr instanceof RestrictedDatatype) { - positiveRestrictions.add((RestrictedDatatype) dr); - } - else if (dr instanceof NegatedDataRange) { - DataRange ndr = ((NegatedDataRange) dr).getDataRange(); - if (ndr instanceof DataValueEnumeration) { - negativeEnumerations.add((DataValueEnumeration) ndr); - } - else if (ndr instanceof RestrictedDatatype) { - negativeRestrictions.add((RestrictedDatatype) ndr); - } - else if (dr != TRIVIALLY_SATISFIABLE) { - log.warning("Unknown datatype: " + dr); - } - } - else if (dr != TRIVIALLY_SATISFIABLE) { - log.warning("Unknown datatype: " + dr); - } - } - } - - private static boolean removeInequalities(Set[] nes, int xIndex) { - - final Set others = nes[xIndex]; - - if (others == null) { - return false; + private static final Map> coreDatatypes; + private static final DataRange EMPTY_RANGE; + private static final Logger log; + private static final DataRange TRIVIALLY_SATISFIABLE; + + static { + log = Logger.getLogger(DatatypeReasonerImpl.class.getCanonicalName()); + + coreDatatypes = new HashMap>(); + + { + coreDatatypes.put(RDFPlainLiteral.getInstance().getName(), RDFPlainLiteral.getInstance()); + coreDatatypes.put(XSDString.getInstance().getName(), XSDString.getInstance()); + coreDatatypes.put(XSDNormalizedString.getInstance().getName(), XSDNormalizedString.getInstance()); + coreDatatypes.put(XSDToken.getInstance().getName(), XSDToken.getInstance()); + coreDatatypes.put(XSDLanguage.getInstance().getName(), XSDLanguage.getInstance()); + coreDatatypes.put(XSDNMToken.getInstance().getName(), XSDNMToken.getInstance()); + coreDatatypes.put(XSDName.getInstance().getName(), XSDName.getInstance()); + coreDatatypes.put(XSDNCName.getInstance().getName(), XSDNCName.getInstance()); + } + + coreDatatypes.put(XSDBoolean.getInstance().getName(), XSDBoolean.getInstance()); + + { + coreDatatypes.put(OWLReal.getInstance().getName(), OWLReal.getInstance()); + coreDatatypes.put(OWLRational.getInstance().getName(), OWLRational.getInstance()); + coreDatatypes.put(XSDDecimal.getInstance().getName(), XSDDecimal.getInstance()); + coreDatatypes.put(XSDInteger.getInstance().getName(), XSDInteger.getInstance()); + coreDatatypes.put(XSDLong.getInstance().getName(), XSDLong.getInstance()); + coreDatatypes.put(XSDInt.getInstance().getName(), XSDInt.getInstance()); + coreDatatypes.put(XSDShort.getInstance().getName(), XSDShort.getInstance()); + coreDatatypes.put(XSDByte.getInstance().getName(), XSDByte.getInstance()); + coreDatatypes.put(XSDNonNegativeInteger.getInstance().getName(), XSDNonNegativeInteger.getInstance()); + coreDatatypes.put(XSDNonPositiveInteger.getInstance().getName(), XSDNonPositiveInteger.getInstance()); + coreDatatypes.put(XSDNegativeInteger.getInstance().getName(), XSDNegativeInteger.getInstance()); + coreDatatypes.put(XSDPositiveInteger.getInstance().getName(), XSDPositiveInteger.getInstance()); + coreDatatypes.put(XSDUnsignedLong.getInstance().getName(), XSDUnsignedLong.getInstance()); + coreDatatypes.put(XSDUnsignedInt.getInstance().getName(), XSDUnsignedInt.getInstance()); + coreDatatypes.put(XSDUnsignedShort.getInstance().getName(), XSDUnsignedShort.getInstance()); + coreDatatypes.put(XSDUnsignedByte.getInstance().getName(), XSDUnsignedByte.getInstance()); + } + + coreDatatypes.put(XSDDouble.getInstance().getName(), XSDDouble.getInstance()); + + coreDatatypes.put(XSDFloat.getInstance().getName(), XSDFloat.getInstance()); + + { + coreDatatypes.put(XSDDateTime.getInstance().getName(), XSDDateTime.getInstance()); + coreDatatypes.put(XSDDateTimeStamp.getInstance().getName(), XSDDateTimeStamp.getInstance()); + } + { + coreDatatypes.put(XSDDate.getInstance().getName(), XSDDate.getInstance()); + coreDatatypes.put(XSDGYearMonth.getInstance().getName(), XSDGYearMonth.getInstance()); + coreDatatypes.put(XSDGMonthDay.getInstance().getName(), XSDGMonthDay.getInstance()); + coreDatatypes.put(XSDGYear.getInstance().getName(), XSDGYear.getInstance()); + coreDatatypes.put(XSDGMonth.getInstance().getName(), XSDGMonth.getInstance()); + coreDatatypes.put(XSDGDay.getInstance().getName(), XSDGDay.getInstance()); + coreDatatypes.put(XSDTime.getInstance().getName(), XSDTime.getInstance()); } - else { - for (Integer yIndex : others) { - Set s = nes[yIndex]; - if (s == null) { - throw new IllegalStateException(); + + coreDatatypes.put(XSDDuration.getInstance().getName(), XSDDuration.getInstance()); + + coreDatatypes.put(XSDAnyURI.getInstance().getName(), XSDAnyURI.getInstance()); + } + + static { + EMPTY_RANGE = new EmptyDataRange(); + + TRIVIALLY_SATISFIABLE = new DataRange() { + + public boolean contains(Object value) { + return true; + } + + public boolean containsAtLeast(int n) { + return true; + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + public Object getValue(int i) { + throw new UnsupportedOperationException(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + public boolean isEmpty() { + return false; + } + + public boolean isEnumerable() { + return false; + } + + public boolean isFinite() { + return false; + } + + public int size() { + throw new UnsupportedOperationException(); + } + + public Iterator valueIterator() { + throw new UnsupportedOperationException(); + } + + }; + } + + private static DataValueEnumeration findSmallestEnumeration( + Collection> ranges) { + DataValueEnumeration ret = null; + int best = Integer.MAX_VALUE; + for (DataValueEnumeration r : ranges) { + final DataValueEnumeration e = r; + final int s = e.size(); + if (s < best) { + ret = e; + best = s; + } + } + return ret; + } + + private static final ATermAppl getDatatypeName(ATermAppl literal) { + if (!ATermUtils.isLiteral(literal)) { + final String msg = "Method expected an ATermAppl literal as an argument"; + log.severe(msg); + throw new IllegalArgumentException(msg); + } + + final ATermAppl dtName = (ATermAppl) literal.getArgument(ATermUtils.LIT_URI_INDEX); + if (ATermUtils.EMPTY.equals(dtName)) { + final String msg = "Untyped literals not supported by this datatype reasoner"; + log.severe(msg); + throw new IllegalArgumentException(msg); + } + + return dtName; + } + + private static int inequalityCount(Set[] nes, int xIndex) { + + final Set others = nes[xIndex]; + return others == null ? 0 : others.size(); + } + + private static void partitionDConjunction(Collection> dconjunction, + Set> positiveEnumerations, + Set> negativeEnumerations, + Set> positiveRestrictions, + Set> negativeRestrictions) { + for (DataRange dr : dconjunction) { + if (dr instanceof DataValueEnumeration) { + positiveEnumerations.add((DataValueEnumeration) dr); + } else if (dr instanceof RestrictedDatatype) { + positiveRestrictions.add((RestrictedDatatype) dr); + } else if (dr instanceof NegatedDataRange) { + DataRange ndr = ((NegatedDataRange) dr).getDataRange(); + if (ndr instanceof DataValueEnumeration) { + negativeEnumerations.add((DataValueEnumeration) ndr); + } else if (ndr instanceof RestrictedDatatype) { + negativeRestrictions.add((RestrictedDatatype) ndr); + } else if (dr != TRIVIALLY_SATISFIABLE) { + log.warning("Unknown datatype: " + dr); + } + } else if (dr != TRIVIALLY_SATISFIABLE) { + log.warning("Unknown datatype: " + dr); + } + } + } + + private static boolean removeInequalities(Set[] nes, int xIndex) { + + final Set others = nes[xIndex]; + + if (others == null) { + return false; + } else { + for (Integer yIndex : others) { + Set s = nes[yIndex]; + if (s == null) { + throw new IllegalStateException(); } - if (!s.remove(xIndex)) { - throw new IllegalStateException(); + if (!s.remove(xIndex)) { + throw new IllegalStateException(); } - } - return true; - } - } - - private final Set declaredUndefined; - private final NamedDataRangeExpander expander; - private final Map namedDataRanges; - - public DatatypeReasonerImpl() { - declaredUndefined = new HashSet(); - expander = new NamedDataRangeExpander(); - namedDataRanges = new HashMap(); - } - - private boolean containedIn(Object value, ATermAppl dconjunction) throws InvalidConstrainingFacetException, - InvalidLiteralException, UnrecognizedDatatypeException { - if (ATermUtils.isAnd(dconjunction)) { - for (ATermList l = (ATermList) dconjunction.getArgument(0); !l.isEmpty(); l = l.getNext()) { - if (!getDataRange((ATermAppl) l.getFirst()).contains(value)) { - return false; + } + return true; + } + } + + private final Set declaredUndefined; + private final NamedDataRangeExpander expander; + private final Map namedDataRanges; + + public DatatypeReasonerImpl() { + declaredUndefined = new HashSet(); + expander = new NamedDataRangeExpander(); + namedDataRanges = new HashMap(); + } + + private boolean containedIn(Object value, ATermAppl dconjunction) throws InvalidConstrainingFacetException, + InvalidLiteralException, UnrecognizedDatatypeException { + if (ATermUtils.isAnd(dconjunction)) { + for (ATermList l = (ATermList) dconjunction.getArgument(0); !l.isEmpty(); l = l.getNext()) { + if (!getDataRange((ATermAppl) l.getFirst()).contains(value)) { + return false; } - } - return true; - } - else { - return getDataRange(dconjunction).contains(value); + } + return true; + } else { + return getDataRange(dconjunction).contains(value); } - } - - public boolean containsAtLeast(int n, Collection ranges) throws UnrecognizedDatatypeException, - InvalidConstrainingFacetException, InvalidLiteralException { - - ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(ranges)); - ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); - if (ATermUtils.isOr(dnf)) { - List> disjuncts = new ArrayList>(); - for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { - final DataRange dr = normalizeVarRanges((ATermAppl) l.getFirst()); - if (!dr.isEmpty()) { - disjuncts.add(dr); + } + + public boolean containsAtLeast(int n, Collection ranges) throws UnrecognizedDatatypeException, + InvalidConstrainingFacetException, InvalidLiteralException { + + ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(ranges)); + ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); + if (ATermUtils.isOr(dnf)) { + List> disjuncts = new ArrayList>(); + for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { + final DataRange dr = normalizeVarRanges((ATermAppl) l.getFirst()); + if (!dr.isEmpty()) { + disjuncts.add(dr); } - } + } - final DataRange disjunction = getDisjunction(disjuncts); - return disjunction.containsAtLeast(n); - } - else { - final DataRange dr = normalizeVarRanges(dnf); - return dr.containsAtLeast(n); - } + final DataRange disjunction = getDisjunction(disjuncts); + return disjunction.containsAtLeast(n); + } else { + final DataRange dr = normalizeVarRanges(dnf); + return dr.containsAtLeast(n); + } - } + } - public boolean declare(ATermAppl name) { - if (isDeclared(name)) { - return false; + public boolean declare(ATermAppl name) { + if (isDeclared(name)) { + return false; + } else { + declaredUndefined.add(name); + return true; } - else { - declaredUndefined.add(name); - return true; - } - } - - public ATermAppl getCanonicalRepresentation(ATermAppl literal) throws InvalidLiteralException, - UnrecognizedDatatypeException { - final ATermAppl dtName = getDatatypeName(literal); - final Datatype dt = getDatatype(dtName); - if (dt == null) { - switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { - case INFINITE_STRING: - return literal; - case EMPTY: - throw new InvalidLiteralException(dtName, ATermUtils.getLiteralValue(literal)); - case EXCEPTION: - throw new UnrecognizedDatatypeException(dtName); - default: - throw new IllegalStateException(); - } - } - else { - return dt.getCanonicalRepresentation(literal); + } + + public ATermAppl getCanonicalRepresentation(ATermAppl literal) throws InvalidLiteralException, + UnrecognizedDatatypeException { + final ATermAppl dtName = getDatatypeName(literal); + final Datatype dt = getDatatype(dtName); + if (dt == null) { + switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { + case INFINITE_STRING: + return literal; + case EMPTY: + throw new InvalidLiteralException(dtName, ATermUtils.getLiteralValue(literal)); + case EXCEPTION: + throw new UnrecognizedDatatypeException(dtName); + default: + throw new IllegalStateException(); + } + } else { + return dt.getCanonicalRepresentation(literal); } - } + } + + LoadingCache> dataRangeCache = + CacheBuilder.newBuilder().maximumSize(10000).softValues().build( + new CacheLoader>() { + @Override + public Optional load(ATermAppl key) throws Exception { + DataRange range = computeDataRange(key); + return Optional.fromNullable(range); + } + } + ); - private DataRange getDataRange(ATermAppl a) throws InvalidConstrainingFacetException, InvalidLiteralException, - UnrecognizedDatatypeException { - // TODO: Investigate the impact of keeping a results cache here + private DataRange getDataRange(ATermAppl a) throws InvalidConstrainingFacetException, InvalidLiteralException, + UnrecognizedDatatypeException { + // TODO: Investigate the impact of keeping a results cache here - /* - * rdfs:Literal - */ - if (a.equals(ATermUtils.TOP_LIT)) { - return TRIVIALLY_SATISFIABLE; + + if (true) { + Optional result; + + try { + result = dataRangeCache.get(a); + if (result.isPresent()) { + return result.get(); + } + } catch (ExecutionException e) { + } } + DataRange dr = computeDataRange(a); - /* - * Negation of rdfs:Literal - */ - if (a.equals(ATermUtils.BOTTOM_LIT)) { - return EMPTY_RANGE; + if (true) + dataRangeCache.put(a, Optional.fromNullable(dr)); + if (dr != null) { + return dr; } - /* - * Named datatype - */ - if (ATermUtils.isPrimitive(a)) { - Datatype dt = getDatatype(a); - if (dt == null) { - switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { - case INFINITE_STRING: - dt = InfiniteNamedDatatype.get(a); - break; - case EMPTY: - return EMPTY_RANGE; - case EXCEPTION: - throw new UnrecognizedDatatypeException(a); - default: - throw new IllegalStateException(); - } - } - return dt.asDataRange(); - } - /* - * Datatype restriction - */ - if (ATermUtils.isRestrictedDatatype(a)) { + final String msg = format("Unrecognized input term (%s) for datarange conversion", a); + log.severe(msg); + throw new IllegalArgumentException(msg); - /* - * Start with the full data range for the datatype - */ - final ATermAppl dtTerm = (ATermAppl) a.getArgument(0); - final DataRange dt = getDataRange(dtTerm); - if (!(dt instanceof RestrictedDatatype)) { - throw new InvalidConstrainingFacetException(dtTerm, dt); - } + } + + private DataRange computeDataRange(ATermAppl a) throws UnrecognizedDatatypeException, InvalidConstrainingFacetException, InvalidLiteralException { + DataRange result = null; + if (a.equals(ATermUtils.TOP_LIT)) { + /* rdfs:Literal */ - RestrictedDatatype dr = (RestrictedDatatype) dt; + result = TRIVIALLY_SATISFIABLE; + } else if (a.equals(ATermUtils.BOTTOM_LIT)) { + // Negation of rdfs:Literal + result = EMPTY_RANGE; + } else if (ATermUtils.isPrimitive(a)) { + result = computePrimitiveRange(a); + } else if (ATermUtils.isRestrictedDatatype(a)) { + result = computeRestrictedRange(a); + + + } else if (ATermUtils.isNot(a)) { + result = computeNegatedRange(a); + } else if (ATermUtils.isNominal(a)) { + result = computeEnumeratedRange(a); + + } + return result; + } + + private DataRange computePrimitiveRange(ATermAppl a) throws UnrecognizedDatatypeException { + DataRange result; + Datatype dt = getDatatype(a); + if (dt == null) { + switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { + case INFINITE_STRING: + dt = InfiniteNamedDatatype.get(a); + break; + case EMPTY: + result = EMPTY_RANGE; + break; + case EXCEPTION: + throw new UnrecognizedDatatypeException(a); + default: + throw new IllegalStateException(); + } + } + result = dt.asDataRange(); + return result; + } + + private DataRange computeEnumeratedRange(ATermAppl a) throws InvalidLiteralException, UnrecognizedDatatypeException { + DataRange result;/* + * TODO: Consider if work before this point to group enumerations (i.e., treat them differently than + * disjunctions of singleton enumerations) is worthwhile. + */ + /* + * Data value enumeration + */ + final ATermAppl literal = (ATermAppl) a.getArgument(0); + final DataRange dr = new DataValueEnumeration(Collections.singleton(getValue(literal))); + result = dr; + return result; + } + + private DataRange computeNegatedRange(ATermAppl a) throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { + DataRange result; + final ATermAppl n = (ATermAppl) a.getArgument(0); + final DataRange ndr = getDataRange(n); + final DataRange dr = new NegatedDataRange(ndr); + + result = dr; + return result; + } + + private DataRange computeRestrictedRange(ATermAppl a) throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { + DataRange result;/* + * Start with the full data range for the datatype + */ + final ATermAppl dtTerm = (ATermAppl) a.getArgument(0); + final DataRange dt = getDataRange(dtTerm); + if (!(dt instanceof RestrictedDatatype)) { + throw new InvalidConstrainingFacetException(dtTerm, dt); + } + + RestrictedDatatype dr = (RestrictedDatatype) dt; /* - * Apply each constraining facet value pair in turn + * Apply each constraining facet value pair in turn */ - final ATermList facetValues = (ATermList) a.getArgument(1); - for (ATermList l = facetValues; !l.isEmpty(); l = l.getNext()) { - final ATermAppl fv = (ATermAppl) l.getFirst(); - final ATermAppl facet = (ATermAppl) fv.getArgument(0); - final ATermAppl valueTerm = (ATermAppl) fv.getArgument(1); - - Object value; - try { - value = getValue(valueTerm); - } - catch (InvalidLiteralException e) { - throw new InvalidConstrainingFacetException(facet, valueTerm, e); - } - dr = dr.applyConstrainingFacet(facet, value); - } - - return dr; - } + final ATermList facetValues = (ATermList) a.getArgument(1); + for (ATermList l = facetValues; !l.isEmpty(); l = l.getNext()) { + final ATermAppl fv = (ATermAppl) l.getFirst(); + final ATermAppl facet = (ATermAppl) fv.getArgument(0); + final ATermAppl valueTerm = (ATermAppl) fv.getArgument(1); + + Object value; + try { + value = getValue(valueTerm); + } catch (InvalidLiteralException e) { + throw new InvalidConstrainingFacetException(facet, valueTerm, e); + } + dr = dr.applyConstrainingFacet(facet, value); + } - /* - * Negated datarange - */ - if (ATermUtils.isNot(a)) { - final ATermAppl n = (ATermAppl) a.getArgument(0); - final DataRange ndr = getDataRange(n); - final DataRange dr = new NegatedDataRange(ndr); + result = dr; + return result; + } + + public Datatype getDatatype(ATermAppl uri) { + try { + Datatype dt = coreDatatypes.get(uri); + if (dt == null) { + ATermAppl definition = namedDataRanges.get(uri); + if (definition != null) { + if (ATermUtils.isRestrictedDatatype(definition)) { + RestrictedDatatype dataRange = (RestrictedDatatype) getDataRange(definition); + @SuppressWarnings("unchecked") + NamedDatatype namedDatatype = new NamedDatatype(uri, dataRange); + dt = namedDatatype; + } + } + } - return dr; - } + return dt; + } catch (Exception e) { + throw new RuntimeException(e); + } + } - /* - * TODO: Consider if work before this point to group enumerations (i.e., treat them differently than - * disjunctions of singleton enumerations) is worthwhile. - */ - /* - * Data value enumeration - */ - if (ATermUtils.isNominal(a)) { - final ATermAppl literal = (ATermAppl) a.getArgument(0); - final DataRange dr = new DataValueEnumeration(Collections.singleton(getValue(literal))); - return dr; - } - - final String msg = format("Unrecognized input term (%s) for datarange conversion", a); - log.severe(msg); - throw new IllegalArgumentException(msg); - } - - public Datatype getDatatype(ATermAppl uri) { - try { - Datatype dt = coreDatatypes.get(uri); - if (dt == null) { - ATermAppl definition = namedDataRanges.get(uri); - if (definition != null) { - if (ATermUtils.isRestrictedDatatype(definition)) { - RestrictedDatatype dataRange = (RestrictedDatatype) getDataRange(definition); - @SuppressWarnings("unchecked") - NamedDatatype namedDatatype = new NamedDatatype(uri, dataRange); - dt = namedDatatype; - } - } - } - - return dt; - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - - private DataRange getDisjunction(Collection> ranges) { - - if (ranges.size() == 1) { - return ranges.iterator().next(); + private DataRange getDisjunction(Collection> ranges) { + + if (ranges.size() == 1) { + return ranges.iterator().next(); } - for (DataRange r : ranges) { - if (r == TRIVIALLY_SATISFIABLE) { - return r; + for (DataRange r : ranges) { + if (r == TRIVIALLY_SATISFIABLE) { + return r; } } - Set oneOf = Collections.emptySet(); - Map, Set>> byPrimitive = new HashMap, Set>>(); + Set oneOf = Collections.emptySet(); + Map, Set>> byPrimitive = new HashMap, Set>>(); /* - * Organize the input data ranges into restrictions partitioned by data and a merged value enumeration. + * Organize the input data ranges into restrictions partitioned by data and a merged value enumeration. */ - for (DataRange dr : ranges) { - if (dr instanceof RestrictedDatatype) { - final RestrictedDatatype rd = (RestrictedDatatype) dr; - final Datatype pd = rd.getDatatype().getPrimitiveDatatype(); - Set> others = byPrimitive.get(pd); - if (others == null) { - others = new HashSet>(); - byPrimitive.put(pd, others); - } - others.add(rd); - } - else if (dr instanceof DataValueEnumeration) { - final DataValueEnumeration enm = (DataValueEnumeration) dr; - if (oneOf.isEmpty()) { - oneOf = new HashSet(); + for (DataRange dr : ranges) { + if (dr instanceof RestrictedDatatype) { + final RestrictedDatatype rd = (RestrictedDatatype) dr; + final Datatype pd = rd.getDatatype().getPrimitiveDatatype(); + Set> others = byPrimitive.get(pd); + if (others == null) { + others = new HashSet>(); + byPrimitive.put(pd, others); } - for (Iterator it = enm.valueIterator(); it.hasNext();) { - oneOf.add(it.next()); + others.add(rd); + } else if (dr instanceof DataValueEnumeration) { + final DataValueEnumeration enm = (DataValueEnumeration) dr; + if (oneOf.isEmpty()) { + oneOf = new HashSet(); } - } - } + for (Iterator it = enm.valueIterator(); it.hasNext(); ) { + oneOf.add(it.next()); + } + } + } /* - * Merge data ranges that have the same primitive datatype + * Merge data ranges that have the same primitive datatype */ - Set> disjointRanges = new HashSet>(); - for (Set> s : byPrimitive.values()) { - Iterator> it = s.iterator(); - RestrictedDatatype merge = it.next(); - while (it.hasNext()) { - merge = merge.union(it.next()); + Set> disjointRanges = new HashSet>(); + for (Set> s : byPrimitive.values()) { + Iterator> it = s.iterator(); + RestrictedDatatype merge = it.next(); + while (it.hasNext()) { + merge = merge.union(it.next()); } - disjointRanges.add(merge); - } + disjointRanges.add(merge); + } /* - * Discard any enum elements that are included in other disjuncts + * Discard any enum elements that are included in other disjuncts */ - for (Iterator it = oneOf.iterator(); it.hasNext();) { - final Object o = it.next(); - for (RestrictedDatatype rd : disjointRanges) { - if (rd.contains(o)) { - it.remove(); + for (Iterator it = oneOf.iterator(); it.hasNext(); ) { + final Object o = it.next(); + for (RestrictedDatatype rd : disjointRanges) { + if (rd.contains(o)) { + it.remove(); + } + } + } + + return new UnionDataRange(disjointRanges, oneOf); + } + + public ATermAppl getLiteral(Object value) { + for (Datatype dt : coreDatatypes.values()) { + if (dt.isPrimitive()) { + if (dt.asDataRange().contains(value)) { + return dt.getLiteral(value); } - } - } - - return new UnionDataRange(disjointRanges, oneOf); - } - - public ATermAppl getLiteral(Object value) { - for (Datatype dt : coreDatatypes.values()) { - if (dt.isPrimitive()) { - if (dt.asDataRange().contains(value)) { - return dt.getLiteral(value); - } - } - } - - final String msg = "Value is not in the value space of any recognized datatypes: " + value.toString(); - log.severe(msg); - throw new IllegalArgumentException(msg); - } - - public Object getValue(ATermAppl literal) throws InvalidLiteralException, UnrecognizedDatatypeException { - final ATermAppl dtName = getDatatypeName(literal); - final Datatype dt = getDatatype(dtName); - if (dt == null) { - switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { - case INFINITE_STRING: - return literal; - case EMPTY: - throw new InvalidLiteralException(dtName, ATermUtils.getLiteralValue(literal)); - case EXCEPTION: - throw new UnrecognizedDatatypeException(dtName); - default: - throw new IllegalStateException(); - } - } - else { - return dt.getValue(literal); + } + } + + final String msg = "Value is not in the value space of any recognized datatypes: " + value.toString(); + log.severe(msg); + throw new IllegalArgumentException(msg); + } + + public Object getValue(ATermAppl literal) throws InvalidLiteralException, UnrecognizedDatatypeException { + final ATermAppl dtName = getDatatypeName(literal); + final Datatype dt = getDatatype(dtName); + if (dt == null) { + switch (PelletOptions.UNDEFINED_DATATYPE_HANDLING) { + case INFINITE_STRING: + return literal; + case EMPTY: + throw new InvalidLiteralException(dtName, ATermUtils.getLiteralValue(literal)); + case EXCEPTION: + throw new UnrecognizedDatatypeException(dtName); + default: + throw new IllegalStateException(); + } + } else { + return dt.getValue(literal); } - } + } - public boolean isDeclared(ATermAppl name) { - return ATermUtils.TOP_LIT.equals(name) || coreDatatypes.containsKey(name) || namedDataRanges.containsKey(name) - || declaredUndefined.contains(name); - } + public boolean isDeclared(ATermAppl name) { + return ATermUtils.TOP_LIT.equals(name) || coreDatatypes.containsKey(name) || namedDataRanges.containsKey(name) + || declaredUndefined.contains(name); + } - public boolean isDefined(ATermAppl name) { - if (ATermUtils.TOP_LIT.equals(name)) { - return true; + public boolean isDefined(ATermAppl name) { + if (ATermUtils.TOP_LIT.equals(name)) { + return true; } - if (coreDatatypes.containsKey(name)) { - return true; + if (coreDatatypes.containsKey(name)) { + return true; } - if (namedDataRanges.containsKey(name)) { - return true; + if (namedDataRanges.containsKey(name)) { + return true; } - return false; - } - - public ATermAppl getDefinition(ATermAppl name) { - return namedDataRanges.get( name ); - } + return false; + } + + public ATermAppl getDefinition(ATermAppl name) { + return namedDataRanges.get(name); + } - public boolean isSatisfiable(Collection dataranges) throws InvalidConstrainingFacetException, - InvalidLiteralException, UnrecognizedDatatypeException { - return isSatisfiable(dataranges, null); - } + public boolean isSatisfiable(Collection dataranges) throws InvalidConstrainingFacetException, + InvalidLiteralException, UnrecognizedDatatypeException { + return isSatisfiable(dataranges, null); + } - public boolean isSatisfiable(Collection dataranges, Object value) - throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { - Set consts, vars; + public boolean isSatisfiable(Collection dataranges, Object value) + throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { + Set consts, vars; - if (value == null) { + if (value == null) { /* * TODO: See if code in next method can be restructured to avoid this allocation. */ - consts = new HashSet(); - vars = new HashSet(Collections.singleton(0)); - } - else { - consts = Collections.singleton(0); - vars = Collections.emptySet(); - } - - ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(dataranges)); - ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); - Collection dnfDisjuncts; - if (ATermUtils.isOr(dnf)) { - List disjuncts = new ArrayList(); - for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { - disjuncts.add((ATermAppl) l.getFirst()); + consts = new HashSet(); + vars = new HashSet(Collections.singleton(0)); + } else { + consts = Collections.singleton(0); + vars = Collections.emptySet(); + } + + ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(dataranges)); + ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); + Collection dnfDisjuncts; + if (ATermUtils.isOr(dnf)) { + List disjuncts = new ArrayList(); + for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { + disjuncts.add((ATermAppl) l.getFirst()); } - dnfDisjuncts = disjuncts; - } - else { - dnfDisjuncts = Collections.singleton(dnf); + dnfDisjuncts = disjuncts; + } else { + dnfDisjuncts = Collections.singleton(dnf); } - @SuppressWarnings("unchecked") - final Collection[] dnfTypes = new Collection[] { dnfDisjuncts }; + @SuppressWarnings("unchecked") + final Collection[] dnfTypes = new Collection[]{dnfDisjuncts}; - @SuppressWarnings("unchecked") - final Set[] ne = new Set[] { Collections. emptySet() }; + @SuppressWarnings("unchecked") + final Set[] ne = new Set[]{Collections.emptySet()}; - return isSatisfiable(consts, vars, dnfTypes, new Object[] { value }, ne); - } + return isSatisfiable(consts, vars, dnfTypes, new Object[]{value}, ne); + } - private boolean isSatisfiable(Set consts, Set vars, Collection[] dnfTypes, - Object[] constValues, Set[] ne) throws InvalidConstrainingFacetException, - InvalidLiteralException, UnrecognizedDatatypeException { + private boolean isSatisfiable(Set consts, Set vars, Collection[] dnfTypes, + Object[] constValues, Set[] ne) throws InvalidConstrainingFacetException, + InvalidLiteralException, UnrecognizedDatatypeException { /* * TODO: Remove need for consts and vars sets by using null in constValues array */ - final int n = dnfTypes.length; + final int n = dnfTypes.length; /* * 1. Loop and eliminate any easy, obvious unsats */ - for (int i = 0; i < n; i++) { - final Collection drs = dnfTypes[i]; - for (Iterator it = drs.iterator(); it.hasNext();) { - ATermAppl dr = it.next(); - if (ATermUtils.BOTTOM_LIT.equals(dr)) { - it.remove(); + for (int i = 0; i < n; i++) { + final Collection drs = dnfTypes[i]; + for (Iterator it = drs.iterator(); it.hasNext(); ) { + ATermAppl dr = it.next(); + if (ATermUtils.BOTTOM_LIT.equals(dr)) { + it.remove(); } - } - if (drs.isEmpty()) { - return false; } - } + if (drs.isEmpty()) { + return false; + } + } /* * 2. Get normalized form of data ranges */ - DataRange[] normalized = new DataRange[n]; - for (int i = 0; i < n; i++) { - - if (consts.contains(i)) { - - boolean satisfied = false; - for (ATermAppl a : dnfTypes[i]) { - if (containedIn(constValues[i], a)) { - satisfied = true; - break; - } - } - if (satisfied) { - normalized[i] = TRIVIALLY_SATISFIABLE; + DataRange[] normalized = new DataRange[n]; + for (int i = 0; i < n; i++) { + + if (consts.contains(i)) { + + boolean satisfied = false; + for (ATermAppl a : dnfTypes[i]) { + if (containedIn(constValues[i], a)) { + satisfied = true; + break; + } } - else { - return false; + if (satisfied) { + normalized[i] = TRIVIALLY_SATISFIABLE; + } else { + return false; } - } - else { - - List> drs = new ArrayList>(); - for (ATermAppl a : dnfTypes[i]) { - DataRange dr = normalizeVarRanges(a); - if (dr == TRIVIALLY_SATISFIABLE) { - drs = Collections.> singletonList(TRIVIALLY_SATISFIABLE); - break; - } - else if (!dr.isEmpty()) { - drs.add(dr); - } - } - if (drs.isEmpty()) { - return false; + } else { + + List> drs = new ArrayList>(); + for (ATermAppl a : dnfTypes[i]) { + DataRange dr = normalizeVarRanges(a); + if (dr == TRIVIALLY_SATISFIABLE) { + drs = Collections.>singletonList(TRIVIALLY_SATISFIABLE); + break; + } else if (!dr.isEmpty()) { + drs.add(dr); + } } - else { - normalized[i] = getDisjunction(drs); + if (drs.isEmpty()) { + return false; + } else { + normalized[i] = getDisjunction(drs); } - } - } + } + } /* * Alg lines 7 - 22 (without the 12-13 or 19-20 blocks) */ - for (Iterator it = vars.iterator(); it.hasNext();) { - Integer i = it.next(); - final DataRange dr = normalized[i]; + for (Iterator it = vars.iterator(); it.hasNext(); ) { + Integer i = it.next(); + final DataRange dr = normalized[i]; /* * First half of condition 9 - 11 block */ - if (TRIVIALLY_SATISFIABLE == dr) { - it.remove(); - removeInequalities(ne, i); - continue; - } + if (TRIVIALLY_SATISFIABLE == dr) { + it.remove(); + removeInequalities(ne, i); + continue; + } /* * Line 15 */ - if (dr.isEmpty()) { - return false; + if (dr.isEmpty()) { + return false; } /* * Second half of condition 9 - 11 block */ - if (dr.containsAtLeast(inequalityCount(ne, i) + 1)) { - it.remove(); - removeInequalities(ne, i); - continue; - } + if (dr.containsAtLeast(inequalityCount(ne, i) + 1)) { + it.remove(); + removeInequalities(ne, i); + continue; + } /* * Data range is a singleton, replace variable with constant (lines 17 - 18) */ - if (dr.isFinite() && dr.isEnumerable() && !dr.containsAtLeast(2)) { - final Object c = dr.valueIterator().next(); - it.remove(); - consts.add(i); - constValues[i] = c; - normalized[i] = TRIVIALLY_SATISFIABLE; - continue; - } - } - - if (log.isLoggable(Level.FINEST)) { - log.finest(format("After variable data range normalization %d variables and %d constants", vars.size(), - consts.size())); - } + if (dr.isFinite() && dr.isEnumerable() && !dr.containsAtLeast(2)) { + final Object c = dr.valueIterator().next(); + it.remove(); + consts.add(i); + constValues[i] = c; + normalized[i] = TRIVIALLY_SATISFIABLE; + continue; + } + } + + if (log.isLoggable(Level.FINEST)) { + log.finest(format("After variable data range normalization %d variables and %d constants", vars.size(), + consts.size())); + } /* * Constant checks (alg lines 23 - 30) */ - for (Integer i : consts) { + for (Integer i : consts) { /* * Check that any constant,constant inequalities are satisfied */ - Set diffs = ne[i]; - if (diffs != null) { - for (Iterator it = diffs.iterator(); it.hasNext();) { - final int j = it.next(); - if (consts.contains(j)) { - - if (constValues[i].equals(constValues[j])) { - return false; + Set diffs = ne[i]; + if (diffs != null) { + for (Iterator it = diffs.iterator(); it.hasNext(); ) { + final int j = it.next(); + if (consts.contains(j)) { + + if (constValues[i].equals(constValues[j])) { + return false; } - it.remove(); - ne[j].remove(i); - } - } - } - } + it.remove(); + ne[j].remove(i); + } + } + } + } /* * Try to eliminate any more variables that can be removed */ - for (Iterator it = vars.iterator(); it.hasNext();) { - final int i = it.next(); - - final DataRange dr = normalized[i]; - - final Set diffs = ne[i]; - final int min = (diffs == null) ? 1 : diffs.size() + 1; - if (dr.containsAtLeast(min)) { - it.remove(); - for (int j : diffs) { - if (ne[j] != null) { - ne[j].remove(i); + for (Iterator it = vars.iterator(); it.hasNext(); ) { + final int i = it.next(); + + final DataRange dr = normalized[i]; + + final Set diffs = ne[i]; + final int min = (diffs == null) ? 1 : diffs.size() + 1; + if (dr.containsAtLeast(min)) { + it.remove(); + for (int j : diffs) { + if (ne[j] != null) { + ne[j].remove(i); } - } - ne[i] = null; - vars.remove(i); - } - } - - if (log.isLoggable(Level.FINEST)) { - log.finest(format("After size check on variable data ranges %d variables", vars.size())); - } - - if (vars.isEmpty()) { - return true; + } + ne[i] = null; + vars.remove(i); + } + } + + if (log.isLoggable(Level.FINEST)) { + log.finest(format("After size check on variable data ranges %d variables", vars.size())); + } + + if (vars.isEmpty()) { + return true; } /* @@ -849,377 +851,367 @@ else if (!dr.isEmpty()) { /* * Partition remaining variables into disjoint collections */ - Set remaining = new HashSet(vars); - List> partitions = new ArrayList>(); - while (!remaining.isEmpty()) { - Set p = new HashSet(); - Iterator it = remaining.iterator(); - int i = it.next(); - it.remove(); - p.add(i); - if (ne[i] != null) { - Set others = new HashSet(); - others.addAll(ne[i]); - while (!others.isEmpty()) { - Iterator jt = others.iterator(); - int j = jt.next(); - jt.remove(); - if (remaining.contains(j)) { - p.add(j); - remaining.remove(j); - if (ne[j] != null) { - others.addAll(ne[j]); + Set remaining = new HashSet(vars); + List> partitions = new ArrayList>(); + while (!remaining.isEmpty()) { + Set p = new HashSet(); + Iterator it = remaining.iterator(); + int i = it.next(); + it.remove(); + p.add(i); + if (ne[i] != null) { + Set others = new HashSet(); + others.addAll(ne[i]); + while (!others.isEmpty()) { + Iterator jt = others.iterator(); + int j = jt.next(); + jt.remove(); + if (remaining.contains(j)) { + p.add(j); + remaining.remove(j); + if (ne[j] != null) { + others.addAll(ne[j]); } - } - } + } + } - } - partitions.add(p); - } + } + partitions.add(p); + } - if (log.isLoggable(Level.FINEST)) { - log.finest(format("Enumerating to find solutions for %d partitions", partitions.size())); - } + if (log.isLoggable(Level.FINEST)) { + log.finest(format("Enumerating to find solutions for %d partitions", partitions.size())); + } /* * Enumerate until a solution is found */ - for (Set p : partitions) { - final int nPart = p.size(); - - int[] indices = new int[nPart]; - Map revInd = new HashMap(); - DataRange[] drs = new DataRange[nPart]; - - int i = 0; - for (int j : p) { - drs[i] = normalized[j]; - indices[i] = j; - revInd.put(j, i); - i++; - } - - Iterator[] its = new Iterator[nPart]; - for (i = 0; i < nPart; i++) { - its[i] = drs[i].valueIterator(); + for (Set p : partitions) { + final int nPart = p.size(); + + int[] indices = new int[nPart]; + Map revInd = new HashMap(); + DataRange[] drs = new DataRange[nPart]; + + int i = 0; + for (int j : p) { + drs[i] = normalized[j]; + indices[i] = j; + revInd.put(j, i); + i++; + } + + Iterator[] its = new Iterator[nPart]; + for (i = 0; i < nPart; i++) { + its[i] = drs[i].valueIterator(); } - Object[] values = new Object[nPart]; + Object[] values = new Object[nPart]; /* * Assign a value to each */ - for (i = 0; i < nPart; i++) { - values[i] = its[i].next(); + for (i = 0; i < nPart; i++) { + values[i] = its[i].next(); } - boolean solutionFound = false; - while (!solutionFound) { + boolean solutionFound = false; + while (!solutionFound) { /* * Check solution */ - solutionFound = true; - for (i = 0; i < nPart && solutionFound; i++) { - Set diffs = ne[indices[i]]; - if (diffs != null) { - final Object a = values[i]; - for (int j : diffs) { - - Object b; - if (p.contains(j)) { - b = values[revInd.get(j)]; - } - else { - b = constValues[j]; + solutionFound = true; + for (i = 0; i < nPart && solutionFound; i++) { + Set diffs = ne[indices[i]]; + if (diffs != null) { + final Object a = values[i]; + for (int j : diffs) { + + Object b; + if (p.contains(j)) { + b = values[revInd.get(j)]; + } else { + b = constValues[j]; } - if (a.equals(b)) { - solutionFound = false; - break; - } - } - } - } + if (a.equals(b)) { + solutionFound = false; + break; + } + } + } + } /* * If current values are not a solution try a new solution. If no more combinations are available, fail. */ - if (!solutionFound) { - i = nPart - 1; - while (!its[i].hasNext()) { - if (i == 0) { - return false; + if (!solutionFound) { + i = nPart - 1; + while (!its[i].hasNext()) { + if (i == 0) { + return false; } - its[i] = drs[i].valueIterator(); - values[i] = its[i].next(); - i--; - } - values[i] = its[i].next(); - } - } - } - - return true; - } - - public boolean isSatisfiable(Set nodes, Map> neqs) - throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { - - Literal[] literals = nodes.toArray(new Literal[0]); - - // TODO: Evaluate replacing with intset or just int arrays. - Set vars = new HashSet(); - Set consts = new HashSet(); - Object[] constValues = new Object[literals.length]; - - Map rev = new HashMap(); - - for (int i = 0; i < literals.length; i++) { - rev.put(literals[i], i); - if (literals[i].isNominal()) { - consts.add(i); - constValues[i] = literals[i].getValue(); - } - else { - vars.add(i); + its[i] = drs[i].valueIterator(); + values[i] = its[i].next(); + i--; + } + values[i] = its[i].next(); + } + } + } + + return true; + } + + public boolean isSatisfiable(Set nodes, Map> neqs) + throws InvalidConstrainingFacetException, InvalidLiteralException, UnrecognizedDatatypeException { + + Literal[] literals = nodes.toArray(new Literal[0]); + + // TODO: Evaluate replacing with intset or just int arrays. + Set vars = new HashSet(); + Set consts = new HashSet(); + Object[] constValues = new Object[literals.length]; + + Map rev = new HashMap(); + + for (int i = 0; i < literals.length; i++) { + rev.put(literals[i], i); + if (literals[i].isNominal()) { + consts.add(i); + constValues[i] = literals[i].getValue(); + } else { + vars.add(i); } - } - - @SuppressWarnings("unchecked") - Set[] ne = new Set[literals.length]; - for (Map.Entry> e : neqs.entrySet()) { - int index = rev.get(e.getKey()); - ne[index] = new HashSet(); - for (Literal l : e.getValue()) { - ne[index].add(rev.get(l)); + } + + @SuppressWarnings("unchecked") + Set[] ne = new Set[literals.length]; + for (Map.Entry> e : neqs.entrySet()) { + int index = rev.get(e.getKey()); + ne[index] = new HashSet(); + for (Literal l : e.getValue()) { + ne[index].add(rev.get(l)); } - } + } - if (log.isLoggable(Level.FINEST)) { - log.finest(format("Checking satisfiability for %d variables and %d constants", vars.size(), consts.size())); - } + if (log.isLoggable(Level.FINEST)) { + log.finest(format("Checking satisfiability for %d variables and %d constants", vars.size(), consts.size())); + } /* * 1. Get to DNF. After this step dnfMap associates literals with a collection of D-conjunctions, * of which it must satisfy at least one to be generally satisfied. */ - @SuppressWarnings("unchecked") - Collection[] dnfs = new Collection[literals.length]; - for (int i = 0; i < literals.length; i++) { - ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(literals[i].getTypes())); - ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); - if (ATermUtils.isOr(dnf)) { - List disjuncts = new ArrayList(); - for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { - disjuncts.add((ATermAppl) l.getFirst()); + @SuppressWarnings("unchecked") + Collection[] dnfs = new Collection[literals.length]; + for (int i = 0; i < literals.length; i++) { + ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(literals[i].getTypes())); + ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); + if (ATermUtils.isOr(dnf)) { + List disjuncts = new ArrayList(); + for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { + disjuncts.add((ATermAppl) l.getFirst()); } - dnfs[i] = disjuncts; - } - else { - dnfs[i] = Collections.singleton(dnf); + dnfs[i] = disjuncts; + } else { + dnfs[i] = Collections.singleton(dnf); } - } + } - return isSatisfiable(consts, vars, dnfs, constValues, ne); - } + return isSatisfiable(consts, vars, dnfs, constValues, ne); + } - public boolean define(ATermAppl name, ATermAppl datarange) { - if (name.equals(datarange)) { - throw new IllegalArgumentException(); + public boolean define(ATermAppl name, ATermAppl datarange) { + if (name.equals(datarange)) { + throw new IllegalArgumentException(); } - if (namedDataRanges.containsKey(name)) { - return false; + if (namedDataRanges.containsKey(name)) { + return false; } - namedDataRanges.put(name, datarange); - declaredUndefined.remove(name); + namedDataRanges.put(name, datarange); + dataRangeCache.invalidate(name); + declaredUndefined.remove(name); - return true; - } + return true; + } - private DataRange normalizeVarRanges(ATermAppl dconjunction) throws InvalidConstrainingFacetException, - InvalidLiteralException, UnrecognizedDatatypeException { + private DataRange normalizeVarRanges(ATermAppl dconjunction) throws InvalidConstrainingFacetException, + InvalidLiteralException, UnrecognizedDatatypeException { - DataRange ret; + DataRange ret; - if (ATermUtils.isAnd(dconjunction)) { - Collection> ranges = new LinkedHashSet>(); - for (ATermList l = (ATermList) dconjunction.getArgument(0); !l.isEmpty(); l = l.getNext()) { - DataRange dr = getDataRange((ATermAppl) l.getFirst()); - if (dr.isEmpty()) { - return EMPTY_RANGE; + if (ATermUtils.isAnd(dconjunction)) { + Collection> ranges = new LinkedHashSet>(); + for (ATermList l = (ATermList) dconjunction.getArgument(0); !l.isEmpty(); l = l.getNext()) { + DataRange dr = getDataRange((ATermAppl) l.getFirst()); + if (dr.isEmpty()) { + return EMPTY_RANGE; } - ranges.add(dr); - } + ranges.add(dr); + } - Set> positiveEnumerations = new HashSet>(); - Set> negativeEnumerations = new HashSet>(); - Set> positiveRestrictions = new HashSet>(); - Set> negativeRestrictions = new HashSet>(); + Set> positiveEnumerations = new HashSet>(); + Set> negativeEnumerations = new HashSet>(); + Set> positiveRestrictions = new HashSet>(); + Set> negativeRestrictions = new HashSet>(); - partitionDConjunction(ranges, positiveEnumerations, negativeEnumerations, positiveRestrictions, - negativeRestrictions); + partitionDConjunction(ranges, positiveEnumerations, negativeEnumerations, positiveRestrictions, + negativeRestrictions); /* * 1. If an enumeration is present, test each element in it against other conjuncts */ - if (!positiveEnumerations.isEmpty()) { - DataRange enumeration = findSmallestEnumeration(positiveEnumerations); - Set remainingValues = new HashSet(); - Iterator it = enumeration.valueIterator(); - boolean same = true; - while (it.hasNext()) { - Object value = it.next(); - boolean permit = true; - for (DataRange dr : ranges) { - if ((dr != enumeration) && !dr.contains(value)) { - permit = false; - same = false; - break; - } - } - if (permit) { - remainingValues.add(value); + if (!positiveEnumerations.isEmpty()) { + DataRange enumeration = findSmallestEnumeration(positiveEnumerations); + Set remainingValues = new HashSet(); + Iterator it = enumeration.valueIterator(); + boolean same = true; + while (it.hasNext()) { + Object value = it.next(); + boolean permit = true; + for (DataRange dr : ranges) { + if ((dr != enumeration) && !dr.contains(value)) { + permit = false; + same = false; + break; + } + } + if (permit) { + remainingValues.add(value); } - } - if (same) { - return enumeration; - } - else if (remainingValues.isEmpty()) { - return EMPTY_RANGE; } - else { - return new DataValueEnumeration(remainingValues); + if (same) { + return enumeration; + } else if (remainingValues.isEmpty()) { + return EMPTY_RANGE; + } else { + return new DataValueEnumeration(remainingValues); } - } + } /* * If there are only negative restrictions, the conjunction is trivially satisfiable (because the * interpretation domain is infinite). */ - if (positiveRestrictions.isEmpty()) { - return TRIVIALLY_SATISFIABLE; + if (positiveRestrictions.isEmpty()) { + return TRIVIALLY_SATISFIABLE; } /* * Verify that all positive restrictions are on the same primitive type. If not, the data range is empty * because the primitives are disjoint. */ - Datatype rootDt = null; - for (RestrictedDatatype pr : positiveRestrictions) { - final Datatype dt = pr.getDatatype().getPrimitiveDatatype(); - - if (rootDt == null) { - rootDt = dt; + Datatype rootDt = null; + for (RestrictedDatatype pr : positiveRestrictions) { + final Datatype dt = pr.getDatatype().getPrimitiveDatatype(); + + if (rootDt == null) { + rootDt = dt; + } else if (!rootDt.equals(dt)) { + return EMPTY_RANGE; } - else if (!rootDt.equals(dt)) { - return EMPTY_RANGE; + } + + Iterator> it = positiveRestrictions.iterator(); + RestrictedDatatype rd = it.next(); + while (it.hasNext()) { + RestrictedDatatype other = it.next(); + rd = rd.intersect(other, false); + } + + for (RestrictedDatatype other : negativeRestrictions) { + if (other.isEmpty()) { + continue; } - } - - Iterator> it = positiveRestrictions.iterator(); - RestrictedDatatype rd = it.next(); - while (it.hasNext()) { - RestrictedDatatype other = it.next(); - rd = rd.intersect(other, false); - } - - for (RestrictedDatatype other : negativeRestrictions) { - if (other.isEmpty()) { - continue; + + final Datatype dt = other.getDatatype().getPrimitiveDatatype(); + + if (!rootDt.equals(dt)) { + continue; } - final Datatype dt = other.getDatatype().getPrimitiveDatatype(); + rd = rd.intersect(other, true); + } - if (!rootDt.equals(dt)) { - continue; + if (!negativeEnumerations.isEmpty()) { + Set notOneOf = new HashSet(); + for (DataValueEnumeration enm : negativeEnumerations) { + for (Iterator oi = enm.valueIterator(); oi.hasNext(); ) { + notOneOf.add(oi.next()); + } } + rd = rd.exclude(notOneOf); + } - rd = rd.intersect(other, true); - } - - if (!negativeEnumerations.isEmpty()) { - Set notOneOf = new HashSet(); - for (DataValueEnumeration enm : negativeEnumerations) { - for (Iterator oi = enm.valueIterator(); oi.hasNext();) { - notOneOf.add(oi.next()); - } - } - rd = rd.exclude(notOneOf); - } - - ret = rd; - } - else { - ret = getDataRange(dconjunction); + ret = rd; + } else { + ret = getDataRange(dconjunction); } - if (!ret.isFinite()) { - return TRIVIALLY_SATISFIABLE; + if (!ret.isFinite()) { + return TRIVIALLY_SATISFIABLE; } - return ret; - } + return ret; + } - public Collection listDataRanges() { - Collection dataRanges = new HashSet(coreDatatypes.keySet()); - dataRanges.addAll(declaredUndefined); - dataRanges.addAll(namedDataRanges.keySet()); + public Collection listDataRanges() { + Collection dataRanges = new HashSet(coreDatatypes.keySet()); + dataRanges.addAll(declaredUndefined); + dataRanges.addAll(namedDataRanges.keySet()); - return dataRanges; - } + return dataRanges; + } - public boolean validLiteral(ATermAppl typedLiteral) throws UnrecognizedDatatypeException { - if (!ATermUtils.isLiteral(typedLiteral)) { - throw new IllegalArgumentException(); + public boolean validLiteral(ATermAppl typedLiteral) throws UnrecognizedDatatypeException { + if (!ATermUtils.isLiteral(typedLiteral)) { + throw new IllegalArgumentException(); } - final ATermAppl dtTerm = (ATermAppl) typedLiteral.getArgument(ATermUtils.LIT_URI_INDEX); - if (dtTerm == null) { - throw new IllegalArgumentException(); + final ATermAppl dtTerm = (ATermAppl) typedLiteral.getArgument(ATermUtils.LIT_URI_INDEX); + if (dtTerm == null) { + throw new IllegalArgumentException(); } - final Datatype dt = getDatatype(dtTerm); - if (dt == null) { - throw new UnrecognizedDatatypeException(dtTerm); + final Datatype dt = getDatatype(dtTerm); + if (dt == null) { + throw new UnrecognizedDatatypeException(dtTerm); } - try { - dt.getValue(typedLiteral); - } - catch (InvalidLiteralException e) { - return false; - } - return true; - } - - public Iterator valueIterator(Collection dataranges) throws InvalidConstrainingFacetException, - InvalidLiteralException, UnrecognizedDatatypeException { - - ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(dataranges)); - ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); - if (ATermUtils.isOr(dnf)) { - List> disjuncts = new ArrayList>(); - for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { - final DataRange dr = normalizeVarRanges((ATermAppl) l.getFirst()); - disjuncts.add(dr); - } - - final DataRange disjunction = getDisjunction(disjuncts); - if (!disjunction.isEnumerable()) { - throw new IllegalArgumentException(); - } - else { - return disjunction.valueIterator(); + try { + dt.getValue(typedLiteral); + } catch (InvalidLiteralException e) { + return false; + } + return true; + } + + public Iterator valueIterator(Collection dataranges) throws InvalidConstrainingFacetException, + InvalidLiteralException, UnrecognizedDatatypeException { + + ATermAppl and = ATermUtils.makeAnd(ATermUtils.makeList(dataranges)); + ATermAppl dnf = DNF.dnf(expander.expand(and, namedDataRanges)); + if (ATermUtils.isOr(dnf)) { + List> disjuncts = new ArrayList>(); + for (ATermList l = (ATermList) dnf.getArgument(0); !l.isEmpty(); l = l.getNext()) { + final DataRange dr = normalizeVarRanges((ATermAppl) l.getFirst()); + disjuncts.add(dr); } - } - else { - final DataRange dr = normalizeVarRanges(dnf); - if (!dr.isEnumerable()) { - throw new IllegalArgumentException(); + + final DataRange disjunction = getDisjunction(disjuncts); + if (!disjunction.isEnumerable()) { + throw new IllegalArgumentException(); + } else { + return disjunction.valueIterator(); } - else { - return dr.valueIterator(); + } else { + final DataRange dr = normalizeVarRanges(dnf); + if (!dr.isEnumerable()) { + throw new IllegalArgumentException(); + } else { + return dr.valueIterator(); } - } - } + } + } } From a5cc187ff392b134602f5df21e7dc76b9949c9c2 Mon Sep 17 00:00:00 2001 From: Simon Spero Date: Wed, 30 Apr 2014 20:27:42 -0400 Subject: [PATCH 4/5] Add intellij project files to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2fa992317..c703428d7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,8 @@ target/ .classpath .project .settings/ - +.idea/ +*.iml +*.iws +*.ipr test-persistence-classification.zip From 1930f8d417511b0bb9e52ab2859b5638bd8f67a2 Mon Sep 17 00:00:00 2001 From: Simon Spero Date: Thu, 1 May 2014 15:56:44 -0400 Subject: [PATCH 5/5] Add changes to support the rdf:langString type from RDF 1.1 . RDF 1.1 gets rid of "plain literals", and instead defines "simple literals". These have the same lexical form as "plain literals", but are defined as syntactic sugar for either xsd:string or rdf:langString, which partition the value space of PlainLiteral based on the absence or presence of a language tag. rdf:langString is not used as an explicit datatype in rdf serializations (just like PlainLiteral). It can appear as the range of a datatype. The OWL 2 and RDF 1.1 specifications are not currently aligned (e.g. explicit xsd:string types may be discarded by RDF processors). The rdf:langRange facet is currently only formally defined for rdf:PlainLiteral, as previously this was the only datatype which could have a language range. Since rdf:langString can be defined as a PlainLiteral with a langRange restriction of "*", I am allowing this facet to also be used on rdf:langString. --- .../datatypes/DatatypeReasonerImpl.java | 2 + .../pellet/datatypes/Datatypes.java | 1 + .../datatypes/types/text/RDFLangString.java | 79 +++++++++ .../datatypes/types/text/RDFPlainLiteral.java | 6 +- .../types/text/RestrictedTextDatatype.java | 152 +++++++++++++++--- .../datatypes/types/text/XSDString.java | 4 +- .../test/DatatypeRestrictionTests.java | 47 ++++++ 7 files changed, 264 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFLangString.java diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java index f98538ce4..6b4706331 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/DatatypeReasonerImpl.java @@ -22,6 +22,7 @@ import com.clarkparsia.pellet.datatypes.types.real.XSDDecimal; import com.clarkparsia.pellet.datatypes.types.real.XSDInteger; import com.clarkparsia.pellet.datatypes.types.real.XSDLong; +import com.clarkparsia.pellet.datatypes.types.text.RDFLangString; import com.clarkparsia.pellet.datatypes.types.text.RDFPlainLiteral; import com.clarkparsia.pellet.datatypes.types.text.XSDLanguage; import com.clarkparsia.pellet.datatypes.types.text.XSDNCName; @@ -76,6 +77,7 @@ public class DatatypeReasonerImpl implements DatatypeReasoner { { coreDatatypes.put(RDFPlainLiteral.getInstance().getName(), RDFPlainLiteral.getInstance()); + coreDatatypes.put(RDFLangString.getInstance().getName(), RDFLangString.getInstance()); coreDatatypes.put(XSDString.getInstance().getName(), XSDString.getInstance()); coreDatatypes.put(XSDNormalizedString.getInstance().getName(), XSDNormalizedString.getInstance()); coreDatatypes.put(XSDToken.getInstance().getName(), XSDToken.getInstance()); diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/Datatypes.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/Datatypes.java index 4652c0440..c4c6e711b 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/Datatypes.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/Datatypes.java @@ -37,6 +37,7 @@ public class Datatypes { public static final ATermAppl LITERAL = term( Namespaces.RDFS + "Literal" ); public static final ATermAppl PLAIN_LITERAL = term( Namespaces.RDF + "PlainLiteral" ); + public static final ATermAppl LANG_STRING = term( Namespaces.RDF + "langString" ); public static final ATermAppl XML_LITERAL = term( Namespaces.RDF + "XMLLiteral" ); public static final ATermAppl REAL = term( Namespaces.OWL + "Real" ); diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFLangString.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFLangString.java new file mode 100644 index 000000000..049197c82 --- /dev/null +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFLangString.java @@ -0,0 +1,79 @@ +package com.clarkparsia.pellet.datatypes.types.text; + +import aterm.ATermAppl; +import com.clarkparsia.pellet.datatypes.AbstractBaseDatatype; +import com.clarkparsia.pellet.datatypes.Datatype; +import com.clarkparsia.pellet.datatypes.RestrictedDatatype; +import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException; +import org.mindswap.pellet.utils.ATermUtils; +import org.mindswap.pellet.utils.Namespaces; + +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.LanguageTagPresence.*; + +/** + *

+ * Title: rdf:langString + *

+ *

+ * Description: Singleton implementation of rdf:langString + */ +public class RDFLangString extends AbstractBaseDatatype { + + private static final RDFLangString instance; + + static { + instance = new RDFLangString(); + RestrictedTextDatatype.addPermittedDatatype( instance.getName() ); + } + + public static RDFLangString getInstance() { + return instance; + } + + private final RestrictedTextDatatype dataRange; + + private RDFLangString() { + super( ATermUtils.makeTermAppl( Namespaces.RDF + "langString" ) ); + dataRange = new RestrictedTextDatatype( this, LANGUAGE_TAG_REQUIRED ); + } + + public RestrictedDatatype asDataRange() { + return dataRange; + } + + public ATermAppl getCanonicalRepresentation(ATermAppl input) throws InvalidLiteralException { + return getValue( input ); + } + + public ATermAppl getLiteral(Object value) { + if( value instanceof ATermAppl ) { + final ATermAppl literal = (ATermAppl) value; + try { + return getCanonicalRepresentation( literal ); + } catch( InvalidLiteralException e ) { + throw new IllegalStateException( e ); + } + } + else + throw new IllegalArgumentException(); + } + + public Datatype getPrimitiveDatatype() { + return RDFPlainLiteral.getInstance(); + } + + public ATermAppl getValue(ATermAppl literal) throws InvalidLiteralException { + /* + * This call checks that the input is a literal and the datatype name + * matches. The return value is not needed because plain literal values + * cannot be canonicalized. + */ + getLexicalForm( literal ); + + return literal; + } + + public boolean isPrimitive() { + return false; + } +} diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFPlainLiteral.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFPlainLiteral.java index 91336db30..cf5758280 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFPlainLiteral.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RDFPlainLiteral.java @@ -10,6 +10,8 @@ import com.clarkparsia.pellet.datatypes.RestrictedDatatype; import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException; +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.*; + /** *

* Title: rdf:plainLiteral @@ -33,7 +35,7 @@ public class RDFPlainLiteral extends AbstractBaseDatatype { static { instance = new RDFPlainLiteral(); - RestrictedTextDatatype.addPermittedDatatype( instance.getName() ); + addPermittedDatatype(instance.getName()); } public static RDFPlainLiteral getInstance() { @@ -44,7 +46,7 @@ public static RDFPlainLiteral getInstance() { private RDFPlainLiteral() { super( ATermUtils.makeTermAppl( Namespaces.RDF + "PlainLiteral" ) ); - dataRange = new RestrictedTextDatatype( this, true ); + dataRange = new RestrictedTextDatatype( this, LanguageTagPresence.LANGUAGE_TAG_ALLOWED ); } public RestrictedDatatype asDataRange() { diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java index 860140adf..4dc760f8c 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/RestrictedTextDatatype.java @@ -1,6 +1,5 @@ package com.clarkparsia.pellet.datatypes.types.text; -import aterm.ATerm; import aterm.ATermAppl; import com.clarkparsia.pellet.datatypes.Datatype; import com.clarkparsia.pellet.datatypes.Facet; @@ -19,6 +18,10 @@ import java.util.Set; import java.util.regex.Pattern; +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.LanguageTagPresence.LANGUAGE_TAG_FORBIDDEN; +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.LanguageTagPresence.LANGUAGE_TAG_MUST_BE_EMPTY; +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.LanguageTagPresence.LANGUAGE_TAG_REQUIRED; + /** *

* Title: Restricted Text Datatype @@ -59,6 +62,92 @@ public class RestrictedTextDatatype implements RestrictedDatatype { private final Set patterns; private final Set langRanges; + public enum LanguageTagPresence { + LANGUAGE_TAG_REQUIRED { + public LanguageTagPresence intersect(LanguageTagPresence that) { + return LANGUAGE_TAG_REQUIRED; + } + + public LanguageTagPresence union(LanguageTagPresence that) { + if (that == LANGUAGE_TAG_REQUIRED) { + return LANGUAGE_TAG_REQUIRED; + } else { + return LANGUAGE_TAG_ALLOWED; + } + } + + boolean isLanguagePresenceOk(ATermAppl literal) { + return doesLiteralHaveLanguageTag(literal); + } + + }, + LANGUAGE_TAG_ALLOWED { + public LanguageTagPresence intersect(LanguageTagPresence that) { + return that; + } + + public LanguageTagPresence union(LanguageTagPresence that) { + return LANGUAGE_TAG_ALLOWED; + } + + boolean isLanguagePresenceOk(ATermAppl literal) { + return true; + } + }, + LANGUAGE_TAG_MUST_BE_EMPTY { + @Override + public LanguageTagPresence intersect(LanguageTagPresence that) { + if (that == LANGUAGE_TAG_FORBIDDEN) { + return LANGUAGE_TAG_FORBIDDEN; + } else { + return LANGUAGE_TAG_MUST_BE_EMPTY; + } + } + + @Override + public LanguageTagPresence union(LanguageTagPresence that) { + switch (that) { + case LANGUAGE_TAG_FORBIDDEN: + case LANGUAGE_TAG_MUST_BE_EMPTY: + return LANGUAGE_TAG_MUST_BE_EMPTY; + default: + return LANGUAGE_TAG_ALLOWED; + } + + } + + @Override + boolean isLanguagePresenceOk(ATermAppl literal) { + return !doesLiteralHaveLanguageTag(literal); + } + }, + LANGUAGE_TAG_FORBIDDEN { + public LanguageTagPresence intersect(LanguageTagPresence that) { + return LANGUAGE_TAG_FORBIDDEN; + } + + public LanguageTagPresence union(LanguageTagPresence that) { + if (that == LANGUAGE_TAG_FORBIDDEN) { + return LANGUAGE_TAG_FORBIDDEN; + } else { + return LANGUAGE_TAG_ALLOWED; + } + } + + boolean isLanguagePresenceOk(ATermAppl literal) { + return !doesLiteralHaveLanguageTag(literal); + } + + + }; + + abstract public LanguageTagPresence intersect(LanguageTagPresence that); + + abstract public LanguageTagPresence union(LanguageTagPresence that); + + abstract boolean isLanguagePresenceOk(ATermAppl literal); + } + static { permittedDts = new HashSet(Arrays.asList(ATermUtils.EMPTY)); } @@ -70,20 +159,22 @@ public static boolean addPermittedDatatype(ATermAppl dt) { return permittedDts.add(dt); } - private final boolean allowLang; + private final LanguageTagPresence languageTagPresence; private final Datatype dt; - public RestrictedTextDatatype(Datatype dt, boolean allowLang) { - this(Collections.emptySet(), allowLang, Collections.emptySet(), dt, Collections.emptySet()); + public RestrictedTextDatatype(Datatype dt, LanguageTagPresence languageTagPresence) { + this(Collections.emptySet(), languageTagPresence, Collections.emptySet(), dt, Collections.emptySet()); } public RestrictedTextDatatype(Datatype dt, String pattern) { - this(Collections.singleton(Pattern.compile(pattern)), false, Collections.emptySet(), dt, Collections.emptySet()); + this(Collections.singleton(Pattern.compile(pattern)), LANGUAGE_TAG_FORBIDDEN, + Collections.emptySet(), dt, Collections.emptySet()); } - private RestrictedTextDatatype(Set patterns, boolean allowLang, Set excludedValues, Datatype dt, Set langRanges) { + private RestrictedTextDatatype(Set patterns, LanguageTagPresence languageTagPresence, Set excludedValues, Datatype dt, + Set langRanges) { this.dt = dt; - this.allowLang = allowLang; + this.languageTagPresence = languageTagPresence; this.excludedValues = excludedValues; this.patterns = patterns; this.langRanges = langRanges; @@ -106,13 +197,20 @@ private RestrictedDatatype applyLangRangFacet(ATermAppl facet, Object } String rangePattern = ATermUtils.getLiteralValue((ATermAppl) value); - if (!allowLang && !rangePattern.equals("")) { - throw new InvalidConstrainingFacetException("can't add langRange facet to type that doesn't allow languages:" + this.dt.getName(), facet, value); + if (languageTagPresence == LANGUAGE_TAG_FORBIDDEN) { + throw new InvalidConstrainingFacetException("can't add langRange facet to type that doesn't allow languages:" + + this.dt.getName() + ":" + languageTagPresence, facet, value); + } + boolean rangePatternIsEmpty = rangePattern.equals(""); + if (rangePatternIsEmpty) { + return new RestrictedTextDatatype(patterns, LANGUAGE_TAG_MUST_BE_EMPTY, + excludedValues, dt, Collections.emptySet()); } + Set newRanges = new HashSet(); newRanges.addAll(langRanges); newRanges.add(new LangRange(rangePattern)); - return new RestrictedTextDatatype(patterns, allowLang, excludedValues, dt, newRanges); + return new RestrictedTextDatatype(patterns, LANGUAGE_TAG_REQUIRED, excludedValues, dt, newRanges); } public boolean contains(Object value) { @@ -126,16 +224,19 @@ public boolean contains(Object value) { if (ATermUtils.isLiteral(a) && permittedDts.contains(a.getArgument(ATermUtils.LIT_URI_INDEX))) { - boolean hasLangTag = !ATermUtils.EMPTY.equals(a.getArgument(ATermUtils.LIT_LANG_INDEX)); - if (!allowLang && hasLangTag) { + if (!languageTagPresence.isLanguagePresenceOk(a)) { return false; } - String langTag = hasLangTag ? ATermUtils.getLiteralLang(a) : ""; - for (LangRange range : langRanges) { - if(!range.match(langTag)) { - return false; + + if (!langRanges.isEmpty()) { + String literalLang = ATermUtils.getLiteralLang(a); + for (LangRange range : langRanges) { + if (!range.match(literalLang)) { + return false; + } } } + if (!patterns.isEmpty()) { String litValue = ((ATermAppl) a.getArgument(ATermUtils.LIT_VAL_INDEX)).getName(); for (Pattern pattern : patterns) { @@ -150,6 +251,10 @@ public boolean contains(Object value) { return false; } + private static boolean doesLiteralHaveLanguageTag(ATermAppl a) { + return !ATermUtils.EMPTY.equals(a.getArgument(ATermUtils.LIT_LANG_INDEX)); + } + public boolean containsAtLeast(int n) { return true; } @@ -157,7 +262,7 @@ public boolean containsAtLeast(int n) { public RestrictedDatatype exclude(Collection values) { Set newExcludedValues = new HashSet(values); newExcludedValues.addAll(excludedValues); - return new RestrictedTextDatatype(patterns, allowLang, newExcludedValues, dt, langRanges); + return new RestrictedTextDatatype(patterns, languageTagPresence, newExcludedValues, dt, langRanges); } public Datatype getDatatype() { @@ -186,7 +291,7 @@ public RestrictedDatatype intersect(RestrictedDatatype other, bool RestrictedTextDatatype that = (RestrictedTextDatatype) other; return new RestrictedTextDatatype(SetUtils.union(this.patterns, that.patterns), - this.allowLang && that.allowLang, + this.languageTagPresence.intersect(that.languageTagPresence), SetUtils.union(this.excludedValues, that.excludedValues), dt, SetUtils.union(this.langRanges, that.langRanges) @@ -214,17 +319,16 @@ public int size() { public RestrictedDatatype union(RestrictedDatatype other) { if (other instanceof RestrictedTextDatatype) { - if (!patterns.isEmpty() || !((RestrictedTextDatatype) other).patterns.isEmpty() - || !langRanges.isEmpty() || !((RestrictedTextDatatype) other).langRanges.isEmpty()) { + RestrictedTextDatatype that = (RestrictedTextDatatype) other; + if (!patterns.isEmpty() || !that.patterns.isEmpty() + || !langRanges.isEmpty() || !that.langRanges.isEmpty()) { //TODO support unions with patterns or langRanges throw new UnsupportedOperationException("union of restricted text types with patterns or langRanges not yet done"); } - if (this.allowLang) { - return this; - } + Set commonExcludedValues = SetUtils.intersection(this.excludedValues, that.excludedValues); + return new RestrictedTextDatatype(patterns, this.languageTagPresence.union(that.languageTagPresence), commonExcludedValues, dt, langRanges); - return (RestrictedTextDatatype) other; } else { throw new IllegalArgumentException(); } diff --git a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/XSDString.java b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/XSDString.java index 9022561ac..a51df2d0b 100644 --- a/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/XSDString.java +++ b/core/src/main/java/com/clarkparsia/pellet/datatypes/types/text/XSDString.java @@ -10,6 +10,8 @@ import com.clarkparsia.pellet.datatypes.RestrictedDatatype; import com.clarkparsia.pellet.datatypes.exceptions.InvalidLiteralException; +import static com.clarkparsia.pellet.datatypes.types.text.RestrictedTextDatatype.LanguageTagPresence.*; + /** *

* Title: xsd:string @@ -46,7 +48,7 @@ public static XSDString getInstance() { private XSDString() { super( ATermUtils.makeTermAppl( Namespaces.XSD + "string" ) ); - dataRange = new RestrictedTextDatatype( this, false ); + dataRange = new RestrictedTextDatatype( this, LANGUAGE_TAG_FORBIDDEN ); } public RestrictedDatatype asDataRange() { diff --git a/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java index e6e3a2a00..bbb431e70 100644 --- a/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java +++ b/test/src/test/java/com/clarkparsia/pellet/datatypes/test/DatatypeRestrictionTests.java @@ -9,17 +9,21 @@ import org.mindswap.pellet.utils.ATermUtils; import static com.clarkparsia.pellet.datatypes.Datatypes.INTEGER; +import static com.clarkparsia.pellet.datatypes.Datatypes.LANG_STRING; import static com.clarkparsia.pellet.datatypes.Datatypes.PLAIN_LITERAL; import static com.clarkparsia.pellet.datatypes.Datatypes.POSITIVE_INTEGER; +import static com.clarkparsia.pellet.datatypes.Datatypes.STRING; import static com.clarkparsia.pellet.utils.TermFactory.list; import static com.clarkparsia.pellet.utils.TermFactory.literal; import static com.clarkparsia.pellet.utils.TermFactory.maxInclusive; import static com.clarkparsia.pellet.utils.TermFactory.minExclusive; import static com.clarkparsia.pellet.utils.TermFactory.minInclusive; import static com.clarkparsia.pellet.utils.TermFactory.oneOf; +import static com.clarkparsia.pellet.utils.TermFactory.or; import static com.clarkparsia.pellet.utils.TermFactory.restrict; import static com.clarkparsia.pellet.utils.TermFactory.some; import static com.clarkparsia.pellet.utils.TermFactory.term; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; @@ -191,6 +195,49 @@ public void testAnyLangRangeRestriction() { } + @Test + public void testRDF11PlainLiteralLangTagPartition() { + ATermAppl langs = term("P_SOME_LANG_STRING"); + ATermAppl strings = term("P_SOME_STRING"); + ATermAppl plains = term("P_SOME_PLAIN_LITERAL"); + ATermAppl ors = term("P_SOME_STRING_OR_LANG_STRING"); + + ATermAppl noTag = term("no_tag"); + ATermAppl withTag = term("with_tag"); + + classes(langs,strings,plains,ors); + kb.addDatatypeDefinition(D,or(LANG_STRING,STRING) ); + + dataProperties(p); + individuals(noTag, withTag); + kb.addEquivalentClass(langs, some(p, LANG_STRING)); + kb.addEquivalentClass(strings, some(p, STRING)); + kb.addEquivalentClass(plains, some(p, PLAIN_LITERAL)); + kb.addEquivalentClass(ors,some(p,D)); + + kb.addPropertyValue(p, noTag, literal("no lang tag")); + kb.addPropertyValue(p, withTag, literal("english string", "en")); + + assertClassMembershipEquals(langs, true, withTag ); + assertClassMembershipEquals(langs, false, noTag ); + + assertClassMembershipEquals(strings, true, noTag ); + assertClassMembershipEquals(strings, false, withTag ); + + assertClassMembershipEquals(plains, true, noTag,withTag ); + assertClassMembershipEquals(ors, true, noTag,withTag ); + + + + + } + + private void assertClassMembershipEquals(ATermAppl c, boolean expected, ATermAppl... individuals) { + for (ATermAppl individual : individuals) { + String message = String.format("%s a %s",individual.getName(),c.getName()); + assertEquals(message,expected,kb.isType(individual,c)); + } + } @Test public void testEnglishLangRangeRestriction() {