blob: 4a6f1af3a0a90f1f78bb79d486b1d54d82155933 [file] [log] [blame]
package org.apache.rya.reasoning;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.HashSet;
import java.util.Set;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Value;
/**
* Abstract class for reasoning in the neighborhood of a particular resource.
* Contains general methods for collecting facts and derivations, and
* determining whether those facts are potentially new.
*
* As reasoning rules are applied, facts and inconsistencies are collected and
* stored in this object. (This allows some simple logic to reduce redundant
* fact generation.) The caller can use getFacts and getInconsistencies to
* retrieve them when needed. (This clears the buffered facts in the reasoner
* object.)
*/
public abstract class AbstractReasoner {
/**
* Reasoning is done with respect to this particular node.
*/
protected final Resource node;
/**
* All schema (TBox/RBox) data is accessed through this.
*/
protected final Schema schema;
/**
* The current iteration in the overall reasoning algorithm.
*/
protected final int currentIteration;
/**
* A newly derived fact should have at least one source which is at least
* this recent.
*/
final int minIteration;
/**
* If the global schema has ever been updated during reasoning iteration,
* this will be the iteration number of that update (otherwise 0).
*/
final int lastSchemaChange;
// Newly derived information
Set<Fact> newFacts = new HashSet<>();
Set<Derivation> inconsistencies = new HashSet<>();
/**
* Constructor.
* @param node Conduct reasoning about/around this node
* @param schema Global schema (class/property) information
* @param t Iteration # of new triples
* @param tSchema Iteration # of latest schema update. If the schema has
* not been changed, we can ignore many triples that we
* expect to already have used.
*/
public AbstractReasoner(Resource node, Schema schema, int t, int tSchema) {
this.node = node;
this.schema = schema;
this.currentIteration = t;
this.lastSchemaChange = tSchema;
if (tSchema < (t - 1)) {
this.minIteration = 0;
}
else {
this.minIteration = t - 1;
}
}
/**
* Store inconsistency if it really is new.
* @return Whether it really needed to be stored
*/
protected boolean collectInconsistency(Derivation inconsistency) {
// If at least one of its sources can indeed be used for derivations,
// store this fact
for (Fact source : inconsistency.getSources()) {
if (frontier(source)) {
return inconsistencies.add(inconsistency);
}
}
return false;
}
/**
* Store fact if it really is new.
* @return Whether it really needed to be stored
*/
protected boolean collect(Fact fact) {
// If this fact was just generated, at least one of its sources can
// indeed be used for derivations, and the sources don't include it
// itself, store this fact
if (fact.getIteration() == currentIteration && !fact.isCycle()) {
Derivation d = fact.getDerivation();
for (Fact source : d.getSources()) {
if (frontier(source)) {
return newFacts.add(fact);
}
}
}
return false;
}
/**
* Whether any new facts have been derived and not yet retrieved.
*/
public boolean hasNewFacts() {
return !newFacts.isEmpty();
}
/**
* Whether any inconsistencies have been derived and not retrieved.
*/
public boolean hasInconsistencies() {
return !inconsistencies.isEmpty();
}
/**
* Return the latest facts and set current new results to empty.
*/
public Set<Fact> getFacts() {
Set<Fact> results = newFacts;
newFacts = new HashSet<Fact>();
return results;
}
/**
* Return the latest inconsistencies and set inconsistencies to empty.
*/
public Set<Derivation> getInconsistencies() {
Set<Derivation> results = inconsistencies;
inconsistencies = new HashSet<Derivation>();
return results;
}
/**
* Create a Fact representing a triple inferred by this reasoner.
* @param s The subject {@link Resource}.
* @param p The predicate {@link IRI}.
* @param o The object {@link Value}.
* @param rule The specific rule rule that yielded the inference
* @param source One (might be the only) fact used in the derivation
*/
protected Fact triple(Resource s, IRI p, Value o, OwlRule rule,
Fact source) {
Fact fact = new Fact(s, p, o, this.currentIteration,
rule, this.node);
fact.addSource(source);
return fact;
}
/**
* Create a Derivation representing an inconsistency found by this reasoner.
* @param rule The specific rule rule that yielded the inconsistency
* @param source One (might be the only) fact used in the derivation
*/
protected Derivation inconsistency(OwlRule rule, Fact source) {
Derivation d = new Derivation(this.currentIteration, rule, this.node);
d.addSource(source);
return d;
}
/**
* Determine whether a fact is on the frontier of knowledge so far, meaning
* it is new enough to imply further unknown information. If false, we can
* expect inferences based on this fact to have already been made in the
* step during which it was initially derived. Any interesting fact coming
* from this reasoner should have at least one of its direct sources on
* the frontier. Considers only age, not semantics.
*
* Three cases that indicate this is on the frontier:
* 1) We are looking at all the data (minIteration==0, either because this
* is the first pass through the data or because we reset on updating
* the schema).
* 2) This fact was generated (by this reasoner) during this iteration, so
* it hasn't been seen before.
* 3) It was generated by another node's reasoner since minIteration,
* meaning it hasn't been seen yet by a reasoner for this node.
*
* In any case, inconsistencies are not used to derive anything, so they
* always return false.
*/
protected boolean frontier(Fact fact) {
int t = fact.getIteration();
Resource dNode = null;
if (fact.isInference()) {
dNode = fact.getDerivation().getNode();
}
return (minIteration == 0) || (t == currentIteration)
|| (t >= minIteration && !this.node.equals(dNode));
}
/**
* Get some summary information for logging/debugging.
*/
public String getDiagnostics() {
StringBuilder sb = new StringBuilder();
sb.append(newFacts.size()).append(" new facts buffered");
sb.append(inconsistencies.size()).append(" new inconsistencies buffered");
return sb.toString();
}
/**
* Get the number of inputs cached.
*/
public int getNumStored() { return 0; }
/**
* Get the node this reasoner reasons around.
*/
public Resource getNode() { return node; }
}