/* 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.Collection;
import java.util.Collections;
import java.util.List;
import org.semanticweb.HermiT.model.ExistentialConcept;
/**
* Represents a node in the tableau. Nodes are initially active, but can be set
* to merged or pruned at a later stage, which does not delete, but marks them
* as inactive.
*/
public final class Node implements Serializable {
private static final long serialVersionUID=-2549229429321484690L;
private static List<ExistentialConcept> NO_EXISTENTIALS=Collections.emptyList();
public static final Node SIGNATURE_CACHE_BLOCKER=new Node(null);
public static enum NodeState { ACTIVE,MERGED,PRUNED }
protected final Tableau m_tableau;
protected int m_nodeID;
protected NodeState m_nodeState;
protected Node m_parent;
protected NodeType m_nodeType;
protected int m_treeDepth;
protected int m_numberOfPositiveAtomicConcepts;
protected int m_numberOfNegatedAtomicConcepts;
protected int m_numberOfNegatedRoleAssertions;
protected List<ExistentialConcept> m_unprocessedExistentials;
protected Node m_previousTableauNode;
protected Node m_nextTableauNode;
protected Node m_previousMergedOrPrunedNode;
protected Node m_mergedInto;
protected PermanentDependencySet m_mergedIntoDependencySet;
protected Node m_blocker;
protected boolean m_directlyBlocked;
protected Object m_blockingObject;
protected Object m_blockingCargo;
protected int m_firstGraphOccurrenceNode;
public Node(Tableau tableau) {
m_tableau=tableau;
m_nodeID=-1;
}
public Tableau getTableau() {
return m_tableau;
}
protected void initialize(int nodeID,Node parent,NodeType nodeType,int treeDepth) {
assert m_nodeID==-1;
assert m_unprocessedExistentials==null;
m_nodeID=nodeID;
m_nodeState=NodeState.ACTIVE;
m_parent=parent;
m_nodeType=nodeType;
m_treeDepth=treeDepth;
m_numberOfPositiveAtomicConcepts=0;
m_numberOfNegatedAtomicConcepts=0;
m_numberOfNegatedRoleAssertions=0;
m_unprocessedExistentials=NO_EXISTENTIALS;
m_previousTableauNode=null;
m_nextTableauNode=null;
m_previousMergedOrPrunedNode=null;
m_mergedInto=null;
m_mergedIntoDependencySet=null;
m_blocker=null;
m_directlyBlocked=false;
m_tableau.m_descriptionGraphManager.intializeNode(this);
}
protected void destroy() {
m_nodeID=-1;
m_nodeState=null;
m_parent=null;
m_nodeType=null;
if (m_unprocessedExistentials!=NO_EXISTENTIALS) {
m_unprocessedExistentials.clear();
m_tableau.putExistentialConceptsBuffer(m_unprocessedExistentials);
}
m_unprocessedExistentials=null;
m_previousTableauNode=null;
m_nextTableauNode=null;
m_previousMergedOrPrunedNode=null;
m_mergedInto=null;
if (m_mergedIntoDependencySet!=null) {
m_tableau.m_dependencySetFactory.removeUsage(m_mergedIntoDependencySet);
m_mergedIntoDependencySet=null;
}
m_blocker=null;
m_tableau.m_descriptionGraphManager.destroyNode(this);
}
public int getNodeID() {
return m_nodeID;
}
public Node getParent() {
return m_parent;
}
public Node getClusterAnchor() {
if (m_nodeType==NodeType.TREE_NODE)
return this;
else
return m_parent;
}
public boolean isRootNode() {
return m_parent==null;
}
public boolean isParentOf(Node potentialChild) {
return potentialChild.m_parent==this;
}
public boolean isAncestorOf(Node potendialDescendant) {
while (potendialDescendant!=null) {
potendialDescendant=potendialDescendant.m_parent;
if (potendialDescendant==this)
return true;
}
return false;
}
public NodeType getNodeType() {
return m_nodeType;
}
public int getTreeDepth() {
return m_treeDepth;
}
public boolean isBlocked() {
return m_blocker!=null;
}
public boolean isDirectlyBlocked() {
return m_directlyBlocked;
}
public boolean isIndirectlyBlocked() {
return m_blocker!=null && !m_directlyBlocked;
}
public Node getBlocker() {
return m_blocker;
}
public void setBlocked(Node blocker,boolean directlyBlocked) {
m_blocker=blocker;
m_directlyBlocked=directlyBlocked;
}
/**
* @return a blocking object (PairwiseBlockingObject or SingleBlockingObject) that stores
* blocking relevant information of a node such as is label.
*/
public Object getBlockingObject() {
return m_blockingObject;
}
/**
* Stores a blocking object (PairwiseBlockingObject or SingleBlockingObject) for this node
* that stores blocking relevant information of a node such as is label.
* @param blockingObject
*/
public void setBlockingObject(Object blockingObject) {
m_blockingObject=blockingObject;
}
/**
* @return an object that should be a BlockersCache.CacheEntry and is used to
* remove or add the object to the blockers cache even after the hash code has
* changed due to label modifications
*/
public Object getBlockingCargo() {
return m_blockingCargo;
}
/**
* @param blockingCargo should be an object of type BlockersCache.CacheEntry
*/
public void setBlockingCargo(Object blockingCargo) {
m_blockingCargo=blockingCargo;
}
public int getNumberOfPositiveAtomicConcepts() {
return m_numberOfPositiveAtomicConcepts;
}
public boolean isActive() {
return m_nodeState==NodeState.ACTIVE;
}
public boolean isMerged() {
return m_nodeState==NodeState.MERGED;
}
public Node getMergedInto() {
return m_mergedInto;
}
public PermanentDependencySet getMergedIntoDependencySet() {
return m_mergedIntoDependencySet;
}
public boolean isPruned() {
return m_nodeState==NodeState.PRUNED;
}
public Node getPreviousTableauNode() {
return m_previousTableauNode;
}
public Node getNextTableauNode() {
return m_nextTableauNode;
}
public Node getCanonicalNode() {
Node result=this;
while (result.m_mergedInto!=null)
result=result.m_mergedInto;
return result;
}
public PermanentDependencySet getCanonicalNodeDependencySet() {
return addCanonicalNodeDependencySet(m_tableau.m_dependencySetFactory.m_emptySet);
}
public PermanentDependencySet addCanonicalNodeDependencySet(DependencySet dependencySet) {
PermanentDependencySet result=m_tableau.m_dependencySetFactory.getPermanent(dependencySet);
Node node=this;
while (node.m_mergedInto!=null) {
result=m_tableau.m_dependencySetFactory.unionWith(result,node.m_mergedIntoDependencySet);
node=node.m_mergedInto;
}
return result;
}
protected void addToUnprocessedExistentials(ExistentialConcept existentialConcept) {
assert NO_EXISTENTIALS.isEmpty();
if (m_unprocessedExistentials==NO_EXISTENTIALS) {
m_unprocessedExistentials=m_tableau.getExistentialConceptsBuffer();
assert m_unprocessedExistentials.isEmpty();
}
m_unprocessedExistentials.add(existentialConcept);
}
protected void removeFromUnprocessedExistentials(ExistentialConcept existentialConcept) {
assert !m_unprocessedExistentials.isEmpty();
if (existentialConcept==m_unprocessedExistentials.get(m_unprocessedExistentials.size()-1))
m_unprocessedExistentials.remove(m_unprocessedExistentials.size()-1);
else {
boolean result=m_unprocessedExistentials.remove(existentialConcept);
assert result;
}
if (m_unprocessedExistentials.isEmpty()) {
m_tableau.putExistentialConceptsBuffer(m_unprocessedExistentials);
m_unprocessedExistentials=NO_EXISTENTIALS;
}
}
public boolean hasUnprocessedExistentials() {
return !m_unprocessedExistentials.isEmpty();
}
public ExistentialConcept getSomeUnprocessedExistential() {
return m_unprocessedExistentials.get(m_unprocessedExistentials.size()-1);
}
public Collection<ExistentialConcept> getUnprocessedExistentials() {
return m_unprocessedExistentials;
}
public String toString() {
return String.valueOf(m_nodeID);
}
}