Source code for ontolearn.ea_utils

# -----------------------------------------------------------------------------
# MIT License
#
# Copyright (c) 2024 Ontolearn Team
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# -----------------------------------------------------------------------------

"""Utils for evolutionary algorithms."""

from enum import Enum
from typing import Callable, Final, List, Optional, Tuple, Union

from deap.gp import Primitive, Terminal
from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClassExpression, OWLDataHasValue, \
    OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectIntersectionOf, OWLObjectExactCardinality, \
    OWLObjectMaxCardinality, OWLObjectMinCardinality
from owlapy.owl_literal import OWLLiteral, NUMERIC_DATATYPES
from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataPropertyExpression, OWLDataProperty, \
    OWLObjectProperty

from ontolearn.concept_generator import ConceptGenerator
import re

from owlapy.providers import owl_datatype_min_exclusive_restriction, owl_datatype_min_inclusive_restriction, \
    owl_datatype_max_exclusive_restriction, owl_datatype_max_inclusive_restriction


Tree = List[Union[Primitive, Terminal]]


[docs] class PrimitiveFactory: __slots__ = 'generator' def __init__(self): self.generator = ConceptGenerator()
[docs] def create_union(self) -> Callable[[OWLClassExpression, OWLClassExpression], OWLObjectUnionOf]: def union(A: OWLClassExpression, B: OWLClassExpression) -> OWLObjectUnionOf: return self.generator.union([A, B]) return union
[docs] def create_intersection(self) -> Callable[[OWLClassExpression, OWLClassExpression], OWLObjectIntersectionOf]: def intersection(A: OWLClassExpression, B: OWLClassExpression) -> OWLObjectIntersectionOf: return self.generator.intersection([A, B]) return intersection
[docs] def create_existential_universal(self, property_: OWLObjectPropertyExpression) \ -> Tuple[Callable[[OWLClassExpression], OWLObjectSomeValuesFrom], Callable[[OWLClassExpression], OWLObjectAllValuesFrom]]: def existential_restriction(filler: OWLClassExpression) -> OWLObjectSomeValuesFrom: return self.generator.existential_restriction(filler, property_) def universal_restriction(filler: OWLClassExpression) -> OWLObjectAllValuesFrom: return self.generator.universal_restriction(filler, property_) return existential_restriction, universal_restriction
[docs] def create_card_restrictions(self, property_: OWLObjectPropertyExpression) \ -> Tuple[Callable[[int, OWLClassExpression], OWLObjectMinCardinality], Callable[[int, OWLClassExpression], OWLObjectMaxCardinality], Callable[[int, OWLClassExpression], OWLObjectExactCardinality]]: def min_cardinality(card: int, filler: OWLClassExpression) -> OWLObjectMinCardinality: return self.generator.min_cardinality_restriction(filler, property_, card) def max_cardinality(card: int, filler: OWLClassExpression) -> OWLObjectMaxCardinality: return self.generator.max_cardinality_restriction(filler, property_, card) def exact_cardinality(card: int, filler: OWLClassExpression) -> OWLObjectExactCardinality: return self.generator.exact_cardinality_restriction(filler, property_, card) return min_cardinality, max_cardinality, exact_cardinality
[docs] def create_data_some_values(self, property_: OWLDataPropertyExpression) \ -> Tuple[Callable[[OWLLiteral], OWLDataSomeValuesFrom], Callable[[OWLLiteral], OWLDataSomeValuesFrom], Callable[[OWLLiteral], OWLDataSomeValuesFrom], Callable[[OWLLiteral], OWLDataSomeValuesFrom]]: def data_some_min_inclusive(value: OWLLiteral) -> OWLDataSomeValuesFrom: filler = owl_datatype_min_inclusive_restriction(value) return self.generator.data_existential_restriction(filler, property_) def data_some_max_inclusive(value: OWLLiteral) -> OWLDataSomeValuesFrom: filler = owl_datatype_max_inclusive_restriction(value) return self.generator.data_existential_restriction(filler, property_) def data_some_min_exclusive(value: OWLLiteral) -> OWLDataSomeValuesFrom: filler = owl_datatype_min_exclusive_restriction(value) return self.generator.data_existential_restriction(filler, property_) def data_some_max_exclusive(value: OWLLiteral) -> OWLDataSomeValuesFrom: filler = owl_datatype_max_exclusive_restriction(value) return self.generator.data_existential_restriction(filler, property_) return data_some_min_inclusive, data_some_max_inclusive, data_some_min_exclusive, data_some_max_exclusive
[docs] def create_data_has_value(self, property_: OWLDataPropertyExpression) -> Callable[[OWLLiteral], OWLDataHasValue]: def data_has_value(value: OWLLiteral) -> OWLDataHasValue: return self.generator.data_has_value_restriction(value, property_) return data_has_value
[docs] class OperatorVocabulary(str, Enum): UNION: Final = "union" #: INTERSECTION: Final = "intersection" #: NEGATION: Final = "negation" #: EXISTENTIAL: Final = "exists" #: UNIVERSAL: Final = "forall" #: INVERSE: Final = "inverse" #: CARD_MIN: Final = "cardMin" #: CARD_MAX: Final = "cardMax" #: CARD_EXACT: Final = "cardExact" #: DATA_MIN_INCLUSIVE: Final = "dataMinInc" #: DATA_MAX_INCLUSIVE: Final = "dataMaxInc" #: DATA_MIN_EXCLUSIVE: Final = "dataMinExc" #: DATA_MAX_EXCLUSIVE: Final = "dataMaxExc" #: DATA_HAS_VALUE: Final = "dataHasValue" #:
[docs] class ToolboxVocabulary(str, Enum): MUTATION: Final = "mutate" #: CROSSOVER: Final = "mate" #: SELECTION: Final = "select" #: COMPILE: Final = "compile" #: INIT_POPULATION: Final = "population" #: FITNESS_FUNCTION: Final = "apply_fitness" #: HEIGHT_KEY: Final = "height" #:
[docs] def escape(name: str) -> str: name = name.replace('-', 'minus') return re.sub(r'[\W+]', '', name)
[docs] def ind_to_string(ind: List[Tree]) -> str: return ''.join([prim.name for prim in ind])
# TODO: Ugly hack for now
[docs] def owlliteral_to_primitive_string(lit: OWLLiteral, pe: Optional[Union[OWLDataProperty, OWLObjectProperty]] = None) \ -> str: str_ = type(lit.to_python()).__name__ + escape(lit.get_literal()) if lit.get_datatype() in NUMERIC_DATATYPES: assert pe is not None return escape(pe.iri.get_remainder()) + str_ return str_