Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixing issue with OWLNothing + new parameter for OWLReasoner.instances #73

Merged
merged 4 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion owlapy/abstracts/abstract_owl_reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,14 @@ def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyE
pass

@abstractmethod
def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
def instances(self, ce: OWLClassExpression, direct: bool = False, timeout: int = 1000) -> Iterable[OWLNamedIndividual]:
"""Gets the individuals which are instances of the specified class expression.

Args:
ce: The class expression whose instances are to be retrieved.
direct: Specifies if the direct instances should be retrieved (True), or if all instances should be
retrieved (False).
timeout: Time limit in seconds until results must be returned, else empty set is returned.

Returns:
If direct is True, each named individual j where the set of reasoner axioms entails
Expand Down
34 changes: 28 additions & 6 deletions owlapy/owl_reasoner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""OWL Reasoner"""
import operator
import logging
import threading

import owlready2

from collections import defaultdict
Expand Down Expand Up @@ -35,6 +37,18 @@
_P = TypeVar('_P', bound=OWLPropertyExpression)


def run_with_timeout(func, timeout, args=(), kwargs={}):
result = [None]
thread = threading.Thread(target=lambda: result.append(func(*args, **kwargs)))
thread.start()
thread.join(timeout)
if thread.is_alive():
print(f"{func.__self__.__class__.__name__}.instances timed out! Timeout limit is currently set to {timeout} "
f"seconds\nReturning empty results...")
return []
return result[-1]


class OntologyReasoner(AbstractOWLReasonerEx):
__slots__ = '_ontology', '_world'
# TODO: CD: We will remove owlready2 from owlapy
Expand Down Expand Up @@ -198,7 +212,7 @@ def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyE
else:
raise NotImplementedError(pe)

def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
def _instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
if direct:
if isinstance(ce, OWLClass):
c_x: owlready2.ThingClass = self._world[ce.str]
Expand Down Expand Up @@ -226,6 +240,9 @@ def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OW
else:
raise NotImplementedError("instances for complex class expressions not implemented", ce)

def instances(self, ce: OWLClassExpression, direct: bool = False, timeout: int = 1000):
return run_with_timeout(self._instances, timeout, (ce, direct))

def _sub_classes_recursive(self, ce: OWLClassExpression, seen_set: Set, only_named: bool = True) \
-> Iterable[OWLClassExpression]:

Expand Down Expand Up @@ -690,14 +707,17 @@ def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyE
-> Iterable[OWLNamedIndividual]:
yield from self._base_reasoner.object_property_values(ind, pe, direct)

def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
def _instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
if direct:
if not self.__warned & 2:
logger.warning("direct not implemented")
self.__warned |= 2
temp = self._find_instances(ce)
yield from temp

def instances(self, ce: OWLClassExpression, direct: bool = False, timeout: int = 1000):
return run_with_timeout(self._instances, timeout, (ce, direct))

def sub_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: bool = True) \
-> Iterable[OWLClassExpression]:
yield from self._base_reasoner.sub_classes(ce, direct=direct, only_named=only_named)
Expand Down Expand Up @@ -1216,10 +1236,9 @@ def __init__(self, ontology: Union[SyncOntology, str], reasoner="HermiT"):
else:
raise NotImplementedError("Not implemented")

self.reasoner = reasoner

self.reasoner=reasoner

def instances(self, ce: OWLClassExpression, direct=False) -> Set[OWLNamedIndividual]:
def _instances(self, ce: OWLClassExpression, direct=False) -> Set[OWLNamedIndividual]:
"""
Get the instances for a given class expression using HermiT.

Expand All @@ -1230,12 +1249,15 @@ def instances(self, ce: OWLClassExpression, direct=False) -> Set[OWLNamedIndivid
Returns:
set: A set of individuals classified by the given class expression.
"""
mapped_ce=self.mapper.map_(ce)
mapped_ce = self.mapper.map_(ce)
instances = self._owlapi_reasoner.getInstances(mapped_ce, direct)
flattended_instances = instances.getFlattened()
assert str(type(flattended_instances)) == "<java class 'java.util.LinkedHashSet'>"
return {self.mapper.map_(ind) for ind in flattended_instances}

def instances(self, ce: OWLClassExpression, direct: bool = False, timeout: int = 1000):
return run_with_timeout(self._instances, timeout, (ce, direct))

def equivalent_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]:
"""
Gets the set of named classes that are equivalent to the specified class expression with
Expand Down
6 changes: 2 additions & 4 deletions owlapy/owlapi_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import jpype.imports

from owlapy import owl_expression_to_manchester, manchester_to_owl_expression
from owlapy.class_expression import OWLClassExpression, OWLDataOneOf, OWLFacetRestriction, OWLDatatypeRestriction, \
OWLNothing, OWLClass
from owlapy.class_expression import OWLClassExpression, OWLDataOneOf, OWLFacetRestriction, OWLDatatypeRestriction
from owlapy.iri import IRI
from owlapy.owl_axiom import OWLDeclarationAxiom, OWLAnnotation, OWLAnnotationProperty, OWLClassAssertionAxiom, \
OWLDataPropertyAssertionAxiom, OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, \
Expand Down Expand Up @@ -111,6 +110,7 @@ def __init__(self, ontology: _SO):
ontology_set.add(self.ontology)
bidi_provider = BidirectionalShortFormProviderAdapter(self.manager, ontology_set, SimpleShortFormProvider())
entity_checker = ShortFormEntityChecker(bidi_provider)
bidi_provider.add(self.manager.getOWLDataFactory().getOWLNothing())
self.parser = ManchesterOWLSyntaxClassExpressionParser(self.manager.getOWLDataFactory(), entity_checker)
self.renderer = ManchesterOWLSyntaxOWLObjectRendererImpl()

Expand Down Expand Up @@ -152,8 +152,6 @@ def _(self, e):

@map_.register
def _(self, e: OWLClassExpression):
if isinstance(e, OWLClass) and e.str == OWLNothing.str:
return OWLClassImpl(self.map_(e.iri))
return self.parser.parse(owl_expression_to_manchester(e))

@map_.register(OWLAnonymousClassExpressionImpl)
Expand Down
Loading