eyeling 1.11.15 → 1.11.17

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 CHANGED
@@ -553,21 +553,12 @@ That “standardize apart” step is essential. Without it, reusing a rule multi
553
553
  **Implementation note (performance):** `standardizeRule` is called for every backward-rule candidate during proof search.
554
554
  To reduce allocation pressure, Eyeling reuses a single fresh `Var(...)` object per *original* variable name within one standardization pass (all occurrences of `?x` in the rule become the same fresh `?x__N` object). This is semantics-preserving — it still “separates” invocations — but it avoids creating many duplicate Var objects when a variable appears repeatedly in a rule body.
555
555
 
556
- ### 8.6 Substitution compaction: keeping DFS fast on deep proofs
556
+ ### 8.6 Substitution size on deep proofs
557
557
 
558
558
  The trail-based substitution store removes the biggest accidental quadratic cost (copying a growing substitution object at every step).
559
- But substitutions can still grow large in deep/branchy searches, and long variable chains make `applySubstTerm` work harder.
559
+ In deep and branchy searches, the substitution trail still grows, and long variable-to-variable chains increase the work done by `applySubstTerm`.
560
560
 
561
- Eyeling therefore still uses `maybeCompactSubst` when emitting answers (and occasionally during deep search): it keeps only bindings relevant to the remaining goals and the original “answer variables”, trimming dead bindings and shortening chains.
562
-
563
-
564
- * if depth is high or substitution is large, it keeps only bindings relevant to:
565
-
566
- * the remaining goals
567
- * variables from the original goal list (“answer variables”)
568
- * plus variables transitively referenced inside kept bindings
569
-
570
- This is semantics-preserving for the ongoing proof search, but dramatically improves performance on deep recursive proofs.
561
+ Eyeling currently keeps the full trail as-is during search and when emitting answers; it does not run a substitution compaction pass, and it does not perform explicit substitution composition.
571
562
 
572
563
  ---
573
564
 
package/README.md CHANGED
@@ -10,6 +10,7 @@ A compact [Notation3 (N3)](https://notation3.org/) reasoner in **JavaScript**.
10
10
  ## Links
11
11
 
12
12
  - **Handbook:** [https://eyereasoner.github.io/eyeling/HANDBOOK](https://eyereasoner.github.io/eyeling/HANDBOOK)
13
+ - **Semantics:** [https://eyereasoner.github.io/eyeling/SEMANTICS](https://eyereasoner.github.io/eyeling/SEMANTICS)
13
14
  - **Playground:** [https://eyereasoner.github.io/eyeling/demo](https://eyereasoner.github.io/eyeling/demo)
14
15
  - **Notation3 test suite:** [https://codeberg.org/phochste/notation3tests](https://codeberg.org/phochste/notation3tests)
15
16
  - **Eyeling conformance report:** [https://codeberg.org/phochste/notation3tests/src/branch/main/reports/report.md](https://codeberg.org/phochste/notation3tests/src/branch/main/reports/report.md)
package/SEMANTICS.md ADDED
@@ -0,0 +1,56 @@
1
+ How does the [Eyeling HANDBOOK](https://eyereasoner.github.io/eyeling/HANDBOOK) line up with the W3C CG [Notation3 Semantics](https://w3c.github.io/N3/spec/semantics) document — and where does it intentionally diverge?
2
+
3
+ ## Where Eyeling is strongly aligned
4
+
5
+ * **Core term model (IRIs, literals, variables, blank nodes, lists, quoted formulas):**
6
+ The semantics spec treats N3 terms as IRIs/literals/variables plus **lists** and **graph terms**.
7
+ Eyeling’s handbook describes the same internal term universe: `Iri`, `Literal`, `Var`, `Blank`, `ListTerm`, `GraphTerm`.
8
+
9
+ * **Quoted formulas need alpha-equivalence / isomorphism:**
10
+ The semantics spec defines isomorphism for graphs and graph terms using renaming mappings (including special handling for nested scopes).
11
+ Eyeling implements this operationally as **alpha-equivalence for `GraphTerm`**, explicitly describing “consistent renaming” as the match criterion.
12
+
13
+ * **Rules as implication (and `true` as empty formula):**
14
+ The semantics spec defines log-semantics for `log:implies` and explicitly treats boolean `true`/`false` as special literals, with `true` corresponding to the empty formula.
15
+ Eyeling’s parser/normalizer explicitly supports `{P} => {C}` and `{P} log:implies {C}`, and treats `true` as `{}`.
16
+
17
+ * **Lists as first-class citizens (not just RDF collections):**
18
+ The semantics spec treats lists as proper N3 terms.
19
+ Eyeling uses concrete `ListTerm`s and even materializes RDF `rdf:first`/`rdf:rest` chains into list terms to operate uniformly.
20
+
21
+ ## Where Eyeling diverges or goes beyond the semantics doc
22
+
23
+ ### 1) Blank nodes in **rule bodies**: Eyeling chooses “N3 practice” over “bnodes are existential”
24
+
25
+ The semantics doc states (for concrete syntax intuition) that **blank nodes correspond to existentially quantified variables** with **local scope**.
26
+ Eyeling *intentionally* rewrites blanks in **premises** into variables (“universally-quantified placeholders”), to avoid “existential in the body” behavior.
27
+
28
+ This is a *real semantic choice*: it matches how many people *write* N3 rules, but it is not the same as a straightforward “bnodes are existentials everywhere” reading.
29
+
30
+ ### 2) “Groundness” of quoted formulas containing variables
31
+
32
+ In the semantics spec, whether a graph term is ground depends on whether the underlying graph is closed (no free variables), and it discusses how variables can appear free when you isolate a nested graph term.
33
+ Eyeling explicitly makes a pragmatic choice: **variables inside a `GraphTerm` do not make the surrounding triple non-ground** (“variables inside formulas don’t leak”).
34
+
35
+ That’s convenient for operational indexing/matching, but it doesn’t mirror the model-theoretic notion of ground graph terms one-to-one.
36
+
37
+ ### 3) Eyeling implements lots of behavior the semantics doc does not yet define
38
+
39
+ The semantics report currently only gives special meaning to `log:implies` (and says LP is planned to be extended).
40
+ Eyeling defines a large operational “standard library” of builtins and advanced control features (e.g., scoped querying / snapshotting). For example, it gives `log:includes`/`log:notIncludes` a two-phase snapshot semantics for determinism.
41
+
42
+ So: Eyeling is **ahead of / outside** what `semantics.html` formally specifies today.
43
+
44
+ ### 4) Constraint handling via “inference fuses” (`=> false`) is operational
45
+
46
+ The semantics doc includes a notion of `false` in connection with `log:implies` constraints.
47
+ Eyeling turns `{...} => false` into an *engine-level hard failure* (exit status, message), i.e., a procedural constraint mechanism rather than just a semantic condition.
48
+
49
+ That’s useful in tooling, but it’s not something the model-theoretic semantics itself “does” (it defines truth/entailment, not process control).
50
+
51
+ ### 5) Possible coverage gaps vs full N3 surface language (not strictly “semantics.html”, but relevant)
52
+
53
+ Eyeling’s handbook lists supported directives/tokens (`@prefix`, `@base`, etc.) but does not mention explicit quantifier directives like `@forAll` / `@forSome`.
54
+ The semantics document leans on explicit quantification in its **abstract syntax** discussion.
55
+ So Eyeling appears to support *implicit* quantification via `?x` and blanks (plus its own rule-normalization choices), but may not implement the full explicit-quantifier surface syntax.
56
+
@@ -0,0 +1,172 @@
1
+ # ============================================================================
2
+ # Gödel Template + Substitution Example
3
+ #
4
+ # Goal
5
+ # Model a “Gödel-like” sentence as DATA:
6
+ # - a token template with a hole (prefix ++ numeral(n) ++ suffix)
7
+ # - a substitution step that splices in the decimal numeral tokens for n
8
+ # - a Gödel encoding that maps the resulting token list to a number:
9
+ # g = Π prime[i] ^ code(token[i])
10
+ #
11
+ # Notes
12
+ # • This is a toy arithmetization: the token alphabet and codes are small and
13
+ # illustrative, not the full formal encoding used in incompleteness proofs.
14
+ # • The numeral construction is demand-driven via backward rules (<=):
15
+ # Eyeling will only compute digits(n) when some other rule needs it.
16
+ # • Integer quotient is obtained via:
17
+ # r = n mod 10
18
+ # q = (n - r) / 10
19
+ # so q stays integral even though math:quotient is real division.
20
+ #
21
+ # What to look for in the output
22
+ # - :Demo :digits ( :d4 :d2 ) (numeral tokens)
23
+ # - :Demo :tokens ( ... :d4 :d2 ... ) (instantiated sentence)
24
+ # - :Demo :godelPairs ( (2 c0) (3 c1) ... ) (prime/exponent pairs)
25
+ # - :Demo :godelNumber <big integer> (Gödel number)
26
+ # ============================================================================
27
+
28
+ @prefix : <http://example.org/godel-template#>.
29
+ @prefix list: <http://www.w3.org/2000/10/swap/list#>.
30
+ @prefix log: <http://www.w3.org/2000/10/swap/log#>.
31
+ @prefix math: <http://www.w3.org/2000/10/swap/math#>.
32
+
33
+ # ----------------------------------------------------------------------------
34
+ # 0) Token alphabet + codes (toy)
35
+ # ----------------------------------------------------------------------------
36
+
37
+ :NOT :code 1.
38
+ :PROVABLE :code 2.
39
+ :IN :code 3.
40
+ :S :code 4.
41
+ :LP :code 5.
42
+ :RP :code 6.
43
+
44
+ # Digit tokens (each has a numeric value + a token code)
45
+ :d0 :digitValue 0; :code 10.
46
+ :d1 :digitValue 1; :code 11.
47
+ :d2 :digitValue 2; :code 12.
48
+ :d3 :digitValue 3; :code 13.
49
+ :d4 :digitValue 4; :code 14.
50
+ :d5 :digitValue 5; :code 15.
51
+ :d6 :digitValue 6; :code 16.
52
+ :d7 :digitValue 7; :code 17.
53
+ :d8 :digitValue 8; :code 18.
54
+ :d9 :digitValue 9; :code 19.
55
+
56
+ # primes for positions 0.. (enough for prefix + digits + suffix)
57
+ :primeBases :is ( 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 ).
58
+
59
+ # ----------------------------------------------------------------------------
60
+ # 1) Template schema as data
61
+ # Think: NOT PROVABLE IN S ( <decimal numeral> )
62
+ # ----------------------------------------------------------------------------
63
+
64
+ :GSchema a :Template;
65
+ :english "This statement cannot be proven within this system.";
66
+ :prefixTokens ( :NOT :PROVABLE :IN :S :LP );
67
+ :suffixTokens ( :RP ).
68
+
69
+ # ----------------------------------------------------------------------------
70
+ # 2) Decimal numeral tokens via backward rules (demand-driven)
71
+ # ----------------------------------------------------------------------------
72
+
73
+ # Base case: n < 10 => digits(n) = ( d(n) )
74
+ {
75
+ ?n :digits ( ?d ).
76
+ } <= {
77
+ ?n math:lessThan 10.
78
+ ?d :digitValue ?n.
79
+ }.
80
+
81
+ # Recursive case: n >= 10
82
+ # digits(n) = digits(q) ++ ( d(r) )
83
+ # where r = n mod 10
84
+ # q = (n - r)/10 (integer-safe)
85
+ {
86
+ ?n :digits ?digs.
87
+ } <= {
88
+ ?n math:notLessThan 10.
89
+
90
+ ( ?n 10 ) math:remainder ?r.
91
+ ( ?n ?r ) math:difference ?nMinusR.
92
+ ( ?nMinusR 10 ) math:quotient ?q.
93
+
94
+ ?q :digits ?qdigs.
95
+ ?dr :digitValue ?r.
96
+
97
+ ( ?qdigs ( ?dr ) ) list:append ?digs.
98
+ }.
99
+
100
+ # ----------------------------------------------------------------------------
101
+ # 3) Substitute numeral(n) into the template to get the token list
102
+ # ----------------------------------------------------------------------------
103
+
104
+ :Demo :n 42.
105
+
106
+ {
107
+ :Demo :n ?n.
108
+ ?n :digits ?digits.
109
+
110
+ :GSchema :prefixTokens ?pre.
111
+ :GSchema :suffixTokens ?suf.
112
+
113
+ ( ?pre ?digits ) list:append ?tmp.
114
+ ( ?tmp ?suf ) list:append ?tokens.
115
+ }
116
+ =>
117
+ {
118
+ :Demo :digits ?digits.
119
+ :Demo :tokens ?tokens.
120
+ }.
121
+
122
+ # ----------------------------------------------------------------------------
123
+ # 4) Gödel encode tokens: g = Π prime[i] ^ code(token[i])
124
+ # - build pairs (prime code)
125
+ # - compute factors prime^code
126
+ # - multiply factors
127
+ # ----------------------------------------------------------------------------
128
+
129
+ # Build godelPairs as a list of list-pairs: ( (p0 c0) (p1 c1) ... )
130
+ {
131
+ :Demo :tokens ?tokens.
132
+ :primeBases :is ?primes.
133
+
134
+ ( (?p ?c)
135
+ {
136
+ ?tokens list:iterate (?i ?tok).
137
+ ( ?primes ?i ) list:memberAt ?p.
138
+ ?tok :code ?c.
139
+ }
140
+ ?pairs
141
+ ) log:collectAllIn _:scope.
142
+ }
143
+ =>
144
+ {
145
+ :Demo :godelPairs ?pairs.
146
+ }.
147
+
148
+ # Compute godelNumber from the factors (p^c) and their product
149
+ {
150
+ :Demo :godelPairs ?pairs.
151
+
152
+ ( ?factor
153
+ {
154
+ ?pairs list:member ?pair.
155
+ ?pair math:exponentiation ?factor.
156
+ }
157
+ ?factors
158
+ ) log:collectAllIn _:scope.
159
+
160
+ ?factors math:product ?g.
161
+ }
162
+ =>
163
+ {
164
+ :Demo :godelNumber ?g.
165
+
166
+ # convenient outputs (so you can spot them quickly)
167
+ :outDigits :is ?digits.
168
+ :outTokens :is ?tokens.
169
+ :outPairs :is ?pairs.
170
+ :outG :is ?g.
171
+ }.
172
+
@@ -0,0 +1,8 @@
1
+ @prefix : <http://example.org/godel-template#> .
2
+
3
+ :Demo :digits (:d4 :d2) .
4
+ :Demo :tokens (:NOT :PROVABLE :IN :S :LP :d4 :d2 :RP) .
5
+ :Demo :godelPairs ((2 1) (3 2) (5 3) (7 4) (11 5) (13 14) (17 12) (19 6)) .
6
+ :Demo :godelNumber 93897428453934743498383922339000952994095115872750 .
7
+ :outPairs :is ((2 1) (3 2) (5 3) (7 4) (11 5) (13 14) (17 12) (19 6)) .
8
+ :outG :is 93897428453934743498383922339000952994095115872750 .
@@ -96451,7 +96451,7 @@ res:AIRPORT_N nepo:hasOutboundRouteTo res:AIRPORT_N.
96451
96451
  ?route list:firstRest (?from ?newRoute).
96452
96452
  }.
96453
96453
 
96454
- # find routes from Manchester-Boston Regional Airport to Helsinki Vantaa Airport with at most 2 stopovers
96454
+ # find routes from Ostend-Bruges International Airport to Václav Havel Airport Prague with at most 2 stopovers
96455
96455
  {
96456
96456
  ?source rdfs:label "Ostend-Bruges International Airport".
96457
96457
  ?destination rdfs:label "Václav Havel Airport Prague".
@@ -275,10 +275,10 @@ log:uri a ex:Builtin ; ex:kind ex:Function ;
275
275
  rdfs:comment "Converts between an IRI and its string representation (with safety checks on IRIREF characters)." .
276
276
 
277
277
  log:trace a ex:Builtin ; ex:kind ex:SideEffect ;
278
- rdfs:comment "Side-effect (debug tracing). Prints '<subject> TRACE <object>' to stderr (Node: process.stderr; browser: console.error). Always succeeds once; does not bind variables.
278
+ rdfs:comment "Side-effect (debug tracing). Prints '<subject> TRACE <object>' to stderr (Node: process.stderr; browser: console.error). Always succeeds once; does not bind variables." .
279
279
 
280
280
  log:outputString a ex:Builtin ; ex:kind ex:SideEffect ;
281
- rdfs:comment "Side-effect (printing). Requires ground subject and non-variable object string. Does not bind variables.
281
+ rdfs:comment "Side-effect (printing). Requires ground subject and non-variable object string. Does not bind variables." .
282
282
 
283
283
  # --- string: (tests + functions) ------------------------------------
284
284