openllet.modularity.IncrementalClassifier 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 openllet.modularity;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import openllet.aterm.ATermAppl;
import openllet.atom.OpenError;
import openllet.core.exceptions.PelletRuntimeException;
import openllet.core.taxonomy.Taxonomy;
import openllet.core.taxonomy.TaxonomyImpl;
import openllet.core.taxonomy.TaxonomyNode;
import openllet.core.taxonomy.printer.ClassTreePrinter;
import openllet.core.taxonomy.printer.TreeTaxonomyPrinter;
import openllet.core.utils.ATermUtils;
import openllet.core.utils.Bool;
import openllet.core.utils.MultiValueMap;
import openllet.core.utils.Namespaces;
import openllet.core.utils.PartialOrderBuilder;
import openllet.core.utils.PartialOrderComparator;
import openllet.core.utils.PartialOrderRelation;
import openllet.core.utils.TaxonomyUtils;
import openllet.core.utils.Timer;
import openllet.core.utils.Timers;
import openllet.owlapi.OWL;
import openllet.owlapi.OpenlletReasoner;
import openllet.owlapi.OpenlletReasonerFactory;
import openllet.shared.tools.Log;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AxiomType;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyExpression;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyChangeListener;
import org.semanticweb.owlapi.model.RemoveAxiom;
import org.semanticweb.owlapi.reasoner.AxiomNotInProfileException;
import org.semanticweb.owlapi.reasoner.BufferingMode;
import org.semanticweb.owlapi.reasoner.ClassExpressionNotInProfileException;
import org.semanticweb.owlapi.reasoner.FreshEntitiesException;
import org.semanticweb.owlapi.reasoner.FreshEntityPolicy;
import org.semanticweb.owlapi.reasoner.InconsistentOntologyException;
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.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration;
import org.semanticweb.owlapi.reasoner.ReasonerInterruptedException;
import org.semanticweb.owlapi.reasoner.TimeOutException;
import org.semanticweb.owlapi.reasoner.UnsupportedEntailmentTypeException;
import org.semanticweb.owlapi.reasoner.impl.NodeFactory;
import org.semanticweb.owlapi.reasoner.impl.OWLClassNode;
import org.semanticweb.owlapi.reasoner.impl.OWLClassNodeSet;
import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNode;
import org.semanticweb.owlapi.reasoner.impl.OWLNamedIndividualNodeSet;
import org.semanticweb.owlapi.util.Version;
/**
*
* Copyright: Copyright (c) 2007
*
*
* Company: Clark & Parsia, LLC.
*
*
* @author Evren Sirin
*/
public class IncrementalClassifier implements OWLReasoner, OWLOntologyChangeListener
{
public static final String _namedClassesSupportOnly = "This reasoner only supports named classes";
public static final Logger _logger = Log.getLogger(IncrementalClassifier.class);
/**
* Modularity results
*/
private volatile MultiValueMap _modules = null;
/**
* Standard Pellet reasoner
*/
private final OpenlletReasoner _reasoner;
/**
* Module _extractor
*/
private volatile ModuleExtractor _extractor = ModuleExtractorFactory.createModuleExtractor();
private volatile Taxonomy _taxonomyImpl = null;
/**
* Do the regular classification and module extraction in two separate threads concurrently. Doing so might reduce overall processing time but increases the
* memory requirements because both processes need additional memory during running which will be freed at the _end of the process.
*/
private volatile boolean _multiThreaded = true;
public volatile Timers _timers = _extractor.getTimers();
private final Random RND = new Random();
private volatile boolean _realized = false;
public IncrementalClassifier(final OWLOntology ontology)
{
this(OpenlletReasonerFactory.getInstance().createReasoner(ontology), ModuleExtractorFactory.createModuleExtractor());
}
public IncrementalClassifier(final OWLOntology ontology, final OWLReasonerConfiguration config)
{
this(OpenlletReasonerFactory.getInstance().createReasoner(ontology, config), ModuleExtractorFactory.createModuleExtractor());
}
public IncrementalClassifier(final OWLOntology ontology, final ModuleExtractor moduleExtractor)
{
this(OpenlletReasonerFactory.getInstance().createReasoner(ontology), moduleExtractor);
}
public IncrementalClassifier(final OWLOntology ontology, final OWLReasonerConfiguration config, final ModuleExtractor moduleExtractor)
{
this(OpenlletReasonerFactory.getInstance().createReasoner(ontology, config), moduleExtractor);
}
public IncrementalClassifier(final OpenlletReasoner reasoner)
{
this(reasoner, ModuleExtractorFactory.createModuleExtractor());
}
public IncrementalClassifier(final OpenlletReasoner reasoner, final ModuleExtractor extractor)
{
_reasoner = reasoner;
_extractor = extractor;
final OWLOntology ontology = reasoner.getRootOntology();
ontology.importsClosure().map(OWLOntology::axioms).forEach(extractor::addAxioms);
reasoner.getManager().addOntologyChangeListener(this);
}
public IncrementalClassifier(final PersistedState persistedState)
{
_extractor = persistedState.getModuleExtractor();
_taxonomyImpl = persistedState.getTaxonomy();
_realized = persistedState.isRealized();
_modules = _extractor.getModules();
final OWLOntology ontology = OWL.Ontology(_extractor.axioms());
_reasoner = OpenlletReasonerFactory.getInstance().createReasoner(ontology);
_reasoner.getManager().addOntologyChangeListener(this);
}
public IncrementalClassifier(final PersistedState persistedState, final OWLOntology ontology)
{
_reasoner = OpenlletReasonerFactory.getInstance().createReasoner(ontology);
_extractor = persistedState.getModuleExtractor();
_taxonomyImpl = persistedState.getTaxonomy();
_realized = persistedState.isRealized();
_modules = _extractor.getModules();
final OntologyDiff diff = OntologyDiff.diffAxiomsWithOntologies(_extractor.axioms(), Collections.singleton(ontology));
if (!diff.areSame())
{
for (final OWLAxiom addition : diff.getAdditions())
_extractor.addAxiom(addition);
for (final OWLAxiom deletion : diff.getDeletions())
_extractor.deleteAxiom(deletion);
}
_reasoner.getManager().addOntologyChangeListener(this);
}
@Deprecated
public Collection getAxioms()
{
return _extractor.getAxioms();
}
public Stream axioms()
{
return _extractor.axioms();
}
/**
* Build the class hierarchy based on the results from the _reasoner
*/
static public Taxonomy buildClassHierarchy(final OpenlletReasoner reasoner)
{
final Taxonomy taxonomy = new TaxonomyImpl<>(null, OWL.Thing, OWL.Nothing);
final Set things = reasoner.getEquivalentClasses(OWL.Thing).entities().collect(Collectors.toSet());
things.remove(OWL.Thing);
if (!things.isEmpty())
taxonomy.addEquivalents(OWL.Thing, things);
final Set nothings = reasoner.getEquivalentClasses(OWL.Nothing).entities().collect(Collectors.toSet());
nothings.remove(OWL.Nothing);
if (!nothings.isEmpty())
taxonomy.addEquivalents(OWL.Nothing, nothings);
for (final Node subEq : reasoner.getSubClasses(OWL.Thing, true))
recursiveBuild(taxonomy, subEq, reasoner);
return taxonomy;
}
static private void recursiveBuild(final Taxonomy taxonomy, final Node eqClasses, final OpenlletReasoner reasoner)
{
assert eqClasses.entities().findAny().isPresent() : "Equivalents empty as passed";
final OWLClass cls = eqClasses.iterator().next();
if (taxonomy.contains(cls))
return;
final Set emptySet = Collections.emptySet();
taxonomy.addNode(eqClasses.entities().collect(Collectors.toList()), emptySet, emptySet, /* hidden =*/false);
for (final Node subEq : reasoner.getSubClasses(cls, true))
{
recursiveBuild(taxonomy, subEq, reasoner);
taxonomy.addSuper(subEq.iterator().next(), cls);
}
}
public void classify()
{
if (isClassified())
{
if (_extractor.isChanged())
// this means that there are some changes to the modules, which do not affect
// the current taxonomy (i.e., that is why isClassified() returns true)
// let's update the modules here
// TODO: maybe we should move these calls somewhere else but in general
// the users expect that all changes are applied after classify()
// and unapplied changes will prevent the classifie
_extractor.applyChanges(_taxonomyImpl);
return;
}
if (_extractor.canUpdate())
incrementalClassify();
else
regularClassify();
resetRealization();
}
@Override
public void dispose()
{
_reasoner.dispose();
_reasoner.getManager().removeOntologyChangeListener(this);
}
@Override
public Node getEquivalentClasses(final OWLClassExpression clsC)
{
if (clsC.isAnonymous())
throw new IllegalArgumentException("This _reasoner only supports named classes");
classify();
return NodeFactory.getOWLClassNode(_taxonomyImpl.getAllEquivalents((OWLClass) clsC));
}
/**
* Get the _modules
*/
public MultiValueMap getModules()
{
return _modules;
}
/**
* Get the underlying reasoner
*/
public OpenlletReasoner getReasoner()
{
return _reasoner;
}
@Override
public NodeSet getSubClasses(final OWLClassExpression clsC, final boolean direct)
{
if (clsC.isAnonymous())
throw new UnsupportedOperationException(_namedClassesSupportOnly);
classify();
final Set> values = new HashSet<>();
for (final Set val : _taxonomyImpl.getSubs((OWLClass) clsC, direct))
values.add(NodeFactory.getOWLClassNode(val));
return new OWLClassNodeSet(values);
}
/**
* This incremental classification _strategy does the following: for all _modules that are affected, collect all of their axioms and classify them all once
* in Openllet. This allows the exploitation current classification optimizations
*/
private void incClassifyAllModStrategy()
{
// Get the entities whose _modules are affected
final Set effects = _extractor.applyChanges(_taxonomyImpl);
_logger.fine(() -> "Module entities " + effects);
// create ontology for all the axioms of all effected _modules
final OWLOntology owlModule = _extractor.getModuleFromSignature(effects);
_logger.fine(() -> "Module axioms " + owlModule.logicalAxioms().map(OWLAxiom::toString).collect(Collectors.joining(" ")));
// load the extracted module to a new _reasoner
final OpenlletReasoner moduleReasoner = OpenlletReasonerFactory.getInstance().createReasoner(owlModule);
// classify the module
moduleReasoner.getKB().classify();
if (_logger.isLoggable(Level.FINE))
{
_logger.fine("Classified module:");
new ClassTreePrinter().print(moduleReasoner.getKB().getTaxonomy(), new PrintWriter(System.err));
}
final Taxonomy moduleTaxonomy = buildClassHierarchy(moduleReasoner);
final Set affectedCls = new HashSet<>();
for (final OWLEntity entity : effects)
if (entity instanceof OWLClass)
affectedCls.add((OWLClass) entity);
_taxonomyImpl = updateClassHierarchy(_taxonomyImpl, moduleTaxonomy, affectedCls);
if (_logger.isLoggable(Level.FINE))
{
_logger.fine("Updated _taxonomy:");
new TreeTaxonomyPrinter().print(_taxonomyImpl, new PrintWriter(System.err));
// new FunctionalTaxonomyPrinter().print( _taxonomy, new OutputFormatter( System.err, false ) );
}
owlModule.getOWLOntologyManager().removeOntology(owlModule);
}
private void incrementalClassify()
{
if (_logger.isLoggable(Level.FINE))
_logger.fine("Incremental classification starting");
final Timer timer = _timers.startTimer("incrementalClassify");
incClassifyAllModStrategy();
timer.stop();
if (_logger.isLoggable(Level.FINE))
_logger.fine("Incremental classification done");
}
public boolean isClassified()
{
// what if expressivity should change because of the yet unapplied changes?
return _modules != null && (!_extractor.isChanged() || !_extractor.isClassificationNeeded(_reasoner.getKB().getExpressivity()));
}
public boolean isRealized()
{
return isClassified() && _realized;
}
public boolean isDefined(final OWLClass cls)
{
return _extractor.axioms(cls).findAny().isPresent();
}
public boolean isDefined(final OWLDataProperty prop)
{
return _extractor.axioms(prop).findAny().isPresent();
}
public boolean isDefined(final OWLNamedIndividual ind)
{
return _extractor.axioms(ind).findAny().isPresent();
}
public boolean isDefined(final OWLObjectProperty prop)
{
return _extractor.axioms(prop).findAny().isPresent();
}
public boolean isEquivalentClass(final OWLClassExpression clsC, final OWLClassExpression clsD)
{
if (clsC.isAnonymous() || clsD.isAnonymous())
throw new UnsupportedOperationException(_namedClassesSupportOnly);
classify();
return _taxonomyImpl.isEquivalent((OWLClass) clsC, (OWLClass) clsD) == Bool.TRUE;
}
@Override
public boolean isSatisfiable(final OWLClassExpression description)
{
if (description.isAnonymous() || !isClassified())
return _reasoner.isSatisfiable(description);
return !getUnsatisfiableClasses().contains((OWLClass) description);
}
@Override
public void ontologiesChanged(final List changes)
{
final OWLOntology ontology = getRootOntology();
if (ontology == null || ontology.getOWLOntologyManager() == null || ontology.getOWLOntologyManager().ontologies() == null)
return;
if (!ontology//
.getOWLOntologyManager()//
.ontologies()//
.filter(o -> o != null)//
.anyMatch(o -> o.getOntologyID()//
.equals(ontology.getOntologyID())//
)) // TODO : need a comment.
return;
final Set ontologies = getRootOntology().importsClosure().collect(Collectors.toSet());
for (final OWLOntologyChange change : changes)
{
if (!change.isAxiomChange() || !ontologies.contains(change.getOntology()))
continue;
resetRealization();
final OWLAxiom axiom = change.getAxiom();
if (change instanceof AddAxiom)
_extractor.addAxiom(axiom);
else
if (change instanceof RemoveAxiom)
_extractor.deleteAxiom(axiom);
else
throw new UnsupportedOperationException("Unrecognized axiom change: " + change);
}
}
private void regularClassify()
{
_logger.fine("Regular classification starting");
final Thread classification = new Thread("classification")
{
@Override
public void run()
{
// classify ontology
Timer timer = _timers.startTimer("reasonerClassify");
_reasoner.flush();
_reasoner.getKB().classify();
timer.stop();
if (_logger.isLoggable(Level.FINE))
{
_logger.fine("Regular taxonomy:");
new TreeTaxonomyPrinter().print(_reasoner.getKB().getTaxonomy(), new PrintWriter(System.err));
}
timer = _timers.startTimer("buildClassHierarchy");
_taxonomyImpl = buildClassHierarchy(_reasoner);
timer.stop();
if (_logger.isLoggable(Level.FINE))
{
_logger.fine("Copied taxonomy:");
new TreeTaxonomyPrinter().print(_taxonomyImpl, new PrintWriter(System.err));
}
}
};
final Thread partitioning = new Thread("partitioning")
{
@Override
public void run()
{
// get _modules for each concept
_modules = _extractor.extractModules();
}
};
try
{
final Timer timer = _timers.startTimer("regularClassify");
if (_multiThreaded)
{
classification.start();
partitioning.start();
classification.join();
partitioning.join();
}
else
{
classification.run();
partitioning.run();
}
timer.stop();
}
catch (final InterruptedException e)
{
throw new OpenError(e);
}
_logger.fine(() -> "Regular classification done");
}
/**
* @param _taxonomy Previous _taxonomy state
* @param moduleTaxonomy Change in _taxonomy state
* @param affected Set of classes affected by changes
*/
private static Taxonomy updateClassHierarchy(final Taxonomy taxonomy, final Taxonomy moduleTaxonomy, final Set affected)
{
final Set inTaxonomy = new HashSet<>(moduleTaxonomy.getClasses());
inTaxonomy.remove(OWL.Thing);
inTaxonomy.remove(OWL.Nothing);
assert affected.containsAll(inTaxonomy) : "Unaffected _nodes in changed _taxonomy";
final Set removed = new HashSet<>(affected);
removed.removeAll(moduleTaxonomy.getClasses());
final List sorted = taxonomy.topologocialSort( /* includeEquivalents = */false);
// TODO: Top equivalents could change?!
final Set emptySet = Collections.emptySet();
for (final OWLClass cls : sorted)
{
// TODO: assert assumption that if any classes equivalent in
// _taxonomy exist in moduleTaxonomy, all are
if (removed.contains(cls) || moduleTaxonomy.contains(cls))
continue;
moduleTaxonomy.addNode(taxonomy.getAllEquivalents(cls), emptySet, emptySet, /* hidden= */
false);
final Set supers = taxonomy.getFlattenedSupers(cls, /* direct = */true);
supers.removeAll(removed);
moduleTaxonomy.addSupers(cls, supers);
}
final List nothings = new ArrayList<>();
for (final OWLClass cls : taxonomy.getEquivalents(OWL.Nothing))
if (!removed.contains(cls) && !moduleTaxonomy.contains(cls))
nothings.add(cls);
if (!nothings.isEmpty())
moduleTaxonomy.addEquivalents(OWL.Nothing, nothings);
return moduleTaxonomy;
}
// /**
// * FIXME: This function is incredibly broken.
// * Main method to update the partial order and find new subsumptions.
// *
// * @param add
// * Flag for additions/deletions
// * @param _node
// * the _node which is being updated
// * @param newR
// * The _reasoner which has been loaded and processed with the new
// * signature of this module
// */
// private void updatePartialOrder(boolean add, TaxonomyNode _node, PelletReasoner newR) {
// if( _logger.isLoggable( Level.FINER ) )
// _logger.finer( "Update _node " + _node );
//
// OWLClass clazz = _node.getName();
//
// // collect all of its valid super classes from the _reasoner
// Set> validSupers = newR.getAncestorClasses( clazz );
//
// // get all of the old super classes from the subclass _index
// Set oldSupers = null;// superClasses.get( clazz );
//
// // case for add
// if( add ) {
//
// // for each subclass check if its new...if it is, then add it to
// // the child of this _node
// for( Set nextCls : validSupers ) {
// // if this is thing, then continue
// if( nextCls.contains( OWL.Thing ) )
// continue;
//
// // iterate over new super classes - again this is a set
// // because pellet returns a set of sets
// for( OWLClass next : nextCls ) {
// // check if this subsumption already exists
// if( !oldSupers.contains( next ) ) {
//
// // add it to the subclass _index
// oldSupers.add( next );
//
// if( _logger.isLoggable( Level.FINER ) ) {
// _logger.finer( " Found new subsumption " + clazz + " subClassOf " + next );
// }
//
// // update the partial _order
// TaxonomyNode newSubNode = _taxonomy.getNode( next );
// if( !newSubNode.getSubs().contains( _node ) ) {
// newSubNode.addSub( _node );
// }
// }
// }
// }
// }
// else {
//
// // case for deletions
//
// // if there were no previous supers then by monotonicity, there
// // still will not be, so return
// if( oldSupers.isEmpty() )
// return;
//
// // used to track invalidated supers
// Set removeSet = new HashSet();
//
// // for each old subclass check if its still exists, if not
// // remove it
// for( OWLClass nextOldSuper : oldSupers ) {
// // if thing, then continue
// if( nextOldSuper.equals( OWL.Thing ) )
// continue;
//
// TaxonomyNode oldSubNode = _taxonomy.getNode( nextOldSuper );
//
// // check if this subsumption still exists
// if( !OntologyUtils.containsClass( validSupers, nextOldSuper ) ) {
// // update remove set
// removeSet.add( nextOldSuper );
//
// if( _logger.isLoggable( Level.FINER ) ) {
// _logger.finer( " Found violated subsumption " + clazz + " subClassOf "
// + nextOldSuper );
// }
//
// // update partial _order
// oldSubNode.removeSub( _node );
// }
// }
//
// // update subclass _index
// oldSupers.removeAll( removeSet );
// }
// }
/**
* Returns the value of multi-threaded option.
*
* @see IncrementalClassifier#setMultiThreaded(boolean)
* @return the value of multi-threaded option
*/
public boolean isMultiThreaded()
{
return _multiThreaded;
}
/**
* Sets the multi-threading option. In multi-threaded mode, during the initial setup, the regular classification and module extraction are performed in two
* separate threads concurrently. Doing so might reduce overall processing time but it also increases the memory requirements because both processes need
* additional memory during running which will be freed at the _end of the process.
*
* @param _multiThreaded value to set the multi-threaded option
*/
public void setMultiThreaded(final boolean multiThreaded)
{
_multiThreaded = multiThreaded;
}
/**
* A class that has access to all the internal parts of the IncrementalClassifier that has to be persisted when saving the state to the stream. This class
* enables the separation between the I/O code and the reasoning code. This class should not be used any other parts of code than the I/O code. This class
* is a variation of Memento design pattern (as it encapsulates the state) with the important difference that actually no state is being copied; instead,
* this class only contains the references to the _data structures to be saved. (The I/O code is thought as actually performing the copy, and therefore
* completing the Memento pattern.)
*
* Copyright: Copyright (c) 2009
*
*
* Company: Clark & Parsia, LLC.
*
*
* @author Blazej Bulka
*/
public static class PersistedState
{
private final ModuleExtractor _persistedExtractor;
private final Taxonomy _persistedTaxonomy;
private final boolean _persistedRealized;
public PersistedState(final IncrementalClassifier incrementalClassifier)
{
_persistedExtractor = incrementalClassifier._extractor;
_persistedTaxonomy = incrementalClassifier._taxonomyImpl;
_persistedRealized = incrementalClassifier._realized;
}
public PersistedState(final ModuleExtractor extractor, final TaxonomyImpl taxonomy, final boolean realized)
{
_persistedExtractor = extractor;
_persistedTaxonomy = taxonomy;
_persistedRealized = realized;
}
public ModuleExtractor getModuleExtractor()
{
return _persistedExtractor;
}
public Taxonomy getTaxonomy()
{
return _persistedTaxonomy;
}
public boolean isRealized()
{
return _persistedRealized;
}
}
/**
* {@inheritDoc}
*/
@Override
public void flush()
{
_reasoner.flush();
// TODO Auto-generated method stub
}
/**
* {@inheritDoc}
*/
@Override
public Node getBottomClassNode()
{
return getEquivalentClasses(OWL.Nothing);
}
/**
* {@inheritDoc}
*/
@Override
public Node getBottomDataPropertyNode()
{
return getEquivalentDataProperties(OWL.bottomDataProperty);
}
/**
* {@inheritDoc}
*/
@Override
public Node getBottomObjectPropertyNode()
{
return getEquivalentObjectProperties(OWL.bottomObjectProperty);
}
/**
* {@inheritDoc}
*/
@Override
public BufferingMode getBufferingMode()
{
return BufferingMode.NON_BUFFERING;
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getDataPropertyDomains(final OWLDataProperty pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getDataPropertyDomains(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public Set getDataPropertyValues(final OWLNamedIndividual ind, final OWLDataProperty pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getDataPropertyValues(ind, pe);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getDifferentIndividuals(final OWLNamedIndividual ind) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getDifferentIndividuals(ind);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getDisjointClasses(final OWLClassExpression ce)
{
final DisjointClassComparator disjointClassComparator = new DisjointClassComparator(_taxonomyImpl, ce);
if (!_taxonomyImpl.contains(disjointClassComparator.getComplementRepresentation()))
{
_reasoner.flush();
final PartialOrderBuilder orderBuilder = new PartialOrderBuilder<>(_taxonomyImpl, disjointClassComparator);
orderBuilder.add(disjointClassComparator.getComplementRepresentation(), true);
}
final OWLClassNodeSet result = new OWLClassNodeSet();
for (final Set equivSet : _taxonomyImpl.getSubs(disjointClassComparator.getComplementRepresentation(), false))
result.addSameEntities(equivSet);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getDisjointDataProperties(final OWLDataPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getDisjointDataProperties(pe);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getDisjointObjectProperties(final OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getDisjointObjectProperties(pe);
}
/**
* {@inheritDoc}
*/
@Override
public Node getEquivalentDataProperties(final OWLDataProperty pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getEquivalentDataProperties(pe);
}
/**
* {@inheritDoc}
*/
@Override
public Node getEquivalentObjectProperties(final OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getEquivalentObjectProperties(pe);
}
/**
* {@inheritDoc}
*/
@Override
public FreshEntityPolicy getFreshEntityPolicy()
{
return _reasoner.getFreshEntityPolicy();
}
/**
* {@inheritDoc}
*/
@Override
public IndividualNodeSetPolicy getIndividualNodeSetPolicy()
{
return _reasoner.getIndividualNodeSetPolicy();
}
private NodeSet getIndividualNodeSetBySameAs(final Collection individuals)
{
final Set> instances = new HashSet<>();
final Set seen = new HashSet<>();
for (final OWLNamedIndividual ind : individuals)
if (!seen.contains(ind))
{
final Node equiv = _reasoner.getSameIndividuals(ind);
instances.add(equiv);
seen.addAll(equiv.entities().collect(Collectors.toList()));
}
return new OWLNamedIndividualNodeSet(instances);
}
private NodeSet getIndividualNodeSetByName(final Collection individuals)
{
final Set> instances = new HashSet<>();
for (final OWLNamedIndividual ind : individuals)
for (final OWLNamedIndividual equiv : _reasoner.getSameIndividuals(ind))
instances.add(new OWLNamedIndividualNode(equiv));
return new OWLNamedIndividualNodeSet(instances);
}
private NodeSet getIndividualNodeSet(final Collection individuals)
{
if (IndividualNodeSetPolicy.BY_NAME.equals(getIndividualNodeSetPolicy()))
return getIndividualNodeSetByName(individuals);
else
if (IndividualNodeSetPolicy.BY_SAME_AS.equals(getIndividualNodeSetPolicy()))
return getIndividualNodeSetBySameAs(individuals);
else
throw new AssertionError("Unsupported IndividualNodeSetPolicy : " + getIndividualNodeSetPolicy());
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getInstances(final OWLClassExpression ce, final boolean direct) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
if (ce.isAnonymous() && direct)
throw new UnsupportedOperationException(_namedClassesSupportOnly);
_reasoner.flush();
if (!isRealized() && !direct)
return _reasoner.getInstances(ce, direct);
realize();
final Set individuals = direct ? TaxonomyUtils. getDirectInstances(_taxonomyImpl, (OWLClass) ce) : TaxonomyUtils. getAllInstances(_taxonomyImpl, (OWLClass) ce);
return getIndividualNodeSet(individuals);
}
/**
* {@inheritDoc}
*/
@Override
public Node getInverseObjectProperties(final OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getInverseObjectProperties(pe);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getObjectPropertyDomains(final OWLObjectPropertyExpression pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getObjectPropertyDomains(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getObjectPropertyRanges(final OWLObjectPropertyExpression pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getObjectPropertyRanges(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getObjectPropertyValues(final OWLNamedIndividual ind, final OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getObjectPropertyValues(ind, pe);
}
/**
* {@inheritDoc}
*/
@Override
public Set getPendingAxiomAdditions()
{
return Collections.emptySet();
}
/**
* {@inheritDoc}
*/
@Override
public Set getPendingAxiomRemovals()
{
return Collections.emptySet();
}
/**
* {@inheritDoc}
*/
@Override
public List getPendingChanges()
{
return Collections.emptyList();
}
/**
* {@inheritDoc}
*/
@Override
public String getReasonerName()
{
return "Openllet (Incremental)";
}
/**
* {@inheritDoc}
*/
@Override
public Version getReasonerVersion()
{
return _reasoner.getReasonerVersion();
}
/**
* {@inheritDoc}
*/
@Override
public OWLOntology getRootOntology()
{
return _reasoner.getRootOntology();
}
/**
* {@inheritDoc}
*/
@Override
public Node getSameIndividuals(final OWLNamedIndividual ind) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getSameIndividuals(ind);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getSubDataProperties(final OWLDataProperty pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getSubDataProperties(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getSubObjectProperties(final OWLObjectPropertyExpression pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getSubObjectProperties(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getSuperClasses(final OWLClassExpression ce, final boolean direct) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
if (ce.isAnonymous())
throw new UnsupportedOperationException(_namedClassesSupportOnly);
final OWLClass namedClass = (OWLClass) ce;
classify();
return new OWLClassNodeSet(//
_taxonomyImpl.supers(namedClass, direct)//
.map(NodeFactory::getOWLClassNode)//
.collect(Collectors.toSet())//
);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getSuperDataProperties(final OWLDataProperty pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getSuperDataProperties(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getSuperObjectProperties(final OWLObjectPropertyExpression pe, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.getSuperObjectProperties(pe, direct);
}
/**
* {@inheritDoc}
*/
@Override
public long getTimeOut()
{
return _reasoner.getTimeOut();
}
/**
* {@inheritDoc}
*/
@Override
public Node getTopClassNode()
{
return getEquivalentClasses(OWL.Thing);
}
/**
* {@inheritDoc}
*/
@Override
public Node getTopDataPropertyNode()
{
return getEquivalentDataProperties(OWL.topDataProperty);
}
/**
* {@inheritDoc}
*/
@Override
public Node getTopObjectPropertyNode()
{
return getEquivalentObjectProperties(OWL.topObjectProperty);
}
/**
* {@inheritDoc}
*/
@Override
public NodeSet getTypes(final OWLNamedIndividual ind, final boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
realize();
final OWLClassNodeSet types = new OWLClassNodeSet();
for (final Set t : TaxonomyUtils.getTypes(_taxonomyImpl, ind, direct))
//Set eqSet = ATermUtils.primitiveOrBottom( t );
//if( !eqSet.isEmpty() )
types.addNode(new OWLClassNode(t));
return types;
}
/**
* {@inheritDoc}
*/
@Override
public Node getUnsatisfiableClasses() throws ReasonerInterruptedException, TimeOutException
{
classify();
return getBottomClassNode();
}
/**
* {@inheritDoc}
*/
@Override
public void interrupt()
{
// TODO : compute the multithreaded case.
}
/**
* {@inheritDoc}
*/
@Override
public boolean isConsistent() throws ReasonerInterruptedException, TimeOutException
{
_reasoner.flush();
return _reasoner.isConsistent();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEntailed(final OWLAxiom axiom) throws ReasonerInterruptedException, UnsupportedEntailmentTypeException, TimeOutException, AxiomNotInProfileException, FreshEntitiesException
{
try
{
final EntailmentChecker entailmentChecker = new EntailmentChecker(this);
return entailmentChecker.isEntailed(axiom);
}
catch (final PelletRuntimeException e)
{
throw convert(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEntailed(final Set axioms) throws ReasonerInterruptedException, UnsupportedEntailmentTypeException, TimeOutException, AxiomNotInProfileException, FreshEntitiesException
{
try
{
final EntailmentChecker entailmentChecker = new EntailmentChecker(this);
return entailmentChecker.isEntailed(axioms);
}
catch (final PelletRuntimeException e)
{
throw convert(e);
}
}
private static PelletRuntimeException convert(final PelletRuntimeException e) throws InconsistentOntologyException, ReasonerInterruptedException, TimeOutException, FreshEntitiesException
{
if (e instanceof openllet.core.exceptions.TimeoutException)
throw new TimeOutException();
if (e instanceof openllet.core.exceptions.TimerInterruptedException)
throw new ReasonerInterruptedException(e);
if (e instanceof openllet.core.exceptions.InconsistentOntologyException)
throw new InconsistentOntologyException();
if (e instanceof openllet.core.exceptions.UndefinedEntityException)
{
final Set unknown = Collections.emptySet();
throw new FreshEntitiesException(unknown);
}
return e;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEntailmentCheckingSupported(final AxiomType axiomType)
{
// the _current EntailmentChecker supports the same set of axioms as
// the underlying _reasoner (if it cannot handle any element directly,
// it forwards the entailment check to the underlying _reasoner)
return getReasoner().isEntailmentCheckingSupported(axiomType);
}
/**
* {@inheritDoc}
*/
public void prepareReasoner() throws ReasonerInterruptedException, TimeOutException
{
classify();
}
public Taxonomy getTaxonomy()
{
return _taxonomyImpl;
}
private void resetRealization()
{
if (_taxonomyImpl != null)
for (final TaxonomyNode node : _taxonomyImpl.getNodes().values())
node.removeDatum(TaxonomyUtils.INSTANCES_KEY);
_realized = false;
}
private void realize()
{
if (isRealized())
return;
final Set allIndividuals = _reasoner.getKB().getIndividuals();
final Set visitedClasses = new HashSet<>();
if (!allIndividuals.isEmpty())
realizeByConcept(ATermUtils.TOP, allIndividuals, _reasoner.getManager().getOWLDataFactory(), visitedClasses);
_realized = true;
}
private Set realizeByConcept(final ATermAppl c, final Collection individuals, final OWLDataFactory factory, final Set visitedClasses)
{
if (c.equals(ATermUtils.BOTTOM))
return Collections.emptySet();
if (_logger.isLoggable(Level.FINER))
_logger.finer("Realizing concept " + c);
final OWLClass owlClass = termToOWLClass(c, factory);
if (visitedClasses.contains(owlClass))
return TaxonomyUtils.getAllInstances(_taxonomyImpl, owlClass);
final Set instances = new HashSet<>(_reasoner.getKB().retrieve(c, individuals));
final Set mostSpecificInstances = new HashSet<>(instances);
if (!instances.isEmpty())
{
final TaxonomyNode node = _taxonomyImpl.getNode(owlClass);
if (node == null)
{
_logger.warning(" no _node for " + c);
return instances;
}
for (final TaxonomyNode sub : node.getSubs())
{
final OWLClass d = sub.getName();
final Set subInstances = realizeByConcept(owlClassToTerm(d), instances, factory, visitedClasses);
if (subInstances == null)
return null;
mostSpecificInstances.removeAll(subInstances);
}
if (!mostSpecificInstances.isEmpty())
node.putDatum(TaxonomyUtils.INSTANCES_KEY, toOWLNamedIndividuals(mostSpecificInstances, factory));
}
return instances;
}
private static Set toOWLNamedIndividuals(final Set terms, final OWLDataFactory factory)
{
final HashSet result = new HashSet<>();
for (final ATermAppl ind : terms)
{
final OWLNamedIndividual owlInd = termToOWLNamedIndividual(ind, factory);
if (owlInd != null)
result.add(owlInd);
}
return result;
}
private static final ATermAppl OWL_THING = ATermUtils.makeTermAppl(Namespaces.OWL + "Thing");
private static final ATermAppl OWL_NOTHING = ATermUtils.makeTermAppl(Namespaces.OWL + "Nothing");
private static OWLClass termToOWLClass(final ATermAppl c, final OWLDataFactory factory)
{
if (c.equals(ATermUtils.TOP))
return factory.getOWLThing();
else
if (c.equals(OWL_THING))
return factory.getOWLThing();
else
if (c.equals(OWL_NOTHING))
return factory.getOWLNothing();
if (!ATermUtils.isBnode(c))
return factory.getOWLClass(IRI.create(c.getName()));
return null;
}
private static OWLNamedIndividual termToOWLNamedIndividual(final ATermAppl c, final OWLDataFactory factory)
{
if (!ATermUtils.isBnode(c))
return factory.getOWLNamedIndividual(IRI.create(c.getName()));
return null;
}
private static ATermAppl owlClassToTerm(final OWLClass c)
{
if (c.isOWLThing())
return ATermUtils.TOP;
else
if (c.isOWLNothing())
return ATermUtils.BOTTOM;
else
return ATermUtils.makeTermAppl(c.getIRI().toString());
}
public class DisjointClassComparator implements PartialOrderComparator
{
private static final String ANONYMOUS_COMPLEMENT_REPRESENTATION_BASE = "http://clarkparsia.com/pellet/complement/";
private static final String COMPLEMENT_POSTFIX = "-complement";
private final OWLClassExpression _complementClass;
private final OWLClass _complementRepresentation;
public DisjointClassComparator(final Taxonomy taxonomy, final OWLClassExpression originalClass)
{
_complementClass = OWL._factory.getOWLObjectComplementOf(originalClass);
_complementRepresentation = generateComplementRepresentation(taxonomy, originalClass);
}
private OWLClass generateComplementRepresentation(final Taxonomy taxonomy, final OWLClassExpression originalClass)
{
OWLClass complementClass = null;
if (!originalClass.isAnonymous() && (originalClass instanceof OWLClass))
return OWL._factory.getOWLClass(IRI.create(((OWLClass) originalClass).getIRI() + COMPLEMENT_POSTFIX));
do
complementClass = OWL._factory.getOWLClass(IRI.create(ANONYMOUS_COMPLEMENT_REPRESENTATION_BASE + RND.nextLong()));
while (taxonomy.contains(complementClass));
return complementClass;
}
public OWLClass getComplementRepresentation()
{
return _complementRepresentation;
}
@Override
public PartialOrderRelation compare(final OWLClass a, final OWLClass b)
{
OWLClassExpression aExpression = a;
OWLClassExpression bExpression = b;
if (a.equals(_complementRepresentation))
aExpression = _complementClass;
if (b.equals(_complementRepresentation))
bExpression = _complementClass;
final OWLAxiom aSubClassBAxiom = OWL._factory.getOWLSubClassOfAxiom(aExpression, bExpression);
final OWLAxiom bSubClassAAxiom = OWL._factory.getOWLSubClassOfAxiom(bExpression, aExpression);
final boolean aLessB = _reasoner.isEntailed(aSubClassBAxiom);
final boolean bLessA = _reasoner.isEntailed(bSubClassAAxiom);
if (aLessB && bLessA)
return PartialOrderRelation.EQUAL;
else
if (aLessB)
return PartialOrderRelation.LESS;
else
if (bLessA)
return PartialOrderRelation.GREATER;
else
return PartialOrderRelation.INCOMPARABLE;
}
}
/**
* {@inheritDoc}
*/
@Override
public Set getPrecomputableInferenceTypes()
{
return _reasoner.getPrecomputableInferenceTypes();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isPrecomputed(final InferenceType inferenceType)
{
switch (inferenceType)
{
case CLASS_HIERARCHY:
return isClassified();
case CLASS_ASSERTIONS:
return isRealized();
default:
return _reasoner.isPrecomputed(inferenceType);
}
}
/**
* {@inheritDoc}
*/
@Override
public void precomputeInferences(final InferenceType... inferenceTypes) throws ReasonerInterruptedException, TimeOutException, InconsistentOntologyException
{
for (final InferenceType inferenceType : inferenceTypes)
switch (inferenceType)
{
case CLASS_HIERARCHY:
classify();
//$FALL-THROUGH$
case CLASS_ASSERTIONS:
realize();
//$FALL-THROUGH$
default:
_reasoner.precomputeInferences(inferenceTypes);
}
}
}