![JAR search and dependency download from the Maven repository](/logo.png)
com.clarkparsia.pellint.lintpattern.ontology.ExistentialExplosionPattern Maven / Gradle / Ivy
// Copyright (c) 2006 - 2008, Clark & Parsia, LLC.
// This source code is available under the terms of the Affero General Public License v3.
//
// Please see LICENSE.txt for full license terms, including the availability of proprietary exceptions.
// Questions, comments, or requests for clarification: [email protected]
package com.clarkparsia.pellint.lintpattern.ontology;
import java.io.BufferedWriter;
import java.io.PrintWriter;
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 java.util.Map.Entry;
import org.jgrapht.Graph;
import org.jgrapht.alg.CycleDetector;
import org.jgrapht.alg.StrongConnectivityInspector;
import org.jgrapht.alg.TransitiveClosure;
import org.jgrapht.ext.DOTExporter;
import org.jgrapht.ext.StringNameProvider;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.DirectedSubgraph;
import org.jgrapht.graph.EdgeReversedGraph;
import org.jgrapht.traverse.TopologicalOrderIterator;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLObjectExactCardinality;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectMinCardinality;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLObjectUnionOf;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.util.OWLClassExpressionVisitorAdapter;
import com.clarkparsia.pellint.format.LintFormat;
import com.clarkparsia.pellint.format.SimpleLintFormat;
import com.clarkparsia.pellint.model.Lint;
import com.clarkparsia.pellint.model.LintFactory;
import com.clarkparsia.pellint.model.Severity;
import com.clarkparsia.pellint.util.OptimizedDirectedMultigraph;
/**
*
* Title:
*
*
* Description:
*
*
* Copyright: Copyright (c) 2008
*
*
* Company: Clark & Parsia, LLC.
*
*
* @author Harris Lin
*/
public class ExistentialExplosionPattern implements OntologyLintPattern {
private static final LintFormat DEFAULT_LINT_FORMAT = new SimpleLintFormat();
private int m_MaxTreeSize = 10000;
private List m_AccumulatedLints;
private LintFactory m_LintFactory;
public String getName() {
return getClass().getSimpleName() + " (MaxTreeSize = " + m_MaxTreeSize + ")";
}
public String getDescription() {
return "Concepts/Individuals are involved in a large some/min/exact value restrictions tree/loop - maximum recommended number of generated nodes is " + m_MaxTreeSize;
}
public boolean isFixable() {
return false;
}
public LintFormat getDefaultLintFormat() {
return DEFAULT_LINT_FORMAT;
}
public void setMaxTreeSize(int value) {
m_MaxTreeSize = value;
}
public List match(OWLOntology ontology) {
m_AccumulatedLints = new ArrayList();
m_LintFactory = new LintFactory(this, ontology);
//Stage 1 - strongly connected components on asserted existential relations
OptimizedDirectedMultigraph existentialRestrictionGraph = extractGraphFromSubsumptionAxiomsWith(ontology, new ExistentialClassCollector());
estimateTreeSizesForCycles(existentialRestrictionGraph);
if (!m_AccumulatedLints.isEmpty()) return m_AccumulatedLints;
//Stage 2 - strongly connected components on asserted and inferred (through subclasses) existential relations
//used as a SimpleDirectedGraph - ignoring weights
OptimizedDirectedMultigraph toldSubsumptionGraph = extractGraphFromSubsumptionAxiomsWith(ontology, new NamedClassCollector());
TransitiveClosure.INSTANCE.closeSimpleDirectedGraph(toldSubsumptionGraph);
addInheritedEdges(existentialRestrictionGraph, toldSubsumptionGraph);
estimateTreeSizesForCycles(existentialRestrictionGraph);
if (!m_AccumulatedLints.isEmpty()) return m_AccumulatedLints;
//Stage 3 - strongly connected components on asserted and inferred (through subclasses) existential relations, multiplied by the number of individuals
Map individualCounts = countIndividuals(ontology);
estimateTreeSizesForCyclesWithIndividuals(existentialRestrictionGraph, toldSubsumptionGraph, individualCounts);
if (!m_AccumulatedLints.isEmpty()) return m_AccumulatedLints;
//Stage 4 - remove cycles, then calculate the size of the weighted tree, multiplied by the number of individuals
removeCyclesAndEstimateTreeSizesWithIndividuals(existentialRestrictionGraph, individualCounts);
return m_AccumulatedLints;
}
@SuppressWarnings("unused")
private static void printGraph(Graph graph) {
DOTExporter exp = new DOTExporter(new StringNameProvider(), null, null);
exp.export(new BufferedWriter(new PrintWriter(System.out)), graph);
}
private static OptimizedDirectedMultigraph extractGraphFromSubsumptionAxiomsWith(OWLOntology ontology, ClassCollector visitor) {
OptimizedDirectedMultigraph graph = new OptimizedDirectedMultigraph();
for (OWLSubClassOfAxiom axiom : ontology.getAxioms(AxiomType.SUBCLASS_OF)) {
processSubsumption(graph, axiom.getSubClass(), axiom.getSuperClass(), visitor);
}
for (OWLEquivalentClassesAxiom axiom : ontology.getAxioms(AxiomType.EQUIVALENT_CLASSES)) {
Set equivalences = axiom.getClassExpressions();
for (OWLClassExpression equivalence1 : equivalences) {
for (OWLClassExpression equivalence2 : equivalences) {
if (equivalence1 != equivalence2) {
processSubsumption(graph, equivalence1, equivalence2, visitor);
}
}
}
}
return graph;
}
private static void processSubsumption(OptimizedDirectedMultigraph graph, OWLClassExpression subDesc, OWLClassExpression superDesc, ClassCollector visitor) {
if (subDesc.isAnonymous()) return;
OWLClass subClass = subDesc.asOWLClass();
visitor.reset();
superDesc.accept(visitor);
for (OWLClass superClass : visitor.getCollectedClasses()) {
if (!subClass.equals(superClass)) {
graph.addVertex(subClass);
graph.addVertex(superClass);
graph.addEdge(subClass, superClass);
}
}
}
private static void addInheritedEdges(OptimizedDirectedMultigraph existentialRestrictionGraph, OptimizedDirectedMultigraph toldSubsumptionGraph) {
for (OWLClass superClass : toldSubsumptionGraph.vertexSet()) {
if (!existentialRestrictionGraph.containsVertex(superClass)) continue;
Set ancestorEdges = existentialRestrictionGraph.outgoingEdgesOf(superClass);
for (DefaultWeightedEdge subClassEdge : toldSubsumptionGraph.incomingEdgesOf(superClass)) {
OWLClass subClass = toldSubsumptionGraph.getEdgeSource(subClassEdge);
if (!existentialRestrictionGraph.containsVertex(subClass)) continue;
for (DefaultWeightedEdge ancestorEdge : ancestorEdges) {
int ancestorEdgeCount = existentialRestrictionGraph.getEdgeMultiplicity(ancestorEdge);
OWLClass ancestorEdgeTarget = existentialRestrictionGraph.getEdgeTarget(ancestorEdge);
if (!subClass.equals(ancestorEdgeTarget)) {
existentialRestrictionGraph.addEdge(subClass, ancestorEdgeTarget, ancestorEdgeCount);
}
}
}
}
}
private static Map countIndividuals(OWLOntology ontology) {
Map individualCount = new HashMap();
for (OWLClassAssertionAxiom axiom : ontology.getAxioms(AxiomType.CLASS_ASSERTION)) {
OWLClassExpression desc = axiom.getClassExpression();
if (!desc.isAnonymous()) {
OWLClass assertedClass = desc.asOWLClass();
Integer oldCount = individualCount.get(assertedClass);
if (oldCount == null) {
oldCount = 0;
}
individualCount.put(assertedClass, oldCount + 1);
}
}
return individualCount;
}
private static int getMaxSizeOfCompleteGraphToIgnore(int maxTreeSize) {
int i = 1;
for (; Math.pow(i - 1, i) < maxTreeSize; i++) { }
return i - 1;
}
private void estimateTreeSizesForCycles(OptimizedDirectedMultigraph existentialRestrictionGraph) {
int maxSizeOfCompleteGraphToIgnore = getMaxSizeOfCompleteGraphToIgnore(m_MaxTreeSize);
StrongConnectivityInspector connectivityInspector = new StrongConnectivityInspector(existentialRestrictionGraph);
for (Set connectedSet : connectivityInspector.stronglyConnectedSets()) {
if (connectedSet.size() <= maxSizeOfCompleteGraphToIgnore) continue;
DirectedSubgraph subgraph = new DirectedSubgraph(existentialRestrictionGraph, connectedSet, null);
double estimatedTreeSize = 1.0;
for (OWLClass owlClass : connectedSet) {
estimatedTreeSize *= subgraph.outDegreeOf(owlClass);
}
if (estimatedTreeSize > m_MaxTreeSize) {
Lint lint = m_LintFactory.make();
lint.addAllParticipatingClasses(connectedSet);
lint.setSeverity(new Severity(estimatedTreeSize));
m_AccumulatedLints.add(lint);
}
}
}
private void estimateTreeSizesForCyclesWithIndividuals(OptimizedDirectedMultigraph existentialRestrictionGraph, OptimizedDirectedMultigraph toldSubsumptionGraph, Map individualCount) {
StrongConnectivityInspector connectivityInspector = new StrongConnectivityInspector(existentialRestrictionGraph);
for (Set connectedSet : connectivityInspector.stronglyConnectedSets()) {
if (connectedSet.size() <= 1) continue;
DirectedSubgraph subgraph = new DirectedSubgraph(existentialRestrictionGraph, connectedSet, null);
double estimatedTreeSize = 1.0;
for (OWLClass owlClass : connectedSet) {
estimatedTreeSize *= subgraph.outDegreeOf(owlClass);
}
Set allSubclassesOfConnectedSet = new HashSet(connectedSet);
for (OWLClass owlClass : connectedSet) {
if (!toldSubsumptionGraph.containsVertex(owlClass)) continue;
for (DefaultWeightedEdge inEdge : toldSubsumptionGraph.incomingEdgesOf(owlClass)) {
allSubclassesOfConnectedSet.add(toldSubsumptionGraph.getEdgeSource(inEdge));
}
}
int totalInvolvedIndividuals = 0;
for (Entry entry : individualCount.entrySet()) {
if (allSubclassesOfConnectedSet.contains(entry.getKey())) {
totalInvolvedIndividuals += entry.getValue();
}
}
estimatedTreeSize *= totalInvolvedIndividuals;
if (estimatedTreeSize > m_MaxTreeSize) {
Lint lint = m_LintFactory.make();
lint.addAllParticipatingClasses(connectedSet);
lint.setSeverity(new Severity(estimatedTreeSize));
m_AccumulatedLints.add(lint);
}
}
}
private void removeCyclesAndEstimateTreeSizesWithIndividuals(OptimizedDirectedMultigraph existentialRestrictionGraph, Map individualCounts) {
Map accumulatedChildren = new HashMap();
CycleDetector cycleDetector = new CycleDetector(existentialRestrictionGraph);
Set nodesInACycle = cycleDetector.findCycles();
for (OWLClass child : nodesInACycle) {
Double childValue = accumulatedChildren.get(child);
if (childValue == null) {
childValue = existentialRestrictionGraph.outDegreeOf(child) + 1.0;
}
for (DefaultWeightedEdge inEdge : existentialRestrictionGraph.incomingEdgesOf(child)) {
int inEdgeCount = existentialRestrictionGraph.getEdgeMultiplicity(inEdge);
OWLClass parent = existentialRestrictionGraph.getEdgeSource(inEdge);
Double oldValue = accumulatedChildren.get(parent);
if (oldValue == null) {
oldValue = (double)existentialRestrictionGraph.outDegreeOf(parent);
}
accumulatedChildren.put(parent, oldValue + (childValue * inEdgeCount));
}
}
existentialRestrictionGraph.removeAllVertices(nodesInACycle);
if (!existentialRestrictionGraph.vertexSet().isEmpty()) {
EdgeReversedGraph reversedForest = new EdgeReversedGraph(existentialRestrictionGraph);
TopologicalOrderIterator bottomUpIt = new TopologicalOrderIterator(reversedForest);
while (bottomUpIt.hasNext()) {
OWLClass node = bottomUpIt.next();
Double nodeSize = accumulatedChildren.get(node);
if (nodeSize == null) {
nodeSize = 1.0;
}
for (DefaultWeightedEdge outEdge : existentialRestrictionGraph.outgoingEdgesOf(node)) {
int outEdgeCount = existentialRestrictionGraph.getEdgeMultiplicity(outEdge);
OWLClass child = existentialRestrictionGraph.getEdgeTarget(outEdge);
Double childValue = accumulatedChildren.get(child);
if (childValue == null) {
childValue = 1.0;
}
nodeSize += childValue * outEdgeCount;
}
accumulatedChildren.put(node, nodeSize);
}
}
Set participatingClasses = new HashSet();
double estimatedTotalTreeSize = 0.0;
for (Entry entry : individualCounts.entrySet()) {
OWLClass owlClass = entry.getKey();
int individualCount = entry.getValue();
Double childCount = accumulatedChildren.get(owlClass);
if (childCount != null) {
double totalCount = childCount * individualCount;
estimatedTotalTreeSize += totalCount;
if (totalCount > 0.0) {
participatingClasses.add(owlClass);
}
}
}
if (estimatedTotalTreeSize > m_MaxTreeSize) {
Lint lint = m_LintFactory.make();
lint.addAllParticipatingClasses(participatingClasses);
lint.setSeverity(new Severity(estimatedTotalTreeSize));
m_AccumulatedLints.add(lint);
}
}
}
abstract class ClassCollector extends OWLClassExpressionVisitorAdapter {
protected Set m_Classes;
public ClassCollector() {
m_Classes = new HashSet();
}
public void reset() {
m_Classes.clear();
}
public Set getCollectedClasses() {
return m_Classes;
}
}
class NamedClassCollector extends ClassCollector {
public void visit(OWLClass desc) {
m_Classes.add(desc);
}
public void visit(OWLObjectIntersectionOf desc) {
for (OWLClassExpression op : desc.getOperands()) {
op.accept(this);
}
}
public void visit(OWLObjectUnionOf desc) {
for (OWLClassExpression op : desc.getOperands()) {
op.accept(this);
}
}
}
class ExistentialClassCollector extends ClassCollector {
public void visit(OWLObjectSomeValuesFrom desc) {
visitObject(desc.getFiller());
}
public void visit(OWLObjectMinCardinality desc) {
if (desc.getCardinality() > 0) {
visitObject(desc.getFiller());
}
}
public void visit(OWLObjectExactCardinality desc) {
if (desc.getCardinality() > 0) {
visitObject(desc.getFiller());
}
}
public void visit(OWLObjectIntersectionOf desc) {
for (OWLClassExpression op : desc.getOperands()) {
op.accept(this);
}
}
public void visit(OWLObjectUnionOf desc) {
for (OWLClassExpression op : desc.getOperands()) {
op.accept(this);
}
}
private void visitObject(OWLClassExpression filler) {
if (!filler.isAnonymous()) {
m_Classes.add(filler.asOWLClass());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy