/* 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.debugger; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import org.semanticweb.HermiT.Prefixes; import org.semanticweb.HermiT.model.Concept; import org.semanticweb.HermiT.model.DLClause; import org.semanticweb.HermiT.model.DLPredicate; import org.semanticweb.HermiT.model.DataRange; import org.semanticweb.HermiT.model.ConstantEnumeration; import org.semanticweb.HermiT.model.DatatypeRestriction; import org.semanticweb.HermiT.model.Equality; import org.semanticweb.HermiT.model.ExistentialConcept; import org.semanticweb.HermiT.model.Inequality; import org.semanticweb.HermiT.model.NodeIDLessEqualThan; import org.semanticweb.HermiT.model.NodeIDsAscendingOrEqual; import org.semanticweb.HermiT.monitor.TableauMonitorAdapter; import org.semanticweb.HermiT.tableau.BranchingPoint; import org.semanticweb.HermiT.tableau.DLClauseEvaluator; import org.semanticweb.HermiT.tableau.DatatypeManager; import org.semanticweb.HermiT.tableau.GroundDisjunction; import org.semanticweb.HermiT.tableau.Node; public class DerivationHistory extends TableauMonitorAdapter { private static final long serialVersionUID=-3963478091986772947L; protected static final Object[] EMPTY_TUPLE=new Object[0]; protected final Map<AtomKey,Atom> m_derivedAtoms; protected final Map<GroundDisjunction,Disjunction> m_derivedDisjunctions; protected final Stack<Derivation> m_derivations; protected final Stack<Atom> m_mergeAtoms; public DerivationHistory() { m_derivedAtoms=new HashMap<AtomKey,Atom>(); m_derivedDisjunctions=new HashMap<GroundDisjunction,Disjunction>(); m_derivations=new Stack<Derivation>(); m_mergeAtoms=new Stack<Atom>(); } public void tableauCleared() { m_derivedAtoms.clear(); m_derivedDisjunctions.clear(); m_derivations.clear(); m_derivations.push(BaseFact.INSTANCE); m_mergeAtoms.clear(); } public void dlClauseMatchedStarted(DLClauseEvaluator dlClauseEvaluator,int dlClauseIndex) { int regularBodyAtomsNumber=0; for (int index=0;index<dlClauseEvaluator.getBodyLength();index++) { DLPredicate dlPredicate=dlClauseEvaluator.getBodyAtom(index).getDLPredicate(); if (!(dlPredicate instanceof NodeIDLessEqualThan) && !(dlPredicate instanceof NodeIDsAscendingOrEqual)) regularBodyAtomsNumber++; } Atom[] premises=new Atom[regularBodyAtomsNumber]; int atomIndex=0; for (int index=0;index<premises.length;index++) { DLPredicate dlPredicate=dlClauseEvaluator.getBodyAtom(index).getDLPredicate(); if (!(dlPredicate instanceof NodeIDLessEqualThan) || !(dlPredicate instanceof NodeIDsAscendingOrEqual)) premises[atomIndex++]=getAtom(dlClauseEvaluator.getTupleMatchedToBody(index)); } m_derivations.push(new DLClauseApplication(dlClauseEvaluator.getDLClause(dlClauseIndex),premises)); } public void dlClauseMatchedFinished(DLClauseEvaluator dlClauseEvaluator) { m_derivations.pop(); } public void addFactFinished(Object[] tuple,boolean isCore,boolean factAdded) { if (factAdded) addAtom(tuple); } public void mergeStarted(Node nodeFrom,Node nodeInto) { Atom equalityAtom=addAtom(new Object[] { Equality.INSTANCE,nodeFrom,nodeInto }); m_mergeAtoms.add(equalityAtom); } public void mergeFactStarted(Node mergeFrom,Node mergeInto,Object[] sourceTuple,Object[] targetTuple) { m_derivations.push(new Merging(m_mergeAtoms.peek(),getAtom(sourceTuple))); } public void mergeFactFinished(Node mergeFrom,Node mergeInto,Object[] sourceTuple,Object[] targetTuple) { m_derivations.pop(); } public void mergeFinished(Node nodeFrom,Node nodeInto) { m_mergeAtoms.pop(); } public void clashDetectionStarted(Object[]... tuples) { Atom[] atoms=new Atom[tuples.length]; for (int index=0;index<tuples.length;index++) atoms[index]=getAtom(tuples[index]); m_derivations.push(new ClashDetection(atoms)); } public void clashDetectionFinished(Object[]... tuples) { m_derivations.pop(); } public void clashDetected() { addAtom(EMPTY_TUPLE); } public void tupleRemoved(Object[] tuple) { m_derivedAtoms.remove(new AtomKey(tuple)); } public void backtrackToFinished(BranchingPoint newCurrentBrancingPoint) { m_derivedAtoms.remove(new AtomKey(EMPTY_TUPLE)); } public void groundDisjunctionDerived(GroundDisjunction groundDisjunction) { Disjunction disjunction=new Disjunction(groundDisjunction,m_derivations.peek()); m_derivedDisjunctions.put(groundDisjunction,disjunction); } public void disjunctProcessingStarted(GroundDisjunction groundDisjunction,int disjunct) { Disjunction disjunction=getDisjunction(groundDisjunction); m_derivations.push(new DisjunctApplication(disjunction,disjunct)); } public void disjunctProcessingFinished(GroundDisjunction groundDisjunction,int disjunct) { m_derivations.pop(); } public void existentialExpansionStarted(ExistentialConcept existentialConcept,Node forNode) { Atom existentialAtom=getAtom(new Object[] { existentialConcept,forNode }); m_derivations.push(new ExistentialExpansion(existentialAtom)); } public void existentialExpansionFinished(ExistentialConcept existentialConcept,Node forNode) { m_derivations.pop(); } public void descriptionGraphCheckingStarted(int graphIndex1,int tupleIndex1,int position1,int graphIndex2,int tupleIndex2,int position2) { Atom graph1=getAtom(m_tableau.getDescriptionGraphManager().getDescriptionGraphTuple(graphIndex1,tupleIndex1)); Atom graph2=getAtom(m_tableau.getDescriptionGraphManager().getDescriptionGraphTuple(graphIndex2,tupleIndex2)); m_derivations.push(new GraphChecking(graph1,position1,graph2,position2)); } public void descriptionGraphCheckingFinished(int graphIndex1,int tupleIndex1,int position1,int graphIndex2,int tupleIndex2,int position2) { m_derivations.pop(); } public void unknownDatatypeRestrictionDetectionStarted(DataRange dataRange1,Node node1,DataRange dataRange2,Node node2) { Atom atom1=getAtom(new Object[] { dataRange1,node1 }); Atom atom2=getAtom(new Object[] { dataRange2,node2 }); m_derivations.push(new UnknownDatatypeRestrictionDetection(new Atom[] { atom1,atom2 })); } public void unknownDatatypeRestrictionDetectionFinished(DataRange dataRange1,Node node1, DataRange dataRange2,Node node2) { m_derivations.pop(); } public void datatypeConjunctionCheckingStarted(DatatypeManager.DConjunction conjunction) { List<Atom> atoms=new ArrayList<Atom>(); for (DatatypeManager.DVariable variable : conjunction.getActiveVariables()) { Node node=variable.getNode(); for (DatatypeRestriction datatypeRestriction : variable.getPositiveDatatypeRestrictions()) atoms.add(getAtom(new Object[] { datatypeRestriction,node })); for (DatatypeRestriction datatypeRestriction : variable.getNegativeDatatypeRestrictions()) atoms.add(getAtom(new Object[] { datatypeRestriction.getNegation(),node })); for (ConstantEnumeration dataValueEnumeration : variable.getPositiveDataValueEnumerations()) atoms.add(getAtom(new Object[] { dataValueEnumeration,node })); for (ConstantEnumeration dataValueEnumeration : variable.getNegativeDataValueEnumerations()) atoms.add(getAtom(new Object[] { dataValueEnumeration.getNegation(),node })); for (DatatypeManager.DVariable neighborVariable : variable.getUnequalToDirect()) atoms.add(getAtom(new Object[] { Inequality.INSTANCE,node,neighborVariable.getNode() })); } Atom[] atomsArray=new Atom[atoms.size()]; atoms.toArray(atomsArray); m_derivations.push(new DatatypeChecking(atomsArray)); } public void datatypeConjunctionCheckingFinished(DatatypeManager.DConjunction conjunction,boolean result) { m_derivations.pop(); } public Atom getAtom(Object[] tuple) { return m_derivedAtoms.get(new AtomKey(tuple)); } public Disjunction getDisjunction(GroundDisjunction groundDisjunction) { return m_derivedDisjunctions.get(groundDisjunction); } protected Atom addAtom(Object[] tuple) { Object[] clonedTuple=tuple.clone(); Atom newAtom=new Atom(clonedTuple,m_derivations.peek()); m_derivedAtoms.put(new AtomKey(clonedTuple),newAtom); return newAtom; } protected static class AtomKey implements Serializable { private static final long serialVersionUID=1409033744982881556L; protected final Object[] m_tuple; protected final int m_hashCode; public AtomKey(Object[] tuple) { m_tuple=tuple; int hashCode=0; for (int index=0;index<tuple.length;index++) hashCode+=tuple[index].hashCode(); m_hashCode=hashCode; } public int hashCode() { return m_hashCode; } public boolean equals(Object that) { if (this==that) return true; if (!(that instanceof AtomKey)) return false; AtomKey thatAtomKey=(AtomKey)that; if (m_tuple.length!=thatAtomKey.m_tuple.length) return false; for (int index=0;index<m_tuple.length;index++) if (!m_tuple[index].equals(thatAtomKey.m_tuple[index])) return false; return true; } } protected static interface Fact extends Serializable { String toString(Prefixes prefixes); Derivation getDerivation(); } public static class Atom implements Fact { private static final long serialVersionUID=-6136317748590721560L; protected final Object[] m_tuple; protected final Derivation m_derivedBy; public Atom(Object[] tuple,Derivation derivedBy) { m_tuple=tuple; m_derivedBy=derivedBy; } public Object getDLPredicate() { return m_tuple[0]; } public int getArity() { return m_tuple.length-1; } public Node getArgument(int index) { return (Node)m_tuple[index+1]; } public Derivation getDerivation() { return m_derivedBy; } public String toString(Prefixes prefixes) { if (m_tuple.length==0) return "[ ]"; else { StringBuffer buffer=new StringBuffer(); Object dlPredicate=getDLPredicate(); if (org.semanticweb.HermiT.model.Atom.s_infixPredicates.contains(dlPredicate)) { buffer.append(getArgument(0).getNodeID()); buffer.append(' '); buffer.append(((DLPredicate)dlPredicate).toString(prefixes)); buffer.append(' '); buffer.append(getArgument(1).getNodeID()); } else { if (dlPredicate instanceof DLPredicate) buffer.append(((DLPredicate)dlPredicate).toString(prefixes)); else if (dlPredicate instanceof Concept) buffer.append(((Concept)dlPredicate).toString(prefixes)); else throw new IllegalStateException("Internal error: invalid DL-predicate."); buffer.append('('); for (int argumentIndex=0;argumentIndex<getArity();argumentIndex++) { if (argumentIndex!=0) buffer.append(','); buffer.append(getArgument(argumentIndex).getNodeID()); } buffer.append(')'); } return buffer.toString(); } } public String toString() { return toString(Prefixes.STANDARD_PREFIXES); } } public static class Disjunction implements Fact { private static final long serialVersionUID=-6645342875287836609L; protected final Object[][] m_atoms; protected final Derivation m_derivedBy; public Disjunction(GroundDisjunction groundDisjunction,Derivation derivedBy) { m_atoms=new Object[groundDisjunction.getNumberOfDisjuncts()][]; for (int disjunctIndex=0;disjunctIndex<groundDisjunction.getNumberOfDisjuncts();disjunctIndex++) { DLPredicate dlPredicate=groundDisjunction.getDLPredicate(disjunctIndex); Object[] tuple=new Object[dlPredicate.getArity()+1]; tuple[0]=dlPredicate; for (int argumentIndex=0;argumentIndex<dlPredicate.getArity();argumentIndex++) tuple[argumentIndex+1]=groundDisjunction.getArgument(disjunctIndex,argumentIndex); m_atoms[disjunctIndex]=tuple; } m_derivedBy=derivedBy; } public int getNumberOfDisjuncts() { return m_atoms.length; } public Object getDLPredicate(int disjunctIndex) { return m_atoms[disjunctIndex][0]; } public Node getArgument(int disjunctIndex,int argumentIndex) { return (Node)m_atoms[disjunctIndex][argumentIndex+1]; } public Derivation getDerivation() { return m_derivedBy; } public String toString(Prefixes prefixes) { StringBuffer buffer=new StringBuffer(); for (int disjunctIndex=0;disjunctIndex<m_atoms.length;disjunctIndex++) { if (disjunctIndex!=0) buffer.append(" v "); Object[] tuple=m_atoms[disjunctIndex]; if (tuple[0] instanceof DLPredicate) buffer.append(((DLPredicate)tuple[0]).toString(prefixes)); else if (tuple[0] instanceof Concept) buffer.append(((Concept)tuple[0]).toString(prefixes)); else throw new IllegalStateException("Internal error: invalid DL-predicate."); buffer.append('('); for (int argumentIndex=1;argumentIndex<tuple.length;argumentIndex++) { if (argumentIndex!=1) buffer.append(','); buffer.append(((Node)tuple[argumentIndex]).getNodeID()); } buffer.append(')'); } return buffer.toString(); } public String toString() { return toString(Prefixes.STANDARD_PREFIXES); } } @SuppressWarnings("serial") public abstract static class Derivation implements Serializable { public abstract String toString(Prefixes prefixes); public String toString() { return toString(Prefixes.STANDARD_PREFIXES); } public abstract int getNumberOfPremises(); public abstract Fact getPremise(int premiseIndex); } public static class DLClauseApplication extends Derivation { private static final long serialVersionUID=5841561027229354512L; protected final DLClause m_dlClause; protected final Atom[] m_premises; public DLClauseApplication(DLClause dlClause,Atom[] premises) { m_dlClause=dlClause; m_premises=premises; } public DLClause getDLClause() { return m_dlClause; } public int getNumberOfPremises() { return m_premises.length; } public Fact getPremise(int premiseIndex) { return m_premises[premiseIndex]; } public String toString(Prefixes prefixes) { return " <-- "+m_dlClause.toString(prefixes); } } public static class DisjunctApplication extends Derivation { private static final long serialVersionUID=6657356873675430986L; protected final Disjunction m_disjunction; protected final int m_disjunctIndex; public DisjunctApplication(Disjunction disjunction,int disjunctIndex) { m_disjunction=disjunction; m_disjunctIndex=disjunctIndex; } public int getDisjunctIndex() { return m_disjunctIndex; } public int getNumberOfPremises() { return 1; } public Fact getPremise(int premiseIndex) { switch (premiseIndex) { case 0: return m_disjunction; default: throw new IndexOutOfBoundsException(); } } public String toString(Prefixes prefixes) { return " | "+String.valueOf(m_disjunctIndex); } } public static class Merging extends Derivation { private static final long serialVersionUID=6815119442652251306L; protected final Atom m_equality; protected final Atom m_fromAtom; public Merging(Atom equality,Atom fromAtom) { m_equality=equality; m_fromAtom=fromAtom; } public int getNumberOfPremises() { return 2; } public Fact getPremise(int premiseIndex) { switch (premiseIndex) { case 0: return m_equality; case 1: return m_fromAtom; default: throw new IndexOutOfBoundsException(); } } public String toString(Prefixes prefixes) { return " <--|"; } } public static class GraphChecking extends Derivation { private static final long serialVersionUID=-3671522413313454739L; protected final Atom m_graph1; protected final int m_position1; protected final Atom m_graph2; protected final int m_position2; public GraphChecking(Atom graph1,int position1,Atom graph2,int position2) { m_graph1=graph1; m_position1=position1; m_graph2=graph2; m_position2=position2; } public int getNumberOfPremises() { return 2; } public Fact getPremise(int premiseIndex) { switch (premiseIndex) { case 0: return m_graph1; case 1: return m_graph2; default: throw new IndexOutOfBoundsException(); } } public String toString(Prefixes prefixes) { return " << DGRAPHS | "+m_position1+" and "+m_position2; } } public static class ExistentialExpansion extends Derivation { private static final long serialVersionUID=-1266097745277870260L; protected final Atom m_existentialAtom; public ExistentialExpansion(Atom existentialAtom) { m_existentialAtom=existentialAtom; } public int getNumberOfPremises() { return 1; } public Fact getPremise(int premiseIndex) { switch (premiseIndex) { case 0: return m_existentialAtom; default: throw new IndexOutOfBoundsException(); } } public String toString(Prefixes prefixes) { return " << EXISTS"; } } public static class ClashDetection extends Derivation { private static final long serialVersionUID=-1046733682276190587L; protected final Atom[] m_causes; public ClashDetection(Atom[] causes) { m_causes=causes; } public int getNumberOfPremises() { return m_causes.length; } public Fact getPremise(int premiseIndex) { return m_causes[premiseIndex]; } public String toString(Prefixes prefixes) { return " << CLASH"; } } public static class DatatypeChecking extends Derivation { private static final long serialVersionUID=-7833124370362424190L; protected final Atom[] m_causes; public DatatypeChecking(Atom[] causes) { m_causes=causes; } public int getNumberOfPremises() { return m_causes.length; } public Fact getPremise(int premiseIndex) { return m_causes[premiseIndex]; } public String toString(Prefixes prefixes) { return " << DATATYPES"; } } public static class UnknownDatatypeRestrictionDetection extends Derivation { private static final long serialVersionUID=-7824360133765453948L; protected final Atom[] m_causes; public UnknownDatatypeRestrictionDetection(Atom[] causes) { m_causes=causes; } public int getNumberOfPremises() { return m_causes.length; } public Fact getPremise(int premiseIndex) { return m_causes[premiseIndex]; } public String toString(Prefixes prefixes) { return " << UNKNOWN DATATYPE"; } } public static class BaseFact extends Derivation { private static final long serialVersionUID=-5998349862414502218L; public static Derivation INSTANCE=new BaseFact(); public int getNumberOfPremises() { return 0; } public Fact getPremise(int premiseIndex) { throw new IndexOutOfBoundsException(); } public String toString(Prefixes prefixes) { return "."; } } }