guile-rdf/rdf/entailment/d.scm

d.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 d)
19
  #:use-module (ice-9 match)
20
  #:use-module (rdf rdf)
21
  #:use-module ((rdf entailment simple) #:prefix simple:)
22
  #:use-module (srfi srfi-1)
23
  #:export (consistent-graph?
24
            entails?))
25
26
(define (consistent-graph? graph vocabulary)
27
  (define consistent-data?
28
    (match-lambda
29
      (($ rdf-literal form ($ rdf-datatype _ _ lexical? _ _ _) _)
30
       (lexical? form))
31
      (_ #t)))
32
33
  (match (recognize graph vocabulary)
34
    ('() #t)
35
    ((($ rdf-triple subject predicate object) graph ...)
36
     (and (consistent-data? subject) (consistent-data? object)
37
          (consistent-graph? graph vocabulary)))))
38
39
;; G entails E if E has an instance (where blank nodes are replaced by literals
40
;; or IRIs) that is a subgraph of G.
41
;;
42
;; We re-use similar procedures to verifying isomorphism of graphs, but this time
43
;; blank nodes can also map to literals and IRIs.
44
45
(define (sat? equivalences)
46
  "Return whether the set of equivalences satisfies the condition that it represents
47
an isomorphism between two blank node sets: for every equality, check that the
48
first component is always associated to the same second component, and that the
49
second component is always associated with the first."
50
  (match equivalences
51
    ('() #t)
52
    (((first . second) equivalences ...)
53
     (if (and (null? (filter
54
                       (lambda (eq)
55
                         (and (equal? (car eq) first)
56
                              (not (equal? (cdr eq) second))))
57
                       equivalences))
58
              (null? (filter
59
                       (lambda (eq)
60
                         (and (not (equal? (car eq) first))
61
                              (equal? (cdr eq) second)))
62
                       equivalences)))
63
         (sat? equivalences)
64
         #f))))
65
66
(define (merge-joins l1 l2)
67
  (cond
68
    ((null? l1) l2)
69
    ((null? l2) l1)
70
    (else
71
      (fold
72
        (lambda (e1 res)
73
          (append
74
            (map (lambda (e2)
75
                   (append e1 e2))
76
                 l2)
77
            res))
78
        '()
79
        l1))))
80
81
(define (to-disjunctions constraints)
82
  (match constraints
83
    (('equiv b1 b2) (list (list (cons b1 b2))))
84
    ('none (list (list)))
85
    ('bot 'bot)
86
    (('or e1 e2)
87
     (let ((e1 (to-disjunctions e1))
88
           (e2 (to-disjunctions e2)))
89
       (cond
90
         ((equal? e2 'bot)
91
          e1)
92
         ((equal? e1 'bot)
93
          e2)
94
         (else
95
           (append e1 e2)))))
96
    (('and e1 e2)
97
     (let ((e1 (to-disjunctions e1))
98
           (e2 (to-disjunctions e2)))
99
       (cond
100
         ((equal? e1 'bot)
101
          'bot)
102
         ((equal? e2 'bot)
103
          'bot)
104
         (else
105
           (merge-joins e1 e2)))))))
106
107
(define (generate-triple-constraints t1 t2)
108
  (match t1
109
    (($ rdf-triple s1 p1 o1)
110
     (match t2
111
       (($ rdf-triple s2 p2 o2)
112
        (if (and (or (equiv? s1 s2) (blank-node? s1))
113
                 (equal? p1 p2)
114
                 (or (equiv? o1 o2) (blank-node? o1)))
115
            (list 'and
116
                  (if (blank-node? s1)
117
                      (list 'equiv s1 s2)
118
                      'none)
119
                  (if (blank-node? o1)
120
                      (list 'equiv o1 o2)
121
                      'none))
122
            #f))))))
123
124
(define (generate-constraints t1 g2)
125
  (match g2
126
    ('() 'bot)
127
    ((t2 g2 ...)
128
     (let ((c (generate-triple-constraints t1 t2)))
129
       (if c
130
         (list 'or c (generate-constraints t1 g2))
131
         (generate-constraints t1 g2))))))
132
133
(define (equiv? n1 n2)
134
  (match (list n1 n2)
135
    ((($ rdf-literal l1 ($ rdf-datatype _ _ lexical1? _ lexical->value1 _) lang1)
136
      ($ rdf-literal l2 ($ rdf-datatype _ _ lexical2? _ lexical->value2 _) lang2))
137
     (and (equal? (and lang1 (string-downcase lang1))
138
                  (and lang2 (string-downcase lang2)))
139
          (lexical1? l1)
140
          (lexical2? l2)
141
          (if (number? (lexical->value1 l1))
142
              (= (lexical->value1 l1) (lexical->value2 l2))
143
              (equal? (lexical->value1 l1) (lexical->value2 l2)))))
144
    (_ (equal? n1 n2))))
145
146
(define (validate-mapping mapping g1 g2)
147
  (match g1
148
    ('() #t)
149
    ((t1 g1 ...)
150
     (and (not (null? (filter
151
                        (lambda (t2)
152
                          (let ((s1 (rdf-triple-subject t1))
153
                                (s2 (rdf-triple-subject t2))
154
                                (p1 (rdf-triple-predicate t1))
155
                                (p2 (rdf-triple-predicate t2))
156
                                (o1 (rdf-triple-object t1))
157
                                (o2 (rdf-triple-object t2)))
158
                            (and
159
                              (if (blank-node? s1)
160
                                  (equiv? (assoc-ref mapping s1) s2)
161
                                  (equiv? s1 s2))
162
                              (equal? p1 p2)
163
                              (if (blank-node? o1)
164
                                  (equiv? (assoc-ref mapping o1) o2)
165
                                  (equiv? o1 o2)))))
166
                        g2)))
167
          (validate-mapping mapping g1 g2)))))
168
169
(define (entails? g e vocabulary)
170
  "Return true if g entails e"
171
  (let ((g (recognize g vocabulary))
172
        (e (recognize e vocabulary)))
173
    (or (not (consistent-graph? g vocabulary))
174
        (let* ((constraints (fold (lambda (t constraints)
175
                                    (list 'and (generate-constraints t g)
176
                                          constraints))
177
                                  'none e))
178
               (disjunctions (to-disjunctions constraints)))
179
          (if (equal? disjunctions 'bot)
180
              #f
181
              (let loop ((disjunctions (filter sat? disjunctions)))
182
                (match disjunctions
183
                  ('() #f)
184
                  ((mapping disjunctions ...)
185
                   (if (validate-mapping mapping e g)
186
                     #t
187
                     (loop disjunctions))))))))))
188