n3 1.19.0 → 1.20.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/README.md +27 -0
- package/browser/n3.min.js +1 -1
- package/lib/N3Reasoner.js +226 -0
- package/lib/index.js +14 -0
- package/package.json +2 -1
- package/src/N3Reasoner.js +206 -0
- package/src/index.js +4 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
exports.getRulesFromDataset = getRulesFromDataset;
|
|
8
|
+
var _N3DataFactory = _interopRequireDefault(require("./N3DataFactory"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/**
|
|
11
|
+
* Gets rules from a dataset. This will only collect horn rules declared using log:implies.
|
|
12
|
+
*/
|
|
13
|
+
function getRulesFromDataset(dataset) {
|
|
14
|
+
const rules = [];
|
|
15
|
+
for (const {
|
|
16
|
+
subject,
|
|
17
|
+
object
|
|
18
|
+
} of dataset.match(null, _N3DataFactory.default.namedNode('http://www.w3.org/2000/10/swap/log#implies'), null, _N3DataFactory.default.defaultGraph())) {
|
|
19
|
+
const premise = [...dataset.match(null, null, null, subject)];
|
|
20
|
+
const conclusion = [...dataset.match(null, null, null, object)];
|
|
21
|
+
rules.push({
|
|
22
|
+
premise,
|
|
23
|
+
conclusion
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return rules;
|
|
27
|
+
}
|
|
28
|
+
class N3Reasoner {
|
|
29
|
+
constructor(store) {
|
|
30
|
+
this._store = store;
|
|
31
|
+
}
|
|
32
|
+
_add(subject, predicate, object, graphItem, cb) {
|
|
33
|
+
// Only add to the remaining indexes if there is not already a value in the index
|
|
34
|
+
if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
|
|
35
|
+
this._store._addToIndex(graphItem.predicates, predicate, object, subject);
|
|
36
|
+
this._store._addToIndex(graphItem.objects, object, subject, predicate);
|
|
37
|
+
cb();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// eslint-disable-next-line no-warning-comments
|
|
41
|
+
_evaluatePremise(rule, content, cb, i = 0) {
|
|
42
|
+
let v1, v2, value, index1, index2;
|
|
43
|
+
const [val0, val1, val2] = rule.premise[i].value,
|
|
44
|
+
index = content[rule.premise[i].content];
|
|
45
|
+
const v0 = !(value = val0.value);
|
|
46
|
+
for (value in v0 ? index : {
|
|
47
|
+
[value]: index[value]
|
|
48
|
+
}) {
|
|
49
|
+
if (index1 = index[value]) {
|
|
50
|
+
if (v0) val0.value = Number(value);
|
|
51
|
+
v1 = !(value = val1.value);
|
|
52
|
+
for (value in v1 ? index1 : {
|
|
53
|
+
[value]: index1[value]
|
|
54
|
+
}) {
|
|
55
|
+
if (index2 = index1[value]) {
|
|
56
|
+
if (v1) val1.value = Number(value);
|
|
57
|
+
v2 = !(value = val2.value);
|
|
58
|
+
for (value in v2 ? index2 : {
|
|
59
|
+
[value]: index2[value]
|
|
60
|
+
}) {
|
|
61
|
+
if (v2) val2.value = Number(value);
|
|
62
|
+
if (i === rule.premise.length - 1) rule.conclusion.forEach(c => {
|
|
63
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
64
|
+
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
|
|
65
|
+
cb(c);
|
|
66
|
+
});
|
|
67
|
+
});else this._evaluatePremise(rule, content, cb, i + 1);
|
|
68
|
+
}
|
|
69
|
+
if (v2) val2.value = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (v1) val1.value = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (v0) val0.value = null;
|
|
76
|
+
}
|
|
77
|
+
_evaluateRules(rules, content, cb) {
|
|
78
|
+
for (let i = 0; i < rules.length; i++) {
|
|
79
|
+
this._evaluatePremise(rules[i], content, cb);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A naive reasoning algorithm where rules are just applied by repeatedly applying rules
|
|
84
|
+
// until no more evaluations are made
|
|
85
|
+
_reasonGraphNaive(rules, content) {
|
|
86
|
+
const newRules = [];
|
|
87
|
+
function addRule(conclusion) {
|
|
88
|
+
if (conclusion.next) conclusion.next.forEach(rule => {
|
|
89
|
+
newRules.push([conclusion.subject.value, conclusion.predicate.value, conclusion.object.value, rule]);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// eslint-disable-next-line func-style
|
|
94
|
+
const addConclusions = conclusion => {
|
|
95
|
+
conclusion.forEach(c => {
|
|
96
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
97
|
+
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
|
|
98
|
+
addRule(c);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
this._evaluateRules(rules, content, addRule);
|
|
103
|
+
let r;
|
|
104
|
+
while ((r = newRules.pop()) !== undefined) {
|
|
105
|
+
const [subject, predicate, object, rule] = r;
|
|
106
|
+
const v1 = rule.basePremise.subject.value;
|
|
107
|
+
if (!v1) rule.basePremise.subject.value = subject;
|
|
108
|
+
const v2 = rule.basePremise.predicate.value;
|
|
109
|
+
if (!v2) rule.basePremise.predicate.value = predicate;
|
|
110
|
+
const v3 = rule.basePremise.object.value;
|
|
111
|
+
if (!v3) rule.basePremise.object.value = object;
|
|
112
|
+
if (rule.premise.length === 0) {
|
|
113
|
+
addConclusions(rule.conclusion);
|
|
114
|
+
} else {
|
|
115
|
+
this._evaluatePremise(rule, content, addRule);
|
|
116
|
+
}
|
|
117
|
+
if (!v1) rule.basePremise.subject.value = null;
|
|
118
|
+
if (!v2) rule.basePremise.predicate.value = null;
|
|
119
|
+
if (!v3) rule.basePremise.object.value = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
_createRule({
|
|
123
|
+
premise,
|
|
124
|
+
conclusion
|
|
125
|
+
}) {
|
|
126
|
+
const varMapping = {};
|
|
127
|
+
const toId = value => value.termType === 'Variable' ?
|
|
128
|
+
// If the term is a variable, then create an empty object that values can be placed into
|
|
129
|
+
varMapping[value.value] = varMapping[value.value] || {} :
|
|
130
|
+
// If the term is not a variable, then set the ID value
|
|
131
|
+
{
|
|
132
|
+
value: this._store._termToNewNumericId(value)
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// eslint-disable-next-line func-style
|
|
136
|
+
const t = term => ({
|
|
137
|
+
subject: toId(term.subject),
|
|
138
|
+
predicate: toId(term.predicate),
|
|
139
|
+
object: toId(term.object)
|
|
140
|
+
});
|
|
141
|
+
return {
|
|
142
|
+
premise: premise.map(p => t(p)),
|
|
143
|
+
conclusion: conclusion.map(p => t(p)),
|
|
144
|
+
variables: Object.values(varMapping)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
reason(rules) {
|
|
148
|
+
if (!Array.isArray(rules)) {
|
|
149
|
+
rules = getRulesFromDataset(rules);
|
|
150
|
+
}
|
|
151
|
+
rules = rules.map(rule => this._createRule(rule));
|
|
152
|
+
for (const r1 of rules) {
|
|
153
|
+
for (const r2 of rules) {
|
|
154
|
+
for (let i = 0; i < r2.premise.length; i++) {
|
|
155
|
+
const p = r2.premise[i];
|
|
156
|
+
for (const c of r1.conclusion) {
|
|
157
|
+
if (termEq(p.subject, c.subject) && termEq(p.predicate, c.predicate) && termEq(p.object, c.object)) {
|
|
158
|
+
const set = new Set();
|
|
159
|
+
const premise = [];
|
|
160
|
+
|
|
161
|
+
// Since these *will* be substituted when we apply the rule,
|
|
162
|
+
// we need to do this, so that we index correctly in the subsequent section
|
|
163
|
+
p.subject.value = p.subject.value || 1;
|
|
164
|
+
p.object.value = p.object.value || 1;
|
|
165
|
+
p.predicate.value = p.predicate.value || 1;
|
|
166
|
+
for (let j = 0; j < r2.premise.length; j++) {
|
|
167
|
+
if (j !== i) {
|
|
168
|
+
premise.push(getIndex(r2.premise[j], set));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// eslint-disable-next-line no-warning-comments
|
|
173
|
+
// TODO: Create new rule, with new indexing
|
|
174
|
+
// Future, 'collapse' the next statements when they share a premise/base-premise
|
|
175
|
+
(c.next = c.next || []).push({
|
|
176
|
+
premise,
|
|
177
|
+
conclusion: r2.conclusion,
|
|
178
|
+
// This is a single premise of the form { subject, predicate, object },
|
|
179
|
+
// which we can use to instantiate the rule using the new data that was emitted
|
|
180
|
+
basePremise: p
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
r2.variables.forEach(v => {
|
|
184
|
+
v.value = null;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
for (const rule of rules) {
|
|
191
|
+
const set = new Set();
|
|
192
|
+
rule.premise = rule.premise.map(p => getIndex(p, set));
|
|
193
|
+
}
|
|
194
|
+
const graphs = this._store._getGraphs();
|
|
195
|
+
for (const graphId in graphs) {
|
|
196
|
+
this._reasonGraphNaive(rules, graphs[graphId]);
|
|
197
|
+
}
|
|
198
|
+
this._store._size = null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.default = N3Reasoner;
|
|
202
|
+
function getIndex({
|
|
203
|
+
subject,
|
|
204
|
+
predicate,
|
|
205
|
+
object
|
|
206
|
+
}, set) {
|
|
207
|
+
const s = subject.value || set.has(subject) || (set.add(subject), false);
|
|
208
|
+
const p = predicate.value || set.has(predicate) || (set.add(predicate), false);
|
|
209
|
+
const o = object.value || set.has(object) || (set.add(object), false);
|
|
210
|
+
return !s && p ? {
|
|
211
|
+
content: 'predicates',
|
|
212
|
+
value: [predicate, object, subject]
|
|
213
|
+
} : o ? {
|
|
214
|
+
content: 'objects',
|
|
215
|
+
value: [object, subject, predicate]
|
|
216
|
+
} : {
|
|
217
|
+
content: 'subjects',
|
|
218
|
+
value: [subject, predicate, object]
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function termEq(t1, t2) {
|
|
222
|
+
if (t1.value === null) {
|
|
223
|
+
t1.value = t2.value;
|
|
224
|
+
}
|
|
225
|
+
return t1.value === t2.value;
|
|
226
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -57,6 +57,12 @@ Object.defineProperty(exports, "Quad", {
|
|
|
57
57
|
return _N3DataFactory.Quad;
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
+
Object.defineProperty(exports, "Reasoner", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function () {
|
|
63
|
+
return _N3Reasoner.default;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
60
66
|
Object.defineProperty(exports, "Store", {
|
|
61
67
|
enumerable: true,
|
|
62
68
|
get: function () {
|
|
@@ -107,6 +113,12 @@ Object.defineProperty(exports, "Writer", {
|
|
|
107
113
|
}
|
|
108
114
|
});
|
|
109
115
|
exports.default = void 0;
|
|
116
|
+
Object.defineProperty(exports, "getRulesFromDataset", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: function () {
|
|
119
|
+
return _N3Reasoner.getRulesFromDataset;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
110
122
|
Object.defineProperty(exports, "termFromId", {
|
|
111
123
|
enumerable: true,
|
|
112
124
|
get: function () {
|
|
@@ -124,6 +136,7 @@ var _N3Parser = _interopRequireDefault(require("./N3Parser"));
|
|
|
124
136
|
var _N3Writer = _interopRequireDefault(require("./N3Writer"));
|
|
125
137
|
var _N3Store = _interopRequireWildcard(require("./N3Store"));
|
|
126
138
|
var _N3StoreFactory = _interopRequireDefault(require("./N3StoreFactory"));
|
|
139
|
+
var _N3Reasoner = _interopRequireWildcard(require("./N3Reasoner"));
|
|
127
140
|
var _N3StreamParser = _interopRequireDefault(require("./N3StreamParser"));
|
|
128
141
|
var _N3StreamWriter = _interopRequireDefault(require("./N3StreamWriter"));
|
|
129
142
|
var Util = _interopRequireWildcard(require("./N3Util"));
|
|
@@ -144,6 +157,7 @@ var _default = exports.default = {
|
|
|
144
157
|
StreamParser: _N3StreamParser.default,
|
|
145
158
|
StreamWriter: _N3StreamWriter.default,
|
|
146
159
|
Util,
|
|
160
|
+
Reasoner: _N3Reasoner.default,
|
|
147
161
|
DataFactory: _N3DataFactory.default,
|
|
148
162
|
Term: _N3DataFactory.Term,
|
|
149
163
|
NamedNode: _N3DataFactory.NamedNode,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n3",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
|
|
5
5
|
"author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
|
|
6
6
|
"keywords": [
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"arrayify-stream": "^1.0.0",
|
|
38
38
|
"browserify": "^17.0.0",
|
|
39
39
|
"colors": "^1.1.2",
|
|
40
|
+
"deep-taxonomy-benchmark": "^1.2.0",
|
|
40
41
|
"docco": "^0.9.1",
|
|
41
42
|
"eslint": "^5.14.1",
|
|
42
43
|
"eslint-plugin-import": "^2.29.1",
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import DF from './N3DataFactory';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gets rules from a dataset. This will only collect horn rules declared using log:implies.
|
|
5
|
+
*/
|
|
6
|
+
export function getRulesFromDataset(dataset) {
|
|
7
|
+
const rules = [];
|
|
8
|
+
for (const { subject, object } of dataset.match(null, DF.namedNode('http://www.w3.org/2000/10/swap/log#implies'), null, DF.defaultGraph())) {
|
|
9
|
+
const premise = [...dataset.match(null, null, null, subject)];
|
|
10
|
+
const conclusion = [...dataset.match(null, null, null, object)];
|
|
11
|
+
rules.push({ premise, conclusion });
|
|
12
|
+
}
|
|
13
|
+
return rules;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default class N3Reasoner {
|
|
17
|
+
constructor(store) {
|
|
18
|
+
this._store = store;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_add(subject, predicate, object, graphItem, cb) {
|
|
22
|
+
// Only add to the remaining indexes if there is not already a value in the index
|
|
23
|
+
if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
|
|
24
|
+
this._store._addToIndex(graphItem.predicates, predicate, object, subject);
|
|
25
|
+
this._store._addToIndex(graphItem.objects, object, subject, predicate);
|
|
26
|
+
cb();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line no-warning-comments
|
|
30
|
+
_evaluatePremise(rule, content, cb, i = 0) {
|
|
31
|
+
let v1, v2, value, index1, index2;
|
|
32
|
+
const [val0, val1, val2] = rule.premise[i].value, index = content[rule.premise[i].content];
|
|
33
|
+
const v0 = !(value = val0.value);
|
|
34
|
+
for (value in v0 ? index : { [value]: index[value] }) {
|
|
35
|
+
if (index1 = index[value]) {
|
|
36
|
+
if (v0) val0.value = Number(value);
|
|
37
|
+
v1 = !(value = val1.value);
|
|
38
|
+
for (value in v1 ? index1 : { [value]: index1[value] }) {
|
|
39
|
+
if (index2 = index1[value]) {
|
|
40
|
+
if (v1) val1.value = Number(value);
|
|
41
|
+
v2 = !(value = val2.value);
|
|
42
|
+
for (value in v2 ? index2 : { [value]: index2[value] }) {
|
|
43
|
+
if (v2) val2.value = Number(value);
|
|
44
|
+
|
|
45
|
+
if (i === rule.premise.length - 1)
|
|
46
|
+
rule.conclusion.forEach(c => {
|
|
47
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
48
|
+
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { cb(c); });
|
|
49
|
+
});
|
|
50
|
+
else
|
|
51
|
+
this._evaluatePremise(rule, content, cb, i + 1);
|
|
52
|
+
}
|
|
53
|
+
if (v2) val2.value = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (v1) val1.value = null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (v0) val0.value = null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_evaluateRules(rules, content, cb) {
|
|
63
|
+
for (let i = 0; i < rules.length; i++) {
|
|
64
|
+
this._evaluatePremise(rules[i], content, cb);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// A naive reasoning algorithm where rules are just applied by repeatedly applying rules
|
|
69
|
+
// until no more evaluations are made
|
|
70
|
+
_reasonGraphNaive(rules, content) {
|
|
71
|
+
const newRules = [];
|
|
72
|
+
|
|
73
|
+
function addRule(conclusion) {
|
|
74
|
+
if (conclusion.next)
|
|
75
|
+
conclusion.next.forEach(rule => {
|
|
76
|
+
newRules.push([conclusion.subject.value, conclusion.predicate.value, conclusion.object.value, rule]);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// eslint-disable-next-line func-style
|
|
81
|
+
const addConclusions = conclusion => {
|
|
82
|
+
conclusion.forEach(c => {
|
|
83
|
+
// eslint-disable-next-line max-nested-callbacks
|
|
84
|
+
this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { addRule(c); });
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
this._evaluateRules(rules, content, addRule);
|
|
89
|
+
|
|
90
|
+
let r;
|
|
91
|
+
while ((r = newRules.pop()) !== undefined) {
|
|
92
|
+
const [subject, predicate, object, rule] = r;
|
|
93
|
+
const v1 = rule.basePremise.subject.value;
|
|
94
|
+
if (!v1) rule.basePremise.subject.value = subject;
|
|
95
|
+
const v2 = rule.basePremise.predicate.value;
|
|
96
|
+
if (!v2) rule.basePremise.predicate.value = predicate;
|
|
97
|
+
const v3 = rule.basePremise.object.value;
|
|
98
|
+
if (!v3) rule.basePremise.object.value = object;
|
|
99
|
+
|
|
100
|
+
if (rule.premise.length === 0) {
|
|
101
|
+
addConclusions(rule.conclusion);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
this._evaluatePremise(rule, content, addRule);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!v1) rule.basePremise.subject.value = null;
|
|
108
|
+
if (!v2) rule.basePremise.predicate.value = null;
|
|
109
|
+
if (!v3) rule.basePremise.object.value = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_createRule({ premise, conclusion }) {
|
|
114
|
+
const varMapping = {};
|
|
115
|
+
|
|
116
|
+
const toId = value => value.termType === 'Variable' ?
|
|
117
|
+
// If the term is a variable, then create an empty object that values can be placed into
|
|
118
|
+
(varMapping[value.value] = varMapping[value.value] || {}) :
|
|
119
|
+
// If the term is not a variable, then set the ID value
|
|
120
|
+
{ value: this._store._termToNewNumericId(value) };
|
|
121
|
+
|
|
122
|
+
// eslint-disable-next-line func-style
|
|
123
|
+
const t = term => ({ subject: toId(term.subject), predicate: toId(term.predicate), object: toId(term.object) });
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
premise: premise.map(p => t(p)),
|
|
127
|
+
conclusion: conclusion.map(p => t(p)),
|
|
128
|
+
variables: Object.values(varMapping),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
reason(rules) {
|
|
133
|
+
if (!Array.isArray(rules)) {
|
|
134
|
+
rules = getRulesFromDataset(rules);
|
|
135
|
+
}
|
|
136
|
+
rules = rules.map(rule => this._createRule(rule));
|
|
137
|
+
|
|
138
|
+
for (const r1 of rules) {
|
|
139
|
+
for (const r2 of rules) {
|
|
140
|
+
for (let i = 0; i < r2.premise.length; i++) {
|
|
141
|
+
const p = r2.premise[i];
|
|
142
|
+
for (const c of r1.conclusion) {
|
|
143
|
+
if (termEq(p.subject, c.subject) && termEq(p.predicate, c.predicate) && termEq(p.object, c.object)) {
|
|
144
|
+
const set = new Set();
|
|
145
|
+
|
|
146
|
+
const premise = [];
|
|
147
|
+
|
|
148
|
+
// Since these *will* be substituted when we apply the rule,
|
|
149
|
+
// we need to do this, so that we index correctly in the subsequent section
|
|
150
|
+
p.subject.value = p.subject.value || 1;
|
|
151
|
+
p.object.value = p.object.value || 1;
|
|
152
|
+
p.predicate.value = p.predicate.value || 1;
|
|
153
|
+
|
|
154
|
+
for (let j = 0; j < r2.premise.length; j++) {
|
|
155
|
+
if (j !== i) {
|
|
156
|
+
premise.push(getIndex(r2.premise[j], set));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// eslint-disable-next-line no-warning-comments
|
|
161
|
+
// TODO: Create new rule, with new indexing
|
|
162
|
+
// Future, 'collapse' the next statements when they share a premise/base-premise
|
|
163
|
+
(c.next = c.next || []).push({
|
|
164
|
+
premise,
|
|
165
|
+
conclusion: r2.conclusion,
|
|
166
|
+
// This is a single premise of the form { subject, predicate, object },
|
|
167
|
+
// which we can use to instantiate the rule using the new data that was emitted
|
|
168
|
+
basePremise: p,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
r2.variables.forEach(v => { v.value = null; });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (const rule of rules) {
|
|
178
|
+
const set = new Set();
|
|
179
|
+
rule.premise = rule.premise.map(p => getIndex(p, set));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const graphs = this._store._getGraphs();
|
|
183
|
+
for (const graphId in graphs) {
|
|
184
|
+
this._reasonGraphNaive(rules, graphs[graphId]);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this._store._size = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function getIndex({ subject, predicate, object }, set) {
|
|
192
|
+
const s = subject.value || set.has(subject) || (set.add(subject), false);
|
|
193
|
+
const p = predicate.value || set.has(predicate) || (set.add(predicate), false);
|
|
194
|
+
const o = object.value || set.has(object) || (set.add(object), false);
|
|
195
|
+
|
|
196
|
+
return (!s && p) ? { content: 'predicates', value: [predicate, object, subject] } :
|
|
197
|
+
o ? { content: 'objects', value: [object, subject, predicate] } :
|
|
198
|
+
{ content: 'subjects', value: [subject, predicate, object] };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function termEq(t1, t2) {
|
|
202
|
+
if (t1.value === null) {
|
|
203
|
+
t1.value = t2.value;
|
|
204
|
+
}
|
|
205
|
+
return t1.value === t2.value;
|
|
206
|
+
}
|
package/src/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import Parser from './N3Parser';
|
|
|
3
3
|
import Writer from './N3Writer';
|
|
4
4
|
import Store, { N3EntityIndex as EntityIndex } from './N3Store';
|
|
5
5
|
import StoreFactory from './N3StoreFactory';
|
|
6
|
+
import Reasoner, { getRulesFromDataset } from './N3Reasoner';
|
|
6
7
|
import StreamParser from './N3StreamParser';
|
|
7
8
|
import StreamWriter from './N3StreamWriter';
|
|
8
9
|
import * as Util from './N3Util';
|
|
@@ -34,6 +35,7 @@ export {
|
|
|
34
35
|
StreamParser,
|
|
35
36
|
StreamWriter,
|
|
36
37
|
Util,
|
|
38
|
+
Reasoner,
|
|
37
39
|
|
|
38
40
|
DataFactory,
|
|
39
41
|
|
|
@@ -48,6 +50,7 @@ export {
|
|
|
48
50
|
|
|
49
51
|
termFromId,
|
|
50
52
|
termToId,
|
|
53
|
+
getRulesFromDataset,
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// Export all named exports as a default object for backward compatibility
|
|
@@ -61,6 +64,7 @@ export default {
|
|
|
61
64
|
StreamParser,
|
|
62
65
|
StreamWriter,
|
|
63
66
|
Util,
|
|
67
|
+
Reasoner,
|
|
64
68
|
|
|
65
69
|
DataFactory,
|
|
66
70
|
|