/* 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.List;
/**
* This is the main class to work with dependency sets and returns instances of
* PermanentDependencySet, which can not directly be created. Dependency sets
* are either permanent (in case they are used for a longer time and more
* frequently) or temporary. The temporary ones are instances of the class
* UnionDependencySet and they can be created directly. If a temporary
* dependency sets is used more frequently, it can be turned into a permanent
* one by this factory.
*/
public final class DependencySetFactory implements Serializable {
private static final long serialVersionUID=8632867055646817311L;
protected final IntegerArray m_mergeArray;
protected final List<PermanentDependencySet> m_mergeSets;
protected final List<UnionDependencySet> m_unprocessedSets;
protected PermanentDependencySet m_emptySet;
protected PermanentDependencySet m_firstUnusedSet;
protected PermanentDependencySet m_firstDestroyedSet;
protected PermanentDependencySet[] m_entries;
protected int m_size;
protected int m_resizeThreshold;
public DependencySetFactory() {
m_mergeArray=new IntegerArray();
m_mergeSets=new ArrayList<PermanentDependencySet>();
m_unprocessedSets=new ArrayList<UnionDependencySet>();
clear();
}
public int sizeInMemory() {
return m_entries.length*4+m_size*20;
}
public void clear() {
m_mergeArray.clear();
m_mergeSets.clear();
m_unprocessedSets.clear();
m_emptySet=new PermanentDependencySet();
m_emptySet.m_branchingPoint=-1;
m_emptySet.m_usageCounter=1;
m_emptySet.m_rest=null;
m_emptySet.m_previousUnusedSet=null;
m_emptySet.m_nextUnusedSet=null;
m_firstUnusedSet=null;
m_firstDestroyedSet=null;
m_entries=new PermanentDependencySet[16];
m_resizeThreshold=(int)(m_entries.length*0.75);
m_size=0;
}
public PermanentDependencySet emptySet() {
return m_emptySet;
}
public void removeUnusedSets() {
while (m_firstUnusedSet!=null)
destroyDependencySet(m_firstUnusedSet);
}
public void addUsage(PermanentDependencySet dependencySet) {
assert dependencySet.m_branchingPoint>=0 || dependencySet==m_emptySet;
if (dependencySet.m_usageCounter==0)
removeFromUnusedList(dependencySet);
dependencySet.m_usageCounter++;
}
public void removeUsage(PermanentDependencySet dependencySet) {
assert dependencySet.m_branchingPoint>=0 || dependencySet==m_emptySet;
assert dependencySet.m_usageCounter>0;
assert dependencySet.m_previousUnusedSet==null;
assert dependencySet.m_nextUnusedSet==null;
dependencySet.m_usageCounter--;
if (dependencySet.m_usageCounter==0)
addToUnusedList(dependencySet);
}
public PermanentDependencySet addBranchingPoint(DependencySet dependencySet,int branchingPoint) {
PermanentDependencySet permanentDependencySet=getPermanent(dependencySet);
if (branchingPoint>permanentDependencySet.m_branchingPoint)
return getDepdendencySet(permanentDependencySet,branchingPoint);
else if (branchingPoint==permanentDependencySet.m_branchingPoint)
return permanentDependencySet;
else {
m_mergeArray.clear();
PermanentDependencySet rest=permanentDependencySet;
while (branchingPoint<rest.m_branchingPoint) {
m_mergeArray.add(rest.m_branchingPoint);
rest=rest.m_rest;
}
if (branchingPoint==rest.m_branchingPoint)
return permanentDependencySet;
else {
rest=getDepdendencySet(rest,branchingPoint);
for (int index=m_mergeArray.size()-1;index>=0;--index)
rest=getDepdendencySet(rest,m_mergeArray.get(index));
return rest;
}
}
}
protected PermanentDependencySet getDepdendencySet(PermanentDependencySet rest,int branchingPoint) {
int index=(rest.hashCode()+branchingPoint) & (m_entries.length-1);
PermanentDependencySet dependencySet=m_entries[index];
while (dependencySet!=null) {
if (dependencySet.m_rest==rest && dependencySet.m_branchingPoint==branchingPoint)
return dependencySet;
dependencySet=dependencySet.m_nextEntry;
}
dependencySet=createDependencySet(rest,branchingPoint);
dependencySet.m_nextEntry=m_entries[index];
m_entries[index]=dependencySet;
if (m_size>=m_resizeThreshold)
resizeEntries();
return dependencySet;
}
protected PermanentDependencySet createDependencySet(PermanentDependencySet rest,int branchingPoint) {
PermanentDependencySet newSet;
if (m_firstDestroyedSet==null)
newSet=new PermanentDependencySet();
else {
newSet=m_firstDestroyedSet;
m_firstDestroyedSet=m_firstDestroyedSet.m_nextEntry;
}
newSet.m_rest=rest;
newSet.m_branchingPoint=branchingPoint;
newSet.m_usageCounter=0;
addUsage(newSet.m_rest);
addToUnusedList(newSet);
m_size++;
return newSet;
}
protected void destroyDependencySet(PermanentDependencySet dependencySet) {
assert dependencySet.m_branchingPoint>=0;
assert dependencySet.m_usageCounter==0;
assert dependencySet.m_rest.m_usageCounter>0;
removeFromUnusedList(dependencySet);
removeUsage(dependencySet.m_rest);
removeFromEntries(dependencySet);
dependencySet.m_rest=null;
dependencySet.m_branchingPoint=-2;
dependencySet.m_nextEntry=m_firstDestroyedSet;
m_firstDestroyedSet=dependencySet;
m_size--;
}
protected void removeFromEntries(PermanentDependencySet dependencySet) {
int index=(dependencySet.m_rest.hashCode()+dependencySet.m_branchingPoint) & (m_entries.length-1);
PermanentDependencySet lastEntry=null;
PermanentDependencySet entry=m_entries[index];
while (entry!=null) {
if (entry==dependencySet) {
if (lastEntry==null)
m_entries[index]=dependencySet.m_nextEntry;
else
lastEntry.m_nextEntry=dependencySet.m_nextEntry;
return;
}
lastEntry=entry;
entry=entry.m_nextEntry;
}
throw new IllegalStateException("Internal error: dependency set not in the entries table. Please inform HermiT authors about this.");
}
protected void removeFromUnusedList(PermanentDependencySet dependencySet) {
if (dependencySet.m_previousUnusedSet!=null)
dependencySet.m_previousUnusedSet.m_nextUnusedSet=dependencySet.m_nextUnusedSet;
else
m_firstUnusedSet=dependencySet.m_nextUnusedSet;
if (dependencySet.m_nextUnusedSet!=null)
dependencySet.m_nextUnusedSet.m_previousUnusedSet=dependencySet.m_previousUnusedSet;
dependencySet.m_previousUnusedSet=null;
dependencySet.m_nextUnusedSet=null;
}
protected void addToUnusedList(PermanentDependencySet dependencySet) {
dependencySet.m_previousUnusedSet=null;
dependencySet.m_nextUnusedSet=m_firstUnusedSet;
if (m_firstUnusedSet!=null)
m_firstUnusedSet.m_previousUnusedSet=dependencySet;
m_firstUnusedSet=dependencySet;
}
protected void resizeEntries() {
int newLength=m_entries.length*2;
int newLengthMinusOne=newLength-1;
PermanentDependencySet[] newEntries=new PermanentDependencySet[newLength];
for (int oldIndex=0;oldIndex<m_entries.length;oldIndex++) {
PermanentDependencySet entry=m_entries[oldIndex];
while (entry!=null) {
PermanentDependencySet nextEntry=entry.m_nextEntry;
int newIndex=(entry.m_rest.hashCode()+entry.m_branchingPoint) & newLengthMinusOne;
entry.m_nextEntry=newEntries[newIndex];
newEntries[newIndex]=entry;
entry=nextEntry;
}
}
m_entries=newEntries;
m_resizeThreshold=(int)(m_entries.length*0.75);
}
public PermanentDependencySet removeBranchingPoint(DependencySet dependencySet,int branchingPoint) {
PermanentDependencySet permanentDependencySet=getPermanent(dependencySet);
if (branchingPoint==permanentDependencySet.m_branchingPoint)
return permanentDependencySet.m_rest;
else if (branchingPoint>permanentDependencySet.m_branchingPoint)
return permanentDependencySet;
else {
m_mergeArray.clear();
PermanentDependencySet rest=permanentDependencySet;
while (branchingPoint<rest.m_branchingPoint) {
m_mergeArray.add(rest.m_branchingPoint);
rest=rest.m_rest;
}
if (branchingPoint!=rest.m_branchingPoint)
return permanentDependencySet;
else {
rest=rest.m_rest;
for (int index=m_mergeArray.size()-1;index>=0;--index)
rest=getDepdendencySet(rest,m_mergeArray.get(index));
return rest;
}
}
}
public PermanentDependencySet unionWith(DependencySet set1,DependencySet set2) {
PermanentDependencySet permanentSet1=getPermanent(set1);
PermanentDependencySet permanentSet2=getPermanent(set2);
if (permanentSet1==permanentSet2)
return permanentSet1;
m_mergeArray.clear();
while (permanentSet1!=permanentSet2) {
if (permanentSet1.m_branchingPoint>permanentSet2.m_branchingPoint) {
m_mergeArray.add(permanentSet1.m_branchingPoint);
permanentSet1=permanentSet1.m_rest;
}
else if (permanentSet1.m_branchingPoint<permanentSet2.m_branchingPoint) {
m_mergeArray.add(permanentSet2.m_branchingPoint);
permanentSet2=permanentSet2.m_rest;
}
else {
m_mergeArray.add(permanentSet1.m_branchingPoint);
permanentSet1=permanentSet1.m_rest;
permanentSet2=permanentSet2.m_rest;
}
}
PermanentDependencySet result=permanentSet1;
for (int index=m_mergeArray.size()-1;index>=0;--index)
result=getDepdendencySet(result,m_mergeArray.get(index));
return result;
}
public PermanentDependencySet getPermanent(DependencySet dependencySet) {
if (dependencySet instanceof PermanentDependencySet)
return (PermanentDependencySet)dependencySet;
m_unprocessedSets.clear();
m_mergeSets.clear();
m_unprocessedSets.add((UnionDependencySet)dependencySet);
while (!m_unprocessedSets.isEmpty()) {
UnionDependencySet unionDependencySet=m_unprocessedSets.remove(m_unprocessedSets.size()-1);
for (int index=0;index<unionDependencySet.m_numberOfConstituents;index++) {
DependencySet constituent=unionDependencySet.m_dependencySets[index];
if (constituent instanceof UnionDependencySet)
m_unprocessedSets.add((UnionDependencySet)constituent);
else
m_mergeSets.add((PermanentDependencySet)constituent);
}
}
int numberOfSets=m_mergeSets.size();
m_mergeArray.clear();
while (true) {
PermanentDependencySet firstSet=m_mergeSets.get(0);
int maximal=firstSet.m_branchingPoint;
int maximalIndex=0;
boolean hasEquals=false;
boolean allAreEqual=true;
for (int index=1;index<numberOfSets;index++) {
PermanentDependencySet permanentDependencySet=m_mergeSets.get(index);
int branchingPoint=permanentDependencySet.m_branchingPoint;
if (branchingPoint>maximal) {
maximal=branchingPoint;
hasEquals=false;
maximalIndex=index;
}
else if (branchingPoint==maximal)
hasEquals=true;
if (permanentDependencySet!=firstSet)
allAreEqual=false;
}
if (allAreEqual)
break;
m_mergeArray.add(maximal);
if (hasEquals) {
for (int index=0;index<numberOfSets;index++) {
PermanentDependencySet permanentDependencySet=m_mergeSets.get(index);
if (permanentDependencySet.m_branchingPoint==maximal)
m_mergeSets.set(index,permanentDependencySet.m_rest);
}
}
else {
PermanentDependencySet permanentDependencySet=m_mergeSets.get(maximalIndex);
m_mergeSets.set(maximalIndex,permanentDependencySet.m_rest);
}
}
PermanentDependencySet result=m_mergeSets.get(0);
for (int index=m_mergeArray.size()-1;index>=0;--index)
result=getDepdendencySet(result,m_mergeArray.get(index));
m_mergeSets.clear();
return result;
}
protected static final class IntegerArray implements Serializable {
private static final long serialVersionUID=7070190530381846058L;
protected int[] m_elements;
protected int m_size;
public IntegerArray() {
m_elements=new int[64];
m_size=0;
}
public void clear() {
m_size=0;
}
public int size() {
return m_size;
}
public int get(int index) {
return m_elements[index];
}
public void add(int element) {
if (m_size>=m_elements.length) {
int[] newElements=new int[m_elements.length*3/2];
System.arraycopy(m_elements,0,newElements,0,m_elements.length);
m_elements=newElements;
}
m_elements[m_size++]=element;
}
}
}