guile-rdf/rdf/entailment/simple.scm

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