RDFClosure.RDFSClosure

Package RDFClosure :: Module RDFSClosure |
[hide private]
[frames] | no frames]

# Source Code for Module RDFClosure.RDFSClosure

      1  #!/d/Bin/Python/python.exe
      2  # -*- coding: utf-8 -*-
      3  #
      4  """
      5  This module is brute force implementation of the RDFS semantics on the top of RDFLib (with some caveats, see in the introductory text).
      6
      7
      8  @requires: U{RDFLib<https://github.com/RDFLib/rdflib>}, 4.0.0 and higher
      9  @license: This software is available for use under the U{W3C Software License<http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231>}
     10  @organization: U{World Wide Web Consortium<http://www.w3.org>}
     11  @author: U{Ivan Herman<a href="http://www.w3.org/People/Ivan/">}
     12
     13  """
     14
     15  __author__  = 'Ivan Herman'
     16  __contact__ = 'Ivan Herman, ivan@w3.org'
     17  __license__ = u'W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231'
     18
     19  from RDFClosure.RDFS    import Property, type
     20  from RDFClosure.RDFS    import Resource, Class, subClassOf, subPropertyOf, domain, range
     21  from RDFClosure.RDFS    import Literal, ContainerMembershipProperty, member, Datatype
     22  # noinspection PyPep8Naming
     23  from RDFClosure.RDFS    import RDFNS as ns_rdf
     24
     25  from RDFClosure.Closure          import Core
     26  from RDFClosure.AxiomaticTriples import RDFS_Axiomatic_Triples, RDFS_D_Axiomatic_Triples
     27
     28
     29  ######################################################################################################
     30
     31  ## RDFS Semantics class
     32  # noinspection PyPep8Naming
     33 -class RDFS_Semantics(Core):
     34          """RDFS Semantics class, ie, implementation of the RDFS closure graph.
     35
     36          Note that the module does I{not} implement the so called Datatype entailment rules, simply because the underlying RDFLib does
     37          not implement the datatypes (ie, RDFLib will not make the literal "1.00" and "1.00000" identical, although
     38          even with all the ambiguities on datatypes, this I{should} be made equal...). Also, the so-called extensional entailment rules
     39          (Section 7.3.1 in the RDF Semantics document) have not been implemented either.
     40
     41          The comments and references to the various rule follow the names as used in the U{RDF Semantics document<http://www.w3.org/TR/rdf-mt/>}.
     42          """
     43 -        def __init__(self, graph, axioms, daxioms, rdfs):
     44                  """
     45                  @param graph: the RDF graph to be extended
     46                  @type graph: rdflib.Graph
     47                  @param axioms: whether (non-datatype) axiomatic triples should be added or not
     48                  @type axioms: bool
     49                  @param daxioms: whether datatype axiomatic triples should be added or not
     50                  @type daxioms: bool
     51                  @param rdfs: whether RDFS inference is also done (used in subclassed only)
     52                  @type rdfs: boolean
     53                  """
     54                  Core.__init__(self, graph, axioms, daxioms, rdfs)
     55
     56 -        def add_axioms(self):
     57                  """Add axioms
     58                  """
     59                  for t in RDFS_Axiomatic_Triples:
     60                          self.graph.add(t)
     61                  for i in xrange(1, self.IMaxNum + 1):
     62                          ci = ns_rdf[("_%d" % i)]
     63                          self.graph.add((ci, type, Property))
     64                          self.graph.add((ci, domain, Resource))
     65                          self.graph.add((ci, range, Resource))
     66                          self.graph.add((ci, type, ContainerMembershipProperty))
     67
     68 -        def add_d_axioms(self):
     69                  """This is not really complete, because it just uses the comparison possibilities that rdflib provides."""
     70                  literals = self.literal_proxies.lit_to_bnode.keys()
     71                  # #1
     72                  for lt in literals:
     73                          if lt.dt is not None:
     74                                  self.graph.add((self.literal_proxies.lit_to_bnode[lt], type, lt.dt))
     75
     76                  for t in RDFS_D_Axiomatic_Triples :
     77                          self.graph.add(t)
     78
     79          # noinspection PyBroadException
     80 -        def one_time_rules(self):
     81                  """Some of the rules in the rule set are axiomatic in nature, meaning that they really have to be added only
     82                  once, there is no reason to add these in a cycle. These are performed by this method that is invoked only once
     83                  at the beginning of the process.
     84
     85                  In this case this is related to a 'hidden' same as rules on literals with identical values (though different lexical values)
     86                  """
     87                  # There is also a hidden sameAs rule in RDF Semantics: if a literal appears in a triple, and another one has the same value,
     88                  # then the triple should be duplicated with the other value.
     89                  for lt1 in self.literal_proxies.lit_to_bnode.keys():
     90                          for lt2 in self.literal_proxies.lit_to_bnode.keys():
     91                                  if lt1 != lt2:
     92                                          try:
     93                                                  lt1_d = lt1.lit.toPython()
     94                                                  lt2_d = lt2.lit.toPython()
     95                                                  if lt1_d == lt2_d :
     96                                                          # In OWL, this line is simply stating a sameAs for the corresponding BNodes, and then let
     97                                                          # the usual rules take effect. In RDFS this is not possible, so the sameAs rule is, essentially
     98                                                          # replicated...
     99                                                          bn1 = self.literal_proxies.lit_to_bnode[lt1]
    100                                                          bn2 = self.literal_proxies.lit_to_bnode[lt2]
    101                                                          for (s, p, o) in self.graph.triples((None, None, bn1)) :
    102                                                                  self.graph.add((s, p, bn2))
    103                                          except:
    104                                                  # there may be a problem with one of the python conversions; the rule is imply ignored
    105                                                  #raise e
    106                                                  pass
    107
    108 -        def rules(self,t,cycle_num):
    109                  """
    110                          Go through the RDFS entailment rules rdf1, rdfs4-rdfs12, by extending the graph.
    111                          @param t: a triple (in the form of a tuple)
    112                          @param cycle_num: which cycle are we in, starting with 1. Can be used for some (though minor) optimization.
    113                  """
    114                  s, p, o = t
    115                  # rdf1
    116                  self.store_triple((p, type, Property))
    117                  # rdfs4a
    118                  if cycle_num == 1:
    119                          self.store_triple((s, type, Resource))
    120                  # rdfs4b
    121                  if cycle_num == 1:
    122                          self.store_triple((o, type, Resource))
    123                  if p == domain:
    124                          # rdfs2
    125                          for uuu, Y, yyy in self.graph.triples((None, s, None)):
    126                                  self.store_triple((uuu, type, o))
    127                  if p == range:
    128                          # rdfs3
    129                          for uuu, Y, vvv in self.graph.triples((None, s, None)):
    130                                  self.store_triple((vvv, type, o))
    131                  if p == subPropertyOf:
    132                          # rdfs5
    133                          for Z, Y, xxx in self.graph.triples((o, subPropertyOf, None)):
    134                                  self.store_triple((s, subPropertyOf, xxx))
    135                          # rdfs7
    136                          for zzz, Z, www in self.graph.triples((None, s, None)):
    137                                  self.store_triple((zzz, o, www))
    138                  if p == type and o == Property:
    139                          # rdfs6
    140                          self.store_triple((s, subPropertyOf, s))
    141                  if p == type and o == Class:
    142                          # rdfs8
    143                          self.store_triple((s, subClassOf, Resource))
    144                          # rdfs10
    145                          self.store_triple((s, subClassOf, s))
    146                  if p == subClassOf:
    147                          # rdfs9
    148                          for vvv, Y, Z in self.graph.triples((None, type, s)):
    149                                  self.store_triple((vvv, type, o))
    150                          # rdfs11
    151                          for Z, Y, xxx in self.graph.triples((o, subClassOf, None)):
    152                                  self.store_triple((s, subClassOf, xxx))
    153                  if p == type and o == ContainerMembershipProperty :
    154                          # rdfs12
    155                          self.store_triple((s, subPropertyOf, member))
    156                  if p == type and o == Datatype:
    157                          self.store_triple((s, subClassOf, Literal))
    158