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

Test hashes #102

Merged
merged 7 commits into from
Nov 8, 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
85 changes: 40 additions & 45 deletions owlapy/class_expression/restriction.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ..owl_individual import OWLIndividual
from ..owl_datatype import OWLDatatype
from ..owl_object import OWLObject
from owlapy.vocab import OWLFacet
from ..vocab import OWLFacet
from datetime import datetime, date
from pandas import Timedelta

Expand Down Expand Up @@ -65,7 +65,7 @@ def __init__(self, value: _T):
def __eq__(self, other):
if type(other) is type(self):
return self._v == other._v
return NotImplemented
return False

def __hash__(self):
return hash(self._v)
Expand Down Expand Up @@ -272,10 +272,11 @@ def __repr__(self):
def __eq__(self, other):
if type(other) is type(self):
return self._filler == other._filler and self._property == other._property
return NotImplemented
else:
return False

def __hash__(self):
return hash((self._filler, self._property))
return hash(("OWLObjectSomeValuesFrom",self._filler, self._property))

def get_property(self) -> OWLObjectPropertyExpression:
# documented in parent
Expand Down Expand Up @@ -303,7 +304,7 @@ def __eq__(self, other):
return False

def __hash__(self):
return hash((self._filler, self._property))
return hash(("OWLObjectAllValuesFrom",self._filler, self._property))

def get_property(self) -> OWLObjectPropertyExpression:
# documented in parent
Expand Down Expand Up @@ -341,8 +342,9 @@ def __eq__(self, other):
else:
return False


def __hash__(self):
return hash(self._property)
return hash(("OWLObjectHasSelf", self._property))

def __repr__(self):
return f'OWLObjectHasSelf({self._property})'
Expand Down Expand Up @@ -428,16 +430,13 @@ def as_object_union_of(self) -> OWLClassExpression:
if len(self._values) == 1:
return self
return OWLObjectUnionOf(map(lambda _: OWLObjectOneOf(_), self.individuals()))

def __hash__(self):
return hash(self._values)

return hash(("OWLObjectOneOf", self._values))
def __eq__(self, other):
if type(other) is type(self):
return self._values == other._values
else:
return False

def __repr__(self):
return f'OWLObjectOneOf({self._values})'

Expand Down Expand Up @@ -485,25 +484,22 @@ def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler
assert isinstance(filler, OWLDataRange), "filler must be an OWLDataRange"
super().__init__(cardinality, filler)
self._property = property

def get_property(self) -> OWLDataPropertyExpression:
# documented in parent
return self._property

def __hash__(self):
return hash(("OWLDataCardinalityRestriction",self._property, self._cardinality, self._filler))
def __repr__(self):
return f"{type(self).__name__}(" \
f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})"

def __eq__(self, other):
if type(other) is type(self):
return self._property == other._property \
and self._cardinality == other._cardinality \
and self._filler == other._filler
return NotImplemented

def __hash__(self):
return hash((self._property, self._cardinality, self._filler))
return (self._property == other._property and self._cardinality == other._cardinality
and self._filler == other._filler)
else:
return False

def get_property(self) -> OWLDataPropertyExpression:
# documented in parent
return self._property

class OWLDataMinCardinality(OWLDataCardinalityRestriction):
"""A minimum cardinality expression DataMinCardinality( n DPE DR ) consists of a nonnegative integer n, a data
Expand Down Expand Up @@ -619,7 +615,7 @@ def __eq__(self, other):
else:
return False
def __hash__(self):
return hash((self._filler, self._property))
return hash(("OWLDataSomeValuesFrom",self._filler, self._property))

def get_property(self) -> OWLDataPropertyExpression:
# documented in parent
Expand Down Expand Up @@ -661,9 +657,8 @@ def __eq__(self, other):
return self._filler == other._filler and self._property == other._property
else:
return False

def __hash__(self):
return hash((self._filler, self._property))
return hash(("OWLDataAllValuesFrom",self._filler, self._property))

def get_property(self) -> OWLDataPropertyExpression:
# documented in parent
Expand Down Expand Up @@ -703,10 +698,10 @@ def __repr__(self):
def __eq__(self, other):
if type(other) is type(self):
return self._v == other._v and self._property == other._property
return NotImplemented

else:
return False
def __hash__(self):
return hash((self._v, self._property))
return hash(("OWLDataHasValue",self._v, self._property))

def as_some_values_from(self) -> OWLClassExpression:
"""A convenience method that obtains this restriction as an existential restriction with a nominal filler.
Expand Down Expand Up @@ -735,6 +730,17 @@ def __init__(self, values: Union[OWLLiteral, Iterable[OWLLiteral]]):
for _ in values:
assert isinstance(_, OWLLiteral)
self._values = tuple(values)
def __repr__(self):
return f'OWLDataOneOf({self._values})'

def __hash__(self):
return hash(("OWLDataOneOf",self._values))

def __eq__(self, other):
if type(other) is type(self):
return {i for i in self._values} == {j for j in other._values}
else:
return False
# TODO:CD: define it as @property as the name of the class method does not correspond to an action
def values(self) -> Iterable[OWLLiteral]:
"""Gets the values that are in the oneOf.
Expand All @@ -748,18 +754,6 @@ def operands(self) -> Iterable[OWLLiteral]:
# documented in parent
yield from self.values()

def __hash__(self):
return hash(self._values)

def __eq__(self, other):
if type(other) is type(self):
return {i for i in self._values} == {j for j in other._values}
else:
return False

def __repr__(self):
return f'OWLDataOneOf({self._values})'


class OWLDatatypeRestriction(OWLDataRange):
"""A datatype restriction DatatypeRestriction( DT F1 lt1 ... Fn ltn ) consists of a unary datatype DT and n pairs
Expand Down Expand Up @@ -792,10 +786,10 @@ def __eq__(self, other):
if type(other) is type(self):
return self._type == other._type \
and self._facet_restrictions == other._facet_restrictions
return NotImplemented

else:
return False
def __hash__(self):
return hash((self._type, self._facet_restrictions))
return hash(("OWLDatatypeRestriction", self._type, self._facet_restrictions))

def __repr__(self):
return f'OWLDatatypeRestriction({repr(self._type)}, {repr(self._facet_restrictions)})'
Expand Down Expand Up @@ -827,10 +821,11 @@ def get_facet_value(self) -> 'OWLLiteral':
def __eq__(self, other):
if type(other) is type(self):
return self._facet == other._facet and self._literal == other._literal
return NotImplemented
else:
return False

def __hash__(self):
return hash((self._facet, self._literal))
return hash(("OWLFacetRestriction",self._facet, self._literal))

def __repr__(self):
return f'OWLFacetRestriction({self._facet}, {repr(self._literal)})'
Expand Down
4 changes: 3 additions & 1 deletion owlapy/iri.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def __init__(self, namespace: Union[str, Namespaces], remainder: str=""):
else:
assert namespace[-1] in ("/", ":", "#"), "It should be a valid IRI based on /, :, and #"
import sys
# https://docs.python.org/3.2/library/sys.html?highlight=sys.intern#sys.intern
self._namespace = sys.intern(namespace)
self._remainder = remainder

Expand Down Expand Up @@ -94,7 +95,8 @@ def __repr__(self):
def __eq__(self, other):
if type(other) is type(self):
return self._namespace is other._namespace and self._remainder == other._remainder
return NotImplemented
else:
raise RuntimeError(f"Invalid equality checking:{self} cannot be compared with {other}")

def __hash__(self):
return hash((self._namespace, self._remainder))
Expand Down
4 changes: 3 additions & 1 deletion owlapy/owl_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ class OWLNamedObject(OWLObject, HasIRI, metaclass=ABCMeta):
def __eq__(self, other):
if type(other) is type(self):
return self._iri == other._iri
return NotImplemented
else:
return False
# raise RuntimeError(f"Invalid equality checking:{self} cannot be compared with {other}")

def __lt__(self, other):
if type(other) is type(self):
Expand Down
52 changes: 52 additions & 0 deletions tests/test_hashing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from owlapy.owl_property import OWLObjectProperty
from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom
from owlapy.converter import owl_expression_to_sparql
from owlapy.render import owl_expression_to_dl
from owlapy.iri import IRI
from owlapy.class_expression import OWLClass, OWLObjectUnionOf, OWLObjectIntersectionOf

class TestHashing:

def test_el_description_logic_hash(self):
"""
EL allows complex concepts of the following form:
C := \top | A | C1 u C2 | \existr.C
where A is a concept and r a role name.
For more, refer to https://www.emse.fr/~zimmermann/Teaching/KRR/el.html
"""
memory = dict()
# An OWL Class can be used as a key in a dictionary.
memory[OWLClass("http://example.com/father#A")] = OWLClass("http://example.com/father#A")
memory[OWLClass("http://example.com/father#B")] = OWLClass("http://example.com/father#B")
memory[OWLClass("http://example.com/father#C")] = OWLClass("http://example.com/father#C")

unions = set()
intersections = set()
for k, v in memory.items():
assert k == v
# An OWLObjectUnionOf over two OWL Classes can be added into a set.
unions.add(OWLObjectUnionOf((k, v)))
# Since the order doesn't matter in an OWLObjectUnionOf the following also holds
assert OWLObjectUnionOf((v, k)) in unions

# This also works for intersections.
intersections.add(OWLObjectIntersectionOf((k, v)))
# Since the order doesn't matter in an OWLObjectUnionOf the following also holds
assert OWLObjectIntersectionOf((v, k)) in intersections
# OWLObjectUnionOf and OWLObjectIntersectionOf can also be used as keys
for i in unions | intersections:
memory[i]=i
for k, v in memory.items():
assert k == v

atomic_concepts={OWLClass("http://example.com/father#A"),OWLClass("http://example.com/father#B")}
properties={OWLObjectProperty("http://example.com/society#hasChild")}
memory = dict()
for ac in atomic_concepts:
for op in properties:
# OWLObjectSomeValuesFrom can be used as a key.
memory[OWLObjectSomeValuesFrom(property=op, filler=ac)] = OWLObjectSomeValuesFrom(property=op, filler=ac)
memory[OWLObjectAllValuesFrom(property=op, filler=ac)] = OWLObjectAllValuesFrom(property=op, filler=ac)

for k, v in memory.items():
assert k == v
Loading