org.semanticweb.owlapi.reasoner.structural.StructuralReasoner 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 2014, The University of Manchester
*
* 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.
* 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 org.semanticweb.owlapi.reasoner.structural;
import static org.semanticweb.owlapi.model.parameters.Imports.INCLUDED;
import static org.semanticweb.owlapi.search.Searcher.sub;
import static org.semanticweb.owlapi.search.Searcher.sup;
import static org.semanticweb.owlapi.util.OWLAPIPreconditions.checkNotNull;
import static org.semanticweb.owlapi.util.OWLAPIPreconditions.verifyNotNull;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLDifferentIndividualsAxiom;
import org.semanticweb.owlapi.model.OWLDisjointClassesAxiom;
import org.semanticweb.owlapi.model.OWLDisjointDataPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObject;
import org.semanticweb.owlapi.model.OWLObjectIntersectionOf;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyDomainAxiom;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectPropertyRangeAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLSameIndividualAxiom;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.parameters.AxiomAnnotations;
import org.semanticweb.owlapi.reasoner.BufferingMode;
import org.semanticweb.owlapi.reasoner.FreshEntityPolicy;
import org.semanticweb.owlapi.reasoner.IndividualNodeSetPolicy;
import org.semanticweb.owlapi.reasoner.InferenceType;
import org.semanticweb.owlapi.reasoner.Node;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration;
import org.semanticweb.owlapi.reasoner.ReasonerInterruptedException;
import org.semanticweb.owlapi.reasoner.ReasonerProgressMonitor;
import org.semanticweb.owlapi.reasoner.TimeOutException;
import org.semanticweb.owlapi.reasoner.impl.DefaultNode;
import org.semanticweb.owlapi.reasoner.impl.DefaultNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLClassNode;
import org.semanticweb.owlapi.reasoner.impl.OWLClassNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLDataPropertyNode;
import org.semanticweb.owlapi.reasoner.impl.OWLDataPropertyNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNode;
import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLObjectPropertyNode;
import org.semanticweb.owlapi.reasoner.impl.OWLObjectPropertyNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLReasonerBase;
import org.semanticweb.owlapi.search.Filters;
import org.semanticweb.owlapi.util.CollectionFactory;
import org.semanticweb.owlapi.util.OWLObjectPropertyManager;
import org.semanticweb.owlapi.util.Version;
/**
* This is a simple structural reasoner that essentially answers with told information. It is
* incomplete.
*
* @author Matthew Horridge, The University of Manchester, Information Management Group
* @since 3.0.0
*/
public class StructuralReasoner extends OWLReasonerBase {
@Nonnull
private final ClassHierarchyInfo classHierarchyInfo = new ClassHierarchyInfo();
@Nonnull
private final ObjectPropertyHierarchyInfo objectPropertyHierarchyInfo =
new ObjectPropertyHierarchyInfo();
@Nonnull
private final DataPropertyHierarchyInfo dataPropertyHierarchyInfo =
new DataPropertyHierarchyInfo();
@Nonnull
private static final Version VERSION = new Version(1, 0, 0, 0);
private boolean interrupted = false;
@Nonnull
protected final ReasonerProgressMonitor pm;
private boolean prepared = false;
/**
* @param rootOntology the ontology
* @param configuration the reasoner configuration
* @param bufferingMode the buffering mode
*/
public StructuralReasoner(@Nonnull OWLOntology rootOntology,
@Nonnull OWLReasonerConfiguration configuration, @Nonnull BufferingMode bufferingMode) {
super(rootOntology, configuration, bufferingMode);
checkNotNull(configuration, "configuration cannot be null");
pm = configuration.getProgressMonitor();
prepareReasoner();
}
@Nonnull
@Override
public String getReasonerName() {
return "Structural Reasoner";
}
@Override
public FreshEntityPolicy getFreshEntityPolicy() {
return FreshEntityPolicy.ALLOW;
}
@Override
public IndividualNodeSetPolicy getIndividualNodeSetPolicy() {
return IndividualNodeSetPolicy.BY_NAME;
}
@Nonnull
@Override
public Version getReasonerVersion() {
return VERSION;
}
@Override
protected void handleChanges(@Nonnull Set addAxioms,
@Nonnull Set removeAxioms) {
handleChanges(addAxioms, removeAxioms, classHierarchyInfo);
handleChanges(addAxioms, removeAxioms, objectPropertyHierarchyInfo);
handleChanges(addAxioms, removeAxioms, dataPropertyHierarchyInfo);
}
private static void handleChanges(@Nonnull Set added,
@Nonnull Set removed, @Nonnull AbstractHierarchyInfo hierarchyInfo) {
Set sig = hierarchyInfo.getEntitiesInSignature(added);
sig.addAll(hierarchyInfo.getEntitiesInSignature(removed));
hierarchyInfo.processChanges(sig, added, removed);
}
@Override
public void interrupt() {
interrupted = true;
}
private void ensurePrepared() {
if (!prepared) {
prepareReasoner();
}
}
/**
* @throws ReasonerInterruptedException on interruption
* @throws TimeOutException on timeout
*/
public final void prepareReasoner() {
classHierarchyInfo.computeHierarchy();
objectPropertyHierarchyInfo.computeHierarchy();
dataPropertyHierarchyInfo.computeHierarchy();
prepared = true;
}
@Override
public void precomputeInferences(InferenceType... inferenceTypes) {
prepareReasoner();
}
@Override
public boolean isPrecomputed(InferenceType inferenceType) {
return true;
}
@Override
public Set getPrecomputableInferenceTypes() {
return CollectionFactory.createSet(InferenceType.CLASS_HIERARCHY,
InferenceType.OBJECT_PROPERTY_HIERARCHY, InferenceType.DATA_PROPERTY_HIERARCHY);
}
protected void throwExceptionIfInterrupted() {
if (interrupted) {
interrupted = false;
throw new ReasonerInterruptedException();
}
}
@Override
public boolean isConsistent() {
return true;
}
@Override
public boolean isSatisfiable(@Nonnull OWLClassExpression classExpression) {
return !classExpression.isAnonymous() && !getEquivalentClasses(classExpression.asOWLClass())
.contains(getDataFactory().getOWLNothing());
}
@Nonnull
@Override
public Node getUnsatisfiableClasses() {
return OWLClassNode.getBottomNode();
}
@Override
public boolean isEntailed(OWLAxiom axiom) {
return getRootOntology().containsAxiom(axiom, INCLUDED,
AxiomAnnotations.IGNORE_AXIOM_ANNOTATIONS);
}
@Override
public boolean isEntailed(@Nonnull Set extends OWLAxiom> axioms) {
for (OWLAxiom ax : axioms) {
assert ax != null;
if (!getRootOntology().containsAxiom(ax, INCLUDED,
AxiomAnnotations.IGNORE_AXIOM_ANNOTATIONS)) {
return false;
}
}
return true;
}
@Override
public boolean isEntailmentCheckingSupported(AxiomType> axiomType) {
return false;
}
@Override
public Node getTopClassNode() {
ensurePrepared();
return classHierarchyInfo.getEquivalents(getDataFactory().getOWLThing());
}
@Override
public Node getBottomClassNode() {
ensurePrepared();
return classHierarchyInfo.getEquivalents(getDataFactory().getOWLNothing());
}
@Nonnull
@Override
public NodeSet getSubClasses(@Nonnull OWLClassExpression ce, boolean direct) {
OWLClassNodeSet ns = new OWLClassNodeSet();
if (!ce.isAnonymous()) {
ensurePrepared();
return classHierarchyInfo.getNodeHierarchyChildren(ce.asOWLClass(), direct, ns);
}
return ns;
}
@Nonnull
@Override
public NodeSet getSuperClasses(@Nonnull OWLClassExpression ce, boolean direct) {
OWLClassNodeSet ns = new OWLClassNodeSet();
if (!ce.isAnonymous()) {
ensurePrepared();
return classHierarchyInfo.getNodeHierarchyParents(ce.asOWLClass(), direct, ns);
}
return ns;
}
@Override
public Node getEquivalentClasses(@Nonnull OWLClassExpression ce) {
ensurePrepared();
if (!ce.isAnonymous()) {
return classHierarchyInfo.getEquivalents(ce.asOWLClass());
} else {
return new OWLClassNode();
}
}
@Nonnull
@Override
public NodeSet getDisjointClasses(@Nonnull OWLClassExpression ce) {
ensurePrepared();
OWLClassNodeSet nodeSet = new OWLClassNodeSet();
if (!ce.isAnonymous()) {
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLDisjointClassesAxiom ax : ontology
.getDisjointClassesAxioms(ce.asOWLClass())) {
for (OWLClassExpression op : ax.getClassExpressions()) {
if (!op.isAnonymous()) {
nodeSet.addNode(getEquivalentClasses(op));
}
}
}
}
}
return nodeSet;
}
@Override
public Node getTopObjectPropertyNode() {
ensurePrepared();
return objectPropertyHierarchyInfo
.getEquivalents(getDataFactory().getOWLTopObjectProperty());
}
@Override
public Node getBottomObjectPropertyNode() {
ensurePrepared();
return objectPropertyHierarchyInfo
.getEquivalents(getDataFactory().getOWLBottomObjectProperty());
}
@Nonnull
@Override
public NodeSet getSubObjectProperties(
OWLObjectPropertyExpression pe, boolean direct) {
OWLObjectPropertyNodeSet ns = new OWLObjectPropertyNodeSet();
ensurePrepared();
return objectPropertyHierarchyInfo.getNodeHierarchyChildren(pe, direct, ns);
}
@Nonnull
@Override
public NodeSet getSuperObjectProperties(
OWLObjectPropertyExpression pe, boolean direct) {
OWLObjectPropertyNodeSet ns = new OWLObjectPropertyNodeSet();
ensurePrepared();
return objectPropertyHierarchyInfo.getNodeHierarchyParents(pe, direct, ns);
}
@Override
public Node getEquivalentObjectProperties(
OWLObjectPropertyExpression pe) {
ensurePrepared();
return objectPropertyHierarchyInfo.getEquivalents(pe);
}
@Nonnull
@Override
public NodeSet getDisjointObjectProperties(
OWLObjectPropertyExpression pe) {
return new OWLObjectPropertyNodeSet();
}
@Override
public Node getInverseObjectProperties(
@Nonnull OWLObjectPropertyExpression pe) {
ensurePrepared();
return getEquivalentObjectProperties(pe.getInverseProperty());
}
@Nonnull
@Override
public NodeSet getObjectPropertyDomains(@Nonnull OWLObjectPropertyExpression pe,
boolean direct) {
ensurePrepared();
DefaultNodeSet result = new OWLClassNodeSet();
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLObjectPropertyDomainAxiom axiom : ontology.getObjectPropertyDomainAxioms(pe)) {
result.addNode(getEquivalentClasses(axiom.getDomain()));
if (!direct) {
result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
}
}
for (OWLObjectPropertyExpression invPe : getInverseObjectProperties(pe).getEntities()) {
assert invPe != null;
for (OWLObjectPropertyRangeAxiom axiom : ontology
.getObjectPropertyRangeAxioms(invPe)) {
result.addNode(getEquivalentClasses(axiom.getRange()));
if (!direct) {
result.addAllNodes(getSuperClasses(axiom.getRange(), false).getNodes());
}
}
}
}
return result;
}
@Nonnull
@Override
public NodeSet getObjectPropertyRanges(@Nonnull OWLObjectPropertyExpression pe,
boolean direct) {
ensurePrepared();
DefaultNodeSet result = new OWLClassNodeSet();
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLObjectPropertyRangeAxiom axiom : ontology.getObjectPropertyRangeAxioms(pe)) {
result.addNode(getEquivalentClasses(axiom.getRange()));
if (!direct) {
result.addAllNodes(getSuperClasses(axiom.getRange(), false).getNodes());
}
}
for (OWLObjectPropertyExpression invPe : getInverseObjectProperties(pe).getEntities()) {
assert invPe != null;
for (OWLObjectPropertyDomainAxiom axiom : ontology
.getObjectPropertyDomainAxioms(invPe)) {
result.addNode(getEquivalentClasses(axiom.getDomain()));
if (!direct) {
result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
}
}
}
}
return result;
}
@Override
public Node getTopDataPropertyNode() {
ensurePrepared();
return dataPropertyHierarchyInfo.getEquivalents(getDataFactory().getOWLTopDataProperty());
}
@Override
public Node getBottomDataPropertyNode() {
ensurePrepared();
return dataPropertyHierarchyInfo
.getEquivalents(getDataFactory().getOWLBottomDataProperty());
}
@Nonnull
@Override
public NodeSet getSubDataProperties(OWLDataProperty pe, boolean direct) {
ensurePrepared();
OWLDataPropertyNodeSet ns = new OWLDataPropertyNodeSet();
return dataPropertyHierarchyInfo.getNodeHierarchyChildren(pe, direct, ns);
}
@Nonnull
@Override
public NodeSet getSuperDataProperties(OWLDataProperty pe, boolean direct) {
ensurePrepared();
OWLDataPropertyNodeSet ns = new OWLDataPropertyNodeSet();
return dataPropertyHierarchyInfo.getNodeHierarchyParents(pe, direct, ns);
}
@Override
public Node getEquivalentDataProperties(OWLDataProperty pe) {
ensurePrepared();
return dataPropertyHierarchyInfo.getEquivalents(pe);
}
@Nonnull
@Override
public NodeSet getDisjointDataProperties(
@Nonnull OWLDataPropertyExpression pe) {
ensurePrepared();
DefaultNodeSet result = new OWLDataPropertyNodeSet();
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLDisjointDataPropertiesAxiom axiom : ontology
.getDisjointDataPropertiesAxioms(pe.asOWLDataProperty())) {
for (OWLDataPropertyExpression dpe : axiom.getPropertiesMinus(pe)) {
if (!dpe.isAnonymous()) {
result.addNode(
dataPropertyHierarchyInfo.getEquivalents(dpe.asOWLDataProperty()));
result.addAllNodes(
getSubDataProperties(dpe.asOWLDataProperty(), false).getNodes());
}
}
}
}
return result;
}
@Nonnull
@Override
public NodeSet getDataPropertyDomains(OWLDataProperty pe, boolean direct) {
ensurePrepared();
DefaultNodeSet result = new OWLClassNodeSet();
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLDataPropertyDomainAxiom axiom : ontology.getDataPropertyDomainAxioms(pe)) {
result.addNode(getEquivalentClasses(axiom.getDomain()));
if (!direct) {
result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
}
}
}
return result;
}
@Nonnull
@Override
public NodeSet getTypes(OWLNamedIndividual ind, boolean direct) {
ensurePrepared();
DefaultNodeSet result = new OWLClassNodeSet();
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLClassAssertionAxiom axiom : ontology.getClassAssertionAxioms(ind)) {
OWLClassExpression ce = axiom.getClassExpression();
if (!ce.isAnonymous()) {
result.addNode(classHierarchyInfo.getEquivalents(ce.asOWLClass()));
if (!direct) {
result.addAllNodes(getSuperClasses(ce, false).getNodes());
}
}
}
}
return result;
}
@Nonnull
@Override
public NodeSet getInstances(@Nonnull OWLClassExpression ce,
boolean direct) {
ensurePrepared();
DefaultNodeSet result = new OWLNamedIndividualNodeSet();
if (!ce.isAnonymous()) {
OWLClass cls = ce.asOWLClass();
Set clses = new HashSet<>();
clses.add(cls);
if (!direct) {
clses.addAll(getSubClasses(cls, false).getFlattened());
}
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLClass curCls : clses) {
assert curCls != null;
for (OWLClassAssertionAxiom axiom : ontology.getClassAssertionAxioms(curCls)) {
OWLIndividual individual = axiom.getIndividual();
if (!individual.isAnonymous()) {
if (getIndividualNodeSetPolicy()
.equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
result
.addNode(getSameIndividuals(individual.asOWLNamedIndividual()));
} else {
result.addNode(
new OWLNamedIndividualNode(individual.asOWLNamedIndividual()));
}
}
}
}
}
}
return result;
}
@Nonnull
@Override
public NodeSet getObjectPropertyValues(OWLNamedIndividual ind,
@Nonnull OWLObjectPropertyExpression pe) {
ensurePrepared();
OWLNamedIndividualNodeSet result = new OWLNamedIndividualNodeSet();
Node inverses = getInverseObjectProperties(pe);
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLObjectPropertyAssertionAxiom axiom : ontology
.getObjectPropertyAssertionAxioms(ind)) {
if (!axiom.getObject().isAnonymous() && axiom.getProperty().equals(pe)) {
if (getIndividualNodeSetPolicy().equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
result
.addNode(getSameIndividuals(axiom.getObject().asOWLNamedIndividual()));
} else {
result.addNode(
new OWLNamedIndividualNode(axiom.getObject().asOWLNamedIndividual()));
}
}
// Inverse of pe
if (axiom.getObject().equals(ind) && !axiom.getSubject().isAnonymous()) {
OWLObjectPropertyExpression invPe = axiom.getProperty().getInverseProperty();
if (!invPe.isAnonymous() && inverses.contains(invPe.asOWLObjectProperty())) {
if (getIndividualNodeSetPolicy()
.equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
result.addNode(
getSameIndividuals(axiom.getObject().asOWLNamedIndividual()));
} else {
result.addNode(new OWLNamedIndividualNode(
axiom.getObject().asOWLNamedIndividual()));
}
}
}
}
}
// Could do other stuff like inspecting owl:hasValue restrictions
return result;
}
@Nonnull
@Override
public Set getDataPropertyValues(OWLNamedIndividual ind, OWLDataProperty pe) {
ensurePrepared();
Set literals = new HashSet<>();
Set superProperties = getSuperDataProperties(pe, false).getFlattened();
superProperties.addAll(getEquivalentDataProperties(pe).getEntities());
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLDataPropertyAssertionAxiom axiom : ontology
.getDataPropertyAssertionAxioms(ind)) {
if (superProperties.contains(axiom.getProperty().asOWLDataProperty())) {
literals.add(axiom.getObject());
}
}
}
return literals;
}
@Nonnull
@Override
public Node getSameIndividuals(OWLNamedIndividual ind) {
ensurePrepared();
Set inds = new HashSet<>();
Set processed = new HashSet<>();
List stack = new LinkedList<>();
stack.add(ind);
while (!stack.isEmpty()) {
OWLNamedIndividual currentInd = stack.remove(0);
assert currentInd != null;
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLSameIndividualAxiom axiom : ontology.getSameIndividualAxioms(currentInd)) {
if (!processed.contains(axiom)) {
processed.add(axiom);
for (OWLIndividual i : axiom.getIndividuals()) {
if (!i.isAnonymous()) {
OWLNamedIndividual namedInd = i.asOWLNamedIndividual();
if (inds.add(namedInd)) {
stack.add(namedInd);
}
}
}
}
}
}
}
if (inds.isEmpty()) {
inds.add(ind);
}
return new OWLNamedIndividualNode(inds);
}
@Nonnull
@Override
public NodeSet getDifferentIndividuals(OWLNamedIndividual ind) {
ensurePrepared();
Set inds = new HashSet<>();
Set processed = new HashSet<>();
List stack = new LinkedList<>();
stack.add(ind);
while (!stack.isEmpty()) {
OWLNamedIndividual currentInd = stack.remove(0);
assert currentInd != null;
for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
for (OWLDifferentIndividualsAxiom axiom : ontology
.getDifferentIndividualAxioms(currentInd)) {
if (!processed.contains(axiom)) {
processed.add(axiom);
for (OWLIndividual i : axiom.getIndividuals()) {
if (!i.isAnonymous()) {
OWLNamedIndividual namedInd = i.asOWLNamedIndividual();
if (inds.add(namedInd)) {
stack.add(namedInd);
}
}
}
}
}
}
}
if (inds.isEmpty()) {
inds.add(ind);
}
Set> set = new HashSet<>();
for (OWLNamedIndividual n : inds) {
set.add(getSameIndividuals(n));
}
return new OWLNamedIndividualNodeSet(set);
}
protected OWLDataFactory getDataFactory() {
return getRootOntology().getOWLOntologyManager().getOWLDataFactory();
}
/**
* @param showBottomNode true if bottom node is to be showed
*/
public void dumpClassHierarchy(boolean showBottomNode) {
dumpClassHierarchy(OWLClassNode.getTopNode(), 0, showBottomNode);
}
private void dumpClassHierarchy(@Nonnull Node cls, int level,
boolean showBottomNode) {
if (!showBottomNode && cls.isBottomNode()) {
return;
}
printIndent(level);
OWLClass representative = cls.getRepresentativeElement();
System.out.println(getEquivalentClasses(representative));
for (Node subCls : getSubClasses(representative, true)) {
assert subCls != null;
dumpClassHierarchy(subCls, level + 1, showBottomNode);
}
}
/**
* @param showBottomNode true if bottom node is to be showed
*/
public void dumpObjectPropertyHierarchy(boolean showBottomNode) {
dumpObjectPropertyHierarchy(OWLObjectPropertyNode.getTopNode(), 0, showBottomNode);
}
private void dumpObjectPropertyHierarchy(@Nonnull Node cls,
int level, boolean showBottomNode) {
if (!showBottomNode && cls.isBottomNode()) {
return;
}
printIndent(level);
OWLObjectPropertyExpression representative = cls.getRepresentativeElement();
System.out.println(getEquivalentObjectProperties(representative));
for (Node subProp : getSubObjectProperties(representative,
true)) {
assert subProp != null;
dumpObjectPropertyHierarchy(subProp, level + 1, showBottomNode);
}
}
/**
* @param showBottomNode true if bottom node is to be showed
*/
public void dumpDataPropertyHierarchy(boolean showBottomNode) {
dumpDataPropertyHierarchy(OWLDataPropertyNode.getTopNode(), 0, showBottomNode);
}
private void dumpDataPropertyHierarchy(@Nonnull Node cls, int level,
boolean showBottomNode) {
if (!showBottomNode && cls.isBottomNode()) {
return;
}
printIndent(level);
OWLDataProperty representative = cls.getRepresentativeElement();
System.out.println(getEquivalentDataProperties(representative));
for (Node subProp : getSubDataProperties(representative, true)) {
assert subProp != null;
dumpDataPropertyHierarchy(subProp, level + 1, showBottomNode);
}
}
private static void printIndent(int level) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
}
// HierarchyInfo
private abstract class AbstractHierarchyInfo {
private final RawHierarchyProvider rawParentChildProvider;
/** The entity that always appears in the top node in the hierarchy. */
@Nonnull
T topEntity;
/**
* The entity that always appears as the bottom node in the hierarchy.
*/
@Nonnull
T bottomEntity;
@Nonnull
private final Set directChildrenOfTopNode = new HashSet<>();
@Nonnull
private final Set directParentsOfBottomNode = new HashSet<>();
private final NodeCache nodeCache;
private final String name;
private int classificationSize;
AbstractHierarchyInfo(String name, @Nonnull T topEntity, @Nonnull T bottomEntity,
RawHierarchyProvider rawParentChildProvider) {
this.topEntity = topEntity;
this.bottomEntity = bottomEntity;
nodeCache = new NodeCache<>(this);
this.rawParentChildProvider = rawParentChildProvider;
this.name = name;
}
public RawHierarchyProvider getRawParentChildProvider() {
return rawParentChildProvider;
}
/**
* Gets the set of relevant entities from the specified ontology.
*
* @param ont The ontology
* @return A set of entities to be "classified"
*/
@Nonnull
protected abstract Set getEntities(@Nonnull OWLOntology ont);
/**
* Creates a node for a given set of entities.
*
* @param cycle The set of entities
* @return A node
*/
@Nonnull
protected abstract DefaultNode createNode(@Nonnull Set cycle);
@Nonnull
protected abstract DefaultNode createNode();
/**
* Gets the set of relevant entities in a particular axiom.
*
* @param ax The axiom
* @return The set of relevant entities in the signature of the specified axiom
*/
@Nonnull
protected abstract Set extends T> getEntitiesInSignature(@Nonnull OWLAxiom ax);
@Nonnull
Set getEntitiesInSignature(@Nonnull Set axioms) {
Set result = new HashSet<>();
for (OWLAxiom ax : axioms) {
assert ax != null;
result.addAll(getEntitiesInSignature(ax));
}
return result;
}
public void computeHierarchy() {
pm.reasonerTaskStarted("Computing " + name + " hierarchy");
pm.reasonerTaskBusy();
nodeCache.clear();
Map> cache = new HashMap<>();
Set entities = new HashSet<>();
for (OWLOntology ont : getRootOntology().getImportsClosure()) {
assert ont != null;
entities.addAll(getEntities(ont));
}
classificationSize = entities.size();
pm.reasonerTaskProgressChanged(0, classificationSize);
updateForSignature(entities, cache);
pm.reasonerTaskStopped();
}
private void updateForSignature(@Nonnull Set signature,
@Nullable Map> cache) {
HashSet> cyclesResult = new HashSet<>();
Set processed = new HashSet<>();
nodeCache.clearTopNode();
nodeCache.clearBottomNode();
nodeCache.clearNodes(signature);
directChildrenOfTopNode.removeAll(signature);
Set equivTopOrChildrenOfTop = new HashSet<>();
Set equivBottomOrParentsOfBottom = new HashSet<>();
for (T entity : signature) {
assert entity != null;
if (!processed.contains(entity)) {
pm.reasonerTaskProgressChanged(processed.size(), signature.size());
tarjan(entity, 0, new Stack(), new HashMap(),
new HashMap(), cyclesResult, processed, new HashSet(), cache,
equivTopOrChildrenOfTop, equivBottomOrParentsOfBottom);
throwExceptionIfInterrupted();
}
}
// Store new cycles
for (Set cycle : cyclesResult) {
assert cycle != null;
nodeCache.addNode(cycle);
}
directChildrenOfTopNode.addAll(equivTopOrChildrenOfTop);
directChildrenOfTopNode.removeAll(nodeCache.getTopNode().getEntities());
directParentsOfBottomNode.addAll(equivBottomOrParentsOfBottom);
directParentsOfBottomNode.removeAll(nodeCache.getBottomNode().getEntities());
// Now check that each found cycle has a proper parent an child
for (Set node : cyclesResult) {
if (!node.contains(topEntity) && !node.contains(bottomEntity)) {
boolean childOfTop = true;
for (T element : node) {
assert element != null;
Collection parents = rawParentChildProvider.getParents(element);
parents.removeAll(node);
parents.removeAll(nodeCache.getTopNode().getEntities());
if (!parents.isEmpty()) {
childOfTop = false;
break;
}
}
if (childOfTop) {
directChildrenOfTopNode.addAll(node);
}
boolean parentOfBottom = true;
for (T element : node) {
assert element != null;
Collection children = rawParentChildProvider.getChildren(element);
children.removeAll(node);
children.removeAll(nodeCache.getBottomNode().getEntities());
if (!children.isEmpty()) {
parentOfBottom = false;
break;
}
}
if (parentOfBottom) {
directParentsOfBottomNode.addAll(node);
}
}
}
}
/**
* Processes the specified signature that represents the signature of potential changes.
*
* @param signature The signature
* @param added added axioms
* @param removed removed axioms
*/
@SuppressWarnings("unused")
public void processChanges(@Nonnull Set signature, @Nonnull Set added,
@Nonnull Set removed) {
updateForSignature(signature, null);
}
/**
* Applies the tarjan algorithm for a given entity. This computes the cycle that the entity
* is involved in (if any).
*
* @param entity The entity
* @param inputIndex index
* @param stack stack
* @param indexMap index map
* @param lowlinkMap low link map
* @param result result
* @param processed processed
* @param stackEntities stack entities
* @param cache A cache of children to parents - may be {@code null} if no caching
* is to take place.
* @param childrenOfTop A set of entities that have a raw parent that is the top entity
* @param parentsOfBottom A set of entities that have a raw parent that is the bottom entity
*/
public void tarjan(@Nonnull T entity, int inputIndex, @Nonnull Stack stack,
@Nonnull Map indexMap, @Nonnull Map lowlinkMap,
@Nonnull Set> result, @Nonnull Set processed, @Nonnull Set stackEntities,
@Nullable Map> cache, @Nonnull Set childrenOfTop,
@Nonnull Set parentsOfBottom) {
int index = inputIndex;
throwExceptionIfInterrupted();
if (processed.add(entity)) {
Collection rawChildren = rawParentChildProvider.getChildren(entity);
if (rawChildren.isEmpty() || rawChildren.contains(bottomEntity)) {
parentsOfBottom.add(entity);
}
}
pm.reasonerTaskProgressChanged(processed.size(), classificationSize);
indexMap.put(entity, Integer.valueOf(index));
lowlinkMap.put(entity, Integer.valueOf(index));
index += 1;
stack.push(entity);
stackEntities.add(entity);
// Get the raw parents - cache if necessary
Collection rawParents = null;
if (cache != null) {
// We are therefore caching raw parents of children.
rawParents = cache.get(entity);
if (rawParents == null) {
// Not in cache!
rawParents = rawParentChildProvider.getParents(entity);
// Note down if our entity is a
if (rawParents.isEmpty() || rawParents.contains(topEntity)) {
childrenOfTop.add(entity);
}
cache.put(entity, rawParents);
}
} else {
rawParents = rawParentChildProvider.getParents(entity);
// Note down if our entity is a
if (rawParents.isEmpty() || rawParents.contains(topEntity)) {
childrenOfTop.add(entity);
}
}
for (T superEntity : rawParents) {
assert superEntity != null;
if (!indexMap.containsKey(superEntity)) {
tarjan(superEntity, index, stack, indexMap, lowlinkMap, result, processed,
stackEntities, cache, childrenOfTop, parentsOfBottom);
lowlinkMap.put(entity,
Integer.valueOf(Math.min(lowlinkMap.get(entity).intValue(),
lowlinkMap.get(superEntity).intValue())));
} else if (stackEntities.contains(superEntity)) {
lowlinkMap.put(entity,
Integer.valueOf(Math.min(lowlinkMap.get(entity).intValue(),
indexMap.get(superEntity).intValue())));
}
}
if (lowlinkMap.get(entity).equals(indexMap.get(entity))) {
Set scc = new HashSet<>();
while (true) {
T clsPrime = stack.pop();
stackEntities.remove(clsPrime);
scc.add(clsPrime);
if (clsPrime.equals(entity)) {
break;
}
}
if (scc.size() > 1) {
// We ADD a cycle
result.add(scc);
}
}
}
@Nonnull
public NodeSet getNodeHierarchyChildren(@Nonnull T parent, boolean direct,
@Nonnull DefaultNodeSet ns) {
Node node = nodeCache.getNode(parent);
if (node.isBottomNode()) {
return ns;
}
Set directChildren = new HashSet<>();
for (T equiv : node) {
assert equiv != null;
directChildren.addAll(rawParentChildProvider.getChildren(equiv));
if (directParentsOfBottomNode.contains(equiv)) {
ns.addNode(nodeCache.getBottomNode());
}
}
directChildren.removeAll(node.getEntities());
if (node.isTopNode()) {
// Special treatment
directChildren.addAll(directChildrenOfTopNode);
}
for (Node childNode : nodeCache.getNodes(directChildren)) {
assert childNode != null;
ns.addNode(childNode);
}
if (!direct) {
for (T child : directChildren) {
assert child != null;
getNodeHierarchyChildren(child, direct, ns);
}
}
return ns;
}
@Nonnull
public NodeSet getNodeHierarchyParents(@Nonnull T child, boolean direct,
@Nonnull DefaultNodeSet ns) {
Node node = nodeCache.getNode(child);
if (node.isTopNode()) {
return ns;
}
Set directParents = new HashSet<>();
for (T equiv : node) {
assert equiv != null;
directParents.addAll(rawParentChildProvider.getParents(equiv));
if (directChildrenOfTopNode.contains(equiv)) {
ns.addNode(nodeCache.getTopNode());
}
}
directParents.removeAll(node.getEntities());
if (node.isBottomNode()) {
// Special treatment
directParents.addAll(directParentsOfBottomNode);
}
for (Node parentNode : nodeCache.getNodes(directParents)) {
assert parentNode != null;
ns.addNode(parentNode);
}
if (!direct) {
for (T parent : directParents) {
assert parent != null;
getNodeHierarchyParents(parent, direct, ns);
}
}
return ns;
}
@Nonnull
public Node getEquivalents(@Nonnull T element) {
return nodeCache.getNode(element);
}
}
private static class NodeCache {
@Nonnull
private final AbstractHierarchyInfo hierarchyInfo;
private Node topNode;
private Node bottomNode;
@Nonnull
private final Map> map = new HashMap<>();
protected NodeCache(@Nonnull AbstractHierarchyInfo hierarchyInfo) {
this.hierarchyInfo = hierarchyInfo;
clearTopNode();
clearBottomNode();
}
public void addNode(@Nonnull Node node) {
for (T element : node.getEntities()) {
map.put(element, node);
if (element.isTopEntity()) {
topNode = node;
} else if (element.isBottomEntity()) {
bottomNode = node;
}
}
}
@Nonnull
public Set> getNodes(@Nonnull Set elements) {
Set> result = new HashSet<>();
for (T element : elements) {
assert element != null;
result.add(getNode(element));
}
return result;
}
@Nonnull
public Node getNode(@Nonnull T containing) {
Node parentNode = map.get(containing);
if (parentNode != null) {
return parentNode;
} else {
return hierarchyInfo.createNode(CollectionFactory.createSet(containing));
}
}
public void addNode(@Nonnull Set elements) {
addNode(hierarchyInfo.createNode(elements));
}
@Nonnull
public Node getTopNode() {
return verifyNotNull(topNode);
}
@Nonnull
public Node getBottomNode() {
return verifyNotNull(bottomNode);
}
public final void clearTopNode() {
removeNode(hierarchyInfo.topEntity);
topNode =
hierarchyInfo.createNode(CollectionFactory.createSet(hierarchyInfo.topEntity));
addNode(getTopNode());
}
public final void clearBottomNode() {
removeNode(hierarchyInfo.bottomEntity);
bottomNode =
hierarchyInfo.createNode(CollectionFactory.createSet(hierarchyInfo.bottomEntity));
addNode(getBottomNode());
}
public void clearNodes(@Nonnull Set containing) {
for (T entity : containing) {
removeNode(entity);
}
}
public void clear() {
map.clear();
clearTopNode();
clearBottomNode();
}
public void removeNode(T containing) {
Node node = map.remove(containing);
if (node != null) {
for (T object : node.getEntities()) {
map.remove(object);
}
}
}
}
private class ClassHierarchyInfo extends AbstractHierarchyInfo {
ClassHierarchyInfo() {
super("class", getDataFactory().getOWLThing(), getDataFactory().getOWLNothing(),
new RawClassHierarchyProvider());
}
@Nonnull
@Override
protected Set getEntitiesInSignature(@Nonnull OWLAxiom ax) {
return ax.getClassesInSignature();
}
@Nonnull
@Override
protected DefaultNode createNode(@Nonnull Set cycle) {
return new OWLClassNode(cycle);
}
@Nonnull
@Override
protected Set getEntities(@Nonnull OWLOntology ont) {
return ont.getClassesInSignature();
}
@Nonnull
@Override
protected DefaultNode createNode() {
return new OWLClassNode();
}
}
private class ObjectPropertyHierarchyInfo
extends AbstractHierarchyInfo {
ObjectPropertyHierarchyInfo() {
super("object property", getDataFactory().getOWLTopObjectProperty(),
getDataFactory().getOWLBottomObjectProperty(),
new RawObjectPropertyHierarchyProvider());
}
@Nonnull
@Override
protected Set getEntitiesInSignature(@Nonnull OWLAxiom ax) {
Set result = new HashSet<>();
for (OWLObjectProperty property : ax.getObjectPropertiesInSignature()) {
result.add(property);
result.add(property.getInverseProperty());
}
return result;
}
@Nonnull
@Override
protected Set getEntities(@Nonnull OWLOntology ont) {
Set result = new HashSet<>();
for (OWLObjectPropertyExpression property : ont.getObjectPropertiesInSignature()) {
result.add(property);
result.add(property.getInverseProperty());
}
return result;
}
@Nonnull
@Override
protected DefaultNode createNode(
Set cycle) {
return new OWLObjectPropertyNode(cycle);
}
@Nonnull
@Override
protected DefaultNode createNode() {
return new OWLObjectPropertyNode();
}
@Override
public void processChanges(@Nonnull Set signature,
@Nonnull Set added, @Nonnull Set removed) {
boolean rebuild = false;
for (OWLAxiom ax : added) {
if (ax instanceof OWLObjectPropertyAxiom) {
rebuild = true;
break;
}
}
if (!rebuild) {
for (OWLAxiom ax : removed) {
if (ax instanceof OWLObjectPropertyAxiom) {
rebuild = true;
break;
}
}
}
if (rebuild) {
((RawObjectPropertyHierarchyProvider) getRawParentChildProvider()).rebuild();
}
super.processChanges(signature, added, removed);
}
}
private class DataPropertyHierarchyInfo extends AbstractHierarchyInfo {
DataPropertyHierarchyInfo() {
super("data property", getDataFactory().getOWLTopDataProperty(),
getDataFactory().getOWLBottomDataProperty(),
new RawDataPropertyHierarchyProvider());
}
@Override
protected Set getEntitiesInSignature(@Nonnull OWLAxiom ax) {
return ax.getDataPropertiesInSignature();
}
@Override
protected Set getEntities(@Nonnull OWLOntology ont) {
return ont.getDataPropertiesInSignature();
}
@Nonnull
@Override
protected DefaultNode createNode(Set cycle) {
return new OWLDataPropertyNode(cycle);
}
@Nonnull
@Override
protected DefaultNode createNode() {
return new OWLDataPropertyNode();
}
}
/**
* An interface for objects who can provide the parents and children of some object.
*
* @param type of elements
*/
private interface RawHierarchyProvider {
/**
* Gets the parents as asserted. These parents may also be children (resulting in
* equivalences).
*
* @param child The child whose parents are to be retrieved
* @return The raw asserted parents of the specified child. If the child does not have any
* parents then the empty set can be returned.
*/
@Nonnull
Collection getParents(@Nonnull T child);
/**
* Gets the children as asserted.
*
* @param parent The parent whose children are to be retrieved
* @return The raw asserted children of the specified parent
*/
@Nonnull
Collection getChildren(@Nonnull T parent);
}
private class RawClassHierarchyProvider implements RawHierarchyProvider {
RawClassHierarchyProvider() {}
@Nonnull
@Override
public Collection getParents(OWLClass child) {
Collection result = new HashSet<>();
for (OWLOntology ont : getRootOntology().getImportsClosure()) {
for (OWLSubClassOfAxiom ax : ont.getSubClassAxiomsForSubClass(child)) {
OWLClassExpression superCls = ax.getSuperClass();
if (!superCls.isAnonymous()) {
result.add(superCls.asOWLClass());
} else if (superCls instanceof OWLObjectIntersectionOf) {
OWLObjectIntersectionOf intersectionOf = (OWLObjectIntersectionOf) superCls;
for (OWLClassExpression conjunct : intersectionOf.asConjunctSet()) {
if (!conjunct.isAnonymous()) {
result.add(conjunct.asOWLClass());
}
}
}
}
for (OWLEquivalentClassesAxiom ax : ont.getEquivalentClassesAxioms(child)) {
for (OWLClassExpression ce : ax.getClassExpressionsMinus(child)) {
if (!ce.isAnonymous()) {
result.add(ce.asOWLClass());
} else if (ce instanceof OWLObjectIntersectionOf) {
OWLObjectIntersectionOf intersectionOf = (OWLObjectIntersectionOf) ce;
for (OWLClassExpression conjunct : intersectionOf.asConjunctSet()) {
if (!conjunct.isAnonymous()) {
result.add(conjunct.asOWLClass());
}
}
}
}
}
}
return result;
}
@Nonnull
@Override
public Collection getChildren(OWLClass parent) {
Collection result = new HashSet<>();
for (OWLAxiom ax : getRootOntology().getReferencingAxioms(parent, INCLUDED)) {
if (ax instanceof OWLSubClassOfAxiom) {
OWLSubClassOfAxiom sca = (OWLSubClassOfAxiom) ax;
if (!sca.getSubClass().isAnonymous()) {
Set conjuncts = sca.getSuperClass().asConjunctSet();
if (conjuncts.contains(parent)) {
result.add(sca.getSubClass().asOWLClass());
}
}
} else if (ax instanceof OWLEquivalentClassesAxiom) {
OWLEquivalentClassesAxiom eca = (OWLEquivalentClassesAxiom) ax;
for (OWLClassExpression ce : eca.getClassExpressions()) {
if (ce.containsConjunct(parent)) {
for (OWLClassExpression sub : eca.getClassExpressions()) {
if (!sub.isAnonymous() && !sub.equals(ce)) {
result.add(sub.asOWLClass());
}
}
}
}
}
}
return result;
}
}
private class RawObjectPropertyHierarchyProvider
implements RawHierarchyProvider {
private OWLObjectPropertyManager propertyManager;
private Map> sub2Super;
private Map> super2Sub;
RawObjectPropertyHierarchyProvider() {
rebuild();
}
public final void rebuild() {
propertyManager = new OWLObjectPropertyManager(
getRootOntology().getOWLOntologyManager(), getRootOntology());
sub2Super = propertyManager.getPropertyHierarchy();
super2Sub = new HashMap<>();
for (OWLObjectPropertyExpression sub : sub2Super.keySet()) {
for (OWLObjectPropertyExpression superProp : sub2Super.get(sub)) {
Set subs = super2Sub.get(superProp);
if (subs == null) {
subs = new HashSet<>();
super2Sub.put(superProp, subs);
}
subs.add(sub);
}
}
}
@Nonnull
@Override
public Collection getParents(
@Nonnull OWLObjectPropertyExpression child) {
if (child.isBottomEntity()) {
return CollectionFactory.emptySet();
}
Set propertyExpressions = sub2Super.get(child);
if (propertyExpressions == null) {
return CollectionFactory.emptySet();
} else {
return new HashSet<>(propertyExpressions);
}
}
@Nonnull
@Override
public Collection getChildren(
@Nonnull OWLObjectPropertyExpression parent) {
if (parent.isTopEntity()) {
return CollectionFactory.emptySet();
}
Set propertyExpressions = super2Sub.get(parent);
if (propertyExpressions == null) {
return CollectionFactory.emptySet();
} else {
return new HashSet<>(propertyExpressions);
}
}
}
private class RawDataPropertyHierarchyProvider
implements RawHierarchyProvider {
RawDataPropertyHierarchyProvider() {}
@Nonnull
@Override
public Collection getParents(@Nonnull OWLDataProperty child) {
Set properties = new HashSet<>();
Collection axioms =
getRootOntology().filterAxioms(Filters.subDataPropertyWithSub, child, INCLUDED);
Collection expressions =
sup(axioms, OWLDataPropertyExpression.class);
for (OWLDataPropertyExpression prop : expressions) {
properties.add(prop.asOWLDataProperty());
}
return properties;
}
@Nonnull
@Override
public Collection getChildren(@Nonnull OWLDataProperty parent) {
Set properties = new HashSet<>();
Collection axioms =
getRootOntology().filterAxioms(Filters.subDataPropertyWithSuper, parent, INCLUDED);
for (OWLDataPropertyExpression prop : sub(axioms, OWLDataPropertyExpression.class)) {
properties.add(prop.asOWLDataProperty());
}
return properties;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy