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

Source Code for Module RDFClosure.OWLRLExtras

  1  #!/d/Bin/Python/python.exe 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  """ 
  5   
  6  Extension to OWL 2 RL, ie, some additional rules added to the system from OWL 2 Full. It is implemented through 
  7  the L{OWLRL_Extension} class, whose reference has to be passed to the relevant semantic class (ie, either the OWL 2 RL or the combined 
  8  closure class) as an 'extension'. 
  9   
 10  The added rules and features are: 
 11   
 12   - self restriction 
 13   - owl:rational datatype 
 14   - datatype restrictions via facets 
 15    
 16  In more details, the rules that are added: 
 17   
 18   1. self restriction 1: C{?z owl:hasSelf ?x. ?x owl:onProperty ?p. ?y rdf:type ?z. => ?y ?p ?y.} 
 19   2. self restriction 2: C{?z owl:hasSelf ?x. ?x owl:onProperty ?p. ?y ?p ?y. => ?y rdf:type ?z. } 
 20   
 21  @requires: U{RDFLib<http://rdflib.net>}, 2.2.2. and higher 
 22  @license: This software is available for use under the U{W3C Software License<http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231>} 
 23  @organization: U{World Wide Web Consortium<http://www.w3.org>} 
 24  @author: U{Ivan Herman<a href="http://www.w3.org/People/Ivan/">} 
 25   
 26  """ 
 27   
 28  """ 
 29  $Id: OWLRLExtras.py,v 1.8 2009/09/21 12:04:45 ivan Exp $ $Date: 2009/09/21 12:04:45 $ 
 30  """ 
 31   
 32  __author__  = 'Ivan Herman' 
 33  __contact__ = 'Ivan Herman, ivan@w3.org' 
 34  __license__ = u'W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231' 
 35   
 36  from rdflib.BNode               import BNode 
 37  from rdflib.Namespace   import Namespace 
 38  from rdflib.Literal             import Literal as rdflibLiteral 
 39  from rdflib.RDF                 import RDFNS  as ns_rdf 
 40  from rdflib.RDFS                import RDFSNS as ns_rdfs 
 41  from rdflib.exceptions  import Error 
 42  from rdflib.Literal     import _XSD_NS as ns_xsd 
 43   
 44  from rdflib.RDF                 import Seq, Bag, Alt, Statement, Property, XMLLiteral, List 
 45  from rdflib.RDF                 import subject, predicate, object, type, value, first, rest, nil 
 46   
 47  from rdflib.RDFS                import Resource, Class, subClassOf, subPropertyOf, comment, label, domain, range 
 48  from rdflib.RDFS                import seeAlso, isDefinedBy, Literal, Container, ContainerMembershipProperty, member, Datatype 
 49   
 50  import sys 
 51  if sys.version_info[1] >= 6 : 
 52          # Running python 2.6 or higher, ie, there is a built in rational called fraction 
 53          from fractions import Fraction as Rational 
 54  else : 
 55          from rational import Rational 
 56   
 57  from RDFClosure.DatatypeHandling        import AltXSDToPYTHON 
 58   
 59  from RDFClosure.OWL                             import * 
 60  from RDFClosure.OWL                                     import OWLNS as ns_owl 
 61  from RDFClosure.Closure                         import Core 
 62  from RDFClosure.AxiomaticTriples        import OWLRL_Axiomatic_Triples, OWLRL_D_Axiomatic_Triples 
 63  from RDFClosure.AxiomaticTriples        import OWLRL_Datatypes_Disjointness 
 64  from RDFClosure.CombinedClosure         import RDFS_OWLRL_Semantics 
 65  from RDFClosure.OWLRL                           import OWLRL_Annotation_properties 
 66   
 67  from RDFClosure.XsdDatatypes import OWL_RL_Datatypes, OWL_Datatype_Subsumptions 
 68   
 69  from RestrictedDatatype import extract_faceted_datatypes 
 70   
 71  ########################################################################################################################### 
 72  # Rational datatype 
 73   
74 -def _strToRational(v) :
75 """Converting a string to a rational. 76 77 According to the OWL spec: numerator must be an integer, denominator a positive integer (ie, xsd['integer'] type), and the denominator 78 should not have a '+' sign. 79 80 @param v: the literal string defined as boolean 81 @return corresponding Rational value 82 @rtype: Rational 83 @raise ValueError: invalid rational string literal 84 """ 85 try : 86 r = v.split('/') 87 if len(r) == 2 : 88 n_str = r[0] 89 d_str = r[1] 90 else : 91 n_str = r[0] 92 d_str = "1" 93 if d_str.strip()[0] == '+' : 94 raise ValueError("Invalid Rational literal value %s" % v) 95 else : 96 return Rational(AltXSDToPYTHON[ns_xsd["integer"]](n_str), AltXSDToPYTHON[ns_xsd["positiveInteger"]](d_str)) 97 except e : 98 raise ValueError("Invalid Rational literal value %s" % v)
99 100 ########################################################################################################################### 101 102
103 -class OWLRL_Extension( RDFS_OWLRL_Semantics ) :
104 """ 105 Additional rules to OWL 2 RL. The initialization method also adds the C{owl:rational} datatype to the set of allowed 106 datatypes with the L{_strToRational} function as a conversion between the literal form and a Rational. The C{xsd:decimal} datatype 107 is also set to be a subclass of C{owl:rational}. Furthermore, the restricted datatypes are extracted from the graph 108 using a L{separate method in a different module<RestrictedDatatype.extract_faceted_datatypes>}, and all those datatypes are also 109 added to the set of allowed datatypes. In the case of the restricted datatypes and extra subsumption relationship is set up 110 between the restricted and the base datatypes. 111 112 @cvar extra_axioms: additional axioms that have to be added to the deductive closure (in case the axiomatic triples are required) 113 @ivar restricted_datatypes : list of the datatype restriction 114 @type restricted_datatypes : array of L{restricted datatype<RestrictedDatatype.RestrictedDatatype>} instances 115 """ 116 extra_axioms = [ 117 (hasSelf, type, Property), 118 (hasSelf, domain, Property), 119 ]
120 - def __init__(self, graph, axioms, daxioms, rdfs = False) :
121 """ 122 @param graph: the RDF graph to be extended 123 @type graph: rdflib.Graph 124 @param axioms: whether (non-datatype) axiomatic triples should be added or not 125 @type axioms: Boolean 126 @param daxioms: whether datatype axiomatic triples should be added or not 127 @type daxioms: Boolean 128 @param rdfs: whether RDFS extension is done 129 @type rdfs: boolean 130 """ 131 RDFS_OWLRL_Semantics.__init__(self, graph, axioms, daxioms, rdfs ) 132 self.rdfs = rdfs 133 self.add_new_datatype(ns_owl["rational"], _strToRational, OWL_RL_Datatypes, 134 subsumption_dict = OWL_Datatype_Subsumptions, 135 subsumption_key = ns_xsd["decimal"], 136 subsumption_list = [ns_owl["rational"]]) 137 138 self.restricted_datatypes = extract_faceted_datatypes(self, graph) 139 for dt in self.restricted_datatypes : 140 self.add_new_datatype(dt.datatype, dt.toPython, OWL_RL_Datatypes, 141 subsumption_dict = OWL_Datatype_Subsumptions, 142 subsumption_key = dt.datatype, 143 subsumption_list = [ dt.base_type ])
144
146 """ 147 A one-time-rule: all the literals are checked whether they are (a) of type restricted by a faceted (restricted) datatype and (b) whether 148 the corresponding value abides to the restrictions. If true, then the literal gets an extra tag as being of type of the restricted datatype, too. 149 """ 150 for rt in self.restricted_datatypes : 151 # This is a recoreded restriction. The base type is: 152 base_type = rt.base_type 153 # Look through all the literals; more precisely, through the 154 # proxy bnodes: 155 for bn in self.literal_proxies.bnode_to_lit : 156 # check if the type of that proxy matches. Note that this also takes 157 # into account the subsumption datatypes, that have been taken 158 # care of by the 'regular' OWL RL process 159 if (bn, type, base_type) in self.graph : 160 # yep, that is a good candidate! 161 lt = self.literal_proxies.bnode_to_lit[bn] 162 try : 163 # the conversion or the check may go wrong and raise an exception; then simply move on 164 value = lt.lit.toPython() 165 if rt.checkValue(value) : 166 # yep, this is also of type 'rt' 167 self.store_triple((bn, type, rt.datatype)) 168 except : 169 continue
170
171 - def one_time_rules(self) :
172 """ 173 This method is invoked only once at the beginning, and prior of, the forward chaing process. 174 175 At present, only the L{subsumption of restricted datatypes<_subsume_restricted_datatypes>} is performed. 176 """ 177 RDFS_OWLRL_Semantics.one_time_rules(self) 178 # it is important to flush the triples at this point, because 179 # the handling of the restriction datatypes rely on the datatype 180 # subsumption triples added by the superclass 181 self.flush_stored_triples() 182 self._subsume_restricted_datatypes()
183
184 - def add_axioms(self) :
185 """ 186 Add the L{extra axioms<OWLRL_Extension.extra_axioms>}, related to the self restrictions. 187 """ 188 RDFS_OWLRL_Semantics.add_axioms(self) 189 for t in self.extra_axioms : self.graph.add(t)
190
191 - def rules(self, t, cycle_num) :
192 """ 193 Go through the additional rules implemented by this module. 194 @param t: a triple (in the form of a tuple) 195 @param cycle_num: which cycle are we in, starting with 1. This value is forwarded to all local rules; it is also used 196 locally to collect the bnodes in the graph. 197 """ 198 RDFS_OWLRL_Semantics.rules(self, t, cycle_num) 199 z, q, x = t 200 if q == hasSelf : 201 for p in self.graph.objects(z, onProperty) : 202 for y in self.graph.subjects( type, z ) : 203 self.store_triple((y, p, y)) 204 for y1, y2 in self.graph.subject_objects(p) : 205 if y1 == y2 : 206 self.store_triple((y1, type, z))
207 208
209 -class OWLRL_Extension_Trimming( OWLRL_Extension ) :
210 """ 211 This Class adds only one feature to L{OWLRL_Extension}: to initialize with a trimming flag set to C{True} by default. 212 213 This is pretty experimental and probably contentious: this class I{removes} a number of triples from the Graph at the very end of the processing steps. 214 These triples are either the by-products of the deductive closure calculation or are axiom like triples that are added following the rules of OWL 2 RL. 215 While these triples I{are necessary} for the correct inference of really 'useful' triples, they may not be of interest for the application 216 for the end result. The triples that are removed are of the form (following a SPARQL-like notation): 217 218 - C{?x owl:sameAs ?x}, C{?x rdfs:subClassOf ?x}, C{?x rdfs:subPropertyOf}, C{?x owl:equivalentClass ?x} type triples 219 - C{?x rdfs:subClassOf rdf:Resource}, C{?x rdfs:subClassOf owl:Thing}, C{?x rdf:type rdf:Resource}, C{owl:Nothing rdfs:subClassOf ?x} type triples 220 - For a datatype that does I{not} appear explicitly in a type assignments (ie, in a C{?x rdf:type dt}) the corresponding C{dt rdf:type owl:Datatype} and C{dt rdf:type owl:DataRange} triples, as well as the disjointness statements with other datatypes 221 - annotation property axioms 222 - a number of axiomatic triples on C{owl:Thing}, C{owl:Nothing} and C{rdf:Resource} (eg, C{owl:Nothing rdf:type owl:Class}, C{owl:Thing owl:equivalentClass rdf:Resource}, etc.) 223 224 Trimming is the only feature of this class, done in the L{post_process} step. If users extend L{OWLRL_Extension}, this class can be safely mixed in via multiple 225 inheritance. 226 """
227 - def __init__(self, graph, axioms, daxioms, rdfs = False) :
228 """ 229 @param graph: the RDF graph to be extended 230 @type graph: rdflib.Graph 231 @param axioms: whether (non-datatype) axiomatic triples should be added or not 232 @type axioms: Boolean 233 @param daxioms: whether datatype axiomatic triples should be added or not 234 @type daxioms: Boolean 235 @param rdfs: whether RDFS extension is done 236 @type rdfs: boolean 237 """ 238 OWLRL_Extension.__init__(self, graph, axioms, daxioms, rdfs = False)
239
240 - def post_process(self) :
241 """ 242 Do some post-processing step performing the trimming of the graph. See the L{class description<OWLRL_Extension_Trimming>} for further details. 243 244 """ 245 OWLRL_Extension.post_process(self) 246 self.flush_stored_triples() 247 248 to_be_removed = set() 249 for t in self.graph : 250 s,p,o = t 251 if s == o : 252 if p == sameAs or p == equivalentClass or p == subClassOf or p == subPropertyOf : to_be_removed.add(t) 253 if (p == subClassOf and (o == Thing or o == Resource)) or (p == type and o == Resource) or (s == Nothing and p == subClassOf) : 254 to_be_removed.add(t) 255 256 for dt in OWL_RL_Datatypes : 257 # see if this datatype appears explicitly in the graph as the type of a symbol 258 if len([ s for s in self.graph.subjects(type,dt) ]) == 0 : 259 to_be_removed.add((dt, type, Datatype)) 260 to_be_removed.add((dt, type, DataRange)) 261 262 for t in self.graph.triples((dt, disjointWith, None)) : 263 to_be_removed.add(t) 264 for t in self.graph.triples((None, disjointWith, dt)) : 265 to_be_removed.add(t) 266 267 # RULE prp-ap 268 269 for an in OWLRL_Annotation_properties : self.graph.remove((an, type, AnnotationProperty)) 270 271 to_be_removed.add((Nothing, type, OWLClass)) 272 to_be_removed.add((Nothing, type, Class)) 273 to_be_removed.add((Thing, type, OWLClass)) 274 to_be_removed.add((Thing, type, Class)) 275 to_be_removed.add((Thing, equivalentClass, Resource)) 276 to_be_removed.add((Resource, equivalentClass, Thing)) 277 to_be_removed.add((OWLClass, equivalentClass, Class)) 278 to_be_removed.add((OWLClass, subClassOf, Class)) 279 to_be_removed.add((Class, equivalentClass, OWLClass)) 280 to_be_removed.add((Class, subClassOf, OWLClass)) 281 to_be_removed.add((Datatype, subClassOf, DataRange)) 282 to_be_removed.add((Datatype, equivalentClass, DataRange)) 283 to_be_removed.add((DataRange, subClassOf, Datatype)) 284 to_be_removed.add((DataRange, equivalentClass, Datatype)) 285 286 for t in to_be_removed : self.graph.remove(t)
287