swoopstatistics.java

来自「Semantic Web Ontology Editor」· Java 代码 · 共 363 行

JAVA
363
字号
//The MIT License
//
// Copyright (c) 2004 Mindswap Research Group, University of Maryland, College Park
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

package org.mindswap.swoop.utils;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;

import org.mindswap.swoop.SwoopModel;
import org.mindswap.swoop.reasoner.SwoopReasoner;
import org.semanticweb.owl.io.vocabulary.OWLVocabularyAdapter;
import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLClassAxiom;
import org.semanticweb.owl.model.OWLDataProperty;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLDisjointClassesAxiom;
import org.semanticweb.owl.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owl.model.OWLObjectProperty;
import org.semanticweb.owl.model.OWLOntology;
import org.semanticweb.owl.model.OWLProperty;
import org.semanticweb.owl.model.OWLSubClassAxiom;

/**
 * @author Aditya
 */
public class SwoopStatistics {

	SwoopModel swoopModel;
	
	public static String ONTOLOGY = "O";
	public static String UNSATISFIABLE_CLASSES = "Unsatisfiable";
	public static String NO_GCI = "GCIs";
	public static String NO_SUBSUMPTIONS = "Subsumptions";
	public static String NO_DISJOINT = "Disjoints";
	public static String NO_TRANSITIVE = "Transitive";
	public static String NO_SYMMETRIC = "Symmetric";
	public static String NO_FUNCTIONAL = "Functional";
	public static String NO_INVFUNCTIONAL = "Inverse-Functional";
	public static String NO_INVERSE = "Inverses";
	
	public static String MAX_DEPTH_CLASS_TREE = "Deepest SubTree [C]";
	public static String MIN_DEPTH_CLASS_TREE = "Shallowest SubTree [C]";
	public static String AVG_DEPTH_CLASS_TREE = "8";
	public static String MAX_DEPTH_PROP_TREE = "Deepest SubTree [P]";
	public static String MIN_DEPTH_PROP_TREE = "Shallowest SubTree [P]";
	public static String AVG_DEPTH_PROP_TREE = "11";
	public static String MAX_BRANCHING_FACTOR = "Most Children [C]";
	public static String MIN_BRANCHING_FACTOR = "Fewest Children [C]";
	public static String AVG_BRANCHING_FACTOR = "";
	
	public static String MULTIPLE_INHERITANCE_CLASS = "Mult. Inheritance [C]";
	public static String MULTIPLE_INHERITANCE_PROP = "Mult. Inheritance [P]";
	
	public SwoopStatistics(SwoopModel model) {
		this.swoopModel = model;
	}
	
	public HashMap computeStatistics(OWLOntology ontology) {
		
		SwoopReasoner reasoner = swoopModel.getReasoner();
		
		HashMap stats = new HashMap();
//		stats.put(this.ONTOLOGY, ontology); // don't need this
		
		Set gci = new HashSet();
		Set disj = new HashSet();
		
		try {
			// class axiom types
			for (Iterator iter = ontology.getClassAxioms().iterator(); iter.hasNext();) {
				OWLClassAxiom axiom = (OWLClassAxiom) iter.next();
				if (axiom instanceof OWLSubClassAxiom) {
					OWLSubClassAxiom subAxiom = (OWLSubClassAxiom) axiom;
					if (!(subAxiom.getSubClass() instanceof OWLClass)) gci.add(axiom);
				}
				else if (axiom instanceof OWLEquivalentClassesAxiom) {
					OWLEquivalentClassesAxiom equAxiom = (OWLEquivalentClassesAxiom) axiom;
					for (Iterator iter2=equAxiom.getEquivalentClasses().iterator(); iter2.hasNext();) {
						OWLDescription desc = (OWLDescription) iter2.next();
						if (!(desc instanceof OWLClass)) gci.add(axiom);
					}
				}
				else if (axiom instanceof OWLDisjointClassesAxiom) 
					disj.add(axiom);
			}
			
			stats.put(this.NO_GCI, gci);
			stats.put(this.NO_DISJOINT, disj);
			
			// prop attribs
			Set props = ontology.getObjectProperties();
			props.addAll(ontology.getDataProperties());
			Set tran = new HashSet();
			Set symm = new HashSet();
			Set invf = new HashSet();
			Set func = new HashSet();
			Set inv = new HashSet();
			Set multP = new HashSet();
			for (Iterator iter = props.iterator(); iter.hasNext();) {
				OWLProperty prop = (OWLProperty) iter.next();
				
				// check multiple inheritance for props
				if (prop!=null && reasoner.getOntology()!=null && reasoner.getOntology().equals(ontology) && reasoner.superPropertiesOf(prop).size()>1) multP.add(prop);
				
				if (prop instanceof OWLObjectProperty) {
					if (((OWLObjectProperty) prop).isFunctional(ontology)) func.add(prop);
					if (((OWLObjectProperty) prop).isInverseFunctional(ontology)) invf.add(prop);
					if (((OWLObjectProperty) prop).isTransitive(ontology)) tran.add(prop);
					if (((OWLObjectProperty) prop).isSymmetric(ontology)) symm.add(prop);
					if (((OWLObjectProperty) prop).getInverses(ontology).size()>0) inv.add(prop);
				}
				else {
					if (((OWLDataProperty) prop).isFunctional(ontology)) func.add(prop);
				}
			}
			stats.put(this.MULTIPLE_INHERITANCE_PROP, multP);
			stats.put(this.NO_FUNCTIONAL, func);
			stats.put(this.NO_INVFUNCTIONAL, invf);
			stats.put(this.NO_TRANSITIVE, tran);
			stats.put(this.NO_SYMMETRIC, symm);
			stats.put(this.NO_INVERSE, inv);
			
			// tree specifics (using current SwoopReasoner and current Class/Prop trees)
			String minCl="?", maxCl="?", avgCl="?"; // class depth
			String minBf="?", maxBf="?", avgBf="?"; // braching factor 
			Set maxCSet = new HashSet();
			Set minCSet = new HashSet();
			Set maxBfSet = new HashSet();
			Set minBfSet = new HashSet();
			OWLOntology cTreeOfOnt = swoopModel.getFrame().termDisplay.getClassTreeOfOntology();
			if (cTreeOfOnt!=null && cTreeOfOnt.equals(ontology)) {
				int minC = Integer.MAX_VALUE, maxC = 0;
				int minB = Integer.MAX_VALUE, maxB = 0; // B for branching factor
				float avgC = 0;
				float avgB = 0;
				HashMap cache = new HashMap();
				HashMap bcache = new HashMap();
				if (swoopModel.getFrame().termDisplay.getTrees()[0]!=null) {
					TreeModel cTreeModel = swoopModel.getFrame().termDisplay.getTrees()[0].getModel();
					DefaultMutableTreeNode cRoot = (DefaultMutableTreeNode) cTreeModel.getRoot();
					
					// compute total subsumptions
					int subsumptions = 0;
//					for (int i = 0; i<cRoot.getChildCount(); i++) {
						subsumptions = getDescendentCount(cRoot) - cRoot.getChildCount();
//					}
					stats.put(this.NO_SUBSUMPTIONS, String.valueOf(subsumptions));
					
					Enumeration depthFirstEnum = cRoot.depthFirstEnumeration();
					int numLeaves = 0;
					int numNonLeaves = 0;
					while ( depthFirstEnum.hasMoreElements() )
					{
						DefaultMutableTreeNode node = (DefaultMutableTreeNode)depthFirstEnum.nextElement();
						
						// do not count the depth/branching factor of unsatisfiable classes
						TreeNode [] path = node.getPath();
						
						if ( path.length > 1 )
						{
							DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode)path[1];
							Set concepts = (Set)dmtn.getUserObject();
							String n = OWLVocabularyAdapter.OWL;
							OWLClass concept = (OWLClass)concepts.iterator().next(); // get first element
							if ( concept.getURI().toString().equals( OWLVocabularyAdapter.OWL + "Nothing"))
								continue;
						}
						
						if ( node.isLeaf() ) // if leaf, count depth
						{
							numLeaves++;
							int depth = path.length - 1; // path.length - 1 = number of links from root to leaf
							if ( depth > 0)
								this.cacheDepth(cache, String.valueOf(depth), (Set)((DefaultMutableTreeNode)path[1]).getUserObject());
							if ( depth == 0 )
								this.cacheDepth(cache, String.valueOf(depth), (Set)(cRoot).getUserObject());
							
							if ( depth > maxC)
								maxC = depth;
							if ( depth < minC )
								minC = depth;
							avgC = avgC + depth;
						}
						else // not a leaf node, count branching factor
						{
							numNonLeaves++;
							int numChildren = node.getChildCount();							
							this.cacheDepth(bcache, String.valueOf(numChildren), 
									(Set)node.getUserObject());
							if ( numChildren > maxB)
								maxB = numChildren;
							if ( numChildren < minB )
								minB = numChildren;
							avgB = avgB + numChildren;
						}
					}
					avgC = avgC / numLeaves;
					avgB = avgB / numNonLeaves;
					maxCl = String.valueOf(maxC);
					if (minC == Integer.MAX_VALUE) minC = 0;
					minCl = String.valueOf(minC);
					avgCl = String.valueOf(avgC);
					
					maxBf = String.valueOf(maxB);
					if (minB == Integer.MAX_VALUE) minB = 0;
					minBf = String.valueOf(minB);
					avgBf = String.valueOf(avgB);
					
					// get element set corresponding to min/max
					maxCSet = (HashSet) cache.get(maxCl);
					minCSet = (HashSet) cache.get(minCl);
					
					maxBfSet = (HashSet) bcache.get( maxBf );
					minBfSet = (HashSet) bcache.get( minBf );
				}
			}
			
			// class tree depth
			if ((avgCl.length()>4) && ( avgCl.indexOf(".") != -1)) avgCl = avgCl.substring(0, avgCl.indexOf(".") + 2);
			stats.put(this.AVG_DEPTH_CLASS_TREE, avgCl);
			List minCList = new ArrayList();
			minCList.add(minCl);
			minCList.add(minCSet);
			stats.put(this.MIN_DEPTH_CLASS_TREE, minCList);
			List maxCList = new ArrayList();
			maxCList.add(maxCl);
			maxCList.add(maxCSet);
			stats.put(this.MAX_DEPTH_CLASS_TREE, maxCList);
			
			// branching factor
			if ((avgBf.length()>4) && ( avgBf.indexOf(".") != -1)) avgBf = avgBf.substring(0, avgBf.indexOf(".") + 2);
			stats.put(this.AVG_BRANCHING_FACTOR, avgBf);
			List minBList = new ArrayList();
			minBList.add(minBf);
			minBList.add(minBfSet);
			stats.put(this.MIN_BRANCHING_FACTOR, minBList);
			List maxBList = new ArrayList();
			maxBList.add(maxBf);
			maxBList.add(maxBfSet);
			stats.put(this.MAX_BRANCHING_FACTOR, maxBList);			
			
			String minPr="?", maxPr="?", avgPr="?";
			Set maxPSet = new HashSet();
			Set minPSet = new HashSet();
			OWLOntology pTreeOfOnt = swoopModel.getFrame().termDisplay.getPropTreeOfOntology();
			if (pTreeOfOnt!=null && pTreeOfOnt.equals(ontology)) {
				int minP = Integer.MAX_VALUE, maxP = 0;
				float avgP = 0;
				HashMap cache = new HashMap();
				if (swoopModel.getFrame().termDisplay.getTrees()[1]!=null) {
					TreeModel pTreeModel = swoopModel.getFrame().termDisplay.getTrees()[1].getModel();			
					DefaultMutableTreeNode pRoot = (DefaultMutableTreeNode) pTreeModel.getRoot();
					
					Enumeration depthFirstEnum = pRoot.depthFirstEnumeration();
					int numLeaves = 0;
					while ( depthFirstEnum.hasMoreElements() )
					{
						DefaultMutableTreeNode node = (DefaultMutableTreeNode)depthFirstEnum.nextElement();
						if ( node.isLeaf() )
						{
							numLeaves++;
							TreeNode [] path = node.getPath(); 
							int depth = path.length - 2; // path.length - 2 = number of links from top node
							if ( depth > 0)
								this.cacheDepth(cache, String.valueOf(depth), (Set)((DefaultMutableTreeNode)path[1]).getUserObject());
							if ( depth == 0 )
								this.cacheDepth(cache, String.valueOf(depth), (Set)(pRoot).getUserObject());
							
							if ( depth > maxP )
								maxP = depth;
							if ( depth < minP )
								minP = depth;
							avgP = avgP + depth;
						}
					}
					
					avgP = avgP / numLeaves;
					maxPr = String.valueOf(maxP);
					minPr = String.valueOf(minP);
					avgPr = String.valueOf(avgP);
					
					// get element set corresponding to min/max
					maxPSet = (HashSet) cache.get(maxPr);
					minPSet = (HashSet) cache.get(minPr);
				}
			}
			
			if (avgPr.length()>4) avgPr = avgPr.substring(0, 4);
			stats.put(this.AVG_DEPTH_PROP_TREE, avgPr);
			List minPList = new ArrayList();
			minPList.add(minPr);
			minPList.add(minPSet);
			stats.put(this.MIN_DEPTH_PROP_TREE, minPList);
			List maxPList = new ArrayList();
			maxPList.add(maxPr);
			maxPList.add(maxPSet);
			stats.put(this.MAX_DEPTH_PROP_TREE, maxPList);
			
			// multiple inheritance for classes
			Set mult = new HashSet();
			if (reasoner.getOntology()!=null && reasoner.getOntology().equals(ontology)) {
				for (Iterator iter = ontology.getClasses().iterator(); iter.hasNext();) {
					OWLClass cla = (OWLClass) iter.next();
					if (reasoner.isConsistent(cla) && reasoner.superClassesOf(cla).size()>1) mult.add(cla);
				}				
			}
			stats.put(this.MULTIPLE_INHERITANCE_CLASS, mult);
		}
		catch (Exception ex) {
			ex.printStackTrace();
		}
		
		return stats;
	}

	/*
	 * cache stores map: depth no. -> set of classes/props with depth 
	 */
	private void cacheDepth(HashMap cache, String key, Set val) {
		Set curr = new HashSet();
		if (cache.containsKey(key)) curr = (HashSet) cache.get(key);
		curr.addAll(val);
		cache.put(key, curr);
	}
	
	private int getDescendentCount(TreeNode node) {
		int count = 0;
		while (((DefaultMutableTreeNode) node).getNextNode()!=null) {
			count ++;
			node = ((DefaultMutableTreeNode) node).getNextNode();
		}
		return count;
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?