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.owlapiv3.XSD;
022import com.google.common.base.Joiner;
023import com.google.common.collect.HashMultimap;
024import com.google.common.collect.Multimap;
025import com.google.common.collect.Sets;
026import org.aksw.jena_sparql_api.core.QueryExecutionFactory;
027import org.aksw.jena_sparql_api.delay.core.QueryExecutionFactoryDelay;
028import org.aksw.jena_sparql_api.http.QueryExecutionFactoryHttp;
029import org.aksw.jena_sparql_api.model.QueryExecutionFactoryModel;
030import org.aksw.jena_sparql_api.pagination.core.QueryExecutionFactoryPaginated;
031import org.apache.commons.lang3.NotImplementedException;
032import org.apache.jena.query.*;
033import org.apache.jena.rdf.model.*;
034import org.apache.jena.riot.RDFDataMgr;
035import org.apache.jena.sparql.engine.http.QueryExceptionHTTP;
036import org.apache.jena.vocabulary.OWL;
037import org.apache.jena.vocabulary.OWL2;
038import org.apache.jena.vocabulary.RDF;
039import org.apache.jena.vocabulary.RDFS;
040import org.dllearner.core.*;
041import org.dllearner.core.annotations.NoConfigOption;
042import org.dllearner.core.config.ConfigOption;
043import org.dllearner.core.owl.ClassHierarchy;
044import org.dllearner.core.owl.DatatypePropertyHierarchy;
045import org.dllearner.core.owl.LazyClassHierarchy;
046import org.dllearner.core.owl.ObjectPropertyHierarchy;
047import org.dllearner.kb.LocalModelBasedSparqlEndpointKS;
048import org.dllearner.kb.OWLFile;
049import org.dllearner.kb.SparqlEndpointKS;
050import org.dllearner.kb.sparql.SPARQLQueryUtils;
051import org.dllearner.kb.sparql.SparqlEndpoint;
052import org.dllearner.utilities.OWLAPIUtils;
053import org.dllearner.utilities.OwlApiJenaUtils;
054import org.dllearner.utilities.datastructures.SortedSetTuple;
055import org.dllearner.utilities.owl.OWLClassExpressionToSPARQLConverter;
056import org.jetbrains.annotations.NotNull;
057import org.semanticweb.owlapi.model.*;
058import org.semanticweb.owlapi.util.OWLObjectDuplicator;
059import org.semanticweb.owlapi.vocab.OWL2Datatype;
060import org.semanticweb.owlapi.vocab.XSDVocabulary;
061import org.slf4j.Logger;
062import org.slf4j.LoggerFactory;
063import org.slf4j.Marker;
064import org.slf4j.helpers.BasicMarkerFactory;
065import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
066
067import java.util.*;
068import java.util.Map.Entry;
069import java.util.concurrent.TimeUnit;
070import java.util.stream.Collectors;
071import java.util.stream.StreamSupport;
072
073/**
074 * A reasoner implementation that provides inference services by the execution
075 * of SPARQL queries on
076 * <ul>
077 * <li> local files (usually in forms of JENA API models)</li>
078 * <li> remote SPARQL endpoints </li>
079 * </ul>
080 * <p>
081 * Compared to other reasoner implementations, it doesn't do any pre-computation
082 * by default because it might be too expensive on very large knowledge bases.
083 * </p>
084 * @author Lorenz Buehmann
085 *
086 */
087@ComponentAnn(name = "SPARQL Reasoner", shortName = "spr", version = 0.1)
088public class SPARQLReasoner extends AbstractReasonerComponent implements SchemaReasoner, IndividualReasoner {
089
090        private static final Logger logger = LoggerFactory.getLogger(SPARQLReasoner.class);
091        private final static Marker sparql_debug = new BasicMarkerFactory().getMarker("SD");
092
093        public enum PopularityType {
094                CLASS, OBJECT_PROPERTY, DATA_PROPERTY
095        }
096        
097        private static final ParameterizedSparqlString CLASS_POPULARITY_QUERY = new ParameterizedSparqlString(
098                        "SELECT (COUNT(*) AS ?cnt) WHERE {?s a ?entity .}");
099        
100        private static final ParameterizedSparqlString PROPERTY_POPULARITY_QUERY = new ParameterizedSparqlString(
101                        "SELECT (COUNT(*) AS ?cnt) WHERE {?s ?entity ?o .}");
102        
103        private static final ParameterizedSparqlString INDIVIDUAL_POPULARITY_QUERY = new ParameterizedSparqlString(
104                        "SELECT (COUNT(*) AS ?cnt) WHERE {?entity ?p ?o .}");
105
106        @ConfigOption(description = "Use alternative relaxed Sparql-queries for Classes and Individuals", defaultValue = "false")
107        private boolean laxMode = false;
108
109        @ConfigOption(description = "Whether to use the generic facet generation code, which requires downloading all instances and is thus not recommended", defaultValue = "false")
110        private boolean useGenericSplitsCode = false;
111        
112        @ConfigOption(description = "Whether to use SPARQL1.1 Value Lists", defaultValue = "false")
113        private boolean useValueLists = false;
114
115        @ConfigOption(defaultValue = "true", description = "Prefer ASK queries when there is a choice in implementation", required = false)
116        private boolean preferAsk = true;
117
118        private QueryExecutionFactory qef;
119
120        private SparqlEndpointKS ks;
121        private ClassHierarchy hierarchy;
122
123        private Map<OWLEntity, Integer> entityPopularityMap = new HashMap<>();
124        private Map<OWLClass, Integer> classPopularityMap = new HashMap<>();
125        private boolean batchedMode = true;
126        private Set<PopularityType> precomputedPopularityTypes = new HashSet<>();
127        
128        private boolean prepared = false;
129        
130        protected OWLClassExpressionToSPARQLConverter converter = new OWLClassExpressionToSPARQLConverter();
131
132        private OWLDataFactory df = new OWLDataFactoryImpl();
133        private OWLObjectDuplicator duplicator = new OWLObjectDuplicator(df);
134
135        /**
136         * Default constructor for usage of config files + Spring API.
137         */
138        public SPARQLReasoner() {
139                setPrecomputeClassHierarchy(false);
140                setPrecomputeObjectPropertyHierarchy(false);
141                setPrecomputeDataPropertyHierarchy(false);
142        }
143
144        public SPARQLReasoner(SparqlEndpointKS ks) {
145                super(ks);
146                this.qef = ks.getQueryExecutionFactory();
147        }
148        
149        public SPARQLReasoner(SparqlEndpoint endpoint) {
150                this(new QueryExecutionFactoryHttp(endpoint.getURL().toString(), endpoint.getDefaultGraphURIs()));
151        }
152
153        public SPARQLReasoner(Model model) {
154                this(new QueryExecutionFactoryModel(model));
155        }
156        
157        public SPARQLReasoner(QueryExecutionFactory qef) {
158                this();
159                this.qef = qef;
160        }
161        
162        /* (non-Javadoc)
163         * @see org.dllearner.core.Component#init()
164         */
165        @Override
166        public void init() throws ComponentInitException {
167                classPopularityMap = new HashMap<>();
168
169                // this is only done if the reasoner is setup via config file
170                if(qef == null) {
171                        if(ks == null) {
172                                KnowledgeSource abstract_ks = sources.iterator().next();
173                                if (SparqlEndpointKS.class.isAssignableFrom(abstract_ks.getClass())) {
174                                        ks = (SparqlEndpointKS) abstract_ks;
175                                } else {
176                                        OWLFile owl_file = (OWLFile) abstract_ks;
177                                        Model model = RDFDataMgr.loadModel(owl_file.getURL().getFile());
178                                        logger.debug(sparql_debug, "file reasoning: " + ((owl_file.getReasoning() == null || owl_file.getReasoning().getReasonerFactory() == null) ? "(none)"
179                                                        : owl_file.getReasoning().getReasonerFactory().getURI()));
180                                        ks = new LocalModelBasedSparqlEndpointKS(model, owl_file.getReasoning());
181                                }
182                                if (sources.size() > 1) {
183                                        throw new ComponentInitException("SPARQLReasoner only supports a single knowledge source");
184                                }
185                        }
186                        if(ks.isRemote()){
187                                qef = ks.getQueryExecutionFactory();
188                                qef = new QueryExecutionFactoryDelay(qef, 50);
189//                              qef = new QueryExecutionFactoryCacheEx(qef, cache);
190                                qef = new QueryExecutionFactoryPaginated(qef, 10000);
191                        } else {
192                                qef = new QueryExecutionFactoryModel(((LocalModelBasedSparqlEndpointKS)ks).getModel());
193                        }
194                }
195                
196                initialized = true;
197        }
198        
199        public QueryExecutionFactory getQueryExecutionFactory() {
200                return qef;
201        }
202        
203        public void precomputePopularities(PopularityType... popularityTypes){
204                for (PopularityType popularityType : popularityTypes) {
205                        switch (popularityType) {
206                        case CLASS:precomputeClassPopularity();break;
207                        case OBJECT_PROPERTY:precomputeObjectPropertyPopularity();break;
208                        case DATA_PROPERTY:precomputeDataPropertyPopularity();break;
209                        default:
210                                break;
211                        }
212                }
213        }
214
215        public void precomputePropertyDomains() {
216                logger.info("precomputing property domains...");
217                String query = SPARQLQueryUtils.PREFIXES +
218                                " SELECT * WHERE {?p rdfs:domain ?dom {?p a owl:ObjectProperty} UNION {?p a owl:DatatypeProperty}}";
219
220                try {
221                        ResultSet rs = executeSelectQuery(query);
222
223                        while(rs.hasNext()) {
224                                QuerySolution qs = rs.next();
225                                OWLObjectProperty p = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
226                                OWLClass dom = df.getOWLClass(IRI.create(qs.getResource("dom").getURI()));
227
228                                propertyDomains.put(p, dom);
229                        }
230                } catch (Exception e) {
231                        logger.error("Failed to compute property domains.", e);
232                }
233                logger.info("finished precomputing property domains.");
234        }
235
236        public void precomputeObjectPropertyRanges() {
237                logger.info("precomputing object property ranges...");
238                String query = SPARQLQueryUtils.PREFIXES +
239                                " SELECT * WHERE {?p rdfs:range ?ran; a owl:ObjectProperty }";
240
241                try {
242                        ResultSet rs = executeSelectQuery(query);
243
244                        while(rs.hasNext()) {
245                                QuerySolution qs = rs.next();
246                                OWLObjectProperty p = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
247                                OWLClass dom = df.getOWLClass(IRI.create(qs.getResource("ran").getURI()));
248
249                                objectPropertyRanges.put(p, dom);
250                        }
251                } catch (Exception e) {
252                        logger.error("Failed to compute property domains.", e);
253                }
254                logger.info("finished precomputing property domains.");
255        }
256
257        public void precomputePopularity(){
258                precomputeClassPopularity();
259                precomputeDataPropertyPopularity();
260                precomputeObjectPropertyPopularity();
261        }
262        
263        public boolean isPrecomputed(PopularityType popularityType){
264                return precomputedPopularityTypes.contains(popularityType);
265        }
266
267        public void precomputeClassPopularity() {
268                if(isPrecomputed(PopularityType.CLASS)){
269                        return;
270                }
271                logger.info("Precomputing class popularity ...");
272
273                long start = System.currentTimeMillis();
274                
275                if (batchedMode) {
276                        String query = "PREFIX owl:<http://www.w3.org/2002/07/owl#>  SELECT ?type (COUNT(?s) AS ?cnt) WHERE {?s a ?type . ?type a owl:Class .} GROUP BY ?type";
277                        ResultSet rs = executeSelectQuery(query);
278                        while (rs.hasNext()) {
279                                QuerySolution qs = rs.next();
280                                if (qs.get("type").isURIResource()) {
281                                        OWLClass cls = df.getOWLClass(IRI.create(qs.getResource("type").getURI()));
282                                        int cnt = qs.getLiteral("cnt").getInt();
283                                        classPopularityMap.put(cls, cnt);
284                                }
285                        }
286                } else {
287                        Set<OWLClass> classes = getOWLClasses();
288                        String queryTemplate = "SELECT (COUNT(?s) AS ?cnt) WHERE {?s a <%s>}";
289                        for (OWLClass cls : classes) {
290                                ResultSet rs = executeSelectQuery(String.format(queryTemplate, cls.toStringID()));
291                                int cnt = rs.next().getLiteral("cnt").getInt();
292                                classPopularityMap.put(cls, cnt);
293                        }
294                }
295                precomputedPopularityTypes.add(PopularityType.CLASS);
296                
297                long end = System.currentTimeMillis();
298                
299                logger.info("... done in " + (end - start) + "ms.");
300        }
301
302        public void precomputeObjectPropertyPopularity(){
303                if(isPrecomputed(PopularityType.OBJECT_PROPERTY)){
304                        return;
305                }
306                logger.info("Precomputing object property popularity ...");
307
308                long start = System.currentTimeMillis();
309                
310                if (batchedMode) {
311                        String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#> SELECT ?p (COUNT(*) AS ?cnt) WHERE {?s ?p ?o . ?p a owl:ObjectProperty .} GROUP BY ?p";
312                        ResultSet rs = executeSelectQuery(query);
313                        while (rs.hasNext()) {
314                                QuerySolution qs = rs.next();
315                                if (qs.get("p").isURIResource()) {
316                                        OWLObjectProperty property = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
317                                        int cnt = qs.getLiteral("cnt").getInt();
318                                        entityPopularityMap.put(property, cnt);
319                                }
320                        }
321                } else {
322                        Set<OWLObjectProperty> properties = getOWLObjectProperties();
323                        String queryTemplate = "SELECT (COUNT(*) AS ?cnt) WHERE {?s <%s> ?o}";
324                        for (OWLObjectProperty property : properties) {
325                                ResultSet rs = executeSelectQuery(String.format(queryTemplate, property.toStringID()));
326                                int cnt = rs.next().getLiteral("cnt").getInt();
327                                entityPopularityMap.put(property, cnt);
328                        }
329                }
330                precomputedPopularityTypes.add(PopularityType.OBJECT_PROPERTY);
331                
332                long end = System.currentTimeMillis();
333                
334                logger.info("... done in " + (end - start) + "ms.");
335        }
336
337        public void precomputeDataPropertyPopularity(){
338                if(isPrecomputed(PopularityType.DATA_PROPERTY)){
339                        return;
340                }
341                logger.info("Precomputing data property popularity ...");
342
343                long start = System.currentTimeMillis();
344                
345                if (batchedMode) {
346                        String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#> SELECT ?p (COUNT(*) AS ?cnt) WHERE {?s ?p ?o . ?p a owl:DatatypeProperty .} GROUP BY ?p";
347                        ResultSet rs = executeSelectQuery(query);
348                        while (rs.hasNext()) {
349                                QuerySolution qs = rs.next();
350                                if (qs.get("p").isURIResource()) {
351                                        OWLDataProperty property = df.getOWLDataProperty(IRI.create(qs.getResource("p").getURI()));
352                                        int cnt = qs.getLiteral("cnt").getInt();
353                                        entityPopularityMap.put(property, cnt);
354                                }
355                        }
356                } else {
357                        Set<OWLDataProperty> properties = getOWLDataProperties();
358                        String queryTemplate = "SELECT (COUNT(*) AS ?cnt) WHERE {?s <%s> ?o}";
359                        for (OWLDataProperty property : properties) {
360                                ResultSet rs = executeSelectQuery(String.format(queryTemplate, property.toStringID()));
361                                int cnt = rs.next().getLiteral("cnt").getInt();
362                                entityPopularityMap.put(property, cnt);
363                        }
364                }
365                precomputedPopularityTypes.add(PopularityType.DATA_PROPERTY);
366                
367                long end = System.currentTimeMillis();
368                
369                logger.info("... done in " + (end - start) + "ms.");
370        }
371
372        public int getSubjectCountForProperty(OWLProperty p, long timeout, TimeUnit timeoutUnits){
373                int cnt = -1;
374                String query = String.format(
375                                "SELECT (COUNT(DISTINCT ?s) AS ?cnt) WHERE {?s <%s> ?o.}",
376                                p.toStringID());
377                ResultSet rs = executeSelectQuery(query, timeout, timeoutUnits);
378                if(rs.hasNext()){
379                        cnt = rs.next().getLiteral("cnt").getInt();
380                }
381
382                return cnt;
383        }
384        
385        public int getSubjectCountForProperty(OWLProperty p){
386                int cnt = -1;
387                String query = String.format(
388                                "SELECT (COUNT(DISTINCT ?s) AS ?cnt) WHERE {?s <%s> ?o.}",
389                                p.toStringID());
390                ResultSet rs = executeSelectQuery(query);
391                if(rs.hasNext()){
392                        cnt = rs.next().getLiteral("cnt").getInt();
393                }
394
395                return cnt;
396        }
397
398        public int getObjectCountForProperty(OWLObjectProperty p, long timeout, TimeUnit timeoutUnits){
399                int cnt = -1;
400                String query = String.format(
401                                "SELECT (COUNT(DISTINCT ?o) AS ?cnt) WHERE {?s <%s> ?o.}",
402                                p.toStringID());
403                ResultSet rs = executeSelectQuery(query, timeout, timeoutUnits);
404                if(rs.hasNext()){
405                        cnt = rs.next().getLiteral("cnt").getInt();
406                }
407
408                return cnt;
409        }
410        
411        public int getObjectCountForProperty(OWLObjectProperty p){
412                int cnt = -1;
413                String query = String.format(
414                                "SELECT (COUNT(DISTINCT ?o) AS ?cnt) WHERE {?s <%s> ?o.}",
415                                p.toStringID());
416                ResultSet rs = executeSelectQuery(query);
417                if(rs.hasNext()){
418                        cnt = rs.next().getLiteral("cnt").getInt();
419                }
420
421                return cnt;
422        }
423
424        /**
425         * Computes the popularity of the given entity.
426         * @param entity the entity
427         * @param <T> the OWL entity type
428         * @return the popularity
429         */
430        public <T extends OWLEntity> int getPopularity(T entity){
431                // check if we have the value cached
432                Integer popularity = entityPopularityMap.get(entity);
433
434                // compute the value if not cached
435                if(popularity == null){
436                        ParameterizedSparqlString queryTemplate;
437                        if(entity.isOWLClass()){
438                                queryTemplate = CLASS_POPULARITY_QUERY;
439                        } else if(entity.isOWLObjectProperty() || entity.isOWLDataProperty()){
440                                queryTemplate = PROPERTY_POPULARITY_QUERY;
441                        } else if(entity.isOWLNamedIndividual()){
442                                queryTemplate = INDIVIDUAL_POPULARITY_QUERY;
443                        } else {
444                                throw new IllegalArgumentException("Popularity computation not supported for entity type " + entity.getEntityType().getName());
445                        }
446
447                        queryTemplate.setIri("entity", entity.toStringID());
448                        ResultSet rs = executeSelectQuery(queryTemplate.toString());
449                        
450                        popularity = rs.next().getLiteral("cnt").getInt();
451
452                        // put to cache
453                        entityPopularityMap.put(entity, popularity);
454                }
455                return popularity;
456        }
457
458        
459        
460        public int getPopularityOf(OWLClassExpression description){
461                if(classPopularityMap != null && classPopularityMap.containsKey(description)){
462                        return classPopularityMap.get(description);
463                } else {
464                        String query = converter.asCountQuery(description).toString();
465                        ResultSet rs = executeSelectQuery(query);
466                        int cnt = rs.next().getLiteral("cnt").getInt();
467                        return cnt;
468                }
469        }
470
471        @Override
472        public ClassHierarchy prepareSubsumptionHierarchy() {
473                if(precomputeClassHierarchy) {
474                        if(!prepared){
475                                hierarchy = prepareSubsumptionHierarchyFast();
476
477                                prepared = true;
478                        }
479                } else {
480                        hierarchy = new LazyClassHierarchy(this);
481                }
482                return hierarchy;
483        }
484        
485        public boolean isFunctional(OWLObjectProperty property){
486                String query = "ASK {<" + property.toStringID() + "> a <" + OWL.FunctionalProperty.getURI() + ">}";
487                return executeAskQuery(query);
488        }
489        
490        public boolean isInverseFunctional(OWLObjectProperty property){
491                String query = "ASK {<" + property.toStringID() + "> a <" + OWL.InverseFunctionalProperty.getURI() + ">}";
492                return executeAskQuery(query);
493        }
494        
495        public boolean isAsymmetric(OWLObjectProperty property){
496                String query = "ASK {<" + property.toStringID() + "> a <" + OWL2.AsymmetricProperty.getURI() + ">}";
497                return executeAskQuery(query);
498        }
499        
500        public boolean isSymmetric(OWLObjectProperty property){
501                String query = "ASK {<" + property.toStringID() + "> a <" + OWL2.SymmetricProperty.getURI() + ">}";
502                return executeAskQuery(query);
503        }
504        
505        public boolean isIrreflexive(OWLObjectProperty property){
506                String query = "ASK {<" + property.toStringID() + "> a <" + OWL2.IrreflexiveProperty.getURI() + ">}";
507                return executeAskQuery(query);
508        }
509        
510        public boolean isReflexive(OWLObjectProperty property){
511                String query = "ASK {<" + property.toStringID() + "> a <" + OWL2.ReflexiveProperty.getURI() + ">}";
512                return executeAskQuery(query);
513        }
514        
515        public boolean isTransitive(OWLObjectProperty property){
516                String query = "ASK {<" + property.toStringID() + "> a <" + OWL2.TransitiveProperty.getURI() + ">}";
517                return executeAskQuery(query);
518        }
519        
520        public boolean isFunctional(OWLDataProperty property){
521                String query = "ASK {<" + property.toStringID() + "> a <" + OWL.FunctionalProperty.getURI() + ">}";
522                return executeAskQuery(query);
523        }
524
525        // we have this variable so that the query can be overwritten in subclasses (for workarounds)
526        protected String buildSubsumptionHierarchyQuery() {
527                return "SELECT * WHERE {"
528                                + " ?sub a <http://www.w3.org/2002/07/owl#Class> . "
529                                + " OPTIONAL { "
530                                + "?sub (<http://www.w3.org/2000/01/rdf-schema#subClassOf>|<http://www.w3.org/2002/07/owl#equivalentClass>) ?sup ."
531                                + "} \n"
532                                + "}";
533        }
534
535        /**
536         * Pre-computes the class hierarchy. Instead of executing queries for each class,
537         * we query by the predicate rdfs:subClassOf.
538         * @return the class hierarchy
539         */
540        public ClassHierarchy prepareSubsumptionHierarchyFast() {
541                logger.info("Preparing class subsumption hierarchy ...");
542                long startTime = System.currentTimeMillis();
543                TreeMap<OWLClassExpression, SortedSet<OWLClassExpression>> subsumptionHierarchyUp = new TreeMap<>();
544                TreeMap<OWLClassExpression, SortedSet<OWLClassExpression>> subsumptionHierarchyDown = new TreeMap<>();
545
546                ResultSet rs = executeSelectQuery(buildSubsumptionHierarchyQuery());
547        
548                while (rs.hasNext()) {
549                        QuerySolution qs = rs.next();
550                        if (qs.get("sub").isURIResource() && (qs.get("sup") == null || qs.get("sup").isURIResource())) {
551                                OWLClass sub = df.getOWLClass(IRI.create(qs.get("sub").asResource().getURI()));
552                                OWLClass sup = qs.get("sup") == null ? df.getOWLThing()
553                                                : df.getOWLClass(IRI.create(qs.get("sup").asResource().getURI()));
554                                
555                                // add subclass
556                                subsumptionHierarchyDown
557                                                .computeIfAbsent(sup, k -> new TreeSet<>())
558                                                .add(sub);
559
560                                // add superclass
561                                subsumptionHierarchyUp
562                                                .computeIfAbsent(sub, k -> new TreeSet<>())
563                                                .add(sup);
564                        }
565                }
566                
567                logger.info("... done in {}ms", (System.currentTimeMillis()-startTime));
568                hierarchy = new ClassHierarchy(subsumptionHierarchyUp, subsumptionHierarchyDown);
569                
570                return hierarchy;
571        }
572        
573        /* (non-Javadoc)
574         * @see org.dllearner.core.AbstractReasonerComponent#prepareObjectPropertyHierarchy()
575         */
576        @Override
577        public ObjectPropertyHierarchy prepareObjectPropertyHierarchy() throws ReasoningMethodUnsupportedException {
578//              if(precomputeObjectPropertyHierarchy) {
579                        logger.info("Preparing object property subsumption hierarchy ...");
580                        long startTime = System.currentTimeMillis();
581                        TreeMap<OWLObjectProperty, SortedSet<OWLObjectProperty>> subsumptionHierarchyUp = new TreeMap<>(
582                        );
583                        TreeMap<OWLObjectProperty, SortedSet<OWLObjectProperty>> subsumptionHierarchyDown = new TreeMap<>(
584                        );
585        
586                        String query = "SELECT * WHERE {"
587                                        + "?sub a <http://www.w3.org/2002/07/owl#ObjectProperty> . "
588                                        + "FILTER NOT EXISTS{?sub a <http://www.w3.org/2002/07/owl#DatatypeProperty>}" // TODO remove workaround
589                                        + "FILTER(?sub != <http://www.w3.org/2002/07/owl#bottomObjectProperty> && ?sub != <http://www.w3.org/2002/07/owl#topObjectProperty>)"
590                                        + "OPTIONAL {"
591                                        + "?sub <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?sup ."
592                                        + "?sup a <http://www.w3.org/2002/07/owl#ObjectProperty> . "
593                                        + "FILTER(?sup != ?sub && ?sup != <http://www.w3.org/2002/07/owl#topObjectProperty>)"
594                                        + "}"
595                                        + "}";
596                        ResultSet rs = executeSelectQuery(query);
597
598                        while (rs.hasNext()) {
599                                QuerySolution qs = rs.next();
600                                if (qs.get("sub").isURIResource()) {
601                                        IRI iri = IRI.create(qs.get("sub").asResource().getURI());
602
603                                        if(!iri.isReservedVocabulary()) {
604                                                OWLObjectProperty sub = df.getOWLObjectProperty(iri);
605
606                                                // add sub properties entry
607                                                subsumptionHierarchyDown.putIfAbsent(sub, new TreeSet<>());
608                                                
609                                                // add super properties entry
610                                                subsumptionHierarchyUp.putIfAbsent(sub, new TreeSet<>());
611                                                
612                                                // if there is a super property
613                                                if(qs.get("sup") != null && qs.get("sup").isURIResource()){
614                                                        OWLObjectProperty sup = df.getOWLObjectProperty(IRI.create(qs.get("sup").asResource().getURI()));
615
616                                                        // add sub properties entry
617                                                        subsumptionHierarchyDown.putIfAbsent(sup, new TreeSet<>());
618                                                        
619                                                        // add super properties entry
620                                                        subsumptionHierarchyUp.putIfAbsent(sup, new TreeSet<>());
621                                                        
622                                                        // add super properties entry
623                                                        subsumptionHierarchyUp
624                                                                        .computeIfAbsent(sub, k -> new TreeSet<>())
625                                                                        .add(sup);
626                                                        
627                                                        // add sub properties entry
628                                                        subsumptionHierarchyDown
629                                                                        .computeIfAbsent(sup, k -> new TreeSet<>())
630                                                                        .add(sub);
631                                                }
632                                        }
633                                }
634                        }
635                        logger.info("... done in {}ms", (System.currentTimeMillis()-startTime));
636                        roleHierarchy = new ObjectPropertyHierarchy(subsumptionHierarchyUp, subsumptionHierarchyDown);
637//              }
638                return roleHierarchy;
639        }
640        
641        /* (non-Javadoc)
642         * @see org.dllearner.core.AbstractReasonerComponent#prepareObjectPropertyHierarchy()
643         */
644        @Override
645        public DatatypePropertyHierarchy prepareDatatypePropertyHierarchy() throws ReasoningMethodUnsupportedException {
646                logger.info("Preparing data property subsumption hierarchy ...");
647                long startTime = System.currentTimeMillis();
648                TreeMap<OWLDataProperty, SortedSet<OWLDataProperty>> subsumptionHierarchyUp = new TreeMap<>(
649                );
650                TreeMap<OWLDataProperty, SortedSet<OWLDataProperty>> subsumptionHierarchyDown = new TreeMap<>(
651                );
652
653                String query = "SELECT * WHERE {"
654                                + "?sub a <http://www.w3.org/2002/07/owl#DatatypeProperty> . "
655                                + "OPTIONAL {"
656                                + "?sub <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?sup ."
657                                + "?sup a <http://www.w3.org/2002/07/owl#DatatypeProperty> . "
658                                + "FILTER(?sup != ?sub && ?sup != <http://www.w3.org/2002/07/owl#topDatatypeProperty> )"
659                                + "}"
660                                + "FILTER(?sub != <http://www.w3.org/2002/07/owl#topDatatypeProperty> && ?sub != <http://www.w3.org/2002/07/owl#bottomDatatypeProperty>)"
661                                + "}";
662                ResultSet rs = executeSelectQuery(query);
663
664                while (rs.hasNext()) {
665                        QuerySolution qs = rs.next();
666                        if (qs.get("sub").isURIResource()) {
667                                OWLDataProperty sub = df.getOWLDataProperty(IRI.create(qs.get("sub").asResource().getURI()));
668
669                                // add sub properties entry
670                                subsumptionHierarchyDown.putIfAbsent(sub, new TreeSet<>());
671
672                                // add super properties entry
673                                subsumptionHierarchyUp.putIfAbsent(sub, new TreeSet<>());
674                                
675                                // if there is a super property
676                                if(qs.get("sup") != null && qs.get("sup").isURIResource()){
677                                        OWLDataProperty sup = df.getOWLDataProperty(IRI.create(qs.get("sup").asResource().getURI()));
678
679                                        // add sub properties entry
680                                        subsumptionHierarchyDown.putIfAbsent(sup, new TreeSet<>());
681                                        
682                                        // add super properties entry
683                                        subsumptionHierarchyUp.putIfAbsent(sup, new TreeSet<>());
684                                        
685                                        // add super properties entry
686                                        subsumptionHierarchyUp
687                                                        .computeIfAbsent(sub, k -> new TreeSet<>())
688                                                        .add(sup);
689                                        
690                                        // add sub properties entry
691                                        subsumptionHierarchyDown
692                                                        .computeIfAbsent(sup, k -> new TreeSet<>())
693                                                        .add(sub);
694                                }
695                        }
696                }
697
698                logger.info("... done in {}ms", (System.currentTimeMillis()-startTime));
699                datatypePropertyHierarchy = new DatatypePropertyHierarchy(subsumptionHierarchyUp, subsumptionHierarchyDown);
700                return datatypePropertyHierarchy;
701        }
702
703        public Model loadSchema(){
704                return loadSchema(null);
705        }
706        
707        public Model loadSchema(String namespace){
708                Model model = ModelFactory.createDefaultModel();
709
710                //load class hierarchy
711                String query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?o} WHERE " +
712                                "{?s <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?o." + (namespace != null ? "FILTER(REGEX(STR(?s), '^" + namespace + "'))}" : "");
713                model.add(loadIncrementally(query));
714                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#equivalentClass> ?o} WHERE {?s <http://www.w3.org/2002/07/owl#equivalentClass> ?o}";
715                model.add(loadIncrementally(query));
716                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#disjointWith> ?o} WHERE {?s <http://www.w3.org/2002/07/owl#disjointWith> ?o}";
717                model.add(loadIncrementally(query));
718                //load domain axioms
719                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#domain> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty> } " +
720                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#domain> ?o.?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}";
721                model.add(loadIncrementally(query));
722                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#domain> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} " +
723                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#domain> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}";
724                model.add(loadIncrementally(query));
725                //load range axioms
726                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#range> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} " +
727                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#range> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}";
728                model.add(loadIncrementally(query));
729                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#range> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} " +
730                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#range> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}";
731                model.add(loadIncrementally(query));
732                //load property hierarchy
733                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} " +
734                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}";
735                model.add(loadIncrementally(query));
736                query = "CONSTRUCT {?s <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} " +
737                                "WHERE {?s <http://www.w3.org/2000/01/rdf-schema#subPropertyOf> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}";
738                model.add(loadIncrementally(query));
739                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#equivalentProperty> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} " +
740                                "WHERE {?s <http://www.w3.org/2002/07/owl#equivalentProperty> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}";
741                model.add(loadIncrementally(query));
742                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#equivalentProperty> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} " +
743                                "WHERE {?s <http://www.w3.org/2002/07/owl#equivalentProperty> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}";
744                model.add(loadIncrementally(query));
745                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#propertyDisjointWith> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} " +
746                                "WHERE {?s <http://www.w3.org/2002/07/owl#propertyDisjointWith> ?o. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}";
747                model.add(loadIncrementally(query));
748                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#propertyDisjointWith> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} " +
749                                "WHERE {?s <http://www.w3.org/2002/07/owl#propertyDisjointWith> ?o. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}";
750                model.add(loadIncrementally(query));
751                //load inverse relation
752                query = "CONSTRUCT {?s <http://www.w3.org/2002/07/owl#inverseOf> ?o} WHERE {?s <http://www.w3.org/2002/07/owl#inverseOf> ?o}";
753                model.add(loadIncrementally(query));
754                //load property characteristics
755                Set<Resource> propertyCharacteristics = new HashSet<>();
756                //              propertyCharacteristics.add(OWL.FunctionalProperty);
757                propertyCharacteristics.add(OWL.InverseFunctionalProperty);
758                propertyCharacteristics.add(OWL.SymmetricProperty);
759                propertyCharacteristics.add(OWL.TransitiveProperty);
760                propertyCharacteristics.add(OWL2.ReflexiveProperty);
761                propertyCharacteristics.add(OWL2.IrreflexiveProperty);
762                propertyCharacteristics.add(OWL2.AsymmetricProperty);
763
764                for(Resource propChar : propertyCharacteristics){
765                        query = "CONSTRUCT {?s a <%s>. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} WHERE {?s a <%s>.}".replaceAll("%s", propChar.getURI());
766                        model.add(loadIncrementally(query));
767                }
768                //for functional properties we have to distinguish between data and object properties,
769                //i.e. we have to keep the property type information, otherwise conversion to OWLAPI ontology makes something curious
770                query = "CONSTRUCT {?s a <%s>. ?s a <http://www.w3.org/2002/07/owl#ObjectProperty>} WHERE {?s a <%s>.?s a <http://www.w3.org/2002/07/owl#ObjectProperty>}".
771                                replaceAll("%s", OWL.FunctionalProperty.getURI());
772                model.add(loadIncrementally(query));
773                query = "CONSTRUCT {?s a <%s>. ?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>} WHERE {?s a <%s>.?s a <http://www.w3.org/2002/07/owl#DatatypeProperty>}".
774                                replaceAll("%s", OWL.FunctionalProperty.getURI());
775                model.add(loadIncrementally(query));
776
777                return model;
778        }
779        
780        /**
781         * Gets all logical axioms according to entities of type owl:Class, owl:ObjectProperty and owl:DatatypeProperty.
782         * @return the OWL schema as Jena model
783         */
784        public Model loadOWLSchema(){
785                Model schema = ModelFactory.createDefaultModel();
786                String prefixes =
787                                "PREFIX owl:<http://www.w3.org/2002/07/owl#> "
788                                + "PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> ";
789                
790                // axioms related to owl:Class entities
791                String query = prefixes +
792                                "CONSTRUCT {" +
793                                "?s a owl:Class." +
794                                "?s rdfs:subClassOf ?sup." +
795                                "?s owl:equivalentClass ?equiv." +
796                                "?s owl:disjointWith ?disj." +
797                                "} WHERE {" +
798                                "?s a owl:Class. " +
799                                "OPTIONAL{?s rdfs:subClassOf ?sup.} " +
800                                "OPTIONAL{?s owl:equivalentClass ?equiv.} " +
801                                "OPTIONAL{?s owl:disjointWith ?disj.}" +
802                                "}";
803                schema.add(loadIncrementally(query));
804                
805                // axioms related to owl:ObjectProperty entities
806                query = prefixes +
807                                "CONSTRUCT {" +
808                                "?s a owl:ObjectProperty." +
809                                "?s a ?type." +
810                                "?s rdfs:domain ?domain." +
811                                "?s rdfs:range ?range." +
812                                "} WHERE {" +
813                                "?s a owl:ObjectProperty." +
814                                "?s a ?type. " +
815                                "OPTIONAL{?s rdfs:domain ?domain.} " +
816                                "OPTIONAL{?s rdfs:range ?range.}" +
817                                "}";
818                schema.add(loadIncrementally(query));
819
820                // axioms related to owl:DatatypeProperty entities
821                query = prefixes +
822                                "CONSTRUCT {" +
823                                "?s a owl:DatatypeProperty." +
824                                "?s a ?type." +
825                                "?s rdfs:domain ?domain." +
826                                "?s rdfs:range ?range." +
827                                "} WHERE {" +
828                                "?s a owl:DatatypeProperty." +
829                                "?s a ?type. " +
830                                "OPTIONAL{?s rdfs:domain ?domain.} " +
831                                "OPTIONAL{?s rdfs:range ?range.}" +
832                                "}";
833                schema.add(loadIncrementally(query));
834                
835                return schema;
836        }
837
838        private Model loadIncrementally(String query){
839                QueryExecutionFactory old = qef;
840                qef = new QueryExecutionFactoryPaginated(qef, 10000);
841                QueryExecution qe = qef.createQueryExecution(query);
842                if (logger.isTraceEnabled()) logger.trace("Sending query \n {}", query);
843                Model model = qe.execConstruct();
844                qe.close();
845                qef = old;
846                return model;
847        }
848
849        @Override
850        public Set<OWLClass> getTypesImpl(OWLIndividual individual) {
851                String query = String.format(SPARQLQueryUtils.SELECT_INSTANCE_TYPES_QUERY, individual.toStringID());
852                ResultSet rs = executeSelectQuery(query);
853                SortedSet<OWLClass> types = asOWLEntities(EntityType.CLASS, rs, "var1");
854                return types;
855        }
856        
857        public Set<OWLClass> getTypes(OWLIndividual individual, String namespace) {
858                return getTypes(individual);
859        }
860        
861        public Set<OWLClass> getMostSpecificTypes(OWLIndividual individual) {
862                Set<OWLClass> types = new HashSet<>();
863                String query = String.format(
864                                "SELECT ?type WHERE {<%s> a ?type ."
865                                + "FILTER NOT EXISTS{<%s> a ?moreSpecificType ."
866                                + "?moreSpecificType <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?type ."
867                                + "FILTER((?type != ?moreSpecificType) && (?moreSpecificType!= <http://www.w3.org/2002/07/owl#Nothing>))}}",
868                                individual.toStringID(), individual.toStringID());
869                ResultSet rs = executeSelectQuery(query);
870                while(rs.hasNext()){
871                        QuerySolution qs = rs.next();
872                        IRI iri = IRI.create(qs.getResource("type").getURI());
873                        if(!iri.isReservedVocabulary()) {
874                                types.add(df.getOWLClass(iri));
875                        }
876                        
877                }
878                return types;
879        }
880        
881        
882        /**
883         * Returns the entity type of the given resource IRI, i.e. whether the resource
884         * is a owl:Class, owl:ObjectProperty,owl:DatatypeProperty or owl:NamedIndividual.
885         * @param iri the IRI of the entity
886         * @return the entity type
887         */
888        public EntityType<? extends OWLEntity> getOWLEntityType(String iri) {
889                ParameterizedSparqlString query = new ParameterizedSparqlString("SELECT ?type WHERE {?s a ?type .}");
890                query.setIri("s", iri);
891                ResultSet rs = executeSelectQuery(query.toString());
892                Set<EntityType<? extends OWLEntity>> entityTypes = new HashSet<>();
893                while(rs.hasNext()){
894                        QuerySolution qs = rs.next();
895                        String uri = qs.getResource("type").getURI();
896                        for(EntityType<? extends OWLEntity> entityType : EntityType.values()){
897                                if(entityType.getIRI().toString().equals(uri)){
898                                        entityTypes.add(entityType);
899                                        break;
900                                }
901                        }
902                }
903                if(entityTypes.size() == 1){
904                        return entityTypes.iterator().next();
905                }
906                return null;
907        }
908
909        public Set<OWLClass> getTypes(String namespace) {
910                return getTypes(namespace, false);
911        }
912        
913        public Set<OWLClass> getTypes(String namespace, boolean omitEmptyTypes) {
914                Set<OWLClass> types = new TreeSet<>();
915                String query =  "SELECT DISTINCT ?cls WHERE {[] a ?cls ." +
916                (omitEmptyTypes ? "[] a ?cls ." : "" ) +
917                (namespace != null ? ("FILTER(REGEX(?cls,'^" + namespace + "'))") : "") + "}";
918                ResultSet rs = executeSelectQuery(query);
919                while(rs.hasNext()){
920                        QuerySolution qs = rs.next();
921                        types.add(df.getOWLClass(IRI.create(qs.getResource("cls").getURI())));
922                }
923                return types;
924        }
925        
926        /* (non-Javadoc)
927         * @see org.dllearner.core.BaseReasoner#getNamedClasses()
928         */
929        @Override
930        public SortedSet<OWLClass> getClasses() {
931                return getOWLClasses();
932        }
933        
934        public SortedSet<OWLClass> getOWLClasses() {
935                return getOWLClasses(null);
936        }
937        
938        public SortedSet<OWLClass> getOWLClasses(String namespace) {
939                ResultSet rs;
940                if (!laxMode) {
941                        rs = executeSelectQuery(SPARQLQueryUtils.SELECT_CLASSES_QUERY);
942                } else {
943                        rs = executeSelectQuery(SPARQLQueryUtils.SELECT_CLASSES_QUERY_ALT);
944                }
945                
946                SortedSet<OWLClass> classes = asOWLEntities(EntityType.CLASS, rs, "var1");
947                return classes;
948        }
949        
950        public Set<OWLClass> getNonEmptyOWLClasses() {
951                String query = "SELECT DISTINCT ?var1 WHERE {?var1 a <http://www.w3.org/2002/07/owl#Class>. FILTER EXISTS{[] a ?var1}}";
952                ResultSet rs = executeSelectQuery(query);
953                SortedSet<OWLClass> classes = asOWLEntities(EntityType.CLASS, rs, "var1");
954                return classes;
955        }
956        
957        /* (non-Javadoc)
958         * @see org.dllearner.core.BaseReasoner#getIndividuals()
959         */
960        @Override
961        public SortedSet<OWLIndividual> getIndividuals() {
962                return getOWLIndividuals();
963        }
964        
965        public SortedSet<OWLIndividual> getOWLIndividuals() {
966                ResultSet rs;
967                if (!laxMode) {
968                        rs = executeSelectQuery(SPARQLQueryUtils.SELECT_INDIVIDUALS_QUERY);
969                } else {
970                        rs = executeSelectQuery(SPARQLQueryUtils.SELECT_INDIVIDUALS_QUERY_ALT);
971                }
972                SortedSet<OWLIndividual> individuals = new TreeSet<>();
973                individuals.addAll(asOWLEntities(EntityType.NAMED_INDIVIDUAL, rs, "var1"));
974                return individuals;
975        }
976
977        /* (non-Javadoc)
978         * @see org.dllearner.core.BaseReasoner#getObjectProperties()
979         */
980        @Override
981        public Set<OWLObjectProperty> getObjectPropertiesImpl() {
982                return getOWLObjectProperties();
983        }
984        
985        public SortedSet<OWLObjectProperty> getOWLObjectProperties() {
986                return getOWLObjectProperties(null);
987        }
988        
989        public SortedSet<OWLObjectProperty> getOWLObjectProperties(String namespace) {
990                ResultSet rs = executeSelectQuery(SPARQLQueryUtils.SELECT_OBJECT_PROPERTIES_QUERY);
991                
992                SortedSet<OWLObjectProperty> properties = asOWLEntities(EntityType.OBJECT_PROPERTY, rs, "var1");
993                return properties;
994        }
995        
996        /* (non-Javadoc)
997         * @see org.dllearner.core.AbstractReasonerComponent#getDatatypePropertiesImpl()
998         */
999        @Override
1000        protected Set<OWLDataProperty> getDatatypePropertiesImpl() throws ReasoningMethodUnsupportedException {
1001                return getOWLDataProperties();
1002        }
1003        
1004        public SortedSet<OWLDataProperty> getOWLDataProperties() {
1005                return getOWLDataProperties(null);
1006        }
1007        
1008        public SortedSet<OWLDataProperty> getOWLDataProperties(String namespace) {
1009                ResultSet rs = executeSelectQuery(SPARQLQueryUtils.SELECT_DATA_PROPERTIES_QUERY);
1010                
1011                SortedSet<OWLDataProperty> properties = asOWLEntities(EntityType.DATA_PROPERTY, rs, "var1");
1012                return properties;
1013        }
1014        
1015        public Set<OWLDataProperty> getDataPropertiesByRange(XSDVocabulary xsdType) {
1016                return getDataPropertiesByRange(xsdType.getIRI());
1017        }
1018        public Set<OWLDataProperty> getDataPropertiesByRange(Set<OWLDatatype> dts) {
1019                Set<OWLDataProperty> r = new TreeSet<>();
1020                for (OWLDatatype dt:dts) {
1021                        r.addAll(getDataPropertiesByRange(dt.getIRI()));
1022                }
1023                return r;
1024        }
1025        public Set<OWLDataProperty> getDataPropertiesByRange(IRI iri) {
1026                String query = String.format(SPARQLQueryUtils.SELECT_DATA_PROPERTIES_BY_RANGE_QUERY, iri.toString());
1027                logger.debug(sparql_debug, "get properties by range query: " + query);
1028                ResultSet rs = executeSelectQuery(query);
1029                
1030                SortedSet<OWLDataProperty> properties = asOWLEntities(EntityType.DATA_PROPERTY, rs, "var1");
1031                return properties;
1032        }
1033        /* (non-Javadoc)
1034         * @see org.dllearner.core.AbstractReasonerComponent#getIntDatatypePropertiesImpl()
1035         */
1036        @Override
1037        protected Set<OWLDataProperty> getIntDatatypePropertiesImpl() throws ReasoningMethodUnsupportedException {
1038                return getDataPropertiesByRange(OWLAPIUtils.intDatatypes);
1039        }
1040        
1041        /* (non-Javadoc)
1042         * @see org.dllearner.core.AbstractReasonerComponent#getDoubleDatatypePropertiesImpl()
1043         */
1044        @Override
1045        protected Set<OWLDataProperty> getDoubleDatatypePropertiesImpl() throws ReasoningMethodUnsupportedException {
1046                return getDataPropertiesByRange(OWLAPIUtils.floatDatatypes);
1047        }
1048        
1049        /* (non-Javadoc)
1050         * @see org.dllearner.core.AbstractReasonerComponent#getBooleanDatatypePropertiesImpl()
1051         */
1052        @Override
1053        protected Set<OWLDataProperty> getBooleanDatatypePropertiesImpl() throws ReasoningMethodUnsupportedException {
1054                return getDataPropertiesByRange(OWLAPIUtils.fixedDatatypes);
1055        }
1056        
1057        /* (non-Javadoc)
1058         * @see org.dllearner.core.AbstractReasonerComponent#getStringDatatypePropertiesImpl()
1059         */
1060        @Override
1061        protected Set<OWLDataProperty> getStringDatatypePropertiesImpl() throws ReasoningMethodUnsupportedException {
1062                return getDataPropertiesByRange(XSDVocabulary.STRING);
1063        }
1064        
1065        public Set<OWLProperty> getProperties(boolean inferType, String namespace) {
1066                Set<OWLProperty> properties = new HashSet<>();
1067                String query = "SELECT DISTINCT ?p ?type WHERE {?s ?p ?o ."
1068                                                + (namespace != null ? ("FILTER(STRSTARTS(STR(?p),'^" + namespace + "'))") : "")
1069                                                + "OPTIONAL{?p a ?type}}";
1070                ResultSet rs = executeSelectQuery(query);
1071                Multimap<String, String> uri2Types = HashMultimap.create();
1072                QuerySolution qs;
1073                while(rs.hasNext()){
1074                        qs = rs.next();
1075                        String uri = qs.getResource("p").getURI();
1076                        String type = "";
1077                        if(qs.getResource("type") != null){
1078                                type = qs.getResource("type").getURI();
1079                        }
1080                        uri2Types.put(uri, type);
1081                }
1082                for (Entry<String, Collection<String>> entry : uri2Types.asMap().entrySet()) {
1083                        String uri = entry.getKey();
1084                        Collection<String> types = entry.getValue();
1085                        if(types.contains(OWL.ObjectProperty.getURI()) && !types.contains(OWL.DatatypeProperty.getURI())){
1086                                properties.add(df.getOWLObjectProperty(IRI.create(uri)));
1087                        } else if(!types.contains(OWL.ObjectProperty.getURI()) && types.contains(OWL.DatatypeProperty.getURI())){
1088                                properties.add(df.getOWLDataProperty(IRI.create(uri)));
1089                        } else if(inferType){
1090                                //infer the type by values
1091                                query = "SELECT ?o WHERE {?s <" + uri + "> ?o. } LIMIT 100";
1092                                rs = executeSelectQuery(query);
1093                                boolean op = true;
1094                                boolean dp = true;
1095                                RDFNode node;
1096                                while(rs.hasNext()){
1097                                        node = rs.next().get("o");
1098                                        op = node.isResource();
1099                                        dp = node.isLiteral();
1100                                }
1101                                if(op && !dp){
1102                                        properties.add(df.getOWLObjectProperty(IRI.create(uri)));
1103                                } else if(!op && dp){
1104                                        properties.add(df.getOWLDataProperty(IRI.create(uri)));
1105                                } else {
1106                                        //not possible to decide
1107                                }
1108                        }
1109                }
1110                return properties;
1111        }
1112        
1113        public Set<OWLProperty> getProperties(boolean inferType) {
1114                return getProperties(inferType, null);
1115        }
1116
1117        /**
1118         * Returns a set of sibling classes, i.e. classes that are on the same level
1119         * in the class hierarchy.
1120         * @param cls the OWL class
1121         * @return the sibling classes
1122         */
1123        public Set<OWLClass> getSiblingClasses(OWLClass cls) {
1124                String query = SPARQLQueryUtils.SELECT_SIBLING_CLASSES_QUERY.replace("%s", cls.toStringID());
1125                ResultSet rs = executeSelectQuery(query);
1126                Set<OWLClass> siblings = asOWLEntities(EntityType.CLASS, rs, "var1");
1127                return siblings;
1128        }
1129
1130        @Override
1131        public boolean hasTypeImpl(OWLClassExpression description, OWLIndividual individual) {
1132                if(description.isOWLThing()) { // owl:Thing -> TRUE
1133                        return true;
1134                } else if(description.isOWLNothing()) { // owl:Nothing -> FALSE
1135                        return false;
1136                } else if(!description.isAnonymous()) { // atomic classes
1137                        String query = String.format("ASK {<%s> a <%s>}", individual.toStringID(), description.asOWLClass().toStringID());
1138                        boolean result = executeAskQuery(query);
1139                        return result;
1140                } else { // complex class expressions
1141//                      //TODO use ASK queries
1142//                      SortedSet<OWLIndividual> individuals = getIndividuals(description, Collections.singleton(individual));
1143//                      return individuals.contains(individual);
1144                        // FIXME universal and cardinality restrictions do not work with ASK queries
1145                        String queryBody = converter.convert("?ind", description);
1146                        if (queryBody.isEmpty())
1147                                return true;
1148                        queryBody = queryBody.replace("?ind", "<" + individual.toStringID() + ">");
1149                        String query = "ASK {" + queryBody + "}";
1150                        boolean b = executeAskQuery(query);
1151                        return b;
1152                }
1153        }
1154
1155        @Override
1156        public SortedSet<OWLIndividual> hasTypeImpl(OWLClassExpression description, Set<OWLIndividual> individuals) {
1157                SortedSet<OWLIndividual> allIndividuals = getIndividuals(description, individuals);
1158                //allIndividuals.retainAll(individuals);
1159                return allIndividuals;
1160        }
1161
1162        @Override
1163        public SortedSet<OWLIndividual> getIndividualsImpl(OWLClassExpression description) {
1164                return getIndividuals(description, 0);
1165        }
1166
1167        protected String buildIndividualsQueryValues(OWLClassExpression description, Collection<OWLIndividual> indValues, boolean isCountQuery) {
1168                StringBuilder query;
1169                String tp = converter.convert("?ind", description);
1170
1171                if (isCountQuery) {
1172                        query = new StringBuilder("SELECT (COUNT(DISTINCT ?ind) as ?cnt) WHERE { \n");
1173                } else {
1174                        query = new StringBuilder("SELECT DISTINCT ?ind WHERE { \n");
1175                }
1176
1177                query.append("VALUES ?ind { \n");
1178                for (OWLIndividual x:indValues) {
1179                        query.append("<").append(x.toStringID()).append("> ");
1180                }
1181                query.append("}. \n ").append(tp).append("\n}");
1182
1183                return query.toString();
1184        }
1185
1186        public SortedSet<OWLIndividual> getIndividuals(OWLClassExpression description, int limit, Set<OWLIndividual> indValues) {
1187                // we need to copy it to get something like A AND B from A AND A AND B
1188                description = duplicator.duplicateObject(description);
1189                
1190                SortedSet<OWLIndividual> individuals = new TreeSet<>();
1191                String query;
1192                
1193                if (indValues != null) {
1194                        query = buildIndividualsQueryValues(description, indValues, false);
1195                } else {
1196                        query = converter.asQuery("?ind", description, false).toString();
1197                }
1198                if(limit != 0) {
1199                        query += " LIMIT " + limit;
1200                }
1201//              query = String.format(SPARQLQueryUtils.PREFIXES + " SELECT ?ind WHERE {?ind rdf:type/rdfs:subClassOf* <%s> .}", description.asOWLClass().toStringID());
1202                logger.trace(sparql_debug, "get individuals query: " + query);
1203
1204                ResultSet rs = executeSelectQuery(query);
1205                while(rs.hasNext()){
1206                        QuerySolution qs = rs.next();
1207                        if(qs.get("ind").isURIResource()){
1208                                individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1209                        }
1210                }
1211                logger.trace(sparql_debug, "get individuals result: " + (individuals.size() > 2 ? individuals.first() + ".."+(individuals.size()-2)+".."+individuals.last()
1212                        : individuals.size() == 1 ? individuals.first() : "0"));
1213                return individuals;
1214        }
1215        
1216        public SortedSet<OWLIndividual> getIndividuals(OWLClassExpression description, int limit) {
1217                return getIndividuals(description, limit, null);
1218        }
1219        
1220        public SortedSet<OWLIndividual> getIndividuals(OWLClassExpression description, Set<OWLIndividual> indValues) {
1221                return getIndividuals(description, 0, indValues);
1222        }
1223
1224        public int getIndividualsCount(OWLClassExpression description, int limit, Set<OWLIndividual> indValues) {
1225                description = duplicator.duplicateObject(description);
1226                
1227                String query;
1228                
1229                if (indValues != null) {
1230                        query = buildIndividualsQueryValues(description, indValues, true);
1231                } else {
1232                        query = converter.asQuery("?ind", description, true).toString();
1233                        System.err.println(query);
1234                        throw new RuntimeException();
1235                }
1236                if(limit != 0) {
1237                        query += " LIMIT " + limit;
1238                }
1239                if(logger.isTraceEnabled()){
1240                        logger.trace(sparql_debug, "get individuals query: " + query);
1241                }
1242                ResultSet rs = executeSelectQuery(query);
1243                while(rs.hasNext()){
1244                        QuerySolution qs = rs.next();
1245                        if(qs.get("cnt").isLiteral()){
1246                                int ret = qs.get("cnt").asLiteral().getInt();logger.trace(sparql_debug, "result: "+ret);
1247                                return ret;
1248                        }
1249                }
1250                throw new Error("no result");
1251        }
1252
1253        public int getIndividualsCount(OWLClassExpression description, int limit) {
1254                return getIndividualsCount(description, limit, null);
1255        }
1256        
1257        public int getIndividualsCount(OWLClassExpression description, Set<OWLIndividual> indValues) {
1258                return getIndividualsCount(description, 0, indValues);
1259        }
1260
1261        /**
1262         * @param wantedClass the class to which the individuals must belong to
1263         * @param excludeClass the class to which the individuals must not belong to
1264         * @param limit the max. number of individuals
1265         * @return get individuals of class wantedClass excluding all individuals of type excludeClass
1266         */
1267        public SortedSet<OWLIndividual> getIndividualsExcluding(OWLClassExpression wantedClass, OWLClassExpression excludeClass, int limit) {
1268                if(wantedClass.isAnonymous()){
1269                        throw new UnsupportedOperationException("Only named classes are supported.");
1270                }
1271                SortedSet<OWLIndividual> individuals = new TreeSet<>();
1272                String query =
1273                                "SELECT DISTINCT ?ind WHERE {" +
1274                                                "?ind a <"+((OWLClass)wantedClass).toStringID() + "> . " +
1275                                                "FILTER NOT EXISTS { ?ind a <" + ((OWLClass)excludeClass).toStringID() + "> } }";
1276                if(limit != 0) {
1277                        query += " LIMIT " + limit;
1278                }
1279                ResultSet rs = executeSelectQuery(query);
1280                while(rs.hasNext()){
1281                        QuerySolution qs = rs.next();
1282                        if(qs.get("ind").isURIResource()){
1283                                individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1284                        }
1285                }
1286                return individuals;
1287        }
1288        
1289//      /**
1290//       * @param cls
1291//       * @param limit
1292//       * @return Random Individuals not including any of the input class individuals
1293//       * @author sherif
1294//       */
1295//      public SortedSet<OWLIndividual> getRandomIndividuals(OWLClass cls, int limit) {
1296//              SortedSet<OWLIndividual> individuals = new TreeSet<OWLIndividual>();
1297//              String query =
1298//                              " SELECT DISTINCT ?ind WHERE {"+
1299//                                              "?ind ?p ?o ."+
1300//                                              "FILTER(NOT EXISTS { ?ind a <" + cls.toStringID() + "> } ) }";
1301//              if(limit != 0) {
1302//                      query += " LIMIT " + limit;
1303//              }
1304//              ResultSet rs = executeSelectQuery(query);
1305//              QuerySolution qs;
1306//              while(rs.hasNext()){
1307//                      qs = rs.next();
1308//                      if(qs.get("ind").isURIResource()){
1309//                              individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1310//                      }
1311//              }
1312//              return individuals;
1313//      }
1314        
1315//      /**
1316//       * @param cls
1317//       * @param limit
1318//       * @return Random Individuals not including any of the input classes individuals
1319//       * @author sherif
1320//       */
1321//      public SortedSet<OWLIndividual> getRandomIndividuals(Set<OWLClass> cls, int limit) {
1322//              SortedSet<OWLIndividual> individuals = new TreeSet<OWLIndividual>();
1323//
1324//              String filterStr="";
1325//              for(OWLClass nc : cls){
1326//                      filterStr = filterStr.concat("FILTER(NOT EXISTS { ?ind a <").concat(nc.toStringID()).concat("> } ) ");
1327//              }
1328//
1329//              String query =
1330//                              " SELECT DISTINCT ?ind WHERE {"+
1331//                                              "?ind a ?o .?o <http://www.w3.org/2000/01/rdf-schema#subClassOf> <http://www.w3.org/2002/07/owl#Class>"+
1332//                                              filterStr+ " }";
1333//              if(limit != 0) {
1334//                      query += " LIMIT " + limit;
1335//              }
1336//
1337//              System.out.println("!!!!!!!!!!!!!!!!!!!! "+query);
1338//              ResultSet rs = executeSelectQuery(query);
1339//              QuerySolution qs;
1340//              while(rs.hasNext()){
1341//                      qs = rs.next();
1342//                      if(qs.get("ind").isURIResource()){
1343//                              individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1344//                      }
1345//              }
1346//              return individuals;
1347//      }
1348
1349//      /**
1350//       * @param cls
1351//       * @param limit
1352//       * @return Super class of the input class Individuals not including any of the input class individuals
1353//       * @author sherif
1354//       */
1355//      public SortedSet<OWLIndividual> getSuperClassIndividuals(OWLClass cls, int limit) {
1356//              SortedSet<OWLIndividual> individuals = new TreeSet<OWLIndividual>();
1357//              Set<OWLClassExpression> superClasses = getSuperClasses(cls);
1358//
1359//              for(OWLClassExpression sup : superClasses){
1360//                      if(!sup.isAnonymous()) {
1361//                              String query = "SELECT DISTINCT ?ind WHERE { "
1362//                                              + "?ind a <" + sup.asOWLClass().toStringID() + "> . "
1363//                                              + "FILTER NOT EXISTS { ?ind a <" + cls.toStringID() + "> }  }";
1364//                              if(limit != 0) {
1365//                                      query += " LIMIT " + limit/superClasses.size();
1366//                              }
1367//
1368//                              System.out.println("----------------------------------------------  "+query);
1369//
1370//                              ResultSet rs = executeSelectQuery(query);
1371//                              QuerySolution qs;
1372//                              while(rs.hasNext()){
1373//                                      qs = rs.next();
1374//                                      if(qs.get("ind").isURIResource()){
1375//                                              individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1376//                                      }
1377//                              }
1378//                              System.out.println(individuals.size());
1379//                              System.out.println(individuals);
1380//                      }
1381//              }
1382//
1383//              return individuals;
1384//      }
1385
1386        @Override
1387        public SortedSetTuple<OWLIndividual> doubleRetrievalImpl(OWLClassExpression description) {
1388                throw new UnsupportedOperationException();
1389        }
1390
1391        @Override
1392        public Set<OWLIndividual> getRelatedIndividualsImpl(OWLIndividual individual, OWLObjectProperty objectProperty) {
1393                Set<OWLIndividual> individuals = new HashSet<>();
1394                String query = String.format("SELECT ?ind WHERE {<%s> <%s> ?ind, FILTER(isIRI(?ind))}", individual.toStringID(), objectProperty.toStringID());
1395
1396                ResultSet rs = executeSelectQuery(query);
1397                while(rs.hasNext()){
1398                        QuerySolution qs = rs.next();
1399                        individuals.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1400                }
1401                return individuals;
1402        }
1403
1404        @Override
1405        public Set<OWLLiteral> getRelatedValuesImpl(OWLIndividual individual, OWLDataProperty datatypeProperty) {
1406                // TODO Auto-generated method stub
1407                return null;
1408        }
1409
1410        @Override
1411        public Map<OWLObjectProperty, Set<OWLIndividual>> getObjectPropertyRelationshipsImpl(OWLIndividual individual) {
1412                Map<OWLObjectProperty, Set<OWLIndividual>> prop2individuals = new HashMap<>();
1413                String query = String.format("SELECT ?prop ?ind WHERE {" +
1414                                "<%s> ?prop ?ind." +
1415                                " FILTER(isIRI(?ind) && ?prop != <%s> && ?prop != <%s>)}",
1416                                individual.toStringID(), RDF.type.getURI(), OWL.sameAs.getURI());
1417
1418                ResultSet rs = executeSelectQuery(query);
1419                while(rs.hasNext()){
1420                        QuerySolution qs = rs.next();
1421                        OWLIndividual ind = df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI()));
1422                        OWLObjectProperty property = df.getOWLObjectProperty(IRI.create(qs.getResource("prop").getURI()));
1423                        prop2individuals.computeIfAbsent(property, k -> new HashSet<>()).add(ind);
1424                }
1425                return prop2individuals;
1426        }
1427
1428        @Override
1429        public Map<OWLIndividual, SortedSet<OWLIndividual>> getPropertyMembersImpl(OWLObjectProperty objectProperty) {
1430                //if (logger.isTraceEnabled()) logger.trace(ExceptionUtils.getStackTrace(new Throwable()));
1431                Map<OWLIndividual, SortedSet<OWLIndividual>> subject2objects = new HashMap<>();
1432                String query = String.format("SELECT ?s ?o WHERE {" +
1433                                "?s <%s> ?o." +
1434                                " FILTER(isIRI(?o))}",
1435                                objectProperty.toStringID());
1436
1437                ResultSet rs = executeSelectQuery(query);
1438                while(rs.hasNext()){
1439                        QuerySolution qs = rs.next();
1440                        if (qs.getResource("s") == null || qs.getResource("s").getURI() == null) {
1441                                logger.warn(sparql_debug, "The ?s is empty {} {}", query, qs);
1442                                continue;
1443                        }
1444                        OWLIndividual sub = df.getOWLNamedIndividual(IRI.create(qs.getResource("s").getURI()));
1445                        OWLIndividual obj = df.getOWLNamedIndividual(IRI.create(qs.getResource("o").getURI()));
1446                        subject2objects.computeIfAbsent(sub, k -> new TreeSet<>()).add(obj);
1447                }
1448                return subject2objects;
1449        }
1450
1451        protected String buildApplicablePropertiesValuesQuery(OWLClassExpression domain, Collection<? extends OWLObjectProperty> objectProperties) {
1452                String domQuery = converter.convert("?dom", domain);
1453                String props = objectProperties.stream().map(op -> "<" + op.toStringID() + ">").collect(Collectors.joining(" "));
1454//              String prop1 = converter.convert("?p", objectProperties.iterator().next());
1455
1456                String query = "SELECT DISTINCT ?p WHERE { " +
1457                                "" + domQuery + " ?dom ?p ?o . \n" +
1458                                "" + " VALUES ?p { \n" + props + " } \n" +
1459                                "" + " }";
1460                return query;
1461        }
1462
1463        public Set<OWLObjectProperty> getApplicableProperties(OWLClassExpression domain, Set<OWLObjectProperty> objectProperties) {
1464                if (isPreferAsk()) {
1465                        String domQuery = converter.convert("?dom", domain);
1466                        return objectProperties.stream()
1467                                        .filter(p -> executeAskQuery("ASK { " + domQuery + " ?dom <" + p.toStringID() + "> ?o . }"))
1468                                        .collect(Collectors.toSet());
1469                } else {
1470                        Set<OWLObjectProperty> ret = new TreeSet<>();
1471
1472                        ResultSet rs = executeSelectQuery(buildApplicablePropertiesValuesQuery(domain, objectProperties));
1473                        while (rs.hasNext()) {
1474                                QuerySolution qs = rs.next();
1475                                OWLObjectProperty prop = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
1476                                ret.add(prop);
1477                        }
1478                        return ret;
1479                }
1480        }
1481
1482        @Override
1483        public Map<OWLIndividual, SortedSet<OWLLiteral>> getDatatypeMembersImpl(OWLDataProperty dataProperty) {
1484                Map<OWLIndividual, SortedSet<OWLLiteral>> subject2objects = new HashMap<>();
1485                
1486                String query = String.format(SPARQLQueryUtils.SELECT_PROPERTY_RELATIONSHIPS_QUERY, dataProperty.toStringID());
1487
1488                ResultSet rs = executeSelectQuery(query);
1489                while(rs.hasNext()){
1490                        QuerySolution qs = rs.next();
1491                        OWLIndividual sub = df.getOWLNamedIndividual(IRI.create(qs.getResource("var1").getURI()));
1492                        OWLLiteral obj = OwlApiJenaUtils.getOWLLiteral(qs.getLiteral("var2"));
1493                        subject2objects.computeIfAbsent(sub, k -> new TreeSet<>()).add(obj);
1494                }
1495                return subject2objects;
1496        }
1497        
1498        private String datatypeSparqlFilter(Iterable<OWLDatatype> dts) {
1499                return Joiner.on(" || ").join(
1500                                StreamSupport.stream(dts.spliterator(), false)
1501                                                .map(input -> "DATATYPE(?o) = <" + input.toStringID() + ">")
1502                                                .collect(Collectors.toList())
1503                                );
1504        }
1505
1506        @Override
1507        public Map<OWLIndividual, SortedSet<Double>> getDoubleDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1508                Map<OWLIndividual, SortedSet<Double>> subject2objects = new HashMap<>();
1509                String query = "SELECT ?s ?o WHERE {" +
1510                                String.format("?s <%s> ?o.", datatypeProperty.toStringID()) +
1511                                " FILTER(" + datatypeSparqlFilter(OWLAPIUtils.floatDatatypes) + ")}";
1512
1513                ResultSet rs = executeSelectQuery(query);
1514                while(rs.hasNext()){
1515                        QuerySolution qs = rs.next();
1516                        OWLIndividual sub = df.getOWLNamedIndividual(IRI.create(qs.getResource("s").getURI()));
1517                        Literal val = qs.getLiteral("o").asLiteral();
1518                        // Virtuoso bug workaround which returns NAN instead of NaN
1519                        Double obj = "NAN".equals(val.getLexicalForm()) ? Double.NaN : val.getDouble();
1520                        subject2objects.computeIfAbsent(sub, k -> new TreeSet<>()).add(obj);
1521                }
1522                return subject2objects;
1523        }
1524
1525        @Override
1526        public Map<OWLIndividual, SortedSet<Integer>> getIntDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1527                Map<OWLIndividual, SortedSet<Integer>> subject2objects = new HashMap<>();
1528                String query = "SELECT ?s ?o WHERE {" +
1529                                String.format("?s <%s> ?o.", datatypeProperty.toStringID()) +
1530                                " FILTER(" + datatypeSparqlFilter(OWLAPIUtils.intDatatypes) + ")}";
1531
1532                ResultSet rs = executeSelectQuery(query);
1533                while(rs.hasNext()){
1534                        QuerySolution qs = rs.next();
1535                        OWLIndividual sub = df.getOWLNamedIndividual(IRI.create(qs.getResource("s").getURI()));
1536                        Integer obj = qs.getLiteral("o").getInt();
1537                        subject2objects.computeIfAbsent(sub, k -> new TreeSet<>()).add(obj);
1538                }
1539                return subject2objects;
1540        }
1541
1542        @Override
1543        public Map<OWLIndividual, SortedSet<Boolean>> getBooleanDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1544                Map<OWLIndividual, SortedSet<Boolean>> subject2objects = new HashMap<>();
1545                String query = "SELECT ?s ?o WHERE {" +
1546                                String.format("?s <%s> ?o.", datatypeProperty.toStringID()) +
1547                                " FILTER(" + datatypeSparqlFilter(OWLAPIUtils.fixedDatatypes) + ")}";
1548
1549                ResultSet rs = executeSelectQuery(query);
1550                while(rs.hasNext()){
1551                        QuerySolution qs = rs.next();
1552                        OWLIndividual sub = df.getOWLNamedIndividual(IRI.create(qs.getResource("s").getURI()));
1553                        Boolean obj = qs.getLiteral("o").getBoolean();
1554                        subject2objects.computeIfAbsent(sub, k -> new TreeSet<>()).add(obj);
1555                }
1556                return subject2objects;
1557        }
1558
1559        @Override
1560        public SortedSet<OWLIndividual> getTrueDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1561                SortedSet<OWLIndividual> members = new TreeSet<>();
1562                String query = String.format("SELECT ?ind WHERE {" +
1563                                "?ind <%s> ?o." +
1564                                " FILTER(isLiteral(?o) && DATATYPE(?o) = <%s> && ?o = %s)}",
1565                                datatypeProperty.toStringID(), XSD.BOOLEAN.toStringID(),
1566                                "\"true\"^^<" + XSD.BOOLEAN.toStringID() + ">");
1567
1568                ResultSet rs = executeSelectQuery(query);
1569                while(rs.hasNext()){
1570                        QuerySolution qs = rs.next();
1571                        members.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1572                }
1573                return members;
1574        }
1575
1576        @Override
1577        public SortedSet<OWLIndividual> getFalseDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1578                SortedSet<OWLIndividual> members = new TreeSet<>();
1579                String query = String.format("SELECT ?ind WHERE {" +
1580                                "?ind <%s> ?o." +
1581                                " FILTER(isLiteral(?o) && DATATYPE(?o) = <%s> && ?o = %s)}",
1582                                datatypeProperty.toStringID(), XSD.BOOLEAN.toStringID(),
1583                                "\"false\"^^<"+XSD.BOOLEAN.toStringID() + ">");
1584
1585                ResultSet rs = executeSelectQuery(query);
1586                while(rs.hasNext()){
1587                        QuerySolution qs = rs.next();
1588                        members.add(df.getOWLNamedIndividual(IRI.create(qs.getResource("ind").getURI())));
1589                }
1590                return members;
1591        }
1592
1593        @Override
1594        public Map<OWLIndividual, SortedSet<String>> getStringDatatypeMembersImpl(OWLDataProperty datatypeProperty) {
1595                // TODO Auto-generated method stub
1596                return null;
1597        }
1598
1599        @Override
1600        public Set<OWLClass> getInconsistentClassesImpl() {
1601                throw new UnsupportedOperationException();
1602        }
1603
1604        private OWLClassExpression computeDomain(OWLProperty property) {
1605                String query = String.format("SELECT ?domain WHERE {" +
1606                                                                                         "<%s> <%s> ?domain. FILTER(isIRI(?domain))" +
1607                                                                                         "}",
1608                                                                         property.toStringID(), RDFS.domain.getURI());
1609
1610                try {
1611                        ResultSet rs = executeSelectQuery(query);
1612                        SortedSet<OWLClassExpression> domains = new TreeSet<>();
1613                        while(rs.hasNext()){
1614                                QuerySolution qs = rs.next();
1615                                domains.add(df.getOWLClass(IRI.create(qs.getResource("domain").getURI())));
1616                        }
1617                        domains.remove(df.getOWLThing());
1618                        if(domains.size() == 1){
1619                                return domains.first();
1620                        } else if(domains.size() > 1){
1621                                return df.getOWLObjectIntersectionOf(domains);
1622                        }
1623                        return df.getOWLThing();
1624                } catch (Exception e) {
1625                        logger.error("Failed to compute the domain for " + property + ".", e);
1626                }
1627                return null;
1628        }
1629
1630        @Override
1631        public OWLClassExpression getDomainImpl(OWLObjectProperty property) {
1632                return propertyDomains.computeIfAbsent(property, k -> computeDomain(property));
1633        }
1634        
1635        public Set<OWLObjectProperty> getObjectPropertiesWithDomain(OWLClass domain) {
1636                Set<OWLObjectProperty> properties = new TreeSet<>();
1637                
1638                String query = "SELECT ?p WHERE {?p <http://www.w3.org/2000/01/rdf-schema#domain> <" + domain.toStringID() + ">.}";
1639                ResultSet rs = executeSelectQuery(query);
1640                QuerySolution qs;
1641                while(rs.hasNext()){
1642                        qs = rs.next();
1643                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI())));
1644                }
1645                
1646                return properties;
1647        }
1648        
1649        public Set<OWLObjectProperty> getObjectProperties(OWLClass cls) {
1650                Set<OWLObjectProperty> properties = new TreeSet<>();
1651                
1652                String query = "SELECT DISTINCT ?p WHERE {?s a <" + cls.toStringID() + ">. ?s ?p ?o}";
1653                ResultSet rs = executeSelectQuery(query);
1654                QuerySolution qs;
1655                while(rs.hasNext()){
1656                        qs = rs.next();
1657                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI())));
1658                }
1659                
1660                return properties;
1661        }
1662        
1663        public SortedSet<OWLClass> getDomains(OWLObjectProperty objectProperty) {
1664                String query = String.format("SELECT ?domain WHERE {" +
1665                                "<%s> <%s> ?domain. FILTER(isIRI(?domain))" +
1666                                "}",
1667                                objectProperty.toStringID(), RDFS.domain.getURI());
1668
1669                ResultSet rs = executeSelectQuery(query);
1670                QuerySolution qs;
1671                SortedSet<OWLClass> domains = new TreeSet<>();
1672                while(rs.hasNext()){
1673                        qs = rs.next();
1674                        domains.add(df.getOWLClass(IRI.create(qs.getResource("domain").getURI())));
1675
1676                }
1677                return domains;
1678        }
1679
1680        @Override
1681        public OWLClassExpression getDomainImpl(OWLDataProperty property) {
1682                return propertyDomains.computeIfAbsent(property, k -> computeDomain(property));
1683        }
1684
1685        @Override
1686        public OWLClassExpression getRangeImpl(OWLObjectProperty property) {
1687                return objectPropertyRanges.computeIfAbsent(property, k -> {
1688                        String query = String.format("SELECT ?range WHERE {" +
1689                                                        "<%s> <%s> ?range. FILTER(isIRI(?range))" +
1690                                                        "}",
1691                                        property.toStringID(), RDFS.range.getURI());
1692
1693                        try {
1694                                ResultSet rs = executeSelectQuery(query);
1695                                SortedSet<OWLClassExpression> ranges = new TreeSet<>();
1696                                while (rs.hasNext()) {
1697                                        QuerySolution qs = rs.next();
1698                                        ranges.add(df.getOWLClass(IRI.create(qs.getResource("range").getURI())));
1699                                }
1700                                ranges.remove(df.getOWLThing());
1701                                if (ranges.size() == 1) {
1702                                        return ranges.first();
1703                                } else if (ranges.size() > 1) {
1704                                        return df.getOWLObjectIntersectionOf(ranges);
1705                                }
1706                                return df.getOWLThing();
1707                        } catch (Exception e) {
1708                                logger.error("Failed to compute range for " + property, e);
1709                        }
1710                        return null;
1711                });
1712        }
1713        
1714        public SortedSet<OWLClass> getRanges(OWLObjectProperty objectProperty) {
1715                String query = String.format("SELECT ?range WHERE {" +
1716                                "<%s> <%s> ?range. FILTER(isIRI(?range))" +
1717                                "}",
1718                                objectProperty.toStringID(), RDFS.range.getURI());
1719
1720                ResultSet rs = executeSelectQuery(query);
1721                QuerySolution qs;
1722                SortedSet<OWLClass> ranges = new TreeSet<>();
1723                while(rs.hasNext()){
1724                        qs = rs.next();
1725                        ranges.add(df.getOWLClass(IRI.create(qs.getResource("range").getURI())));
1726                }
1727                return ranges;
1728        }
1729
1730        public boolean isObjectProperty(String propertyURI){
1731                String query = String.format("ASK {<%s> a <%s>}", propertyURI, OWL.ObjectProperty.getURI());
1732                boolean isObjectProperty = executeAskQuery(query);
1733                return isObjectProperty;
1734        }
1735
1736        public boolean isObjectProperty(String propertyURI, boolean analyzeData){
1737                String query = String.format("ASK {<%s> a <%s>}", propertyURI, OWL.ObjectProperty.getURI());
1738                boolean isObjectProperty = executeAskQuery(query);
1739                if(!isObjectProperty && analyzeData){
1740                        query = String.format("ASK {?s <%s> ?o.FILTER(isURI(?o))}", propertyURI);
1741                        isObjectProperty = executeAskQuery(query);
1742                }
1743                return isObjectProperty;
1744        }
1745
1746        public boolean isDataProperty(String propertyURI){
1747                if(propertyURI.equals("http://www.w3.org/2000/01/rdf-schema#label")) return true;
1748                String query = String.format("ASK {<%s> a <%s>}", propertyURI, OWL.DatatypeProperty.getURI());
1749                boolean isDataProperty = executeAskQuery(query);
1750                return isDataProperty;
1751        }
1752
1753        public boolean isDataProperty(String propertyURI, boolean analyzeData){
1754                if(propertyURI.equals("http://www.w3.org/2000/01/rdf-schema#label")) return true;
1755                String query = String.format("ASK {<%s> a <%s>}", propertyURI, OWL.DatatypeProperty.getURI());
1756                boolean isDataProperty = executeAskQuery(query);
1757                if(!isDataProperty && analyzeData){
1758                        query = String.format("ASK {?s <%s> ?o.FILTER(isLITERAL(?o))}", propertyURI);
1759                        isDataProperty = executeAskQuery(query);
1760                }
1761                return isDataProperty;
1762        }
1763
1764        public int getIndividualsCount(OWLClass cls){
1765                String query = String.format("SELECT (COUNT(?s) AS ?cnt) WHERE {?s a <%s>.}", cls.toStringID());
1766                ResultSet rs = executeSelectQuery(query);
1767                int cnt = rs.next().get(rs.getResultVars().get(0)).asLiteral().getInt();
1768                return cnt;
1769
1770        }
1771
1772        public int getPropertyCount(OWLObjectProperty property){
1773                String query = String.format("SELECT (COUNT(*) AS ?cnt) WHERE {?s <%s> ?o.}", property.toStringID());
1774                ResultSet rs = executeSelectQuery(query);
1775                int cnt = rs.next().get(rs.getResultVars().get(0)).asLiteral().getInt();
1776                return cnt;
1777
1778        }
1779
1780        public SortedSet<OWLObjectProperty> getInverseObjectProperties(OWLObjectProperty property){
1781                SortedSet<OWLObjectProperty> inverseObjectProperties = new TreeSet<>();
1782                String query = "SELECT ?p WHERE {" +
1783                                "{<%p> <%ax> ?p.} UNION {?p <%ax> <%p>}}".replace("%p", property.toStringID()).replace("%ax", OWL.inverseOf.getURI());
1784                ResultSet rs = executeSelectQuery(query);
1785                QuerySolution qs;
1786                while(rs.hasNext()){
1787                        qs = rs.next();
1788                        inverseObjectProperties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI())));
1789
1790                }
1791                return inverseObjectProperties;
1792        }
1793
1794        @Override
1795        public OWLDataRange getRangeImpl(OWLDataProperty datatypeProperty) {
1796                String query = String.format("SELECT ?range WHERE {" +
1797                                "<%s> <%s> ?range. FILTER(isIRI(?range))" +
1798                                "}",
1799                                datatypeProperty.toStringID(), RDFS.range.getURI());
1800
1801                ResultSet rs = executeSelectQuery(query);
1802                QuerySolution qs;
1803                OWLDataRange range = null;
1804                while(rs.hasNext()){
1805                        qs = rs.next();
1806                        range = df.getOWLDatatype(IRI.create(qs.getResource("range").getURI()));
1807
1808                }
1809                return range == null ? df.getOWLDatatype(OWL2Datatype.RDFS_LITERAL.getIRI()) : range;
1810        }
1811
1812        @Override
1813        public boolean isSuperClassOfImpl(OWLClassExpression superClass, OWLClassExpression subClass) {
1814                if(subClass.isAnonymous() || superClass.isAnonymous()){
1815//                      throw new IllegalArgumentException("Only named classes are supported.");
1816                        return false;
1817                }
1818                String query = String.format("ASK {<%s> <%s> <%s>.}",
1819                                ((OWLClass)subClass).toStringID(),
1820                                RDFS.subClassOf.getURI(),
1821                                ((OWLClass)superClass).toStringID());
1822                boolean superClassOf = executeAskQuery(query);
1823                return superClassOf;
1824        }
1825
1826        @Override
1827        public boolean isEquivalentClassImpl(OWLClassExpression class1, OWLClassExpression class2) {
1828                if(class1.isAnonymous() || class2.isAnonymous()){
1829//                      throw new IllegalArgumentException("Only named classes are supported.");
1830                        return false;
1831                }
1832                String query = String.format("ASK {<%s> <%s> <%s>.}",
1833                                ((OWLClass)class1).toStringID(),
1834                                OWL.equivalentClass.getURI(),
1835                                ((OWLClass)class2).toStringID());
1836                boolean equivalentClass = executeAskQuery(query);
1837                return equivalentClass;
1838        }
1839
1840        @Override
1841        public Set<OWLClassExpression> getAssertedDefinitions(OWLClass cls) {
1842                // currently we are not able to do this because of the blank node style representation of complex class expressions in RDF
1843                return Collections.emptySet();
1844//              Set<OWLClassExpression> definitions = new HashSet<OWLClassExpression>();
1845//              String query = String.format(SPARQLQueryUtils.SELECT_EQUIVALENT_CLASSES_QUERY, cls.toStringID(), cls.toStringID());
1846//
1847//              ResultSet rs = executeSelectQuery(query);
1848//              QuerySolution qs;
1849//              while(rs.hasNext()){
1850//                      qs = rs.next();
1851////                    definitions.add(df.getOWLClass(IRI.create(qs.getResource("class").getURI())));
1852//              }
1853//              return definitions;
1854        }
1855
1856        @Override
1857        public Set<OWLClassExpression> isSuperClassOfImpl(Set<OWLClassExpression> superClasses, OWLClassExpression subClasses) {
1858                // TODO Auto-generated method stub
1859                return null;
1860        }
1861
1862        
1863        public SortedSet<OWLClassExpression> getMostGeneralClasses() {
1864                return hierarchy.getMostGeneralClasses();
1865        }
1866        
1867        public SortedSet<OWLClass> getMostSpecificClasses() {
1868                SortedSet<OWLClass> classes = new TreeSet<>();
1869                String query = "SELECT ?cls WHERE {?cls a <http://www.w3.org/2002/07/owl#Class>. "
1870                                + "FILTER NOT EXISTS{?sub <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?cls. FILTER(?sub != <http://www.w3.org/2002/07/owl#Nothing>)}}";
1871                ResultSet rs = executeSelectQuery(query);
1872                QuerySolution qs;
1873                while(rs.hasNext()){
1874                        qs = rs.next();
1875                        classes.add(df.getOWLClass(IRI.create(qs.getResource("cls").getURI())));
1876                }
1877                return classes;
1878        }
1879
1880        @Override
1881        public SortedSet<OWLClassExpression> getSuperClassesImpl(OWLClassExpression description) {
1882                String query;
1883                if(description.isAnonymous()){
1884                        throw new IllegalArgumentException("Only named classes are supported.");
1885                } else if(description.isOWLThing()) {
1886                        return Sets.newTreeSet();
1887                } else if(description.isOWLNothing()) {
1888                        query = SPARQLQueryUtils.SELECT_LEAF_CLASSES_OWL;
1889                } else {
1890                        query = String.format(
1891                                        SPARQLQueryUtils.SELECT_DIRECT_SUPERCLASS_OF_QUERY,
1892                                        description.asOWLClass().toStringID()
1893                                        );
1894                }
1895                
1896                ResultSet rs = executeSelectQuery(query);
1897                
1898                SortedSet<OWLClass> superClasses = asOWLEntities(EntityType.CLASS, rs, "var1");
1899                superClasses.remove(description);
1900//              System.out.println("Sup(" + description + "):" + superClasses);
1901                return new TreeSet<OWLClassExpression>(superClasses);
1902        }
1903
1904        public SortedSet<OWLClassExpression> getSuperClasses(OWLClassExpression description, boolean direct){
1905                if(description.isAnonymous()){
1906                        throw new IllegalArgumentException("Only named classes are supported.");
1907                }
1908                SortedSet<OWLClassExpression> superClasses = new TreeSet<>();
1909                String query;
1910                if(direct){
1911                        query = String.format("SELECT ?sup {<%s> <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?sup. FILTER(isIRI(?sup))}",
1912                                        description.asOWLClass().toStringID());
1913                } else {
1914                        query = String.format("SELECT ?sup {<%s> <http://www.w3.org/2000/01/rdf-schema#subClassOf>* ?sup. FILTER(isIRI(?sup))}",
1915                                        description.asOWLClass().toStringID());
1916                }
1917                ResultSet rs = executeSelectQuery(query);
1918                QuerySolution qs;
1919                while(rs.hasNext()){
1920                        qs = rs.next();
1921                        superClasses.add(df.getOWLClass(IRI.create(qs.getResource("sup").getURI())));
1922                }
1923                superClasses.remove(description);
1924
1925                return superClasses;
1926        }
1927
1928        @Override
1929        public SortedSet<OWLClassExpression> getSubClassesImpl(OWLClassExpression description) {
1930                return getSubClasses(description, true);
1931        }
1932
1933        public SortedSet<OWLClassExpression> getSubClasses(OWLClassExpression description, boolean direct) {
1934                if(description.isAnonymous()){
1935                        throw new IllegalArgumentException("Only named classes are supported.");
1936                }
1937                SortedSet<OWLClassExpression> subClasses = new TreeSet<>();
1938                        
1939                        String query;
1940                        if(description.isOWLThing()) {
1941                                query = SPARQLQueryUtils.SELECT_TOP_LEVEL_OWL_CLASSES;
1942                        } else {
1943                                query = String.format(SPARQLQueryUtils.SELECT_SUBCLASS_OF_QUERY, description.asOWLClass().toStringID());
1944                                if(direct){
1945                                        
1946                                } else {
1947                                        
1948                                }
1949                        }
1950                        
1951                        ResultSet rs = executeSelectQuery(query);
1952                        subClasses.addAll(asOWLEntities(EntityType.CLASS, rs, "var1"));
1953
1954                subClasses.remove(description);
1955                subClasses.remove(df.getOWLNothing());
1956//              System.out.println("Sub(" + description + "):" + subClasses);
1957                return new TreeSet<>(subClasses);
1958        }
1959        
1960        public boolean isSuperClassOf(OWLClass sup, OWLClass sub, boolean direct) {
1961                String query = direct ? SPARQLQueryUtils.SELECT_SUPERCLASS_OF_QUERY : SPARQLQueryUtils.SELECT_SUPERCLASS_OF_QUERY_RDFS;
1962                query = String.format(query, sub.toStringID());
1963                ResultSet rs = executeSelectQuery(query);
1964                SortedSet<OWLClass> superClasses = asOWLEntities(EntityType.CLASS, rs, "var1");
1965                return superClasses.contains(sup);
1966        }
1967
1968        @Override
1969        public SortedSet<OWLObjectProperty> getSuperPropertiesImpl(OWLObjectProperty objectProperty) {
1970                SortedSet<OWLObjectProperty> properties = new TreeSet<>();
1971                String query = String.format(
1972                                SPARQLQueryUtils.SELECT_SUPERPROPERTY_OF_QUERY,
1973                                objectProperty.toStringID()
1974                                );
1975                ResultSet rs = executeSelectQuery(query);
1976                QuerySolution qs;
1977                while(rs.hasNext()){
1978                        qs = rs.next();
1979                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("var1").getURI())));
1980                }
1981                properties.remove(objectProperty);
1982                properties.remove(df.getOWLTopObjectProperty());
1983                return properties;
1984        }
1985
1986        @Override
1987        public SortedSet<OWLObjectProperty> getSubPropertiesImpl(OWLObjectProperty objectProperty) {
1988                SortedSet<OWLObjectProperty> properties = new TreeSet<>();
1989                String query = String.format(
1990                                SPARQLQueryUtils.SELECT_SUBPROPERTY_OF_QUERY,
1991                                objectProperty.toStringID()
1992                                );
1993                ResultSet rs = executeSelectQuery(query);
1994                QuerySolution qs;
1995                while(rs.hasNext()){
1996                        qs = rs.next();
1997                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("var1").getURI())));
1998                }
1999                properties.remove(objectProperty);
2000                properties.remove(df.getOWLBottomObjectProperty());
2001                return properties;
2002        }
2003
2004        public SortedSet<OWLObjectProperty> getEquivalentProperties(OWLObjectProperty objectProperty) {
2005                SortedSet<OWLObjectProperty> properties = new TreeSet<>();
2006                String query = String.format(
2007                                SPARQLQueryUtils.SELECT_EQUIVALENT_PROPERTIES_QUERY, objectProperty.toStringID(), objectProperty.toStringID()
2008                                );
2009                ResultSet rs = executeSelectQuery(query);
2010                QuerySolution qs;
2011                while(rs.hasNext()){
2012                        qs = rs.next();
2013                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("var1").getURI())));
2014                }
2015                return properties;
2016        }
2017        
2018        public SortedSet<OWLObjectProperty> getDisjointProperties(OWLObjectProperty objectProperty) {
2019                SortedSet<OWLObjectProperty> properties = new TreeSet<>();
2020                String query = String.format(
2021                                SPARQLQueryUtils.SELECT_DISJOINT_PROPERTIES_QUERY,
2022                                objectProperty.toStringID(), objectProperty.toStringID()
2023                                );
2024                ResultSet rs = executeSelectQuery(query);
2025                QuerySolution qs;
2026                while(rs.hasNext()){
2027                        qs = rs.next();
2028                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("var1").getURI())));
2029                }
2030                return properties;
2031        }
2032
2033        public SortedSet<OWLDataProperty> getEquivalentProperties(OWLDataProperty objectProperty) {
2034                SortedSet<OWLDataProperty> superProperties = new TreeSet<>();
2035                String query = String.format(
2036                                SPARQLQueryUtils.SELECT_EQUIVALENT_PROPERTIES_QUERY,
2037                                objectProperty.toStringID(), objectProperty.toStringID()
2038                                );
2039                ResultSet rs = executeSelectQuery(query);
2040                QuerySolution qs;
2041                while(rs.hasNext()){
2042                        qs = rs.next();
2043                        superProperties.add(df.getOWLDataProperty(IRI.create(qs.getResource("var1").getURI())));
2044                }
2045                return superProperties;
2046        }
2047
2048        @Override
2049        public SortedSet<OWLDataProperty> getSuperPropertiesImpl(OWLDataProperty dataProperty) {
2050                SortedSet<OWLDataProperty> properties = new TreeSet<>();
2051                String query = String.format(
2052                                SPARQLQueryUtils.SELECT_SUPERPROPERTY_OF_QUERY,
2053                                dataProperty.toStringID()
2054                                );
2055                ResultSet rs = executeSelectQuery(query);
2056                QuerySolution qs;
2057                while(rs.hasNext()){
2058                        qs = rs.next();
2059                        properties.add(df.getOWLDataProperty(IRI.create(qs.getResource("var1").getURI())));
2060                }
2061                properties.remove(dataProperty);
2062                properties.remove(df.getOWLTopDataProperty());
2063                return properties;
2064        }
2065
2066        @Override
2067        public SortedSet<OWLDataProperty> getSubPropertiesImpl(OWLDataProperty dataProperty) {
2068                SortedSet<OWLDataProperty> properties = new TreeSet<>();
2069                String query = String.format(
2070                                SPARQLQueryUtils.SELECT_SUPERPROPERTY_OF_QUERY,
2071                                dataProperty.toStringID()
2072                                );
2073                ResultSet rs = executeSelectQuery(query);
2074                QuerySolution qs;
2075                while(rs.hasNext()){
2076                        qs = rs.next();
2077                        properties.add(df.getOWLDataProperty(IRI.create(qs.getResource("var1").getURI())));
2078                }
2079                properties.remove(dataProperty);
2080                properties.remove(df.getOWLBottomDataProperty());
2081                return properties;
2082        }
2083        
2084        public SortedSet<OWLDataProperty> getDisjointProperties(OWLDataProperty dataProperty) {
2085                SortedSet<OWLDataProperty> properties = new TreeSet<>();
2086                String query = String.format(
2087                                SPARQLQueryUtils.SELECT_DISJOINT_PROPERTIES_QUERY,
2088                                dataProperty.toStringID(), dataProperty.toStringID()
2089                                );
2090                ResultSet rs = executeSelectQuery(query);
2091                QuerySolution qs;
2092                while(rs.hasNext()){
2093                        qs = rs.next();
2094                        properties.add(df.getOWLDataProperty(IRI.create(qs.getResource("var1").getURI())));
2095                }
2096                properties.remove(dataProperty);
2097                return properties;
2098        }
2099        
2100        /* (non-Javadoc)
2101         * @see org.dllearner.core.AbstractReasonerComponent#getObjectPropertyDomains()
2102         */
2103        @Override
2104        public Map<OWLObjectProperty, OWLClassExpression> getObjectPropertyDomains() {
2105                Map<OWLObjectProperty, OWLClassExpression> result = new HashMap<>();
2106                
2107                String query = SPARQLQueryUtils.PREFIXES + "SELECT ?p ?dom WHERE {?p a owl:ObjectProperty . OPTIONAL{?p rdfs:domain ?dom .}}";
2108                ResultSet rs = executeSelectQuery(query);
2109                while(rs.hasNext()) {
2110                        QuerySolution qs = rs.next();
2111                        OWLObjectProperty op = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
2112                        
2113                        // default domain is owl:Thing
2114                        OWLClassExpression domain = df.getOWLThing();
2115                        if(qs.get("dom") != null) {
2116                                if(qs.get("dom").isURIResource()) {
2117                                        domain = df.getOWLClass(IRI.create(qs.getResource("dom").getURI()));
2118                                        
2119                                } else {
2120                                        logger.warn("Can not resolve complex domain for object property " + op);
2121                                }
2122                        }
2123                        result.put(op, domain);
2124                }
2125                return result;
2126        }
2127        
2128        /* (non-Javadoc)
2129         * @see org.dllearner.core.AbstractReasonerComponent#getObjectPropertyRanges()
2130         */
2131        @Override
2132        public Map<OWLObjectProperty, OWLClassExpression> getObjectPropertyRanges() {
2133                Map<OWLObjectProperty, OWLClassExpression> result = new HashMap<>();
2134                
2135                String query = SPARQLQueryUtils.PREFIXES + "SELECT ?p ?ran WHERE {?p a owl:ObjectProperty . OPTIONAL{?p rdfs:range ?ran .}}";
2136                ResultSet rs = executeSelectQuery(query);
2137                while(rs.hasNext()) {
2138                        QuerySolution qs = rs.next();
2139                        OWLObjectProperty op = df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI()));
2140                        
2141                        // default range is owl:Thing
2142                        OWLClassExpression range = df.getOWLThing();
2143                        if (qs.get("ran") != null) {
2144                                if(qs.get("ran").isURIResource()) {
2145                                        range = df.getOWLClass(IRI.create(qs.getResource("ran").getURI()));
2146                                } else {
2147                                        logger.warn("Can not resolve complex range for object property " + op);
2148                                }
2149                        }
2150                        result.put(op, range);
2151                }
2152                return result;
2153        }
2154        
2155        /* (non-Javadoc)
2156         * @see org.dllearner.core.AbstractReasonerComponent#getDataPropertyDomains()
2157         */
2158        @Override
2159        public Map<OWLDataProperty, OWLClassExpression> getDataPropertyDomains() {
2160                Map<OWLDataProperty, OWLClassExpression> result = new HashMap<>();
2161                
2162                String query = SPARQLQueryUtils.PREFIXES + "SELECT ?p ?dom WHERE {?p a owl:DatatypeProperty . OPTIONAL{?p rdfs:domain ?dom .}}";
2163                ResultSet rs = executeSelectQuery(query);
2164                while(rs.hasNext()) {
2165                        QuerySolution qs = rs.next();
2166                        OWLDataProperty dp = df.getOWLDataProperty(IRI.create(qs.getResource("p").getURI()));
2167                        
2168                        // default domain is owl:Thing
2169                        OWLClassExpression domain = df.getOWLThing();
2170                        if (qs.get("dom") != null) {
2171                                if (qs.get("dom").isURIResource()) {
2172                                        domain = df.getOWLClass(IRI.create(qs.getResource("dom").getURI()));
2173
2174                                } else {
2175                                        logger.warn("Can not resolve complex domain for data property " + dp);
2176                                }
2177                        }
2178                        result.put(dp, domain);
2179                }
2180                return result;
2181        }
2182
2183
2184
2185
2186        public SortedSet<OWLClassExpression> getMeaningfulClasses(OWLClassExpression index, SortedSet<OWLClassExpression> targetClasses) {
2187                String query = buildMeaningfulClassesQuery(index, targetClasses);
2188                if (logger.isDebugEnabled()) logger.debug(sparql_debug, query);
2189
2190                SortedSet<OWLClassExpression> meaningfulClasses = new TreeSet<>();
2191                ResultSet rs = executeSelectQuery(query);
2192                while(rs.hasNext()) {
2193                        QuerySolution qs = rs.next();
2194                        meaningfulClasses.add(df.getOWLClass(IRI.create(qs.getResource("concept").getURI())));
2195                }
2196                return meaningfulClasses;
2197        }
2198
2199        protected String buildMeaningfulClassesQuery(OWLClassExpression index, SortedSet<OWLClassExpression> targetClasses) {
2200                String query = "SELECT DISTINCT ?concept WHERE {";
2201                query += converter.convert("?ind", index);
2202                query += "?ind a ?concept . ";
2203                query += "VALUES ?concept {"
2204                                + targetClasses.stream().map(ce -> "<" + ce.asOWLClass().toStringID() + ">").collect(Collectors.joining(" "))
2205                                + "}";
2206                query += "}";
2207                return query;
2208        }
2209
2210
2211        /**
2212         * Convert a SPARQL resultset into OWL entities based on the given entity type.
2213         * @param entityType the entity type
2214         * @param rs the Jena resultset
2215         * @param var the var name in the resultset
2216         * @return a set of entities of the given entity type
2217         */
2218        private <E extends OWLEntity> SortedSet<E> asOWLEntities(EntityType<E> entityType, ResultSet rs, String var) {
2219                Collection<IRI> entityIRIs = new HashSet<>();
2220                while(rs.hasNext()) {
2221                        QuerySolution qs = rs.next();
2222                        Resource resource = qs.getResource(var);
2223                        if(resource.isURIResource()) {
2224                                entityIRIs.add(IRI.create(resource.getURI()));
2225                        }
2226                }
2227                return asOWLEntities(entityType, entityIRIs);
2228        }
2229        
2230        /**
2231         * Convert a collection of IRIs into OWL entities based on the given entity type.
2232         * @param entityType the entity type
2233         * @param entityIRIs the entity IRIs
2234         * @return a set of entities of the given entity type
2235         */
2236        private <E extends OWLEntity> SortedSet<E> asOWLEntities(EntityType<E> entityType, Collection<IRI> entityIRIs) {
2237                SortedSet<E> entities = new TreeSet<>();
2238                for (IRI iri : entityIRIs) {
2239                        if(!iri.isReservedVocabulary()) {
2240                                entities.add(df.getOWLEntity(entityType, iri));
2241                        }
2242                }
2243                
2244                // remove top and bottom entities
2245                entities.remove(df.getOWLThing());
2246                entities.remove(df.getOWLNothing());
2247                entities.remove(df.getOWLTopObjectProperty());
2248                entities.remove(df.getOWLBottomObjectProperty());
2249                entities.remove(df.getOWLTopDataProperty());
2250                entities.remove(df.getOWLBottomDataProperty());
2251                
2252                return entities;
2253        }
2254
2255        protected ResultSet executeSelectQuery(String queryString, long timeout, TimeUnit timeoutUnits){
2256                if (logger.isTraceEnabled()) {
2257                        logger.trace("Sending query \n {}", queryString);
2258                }
2259                try(QueryExecution qe = qef.createQueryExecution(queryString)) {
2260                        qe.setTimeout(timeout, timeoutUnits);
2261                        ResultSet rs = qe.execSelect();
2262                        return ResultSetFactory.copyResults(rs);
2263                } catch (QueryExceptionHTTP e) {
2264                        throw new QueryExceptionHTTP("Error sending query \"" + queryString + "\" to endpoint " + qef.getId(), e);
2265                } catch (Exception e) {
2266                        throw new RuntimeException("Error sending query \"" + queryString + "\" to endpoint " + qef.getId(), e);
2267                }
2268        }
2269        
2270        protected ResultSet executeSelectQuery(String queryString) {
2271                return executeSelectQuery(queryString, -1, TimeUnit.MILLISECONDS);
2272        }
2273        
2274        protected boolean executeAskQuery(String queryString){
2275                if (logger.isTraceEnabled()) logger.trace("Sending query \n {}", queryString);
2276                try(QueryExecution qe = qef.createQueryExecution(queryString)) {
2277                        boolean ret = qe.execAsk();
2278                        qe.close();
2279                        return ret;
2280                } catch (QueryExceptionHTTP e)  {
2281                        throw new QueryExceptionHTTP("Error sending query \"" + queryString + "\" to endpoint " + qef.getId(), e);
2282                } catch (Exception e) {
2283                        throw new RuntimeException("Error sending query \"" + queryString + "\" to endpoint " + qef.getId(), e);
2284                }
2285        }
2286
2287        /**
2288         * @return TRUE if the class hierarchy was computed before, otherwise FALSE
2289         */
2290        public boolean isPrepared(){
2291                return hierarchy != null;
2292        }
2293
2294        public boolean supportsSPARQL1_1(){
2295                try {
2296                        String query = "SELECT ?s WHERE {?s a <http://foo.org/A> . FILTER NOT EXISTS {?s a <http://foo.org/B>}} LIMIT 1";
2297                        ResultSet rs = executeSelectQuery(query);
2298                        return true;
2299                } catch (Exception e) {
2300                        logger.error("Endpoint does not support SPARQL 1.1, e.g. FILTER NOT EXISTS", e);
2301                }
2302                return false;
2303        }
2304
2305        /* (non-Javadoc)
2306         * @see org.dllearner.core.BaseReasoner#getBaseURI()
2307         */
2308        @Override
2309        public String getBaseURI() {
2310                return null;
2311        }
2312
2313        /* (non-Javadoc)
2314         * @see org.dllearner.core.BaseReasoner#getPrefixes()
2315         */
2316        @Override
2317        public Map<String, String> getPrefixes() {
2318                return null;
2319        }
2320        
2321        /* (non-Javadoc)
2322         * @see org.dllearner.core.AbstractReasonerComponent#remainsSatisfiableImpl(org.semanticweb.owlapi.model.OWLAxiom)
2323         */
2324        @Override
2325        protected boolean remainsSatisfiableImpl(OWLAxiom axiom) throws ReasoningMethodUnsupportedException {
2326                return true;
2327        }
2328
2329        /* (non-Javadoc)
2330         * @see org.dllearner.core.AbstractReasonerComponent#getReasonerType()
2331         */
2332        @Override
2333        public ReasonerType getReasonerType() {
2334                return ReasonerType.SPARQL_NATIVE;
2335        }
2336
2337        /* (non-Javadoc)
2338         * @see org.dllearner.core.AbstractReasonerComponent#releaseKB()
2339         */
2340        @Override
2341        public void releaseKB() {
2342        }
2343
2344        public boolean isLaxMode() {
2345                return laxMode;
2346        }
2347
2348        public void setLaxMode(boolean laxMode) {
2349                this.laxMode = laxMode;
2350        }
2351        
2352        public boolean isUseGenericSplitsCode() {
2353                return useGenericSplitsCode;
2354        }
2355
2356        public void setUseGenericSplitsCode(boolean useGenericSplitsCode) {
2357                this.useGenericSplitsCode = useGenericSplitsCode;
2358        }
2359
2360        /* (non-Javadoc)
2361         * @see org.dllearner.core.AbstractReasonerComponent#getDatatype(org.semanticweb.owlapi.model.OWLDataProperty)
2362         */
2363        @Override
2364        public OWLDatatype getDatatype(OWLDataProperty dp) {
2365                // get the range of the property
2366                OWLDataRange range = getRangeImpl(dp);
2367
2368                // if range is a datatype return this
2369                if(range != null && range.isDatatype()) {
2370                        return range.asOWLDatatype();
2371                }
2372
2373                // otherwise, return xsd:string as default datatype
2374                return XSD.STRING;
2375        }
2376
2377        /* (non-Javadoc)
2378         * @see org.dllearner.core.AbstractReasonerComponent#setSynchronized()
2379         */
2380        @Override @NoConfigOption
2381        public void setSynchronized() {
2382                throw new NotImplementedException("Method setSynchronized() not implemented yet!");
2383        }
2384
2385        public boolean isUseValueLists() {
2386                return useValueLists;
2387        }
2388
2389        public void setUseValueLists(boolean useValueLists) {
2390                this.useValueLists = useValueLists;
2391        }
2392
2393        public boolean isPreferAsk() {
2394                return preferAsk;
2395        }
2396
2397        public void setPreferAsk(boolean preferAsk) {
2398                this.preferAsk = preferAsk;
2399        }
2400}