![JAR search and dependency download from the Maven repository](/logo.png)
com.clarkparsia.owlapi.explanation.HSTExplanationGenerator Maven / Gradle / Ivy
The newest version!
/*
* This file is part of the OWL API.
*
* The contents of this file are subject to the LGPL License, Version 3.0.
*
* Copyright (C) 2011, Clark & Parsia, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*
* Alternatively, the contents of this file may be used under the terms of the Apache License, Version 2.0
* in which case, the provisions of the Apache License Version 2.0 are applicable instead of those above.
*
* Copyright 2011, Clark & Parsia, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.clarkparsia.owlapi.explanation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDeclarationAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLException;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLRuntimeException;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.util.OWLEntityCollector;
import com.clarkparsia.owlapi.explanation.util.ExplanationProgressMonitor;
import com.clarkparsia.owlapi.explanation.util.OntologyUtils;
import com.clarkparsia.owlapi.explanation.util.SilentExplanationProgressMonitor;
/** HST explanation generator */
public class HSTExplanationGenerator implements MultipleExplanationGenerator {
private static final Logger log = Logger.getLogger(HSTExplanationGenerator.class
.getName());
private final TransactionAwareSingleExpGen singleExplanationGenerator;
private ExplanationProgressMonitor progressMonitor = new SilentExplanationProgressMonitor();
/** @param singleExplanationGenerator
* explanation generator to use */
public HSTExplanationGenerator(TransactionAwareSingleExpGen singleExplanationGenerator) {
this.singleExplanationGenerator = singleExplanationGenerator;
}
@Override
public void setProgressMonitor(ExplanationProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
}
@Override
public OWLOntologyManager getOntologyManager() {
return singleExplanationGenerator.getOntologyManager();
}
@Override
public OWLOntology getOntology() {
return singleExplanationGenerator.getOntology();
}
@Override
public OWLReasoner getReasoner() {
return singleExplanationGenerator.getReasoner();
}
@Override
public OWLReasonerFactory getReasonerFactory() {
return singleExplanationGenerator.getReasonerFactory();
}
/** @return the explanation generator */
public TransactionAwareSingleExpGen getSingleExplanationGenerator() {
return singleExplanationGenerator;
}
@Override
public Set getExplanation(OWLClassExpression unsatClass) {
return singleExplanationGenerator.getExplanation(unsatClass);
}
@Override
public Set> getExplanations(OWLClassExpression unsatClass) {
return getExplanations(unsatClass, 0);
}
// XXX onche the interface changes, uncomment this
// @Override
// public void dispose() {
// singleExplanationGenerator.dispose();
// }
@Override
public Set> getExplanations(OWLClassExpression unsatClass,
int maxExplanations) {
if (maxExplanations < 0) {
throw new IllegalArgumentException();
}
if (log.isLoggable(Level.CONFIG)) {
log.config("Get " + (maxExplanations == 0 ? "all" : maxExplanations)
+ " explanation(s) for: " + unsatClass);
}
try {
Set firstMups = getExplanation(unsatClass);
if (firstMups.isEmpty()) {
return Collections.emptySet();
}
Set> allMups = new LinkedHashSet>();
progressMonitor.foundExplanation(firstMups);
allMups.add(firstMups);
Set> satPaths = new HashSet>();
Set currentPathContents = new HashSet();
singleExplanationGenerator.beginTransaction();
try {
constructHittingSetTree(unsatClass, firstMups, allMups, satPaths,
currentPathContents, maxExplanations);
} finally {
singleExplanationGenerator.endTransaction();
}
progressMonitor.foundAllExplanations();
return allMups;
} catch (OWLException e) {
throw new OWLRuntimeException(e);
}
}
// //////////////////////////////////////////////////////////////////////////////////////////
//
// Hitting Set Stuff
//
// /////////////////////////////////////////////////////////////////////////////////////////
/** Orders the axioms in a single MUPS by the frequency of which they appear
* in all MUPS.
*
* @param mups
* The MUPS containing the axioms to be ordered
* @param allMups
* The set of all MUPS which is used to calculate the ordering */
private static List getOrderedMUPS(List mups,
final Set> allMups) {
Comparator mupsComparator = new Comparator() {
@Override
public int compare(OWLAxiom o1, OWLAxiom o2) {
// The axiom that appears in most MUPS has the lowest index
// in the list
int occ1 = getOccurrences(o1, allMups);
int occ2 = getOccurrences(o2, allMups);
return -occ1 + occ2;
}
};
Collections.sort(mups, mupsComparator);
return mups;
}
/** Given an axiom and a set of axioms this method determines how many sets
* contain the axiom.
*
* @param ax
* The axiom that will be counted.
* @param axiomSets
* The sets to count from */
protected static int getOccurrences(OWLAxiom ax, Set> axiomSets) {
int count = 0;
for (Set axioms : axiomSets) {
if (axioms.contains(ax)) {
count++;
}
}
return count;
}
/** Returns the entities referenced in an axiom.
*
* @param axiom
* axiom whose signature is being computed
* @return the entities referenced in the axiom */
private Set getSignature(OWLAxiom axiom) {
Set toReturn = new HashSet();
OWLEntityCollector collector = new OWLEntityCollector(toReturn);
collector.setCollectDatatypes(false);
axiom.accept(collector);
return toReturn;
}
/** This is a recursive method that builds a hitting set tree to obtain all
* justifications for an unsatisfiable class.
*
* @param mups
* The current justification for the current class. This
* corresponds to a node in the hitting set tree.
* @param allMups
* All of the MUPS that have been found - this set gets populated
* over the course of the tree building process. Initially this
* should just contain the first justification
* @param satPaths
* Paths that have been completed.
* @param currentPathContents
* The contents of the current path. Initially this should be an
* empty set. */
private void constructHittingSetTree(OWLClassExpression unsatClass,
Set mups, Set> allMups, Set> satPaths,
Set currentPathContents, int maxExplanations) throws OWLException {
if (log.isLoggable(Level.FINE)) {
log.fine("MUPS " + allMups.size() + ": " + mups);
}
if (progressMonitor.isCancelled()) {
return;
}
// We go through the current mups, axiom by axiom, and extend the tree
// with edges for each axiom
List orderedMups = getOrderedMUPS(new ArrayList(mups),
allMups);
while (!orderedMups.isEmpty()) {
if (progressMonitor.isCancelled()) {
return;
}
OWLAxiom axiom = orderedMups.get(0);
orderedMups.remove(0);
if (allMups.size() == maxExplanations) {
if (log.isLoggable(Level.FINE)) {
log.fine("Computed " + maxExplanations + "explanations");
}
return;
}
if (log.isLoggable(Level.FINE)) {
log.fine("Removing axiom: " + axiom + " " + currentPathContents.size()
+ " more removed: " + currentPathContents);
}
// Remove the current axiom from all the ontologies it is included
// in
Set ontologies = OntologyUtils.removeAxiom(axiom, getReasoner()
.getRootOntology().getImportsClosure(), getOntologyManager());
// Removal may have dereferenced some entities, if so declarations
// are added
Set sig = getSignature(axiom);
List temporaryDeclarations = new ArrayList(
sig.size());
for (OWLEntity e : sig) {
boolean referenced = false;
for (Iterator i = ontologies.iterator(); !referenced
&& i.hasNext();) {
for (Iterator j = i.next().getReferencingAxioms(e)
.iterator(); !referenced && j.hasNext();) {
OWLAxiom a = j.next();
referenced = a.isLogicalAxiom()
|| a instanceof OWLDeclarationAxiom;
}
}
if (!referenced) {
OWLDeclarationAxiom declaration = getOntologyManager()
.getOWLDataFactory().getOWLDeclarationAxiom(e);
temporaryDeclarations.add(declaration);
}
}
for (OWLDeclarationAxiom decl : temporaryDeclarations) {
OntologyUtils.addAxiom(decl, getReasoner().getRootOntology()
.getImportsClosure(), getOntologyManager());
}
currentPathContents.add(axiom);
boolean earlyTermination = false;
// Early path termination. If our path contents are the superset of
// the contents of a path then we can terminate here.
for (Set satPath : satPaths) {
if (currentPathContents.containsAll(satPath)) {
earlyTermination = true;
if (log.isLoggable(Level.FINE)) {
log.fine("Stop - satisfiable (early termination)");
}
break;
}
}
if (!earlyTermination) {
Set newMUPS = null;
for (Set foundMUPS : allMups) {
Set foundMUPSCopy = new HashSet(foundMUPS);
foundMUPSCopy.retainAll(currentPathContents);
if (foundMUPSCopy.isEmpty()) {
newMUPS = foundMUPS;
break;
}
}
if (newMUPS == null) {
newMUPS = getExplanation(unsatClass);
}
// Generate a new node - i.e. a new justification set
if (newMUPS.contains(axiom)) {
// How can this be the case???
throw new OWLRuntimeException("Explanation contains removed axiom: "
+ axiom);
}
if (!newMUPS.isEmpty()) {
// Note that getting a previous justification does not mean
// we can stop. stopping here causes some justifications to
// be missed
allMups.add(newMUPS);
progressMonitor.foundExplanation(newMUPS);
// Recompute priority here?
constructHittingSetTree(unsatClass, newMUPS, allMups, satPaths,
currentPathContents, maxExplanations);
// We have found a new MUPS, so recalculate the ordering
// axioms in the MUPS at the current level
orderedMups = getOrderedMUPS(orderedMups, allMups);
} else {
if (log.isLoggable(Level.FINE)) {
log.fine("Stop - satisfiable");
}
// End of current path - add it to the list of paths
satPaths.add(new HashSet(currentPathContents));
}
}
// Back track - go one level up the tree and run for the next axiom
currentPathContents.remove(axiom);
if (log.isLoggable(Level.FINE)) {
log.fine("Restoring axiom: " + axiom);
}
// Remove any temporary declarations
for (OWLDeclarationAxiom decl : temporaryDeclarations) {
OntologyUtils.removeAxiom(decl, getReasoner().getRootOntology()
.getImportsClosure(), getOntologyManager());
}
// Done with the axiom that was removed. Add it back in
OntologyUtils.addAxiom(axiom, ontologies, getOntologyManager());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy