http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/Fact.java
----------------------------------------------------------------------
diff --git a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/Fact.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/Fact.java
new file mode 100644
index 0000000..75c3a78
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/Fact.java
@@ -0,0 +1,514 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import mvm.rya.api.domain.RyaStatement;
+import mvm.rya.api.resolver.RyaToRdfConversions;
+
+import org.apache.hadoop.io.WritableComparable;
+import org.openrdf.model.Literal;
+import org.openrdf.model.Resource;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ContextStatementImpl;
+import org.openrdf.model.impl.StatementImpl;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.RDF;
+
+/**
+ * Represents a fact used and/or generated by the reasoner.
+ */
+public class Fact implements WritableComparable<Fact>, Cloneable {
+    Statement triple;
+
+    // If this is a derived fact:
+    Derivation derivation;
+
+    // Potentially useful for future derivations
+    boolean useful = true;
+
+    // An empty fact
+    public static final Fact NONE = new Fact();
+
+    private static final String SEP = "\u0000";
+
+    /**
+     * Default constructor, contains no information
+     */
+    public Fact() { }
+
+    /**
+     * A fact containing a triple and no generating rule.
+     */
+    public Fact(Statement stmt) {
+        this.triple = stmt;
+    }
+
+    /**
+     * A fact containing a triple and no generating rule.
+     */
+    public Fact(Resource s, URI p, Value o) {
+        this.triple = new StatementImpl(s, p, o);
+    }
+
+    /**
+     * A fact which contains a triple and was generated using a
+     * particular rule by a reasoner for a particular node.
+     */
+    public Fact(Resource s, URI p, Value o, int iteration,
+            OwlRule rule, Resource node) {
+        this.triple = new StatementImpl(s, p, o);
+        this.derivation = new Derivation(iteration, rule, node);
+    }
+
+    public Statement getTriple() {
+        return triple;
+    }
+
+    public Resource getSubject() {
+        if (triple == null) {
+            return null;
+        }
+        else {
+            return triple.getSubject();
+        }
+    }
+
+    public URI getPredicate() {
+        if (triple == null) {
+            return null;
+        }
+        else {
+            return triple.getPredicate();
+        }
+    }
+
+    public Value getObject() {
+        if (triple == null) {
+            return null;
+        }
+        else {
+            return triple.getObject();
+        }
+    }
+
+    /**
+     * Get the derivation if it exists, or the empty derivation otherwise.
+     */
+    public Derivation getDerivation() {
+        if (derivation == null) {
+            return Derivation.NONE;
+        }
+        else {
+            return derivation;
+        }
+    }
+
+    public boolean isInference() {
+        return derivation != null;
+    }
+
+    public boolean isUseful() {
+        return useful;
+    }
+
+    public boolean isEmpty() {
+        return triple == null;
+    }
+
+    /**
+     * Assign a particular statement to this fact.
+     */
+    public void setTriple(Statement stmt) {
+        triple = stmt;
+    }
+
+    /**
+     * Assign a particular statement to this fact.
+     */
+    public void setTriple(RyaStatement rs) {
+        setTriple(RyaToRdfConversions.convertStatement(rs));
+    }
+
+    /**
+     * Set a flag if this triple *could* be used in future derivations
+     * (may only actually happen if certain other facts are seen as well.)
+     */
+    public void setUseful(boolean useful) {
+        this.useful = useful;
+    }
+
+    /**
+     * Set derivation. Allows reconstructing a fact and the way it was 
produced.
+     */
+    public void setDerivation(Derivation d) {
+        this.derivation = d;
+    }
+
+    /**
+     * Set derivation to null and return its former value. Allows decoupling
+     * of the fact from the way it was produced.
+     */
+    public Derivation unsetDerivation() {
+        Derivation d = getDerivation();
+        this.derivation = null;
+        return d;
+    }
+
+    /**
+     * Generate a String showing this fact's derivation.
+     * @param   multiline    Print a multi-line tree as opposed to a nested 
list
+     * @param   schema       Use schema knowledge to further explain BNodes
+     */
+    public String explain(boolean multiline, Schema schema) {
+        return explain(multiline, "", schema);
+    }
+
+    /**
+     * Generate a String showing this fact's derivation. Does not incorporate
+     * schema information.
+     * @param   multiline    Print a multi-line tree as opposed to a nested 
list
+     */
+    public String explain(boolean multiline) {
+        return explain(multiline, "", null);
+    }
+
+    /**
+     * Recursively generate a String to show this fact's derivation.
+     */
+    String explain(boolean multiline, String prefix, Schema schema) {
+        StringBuilder sb = new StringBuilder();
+        String sep = " ";
+        if (multiline) {
+            sep = "\n" + prefix;
+        }
+        if (triple == null) {
+            sb.append("(empty)").append(sep);
+        }
+        else {
+            Resource s = getSubject();
+            URI p = getPredicate();
+            Value o = getObject();
+            sb.append("<").append(s.toString()).append(">").append(sep);
+            sb.append("<").append(p.toString()).append(">").append(sep);
+            sb.append("<").append(o.toString()).append(">");
+            // Restrictions warrant further explanation
+            if (schema != null && p.equals(RDF.TYPE)) {
+                Resource objClass = (Resource) o;
+                if (schema.hasRestriction(objClass)) {
+                    sb.append(" { ");
+                    sb.append(schema.explainRestriction(objClass));
+                    sb.append(" }");
+                }
+            }
+            sb.append(sep);
+        }
+        if (isInference()) {
+            sb.append(derivation.explain(multiline, prefix, schema));
+        }
+        else {
+            sb.append("[input]");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Represent the content only, not the derivation.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (triple != null) {
+            sb.append("<").append(getSubject().toString()).append("> ");
+            sb.append("<").append(getPredicate().toString()).append("> ");
+            if (getObject() instanceof Literal) {
+                sb.append(getObject().toString());
+            }
+            else {
+                sb.append("<").append(getObject().toString()).append(">");
+            }
+        }
+        return sb.append(" .").toString();
+    }
+
+    @Override
+    public void write(DataOutput out) throws IOException {
+        if (triple == null) {
+            out.writeInt(0);
+        }
+        else {
+            StringBuilder sb = new StringBuilder();
+            if (triple.getContext() != null) {
+                sb.append(triple.getContext().toString());
+            }
+            sb.append(SEP).append(getSubject().toString());
+            sb.append(SEP).append(getPredicate().toString());
+            sb.append(SEP).append(getObject().toString());
+            byte[] encoded = sb.toString().getBytes(StandardCharsets.UTF_8);
+            out.writeInt(encoded.length);
+            out.write(encoded);
+        }
+        out.writeBoolean(useful);
+        // Write the derivation if there is one
+        boolean derived = isInference();
+        out.writeBoolean(derived);
+        if (derived) {
+            derivation.write(out);
+        }
+    }
+
+    @Override
+    public void readFields(DataInput in) throws IOException {
+        derivation = null;
+        int tripleLength = in.readInt();
+        if (tripleLength == 0) {
+            triple = null;
+        }
+        else {
+            byte[] tripleBytes = new byte[tripleLength];
+            in.readFully(tripleBytes);
+            String tripleString = new String(tripleBytes, 
StandardCharsets.UTF_8);
+            String[] parts = tripleString.split(SEP);
+            ValueFactory factory = ValueFactoryImpl.getInstance();
+            String context = parts[0];
+            Resource s = null;
+            URI p = factory.createURI(parts[2]);
+            Value o = null;
+            // Subject: either bnode or URI
+            if (parts[1].startsWith("_")) {
+                s = factory.createBNode(parts[1].substring(2));
+            }
+            else {
+                s = factory.createURI(parts[1]);
+            }
+            // Object: literal, bnode, or URI
+            if (parts[3].startsWith("_")) {
+                o = factory.createBNode(parts[3].substring(2));
+            }
+            else if (parts[3].startsWith("\"")) {
+                //literal: may have language or datatype
+                int close = parts[3].lastIndexOf("\"");
+                int length = parts[3].length();
+                String label = parts[3].substring(1, close);
+                if (close == length - 1) {
+                    // Just a string enclosed in quotes
+                    o = factory.createLiteral(label);
+                }
+                else {
+                    String data = parts[3].substring(close + 1);
+                    if (data.startsWith("@")) {
+                        String lang = data.substring(1);
+                        o = factory.createLiteral(label, lang);
+                    }
+                    else if (data.startsWith("^^<")) {
+                        o = factory.createLiteral(label, factory.createURI(
+                            data.substring(3, data.length() - 1)));
+                    }
+                }
+            }
+            else {
+                o = factory.createURI(parts[3]);
+            }
+            // Create a statement with or without context
+            if (context.isEmpty()) {
+                triple = new StatementImpl(s, p, o);
+            }
+            else {
+                triple = new ContextStatementImpl(s, p, o, 
factory.createURI(context));
+            }
+        }
+        useful = in.readBoolean();
+        if (in.readBoolean()) {
+            derivation = new Derivation();
+            derivation.readFields(in);
+        }
+    }
+
+    /**
+     * Defines an ordering based on equals.
+     * Two ReasonerFacts belong together if they represent the same
+     * triple (regardless of where it came from). If they both are empty
+     * (represent no triple), compare their derivations instead.
+     */
+    @Override
+    public int compareTo(Fact other) {
+        if (this.equals(other)) {
+            return 0;
+        }
+        else if (other == null) {
+            return 1;
+        }
+        if (this.triple == null) {
+            if (other.triple == null) {
+                // The only case where Derivation matters
+                return this.getDerivation().compareTo(other.getDerivation());
+            }
+            else {
+                // triple > no triple
+                return -1;
+            }
+        }
+        else if (other.triple == null) {
+            // triple > no triple
+            return 1;
+        }
+        // Compare two triples, ignoring where the information came from
+        int result = this.getSubject().toString().compareTo(
+            other.getSubject().toString());
+        if (result == 0) {
+            result = this.getPredicate().toString().compareTo(
+                other.getPredicate().toString());
+            if (result == 0) {
+                result = this.getObject().toString().compareTo(
+                    other.getObject().toString());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Two ReasonerFacts are equivalent if they represent the same triple
+     * (regardless of where it came from). If they don't contain triples,
+     * compare their derivations.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || this.getClass() != o.getClass()) {
+            return false;
+        }
+        Fact other = (Fact) o;
+        if (this.triple == null) {
+            if (other.triple == null) {
+                // Derivations only matter if both facts are empty
+                return this.getDerivation().equals(other.getDerivation());
+            }
+            else {
+                return false;
+            }
+        }
+        else {
+            return this.triple.equals(other.triple);
+        }
+    }
+
+    /**
+     * Two statements are the same as long as they represent the same triple.
+     * Derivation matters if and only if there is no triple.
+     */
+    @Override
+    public int hashCode() {
+        if (triple == null) {
+            return getDerivation().hashCode();
+        }
+        else {
+            return triple.hashCode();
+        }
+    }
+
+    @Override
+    public Fact clone() {
+        Fact other = new Fact();
+        other.triple = this.triple;
+        other.useful = this.useful;
+        if (this.derivation != null) {
+            other.derivation = this.derivation.clone();
+        }
+        return other;
+    }
+
+    /**
+     * Specify a source. Wrapper for Derivation.addSource. Instantiates a
+     * derivation if none exists.
+     */
+    public void addSource(Fact other) {
+        if (derivation == null) {
+            derivation = new Derivation();
+        }
+        derivation.addSource(other);
+    }
+
+    /**
+     * If this is a derived fact, get the iteration it was derived, otherwise
+     * return zero.
+     */
+    public int getIteration() {
+        if (derivation == null) {
+            return 0;
+        }
+        else {
+            return derivation.getIteration();
+        }
+    }
+
+    /**
+     * Return whether this fact has itself as a source.
+     */
+    public boolean isCycle() {
+        return derivation != null && derivation.hasSource(this);
+    }
+
+    /**
+     * Return whether a particular fact is identical to one used to derive 
this.
+     * Wrapper for Derivation.hasSource.
+     */
+    public boolean hasSource(Fact other) {
+        return derivation != null && derivation.hasSource(other);
+    }
+
+    /**
+     * Return whether this fact was derived using a particular rule.
+     */
+    public boolean hasRule(OwlRule rule) {
+        return derivation != null && derivation.getRule() == rule;
+    }
+
+    /**
+     * Get the size of the derivation tree, computed by counting up the number
+     * of distinct nodes that are part of this edge or were used to produce 
this
+     * fact, minus 1. An input triple has span 1, a triple derived in one 
reduce
+     * step has span 2, etc. Related to the derivation's span, but takes
+     * subject and object of this fact into account.
+     */
+    public int span() {
+        if (isInference()) {
+            int d = derivation.span() + 1;
+            if (derivation.hasSourceNode(getSubject())) {
+                d--;
+            }
+            if (derivation.hasSourceNode(getObject())) {
+                d--;
+            }
+            return d;
+        }
+        else {
+            return 1;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/LocalReasoner.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/LocalReasoner.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/LocalReasoner.java
new file mode 100644
index 0000000..41ac734
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/LocalReasoner.java
@@ -0,0 +1,667 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.openrdf.model.Literal;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.vocabulary.OWL;
+import org.openrdf.model.vocabulary.RDF;
+
+/**
+ * Perform reasoning with respect to a particular node, given a global schema.
+ * Assumes that incoming input triples will be provided first (i.e. triples
+ * where this node is the object) in order to perform some joins.
+ * <p>
+ * Rules implemented so far:
+ * <p>
+ * Simple rules implemented here:
+ * <ul>
+ * <li>prp-dom:         domain: infer subject's type from predicate's domain
+ * <li>prp-rng:         range: infer object's type from predicate's range
+ * <li>prp-irp:         If p is irreflexive, (x p x) is inconsistent
+ * <li>prp-symp:        If p is symmetric, (x p y) implies (y p x)
+ * <li>prp-spo1:        subPropertyOf semantics: inherit superproperties
+ * <li>prp-inv1:        If p1 inverseOf p2, (x p1 y) implies (y p2 x)
+ * <li>prp-inv2:        If p1 inverseOf p2, (x p2 y) implies (y p1 x)
+ * <li>cls-svf2:        If [x someValuesFrom owl:Thing onProperty p],
+ *                          (u p v) implies (u type x)
+ * <li>cls-hv2:         If [x hasValue v onProperty p], (u p v) implies
+ *                          (u type x)
+ * </ul>
+ * <p>
+ * Join rules implemented here:
+ * <ul>
+ * <li>prp-asyp:        If p is asymmetric, (x p y) and (y p x) is inconsistent
+ * <li>prp-trp:         If p is transitive, (x p y) and (y p z) implies (x p z)
+ * <li>prp-pdw:         If p is disjoint with q, (x p y) and (x q y) is
+ *                          inconsistent
+ * <li>cls-svf1:        If [x someValuesFrom y onProperty p],
+ *                          (u p v) and (v type y) imply (u type x)
+ * <li>cls-avf:         If [x allValuesFrom y onProperty p],
+ *                          (u p v) and (u type x) imply (v type y)
+ * <li>cls-maxc1:       (x p y) is inconsistent if p has maxCardinality 0
+ * <li>cls-maxqc2:      ...or if p has maxQualifiedCardinality 0 on owl:Thing
+ * </ul>
+ * <p>
+ * Simple and join rules handled in {@link TypeReasoner}:
+ * <ul>
+ * <li>cax-sco:         subClassOf semantics: inherit supertypes
+ * <li>cls-hv1:         If [x hasValue v onProperty p], (u type x) implies
+ *                          (u p v)
+ * <li>cls-nothing2:    type owl:Nothing is automatically inconsistent
+ * <li>cls-com:         If c1 has complement c2, having both types is
+ *                          inconsistent
+ * <li>cax-dw:          If c1 and c2 are disjoint, having both types is
+ *                          inconsistent
+ * </ul>
+ */
+public class LocalReasoner extends AbstractReasoner {
+    public enum Relevance {
+        NONE, SUBJECT, OBJECT, BOTH;
+        static Relevance get(boolean s, boolean o) {
+            if (s && o) return BOTH;
+            else if (s) return SUBJECT;
+            else if (o) return OBJECT;
+            else return NONE;
+        }
+        public boolean subject() { return this == SUBJECT || this == BOTH; }
+        public boolean object() { return this == OBJECT || this == BOTH; }
+    }
+
+    /**
+     * Determine whether a fact is a triple which might be used by a local
+     * reasoner for its subject and/or object.
+     * @param   fact  Fact to be evaluated
+     * @param   schema  Global schema
+     * @return  Relevance to subject and/or object. Relevance means that it's a
+     *          triple that *could* be used in reasoning. It may only be useful
+     *          when combined with other facts, which may or may not exist
+     *          somewhere, so this doesn't guarantee that information will be
+     *          derived.
+     */
+    public static Relevance relevantFact(Fact fact, Schema schema) {
+        // If this is schema information, we know it's already
+        // contained in the schema object.
+        if (Schema.isSchemaTriple(fact.getTriple())) {
+            return Relevance.NONE;
+        }
+        // Otherwise, consider the semantics of the statement:
+        Resource subject = fact.getSubject();
+        URI predURI = fact.getPredicate();
+        Value object = fact.getObject();
+        boolean relevantToSubject = false;
+        boolean relevantToObject = false;
+        // Literals don't get reasoners, so determine whether object is a uri:
+        boolean literalObject = object instanceof Literal;
+
+        // Type statements could be relevant to the subject, if the schema 
gives
+        // them any meaning:
+        if (predURI.equals(RDF.TYPE)) {
+            // Assume the object is a valid URI
+            Resource typeURI = (Resource) fact.getObject();
+            if (typeURI.equals(OWL.NOTHING)
+                || schema.hasClass(typeURI)) {
+                relevantToSubject = true;
+            }
+        }
+
+        // If the schema knows about the property:
+        if (schema.hasProperty(predURI)) {
+            OwlProperty prop = schema.getProperty(predURI);
+
+            // Relevant to both:
+                    // Any statement with an asymmetric property
+            if (prop.isAsymmetric()
+                    // Any statement with a transitive property
+                    || prop.isTransitive()
+                    // Statements involving restricted properties
+                    || !prop.getRestrictions().isEmpty()) {
+                relevantToSubject = true;
+                relevantToObject = !literalObject;
+            }
+
+            // Relevant to subject:
+            if (!relevantToSubject && // skip these checks if it already is
+                    // Any statement whose property has a domain.
+                    (!prop.getDomain().isEmpty()
+                    // Choose to apply superproperties here
+                    // (every property is its own superproperty; ignore that)
+                    || prop.getSuperProperties().size() > 1
+                    // Choose to apply disjoint properties here
+                    || !prop.getDisjointProperties().isEmpty())) {
+                relevantToSubject = true;
+            }
+
+            // Relevant to object if the object is not a literal and one other
+            // condition matches:
+            if (!literalObject && !relevantToObject &&
+                    // Any statement whose property has a defined range
+                    (!prop.getRange().isEmpty()
+                    // Choose to apply inverse rule in the object's reasoner
+                    || !prop.getInverseProperties().isEmpty()
+                    // Choose to apply symmetry in the object's reasoner
+                    || prop.isSymmetric()
+                    // Choose to check irreflexivity in the object's reasoner
+                    || prop.isIrreflexive() && subject.equals(object))) {
+                relevantToObject = true;
+            }
+        }
+        return Relevance.get(relevantToSubject, relevantToObject);
+    }
+
+    /**
+     * Determine whether a fact is a triple which might be used in some join
+     * rule for its subject and/or object.
+     */
+    public static Relevance relevantJoinRule(Fact fact, Schema schema) {
+        // If this is schema information, we know it's already
+        // contained in the schema object.
+        if (Schema.isSchemaTriple(fact.getTriple())) {
+            return Relevance.NONE;
+        }
+        // Otherwise, consider the semantics of the statement:
+        URI predURI = fact.getPredicate();
+        Value object = fact.getObject();
+        boolean relevantToSubject = false;
+        boolean relevantToObject = false;
+        // Literals don't get reasoners, so determine whether object is a uri:
+        boolean literalObject = object instanceof Literal;
+
+        // Type statements can be joined if...
+        if (predURI.equals(RDF.TYPE)) {
+            Resource typeURI = (Resource) fact.getObject();
+            if (schema.hasClass(typeURI)) {
+                OwlClass c = schema.getClass(typeURI);
+                // 1. the type is a property restriction
+                if (!c.getOnProperty().isEmpty()
+                // 2. the type is relevant to a property restriction
+                    || !c.getSvfRestrictions().isEmpty()
+                    || !c.getAvfRestrictions().isEmpty()
+                    || !c.getQCRestrictions().isEmpty()
+                // 3. the type has complementary/disjoint types
+                    || !c.getDisjointClasses().isEmpty()
+                    || !c.getComplementaryClasses().isEmpty()) {
+                    relevantToSubject = true;
+                }
+            }
+        }
+
+        // If the schema knows about the property:
+        if (schema.hasProperty(predURI)) {
+            OwlProperty prop = schema.getProperty(predURI);
+            // transitivity: relevant to both
+            if (prop.isTransitive()) {
+                relevantToSubject = true;
+                relevantToObject = !literalObject;
+            }
+            else {
+                // disjoint properties: relevant to subject
+                if (!prop.getDisjointProperties().isEmpty()) {
+                    relevantToSubject = true;
+                }
+                // Property restrictions: possibly relevant to either
+                for (Resource rURI : prop.getRestrictions()) {
+                    OwlClass r = schema.getClass(rURI);
+                    // allValuesFrom requires a join on the subject
+                    // (if <subject type rURI>, infer object's type)
+                    if (!r.allValuesFrom().isEmpty()) {
+                        relevantToSubject = true;
+                    }
+                    // someValuesFrom requires a join on the object
+                    // (if the object is the appropriate type, infer rURI)
+                    // max cardinality requires a join on the subject
+                    if (!literalObject &&
+                        (r.getMaxCardinality() >= 0
+                        || r.getMaxQualifiedCardinality() >= 0
+                        || !r.someValuesFrom().isEmpty())) {
+                        relevantToObject = true;
+                    }
+                    if (relevantToSubject
+                        && (relevantToObject || literalObject)) {
+                        break;
+                    }
+                }
+            }
+        }
+        return Relevance.get(relevantToSubject, relevantToObject);
+    }
+
+    /**
+     * Use the semantics of a fact to determine whether it could be relevant
+     * to future reasoners, or whether we should assume we've extracted all
+     * the information implied by the fact during this iteration. Considers
+     * semantics but not age.
+     * @return true if this fact might still be used later.
+     */
+    boolean relevantToFuture(Fact fact) {
+        // If it's a join rule, it needs to be kept no matter what
+        if (relevantJoinRule(fact, schema) != Relevance.NONE) {
+            return true;
+        }
+        // Otherwise, it can be skipped under certain circumstances.
+        Relevance general = relevantFact(fact, schema);
+        Resource s = fact.getSubject();
+        Value o = fact.getObject();
+        // Exception: if subject==object, recursive derivation is limited, so
+        // we can't make assumptions about what's already been done.
+        if (!s.equals(o)) {
+            // Otherwise, if this is a reasoner for the subject, and the fact
+            // is only relevant to the subject, we can assume this reasoner
+            // did all the reasoning we needed to.
+            if (general == Relevance.SUBJECT && node.equals(s)) {
+                return false;
+            }
+            // Same reasoning for the object:
+            if (general == Relevance.OBJECT && node.equals(o)) {
+                return false;
+            }
+        }
+        // If we can't skip it, return true if it's ever relevant
+        return general != Relevance.NONE;
+    }
+
+    // Many rules derive types; keep track of them with a TypeReasoner
+    TypeReasoner types;
+
+    // Keep track of statements whose properties might make them relevant later
+    Map<URI, List<Fact>> transitiveIncoming = new HashMap<>();
+    Map<URI, List<Fact>> asymmetricIncoming = new HashMap<>();
+    Map<URI, List<Fact>> disjointOutgoing = new HashMap<>();
+
+    // Only combine transitive paths of a certain size, based on the current
+    // iteration, to avoid duplicate derivations and unnecessary memory use.
+    int minTransitiveLeft;
+    int minTransitiveRight;
+
+    /**
+     * Constructor.
+     * @param   node    Conduct reasoning about/around this node
+     * @param   schema  Global schema (class/property) information
+     * @param   t       Current iteration; any new facts will be generated with
+     *                  this number
+     * @param   tSchema Iteration of latest schema update (0 if original
+     *                  schema is unchanged)
+     */
+    public LocalReasoner(Resource node, Schema schema, int t, int tSchema) {
+        super(node, schema, t, tSchema);
+        types = new TypeReasoner(node, schema, t, tSchema);
+        // "Smart TC": combine incoming paths of length 2^(n-1) with outgoing
+        // paths of any length.
+        int n = t - tSchema; // count iterations since any schema change
+        minTransitiveLeft = (int) Math.pow(2, n-1);
+        minTransitiveRight = 1;
+    }
+
+    /**
+     * Read in a fact involving this node and make any inferences we can.
+     * Assumes that incoming triples are received before outgoing triples.
+     * Recursively call processFact on new triples until nothing else is
+     * derived.
+     * @param   fact  Contains a triple assumed to be relevant to this reasoner
+     */
+    public void processFact(Fact fact) {
+        Resource subject = fact.getSubject();
+        URI pred = fact.getPredicate();
+        Value object = fact.getObject();
+        // Whether this is a recursive call on a fact that's just been inferred
+        boolean recursive = fact.getIteration() == currentIteration;
+        // Figure out what kind of edge this is with respect to this node
+        boolean incoming = object.equals(node);
+        boolean outgoing = subject.equals(node);
+        // Avoid some derivation chains on recursive calls to avoid cycles
+        boolean skipReflexive = incoming && outgoing && recursive;
+        // Perform reasoning (incoming before outgoing, so reflexive edges are
+        // handled in the right order)
+        if (incoming && !skipReflexive) {
+            processIncoming(fact);
+        }
+        if (outgoing) {
+            if (pred.equals(RDF.TYPE)) {
+                types.processType(fact);
+            }
+            else {
+                processOutgoing(fact);
+            }
+        }
+        // If newly-learned facts cause further derivations, apply them 
recursively
+        Set<Fact> resultsSoFar = getFacts();
+        for (Fact newFact : resultsSoFar) {
+            processFact(newFact);
+        }
+        newFacts.addAll(resultsSoFar);
+    }
+
+    /**
+     * Process a triple in which this node is the subject.
+     */
+    private void processOutgoing(Fact fact) {
+        URI predURI = fact.getPredicate();
+        Value object = fact.getObject();
+        OwlProperty prop = schema.getProperty(predURI);
+        Set<Resource> restrictions = prop.getRestrictions();
+        Set<URI> disjointProps = prop.getDisjointProperties();
+        // RL rule prp-dom: Apply domain(s), if appropriate
+        for (Resource type : prop.getDomain()) {
+            types.processType(type, OwlRule.PRP_DOM, fact);
+        }
+        // RL rule prp-spo1: assert superproperties
+        // Assume we have the full property hierarchy in the schema, so that
+        // if the input fact was derived using this rule, we must have  gotten
+        // all the superproperties and don't need to apply them again.
+        if (!fact.hasRule(OwlRule.PRP_SPO1)) {
+            for (URI superProp : prop.getSuperProperties()) {
+                // (everything is its own superproperty)
+                if (superProp.equals(predURI)) {
+                    continue;
+                }
+                collect(triple(node, superProp, object, OwlRule.PRP_SPO1, 
fact));
+            }
+        }
+        // RL rule prp-pdw: Check if this conflicts with any disjoint 
properties
+        if (!disjointProps.isEmpty()) {
+            for (URI disjointProp : disjointProps) {
+                if (disjointOutgoing.containsKey(disjointProp)) {
+                    for (Fact other : disjointOutgoing.get(disjointProp)) {
+                        if (object.equals(other.getObject())) {
+                            Derivation pdwFact = 
inconsistency(OwlRule.PRP_PDW, fact);
+                            pdwFact.addSource(other);
+                            collectInconsistency(pdwFact);
+                        }
+                    }
+                }
+            }
+            if (!disjointOutgoing.containsKey(predURI)) {
+                disjointOutgoing.put(predURI, new LinkedList<Fact>());
+            }
+            disjointOutgoing.get(predURI).add(fact);
+        }
+        // Property restriction rules:
+        for (Resource rNode : restrictions) {
+            OwlClass restriction = schema.getClass(rNode);
+            // RL rule cls-svf2: if (?x owl:someValuesFrom owl:Thing)
+            if (restriction.someValuesFrom().contains(OWL.THING)) {
+                // If there are any property restrictions stating that class
+                // x is equivalent to having someValuesFrom owl:Thing for this
+                // property, then this node is a member of type x
+                types.processType(rNode, OwlRule.CLS_SVF2, fact);
+            }
+            // RL rule cls-hv2: if (?x owl:hasValue <object>)
+            if (restriction.hasValue().contains(object)) {
+                //... then node (subject) satisfies/belongs to x
+                types.processType(rNode, OwlRule.CLS_HV2, fact);
+            }
+            // RL rule cls-avf: if x=[allValuesFrom ?c onProperty ?p]:
+            for (Resource c : restriction.allValuesFrom()) {
+                // If/when we learn this node is supposed to satisfy this
+                // restriction, and if object is a resource, assert
+                // (object type c).
+                if (object instanceof Resource) {
+                    types.onType(rNode, triple((Resource) object, RDF.TYPE,
+                        c, OwlRule.CLS_AVF, fact));
+                }
+            }
+            // RL rule cls-maxc1: if x=[maxCardinality 0], subject can't be x
+            if (restriction.getMaxCardinality() == 0) {
+                types.inconsistentOnType(rNode,
+                    inconsistency(OwlRule.CLS_MAXC1, fact));
+            }
+            // RL rule cls-maxqc2: x=[maxQualifiedCardinality 0 on owl:Thing]
+            // (same as maxCardinality 0)
+            if (restriction.getMaxQualifiedCardinality() == 0
+                && restriction.onClass().contains(OWL.THING)) {
+                types.inconsistentOnType(rNode,
+                    inconsistency(OwlRule.CLS_MAXQC2, fact));
+            }
+        }
+        // RL rule prp-trp (part 1/2): Apply against incoming statements
+        // with the same predicate (skip if this node is both the subject and
+        // object) .
+        // Assumes that input is sorted with incoming coming first, so we don't
+        // need to store this triple after joining.
+        if (prop.isTransitive() && !object.equals(node)
+            && checkTransitivityOutgoing(fact)) {
+            if (transitiveIncoming.containsKey(predURI)) {
+                for (Fact other : transitiveIncoming.get(predURI)) {
+                    Resource otherSubject = other.getSubject();
+                    Fact trpFact = triple(otherSubject, predURI, object,
+                        OwlRule.PRP_TRP, fact);
+                    trpFact.addSource(other);
+                    collect(trpFact);
+                }
+            }
+        }
+        // RL rule prp-asyp (part 2/2): Check against incoming statements with
+        // the same predicate. Don't store this one since we assume input is
+        // sorted by the direction of the edge.
+        if (prop.isAsymmetric() && asymmetricIncoming.containsKey(predURI)) {
+            for (Fact other : asymmetricIncoming.get(predURI)) {
+                if (object.equals(other.getSubject())) {
+                    Derivation asypFact = inconsistency(OwlRule.PRP_ASYP, 
fact);
+                    asypFact.addSource(other);
+                    collectInconsistency(asypFact);
+                }
+            }
+        }
+    }
+
+    /**
+     * Process a triple in which this node is the object.
+     */
+    private void processIncoming(Fact fact) {
+        Resource subject = fact.getSubject();
+        URI predURI = fact.getPredicate();
+        OwlProperty prop = schema.getProperty(predURI);
+        // RL rule prp-rng: Apply range(s), if appropriate
+        for (Resource type : prop.getRange()) {
+            types.processType(type, OwlRule.PRP_RNG, fact);
+        }
+        // RL rules prp-inv1, prp-inv2: assert any inverse properties
+        for (URI inverseProp : prop.getInverseProperties()) {
+            collect(triple(node, inverseProp, subject, OwlRule.PRP_INV, fact));
+        }
+        // RL rule prp-symp: Assert the symmetric statement if appropriate
+        if (prop.isSymmetric()
+            && !fact.hasRule(OwlRule.PRP_SYMP)
+            && !subject.equals(node)) {
+            collect(triple(node, predURI, subject, OwlRule.PRP_SYMP, fact));
+        }
+        // RL rule prp-irp: (x p x) is inconsistent if p is irreflexive
+        if (prop.isIrreflexive() && subject.equals(node)) {
+            collectInconsistency(inconsistency(OwlRule.PRP_IRP, fact));
+        }
+        // RL rule prp-trp (part 1/2): We assume triples are sorted with
+        // incoming first, so store this triple in case it needs to be joined
+        // with any later outgoing triples with the same property.
+        if (prop.isTransitive() && !subject.equals(node)
+            && checkTransitivityIncoming(fact)) {
+            if (!transitiveIncoming.containsKey(predURI)) {
+                transitiveIncoming.put(predURI, new LinkedList<Fact>());
+            }
+            transitiveIncoming.get(predURI).add(fact);
+        }
+        // RL rule prp-asyp (part 1/2): Store this incoming edge so we can
+        // compare later outgoing edges against it. (Assume sorted input.)
+        if (prop.isAsymmetric()) {
+            if (!asymmetricIncoming.containsKey(predURI)) {
+                asymmetricIncoming.put(predURI, new LinkedList<Fact>());
+            }
+            asymmetricIncoming.get(predURI).add(fact);
+        }
+        for (Resource rNode : prop.getRestrictions()) {
+            OwlClass restriction = schema.getClass(rNode);
+            // RL rule cls-svf1: Check for a someValuesFrom restriction
+            Set<Resource> valuesFrom = restriction.someValuesFrom();
+            // type owl:Thing would be checked by cls-svf2
+            valuesFrom.remove(OWL.THING);
+            for (Resource commonType : valuesFrom) {
+                // If we learn the type, assert the other node's membership in 
rNode
+                types.onType(commonType, triple(subject, RDF.TYPE,
+                    rNode, OwlRule.CLS_SVF1, fact));
+            }
+        }
+    }
+
+    /**
+     * Collect all the derived type information in a single ResultSet.
+     */
+    public void getTypes() {
+        types.collectTypes();
+        newFacts.addAll(types.getFacts());
+    }
+
+    /**
+     * Determine whether an inconsistency has been found.
+     */
+    @Override
+    public boolean hasInconsistencies() {
+        return types.hasInconsistencies() || !inconsistencies.isEmpty();
+    }
+
+    /**
+     * Get results, including those stored in the TypeReasoner.
+     */
+    @Override
+    public Set<Fact> getFacts() {
+        Set<Fact> results = types.getFacts();
+        if (hasNewFacts()) {
+            results.addAll(newFacts);
+            newFacts.clear();
+        }
+        // If we can mark some facts as not needing to be processed during the
+        // next step, do so:
+        for (Fact result : results) {
+            result.setUseful(relevantToFuture(result));
+        }
+        return results;
+    }
+
+    /**
+     * Get inconsistencies, including those stored in the TypeReasoner.
+     */
+    @Override
+    public Set<Derivation> getInconsistencies() {
+        Set<Derivation> results = types.getInconsistencies();
+        if (hasInconsistencies()) {
+            results.addAll(inconsistencies);
+            inconsistencies.clear();
+        }
+        return results;
+    }
+
+    /**
+     * Get some diagnostic info for logging purposes.
+     */
+    @Override
+    public String getDiagnostics() {
+        // Count the different types of triples in memory:
+        int sumIncomingAsymmetric = 0;
+        int sumOutgoingDisjoint = 0;
+        int sumIncomingTransitive = 0;
+        for (List<Fact> l : asymmetricIncoming.values()) {
+            sumIncomingAsymmetric += l.size();;
+        }
+        for (List<Fact> l : disjointOutgoing.values()) {
+            sumOutgoingDisjoint += l.size();;
+        }
+        int maxTransitiveSpan = (int) Math.pow(2, currentIteration);
+        int[] distribution = new int[maxTransitiveSpan+1];
+        for (int i = 0; i <= maxTransitiveSpan; i++) {
+            distribution[i] = 0;
+        }
+        for (List<Fact> l : transitiveIncoming.values()) {
+            for (Fact fact : l) {
+                sumIncomingTransitive++;
+                int x = fact.span();
+                if (x > 0 && x <= maxTransitiveSpan) {
+                    distribution[x]++;
+                }
+                else {
+                    distribution[0]++;
+                }
+            }
+        }
+
+        // Collect totals:
+        StringBuilder sb = new StringBuilder();
+        sb.append("Node: ").append(node.stringValue()).append("\n");
+        sb.append(newFacts.size()).append(" new triples stored\n");
+        sb.append(sumIncomingAsymmetric).append(" stored incoming triples w/ 
");
+        sb.append(asymmetricIncoming.size()).append(" asymmetric 
properties\n");
+        sb.append(sumOutgoingDisjoint).append(" stored outgoing triples w/ ");
+        sb.append(disjointOutgoing.size()).append(" disjoint properties\n");
+        sb.append(sumIncomingTransitive).append(" stored incoming triples w/ 
");
+        sb.append(transitiveIncoming.size()).append(" transitive 
properties\n");
+        sb.append("Span of stored transitive triples:\n");
+        for (int i = 0; i <= maxTransitiveSpan; i++) {
+            sb.append("    ").append(i).append(": ").append(distribution[i]);
+            sb.append("\n");
+        }
+        sb.append(types.getDiagnostics());
+        return sb.toString();
+    }
+
+    /**
+     * Get the total number of input facts cached.
+     */
+    @Override
+    public int getNumStored() {
+        int total = 0;
+        for (List<Fact> l : asymmetricIncoming.values()) {
+            total += l.size();;
+        }
+        for (List<Fact> l : disjointOutgoing.values()) {
+            total += l.size();;
+        }
+        for (List<Fact> l : transitiveIncoming.values()) {
+            total += l.size();
+        }
+        return total + types.getNumStored();
+    }
+
+    /**
+     * Determine whether transitivity should be applied to an incoming triple.
+     * Decide based on the distance of the relationship. For any length l, 
there
+     * should be a unique split l1 and l2 such that any connection of length l
+     * will be made only by combining a left-hand/incoming connection of length
+     * l1 and a right-hand/outgoing connection of length l2.
+     */
+    boolean checkTransitivityIncoming(Fact fact) {
+        return fact.span() >= minTransitiveLeft;
+    }
+
+    /**
+     * Determine whether transitivity should be applied to an outgoing triple.
+     * Decide based on the distance of the relationship. For any length l, 
there
+     * should be a unique split l1 and l2 such that any connection of length l
+     * will be made only by combining a left-hand/incoming connection of length
+     * l1 and a right-hand/outgoing connection of length l2.
+     */
+    boolean checkTransitivityOutgoing(Fact fact) {
+        return fact.span() >= minTransitiveRight;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OWL2.java
----------------------------------------------------------------------
diff --git a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OWL2.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OWL2.java
new file mode 100644
index 0000000..a4492e3
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OWL2.java
@@ -0,0 +1,38 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.openrdf.model.URI;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.OWL;
+
+/**
+ * Some useful OWL 2 URIs not in Sesame API.
+ */
+public class OWL2 {
+    private static URI uri(String local) {
+        return ValueFactoryImpl.getInstance().createURI(OWL.NAMESPACE, local);
+    }
+    public static final URI ASYMMETRICPROPERTY = uri("AsymmetricProperty");
+    public static final URI IRREFLEXIVEPROPERTY = uri("IrreflexiveProperty");
+    public static final URI PROPERTYDISJOINTWITH = uri("propertyDisjointWith");
+    public static final URI ONCLASS = uri("onClass");
+    public static final URI MAXQUALIFIEDCARDINALITY = 
uri("maxQualifiedCardinality");
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlClass.java
----------------------------------------------------------------------
diff --git a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlClass.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlClass.java
new file mode 100644
index 0000000..64a19ba
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlClass.java
@@ -0,0 +1,489 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.vocabulary.OWL;
+
+/**
+ * Contains all the schema information we might need about a class.
+ * <p>
+ * Rules applied dynamically by getter methods:
+ * <ul>
+ * <li>
+ * scm-cls  States that every class is its own subclass and equivalent class,
+ *          and is a subclass of owl:Thing. These facts are included by
+ *          getSuperClasses and getEquivalentClasses. (It also states that
+ *          owl:Nothing is a subclass of every class).
+ * <li>
+ * scm-eqc1 States that if two classes are equivalent, they are also
+ *          subclasses. Equivalence is represented using subclass relations
+ *          internally.
+ * <li>
+ * scm-eqc2 States that if two classes are each other's subclasses, they are
+ *          also equivalent classes.
+ * </ul>
+ * Rules applied by explicitly calling methods once all data has been read in:
+ * <ul>
+ * <p>
+ * <li>
+ * scm-sco  States that subClassOf is transitive. Computed by
+ *          computeSuperClasses().
+ * </ul>
+ */
+public class OwlClass implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private Resource uri;
+
+    // Relations to other classes:
+    private Set<OwlClass> superClasses = new HashSet<>();
+    private Set<OwlClass> disjointClasses = new HashSet<>();
+    private Set<OwlClass> complementaryClasses = new HashSet<>();
+
+    // If this class is referenced by property restrictions:
+    private Set<OwlClass> svfRestrictions = new HashSet<>();
+    private Set<OwlClass> avfRestrictions = new HashSet<>();
+    private Set<OwlClass> qcRestrictions = new HashSet<>();
+
+    // If this is a property restriction, Which propert(y/ies) does it apply 
to?
+    Set<OwlProperty> properties = new HashSet<OwlProperty>();
+    // These represent the semantics of the restriction:
+    Set<OwlClass> svfClasses = new HashSet<>();
+    Set<OwlClass> avfClasses = new HashSet<>();
+    Set<OwlClass> qcClasses = new HashSet<>();
+    Set<Value> values = new HashSet<>();
+    int maxCardinality = -1;
+    int maxQualifiedCardinality = -1;
+
+    OwlClass(Resource uri) {
+        this.uri = uri;
+    }
+
+    public Resource getURI() { return uri; }
+    public void setURI(Resource uri) { this.uri = uri; }
+
+    /**
+     * Add a superclass
+     */
+    boolean addSuperClass(OwlClass c) {
+        return superClasses.add(c);
+    }
+
+    /**
+     * Add an equivalent class
+     * RL rule scm-eqc1: Store equivalence as mutual subClassOf relations
+     */
+    boolean addEquivalentClass(OwlClass c) {
+        boolean change = superClasses.add(c);
+        change = c.superClasses.add(this) || change;
+        return change;
+    }
+    /**
+     * Add a disjoint class
+     */
+    boolean addDisjoint(OwlClass c) { return disjointClasses.add(c); }
+    /**
+     * Add a complementary class
+     */
+    boolean addComplement(OwlClass c) { return complementaryClasses.add(c); }
+    /**
+     * Add a someValuesFrom restriction on this class
+     */
+    boolean addSvfRestriction(OwlClass r) { return svfRestrictions.add(r); }
+    /**
+     * Add an allValuesFrom restriction on this class
+     */
+    boolean addAvfRestriction(OwlClass r) { return avfRestrictions.add(r); }
+    /**
+     * Add a qualified cardinality restriction on this class
+     */
+    boolean addQCRestriction(OwlClass r) { return qcRestrictions.add(r); }
+
+    /**
+     * Apply RL rule scm-sco: subClassOf transitivity.
+     * Follows subClassOf chains to compute all the ancestor classes. Assumes
+     * the hierarchy is small enough that a simple BFS is fine.
+     * @return  Whether new information was discovered
+     */
+    boolean computeSuperClasses() {
+        Set<OwlClass> ancestors = new HashSet<OwlClass>();
+        Set<OwlClass> frontier = new HashSet<OwlClass>(superClasses);
+        while (!frontier.isEmpty()) {
+            Set<OwlClass> next = new HashSet<OwlClass>();
+            for (OwlClass ancestor : frontier) {
+                // This node is an ancestor; it's parents should be explored 
next
+                ancestors.add(ancestor);
+                next.addAll(ancestor.superClasses);
+            }
+            // Don't revisit nodes
+            next.removeAll(ancestors);
+            frontier = next;
+        }
+        boolean newInfo = !ancestors.equals(superClasses);
+        superClasses = ancestors;
+        return newInfo;
+    }
+
+    /**
+     * Add all of this class' ancestors to the domain of a given property.
+     */
+    void inheritDomains(OwlProperty prop) {
+        for (OwlClass superclass : this.superClasses) {
+            prop.addDomain(superclass);
+        }
+    }
+
+    /**
+     * Add all of this class' ancestors to the range of a given property.
+     */
+    void inheritRanges(OwlProperty prop) {
+        for (OwlClass superclass : this.superClasses) {
+            prop.addRange(superclass);
+        }
+    }
+
+    /**
+     * Add "onProperty p" information, and tell p to point back here.
+     */
+    public boolean addProperty(OwlProperty property) {
+        property.addRestriction(this);
+        return properties.add(property);
+    }
+
+    /**
+     * Add "someValuesFrom c" information, and tell c to point back here.
+     */
+    public boolean addSvf(OwlClass targetClass) {
+        targetClass.addSvfRestriction(this);
+        return svfClasses.add(targetClass);
+    }
+
+    /**
+     * Add "allValuesFrom c" information, and tell c to point back here.
+     */
+    public boolean addAvf(OwlClass targetClass) {
+        targetClass.addAvfRestriction(this);
+        return avfClasses.add(targetClass);
+    }
+
+    /**
+     * Add "onClass c" information, and tell c to point back here.
+     */
+    public boolean addClass(OwlClass targetClass) {
+        targetClass.addQCRestriction(this);
+        return qcClasses.add(targetClass);
+    }
+
+    /**
+     * Add "hasValue v" information.
+     */
+    public boolean addValue(Value v) {
+        return values.add(v);
+    }
+
+    /**
+     * Set a maxCardinality.
+     */
+    public boolean setMaxCardinality(Value v) {
+        int mc = Integer.parseInt(v.stringValue());
+        if (maxCardinality < 0 || mc < maxCardinality) {
+            maxCardinality = mc;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Set maxQualifiedCardinality.
+     */
+    public boolean setMaxQualifiedCardinality(Value v) {
+        int mqc = Integer.parseInt(v.stringValue());
+        if (maxQualifiedCardinality < 0 || mqc < maxQualifiedCardinality) {
+            maxQualifiedCardinality = mqc;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Get all the superclasses of this subclass. Includes self and owl:Thing.
+     */
+    public Set<Resource> getSuperClasses() {
+        Set<Resource> ancestors = new HashSet<>();
+        for (OwlClass ancestor : superClasses) {
+            ancestors.add(ancestor.uri);
+        }
+        // RL rule scm-cls: Every class is a subclass of itself and owl:Thing
+        ancestors.add(this.uri);
+        ancestors.add(OWL.THING);
+        return ancestors;
+    }
+
+    /**
+     * Get all the equivalent classes, meaning those who are both subclasses
+     * and superclasses of this one.
+     */
+    public Set<Resource> getEquivalentClasses() {
+        // RL rule scm-eqc2: mutual subClassOf relations imply equivalentClass
+        Set<Resource> equivalents = new HashSet<>();
+        for (OwlClass other : superClasses) {
+            if (other.superClasses.contains(this)) {
+                equivalents.add(other.uri);
+            }
+        }
+        // RL rule scm-cls: Every class is its own equivalent
+        equivalents.add(this.uri);
+        return equivalents;
+    }
+
+    /**
+     * Get all classes declared disjoint with this one.
+     */
+    public Set<Resource> getDisjointClasses() {
+        Set<Resource> disjoint = new HashSet<>();
+        for (OwlClass other : disjointClasses) {
+            disjoint.add(other.uri);
+        }
+        return disjoint;
+    }
+
+    /**
+     * Get all classes declared complement to a specific class.
+     */
+    public Set<Resource> getComplementaryClasses() {
+        Set<Resource> complements = new HashSet<>();
+        for (OwlClass other : complementaryClasses) {
+            complements.add(other.uri);
+        }
+        return complements;
+    }
+
+    /**
+     * Get all someValuesFrom restrictions on this class
+     */
+    public Set<Resource> getSvfRestrictions() {
+        Set<Resource> restrictions = new HashSet<>();
+        for (OwlClass r : svfRestrictions) {
+            restrictions.add(r.getURI());
+        }
+        return restrictions;
+    }
+
+    /**
+     * Get all allValuesFrom restrictions on this class
+     */
+    public Set<Resource> getAvfRestrictions() {
+        Set<Resource> restrictions = new HashSet<>();
+        for (OwlClass r : avfRestrictions) {
+            restrictions.add(r.getURI());
+        }
+        return restrictions;
+    }
+
+    /**
+     * Get all onClass (qualified cardinality) restrictions on this class
+     */
+    public Set<Resource> getQCRestrictions() {
+        Set<Resource> restrictions = new HashSet<>();
+        for (OwlClass r : qcRestrictions) {
+            restrictions.add(r.getURI());
+        }
+        return restrictions;
+    }
+
+    /**
+     * Get the onProperty relation(s) for this property restriction.
+     */
+    public Set<URI> getOnProperty() {
+        Set<URI> onp = new HashSet<>();
+        for (OwlProperty prop : properties) {
+            onp.add(prop.getURI());
+        }
+        return onp;
+    }
+
+    /**
+     * Get all someValuesFrom relations for this property restriction.
+     */
+    public Set<Resource> someValuesFrom() {
+        Set<Resource> targets = new HashSet<>();
+        for (OwlClass c : svfClasses) {
+            targets.add(c.getURI());
+        }
+        return targets;
+    }
+
+    /**
+     * Get all allValuesFrom relations for this property restriction.
+     */
+    public Set<Resource> allValuesFrom() {
+        Set<Resource> targets = new HashSet<>();
+        for (OwlClass c : avfClasses) {
+            targets.add(c.getURI());
+        }
+        return targets;
+    }
+
+    /**
+     * Get all onClass relations for this property restriction.
+     */
+    public Set<Resource> onClass() {
+        Set<Resource> targets = new HashSet<>();
+        for (OwlClass c : qcClasses) {
+            targets.add(c.getURI());
+        }
+        return targets;
+    }
+
+    /**
+     * Get all hasValue relations for this property restriction.
+     */
+    public Set<Value> hasValue() { return new HashSet<Value>(values); }
+
+    /**
+     * Get the maxCardinality. Negative means it was not specified, otherwise
+     * returns the lowest value ever given.
+     */
+    public int getMaxCardinality() { return maxCardinality; }
+
+    /**
+     * Get the maxQualifiedCardinality. Negative means it was not specified,
+     * otherwise returns the lowest value ever given.
+     */
+    public int getMaxQualifiedCardinality() { return maxQualifiedCardinality; }
+
+    /**
+     * Compares someValuesFrom target classes, and returns true if this one's
+     * is a subclass of the other's.
+     */
+    boolean svfSubClass(OwlClass other) {
+        for (OwlClass svfClass : this.svfClasses) {
+            Set<Resource> intersection = svfClass.getSuperClasses();
+            intersection.retainAll(other.someValuesFrom());
+            if (!intersection.isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Compares someValuesFrom target classes, and returns true if this one's
+     * is a subclass of the other's.
+     */
+    boolean avfSubClass(OwlClass other) {
+        for (OwlClass avfClass : this.avfClasses) {
+            Set<Resource> intersection = avfClass.getSuperClasses();
+            intersection.retainAll(other.allValuesFrom());
+            if (!intersection.isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Compares onProperty properties, and returns true if this one's
+     * is a subproperty of the other's.
+     */
+    boolean onSubProperty(OwlClass other) {
+        Set<URI> otherProp = other.getOnProperty();
+        for (OwlProperty prop : this.properties) {
+            Set<URI> intersection = prop.getSuperProperties();
+            intersection.retainAll(otherProp);
+            if (!intersection.isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Apply property restriction rules that involve the same class/value
+     * and properties related by subPropertyOf.
+     * RL rule scm-hv: [subprop hasValue] subClassOf [superprop hasValue]
+     * RL rule scm-svf2: [subprop someValuesFrom x] subClassOf [superprop 
someValuesFrom x]
+     * RL rule scm-avf2: [superprop allValuesFrom x] subClassOf [subprop 
allValuesFrom x]
+     * Doesn't check subproperty transitivity.
+     * @return  Whether any information was generated
+     */
+    boolean compareRestrictions(OwlClass other) {
+        boolean newInfo = false;
+        // These rules apply iff the restrictions are on subprop and superprop
+        if (this.onSubProperty(other)) {
+            // scm-hv
+            Set<Value> sharedValues = new HashSet<>(this.values);
+            sharedValues.retainAll(other.values);
+            if (!sharedValues.isEmpty()) {
+                newInfo = this.addSuperClass(other) || newInfo;
+            }
+            else {
+                // scm-svf2
+                // (same result as scm-hv, no need to derive twice)
+                Set<OwlClass> sharedSvf = new HashSet<>(this.svfClasses);
+                sharedSvf.retainAll(other.svfClasses);
+                if (!sharedSvf.isEmpty()) {
+                    newInfo = this.addSuperClass(other) || newInfo;
+                }
+            }
+            // scm-avf2
+            // (applies in the other direction)
+            Set<OwlClass> sharedAvf = new HashSet<>(this.avfClasses);
+            sharedAvf.retainAll(other.avfClasses);
+            if (!sharedAvf.isEmpty()) {
+                newInfo = other.addSuperClass(this) || newInfo;
+            }
+        }
+        return newInfo;
+    }
+
+    /**
+     * Get all superclasses of the target(s) of any someValuesFrom relations
+     * this class has, including the target class itself and any transitive
+     * superclasses.
+     */
+    Set<Resource> getSvfSuperClasses() {
+        Set<Resource> svfSuperClasses = new HashSet<>();
+        for (OwlClass svfClass : svfClasses) {
+            svfSuperClasses.addAll(svfClass.getSuperClasses());
+        }
+        return svfSuperClasses;
+    }
+
+    /**
+     * Get all superclasses of the target(s) of any allValuesFrom relations
+     * this class has, including the target class itself and any transitive
+     * superclasses.
+     */
+    Set<Resource> getAvfSuperClasses() {
+        Set<Resource> avfSuperClasses = new HashSet<>();
+        for (OwlClass avfClass : avfClasses) {
+            avfSuperClasses.addAll(avfClass.getSuperClasses());
+        }
+        return avfSuperClasses;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlProperty.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlProperty.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlProperty.java
new file mode 100644
index 0000000..ed0a3f3
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlProperty.java
@@ -0,0 +1,309 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+
+/**
+ * Contains all the schema information we might need about a property.
+ *
+ * Rules implemented dynamically by getter methods:
+ *
+ * scm-op   States that every object property is its own subproperty and
+ *          equivalent property.
+ * scm-dp   States that every datatype property is its own subproperty and
+ *          equivalent property.
+ * scm-eqp1 States that if two properties are equivalent, they are also
+ *          subproperties. Equivalence is represented this way internally.
+ * scm-eqp2 States that if two properties are each other's subproperties,
+ *          they are also equivalent properties.
+ *
+ * Rules implemented explicitly by calling methods once all the necessary data
+ * has been read in:
+ *
+ * scm-spo  States that subPropertyOf is transitive; computed by
+ *          computeSuperProperties().
+ * scm-dom1 States that a property with domain c also has as domain any
+ *          of c's superclasses. Computed in inheritDomainRange().
+ * scm-dom2 States that a property inherits its superproperties' domains.
+ *          Computed in inheritDomainRange().
+ * scm-rng1 States that a property with range c also has as domain any
+ *          of c's superclasses. Computed in inheritDomainRange().
+ * scm-rng2 States that a property inherits its superproperties' ranges.
+ *          Computed in inheritDomainRange().
+ * svm-svf1 States that property restriction c1 is a subclass of another c2 if
+ *          they are someValuesFrom restrictions on the same property where
+ *          c1's target class is a subclass of c2's target class.
+ *          Computed in compareRestrictions(), depends on subclass info.
+ * svm-avf1 States that property restriction c1 is a subclass of another c2 if
+ *          they are allValuesFrom restrictions on the same property where
+ *          c1's target class is a subclass of c2's target class.
+ *          Computed in compareRestrictions(), depends on subclass info.
+ */
+public class OwlProperty implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private URI uri;
+
+    // Boolean qualities the property might have
+    private boolean transitive = false;
+    private boolean symmetric = false;
+    private boolean asymmetric = false;
+    private boolean functional = false;
+    private boolean inverseFunctional = false;
+    private boolean irreflexive = false;
+
+    // Relations to other properties
+    private Set<OwlProperty> superProperties = new HashSet<OwlProperty>();
+    private Set<OwlProperty> disjointProperties = new HashSet<OwlProperty>();
+    private Set<OwlProperty> inverseProperties = new HashSet<OwlProperty>();
+
+    // Relations to classes
+    private Set<OwlClass> domain = new HashSet<OwlClass>();
+    private Set<OwlClass> range = new HashSet<OwlClass>();
+
+    // Restrictions on this property
+    private Set<OwlClass> restrictions = new HashSet<OwlClass>();
+
+    OwlProperty(URI uri) {
+        this.uri = uri;
+    }
+
+    boolean addSuperProperty(OwlProperty p) {
+        return superProperties.add(p);
+    }
+
+    /**
+     * Add an equivalient property
+     * RL rule scm-eqp1: Store equivalence as mutual subPropertyOf relations
+     */
+    boolean addEquivalentProperty(OwlProperty p) {
+        boolean change = this.superProperties.add(p);
+        change = p.superProperties.add(this) || change;
+        return change;
+    }
+
+    boolean addDisjoint(OwlProperty p) { return disjointProperties.add(p); }
+    boolean addInverse(OwlProperty p) { return inverseProperties.add(p); }
+    boolean addDomain(OwlClass c) {
+        return domain.add(c);
+    }
+    boolean addRange(OwlClass c) {
+        return range.add(c);
+    }
+    boolean addRestriction(OwlClass r) { return restrictions.add(r); }
+
+    public void setURI(URI uri) { this.uri = uri; }
+    void setTransitive() { transitive = true; }
+    void setSymmetric() { symmetric = true; }
+    void setAsymmetric() { asymmetric = true; }
+    void setFunctional() { functional = true; }
+    void setInverseFunctional() { inverseFunctional = true; }
+    void setIrreflexive() { irreflexive = true; }
+
+    public URI getURI() { return uri; }
+    public boolean isTransitive() { return transitive; }
+    public boolean isSymmetric() { return symmetric; }
+    public boolean isAsymmetric() { return asymmetric; }
+    public boolean isFunctional() { return functional; }
+    public boolean isInverseFunctional() { return inverseFunctional; }
+    public boolean isIrreflexive() { return irreflexive; }
+
+    /**
+     * Apply RL rule scm-spo: subPropertyOf transitivity.
+     * Follows subPropertyOf chains to compute all the ancestor properties.
+     * Assumes the hierarchy is small enough that a simple BFS is fine.
+     * @return  Whether new information was discovered
+     */
+    boolean computeSuperProperties() {
+        Set<OwlProperty> ancestors = new HashSet<OwlProperty>();
+        Set<OwlProperty> frontier = new HashSet<OwlProperty>(superProperties);
+        while (!frontier.isEmpty()) {
+            Set<OwlProperty> next = new HashSet<OwlProperty>();
+            for (OwlProperty ancestor : frontier) {
+                // This node is an ancestor; it's parents should be explored 
next
+                ancestors.add(ancestor);
+                next.addAll(ancestor.superProperties);
+            }
+            // Don't revisit nodes
+            next.removeAll(ancestors);
+            frontier = next;
+        }
+        boolean newInfo = !ancestors.equals(superProperties);
+        superProperties = ancestors;
+        return newInfo;
+    }
+
+    /**
+     * Infer domain and range from parents' domains and ranges. Only looks at
+     * those superproperties that are explicitly known; computeSuperProperties
+     * should generally be called first to get the full closure.
+     */
+    void inheritDomainRange() {
+        //RL rule scm-dom2: (p2 domain c) && (p1 subPropertyOf p2) -> (p1 
domain c)
+        //RL rule scm-rng2: (p2 range c) && (p1 subPropertyOf p2) -> (p1 range 
c)
+        for (OwlProperty ancestorProperty : superProperties) {
+            for (OwlClass c : ancestorProperty.domain) {
+                addDomain(c);
+            }
+            for (OwlClass c : ancestorProperty.range) {
+                addRange(c);
+            }
+        }
+        //RL rule scm-dom1: (p domain c1) && (c1 subClassOf c2) -> (p domain 
c2)
+        for (OwlClass domainClass : new HashSet<OwlClass>(this.domain)) {
+            domainClass.inheritDomains(this);
+        }
+        //RL rule scm-rng1: (p range c1) && (c1 subClassOf c2) -> (p range c2)
+        for (OwlClass rangeClass : new HashSet<OwlClass>(this.range)) {
+            rangeClass.inheritRanges(this);
+        }
+    }
+
+    /**
+     * Get all the superproperties of this subproperty.
+     */
+    public Set<URI> getSuperProperties() {
+        Set<URI> ancestors = new HashSet<>();
+        for (OwlProperty ancestor : superProperties) {
+            ancestors.add(ancestor.uri);
+        }
+        // RL rules scm-op & scm-dp: Every property is a subproperty of itself
+        ancestors.add(this.uri);
+        return ancestors;
+    }
+
+    /**
+     * Get all the equivalent properties for this property.
+     * Apply RL rules scm-op and scm-dp: Every property is its own equivalent.
+     */
+    public Set<URI> getEquivalentProperties() {
+        Set<URI> equivalents = new HashSet<>();
+        for (OwlProperty other : superProperties) {
+            if (other.superProperties.contains(this)) {
+                equivalents.add(other.uri);
+            }
+        }
+        // RL rules scm-op & scm-dp: Every property is equivalent to itself
+        equivalents.add(this.uri);
+        return equivalents;
+    }
+
+    /**
+     * Get all properties declared disjoint with this one.
+     */
+    public Set<URI> getDisjointProperties() {
+        Set<URI> disjoint = new HashSet<>();
+        for (OwlProperty other : disjointProperties) {
+            disjoint.add(other.uri);
+        }
+        return disjoint;
+    }
+
+    /**
+     * Get all properties declared inverse of this one.
+     */
+    public Set<URI> getInverseProperties() {
+        Set<URI> inverse = new HashSet<>();
+        for (OwlProperty other : inverseProperties) {
+            inverse.add(other.uri);
+        }
+        return inverse;
+    }
+
+    /**
+     * Get the domain (set of class URIs/Resources).
+     */
+    public Set<Resource> getDomain() {
+        Set<Resource> domain = new HashSet<>();
+        for (OwlClass d : this.domain) {
+            domain.add(d.getURI());
+        }
+        return domain;
+    }
+
+    /**
+     * Get the range (set of class URIs/Resources).
+     */
+    public Set<Resource> getRange() {
+        Set<Resource> range = new HashSet<>();
+        for (OwlClass r : this.range) {
+            range.add(r.getURI());
+        }
+        return range;
+    }
+
+    /**
+     * Get the property restrictions relevant to this property.
+     */
+    public Set<Resource> getRestrictions() {
+        Set<Resource> restrictions = new HashSet<>();
+        for (OwlClass pr : this.restrictions) {
+            restrictions.add(pr.getURI());
+        }
+        return restrictions;
+    }
+
+    /**
+     * Apply property restriction rules that involve the same property.
+     * RL rule scm-svf1: [someValuesFrom sub] subClassOf [someValuesFrom super]
+     * RL rule scm-avf1: [allValuesFrom sub] subClassOf [allValuesFrom super]
+     * Doesn't check subclass transitivity.
+     * @return  Whether any information was generated
+     */
+    public boolean compareRestrictions() {
+        boolean newInfo = false;
+        for (OwlClass c1 : restrictions) {
+            // Get all superclasses of this restriction's avf target class(es)
+            // and avf target classes.
+            Set<Resource> avfSuperClasses = c1.getAvfSuperClasses();
+            Set<Resource> svfSuperClasses = c1.getSvfSuperClasses();
+            if (avfSuperClasses.isEmpty() && svfSuperClasses.isEmpty()) {
+                continue;
+            }
+            // Compare each other restriction's avf and svf targets to the
+            // appropriate set of superclasses.
+            for (OwlClass c2 : restrictions) {
+                //svm-svf1, svm-avf1
+                if (c1 != c2) {
+                    Set<Resource> avf2 = c2.allValuesFrom();
+                    avf2.retainAll(avfSuperClasses);
+                    if (avf2.isEmpty()) {
+                        Set<Resource> svf2 = c2.someValuesFrom();
+                        svf2.retainAll(svfSuperClasses);
+                        if (svf2.isEmpty()) {
+                            continue;
+                        }
+                    }
+                    // If c2's target is one of the parent classes of c1's
+                    // target, then c2 is a more general version of c1 and
+                    // therefore a superclass of c1.
+                    newInfo = c1.addSuperClass(c2) || newInfo;
+                }
+            }
+        }
+        return newInfo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/01489efb/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlRule.java
----------------------------------------------------------------------
diff --git a/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlRule.java 
b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlRule.java
new file mode 100644
index 0000000..efdb628
--- /dev/null
+++ b/extras/rya.reasoning/src/main/java/mvm/rya/reasoning/OwlRule.java
@@ -0,0 +1,78 @@
+package mvm.rya.reasoning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Represents the OWL RL/RDF rules used in reasoning.
+ */
+public enum OwlRule {
+    // Schema rules, handled by Schema:
+    SCM_CLS,
+    SCM_SCO,
+    SCM_EQC1,
+    SCM_EQC2,
+    SCM_OP,
+    SCM_DP,
+    SCM_SPO,
+    SCM_EQP1,
+    SCM_EQP2,
+    SCM_DOM1,
+    SCM_DOM2,
+    SCM_RNG1,
+    SCM_RNG2,
+    SCM_HV,
+    SCM_SVF1,
+    SCM_SVF2,
+    SCM_AVF1,
+    SCM_AVF2,
+
+    // Instance rules, handled by LocalReasoner:
+    CLS_NOTHING2("No resource can have type owl:Nothing"),
+    PRP_IRP("owl:IrreflexiveProperty -- Resource can't be related to itself 
via irreflexive property"),
+    PRP_DOM("rdfs:domain -- Predicate's domain implies subject's type"),
+    PRP_RNG("rdfs:range -- Predicate's range implies object's type"),
+    CAX_SCO("owl:subClassOf -- Infer supertypes"),
+    // Combine prp-inv1 and prp-inv2, since inverseOf is symmetric:
+    PRP_INV("owl:inverseOf -- Relation via one property implies reverse 
relation via the inverse property"),
+    PRP_SPO1("rdfs:subPropertyOf -- Relation via subproperty implies relation 
via superproperty"),
+    PRP_SYMP("owl:SymmetricProperty -- Relation via this property is always 
bidirectional"),
+    CLS_SVF2("owl:someValuesFrom(owl:Thing) -- Infer membership in the set of 
resources related via this property to anything"),
+    CLS_HV2("owl:hasValue -- Infer membership in the set of all resources 
having a specific property+value"),
+    CLS_HV1("owl:hasValue -- Infer a specific property+value from the 
subject's membership in the set of resources with that property+value"),
+
+    // Combine multiple instance triples, handled by LocalReasoner:
+    PRP_ASYP("owl:AsymmetricProperty -- Asymmetric property can't be 
bidirectional"),
+    PRP_PDW("owl:propertyDisjointWith -- Two disjoint properties can't relate 
the same subject and object"),
+    CAX_DW("owl:disjointWith -- Resource can't belong to two disjoint 
classes"),
+    CLS_COM("owl:complementOf -- Resource can't belong to both a class and its 
complement"),
+    CLS_MAXC1("owl:maxCardinality(0) -- Max cardinality 0 for this property 
implies subject can't have any relation via the property"),
+    CLS_MAXQC2("owl:maxQualifiedCardinality(0/owl:Thing) -- Max cardinality 0 
(with respect to owl:Thing) implies subject can't have any relation via the 
property"),
+    PRP_TRP("owl:TransitiveProperty -- Infer transitive relation"),
+    CLS_SVF1("owl:someValuesFrom -- Infer membership in the set of resources 
related via this property to an instance of the appropriate type"),
+    CLS_AVF("owl:allValuesFrom -- Infer the object's type from the subject's 
membership in the set of resources whose values for this property all belong to 
one type"),
+
+    NONE("No rule given");
+
+    public String desc;
+    OwlRule() { desc = this.toString(); }
+    OwlRule(String desc) {
+        this.desc = desc;
+    }
+}

Reply via email to