/* 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 org.semanticweb.HermiT.model.DescriptionGraph;
import org.semanticweb.HermiT.monitor.TableauMonitor;
/**
* Implements the merge rule and is used whenever the merge rule needs to be applied
* during the expansion of the tableau object used in the constructor of the class.
*/
public final class MergingManager implements Serializable {
private static final long serialVersionUID=-8404748898127176927L;
protected final Tableau m_tableau;
protected final TableauMonitor m_tableauMonitor;
protected final ExtensionManager m_extensionManager;
protected final ExtensionTable.Retrieval m_binaryExtensionTableSearch1Bound;
protected final ExtensionTable.Retrieval m_ternaryExtensionTableSearch1Bound;
protected final ExtensionTable.Retrieval m_ternaryExtensionTableSearch2Bound;
protected final Object[] m_binaryAuxiliaryTuple;
protected final Object[] m_ternaryAuxiliaryTuple;
protected final UnionDependencySet m_binaryUnionDependencySet;
public MergingManager(Tableau tableau) {
m_tableau=tableau;
m_tableauMonitor=m_tableau.m_tableauMonitor;
m_extensionManager=m_tableau.m_extensionManager;
m_binaryExtensionTableSearch1Bound=m_extensionManager.m_binaryExtensionTable.createRetrieval(new boolean[] { false,true },ExtensionTable.View.TOTAL);
m_ternaryExtensionTableSearch1Bound=m_extensionManager.m_ternaryExtensionTable.createRetrieval(new boolean[] { false,true,false },ExtensionTable.View.TOTAL);
m_ternaryExtensionTableSearch2Bound=m_extensionManager.m_ternaryExtensionTable.createRetrieval(new boolean[] { false,false,true },ExtensionTable.View.TOTAL);
m_binaryAuxiliaryTuple=new Object[2];
m_ternaryAuxiliaryTuple=new Object[3];
m_binaryUnionDependencySet=new UnionDependencySet(2);
}
public void clear() {
m_binaryExtensionTableSearch1Bound.clear();
m_ternaryExtensionTableSearch1Bound.clear();
m_ternaryExtensionTableSearch2Bound.clear();
m_binaryAuxiliaryTuple[0]=null;
m_binaryAuxiliaryTuple[1]=null;
m_ternaryAuxiliaryTuple[0]=null;
m_ternaryAuxiliaryTuple[1]=null;
m_ternaryAuxiliaryTuple[2]=null;
}
/**
* Merges the two given nodes and adjusts the dependency set as required. It is
* automatically figured out which node has to be merged into which -- that is,
* the order between node0 and node1 is not important.
*/
public boolean mergeNodes(Node node0,Node node1,DependencySet dependencySet) {
assert node0.getNodeType().isAbstract()==node1.getNodeType().isAbstract();
if (!node0.isActive() || !node1.isActive() || node0==node1)
return false;
else {
Node mergeFrom;
Node mergeInto;
int node0Precedence=node0.getNodeType().getMergePrecedence();
int node1Precedence=node1.getNodeType().getMergePrecedence();
if (node0Precedence<node1Precedence) {
mergeFrom=node1;
mergeInto=node0;
}
else if (node0Precedence>node1Precedence) {
mergeFrom=node0;
mergeInto=node1;
}
else {
// Cluster anchors correspond to the [s] notation in the graphs paper.
Node node0ClusterAnchor=node0.getClusterAnchor();
Node node1ClusterAnchor=node1.getClusterAnchor();
// Watch out: node0ClusterAnchor and/or node1ClusterAnchor can be 'null' -- that is,
// 'null' plays the role of the \triangleright symbol from the graphs paper.
boolean canMerge0Into1=node0.m_parent==node1.m_parent || isDescendantOfAtMostThreeLevels(node0,node1ClusterAnchor);
boolean canMerge1Into0=node0.m_parent==node1.m_parent || isDescendantOfAtMostThreeLevels(node1,node0ClusterAnchor);
if (canMerge0Into1 && canMerge1Into0) {
if (node0.m_numberOfPositiveAtomicConcepts>node1.m_numberOfPositiveAtomicConcepts) {
mergeFrom=node1;
mergeInto=node0;
}
else {
mergeFrom=node0;
mergeInto=node1;
}
}
else if (canMerge0Into1) {
mergeFrom=node0;
mergeInto=node1;
}
else if (canMerge1Into0) {
mergeFrom=node1;
mergeInto=node0;
}
else
throw new IllegalStateException("Internal error: unsupported merge type.");
}
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeStarted(mergeFrom,mergeInto);
// Now prune the mergeFrom node. We go through all subsequent nodes
// (all successors of mergeFrom come after mergeFrom)
// and delete them it their parent is not in tableau or if it is the
// mergeFrom node.
Node node=mergeFrom;
while (node!=null) {
if (node.isActive() && node.m_parent!=null && (!node.m_parent.isActive() || node.m_parent==mergeFrom)) {
if (m_tableauMonitor!=null)
m_tableauMonitor.nodePruned(node);
m_tableau.pruneNode(node);
}
node=node.getNextTableauNode();
}
m_binaryUnionDependencySet.m_dependencySets[1]=dependencySet;
// Copy all unary assertions
m_binaryAuxiliaryTuple[1]=mergeInto;
m_binaryExtensionTableSearch1Bound.getBindingsBuffer()[1]=mergeFrom;
m_binaryExtensionTableSearch1Bound.open();
Object[] tupleBuffer=m_binaryExtensionTableSearch1Bound.getTupleBuffer();
while (!m_binaryExtensionTableSearch1Bound.afterLast()) {
Object predicate=tupleBuffer[0];
if (!(predicate instanceof DescriptionGraph)) {
m_binaryAuxiliaryTuple[0]=predicate;
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactStarted(mergeFrom,mergeInto,tupleBuffer,m_binaryAuxiliaryTuple);
m_binaryUnionDependencySet.m_dependencySets[0]=m_binaryExtensionTableSearch1Bound.getDependencySet();
m_extensionManager.addTuple(m_binaryAuxiliaryTuple,m_binaryUnionDependencySet,m_binaryExtensionTableSearch1Bound.isCore());
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactFinished(mergeFrom,mergeInto,tupleBuffer,m_binaryAuxiliaryTuple);
}
m_binaryExtensionTableSearch1Bound.next();
}
// Copy all binary assertions where mergeFrom occurs in the first position
m_ternaryAuxiliaryTuple[1]=mergeInto;
m_ternaryExtensionTableSearch1Bound.getBindingsBuffer()[1]=mergeFrom;
m_ternaryExtensionTableSearch1Bound.open();
tupleBuffer=m_ternaryExtensionTableSearch1Bound.getTupleBuffer();
while (!m_ternaryExtensionTableSearch1Bound.afterLast()) {
Object predicate=tupleBuffer[0];
if (!(predicate instanceof DescriptionGraph)) {
m_ternaryAuxiliaryTuple[0]=predicate;
m_ternaryAuxiliaryTuple[2]=(tupleBuffer[2]==mergeFrom ? mergeInto : tupleBuffer[2]);
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactStarted(mergeFrom,mergeInto,tupleBuffer,m_ternaryAuxiliaryTuple);
m_binaryUnionDependencySet.m_dependencySets[0]=m_ternaryExtensionTableSearch1Bound.getDependencySet();
m_extensionManager.addTuple(m_ternaryAuxiliaryTuple,m_binaryUnionDependencySet,m_ternaryExtensionTableSearch1Bound.isCore());
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactFinished(mergeFrom,mergeInto,tupleBuffer,m_ternaryAuxiliaryTuple);
}
m_ternaryExtensionTableSearch1Bound.next();
}
// Copy all binary assertions where mergeFrom occurs in the second position
m_ternaryAuxiliaryTuple[2]=mergeInto;
m_ternaryExtensionTableSearch2Bound.getBindingsBuffer()[2]=mergeFrom;
m_ternaryExtensionTableSearch2Bound.open();
tupleBuffer=m_ternaryExtensionTableSearch2Bound.getTupleBuffer();
while (!m_ternaryExtensionTableSearch2Bound.afterLast()) {
Object predicate=tupleBuffer[0];
if (!(predicate instanceof DescriptionGraph)) {
m_ternaryAuxiliaryTuple[0]=predicate;
m_ternaryAuxiliaryTuple[1]=(tupleBuffer[1]==mergeFrom ? mergeInto : tupleBuffer[1]);
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactStarted(mergeFrom,mergeInto,tupleBuffer,m_ternaryAuxiliaryTuple);
m_binaryUnionDependencySet.m_dependencySets[0]=m_ternaryExtensionTableSearch2Bound.getDependencySet();
m_extensionManager.addTuple(m_ternaryAuxiliaryTuple,m_binaryUnionDependencySet,m_ternaryExtensionTableSearch2Bound.isCore());
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFactFinished(mergeFrom,mergeInto,tupleBuffer,m_ternaryAuxiliaryTuple);
}
m_ternaryExtensionTableSearch2Bound.next();
}
// Now merge the description graphs
m_tableau.m_descriptionGraphManager.mergeGraphs(mergeFrom,mergeInto,m_binaryUnionDependencySet);
// Now finally merge the nodes
m_tableau.mergeNode(mergeFrom,mergeInto,dependencySet);
// Inform the monitor
if (m_tableauMonitor!=null)
m_tableauMonitor.mergeFinished(mergeFrom,mergeInto);
return true;
}
}
protected boolean isDescendantOfAtMostThreeLevels(Node descendant,Node ancestor) {
// The method tests ancestry, but only up to three levels.
// Merges over more levels should not happen.
if (descendant!=null) {
Node descendantParent=descendant.m_parent;
if (descendantParent==ancestor)
return true;
if (descendantParent!=null) {
Node descendantParentParent=descendantParent.m_parent;
if (descendantParentParent==ancestor)
return true;
if (descendantParentParent!=null) {
Node descendantParentParentParent=descendantParentParent.m_parent;
if (descendantParentParentParent==ancestor)
return true;
}
}
}
return false;
}
}