eyemind 0.0.0-stage → 0.1.22

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/SPEC.md ADDED
@@ -0,0 +1,962 @@
1
+ # <img src="assets/eye.png" alt="" width="48" height="48" align="absmiddle"> eyemind specification
2
+
3
+ ```text
4
+ Title: The eyemind Rule Language and Proof Format
5
+ Version: eyemind 0.1.22
6
+ Status: Informational
7
+ Author: Jos De Roo, KNoWS office of IDLab, Ghent University - imec
8
+ Repository: https://github.com/eyereasoner/eyemind
9
+ ```
10
+
11
+ ## Abstract
12
+
13
+ eyemind is a rule language written in JavaScript, with forward and backward
14
+ reasoning, and a proof format whose documents a separate checker verifies
15
+ against the program that produced them. This document specifies the terms
16
+ the language reasons over, how a program is stated in JavaScript, what a
17
+ program concludes, the canonical text in which terms, conclusions, proofs and
18
+ check reports are written and read back, the proof document, the eight
19
+ conditions (C1-C8) a proof checker establishes, the check report, and the
20
+ command line.
21
+
22
+ ## Status of This Memo
23
+
24
+ This document is not an Internet Standards Track specification. It describes
25
+ the language and formats as implemented by eyemind 0.1.22, for readers who want
26
+ to write programs, produce or consume proofs and reports, or implement a
27
+ compatible reasoner or checker. Where this document and the implementation
28
+ disagree, that is a defect in one of them.
29
+
30
+ ## Table of Contents
31
+
32
+ 1. [Introduction](#1-introduction)
33
+ 2. [Conventions and Terminology](#2-conventions-and-terminology)
34
+ 3. [Terms](#3-terms)
35
+ 4. [Programs](#4-programs)
36
+ 5. [Goals, Controls and Primitives](#5-goals-controls-and-primitives)
37
+ 6. [Arithmetic](#6-arithmetic)
38
+ 7. [Reasoning](#7-reasoning)
39
+ 8. [Canonical Text](#8-canonical-text)
40
+ 9. [Reading Documents](#9-reading-documents)
41
+ 10. [Proof Documents](#10-proof-documents)
42
+ 11. [Proof Checking](#11-proof-checking)
43
+ 12. [Check Reports](#12-check-reports)
44
+ 13. [Unused Clauses](#13-unused-clauses)
45
+ 14. [Command Line](#14-command-line)
46
+ 15. [Security Considerations](#15-security-considerations)
47
+ 16. [Conformance](#16-conformance)
48
+ - [Appendix A. Document Grammar](#appendix-a-document-grammar)
49
+ - [Appendix B. Example](#appendix-b-example)
50
+
51
+ ---
52
+
53
+ ## 1. Introduction
54
+
55
+ An eyemind program states facts and rules. Forward rules are applied until no
56
+ new conclusion follows; backward rules are applied when a goal asks for them.
57
+ Every conclusion can be accompanied by a proof: a document that names, for
58
+ each step, the program clause or primitive that justifies it. A checker that
59
+ never consults the reasoner verifies such a document against the program and
60
+ reports, condition by condition, what it established and what it had to take
61
+ on trust.
62
+
63
+ Programs are JavaScript scripts. Conclusions, proofs and check reports are
64
+ JavaScript expressions, one per line, which a reader turns back into terms
65
+ without executing them. One language thus states the rules, computes with
66
+ them, and holds every result.
67
+
68
+ ## 2. Conventions and Terminology
69
+
70
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
71
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document
72
+ are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and
73
+ only when, they appear in all capitals.
74
+
75
+ - **Term**: a value the language reasons over (Section 3).
76
+ - **Clause**: a fact, a forward rule or a backward rule (Section 4).
77
+ - **Goal**: a term solved by resolution or by a primitive (Section 5).
78
+ - **Substitution**: a mapping from variable names to terms.
79
+ - **Instance**: a term obtained from another by applying a substitution.
80
+ - **Identical**: two terms are identical when their canonical texts
81
+ (Section 8) are equal; variables are identical only to themselves.
82
+ - **Ground**: containing no variable.
83
+ - **Conclusion**: a term a run reports (Section 7.6).
84
+ - **Document**: text holding a sequence of expressions (Sections 9-12).
85
+ - **Reasoner**: an implementation of Sections 3-10, which checks its own
86
+ proofs as Section 11 describes.
87
+ - **Checker**: an implementation of Sections 9, 11 and 12.
88
+
89
+ ## 3. Terms
90
+
91
+ A term is one of:
92
+
93
+ | Kind | Representation | Example |
94
+ | --- | --- | --- |
95
+ | Atom | a JavaScript string | `'socrates'`, `'[]'` |
96
+ | Integer | a JavaScript `BigInt`, of unbounded size | `42`, `-7` |
97
+ | Float | a JavaScript number that is a float, an IEEE-754 binary64 value | `0.5`, `1e+22`, `2.0` |
98
+ | Variable | a name | `X`, `_Rest` |
99
+ | Compound | a name (an atom) and one or more argument terms | `parent('alice', 'bob')` |
100
+
101
+ A compound term is identified by its name and its arity, the number of its
102
+ arguments, written `name/arity`. An atom used as a goal has arity 0.
103
+
104
+ **Lists.** The empty list is the atom `'[]'`. A non-empty list is the
105
+ compound `'.'(Head, Tail)`. A list whose final tail is not `'[]'` is an open
106
+ list. Character text is a list of one-character atoms.
107
+
108
+ **Numbers.** Integers and floats are distinct: `1` and `1.0` MUST NOT unify.
109
+ Floats MUST be finite; no operation produces an infinity or a NaN as a term
110
+ (Section 6). Nonfinite JavaScript values and float literals that overflow,
111
+ such as `1e999`, MUST be rejected in programs, goals and documents. Booleans,
112
+ `null` and `undefined` are not terms.
113
+
114
+ **Unification** is syntactic unification on finite trees. It MUST apply the
115
+ occurs check: binding a variable to a term that contains it fails. Atoms unify
116
+ when their texts are equal; numbers when they are of the same kind and equal;
117
+ compounds when their names and arities are equal and their arguments unify
118
+ pairwise.
119
+
120
+ **Standard order.** Terms are totally ordered as: variables, then numbers,
121
+ then atoms, then compounds. Numbers are ordered by value, compared exactly
122
+ across integers and floats; a float precedes an integer of equal value.
123
+ Atoms are ordered by the code points of their characters. Compounds are
124
+ ordered by arity, then name, then arguments from left to right. Distinct
125
+ variables are ordered by the code points of their names, so the order is the
126
+ same in every comparison. The names of renamed-apart variables (Section 7.1)
127
+ are implementation-specific, so a program SHOULD NOT depend on the relative
128
+ order of two distinct unbound variables.
129
+
130
+ The floats `0.0` and `-0.0` unify and compare equal, but are not identical:
131
+ their canonical texts differ (Sections 2 and 8.1). This distinction also
132
+ applies when they occur inside compounds or lists. A lone UTF-16 surrogate
133
+ in a JavaScript string is ordered by its own code point; a valid surrogate
134
+ pair denotes one supplementary code point.
135
+
136
+ ## 4. Programs
137
+
138
+ ### 4.1 Program scripts
139
+
140
+ A program is a JavaScript script, run in sloppy mode with every name it does
141
+ not declare resolved as Section 4.3 says. It needs no import. Running the
142
+ script states the program's clauses in the order the calls are made; `fact`
143
+ MAY state several clauses in one call (Section 4.2). Several scripts MAY be
144
+ loaded as one program; their clauses are then numbered in the order the
145
+ scripts are run.
146
+
147
+ A program is given exactly the names needed to state it: the statements of
148
+ Section 4.2, `preds`, `vars`, `struct`, the controls and primitives of
149
+ Section 5, the atom `fail`, and `eyemind`, the library, with which a program
150
+ can build and run another program and read and write documents
151
+ (`eyemind.build`, `eyemind.run`, `eyemind.checkProof`, `eyemind.checkReport`,
152
+ `eyemind.verdictText`, `eyemind.readTerm`, `eyemind.readTerms`, `eyemind.write`).
153
+
154
+ ### 4.2 Statements
155
+
156
+ | Statement | Clause stated |
157
+ | --- | --- |
158
+ | `fact(T1, T2, ...)` | One fact per argument. |
159
+ | `implies(Premise, Conclusion)` | A forward rule: the premise's goals are its body and the conclusion its head, or its heads when the conclusion is an array of them. |
160
+ | `implied_by(Conclusion, Premise)` | A backward rule: the conclusion is its head and the premise's goals are its body. |
161
+ | `query(G1, G2, ...)` | A forward rule with the head `'true'` and the body `G1, G2, ...`: it reports its body's instances (Section 7.2). At least one goal is REQUIRED. |
162
+ | `contradiction(G1, G2, ...)` | A forward rule with the head `'false'` and the body `G1, G2, ...`: it halts the run (Section 7.2). At least one goal is REQUIRED. |
163
+ | `facts_from(path)` or `facts_from({text: ...})` | One fact per expression of a document (Section 9). |
164
+
165
+ A premise is a goal or an array of goals, their conjunction (Section 5.1). A
166
+ body goal that is a conjunction is split into its conjuncts; the clause body
167
+ is the resulting sequence of goals.
168
+
169
+ Clauses are numbered from 1 in the order they are stated. Each clause records
170
+ the line of the program on which the statement stating it begins; the facts
171
+ of `facts_from` record the line of that call.
172
+
173
+ `facts_from` is how a program takes in data that is not a program: a document
174
+ of plain expressions, one per line, such as the conclusions, proof or check
175
+ report of another run, or data from a source that is not trusted. The
176
+ document is read as Section 9 describes and is never executed, so it can only
177
+ ever state facts. A data file written as a program instead (`fact(...)`
178
+ statements) would run as JavaScript code.
179
+
180
+ A clause MUST be rejected when:
181
+
182
+ - a head is not an atom or a compound;
183
+ - a head is `step/4` or `clause/2`, which are reserved for proof documents;
184
+ - a head is a primitive (Section 5.2) or a control (Section 5.1), except the
185
+ head `'true'` of a query and `'false'` of a contradiction; in particular a
186
+ conclusion of `implies` is never `'true'` or `'false'`;
187
+ - a body goal is not a variable, an atom or a compound, or is an empty array.
188
+
189
+ ### 4.3 Names a program does not define
190
+
191
+ A name a program uses without declaring it (with `const`, `let`, `var`,
192
+ `function` or `class`, or by assigning to it) is supplied as follows:
193
+
194
+ 1. a name the program is given (Section 4.1) has that meaning;
195
+ 2. the JavaScript globals `Math`, `JSON`, `BigInt`, `Infinity`, `NaN`,
196
+ `undefined`, `console`, `globalThis`, `parseInt`, `parseFloat`, `isNaN`
197
+ and `isFinite` keep their meaning;
198
+ 3. any other name beginning with an uppercase letter or `_` is the variable of
199
+ that name, so that `Date`, `Map` or `Object` are variables as logic
200
+ programs name them (`globalThis.Date` still reaches the global);
201
+ 4. any other name is the predicate of that name: calling it with arguments
202
+ builds the compound with that name, calling it without arguments or using
203
+ it uncalled stands for the atom of that name.
204
+
205
+ A program MAY name predicates and variables explicitly, which it MUST do for
206
+ a predicate named like a name of rules 1 or 2 or a variable whose name begins
207
+ with a lowercase letter: `const [p, q] = preds('p q')` and
208
+ `const [X, Y] = vars('X Y')`, where one name gives the predicate or variable
209
+ itself rather than an array.
210
+
211
+ A top-level expression statement that calls a predicate supplied by rule 4,
212
+ such as a misspelled `fcat(p(1))`, states nothing; a loader MUST report it as
213
+ an error rather than ignore it.
214
+
215
+ ### 4.4 Terms in a program
216
+
217
+ Within a program, a JavaScript string is an atom and a `BigInt` an integer. A
218
+ finite JavaScript number is an integer when it is integral and a float
219
+ otherwise: `2` and `2.0` are both the integer 2, and `float(2)` is the float
220
+ 2.0. An integer beyond 2^53 is written as a `BigInt` literal, such as
221
+ `9007199254740993n`, since a number literal would already have rounded it. An
222
+ array is a list, and `[H, ...T]` the list with head `H` and tail `T`.
223
+ `struct('name', A1, ...)` builds a compound with any name, and
224
+ `struct('name')` the atom. Every occurrence of `_` in a clause is a distinct
225
+ variable, an **anonymous variable**: the occurrences are named `_0`, `_1`,
226
+ ... in the order of the clause's text, skipping names the clause already
227
+ uses, and clause displays and bindings (Section 10) show these names. A
228
+ program SHOULD NOT name its own variables `_` followed by digits, which
229
+ Section 5.1 treats as anonymous.
230
+
231
+ In a goal position, an array is the conjunction of its items: a statement's
232
+ goal, the argument of `and`, `or`, `not`, `call` and `once`, and the goal of
233
+ `findall`. Anywhere else an array is a list.
234
+
235
+ Operators do not build terms. Variables, compounds and predicates have no
236
+ JavaScript primitive value, so an operator applied to one, such as `X + 1` or
237
+ `X > 1`, MUST raise an error that says what to write instead: `add(X, 1)`,
238
+ `gt(X, 1)`. An operator applied only to plain JavaScript values is
239
+ JavaScript's own: `3 + 4` is the integer 7, and `1 < 2` is the JavaScript
240
+ `true`, which is not a term, so stating it is an error.
241
+
242
+ ### 4.5 Stratification
243
+
244
+ A body goal depends on a clause when the goal, renamed apart, unifies with
245
+ one of the clause's heads. The dependency is **closed** when the goal occurs
246
+ inside a negation or as the goal of a collection (Section 5.1), and **open**
247
+ otherwise. Each clause has a rank: the least assignment such that a clause's
248
+ rank is at least the rank of every clause it depends on, plus one for a closed
249
+ dependency. Forward rules run in order of rank (Section 7.2).
250
+
251
+ A program MUST be rejected when:
252
+
253
+ - no such assignment exists ("unstratified negation or collection
254
+ dependency"), that is, a closed dependency lies on a cycle;
255
+ - a forward rule can reach, through dependencies, a clause with a body goal
256
+ that is a variable ("forward dependencies require statically named calls").
257
+
258
+ Because dependencies compare whole terms, two relations sharing a predicate
259
+ name MAY have different ranks.
260
+
261
+ ## 5. Goals, Controls and Primitives
262
+
263
+ ### 5.1 Controls
264
+
265
+ | Control | Term | Meaning |
266
+ | --- | --- | --- |
267
+ | `and(A, B)`, `[A, B]` | `and(A, B)` | Conjunction: solve `A`, then `B`. |
268
+ | `or(A, B)` | `or(A, B)` | Disjunction: the solutions of `A`, then those of `B`. |
269
+ | `not(G)` | `not(G)` | Negation: succeeds once, binding nothing, when `G` has no solution. When the negation is solved, every variable of `G` MUST be bound except anonymous ones, which stand for any value: `not(q(X, _))` succeeds when `q(X, Y)` has no solution for any `Y`. A named unbound variable is an error. |
270
+ | `call(G)` | `call(G)` | The solutions of `G`. |
271
+ | `once(G)` | `once(G)` | The first solution of `G`. |
272
+ | `findall(T, G, L)` | `findall(T, G, L)` | Unifies `L` with the list of instances of `T`, one per solution of `G`, in order, each renamed apart. |
273
+
274
+ A variable is anonymous when its name, up to any `#` a renaming apart
275
+ (Section 7.1) adds, is `_` followed by digits (Section 4.4), or is one a
276
+ reader made for a `_` (Section 9).
277
+
278
+ Conjunction and disjunction are binary. In a program, `and` and `or` with
279
+ more than two goals build the chain from the left, `and(A, B, C)` being
280
+ `and(and(A, B), C)`, and `or` with one goal is that goal. `not`, `call` and
281
+ `once` with several goals take their conjunction. A goal text (Section 9)
282
+ reads `and` and `or` with more than two arguments the same way.
283
+
284
+ ### 5.2 Primitives
285
+
286
+ In a flow pattern, `+` marks an argument that MUST be bound when the goal
287
+ runs, `-` one that MUST be unbound, `?` either, and `@` one only inspected. A
288
+ primitive called outside its patterns raises an error.
289
+
290
+ | Primitive | Pattern | Meaning |
291
+ | --- | --- | --- |
292
+ | `'true'`, `'fail'`, `'false'` | | Succeeds; fails; fails. |
293
+ | `unify(?X, ?Y)` | | Unifies `X` and `Y`. |
294
+ | `not_unify(@X, @Y)` | | Succeeds, binding nothing, when `X` and `Y` do not unify. |
295
+ | `identical(@X, @Y)` | | `X` and `Y` are identical. |
296
+ | `not_identical(@X, @Y)` | | `X` and `Y` are not identical. |
297
+ | `compare(?O, @X, @Y)` | | Unifies `O` with `'<'`, `'='` or `'>'`, by the standard order. |
298
+ | `is(?V, +E)` | | Evaluates `E` (Section 6) and unifies `V` with the result. |
299
+ | `eq(+E1, +E2)`, `ne(+E1, +E2)` | | The values of `E1` and `E2` are equal, or not. |
300
+ | `lt(+E1, +E2)`, `le(+E1, +E2)`, `gt(+E1, +E2)`, `ge(+E1, +E2)` | | Compares the values of `E1` and `E2`. |
301
+ | `is_var(@X)`, `is_nonvar(@X)` | | `X` is an unbound variable, or is not. |
302
+ | `is_ground(@X)` | | `X` contains no unbound variable. |
303
+ | `is_atom(@X)`, `is_number(@X)` | | `X` is an atom, or a number. |
304
+ | `is_int(@X)`, `is_float(@X)` | | `X` is an integer, or a float. |
305
+ | `is_compound(@X)` | | `X` is a compound; a non-empty list is one. |
306
+ | `functor` | `functor(+T, ?N, ?A)`, `functor(-T, +N, +A)` | Name and arity of `T`, or `T` built with fresh variable arguments. `A` MUST be between 0 and 1024. |
307
+ | `arg` | `arg(+N, +T, ?A)` | `A` is the `N`th argument of `T`, counting from 1. |
308
+ | `univ` | `univ(+T, ?L)`, `univ(-T, +L)` | `L` is the list of `T`'s name and arguments. |
309
+ | `atom_chars` | `atom_chars(+A, ?L)`, `atom_chars(-A, +L)` | `L` is the list of `A`'s characters as atoms. |
310
+ | `atom_codes` | `atom_codes(+A, ?L)`, `atom_codes(-A, +L)` | `L` is the list of `A`'s character code points. |
311
+ | `atom_length` | `atom_length(+A, ?N)` | `N` is the number of characters of `A`. |
312
+ | `number_chars` | `number_chars(?N, +L)`, `number_chars(+N, -L)` | A bound `L` is read as a number: an optional sign and decimal digits give an integer, and with a fraction or an exponent a float, as in `'007'`, `'-21.5'`, `'.5'` and `'1E3'`; other text fails. Otherwise `L` spells `N` in its canonical text (Section 8.1). |
313
+ | `atom_concat` | `atom_concat(+A, +B, ?AB)`, `atom_concat(?A, ?B, +AB)` | `AB` is `A` followed by `B`; with `AB` given, every split, shortest `A` first. |
314
+
315
+ A character is a Unicode code point. Every primitive except `atom_concat` has
316
+ at most one solution. Primitives MUST be pure: their solutions depend only on
317
+ their arguments. A primitive given an argument of the wrong kind for its
318
+ patterns raises an error, as `atom_length(123, N)` does; one given arguments
319
+ of the right kinds that has no solution fails, as `arg(5, f(1), A)` does.
320
+
321
+ A goal whose name and arity are neither a control, a primitive nor the head
322
+ of any clause has no solution.
323
+
324
+ ## 6. Arithmetic
325
+
326
+ An expression term is evaluated as follows:
327
+
328
+ - a number is its value; the atoms `'pi'`, `'e'` and `'tau'` are π, e and
329
+ 2π; a variable bound to an expression is that expression's value; an
330
+ unbound variable or any other atom is an error;
331
+ - `add`, `sub`, `mul`, `div`, `floordiv`, `mod`, `pow`, `shl`, `shr` and
332
+ `xor` with two arguments are addition, subtraction, multiplication, true
333
+ division, floor division, modulo, power, shifts and exclusive or; `and` and
334
+ `or` with two arguments are bitwise and and or; `not`, `neg` and `pos` with
335
+ one argument are bitwise inversion, negation and identity;
336
+ - the functions `abs`, `min`, `max` (with two or more arguments), `round`
337
+ (with one or two), `int`, `float`, `floor`, `ceil`, `trunc`, `sqrt`,
338
+ `isqrt`, `exp`, `log` (with one or two: a value and a base), `log2`,
339
+ `log10`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `sinh`,
340
+ `cosh`, `tanh`, `hypot`, `degrees`, `radians`, `fmod`, `copysign`, `gcd`
341
+ and `lcm`.
342
+
343
+ Integers are exact and unbounded. An operation on integers gives an integer,
344
+ except `div`, which always gives a float, and `pow` with a negative exponent.
345
+ An operation with a float operand gives a float. `floordiv` rounds toward
346
+ negative infinity and `mod` takes the sign of its divisor: `floordiv(-7, 3)`
347
+ is -3 and `mod(-7, 3)` is 2. `div` of two integers is the float nearest to
348
+ their exact quotient. `round` rounds half to even, to an integer with one
349
+ argument and to the given number of decimals with two; `int`, `floor`, `ceil`
350
+ and `trunc` give integers. A float is written as Section 8.1 says.
351
+
352
+ Integer true division rounds once, including in the subnormal range: the
353
+ nearest float to `div(1, shl(1, 1074))` is `5e-324`. Halfway cases round to
354
+ even; a result that underflows to zero keeps its sign.
355
+
356
+ An evaluation MUST raise an error, rather than produce a value, on a division
357
+ or modulo by zero, a domain error (such as `sqrt(-1)` or `log(0)`), a bitwise
358
+ operation or `gcd` on a float, when the result is not a finite real number,
359
+ or when a power or left shift would need more than 2^26 bits: for a power of
360
+ integers `pow(A, B)` with `B > 0` and `abs(A) > 1`, when `B` times the bit
361
+ length of `A` exceeds 2^26; for a shift `shl(A, B)` of integers, when `B`
362
+ exceeds 2^26.
363
+
364
+ Comparisons are primitives (Section 5.2), not arithmetic functions: `lt` and
365
+ the other comparisons in an expression are an error. Comparison primitives
366
+ compare values exactly, including across integers and floats.
367
+
368
+ ## 7. Reasoning
369
+
370
+ ### 7.1 Search
371
+
372
+ Goals are solved depth-first, left to right. A goal is solved, in order:
373
+
374
+ 1. by a control or primitive (Section 5), when it is one;
375
+ 2. otherwise against the facts derived so far by forward rules with the same
376
+ name and arity, in the order they were derived;
377
+ 3. then against the program's facts and backward rules with the same name and
378
+ arity, in clause order, each renamed apart before it is unified with the
379
+ goal; a rule's body is then solved in its place.
380
+
381
+ Renaming a clause apart gives each of its variables a fresh variable whose
382
+ name is the variable's name followed by `#` and an implementation-specific
383
+ suffix. Such names never appear in the documents a run writes (Section 8.3).
384
+
385
+ An implementation MAY index clauses, provided the order above is kept.
386
+
387
+ ### 7.2 Forward reasoning
388
+
389
+ Forward rules run stratum by stratum, in increasing rank (Section 4.5). Within
390
+ a stratum, rounds are repeated until a round adds no new fact. In a round,
391
+ each rule in clause order is renamed apart and its body solved against the
392
+ current state; all solutions of the body are collected first, then each is
393
+ concluded:
394
+
395
+ - a head variable the solution leaves unbound is bound to a **Skolem term**
396
+ `skolem(Rule, Variable, Arguments)`: `Rule` is the clause number of the
397
+ rule, `Variable` the variable's name as the program writes it (an
398
+ anonymous one as `_0`, `_1`, ..., Section 4.4), and `Arguments` the list of
399
+ the ground values the solution gives the heads' other variables, in order
400
+ of their first occurrence in the heads. A Skolem term is thus a function of
401
+ the activation: the rule and the instance of its heads. The same activation
402
+ gives the same terms, in any round and in any run, and different
403
+ activations give different terms; variables shared between heads stay
404
+ shared. A variable that a value of the solution brought in, rather than a
405
+ head variable, is named after its own variable, followed by `1`, `2`, ...
406
+ when that name is taken. A rule that keeps meeting new activations does
407
+ not terminate (Section 7.3). Derived facts are therefore ground. A
408
+ checker verifies the Skolem terms of a proof (C8, Section 11.9);
409
+ - a head `'true'` reports the instance of the rule's body, as a conjunction,
410
+ once per distinct instance (by identity of canonical text);
411
+ - a head `'false'` records the conclusion `'false'` and stops all reasoning
412
+ with halt code 65;
413
+ - any other head is added as a derived fact unless an identical fact is
414
+ already derived or is a ground fact of the program.
415
+
416
+ When the run asks its own goals (Section 7.4), rules whose heads are all
417
+ `'true'` are not run.
418
+
419
+ ### 7.3 Bounds
420
+
421
+ A run is bounded by `max_depth`, the depth of nested rule bodies (default
422
+ 1000000), by `max_inferences`, the number of goals started (default
423
+ 1000000), and by `max_iterations`, the rounds per stratum (default 1000).
424
+ Exceeding a bound MUST raise an error; a partial result MUST NOT be returned
425
+ as complete.
426
+
427
+ Each supplied bound MUST be a positive safe integer, at most
428
+ 9007199254740991, so a work counter can represent it exactly.
429
+
430
+ ### 7.4 Goals
431
+
432
+ A run MAY be given goals. After forward reasoning, each goal is solved in
433
+ turn, and each solution is reported as the instance of its goal, unless an
434
+ instance identical up to renaming of its variables was already reported for
435
+ this goal or an earlier one of the same run.
436
+
437
+ ### 7.5 Halting
438
+
439
+ A run that concluded `'false'` has halt code 65; otherwise it has none.
440
+
441
+ ### 7.6 Conclusions
442
+
443
+ The conclusions of a run are, in order:
444
+
445
+ 1. when it halted: every derived fact, in the order derived, ending with
446
+ `'false'`;
447
+ 2. otherwise, when it was given goals: the reported instances of its goals;
448
+ 3. otherwise, when the program has a forward rule with a head `'true'`: the
449
+ reported instances, in order of first report, which MAY be none;
450
+ 4. otherwise: every derived fact, in the order derived.
451
+
452
+ The output of a run is the canonical text (Section 8) of each conclusion,
453
+ one per line.
454
+
455
+ ### 7.7 Proof recording
456
+
457
+ When a proof is requested, each solution records how each of its goals was
458
+ justified: by a fact or rule of the program, by a derived fact (whose own
459
+ record is kept), by a primitive, by a control, by an absence (a negation) or
460
+ by a collection (`findall`). For each conclusion the first derivation found
461
+ is recorded. A reasoner MUST check every proof it generates (Section 11)
462
+ before returning it, and MUST fail with an error rather than return a proof
463
+ that does not pass. A run without conclusions has a proof without claims,
464
+ which is valid and certifies nothing.
465
+
466
+ A goal such as `is_var(X)` followed by `unify(X, 'a')`
467
+ cannot be recorded faithfully by its final substitution, so such a run
468
+ cannot produce a proof.
469
+
470
+ ## 8. Canonical Text
471
+
472
+ Every term has exactly one canonical text, which is a JavaScript expression.
473
+
474
+ ### 8.1 Atoms, numbers, variables and lists
475
+
476
+ - An atom is written between single quotes, with `\\`, `\'`, and the
477
+ characters that need it escaped as `\n`, `\t`, `\r`, `\b`, `\f`, `\v`,
478
+ `\0`, `\xHH` or `\uHHHH`; `'[]'` is written `[]`.
479
+ - An integer is written in decimal. A float is written as the shortest
480
+ decimal that reads back as the same value, with at least one digit after
481
+ the point, in exponent form `1e+22` or `1e-05` when the exponent is below
482
+ -4 or at least 16: `0.1`, `2.0`, `-0.0`, `1e+22`.
483
+ - A variable is written as its name when the name is an ASCII identifier
484
+ (letters, digits and `_`, not starting with a digit), not a reserved word
485
+ of JavaScript, not `_` and does not begin with `VAR_`. Any other name is
486
+ written `VAR_` followed by the name with every ASCII letter and digit kept,
487
+ every `_` doubled and every other character `c` replaced by `_hex_` where
488
+ `hex` is the lowercase hexadecimal code point of `c`. The variable `X#12`
489
+ is thus written `VAR_X_23_12`. A reader decodes such a name back
490
+ (Section 9).
491
+ - A list is written `[I1, I2, ...]`; an open list ends with `, ...Tail`.
492
+
493
+ ### 8.2 Compounds
494
+
495
+ A compound is written `name(A1, A2, ...)` when its name is an ASCII
496
+ identifier, not a reserved word of JavaScript and not `struct`, and
497
+ `struct('name', A1, ...)` otherwise. Arguments are separated by `, `.
498
+ There are no operators: `add(X, 1)` is written `add(X, 1)`.
499
+
500
+ A chain of conjunctions or disjunctions built from the left,
501
+ `and(and(A, B), C)`, is written as one call, `and(A, B, C)`. A compound
502
+ `and/N` or `or/N` with more than two arguments is written with `struct`, as
503
+ `struct('and', A, B, C)`.
504
+
505
+ ### 8.3 Variables in written documents
506
+
507
+ The conclusions a run writes, its proof documents (Section 10) and check
508
+ reports (Section 12) do not show the names variables have inside a run. In
509
+ the conclusions of a run and in a proof document, the variables are named
510
+ `A`, `B`, ..., `Z`, `A1`, ..., `Z1`, `A2`, ... in the order the document
511
+ first shows them, across the whole document, the conclusions written first;
512
+ the clause displays of a proof keep the program's names. A check report
513
+ names the variables of each fact anew (Section 12). The bindings an
514
+ implementation reports for each answer to a goal SHOULD name its variables as
515
+ the answer does.
516
+
517
+ ## 9. Reading Documents
518
+
519
+ A document is UTF-8 text holding a sequence of JavaScript expression
520
+ statements. A statement ends at the end of its line, unless a bracket is
521
+ still open, or at a `;`; comments (`// ...` and `/* ... */`), blank lines and
522
+ indentation are ignored; each term records the line on which its statement
523
+ begins. The documents eyemind writes hold one statement per line. A reader
524
+ MUST NOT execute the text. It accepts exactly:
525
+
526
+ - a string literal between single or double quotes, with JavaScript's
527
+ escapes: the atom; a decimal integer literal, or one with the `BigInt`
528
+ suffix `n`, or a finite decimal float literal (one with a point or an
529
+ exponent): the number;
530
+ - a name: the variable of that name, where each `_` is a new anonymous
531
+ variable (Section 5.1) and a name starting with `VAR_` is decoded
532
+ (Section 8.1), or rejected when it encodes no name;
533
+ - a call of a plain name: the compound, or the atom when there are no
534
+ arguments; `struct('name', ...)` as in Section 8.2; `and` and `or` with
535
+ more than two arguments as in Section 5.1;
536
+ - an array literal: the list, where only the last item MAY be spread
537
+ (`...Tail`) and then is the tail; `[...T]` is `T`;
538
+ - an object literal `{K: V, ...}` whose keys are names or strings: the list
539
+ of compounds `'='(K, V)`, in order;
540
+ - a minus sign applied directly to a numeric literal: the negative number;
541
+ - an expression in parentheses: that expression.
542
+
543
+ A trailing comma is allowed in a call, an array and an object. Anything else
544
+ MUST be rejected: an operator, a property access, a subscript, a call of a
545
+ call, a spread argument, a comma expression, an assignment, a template
546
+ literal, a regular expression, a hexadecimal, octal or binary literal, a
547
+ numeric separator, an integer literal with a leading zero, the names `true`,
548
+ `false`, `null`, `undefined`, `NaN`, `Infinity` and the other reserved words,
549
+ a name containing `$`, an arrow function, a declaration, a raw control
550
+ character other than a tab in a string, and a nonbreaking space outside a
551
+ string. Reading the canonical text of a term MUST give the term back.
552
+
553
+ ## 10. Proof Documents
554
+
555
+ ### 10.1 Structure
556
+
557
+ A proof document is a document (Section 9) holding, in this order:
558
+
559
+ 1. the conclusions of the run (Section 7.6), one per line;
560
+ 2. an empty line;
561
+ 3. one `clause(N, Display)` per program clause the proof cites, by
562
+ increasing `N`;
563
+ 4. an empty line;
564
+ 5. one `step(Goal, By, Bindings, Uses)` per justified goal.
565
+
566
+ A checker MUST treat every statement that is neither `clause/2` nor `step/4`
567
+ as a claim, whatever its position.
568
+
569
+ ### 10.2 Clause displays
570
+
571
+ `Display` shows clause `N` as the program states it: `fact(Head)`,
572
+ `implies(Body, Head)`, `implied_by(Head, Body)`, `query(G1, ...)` or
573
+ `contradiction(G1, ...)`, where `Body` is the clause's one body goal, or the
574
+ array of its body goals when it has several, `Head` likewise the head or the
575
+ array of heads, and `G1, ...` are the body goals themselves. Displays are not
576
+ authority: a checker MUST compare each with the program it checks against.
577
+
578
+ ### 10.3 Steps
579
+
580
+ `Goal` is the justified goal as it stands once the whole solution is found:
581
+ the goal with every variable the solution bound replaced by its value. The
582
+ program's goal `unify(Y, 6)`, solved with `Y` unbound, thus has the step
583
+ `step(unify(6, 6), 'builtin', {}, [])`; the value `Y` received is recorded in
584
+ the bindings of the step that cites the clause, as `{Y: 6}`. Steps appear
585
+ in the order a depth-first walk
586
+ from the claims first meets each goal, and each distinct goal (by canonical
587
+ text) has one step. `Uses` is the list of the goals that justify `Goal`, in
588
+ order. `By` is one of:
589
+
590
+ | `By` | Meaning | `Bindings` | `Uses` |
591
+ | --- | --- | --- | --- |
592
+ | `clause(N)` | `Goal` is an instance of a head of clause `N`, a fact or a rule, whose body instance is `Uses`. | the clause's variables | the body instance, empty for a fact |
593
+ | `'builtin'` | `Goal` is a primitive that holds. | empty | empty |
594
+ | `'control'` | `Goal` is `call`, `once` or a disjunction, solved by `Uses`. | empty | the solved goals |
595
+ | `'absent'` | `Goal` is a negation taken on trust. | empty | empty |
596
+ | `'collected'` | `Goal` is a `findall` taken on trust. | empty | empty |
597
+
598
+ `Bindings` is an object from each variable name of the cited clause, as
599
+ the program wrote it, to its value in this step: `{X: 'socrates'}`. A
600
+ reasoner writes every variable of the clause, in the order the clause display
601
+ first shows them (for `implies`, the premise first);
602
+ a checker MUST accept any subset, since the goal and uses determine the
603
+ rest. A primitive has no variables of its own, so `'builtin'` steps have
604
+ empty bindings.
605
+
606
+ ## 11. Proof Checking
607
+
608
+ A checker is given a program, a proof document and, when the proof answers
609
+ goals asked from outside the program, those goals. It MUST NOT call a
610
+ reasoner to supply a missing step; it MAY recompute primitives. It
611
+ establishes eight conditions and records each failure with its condition, a
612
+ detail and, where there is one, the term concerned.
613
+
614
+ ### 11.1 Reading the document
615
+
616
+ The document MUST read (Section 9); otherwise C3 fails and the document has
617
+ no claims and no steps. Each `clause(N, Display)` MUST name a clause of the
618
+ program whose display (Section 10.2) is identical to `Display`; otherwise C1
619
+ fails. Each `step` MUST have bindings that read as a list of `'='/2` pairs,
620
+ as an object literal does, and a list of uses, and no two steps may have
621
+ identical goals; otherwise C3 fails and the step is set aside. Every other
622
+ statement is a claim (Section 10.1).
623
+
624
+ ### 11.2 C1 Resolution
625
+
626
+ For a `clause(N)` step, `N` MUST be a clause of the program. The clause,
627
+ renamed apart, MUST satisfy: each binding names a distinct variable of the
628
+ clause and unifies it with its value; and for one of the clause's heads
629
+ (each conjunct of a forward rule's head), the head unifies with `Goal` and
630
+ the body, of the same length as `Uses`, unifies with `Uses` pairwise, such
631
+ that afterwards the head is identical to `Goal` and each body goal to its
632
+ use. A step's own terms MUST NOT need further instantiation to match: a
633
+ source clause `same(X, X)` cannot justify `same('a', 'b')`.
634
+
635
+ ### 11.3 C2 Well-foundedness
636
+
637
+ No step MAY depend on itself through the uses of steps.
638
+
639
+ ### 11.4 C3 Justification
640
+
641
+ `By` MUST be one of the forms of Section 10.3. A `'builtin'` step MUST have
642
+ no bindings and no uses and a goal that is a primitive; an `'absent'` or
643
+ `'collected'` step MUST have no bindings and no uses and a goal that is a
644
+ negation or a `findall`, respectively.
645
+
646
+ ### 11.5 C4 Coverage
647
+
648
+ Each conjunct of each claim MUST have a step. Each use, and each conjunct of
649
+ a use, MUST have a step or be identical to an instance of a fact of the
650
+ program. A document without claims is valid and certifies nothing.
651
+
652
+ ### 11.6 C5 Re-decision
653
+
654
+ A `'builtin'` step's goal, solved as a primitive with no prior bindings, MUST
655
+ succeed without binding anything. A `'control'` step MUST have no bindings,
656
+ and its uses MUST be identical, in order, to the conjuncts of the argument of
657
+ `call` or `once`, or of one side of a disjunction. When trusted boundaries are
658
+ forbidden ("strict"), each `'absent'` or `'collected'` step fails C5.
659
+
660
+ ### 11.7 C6 Boundary consistency
661
+
662
+ A trusted boundary cannot be proved, but the evidence at hand can refute it.
663
+ The evidence for a goal is: when the goal is a ground primitive, the goal
664
+ itself if it holds; when it is a control, none, and the boundary is left
665
+ undecided; otherwise the program's facts and the goals of the document's
666
+ steps with the same name and arity.
667
+
668
+ - An absence `not(G)` is decided when `G` is a single goal, or a ground
669
+ conjunction, whose every goal has evidence. It fails C6 when every goal of
670
+ `G` unifies with some of its evidence; the anonymous variables of `G`
671
+ unify with anything.
672
+ - A collection `findall(T, G, L)` fails C6 when `L` is not a list, and is
673
+ decided when `G` is a single goal with evidence. It fails C6 when an
674
+ instance of `T` for some evidence of `G` unifies with no element of `L`.
675
+
676
+ A boundary that is not refuted remains an obligation (Section 12).
677
+
678
+ ### 11.8 C7 Relevance
679
+
680
+ When goals were given and no claim is `'false'`, the questions are the goals.
681
+ Otherwise the questions are, for each forward rule, each head other than
682
+ `'true'`, and the rule's body as a conjunction when one of its heads is
683
+ `'true'` and no claim is `'false'`. Each claim MUST be an instance of a
684
+ question. Each step MUST be reachable from a conjunct of a claim through the
685
+ conjuncts of uses.
686
+
687
+ ### 11.9 C8 Witness integrity
688
+
689
+ A forward rule's head MAY contain variables its body does not contain; each
690
+ says that something exists, and a reasoner concludes it with a Skolem term
691
+ (Section 7.2). C1 alone would accept any value for such a variable, since any
692
+ value gives an instance of the rule, so for a `clause(N)` step citing a
693
+ forward rule, under the substitution of C1, each such variable `V` MUST be
694
+ bound to `skolem(N, Name, Args)`, where:
695
+
696
+ - `Name` is the name of `V` as the program writes it, or that name followed
697
+ by digits (Section 7.2);
698
+ - `Args` is the same for every such variable of the step, and is the list of
699
+ the values of the heads' variables, in order of their first occurrence in
700
+ the heads, that are ground and contain no Skolem term `skolem(N, _, Args)`:
701
+ the values that do contain one hold a witness of this firing.
702
+
703
+ A variable of the head that also occurs in the body is not checked by C8,
704
+ even when the body leaves it unbound; its value comes from the uses, which
705
+ other conditions check. A step citing a rule without such variables is not
706
+ covered by C8.
707
+
708
+ ### 11.10 Counts and validity
709
+
710
+ | Condition | Covered |
711
+ | --- | --- |
712
+ | C1 resolution | `clause` steps that passed C1 |
713
+ | C2 well_founded | steps |
714
+ | C3 justification | steps |
715
+ | C4 coverage | claims plus uses |
716
+ | C5 re_decision | `'builtin'` and `'control'` steps that passed C5 |
717
+ | C6 boundary_consistency | boundaries decided |
718
+ | C7 relevance | claims plus steps |
719
+ | C8 witness_integrity | `clause` steps of forward rules with witnesses that passed C8 |
720
+
721
+ A check also counts the **steps** it read, the **claims**, the `clause` steps
722
+ **verified** by C1, the `'builtin'` steps **recomputed** by C5, the
723
+ `'control'` steps **composed** by C5, and the `'absent'` and `'collected'`
724
+ steps **trusted**.
725
+
726
+ A proof is **valid** when no condition failed. A valid proof with trusted
727
+ boundaries is valid *conditional on* them.
728
+
729
+ ### 11.11 What a valid proof establishes
730
+
731
+ A valid proof establishes that each of its claims follows from the program
732
+ by the recorded steps, given its trusted boundaries. It does not establish
733
+ that the claims are all the conclusions of the program, that the program
734
+ derives no `'false'`, or that the program is the one intended: a proof MAY
735
+ leave conclusions out, and a run's own proof holds exactly its conclusions.
736
+
737
+ ## 12. Check Reports
738
+
739
+ A check report is a document (Section 9) holding, in this order, one fact per
740
+ line:
741
+
742
+ 1. `condition(Id, Name, Outcome, Covered)` for C1 to C8, where `Outcome` is
743
+ `'ok'` or `failed(N)`, `N` the number of that condition's failures;
744
+ 2. `failure(Condition, Subject, Detail)` per failure, where `Subject` is the
745
+ term concerned or `'proof_document'`, and `Detail` an atom;
746
+ 3. `obligation(Kind, 'theory_scoped', Goal)` per trusted boundary, in step
747
+ order, where `Kind` is `'absent'` or `'collected'`;
748
+ 4. `steps(N)`, `verified(N)`, `recomputed(N)`, `composed(N)`, `trusted(N)`,
749
+ `claims(N)`, the counts of Section 11.10;
750
+ 5. `verdict(V)`, where `V` is `failed(N)` when `N` failures were recorded,
751
+ otherwise `'checked_with_obligations'` when there are obligations,
752
+ otherwise `'checked'`.
753
+
754
+ Failures are listed in the order they are found: those of reading the
755
+ document (Section 11.1), in document order; C4 for each claim, in claim
756
+ order; then for each step, in document order, C4 for its uses and the C1, C3,
757
+ C5 or C8 failure of its justification; C6 for each boundary, in step order;
758
+ C7 for each claim, then for each step; and C2.
759
+
760
+ `Detail` is a short human-readable text that names what failed, often with
761
+ the canonical text of a term; it is informative, and implementations MAY word
762
+ it differently. eyemind's details are, by condition:
763
+
764
+ | Condition | Details |
765
+ | --- | --- |
766
+ | C1 | `clause display differs from source`, `unknown clause ...`, `not an instance of source clause N: ...` |
767
+ | C2 | `cyclic derivation at ...` |
768
+ | C3 | the reader's error, `step bindings must be an object and uses an array`, `duplicate justification for ...`, `invalid builtin justification`, `trusted boundaries cannot have bindings or uses`, `unknown justification ...` |
769
+ | C4 | `unjustified claim ...`, `unjustified use ...` |
770
+ | C5 | `primitive disagrees: ...`, `control step does not follow from its uses: ...`, `trusted boundary forbidden: absent` or `collected` |
771
+ | C6 | `absence contradicted by evidence: ...`, `collected result is not a proper list: ...`, `collection misses ...: ...` |
772
+ | C7 | `claim answers no goal: ...`, `step serves no claim: ...` |
773
+ | C8 | `not the witness of this firing of clause N: ...` |
774
+
775
+ The variables of each fact are renamed `A`, `B`, ..., `Z`, `A1`, ... in order
776
+ of first occurrence. A report is ordinary data: `facts_from` (Section 4.2)
777
+ states it as facts.
778
+
779
+ The JSON form of a report is an object with `valid` (boolean), `steps`,
780
+ `claims`, `verified`, `redecided` (the count `recomputed`), `composed`,
781
+ `uses` (the number of uses of all steps, integers), `trusted`
782
+ (a list of `{kind, conclusion}`), `failures` (a list of
783
+ `{condition, detail, conclusion?}`) and `conditions` (a list of
784
+ `{id, name, covered, failed}`), where `conclusion` is a canonical text.
785
+
786
+ ## 13. Unused Clauses
787
+
788
+ A clause is **unused** when no conclusion's recorded derivation cites it,
789
+ unless a negation or collection in the proof could consult it and running the
790
+ program without it changes the conclusions or the halt code, or fails. The clauses a
791
+ negation or collection could consult are those whose heads have the name and
792
+ arity of a goal it reaches through the program's bodies. Running the program
793
+ without a clause leaves every other clause its number (Section 4.2), so the
794
+ Skolem terms of the other rules (Section 7.2) do not change.
795
+
796
+ Unused clauses are reported one per line, in clause order, as
797
+ `unused(line(L), Display)`, where `L` is the clause's line (Section 4.2) and
798
+ `Display` as in Section 10.2.
799
+
800
+ "Unused" is relative to the recorded derivations, which are the first ones
801
+ found (Section 7.7). A clause that only offers a second derivation of a
802
+ conclusion, such as a duplicate rule, is unused, though leaving out the
803
+ clause that offers the first one would make it used; leaving out several
804
+ unused clauses together can therefore change the conclusions. A
805
+ `contradiction` rule that never fires changes no conclusion and is unused,
806
+ though it guards the program against data that would make it fire.
807
+
808
+ ## 14. Command Line
809
+
810
+ ```text
811
+ eyemind [OPTION ...] [FILE ...]
812
+ ```
813
+
814
+ | Option | Meaning |
815
+ | --- | --- |
816
+ | (none) | Load the files, or standard input, as one program and print its conclusions. |
817
+ | `--proof` | Print the proof document instead. |
818
+ | `--check-proof FILE` | Check the proof in `FILE` (`-` for standard input) against the program and print its report. |
819
+ | `--json` | With `--check-proof`, print the report as JSON. |
820
+ | `--goal GOAL` | Ask `GOAL`, read as in Section 9, where an array is a conjunction; MAY be repeated. With `--check-proof`, the goals the proof answers. |
821
+ | `--strict-proof` | With `--check-proof`, forbid trusted boundaries. |
822
+ | `--unused` | Print the unused clauses (Section 13). |
823
+ | `--stats` | Print reasoning statistics as JSON to standard error: `inferences`, the goals started, which `--max-inferences` bounds; `rounds`, the forward rounds run over all strata; and `derived`, the facts forward rules added, not counting a conclusion the program states as a fact, a query's answers or `'false'`. |
824
+ | `--max-depth N`, `--max-iterations N`, `--max-inferences N` | The bounds of Section 7.3; `N` MUST be a positive safe integer, at most 9007199254740991. |
825
+ | `--version`, `--help` | Print the version, or the usage. |
826
+
827
+ `--check-proof` MUST NOT be combined with `--proof`, nor `--unused` with
828
+ either, and `--json` and `--strict-proof` need `--check-proof`. A program
829
+ text that has a line starting with `step(` is a proof document; given one as
830
+ a program, the command line MUST say how to check it instead.
831
+
832
+ | Exit code | Meaning |
833
+ | --- | --- |
834
+ | 0 | Success, including a check that found the proof valid. |
835
+ | 1 | An error, printed to standard error as `eyemind: message`. |
836
+ | 2 | A check that found the proof not valid; the report is printed as usual. |
837
+ | 65 | The run halted (Section 7.5). |
838
+
839
+ ## 15. Security Considerations
840
+
841
+ A **program** is JavaScript code and runs with the privileges of whoever runs
842
+ it; only programs from trusted sources should be run. Reasoning itself calls
843
+ no code of the program: once stated, clauses are terms.
844
+
845
+ A **document** (conclusions, proofs, reports, `facts_from` input and goals)
846
+ is untrusted data. It MUST NOT be executed. The reader of Section 9 accepts
847
+ literals, names, calls of a plain name and array and object literals, so no
848
+ document can run code, import modules or reach properties. Checking a proof
849
+ from a third party is therefore safe in the sense that it runs none of the
850
+ third party's code.
851
+
852
+ Reasoning and checking consume time and memory. The bounds of Section 7.3,
853
+ the limit on powers and shifts in Section 6 and the limit on `functor`
854
+ arities in Section 5.2 bound some of this; a deployment that checks untrusted
855
+ proofs SHOULD additionally bound document size, nesting depth and running
856
+ time.
857
+
858
+ A valid proof establishes that its claims follow from the program supplied
859
+ to the checker (Section 11.11). It does not establish that the program is
860
+ correct or that the claims are all its conclusions, and a proof with
861
+ obligations holds only conditional on them.
862
+
863
+ ## 16. Conformance
864
+
865
+ A conforming **reasoner** implements Sections 3 to 10, produces
866
+ conclusions and proof documents in the canonical text, and checks every proof
867
+ it produces as Section 11 describes. A conforming **checker** implements
868
+ Sections 9, 11 and 12 and does not depend on a reasoner. For the same
869
+ program, a conforming reasoner and checker MUST produce the same
870
+ conclusions, proof documents and reports as eyemind 0.1.22, byte for byte,
871
+ except for the `Detail` texts of failures (Section 12), the internal names of
872
+ variables where Section 3 says so, and where the host's floating-point
873
+ library functions (`exp`, `log`, the trigonometric and hyperbolic functions,
874
+ `pow` of floats) differ in the last digit.
875
+
876
+ The conformance suite in the repository's `conformance/` directory tests an
877
+ implementation against this document through its command line, case by case,
878
+ each case naming the sections it tests; `conformance/README.md` describes how
879
+ to run it against any implementation. The repository's examples, with their
880
+ saved conclusions (`examples/output/`), proofs (`examples/proof/`) and reports
881
+ (`examples/check/`), test the same on larger programs.
882
+
883
+ ---
884
+
885
+ ## Appendix A. Document Grammar
886
+
887
+ The documents of Sections 9 to 12 use this subset of JavaScript's expression
888
+ grammar, in the ABNF style of RFC 5234, with spaces, tabs and comments
889
+ between tokens allowed, and line breaks too inside brackets.
890
+
891
+ ```abnf
892
+ document = *( line LF ) [ line ]
893
+ line = [ expression *( ";" expression ) [ ";" ] ]
894
+ expression = string / number / "-" number / name / call / array / object
895
+ / "(" expression ")"
896
+ call = name "(" [ expression *( "," expression ) [ "," ] ] ")"
897
+ array = "[" [ items ] "]"
898
+ items = expression *( "," expression ) [ "," "..." expression ] [ "," ]
899
+ / "..." expression [ "," ]
900
+ object = "{" [ pair *( "," pair ) [ "," ] ] "}"
901
+ pair = ( name / string ) ":" expression
902
+ string = "'" *<character or escape> "'" / DQUOTE *<character or escape> DQUOTE
903
+ number = 1*DIGIT [ "n" ] / float
904
+ float = ( 1*DIGIT "." *DIGIT / "." 1*DIGIT ) [ exponent ] / 1*DIGIT exponent
905
+ exponent = ( "e" / "E" ) [ "+" / "-" ] 1*DIGIT
906
+ name = ( ALPHA / "_" ) *( ALPHA / DIGIT / "_" ) ; not a reserved word
907
+ ```
908
+
909
+ An integer literal other than `0` MUST NOT begin with `0`.
910
+
911
+ ## Appendix B. Example
912
+
913
+ The program `socrates.js`:
914
+
915
+ ```js
916
+ fact(type('socrates', 'human'))
917
+ fact(subclass_of('human', 'mortal'))
918
+ implies([type(S, A), subclass_of(A, B)], type(S, B))
919
+ query(type(X, Y))
920
+ ```
921
+
922
+ Its conclusions:
923
+
924
+ ```js
925
+ type('socrates', 'mortal')
926
+ type('socrates', 'human')
927
+ ```
928
+
929
+ Its proof document (Section 10):
930
+
931
+ ```js
932
+ type('socrates', 'mortal')
933
+ type('socrates', 'human')
934
+
935
+ clause(1, fact(type('socrates', 'human')))
936
+ clause(2, fact(subclass_of('human', 'mortal')))
937
+ clause(3, implies([type(S, A), subclass_of(A, B)], type(S, B)))
938
+
939
+ step(type('socrates', 'mortal'), clause(3), {S: 'socrates', A: 'human', B: 'mortal'}, [type('socrates', 'human'), subclass_of('human', 'mortal')])
940
+ step(type('socrates', 'human'), clause(1), {}, [])
941
+ step(subclass_of('human', 'mortal'), clause(2), {}, [])
942
+ ```
943
+
944
+ Its check report (Section 12):
945
+
946
+ ```js
947
+ condition('C1', 'resolution', 'ok', 3)
948
+ condition('C2', 'well_founded', 'ok', 3)
949
+ condition('C3', 'justification', 'ok', 3)
950
+ condition('C4', 'coverage', 'ok', 4)
951
+ condition('C5', 're_decision', 'ok', 0)
952
+ condition('C6', 'boundary_consistency', 'ok', 0)
953
+ condition('C7', 'relevance', 'ok', 5)
954
+ condition('C8', 'witness_integrity', 'ok', 0)
955
+ steps(3)
956
+ verified(3)
957
+ recomputed(0)
958
+ composed(0)
959
+ trusted(0)
960
+ claims(2)
961
+ verdict('checked')
962
+ ```