/* 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.existentials;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.semanticweb.HermiT.Prefixes;
import org.semanticweb.HermiT.blocking.BlockingStrategy;
import org.semanticweb.HermiT.model.AtLeast;
import org.semanticweb.HermiT.model.AtLeastConcept;
import org.semanticweb.HermiT.model.AtLeastDataRange;
import org.semanticweb.HermiT.model.AtomicConcept;
import org.semanticweb.HermiT.tableau.BranchingPoint;
import org.semanticweb.HermiT.tableau.DependencySet;
import org.semanticweb.HermiT.tableau.Node;
import org.semanticweb.HermiT.tableau.Tableau;
import org.semanticweb.HermiT.tableau.TupleTable;
public class IndividualReuseStrategy extends AbstractExpansionStrategy implements Serializable {
private static final long serialVersionUID=-7373787507623860081L;
protected final boolean m_isDeterministic;
protected final Map<AtomicConcept,NodeBranchingPointPair> m_reusedNodes;
protected final Set<AtomicConcept> m_doReuseConceptsAlways;
protected final Set<AtomicConcept> m_dontReuseConceptsThisRun;
protected final Set<AtomicConcept> m_dontReuseConceptsEver;
protected final TupleTable m_reuseBacktrackingTable;
protected final Object[] m_auxiliaryBuffer;
protected int[] m_indicesByBranchingPoint;
public IndividualReuseStrategy(BlockingStrategy strategy,boolean isDeterministic) {
super(strategy,true);
m_isDeterministic=isDeterministic;
m_reusedNodes=new HashMap<AtomicConcept,NodeBranchingPointPair>();
m_doReuseConceptsAlways=new HashSet<AtomicConcept>();
m_dontReuseConceptsThisRun=new HashSet<AtomicConcept>();
m_dontReuseConceptsEver=new HashSet<AtomicConcept>();
m_reuseBacktrackingTable=new TupleTable(1);
m_auxiliaryBuffer=new Object[1];
m_indicesByBranchingPoint=new int[10];
}
@SuppressWarnings("unchecked")
public void initialize(Tableau tableau) {
super.initialize(tableau);
m_doReuseConceptsAlways.clear();
m_dontReuseConceptsEver.clear();
Object object=tableau.getParameters().get("IndividualReuseStrategy.reuseAlways");
if (object instanceof Set)
m_doReuseConceptsAlways.addAll((Set<? extends AtomicConcept>)object);
object=tableau.getParameters().get("IndividualReuseStrategy.reuseNever");
if (object instanceof Set)
m_dontReuseConceptsEver.addAll((Set<? extends AtomicConcept>)object);
}
public void clear() {
super.clear();
m_reusedNodes.clear();
m_reuseBacktrackingTable.clear();
m_dontReuseConceptsThisRun.clear();
m_dontReuseConceptsThisRun.addAll(m_dontReuseConceptsEver);
}
public void branchingPointPushed() {
int start=m_tableau.getCurrentBranchingPoint().getLevel();
int requiredSize=start+1;
if (requiredSize>m_indicesByBranchingPoint.length) {
int newSize=m_indicesByBranchingPoint.length*3/2;
while (requiredSize>newSize)
newSize=newSize*3/2;
int[] newIndicesByBranchingPoint=new int[newSize];
System.arraycopy(m_indicesByBranchingPoint,0,newIndicesByBranchingPoint,0,m_indicesByBranchingPoint.length);
m_indicesByBranchingPoint=newIndicesByBranchingPoint;
}
m_indicesByBranchingPoint[start]=m_reuseBacktrackingTable.getFirstFreeTupleIndex();
}
public void backtrack() {
int requiredFirstFreeTupleIndex=m_indicesByBranchingPoint[m_tableau.getCurrentBranchingPoint().getLevel()];
for (int index=m_reuseBacktrackingTable.getFirstFreeTupleIndex()-1;index>=requiredFirstFreeTupleIndex;--index) {
AtomicConcept reuseConcept=(AtomicConcept)m_reuseBacktrackingTable.getTupleObject(index,0);
Object result=m_reusedNodes.remove(reuseConcept);
assert result!=null;
}
m_reuseBacktrackingTable.truncate(requiredFirstFreeTupleIndex);
}
public void modelFound() {
m_dontReuseConceptsEver.addAll(m_dontReuseConceptsThisRun);
}
public boolean isDeterministic() {
return m_isDeterministic;
}
public AtomicConcept getConceptForNode(Node node) {
for (Map.Entry<AtomicConcept,NodeBranchingPointPair> entry : m_reusedNodes.entrySet())
if (entry.getValue().m_node==node)
return entry.getKey();
return null;
}
public Set<AtomicConcept> getDontReuseConceptsEver() {
return m_dontReuseConceptsEver;
}
protected void expandExistential(AtLeast atLeast,Node forNode) {
// Mark existential as processed BEFORE branching takes place!
m_existentialExpansionManager.markExistentialProcessed(atLeast,forNode);
if (!m_existentialExpansionManager.tryFunctionalExpansion(atLeast,forNode))
if (atLeast instanceof AtLeastDataRange)
m_existentialExpansionManager.doNormalExpansion((AtLeastDataRange)atLeast,forNode);
else {
AtLeastConcept atLeastConcept=(AtLeastConcept)atLeast;
if (!tryParentReuse(atLeastConcept,forNode))
if (!expandWithModelReuse(atLeastConcept,forNode))
m_existentialExpansionManager.doNormalExpansion(atLeastConcept,forNode);
}
}
protected boolean tryParentReuse(AtLeastConcept atLeastConcept,Node node) {
if (atLeastConcept.getNumber()==1) {
Node parent=node.getParent();
if (parent!=null && m_extensionManager.containsConceptAssertion(atLeastConcept.getToConcept(),parent)) {
DependencySet dependencySet=m_extensionManager.getConceptAssertionDependencySet(atLeastConcept,node);
if (!m_isDeterministic) {
BranchingPoint branchingPoint=new IndividualReuseBranchingPoint(m_tableau,atLeastConcept,node,true);
m_tableau.pushBranchingPoint(branchingPoint);
dependencySet=m_tableau.getDependencySetFactory().addBranchingPoint(dependencySet,branchingPoint.getLevel());
}
m_extensionManager.addRoleAssertion(atLeastConcept.getOnRole(),node,parent,dependencySet,true);
return true;
}
}
return false;
}
protected boolean expandWithModelReuse(AtLeastConcept atLeastConcept,Node node) {
if (!(atLeastConcept.getToConcept() instanceof AtomicConcept))
return false;
AtomicConcept toConcept=(AtomicConcept)atLeastConcept.getToConcept();
if (Prefixes.isInternalIRI(toConcept.getIRI()))
return false;
if (atLeastConcept.getNumber()==1 && (m_doReuseConceptsAlways.contains(toConcept) || !m_dontReuseConceptsThisRun.contains(toConcept))) {
if (m_tableau.getTableauMonitor()!=null)
m_tableau.getTableauMonitor().existentialExpansionStarted(atLeastConcept,node);
DependencySet dependencySet=m_extensionManager.getConceptAssertionDependencySet(atLeastConcept,node);
Node existentialNode;
NodeBranchingPointPair reuseInfo=m_reusedNodes.get(toConcept);
if (reuseInfo==null) {
// No existential with the target concept toConcept has been expanded.
if (!m_isDeterministic) {
BranchingPoint branchingPoint=new IndividualReuseBranchingPoint(m_tableau,atLeastConcept,node,false);
m_tableau.pushBranchingPoint(branchingPoint);
dependencySet=m_tableau.getDependencySetFactory().addBranchingPoint(dependencySet,branchingPoint.getLevel());
}
// create a root node so that keys are not applicable
existentialNode=m_tableau.createNewNINode(dependencySet);
reuseInfo=new NodeBranchingPointPair(existentialNode,m_tableau.getCurrentBranchingPointLevel());
m_reusedNodes.put(toConcept,reuseInfo);
m_extensionManager.addConceptAssertion(toConcept,existentialNode,dependencySet,true);
m_auxiliaryBuffer[0]=toConcept;
m_reuseBacktrackingTable.addTuple(m_auxiliaryBuffer);
}
else {
dependencySet=reuseInfo.m_node.addCanonicalNodeDependencySet(dependencySet);
existentialNode=reuseInfo.m_node.getCanonicalNode();
if (!m_isDeterministic)
dependencySet=m_tableau.getDependencySetFactory().addBranchingPoint(dependencySet,reuseInfo.m_branchingPoint);
}
m_extensionManager.addRoleAssertion(atLeastConcept.getOnRole(),node,existentialNode,dependencySet,true);
if (m_tableau.getTableauMonitor()!=null)
m_tableau.getTableauMonitor().existentialExpansionFinished(atLeastConcept,node);
return true;
}
return false;
}
protected class IndividualReuseBranchingPoint extends BranchingPoint {
private static final long serialVersionUID=-5715836252258022216L;
protected final AtLeastConcept m_existential;
protected final Node m_node;
protected final boolean m_wasParentReuse;
public IndividualReuseBranchingPoint(Tableau tableau,AtLeastConcept existential,Node node,boolean wasParentReuse) {
super(tableau);
m_existential=existential;
m_node=node;
m_wasParentReuse=wasParentReuse;
}
public void startNextChoice(Tableau tableau,DependencySet clashDependencySet) {
if (!m_wasParentReuse)
m_dontReuseConceptsThisRun.add((AtomicConcept)m_existential.getToConcept());
DependencySet dependencySet=tableau.getDependencySetFactory().removeBranchingPoint(clashDependencySet,m_level);
if (tableau.getTableauMonitor()!=null)
tableau.getTableauMonitor().existentialExpansionStarted(m_existential,m_node);
Node existentialNode=tableau.createNewTreeNode(dependencySet,m_node);
m_extensionManager.addConceptAssertion(m_existential.getToConcept(),existentialNode,dependencySet,true);
m_extensionManager.addRoleAssertion(m_existential.getOnRole(),m_node,existentialNode,dependencySet,true);
if (tableau.getTableauMonitor()!=null)
tableau.getTableauMonitor().existentialExpansionFinished(m_existential,m_node);
}
}
protected static class NodeBranchingPointPair implements Serializable {
private static final long serialVersionUID=427963701900451471L;
protected final Node m_node;
protected final int m_branchingPoint;
public NodeBranchingPointPair(Node node,int branchingPoint) {
m_node=node;
m_branchingPoint=branchingPoint;
}
}
}