guile-rdf/rdf/entailment/rdf.scm

rdf.scm

1
;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu>
2
;;;; 
3
;;;; This library is free software; you can redistribute it and/or
4
;;;; modify it under the terms of the GNU Lesser General Public
5
;;;; License as published by the Free Software Foundation; either
6
;;;; version 3 of the License, or (at your option) any later version.
7
;;;; 
8
;;;; This library is distributed in the hope that it will be useful,
9
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
;;;; Lesser General Public License for more details.
12
;;;; 
13
;;;; You should have received a copy of the GNU Lesser General Public
14
;;;; License along with this library; if not, write to the Free Software
15
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
;;;; 
17
18
(define-module (rdf entailment rdf)
19
  #:use-module (ice-9 match)
20
  #:use-module (rdf rdf)
21
  #:use-module ((rdf entailment d) #:prefix d:)
22
  #:use-module (srfi srfi-1)
23
  #:export (consistent-graph?
24
            entails?))
25
26
(define (rdf-iri name)
27
  (string-append "http://www.w3.org/1999/02/22-rdf-syntax-ns#" name))
28
29
(define (consistent-graph? graph vocabulary)
30
  (define (alist-set lst key val)
31
    (match lst
32
      (() (list (cons key val)))
33
      (((k . v) lst ...)
34
       (if (equal? k key)
35
           (cons (cons key val) lst)
36
           (cons (cons k v) (alist-set lst key val))))))
37
38
  (define (compatible? types)
39
    (match types
40
      (() #t)
41
      ((_) #t)
42
      ((a b ...)
43
       (and (null? (filter
44
                     (lambda (t)
45
                       ((rdf-vocabulary-compatible? vocabulary) a t))
46
                     b))
47
            (compatible? b)))))
48
49
  (define (compatible-types? graph)
50
    (let loop ((graph graph) (type-mappings '()))
51
      (if (null? graph)
52
          (null?
53
            (filter
54
              (lambda (t)
55
                (not (compatible? (cdr t))))
56
              type-mappings))
57
          (let* ((t (car graph)))
58
            (if (equal? (rdf-triple-predicate t) (rdf-iri "type"))
59
                (loop
60
                  (cdr graph)
61
                  (alist-set type-mappings (rdf-triple-subject t)
62
                             (cons (rdf-triple-object t)
63
                                   (or
64
                                     (assoc-ref type-mappings
65
                                                (rdf-triple-subject t))
66
                                     '())))))))))
67
68
  (and (d:consistent-graph? graph vocabulary)
69
       (compatible-types? (augment (recognize graph vocabulary)))))
70
71
;; G entails E if E has an instance (where blank nodes are replaced by literals
72
;; or IRIs) that is a subgraph of G.
73
;;
74
;; We re-use similar procedures to verifying isomorphism of graphs, but this time
75
;; blank nodes can also map to literals and IRIs.
76
77
;; We follow appendix A and use a subgraph comparison (like the simple:entails?
78
;; procedure) after augmenting the graph with additional true triples.
79
80
(define rdf-axioms
81
  (list
82
    (make-rdf-triple (rdf-iri "type") (rdf-iri "type") (rdf-iri "Property"))
83
    (make-rdf-triple (rdf-iri "subject") (rdf-iri "type") (rdf-iri "Property"))
84
    (make-rdf-triple (rdf-iri "predicate") (rdf-iri "type") (rdf-iri "Property"))
85
    (make-rdf-triple (rdf-iri "object") (rdf-iri "type") (rdf-iri "Property"))
86
    (make-rdf-triple (rdf-iri "first") (rdf-iri "type") (rdf-iri "Property"))
87
    (make-rdf-triple (rdf-iri "rest") (rdf-iri "type") (rdf-iri "Property"))
88
    (make-rdf-triple (rdf-iri "value") (rdf-iri "type") (rdf-iri "Property"))
89
    (make-rdf-triple (rdf-iri "nil") (rdf-iri "type") (rdf-iri "List"))))
90
91
(define (rdf-axioms-container container)
92
  (list
93
    (make-rdf-triple 
94
      container (rdf-iri "type") (rdf-iri "Property"))))
95
96
(define (rdf-container-property? p)
97
  (define rdf-container-property-base (rdf-iri "_"))
98
  (and (string? p)
99
       (> (string-length p) (string-length rdf-container-property-base))
100
       (equal? (substring p 0 (string-length rdf-container-property-base))
101
               rdf-container-property-base)
102
       (string->number
103
         (substring p (string-length rdf-container-property-base)))))
104
105
(define (rdf-container-properties g)
106
  (let loop ((answer '()) (g g))
107
    (match g
108
      (() (if (null? answer) (list (rdf-iri "_1")) answer))
109
      ((($ rdf-triple subject predicate object) g ...)
110
       (let* ((answer (if (and (rdf-container-property? subject)
111
                               (not (member subject answer)))
112
                          (cons subject answer)
113
                          answer))
114
              (answer (if (and (rdf-container-property? predicate)
115
                               (not (member predicate answer)))
116
                          (cons predicate answer)
117
                          answer))
118
              (answer (if (and (rdf-container-property? object)
119
                               (not (member object answer)))
120
                          (cons object answer)
121
                          answer)))
122
         (loop answer g))))))
123
124
(define (augment g)
125
  (let* ((g (append rdf-axioms g))
126
         (g (append
127
              (append-map rdf-axioms-container (rdf-container-properties g))
128
              g)))
129
    (let loop ((g g))
130
      (let ((augment-set
131
             (let loop2 ((g2 g) (augment-set '()))
132
               (match g2
133
                 (() augment-set)
134
                 ((($ rdf-triple subject predicate object) g2 ...)
135
                  (let ((type-triple
136
                          (if (and (rdf-literal? object)
137
                                   (rdf-datatype? (rdf-literal-type object)))
138
                            (make-rdf-triple object (rdf-iri "type")
139
                                             (rdf-literal-type object))
140
                            #f))
141
                        (property-triple
142
                          (make-rdf-triple predicate (rdf-iri "type")
143
                                           (rdf-iri "Property"))))
144
                  (loop2
145
                    g2
146
                    (append
147
                      (if (or (not type-triple) (member type-triple g)
148
                              (member type-triple augment-set))
149
                          '()
150
                          (list type-triple))
151
                      (if (or (member property-triple g)
152
                              (member type-triple augment-set))
153
                          '()
154
                          (list property-triple))
155
                      augment-set))))))))
156
        (if (null? augment-set)
157
            g
158
            (loop (append augment-set g)))))))
159
160
(define (equiv? n1 n2)
161
  (match (list n1 n2)
162
    ((($ rdf-literal l1 ($ rdf-datatype _ _ _ _ lexical->value1 _) lang1)
163
      ($ rdf-literal l2 ($ rdf-datatype _ _ _ _ lexical->value2 _) lang2))
164
     (and (equal? lang1 lang2)
165
          (equal? (lexical->value1 l1))
166
          (equal? (lexical->value2 l2))))
167
    (_ (equal? n1 n2))))
168
169
(define (validate-mapping mapping g1 g2)
170
  (match g1
171
    ('() #t)
172
    ((t1 g1 ...)
173
     (and (not (null? (filter
174
                        (lambda (t2)
175
                          (let ((s1 (rdf-triple-subject t1))
176
                                (s2 (rdf-triple-subject t2))
177
                                (p1 (rdf-triple-predicate t1))
178
                                (p2 (rdf-triple-predicate t2))
179
                                (o1 (rdf-triple-object t1))
180
                                (o2 (rdf-triple-object t2)))
181
                            (and
182
                              (if (blank-node? s1)
183
                                  (equiv? (assoc-ref mapping s1) s2)
184
                                  (equiv? s1 s2))
185
                              (equal? p1 p2)
186
                              (if (blank-node? o1)
187
                                  (equiv? (assoc-ref mapping o1) o2)
188
                                  (equiv? o1 o2)))))
189
                        g2)))
190
          (validate-mapping mapping g1 g2)))))
191
192
(define (entails? g e vocabulary)
193
  "Return true if g entails e"
194
  (let* ((g (recognize g vocabulary))
195
         (g (augment g))
196
         (e (recognize e vocabulary)))
197
    (or (not (consistent-graph? g vocabulary))
198
        (d:entails? g e vocabulary))))
199