/* Copyright 2008, 2009, 2010 by the Oxford University Computing Laboratory
This file is part of HermiT.
HermiT is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
HermiT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with HermiT. If not, see <http://www.gnu.org/licenses/>.
*/
package org.semanticweb.HermiT.tableau;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.semanticweb.HermiT.existentials.ExistentialExpansionStrategy;
import org.semanticweb.HermiT.model.Atom;
import org.semanticweb.HermiT.model.AtomicConcept;
import org.semanticweb.HermiT.model.AtomicRole;
import org.semanticweb.HermiT.model.Constant;
import org.semanticweb.HermiT.model.ConstantEnumeration;
import org.semanticweb.HermiT.model.DLClause;
import org.semanticweb.HermiT.model.DLOntology;
import org.semanticweb.HermiT.model.DLPredicate;
import org.semanticweb.HermiT.model.DescriptionGraph;
import org.semanticweb.HermiT.model.Equality;
import org.semanticweb.HermiT.model.ExistentialConcept;
import org.semanticweb.HermiT.model.Individual;
import org.semanticweb.HermiT.model.Inequality;
import org.semanticweb.HermiT.model.InternalDatatype;
import org.semanticweb.HermiT.model.LiteralConcept;
import org.semanticweb.HermiT.model.NegatedAtomicRole;
import org.semanticweb.HermiT.model.Term;
import org.semanticweb.HermiT.monitor.TableauMonitor;
import org.semanticweb.HermiT.tableau.Node.NodeState;
/**
* This class coordinates the main tableau expansion for a given DLOntology
* (a normalized and clausified ontology). It represents the state of a run
* on a set of clauses and coordinates the extension of the ABox and also the
* retraction of facts when backtracking. Before starting the expansion,
* the given clauses are (for better performance) preprocessed via the
* HyperresolutionManager into a compiled and executable form.
*/
public final class Tableau implements Serializable {
private static final long serialVersionUID=-28982363158925221L;
protected final InterruptFlag m_interruptFlag;
protected final Map<String,Object> m_parameters;
protected final TableauMonitor m_tableauMonitor;
protected final ExistentialExpansionStrategy m_existentialExpansionStrategy;
protected final DLOntology m_permanentDLOntology;
protected DLOntology m_additionalDLOntology;
protected final DependencySetFactory m_dependencySetFactory;
protected final ExtensionManager m_extensionManager;
protected final ClashManager m_clashManager;
protected final HyperresolutionManager m_permanentHyperresolutionManager;
protected HyperresolutionManager m_additionalHyperresolutionManager;
protected final MergingManager m_mergingManager;
protected final ExistentialExpansionManager m_existentialExpasionManager;
protected final NominalIntroductionManager m_nominalIntroductionManager;
protected final DescriptionGraphManager m_descriptionGraphManager;
protected final DatatypeManager m_datatypeManager;
protected final List<List<ExistentialConcept>> m_existentialConceptsBuffers;
protected final boolean m_useDisjunctionLearning;
protected final boolean m_hasDescriptionGraphs;
protected BranchingPoint[] m_branchingPoints;
protected int m_currentBranchingPoint;
protected int m_nonbacktrackableBranchingPoint;
protected boolean m_isCurrentModelDeterministic;
protected boolean m_needsThingExtension;
protected boolean m_needsNamedExtension;
protected boolean m_needsRDFSLiteralExtension;
protected boolean m_checkDatatypes;
protected boolean m_checkUnknownDatatypeRestrictions;
protected int m_allocatedNodes;
protected int m_numberOfNodesInTableau;
protected int m_numberOfMergedOrPrunedNodes;
protected int m_numberOfNodeCreations;
protected Node m_firstFreeNode;
protected Node m_firstTableauNode;
protected Node m_lastTableauNode;
protected Node m_lastMergedOrPrunedNode;
protected GroundDisjunction m_firstGroundDisjunction;
protected GroundDisjunction m_firstUnprocessedGroundDisjunction;
public Tableau(InterruptFlag interruptFlag,TableauMonitor tableauMonitor,ExistentialExpansionStrategy existentialsExpansionStrategy,boolean useDisjunctionLearning,DLOntology permanentDLOntology,DLOntology additionalDLOntology,Map<String,Object> parameters) {
if (additionalDLOntology!=null && !additionalDLOntology.getAllDescriptionGraphs().isEmpty())
throw new IllegalArgumentException("Additional ontology cannot contain description graphs.");
m_interruptFlag=interruptFlag;
m_interruptFlag.startTask();
try {
m_parameters=parameters;
m_tableauMonitor=tableauMonitor;
m_existentialExpansionStrategy=existentialsExpansionStrategy;
m_permanentDLOntology=permanentDLOntology;
m_additionalDLOntology=additionalDLOntology;
m_dependencySetFactory=new DependencySetFactory();
m_extensionManager=new ExtensionManager(this);
m_clashManager=new ClashManager(this);
m_permanentHyperresolutionManager=new HyperresolutionManager(this,m_permanentDLOntology.getDLClauses());
if (m_additionalDLOntology!=null)
m_additionalHyperresolutionManager=new HyperresolutionManager(this,m_additionalDLOntology.getDLClauses());
else
m_additionalHyperresolutionManager=null;
m_mergingManager=new MergingManager(this);
m_existentialExpasionManager=new ExistentialExpansionManager(this);
m_nominalIntroductionManager=new NominalIntroductionManager(this);
m_descriptionGraphManager=new DescriptionGraphManager(this);
m_datatypeManager=new DatatypeManager(this);
m_existentialExpansionStrategy.initialize(this);
m_existentialConceptsBuffers=new ArrayList<List<ExistentialConcept>>();
m_useDisjunctionLearning=useDisjunctionLearning;
m_hasDescriptionGraphs=!m_permanentDLOntology.getAllDescriptionGraphs().isEmpty();
m_branchingPoints=new BranchingPoint[2];
m_currentBranchingPoint=-1;
m_nonbacktrackableBranchingPoint=-1;
updateFlagsDependentOnAdditionalOntology();
if (m_tableauMonitor!=null)
m_tableauMonitor.setTableau(this);
}
finally {
m_interruptFlag.endTask();
}
}
public InterruptFlag getInterruptFlag() {
return m_interruptFlag;
}
public DLOntology getPermanentDLOntology() {
return m_permanentDLOntology;
}
public DLOntology getAdditionalDLOntology() {
return m_additionalDLOntology;
}
public Map<String,Object> getParameters() {
return m_parameters;
}
public TableauMonitor getTableauMonitor() {
return m_tableauMonitor;
}
public ExistentialExpansionStrategy getExistentialsExpansionStrategy() {
return m_existentialExpansionStrategy;
}
public boolean isDeterministic() {
return m_permanentDLOntology.isHorn() && (m_additionalDLOntology==null || m_additionalDLOntology.isHorn()) && m_existentialExpansionStrategy.isDeterministic();
}
public DependencySetFactory getDependencySetFactory() {
return m_dependencySetFactory;
}
public ExtensionManager getExtensionManager() {
return m_extensionManager;
}
public HyperresolutionManager getPermanentHyperresolutionManager() {
return m_permanentHyperresolutionManager;
}
public HyperresolutionManager getAdditionalHyperresolutionManager() {
return m_additionalHyperresolutionManager;
}
public MergingManager getMergingManager() {
return m_mergingManager;
}
public ExistentialExpansionManager getExistentialExpansionManager() {
return m_existentialExpasionManager;
}
public NominalIntroductionManager getNominalIntroductionManager() {
return m_nominalIntroductionManager;
}
public DescriptionGraphManager getDescriptionGraphManager() {
return m_descriptionGraphManager;
}
public void clear() {
m_allocatedNodes=0;
m_numberOfNodesInTableau=0;
m_numberOfMergedOrPrunedNodes=0;
m_numberOfNodeCreations=0;
m_firstFreeNode=null;
m_firstTableauNode=null;
m_lastTableauNode=null;
m_lastMergedOrPrunedNode=null;
m_firstGroundDisjunction=null;
m_firstUnprocessedGroundDisjunction=null;
m_branchingPoints=new BranchingPoint[2];
m_currentBranchingPoint=-1;
m_nonbacktrackableBranchingPoint=-1;
m_dependencySetFactory.clear();
m_extensionManager.clear();
m_clashManager.clear();
m_permanentHyperresolutionManager.clear();
if (m_additionalHyperresolutionManager!=null)
m_additionalHyperresolutionManager.clear();
m_mergingManager.clear();
m_existentialExpasionManager.clear();
m_nominalIntroductionManager.clear();
m_descriptionGraphManager.clear();
m_isCurrentModelDeterministic=true;
m_existentialExpansionStrategy.clear();
m_datatypeManager.clear();
m_existentialConceptsBuffers.clear();
if (m_tableauMonitor!=null)
m_tableauMonitor.tableauCleared();
}
public boolean supportsAdditionalDLOntology(DLOntology additionalDLOntology) {
boolean hasInverseRoles=(m_permanentDLOntology.hasInverseRoles() || (m_additionalDLOntology!=null && m_additionalDLOntology.hasInverseRoles()));
boolean hasNominals=(m_permanentDLOntology.hasNominals() || (m_additionalDLOntology!=null && m_additionalDLOntology.hasNominals()));
boolean isHorn=(m_permanentDLOntology.isHorn() || (m_additionalDLOntology!=null && m_additionalDLOntology.isHorn()));
boolean permanentHasBottomObjectProperty=m_permanentDLOntology.containsObjectRole(AtomicRole.BOTTOM_OBJECT_ROLE);
boolean hasBottomObjectProperty=(permanentHasBottomObjectProperty || (m_additionalDLOntology!=null && m_additionalDLOntology.containsObjectRole(AtomicRole.BOTTOM_OBJECT_ROLE)));
if (!additionalDLOntology.getAllDescriptionGraphs().isEmpty() || (additionalDLOntology.hasInverseRoles() && !hasInverseRoles) || (additionalDLOntology.hasNominals() && !hasNominals) || (!additionalDLOntology.isHorn() && isHorn) || (hasBottomObjectProperty && !permanentHasBottomObjectProperty))
return false;
for (DLClause dlClause : additionalDLOntology.getDLClauses())
if (dlClause.isAtomicRoleInclusion() || dlClause.isAtomicRoleInverseInclusion() || dlClause.isFunctionalityAxiom() || dlClause.isInverseFunctionalityAxiom())
return false;
return true;
}
public void setAdditionalDLOntology(DLOntology additionalDLOntology) {
if (!supportsAdditionalDLOntology(additionalDLOntology))
throw new IllegalArgumentException("Additional DL-ontology contains features that are incompatible with this tableau.");
m_additionalDLOntology=additionalDLOntology;
m_additionalHyperresolutionManager=new HyperresolutionManager(this,m_additionalDLOntology.getDLClauses());
m_existentialExpansionStrategy.additionalDLOntologySet(m_additionalDLOntology);
m_datatypeManager.additionalDLOntologySet(m_additionalDLOntology);
updateFlagsDependentOnAdditionalOntology();
}
public void clearAdditionalDLOntology() {
m_additionalDLOntology=null;
m_additionalHyperresolutionManager=null;
m_existentialExpansionStrategy.additionalDLOntologyCleared();
m_datatypeManager.additionalDLOntologyCleared();
updateFlagsDependentOnAdditionalOntology();
}
protected void updateFlagsDependentOnAdditionalOntology() {
m_needsThingExtension=m_permanentHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(AtomicConcept.THING);
m_needsNamedExtension=m_permanentHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(AtomicConcept.INTERNAL_NAMED);
m_needsRDFSLiteralExtension=m_permanentHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(InternalDatatype.RDFS_LITERAL);
m_checkDatatypes=m_permanentDLOntology.hasDatatypes();
m_checkUnknownDatatypeRestrictions=m_permanentDLOntology.hasUnknownDatatypeRestrictions();
if (m_additionalHyperresolutionManager!=null) {
m_needsThingExtension|=m_additionalHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(AtomicConcept.THING);
m_needsNamedExtension|=m_additionalHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(AtomicConcept.INTERNAL_NAMED);
m_needsRDFSLiteralExtension|=m_additionalHyperresolutionManager.m_tupleConsumersByDeltaPredicate.containsKey(InternalDatatype.RDFS_LITERAL);
}
if (m_additionalDLOntology!=null) {
m_checkDatatypes|=m_additionalDLOntology.hasDatatypes();
m_checkUnknownDatatypeRestrictions|=m_additionalDLOntology.hasUnknownDatatypeRestrictions();
}
}
public boolean isSatisfiable(boolean loadAdditionalABox,Set<Atom> perTestPositiveFactsNoDependency,Set<Atom> perTestNegativeFactsNoDependency,Set<Atom> perTestPositiveFactsDummyDependency,Set<Atom> perTestNegativeFactsDummyDependency,Map<Individual,Node> nodesForIndividuals,ReasoningTaskDescription reasoningTaskDescription) {
boolean loadPermanentABox=m_permanentDLOntology.hasNominals() || (m_additionalDLOntology!=null && m_additionalDLOntology.hasNominals());
return isSatisfiable(loadPermanentABox,loadAdditionalABox,perTestPositiveFactsNoDependency,perTestNegativeFactsNoDependency,perTestPositiveFactsDummyDependency,perTestNegativeFactsDummyDependency,new HashMap<Term,Node>(),nodesForIndividuals,reasoningTaskDescription);
}
public boolean isSatisfiable(boolean loadPermanentABox,boolean loadAdditionalABox,Set<Atom> perTestPositiveFactsNoDependency,Set<Atom> perTestNegativeFactsNoDependency,Set<Atom> perTestPositiveFactsDummyDependency,Set<Atom> perTestNegativeFactsDummyDependency,Map<Individual,Node> nodesForIndividuals,ReasoningTaskDescription reasoningTaskDescription) {
return isSatisfiable(loadPermanentABox,loadAdditionalABox,perTestPositiveFactsNoDependency,perTestNegativeFactsNoDependency,perTestPositiveFactsDummyDependency,perTestNegativeFactsDummyDependency,new HashMap<Term,Node>(),nodesForIndividuals,reasoningTaskDescription);
}
public boolean isSatisfiable(boolean loadPermanentABox,boolean loadAdditionalABox,Set<Atom> perTestPositiveFactsNoDependency,Set<Atom> perTestNegativeFactsNoDependency,Set<Atom> perTestPositiveFactsDummyDependency,Set<Atom> perTestNegativeFactsDummyDependency,Map<Term,Node> termsToNodes,Map<Individual,Node> nodesForIndividuals,ReasoningTaskDescription reasoningTaskDescription) {
if (m_tableauMonitor!=null)
m_tableauMonitor.isSatisfiableStarted(reasoningTaskDescription);
clear();
if (loadPermanentABox) {
for (Atom atom : m_permanentDLOntology.getPositiveFacts())
loadPositiveFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
for (Atom atom : m_permanentDLOntology.getNegativeFacts())
loadNegativeFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
}
if (loadAdditionalABox && m_additionalDLOntology!=null) {
for (Atom atom : m_additionalDLOntology.getPositiveFacts())
loadPositiveFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
for (Atom atom : m_additionalDLOntology.getNegativeFacts())
loadNegativeFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
}
if (perTestPositiveFactsNoDependency!=null && !perTestPositiveFactsNoDependency.isEmpty())
for (Atom atom : perTestPositiveFactsNoDependency)
loadPositiveFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
if (perTestNegativeFactsNoDependency!=null && !perTestNegativeFactsNoDependency.isEmpty())
for (Atom atom : perTestNegativeFactsNoDependency)
loadNegativeFact(termsToNodes,atom,m_dependencySetFactory.emptySet());
if ((perTestPositiveFactsDummyDependency!=null && !perTestPositiveFactsDummyDependency.isEmpty()) || (perTestNegativeFactsDummyDependency!=null && !perTestNegativeFactsDummyDependency.isEmpty())) {
m_branchingPoints[0]=new BranchingPoint(this);
m_currentBranchingPoint++;
m_nonbacktrackableBranchingPoint=m_currentBranchingPoint;
DependencySet dependencySet=m_dependencySetFactory.addBranchingPoint(m_dependencySetFactory.emptySet(),m_currentBranchingPoint);
if (perTestPositiveFactsDummyDependency!=null && !perTestPositiveFactsDummyDependency.isEmpty())
for (Atom atom : perTestPositiveFactsDummyDependency)
loadPositiveFact(termsToNodes,atom,dependencySet);
if (perTestNegativeFactsDummyDependency!=null && !perTestNegativeFactsDummyDependency.isEmpty())
for (Atom atom : perTestNegativeFactsDummyDependency)
loadNegativeFact(termsToNodes,atom,dependencySet);
}
if (nodesForIndividuals!=null)
for (Map.Entry<Individual,Node> entry : nodesForIndividuals.entrySet()) {
if (termsToNodes.get(entry.getValue())==null) {
Atom topAssertion=Atom.create(AtomicConcept.THING, entry.getKey());
loadPositiveFact(termsToNodes,topAssertion,m_dependencySetFactory.emptySet());
}
entry.setValue(termsToNodes.get(entry.getKey()));
}
// Ensure that at least one individual exists.
if (m_firstTableauNode==null)
createNewNINode(m_dependencySetFactory.emptySet());
boolean result=runCalculus();
if (m_tableauMonitor!=null)
m_tableauMonitor.isSatisfiableFinished(reasoningTaskDescription,result);
return result;
}
protected void loadPositiveFact(Map<Term,Node> termsToNodes,Atom atom,DependencySet dependencySet) {
DLPredicate dlPredicate=atom.getDLPredicate();
if (dlPredicate instanceof LiteralConcept)
m_extensionManager.addConceptAssertion((LiteralConcept)dlPredicate,getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet),dependencySet,true);
else if (dlPredicate instanceof AtomicRole || Equality.INSTANCE.equals(dlPredicate) || Inequality.INSTANCE.equals(dlPredicate))
m_extensionManager.addAssertion(dlPredicate,getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet),getNodeForTerm(termsToNodes,atom.getArgument(1),dependencySet),dependencySet,true);
else if (dlPredicate instanceof DescriptionGraph) {
DescriptionGraph descriptionGraph=(DescriptionGraph)dlPredicate;
Object[] tuple=new Object[descriptionGraph.getArity()+1];
tuple[0]=descriptionGraph;
for (int argumentIndex=0;argumentIndex<descriptionGraph.getArity();argumentIndex++)
tuple[argumentIndex+1]=getNodeForTerm(termsToNodes,atom.getArgument(argumentIndex),dependencySet);
m_extensionManager.addTuple(tuple,dependencySet,true);
}
else
throw new IllegalArgumentException("Unsupported type of positive ground atom.");
}
protected void loadNegativeFact(Map<Term,Node> termsToNodes,Atom atom,DependencySet dependencySet) {
DLPredicate dlPredicate=atom.getDLPredicate();
if (dlPredicate instanceof LiteralConcept)
m_extensionManager.addConceptAssertion(((LiteralConcept)dlPredicate).getNegation(),getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet),dependencySet,true);
else if (dlPredicate instanceof AtomicRole) {
Object[] ternaryTuple=m_extensionManager.m_ternaryAuxiliaryTupleAdd;
ternaryTuple[0]=NegatedAtomicRole.create((AtomicRole)dlPredicate);
ternaryTuple[1]=getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet);
ternaryTuple[2]=getNodeForTerm(termsToNodes,atom.getArgument(1),dependencySet);
m_extensionManager.addTuple(ternaryTuple,dependencySet,true);
}
else if (Equality.INSTANCE.equals(dlPredicate))
m_extensionManager.addAssertion(Inequality.INSTANCE,getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet),getNodeForTerm(termsToNodes,atom.getArgument(1),dependencySet),dependencySet,true);
else if (Inequality.INSTANCE.equals(dlPredicate))
m_extensionManager.addAssertion(Equality.INSTANCE,getNodeForTerm(termsToNodes,atom.getArgument(0),dependencySet),getNodeForTerm(termsToNodes,atom.getArgument(1),dependencySet),dependencySet,true);
else
throw new IllegalArgumentException("Unsupported type of negative ground atom.");
}
protected Node getNodeForTerm(Map<Term,Node> termsToNodes,Term term,DependencySet dependencySet) {
Node node=termsToNodes.get(term);
if (node==null) {
if (term instanceof Individual) {
Individual individual=(Individual)term;
if (individual.isAnonymous())
node=createNewNINode(dependencySet);
else
node=createNewNamedNode(dependencySet);
}
else {
Constant constant=(Constant)term;
node=createNewRootConstantNode(dependencySet);
// Anonymous constant values are not assigned a particular value.
// See the hack in OWLClausification for an explanation.
if (!constant.isAnonymous())
m_extensionManager.addAssertion(ConstantEnumeration.create(new Constant[] { constant }),node,dependencySet,true);
}
termsToNodes.put(term,node);
}
return node.getCanonicalNode();
}
protected boolean runCalculus() {
m_interruptFlag.startTask();
try {
boolean existentialsAreExact=m_existentialExpansionStrategy.isExact();
if (m_tableauMonitor!=null)
m_tableauMonitor.saturateStarted();
boolean hasMoreWork=true;
while (hasMoreWork) {
if (m_tableauMonitor!=null)
m_tableauMonitor.iterationStarted();
hasMoreWork=doIteration();
if (m_tableauMonitor!=null)
m_tableauMonitor.iterationFinished();
if (!existentialsAreExact && !hasMoreWork && !m_extensionManager.containsClash()) {
// no more work to do, but since we use a blocking strategy that does not necessarily
// establish only valid blocks (existentialsAreExact == false), we tell the blocking
// strategy to go through the nodes and check whether all blocks are valid and if not,
// continue with the expansion
if (m_tableauMonitor!=null)
m_tableauMonitor.iterationStarted();
hasMoreWork=m_existentialExpansionStrategy.expandExistentials(true); // returns true if some blocks were invalid
if (m_tableauMonitor!=null)
m_tableauMonitor.iterationFinished();
}
}
if (m_tableauMonitor!=null)
m_tableauMonitor.saturateFinished(!m_extensionManager.containsClash());
if (!m_extensionManager.containsClash()) {
m_existentialExpansionStrategy.modelFound();
return true;
}
else
return false;
}
finally {
m_interruptFlag.endTask();
}
}
protected boolean doIteration() {
if (!m_extensionManager.containsClash()) {
m_nominalIntroductionManager.processAnnotatedEqualities();
boolean hasChange=false;
while (m_extensionManager.propagateDeltaNew() && !m_extensionManager.containsClash()) {
if (m_hasDescriptionGraphs && !m_extensionManager.containsClash())
m_descriptionGraphManager.checkGraphConstraints();
if (!m_extensionManager.containsClash())
m_permanentHyperresolutionManager.applyDLClauses();
if (m_additionalHyperresolutionManager!=null && !m_extensionManager.containsClash())
m_additionalHyperresolutionManager.applyDLClauses();
if (m_checkUnknownDatatypeRestrictions && !m_extensionManager.containsClash())
m_datatypeManager.applyUnknownDatatypeRestrictionSemantics();
if (m_checkDatatypes && !m_extensionManager.containsClash())
m_datatypeManager.checkDatatypeConstraints();
if (!m_extensionManager.containsClash())
m_nominalIntroductionManager.processAnnotatedEqualities();
hasChange=true;
}
if (hasChange)
return true;
}
if (!m_extensionManager.containsClash())
if (m_existentialExpansionStrategy.expandExistentials(false))
return true;
if (!m_extensionManager.containsClash()) {
while (m_firstUnprocessedGroundDisjunction!=null) {
GroundDisjunction groundDisjunction=m_firstUnprocessedGroundDisjunction;
if (m_tableauMonitor!=null)
m_tableauMonitor.processGroundDisjunctionStarted(groundDisjunction);
m_firstUnprocessedGroundDisjunction=groundDisjunction.m_previousGroundDisjunction;
if (!groundDisjunction.isPruned() && !groundDisjunction.isSatisfied(this)) {
int[] sortedDisjunctIndexes=groundDisjunction.getGroundDisjunctionHeader().getSortedDisjunctIndexes();
DependencySet dependencySet=groundDisjunction.getDependencySet();
if (groundDisjunction.getNumberOfDisjuncts()>1) {
BranchingPoint branchingPoint=new DisjunctionBranchingPoint(this,groundDisjunction,sortedDisjunctIndexes);
pushBranchingPoint(branchingPoint);
dependencySet=m_dependencySetFactory.addBranchingPoint(dependencySet,branchingPoint.getLevel());
}
if (m_tableauMonitor!=null)
m_tableauMonitor.disjunctProcessingStarted(groundDisjunction,sortedDisjunctIndexes[0]);
groundDisjunction.addDisjunctToTableau(this,sortedDisjunctIndexes[0],dependencySet);
if (m_tableauMonitor!=null) {
m_tableauMonitor.disjunctProcessingFinished(groundDisjunction,sortedDisjunctIndexes[0]);
m_tableauMonitor.processGroundDisjunctionFinished(groundDisjunction);
}
return true;
}
else {
if (m_tableauMonitor!=null)
m_tableauMonitor.groundDisjunctionSatisfied(groundDisjunction);
}
m_interruptFlag.checkInterrupt();
}
}
if (m_extensionManager.containsClash()) {
DependencySet clashDependencySet=m_extensionManager.getClashDependencySet();
int newCurrentBranchingPoint=clashDependencySet.getMaximumBranchingPoint();
if (newCurrentBranchingPoint<=m_nonbacktrackableBranchingPoint)
return false;
backtrackTo(newCurrentBranchingPoint);
BranchingPoint branchingPoint=getCurrentBranchingPoint();
if (m_tableauMonitor!=null)
m_tableauMonitor.startNextBranchingPointStarted(branchingPoint);
branchingPoint.startNextChoice(this,clashDependencySet);
if (m_tableauMonitor!=null)
m_tableauMonitor.startNextBranchingPointFinished(branchingPoint);
m_dependencySetFactory.removeUnusedSets();
return true;
}
return false;
}
public boolean isCurrentModelDeterministic() {
return m_isCurrentModelDeterministic;
}
public int getCurrentBranchingPointLevel() {
return m_currentBranchingPoint;
}
public BranchingPoint getCurrentBranchingPoint() {
return m_branchingPoints[m_currentBranchingPoint];
}
public void addGroundDisjunction(GroundDisjunction groundDisjunction) {
groundDisjunction.m_nextGroundDisjunction=m_firstGroundDisjunction;
groundDisjunction.m_previousGroundDisjunction=null;
if (m_firstGroundDisjunction!=null)
m_firstGroundDisjunction.m_previousGroundDisjunction=groundDisjunction;
m_firstGroundDisjunction=groundDisjunction;
if (m_firstUnprocessedGroundDisjunction==null)
m_firstUnprocessedGroundDisjunction=groundDisjunction;
if (m_tableauMonitor!=null)
m_tableauMonitor.groundDisjunctionDerived(groundDisjunction);
}
public GroundDisjunction getFirstUnprocessedGroundDisjunction() {
return m_firstUnprocessedGroundDisjunction;
}
/**
* Add a branching point in case we need to backtrack to this state.
*
* @param branchingPoint
*/
public void pushBranchingPoint(BranchingPoint branchingPoint) {
assert m_currentBranchingPoint+1==branchingPoint.m_level;
if (m_tableauMonitor!=null)
m_tableauMonitor.pushBranchingPointStarted(branchingPoint);
m_currentBranchingPoint++;
if (m_currentBranchingPoint>=m_branchingPoints.length) {
BranchingPoint[] newBranchingPoints=new BranchingPoint[m_currentBranchingPoint*3/2];
System.arraycopy(m_branchingPoints,0,newBranchingPoints,0,m_branchingPoints.length);
m_branchingPoints=newBranchingPoints;
}
m_branchingPoints[m_currentBranchingPoint]=branchingPoint;
m_extensionManager.branchingPointPushed();
m_existentialExpasionManager.branchingPointPushed();
m_existentialExpansionStrategy.branchingPointPushed();
m_nominalIntroductionManager.branchingPointPushed();
m_isCurrentModelDeterministic=false;
if (m_tableauMonitor!=null)
m_tableauMonitor.pushBranchingPointFinished(branchingPoint);
}
/**
* Backtrack to a certain branching point in the list of branching points that have been set during the run.
*
* @param newCurrentBrancingPoint
*/
protected void backtrackTo(int newCurrentBrancingPoint) {
BranchingPoint branchingPoint=m_branchingPoints[newCurrentBrancingPoint];
if (m_tableauMonitor!=null)
m_tableauMonitor.backtrackToStarted(branchingPoint);
// backtrack the list of branching points
for (int index=newCurrentBrancingPoint+1;index<=m_currentBranchingPoint;index++)
m_branchingPoints[index]=null;
m_currentBranchingPoint=newCurrentBrancingPoint;
// backtrack processed ground disjunctions
m_firstUnprocessedGroundDisjunction=branchingPoint.m_firstUnprocessedGroundDisjunction;
// backtrack added ground disjunctions
GroundDisjunction firstGroundDisjunctionShouldBe=branchingPoint.m_firstGroundDisjunction;
while (m_firstGroundDisjunction!=firstGroundDisjunctionShouldBe) {
m_firstGroundDisjunction.destroy(this);
m_firstGroundDisjunction=m_firstGroundDisjunction.m_nextGroundDisjunction;
}
if (m_firstGroundDisjunction!=null)
m_firstGroundDisjunction.m_previousGroundDisjunction=null;
// backtrack existentials
m_existentialExpansionStrategy.backtrack();
m_existentialExpasionManager.backtrack();
// backtrack nominal introduction
m_nominalIntroductionManager.backtrack();
// backtrack extensions
m_extensionManager.backtrack();
// backtrack node merges/prunes
Node lastMergedOrPrunedNodeShouldBe=branchingPoint.m_lastMergedOrPrunedNode;
while (m_lastMergedOrPrunedNode!=lastMergedOrPrunedNodeShouldBe)
backtrackLastMergedOrPrunedNode();
// backtrack node change list
Node lastTableauNodeShouldBe=branchingPoint.m_lastTableauNode;
while (lastTableauNodeShouldBe!=m_lastTableauNode)
destroyLastTableauNode();
// finish
m_extensionManager.clearClash();
if (m_tableauMonitor!=null)
m_tableauMonitor.backtrackToFinished(branchingPoint);
}
/**
* Create a new node that represents an individual named in the input ontology (thus, keys have to be applied to it)
*
* @param dependencySet
* the dependency set for the node
* @return the created node
*/
public Node createNewNamedNode(DependencySet dependencySet) {
return createNewNodeRaw(dependencySet,null,NodeType.NAMED_NODE,0);
}
/**
* Create a new node that represents a nominal, but one that is not named in the input ontology (thus, keys are not applicable)
*
* @param dependencySet
* the dependency set for the node
* @return the created node
*/
public Node createNewNINode(DependencySet dependencySet) {
return createNewNodeRaw(dependencySet,null,NodeType.NI_NODE,0);
}
/**
* Create a new tree node.
*
* @param dependencySet
* the dependency set for the node
* @param parent
* the parent of the node that is to be created
* @return the created node
*/
public Node createNewTreeNode(DependencySet dependencySet,Node parent) {
return createNewNodeRaw(dependencySet,parent,NodeType.TREE_NODE,parent.getTreeDepth()+1);
}
/**
* Create a new concrete node for datatypes.
*
* @param dependencySet
* the dependency set for the node
* @param parent
* the parent of the node that is to be created
* @return the created node
*/
public Node createNewConcreteNode(DependencySet dependencySet,Node parent) {
return createNewNodeRaw(dependencySet,parent,NodeType.CONCRETE_NODE,parent.getTreeDepth()+1);
}
/**
* Create a new root constant node for datatypes.
*
* @param dependencySet
* the dependency set for the node
* @return the created node
*/
public Node createNewRootConstantNode(DependencySet dependencySet) {
return createNewNodeRaw(dependencySet,null,NodeType.ROOT_CONSTANT_NODE,0);
}
/**
* Create a new node graph node for description graphs
*
* @param parent
* the parent of the node that is to be created (may be null)
* @param dependencySet
* the dependency set for the node
* @return the created node
*/
public Node createNewGraphNode(Node parent,DependencySet dependencySet) {
return createNewNodeRaw(dependencySet,parent,NodeType.GRAPH_NODE,parent==null ? 0 : parent.getTreeDepth());
}
protected Node createNewNodeRaw(DependencySet dependencySet,Node parent,NodeType nodeType,int treeDepth) {
Node node;
if (m_firstFreeNode==null) {
node=new Node(this);
m_allocatedNodes++;
}
else {
node=m_firstFreeNode;
m_firstFreeNode=m_firstFreeNode.m_nextTableauNode;
}
assert node.m_nodeID==-1;
assert node.m_nodeState==null;
node.initialize(++m_numberOfNodesInTableau,parent,nodeType,treeDepth);
m_existentialExpansionStrategy.nodeInitialized(node);
node.m_previousTableauNode=m_lastTableauNode;
if (m_lastTableauNode==null)
m_firstTableauNode=node;
else
m_lastTableauNode.m_nextTableauNode=node;
m_lastTableauNode=node;
m_existentialExpansionStrategy.nodeStatusChanged(node);
m_numberOfNodeCreations++;
if (m_tableauMonitor!=null)
m_tableauMonitor.nodeCreated(node);
if (nodeType.m_isAbstract) {
m_extensionManager.addConceptAssertion(AtomicConcept.THING,node,dependencySet,true);
if (nodeType==NodeType.NAMED_NODE && m_needsNamedExtension)
m_extensionManager.addConceptAssertion(AtomicConcept.INTERNAL_NAMED,node,dependencySet,true);
}
else
m_extensionManager.addDataRangeAssertion(InternalDatatype.RDFS_LITERAL,node,dependencySet,true);
return node;
}
/**
* Merges node into mergeInto. We assume that concepts and roles have already been copied from node to mergeInto. After the merge node has state NodeState.MERGED.
*
* @param node
* the node that is to be merged
* @param mergeInto
* the node we merge into
* @param dependencySet
*/
public void mergeNode(Node node,Node mergeInto,DependencySet dependencySet) {
assert node.m_nodeState==Node.NodeState.ACTIVE;
assert node.m_mergedInto==null;
assert node.m_mergedIntoDependencySet==null;
assert node.m_previousMergedOrPrunedNode==null;
node.m_mergedInto=mergeInto;
node.m_mergedIntoDependencySet=m_dependencySetFactory.getPermanent(dependencySet);
m_dependencySetFactory.addUsage(node.m_mergedIntoDependencySet);
node.m_nodeState=NodeState.MERGED;
node.m_previousMergedOrPrunedNode=m_lastMergedOrPrunedNode;
m_lastMergedOrPrunedNode=node;
m_numberOfMergedOrPrunedNodes++;
m_existentialExpansionStrategy.nodeStatusChanged(node);
m_existentialExpansionStrategy.nodesMerged(node,mergeInto);
}
public void pruneNode(Node node) {
assert node.m_nodeState==Node.NodeState.ACTIVE;
assert node.m_mergedInto==null;
assert node.m_mergedIntoDependencySet==null;
assert node.m_previousMergedOrPrunedNode==null;
node.m_nodeState=NodeState.PRUNED;
node.m_previousMergedOrPrunedNode=m_lastMergedOrPrunedNode;
m_lastMergedOrPrunedNode=node;
m_numberOfMergedOrPrunedNodes++;
m_existentialExpansionStrategy.nodeStatusChanged(node);
}
protected void backtrackLastMergedOrPrunedNode() {
Node node=m_lastMergedOrPrunedNode;
assert (node.m_nodeState==Node.NodeState.MERGED && node.m_mergedInto!=null && node.m_mergedInto!=null) || (node.m_nodeState==Node.NodeState.PRUNED && node.m_mergedInto==null && node.m_mergedInto==null);
Node savedMergedInfo=null;
if (node.m_nodeState==Node.NodeState.MERGED) {
m_dependencySetFactory.removeUsage(node.m_mergedIntoDependencySet);
savedMergedInfo=node.m_mergedInto;
node.m_mergedInto=null;
node.m_mergedIntoDependencySet=null;
}
node.m_nodeState=Node.NodeState.ACTIVE;
m_lastMergedOrPrunedNode=node.m_previousMergedOrPrunedNode;
node.m_previousMergedOrPrunedNode=null;
m_numberOfMergedOrPrunedNodes--;
m_existentialExpansionStrategy.nodeStatusChanged(node);
if (savedMergedInfo!=null)
m_existentialExpansionStrategy.nodesUnmerged(node,savedMergedInfo);
}
protected void destroyLastTableauNode() {
Node node=m_lastTableauNode;
assert node.m_nodeState==Node.NodeState.ACTIVE;
assert node.m_mergedInto==null;
assert node.m_mergedIntoDependencySet==null;
assert node.m_previousMergedOrPrunedNode==null;
m_existentialExpansionStrategy.nodeDestroyed(node);
if (node.m_previousTableauNode==null)
m_firstTableauNode=null;
else
node.m_previousTableauNode.m_nextTableauNode=null;
m_lastTableauNode=node.m_previousTableauNode;
node.destroy();
node.m_nextTableauNode=m_firstFreeNode;
m_firstFreeNode=node;
m_numberOfNodesInTableau--;
if (m_tableauMonitor!=null)
m_tableauMonitor.nodeDestroyed(node);
}
public int getNumberOfNodeCreations() {
return m_numberOfNodeCreations;
}
public Node getFirstTableauNode() {
return m_firstTableauNode;
}
public Node getLastTableauNode() {
return m_lastTableauNode;
}
public int getNumberOfAllocatedNodes() {
return m_allocatedNodes;
}
public int getNumberOfNodesInTableau() {
return m_numberOfNodesInTableau;
}
public int getNumberOfMergedOrPrunedNodes() {
return m_numberOfMergedOrPrunedNodes;
}
public Node getNode(int nodeID) {
Node node=m_firstTableauNode;
while (node!=null) {
if (node.getNodeID()==nodeID)
return node;
node=node.getNextTableauNode();
}
return null;
}
protected List<ExistentialConcept> getExistentialConceptsBuffer() {
if (m_existentialConceptsBuffers.isEmpty())
return new ArrayList<ExistentialConcept>();
else
return m_existentialConceptsBuffers.remove(m_existentialConceptsBuffers.size()-1);
}
public void putExistentialConceptsBuffer(List<ExistentialConcept> buffer) {
assert buffer.isEmpty();
m_existentialConceptsBuffers.add(buffer);
}
public void checkTableauList() {
Node node=m_firstTableauNode;
int numberOfNodesInTableau=0;
while (node!=null) {
if (node.m_previousTableauNode==null) {
if (m_firstTableauNode!=node)
throw new IllegalStateException("First tableau node is pointing wrongly.");
}
else {
if (node.m_previousTableauNode.m_nextTableauNode!=node)
throw new IllegalStateException("Previous tableau node is pointing wrongly.");
}
if (node.m_nextTableauNode==null) {
if (m_lastTableauNode!=node)
throw new IllegalStateException("Last tableau node is pointing wrongly.");
}
else {
if (node.m_nextTableauNode.m_previousTableauNode!=node)
throw new IllegalStateException("Next tableau node is pointing wrongly.");
}
numberOfNodesInTableau++;
node=node.m_nextTableauNode;
}
if (numberOfNodesInTableau!=m_numberOfNodesInTableau)
throw new IllegalStateException("Invalid number of nodes in the tableau.");
}
}