@skaterqiang/protege-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +48 -0
- package/README.md +287 -0
- package/docs/API.md +654 -0
- package/docs/design/OWL2-/347/274/272/345/217/243/345/210/206/346/236/220.md +140 -0
- package/docs/owl2-rl/OWL2-RL-/350/247/204/345/210/231/347/273/206/345/210/231.md +168 -0
- package/docs/owl2-rl/owl2-profiles-spec-zh.html +1914 -0
- package/docs/owl2-rl/owl2-profiles-spec.html +1916 -0
- package/docs/owl2-rl/rl_rules.json +392 -0
- package/main.js +46 -0
- package/package.json +76 -0
- package/sample/README.md +74 -0
- package/sample/case1-ecommerce-risk.js +170 -0
- package/sample/case10-ecommerce-customer-service.js +454 -0
- package/sample/case2-family-swrl.js +147 -0
- package/sample/case3-pharma-safety.js +132 -0
- package/sample/case4-knowledge-publishing.js +111 -0
- package/sample/case5-obda-profiles.js +153 -0
- package/sample/case6-medical-ontology.js +152 -0
- package/sample/case7-manufacturing-ppr.js +155 -0
- package/sample/case8-real-medical-bfo-ogms.js +353 -0
- package/sample/case9-real-manufacturing-iao.js +360 -0
- package/sample/ontologies/bfo.owl +1715 -0
- package/sample/ontologies/iao.owl +8532 -0
- package/sample/ontologies/ogms.owl +4320 -0
- package/sample/ontologies/ro-core.owl +1010 -0
- package/scripts/verify-api.js +53 -0
- package/src/index.js +176 -0
- package/src/inference/OWL2ProfileReasoners.js +67 -0
- package/src/inference/OWL2RLReasoner.js +65 -0
- package/src/inference/ReasonerQueries.js +111 -0
- package/src/inference/SWRLReasoner.js +409 -0
- package/src/inference/TripleStore.js +82 -0
- package/src/inference/rdf.js +83 -0
- package/src/inference/rules/owl2el.js +33 -0
- package/src/inference/rules/owl2ql.js +29 -0
- package/src/inference/rules/owl2rl.js +823 -0
- package/src/io/FunctionalSyntaxParser.js +399 -0
- package/src/io/FunctionalSyntaxWriter.js +180 -0
- package/src/io/ManchesterSyntaxParser.js +398 -0
- package/src/io/OWLXMLParser.js +356 -0
- package/src/io/OntologyLoader.js +125 -0
- package/src/io/RDFGraphToOntology.js +702 -0
- package/src/io/RDFXMLParser.js +319 -0
- package/src/io/RDFXMLWriter.js +196 -0
- package/src/io/SWRLParser.js +150 -0
- package/src/io/TurtleParser.js +363 -0
- package/src/io/TurtleWriter.js +393 -0
- package/src/model/IRI.js +62 -0
- package/src/model/OWLAxiom.js +507 -0
- package/src/model/OWLClassExpression.js +242 -0
- package/src/model/OWLEntity.js +142 -0
- package/src/model/OWLLiteral.js +30 -0
- package/src/model/OWLModelManager.js +106 -0
- package/src/model/OWLOntology.js +119 -0
- package/src/model/SWRL.js +152 -0
- package/src/model/event/OWLModelManagerEvent.js +33 -0
- package/src/model/hierarchy/HierarchyProvider.js +214 -0
- package/src/profiles/OWL2Profiles.js +185 -0
- package/src/server/public/app.js +97 -0
- package/src/server/public/index.html +49 -0
- package/src/server/webServer.js +138 -0
- package/src/validation/GlobalRestrictionsValidator.js +172 -0
- package/test/core.test.js +111 -0
- package/test/exports-map.test.js +165 -0
- package/test/owl2/axioms.test.js +160 -0
- package/test/owl2/classExpressions.test.js +99 -0
- package/test/owl2/functional-syntax-writer.test.js +65 -0
- package/test/owl2/functional.test.js +113 -0
- package/test/owl2/global-restrictions.test.js +76 -0
- package/test/owl2/longtail.test.js +74 -0
- package/test/owl2/manchester-syntax.test.js +100 -0
- package/test/owl2/ontology-loader-imports.test.js +62 -0
- package/test/owl2/owlxml-parser.test.js +112 -0
- package/test/owl2/profile-reasoners.test.js +108 -0
- package/test/owl2/profiles.test.js +66 -0
- package/test/owl2/rdf-graph-to-ontology.test.js +177 -0
- package/test/owl2/rdfxml-punning.test.js +25 -0
- package/test/owl2/rdfxml-writer.test.js +55 -0
- package/test/owl2/rdfxml.test.js +91 -0
- package/test/owl2/reasoner-queries.test.js +58 -0
- package/test/owl2/sample-e2e.test.js +195 -0
- package/test/owl2/swrl-parser.test.js +60 -0
- package/test/owl2/swrl.test.js +131 -0
- package/test/owl2/turtle-writer.test.js +84 -0
- package/test/owl2/turtle.test.js +124 -0
- package/test/owl2rl/cax.test.js +57 -0
- package/test/owl2rl/cls.test.js +210 -0
- package/test/owl2rl/dt.test.js +72 -0
- package/test/owl2rl/eq.test.js +95 -0
- package/test/owl2rl/prp.test.js +198 -0
- package/test/owl2rl/scm.test.js +203 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
|
|
6
|
+
const { writeTurtle } = require('../../src/io/TurtleWriter');
|
|
7
|
+
const { TurtleParser } = require('../../src/io/TurtleParser');
|
|
8
|
+
const { triplesToOntology } = require('../../src/io/RDFGraphToOntology');
|
|
9
|
+
const { OWLOntology, OWLOntologyID } = require('../../src/model/OWLOntology');
|
|
10
|
+
const { OWLClass, OWLObjectProperty, OWLNamedIndividual } = require('../../src/model/OWLEntity');
|
|
11
|
+
const AX = require('../../src/model/OWLAxiom');
|
|
12
|
+
const CE = require('../../src/model/OWLClassExpression');
|
|
13
|
+
const { IRI } = require('../../src/model/IRI');
|
|
14
|
+
|
|
15
|
+
const EX = 'http://ex.org/';
|
|
16
|
+
const c = (n) => new OWLClass(EX + n);
|
|
17
|
+
const p = (n) => new OWLObjectProperty(EX + n);
|
|
18
|
+
const ind = (n) => new OWLNamedIndividual(EX + n);
|
|
19
|
+
|
|
20
|
+
function ontWith(...axioms) {
|
|
21
|
+
const ont = new OWLOntology(new OWLOntologyID(IRI.create(EX + 'ont')));
|
|
22
|
+
for (const a of axioms) ont.addAxiom(a);
|
|
23
|
+
return ont;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function roundTrip(ont) {
|
|
27
|
+
const turtle = writeTurtle(ont);
|
|
28
|
+
const store = new TurtleParser().parse(turtle);
|
|
29
|
+
return { turtle, back: triplesToOntology(store, { ontologyIRI: EX + 'ont' }) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test('SubClassOf round-trip', () => {
|
|
33
|
+
const ont = ontWith(
|
|
34
|
+
new AX.OWLDeclarationAxiom(c('A')),
|
|
35
|
+
new AX.OWLDeclarationAxiom(c('B')),
|
|
36
|
+
new AX.OWLSubClassOfAxiom(c('A'), c('B'))
|
|
37
|
+
);
|
|
38
|
+
const { back } = roundTrip(ont);
|
|
39
|
+
const subs = back.getAxiomsOfType('SubClassOf');
|
|
40
|
+
assert.ok(subs.length >= 1);
|
|
41
|
+
assert.equal(subs[0].subClass.getIRI().toString(), EX + 'A');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('SomeValuesFrom restriction round-trip', () => {
|
|
45
|
+
const ont = ontWith(
|
|
46
|
+
new AX.OWLDeclarationAxiom(c('Parent')),
|
|
47
|
+
new AX.OWLDeclarationAxiom(c('Person')),
|
|
48
|
+
new AX.OWLDeclarationAxiom(p('hasChild')),
|
|
49
|
+
new AX.OWLSubClassOfAxiom(c('Parent'), new CE.OWLObjectSomeValuesFrom(p('hasChild'), c('Person')))
|
|
50
|
+
);
|
|
51
|
+
const { back } = roundTrip(ont);
|
|
52
|
+
const subs = back.getAxiomsOfType('SubClassOf');
|
|
53
|
+
assert.equal(subs.length, 1);
|
|
54
|
+
assert.equal(subs[0].superClass.type, 'ObjectSomeValuesFrom');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('ObjectProperty characteristics round-trip', () => {
|
|
58
|
+
const ont = ontWith(
|
|
59
|
+
new AX.OWLDeclarationAxiom(p('hasAncestor')),
|
|
60
|
+
new AX.OWLTransitiveObjectPropertyAxiom(p('hasAncestor'))
|
|
61
|
+
);
|
|
62
|
+
const { back } = roundTrip(ont);
|
|
63
|
+
assert.ok(back.getAxiomsOfType('TransitiveObjectProperty').length >= 1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('ClassAssertion round-trip', () => {
|
|
67
|
+
const ont = ontWith(
|
|
68
|
+
new AX.OWLDeclarationAxiom(c('Person')),
|
|
69
|
+
new AX.OWLDeclarationAxiom(ind('alice')),
|
|
70
|
+
new AX.OWLClassAssertionAxiom(ind('alice'), c('Person'))
|
|
71
|
+
);
|
|
72
|
+
const { back } = roundTrip(ont);
|
|
73
|
+
const cas = back.getAxiomsOfType('ClassAssertion');
|
|
74
|
+
assert.ok(cas.length >= 1);
|
|
75
|
+
assert.equal(cas[0].individual.getIRI().toString(), EX + 'alice');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('Turtle output contains prefixes and header', () => {
|
|
79
|
+
const ont = ontWith(new AX.OWLDeclarationAxiom(c('Widget')));
|
|
80
|
+
const turtle = writeTurtle(ont);
|
|
81
|
+
assert.ok(turtle.includes('@prefix owl:'));
|
|
82
|
+
assert.ok(turtle.includes('owl:Ontology'));
|
|
83
|
+
assert.ok(turtle.includes('owl:Class'));
|
|
84
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test');
|
|
4
|
+
const assert = require('node:assert');
|
|
5
|
+
const { TurtleParser } = require('../../src/io/TurtleParser');
|
|
6
|
+
const { TripleStore } = require('../../src/inference/TripleStore');
|
|
7
|
+
const { NS } = require('../../src/inference/rdf');
|
|
8
|
+
|
|
9
|
+
test('Turtle: basic triples with @prefix', () => {
|
|
10
|
+
const text = `
|
|
11
|
+
@prefix ex: <http://example.org/> .
|
|
12
|
+
ex:alice a ex:Person .
|
|
13
|
+
`;
|
|
14
|
+
const store = new TurtleParser().parse(text);
|
|
15
|
+
assert.strictEqual(
|
|
16
|
+
store.match('http://example.org/alice', NS.RDF + 'type', 'http://example.org/Person').length,
|
|
17
|
+
1
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('Turtle: semicolon predicate-object lists', () => {
|
|
22
|
+
const text = `
|
|
23
|
+
@prefix ex: <http://example.org/> .
|
|
24
|
+
ex:alice ex:name "Alice" ;
|
|
25
|
+
ex:age 30 .
|
|
26
|
+
`;
|
|
27
|
+
const store = new TurtleParser().parse(text);
|
|
28
|
+
assert.strictEqual(store.match('http://example.org/alice', 'http://example.org/name', null).length, 1);
|
|
29
|
+
assert.strictEqual(store.match('http://example.org/alice', 'http://example.org/age', null).length, 1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('Turtle: comma object lists', () => {
|
|
33
|
+
const text = `
|
|
34
|
+
@prefix ex: <http://example.org/> .
|
|
35
|
+
ex:alice ex:knows ex:bob, ex:carol .
|
|
36
|
+
`;
|
|
37
|
+
const store = new TurtleParser().parse(text);
|
|
38
|
+
assert.strictEqual(store.match('http://example.org/alice', 'http://example.org/knows', null).length, 2);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('Turtle: typed literal', () => {
|
|
42
|
+
const text = `
|
|
43
|
+
@prefix ex: <http://example.org/> .
|
|
44
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
45
|
+
ex:alice ex:age "30"^^xsd:integer .
|
|
46
|
+
`;
|
|
47
|
+
const store = new TurtleParser().parse(text);
|
|
48
|
+
const objs = store.match('http://example.org/alice', 'http://example.org/age', null);
|
|
49
|
+
assert.strictEqual(objs.length, 1);
|
|
50
|
+
assert.match(objs[0][2], /30/);
|
|
51
|
+
assert.match(objs[0][2], /integer/);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('Turtle: language-tagged literal', () => {
|
|
55
|
+
const text = `
|
|
56
|
+
@prefix ex: <http://example.org/> .
|
|
57
|
+
ex:alice ex:name "Alice"@en .
|
|
58
|
+
`;
|
|
59
|
+
const store = new TurtleParser().parse(text);
|
|
60
|
+
const objs = store.match('http://example.org/alice', 'http://example.org/name', null);
|
|
61
|
+
assert.match(objs[0][2], /@en/);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('Turtle: numeric auto-typing', () => {
|
|
65
|
+
const text = `
|
|
66
|
+
@prefix ex: <http://example.org/> .
|
|
67
|
+
ex:x ex:i 42 ; ex:d 3.14 ; ex:e 1.5e3 .
|
|
68
|
+
`;
|
|
69
|
+
const store = new TurtleParser().parse(text);
|
|
70
|
+
assert.match(store.match('http://example.org/x', 'http://example.org/i', null)[0][2], /integer/);
|
|
71
|
+
assert.match(store.match('http://example.org/x', 'http://example.org/d', null)[0][2], /decimal/);
|
|
72
|
+
assert.match(store.match('http://example.org/x', 'http://example.org/e', null)[0][2], /double/);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('Turtle: boolean literals', () => {
|
|
76
|
+
const text = `
|
|
77
|
+
@prefix ex: <http://example.org/> .
|
|
78
|
+
ex:x ex:flag true .
|
|
79
|
+
`;
|
|
80
|
+
const store = new TurtleParser().parse(text);
|
|
81
|
+
assert.match(store.match('http://example.org/x', 'http://example.org/flag', null)[0][2], /true/);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('Turtle: blank node', () => {
|
|
85
|
+
const text = `
|
|
86
|
+
@prefix ex: <http://example.org/> .
|
|
87
|
+
ex:alice ex:address [ ex:city "NYC" ] .
|
|
88
|
+
`;
|
|
89
|
+
const store = new TurtleParser().parse(text);
|
|
90
|
+
const addr = store.match('http://example.org/alice', 'http://example.org/address', null);
|
|
91
|
+
assert.strictEqual(addr.length, 1);
|
|
92
|
+
const bn = addr[0][2];
|
|
93
|
+
assert.match(bn, /^_:/);
|
|
94
|
+
assert.strictEqual(store.match(bn, 'http://example.org/city', null).length, 1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('Turtle: collection list', () => {
|
|
98
|
+
const text = `
|
|
99
|
+
@prefix ex: <http://example.org/> .
|
|
100
|
+
ex:x ex:items ( ex:a ex:b ex:c ) .
|
|
101
|
+
`;
|
|
102
|
+
const store = new TurtleParser().parse(text);
|
|
103
|
+
const list = store.listElements(store.match('http://example.org/x', 'http://example.org/items', null)[0][2]);
|
|
104
|
+
assert.strictEqual(list.length, 3);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('Turtle: comments ignored', () => {
|
|
108
|
+
const text = `
|
|
109
|
+
# a comment
|
|
110
|
+
@prefix ex: <http://example.org/> .
|
|
111
|
+
ex:a ex:b ex:c . # trailing comment
|
|
112
|
+
`;
|
|
113
|
+
const store = new TurtleParser().parse(text);
|
|
114
|
+
assert.strictEqual(store.match('http://example.org/a', 'http://example.org/b', 'http://example.org/c').length, 1);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('Turtle: SPARQL PREFIX style', () => {
|
|
118
|
+
const text = `
|
|
119
|
+
PREFIX ex: <http://example.org/>
|
|
120
|
+
ex:a ex:b ex:c .
|
|
121
|
+
`;
|
|
122
|
+
const store = new TurtleParser().parse(text);
|
|
123
|
+
assert.strictEqual(store.match('http://example.org/a', 'http://example.org/b', 'http://example.org/c').length, 1);
|
|
124
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test');
|
|
4
|
+
const assert = require('node:assert');
|
|
5
|
+
const { OWL2RLReasoner } = require('../../src/inference/OWL2RLReasoner');
|
|
6
|
+
|
|
7
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
8
|
+
const RDFS = 'http://www.w3.org/2000/01/rdf-schema#';
|
|
9
|
+
const OWL = 'http://www.w3.org/2002/07/owl#';
|
|
10
|
+
const T = RDF + 'type';
|
|
11
|
+
|
|
12
|
+
test('cax-sco: subclass membership propagates to superclass', () => {
|
|
13
|
+
const r = new OWL2RLReasoner();
|
|
14
|
+
r.store.add('ex:A', RDFS + 'subClassOf', 'ex:B');
|
|
15
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
16
|
+
r.materialize();
|
|
17
|
+
assert.ok(r.entails('ex:x', T, 'ex:B'));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('cax-eqc1: equivalent class forward direction', () => {
|
|
21
|
+
const r = new OWL2RLReasoner();
|
|
22
|
+
r.store.add('ex:A', OWL + 'equivalentClass', 'ex:B');
|
|
23
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
24
|
+
r.materialize();
|
|
25
|
+
assert.ok(r.entails('ex:x', T, 'ex:B'));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('cax-eqc2: equivalent class backward direction', () => {
|
|
29
|
+
const r = new OWL2RLReasoner();
|
|
30
|
+
r.store.add('ex:A', OWL + 'equivalentClass', 'ex:B');
|
|
31
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
32
|
+
r.materialize();
|
|
33
|
+
assert.ok(r.entails('ex:x', T, 'ex:A'));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('cax-dw: disjoint classes sharing an instance is inconsistent', () => {
|
|
37
|
+
const r = new OWL2RLReasoner();
|
|
38
|
+
r.store.add('ex:A', OWL + 'disjointWith', 'ex:B');
|
|
39
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
40
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
41
|
+
r.materialize();
|
|
42
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cax-dw'));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('cax-adc: AllDisjointClasses sharing an instance is inconsistent', () => {
|
|
46
|
+
const r = new OWL2RLReasoner();
|
|
47
|
+
r.store.add('ex:ad', T, OWL + 'AllDisjointClasses');
|
|
48
|
+
r.store.add('ex:ad', OWL + 'members', '_:m1');
|
|
49
|
+
r.store.add('_:m1', RDF + 'first', 'ex:A');
|
|
50
|
+
r.store.add('_:m1', RDF + 'rest', '_:m2');
|
|
51
|
+
r.store.add('_:m2', RDF + 'first', 'ex:B');
|
|
52
|
+
r.store.add('_:m2', RDF + 'rest', RDF + 'nil');
|
|
53
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
54
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
55
|
+
r.materialize();
|
|
56
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cax-adc'));
|
|
57
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test');
|
|
4
|
+
const assert = require('node:assert');
|
|
5
|
+
const { OWL2RLReasoner } = require('../../src/inference/OWL2RLReasoner');
|
|
6
|
+
|
|
7
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
8
|
+
const OWL = 'http://www.w3.org/2002/07/owl#';
|
|
9
|
+
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
10
|
+
const T = RDF + 'type';
|
|
11
|
+
const SA = OWL + 'sameAs';
|
|
12
|
+
const ZERO = `"0"^^<${XSD}nonNegativeInteger>`;
|
|
13
|
+
const ONE = `"1"^^<${XSD}nonNegativeInteger>`;
|
|
14
|
+
|
|
15
|
+
test('cls-thing: owl:Thing is a class', () => {
|
|
16
|
+
const r = new OWL2RLReasoner();
|
|
17
|
+
r.store.add('ex:a', 'ex:p', 'ex:b');
|
|
18
|
+
r.materialize();
|
|
19
|
+
assert.ok(r.entails(OWL + 'Thing', T, OWL + 'Class'));
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('cls-nothing1: owl:Nothing is a class', () => {
|
|
23
|
+
const r = new OWL2RLReasoner();
|
|
24
|
+
r.store.add('ex:a', 'ex:p', 'ex:b');
|
|
25
|
+
r.materialize();
|
|
26
|
+
assert.ok(r.entails(OWL + 'Nothing', T, OWL + 'Class'));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('cls-nothing2: instance of owl:Nothing is inconsistent', () => {
|
|
30
|
+
const r = new OWL2RLReasoner();
|
|
31
|
+
r.store.add('ex:x', T, OWL + 'Nothing');
|
|
32
|
+
r.materialize();
|
|
33
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cls-nothing2'));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('cls-int1: intersection member-of-all implies intersection', () => {
|
|
37
|
+
const r = new OWL2RLReasoner();
|
|
38
|
+
r.store.add('ex:C', OWL + 'intersectionOf', '_:i1');
|
|
39
|
+
r.store.add('_:i1', RDF + 'first', 'ex:A');
|
|
40
|
+
r.store.add('_:i1', RDF + 'rest', '_:i2');
|
|
41
|
+
r.store.add('_:i2', RDF + 'first', 'ex:B');
|
|
42
|
+
r.store.add('_:i2', RDF + 'rest', RDF + 'nil');
|
|
43
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
44
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
45
|
+
r.materialize();
|
|
46
|
+
assert.ok(r.entails('ex:x', T, 'ex:C'));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('cls-int2: intersection instance belongs to each operand', () => {
|
|
50
|
+
const r = new OWL2RLReasoner();
|
|
51
|
+
r.store.add('ex:C', OWL + 'intersectionOf', '_:i1');
|
|
52
|
+
r.store.add('_:i1', RDF + 'first', 'ex:A');
|
|
53
|
+
r.store.add('_:i1', RDF + 'rest', '_:i2');
|
|
54
|
+
r.store.add('_:i2', RDF + 'first', 'ex:B');
|
|
55
|
+
r.store.add('_:i2', RDF + 'rest', RDF + 'nil');
|
|
56
|
+
r.store.add('ex:x', T, 'ex:C');
|
|
57
|
+
r.materialize();
|
|
58
|
+
assert.ok(r.entails('ex:x', T, 'ex:A'));
|
|
59
|
+
assert.ok(r.entails('ex:x', T, 'ex:B'));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('cls-uni: member of any union operand belongs to the union', () => {
|
|
63
|
+
const r = new OWL2RLReasoner();
|
|
64
|
+
r.store.add('ex:C', OWL + 'unionOf', '_:u1');
|
|
65
|
+
r.store.add('_:u1', RDF + 'first', 'ex:A');
|
|
66
|
+
r.store.add('_:u1', RDF + 'rest', '_:u2');
|
|
67
|
+
r.store.add('_:u2', RDF + 'first', 'ex:B');
|
|
68
|
+
r.store.add('_:u2', RDF + 'rest', RDF + 'nil');
|
|
69
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
70
|
+
r.materialize();
|
|
71
|
+
assert.ok(r.entails('ex:x', T, 'ex:C'));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('cls-com: instance of a class and its complement is inconsistent', () => {
|
|
75
|
+
const r = new OWL2RLReasoner();
|
|
76
|
+
r.store.add('ex:A', OWL + 'complementOf', 'ex:B');
|
|
77
|
+
r.store.add('ex:x', T, 'ex:A');
|
|
78
|
+
r.store.add('ex:x', T, 'ex:B');
|
|
79
|
+
r.materialize();
|
|
80
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cls-com'));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('cls-svf1: someValuesFrom — a filler typed y classifies the subject', () => {
|
|
84
|
+
const r = new OWL2RLReasoner();
|
|
85
|
+
r.store.add('ex:X', OWL + 'someValuesFrom', 'ex:Y');
|
|
86
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
87
|
+
r.store.add('ex:u', 'ex:p', 'ex:v');
|
|
88
|
+
r.store.add('ex:v', T, 'ex:Y');
|
|
89
|
+
r.materialize();
|
|
90
|
+
assert.ok(r.entails('ex:u', T, 'ex:X'));
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('cls-svf2: someValuesFrom owl:Thing — any p-edge classifies the subject', () => {
|
|
94
|
+
const r = new OWL2RLReasoner();
|
|
95
|
+
r.store.add('ex:X', OWL + 'someValuesFrom', OWL + 'Thing');
|
|
96
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
97
|
+
r.store.add('ex:u', 'ex:p', 'ex:v');
|
|
98
|
+
r.materialize();
|
|
99
|
+
assert.ok(r.entails('ex:u', T, 'ex:X'));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('cls-avf: allValuesFrom forces p-fillers of X into Y', () => {
|
|
103
|
+
const r = new OWL2RLReasoner();
|
|
104
|
+
r.store.add('ex:X', OWL + 'allValuesFrom', 'ex:Y');
|
|
105
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
106
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
107
|
+
r.store.add('ex:u', 'ex:p', 'ex:v');
|
|
108
|
+
r.materialize();
|
|
109
|
+
assert.ok(r.entails('ex:v', T, 'ex:Y'));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('cls-hv1: hasValue — every X has p = y', () => {
|
|
113
|
+
const r = new OWL2RLReasoner();
|
|
114
|
+
r.store.add('ex:X', OWL + 'hasValue', 'ex:y');
|
|
115
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
116
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
117
|
+
r.materialize();
|
|
118
|
+
assert.ok(r.entails('ex:u', 'ex:p', 'ex:y'));
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('cls-hv2: hasValue — a p-edge to y classifies the subject as X', () => {
|
|
122
|
+
const r = new OWL2RLReasoner();
|
|
123
|
+
r.store.add('ex:X', OWL + 'hasValue', 'ex:y');
|
|
124
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
125
|
+
r.store.add('ex:u', 'ex:p', 'ex:y');
|
|
126
|
+
r.materialize();
|
|
127
|
+
assert.ok(r.entails('ex:u', T, 'ex:X'));
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('cls-maxc1: maxCardinality 0 with a p-edge is inconsistent', () => {
|
|
131
|
+
const r = new OWL2RLReasoner();
|
|
132
|
+
r.store.add('ex:X', OWL + 'maxCardinality', ZERO);
|
|
133
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
134
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
135
|
+
r.store.add('ex:u', 'ex:p', 'ex:v');
|
|
136
|
+
r.materialize();
|
|
137
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cls-maxc1'));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('cls-maxc2: maxCardinality 1 merges two fillers', () => {
|
|
141
|
+
const r = new OWL2RLReasoner();
|
|
142
|
+
r.store.add('ex:X', OWL + 'maxCardinality', ONE);
|
|
143
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
144
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
145
|
+
r.store.add('ex:u', 'ex:p', 'ex:y1');
|
|
146
|
+
r.store.add('ex:u', 'ex:p', 'ex:y2');
|
|
147
|
+
r.materialize();
|
|
148
|
+
assert.ok(r.entails('ex:y1', SA, 'ex:y2'));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('cls-maxqc1: maxQualifiedCardinality 0 with a typed filler is inconsistent', () => {
|
|
152
|
+
const r = new OWL2RLReasoner();
|
|
153
|
+
r.store.add('ex:X', OWL + 'maxQualifiedCardinality', ZERO);
|
|
154
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
155
|
+
r.store.add('ex:X', OWL + 'onClass', 'ex:C');
|
|
156
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
157
|
+
r.store.add('ex:u', 'ex:p', 'ex:y');
|
|
158
|
+
r.store.add('ex:y', T, 'ex:C');
|
|
159
|
+
r.materialize();
|
|
160
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cls-maxqc1'));
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('cls-maxqc2: maxQualifiedCardinality 0 on Thing with any p-edge is inconsistent', () => {
|
|
164
|
+
const r = new OWL2RLReasoner();
|
|
165
|
+
r.store.add('ex:X', OWL + 'maxQualifiedCardinality', ZERO);
|
|
166
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
167
|
+
r.store.add('ex:X', OWL + 'onClass', OWL + 'Thing');
|
|
168
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
169
|
+
r.store.add('ex:u', 'ex:p', 'ex:y');
|
|
170
|
+
r.materialize();
|
|
171
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'cls-maxqc2'));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('cls-maxqc3: maxQualifiedCardinality 1 merges two C-typed fillers', () => {
|
|
175
|
+
const r = new OWL2RLReasoner();
|
|
176
|
+
r.store.add('ex:X', OWL + 'maxQualifiedCardinality', ONE);
|
|
177
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
178
|
+
r.store.add('ex:X', OWL + 'onClass', 'ex:C');
|
|
179
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
180
|
+
r.store.add('ex:u', 'ex:p', 'ex:y1');
|
|
181
|
+
r.store.add('ex:u', 'ex:p', 'ex:y2');
|
|
182
|
+
r.store.add('ex:y1', T, 'ex:C');
|
|
183
|
+
r.store.add('ex:y2', T, 'ex:C');
|
|
184
|
+
r.materialize();
|
|
185
|
+
assert.ok(r.entails('ex:y1', SA, 'ex:y2'));
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('cls-maxqc4: maxQualifiedCardinality 1 on Thing merges any two fillers', () => {
|
|
189
|
+
const r = new OWL2RLReasoner();
|
|
190
|
+
r.store.add('ex:X', OWL + 'maxQualifiedCardinality', ONE);
|
|
191
|
+
r.store.add('ex:X', OWL + 'onProperty', 'ex:p');
|
|
192
|
+
r.store.add('ex:X', OWL + 'onClass', OWL + 'Thing');
|
|
193
|
+
r.store.add('ex:u', T, 'ex:X');
|
|
194
|
+
r.store.add('ex:u', 'ex:p', 'ex:y1');
|
|
195
|
+
r.store.add('ex:u', 'ex:p', 'ex:y2');
|
|
196
|
+
r.materialize();
|
|
197
|
+
assert.ok(r.entails('ex:y1', SA, 'ex:y2'));
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('cls-oo: oneOf enumerates class membership', () => {
|
|
201
|
+
const r = new OWL2RLReasoner();
|
|
202
|
+
r.store.add('ex:C', OWL + 'oneOf', '_:o1');
|
|
203
|
+
r.store.add('_:o1', RDF + 'first', 'ex:a');
|
|
204
|
+
r.store.add('_:o1', RDF + 'rest', '_:o2');
|
|
205
|
+
r.store.add('_:o2', RDF + 'first', 'ex:b');
|
|
206
|
+
r.store.add('_:o2', RDF + 'rest', RDF + 'nil');
|
|
207
|
+
r.materialize();
|
|
208
|
+
assert.ok(r.entails('ex:a', T, 'ex:C'));
|
|
209
|
+
assert.ok(r.entails('ex:b', T, 'ex:C'));
|
|
210
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test');
|
|
4
|
+
const assert = require('node:assert');
|
|
5
|
+
const { OWL2RLReasoner } = require('../../src/inference/OWL2RLReasoner');
|
|
6
|
+
|
|
7
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
8
|
+
const RDFS = 'http://www.w3.org/2000/01/rdf-schema#';
|
|
9
|
+
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
10
|
+
const T = RDF + 'type';
|
|
11
|
+
const SA = 'http://www.w3.org/2002/07/owl#sameAs';
|
|
12
|
+
const DF = 'http://www.w3.org/2002/07/owl#differentFrom';
|
|
13
|
+
|
|
14
|
+
test('dt-type1: built-in datatypes are typed rdfs:Datatype', () => {
|
|
15
|
+
const r = new OWL2RLReasoner();
|
|
16
|
+
r.store.add('ex:a', 'ex:p', 'ex:b');
|
|
17
|
+
r.materialize();
|
|
18
|
+
assert.ok(r.entails(XSD + 'string', T, RDFS + 'Datatype'));
|
|
19
|
+
assert.ok(r.entails(XSD + 'boolean', T, RDFS + 'Datatype'));
|
|
20
|
+
assert.ok(r.entails(XSD + 'integer', T, RDFS + 'Datatype'));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('dt-type2: typed literal belongs to its datatype', () => {
|
|
24
|
+
const r = new OWL2RLReasoner();
|
|
25
|
+
const lit = `"5"^^<${XSD}integer>`;
|
|
26
|
+
r.store.add('ex:a', 'ex:p', lit);
|
|
27
|
+
r.materialize();
|
|
28
|
+
assert.ok(r.entails(lit, T, XSD + 'integer'));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('dt-type2: untyped literal belongs to rdfs:Literal', () => {
|
|
32
|
+
const r = new OWL2RLReasoner();
|
|
33
|
+
const lit = '"hello"';
|
|
34
|
+
r.store.add('ex:a', 'ex:p', lit);
|
|
35
|
+
r.materialize();
|
|
36
|
+
assert.ok(r.entails(lit, T, RDFS + 'Literal'));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('dt-eq: identical typed literals are sameAs', () => {
|
|
40
|
+
const r = new OWL2RLReasoner();
|
|
41
|
+
const lit = `"5"^^<${XSD}integer>`;
|
|
42
|
+
r.store.add('ex:a', 'ex:p', lit);
|
|
43
|
+
r.materialize();
|
|
44
|
+
assert.ok(r.entails(lit, SA, lit));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('dt-diff: distinct typed literals of the same datatype are differentFrom', () => {
|
|
48
|
+
const r = new OWL2RLReasoner();
|
|
49
|
+
const a = `"5"^^<${XSD}integer>`;
|
|
50
|
+
const b = `"7"^^<${XSD}integer>`;
|
|
51
|
+
r.store.add('ex:x', 'ex:p', a);
|
|
52
|
+
r.store.add('ex:y', 'ex:q', b);
|
|
53
|
+
r.materialize();
|
|
54
|
+
assert.ok(r.entails(a, DF, b));
|
|
55
|
+
assert.ok(r.entails(b, DF, a));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('dt-not-type: ill-typed nonNegativeInteger is inconsistent', () => {
|
|
59
|
+
const r = new OWL2RLReasoner();
|
|
60
|
+
const bad = `"-3"^^<${XSD}nonNegativeInteger>`;
|
|
61
|
+
r.store.add('ex:a', 'ex:p', bad);
|
|
62
|
+
r.materialize();
|
|
63
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'dt-not-type'));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('dt-not-type: well-typed integer is consistent', () => {
|
|
67
|
+
const r = new OWL2RLReasoner();
|
|
68
|
+
const ok = `"42"^^<${XSD}integer>`;
|
|
69
|
+
r.store.add('ex:a', 'ex:p', ok);
|
|
70
|
+
r.materialize();
|
|
71
|
+
assert.ok(!r.inconsistencies.some(c => c.rule === 'dt-not-type'));
|
|
72
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { test } = require('node:test');
|
|
4
|
+
const assert = require('node:assert');
|
|
5
|
+
const { OWL2RLReasoner } = require('../../src/inference/OWL2RLReasoner');
|
|
6
|
+
|
|
7
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
8
|
+
const OWL = 'http://www.w3.org/2002/07/owl#';
|
|
9
|
+
const T = RDF + 'type';
|
|
10
|
+
const SA = OWL + 'sameAs';
|
|
11
|
+
const DF = OWL + 'differentFrom';
|
|
12
|
+
|
|
13
|
+
test('eq-ref: every subject/object is sameAs itself', () => {
|
|
14
|
+
const r = new OWL2RLReasoner();
|
|
15
|
+
r.store.add('ex:a', 'ex:p', 'ex:b');
|
|
16
|
+
r.materialize();
|
|
17
|
+
assert.ok(r.entails('ex:a', SA, 'ex:a'));
|
|
18
|
+
assert.ok(r.entails('ex:b', SA, 'ex:b'));
|
|
19
|
+
assert.ok(r.entails('ex:p', SA, 'ex:p'));
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('eq-sym: sameAs is symmetric', () => {
|
|
23
|
+
const r = new OWL2RLReasoner();
|
|
24
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
25
|
+
r.materialize();
|
|
26
|
+
assert.ok(r.entails('ex:b', SA, 'ex:a'));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('eq-trans: sameAs is transitive', () => {
|
|
30
|
+
const r = new OWL2RLReasoner();
|
|
31
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
32
|
+
r.store.add('ex:b', SA, 'ex:c');
|
|
33
|
+
r.materialize();
|
|
34
|
+
assert.ok(r.entails('ex:a', SA, 'ex:c'));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('eq-rep-s: replace subject by equal subject', () => {
|
|
38
|
+
const r = new OWL2RLReasoner();
|
|
39
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
40
|
+
r.store.add('ex:a', 'ex:p', 'ex:x');
|
|
41
|
+
r.materialize();
|
|
42
|
+
assert.ok(r.entails('ex:b', 'ex:p', 'ex:x'));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('eq-rep-p: replace predicate by equal predicate', () => {
|
|
46
|
+
const r = new OWL2RLReasoner();
|
|
47
|
+
r.store.add('ex:p', SA, 'ex:q');
|
|
48
|
+
r.store.add('ex:a', 'ex:p', 'ex:x');
|
|
49
|
+
r.materialize();
|
|
50
|
+
assert.ok(r.entails('ex:a', 'ex:q', 'ex:x'));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('eq-rep-o: replace object by equal object', () => {
|
|
54
|
+
const r = new OWL2RLReasoner();
|
|
55
|
+
r.store.add('ex:x', SA, 'ex:y');
|
|
56
|
+
r.store.add('ex:a', 'ex:p', 'ex:x');
|
|
57
|
+
r.materialize();
|
|
58
|
+
assert.ok(r.entails('ex:a', 'ex:p', 'ex:y'));
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('eq-diff1: sameAs + differentFrom -> inconsistency', () => {
|
|
62
|
+
const r = new OWL2RLReasoner();
|
|
63
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
64
|
+
r.store.add('ex:a', DF, 'ex:b');
|
|
65
|
+
r.materialize();
|
|
66
|
+
assert.ok(!r.isConsistent());
|
|
67
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'eq-diff1'));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('eq-diff2: AllDifferent members pairwise distinct (inconsistency when same)', () => {
|
|
71
|
+
const r = new OWL2RLReasoner();
|
|
72
|
+
// AllDifferent x with members (a b), and a sameAs b
|
|
73
|
+
r.store.add('ex:ad', T, OWL + 'AllDifferent');
|
|
74
|
+
r.store.add('ex:ad', OWL + 'members', '_:l1');
|
|
75
|
+
r.store.add('_:l1', RDF + 'first', 'ex:a');
|
|
76
|
+
r.store.add('_:l1', RDF + 'rest', '_:l2');
|
|
77
|
+
r.store.add('_:l2', RDF + 'first', 'ex:b');
|
|
78
|
+
r.store.add('_:l2', RDF + 'rest', RDF + 'nil');
|
|
79
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
80
|
+
r.materialize();
|
|
81
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'eq-diff2'));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('eq-diff3: AllDifferent distinctMembers inconsistency when same', () => {
|
|
85
|
+
const r = new OWL2RLReasoner();
|
|
86
|
+
r.store.add('ex:ad', T, OWL + 'AllDifferent');
|
|
87
|
+
r.store.add('ex:ad', OWL + 'distinctMembers', '_:l1');
|
|
88
|
+
r.store.add('_:l1', RDF + 'first', 'ex:a');
|
|
89
|
+
r.store.add('_:l1', RDF + 'rest', '_:l2');
|
|
90
|
+
r.store.add('_:l2', RDF + 'first', 'ex:b');
|
|
91
|
+
r.store.add('_:l2', RDF + 'rest', RDF + 'nil');
|
|
92
|
+
r.store.add('ex:a', SA, 'ex:b');
|
|
93
|
+
r.materialize();
|
|
94
|
+
assert.ok(r.inconsistencies.some(c => c.rule === 'eq-diff3'));
|
|
95
|
+
});
|