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.clarkparsia.owlapi.explanation.PelletExplanation;
022import com.clarkparsia.owlapiv3.XSD;
023import com.clarkparsia.pellet.owlapiv3.PelletReasonerFactory;
024import com.google.common.base.StandardSystemProperty;
025import org.apache.log4j.Level;
026import org.apache.log4j.Logger;
027import org.dllearner.core.*;
028import org.dllearner.core.annotations.NoConfigOption;
029import org.dllearner.core.annotations.OutVariable;
030import org.dllearner.core.config.ConfigOption;
031import org.dllearner.kb.OWLAPIOntology;
032import org.dllearner.kb.OWLOntologyKnowledgeSource;
033import org.dllearner.utilities.OWLAPIUtils;
034import org.dllearner.utilities.owl.OWLClassExpressionMinimizer;
035import org.semanticweb.HermiT.Configuration;
036import org.semanticweb.elk.owlapi.ElkReasonerFactory;
037import org.semanticweb.owlapi.apibinding.OWLManager;
038import org.semanticweb.owlapi.model.*;
039import org.semanticweb.owlapi.model.parameters.Imports;
040import org.semanticweb.owlapi.owllink.OWLlinkHTTPXMLReasonerFactory;
041import org.semanticweb.owlapi.owllink.OWLlinkReasonerConfiguration;
042import org.semanticweb.owlapi.reasoner.*;
043import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory;
044import org.semanticweb.owlapi.search.EntitySearcher;
045import org.semanticweb.owlapi.vocab.OWL2Datatype;
046import uk.ac.manchester.cs.factplusplus.owlapiv3.FaCTPlusPlusReasonerFactory;
047import uk.ac.manchester.cs.jfact.JFactFactory;
048import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
049import uk.ac.manchester.cs.owl.owlapi.alternateimpls.ThreadSafeOWLReasoner;
050
051import java.io.File;
052import java.net.MalformedURLException;
053import java.net.URL;
054import java.util.*;
055
056//import de.tudresden.inf.lat.cel.owlapi.CelReasoner;
057//import eu.trowl.owlapi3.rel.reasoner.dl.RELReasonerFactory;
058//import org.semanticweb.elk.owlapi.ElkReasonerFactory;
059
060/**
061 * Mapping to OWL API reasoner interface. The OWL API currently
062 * supports the following OWL reasoners({@link ReasonerType}): FaCT++, HermiT, Pellet, ELK, CEL and TrOWL. FaCT++ is connected
063 * using JNI and native libraries, while the others are pure Java
064 * libraries.
065 *
066 * @author Jens Lehmann
067 * @author Lorenz Buehmann
068 */
069@ComponentAnn(name = "OWL API Reasoner", shortName = "oar", version = 0.8)
070public class OWLAPIReasoner extends AbstractReasonerComponent {
071
072    private OWLReasoner reasoner;
073    private OWLOntologyManager manager;
074
075    private OWLOntology ontology;
076    // the data factory is used to generate OWL API objects
077    private OWLDataFactory df;
078
079    // primitives
080    Set<OWLClass> atomicConcepts = new TreeSet<>();
081    Set<OWLObjectProperty> atomicRoles = new TreeSet<>();
082    SortedSet<OWLDataProperty> datatypeProperties = new TreeSet<>();
083    SortedSet<OWLIndividual> individuals = new TreeSet<>();
084
085    // namespaces
086        @OutVariable
087    private Map<String, String> prefixes = new TreeMap<>();
088        @OutVariable
089    private String baseURI;
090
091    // references to OWL API ontologies
092    private Set<OWLOntology> owlAPIOntologies = new HashSet<>();
093
094    private OWLClassExpressionMinimizer minimizer;
095
096    private OWLReasoner fallbackReasoner;
097    
098    
099 // default reasoner is Pellet
100    @ConfigOption(defaultValue="pellet", description="specifies the used OWL API reasoner implementation")
101    private ReasonerImplementation reasonerImplementation = ReasonerImplementation.PELLET;
102
103    @ConfigOption(defaultValue="false", description="specifies whether to use a fallback reasoner if a reasoner call fails because it's not supported or results in a bug. (the fallback works only on the assertional level")
104    private boolean useFallbackReasoner = false;
105
106    @ConfigOption(defaultValue="null", description="specifies the URL of the remote OWLLink server")
107    private String owlLinkURL;
108
109    public OWLAPIReasoner() {
110
111    }
112
113    public OWLAPIReasoner(KnowledgeSource... sources) {
114        super(new HashSet<>(Arrays.asList(sources)));
115    }
116
117    public OWLAPIReasoner(Set<KnowledgeSource> sources) {
118        super(sources);
119    }
120
121    public OWLAPIReasoner(OWLReasoner reasoner) {
122        this.reasoner = reasoner;
123        KnowledgeSource ks = new OWLAPIOntology(reasoner.getRootOntology());
124        sources = Collections.singleton(ks);
125    }
126
127    @Override
128    public void init() throws ComponentInitException {
129        // reset variables (otherwise subsequent initialisation with
130        // different knowledge sources will merge both)
131        atomicConcepts = new TreeSet<>();
132        atomicRoles = new TreeSet<>();
133        datatypeProperties = new TreeSet<>();
134        individuals = new TreeSet<>();
135
136        // create OWL API ontology manager - make sure we use a new data factory so that we don't default to the static one which can cause problems in a multi threaded environment.
137        df = new OWLDataFactoryImpl();
138        manager = OWLManager.createOWLOntologyManager();
139
140        prefixes = new TreeMap<>();
141
142        for (KnowledgeSource source : sources) {
143            if (source instanceof OWLOntologyKnowledgeSource) {
144                ontology = ((OWLOntologyKnowledgeSource) source).createOWLOntology(manager);
145                owlAPIOntologies.add(ontology);
146            }else{
147                //This reasoner requires an ontology to process
148                throw new ComponentInitException("OWL API Reasoner requires an OWLKnowledgeSource.  Received a KS of type: " + source.getClass().getName());
149            }
150
151            atomicConcepts.addAll(ontology.getClassesInSignature(Imports.INCLUDED));
152            atomicRoles.addAll(ontology.getObjectPropertiesInSignature(Imports.INCLUDED));
153            datatypeProperties.addAll(ontology.getDataPropertiesInSignature(Imports.INCLUDED));
154            individuals.addAll(ontology.getIndividualsInSignature(Imports.INCLUDED));
155
156            // if several knowledge sources are included, then we can only
157            // guarantee that the base URI is from one of those sources (there
158            // can't be more than one); but we will take care that all prefixes are
159            // correctly imported
160            OWLDocumentFormat format = manager.getOntologyFormat(ontology);
161            if (format != null && format.isPrefixOWLOntologyFormat()) {
162                prefixes.putAll(format.asPrefixOWLOntologyFormat().getPrefixName2PrefixMap());
163                baseURI = format.asPrefixOWLOntologyFormat().getDefaultPrefix();
164                prefixes.remove("");
165            }
166        }
167
168        //Now merge all of the knowledge sources into one ontology instance.
169        try {
170            //The following line illustrates a problem with using different OWLOntologyManagers.  This can manifest itself if we have multiple sources who were created with different manager instances.
171            //ontology = OWLManager.createOWLOntologyManager().createOntology(IRI.create("http://dl-learner/all"), new HashSet<OWLOntology>(owlAPIOntologies));
172            ontology = manager.createOntology(IRI.generateDocumentIRI(), new HashSet<>(owlAPIOntologies));
173
174                        //we have to add all import declarations manually here, because these are not OWL axioms
175            List<OWLOntologyChange> addImports = new ArrayList<>();
176            for (OWLOntology ont : owlAPIOntologies) {
177                for (OWLImportsDeclaration importDeclaration : ont.getImportsDeclarations()) {
178                        addImports.add(new AddImport(ontology, importDeclaration));
179                                }
180            }
181            manager.applyChanges(addImports);
182            // free some memory. It is useless to keep two copies of the same 
183            // ontology
184            for (OWLOntology toRemove : owlAPIOntologies) {
185                manager.removeOntology(toRemove);
186            }
187            owlAPIOntologies = new HashSet<>();
188        } catch (OWLOntologyCreationException e1) {
189            e1.printStackTrace();
190        }
191
192        //set up OWL reasoner
193        if(reasoner == null) {
194                initBaseReasoner();
195        }
196
197        // compute class hierarchy and types of individuals
198        // (done here to speed up later reasoner calls)
199        boolean inconsistentOntology = !reasoner.isConsistent();
200
201        if (!inconsistentOntology) {
202            reasoner.precomputeInferences(
203                        InferenceType.CLASS_HIERARCHY, 
204                        InferenceType.CLASS_ASSERTIONS, 
205                        InferenceType.OBJECT_PROPERTY_HIERARCHY,
206                        InferenceType.DATA_PROPERTY_HIERARCHY,
207                        InferenceType.OBJECT_PROPERTY_ASSERTIONS,
208                                        InferenceType.DATA_PROPERTY_ASSERTIONS,
209                        InferenceType.SAME_INDIVIDUAL);
210        } else {
211                PelletExplanation expGen = new PelletExplanation(ontology);
212                logger.error("The loaded ontology is logically inconsistent! One explanation for this is the following minimal set of axioms: "
213                                        + expGen.getInconsistencyExplanation());
214            throw new ComponentInitException("Inconsistent ontologies.");
215        }
216
217        df = manager.getOWLDataFactory();
218
219        initDatatypes();
220
221        // remove top and bottom properties (for backwards compatibility)
222//              atomicRoles.remove(df.getOWLObjectProperty(IRI.create("http://www.w3.org/2002/07/owl#bottomObjectProperty"));
223//              atomicRoles.remove(df.getOWLObjectProperty(IRI.create("http://www.w3.org/2002/07/owl#topObjectProperty"));
224
225        // remove classes that are built-in entities
226                atomicConcepts.removeIf(cls -> cls.getIRI().isReservedVocabulary());
227
228                 minimizer = new OWLClassExpressionMinimizer(df, this);
229                 logger.info("Loaded reasoner: " + reasoner.getReasonerName() + " (" + reasoner.getClass().getName() + ")");
230                 
231                 initialized = true;
232    }
233    
234    private void initDatatypes() {
235            Set<OWLDataProperty> numericDataProperties = new HashSet<>();
236            for (OWLDataProperty dataProperty : datatypeProperties) {
237//                  Collection<OWLDataRange> ranges = EntitySearcher.getRanges(dataProperty, owlAPIOntologies);
238                    Collection<OWLDataRange> ranges = Collections.EMPTY_SET;
239                    LinkedList<OWLDataProperty> superDataProperties = new LinkedList<>();
240                    superDataProperties.add(dataProperty);
241                    while (ranges.isEmpty() && !superDataProperties.isEmpty()) {
242                            OWLDataProperty sDP = superDataProperties.removeFirst();
243                            ranges = EntitySearcher.getRanges(sDP, ontology);
244                            if (ranges.isEmpty()) {
245                                    final NodeSet<OWLDataProperty> sps = reasoner.getSuperDataProperties(sDP, true);
246                                    superDataProperties.addAll(sps.getFlattened());
247                            }
248                    }
249                    Iterator<OWLDataRange> it = ranges.iterator();
250                    if (it.hasNext()) {
251                            OWLDataRange range = it.next();
252                            if (range.isDatatype()) {
253                                    OWLDatatype datatype = range.asOWLDatatype();
254
255                                    if (datatype.isBuiltIn()) { // OWL 2 DL compliant datatypes
256                                            datatype2Properties.put(range.asOWLDatatype(), dataProperty);
257
258                                            dataproperty2datatype.put(dataProperty, range.asOWLDatatype());
259
260                                            if (OWLAPIUtils.isNumericDatatype(range.asOWLDatatype())) {
261                                                    numericDataProperties.add(dataProperty);
262                                            }
263                                    } else if (OWLAPIUtils.dtDatatypes.contains(datatype)) { // support for other XSD datatypes, e.g. xsd:date
264                                            datatype2Properties.put(range.asOWLDatatype(), dataProperty);
265
266                                            dataproperty2datatype.put(dataProperty, range.asOWLDatatype());
267                                    } else { // TODO handle non-built-in data types
268                                    }
269                            } else { // TODO handle complex data property ranges
270                            }
271                    } else { // TODO handle data properties without range assertion
272                    }
273            }
274    }
275
276    private void initBaseReasoner() {
277        ReasonerProgressMonitor progressMonitor = new NullReasonerProgressMonitor();
278        FreshEntityPolicy freshEntityPolicy = FreshEntityPolicy.ALLOW;
279        long timeOut = Integer.MAX_VALUE;
280        IndividualNodeSetPolicy individualNodeSetPolicy = IndividualNodeSetPolicy.BY_NAME;
281        OWLReasonerConfiguration conf = new SimpleConfiguration(progressMonitor, freshEntityPolicy, timeOut, individualNodeSetPolicy);
282
283        OWLReasonerFactory reasonerFactory = null;
284        // create actual reasoner
285                switch (reasonerImplementation) {
286                case PELLET:
287                        reasonerFactory = PelletReasonerFactory.getInstance();
288                        // change log level to WARN for Pellet, because otherwise log
289                        // output will be very large
290                        Logger pelletLogger = Logger.getLogger("org.mindswap.pellet");
291                        pelletLogger.setLevel(Level.WARN);
292                        break;
293                case JFACT:
294                        reasonerFactory = new JFactFactory();
295                        break;
296                case FACT:
297                        reasonerFactory = new FaCTPlusPlusReasonerFactory();
298                        break;
299                case ELK:
300                        reasonerFactory = new ElkReasonerFactory();
301                        break;
302                case HERMIT:
303                        reasonerFactory = new org.semanticweb.HermiT.ReasonerFactory();
304                        Configuration c = new Configuration();
305                        c.ignoreUnsupportedDatatypes = true;
306//                      c.throwInconsistentOntologyException = false;
307                        conf = c;
308                        break;
309//              case TROWL:
310//                      reasonerFactory = new RELReasonerFactory();
311//                      break;
312//              case CEL:
313//                      reasoner = new CelReasoner(ontology, conf);
314//                      break;
315                case OWLLINK:
316                        reasonerFactory = new OWLlinkHTTPXMLReasonerFactory();
317                        URL url;
318                        try {
319                                url = new URL(getOwlLinkURL());//Configure the server end-point
320                                conf = new OWLlinkReasonerConfiguration(url);
321                        } catch (MalformedURLException e) {
322                                logger.error("Illegal URL <" + getOwlLinkURL() + "> for OWL Link HTTP reasoner", e);
323                        }
324                        break;
325                case STRUCTURAL : 
326                        reasonerFactory = new StructuralReasonerFactory();
327                        break;
328                default:
329                        reasonerFactory = PelletReasonerFactory.getInstance();
330                }
331
332                if (null != reasonerFactory) {
333                        reasoner = reasonerFactory.createNonBufferingReasoner(ontology, conf);
334                }
335
336        if(useFallbackReasoner){
337                fallbackReasoner = new StructuralReasonerExtended(ontology, conf, BufferingMode.NON_BUFFERING);
338        }
339    }
340
341    /* (non-Javadoc)
342      * @see org.dllearner.core.Reasoner#getAtomicConcepts()
343      */
344    @Override
345    public Set<OWLClass> getClasses() {
346        return Collections.unmodifiableSet(atomicConcepts);
347    }
348
349    /* (non-Javadoc)
350      * @see org.dllearner.core.Reasoner#getAtomicRoles()
351      */
352    @Override
353    public Set<OWLObjectProperty> getObjectPropertiesImpl() {
354        return Collections.unmodifiableSet(atomicRoles);
355    }
356
357    @Override
358    public Set<OWLDataProperty> getDatatypePropertiesImpl() {
359        return datatypeProperties;
360    }
361
362    /* (non-Javadoc)
363      * @see org.dllearner.core.Reasoner#getIndividuals()
364      */
365    @Override
366    public SortedSet<OWLIndividual> getIndividuals() {
367        return individuals;
368    }
369
370    /**
371         * @param prefixes the prefixes to set
372         */
373        public void setPrefixes(Map<String, String> prefixes) {
374                this.prefixes = prefixes;
375        }
376
377        /**
378         * @param baseURI the baseURI to set
379         */
380        public void setBaseURI(String baseURI) {
381                this.baseURI = baseURI;
382        }
383
384    /* (non-Javadoc)
385      * @see org.dllearner.core.Reasoner#getReasonerType()
386      */
387    @Override
388    public ReasonerType getReasonerType() {
389        if (reasoner instanceof org.semanticweb.HermiT.Reasoner) {
390                return ReasonerType.OWLAPI_HERMIT;
391        }
392        else if (reasoner instanceof com.clarkparsia.pellet.owlapiv3.PelletReasoner) {
393                return ReasonerType.OWLAPI_PELLET;
394        }
395        else if (reasoner instanceof uk.ac.manchester.cs.jfact.JFactReasoner) {
396                return ReasonerType.OWLAPI_JFACT;
397        }
398        else if (reasoner instanceof uk.ac.manchester.cs.factplusplus.owlapiv3.FaCTPlusPlusReasoner) {
399                return ReasonerType.OWLAPI_FACT;
400        }
401        return ReasonerType.OWLAPI_FUZZY; // TODO
402    }
403
404        /**
405         * A convenience method that determines if the specified axiom is entailed by the set of reasoner axioms.
406         * @see OWLReasoner#isEntailed(OWLAxiom)
407         * @param axiom the axiom
408         * @return {@code true} if {@code axiom} is entailed by the reasoner axioms
409         *         or {@code false} if {@code axiom} is not entailed by the reasoner
410         *         axioms. {@code true} if the set of reasoner axioms is
411         *         inconsistent.
412         */
413        public boolean isEntailed(OWLAxiom axiom) {
414                try {
415                        return reasoner.isEntailed(axiom);
416                } catch (UnsupportedOperationException e) {
417                        if (useFallbackReasoner) {
418                                return fallbackReasoner.isEntailed(axiom);
419                        } else {
420                                throw e;
421                        }
422                }
423        }
424
425        @Override
426        public boolean isSuperClassOfImpl(OWLClassExpression superConcept,
427                        OWLClassExpression subConcept) {
428                if (superConcept.isOWLThing() || subConcept.isOWLNothing()) {
429                        return true;
430                }
431                boolean res;
432                try {
433                        res = reasoner.isEntailed(df.getOWLSubClassOfAxiom(subConcept,
434                                        superConcept));
435                } catch (UnsupportedOperationException e) {
436                        if (useFallbackReasoner) {
437                                res = fallbackReasoner.isEntailed(df.getOWLSubClassOfAxiom(
438                                                subConcept, superConcept));
439                        } else {
440                                throw e;
441                        }
442                }
443                return res;
444        }
445
446    /* (non-Javadoc)
447     * @see org.dllearner.core.Reasoner#isDisjoint(OWLClass class1, OWLClass class2)
448     */
449        @Override
450        public boolean isDisjointImpl(OWLClass clsA, OWLClass clsB) {
451                // we have two ways, not sure which one is more efficient
452                // 1. get all disjoint classes and check for set containment (could be fast if taxonomy
453                // is cached somewhere in the reasoner internals)
454//              return reasoner.getDisjointClasses(clsA).containsEntity(clsB);
455
456                // 2. check for entailment of DisjointClass(A, B) resp.
457                // SubClassOf(OWLIntersectionOf(A, B), owl:Nothing)
458//              OWLAxiom axiom = df.getOWLDisjointClassesAxiom(clsA, clsB);
459
460                return isEntailed(df.getOWLSubClassOfAxiom(
461                                                        df.getOWLObjectIntersectionOf(clsA, clsB),
462                                                        df.getOWLNothing()));
463        }
464
465        @Override
466        protected boolean isEquivalentClassImpl(OWLClassExpression class1, OWLClassExpression class2) {
467                return isEntailed(df.getOWLEquivalentClassesAxiom(class1, class2));
468        }
469
470        @Override
471        protected TreeSet<OWLClassExpression> getSuperClassesImpl(OWLClassExpression concept) {
472                NodeSet<OWLClass> classes;
473                try {
474                        classes = reasoner.getSuperClasses(concept, true);
475                } catch (UnsupportedOperationException e) {
476                        e.printStackTrace();
477                        if (useFallbackReasoner) {
478                                classes = fallbackReasoner.getSubClasses(concept, true);
479                        } else {
480                                throw e;
481                        }
482                }
483                return new TreeSet<>(classes.getFlattened());
484//              return getFirstClasses(classes);
485        }
486
487        @Override
488        protected TreeSet<OWLClassExpression> getSubClassesImpl(OWLClassExpression ce) {
489                NodeSet<OWLClass> classes;
490
491                try {
492                        classes = reasoner.getSubClasses(ce, true);
493                } catch (UnsupportedOperationException e) {
494                        if (useFallbackReasoner) {
495                                classes = fallbackReasoner.getSubClasses(ce, true);
496                        } else {
497                                throw e;
498                        }
499                }
500                TreeSet<OWLClassExpression> subClasses = new TreeSet<>(classes.getFlattened());//getFirstClasses(classes);
501                subClasses.remove(df.getOWLNothing());
502                // remove built-in entities sometimes returned as subclasses of
503                // owl:Thing
504                if (ce.isOWLThing()) {
505                        subClasses.removeIf(_ce -> !_ce.isAnonymous() &&
506                                        _ce.asOWLClass().getIRI().isReservedVocabulary());
507                }
508                return subClasses;
509        }
510
511    private <T extends OWLObject> SortedSet<T> getRepresentativeEntities(NodeSet<T> nodeSet){
512        SortedSet<T> representatives = new TreeSet<>();
513        for (Node<T> node : nodeSet) {
514                        if(!node.isBottomNode() && !node.isTopNode()){
515                                representatives.add(node.getRepresentativeElement());
516                        }
517                }
518        return representatives;
519    }
520
521        protected SortedSet<OWLClassExpression> getEquivalentClassesImpl(OWLClassExpression ce) {
522                SortedSet<OWLClassExpression> equivalentClasses = new TreeSet<>();
523                Node<OWLClass> classNodes;
524                try {
525                        classNodes = reasoner.getEquivalentClasses(ce);
526                } catch (UnsupportedOperationException e) {
527                        if (useFallbackReasoner) {
528                                classNodes = fallbackReasoner.getEquivalentClasses(ce);
529                        } else {
530                                throw e;
531                        }
532                }
533
534                equivalentClasses.addAll(classNodes.getEntitiesMinusTop());
535                equivalentClasses.remove(ce);
536                return equivalentClasses;
537        }
538
539        @Override
540        protected TreeSet<OWLObjectProperty> getSuperPropertiesImpl(OWLObjectProperty objectProperty) {
541                NodeSet<OWLObjectPropertyExpression> properties;
542                try {
543                        properties = reasoner
544                                        .getSuperObjectProperties(objectProperty, true);
545                } catch (UnsupportedOperationException e) {
546                        if (useFallbackReasoner) {
547                                properties = fallbackReasoner.getSubObjectProperties(
548                                                objectProperty, true);
549                        } else {
550                                throw e;
551                        }
552                }
553                return getFirstObjectProperties(properties);
554        }
555
556        @Override
557        protected TreeSet<OWLObjectProperty> getSubPropertiesImpl(OWLObjectProperty objectProperty) {
558                NodeSet<OWLObjectPropertyExpression> properties;
559
560                try {
561                        properties = reasoner.getSubObjectProperties(objectProperty, true);
562                } catch (UnsupportedOperationException e) {
563                        if (useFallbackReasoner) {
564                                properties = fallbackReasoner.getSubObjectProperties(
565                                                objectProperty, true);
566                        } else {
567                                throw e;
568                        }
569                }
570                return getFirstObjectProperties(properties);
571        }
572
573        @Override
574        protected TreeSet<OWLDataProperty> getSuperPropertiesImpl(OWLDataProperty dataProperty) {
575                NodeSet<OWLDataProperty> properties;
576
577                try {
578                        properties = reasoner.getSuperDataProperties(dataProperty, true);
579                } catch (UnsupportedOperationException e) {
580                        if (useFallbackReasoner) {
581                                properties = fallbackReasoner.getSuperDataProperties(dataProperty, true);
582                        } else {
583                                throw e;
584                        }
585                }
586                return getFirstDatatypeProperties(properties);
587        }
588
589        @Override
590        protected TreeSet<OWLDataProperty> getSubPropertiesImpl(OWLDataProperty dataProperty) {
591                NodeSet<OWLDataProperty> properties;
592
593                try {
594                        properties = reasoner.getSubDataProperties(dataProperty, true);
595                } catch (UnsupportedOperationException e) {
596                        if (useFallbackReasoner) {
597                                properties = fallbackReasoner.getSubDataProperties(dataProperty, true);
598                        } else {
599                                throw e;
600                        }
601                }
602                return getFirstDatatypeProperties(properties);
603        }
604
605        @Override
606        public boolean hasTypeImpl(OWLClassExpression concept, OWLIndividual individual) {
607                if (concept.isOWLThing()) {
608                        return true;
609
610                } else if (concept.isOWLNothing()) {
611                        return false;
612
613                } else {
614                        OWLClassAssertionAxiom axiom = df.getOWLClassAssertionAxiom(
615                                        concept, individual);
616                        boolean res;
617                        try {
618                                res = reasoner.isEntailed(axiom);
619                        } catch (UnsupportedOperationException e) {
620                                if (useFallbackReasoner) {
621                                        res = fallbackReasoner.isEntailed(axiom);
622                                } else {
623                                        throw e;
624                                }
625                        }
626
627                        return res;
628                }
629        }
630
631        @Override
632        public SortedSet<OWLIndividual> getIndividualsImpl(OWLClassExpression ce) {
633                Set<OWLNamedIndividual> individuals;
634                logger.trace("getIndividuals for " + ce);
635                try {
636                        individuals = reasoner.getInstances(ce, false).getFlattened();
637                } catch (UnsupportedOperationException e) {
638                        if (useFallbackReasoner) {
639                                individuals = fallbackReasoner.getInstances(ce, false).getFlattened();
640                        } else {
641                                throw e;
642                        }
643                }
644
645                return new TreeSet<>(individuals);
646        }
647
648        @Override
649        public Set<OWLClass> getTypesImpl(OWLIndividual individual) {
650                NodeSet<OWLClass> nodeSet;
651                try {
652                        nodeSet = reasoner.getTypes(individual.asOWLNamedIndividual(), false);
653                } catch (UnsupportedOperationException e) {
654                        if (useFallbackReasoner) {
655                                nodeSet = fallbackReasoner.getTypes(individual.asOWLNamedIndividual(), false);
656                        } else {
657                                throw e;
658                        }
659                }
660                return getFirstClassesNoTopBottom(nodeSet);
661        }
662
663        @Override
664        public boolean isSatisfiableImpl() {
665                boolean res;
666                try {
667                        res = reasoner.isSatisfiable(df.getOWLThing());
668                } catch (UnsupportedOperationException e) {
669                        if (useFallbackReasoner) {
670                                res = fallbackReasoner.isSatisfiable(df.getOWLThing());
671                        } else {
672                                throw e;
673                        }
674                }
675                return res;
676        }
677
678        @Override
679        public OWLClassExpression getDomainImpl(OWLObjectProperty objectProperty) {
680                // this is a bit tricky because the reasoner interface only returns
681                // atomic classes, but it might be the case that in the ontology complex
682                // domain definitions are contained
683
684                Set<OWLClassExpression> domains = new HashSet<>();
685
686                // get all asserted domains
687                domains.addAll(EntitySearcher.getDomains(objectProperty, ontology));
688
689                // do the same for all super properties
690                SortedSet<OWLObjectProperty> superProperties = getSuperProperties(objectProperty);
691                for (OWLObjectProperty supProp : superProperties) {
692                        domains.addAll(EntitySearcher.getDomains(supProp, ontology));
693                }
694
695                // last but not least, call a reasoner
696                NodeSet<OWLClass> nodeSet;
697                try {
698                        nodeSet = reasoner.getObjectPropertyDomains(objectProperty, true);
699                } catch (UnsupportedOperationException e) {
700                        if (useFallbackReasoner) {
701                                nodeSet = fallbackReasoner.getObjectPropertyDomains(objectProperty, true);
702                        } else {
703                                throw e;
704                        }
705                }
706
707                domains.addAll(nodeSet.getFlattened());
708
709                domains.remove(df.getOWLThing());
710
711                // several domains have to be treated as intersection
712                OWLClassExpression domain = asIntersection(domains);
713
714                logger.trace("Domain({},{})", objectProperty, domain);
715                return domain;
716        }
717
718//    @Override
719//    public OWLClassExpression getDomainImpl(OWLDataProperty objectProperty) {
720//      return asIntersection(reasoner.getDataPropertyDomains(objectProperty, true));
721//    }
722
723        @Override
724        public OWLClassExpression getDomainImpl(OWLDataProperty dataProperty) {
725                // this is a bit tricky because the reasoner interface only returns
726                // atomic classes, but it might be the case that in the ontology complex
727                // domain definitions are contained
728
729                Set<OWLClassExpression> domains = new HashSet<>();
730
731                // get all asserted domains
732                domains.addAll(EntitySearcher.getDomains(dataProperty, ontology));
733
734                // do the same for all super properties
735                SortedSet<OWLDataProperty> superProperties = getSuperProperties(dataProperty);
736                for (OWLDataProperty supProp : superProperties) {
737                        domains.addAll(EntitySearcher.getDomains(supProp, ontology));
738                }
739
740                // last but not least, call a reasoner
741                NodeSet<OWLClass> nodeSet;
742
743                try {
744                        nodeSet = reasoner.getDataPropertyDomains(dataProperty, true);
745                } catch (UnsupportedOperationException e) {
746                        if (useFallbackReasoner) {
747                                nodeSet = fallbackReasoner.getDataPropertyDomains(dataProperty, true);
748                        } else {
749                                throw e;
750                        }
751                }
752                domains.addAll(nodeSet.getFlattened());
753
754                domains.remove(df.getOWLThing());
755
756                // several domains have to be treated as intersection
757                OWLClassExpression domain = asIntersection(domains);
758
759                logger.trace("Domain({},{})", dataProperty, domain);
760                return domain;
761        }
762
763//    @Override
764//    public OWLClassExpression getRangeImpl(OWLObjectProperty objectProperty) {
765//      return asIntersection(reasoner.getObjectPropertyRanges(objectProperty, true));
766//    }
767
768        @Override
769        public OWLClassExpression getRangeImpl(OWLObjectProperty objectProperty) {
770                // this is a little bit tricky because the reasoner interface only
771                // returns
772                // atomic classes, but it might be the case that in the ontology complex
773                // range definitions are contained
774
775                Set<OWLClassExpression> ranges = new HashSet<>();
776
777                // get all asserted ranges
778                ranges.addAll(EntitySearcher.getRanges(objectProperty, ontology));
779
780                // do the same for all super properties
781                SortedSet<OWLObjectProperty> superProperties = getSuperProperties(objectProperty);
782                for (OWLObjectPropertyExpression supProp : superProperties) {
783                        ranges.addAll(EntitySearcher.getRanges(supProp, ontology));
784                }
785
786                // last but not least, call a reasoner
787                NodeSet<OWLClass> nodeSet;
788                try {
789                        nodeSet = reasoner.getObjectPropertyRanges(objectProperty, true);
790                } catch (UnsupportedOperationException e) {
791                        if (useFallbackReasoner) {
792                                nodeSet = fallbackReasoner.getObjectPropertyRanges(objectProperty, true);
793                        } else {
794                                throw e;
795                        }
796                }
797                ranges.addAll(nodeSet.getFlattened());
798
799                // several ranges have to be treated as intersection
800                OWLClassExpression range = asIntersection(ranges);
801
802                logger.trace("Range({},{})", objectProperty, range);
803                return range;
804        }
805
806    @Override
807    public OWLDataRange getRangeImpl(OWLDataProperty datatypeProperty) {
808        Set<OWLDataPropertyRangeAxiom> axioms = ontology.getDataPropertyRangeAxioms(datatypeProperty);
809        if(!axioms.isEmpty()){
810                OWLDataPropertyRangeAxiom axiom = axioms.iterator().next();
811                return axiom.getRange();
812        } else {
813                return df.getOWLDatatype(OWL2Datatype.RDFS_LITERAL.getIRI());
814        }
815    }
816
817    private OWLClassExpression asIntersection(Set<OWLClassExpression> classExpressions){
818        if(classExpressions.isEmpty()){
819                return df.getOWLThing();
820        } else if(classExpressions.size() == 1){
821                return classExpressions.iterator().next();
822        } else {
823                return df.getOWLObjectIntersectionOf(classExpressions);
824        }
825    }
826
827    private OWLClassExpression getDescriptionFromReturnedDomain(NodeSet<OWLClass> nodeSet) {
828        if (nodeSet.isEmpty()){
829                return df.getOWLThing();
830        }
831
832        Set<OWLClassExpression> union = new HashSet<>();
833        Set<OWLClassExpression> domains = new HashSet<>();
834
835        for (Node<OWLClass> node : nodeSet) {
836            union.add(node.getRepresentativeElement());
837        }
838        for (OWLClassExpression desc : union) {
839            boolean isSuperClass = false;
840            for (OWLClassExpression d : getClassHierarchy().getSubClasses(desc)) {
841                if (union.contains(d)) {
842                    isSuperClass = true;
843                    break;
844                }
845            }
846            if (!isSuperClass) {
847                domains.add(desc);
848            }
849        }
850
851        OWLClass oc = (OWLClass) domains.iterator().next();
852        if (oc.isOWLThing()) {
853            return df.getOWLThing();
854        } else {
855            return df.getOWLClass(IRI.create(oc.toStringID()));
856        }
857    }
858
859    @Override
860    public Map<OWLIndividual, SortedSet<OWLIndividual>> getPropertyMembersImpl(OWLObjectProperty objectProperty) {
861        Map<OWLIndividual, SortedSet<OWLIndividual>> map = new TreeMap<>();
862        for (OWLIndividual ind : individuals) {
863            Set<OWLIndividual> inds = getRelatedIndividuals(ind, objectProperty);
864            map.put(ind, new TreeSet<>(inds));
865        }
866        return map;
867    }
868
869    @Override
870    protected Map<OWLObjectProperty, Set<OWLIndividual>> getObjectPropertyRelationshipsImpl(OWLIndividual individual) {
871        Map<OWLObjectProperty, Set<OWLIndividual>> map = new HashMap<>();
872
873        for (OWLObjectProperty prop : ontology.getObjectPropertiesInSignature(Imports.INCLUDED)) {
874            map.put(prop, getRelatedIndividualsImpl(individual, prop));
875        }
876
877        return map;
878    }
879
880        @Override
881        protected Map<OWLDataProperty, Set<OWLLiteral>> getDataPropertyRelationshipsImpl(OWLIndividual individual) throws ReasoningMethodUnsupportedException {
882                Map<OWLDataProperty, Set<OWLLiteral>> map = new HashMap<>();
883
884                for (OWLDataProperty prop : ontology.getDataPropertiesInSignature(Imports.INCLUDED)) {
885                        map.put(prop, getRelatedValuesImpl(individual, prop));
886                }
887
888                return map;
889        }
890
891        @SuppressWarnings("unchecked")
892        @Override
893        public Set<OWLIndividual> getRelatedIndividualsImpl(
894                        OWLIndividual individual, OWLObjectProperty objectProperty) {
895
896                Set<? extends OWLIndividual> namedIndividuals;
897                try {
898                        namedIndividuals = reasoner.getObjectPropertyValues(
899                                        individual.asOWLNamedIndividual(), objectProperty).getFlattened();
900                } catch (UnsupportedOperationException e) {
901                        if (useFallbackReasoner) {
902                                namedIndividuals = fallbackReasoner.getObjectPropertyValues(
903                                                individual.asOWLNamedIndividual(), objectProperty).getFlattened();
904                        } else {
905                                throw e;
906                        }
907                }
908
909                return (Set<OWLIndividual>) namedIndividuals;
910        }
911
912        @Override
913        public Set<OWLLiteral> getRelatedValuesImpl(OWLIndividual individual,
914                        OWLDataProperty datatypeProperty) {
915
916                Set<OWLLiteral> propVals;
917                try {
918                        propVals = reasoner.getDataPropertyValues(
919                                        individual.asOWLNamedIndividual(), datatypeProperty);
920
921                } catch (UnsupportedOperationException e) {
922                        if (useFallbackReasoner) {
923                                propVals = fallbackReasoner.getDataPropertyValues(
924                                                individual.asOWLNamedIndividual(), datatypeProperty);
925                        } else {
926                                throw e;
927                        }
928                }
929
930                return propVals;
931        }
932
933//    @Override
934//    public Set<OWLLiteral> getRelatedValuesImpl(OWLIndividual individual, OWLDataProperty datatypeProperty) {
935//        return reasoner.getDataPropertyValues(individual.asOWLNamedIndividual(), datatypeProperty);
936//    }
937
938        public Map<OWLIndividual, SortedSet<Double>> getDoubleValues(OWLDataProperty dataProperty) {
939                Map<OWLIndividual, SortedSet<Double>> map = new TreeMap<>();
940
941                for (OWLIndividual ind : individuals) {
942                        Set<OWLLiteral> literals = getRelatedValuesImpl(ind, dataProperty);
943
944                        if (!literals.isEmpty()) {
945                                SortedSet<Double> values = new TreeSet<>();
946                                for (OWLLiteral lit : literals) {
947                                        if (lit.isDouble()) {
948                                                values.add(lit.parseDouble());
949                                        }
950                                }
951                                map.put(ind, values);
952                        }
953                }
954                return map;
955        }
956
957        @Override
958        public Map<OWLIndividual, SortedSet<OWLLiteral>> getDatatypeMembersImpl(OWLDataProperty dataProperty) {
959
960                Map<OWLIndividual, SortedSet<OWLLiteral>> map = new TreeMap<>();
961
962                for (OWLIndividual ind : individuals) {
963                        Set<OWLLiteral> literals = getRelatedValuesImpl(ind, dataProperty);
964
965                        if (!literals.isEmpty()) {
966                                map.put(ind, new TreeSet<>(literals));
967                        }
968                }
969                return map;
970        }
971
972    // OWL API returns a set of nodes of classes, where each node
973    // consists of equivalent classes; this method picks one class
974    // from each node to flatten the set of nodes
975    private TreeSet<OWLClassExpression> getFirstClasses(NodeSet<OWLClass> nodeSet) {
976        TreeSet<OWLClassExpression> concepts = new TreeSet<>();
977        for (Node<OWLClass> node : nodeSet) {
978            // take one element from the set and ignore the rest
979            // (TODO: we need to make sure we always ignore the same concepts)
980                if(node.getSize() != 0) {
981                        OWLClass concept = node.getRepresentativeElement();
982                concepts.add(concept);
983                } else {
984                        logger.warn("Reasoner returned empty node. Seems to be a bug.");
985                }
986        }
987        return concepts;
988    }
989
990    private Set<OWLClass> getFirstClassesNoTopBottom(NodeSet<OWLClass> nodeSet) {
991        Set<OWLClass> concepts = new HashSet<>();
992        for (Node<OWLClass> node : nodeSet) {
993                if(!node.isBottomNode() && !node.isTopNode()){
994                        concepts.add(node.getRepresentativeElement());
995                }
996        }
997        return concepts;
998    }
999
1000    private TreeSet<OWLObjectProperty> getFirstObjectProperties(NodeSet<OWLObjectPropertyExpression> nodeSet) {
1001        TreeSet<OWLObjectProperty> roles = new TreeSet<>();
1002        for (Node<OWLObjectPropertyExpression> node : nodeSet) {
1003            if (node.isBottomNode() || node.isTopNode()) {
1004                continue;
1005            }
1006            if(node.getSize() == 0){
1007                logger.warn("Reasoner returned empty property node. Could be a bug.");
1008                continue;
1009            }
1010            // take one element from the set and ignore the rest
1011            // (TODO: we need to make sure we always ignore the same concepts)
1012            OWLObjectPropertyExpression property = node.getRepresentativeElement();
1013            if (!property.isAnonymous()) {
1014                roles.add(property.asOWLObjectProperty());
1015            }
1016        }
1017                // we ignore top and bottom properties
1018        roles.remove(df.getOWLTopObjectProperty());
1019        roles.remove(df.getOWLBottomObjectProperty());
1020        return roles;
1021    }
1022
1023    private TreeSet<OWLDataProperty> getFirstDatatypeProperties(NodeSet<OWLDataProperty> nodeSet) {
1024        TreeSet<OWLDataProperty> roles = new TreeSet<>();
1025        for (Node<OWLDataProperty> node : nodeSet) {
1026            if (node.isBottomNode() || node.isTopNode()) {
1027                continue;
1028            }
1029            if(node.getSize() == 0){
1030                logger.warn("Reasoner returned empty property node. Could be a bug.");
1031                continue;
1032            }
1033            OWLDataProperty property = node.getRepresentativeElement();
1034            roles.add(property);
1035        }
1036                // we ignore top and bottom properties
1037        roles.remove(df.getOWLTopDataProperty());
1038        roles.remove(df.getOWLBottomDataProperty());
1039        return roles;
1040    }
1041
1042    @Override
1043        public Set<OWLDataProperty> getBooleanDatatypePropertiesImpl() {
1044                return (Set<OWLDataProperty>) datatype2Properties.get(XSD.BOOLEAN);
1045        }
1046
1047        @Override
1048        public Set<OWLDataProperty> getDoubleDatatypePropertiesImpl() {
1049                Set<OWLDataProperty> properties = new TreeSet<>();
1050                
1051                for (OWLDatatype dt:OWLAPIUtils.floatDatatypes) {
1052                        properties.addAll(datatype2Properties.get(dt));
1053                }
1054
1055                return properties;
1056        }
1057
1058        @Override
1059        public Set<OWLDataProperty> getIntDatatypePropertiesImpl() {
1060                Set<OWLDataProperty> properties = new TreeSet<>();
1061                
1062                for (OWLDatatype dt:OWLAPIUtils.intDatatypes) {
1063                        properties.addAll(datatype2Properties.get(dt));
1064                }
1065
1066                return properties;
1067        }
1068
1069        @Override
1070        public Set<OWLDataProperty> getStringDatatypePropertiesImpl() {
1071                return (Set<OWLDataProperty>) datatype2Properties.get(XSD.STRING);
1072        }
1073
1074        /* (non-Javadoc)
1075          * @see org.dllearner.core.Reasoner#getBaseURI()
1076          */
1077        @Override
1078        public String getBaseURI() {
1079                return baseURI;
1080        }
1081
1082    /* (non-Javadoc)
1083      * @see org.dllearner.core.Reasoner#getPrefixes()
1084      */
1085    @Override
1086    public Map<String, String> getPrefixes() {
1087        return prefixes;
1088    }
1089
1090    /* (non-Javadoc)
1091      * @see org.dllearner.core.ReasonerComponent#releaseKB()
1092      */
1093    @Override
1094    public void releaseKB() {
1095        reasoner.dispose();
1096    }
1097
1098//    public Set<OWLOntology> getOWLAPIOntologies() {
1099//        return owlAPIOntologies;
1100//    }
1101
1102    /*public void setReasonerType(String type){
1103         configurator.setReasonerType(type);
1104     }*/
1105
1106//      @Override
1107//      public boolean hasDatatypeSupport() {
1108//              return true;
1109//      }
1110
1111        @Override
1112        public Set<OWLClass> getInconsistentClassesImpl() {
1113                Set<OWLClass> unsatisfiableClasses;
1114
1115                try {
1116                        unsatisfiableClasses = reasoner.getUnsatisfiableClasses().getEntitiesMinusBottom();
1117                } catch (UnsupportedOperationException e) {
1118                        if (useFallbackReasoner) {
1119                                unsatisfiableClasses = fallbackReasoner.getUnsatisfiableClasses().getEntitiesMinusBottom();
1120                        } else {
1121                                throw e;
1122                        }
1123                }
1124
1125                return unsatisfiableClasses;
1126        }
1127
1128        public Set<OWLClass> getInconsistentOWLClasses() {
1129                Node<OWLClass> inconsClsNodes;
1130                try {
1131                        inconsClsNodes = reasoner.getUnsatisfiableClasses();
1132                } catch (UnsupportedOperationException e) {
1133                        if (useFallbackReasoner) {
1134                                inconsClsNodes = fallbackReasoner.getUnsatisfiableClasses();
1135                        } else {
1136                                throw e;
1137                        }
1138                }
1139                return inconsClsNodes.getEntities();
1140        }
1141
1142    @Override
1143    public Set<OWLLiteral> getLabelImpl(OWLEntity entity) {
1144        Collection<OWLAnnotation> labelAnnotations = EntitySearcher.getAnnotations(entity, ontology, df.getRDFSLabel());
1145        Set<OWLLiteral> annotations = new HashSet<>();
1146        for (OWLAnnotation label : labelAnnotations) {
1147            annotations.add((OWLLiteral) label.getValue());
1148        }
1149        return annotations;
1150    }
1151
1152        /*
1153         * (non-Javadoc)
1154         *
1155         * @see org.dllearner.core.BaseReasoner#remainsSatisfiable(org.dllearner.core.owl.Axiom)
1156         */
1157        @Override
1158        public boolean remainsSatisfiableImpl(OWLAxiom axiom) {
1159                boolean consistent;
1160
1161                manager.addAxiom(ontology, axiom);
1162
1163                try {
1164                        consistent = reasoner.isConsistent();
1165                } catch (UnsupportedOperationException e) {
1166                        if (useFallbackReasoner) {
1167                                consistent = fallbackReasoner.isConsistent();
1168                        } else {
1169                                throw e;
1170                        }
1171                }
1172
1173                manager.removeAxiom(ontology, axiom);
1174
1175                return consistent;
1176        }
1177
1178    /**
1179     * Returns asserted class definitions of given class
1180     *
1181     * @param cls the class
1182     * @return the asserted class definitions
1183     */
1184    @Override
1185    protected Set<OWLClassExpression> getAssertedDefinitionsImpl(OWLClass cls) {
1186        Collection<OWLClassExpression> definitions = EntitySearcher.getEquivalentClasses(cls, ontology);
1187        return new HashSet<>(definitions);
1188    }
1189
1190    /**
1191     * Gets the OWL API ontology manager. Use with great caution.
1192     *
1193     * @return The OWL API ontology manager.
1194     */
1195    public OWLOntologyManager getManager() {
1196        return manager;
1197    }
1198
1199    /**
1200     * Gets the internal OWL API ontology. Use with great caution.
1201     *
1202     * @return The internal OWL API ontology.
1203     */
1204    public OWLOntology getOntology() {
1205        return ontology;
1206    }
1207
1208    /**
1209     * Gets the internal OWL API reasoner. Use with great caution.
1210     *
1211     * @return The internal OWL API reasoner.
1212     */
1213    public OWLReasoner getReasoner() {
1214        return reasoner;
1215    }
1216
1217    /**
1218         * @param reasonerImplementation the reasonerImplementation to set
1219         */
1220        public void setReasonerImplementation(ReasonerImplementation reasonerImplementation) {
1221                this.reasonerImplementation = reasonerImplementation;
1222        }
1223
1224    public String getOwlLinkURL() {
1225        return owlLinkURL;
1226    }
1227
1228    /**
1229     * set the URL of the remote OWLLink server
1230     * @param owlLinkURL the URL of the remote OWLLink server
1231     */
1232    public void setOwlLinkURL(String owlLinkURL) {
1233        this.owlLinkURL = owlLinkURL;
1234    }
1235
1236    /**
1237     * Some reasoner implementations do not support all operations yet.
1238     * In that case a fallback reasoner based only on the asserted
1239     * axioms can be enabled.
1240         * @param useFallbackReasoner whether to enable a fallback reasoner
1241         */
1242        public void setUseFallbackReasoner(boolean useFallbackReasoner) {
1243                this.useFallbackReasoner = useFallbackReasoner;
1244        }
1245        
1246        @Override
1247        public OWLDatatype getDatatype(OWLDataProperty dp) {
1248                return dataproperty2datatype.get(dp);
1249        }
1250
1251        /* (non-Javadoc)
1252         * @see org.dllearner.core.AbstractReasonerComponent#setSynchronized()
1253         */
1254        @Override @NoConfigOption
1255        public void setSynchronized() {
1256                if(!(reasoner instanceof ThreadSafeOWLReasoner)) {
1257                        reasoner = new ThreadSafeOWLReasoner(reasoner);
1258                }
1259        }
1260
1261        public static void main(String[] args) throws Exception{
1262                OWLOntology o = OWLManager.createOWLOntologyManager().loadOntologyFromOntologyDocument(new File(System.getProperty("java.io.tmpdir") + File.separator + "test2.rdf"));
1263                System.out.println(o.getClassesInSignature());
1264                System.out.println(o.getDataPropertiesInSignature());
1265                System.out.println(o.getIndividualsInSignature().size());
1266        }
1267}