001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.reasoning;
020
021import com.google.common.base.StandardSystemProperty;
022import org.dllearner.kb.OWLAPIOntology;
023import org.dllearner.kb.OWLOntologyKnowledgeSource;
024import org.joda.time.Period;
025import org.joda.time.format.PeriodFormat;
026import org.semanticweb.owlapi.apibinding.OWLManager;
027import org.semanticweb.owlapi.model.*;
028import org.semanticweb.owlapi.model.parameters.AxiomAnnotations;
029import org.semanticweb.owlapi.reasoner.*;
030import org.semanticweb.owlapi.reasoner.impl.*;
031import org.semanticweb.owlapi.search.EntitySearcher;
032import org.semanticweb.owlapi.util.CollectionFactory;
033import org.semanticweb.owlapi.util.OWLObjectPropertyManager;
034import org.semanticweb.owlapi.util.Version;
035
036import javax.annotation.Nonnull;
037import java.io.File;
038import java.util.*;
039import java.util.stream.Stream;
040
041import static org.semanticweb.owlapi.model.parameters.Imports.INCLUDED;
042
043/**
044 * Author: Matthew Horridge<br>
045 * The University of Manchester<br>
046 * Information Management Group<br>
047 * Date: 04-Dec-2009
048 * </p>
049 * This is a simple structural reasoner that essentially answers with told information.  It is incomplete.
050 */
051public class StructuralReasonerExtended extends OWLReasonerBase {
052
053    private final ClassHierarchyInfo classHierarchyInfo = new ClassHierarchyInfo();
054
055    private final ObjectPropertyHierarchyInfo objectPropertyHierarchyInfo = new ObjectPropertyHierarchyInfo();
056
057    private final DataPropertyHierarchyInfo dataPropertyHierarchyInfo = new DataPropertyHierarchyInfo();
058
059    private static final Version version = new Version(1, 0, 0, 0);
060
061    private boolean interrupted = false;
062
063    protected final ReasonerProgressMonitor pm;
064
065    private boolean prepared = false;
066
067        private OWLDataFactory df;
068
069    /**
070     * @param rootOntology the ontology
071     * @param configuration the reasoner configuration
072     * @param bufferingMode the buffering mode
073     */
074    public StructuralReasonerExtended(OWLOntology rootOntology, OWLReasonerConfiguration configuration, BufferingMode bufferingMode) {
075        super(rootOntology, configuration, bufferingMode);
076        pm = configuration.getProgressMonitor();
077        prepareReasoner();
078        df = rootOntology.getOWLOntologyManager().getOWLDataFactory();
079    }
080
081    @Nonnull
082    @Override
083    public String getReasonerName() {
084        return "Structural Reasoner";
085    }
086
087    @Nonnull
088    @Override
089    public FreshEntityPolicy getFreshEntityPolicy() {
090        return FreshEntityPolicy.ALLOW;
091    }
092
093    @Nonnull
094    @Override
095    public IndividualNodeSetPolicy getIndividualNodeSetPolicy() {
096        return IndividualNodeSetPolicy.BY_NAME;
097    }
098
099    @Nonnull
100    @Override
101    public Version getReasonerVersion() {
102        return version;
103    }
104
105    @Override
106    protected void handleChanges(@Nonnull Set<OWLAxiom> addAxioms, @Nonnull Set<OWLAxiom> removeAxioms) {
107        handleChanges(addAxioms, removeAxioms, classHierarchyInfo);
108        handleChanges(addAxioms, removeAxioms, objectPropertyHierarchyInfo);
109        handleChanges(addAxioms, removeAxioms, dataPropertyHierarchyInfo);
110    }
111
112    private <T extends OWLObject> void handleChanges(Set<OWLAxiom> added, Set<OWLAxiom> removed, HierarchyInfo<T> hierarchyInfo) {
113        Set<T> sig = hierarchyInfo.getEntitiesInSignature(added);
114        sig.addAll(hierarchyInfo.getEntitiesInSignature(removed));
115        hierarchyInfo.processChanges(sig, added, removed);
116
117    }
118
119    @Override
120    public void interrupt() {
121        interrupted = true;
122    }
123
124    private void ensurePrepared() {
125        if (!prepared) {
126            prepareReasoner();
127        }
128    }
129
130    /**
131     * @throws ReasonerInterruptedException on interruption
132     * @throws TimeOutException on timeout
133     */
134    public void prepareReasoner() throws ReasonerInterruptedException, TimeOutException {
135        classHierarchyInfo.computeHierarchy();
136        objectPropertyHierarchyInfo.computeHierarchy();
137        dataPropertyHierarchyInfo.computeHierarchy();
138        prepared = true;
139    }
140
141    @Override
142
143    public void precomputeInferences(@Nonnull InferenceType... inferenceTypes) throws ReasonerInterruptedException, TimeOutException, InconsistentOntologyException {
144        prepareReasoner();
145    }
146
147    @Override
148
149    public boolean isPrecomputed(@Nonnull InferenceType inferenceType) {
150        return true;
151    }
152
153    @Nonnull
154    @Override
155    public Set<InferenceType> getPrecomputableInferenceTypes() {
156        return CollectionFactory.createSet(InferenceType.CLASS_HIERARCHY, InferenceType.OBJECT_PROPERTY_HIERARCHY, InferenceType.DATA_PROPERTY_HIERARCHY);
157    }
158
159    protected void throwExceptionIfInterrupted() {
160        if (interrupted) {
161            interrupted = false;
162            throw new ReasonerInterruptedException();
163        }
164    }
165
166    //////////////////////////////////////////////////////////////////////////////////////////////////////
167
168    @Override
169    public boolean isConsistent() throws ReasonerInterruptedException, TimeOutException {
170        return true;
171    }
172
173    @Override
174    public boolean isSatisfiable(@Nonnull OWLClassExpression classExpression) throws ReasonerInterruptedException, TimeOutException, ClassExpressionNotInProfileException, FreshEntitiesException, InconsistentOntologyException {
175        return !classExpression.isAnonymous() && !getEquivalentClasses(classExpression.asOWLClass()).contains(getDataFactory().getOWLNothing());
176    }
177
178    @Nonnull
179    @Override
180    public Node<OWLClass> getUnsatisfiableClasses() throws ReasonerInterruptedException, TimeOutException {
181        return OWLClassNode.getBottomNode();
182    }
183
184    @Override
185    public boolean isEntailed(@Nonnull OWLAxiom axiom) throws ReasonerInterruptedException, UnsupportedEntailmentTypeException, TimeOutException, AxiomNotInProfileException, FreshEntitiesException, InconsistentOntologyException {
186        boolean containsAxiom = getRootOntology().containsAxiom(axiom, INCLUDED, AxiomAnnotations.IGNORE_AXIOM_ANNOTATIONS);
187                
188                if(containsAxiom){
189                        return true;
190                }
191        
192        if (axiom instanceof OWLClassAssertionAxiom) {// extension of OWL API code
193                        ensurePrepared();
194
195                        OWLClassExpression ce = ((OWLClassAssertionAxiom) axiom).getClassExpression();
196                        OWLIndividual individual = ((OWLClassAssertionAxiom) axiom).getIndividual();
197
198                        if (ce.isOWLThing()) {
199                                return true;
200                        } else if (ce.isOWLNothing()) {
201                                return false;
202                        } else if (!ce.isAnonymous()) {
203                return getSubClasses(ce.asOWLClass(), false).getFlattened().stream()
204                        .anyMatch(sub -> getRootOntology().containsAxiom(df.getOWLClassAssertionAxiom(sub, individual), INCLUDED, AxiomAnnotations.IGNORE_AXIOM_ANNOTATIONS));
205            } else {
206                                if (ce instanceof OWLObjectIntersectionOf) {
207                    return ((OWLObjectIntersectionOf) ce).getOperands().stream()
208                            .allMatch(op -> isEntailed(df.getOWLClassAssertionAxiom(op, individual)));
209                                } else if (ce instanceof OWLObjectUnionOf) {
210                    return ((OWLObjectUnionOf) ce).getOperands().stream()
211                            .anyMatch(op -> isEntailed(df.getOWLClassAssertionAxiom(op, individual)));
212                                } else if (ce instanceof OWLObjectSomeValuesFrom) {
213                                        OWLObjectPropertyExpression ope = ((OWLObjectSomeValuesFrom) ce).getProperty();
214                                        
215                                        OWLClassExpression filler = ((OWLObjectSomeValuesFrom) ce).getFiller();
216                                        
217                                        Set<OWLIndividualAxiom> axioms = getRootOntology().getAxioms(individual, INCLUDED);
218                                        
219                                        for (OWLIndividualAxiom curAx : axioms) {
220                                                if(curAx instanceof OWLObjectPropertyAssertionAxiom && 
221                                                                ope.equals(((OWLObjectPropertyAssertionAxiom) curAx).getProperty())) {
222                                                        
223                                                        OWLIndividual object = ((OWLObjectPropertyAssertionAxiom) curAx).getObject();
224                                                        return isEntailed(df.getOWLClassAssertionAxiom(filler, object));
225                                                }
226                                        }
227                                        return false;
228                                }
229                        }
230                }
231        
232        return false;
233    }
234
235    @Override
236    public boolean isEntailed(@Nonnull Set<? extends OWLAxiom> axioms) throws ReasonerInterruptedException, UnsupportedEntailmentTypeException, TimeOutException, AxiomNotInProfileException, FreshEntitiesException, InconsistentOntologyException {
237        for (OWLAxiom ax : axioms) {
238            assert ax != null;
239            if (!getRootOntology().containsAxiom(ax, INCLUDED, AxiomAnnotations.IGNORE_AXIOM_ANNOTATIONS)) {
240                return false;
241            }
242        }
243        return true;
244    }
245
246    @Override
247
248    public boolean isEntailmentCheckingSupported(@Nonnull AxiomType<?> axiomType) {
249        return false;
250    }
251
252    @Nonnull
253    @Override
254    public Node<OWLClass> getTopClassNode() {
255        ensurePrepared();
256        return classHierarchyInfo.getEquivalents(getDataFactory().getOWLThing());
257    }
258
259    @Nonnull
260    @Override
261    public Node<OWLClass> getBottomClassNode() {
262        ensurePrepared();
263        return classHierarchyInfo.getEquivalents(getDataFactory().getOWLNothing());
264    }
265
266    @Nonnull
267    @Override
268    public NodeSet<OWLClass> getSubClasses(@Nonnull OWLClassExpression ce, boolean direct) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
269        OWLClassNodeSet ns = new OWLClassNodeSet();
270        if (!ce.isAnonymous()) {
271            ensurePrepared();
272            return classHierarchyInfo.getNodeHierarchyChildren(ce.asOWLClass(), direct, ns);
273        }
274        return ns;
275    }
276
277    @Nonnull
278    @Override
279    public NodeSet<OWLClass> getSuperClasses(@Nonnull OWLClassExpression ce, boolean direct) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
280        OWLClassNodeSet ns = new OWLClassNodeSet();
281        if (!ce.isAnonymous()) {
282            ensurePrepared();
283            return classHierarchyInfo.getNodeHierarchyParents(ce.asOWLClass(), direct, ns);
284        }
285        return ns;
286    }
287
288    @Nonnull
289    @Override
290    public Node<OWLClass> getEquivalentClasses(@Nonnull OWLClassExpression ce) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
291        ensurePrepared();
292        if (!ce.isAnonymous()) {
293            return classHierarchyInfo.getEquivalents(ce.asOWLClass());
294        }
295        else {
296            return new OWLClassNode();
297        }
298    }
299
300    @Nonnull
301    @Override
302    public NodeSet<OWLClass> getDisjointClasses(@Nonnull OWLClassExpression ce) {
303        ensurePrepared();
304        OWLClassNodeSet nodeSet = new OWLClassNodeSet();
305        if (!ce.isAnonymous()) {
306            for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
307                for (OWLDisjointClassesAxiom ax : ontology.getDisjointClassesAxioms(ce.asOWLClass())) {
308                    for (OWLClassExpression op : ax.getClassExpressions()) {
309                        if (!op.isAnonymous()) {
310                            nodeSet.addNode(getEquivalentClasses(op));
311                        }
312                    }
313                }
314            }
315        }
316        return nodeSet;
317    }
318
319    @Nonnull
320    @Override
321    public Node<OWLObjectPropertyExpression> getTopObjectPropertyNode() {
322        ensurePrepared();
323        return objectPropertyHierarchyInfo.getEquivalents(getDataFactory().getOWLTopObjectProperty());
324    }
325
326    @Nonnull
327    @Override
328    public Node<OWLObjectPropertyExpression> getBottomObjectPropertyNode() {
329        ensurePrepared();
330        return objectPropertyHierarchyInfo.getEquivalents(getDataFactory().getOWLBottomObjectProperty());
331    }
332
333    @Nonnull
334    @Override
335    public NodeSet<OWLObjectPropertyExpression> getSubObjectProperties(@Nonnull OWLObjectPropertyExpression pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
336        OWLObjectPropertyNodeSet ns = new OWLObjectPropertyNodeSet();
337        ensurePrepared();
338        return objectPropertyHierarchyInfo.getNodeHierarchyChildren(pe, direct, ns);
339    }
340
341    @Nonnull
342    @Override
343    public NodeSet<OWLObjectPropertyExpression> getSuperObjectProperties(@Nonnull OWLObjectPropertyExpression pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
344        OWLObjectPropertyNodeSet ns = new OWLObjectPropertyNodeSet();
345        ensurePrepared();
346        return objectPropertyHierarchyInfo.getNodeHierarchyParents(pe, direct, ns);
347    }
348
349    @Nonnull
350    @Override
351    public Node<OWLObjectPropertyExpression> getEquivalentObjectProperties(@Nonnull OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
352        ensurePrepared();
353        return objectPropertyHierarchyInfo.getEquivalents(pe);
354    }
355
356    @Nonnull
357    @Override
358
359    public NodeSet<OWLObjectPropertyExpression> getDisjointObjectProperties(@Nonnull OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
360        return new OWLObjectPropertyNodeSet();
361    }
362
363    @Nonnull
364    @Override
365    public Node<OWLObjectPropertyExpression> getInverseObjectProperties(@Nonnull OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
366        ensurePrepared();
367        OWLObjectPropertyExpression inv = pe.getInverseProperty();
368        return getEquivalentObjectProperties(inv);
369    }
370
371    @Nonnull
372    @Override
373    public NodeSet<OWLClass> getObjectPropertyDomains(@Nonnull OWLObjectPropertyExpression pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
374
375        ensurePrepared();
376        DefaultNodeSet<OWLClass> result = new OWLClassNodeSet();
377        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
378            for (OWLObjectPropertyDomainAxiom axiom : ontology.getObjectPropertyDomainAxioms(pe)) {
379                result.addNode(getEquivalentClasses(axiom.getDomain()));
380                if (!direct) {
381                    result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
382                }
383            }
384
385            for (OWLObjectPropertyExpression invPe : getInverseObjectProperties(pe).getEntities()) {
386                for (OWLObjectPropertyRangeAxiom axiom : ontology.getObjectPropertyRangeAxioms(invPe)) {
387                    result.addNode(getEquivalentClasses(axiom.getRange()));
388                    if (!direct) {
389                        result.addAllNodes(getSuperClasses(axiom.getRange(), false).getNodes());
390                    }
391                }
392            }
393        }
394        return result;
395    }
396
397    @Nonnull
398    @Override
399    public NodeSet<OWLClass> getObjectPropertyRanges(@Nonnull OWLObjectPropertyExpression pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
400        ensurePrepared();
401        DefaultNodeSet<OWLClass> result = new OWLClassNodeSet();
402        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
403            for (OWLObjectPropertyRangeAxiom axiom : ontology.getObjectPropertyRangeAxioms(pe)) {
404                result.addNode(getEquivalentClasses(axiom.getRange()));
405                if (!direct) {
406                    result.addAllNodes(getSuperClasses(axiom.getRange(), false).getNodes());
407                }
408            }
409            for (OWLObjectPropertyExpression invPe : getInverseObjectProperties(pe).getEntities()) {
410                for (OWLObjectPropertyDomainAxiom axiom : ontology.getObjectPropertyDomainAxioms(invPe)) {
411                    result.addNode(getEquivalentClasses(axiom.getDomain()));
412                    if (!direct) {
413                        result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
414                    }
415                }
416            }
417        }
418        return result;
419    }
420
421    @Nonnull
422    @Override
423    public Node<OWLDataProperty> getTopDataPropertyNode() {
424        ensurePrepared();
425        return dataPropertyHierarchyInfo.getEquivalents(getDataFactory().getOWLTopDataProperty());
426    }
427
428    @Nonnull
429    @Override
430    public Node<OWLDataProperty> getBottomDataPropertyNode() {
431        ensurePrepared();
432        return dataPropertyHierarchyInfo.getEquivalents(getDataFactory().getOWLBottomDataProperty());
433    }
434
435    @Nonnull
436    @Override
437    public NodeSet<OWLDataProperty> getSubDataProperties(@Nonnull OWLDataProperty pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
438        ensurePrepared();
439        OWLDataPropertyNodeSet ns = new OWLDataPropertyNodeSet();
440        return dataPropertyHierarchyInfo.getNodeHierarchyChildren(pe, direct, ns);
441    }
442
443    @Nonnull
444    @Override
445    public NodeSet<OWLDataProperty> getSuperDataProperties(@Nonnull OWLDataProperty pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
446        ensurePrepared();
447        OWLDataPropertyNodeSet ns = new OWLDataPropertyNodeSet();
448        return dataPropertyHierarchyInfo.getNodeHierarchyParents(pe, direct, ns);
449    }
450
451    @Nonnull
452    @Override
453    public Node<OWLDataProperty> getEquivalentDataProperties(@Nonnull OWLDataProperty pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
454        ensurePrepared();
455        return dataPropertyHierarchyInfo.getEquivalents(pe);
456    }
457
458    @Nonnull
459    @Override
460    public NodeSet<OWLDataProperty> getDisjointDataProperties(@Nonnull OWLDataPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
461        ensurePrepared();
462        DefaultNodeSet<OWLDataProperty> result = new OWLDataPropertyNodeSet();
463        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
464            for (OWLDisjointDataPropertiesAxiom axiom : ontology.getDisjointDataPropertiesAxioms(pe.asOWLDataProperty())) {
465                for (OWLDataPropertyExpression dpe : axiom.getPropertiesMinus(pe)) {
466                    if (!dpe.isAnonymous()) {
467                        result.addNode(dataPropertyHierarchyInfo.getEquivalents(dpe.asOWLDataProperty()));
468                        result.addAllNodes(getSubDataProperties(dpe.asOWLDataProperty(), false).getNodes());
469                    }
470                }
471            }
472        }
473        return result;
474    }
475
476    @Nonnull
477    @Override
478    public NodeSet<OWLClass> getDataPropertyDomains(@Nonnull OWLDataProperty pe, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
479        ensurePrepared();
480        DefaultNodeSet<OWLClass> result = new OWLClassNodeSet();
481        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
482            for (OWLDataPropertyDomainAxiom axiom : ontology.getDataPropertyDomainAxioms(pe)) {
483                result.addNode(getEquivalentClasses(axiom.getDomain()));
484                if (!direct) {
485                    result.addAllNodes(getSuperClasses(axiom.getDomain(), false).getNodes());
486                }
487            }
488        }
489        return result;
490    }
491
492    @Nonnull
493    @Override
494    public NodeSet<OWLClass> getTypes(@Nonnull OWLNamedIndividual ind, boolean direct) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
495        ensurePrepared();
496        DefaultNodeSet<OWLClass> result = new OWLClassNodeSet();
497        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
498            for (OWLClassAssertionAxiom axiom : ontology.getClassAssertionAxioms(ind)) {
499                OWLClassExpression ce = axiom.getClassExpression();
500                if (!ce.isAnonymous()) {
501                    result.addNode(classHierarchyInfo.getEquivalents(ce.asOWLClass()));
502                    if (!direct) {
503                        result.addAllNodes(getSuperClasses(ce, false).getNodes());
504                    }
505                }
506            }
507        }
508        return result;
509    }
510
511    @Nonnull
512    @Override
513    public NodeSet<OWLNamedIndividual> getInstances(@Nonnull OWLClassExpression ce, boolean direct) throws InconsistentOntologyException, ClassExpressionNotInProfileException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
514        ensurePrepared();
515        DefaultNodeSet<OWLNamedIndividual> result = new OWLNamedIndividualNodeSet();
516        if (!ce.isAnonymous()) {
517            OWLClass cls = ce.asOWLClass();
518            Set<OWLClass> clses = new HashSet<>();
519            clses.add(cls);
520            if (!direct) {
521                clses.addAll(getSubClasses(cls, false).getFlattened());
522            }
523            for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
524                for (OWLClass curCls : clses) {
525                    for (OWLClassAssertionAxiom axiom : ontology.getClassAssertionAxioms(curCls)) {
526                        OWLIndividual individual = axiom.getIndividual();
527                        if (!individual.isAnonymous()) {
528                            if (getIndividualNodeSetPolicy().equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
529                                result.addNode(getSameIndividuals(individual.asOWLNamedIndividual()));
530                            }
531                            else {
532                                result.addNode(new OWLNamedIndividualNode(individual.asOWLNamedIndividual()));
533                            }
534                        }
535                    }
536                }
537            }
538        } else { // extension of OWL API implementation
539                if(ce instanceof OWLObjectIntersectionOf){
540                        List<OWLClassExpression> operands = ((OWLObjectIntersectionOf) ce).getOperandsAsList();
541                        
542                        Set<Node<OWLNamedIndividual>> tmp = new HashSet<>();
543                        
544                        tmp.addAll(getInstances(operands.get(0), direct).getNodes());
545                        
546                        for (int i = 1; i < operands.size(); i++) {
547                                tmp.retainAll(getInstances(operands.get(i), direct).getNodes());
548                                }
549                result.addAllNodes(tmp);
550                } else if(ce instanceof OWLObjectUnionOf){
551                        Set<OWLClassExpression> operands = ((OWLObjectUnionOf) ce).getOperands();
552                        
553                        for (OWLClassExpression op : operands) {
554                                        result.addAllNodes(getInstances(op, direct).getNodes());
555                                }
556                } else if(ce instanceof OWLObjectSomeValuesFrom){
557                        System.out.println(ce);
558                        OWLObjectPropertyExpression ope = ((OWLObjectSomeValuesFrom) ce).getProperty();
559                        OWLClassExpression filler = ((OWLObjectSomeValuesFrom) ce).getFiller();
560                Set<OWLObjectPropertyExpression> properties = new HashSet<>();
561                properties.add(ope.asOWLObjectProperty());
562                if (!direct) {
563                    properties.addAll(getSubObjectProperties(ope, false).getFlattened());
564                }
565                        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
566                    for (OWLObjectPropertyExpression curProp : properties) {
567                        Set<OWLAxiom> referencingAxioms = ontology.getReferencingAxioms(curProp.asOWLObjectProperty());
568
569                                                        for (OWLAxiom axiom : referencingAxioms) {
570                                if(axiom instanceof OWLObjectPropertyAssertionAxiom){
571                                        // check if object is instance of filler 
572                                        OWLIndividual object = ((OWLObjectPropertyAssertionAxiom) axiom).getObject();
573                                        if(!object.isAnonymous()){
574                                                if(filler.isOWLThing() || getInstances(filler, false).containsEntity(object.asOWLNamedIndividual())){
575                                                        OWLIndividual subject = ((OWLObjectPropertyAssertionAxiom) axiom).getSubject();
576                                        if (!subject.isAnonymous()) {
577                                            if (getIndividualNodeSetPolicy().equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
578                                                result.addNode(getSameIndividuals(subject.asOWLNamedIndividual()));
579                                            }
580                                            else {
581                                                result.addNode(new OWLNamedIndividualNode(subject.asOWLNamedIndividual()));
582                                            }
583                                        }
584                                                }
585                                        }
586                                }
587                        }
588                    }
589                }
590                } else if(ce instanceof OWLObjectAllValuesFrom){
591                        
592                }
593        }
594        return result;
595    }
596
597    @Nonnull
598    @Override
599    public NodeSet<OWLNamedIndividual> getObjectPropertyValues(@Nonnull OWLNamedIndividual ind, @Nonnull OWLObjectPropertyExpression pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
600        ensurePrepared();
601        OWLNamedIndividualNodeSet result = new OWLNamedIndividualNodeSet();
602        Node<OWLObjectPropertyExpression> inverses = getInverseObjectProperties(pe);
603        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
604            for (OWLObjectPropertyAssertionAxiom axiom : ontology.getObjectPropertyAssertionAxioms(ind)) {
605                if (!axiom.getObject().isAnonymous()) {
606                    if (axiom.getProperty().equals(pe)) {
607                        if (getIndividualNodeSetPolicy().equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
608                            result.addNode(getSameIndividuals(axiom.getObject().asOWLNamedIndividual()));
609                        }
610                        else {
611                            result.addNode(new OWLNamedIndividualNode(axiom.getObject().asOWLNamedIndividual()));
612                        }
613                    }
614                }
615                // Inverse of pe
616                if (axiom.getObject().equals(ind) && !axiom.getSubject().isAnonymous()) {
617                    OWLObjectPropertyExpression invPe = axiom.getProperty().getInverseProperty();
618                    if (!invPe.isAnonymous() && inverses.contains(invPe.asOWLObjectProperty())) {
619                        if (getIndividualNodeSetPolicy().equals(IndividualNodeSetPolicy.BY_SAME_AS)) {
620                            result.addNode(getSameIndividuals(axiom.getObject().asOWLNamedIndividual()));
621                        }
622                        else {
623                            result.addNode(new OWLNamedIndividualNode(axiom.getObject().asOWLNamedIndividual()));
624                        }
625                    }
626                }
627
628            }
629        }
630        // Could do other stuff like inspecting owl:hasValue restrictions
631        return result;
632    }
633
634    @Nonnull
635    @Override
636    public Set<OWLLiteral> getDataPropertyValues(@Nonnull OWLNamedIndividual ind, @Nonnull OWLDataProperty pe) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
637        ensurePrepared();
638        Set<OWLLiteral> literals = new HashSet<>();
639        Set<OWLDataProperty> superProperties = getSuperDataProperties(pe, false).getFlattened();
640        superProperties.addAll(getEquivalentDataProperties(pe).getEntities());
641        for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
642            for (OWLDataPropertyAssertionAxiom axiom : ontology.getDataPropertyAssertionAxioms(ind)) {
643                if (superProperties.contains(axiom.getProperty().asOWLDataProperty())) {
644                    literals.add(axiom.getObject());
645                }
646            }
647        }
648        return literals;
649    }
650
651    @Nonnull
652    @Override
653    public Node<OWLNamedIndividual> getSameIndividuals(@Nonnull OWLNamedIndividual ind) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
654        ensurePrepared();
655        Set<OWLNamedIndividual> inds = new HashSet<>();
656        Set<OWLSameIndividualAxiom> processed = new HashSet<>();
657        List<OWLNamedIndividual> stack = new ArrayList<>();
658        stack.add(ind);
659        while (!stack.isEmpty()) {
660            OWLNamedIndividual currentInd = stack.remove(0);
661            for (OWLOntology ontology : getRootOntology().getImportsClosure()) {
662                for (OWLSameIndividualAxiom axiom : ontology.getSameIndividualAxioms(currentInd)) {
663                    if (!processed.contains(axiom)) {
664                        processed.add(axiom);
665                        for (OWLIndividual i : axiom.getIndividuals()) {
666                            if (!i.isAnonymous()) {
667                                OWLNamedIndividual namedInd = i.asOWLNamedIndividual();
668                                if (!inds.contains(namedInd)) {
669                                    inds.add(namedInd);
670                                    stack.add(namedInd);
671                                }
672                            }
673                        }
674                    }
675                }
676            }
677        }
678
679        return new OWLNamedIndividualNode(inds);
680    }
681
682    @Nonnull
683    @Override
684
685    public NodeSet<OWLNamedIndividual> getDifferentIndividuals(@Nonnull OWLNamedIndividual ind) throws InconsistentOntologyException, FreshEntitiesException, ReasonerInterruptedException, TimeOutException {
686        return new OWLNamedIndividualNodeSet();
687    }
688
689    protected OWLDataFactory getDataFactory() {
690        return getRootOntology().getOWLOntologyManager().getOWLDataFactory();
691    }
692    /**
693     * @param showBottomNode true if bottom node is to be showed
694     */
695    public void dumpClassHierarchy(boolean showBottomNode) {
696        dumpClassHierarchy(OWLClassNode.getTopNode(), 0, showBottomNode);
697    }
698
699    private void dumpClassHierarchy(Node<OWLClass> cls, int level, boolean showBottomNode) {
700        if (!showBottomNode && cls.isBottomNode()) {
701            return;
702        }
703        printIndent(level);
704        OWLClass representative = cls.getRepresentativeElement();
705        System.out.println(getEquivalentClasses(representative));
706        for (Node<OWLClass> subCls : getSubClasses(representative, true)) {
707            dumpClassHierarchy(subCls, level + 1, showBottomNode);
708        }
709    }
710
711    /**
712     * @param showBottomNode true if bottom node is to be showed
713     */
714    public void dumpObjectPropertyHierarchy(boolean showBottomNode) {
715        dumpObjectPropertyHierarchy(OWLObjectPropertyNode.getTopNode(), 0, showBottomNode);
716    }
717
718    private void dumpObjectPropertyHierarchy(Node<OWLObjectPropertyExpression> cls, int level, boolean showBottomNode) {
719        if (!showBottomNode && cls.isBottomNode()) {
720            return;
721        }
722        printIndent(level);
723        OWLObjectPropertyExpression representative = cls.getRepresentativeElement();
724        System.out.println(getEquivalentObjectProperties(representative));
725        for (Node<OWLObjectPropertyExpression> subProp : getSubObjectProperties(representative, true)) {
726            dumpObjectPropertyHierarchy(subProp, level + 1, showBottomNode);
727        }
728    }
729
730    /**
731     * @param showBottomNode true if bottom node is to be showed
732     */
733    public void dumpDataPropertyHierarchy(boolean showBottomNode) {
734        dumpDataPropertyHierarchy(OWLDataPropertyNode.getTopNode(), 0, showBottomNode);
735    }
736
737    private void dumpDataPropertyHierarchy(Node<OWLDataProperty> cls, int level, boolean showBottomNode) {
738        if (!showBottomNode && cls.isBottomNode()) {
739            return;
740        }
741        printIndent(level);
742        OWLDataProperty representative = cls.getRepresentativeElement();
743        System.out.println(getEquivalentDataProperties(representative));
744        for (Node<OWLDataProperty> subProp : getSubDataProperties(representative, true)) {
745            dumpDataPropertyHierarchy(subProp, level + 1, showBottomNode);
746        }
747    }
748
749    private void printIndent(int level) {
750        for (int i = 0; i < level; i++) {
751            System.out.print("    ");
752        }
753    }
754
755    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
756    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
757    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
758    //////
759    //////  HierarchyInfo
760    //////
761    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
762    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
763    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
764
765    private abstract class HierarchyInfo<T extends OWLObject> {
766
767        private RawHierarchyProvider<T> rawParentChildProvider;
768
769        /**
770         * The entity that always appears in the top node in the hierarchy
771         */
772        T topEntity;
773
774        /**
775         * The entity that always appears as the bottom node in the hierarchy
776         */
777        T bottomEntity;
778
779        private Set<T> directChildrenOfTopNode = new HashSet<>();
780
781        private Set<T> directParentsOfBottomNode = new HashSet<>();
782
783        private NodeCache<T> nodeCache;
784
785        private String name;
786
787        private int classificationSize;
788
789        public HierarchyInfo(String name, T topEntity, T bottomEntity, RawHierarchyProvider<T> rawParentChildProvider) {
790            this.topEntity = topEntity;
791            this.bottomEntity = bottomEntity;
792            this.nodeCache = new NodeCache<>(this);
793            this.rawParentChildProvider = rawParentChildProvider;
794            this.name = name;
795        }
796
797        public RawHierarchyProvider<T> getRawParentChildProvider() {
798            return rawParentChildProvider;
799        }
800
801        /**
802         * Gets the set of relevant entities from the specified ontology
803         * @param ont The ontology
804         * @return A set of entities to be "classified"
805         */
806        protected abstract Set<T> getEntities(OWLOntology ont);
807
808        /**
809         * Creates a node for a given set of entities
810         * @param cycle The set of entities
811         * @return A node
812         */
813        protected abstract DefaultNode<T> createNode(Set<T> cycle);
814
815        protected abstract DefaultNode<T> createNode();
816
817        /**
818         * Gets the set of relevant entities in a particular axiom
819         * @param ax The axiom
820         * @return The set of relevant entities in the signature of the specified axiom
821         */
822        protected abstract Set<? extends T> getEntitiesInSignature(OWLAxiom ax);
823
824        Set<T> getEntitiesInSignature(Set<OWLAxiom> axioms) {
825            Set<T> result = new HashSet<>();
826            for (OWLAxiom ax : axioms) {
827                result.addAll(getEntitiesInSignature(ax));
828            }
829            return result;
830        }
831
832        public void computeHierarchy() {
833            pm.reasonerTaskStarted("Computing " + name + " hierarchy");
834            pm.reasonerTaskBusy();
835            nodeCache.clear();
836            Map<T, Collection<T>> cache = new HashMap<>();
837            Set<T> entities = new HashSet<>();
838            for (OWLOntology ont : getRootOntology().getImportsClosure()) {
839                entities.addAll(getEntities(ont));
840            }
841            classificationSize = entities.size();
842            pm.reasonerTaskProgressChanged(0, classificationSize);
843            updateForSignature(entities, cache);
844            pm.reasonerTaskStopped();
845        }
846
847        private void updateForSignature(Set<T> signature, Map<T, Collection<T>> cache) {
848            HashSet<Set<T>> cyclesResult = new HashSet<>();
849            Set<T> processed = new HashSet<>();
850            nodeCache.clearTopNode();
851            nodeCache.clearBottomNode();
852            nodeCache.clearNodes(signature);
853
854            directChildrenOfTopNode.removeAll(signature);
855
856            Set<T> equivTopOrChildrenOfTop = new HashSet<>();
857            Set<T> equivBottomOrParentsOfBottom = new HashSet<>();
858            for (T entity : signature) {
859                if (!processed.contains(entity)) {
860                    pm.reasonerTaskProgressChanged(processed.size(), signature.size());
861                    tarjan(entity, 0, new Stack<>(), new HashMap<>(), new HashMap<>(), cyclesResult, processed, new HashSet<>(), cache, equivTopOrChildrenOfTop, equivBottomOrParentsOfBottom);
862                    throwExceptionIfInterrupted();
863                }
864            }
865            // Store new cycles
866            for (Set<T> cycle : cyclesResult) {
867                nodeCache.addNode(cycle);
868            }
869
870            directChildrenOfTopNode.addAll(equivTopOrChildrenOfTop);
871            directChildrenOfTopNode.removeAll(nodeCache.getTopNode().getEntities());
872
873            directParentsOfBottomNode.addAll(equivBottomOrParentsOfBottom);
874            directParentsOfBottomNode.removeAll(nodeCache.getBottomNode().getEntities());
875
876            // Now check that each found cycle has a proper parent an child
877            for (Set<T> node : cyclesResult) {
878                if (!node.contains(topEntity) && !node.contains(bottomEntity)) {
879                    boolean childOfTop = true;
880                    for (T element : node) {
881                        Collection<T> parents = rawParentChildProvider.getParents(element);
882                        parents.removeAll(node);
883                        parents.removeAll(nodeCache.getTopNode().getEntities());
884                        if (!parents.isEmpty()) {
885                            childOfTop = false;
886                            break;
887                        }
888                    }
889                    if (childOfTop) {
890                        directChildrenOfTopNode.addAll(node);
891                    }
892
893                    boolean parentOfBottom = true;
894                    for (T element : node) {
895                        Collection<T> children = rawParentChildProvider.getChildren(element);
896                        children.removeAll(node);
897                        children.removeAll(nodeCache.getBottomNode().getEntities());
898                        if (!children.isEmpty()) {
899                            parentOfBottom = false;
900                            break;
901                        }
902                    }
903                    if (parentOfBottom) {
904                        directParentsOfBottomNode.addAll(node);
905                    }
906                }
907
908            }
909
910        }
911
912        /**
913         * Processes the specified signature that represents the signature of potential changes
914         * @param signature The signature
915         * @param added added axioms
916         * @param removed removed axioms
917         */
918        @SuppressWarnings("unused")
919        public void processChanges(Set<T> signature, Set<OWLAxiom> added, Set<OWLAxiom> removed) {
920            updateForSignature(signature, null);
921        }
922
923        //////////////////////////////////////////////////////////////////////////////////////////////////////////
924        //////////////////////////////////////////////////////////////////////////////////////////////////////////
925
926        /**
927         * Applies the tarjan algorithm for a given entity.  This computes the cycle that the entity is involved in (if
928         * any).
929         * @param entity The entity
930         * @param index index
931         * @param stack stack
932         * @param indexMap index map
933         * @param lowlinkMap low link map
934         * @param result result
935         * @param processed processed
936         * @param stackEntities stack entities
937         * @param cache A cache of children to parents - may be <code>null</code> if no caching is to take place.
938         * @param childrenOfTop A set of entities that have a raw parent that is the top entity
939         * @param parentsOfBottom A set of entities that have a raw parent that is the bottom entity
940         */
941        public void tarjan(T entity, int index, Stack<T> stack, Map<T, Integer> indexMap, Map<T, Integer> lowlinkMap, Set<Set<T>> result, Set<T> processed, Set<T> stackEntities, Map<T, Collection<T>> cache, Set<T> childrenOfTop, Set<T> parentsOfBottom) {
942            throwExceptionIfInterrupted();
943            if (processed.add(entity)) {
944                Collection<T> rawChildren = rawParentChildProvider.getChildren(entity);
945                if (rawChildren.isEmpty() || rawChildren.contains(bottomEntity)) {
946                    parentsOfBottom.add(entity);
947                }
948            }
949            pm.reasonerTaskProgressChanged(processed.size(), classificationSize);
950            indexMap.put(entity, index);
951            lowlinkMap.put(entity, index);
952            index = index + 1;
953            stack.push(entity);
954            stackEntities.add(entity);
955
956            // Get the raw parents - cache if necessary
957            Collection<T> rawParents = null;
958            if (cache != null) {
959                // We are therefore caching raw parents of children.
960                rawParents = cache.get(entity);
961                if (rawParents == null) {
962                    // Not in cache!
963                    rawParents = rawParentChildProvider.getParents(entity);
964                    // Note down if our entity is a
965                    if (rawParents.isEmpty() || rawParents.contains(topEntity)) {
966                        childrenOfTop.add(entity);
967                    }
968                    cache.put(entity, rawParents);
969
970                }
971            }
972            else {
973                rawParents = rawParentChildProvider.getParents(entity);
974                // Note down if our entity is a
975                if (rawParents.isEmpty() || rawParents.contains(topEntity)) {
976                    childrenOfTop.add(entity);
977                }
978            }
979
980            for (T superEntity : rawParents) {
981                if (!indexMap.containsKey(superEntity)) {
982                    tarjan(superEntity, index, stack, indexMap, lowlinkMap, result, processed, stackEntities, cache, childrenOfTop, parentsOfBottom);
983                    lowlinkMap.put(entity, Math.min(lowlinkMap.get(entity), lowlinkMap.get(superEntity)));
984                }
985                else if (stackEntities.contains(superEntity)) {
986                    lowlinkMap.put(entity, Math.min(lowlinkMap.get(entity), indexMap.get(superEntity)));
987                }
988            }
989            if (lowlinkMap.get(entity).equals(indexMap.get(entity))) {
990                Set<T> scc = new HashSet<>();
991                while (true) {
992                    T clsPrime = stack.pop();
993                    stackEntities.remove(clsPrime);
994                    scc.add(clsPrime);
995                    if (clsPrime.equals(entity)) {
996                        break;
997                    }
998                }
999                if (scc.size() > 1) {
1000                    // We ADD a cycle
1001                    result.add(scc);
1002                }
1003            }
1004        }
1005
1006        //////////////////////////////////////////////////////////////////////////////////////////////////////////
1007        //////////////////////////////////////////////////////////////////////////////////////////////////////////
1008
1009        public NodeSet<T> getNodeHierarchyChildren(T parent, boolean direct, DefaultNodeSet<T> ns) {
1010            Node<T> node = nodeCache.getNode(parent);
1011
1012            if (node.isBottomNode()) {
1013                return ns;
1014            }
1015
1016            Set<T> directChildren = new HashSet<>();
1017            for (T equiv : node) {
1018                directChildren.addAll(rawParentChildProvider.getChildren(equiv));
1019                if(directParentsOfBottomNode.contains(equiv)) {
1020                    ns.addNode(nodeCache.getBottomNode());
1021                }
1022            }
1023            directChildren.removeAll(node.getEntities());
1024
1025            if (node.isTopNode()) {
1026                // Special treatment
1027                directChildren.addAll(directChildrenOfTopNode);
1028            }
1029
1030            for (Node<T> childNode : nodeCache.getNodes(directChildren)) {
1031                ns.addNode(childNode);
1032            }
1033
1034            if (!direct) {
1035                for (T child : directChildren) {
1036                    getNodeHierarchyChildren(child, direct, ns);
1037                }
1038            }
1039            return ns;
1040        }
1041
1042        public NodeSet<T> getNodeHierarchyParents(T child, boolean direct, DefaultNodeSet<T> ns) {
1043            Node<T> node = nodeCache.getNode(child);
1044
1045            if (node.isTopNode()) {
1046                return ns;
1047            }
1048
1049            Set<T> directParents = new HashSet<>();
1050            for (T equiv : node) {
1051                directParents.addAll(rawParentChildProvider.getParents(equiv));
1052                if(directChildrenOfTopNode.contains(equiv)) {
1053                    ns.addNode(nodeCache.getTopNode());
1054                }
1055            }
1056            directParents.removeAll(node.getEntities());
1057
1058            if (node.isBottomNode()) {
1059                // Special treatment
1060                directParents.addAll(directParentsOfBottomNode);
1061            }
1062
1063            for (Node<T> parentNode : nodeCache.getNodes(directParents)) {
1064                ns.addNode(parentNode);
1065            }
1066
1067            if (!direct) {
1068                for(T parent : directParents) {
1069                    getNodeHierarchyParents(parent, direct, ns);
1070                }
1071            }
1072            return ns;
1073        }
1074
1075        public Node<T> getEquivalents(T element) {
1076            return nodeCache.getNode(element);
1077        }
1078    }
1079
1080    private static class NodeCache<T extends OWLObject> {
1081
1082        private HierarchyInfo<T> hierarchyInfo;
1083
1084        private Node<T> topNode;
1085
1086        private Node<T> bottomNode;
1087
1088        private Map<T, Node<T>> map = new HashMap<>();
1089
1090        protected NodeCache(HierarchyInfo<T> hierarchyInfo) {
1091            this.hierarchyInfo = hierarchyInfo;
1092            clearTopNode();
1093            clearBottomNode();
1094        }
1095
1096        public void addNode(Node<T> node) {
1097            for (T element : node.getEntities()) {
1098                map.put(element, node);
1099                if (element.isTopEntity()) {
1100                    topNode = node;
1101                }
1102                else if (element.isBottomEntity()) {
1103                    bottomNode = node;
1104                }
1105            }
1106        }
1107
1108        public Set<Node<T>> getNodes(Set<T> elements) {
1109            Set<Node<T>> result = new HashSet<>();
1110            for (T element : elements) {
1111                result.add(getNode(element));
1112            }
1113            return result;
1114        }
1115
1116        public Node<T> getNode(T containing) {
1117            Node<T> parentNode = map.get(containing);
1118            if (parentNode != null) {
1119                return parentNode;
1120            }
1121            else {
1122                return hierarchyInfo.createNode(Collections.singleton(containing));
1123            }
1124        }
1125
1126        public void addNode(Set<T> elements) {
1127            addNode(hierarchyInfo.createNode(elements));
1128        }
1129
1130        public Node<T> getTopNode() {
1131            return topNode;
1132        }
1133
1134        public Node<T> getBottomNode() {
1135            return bottomNode;
1136        }
1137
1138        public void clearTopNode() {
1139            removeNode(hierarchyInfo.topEntity);
1140            topNode = hierarchyInfo.createNode(Collections.singleton(hierarchyInfo.topEntity));
1141            addNode(topNode);
1142        }
1143
1144        public void clearBottomNode() {
1145            removeNode(hierarchyInfo.bottomEntity);
1146            bottomNode = hierarchyInfo.createNode(Collections.singleton(hierarchyInfo.bottomEntity));
1147            addNode(bottomNode);
1148        }
1149
1150        public void clearNodes(Set<T> containing) {
1151            for (T entity : containing) {
1152                removeNode(entity);
1153            }
1154        }
1155
1156        public void clear() {
1157            map.clear();
1158            clearTopNode();
1159            clearBottomNode();
1160        }
1161
1162        public void removeNode(T containing) {
1163            Node<T> node = map.remove(containing);
1164            if (node != null) {
1165                for (T object : node.getEntities()) {
1166                    map.remove(object);
1167                }
1168            }
1169        }
1170    }
1171
1172    private class ClassHierarchyInfo extends HierarchyInfo<OWLClass> {
1173
1174        public ClassHierarchyInfo() {
1175            super("class", getDataFactory().getOWLThing(), getDataFactory().getOWLNothing(), new RawClassHierarchyProvider());
1176        }
1177
1178        @Override
1179        protected Set<OWLClass> getEntitiesInSignature(OWLAxiom ax) {
1180            return ax.getClassesInSignature();
1181        }
1182
1183        @Override
1184        protected DefaultNode<OWLClass> createNode(Set<OWLClass> cycle) {
1185            return new OWLClassNode(cycle);
1186        }
1187
1188        @Override
1189        protected Set<OWLClass> getEntities(OWLOntology ont) {
1190            return ont.getClassesInSignature();
1191        }
1192
1193        @Override
1194        protected DefaultNode<OWLClass> createNode() {
1195            return new OWLClassNode();
1196        }
1197    }
1198
1199    private class ObjectPropertyHierarchyInfo extends HierarchyInfo<OWLObjectPropertyExpression> {
1200
1201        public ObjectPropertyHierarchyInfo() {
1202            super("object property", getDataFactory().getOWLTopObjectProperty(), getDataFactory().getOWLBottomObjectProperty(), new RawObjectPropertyHierarchyProvider());
1203        }
1204
1205        @Override
1206        protected Set<OWLObjectPropertyExpression> getEntitiesInSignature(OWLAxiom ax) {
1207            Set<OWLObjectPropertyExpression> result = new HashSet<>();
1208            for (OWLObjectProperty property : ax.getObjectPropertiesInSignature()) {
1209                result.add(property);
1210                result.add(property.getInverseProperty());
1211            }
1212            return result;
1213        }
1214
1215        @Override
1216        protected Set<OWLObjectPropertyExpression> getEntities(OWLOntology ont) {
1217            Set<OWLObjectPropertyExpression> result = new HashSet<>();
1218            for (OWLObjectPropertyExpression property : ont.getObjectPropertiesInSignature()) {
1219                result.add(property);
1220                result.add(property.getInverseProperty());
1221            }
1222            return result;
1223        }
1224
1225        @Override
1226        protected DefaultNode<OWLObjectPropertyExpression> createNode(Set<OWLObjectPropertyExpression> cycle) {
1227            return new OWLObjectPropertyNode(cycle);
1228        }
1229
1230        @Override
1231        protected DefaultNode<OWLObjectPropertyExpression> createNode() {
1232            return new OWLObjectPropertyNode();
1233        }
1234
1235        @Override
1236        public void processChanges(Set<OWLObjectPropertyExpression> signature, Set<OWLAxiom> added, Set<OWLAxiom> removed) {
1237            boolean rebuild = false;
1238            for (OWLAxiom ax : added) {
1239                if(ax instanceof OWLObjectPropertyAxiom) {
1240                    rebuild = true;
1241                    break;
1242                }
1243            }
1244            if(!rebuild) {
1245                for(OWLAxiom ax : removed) {
1246                    if(ax instanceof OWLObjectPropertyAxiom) {
1247                        rebuild = true;
1248                        break;
1249                    }
1250                }
1251            }
1252            if(rebuild) {
1253                ((RawObjectPropertyHierarchyProvider) getRawParentChildProvider()).rebuild();
1254            }
1255            super.processChanges(signature, added, removed);
1256        }
1257    }
1258
1259    private class DataPropertyHierarchyInfo extends HierarchyInfo<OWLDataProperty> {
1260
1261        public DataPropertyHierarchyInfo() {
1262            super("data property", getDataFactory().getOWLTopDataProperty(), getDataFactory().getOWLBottomDataProperty(), new RawDataPropertyHierarchyProvider());
1263        }
1264
1265        @Override
1266        protected Set<OWLDataProperty> getEntitiesInSignature(OWLAxiom ax) {
1267            return ax.getDataPropertiesInSignature();
1268        }
1269
1270        @Override
1271        protected Set<OWLDataProperty> getEntities(OWLOntology ont) {
1272            return ont.getDataPropertiesInSignature();
1273        }
1274
1275        @Override
1276        protected DefaultNode<OWLDataProperty> createNode(Set<OWLDataProperty> cycle) {
1277            return new OWLDataPropertyNode(cycle);
1278        }
1279
1280        @Override
1281        protected DefaultNode<OWLDataProperty> createNode() {
1282            return new OWLDataPropertyNode();
1283        }
1284    }
1285
1286    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
1287    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
1288    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
1289
1290    /**
1291     * An interface for objects who can provide the parents and children of some object.
1292     * @param <T>
1293     */
1294    private interface RawHierarchyProvider<T> {
1295
1296        /**
1297         * Gets the parents as asserted.  These parents may also be children (resulting in equivalences).
1298         * @param child The child whose parents are to be retrieved
1299         * @return The raw asserted parents of the specified child.  If the child does not have any parents
1300         *         then the empty set can be returned.
1301         */
1302        Collection<T> getParents(T child);
1303
1304        /**
1305         * Gets the children as asserted
1306         * @param parent The parent whose children are to be retrieved
1307         * @return The raw asserted children of the speicified parent
1308         */
1309        Collection<T> getChildren(T parent);
1310
1311    }
1312
1313    private class RawClassHierarchyProvider implements RawHierarchyProvider<OWLClass> {
1314        public RawClassHierarchyProvider() {}
1315 
1316        @Override
1317        public Collection<OWLClass> getParents(OWLClass child) {
1318            Collection<OWLClass> result = new HashSet<>();
1319            for (OWLOntology ont : getRootOntology().getImportsClosure()) {
1320                Stream.concat(
1321                        ont.getSubClassAxiomsForSubClass(child).stream().map(OWLSubClassOfAxiom::getSuperClass),
1322                        ont.getEquivalentClassesAxioms(child).stream().flatMap(ax -> ax.getClassExpressionsMinus(child).stream())
1323                ).forEach(ce -> {
1324                    if (!ce.isAnonymous()) {
1325                        result.add(ce.asOWLClass());
1326                    } else if (ce instanceof OWLObjectIntersectionOf) {
1327                        OWLObjectIntersectionOf intersectionOf = (OWLObjectIntersectionOf) ce;
1328                        for (OWLClassExpression conjunct : intersectionOf.asConjunctSet()) {
1329                            if (!conjunct.isAnonymous()) {
1330                                result.add(conjunct.asOWLClass());
1331                            }
1332                        }
1333                    }
1334                });
1335            }
1336            return result;
1337        }
1338
1339        @Override
1340        public Collection<OWLClass> getChildren(OWLClass parent) {
1341            Collection<OWLClass> result = new HashSet<>();
1342            for (OWLOntology ont : getRootOntology().getImportsClosure()) {
1343                for (OWLAxiom ax : ont.getReferencingAxioms(parent)) {
1344                    if (ax instanceof OWLSubClassOfAxiom) {
1345                        OWLSubClassOfAxiom sca = (OWLSubClassOfAxiom) ax;
1346                        if (!sca.getSubClass().isAnonymous()) {
1347                            Set<OWLClassExpression> conjuncts = sca.getSuperClass().asConjunctSet();
1348                            if (conjuncts.contains(parent)) {
1349                                result.add(sca.getSubClass().asOWLClass());
1350                            }
1351                        }
1352                    }
1353                    else if (ax instanceof OWLEquivalentClassesAxiom) {
1354                        OWLEquivalentClassesAxiom eca = (OWLEquivalentClassesAxiom) ax;
1355                        for (OWLClassExpression ce : eca.getClassExpressions()) {
1356                            if (ce.containsConjunct(parent)) {
1357                                for (OWLClassExpression sub : eca.getClassExpressions()) {
1358                                    if (!sub.isAnonymous() && !sub.equals(ce)) {
1359                                        result.add(sub.asOWLClass());
1360                                    }
1361                                }
1362                            }
1363                        }
1364                    }
1365                }
1366            }
1367            return result;
1368        }
1369    }
1370
1371    private class RawObjectPropertyHierarchyProvider implements RawHierarchyProvider<OWLObjectPropertyExpression> {
1372
1373        private OWLObjectPropertyManager propertyManager;
1374
1375        private Map<OWLObjectPropertyExpression, Set<OWLObjectPropertyExpression>> sub2Super;
1376
1377        private Map<OWLObjectPropertyExpression, Set<OWLObjectPropertyExpression>> super2Sub;
1378
1379        public RawObjectPropertyHierarchyProvider() {
1380            rebuild();
1381        }
1382
1383        public void rebuild() {
1384            propertyManager = new OWLObjectPropertyManager(getRootOntology().getOWLOntologyManager(), getRootOntology());
1385            sub2Super = propertyManager.getPropertyHierarchy();
1386            super2Sub = new HashMap<>();
1387            for(Map.Entry<OWLObjectPropertyExpression, Set<OWLObjectPropertyExpression>> entry : sub2Super.entrySet()) {
1388                for(OWLObjectPropertyExpression superProp : entry.getValue()) {
1389                    super2Sub
1390                            .computeIfAbsent(superProp, k -> new HashSet<>())
1391                            .add(entry.getKey());
1392                }
1393            }
1394        }
1395
1396        @Override
1397        public Collection<OWLObjectPropertyExpression> getParents(OWLObjectPropertyExpression child) {
1398            if(child.isBottomEntity()) {
1399                return Collections.emptySet();
1400            }
1401            Set<OWLObjectPropertyExpression> propertyExpressions = sub2Super.get(child);
1402            if(propertyExpressions == null) {
1403                return Collections.emptySet();
1404            }
1405            else {
1406                return new HashSet<>(propertyExpressions);
1407            }
1408
1409        }
1410
1411        @Override
1412        public Collection<OWLObjectPropertyExpression> getChildren(OWLObjectPropertyExpression parent) {
1413            if(parent.isTopEntity()) {
1414                return Collections.emptySet();
1415            }
1416            Set<OWLObjectPropertyExpression> propertyExpressions = super2Sub.get(parent);
1417            if(propertyExpressions == null) {
1418                return Collections.emptySet();
1419            }
1420            else {
1421                return new HashSet<>(propertyExpressions);
1422            }
1423
1424        }
1425    }
1426
1427    private class RawDataPropertyHierarchyProvider implements RawHierarchyProvider<OWLDataProperty> {
1428        public RawDataPropertyHierarchyProvider() {}
1429        @Override
1430        public Collection<OWLDataProperty> getParents(OWLDataProperty child) {
1431            Set<OWLDataProperty> properties = new HashSet<>();
1432            for (OWLDataPropertyExpression prop : EntitySearcher.getSuperProperties(child, getRootOntology().getImportsClosure())) {
1433                properties.add(prop.asOWLDataProperty());
1434            }
1435            return properties;
1436        }
1437
1438        @Override
1439        public Collection<OWLDataProperty> getChildren(OWLDataProperty parent) {
1440            Set<OWLDataProperty> properties = new HashSet<>();
1441            for (OWLDataPropertyExpression prop : EntitySearcher.getSubProperties(parent, getRootOntology().getImportsClosure())) {
1442                properties.add(prop.asOWLDataProperty());
1443            }
1444            return properties;
1445        }
1446    }
1447
1448    public static void main(String[] args) throws Exception {
1449        OWLOntologyManager man = OWLManager.createOWLOntologyManager();
1450        OWLOntology schema = //man.loadOntology(IRI.create("http://downloads.dbpedia.org/2016-10/dbpedia_2016-10.nt"));
1451        man.loadOntology(IRI.create("file://" + System.getProperty("java.io.tmpdir") + "/merged.ttl"));
1452
1453        OWLOntologyKnowledgeSource sampleKS = new OWLAPIOntology(schema);
1454        sampleKS.init();
1455
1456
1457        final long start = System.currentTimeMillis();
1458
1459        OWLAPIReasoner baseReasoner = new OWLAPIReasoner(sampleKS);
1460        baseReasoner.setReasonerImplementation(ReasonerImplementation.STRUCTURAL);
1461        baseReasoner.init();
1462
1463        ClosedWorldReasoner reasoner = new ClosedWorldReasoner(baseReasoner);
1464        reasoner.init();
1465
1466        System.out.println(PeriodFormat.getDefault().print(new Period(System.currentTimeMillis() - start)));
1467    }
1468
1469}