1
2
3
4 """
5 This module is a C{brute force} implementation of the OWL 2 RL profile.
6
7 RDFLib works with 'generalized' RDF, meaning that triples with a BNode predicate are I{allowed}. This is good because, eg, some of the
8 triples generated for RDF from an OWL 2 functional syntax might look like '[ owl:inverseOf p]', and the RL rules would then operate
9 on such generalized triple. However, as a last, post processing steps, these triples are removed from the graph before serialization
10 to produce 'standard' RDF (which is o.k. for RL, too, because the consequent triples are all right, generalized triples might
11 have had a role in the deduction steps only).
12
13 @requires: U{RDFLib<https://github.com/RDFLib/rdflib>}, 4.0.0 and higher
14 @license: This software is available for use under the U{W3C Software License<http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231>}
15 @organization: U{World Wide Web Consortium<http://www.w3.org>}
16 @author: U{Ivan Herman<a href="http://www.w3.org/People/Ivan/">}
17
18 """
19
20 __author__ = 'Ivan Herman'
21 __contact__ = 'Ivan Herman, ivan@w3.org'
22 __license__ = u'W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231'
23
24 import rdflib
25 from rdflib import BNode
26
27 from RDFClosure.RDFS import Property, type
28 from RDFClosure.RDFS import subClassOf, subPropertyOf, comment, label, domain, range
29 from RDFClosure.RDFS import seeAlso, isDefinedBy, Datatype
30
31 from RDFClosure.OWL import *
32 from RDFClosure.Closure import Core
33 from RDFClosure.AxiomaticTriples import OWLRL_Axiomatic_Triples, OWLRL_D_Axiomatic_Triples
34 from RDFClosure.AxiomaticTriples import OWLRL_Datatypes_Disjointness
35
36 OWLRL_Annotation_properties = [label, comment, seeAlso, isDefinedBy, deprecated, versionInfo, priorVersion, backwardCompatibleWith, incompatibleWith]
37
38 from .XsdDatatypes import OWL_RL_Datatypes, OWL_Datatype_Subsumptions
39
40
41
42
43
44
45
46
47
48
50 """OWL 2 RL Semantics class, ie, implementation of the OWL 2 RL closure graph.
51
52 Note that the module does I{not} implement the so called Datatype entailment rules, simply because the underlying RDFLib does
53 not implement the datatypes (ie, RDFLib will not make the literal "1.00" and "1.00000" identical, although
54 even with all the ambiguities on datatypes, this I{should} be made equal...). Also, the so-called extensional entailment rules
55 (Section 7.3.1 in the RDF Semantics document) have not been implemented either.
56
57 The comments and references to the various rule follow the names as used in the U{OWL 2 RL document<http://www.w3.org/TR/owl2-profiles/#Reasoning_in_OWL_2_RL_and_RDF_Graphs_using_Rules>}.
58 """
59 - def __init__(self, graph, axioms, daxioms, rdfs=None):
60 """
61 @param graph: the RDF graph to be extended
62 @type graph: rdflib.Graph
63 @param axioms: whether (non-datatype) axiomatic triples should be added or not
64 @type axioms: bool
65 @param daxioms: whether datatype axiomatic triples should be added or not
66 @type daxioms: bool
67 @param rdfs: whether RDFS inference is also done (used in subclassed only)
68 @type rdfs: boolean
69 """
70 Core.__init__(self, graph, axioms, daxioms, rdfs)
71 self.bnodes = []
72
74 """
75 Shorthand to get a list of values (ie, from an rdf:List structure) starting at a head
76
77 @param l: RDFLib resource, should be the head of an rdf:List
78 @return: array of resources
79 """
80 return [ch for ch in self.graph.items(l)]
81
83 if node in self.literal_proxies.bnode_to_lit:
84 return "'" + self.literal_proxies.bnode_to_lit[node].lex + "'"
85 else :
86 return node
87
88 - def post_process(self):
89 """
90 Remove triples with bnode predicates. The Bnodes in the graph are collected in the first cycle run.
91 """
92 to_be_removed = []
93 for b in self.bnodes:
94 for t in self.graph.triples((None, b, None)):
95 if t not in to_be_removed:
96 to_be_removed.append(t)
97 for t in to_be_removed:
98 self.graph.remove(t)
99
106
113
115 """Helping method to check whether a type statement is in line with a possible
116 restriction. This method is invoked by rule "cls-avf" before setting a type
117 on an allValuesFrom restriction.
118
119 The method is a placeholder at this level. It is typically implemented by subclasses for
120 extra checks, eg, for datatype facet checks.
121 @param v: the resource that is to be 'typed'
122 @param t: the targeted type (ie, Class)
123 @return: boolean
124 """
125 return True
126
128 """
129 Some of the rules in the rule set are axiomatic in nature, meaning that they really have to be added only
130 once, there is no reason to add these in a cycle. These are performed by this method that is invoked only once
131 at the beginning of the process.
132
133 These are: cls-thing, cls-nothing1, prp-ap, dt-types1, dt-types2, dt-eq, dt-diff.
134
135 Note, however, that the dt-* are executed only partially, limited by the possibilities offered by RDFLib. These may not
136 cover all the edge cases of OWL RL. Especially, dt-not-type has not (yet?) been implemented (I wonder whether RDFLib should not raise
137 exception for those anyway...
138 """
139
140 def _add_to_explicit(s, o):
141 if s not in explicit:
142 explicit[s] = []
143 if o not in explicit[s]:
144 explicit[s].append(o)
145
146
147 def _append_to_explicit(s, o):
148 if s not in explicit:
149 explicit[s] = []
150 for d in explicit[o]:
151 if d not in explicit[s]:
152 explicit[s].append(d)
153
154 def _add_to_used_datatypes(d):
155 used_datatypes.add(d)
156
157
158 def _handle_subsumptions(r, dt):
159 if dt in OWL_Datatype_Subsumptions:
160 for new_dt in OWL_Datatype_Subsumptions[dt]:
161 self.store_triple((r, type, new_dt))
162 self.store_triple((new_dt, type, Datatype))
163 _add_to_used_datatypes(new_dt)
164
165
166
167
168
169 implicit = {}
170
171
172
173 explicit = {}
174
175
176
177 used_datatypes = set()
178
179
180
181
182
183
184
185 for lt in self.literal_proxies.lit_to_bnode.keys():
186
187 if lt.dt is not None and lt.dt in OWL_RL_Datatypes:
188 bn = self.literal_proxies.lit_to_bnode[lt]
189
190 self.store_triple((bn, type, lt.dt))
191 if bn not in implicit:
192 implicit[bn] = lt.dt
193 _add_to_used_datatypes(lt.dt)
194
195
196
197
198 try :
199 val = lt.lit.toPython()
200 except:
201 self.add_error("Literal's lexical value and datatype do not match: (%s,%s)" % (lt.lex, lt.dt))
202
203
204
205
206
207 for lt1 in self.literal_proxies.lit_to_bnode.keys():
208 for lt2 in self.literal_proxies.lit_to_bnode.keys() :
209 if lt1 != lt2:
210 try :
211 lt1_d = lt1.lit.toPython()
212 lt2_d = lt2.lit.toPython()
213
214
215
216
217 except:
218
219
220 pass
221
222
223
224
225 for (s,p,o) in self.graph.triples((None, type, None)):
226 if o in OWL_RL_Datatypes:
227 _add_to_used_datatypes(o)
228 if s not in implicit:
229 _add_to_explicit(s, o)
230
231
232
233 for (s,p,o) in self.graph.triples((None, sameAs, None)):
234 if o in implicit:
235 _add_to_explicit(s, implicit[o])
236
237
238 if o in explicit :
239 _append_to_explicit(s, o)
240 if s in explicit :
241 _append_to_explicit(o, s)
242
243
244
245
246
247
248
249
250
251 for dt in OWL_RL_Datatypes:
252 self.store_triple((dt,type,Datatype))
253 for dts in explicit.values():
254 for dt in dts:
255 self.store_triple((dt, type, Datatype))
256
257
258
259
260
261 for r in explicit:
262
263 dtypes = explicit[r]
264 for dt in dtypes:
265 _handle_subsumptions(r, dt)
266
267 for r in implicit:
268 dt = implicit[r]
269 _handle_subsumptions(r, dt)
270
271
272
273
274 for t in OWLRL_Datatypes_Disjointness:
275 (l, pred, r) = t
276 if l in used_datatypes and r in used_datatypes:
277 self.store_triple(t)
278
292
294 """
295 Some of the rules in the rule set are axiomatic in nature, meaning that they really have to be added only
296 once, there is no reason to add these in a cycle. These are performed by this method that is invoked only once
297 at the beginning of the process.
298
299 These are: cls-thing, cls-nothing1, prp-ap, dt-types1, dt-types2, dt-eq, dt-diff.
300 """
301 self._one_time_rules_misc()
302 self._one_time_rules_datatypes()
303
304 - def rules(self, t, cycle_num):
305 """
306 Go through the various rule groups, as defined in the OWL-RL profile text and implemented via
307 local methods. (The calling cycle takes every tuple in the graph.)
308 @param t: a triple (in the form of a tuple)
309 @param cycle_num: which cycle are we in, starting with 1. This value is forwarded to all local rules; it is also used
310 locally to collect the bnodes in the graph.
311 """
312 if cycle_num == 1:
313 for r in t:
314 if isinstance(r, BNode) and r not in self.bnodes:
315 self.bnodes.append(r)
316
317 self._properties(t,cycle_num)
318 self._equality(t,cycle_num)
319 self._classes(t,cycle_num)
320 self._class_axioms(t,cycle_num)
321 self._schema_vocabulary(t,cycle_num)
322
324 """
325 Implementation of the property chain axiom, invoked from inside the property axiom handler. This is the
326 implementation of rule prp-spo2, taken aside for an easier readability of the code. """
327 chain = self._list(x)
328
329
330 if len(chain) > 0:
331 for (u1, _y, _z) in self.graph.triples((None, chain[0], None)):
332
333
334 finalList = [(u1, _z)]
335 chainExists = True
336 for pi in chain[1:]:
337 newList = []
338 for (_u,ui) in finalList:
339 for u in self.graph.objects(ui,pi):
340
341
342 newList.append((u1, u))
343
344
345
346 if len(newList) == 0:
347 chainExists = False
348 break
349 else :
350 finalList = newList
351 if chainExists:
352 for (_u, un) in finalList :
353 self.store_triple((u1, p, un))
354
356 """
357 Table 4: Semantics of equality. Essentially, the eq-* rules.
358 @param triple: triple to work on
359 @param cycle_num: which cycle are we in, starting with 1. Can be used for some optimization.
360 """
361
362
363
364
365
366 s,p,o = triple
367
368 self.store_triple((s, sameAs, s))
369 self.store_triple((o, sameAs, o))
370 self.store_triple((p, sameAs, p))
371 if p == sameAs:
372 x, y = s, o
373
374 self.store_triple((y, sameAs, x))
375
376 for z in self.graph.objects(y, sameAs):
377 self.store_triple((x, sameAs, z))
378
379 for pp,oo in self.graph.predicate_objects(s):
380 self.store_triple((o, pp, oo))
381
382 for ss,oo in self.graph.subject_objects(s):
383 self.store_triple((ss, o, oo))
384
385 for ss,pp in self.graph.subject_predicates(o):
386 self.store_triple((ss, pp, s))
387
388 if (s,differentFrom,o) in self.graph or (o,differentFrom,s) in self.graph:
389 s_e = self._get_resource_or_literal(s)
390 o_e = self._get_resource_or_literal(o)
391 self.add_error("'sameAs' and 'differentFrom' cannot be used on the same subject-object pair: (%s, %s)" % (s_e, o_e))
392
393
394 if p == type and o == AllDifferent:
395 x = s
396
397
398
399 m1 = [i for i in self.graph.objects(x, members)]
400 m2 = [i for i in self.graph.objects(x, distinctMembers)]
401 for y in m1 + m2:
402 zis = self._list(y)
403 for i in xrange(0, len(zis) - 1):
404 zi = zis[i]
405 for j in xrange(i+1, len(zis) - 1):
406 zj = zis[j]
407 if ((zi, sameAs, zj) in self.graph or (zj, sameAs, zi) in self.graph) and zi != zj:
408 self.add_error("'sameAs' and 'AllDifferent' cannot be used on the same subject-object pair: (%s, %s)" % (zi,zj))
409
411 """
412 Table 5: The Semantics of Axioms about Properties. Essentially, the prp-* rules.
413 @param triple: triple to work on
414 @param cycle_num: which cycle are we in, starting with 1. Can be used for some optimization.
415 """
416
417
418
419
420
421 p, t, o = triple
422
423
424 if cycle_num == 1 and t in OWLRL_Annotation_properties:
425 self.store_triple((t, type, AnnotationProperty))
426
427
428 if t == domain:
429 for x, y in self.graph.subject_objects(p):
430 self.store_triple((x, type, o))
431
432
433 elif t == range:
434 for x, y in self.graph.subject_objects(p):
435 self.store_triple((y, type, o))
436
437 elif t == type:
438
439 if o == FunctionalProperty:
440
441 for x, y1 in self.graph.subject_objects(p):
442 for y2 in self.graph.objects(x,p):
443
444
445 if y1 != y2:
446 self.store_triple((y1, sameAs, y2))
447
448
449 elif o == InverseFunctionalProperty:
450 for x1, y in self.graph.subject_objects(p):
451 for x2 in self.graph.subjects(p,y):
452
453
454 if x1 != x2:
455 self.store_triple((x1, sameAs, x2))
456
457
458 elif o == IrreflexiveProperty:
459 for x, y in self.graph.subject_objects(p):
460 if x == y:
461 self.add_error("Irreflexive property used on %s with %s" % (x,p))
462
463
464 elif o == SymmetricProperty:
465 for x, y in self.graph.subject_objects(p):
466 self.store_triple((y, p, x))
467
468
469 elif o == AsymmetricProperty:
470 for x, y in self.graph.subject_objects(p):
471 if (y, p, x) in self.graph :
472 self.add_error("Erroneous usage of asymmetric property %s on %s and %s" % (p, x, y))
473
474
475 elif o == TransitiveProperty:
476 for x, y in self.graph.subject_objects(p):
477 for z in self.graph.objects(y, p):
478 self.store_triple((x, p, z))
479
480
481
482
483
484 elif o == AllDisjointProperties:
485 x = p
486 for y in self.graph.objects(x, members):
487 pis = self._list(y)
488 for i in xrange(0,len(pis) - 1):
489 pi = pis[i]
490 for j in xrange(i+1,len(pis) - 1):
491 pj = pis[j]
492 for x,y in self.graph.subject_objects(pi):
493 if (x, pj, y) in self.graph :
494 self.add_error("Disjoint properties in an 'AllDisjointProperties' are not really disjoint: (%s, %s,%s) and (%s,%s,%s)" % (x, pi, y, x, pj, y))
495
496
497 elif t == subPropertyOf:
498 p1, p2 = p, o
499 for x, y in self.graph.subject_objects(p1):
500 self.store_triple((x, p2, y))
501
502
503 elif t == propertyChainAxiom:
504 self._property_chain(p, o)
505
506
507 elif t == equivalentProperty:
508 p1, p2 = p, o
509
510
511
512
513 if p1 != p2:
514
515 for x, y in self.graph.subject_objects(p1):
516 self.store_triple((x, p2, y))
517
518 for x, y in self.graph.subject_objects(p2):
519 self.store_triple((x, p1, y))
520
521
522 elif t == propertyDisjointWith:
523 p1, p2 = p, o
524 for x, y in self.graph.subject_objects(p1):
525 if (x, p2, y) in self.graph:
526 self.add_error("Erroneous usage of disjoint properties %s and %s on %s and %s" % (p1,p2,x,y))
527
528
529
530 elif t == inverseOf:
531 p1, p2 = p, o
532
533 for x, y in self.graph.subject_objects(p1):
534 self.store_triple((y, p2, x))
535
536 for x, y in self.graph.subject_objects(p2):
537 self.store_triple((y, p1, x))
538
539
540 elif t == hasKey :
541 c, u = p, o
542 pis = self._list(u)
543 if len(pis) > 0 :
544 for x in self.graph.subjects(type, c):
545
546
547
548
549
550
551 finalList = [[zi] for zi in self.graph.objects(x, pis[0])]
552 for pi in pis[1:]:
553 newList = []
554 for zi in self.graph.objects(x, pi):
555 newList = newList + [l + [zi] for l in finalList]
556 finalList = newList
557
558
559
560
561 valueList = [l for l in finalList if len(l) == len(pis)]
562
563
564 for y in self.graph.subjects(type, c):
565
566 if not(y == x or (y, sameAs, x) in self.graph or (x, sameAs, y) in self.graph) :
567
568 for vals in valueList:
569 same = True
570 for i in xrange(0,len(pis) - 1):
571 if (y, pis[i], vals[i]) not in self.graph :
572 same = False
573
574 break
575 if same :
576 self.store_triple((x, sameAs, y))
577
578 break
579
580
581 elif t == sourceIndividual:
582 x, i1 = p, o
583 for p1 in self.graph.objects(x, assertionProperty):
584 for i2 in self.graph.objects(x, targetIndividual):
585 if (i1, p1, i2) in self.graph :
586 self.add_error("Negative (object) property assertion violated for: (%s, %s, %s)" % (i1, p1, i2))
587 for i2 in self.graph.objects(x,targetValue) :
588 if (i1, p1, i2) in self.graph :
589 self.add_error("Negative (datatype) property assertion violated for: (%s, %s, %s)" % (i1, p1, self.get_literal_value(i2)))
590
591 - def _classes(self, triple, cycle_num) :
592 """
593 Table 6: The Semantics of Classes. Essentially, the cls-* rules
594 @param triple: triple to work on
595 @param cycle_num: which cycle are we in, starting with 1. Can be used for some optimization.
596 """
597
598
599
600
601
602 c, p, x = triple
603
604
605 if p == type and x == Nothing :
606 self.add_error("%s is defined of type 'Nothing'" % c)
607
608
609 if p == intersectionOf:
610 classes = self._list(x)
611
612
613
614
615
616
617 if len(classes) > 0 :
618 for y in self.graph.subjects(type, classes[0]):
619 if False not in [(y, type, cl) in self.graph for cl in classes[1:]] :
620 self.store_triple((y, type, c))
621
622 for y in self.graph.subjects(type, c):
623 for cl in classes:
624 self.store_triple((y, type, cl))
625
626
627 elif p == unionOf:
628 for cl in self._list(x):
629 for y in self.graph.subjects(type, cl):
630 self.store_triple((y, type, c))
631
632
633 elif p == complementOf:
634 c1, c2 = c, x
635 for x1 in self.graph.subjects(type, c1):
636 if (x1, type, c2) in self.graph :
637 self.add_error("Violation of complementarity for classes %s and %s on element %s" % (c1, c2, x))
638
639
640 elif p == someValuesFrom:
641 xx, y = c, x
642
643
644 for pp in self.graph.objects(xx, onProperty):
645 for u, v in self.graph.subject_objects(pp) :
646 if y == Thing or (v, type, y) in self.graph:
647 self.store_triple((u, type, xx))
648
649
650 elif p == allValuesFrom:
651 xx, y = c, x
652 for pp in self.graph.objects(xx, onProperty):
653 for u in self.graph.subjects(type, xx):
654 for v in self.graph.objects(u, pp) :
655 if self.restriction_typing_check(v, y):
656 self.store_triple((v, type, y))
657 else :
658 self.add_error("Violation of type restriction for allValuesFrom in %s for datatype %s on value %s" % (pp, y, self._get_resource_or_literal(v)))
659
660
661 elif p == hasValue:
662 xx, y = c, x
663 for pp in self.graph.objects(xx, onProperty):
664
665 for u in self.graph.subjects(type, xx):
666 self.store_triple((u, pp, y))
667
668 for u in self.graph.subjects(pp, y):
669 self.store_triple((u, type, xx))
670
671
672 elif p == maxCardinality:
673
674
675
676
677
678 val = -1
679 try:
680 val = int(self.literal_proxies.bnode_to_lit[x].lit)
681 except:
682 pass
683 xx = c
684 if val == 0:
685
686 for pp in self.graph.objects(xx, onProperty):
687 for u,y in self.graph.subject_objects(pp):
688
689 if (u, type, xx) in self.graph:
690 self.add_error("Erroneous usage of maximum cardinality with %s, %s" % (xx, y))
691 elif val == 1:
692
693 for pp in self.graph.objects(xx, onProperty):
694 for u, y1 in self.graph.subject_objects(pp):
695 if (u, type, xx) in self.graph:
696 for y2 in self.graph.objects(u, pp):
697 if y1 != y2 :
698 self.store_triple((y1, sameAs, y2))
699
700
701 elif p == maxQualifiedCardinality:
702
703
704
705
706
707 val = -1
708 try :
709 val = int(self.literal_proxies.bnode_to_lit[x].lit)
710 except:
711 pass
712 xx = c
713 if val == 0 :
714
715 for pp in self.graph.objects(xx, onProperty):
716 for cc in self.graph.objects(xx, onClass):
717 for u,y in self.graph.subject_objects(pp):
718
719 if (u, type, xx) in self.graph and (cc == Thing or (y, type, cc) in self.graph):
720 self.add_error("Erroneous usage of maximum qualified cardinality with %s, %s, and %s" % (xx, cc, y))
721 elif val == 1 :
722
723 for pp in self.graph.objects(xx, onProperty):
724 for cc in self.graph.objects(xx, onClass) :
725 for u, y1 in self.graph.subject_objects(pp):
726 if (u, type, xx) in self.graph :
727 if cc == Thing:
728 for y2 in self.graph.objects(u, pp):
729 if y1 != y2:
730 self.store_triple((y1, sameAs, y2))
731 else :
732 if (y1, type, cc) in self.graph:
733 for y2 in self.graph.objects(u, pp) :
734 if y1 != y2 and (y2, type, cc) in self.graph:
735 self.store_triple((y1, sameAs, y2))
736
737
738 elif p == oneOf:
739 for y in self._list(x):
740 self.store_triple((y, type, c))
741
743 """
744 Table 7: Class Axioms. Essentially, the cax-* rules.
745 @param triple: triple to work on
746 @param cycle_num: which cycle are we in, starting with 1. Can be used for some optimization.
747 """
748
749
750
751
752
753 c1,p,c2 = triple
754
755 if p == subClassOf:
756
757 if c1 != c2 :
758 for x in self.graph.subjects(type, c1):
759 self.store_triple((x, type, c2))
760
761
762
763 elif p == equivalentClass and c1 != c2:
764
765 for x in self.graph.subjects(type, c1):
766 self.store_triple((x, type, c2))
767
768 for x in self.graph.subjects(type, c2):
769 self.store_triple((x, type, c1))
770
771
772 elif p == disjointWith:
773 for x in self.graph.subjects(type, c1):
774 if (x, type, c2) in self.graph:
775 self.add_error("Disjoint classes %s and %s have a common individual %s" % (c1, c2, self._get_resource_or_literal(x)))
776
777
778 elif p == type and c2 == AllDisjointClasses:
779 x = c1
780 for y in self.graph.objects(x, members):
781 classes = self._list(y)
782 if len(classes) > 0:
783 for i in xrange(0, len(classes) - 1):
784 cl1 = classes[i]
785 for z in self.graph.subjects(type,cl1):
786 for cl2 in classes[(i + 1):]:
787 if (z, type, cl2) in self.graph:
788 self.add_error("Disjoint classes %s and %s have a common individual %s" % (cl1, cl2, z))
789
791 """
792 Table 9: The Semantics of Schema Vocabulary. Essentially, the scm-* rules
793 @param triple: triple to work on
794 @param cycle_num: which cycle are we in, starting with 1. Can be used for some optimization.
795 """
796
797
798
799
800
801 s,p,o = triple
802
803
804 if p == type and o == OWLClass:
805 c = s
806 self.store_triple((c, subClassOf, c))
807 self.store_triple((c, equivalentClass, c))
808 self.store_triple((c, subClassOf, Thing))
809 self.store_triple((Nothing, subClassOf, c))
810
811
812
813 elif p == subClassOf:
814 c1, c2 = s, o
815
816
817 if c1 != c2:
818 for c3 in self.graph.objects(c2, subClassOf):
819
820 if c1 != c3 : self.store_triple((c1, subClassOf, c3))
821
822 if (c2, subClassOf, c1) in self.graph:
823 self.store_triple((c1, equivalentClass, c2))
824
825
826 elif p == equivalentClass and s != o:
827 c1,c2 = s,o
828 self.store_triple((c1, subClassOf, c2))
829 self.store_triple((c2, subClassOf, c1))
830
831
832
833 elif p == type and (o == ObjectProperty or o == DatatypeProperty or o == Property):
834 pp = s
835 self.store_triple((pp, subPropertyOf, pp))
836 self.store_triple((pp, equivalentProperty, pp))
837
838
839
840 elif p == subPropertyOf and s != o:
841 p1, p2 = s, o
842
843
844 if p1 != p2 :
845 for p3 in self.graph.objects(p2,subPropertyOf):
846 if p1 != p3:
847 self.store_triple((p1, subPropertyOf, p3))
848
849
850 if (p2, subPropertyOf, p1) in self.graph:
851 self.store_triple((p1, equivalentProperty, p2))
852
853
854
855 elif p == equivalentProperty and s != o:
856 p1, p2 = s, o
857 self.store_triple((p1, subPropertyOf, p2))
858 self.store_triple((p2, subPropertyOf, p1))
859
860
861 elif p == domain:
862
863 pp, c1 = s, o
864 for (_x, _y, c2) in self.graph.triples((c1, subClassOf, None)) :
865 if c1 != c2 :
866 self.store_triple((pp, domain, c2))
867
868 p2, c = s, o
869 for (p1,_x,_y) in self.graph.triples((None, subPropertyOf, p2)) :
870 if p1 != p2 :
871 self.store_triple((p1, domain, c))
872
873
874 elif p == range:
875
876 pp, c1 = s, o
877 for (_x,_y,c2) in self.graph.triples((c1, subClassOf, None)) :
878 if c1 != c2 : self.store_triple((pp, range, c2))
879
880 p2, c = s, o
881 for (p1,_x,_y) in self.graph.triples((None, subPropertyOf, p2)) :
882 if p1 != p2 : self.store_triple((p1, range, c))
883
884
885 elif p == hasValue:
886 c1, i = s, o
887 for p1 in self.graph.objects(c1, onProperty):
888 for c2 in self.graph.subjects(hasValue, i):
889 for p2 in self.graph.objects(c2, onProperty):
890 if (p1, subPropertyOf, p2) in self.graph:
891 self.store_triple((c1, subClassOf, c2))
892
893
894 elif p == someValuesFrom:
895
896 c1, y1 = s, o
897 for pp in self.graph.objects(c1,onProperty):
898 for c2 in self.graph.subjects(onProperty,pp):
899 for y2 in self.graph.objects(c2, someValuesFrom):
900 if (y1,subClassOf, y2) in self.graph:
901 self.store_triple((c1, subClassOf, c2))
902
903
904 c1, y = s, o
905 for p1 in self.graph.objects(c1, onProperty):
906 for c2 in self.graph.subjects(someValuesFrom,y):
907 for p2 in self.graph.objects(c2, onProperty):
908 if (p1,subPropertyOf,p2) in self.graph:
909 self.store_triple((c1, subClassOf, c2))
910
911
912 elif p == allValuesFrom:
913
914 c1, y1 = s, o
915 for pp in self.graph.objects(c1, onProperty):
916 for c2 in self.graph.subjects(onProperty, pp) :
917 for y2 in self.graph.objects(c2, allValuesFrom) :
918 if (y1,subClassOf,y2) in self.graph:
919 self.store_triple((c1, subClassOf, c2))
920
921
922 c1, y = s, o
923 for p1 in self.graph.objects(c1, onProperty):
924 for c2 in self.graph.subjects(allValuesFrom, y):
925 for p2 in self.graph.objects(c2, onProperty):
926 if (p1,subPropertyOf, p2) in self.graph :
927 self.store_triple((c2, subClassOf, c1))
928
929
930 elif p == intersectionOf:
931 c, x = s, o
932 for ci in self._list(x):
933 self.store_triple((c, subClassOf, ci))
934
935
936 elif p == unionOf:
937 c, x = s, o
938 for ci in self._list(x):
939 self.store_triple((ci, subClassOf, c))
940