/* 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.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.semanticweb.HermiT.model.DescriptionGraph;
import org.semanticweb.HermiT.model.ExistsDescriptionGraph;
import org.semanticweb.HermiT.monitor.TableauMonitor;
public final class DescriptionGraphManager implements Serializable {
private static final long serialVersionUID=4536271856850424712L;
protected final Tableau m_tableau;
protected final InterruptFlag m_interruptFlag;
protected final TableauMonitor m_tableauMonitor;
protected final ExtensionManager m_extensionManager;
protected final MergingManager m_mergingManager;
protected final OccurrenceManager m_occurrenceManager;
protected final Map<DescriptionGraph,Integer> m_descriptionGraphIndices;
protected final DescriptionGraph[] m_descriptionGraphsByIndex;
protected final ExtensionTable[] m_extensionTablesByIndex;
protected final Object[][] m_auxiliaryTuples1;
protected final Object[][] m_auxiliaryTuples2;
protected final List<Node> m_newNodes;
protected final UnionDependencySet m_binaryUnionDependencySet;
protected final ExtensionTable.Retrieval[] m_deltaOldRetrievals;
public DescriptionGraphManager(Tableau tableau) {
m_tableau=tableau;
m_interruptFlag=m_tableau.m_interruptFlag;
m_tableauMonitor=m_tableau.m_tableauMonitor;
m_extensionManager=m_tableau.m_extensionManager;
m_mergingManager=m_tableau.m_mergingManager;
m_occurrenceManager=new OccurrenceManager();
m_descriptionGraphIndices=new HashMap<DescriptionGraph,Integer>();
Set<ExtensionTable> extensionTables=new HashSet<ExtensionTable>();
List<DescriptionGraph> descriptionGraphsByIndex=new ArrayList<DescriptionGraph>();
List<ExtensionTable> extensionTablesByIndex=new ArrayList<ExtensionTable>();
for (DescriptionGraph descriptionGraph : m_tableau.m_permanentDLOntology.getAllDescriptionGraphs()) {
m_descriptionGraphIndices.put(descriptionGraph,Integer.valueOf(descriptionGraphsByIndex.size()));
descriptionGraphsByIndex.add(descriptionGraph);
ExtensionTable extensionTable=m_extensionManager.getExtensionTable(descriptionGraph.getNumberOfVertices()+1);
extensionTablesByIndex.add(extensionTable);
extensionTables.add(extensionTable);
}
m_descriptionGraphsByIndex=new DescriptionGraph[descriptionGraphsByIndex.size()];
descriptionGraphsByIndex.toArray(m_descriptionGraphsByIndex);
m_extensionTablesByIndex=new ExtensionTable[extensionTablesByIndex.size()];
extensionTablesByIndex.toArray(m_extensionTablesByIndex);
m_auxiliaryTuples1=new Object[m_descriptionGraphsByIndex.length][];
m_auxiliaryTuples2=new Object[m_descriptionGraphsByIndex.length][];
for (int index=0;index<m_descriptionGraphsByIndex.length;index++) {
DescriptionGraph descriptionGraph=m_descriptionGraphsByIndex[index];
m_auxiliaryTuples1[index]=new Object[descriptionGraph.getNumberOfVertices()+1];
m_auxiliaryTuples2[index]=new Object[descriptionGraph.getNumberOfVertices()+1];
}
m_newNodes=new ArrayList<Node>();
m_binaryUnionDependencySet=new UnionDependencySet(2);
m_deltaOldRetrievals=new ExtensionTable.Retrieval[extensionTables.size()];
int index=0;
for (ExtensionTable extensionTable : extensionTables)
m_deltaOldRetrievals[index++]=extensionTable.createRetrieval(new boolean[extensionTable.getArity()],ExtensionTable.View.DELTA_OLD);
}
public void clear() {
for (int index=0;index<m_auxiliaryTuples1.length;index++) {
Arrays.fill(m_auxiliaryTuples1[index],null);
Arrays.fill(m_auxiliaryTuples2[index],null);
}
m_occurrenceManager.clear();
for (Object[] tuple : m_auxiliaryTuples1)
Arrays.fill(tuple,null);
for (Object[] tuple : m_auxiliaryTuples2)
Arrays.fill(tuple,null);
m_newNodes.clear();
m_binaryUnionDependencySet.m_dependencySets[0]=null;
m_binaryUnionDependencySet.m_dependencySets[1]=null;
for (ExtensionTable.Retrieval retrieval : m_deltaOldRetrievals)
retrieval.clear();
}
public Object[] getDescriptionGraphTuple(int graphIndex,int tupleIndex) {
DescriptionGraph descriptionGraph=m_descriptionGraphsByIndex[graphIndex];
ExtensionTable extensionTable=m_extensionTablesByIndex[graphIndex];
Object[] tuple=new Object[descriptionGraph.getNumberOfVertices()+1];
extensionTable.retrieveTuple(tuple,tupleIndex);
return tuple;
}
public boolean checkGraphConstraints() {
boolean hasChange=false;
for (int retrievalIndex=0;retrievalIndex<m_deltaOldRetrievals.length && !m_extensionManager.containsClash();retrievalIndex++) {
ExtensionTable.Retrieval retrieval=m_deltaOldRetrievals[retrievalIndex];
ExtensionTable extensionTable=retrieval.getExtensionTable();
retrieval.open();
Object[] tupleBuffer=retrieval.getTupleBuffer();
int arity=tupleBuffer.length;
while (!retrieval.afterLast() && !m_extensionManager.containsClash()) {
if (tupleBuffer[0] instanceof DescriptionGraph) {
int thisGraphIndex=m_descriptionGraphIndices.get(tupleBuffer[0]).intValue();
int thisTupleIndex=retrieval.getCurrentTupleIndex();
for (int thisPositionInTuple=1;thisPositionInTuple<arity;thisPositionInTuple++) {
Node node=(Node)tupleBuffer[thisPositionInTuple];
int listNode=node.m_firstGraphOccurrenceNode;
while (listNode!=-1) {
int graphIndex=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.GRAPH_INDEX);
int tupleIndex=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.TUPLE_INDEX);
int positionInTuple=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.POSITION_IN_TUPLE);
if (thisGraphIndex==graphIndex && (thisTupleIndex!=tupleIndex || thisPositionInTuple!=positionInTuple) && extensionTable.isTupleActive(tupleIndex)) {
m_binaryUnionDependencySet.m_dependencySets[0]=retrieval.getDependencySet();
m_binaryUnionDependencySet.m_dependencySets[1]=extensionTable.getDependencySet(tupleIndex);
if (m_tableauMonitor!=null)
m_tableauMonitor.descriptionGraphCheckingStarted(thisGraphIndex,thisTupleIndex,thisPositionInTuple,graphIndex,tupleIndex,positionInTuple);
if (thisPositionInTuple==positionInTuple) {
for (int mergePosition=arity-1;mergePosition>=1;--mergePosition) {
Node nodeFirst=(Node)extensionTable.getTupleObject(thisTupleIndex,mergePosition);
Node nodeSecond=(Node)extensionTable.getTupleObject(tupleIndex,mergePosition);
if (nodeFirst!=nodeSecond) {
m_mergingManager.mergeNodes(nodeFirst,nodeSecond,m_binaryUnionDependencySet);
hasChange=true;
}
m_interruptFlag.checkInterrupt();
}
}
else {
m_extensionManager.setClash(m_binaryUnionDependencySet);
hasChange=true;
}
if (m_tableauMonitor!=null)
m_tableauMonitor.descriptionGraphCheckingFinished(thisGraphIndex,thisTupleIndex,thisPositionInTuple,graphIndex,tupleIndex,positionInTuple);
}
listNode=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.NEXT_NODE);
m_interruptFlag.checkInterrupt();
}
}
}
retrieval.next();
}
m_interruptFlag.checkInterrupt();
}
return hasChange;
}
public boolean isSatisfied(ExistsDescriptionGraph existsDescriptionGraph,Node node) {
int graphIndex=m_descriptionGraphIndices.get(existsDescriptionGraph.getDescriptionGraph()).intValue();
int positionInTuple=existsDescriptionGraph.getVertex()+1;
int listNode=node.m_firstGraphOccurrenceNode;
while (listNode!=-1) {
if (graphIndex==m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.GRAPH_INDEX) && positionInTuple==m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.POSITION_IN_TUPLE))
return true;
listNode=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.NEXT_NODE);
}
return false;
}
public void mergeGraphs(Node mergeFrom,Node mergeInto,UnionDependencySet binaryUnionDependencySet) {
int listNode=mergeFrom.m_firstGraphOccurrenceNode;
while (listNode!=-1) {
int graphIndex=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.GRAPH_INDEX);
int tupleIndex=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.TUPLE_INDEX);
int positionInTuple=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.POSITION_IN_TUPLE);
ExtensionTable extensionTable=m_extensionTablesByIndex[graphIndex];
Object[] auxiliaryTuple=m_auxiliaryTuples1[graphIndex];
extensionTable.retrieveTuple(auxiliaryTuple,tupleIndex);
if (extensionTable.isTupleActive(auxiliaryTuple)) {
m_binaryUnionDependencySet.m_dependencySets[0]=extensionTable.getDependencySet(tupleIndex);
boolean isCore=extensionTable.isCore(tupleIndex);
if (m_tableauMonitor!=null) {
Object[] sourceTuple=m_auxiliaryTuples2[graphIndex];
System.arraycopy(auxiliaryTuple,0,sourceTuple,0,auxiliaryTuple.length);
auxiliaryTuple[positionInTuple]=mergeInto;
m_tableauMonitor.mergeFactStarted(mergeFrom,mergeInto,sourceTuple,auxiliaryTuple);
m_extensionManager.addTuple(auxiliaryTuple,m_binaryUnionDependencySet,isCore);
m_tableauMonitor.mergeFactFinished(mergeFrom,mergeInto,sourceTuple,auxiliaryTuple);
}
else {
auxiliaryTuple[positionInTuple]=mergeInto;
m_extensionManager.addTuple(auxiliaryTuple,m_binaryUnionDependencySet,isCore);
}
}
listNode=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.NEXT_NODE);
}
}
public void descriptionGraphTupleAdded(int tupleIndex,Object[] tuple) {
int graphIndex=m_descriptionGraphIndices.get(tuple[0]).intValue();
for (int positionInTuple=tuple.length-1;positionInTuple>=1;--positionInTuple) {
Node node=(Node)tuple[positionInTuple];
int listNode=m_occurrenceManager.newListNode();
m_occurrenceManager.initializeListNode(listNode,graphIndex,tupleIndex,positionInTuple,node.m_firstGraphOccurrenceNode);
node.m_firstGraphOccurrenceNode=listNode;
}
}
public void descriptionGraphTupleRemoved(int tupleIndex,Object[] tuple) {
for (int positionInTuple=tuple.length-1;positionInTuple>=1;--positionInTuple) {
Node node=(Node)tuple[positionInTuple];
int listNode=node.m_firstGraphOccurrenceNode;
assert m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.GRAPH_INDEX)==m_descriptionGraphIndices.get(tuple[0]).intValue();
assert m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.TUPLE_INDEX)==tupleIndex;
assert m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.POSITION_IN_TUPLE)==positionInTuple;
node.m_firstGraphOccurrenceNode=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.NEXT_NODE);
m_occurrenceManager.deleteListNode(listNode);
}
}
public void expand(ExistsDescriptionGraph existsDescriptionGraph,Node forNode) {
if (m_tableau.m_tableauMonitor!=null)
m_tableau.m_tableauMonitor.existentialExpansionStarted(existsDescriptionGraph,forNode);
m_newNodes.clear();
DescriptionGraph descriptionGraph=existsDescriptionGraph.getDescriptionGraph();
DependencySet dependencySet=m_extensionManager.getConceptAssertionDependencySet(existsDescriptionGraph,forNode);
Object[] auxiliaryTuple=m_auxiliaryTuples1[m_descriptionGraphIndices.get(descriptionGraph).intValue()];
auxiliaryTuple[0]=descriptionGraph;
for (int vertex=0;vertex<descriptionGraph.getNumberOfVertices();vertex++) {
Node newNode;
if (vertex==existsDescriptionGraph.getVertex())
newNode=forNode;
else
newNode=m_tableau.createNewGraphNode(forNode.getClusterAnchor(),dependencySet);
m_newNodes.add(newNode);
auxiliaryTuple[vertex+1]=newNode;
}
m_extensionManager.addTuple(auxiliaryTuple,dependencySet,true);
// Replace all nodes with the canonical node because the nodes might have been merged
for (int vertex=0;vertex<descriptionGraph.getNumberOfVertices();vertex++) {
Node newNode=m_newNodes.get(vertex);
dependencySet=newNode.addCanonicalNodeDependencySet(dependencySet);
m_newNodes.set(vertex,newNode.getCanonicalNode());
}
// Now add the graph layout
for (int vertex=0;vertex<descriptionGraph.getNumberOfVertices();vertex++)
m_extensionManager.addConceptAssertion(descriptionGraph.getAtomicConceptForVertex(vertex),m_newNodes.get(vertex),dependencySet,true);
for (int edgeIndex=0;edgeIndex<descriptionGraph.getNumberOfEdges();edgeIndex++) {
DescriptionGraph.Edge edge=descriptionGraph.getEdge(edgeIndex);
m_extensionManager.addRoleAssertion(edge.getAtomicRole(),m_newNodes.get(edge.getFromVertex()),m_newNodes.get(edge.getToVertex()),dependencySet,true);
}
m_newNodes.clear();
if (m_tableau.m_tableauMonitor!=null)
m_tableau.m_tableauMonitor.existentialExpansionFinished(existsDescriptionGraph,forNode);
}
public void intializeNode(Node node) {
node.m_firstGraphOccurrenceNode=-1;
}
public void destroyNode(Node node) {
int listNode=node.m_firstGraphOccurrenceNode;
while (listNode!=-1) {
int nextListNode=m_occurrenceManager.getListNodeComponent(listNode,OccurrenceManager.NEXT_NODE);
m_occurrenceManager.deleteListNode(listNode);
listNode=nextListNode;
}
node.m_firstGraphOccurrenceNode=-1;
}
protected static class OccurrenceManager implements Serializable {
private static final long serialVersionUID = 7594355731105478918L;
public static final int GRAPH_INDEX=0;
public static final int TUPLE_INDEX=1;
public static final int POSITION_IN_TUPLE=2;
public static final int NEXT_NODE=3;
public static final int LIST_NODE_SIZE=4;
public static final int LIST_NODE_PAGE_SIZE=LIST_NODE_SIZE*512;
protected int[][] m_nodePages;
protected int m_firstFreeListNode;
protected int m_numberOfPages;
public OccurrenceManager() {
m_nodePages=new int[10][];
m_nodePages[0]=new int[LIST_NODE_PAGE_SIZE];
m_numberOfPages=1;
m_firstFreeListNode=0;
setListNodeComponent(m_firstFreeListNode,NEXT_NODE,-1);
}
public void clear() {
m_firstFreeListNode=0;
setListNodeComponent(m_firstFreeListNode,NEXT_NODE,-1);
}
public int getListNodeComponent(int listNode,int component) {
return m_nodePages[listNode / LIST_NODE_PAGE_SIZE][(listNode % LIST_NODE_PAGE_SIZE)+component];
}
public void setListNodeComponent(int listNode,int component,int value) {
m_nodePages[listNode / LIST_NODE_PAGE_SIZE][(listNode % LIST_NODE_PAGE_SIZE)+component]=value;
}
public void initializeListNode(int listNode,int graphIndex,int tupleIndex,int positionInTuple,int nextListNode) {
int pageIndex=listNode / LIST_NODE_PAGE_SIZE;
int indexInPage=listNode % LIST_NODE_PAGE_SIZE;
int[] nodePage=m_nodePages[pageIndex];
nodePage[indexInPage+GRAPH_INDEX]=graphIndex;
nodePage[indexInPage+TUPLE_INDEX]=tupleIndex;
nodePage[indexInPage+POSITION_IN_TUPLE]=positionInTuple;
nodePage[indexInPage+NEXT_NODE]=nextListNode;
}
public int newListNode() {
int newListNode=m_firstFreeListNode;
int nextFreeListNode=getListNodeComponent(m_firstFreeListNode,NEXT_NODE);
if (nextFreeListNode!=-1)
m_firstFreeListNode=nextFreeListNode;
else {
m_firstFreeListNode+=LIST_NODE_SIZE;
int pageIndex=m_firstFreeListNode / LIST_NODE_PAGE_SIZE;
if (pageIndex>=m_numberOfPages) {
if (pageIndex>=m_nodePages.length) {
int[][] newNodePages=new int[m_nodePages.length*3/2][];
System.arraycopy(m_nodePages,0,newNodePages,0,m_nodePages.length);
m_nodePages=newNodePages;
}
m_nodePages[pageIndex]=new int[LIST_NODE_PAGE_SIZE];
m_numberOfPages++;
}
setListNodeComponent(m_firstFreeListNode,NEXT_NODE,-1);
}
return newListNode;
}
public void deleteListNode(int listNode) {
setListNodeComponent(listNode,NEXT_NODE,m_firstFreeListNode);
m_firstFreeListNode=listNode;
}
}
}