eyeling 1.19.4 → 1.19.6
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/HANDBOOK.md +48 -89
- package/examples/deck/extra.md +169 -0
- package/examples/extra/collatz-1000.js +138 -0
- package/examples/extra/control-system.js +68 -0
- package/examples/extra/deep-taxonomy-100000.js +95 -0
- package/examples/extra/delfour.js +110 -0
- package/examples/extra/euler-identity.js +41 -0
- package/examples/extra/fibonacci.js +81 -0
- package/examples/extra/goldbach-1000.js +112 -0
- package/examples/extra/gps.js +274 -0
- package/examples/extra/kaprekar-6174.js +112 -0
- package/examples/extra/matrix-mechanics.js +69 -0
- package/examples/extra/odrl-dpv-ehds-risk-ranked.js +255 -0
- package/examples/extra/output/collatz-1000.txt +18 -0
- package/examples/extra/output/control-system.txt +14 -0
- package/examples/extra/output/deep-taxonomy-100000.txt +15 -0
- package/examples/extra/output/delfour.txt +20 -0
- package/examples/extra/output/euler-identity.txt +12 -0
- package/examples/extra/output/fibonacci.txt +21 -0
- package/examples/extra/output/goldbach-1000.txt +17 -0
- package/examples/extra/output/gps.txt +33 -0
- package/examples/extra/output/kaprekar-6174.txt +17 -0
- package/examples/extra/output/matrix-mechanics.txt +14 -0
- package/examples/extra/output/odrl-dpv-ehds-risk-ranked.txt +48 -0
- package/examples/extra/output/path-discovery.txt +28 -0
- package/examples/extra/output/pn-junction-tunneling.txt +15 -0
- package/examples/extra/output/polynomial.txt +20 -0
- package/examples/extra/output/sudoku.txt +47 -0
- package/examples/extra/output/transistor-switch.txt +16 -0
- package/examples/extra/path-discovery.js +45114 -0
- package/examples/extra/pn-junction-tunneling.js +69 -0
- package/examples/extra/polynomial.js +181 -0
- package/examples/extra/sudoku.js +330 -0
- package/examples/extra/transistor-switch.js +93 -0
- package/examples/fibonacci.n3 +2 -0
- package/examples/output/fibonacci.n3 +1 -0
- package/eyeling.js +49 -45
- package/lib/engine.js +49 -45
- package/package.json +3 -2
- package/test/extra.test.js +100 -0
package/eyeling.js
CHANGED
|
@@ -8133,6 +8133,18 @@ function __printTriggeredFuse(rule, prefixes, subst /* optional */, extraNote /*
|
|
|
8133
8133
|
}
|
|
8134
8134
|
}
|
|
8135
8135
|
|
|
8136
|
+
function __exitReasoning(code, message /* optional */) {
|
|
8137
|
+
if (typeof process !== 'undefined' && process && typeof process.exit === 'function') {
|
|
8138
|
+
process.exit(code);
|
|
8139
|
+
return;
|
|
8140
|
+
}
|
|
8141
|
+
|
|
8142
|
+
const err = new Error(message || `Process exited with code ${code}`);
|
|
8143
|
+
err.__eyelingExit = true;
|
|
8144
|
+
err.code = code;
|
|
8145
|
+
throw err;
|
|
8146
|
+
}
|
|
8147
|
+
|
|
8136
8148
|
function forwardChain(facts, forwardRules, backRules, onDerived /* optional */, opts = {}) {
|
|
8137
8149
|
enterReasoningRun();
|
|
8138
8150
|
try {
|
|
@@ -8272,7 +8284,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8272
8284
|
// Allow dynamic fuses: ... => ?X. where ?X becomes false
|
|
8273
8285
|
if (dynTerm instanceof Literal && dynTerm.value === 'false') {
|
|
8274
8286
|
__printTriggeredFuse(r, opts && opts.prefixes, s, 'Dynamic head resolved to false.');
|
|
8275
|
-
|
|
8287
|
+
__exitReasoning(2, 'Inference fuse triggered.');
|
|
8276
8288
|
}
|
|
8277
8289
|
|
|
8278
8290
|
const dynTriples = __graphTriplesOrTrue(dynTerm);
|
|
@@ -8300,10 +8312,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8300
8312
|
const objIsGraph = obj instanceof GraphTerm;
|
|
8301
8313
|
const subjIsTrue = subj instanceof Literal && subj.value === 'true';
|
|
8302
8314
|
const objIsTrue = obj instanceof Literal && obj.value === 'true';
|
|
8315
|
+
const objIsFalse = obj instanceof Literal && obj.value === 'false';
|
|
8303
8316
|
|
|
8304
8317
|
const isFwRuleTriple =
|
|
8305
|
-
isLogImplies(instantiated.p) &&
|
|
8306
|
-
((subjIsGraph && objIsGraph) || (subjIsTrue && objIsGraph) || (subjIsGraph && objIsTrue));
|
|
8318
|
+
isLogImplies(instantiated.p) && (subjIsGraph || subjIsTrue) && (objIsGraph || objIsTrue || objIsFalse);
|
|
8307
8319
|
|
|
8308
8320
|
const isBwRuleTriple =
|
|
8309
8321
|
isLogImpliedBy(instantiated.p) &&
|
|
@@ -8318,47 +8330,39 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8318
8330
|
changedHere = true;
|
|
8319
8331
|
}
|
|
8320
8332
|
|
|
8321
|
-
// Promote rule-producing triples to live rules, treating literal true as {}
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
newRule.__dynamicConclusionTerm || null,
|
|
8355
|
-
);
|
|
8356
|
-
if (!backRules.__ruleKeySet.has(key)) {
|
|
8357
|
-
backRules.__ruleKeySet.add(key);
|
|
8358
|
-
backRules.push(newRule);
|
|
8359
|
-
indexBackRule(backRules, newRule);
|
|
8360
|
-
rulesChanged = true;
|
|
8361
|
-
}
|
|
8333
|
+
// Promote rule-producing triples to live rules, treating literal true as {}
|
|
8334
|
+
// and literal false as a fuse head.
|
|
8335
|
+
if (isFwRuleTriple) {
|
|
8336
|
+
const newRule = __makeRuleFromTerms(subj, obj, true);
|
|
8337
|
+
__prepareForwardRule(newRule);
|
|
8338
|
+
|
|
8339
|
+
const key = __ruleKey(
|
|
8340
|
+
newRule.isForward,
|
|
8341
|
+
newRule.isFuse,
|
|
8342
|
+
newRule.premise,
|
|
8343
|
+
newRule.conclusion,
|
|
8344
|
+
newRule.__dynamicConclusionTerm || null,
|
|
8345
|
+
);
|
|
8346
|
+
if (!forwardRules.__ruleKeySet.has(key)) {
|
|
8347
|
+
forwardRules.__ruleKeySet.add(key);
|
|
8348
|
+
forwardRules.push(newRule);
|
|
8349
|
+
rulesChanged = true;
|
|
8350
|
+
}
|
|
8351
|
+
} else if (isBwRuleTriple) {
|
|
8352
|
+
const newRule = __makeRuleFromTerms(subj, obj, false);
|
|
8353
|
+
|
|
8354
|
+
const key = __ruleKey(
|
|
8355
|
+
newRule.isForward,
|
|
8356
|
+
newRule.isFuse,
|
|
8357
|
+
newRule.premise,
|
|
8358
|
+
newRule.conclusion,
|
|
8359
|
+
newRule.__dynamicConclusionTerm || null,
|
|
8360
|
+
);
|
|
8361
|
+
if (!backRules.__ruleKeySet.has(key)) {
|
|
8362
|
+
backRules.__ruleKeySet.add(key);
|
|
8363
|
+
backRules.push(newRule);
|
|
8364
|
+
indexBackRule(backRules, newRule);
|
|
8365
|
+
rulesChanged = true;
|
|
8362
8366
|
}
|
|
8363
8367
|
}
|
|
8364
8368
|
|
|
@@ -8441,7 +8445,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
8441
8445
|
// Inference fuse
|
|
8442
8446
|
if (r.isFuse && sols.length) {
|
|
8443
8447
|
__printTriggeredFuse(r, opts && opts.prefixes, sols[0]);
|
|
8444
|
-
|
|
8448
|
+
__exitReasoning(2, 'Inference fuse triggered.');
|
|
8445
8449
|
}
|
|
8446
8450
|
|
|
8447
8451
|
for (const s of sols) {
|
package/lib/engine.js
CHANGED
|
@@ -2651,6 +2651,18 @@ function __printTriggeredFuse(rule, prefixes, subst /* optional */, extraNote /*
|
|
|
2651
2651
|
}
|
|
2652
2652
|
}
|
|
2653
2653
|
|
|
2654
|
+
function __exitReasoning(code, message /* optional */) {
|
|
2655
|
+
if (typeof process !== 'undefined' && process && typeof process.exit === 'function') {
|
|
2656
|
+
process.exit(code);
|
|
2657
|
+
return;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
const err = new Error(message || `Process exited with code ${code}`);
|
|
2661
|
+
err.__eyelingExit = true;
|
|
2662
|
+
err.code = code;
|
|
2663
|
+
throw err;
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2654
2666
|
function forwardChain(facts, forwardRules, backRules, onDerived /* optional */, opts = {}) {
|
|
2655
2667
|
enterReasoningRun();
|
|
2656
2668
|
try {
|
|
@@ -2790,7 +2802,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
2790
2802
|
// Allow dynamic fuses: ... => ?X. where ?X becomes false
|
|
2791
2803
|
if (dynTerm instanceof Literal && dynTerm.value === 'false') {
|
|
2792
2804
|
__printTriggeredFuse(r, opts && opts.prefixes, s, 'Dynamic head resolved to false.');
|
|
2793
|
-
|
|
2805
|
+
__exitReasoning(2, 'Inference fuse triggered.');
|
|
2794
2806
|
}
|
|
2795
2807
|
|
|
2796
2808
|
const dynTriples = __graphTriplesOrTrue(dynTerm);
|
|
@@ -2818,10 +2830,10 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
2818
2830
|
const objIsGraph = obj instanceof GraphTerm;
|
|
2819
2831
|
const subjIsTrue = subj instanceof Literal && subj.value === 'true';
|
|
2820
2832
|
const objIsTrue = obj instanceof Literal && obj.value === 'true';
|
|
2833
|
+
const objIsFalse = obj instanceof Literal && obj.value === 'false';
|
|
2821
2834
|
|
|
2822
2835
|
const isFwRuleTriple =
|
|
2823
|
-
isLogImplies(instantiated.p) &&
|
|
2824
|
-
((subjIsGraph && objIsGraph) || (subjIsTrue && objIsGraph) || (subjIsGraph && objIsTrue));
|
|
2836
|
+
isLogImplies(instantiated.p) && (subjIsGraph || subjIsTrue) && (objIsGraph || objIsTrue || objIsFalse);
|
|
2825
2837
|
|
|
2826
2838
|
const isBwRuleTriple =
|
|
2827
2839
|
isLogImpliedBy(instantiated.p) &&
|
|
@@ -2836,47 +2848,39 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
2836
2848
|
changedHere = true;
|
|
2837
2849
|
}
|
|
2838
2850
|
|
|
2839
|
-
// Promote rule-producing triples to live rules, treating literal true as {}
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
newRule.__dynamicConclusionTerm || null,
|
|
2873
|
-
);
|
|
2874
|
-
if (!backRules.__ruleKeySet.has(key)) {
|
|
2875
|
-
backRules.__ruleKeySet.add(key);
|
|
2876
|
-
backRules.push(newRule);
|
|
2877
|
-
indexBackRule(backRules, newRule);
|
|
2878
|
-
rulesChanged = true;
|
|
2879
|
-
}
|
|
2851
|
+
// Promote rule-producing triples to live rules, treating literal true as {}
|
|
2852
|
+
// and literal false as a fuse head.
|
|
2853
|
+
if (isFwRuleTriple) {
|
|
2854
|
+
const newRule = __makeRuleFromTerms(subj, obj, true);
|
|
2855
|
+
__prepareForwardRule(newRule);
|
|
2856
|
+
|
|
2857
|
+
const key = __ruleKey(
|
|
2858
|
+
newRule.isForward,
|
|
2859
|
+
newRule.isFuse,
|
|
2860
|
+
newRule.premise,
|
|
2861
|
+
newRule.conclusion,
|
|
2862
|
+
newRule.__dynamicConclusionTerm || null,
|
|
2863
|
+
);
|
|
2864
|
+
if (!forwardRules.__ruleKeySet.has(key)) {
|
|
2865
|
+
forwardRules.__ruleKeySet.add(key);
|
|
2866
|
+
forwardRules.push(newRule);
|
|
2867
|
+
rulesChanged = true;
|
|
2868
|
+
}
|
|
2869
|
+
} else if (isBwRuleTriple) {
|
|
2870
|
+
const newRule = __makeRuleFromTerms(subj, obj, false);
|
|
2871
|
+
|
|
2872
|
+
const key = __ruleKey(
|
|
2873
|
+
newRule.isForward,
|
|
2874
|
+
newRule.isFuse,
|
|
2875
|
+
newRule.premise,
|
|
2876
|
+
newRule.conclusion,
|
|
2877
|
+
newRule.__dynamicConclusionTerm || null,
|
|
2878
|
+
);
|
|
2879
|
+
if (!backRules.__ruleKeySet.has(key)) {
|
|
2880
|
+
backRules.__ruleKeySet.add(key);
|
|
2881
|
+
backRules.push(newRule);
|
|
2882
|
+
indexBackRule(backRules, newRule);
|
|
2883
|
+
rulesChanged = true;
|
|
2880
2884
|
}
|
|
2881
2885
|
}
|
|
2882
2886
|
|
|
@@ -2959,7 +2963,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
|
|
|
2959
2963
|
// Inference fuse
|
|
2960
2964
|
if (r.isFuse && sols.length) {
|
|
2961
2965
|
__printTriggeredFuse(r, opts && opts.prefixes, sols[0]);
|
|
2962
|
-
|
|
2966
|
+
__exitReasoning(2, 'Inference fuse triggered.');
|
|
2963
2967
|
}
|
|
2964
2968
|
|
|
2965
2969
|
for (const s of sols) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eyeling",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.6",
|
|
4
4
|
"description": "A minimal Notation3 (N3) reasoner in JavaScript.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -43,10 +43,11 @@
|
|
|
43
43
|
"test:builtin-contract": "node test/builtin-contract.test.js",
|
|
44
44
|
"test:n3gen": "node test/n3gen.test.js",
|
|
45
45
|
"test:examples": "node test/examples.test.js",
|
|
46
|
+
"test:extra": "node test/extra.test.js",
|
|
46
47
|
"test:manifest": "node test/manifest.test.js",
|
|
47
48
|
"test:playground": "node test/playground.test.js",
|
|
48
49
|
"test:package": "node test/package.test.js",
|
|
49
|
-
"test:all": "npm run test:api && npm run test:builtin-contract && npm run test:n3gen && npm run test:examples && npm run test:manifest && npm run test:playground",
|
|
50
|
+
"test:all": "npm run test:api && npm run test:builtin-contract && npm run test:n3gen && npm run test:examples && npm run test:extra && npm run test:manifest && npm run test:playground",
|
|
50
51
|
"pretest": "npm run build && npm run test:packlist",
|
|
51
52
|
"test": "npm run test:all",
|
|
52
53
|
"posttest": "npm run test:package",
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const cp = require('node:child_process');
|
|
7
|
+
|
|
8
|
+
const TTY = process.stdout.isTTY;
|
|
9
|
+
const C = TTY
|
|
10
|
+
? { g: '\x1b[32m', r: '\x1b[31m', y: '\x1b[33m', dim: '\x1b[2m', n: '\x1b[0m' }
|
|
11
|
+
: { g: '', r: '', y: '', dim: '', n: '' };
|
|
12
|
+
const msTag = (ms) => `${C.dim}(${ms} ms)${C.n}`;
|
|
13
|
+
|
|
14
|
+
function ok(msg) {
|
|
15
|
+
console.log(`${C.g}OK${C.n} ${msg}`);
|
|
16
|
+
}
|
|
17
|
+
function fail(msg) {
|
|
18
|
+
console.error(`${C.r}FAIL${C.n} ${msg}`);
|
|
19
|
+
}
|
|
20
|
+
function info(msg) {
|
|
21
|
+
console.log(`${C.y}==${C.n} ${msg}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function main() {
|
|
25
|
+
const suiteStart = Date.now();
|
|
26
|
+
const root = path.resolve(__dirname, '..');
|
|
27
|
+
const extraDir = path.join(root, 'examples', 'extra');
|
|
28
|
+
const outputDir = path.join(extraDir, 'output');
|
|
29
|
+
const nodePath = process.execPath;
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(extraDir)) {
|
|
32
|
+
fail(`Cannot find examples/extra directory: ${extraDir}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
37
|
+
|
|
38
|
+
const files = fs
|
|
39
|
+
.readdirSync(extraDir)
|
|
40
|
+
.filter((f) => f.endsWith('.js'))
|
|
41
|
+
.sort((a, b) => a.localeCompare(b));
|
|
42
|
+
|
|
43
|
+
info(`Running ${files.length} extra examples`);
|
|
44
|
+
console.log(`${C.dim}node ${process.version}${C.n}`);
|
|
45
|
+
|
|
46
|
+
if (files.length === 0) {
|
|
47
|
+
ok('No .js files found in examples/extra/');
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let passed = 0;
|
|
52
|
+
let failed = 0;
|
|
53
|
+
const idxWidth = String(files.length).length;
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < files.length; i += 1) {
|
|
56
|
+
const idx = String(i + 1).padStart(idxWidth, '0');
|
|
57
|
+
const file = files[i];
|
|
58
|
+
const start = Date.now();
|
|
59
|
+
|
|
60
|
+
const inputPath = path.join(extraDir, file);
|
|
61
|
+
const outputPath = path.join(outputDir, file.replace(/\.js$/i, '.txt'));
|
|
62
|
+
|
|
63
|
+
const r = cp.spawnSync(nodePath, [inputPath], {
|
|
64
|
+
cwd: extraDir,
|
|
65
|
+
encoding: 'utf8',
|
|
66
|
+
maxBuffer: 200 * 1024 * 1024,
|
|
67
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const stdout = r.stdout || '';
|
|
71
|
+
fs.writeFileSync(outputPath, stdout, 'utf8');
|
|
72
|
+
|
|
73
|
+
const rc = r.status == null ? 1 : r.status;
|
|
74
|
+
const ms = Date.now() - start;
|
|
75
|
+
|
|
76
|
+
if (rc === 0) {
|
|
77
|
+
ok(`${idx} ${file} -> output/${path.basename(outputPath)} ${msTag(ms)}`);
|
|
78
|
+
passed += 1;
|
|
79
|
+
} else {
|
|
80
|
+
fail(`${idx} ${file} ${msTag(ms)}`);
|
|
81
|
+
fail(`Exit code ${rc}`);
|
|
82
|
+
if (r.stderr) process.stderr.write(r.stderr);
|
|
83
|
+
failed += 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('');
|
|
88
|
+
const suiteMs = Date.now() - suiteStart;
|
|
89
|
+
info(`Total elapsed: ${suiteMs} ms (${(suiteMs / 1000).toFixed(2)} s)`);
|
|
90
|
+
|
|
91
|
+
if (failed === 0) {
|
|
92
|
+
ok(`All extra examples passed (${passed}/${files.length})`);
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fail(`Some extra examples failed (${passed}/${files.length})`);
|
|
97
|
+
process.exit(2);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main();
|