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