/* 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.PrintWriter; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.semanticweb.HermiT.model.AtLeastConcept; import org.semanticweb.HermiT.model.AtomicConcept; import org.semanticweb.HermiT.model.AtomicNegationConcept; import org.semanticweb.HermiT.model.AtomicNegationDataRange; import org.semanticweb.HermiT.model.AtomicRole; import org.semanticweb.HermiT.model.Concept; import org.semanticweb.HermiT.model.Constant; import org.semanticweb.HermiT.model.ConstantEnumeration; import org.semanticweb.HermiT.model.DataRange; import org.semanticweb.HermiT.model.DatatypeRestriction; import org.semanticweb.HermiT.model.DescriptionGraph; import org.semanticweb.HermiT.model.ExistentialConcept; import org.semanticweb.HermiT.model.ExistsDescriptionGraph; import org.semanticweb.HermiT.model.InternalDatatype; import org.semanticweb.HermiT.model.InverseRole; import org.semanticweb.HermiT.model.Role; import org.semanticweb.HermiT.tableau.ExtensionTable; import org.semanticweb.HermiT.tableau.Node; public class Printing { public static void printPadded(PrintWriter writer,int number,int size) { printPadded(writer,String.valueOf(number),size); } public static void printPadded(PrintWriter writer,String string,int size) { for (int i=size-string.length();i>=0;--i) writer.print(' '); writer.print(string); } public static <T> void printCollection(Collection<T> collection,PrintWriter writer) { for (T object : collection) { writer.print(" "); writer.print(object.toString()); writer.println(); } } public static <T> void diffCollections(String in1NotIn2,String in2NotIn1,PrintWriter writer,Collection<T> c1,Collection<T> c2) { boolean window1Message=false; for (Object object : c1) { if (!c2.contains(object)) { if (!window1Message) { writer.println("<<< "+in1NotIn2+":"); window1Message=true; } writer.print(" "); writer.print(object.toString()); writer.println(); } } if (window1Message) writer.println("--------------------------------------------"); boolean window2Message=false; for (Object object : c2) { if (!c1.contains(object)) { if (!window2Message) { writer.println(">>> "+in2NotIn1+":"); window2Message=true; } writer.print(" "); writer.print(object.toString()); writer.println(); } } if (window1Message) writer.println("--------------------------------------------"); } public static void printNodeData(Debugger debugger,Node node,PrintWriter writer) { writer.print("Node ID: "); writer.println(node.getNodeID()); writer.print("Node Type: "); writer.println(node.getNodeType()); writer.print("Parent ID: "); writer.println(node.getParent()==null ? "(root node)" : node.getParent().getNodeID()); writer.print("Depth: "); writer.println(node.getTreeDepth()); writer.print("Status: "); if (node.isActive()) writer.println("active"); else if (node.isMerged()) { Node mergeTarget=node.getMergedInto(); while (mergeTarget!=null) { writer.print(" --> "); writer.print(mergeTarget.getNodeID()); mergeTarget=mergeTarget.getMergedInto(); } writer.println(); } else writer.println("pruned"); writer.print("Blocked: "); writer.println(formatBlockingStatus(node)); writer.print("Created as: "); Debugger.NodeCreationInfo nodeCreationInfo=debugger.getNodeCreationInfo(node); ExistentialConcept startExistential=nodeCreationInfo.m_createdByExistential; if (!(startExistential instanceof AtLeastConcept)) writer.println("(root)"); else writer.println(((AtLeastConcept)startExistential).getToConcept().toString(debugger.getPrefixes())); printConceptLabel(debugger,node,writer); printEdges(debugger,node,writer); } protected static String formatBlockingStatus(Node node) { if (!node.isBlocked()) return "no"; else if (node.isDirectlyBlocked()) return "directly by "+(node.getBlocker()==Node.SIGNATURE_CACHE_BLOCKER ? "signature in cache" : node.getBlocker().getNodeID()); else return "indirectly by "+(node.getBlocker()==Node.SIGNATURE_CACHE_BLOCKER ? "signature in cache" : node.getBlocker().getNodeID()); } protected static void printConceptLabel(Debugger debugger,Node node,PrintWriter writer) { TreeSet<AtomicConcept> atomicConceptsCore=new TreeSet<AtomicConcept>(ConceptComparator.INSTANCE); TreeSet<AtomicConcept> atomicConceptsNoncore=new TreeSet<AtomicConcept>(ConceptComparator.INSTANCE); TreeSet<ExistentialConcept> existentialConcepts=new TreeSet<ExistentialConcept>(ConceptComparator.INSTANCE); TreeSet<AtomicNegationConcept> negativeConcepts=new TreeSet<AtomicNegationConcept>(ConceptComparator.INSTANCE); TreeSet<DataRange> dataRanges=new TreeSet<DataRange>(DataRangeComparator.INSTANCE); ExtensionTable.Retrieval retrieval=debugger.getTableau().getExtensionManager().getBinaryExtensionTable().createRetrieval(new boolean[] { false,true },ExtensionTable.View.TOTAL); retrieval.getBindingsBuffer()[1]=node; retrieval.open(); while (!retrieval.afterLast()) { Object potentialConcept=retrieval.getTupleBuffer()[0]; if (potentialConcept instanceof AtomicNegationConcept) negativeConcepts.add((AtomicNegationConcept)potentialConcept); else if (potentialConcept instanceof AtomicConcept) { if (retrieval.isCore()) atomicConceptsCore.add((AtomicConcept)potentialConcept); else atomicConceptsNoncore.add((AtomicConcept)potentialConcept); } else if (potentialConcept instanceof ExistentialConcept) existentialConcepts.add((ExistentialConcept)potentialConcept); else if (potentialConcept instanceof DataRange) dataRanges.add((DataRange)potentialConcept); else if (potentialConcept instanceof DescriptionGraph) { // ignore description graphs here } else throw new IllegalStateException("Found something in the label that is not a known type!"); retrieval.next(); } Set<AtomicConcept> noConcepts=Collections.emptySet(); if (!atomicConceptsCore.isEmpty()) { writer.print("-- Positive concept label (core part) -------"); printConcepts(debugger,atomicConceptsCore,noConcepts,writer,3); } if (!atomicConceptsNoncore.isEmpty() || !existentialConcepts.isEmpty()) { writer.print("-- Positive concept label (noncore part) ----"); printConcepts(debugger,atomicConceptsNoncore,noConcepts,writer,3); printConcepts(debugger,existentialConcepts,node.getUnprocessedExistentials(),writer,1); } if (!negativeConcepts.isEmpty()) { writer.print("-- Negative concept label -------------------"); printConcepts(debugger,negativeConcepts,noConcepts,writer,3); } if (!dataRanges.isEmpty()) { writer.print("-- Data ranges label ------------------------"); printDataRanges(debugger,dataRanges,writer,1); } } protected static void printEdges(Debugger debugger,Node node,PrintWriter writer) { Map<Node,Set<AtomicRole>> outgoingEdges=new TreeMap<Node,Set<AtomicRole>>(NodeComparator.INSTANCE); ExtensionTable.Retrieval retrieval=debugger.getTableau().getExtensionManager().getTernaryExtensionTable().createRetrieval(new boolean[] { false,true,false },ExtensionTable.View.TOTAL); retrieval.getBindingsBuffer()[1]=node; retrieval.open(); while (!retrieval.afterLast()) { Object atomicRoleObject=retrieval.getTupleBuffer()[0]; if (atomicRoleObject instanceof AtomicRole) { AtomicRole atomicRole=(AtomicRole)retrieval.getTupleBuffer()[0]; Node toNode=(Node)retrieval.getTupleBuffer()[2]; Set<AtomicRole> set=outgoingEdges.get(toNode); if (set==null) { set=new TreeSet<AtomicRole>(RoleComparator.INSTANCE); outgoingEdges.put(toNode,set); } set.add(atomicRole); } retrieval.next(); } if (!outgoingEdges.isEmpty()) { writer.println("-- Outgoing edges --------------------------------"); printEdgeMap(debugger,outgoingEdges,writer); } Map<Node,Set<AtomicRole>> incomingEdges=new TreeMap<Node,Set<AtomicRole>>(NodeComparator.INSTANCE); retrieval=debugger.getTableau().getExtensionManager().getTernaryExtensionTable().createRetrieval(new boolean[] { false,false,true },ExtensionTable.View.TOTAL); retrieval.getBindingsBuffer()[2]=node; retrieval.open(); while (!retrieval.afterLast()) { Object atomicRoleObject=retrieval.getTupleBuffer()[0]; if (atomicRoleObject instanceof AtomicRole) { AtomicRole atomicRole=(AtomicRole)retrieval.getTupleBuffer()[0]; Node fromNode=(Node)retrieval.getTupleBuffer()[1]; Set<AtomicRole> set=incomingEdges.get(fromNode); if (set==null) { set=new TreeSet<AtomicRole>(RoleComparator.INSTANCE); incomingEdges.put(fromNode,set); } set.add(atomicRole); } retrieval.next(); } if (!incomingEdges.isEmpty()) { writer.println("-- Incoming edges --------------------------------"); printEdgeMap(debugger,incomingEdges,writer); } } protected static void printConcepts(Debugger debugger,Set<? extends Concept> set,Collection<? extends Concept> markedElements,PrintWriter writer,int numberInRow) { int number=0; for (Concept concept : set) { if (number!=0) writer.print(", "); if ((number%numberInRow)==0) { writer.println(); writer.print(" "); } writer.print(concept.toString(debugger.getPrefixes())); if (markedElements.contains(concept)) writer.print(" (*)"); number++; } writer.println(); } protected static void printDataRanges(Debugger debugger,Set<? extends DataRange> set,PrintWriter writer,int numberInRow) { int number=0; for (DataRange range : set) { if (number!=0) writer.print(", "); if ((number%numberInRow)==0) { writer.println(); writer.print(" "); } writer.print(range.toString(debugger.getPrefixes())); number++; } writer.println(); } protected static void printEdgeMap(Debugger debugger,Map<Node,Set<AtomicRole>> map,PrintWriter writer) { for (Map.Entry<Node,Set<AtomicRole>> entry : map.entrySet()) { writer.print(" "); writer.print(entry.getKey().getNodeID()); writer.print(" -->"); int number=0; for (AtomicRole atomicRole : entry.getValue()) { if (number!=0) writer.print(", "); if ((number%3)==0) { writer.println(); writer.print(" "); } writer.print(atomicRole.toString(debugger.getPrefixes())); number++; } writer.println(); } } public static class ConceptComparator implements Comparator<Concept> { public static final ConceptComparator INSTANCE=new ConceptComparator(); public int compare(Concept c1,Concept c2) { ConceptType type1=getConceptType(c1); ConceptType type2=getConceptType(c2); if (type1!=type2) return type1.getTypeIndex()-type2.getTypeIndex(); switch (type1) { case AtomicConcept: return ((AtomicConcept)c1).getIRI().compareTo(((AtomicConcept)c2).getIRI()); case AtLeastConcept: { AtLeastConcept l1=(AtLeastConcept)c1; AtLeastConcept l2=(AtLeastConcept)c2; int comparison=RoleComparator.INSTANCE.compare(l1.getOnRole(),l2.getOnRole()); if (comparison!=0) return comparison; return compare(l1.getToConcept(),l2.getToConcept()); } case ExistsDescriptionGraph: { ExistsDescriptionGraph g1=(ExistsDescriptionGraph)c1; ExistsDescriptionGraph g2=(ExistsDescriptionGraph)c2; return g1.getDescriptionGraph().getName().compareTo(g2.getDescriptionGraph().getName()); } case AtomicNegationConcept: return ((AtomicNegationConcept)c1).getNegatedAtomicConcept().getIRI().compareTo(((AtomicNegationConcept)c2).getNegatedAtomicConcept().getIRI()); default: throw new IllegalArgumentException(); } } protected static enum ConceptType { AtomicConcept(0), AtLeastConcept(1), ExistsDescriptionGraph(2), AtomicNegationConcept(3); private final int m_typeIndex; ConceptType(int typeIndex) { m_typeIndex=typeIndex; } final int getTypeIndex() { return m_typeIndex; } } protected ConceptType getConceptType(Concept c) { if (c instanceof AtomicConcept) return ConceptType.AtomicConcept; else if (c instanceof AtLeastConcept) return ConceptType.AtLeastConcept; else if (c instanceof ExistsDescriptionGraph) return ConceptType.ExistsDescriptionGraph; else if (c instanceof AtomicNegationConcept) return ConceptType.AtomicNegationConcept; else throw new IllegalArgumentException(); } } public static class DataRangeComparator implements Comparator<DataRange> { public static final DataRangeComparator INSTANCE=new DataRangeComparator(); public int compare(DataRange c1,DataRange c2) { DataRangeType type1=getDataRangeType(c1); DataRangeType type2=getDataRangeType(c2); if (type1!=type2) return type1.getTypeIndex()-type2.getTypeIndex(); switch (type1) { case DatatypeRestriction: return compareDatatypeRestrictions((DatatypeRestriction)c1,(DatatypeRestriction)c2); case ConstantEnumeration: return compareConstantEnumerations((ConstantEnumeration)c1,(ConstantEnumeration)c2); case AtomicNegationDataRange: { AtomicNegationDataRange ndr1=(AtomicNegationDataRange)c1; AtomicNegationDataRange ndr2=(AtomicNegationDataRange)c2; return compare(ndr1.getNegatedDataRange(),ndr2.getNegatedDataRange()); } case InternalDatatype: return ((InternalDatatype)c1).getIRI().compareTo(((InternalDatatype)c2).getIRI()); default: throw new IllegalArgumentException(); } } protected static enum DataRangeType { DatatypeRestriction(0), ConstantEnumeration(1), AtomicNegationDataRange(2), InternalDatatype(3); private final int m_typeIndex; DataRangeType(int typeIndex) { m_typeIndex=typeIndex; } final int getTypeIndex() { return m_typeIndex; } } protected DataRangeType getDataRangeType(DataRange dr) { if (dr instanceof DatatypeRestriction) return DataRangeType.DatatypeRestriction; else if (dr instanceof InternalDatatype) return DataRangeType.InternalDatatype; else if (dr instanceof ConstantEnumeration) return DataRangeType.ConstantEnumeration; else if (dr instanceof AtomicNegationDataRange) return DataRangeType.AtomicNegationDataRange; else throw new IllegalArgumentException(); } protected int compareDatatypeRestrictions(DatatypeRestriction dr1,DatatypeRestriction dr2) { int comparison=dr1.getDatatypeURI().compareTo(dr2.getDatatypeURI()); if (comparison!=0) return comparison; comparison=dr1.getNumberOfFacetRestrictions()-dr2.getNumberOfFacetRestrictions(); if (comparison!=0) return comparison; for (int index=0;index<dr1.getNumberOfFacetRestrictions();index++) { comparison=dr1.getFacetURI(index).compareTo(dr2.getFacetURI(index)); if (comparison!=0) return comparison; comparison=compareConstants(dr1.getFacetValue(index),dr2.getFacetValue(index)); if (comparison!=0) return comparison; } return 0; } protected int compareConstantEnumerations(ConstantEnumeration dve1,ConstantEnumeration dve2) { int comparison=dve1.getNumberOfConstants()-dve2.getNumberOfConstants(); if (comparison!=0) return comparison; for (int index=0;index<dve1.getNumberOfConstants();index++) { comparison=compareConstants(dve1.getConstant(index),dve2.getConstant(index)); if (comparison!=0) return comparison; } return 0; } protected int compareConstants(Constant c1,Constant c2) { int comparison=c1.getDatatypeURI().compareTo(c2.getDatatypeURI()); if (comparison!=0) return comparison; return c1.getLexicalForm().compareTo(c2.getLexicalForm()); } } protected static class RoleComparator implements Comparator<Role> { public static final RoleComparator INSTANCE=new RoleComparator(); public int compare(Role ar1,Role ar2) { int type1=getRoleType(ar1); int type2=getRoleType(ar2); if (type1!=type2) return type1-type2; if (type1==0) return ((AtomicRole)ar1).getIRI().compareTo(((AtomicRole)ar2).getIRI()); else return ((InverseRole)ar1).getInverseOf().getIRI().compareTo(((InverseRole)ar2).getInverseOf().getIRI()); } protected int getRoleType(Role ar) { if (ar instanceof AtomicRole) return 0; else return 1; } } protected static class NodeComparator implements Comparator<Node> { public static final NodeComparator INSTANCE=new NodeComparator(); public int compare(Node o1,Node o2) { return o1.getNodeID()-o2.getNodeID(); } } public static class FactComparator implements Comparator<Object[]> { public static final FactComparator INSTANCE=new FactComparator(); public int compare(Object[] o1,Object[] o2) { int compare=o1.length-o2.length; if (compare!=0) return compare; compare=o1[0].toString().compareTo(o2[0].toString()); if (compare!=0) return compare; for (int index=1;index<o1.length;index++) { compare=((Node)o1[index]).getNodeID()-((Node)o2[index]).getNodeID(); if (compare!=0) return compare; } return 0; } } }