/* 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.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.semanticweb.HermiT.existentials.ExistentialExpansionStrategy; import org.semanticweb.HermiT.model.Atom; import org.semanticweb.HermiT.model.DLClause; import org.semanticweb.HermiT.model.DLPredicate; import org.semanticweb.HermiT.model.NodeIDLessEqualThan; import org.semanticweb.HermiT.model.NodeIDsAscendingOrEqual; import org.semanticweb.HermiT.model.Term; import org.semanticweb.HermiT.model.Variable; import org.semanticweb.HermiT.monitor.TableauMonitor; public class DLClauseEvaluator implements Serializable { private static final long serialVersionUID=4639844159658590456L; protected static final String CRLF=System.getProperty("line.separator"); protected final InterruptFlag m_interruptFlag; protected final ExtensionManager m_extensionManager; protected final ExtensionTable.Retrieval[] m_retrievals; protected final Worker[] m_workers; protected final DLClause m_bodyDLClause; protected final List<DLClause> m_headDLClauses; public DLClauseEvaluator(Tableau tableau,DLClause bodyDLClause,List<DLClause> headDLClauses,ExtensionTable.Retrieval firstAtomRetrieval,BufferSupply bufferSupply,ValuesBufferManager valuesBufferManager,GroundDisjunctionHeaderManager groundDisjunctionHeaderManager,Map<Integer,UnionDependencySet> unionDependencySetsBySize) { m_interruptFlag=tableau.m_interruptFlag; m_extensionManager=tableau.m_extensionManager; DLClauseCompiler compiler=new DLClauseCompiler(bufferSupply,valuesBufferManager,groundDisjunctionHeaderManager,unionDependencySetsBySize,this,m_extensionManager,tableau.getExistentialsExpansionStrategy(),bodyDLClause,headDLClauses,firstAtomRetrieval); m_retrievals=new ExtensionTable.Retrieval[compiler.m_retrievals.size()]; compiler.m_retrievals.toArray(m_retrievals); m_workers=new Worker[compiler.m_workers.size()]; compiler.m_workers.toArray(m_workers); m_bodyDLClause=bodyDLClause; m_headDLClauses=headDLClauses; } public int getBodyLength() { return m_bodyDLClause.getBodyLength(); } public Atom getBodyAtom(int atomIndex) { return m_bodyDLClause.getBodyAtom(atomIndex); } public int getNumberOfDLClauses() { return m_headDLClauses.size(); } public DLClause getDLClause(int dlClauseIndex) { return m_headDLClauses.get(dlClauseIndex); } public int getHeadLength(int dlClauseIndex) { return m_headDLClauses.get(dlClauseIndex).getHeadLength(); } public Atom getHeadAtom(int dlClauseIndex,int atomIndex) { return m_headDLClauses.get(dlClauseIndex).getHeadAtom(atomIndex); } public Object[] getTupleMatchedToBody(int atomIndex) { return m_retrievals[atomIndex].getTupleBuffer(); } public void evaluate() { int programCounter=0; while (programCounter<m_workers.length && !m_extensionManager.containsClash()) { m_interruptFlag.checkInterrupt(); programCounter=m_workers[programCounter].execute(programCounter); } } public String toString() { StringBuffer buffer=new StringBuffer(); int maximalPCLength=String.valueOf(m_workers.length-1).length(); for (int programCounter=0;programCounter<m_workers.length;programCounter++) { String programCounterString=String.valueOf(programCounter); for (int count=maximalPCLength-programCounterString.length();count>0;--count) buffer.append(' '); buffer.append(programCounterString); buffer.append(": "); buffer.append(m_workers[programCounter].toString()); buffer.append(CRLF); } return buffer.toString(); } public static class BufferSupply { protected final List<Object[]> m_allBuffers; protected final Map<Integer,List<Object[]>> m_availableBuffersByArity; public BufferSupply() { m_allBuffers=new ArrayList<Object[]>(); m_availableBuffersByArity=new HashMap<Integer,List<Object[]>>(); } public void reuseBuffers() { m_availableBuffersByArity.clear(); for (Object[] buffer : m_allBuffers) { Integer arityInteger=Integer.valueOf(buffer.length); List<Object[]> buffers=m_availableBuffersByArity.get(arityInteger); if (buffers==null) { buffers=new ArrayList<Object[]>(); m_availableBuffersByArity.put(arityInteger,buffers); } buffers.add(buffer); } } public Object[] getBuffer(int arity) { Object[] buffer; Integer arityInteger=Integer.valueOf(arity); List<Object[]> buffers=m_availableBuffersByArity.get(arityInteger); if (buffers==null || buffers.isEmpty()) { buffer=new Object[arity]; m_allBuffers.add(buffer); } else buffer=buffers.remove(buffers.size()-1); return buffer; } public Object[][] getAllBuffers() { Object[][] result=new Object[m_allBuffers.size()][]; m_allBuffers.toArray(result); return result; } } public static class ValuesBufferManager { public final Object[] m_valuesBuffer; public final Map<DLPredicate,Integer> m_bodyDLPredicatesToIndexes; public final int m_maxNumberOfVariables; public final Map<Term,Integer> m_bodyNonvariableTermsToIndexes; public ValuesBufferManager(Set<DLClause> dlClauses,Map<Term,Node> termsToNodes) { Set<DLPredicate> bodyDLPredicates=new HashSet<DLPredicate>(); Set<Variable> variables=new HashSet<Variable>(); m_bodyNonvariableTermsToIndexes=new HashMap<Term,Integer>(); int maxNumberOfVariables=0; for (DLClause dlClause : dlClauses) { variables.clear(); for (int bodyIndex=dlClause.getBodyLength()-1;bodyIndex>=0;--bodyIndex) { Atom atom=dlClause.getBodyAtom(bodyIndex); bodyDLPredicates.add(atom.getDLPredicate()); for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Term term=atom.getArgument(argumentIndex); if (term instanceof Variable) variables.add((Variable)term); else m_bodyNonvariableTermsToIndexes.put(term,-1); } } if (variables.size()>maxNumberOfVariables) maxNumberOfVariables=variables.size(); } m_valuesBuffer=new Object[maxNumberOfVariables+bodyDLPredicates.size()+m_bodyNonvariableTermsToIndexes.size()]; m_bodyDLPredicatesToIndexes=new HashMap<DLPredicate,Integer>(); int bindingIndex=maxNumberOfVariables; for (DLPredicate bodyDLPredicate : bodyDLPredicates) { m_bodyDLPredicatesToIndexes.put(bodyDLPredicate,Integer.valueOf(bindingIndex)); m_valuesBuffer[bindingIndex]=bodyDLPredicate; bindingIndex++; } for (Map.Entry<Term,Integer> entry : m_bodyNonvariableTermsToIndexes.entrySet()) { Node termNode=termsToNodes.get(entry.getKey()); if (termNode==null) throw new IllegalArgumentException("Term '"+entry.getValue()+"' is unknown to the reasoner."); entry.setValue(bindingIndex); m_valuesBuffer[bindingIndex]=termNode.getCanonicalNode(); bindingIndex++; } m_maxNumberOfVariables=maxNumberOfVariables; } } public static class GroundDisjunctionHeaderManager { protected GroundDisjunctionHeader[] m_buckets; protected int m_numberOfElements; protected int m_threshold; public GroundDisjunctionHeaderManager() { m_buckets=new GroundDisjunctionHeader[1024]; m_threshold=(int)(m_buckets.length*0.75); m_numberOfElements=0; } public GroundDisjunctionHeader get(DLPredicate[] dlPredicates) { int hashCode=0; for (int disjunctIndex=0;disjunctIndex<dlPredicates.length;disjunctIndex++) hashCode=hashCode*7+dlPredicates[disjunctIndex].hashCode(); int bucketIndex=getIndexFor(hashCode,m_buckets.length); GroundDisjunctionHeader entry=m_buckets[bucketIndex]; while (entry!=null) { if (hashCode==entry.m_hashCode && entry.isEqual(dlPredicates)) return entry; entry=entry.m_nextEntry; } entry=new GroundDisjunctionHeader(dlPredicates,hashCode,entry); m_buckets[bucketIndex]=entry; m_numberOfElements++; if (m_numberOfElements>=m_threshold) resize(m_buckets.length*2); return entry; } protected void resize(int newCapacity) { GroundDisjunctionHeader[] newBuckets=new GroundDisjunctionHeader[newCapacity]; for (int i=0;i<m_buckets.length;i++) { GroundDisjunctionHeader entry=m_buckets[i]; while (entry!=null) { GroundDisjunctionHeader nextEntry=entry.m_nextEntry; int newIndex=getIndexFor(entry.hashCode(),newCapacity); entry.m_nextEntry=newBuckets[newIndex]; newBuckets[newIndex]=entry; entry=nextEntry; } } m_buckets=newBuckets; m_threshold=(int)(newCapacity*0.75); } protected static int getIndexFor(int hashCode,int tableLength) { hashCode+=~(hashCode << 9); hashCode^=(hashCode >>> 14); hashCode+=(hashCode << 4); hashCode^=(hashCode >>> 10); return hashCode & (tableLength-1); } } public static interface Worker { int execute(int programCounter); } protected static interface BranchingWorker extends Worker { int getBranchingAddress(); void setBranchingAddress(int branchingAddress); } protected static final class CopyValues implements Worker,Serializable { private static final long serialVersionUID=-4323769483485648756L; protected final Object[] m_fromBuffer; protected final int m_fromIndex; protected final Object[] m_toBuffer; protected final int m_toIndex; public CopyValues(Object[] fromBuffer,int fromIndex,Object[] toBuffer,int toIndex) { m_fromBuffer=fromBuffer; m_fromIndex=fromIndex; m_toBuffer=toBuffer; m_toIndex=toIndex; } public int execute(int programCounter) { m_toBuffer[m_toIndex]=m_fromBuffer[m_fromIndex]; return programCounter+1; } public String toString() { return "Copy "+m_fromIndex+" --> "+m_toIndex; } } protected static final class CopyDependencySet implements Worker,Serializable { private static final long serialVersionUID=705172386083123813L; protected final ExtensionTable.Retrieval m_retrieval; protected final DependencySet[] m_targetDependencySets; protected final int m_targetIndex; public CopyDependencySet(ExtensionTable.Retrieval retrieval,DependencySet[] targetDependencySets,int targetIndex) { m_retrieval=retrieval; m_targetDependencySets=targetDependencySets; m_targetIndex=targetIndex; } public int execute(int programCounter) { m_targetDependencySets[m_targetIndex]=m_retrieval.getDependencySet(); return programCounter+1; } public String toString() { return "Copy dependency set to "+m_targetIndex; } } protected static final class BranchIfNotEqual implements BranchingWorker,Serializable { private static final long serialVersionUID=-1880147431680856293L; protected int m_notEqualProgramCounter; protected final Object[] m_buffer; protected final int m_index1; protected final int m_index2; public BranchIfNotEqual(int notEqualProgramCounter,Object[] buffer,int index1,int index2) { m_notEqualProgramCounter=notEqualProgramCounter; m_buffer=buffer; m_index1=index1; m_index2=index2; } public int execute(int programCounter) { if (m_buffer[m_index1].equals(m_buffer[m_index2])) return programCounter+1; else return m_notEqualProgramCounter; } public int getBranchingAddress() { return m_notEqualProgramCounter; } public void setBranchingAddress(int branchingAddress) { m_notEqualProgramCounter=branchingAddress; } public String toString() { return "Branch to "+m_notEqualProgramCounter+" if "+m_index1+" != "+m_index2; } } protected static final class BranchIfNotNodeIDLessEqualThan implements BranchingWorker,Serializable { private static final long serialVersionUID=2484359261424674914L; protected int m_notLessProgramCounter; protected final Object[] m_buffer; protected final int m_index1; protected final int m_index2; public BranchIfNotNodeIDLessEqualThan(int notLessProgramCounter,Object[] buffer,int index1,int index2) { m_notLessProgramCounter=notLessProgramCounter; m_buffer=buffer; m_index1=index1; m_index2=index2; } public int execute(int programCounter) { if (((Node)m_buffer[m_index1]).getNodeID()<=((Node)m_buffer[m_index2]).getNodeID()) return programCounter+1; else return m_notLessProgramCounter; } public int getBranchingAddress() { return m_notLessProgramCounter; } public void setBranchingAddress(int branchingAddress) { m_notLessProgramCounter=branchingAddress; } public String toString() { return "Branch to "+m_notLessProgramCounter+" if "+m_index1+".ID > "+m_index2+".ID"; } } protected static final class BranchIfNotNodeIDsAscendingOrEqual implements BranchingWorker,Serializable { private static final long serialVersionUID=8053779312249250349L; protected int m_branchProgramCounter; protected final Object[] m_buffer; protected final int[] m_nodeIndexes; public BranchIfNotNodeIDsAscendingOrEqual(int branchProgramCounter,Object[] buffer,int[] nodeIndexes) { m_branchProgramCounter=branchProgramCounter; m_buffer=buffer; m_nodeIndexes=nodeIndexes; } public int execute(int programCounter) { boolean strictlyAscending=true; boolean allEqual=true; int lastNodeID=((Node)m_buffer[m_nodeIndexes[0]]).getNodeID(); for (int index=1;index<m_nodeIndexes.length;index++) { int nodeID=((Node)m_buffer[m_nodeIndexes[index]]).getNodeID(); if (lastNodeID>=nodeID) strictlyAscending=false; if (nodeID!=lastNodeID) allEqual=false; lastNodeID=nodeID; } if ((!strictlyAscending && allEqual) || (strictlyAscending && !allEqual)) return programCounter+1; else return m_branchProgramCounter; } public int getBranchingAddress() { return m_branchProgramCounter; } public void setBranchingAddress(int branchingAddress) { m_branchProgramCounter=branchingAddress; } public String toString() { return "Branch to "+m_branchProgramCounter+" if node IDs are not ascending or equal"; } } protected static final class OpenRetrieval implements Worker,Serializable { private static final long serialVersionUID=8246610603084803950L; protected final ExtensionTable.Retrieval m_retrieval; public OpenRetrieval(ExtensionTable.Retrieval retrieval) { m_retrieval=retrieval; } public int execute(int programCounter) { m_retrieval.open(); return programCounter+1; } public String toString() { return "Open "+m_retrieval.getBindingsBuffer()[m_retrieval.getBindingPositions()[0]]; } } protected static final class NextRetrieval implements Worker,Serializable { private static final long serialVersionUID=-2787897558147109082L; protected final ExtensionTable.Retrieval m_retrieval; public NextRetrieval(ExtensionTable.Retrieval retrieval) { m_retrieval=retrieval; } public int execute(int programCounter) { m_retrieval.next(); return programCounter+1; } public String toString() { return "Next "+m_retrieval.getBindingsBuffer()[m_retrieval.getBindingPositions()[0]]; } } protected static final class HasMoreRetrieval implements BranchingWorker,Serializable { private static final long serialVersionUID=-2415094151423166585L; protected int m_eofProgramCounter; protected final ExtensionTable.Retrieval m_retrieval; public HasMoreRetrieval(int eofProgramCounter,ExtensionTable.Retrieval retrieval) { m_eofProgramCounter=eofProgramCounter; m_retrieval=retrieval; } public int execute(int programCounter) { if (m_retrieval.afterLast()) return m_eofProgramCounter; else return programCounter+1; } public int getBranchingAddress() { return m_eofProgramCounter; } public void setBranchingAddress(int branchingAddress) { m_eofProgramCounter=branchingAddress; } public String toString() { return "Branch to "+m_eofProgramCounter+" if "+m_retrieval.getBindingsBuffer()[m_retrieval.getBindingPositions()[0]]+" is empty"; } } protected static final class JumpTo implements BranchingWorker,Serializable { private static final long serialVersionUID=-6957866973028474739L; protected int m_jumpTo; public JumpTo(int jumpTo) { m_jumpTo=jumpTo; } public int execute(int programCounter) { return m_jumpTo; } public int getBranchingAddress() { return m_jumpTo; } public void setBranchingAddress(int branchingAddress) { m_jumpTo=branchingAddress; } public String toString() { return "Jump to "+m_jumpTo; } } protected static final class CallMatchStartedOnMonitor implements Worker,Serializable { private static final long serialVersionUID=8736659573939242252L; protected final TableauMonitor m_tableauMonitor; protected final DLClauseEvaluator m_dlClauseEvaluator; protected final int m_dlClauseIndex; public CallMatchStartedOnMonitor(TableauMonitor tableauMonitor,DLClauseEvaluator dlClauseEvaluator,int dlClauseIndex) { m_tableauMonitor=tableauMonitor; m_dlClauseEvaluator=dlClauseEvaluator; m_dlClauseIndex=dlClauseIndex; } public int execute(int programCounter) { m_tableauMonitor.dlClauseMatchedStarted(m_dlClauseEvaluator,m_dlClauseIndex); return programCounter+1; } public String toString() { return "Monitor -> Match started"; } } protected static final class CallMatchFinishedOnMonitor implements Worker,Serializable { private static final long serialVersionUID=1046400921858176361L; protected final TableauMonitor m_tableauMonitor; protected final DLClauseEvaluator m_dlClauseEvaluator; protected final int m_dlClauseIndex; public CallMatchFinishedOnMonitor(TableauMonitor tableauMonitor,DLClauseEvaluator dlClauseEvaluator,int dlClauseIndex) { m_tableauMonitor=tableauMonitor; m_dlClauseEvaluator=dlClauseEvaluator; m_dlClauseIndex=dlClauseIndex; } public int execute(int programCounter) { m_tableauMonitor.dlClauseMatchedFinished(m_dlClauseEvaluator,m_dlClauseIndex); return programCounter+1; } public String toString() { return "Monitor -> Match finished"; } } protected static final class SetClash implements Worker,Serializable { private static final long serialVersionUID=-4981087765064918953L; protected final ExtensionManager m_extensionManager; protected final DependencySet m_dependencySet; public SetClash(ExtensionManager extensionManager,DependencySet dependencySet) { m_extensionManager=extensionManager; m_dependencySet=dependencySet; } public int execute(int programCounter) { m_extensionManager.setClash(m_dependencySet); return programCounter+1; } public String toString() { return "Set clash"; } } protected static final class DeriveUnaryFact implements Worker,Serializable { private static final long serialVersionUID=7883620022252842010L; protected final ExtensionManager m_extensionManager; protected final Object[] m_valuesBuffer; protected final boolean[] m_coreVariables; protected final DependencySet m_dependencySet; protected final DLPredicate m_dlPredicate; protected final int m_argumentIndex; public DeriveUnaryFact(ExtensionManager extensionManager,Object[] valuesBuffer,boolean[] coreVariables,DependencySet dependencySet,DLPredicate dlPredicate,int argumentIndex) { m_extensionManager=extensionManager; m_valuesBuffer=valuesBuffer; m_coreVariables=coreVariables; m_dependencySet=dependencySet; m_argumentIndex=argumentIndex; m_dlPredicate=dlPredicate; } public int execute(int programCounter) { Node argument=(Node)m_valuesBuffer[m_argumentIndex]; boolean isCore=m_coreVariables[m_argumentIndex]; m_extensionManager.addAssertion(m_dlPredicate,argument,m_dependencySet,isCore); return programCounter+1; } public String toString() { return "Derive unary fact"; } } protected static final class DeriveBinaryFact implements Worker,Serializable { private static final long serialVersionUID=1823363493615682288L; protected final ExtensionManager m_extensionManager; protected final Object[] m_valuesBuffer; protected final DependencySet m_dependencySet; protected final DLPredicate m_dlPredicate; protected final int m_argumentIndex1; protected final int m_argumentIndex2; public DeriveBinaryFact(ExtensionManager extensionManager,Object[] valuesBuffer,DependencySet dependencySet,DLPredicate dlPredicate,int argumentIndex1,int argumentIndex2) { m_extensionManager=extensionManager; m_valuesBuffer=valuesBuffer; m_dependencySet=dependencySet; m_dlPredicate=dlPredicate; m_argumentIndex1=argumentIndex1; m_argumentIndex2=argumentIndex2; } public int execute(int programCounter) { Node argument1=(Node)m_valuesBuffer[m_argumentIndex1]; Node argument2=(Node)m_valuesBuffer[m_argumentIndex2]; m_extensionManager.addAssertion(m_dlPredicate,argument1,argument2,m_dependencySet,true); return programCounter+1; } public String toString() { return "Derive binary fact"; } } protected static final class DeriveTernaryFact implements Worker,Serializable { private static final long serialVersionUID=1823363493615682288L; protected final ExtensionManager m_extensionManager; protected final Object[] m_valuesBuffer; protected final DependencySet m_dependencySet; protected final DLPredicate m_dlPredicate; protected final int m_argumentIndex1; protected final int m_argumentIndex2; protected final int m_argumentIndex3; public DeriveTernaryFact(ExtensionManager extensionManager,Object[] valuesBuffer,DependencySet dependencySet,DLPredicate dlPredicate,int argumentIndex1,int argumentIndex2,int argumentIndex3) { m_extensionManager=extensionManager; m_valuesBuffer=valuesBuffer; m_dependencySet=dependencySet; m_dlPredicate=dlPredicate; m_argumentIndex1=argumentIndex1; m_argumentIndex2=argumentIndex2; m_argumentIndex3=argumentIndex3; } public int execute(int programCounter) { Node argument1=(Node)m_valuesBuffer[m_argumentIndex1]; Node argument2=(Node)m_valuesBuffer[m_argumentIndex2]; Node argument3=(Node)m_valuesBuffer[m_argumentIndex3]; m_extensionManager.addAssertion(m_dlPredicate,argument1,argument2,argument3,m_dependencySet,true); return programCounter+1; } public String toString() { return "Derive ternary fact"; } } protected static final class DeriveDisjunction implements Worker,Serializable { private static final long serialVersionUID=-3546622575743138887L; protected final Tableau m_tableau; protected final Object[] m_valuesBuffer; protected final boolean[] m_coreVariables; protected final DependencySet m_dependencySet; protected final GroundDisjunctionHeader m_groundDisjunctionHeader; protected final int[] m_copyIsCore; protected final int[] m_copyValuesToArguments; public DeriveDisjunction(Object[] valuesBuffer,boolean[] coreVariables,DependencySet dependencySet,Tableau tableau,GroundDisjunctionHeader groundDisjunctionHeader,int[] copyIsCore,int[] copyValuesToArguments) { m_valuesBuffer=valuesBuffer; m_coreVariables=coreVariables; m_dependencySet=dependencySet; m_tableau=tableau; m_groundDisjunctionHeader=groundDisjunctionHeader; m_copyIsCore=copyIsCore; m_copyValuesToArguments=copyValuesToArguments; } public void clear() { } public int execute(int programCounter) { Node[] arguments=new Node[m_copyValuesToArguments.length]; for (int argumentIndex=m_copyValuesToArguments.length-1;argumentIndex>=0;--argumentIndex) arguments[argumentIndex]=(Node)m_valuesBuffer[m_copyValuesToArguments[argumentIndex]]; boolean[] isCore=new boolean[m_copyIsCore.length]; for (int copyIndex=m_copyIsCore.length-1;copyIndex>=0;--copyIndex) { int copyFrom=m_copyIsCore[copyIndex]; if (copyFrom==-1) isCore[copyIndex]=true; else isCore[copyIndex]=m_coreVariables[copyFrom]; } GroundDisjunction groundDisjunction=new GroundDisjunction(m_tableau,m_groundDisjunctionHeader,arguments,isCore,m_tableau.m_dependencySetFactory.getPermanent(m_dependencySet)); if (!groundDisjunction.isSatisfied(m_tableau)) m_tableau.addGroundDisjunction(groundDisjunction); return programCounter+1; } public String toString() { return "Derive disjunction"; } } protected static final class DLClauseCompiler extends ConjunctionCompiler { protected final DLClauseEvaluator m_dlClauseEvalautor; protected final GroundDisjunctionHeaderManager m_groundDisjunctionHeaderManager; protected final ExistentialExpansionStrategy m_existentialExpansionStrategy; protected final DLClause m_bodyDLClause; protected final List<DLClause> m_headDLClauses; protected final boolean[] m_coreVariables; public DLClauseCompiler(BufferSupply bufferSupply,ValuesBufferManager valuesBufferManager,GroundDisjunctionHeaderManager groundDisjunctionHeaderManager,Map<Integer,UnionDependencySet> unionDependencySetsBySize,DLClauseEvaluator dlClauseEvalautor,ExtensionManager extensionManager,ExistentialExpansionStrategy existentialExpansionStrategy,DLClause bodyDLClause,List<DLClause> headDLClauses,ExtensionTable.Retrieval firstAtomRetrieval) { super(bufferSupply,valuesBufferManager,unionDependencySetsBySize,extensionManager,bodyDLClause.getBodyAtoms(),getHeadVariables(headDLClauses)); m_groundDisjunctionHeaderManager=groundDisjunctionHeaderManager; m_dlClauseEvalautor=dlClauseEvalautor; m_existentialExpansionStrategy=existentialExpansionStrategy; m_bodyDLClause=bodyDLClause; m_headDLClauses=headDLClauses; m_coreVariables=new boolean[m_variables.size()]; generateCode(1,firstAtomRetrieval); } protected int getNumberOfHeads() { return m_headDLClauses.size(); } protected int getHeadLength(int dlClauseIndex) { return m_headDLClauses.get(dlClauseIndex).getHeadLength(); } protected Atom getHeadAtom(int dlClauseIndex,int atomIndex) { return m_headDLClauses.get(dlClauseIndex).getHeadAtom(atomIndex); } protected void compileHeads() { m_existentialExpansionStrategy.dlClauseBodyCompiled(m_workers,m_bodyDLClause,m_variables,m_valuesBufferManager.m_valuesBuffer,m_coreVariables); for (int dlClauseIndex=0;dlClauseIndex<getNumberOfHeads();dlClauseIndex++) { if (m_extensionManager.m_tableauMonitor!=null) m_workers.add(new CallMatchStartedOnMonitor(m_extensionManager.m_tableauMonitor,m_dlClauseEvalautor,dlClauseIndex)); if (getHeadLength(dlClauseIndex)==0) m_workers.add(new SetClash(m_extensionManager,m_unionDependencySet)); else if (getHeadLength(dlClauseIndex)==1) { Atom atom=getHeadAtom(dlClauseIndex,0); switch (atom.getArity()) { case 1: m_workers.add(new DeriveUnaryFact(m_extensionManager,m_valuesBufferManager.m_valuesBuffer,m_coreVariables,m_unionDependencySet,atom.getDLPredicate(),m_variables.indexOf(atom.getArgumentVariable(0)))); break; case 2: m_workers.add(new DeriveBinaryFact(m_extensionManager,m_valuesBufferManager.m_valuesBuffer,m_unionDependencySet,atom.getDLPredicate(),m_variables.indexOf(atom.getArgumentVariable(0)),m_variables.indexOf(atom.getArgumentVariable(1)))); break; case 3: m_workers.add(new DeriveTernaryFact(m_extensionManager,m_valuesBufferManager.m_valuesBuffer,m_unionDependencySet,atom.getDLPredicate(),m_variables.indexOf(atom.getArgumentVariable(0)),m_variables.indexOf(atom.getArgumentVariable(1)),m_variables.indexOf(atom.getArgumentVariable(2)))); break; default: throw new IllegalArgumentException("Unsupported atom arity."); } } else { int totalNumberOfArguments=0; for (int headIndex=0;headIndex<getHeadLength(dlClauseIndex);headIndex++) totalNumberOfArguments+=getHeadAtom(dlClauseIndex,headIndex).getArity(); DLPredicate[] headDLPredicates=new DLPredicate[getHeadLength(dlClauseIndex)]; int[] copyIsCore=new int[getHeadLength(dlClauseIndex)]; int[] copyValuesToArguments=new int[totalNumberOfArguments]; int index=0; for (int headIndex=0;headIndex<getHeadLength(dlClauseIndex);headIndex++) { Atom atom=getHeadAtom(dlClauseIndex,headIndex); headDLPredicates[headIndex]=atom.getDLPredicate(); for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); int variableIndex=m_variables.indexOf(variable); assert variableIndex!=-1; copyValuesToArguments[index++]=variableIndex; } if (headDLPredicates[headIndex].getArity()==1) { Variable variable=atom.getArgumentVariable(0); copyIsCore[headIndex]=m_variables.indexOf(variable); } else copyIsCore[headIndex]=-1; } GroundDisjunctionHeader groundDisjunctionHeader=m_groundDisjunctionHeaderManager.get(headDLPredicates); m_workers.add(new DeriveDisjunction(m_valuesBufferManager.m_valuesBuffer,m_coreVariables,m_unionDependencySet,m_extensionManager.m_tableau,groundDisjunctionHeader,copyIsCore,copyValuesToArguments)); } if (m_extensionManager.m_tableauMonitor!=null) m_workers.add(new CallMatchFinishedOnMonitor(m_extensionManager.m_tableauMonitor,m_dlClauseEvalautor,dlClauseIndex)); } } protected static List<Variable> getHeadVariables(List<DLClause> headDLClauses) { List<Variable> result=new ArrayList<Variable>(); for (DLClause dlClause : headDLClauses) { for (int headIndex=0;headIndex<dlClause.getHeadLength();headIndex++) { Atom atom=dlClause.getHeadAtom(headIndex); for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); if (variable!=null && !result.contains(variable)) result.add(variable); } } } return result; } } public static abstract class ConjunctionCompiler { protected final BufferSupply m_bufferSupply; protected final ValuesBufferManager m_valuesBufferManager; protected final ExtensionManager m_extensionManager; protected final Atom[] m_bodyAtoms; protected final List<Variable> m_variables; protected final Set<Variable> m_boundSoFar; protected final UnionDependencySet m_unionDependencySet; protected final List<ExtensionTable.Retrieval> m_retrievals; public final List<Worker> m_workers; protected final List<Integer> m_labels; public ConjunctionCompiler(BufferSupply bufferSupply,ValuesBufferManager valuesBufferManager,Map<Integer,UnionDependencySet> unionDependencySetsBySize,ExtensionManager extensionManager,Atom[] bodyAtoms,List<Variable> headVariables) { m_bufferSupply=bufferSupply; m_valuesBufferManager=valuesBufferManager; m_extensionManager=extensionManager; m_bodyAtoms=bodyAtoms; m_variables=new ArrayList<Variable>(); m_boundSoFar=new HashSet<Variable>(); int numberOfRealAtoms=0; for (int bodyIndex=0;bodyIndex<getBodyLength();bodyIndex++) { Atom atom=getBodyAtom(bodyIndex); for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); if (variable!=null && !m_variables.contains(variable) && occursInBodyAtomsAfter(variable,bodyIndex+1)) m_variables.add(variable); } if (!atom.getDLPredicate().equals(NodeIDLessEqualThan.INSTANCE) && !(atom.getDLPredicate() instanceof NodeIDsAscendingOrEqual)) numberOfRealAtoms++; } for (Variable variable : headVariables) if (!m_variables.contains(variable)) m_variables.add(variable); if (unionDependencySetsBySize!=null) { Integer numberOfRealAtomsInteger=Integer.valueOf(numberOfRealAtoms); UnionDependencySet unionDependencySet=unionDependencySetsBySize.get(numberOfRealAtomsInteger); if (unionDependencySet==null) { unionDependencySet=new UnionDependencySet(numberOfRealAtoms); unionDependencySetsBySize.put(numberOfRealAtomsInteger,unionDependencySet); } m_unionDependencySet=unionDependencySet; } else m_unionDependencySet=null; m_retrievals=new ArrayList<ExtensionTable.Retrieval>(); m_workers=new ArrayList<Worker>(); m_labels=new ArrayList<Integer>(); } protected final void generateCode(int firstBodyAtomToCompile,ExtensionTable.Retrieval firstAtomRetrieval) { m_labels.add(null); m_retrievals.add(firstAtomRetrieval); int afterRule=addLabel(); if (firstBodyAtomToCompile>0) { compileCheckUnboundVariableMatches(getBodyAtom(0),firstAtomRetrieval,afterRule); compileGenerateBindings(firstAtomRetrieval,getBodyAtom(0)); if (m_unionDependencySet!=null) m_workers.add(new CopyDependencySet(firstAtomRetrieval,m_unionDependencySet.m_dependencySets,0)); } compileBodyAtom(firstBodyAtomToCompile,afterRule); setLabelProgramCounter(afterRule); for (Worker worker : m_workers) if (worker instanceof BranchingWorker) { BranchingWorker branchingWorker=(BranchingWorker)worker; int branchingAddress=branchingWorker.getBranchingAddress(); if (branchingAddress<0) { int resolvedAddress=m_labels.get(-branchingAddress); branchingWorker.setBranchingAddress(resolvedAddress); } } } protected final boolean occursInBodyAtomsAfter(Variable variable,int startIndex) { for (int argumentIndex=startIndex;argumentIndex<getBodyLength();argumentIndex++) if (getBodyAtom(argumentIndex).containsVariable(variable)) return true; return false; } protected final void compileBodyAtom(int bodyAtomIndex,int lastAtomNextElement) { if (bodyAtomIndex==getBodyLength()) compileHeads(); else if (getBodyAtom(bodyAtomIndex).getDLPredicate().equals(NodeIDLessEqualThan.INSTANCE)) { Atom atom=getBodyAtom(bodyAtomIndex); int variable1Index=m_variables.indexOf(atom.getArgumentVariable(0)); int variable2Index=m_variables.indexOf(atom.getArgumentVariable(1)); assert variable1Index!=-1; assert variable2Index!=-1; m_workers.add(new BranchIfNotNodeIDLessEqualThan(lastAtomNextElement,m_valuesBufferManager.m_valuesBuffer,variable1Index,variable2Index)); compileBodyAtom(bodyAtomIndex+1,lastAtomNextElement); } else if (getBodyAtom(bodyAtomIndex).getDLPredicate() instanceof NodeIDsAscendingOrEqual) { Atom atom=getBodyAtom(bodyAtomIndex); int[] nodeIndexes=new int[atom.getArity()]; for (int index=0;index<atom.getArity();index++) { nodeIndexes[index]=m_variables.indexOf(atom.getArgumentVariable(index)); assert nodeIndexes[index]!=-1; } m_workers.add(new BranchIfNotNodeIDsAscendingOrEqual(lastAtomNextElement,m_valuesBufferManager.m_valuesBuffer,nodeIndexes)); compileBodyAtom(bodyAtomIndex+1,lastAtomNextElement); } else { // Each atom is compiled into the following structure: // // retrieval.open() // loopStart: if (!retrieval.hasMore) goto afterLoop // if (!retrieval.unboundVariableMatches) goto nextElement // generate bindings - copy bindings from the retrieval to the values buffer // copy the dependency set from the retrieval into the union dependency set // < the code for the next atom > // nextElement: retrieval.next // goto loopStart // afterLoop: // // NodeIDLessEqualThan and NodeIDsAscendingOrEqual atoms are compiled such that they // immediately jump to the next element of the previous regular atom. int afterLoop=addLabel(); int nextElement=addLabel(); Atom atom=getBodyAtom(bodyAtomIndex); int[] bindingPositions=new int[atom.getArity()+1]; bindingPositions[0]=m_valuesBufferManager.m_bodyDLPredicatesToIndexes.get(atom.getDLPredicate()).intValue(); for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Term term=atom.getArgument(argumentIndex); if (term instanceof Variable) { if (m_boundSoFar.contains(term)) bindingPositions[argumentIndex+1]=m_variables.indexOf((Variable)term); else bindingPositions[argumentIndex+1]=-1; } else bindingPositions[argumentIndex+1]=m_valuesBufferManager.m_bodyNonvariableTermsToIndexes.get(term).intValue(); } ExtensionTable.Retrieval retrieval=m_extensionManager.getExtensionTable(atom.getArity()+1).createRetrieval(bindingPositions,m_valuesBufferManager.m_valuesBuffer,m_bufferSupply.getBuffer(atom.getArity()+1),false,ExtensionTable.View.EXTENSION_THIS); m_retrievals.add(retrieval); m_workers.add(new OpenRetrieval(retrieval)); int loopStart=m_workers.size(); m_workers.add(new HasMoreRetrieval(afterLoop,retrieval)); compileCheckUnboundVariableMatches(atom,retrieval,nextElement); compileGenerateBindings(retrieval,atom); if (m_unionDependencySet!=null) m_workers.add(new CopyDependencySet(retrieval,m_unionDependencySet.m_dependencySets,m_retrievals.size()-1)); compileBodyAtom(bodyAtomIndex+1,nextElement); setLabelProgramCounter(nextElement); m_workers.add(new NextRetrieval(retrieval)); m_workers.add(new JumpTo(loopStart)); setLabelProgramCounter(afterLoop); } } protected final int getBodyLength() { return m_bodyAtoms.length; } protected final Atom getBodyAtom(int atomIndex) { return m_bodyAtoms[atomIndex]; } protected final void compileCheckUnboundVariableMatches(Atom atom,ExtensionTable.Retrieval retrieval,int jumpIndex) { for (int outerArgumentIndex=0;outerArgumentIndex<atom.getArity();outerArgumentIndex++) { Variable variable=atom.getArgumentVariable(outerArgumentIndex); if (variable!=null && !m_boundSoFar.contains(variable)) { for (int innerArgumentIndex=outerArgumentIndex+1;innerArgumentIndex<atom.getArity();innerArgumentIndex++) { if (variable.equals(atom.getArgument(innerArgumentIndex))) m_workers.add(new BranchIfNotEqual(jumpIndex,retrieval.getTupleBuffer(),outerArgumentIndex+1,innerArgumentIndex+1)); } } } } protected final void compileGenerateBindings(ExtensionTable.Retrieval retrieval,Atom atom) { for (int argumentIndex=0;argumentIndex<atom.getArity();argumentIndex++) { Variable variable=atom.getArgumentVariable(argumentIndex); if (variable!=null && !m_boundSoFar.contains(variable)) { int variableIndex=m_variables.indexOf(variable); if (variableIndex!=-1) { m_workers.add(new CopyValues(retrieval.getTupleBuffer(),argumentIndex+1,m_valuesBufferManager.m_valuesBuffer,variableIndex)); m_boundSoFar.add(variable); } } } } protected final int addLabel() { int labelIndex=m_labels.size(); m_labels.add(null); return -labelIndex; } protected final void setLabelProgramCounter(int labelID) { m_labels.set(-labelID,Integer.valueOf(m_workers.size())); } protected abstract void compileHeads(); } }