Add simple entailment regime and associated tests
Makefile.am
| 1 | 1 | include guile.am | |
| 2 | 2 | ||
| 3 | 3 | SOURCES= \ | |
| 4 | + | rdf/entailment/simple.scm \ | |
| 4 | 5 | rdf/rdf.scm \ | |
| 5 | 6 | rdf/xsd.scm \ | |
| 6 | 7 | turtle/parser.scm \ | |
… | |||
| 12 | 13 | ||
| 13 | 14 | TEST_EXTENSIONS = .scm | |
| 14 | 15 | SCM_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh --color-tests yes --ignore-exit | |
| 15 | - | TESTS = tests/turtle.scm | |
| 16 | + | TESTS = tests/turtle.scm tests/semantics.scm | |
| 16 | 17 | EXTRA_DIST += $(TESTS) | |
configure.ac
| 11 | 11 | GUILE_SITE_DIR | |
| 12 | 12 | ||
| 13 | 13 | AC_CONFIG_FILES([pre-inst-env], [chmod +x pre-inst-env]) | |
| 14 | + | AC_CONFIG_FILES([tests/semantics.scm], [chmod +x tests/semantics.scm]) | |
| 14 | 15 | AC_CONFIG_FILES([tests/turtle.scm], [chmod +x tests/turtle.scm]) | |
| 15 | 16 | AC_CONFIG_FILES(Makefile) | |
| 16 | 17 | AC_REQUIRE_AUX_FILE([tap-driver.sh]) |
rdf/entailment/simple.scm unknown status 1
| 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))))))))) |
test-modules/online.scm
| 20 | 20 | #:use-module (rnrs bytevectors) | |
| 21 | 21 | #:use-module (srfi srfi-1) | |
| 22 | 22 | #:use-module (test-modules result) | |
| 23 | + | #:use-module ((rdf entailment simple) #:prefix simple:) | |
| 23 | 24 | #:use-module (rdf rdf) | |
| 24 | 25 | #:use-module (srfi srfi-1) | |
| 25 | 26 | #:use-module (turtle tordf) | |
… | |||
| 47 | 48 | (define (execute-test test) | |
| 48 | 49 | (let* ((predicates (test-case-document test)) | |
| 49 | 50 | (type (car (get-objects predicates "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"))) | |
| 50 | - | (type (substring type (string-length "http://www.w3.org/ns/rdftest#"))) | |
| 51 | + | (type (car (reverse (string-split type #\#)))) | |
| 51 | 52 | (action (car (get-objects predicates "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action")))) | |
| 52 | 53 | (turtle->rdf (get-test-doc action) action))) | |
| 53 | 54 | ||
| 54 | 55 | (define (run-test test) | |
| 55 | 56 | (let* ((predicates (test-case-document test)) | |
| 56 | 57 | (type (car (get-objects predicates "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"))) | |
| 57 | - | (type (substring type (string-length "http://www.w3.org/ns/rdftest#"))) | |
| 58 | + | (type (car (reverse (string-split type #\#)))) | |
| 58 | 59 | (result | |
| 59 | 60 | (catch #t | |
| 60 | 61 | (lambda () | |
… | |||
| 100 | 101 | #:result 'fail | |
| 101 | 102 | #:reason (format #f "expected ~a but got ~a" | |
| 102 | 103 | expected result))))))) | |
| 104 | + | ((member type '("PositiveEntailmentTest" "NegativeEntailmentTest")) | |
| 105 | + | (let* ((regime (rdf-literal-lexical-form | |
| 106 | + | (car | |
| 107 | + | (get-objects | |
| 108 | + | predicates | |
| 109 | + | (string-append | |
| 110 | + | "http://www.w3.org/2001/sw/DataAccess/tests/" | |
| 111 | + | "test-manifest#entailmentRegime"))))) | |
| 112 | + | (expected | |
| 113 | + | (car | |
| 114 | + | (get-objects | |
| 115 | + | predicates | |
| 116 | + | (string-append "http://www.w3.org/2001/sw/DataAccess/tests/" | |
| 117 | + | "test-manifest#result")))) | |
| 118 | + | (expected | |
| 119 | + | (catch #t | |
| 120 | + | (lambda () | |
| 121 | + | (if expected | |
| 122 | + | (turtle->rdf (get-test-doc expected) expected) | |
| 123 | + | #f)) | |
| 124 | + | (lambda (key . value) | |
| 125 | + | (cons key value))))) | |
| 126 | + | (match regime | |
| 127 | + | ("simple" | |
| 128 | + | (if (if (equal? expected #f) | |
| 129 | + | (simple:consistent-graph? result) | |
| 130 | + | (simple:entails? result expected)) | |
| 131 | + | (if (equal? type "PositiveEntailmentTest") | |
| 132 | + | (update-test-case test #:result 'pass) | |
| 133 | + | (update-test-case test | |
| 134 | + | #:result 'fail | |
| 135 | + | #:reason "Expected negative result, got positive")) | |
| 136 | + | (if (equal? type "PositiveEntailmentTest") | |
| 137 | + | (update-test-case test | |
| 138 | + | #:result 'fail | |
| 139 | + | #:reason (format #f "Expected positive result, got negative")) | |
| 140 | + | (update-test-case test #:result 'pass)))) | |
| 141 | + | (_ (update-test-case test | |
| 142 | + | #:result 'skip | |
| 143 | + | #:reason (format #f "Unrecognized entailment regime: ~a" | |
| 144 | + | regime)))))) | |
| 103 | 145 | (else | |
| 104 | 146 | (update-test-case test | |
| 105 | 147 | #:result 'skip | |
… | |||
| 157 | 199 | manifest)))) | |
| 158 | 200 | ||
| 159 | 201 | (define (find-rest node) | |
| 160 | - | (pk 'rest node) | |
| 161 | 202 | (rdf-triple-object | |
| 162 | 203 | (car | |
| 163 | 204 | (filter | |
test-modules/testsuite.scm
| 17 | 17 | ||
| 18 | 18 | (define-module (test-modules testsuite) | |
| 19 | 19 | #:export (expected-failures | |
| 20 | - | turtle-test-manifest)) | |
| 20 | + | turtle-test-manifest | |
| 21 | + | semantics-test-manifest)) | |
| 21 | 22 | ||
| 22 | 23 | (define expected-failures | |
| 23 | 24 | '()) | |
| 24 | 25 | ||
| 25 | 26 | (define turtle-test-manifest "http://www.w3.org/2013/TurtleTests/manifest.ttl") | |
| 27 | + | (define semantics-test-manifest | |
| 28 | + | "https://www.w3.org/2013/rdf-mt-tests/manifest.ttl") |
tests/semantics.scm.in unknown status 1
| 1 | + | #!@abs_top_srcdir@/pre-inst-env guile | |
| 2 | + | !# | |
| 3 | + | ;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu> | |
| 4 | + | ;;;; | |
| 5 | + | ;;;; This library is free software; you can redistribute it and/or | |
| 6 | + | ;;;; modify it under the terms of the GNU Lesser General Public | |
| 7 | + | ;;;; License as published by the Free Software Foundation; either | |
| 8 | + | ;;;; version 3 of the License, or (at your option) any later version. | |
| 9 | + | ;;;; | |
| 10 | + | ;;;; This library is distributed in the hope that it will be useful, | |
| 11 | + | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 | + | ;;;; Lesser General Public License for more details. | |
| 14 | + | ;;;; | |
| 15 | + | ;;;; You should have received a copy of the GNU Lesser General Public | |
| 16 | + | ;;;; License along with this library; if not, write to the Free Software | |
| 17 | + | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 18 | + | ;;;; | |
| 19 | + | ||
| 20 | + | (use-modules (test-modules online)) | |
| 21 | + | (use-modules (test-modules result)) | |
| 22 | + | (use-modules (test-modules testsuite)) | |
| 23 | + | ||
| 24 | + | (run-test-suite semantics-test-manifest expected-failures tap-driver) |
turtle/tordf.scm
| 89 | 89 | (not (string-any #\> iri)))) | |
| 90 | 90 | ||
| 91 | 91 | (define (parse-iri iri state) | |
| 92 | - | (pk 'iri iri) | |
| 93 | 92 | (match iri | |
| 94 | 93 | (('iri ('prefixed-name ('pname-ln ('pname-ns ns) ('pn-local suffix)))) | |
| 95 | 94 | `(("iri" . ,(string-append (assoc-ref (parser-state-namespaces state) ns) |