git @ Cat's Eye Technologies Eqthy / master doc / Eqthy.md
master

Tree @master (Download .tar.gz)

Eqthy.md @masterview rendered · raw · history · blame

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
<!--
Copyright (c) 2022-2024 Chris Pressey, Cat's Eye Technologies
This file is distributed under a 2-clause BSD license.  See LICENSES directory:
SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Eqthy
-->

Eqthy
=====

Description of the Language
---------------------------

An Eqthy document consists of any number of axioms and theorems.  Each
axiom is an equation.  An equation equates two terms.  Terms consist of
constructors (also called function symbols) and variables.  Variables begin
with uppercase letters.  Constructors begin with lowercase letters and are
followed by a list of zero or more subterms, enclosed in parentheses.  If a
term has no subterms, it is called an "atom" and the parentheses may be
omitted.

Each axiom may optionally by named.  Here are some example axioms:

    axiom (#id-right) mul(A, e) = A
    axiom (#id-left)  mul(e, A) = A
    axiom (#assoc)    mul(A, mul(B, C)) = mul(mul(A, B), C)

A theorem gives an equation, followed by a sequence of equations that shows
that the equation can be derived using the available means.  The available
means are:

*   the axioms that have been previously defined
*   the theorems that have been previously proved
*   the rules of inference of [equational logic](Equational-Logic.md)

The sequence of equations following a theorem is a proof.  Each equation in
the proof is optionally annotated with a hint that follows it, indicating what
axiom, theorem, or rule of inference was used to derive it.

    theorem (#id-comm)
        mul(A, e) = mul(e, A)
    proof
        A = A                   [by reflexivity]
        mul(A, e) = A           [by #id-right on LHS]
        mul(A, e) = mul(e, A)   [by #id-left on RHS]
    qed

Each step in a theorem can be checked for validity by a processor.  The processor
may be a computer program.  During this checking, the processor has access to all
the axioms and all the theories previously given in this Eqthy document
(and possibly from shared libraries).  The checking process ensures that the first
step can be obtained from an axiom or previously proved theory, that each step
can be derived from the previous step, and that the equation being proved matches
the last step.  Once a theorem has been checked, the equation that was provded
is available for use in subsequent theorems.

The hint on each step is optional.  If omitted, it is assumed that the processor will do
what it can to search for what rule might have been applied, to derive this step from the previous
step.  It is also assumed that the processor may have limitations in this regard, so in
practice, the hint might not be optional on steps for which necessarily involve more searching.

Eqthy itself makes no assumption about the power of any particular processor to
search for derivations in the absence of hints.  A processor may not be able to
derive anything without hints, or it may not require any hints at all.  What is
required of a processor is that it does not allow a chain of steps which is invalid
to be reported as valid and subsequently used in other proofs.

In the above theorem, if we omit the hints, the processor must deduce by itself that:

*   `A = A` is an instance of reflexivity.  This is easy to see, because the LHS and RHS are
    identical.
*   `mul(A, e) = A` is an application of `#id-right` on the LHS.  This can be seen
    by searching through the available axioms and previously-proved theorem steps,
    to see which rewrite of `A = A` would result in `mul(A, e) = A`.
*   The third step is similar to the second.

Additionally, if the step `B = A` appears immediately after `A = B`, it can infer that
the rule of symmetry was invoked.

The rules of substitution and congruence may also be invoked; they may require a hint,
as it is sometimes not obvious what is being substituted where.

    e = e                                                [by reflexivity]
    mul(C, inv(C)) = e                                   [by #inverse on LHS]
    mul(mul(A, B), inv(mul(A, B))) = e                   [by substitution of mul(A, B) for C]
    mul(A, mul(mul(A, B), inv(mul(A, B)))) = mul(A, e)   [by congruence of B and mul(A, B)]

Once the processor has resolved what rules were applies and checked that the proof is
valid, it can _pretty-print_ an _annotated_ version of the input Eqthy document, one which
includes all of the hints that it inferred.  This pretty-printed document can be checked
again in the future, and more efficiently, as all the searches for hints have been
already performed.

Prescriptive Examples
---------------------

We now present a number of example Eqthy documents in
Falderal format, in the hopes that they will help clarify
the semantics of the language.

    -> Functionality "Parse Eqthy Document" is implemented by shell command
    -> "python3 bin/eqthy --input-format=bare-eqthy --dump-ast %(test-body-file) 2>&1 > /dev/null && echo 'ok'"

### Parse Eqthy Document

    -> Tests for functionality "Parse Eqthy Document"

This document is well-formed.  It will parse.

    axiom inv(A) = A
    ===> ok

This document is not well-formed.  It will not parse.

    axiom inv(A) .
    ???> 

Comments are introduced with the symbol sequence `//`.  They extend
until the end of the line.

    // This is a comment.
    axiom inv(A) = A  // This is also a comment.
    
    ===> ok

A comment may not be the very last thing in the document though.
They do need to end with a newline character.

    // This is a comment.
    axiom inv(A) = A  // This is also a comment.
    ???> 

A theorem may be followed only by another theorem or the end of the
document.  A theorem may not be followed by, e.g., an axiom.

    axiom inv(A) = A.
    theorem inv(A) = A proof A = A inv(A) = A qed.
    axiom dec(A) = A.
    ???> 

### Check Eqthy Document

    -> Functionality "Check Eqthy Document" is implemented by shell command
    -> "python3 bin/eqthy --input-format=bare-eqthy %(test-body-file) && echo 'ok'"

    -> Tests for functionality "Check Eqthy Document"

This document consists of some axioms and a theorem.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = A
    proof
        A = A
        mul(A, e) = A
    qed
    ===> ok

A document need not have any axioms.

    theorem
        a = a
    proof
        a = a
    qed
    ===> ok

A document may contain more than one theorem.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = mul(e, A)
    proof
        A = A
        mul(A, e) = A
        mul(A, e) = mul(e, A)
    qed
    theorem
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(A, e)
    qed
    ===> ok

Subsequent theorems can build on the results of previously-proved
theorems.

(TODO: this is definitely not the best example; give a better one.)

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(A, e)
    qed
    theorem
        A = mul(A, e)
    proof
        A = A
        A = mul(e, A)
        A = mul(A, e)
    qed
    ===> ok

Any variable name you like can be used in a theorem.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(Z, e) = Z
    proof
        Z = Z
        mul(Z, e) = Z
    qed
    ===> ok

This "proof" contains a misstep.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = mul(foo, mul(e, A))
    proof
        A = A
        mul(A, e) = A
        mul(A, e) = mul(foo, mul(e, A))
    qed
    ???> Could not derive mul(A, e) = mul(foo, mul(e, A)) from mul(A, e) = A

This theorem does not prove what it says it proves.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = mul(A, A)
    proof
        A = A
        mul(A, e) = A
    qed
    ???> No step in proof of unnamed_theorem_1 showed mul(A, e) = mul(A, A)

Typically, all theorems that are given in the document are checked,
and are checked in sequence, and checking stops at the first failure.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = mul(e, A)
    proof
        A = A
        mul(A, e) = A
        mul(A, e) = mul(e, A)
    qed
    theorem
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(A, A)
    qed
    theorem
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(e, A)
    qed
    ???> Could not derive mul(e, A) = mul(A, A) from A = mul(A, e)

This proof requires rewrites on the right-hand side of the equation.

    axiom mul(A, e) = A
    axiom mul(e, A) = A
    axiom mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = mul(e, A)
    proof
        A = A
        mul(A, e) = A
        mul(A, e) = mul(e, A)
    qed
    ===> ok

Axioms and theorems can be named.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem (idcomm)
        mul(A, e) = mul(e, A)
    proof
        A = A
        mul(A, e) = A
        mul(A, e) = mul(e, A)
    qed
    ===> ok

The name of an axiom or a theorem can either begin with an alphabetic
character, or it can begin with a `#` symbol.  If it begins with a `#`
symbol, it may contain `-` symbols.

    axiom (#id-right) mul(A, e) = A
    axiom (#id-left)  mul(e, A) = A
    axiom (#assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem (#id-comm)
        mul(A, e) = mul(e, A)
    proof
        A = A
        mul(A, e) = A [by #id-right]
        mul(A, e) = mul(e, A)
    qed
    ===> ok

#### Hints

Proof steps can name the axiom being used in a hint written next to
the step.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        A = mul(A, e)
    proof
        A = A
        A = mul(A, e)  [by idright]
    qed
    ===> ok

Naming an axiom in a hint when the axiom used was not actually used there
is incorrect.  It is reasonable to (at least) warn the user of this mistake.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        A = mul(A, e)
    proof
        A = A
        A = mul(A, e)  [by idleft]
    qed
    ???> Could not derive A = mul(A, e) from A = A

Proof steps can also name a previously-proved theorem in a hint.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem (idcomm)
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(A, e)
    qed
    theorem (something)
        A = mul(A, e)
    proof
        A = A
        A = mul(e, A)
        A = mul(A, e)   [by idcomm]
    qed
    ===> ok

Naming a theorem in a hint when the theorem used was not actually used there
is incorrect.  It is reasonable to (at least) warn the user of this mistake.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem (idcomm)
        mul(e, A) = mul(A, e)
    proof
        A = A
        A = mul(A, e)
        mul(e, A) = mul(A, e)
    qed
    theorem (something)
        A = mul(A, e)
    proof
        A = A
        A = mul(e, A)
        A = mul(A, A)   [by idcomm]
    qed
    ???> Could not derive A = mul(A, A) from A = mul(e, A)

When naming an axiom or theorem in a hint, variables used in that
axiom or theorem can be renamed before it is applied to the current step.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        R = mul(R, e)
    proof
        R = R
        R = mul(R, e)  [by idright with A=R]
    qed
    ===> ok

Using the reflexivity hint when the rule used was not actually reflexivity
is incorrect.  It is reasonable to (at least) warn the user of this mistake.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        A = mul(A, e)
    proof
        A = A
        A = mul(A, e) [by reflexivity]
    qed
    ???> Reflexivity

Proof steps can use the "substitution" hint.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(mul(e, B), e) = mul(e, B)
    proof
        A = A
        mul(A, e) = A
        mul(mul(e, B), e) = mul(e, B)   [by substitution of mul(e, B) into A]
    qed
    ===> ok

In a substitution hint, the "into" part must name a variable.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(mul(e, B), e) = mul(e, B)
    proof
        A = A
        mul(A, e) = A
        mul(mul(e, B), e) = mul(e, B)   [by substitution of mul(e, B) into mul(e, e)]
    qed
    ???> Expected variable

Using the substitution hint when the rule used was not actually substitution
is incorrect.  It is reasonable to (at least) warn the user of this mistake.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = A
    proof
        A = A
        mul(A, e) = A             [by substitution of mul(A, e) into A]
    qed
    ???> Substitution

Proof steps can use the "congruence" hint.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(B, mul(A, e)) = mul(B, A)
    proof
        A = A
        mul(A, e) = A
        mul(B, mul(A, e)) = mul(B, A)     [by congruence of A and mul(B, A)]
    qed
    ===> ok

In a congruence hint, the first part must name a variable.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(B, mul(A, e)) = mul(B, A)
    proof
        A = A
        mul(A, e) = A
        mul(B, mul(A, e)) = mul(B, A)     [by congruence of mul(B, A) and A]
    qed
    ???> Expected variable

Using the congruence hint when the rule used was not actually substitution
is incorrect.  It is reasonable to (at least) warn the user of this mistake.

    axiom (idright) mul(A, e) = A
    axiom (idleft)  mul(e, A) = A
    axiom (assoc)   mul(A, mul(B, C)) = mul(mul(A, B), C)
    theorem
        mul(A, e) = A
    proof
        A = A
        mul(A, e) = A             [by congruence of A and mul(A, e)]
    qed
    ???> Congruence