Source code for ontolearn.learners.spell_kit.o2p_ontology

SPECIAL_CHARS = {
    r"\sqsubseteq": "\u2291",
    r"\exists": "\u2203",
    r"\sqcap": "\u2293",
    r"\equiv": "\u2261",
    r"\top": "\u22A4",
}


[docs] class FeatureNotSupported(Exception): def __init__(self, *args): super(FeatureNotSupported, self).__init__(*args)
[docs] class Ontology(object): def __init__(self): self.__classes = {} self.__rules = [] # class rules self.__properties = [] self.__prop_sub = {} # property subclasses self.__prop_range = {} # property ranges self.__prop_domain = {} # property domains
[docs] def add_rule(self, rule): self.__rules.append(rule)
[docs] def normalize(self): result = Ontology() for rule in self.rules: for r in rule.normalize(): result.add_rule(r) for prop in self.properties: result.add_property(prop) return result
[docs] def add_property(self, prop): self.__prop_sub[prop.identifier] = prop.parent if prop.domain is not None: self.__prop_domain[prop.identifier] = prop.domain if prop.range is not None: self.__prop_range[prop.identifier] = prop.range elif prop.identifier not in self.__prop_range: self.__prop_range[prop.identifier] = TopClass() self.__properties.append(prop)
[docs] def check_implicit_cycle(self): for prop in self.__properties: pass
@property def properties(self): return iter(self.__properties) @property def rules(self): return iter(self.__rules) @property def subproperties(self): for sub, sups in self.__prop_sub.items(): for sup in sups: yield SubProperty(PropertyReference(sub), sup) @property def property_ranges(self): return iter(self.__prop_range.items()) @property def property_domains(self): return iter(self.__prop_domain.items())
[docs] def __iter__(self): return iter(self.__rules)
[docs] def __len__(self): return len(self.__rules)
[docs] class NameFactory(object): __i = 0 created_names = set()
[docs] @classmethod def next_name(cls): cls.__i += 1 name = "NC_%d" % cls.__i cls.created_names.add(name) return name
[docs] class OntologyObject(object): """The base class for all entities in the ontology."""
[docs] def to_latex(self): raise NotImplementedError()
[docs] def __repr__(self): return self.__str__()
@property def is_rule(self): return False
[docs] class SubProperty(object): def __init__(self, subject, object_): self.subject = subject self.object = object_
[docs] def __str__(self): return "%s %s %s" % (self.subject, SPECIAL_CHARS["\sqsubseteq"], self.object)
[docs] class Property(object): pass
[docs] class PropertyReference(Property): def __init__(self, identifier): self.identifier = identifier
[docs] def __str__(self): return self.identifier
[docs] class ObjectProperty(Property): def __init__( self, identifier, parent=None, is_functional=False, is_reflexive=False, is_inverse_functional=False, is_transitive=False, is_symmetric=False, domain=None, range=None, inverse_of=None, ): if parent is None: parent = [] self.identifier = identifier self.parent = parent self.is_functional = is_functional self.is_inverse_functional = is_inverse_functional self.is_transitive = is_transitive self.is_symmetric = is_symmetric self.is_reflexive = is_reflexive self.domain = domain self.range = range self.inverse_of = inverse_of
[docs] def __str__(self): if self.identifier is None and self.inverse_of is not None: return "{}-".format(self.inverse_of) return self.identifier
[docs] class Expression(OntologyObject): varcount = 0
[docs] @classmethod def get_safe_varname(cls): cls.varcount += 1 return "Y%d" % cls.varcount
expression_types = {}
[docs] @classmethod def register_type(cls, tagname, factory): cls.expression_types[tagname] = factory
[docs] @classmethod def get_factory(cls, tagname): return cls.expression_types.get(tagname)
def __init__(self, identifier=None): self.identifier = identifier
[docs] def normalize_rhs(self): raise NotImplementedError()
[docs] def normalize_lhs(self): return self, []
[docs] def __and__(self, other): return Intersection([self, other])
[docs] def __lshift__(self, other): return SubClassOf(self, other)
[docs] class Rule(OntologyObject): """A ontology expression of the form A \sqsubseteq B.""" def __init__(self, subject, object_): """ :param subject: :type subject: Expression :param object_: :type object_: Expression """ super(Rule, self).__init__() self.__subject = subject self.__object = object_ @property def subject(self): return self.__subject @subject.setter def subject(self, value): self.__subject = value @property def object(self): return self.__object @property def is_rule(self): return True
[docs] def normalize(self): """Return a normalization of this rule. :return: list of new rules """ raise FeatureNotSupported()
[docs] def issimple(expr): return type(expr) == ClassIdentifier or type(expr) == Thing
[docs] class SubClassOf(Rule):
[docs] def normalize(self): lhs, rules_lhs = self.subject.normalize_lhs() rhss, rules_rhs = self.object.normalize_rhs() rules = [] for rhs in rhss: if issimple(lhs) or issimple(rhs): rules.append(SubClassOf(lhs, rhs)) else: name = NameFactory.next_name() new_class = ClassIdentifier(name) rules.append(SubClassOf(lhs, new_class)) rules.append(SubClassOf(new_class, rhs)) rules += rules_lhs rules += rules_rhs return rules
[docs] def __str__(self): return "%s %s %s" % (self.subject, SPECIAL_CHARS["\sqsubseteq"], self.object)
# return '%s %s %s' % (self.subject, '->', self.object)
[docs] def to_latex(self): return r"%s \sqsubseteq %s" % (self.subject.to_latex(), self.object.to_latex())
[docs] class EquivalentClass(Rule):
[docs] def normalize(self): return ( SubClassOf(self.subject, self.object).normalize() + SubClassOf(self.object, self.subject).normalize() )
[docs] def __str__(self): return "%s %s %s" % (self.subject, SPECIAL_CHARS["\equiv"], self.object)
[docs] class DisjointWith(Rule):
[docs] def normalize(self): return [self]
# raise FeatureNotSupported('rule disjointWith')
[docs] def __str__(self): return "%s %s %s" % (self.subject, " disjoint ", self.object)
[docs] class Thing(Expression): def __init__(self, identifier): super(Thing, self).__init__(identifier)
[docs] def normalize_rhs(self): return [self], []
[docs] def __str__(self): return self.identifier
[docs] class ClassIdentifier(Expression): """A class in the ontology.""" def __init__(self, identifier): super(ClassIdentifier, self).__init__(identifier)
[docs] def normalize_rhs(self): return [self], []
[docs] def __str__(self): return self.identifier
[docs] def to_latex(self): return r"%s" % self.identifier
[docs] class TopClass(Expression): """A class in the ontology.""" def __init__(self): super(TopClass, self).__init__()
[docs] def normalize_rhs(self): return [self], []
[docs] def __str__(self): return SPECIAL_CHARS[r"\top"]
[docs] def to_latex(self): return r"\top"
[docs] class Restriction(Expression): """""" def __init__(self, quantifier, prop): super(Restriction, self).__init__() self.quantifier = quantifier self.prop = prop
[docs] def normalize_lhs(self): quantifier, rules = self.quantifier.normalize_lhs() return Restriction(quantifier, self.prop), rules
[docs] def normalize_rhs(self): quantifier, rules = self.quantifier.normalize_rhs() return [Restriction(quantifier, self.prop)], rules
[docs] def to_latex(self): return self.quantifier.to_latex(self.prop)
[docs] def __str__(self): return self.quantifier.to_string(self.prop)
[docs] class Intersection(Expression): """""" def __init__(self, children): super(Intersection, self).__init__() self.children = children
[docs] def normalize_lhs(self): # TODO extend to n-ary intersections, this here assumes binary rules = [] children = [] for child in self.children: nc, nr = child.normalize_lhs() rules += nr if issimple(nc): children.append(nc) else: name = NameFactory.next_name() new_class = ClassIdentifier(name) rules.append(SubClassOf(nc, new_class)) children.append(new_class) return Intersection(children), rules
[docs] def normalize_rhs(self): rules = [] children = [] for child in self.children: child_rhs, child_rules = child.normalize_rhs() assert len(child_rhs) == 1 children += child_rhs rules += child_rules return children, rules
[docs] def __str__(self): sep = " %s " % SPECIAL_CHARS["\sqcap"] return "(%s)" % sep.join(map(str, self.children))
[docs] def to_latex(self): return r" \sqcap ".join(c.to_latex() for c in self.children)
[docs] def __and__(self, other): return Intersection(self.children + [other])
[docs] class Union(Expression): """""" def __init__(self, children): super(Union, self).__init__() self.children = children
[docs] def normalize_rhs(self): return [self], []
# raise FeatureNotSupported("union in RHS")
[docs] def __str__(self): sep = " | " return sep.join(map(str, self.children))
[docs] class Complement(Expression): def __init__(self, child): super(Complement, self).__init__() self.child = child
[docs] def normalize_rhs(self): return [self], []
# raise FeatureNotSupported('complement')
[docs] def __str__(self): return "not {}".format(str(self.child))
[docs] class OneOf(Expression): def __init__(self, children): super(OneOf, self).__init__() self.children = children
[docs] def normalize_rhs(self): raise FeatureNotSupported("oneOf in RHS")
[docs] def __str__(self): sep = ", " return "one_of(%s)" % sep.join(map(str, self.children))
[docs] class Quantifier(object):
[docs] def to_string(self, prop): raise NotImplementedError()
[docs] def normalize_rhs(self): raise NotImplementedError()
[docs] class HasSelf(Quantifier):
[docs] def to_string(self, prop): return "hasSelf {}".format(prop)
[docs] def normalize_rhs(self): return self, []
[docs] def normalize_lhs(self): return self, []
[docs] class SomeValues(Quantifier): def __init__(self, from_class): self.from_class = from_class
[docs] def to_string(self, prop): return "%s %s.%s" % (SPECIAL_CHARS["\exists"], prop, self.from_class)
[docs] def to_latex(self, prop): if self.from_class.identifier is not None: return r"\exists %s.\!%s" % (prop, self.from_class.to_latex()) else: return r"\exists %s.\!(%s)" % (prop, self.from_class.to_latex())
[docs] def normalize_lhs(self): rules = [] if self.from_class.identifier is None: name = NameFactory.next_name() from_class = ClassIdentifier(name) fc_n, fc_r = self.from_class.normalize_lhs() rules += fc_r for fc in fc_n: rules.append(SubClassOf(fc, from_class)) else: from_class = self.from_class return SomeValues(from_class), rules
[docs] def normalize_rhs(self): rules = [] if self.from_class.identifier is None: name = NameFactory.next_name() from_class = ClassIdentifier(name) fc_n, fc_r = self.from_class.normalize_rhs() rules += fc_r for fc in fc_n: rules.append(SubClassOf(from_class, fc)) else: from_class = self.from_class return SomeValues(from_class), rules
[docs] class AllValues(Quantifier): def __init__(self, from_class): self.from_class = from_class
[docs] def to_string(self, prop): return "all %s %s" % (prop, self.from_class)
[docs] def normalize_rhs(self): raise FeatureNotSupported("quantifier allValues")
[docs] class Cardinality(Quantifier): def __init__(self, count): self.count = count
[docs] def to_string(self, prop): return "count(%s) = %s" % (prop, self.count)
[docs] def normalize_rhs(self): raise FeatureNotSupported("quantifier cardinality")
[docs] class MinCardinality(Quantifier): def __init__(self, count): self.count = count
[docs] def to_string(self, prop): return "count(%s) >= %s" % (prop, self.count)
[docs] def normalize_rhs(self): raise FeatureNotSupported("quantifier minCardinality")
[docs] class MaxCardinality(Quantifier): def __init__(self, count): self.count = count
[docs] def to_string(self, prop): return "count(%s) <= %s" % (prop, self.count)
[docs] def normalize_rhs(self): raise FeatureNotSupported("quantifier maxCardinality")
[docs] class HasValue(Quantifier): def __init__(self, value): self.value = value
[docs] def to_string(self, prop): return "value(%s) = %s" % (prop, self.value)
[docs] def normalize_rhs(self): return self, []
# raise FeatureNotSupported('hasValue')
[docs] def normalize_lhs(self): return self, []