eyeprolog 1.6.39 → 1.6.41
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/examples/check/dependency-depth-10000.pl +14 -0
- package/examples/check/dependency-preparation-5000.pl +14 -0
- package/examples/deck/README.md +2 -0
- package/examples/deck/dependency-depth-10000.md +107 -0
- package/examples/deck/dependency-preparation-5000.md +106 -0
- package/examples/dependency-depth-10000.pl +10008 -0
- package/examples/dependency-preparation-5000.pl +5008 -0
- package/examples/output/dependency-depth-10000.pl +1 -0
- package/examples/output/dependency-preparation-5000.pl +1 -0
- package/examples/proof/dependency-depth-10000.pl +8 -0
- package/examples/proof/dependency-preparation-5000.pl +7 -0
- package/package.json +1 -1
- package/playground.html +2 -0
- package/src/check-proof.js +30 -3
- package/src/explain.js +36 -4
- package/src/parser.js +14 -5
- package/src/program-analysis.js +80 -22
- package/src/program.js +31 -37
- package/src/result-format.js +24 -3
- package/src/write.js +11 -3
- package/test/README.md +4 -0
- package/test/parallel-tasks.mjs +23 -5
- package/test/regression/cases-regression.mjs +34 -0
- package/test/regression/cases-white-box.mjs +116 -0
- package/test/run-examples.mjs +1 -0
- package/test/run-proof-checking.mjs +2 -1
- package/test/test-support.mjs +23 -15
- package/the-art-of-eyeprolog.md +4 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
condition('C1', resolution, ok, 2).
|
|
2
|
+
condition('C2', well_founded, ok, 3).
|
|
3
|
+
condition('C3', justification, ok, 3).
|
|
4
|
+
condition('C4', coverage, ok, 3).
|
|
5
|
+
condition('C5', re_decision, ok, 1).
|
|
6
|
+
condition('C6', boundary_consistency, ok, 0).
|
|
7
|
+
condition('C7', relevance, ok, 4).
|
|
8
|
+
steps(3).
|
|
9
|
+
verified(2).
|
|
10
|
+
recomputed(1).
|
|
11
|
+
composed(0).
|
|
12
|
+
trusted(0).
|
|
13
|
+
claims(1).
|
|
14
|
+
verdict(checked).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
condition('C1', resolution, ok, 2).
|
|
2
|
+
condition('C2', well_founded, ok, 2).
|
|
3
|
+
condition('C3', justification, ok, 2).
|
|
4
|
+
condition('C4', coverage, ok, 2).
|
|
5
|
+
condition('C5', re_decision, ok, 0).
|
|
6
|
+
condition('C6', boundary_consistency, ok, 0).
|
|
7
|
+
condition('C7', relevance, ok, 3).
|
|
8
|
+
steps(2).
|
|
9
|
+
verified(2).
|
|
10
|
+
recomputed(0).
|
|
11
|
+
composed(0).
|
|
12
|
+
trusted(0).
|
|
13
|
+
claims(1).
|
|
14
|
+
verdict(checked).
|
package/examples/deck/README.md
CHANGED
|
@@ -81,6 +81,8 @@ check of that proof. Each deck links to the source and opens the example in the
|
|
|
81
81
|
- [Delayed disequality with dif/2](https://eyereasoner.github.io/eyeprolog/examples/deck/dif-constraints) — How do you say "these must differ" before you know what they are?
|
|
82
82
|
- [Delfour: a privacy-preserving shopping insight](https://eyereasoner.github.io/eyeprolog/examples/deck/delfour) — Can a store scanner give diabetes-aware advice without ever learning about the diabetes?
|
|
83
83
|
- [Deontic logic](https://eyereasoner.github.io/eyeprolog/examples/deck/deontic-logic) — Which duties were broken, which were repaired, and does someone need to review it?
|
|
84
|
+
- [Dependency depth: 10,000 predicates](https://eyereasoner.github.io/eyeprolog/examples/deck/dependency-depth-10000) — Can dependency analysis follow a deep chain without exhausting the JavaScript stack?
|
|
85
|
+
- [Dependency preparation: 5,000 predicates](https://eyereasoner.github.io/eyeprolog/examples/deck/dependency-preparation-5000) — How quickly can the engine prepare thousands of distinct predicates?
|
|
84
86
|
- [Dijkstra with findall and sort](https://eyereasoner.github.io/eyeprolog/examples/deck/dijkstra-findall-sort) — What is the cheapest route, found the way Dijkstra would?
|
|
85
87
|
- [Dining philosophers](https://eyereasoner.github.io/eyeprolog/examples/deck/dining-philosophers) — Who eats when, and with which forks?
|
|
86
88
|
- [DONALD + GERALD = ROBERT](https://eyereasoner.github.io/eyeprolog/examples/deck/donald-gerald-robert) — Which digit does each letter stand for?
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Dependency depth: 10,000 predicates
|
|
2
|
+
|
|
3
|
+
## Can dependency analysis follow a deep chain without exhausting the JavaScript stack?
|
|
4
|
+
|
|
5
|
+
A dependency graph can be deep even when its clauses are simple. This
|
|
6
|
+
example has 10,000 distinct predicates and 9,999 edges in one chain.
|
|
7
|
+
Dependency analysis uses an explicit traversal stack, so the graph's depth
|
|
8
|
+
does not consume one JavaScript call frame per predicate.
|
|
9
|
+
|
|
10
|
+
[Run it in the playground](https://eyereasoner.github.io/eyeprolog/playground#example=dependency-depth-10000) ·
|
|
11
|
+
[Source](../dependency-depth-10000.pl) ·
|
|
12
|
+
[Answer](../output/dependency-depth-10000.pl) ·
|
|
13
|
+
[Proof](../proof/dependency-depth-10000.pl) ·
|
|
14
|
+
[Check](../check/dependency-depth-10000.pl)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# The question
|
|
19
|
+
|
|
20
|
+
Can the engine prepare and analyze the whole chain, including propagation
|
|
21
|
+
of a cut from its final predicate back to every caller?
|
|
22
|
+
The declared query asks `chain9998(ready)` to keep the resulting proof small.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# The rules
|
|
27
|
+
|
|
28
|
+
```prolog
|
|
29
|
+
chain0(X) :- chain1(X).
|
|
30
|
+
chain1(X) :- chain2(X).
|
|
31
|
+
% ... one clause per predicate ...
|
|
32
|
+
chain9998(X) :- chain9999(X).
|
|
33
|
+
chain9999(ready) :- !.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
There are no cycles. Each predicate can reach the terminal cut, including
|
|
37
|
+
`chain0/1`, which is 9,999 edges away. The graph is also stratified: there is
|
|
38
|
+
no negative cycle.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# The answer
|
|
43
|
+
|
|
44
|
+
Run from the repository root:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
node bin/eyeprolog.js examples/dependency-depth-10000.pl
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
chain9998(ready).
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# The reason
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
step(chain9998(ready), rule(9999), ['X' = ready], [chain9999(ready)]).
|
|
60
|
+
step(chain9999(ready), rule(10000), [], "!").
|
|
61
|
+
step(!, builtin, [], []).
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Two rule applications and the cut establish the answer. This short proof
|
|
65
|
+
keeps the example inexpensive to prove and check during `npm test`.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
# The check
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
node bin/eyeprolog.js --check-proof examples/proof/dependency-depth-10000.pl examples/dependency-depth-10000.pl
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The packaged report records `steps(3)`, `verified(2)`, `recomputed(1)`,
|
|
76
|
+
`trusted(0)`, and `verdict(checked)`. It checks the query's derivation.
|
|
77
|
+
The white-box regression checks the complete dependency graph separately.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
# Analyze the full graph
|
|
82
|
+
|
|
83
|
+
Run this from the repository root with the ordinary Node stack setting:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
node --input-type=module <<'JS'
|
|
87
|
+
import assert from 'node:assert/strict';
|
|
88
|
+
import fs from 'node:fs';
|
|
89
|
+
import { Program } from './src/index.js';
|
|
90
|
+
const source = fs.readFileSync('examples/dependency-depth-10000.pl', 'utf8');
|
|
91
|
+
const program = Program.parse(source);
|
|
92
|
+
assert.equal(program.groups.size, 10000);
|
|
93
|
+
assert.equal(program.isStratifiedNegation(), true);
|
|
94
|
+
assert.equal(program.negationDependencies.length, 9999);
|
|
95
|
+
for (let i = 0; i < 10000; i++) {
|
|
96
|
+
const group = program.findGroup(`chain${i}`, 1);
|
|
97
|
+
assert.equal(group.recursive, false);
|
|
98
|
+
assert.equal(group.cutReachable, true);
|
|
99
|
+
}
|
|
100
|
+
console.log('10,000 predicates analyzed; terminal cut reaches every caller.');
|
|
101
|
+
JS
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This exercises preparation and negation analysis across the full depth.
|
|
105
|
+
The result establishes graph-analysis depth, rather than a bound on the
|
|
106
|
+
depth of arbitrary Prolog execution. For preparation timing, see
|
|
107
|
+
[the 5,000-predicate example](dependency-preparation-5000.md).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Dependency preparation: 5,000 predicates
|
|
2
|
+
|
|
3
|
+
## How quickly can the engine prepare thousands of distinct predicates?
|
|
4
|
+
|
|
5
|
+
Generated programs can contain thousands of predicate names. Before answering
|
|
6
|
+
any query, EyeProlog prepares their dependency graph and execution plans.
|
|
7
|
+
This example gives that work a reproducible input: 5,000 predicates connected
|
|
8
|
+
by 4,999 dependency edges.
|
|
9
|
+
|
|
10
|
+
[Run it in the playground](https://eyereasoner.github.io/eyeprolog/playground#example=dependency-preparation-5000) ·
|
|
11
|
+
[Source](../dependency-preparation-5000.pl) ·
|
|
12
|
+
[Answer](../output/dependency-preparation-5000.pl) ·
|
|
13
|
+
[Proof](../proof/dependency-preparation-5000.pl) ·
|
|
14
|
+
[Check](../check/dependency-preparation-5000.pl)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# The question
|
|
19
|
+
|
|
20
|
+
How much preparation does a long chain of distinct predicates require?
|
|
21
|
+
The declared query asks only `chain4998(ready)`. Loading the source prepares
|
|
22
|
+
the entire graph; answering this query needs only its final edge.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# The rules
|
|
27
|
+
|
|
28
|
+
```prolog
|
|
29
|
+
chain0(X) :- chain1(X).
|
|
30
|
+
chain1(X) :- chain2(X).
|
|
31
|
+
% ... one clause per predicate ...
|
|
32
|
+
chain4998(X) :- chain4999(X).
|
|
33
|
+
chain4999(ready).
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Each name introduces a separate graph vertex. The engine identifies the
|
|
37
|
+
components once and propagates planning properties over the graph. None of
|
|
38
|
+
these predicates is recursive, and none reaches a cut.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# The answer
|
|
43
|
+
|
|
44
|
+
Run from the repository root:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
node bin/eyeprolog.js examples/dependency-preparation-5000.pl
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
chain4998(ready).
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
# The reason
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
step(chain4998(ready), rule(4999), ['X' = ready], [chain4999(ready)]).
|
|
60
|
+
step(chain4999(ready), fact(5000), [], []).
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The proof has two steps. Keeping the query short lets this example exercise
|
|
64
|
+
preparation without adding a 5,000-step proof to every test run.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# The check
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
node bin/eyeprolog.js --check-proof examples/proof/dependency-preparation-5000.pl examples/dependency-preparation-5000.pl
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The packaged report records `steps(2)`, `verified(2)`, `trusted(0)`, and
|
|
75
|
+
`verdict(checked)`. It checks the answer's two inferences. The white-box
|
|
76
|
+
regression separately checks all 5,000 predicate plans and all 4,999 graph
|
|
77
|
+
edges, including negation stratification.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
# Time preparation
|
|
82
|
+
|
|
83
|
+
Run this from the repository root. Source reading and module startup happen
|
|
84
|
+
outside the timed region. Three warm-ups precede nine measured parses;
|
|
85
|
+
the printed value is their median. Use the same Node version and machine
|
|
86
|
+
when comparing releases. Timing is an observation, not a test threshold.
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
node --input-type=module <<'JS'
|
|
90
|
+
import fs from 'node:fs';
|
|
91
|
+
import { Program } from './src/index.js';
|
|
92
|
+
const source = fs.readFileSync('examples/dependency-preparation-5000.pl', 'utf8');
|
|
93
|
+
for (let i = 0; i < 3; i++) Program.parse(source);
|
|
94
|
+
const samples = [];
|
|
95
|
+
for (let i = 0; i < 9; i++) {
|
|
96
|
+
const start = performance.now();
|
|
97
|
+
const program = Program.parse(source);
|
|
98
|
+
samples.push(performance.now() - start);
|
|
99
|
+
if (program.groups.size !== 5000) throw new Error('wrong predicate count');
|
|
100
|
+
}
|
|
101
|
+
samples.sort((a, b) => a - b);
|
|
102
|
+
console.log(`Median preparation: ${samples[4].toFixed(1)} ms`);
|
|
103
|
+
JS
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Continue with [the 10,000-predicate depth example](dependency-depth-10000.md).
|