CalcCheck Reference
Table of Contents
Why The Calculational Method and CalcCheck
The pragmatic efficiency of employing the calculational approach for education is well known and is argued in a few places. Notable mentions include,
- A Logical Approach to Discrete Math, or LADM, by Gries and Schneider, the text book used for teaching logic and discrete mathematics at McMaster University in Computing and Software for the past seven years.
- Program Construction — Calculating Implementations from Specifications, by Roland Backhouse and it is essentially the LADM applied to software design; and it is has been the text book for Computer Science 3EA3: Specifications and Correctness.
- Principles and Applications of Algorithmic Problem Solving, a study in Nottingham supporting using the calculational approach. Online at http://joaoff.com/publications/2009/feedback-calculational/feedback-calculational.pdf
- Youtube Video: A Calculational Proof :: The square root of 2 is irrational —with CalcCheck
What is CalcCheck? It is a proof checker for equational-style proofs. Checking proofs is easy enough for being automated; whereas finding proofs is hard and in general requires humans.
Originally, the system used LaTeX input and feedback was presented with Unicode to the terminal and to HTML. Now, the system is in-browser with Unicode support, code completion, coloured errors, and more.
It has an impressive similarity to the programming language Agda in that it supports Unicode mixfix identifiers and allows users to implement their own theories and use them. E.g., there is no need to use the theories of LADM.
Students following a first-year course based on Gries and Schneider's LADM textbook had frequently been asking: “How can I know whether my solution is good?”
We now report on the development of a proof-checker designed to answer exactly that question, while intentionally not helping to find the solutions in the first place. CalcCheck provides detailed feedback to LaTeX-formatted calculational proofs, and thus helps students to develop confidence in their own skills in “rigorous mathematical writing”.
Gries and Schneider's book emphasises rigorous development of mathematical results, while striking one particular compromise between full formality and customary, more informal, mathematical practises, and thus teaches aspects of both. This is one source of several unusual requirements for a mechanised proof-checker; other interesting aspects arise from details of their notational conventions.
A Brief Glance at the CalcCheck Language
We look at a formal proof in the language and make some remarks that will be expanded on in other sections.
Recall that,
- An equational calculation consists of a sequence of expressions, each on a line (or several lines) of it own, and these expressions are separated by hint lines.
- A hint line contains an equality symbol (later also other symbols) immediately followed by a hint enclosed in angle brackets `⟨' and `⟩'.
For example, —in UTF-8 encoding—,
Theorem (15.17) “Self-inverse of unary minus”: - (- a) = a Proof: - (- a) =⟨ “Identity of +” ⟩ 0 + - (- a) =⟨ “Unary minus” — silently using associativity of + ⟩ a + (- a) + - (- a) =⟨ “Unary minus” — silently using symmetry of + ⟩ a + 0 =⟨ “Identity of +” ⟩ a
Overall Structure
- The theorem being proven is given both a number and a name; we may provide more names if we wish.
- The keywords
Theorem
andProof
are not indented at all. - Everything that is part of the theorem needs to be either after the keyword
Theorem
, or indented by at least two spaces on the following lines. - Proofs by calculation start on the line after the
Proof:
, and every part of the calculation needs to be indented by at least two spaces.
Hint Level
- The hint must be surrounded by spaces: There needs to be at least one space after the opening hint bracket, and at least one space before the closing hint bracket.
- The recommended style for the current calculations is to indent the hint lines by two spaces (from the parent keyword), and indent the expression lines by four spaces (from the parent).
- The expressions in a calculation need to be indented at least two spaces more than the equality symbols of the hint lines.
- Simple hints consist of theorem names or theorem numbers, separated by commas or by keyword
and
.- Theorem numbers following the style of LADM are delimited by parentheses and consist of numbers, dots, and occasional letters. Examples:
(15.17)
,(15.25a)
. The enclosure always consists of round parentheses, and there are never any space characters inside.
- Theorem numbers following the style of LADM are delimited by parentheses and consist of numbers, dots, and occasional letters. Examples:
- Theorem names are delimited by opening and closing double quote characters “ and ”.
- A hint may contain a comment via the `—' token; entered
\---
.
More on Hints
- A calculation may have an arbitrary number of steps, however one should always strive to find nice, short
proofs —this should become easier with practice.
- At times, exceptionally lengthy proofs may incur grading penalties.
- A single hint step may have any number of justifications, separated by commas or
and
.- If too many are provided, the system may time out and request you to
Split proof into smaller steps!
- A hint is to convey how one expression transforms into another, so they are usually not more than 3 justifications.
- At times, for learning purposes, we may restrict the number of hints to be 1.
- In such a scenario, even though only one theorem reference is allowed, that theorem may be applied more than once in that step.
- Using 2 hints, for example, results in:
Only 1 item allowed per hint, but 2 items encountered!
- If too many are provided, the system may time out and request you to
Unicode Identifiers and a Template
Multi-letter variable names are supported in a rather liberal way. Therefore, spaces around operators are necessary almost everywhere.
- E.g., the application of a unary minus symbol to a name is rendered
- x
, without the space-x
is a name!
A helpful idea when programming is that of sanity checks: Checking your progress periodically. The same holds for proving.
When one declares their theorem, they may want to immediately write down the structure of the proof-body. To do so they may
use (non-special) variable ?
—or any other variable they like— and special hint token ?
to get their template going:
Theorem “My Result”: lhs = rhs Proof: lhs =⟨ ? ⟩ ? =⟨ ? ⟩ rhs
So one may use the special hint ?
and the non-special variable name ?
to make holes in their calculation as they are constructing it.
One immediate benefit is to be able to proof-check, or syntax-check, one's progress.
Type-checking the above results in the middle expression ?
to be coloured blue since it is a variable name, and for the two hints ?
we see
— CalcCheck: “?” does not prove anything! — CalcCheck: Not-yet-implemented hint item encountered. — CalcCheck: Incomplete hint, not checked.
CalcCheckWeb
This section tries to help you getting started with the web interface aspects of CalcCheckWeb.
There are two kinds of cells:
- Code cells
- are intended for the formal CalcCheck content.
- They are displayed as a cell box containing two boxes, which are currently displayed side-by-side: The left box is the text entry area, and the right box shows CalcCheck output.
- MarkDown cells
- are intended for natural-language documentation and explanations.
- They are displayed as a cell box containing just one box.
- MarkDown cells either show the MarkDown source on a light green background in an entry box, or the generated HTML in a box that cannot be edited.
- Sending a source cell with
Ctrl-ENTER
generates HTML on the server, and then displays that.
Each cell is in one of the following two modes:
- Edit mode
- The cursor is active in the text area, and the text area is displayed in a lighter colour lighter than label to the left.
- Clicking on a text entry area forces a cell into edit mode.
- If the current cell is in edit mode, then the text area has focus, and you have a cursor (or selection) there.
- Command mode
- The label to the left is lighter.
- Clicking on the label to the left forces a cell into command mode.
- If the current cell is in command mode, then the outer box has focus, and a slightly thicker line than the outer boxes of the other cells.
- (no term)
- Pressing the
Enter
key switches the current cell from command mode into edit mode. - (no term)
- Pressing the
Esc
key switches the current cell from edit mode into command mode.
The following key bindings work the same in both modes:
Key Bindings for both modes
Ctrl-Enter | performs a syntax check on the contents of all code cells before and up to the current cell. |
Ctrl-Alt-Enter | performs proof checks on the contents of all code cells before and up to the current cell. |
Shift-Ctrl-v | (for visible spaces) toggles display of initial spaces on each line as “␣” characters. |
Ctrl-/ | splits the cell at the current cursor point. |
Ctrl-s | saves the notebook on the server, ONLY if you are logged in via Avenue. |
(Links for reloading the last three saved versions are displayed when you load the notebook again later.)
Key Bindings for command mode
Enter | enters edit mode |
a | inserts a code cell above the current cell |
A | inserts a MarkDown cell above the current cell |
b | inserts a code cell below the current cell |
B | inserts a MarkDown cell below the current cell |
x | clears the output area for current code cell |
Ctrl-x | clears the output areas for all code cells |
d | deletes the current cell, with a confirmation dialogue — there is no “undo” |
DownArrow | shifts focus onto the next cell |
UpArrow | shifts focus onto the previous cell |
Key Bindings for edit mode
Esc | enters command mode |
\ | brings up symbol completion menu, see below |
TAB | If there is a left double quote (“) or a normal double quote character (") at least three characters to the |
left of the cursor, TAB brings up the theorem name completion menu if those charaters are the start of at least one theorem name.
Standard Browser Bindings
Some standard functionality of your browser and/or windowing system will typically still be available, including:
Ctrl-a | selects all contents of current cell |
Ctrl-x | cuts selected contents (to an internal clipboard) |
Ctrl-c | copies selected contents (to the clipboard) |
Ctrl-v | pastes the clipboard contents |
If you are using the X11 window system (that is, essentially if you are on Linux or FreeBSD/PC-BSD/OpenBSD), you also have
selection by MouseLeft-down-and-drag
and paste by MouseMiddle-click
.
Identifier Colouring
Existing names are coloured yellow, variable names are in blue —in the proof checked output.
- This explains why, for example,
- n
is a valid expression when working with naturals: The unary minus symbol is interpreted as a function variable! - Remember that variable names may be (almost) any whitespace-free sequence of symbols.
Inputting Special Characters
These special characters can be entered via character completion, which is triggered by typing a backslash (“\”). Special keystrokes in that mode:
“ESC”
Removes the popup and the material typed so far, including the backslash (if it is still displayed).“Ctrl-SPACE”
Leaves the text in the current state, removing the popup.“ENTER”
If the menu is displayed, uses the current selection; otherwise leaves the text in the current state, but adding a line break, removing the popup.“BACK_SPACE”
Undoes the narrowing of options performed by the previously-typed character. If only the backslash had been typed, removes that and the popup.
“TAB”
If an extension of the currently typed prefix is common to all still-active options, narrow down to the maximal such extension. Otherwise, display the menu.
Sample Unicode Input Sequences
\<, \langle, \beginhint
\>, \langle, \endhint
\``, \ldquo
\'', \rdquo
\., \cdot
\leq
\geq
\BB, \bool
\NN, \nat
\ZZ, \int
\QQ, \rat
\RR, \real
\PP, \powerset
==
, \equiv
\lnot
\lor
\land
\implies, \=>
\----
\forall
\exists
\sum
\product
\min
\max
Symbol | Key sequence(s) |
𝜖 | \eps |
ε | \epsilon |
∈ | \in |
∋ | \ni, \haselement |
⊆ | \subseteq |
⊂ | \subset |
⊃ | \supset |
⌢ | \catenate, \++ |
∩ | \intersection |
∪ | \union |
𝑼 | \universe |
❙ | \with |
• | \spot |
₁¹, ₂², …, ₉⁹ | \_1 \^1, \_2 \^2, \_9 \^9 |
ₙ | \_n |
⨾ | \; |
αβγζ | \alpha \beta \gamma \zeta |
The majority of CalcCheck
input sequences correspond to their standard LaTeX counterparts.
Elementary uses of CalcCheck
Here we cover the most basic constructions to get going with the CalcCheck system. Later parts introduce syntactic sugar to expand on these constructs and improve clarity for readers of proofs as well as writers of proofs.
By, Declaration, Explanation
and Axiom
-atisation
To showcase the keywords in the section title, we begin with a puzzle:
You and a friend are playing a game where you arrange a collection of balls in the shape of a right-angle triangle such that the i-th row has precisely i-many balls in it. How many balls do you need to make a triangle with 100 rows?
Our setup has the naturals formed from 0
and the successor operation S
;
Declaration: T : ℕ → ℕ Explanation: T n := “the area of our discrete triangles.” Axiom “Super Small Triangle” “Definition of T on 0”: T 0 = 0 Axiom “Triangle with new base” “Definition of T on `S`”: T (S n) = (S n) + T n
Notice that
- Declaration
- We introduced a name
T
to assist in our calculation. - Explanation
- We gave a colloquial English explanation to document what it represents when evaluated.
- Axiom
- We defined it inductively and gave alternate names for the clauses for the sake of readability.
- Axioms need to be chosen carefully! Too strong and you may prove anything you want, including
false
; too weak and you will not be able to make progress in your problem.
- Axioms need to be chosen carefully! Too strong and you may prove anything you want, including
- Important
- All colons, part of a keyword phrase, cannot be preceded by a space.
- This includes
Theorem “X”:, Proof:, Axiom “A_1” “A_2” ⋯ “A_N”:, Explanation:, Declaration:
- In the previous item, the
A_i
denote the alternate names for the axiom being declared.
- This includes
To wrap-up the example: We know from grade school that a triangle’s area is half its height times its base and so aim to use this to solve
our problem. Since multiplication is less messy than the non-associative division, we remove divisions in-favour of
multiplications to obtain the conjecture that 2 · T n = n · (n + 1)
.
This candidate solution can be verified by induction
, which is covered in a later section.
As another example, we show how (a variant of) the natural numbers may be defined:
Declaration: Nat : Type Declaration: Zero : Nat Declaration: Succ : Nat → Nat
Observe
- The type
Type
serves to introduce new types. - The second declaration serves to show that the declared type is non-empty.
- The third declaration provides us with a method to construct possibly new elements
from existing elements.
- Possibly new-elements since we are not guaranteed that
Succ n ≠ n
. - This is an axiomatic definition: We have only what we see, what we declared.
- This is not an inductive definition: We are not given an induction principle for the type.
- Possibly new-elements since we are not guaranteed that
However, the built-in naturals do come with an induction principle and helpful syntactic-sugar for performing
induction
proofs —more on this later.
We can always express additional axioms for our defined types; e.g.,
Axiom “Cancellation of Succ” “Succ injectivity”: Succ m = Succ n ≡ m = n Axiom “Zero is not Succ” “0≠+1”: Zero = Succ n ≡ false
Recall that we can have unicode identifiers for names.
Theorem “0≠1”: Zero ≠ Succ Zero Proof: By “0≠+1” and “Definition of ≠” and (3.15) — i.e. ¬ p ≡ p ≡ false
Finally, the By
syntax allows us to take a simple proof and render it in one-line:
We ignore the expressions in a calculation and merely list the hints.
- This is a good idea when a result is an instance of a more general result or is two or three clear steps.
- This is not a good idea when a result is many steps or the steps are unclear and seeing the expressions would assist in understanding the proof.
Adventuring with Calculation
Sometimes we do not have a particular theorem we wish to prove, but are rather attempting to solve a problem by manipulating some given data. In such a case, the Theorem
keyword is inappropriate since we do not know what we are aiming at calculating. Instead we use the Calculation
keyword. If later we wish to name the result of our calculation for referencing purposes, we may append the calculational proof with the key-phrase This proves “My new result”
.
We shall provide an example to illustrate this keyword, and along the way we again showcase the keywords of the previous section.
Declaration
, to bring a typed name into scopeExplanation
, to document a name.- — is entered via
\---
and it permits a one-line comment within a hint.- This comment token must be followed by a space.
The example: Adapted from Raymond Smullyan’s Alice in Puzzleland,
“How about making us some nice tarts?” the King of Hearts asked the Queen of Hearts one cool summer day.
“I can’t!” shouted the Queen. “A necessary item has been stolen!”
“Really! said the King. ‘This is quite serious! Who stole it?”
“How do you expect me to know who stole it? If I knew, I would have had it back long ago and the miscreant’s head in the bargain!”
Well, the King had his soldiers scout around for the missing item, and it was found in the house of the March Hare, the Mad Hatter, and the Dormouse. All three were promptly arrested and tried.
The puzzle is to deduce the criminal(s) from what the defendants have to say and the findings of the investigators that found them.
The defendants had the following to say:
March Hare: The Hatter stole it. Mad Hatter: —said nothing--- Dormouse : —said nothing--- As subsequent investigation revealed, only one of the three had stolen the flour, and he was the only one of the three who told the truth.
There is no Theorem
to prove, but a Calculation
may be performed provided we furnish ourselves with a sufficient setup.
We begin my formalising the candidates of the crime,
Declaration: R, H, M : 𝔹 Explanation: R := “the `R`abbit, the March Hare, stole the item” Explanation: H := “the `H`uman, the Mad Hatter, stole the item” Explanation: M := “the `M`ouse, the Dourmouse, stole the item”
Then we explicitly clarify what was said,
March Hare: | H |
Mad Hatter: | --- |
Dormouse: | --- |
The investigation’s findings are the only true things we have, so we being there.
That only one of the three had stolen the flour means we have R ≢ H ≢ M
, and that the thief was the only
one of the three who told the truth means that the rabbit –the only one whose statement we know– is the thief
precisely if what he claims is true; i.e., R ≡ H
.
With these formalisation in hand, we calculate,
Calculation: (R ≡ H) ∧ (R ≢ H ≢ M) ≡⟨ “Definition of ≢” and “Double Negation” — silently using associativity of ≢ ⟩ (R ≡ H) ∧ (R ≡ H ≡ M) ≡⟨ “Substitution” and “Identity of ≡” ⟩ (R ≡ H) ∧ M ⇒⟨ “Weakening” ⟩ M This proves: Theorem “Deducing the Criminal”: (R ≡ H) ∧ (R ≢ H ≢ M) ⇒ M
Hence the thief is the `M`ouse: The Dormouse stole the flour.
Note that “Substitution”
above refers to a theorem of propositional logic, namely \\ \(e = f ∧ E[z := e] \;\;≡\;\; e = f ∧ E[z := f]\),
not the keyword Substitution
which provides a rewrite rule for terms of the shape E[x := expr].
Rigid Matching with with
Here we document how a theorem mentioned in a hint is applied in a particular case, a substitution can be provided following the keyword with
.
For example,
Theorem (15.19): -(a + b) = (- a) + (- b) Proof: -(a + b) =⟨ (15.20) with `a := a + b` ⟩ - 1 · (a + b) =⟨ “Distributivity of · over +” with `a, b, c := - 1, a, b` ⟩ - 1 · a + - 1 · b =⟨ (15.20) with `a := a` ⟩ - a + - 1 · b =⟨ (15.20) with `a := b` ⟩ - a + - b
Note:
- There are spaces around
with
. - The substitution is surrounded by backquotes (
`
).- On most keyboards, the backquote is in the upper left corner, on the same key as the tilde (
~
). - Other quote-like characters will not work.
- The use of backquotes here is following the MarkDown convention, according to which code pieces embedded in English sentences are surrounded by backquotes.
- On most keyboards, the backquote is in the upper left corner, on the same key as the tilde (
- The substitution notation is that of LADM: \(\mathsf{variables} :\!= \mathsf{expressions}\)
- The variable list has the same length as the expression list.
- No variable occurs twice in the variable list.
- The “becomes” symbol \(:\!=\) is obtained via the symbol completion sequence
\:=
(backslash-colon-equal). - Writing two-character sequence colon-equal := will not work; the one-character becomes \(:\!=\) must be used.
When CalcCheck is invoked “with rigid matching”:
- All theorem variables in a hint justification need to be substituted possibly in the form
a:=a
. - Otherwise, messages like
Rule variable `a` not substituted!
will be produced when proof checking. - When a theorem is invoked with a particular substitution then it may be applied more than once in that step but all such applications would need to be with that substitution.
Textual Substitution
Let E
and R
expressions and let x
be a variable. We write E[x∶=R]
denote an expression that is the same as E
but with all occurrences of x
replaced by (R)
.
- This concept allows one to define function application where a `function' is an alias for a particular expression.
- This concept is integral in evaluating programs in (functional) programming languages.
- In general,
R
andx
may be lists of expressions and distinct variables, respectively, of the same length, then the resultE[x:=R]
is the simultaneous replacement of variablesx
by corresponding expressionsR
. Python, for example, has a similar feature: Concurrent assignment.
Applying a substitution is performed with the Substitution
keyword; as in
Calculation: (3 · x + y)[y := x + 2] =⟨ Substitution ⟩ 3 · x + (x + 2) =⟨ “Reflexivity of =” ⟩ 3 · x + x + 2 =⟨ “Identity of ·” ⟩ 3 · x + 1 · x + 2 =⟨ “Distributivity of · over +” ⟩ (3 + 1) · x + 2 =⟨ Evaluation ⟩ 4 · x + 2
- Steps that just omit unnecessary parentheses can be explained with
“Reflexivity of =”
as hint. - Just as with
with
, the becomes symbol must be used rather than colon-equal /:= / !
To see that a sequential substitution differs from a simultaneous one, consider working out the following,
Calculation: (2 · x + 3 · y)[x := y + 7][y := x + 6] Calculation: (2 · x + 3 · y)[x, y := y + 7, x + 6]
Rewriting with Evaluation
The Evaluation
keyword rewrites integer expressions having no variables as integer values.
For example, (3 - 2) · x
is rewritten to 1 · x
since the integer expression 3 - 2
reduces to 1
.
Moreover, the rewrite does not continue any further to, say, x
since 1 · x = x
involves a variable and so must be proven as a theorem
and then invoked in a hint by its name.
We shall demonstrate these ideas by solving a system of integer equations in a very constrained way.
Given the system
Declaration: r, s : ℤ Axiom (1): 5 · r + 8 · s = 49 Axiom (2): 6 · r + 7 · s = 51
We attempt to solve for one of the unknowns: —the numbers on the side are for commentary purposes only—
1: Calculation: 2: r 3: =⟨ “Identity of ·” ⟩ 4: 1 · r 5: =⟨ Evaluation ⟩ 6: (6 - 5) · r 7: =⟨ “Distributivity of · over -” ⟩ 8: 6 · r - 5 · r 9: =⟨ “Subtraction” ⟩ 10: 6 · r + -(5 · r) 11: =⟨ “Identity of +” ⟩ 12: 6 · r + 0 + -(5 · r) + 0 13: =⟨ “Unary minus” and “Distributivity of unary minus over +” ⟩ 14: 6 · r + 7 · s + -(7 · s) + -(5 · r + 8 · s) + 8 · s 15: =⟨ (2) and (1) ⟩ 16: 51 + -(7 · s) + - 49 + 8 · s 17: =⟨ Evaluation and (15.22) 18: — (15.22): a · (- b) = - (a · b) ⟩ 19: (- 7) · s + 8 · s + 2 20: =⟨ “Distributivity of · over +” and Evaluation and “Identity of ·” ⟩ 21: s + 2 22: This proves: Theorem “`r` in terms of `s`”: r = s + 2
Observe
- Line 3 could not have been an
Evaluation
since there the expression being rewritten contains variables. - Line 5 rewrites only the integer subexpression that does not contain any free variables.
- Line 15 references the axioms by the numbers assigned to them.
- Line 18 is a comment to remind the reader the statement of LADM's theorem
(15.22)
. - Line 22 gives a name to the result of this calculation so that it can be used in further calculations, such as to prove
s = 3
andr = 5
.
At times, the keyword Evaluation
is not permitted as a justification; it is disabled.
— This is
Saves the Day, or two lines
One way to show a statement is a theorem is by proving that it equivales an existing theorem.
This short-circuiting of a calculation occurs by appending the final line of a calculation
with — This is <<theorem reference here>>
. That is, this syntax justifies the other end of an ≡-chain.
- This is not a a usual comment!
- The spacing and capitalisation in
— This is
is fixed. - It currently only parses with only single spaces around
This
andis
.
For example, if we have a theorem “q is a Theorem”
that proves statement q
,
then we could prove a statement p
is true as follows,
Theorem “p is a theorem”: p Proof: p ≡⟨ hint ⟩ … ≡⟨ hint ⟩ q — This is “q is a Theorem”
This really saves us two lines since it is equivalent to,
Theorem “p is a theorem”: p Proof: p ≡⟨ hint ⟩ … ≡⟨ hint ⟩ q ≡⟨ “q is a Theorem” ⟩ true
Why do these templates suffice to prove p
is a theorem when the
calculations explicitly prove p ≡ true
? It is the “Identity of ≡”
which states (p ≡ true) ≡ p
that permits this.
Like all identity statements, this rule implies that occurrences of “≡ true”, or “true ≡”, in an expression are redundant and so are eliminated unless there is a compelling reason otherwise.
Note that true
is itself a theorem: It is LADM's theorem (3.4).
As such, we could append the previous calculation with
— This is (3.4)
, however this would be redundant and should not be performed.
As such, the “Identity of ≡”
is tantamount to saying that no “— This is” syntax
is required for true
, the least interesting theorem.
Warning The — This is
syntax currently does not work with keyword Assumption
nor induction hypothesis
.
Automatic Associativity and Symmetry
CalcCheck allows us to reason up to symmetry and associativity: If an operation has been to be proven to have one of these properties, then it can be admitted to CalcCheck's rewrite rules and no explicit call to such a result is henceforth necessary.
- Making symmetry and associativity steps explicit is always allowed; it is sometimes very useful for readability.
- For learning purposes, such features are sometimes disabled! E.g., Exercise 1.4 and Assignment 1.3.
For example, if we define addition
Declaration: _+_ : ℕ → ℕ → ℕ Axiom “Definition of +” “Left-identity of +” “Definition of + for 0”: 0 + n = n Axiom “Definition of +” “Addition of successor” “Definition of + for `S`”: (S m) + n = S (m + n)
( Note that we are using multiple aliases for the particular definition clauses for readability purposes. )
Then if we can realise
Theorem “Associativity of +”: (a + b) + c = a + (b + c) Proof: ?
Then we can set the properties to be implicit:
Activate associativity property “Associativity of +”
Now calculations involving addition needn not both explicit calls to this theorem.
In a similar fashion,
Theorem “Symmetry of +”: m + n = n + m Proof: ? Activate symmetry property “Symmetry of +”
induction
Proofs
For an expression P
, an induction proof looks as follows:
Theorem: P Proof: By induction on `m ∶ ℕ`: Base case: Proof for P[m := 0] Induction step: Proof for P[m := S m] using Induction hypothesis P
For example, with the setup
Declaration: _≤_ : ℕ → ℕ → 𝔹 Axiom “Zero is least element”: 0 ≤ a Axiom “Isotony of successor”: S a ≤ S b ≡ a ≤ b Axiom “Successor is not at most zero”: S a ≤ 0 ≡ false Theorem “Zero is unique least element”: a ≤ 0 ≡ a = 0
We can show that mutually contained numbers are necessarily equivalent.
Theorem “Antisymmetry of ≤”: a ≤ b ⇒ b ≤ a ⇒ a = b Proof: By induction on `a : ℕ`: Base case `0 ≤ b ⇒ b ≤ 0 ⇒ 0 = b`: 0 ≤ b ⇒ b ≤ 0 ⇒ 0 = b ≡⟨ “Zero is unique least element” ⟩ 0 ≤ b ⇒ b = 0 ⇒ 0 = b ≡⟨ “Reflexivity of ⇒” ⟩ 0 ≤ b ⇒ true ≡⟨ “Right-zero of ⇒” ⟩ true Induction step `S a ≤ b ⇒ b ≤ S a ⇒ S a = b`: By induction on `b : ℕ`: Base case `S a ≤ 0 ⇒ 0 ≤ S a ⇒ S a = 0`: S a ≤ 0 ⇒ 0 ≤ S a ⇒ S a = 0 ≡⟨ “Zero is least element” ⟩ S a ≤ 0 ⇒ true ⇒ S a = 0 ≡⟨ “Left-Identity of ⇒” ⟩ S a ≤ 0 ⇒ S a = 0 ≡⟨ “Zero is unique least element” ⟩ S a = 0 ⇒ S a = 0 ≡⟨ “Reflexivity of ⇒” ⟩ true Induction step `S a ≤ S b ⇒ S b ≤ S a ⇒ S a = S b`: S a ≤ S b ⇒ S b ≤ S a ⇒ S a = S b ≡⟨ “Isotony of successor” ⟩ a ≤ b ⇒ b ≤ a ⇒ S a = S b ≡⟨ “Cancellation of `S`”⟩ a ≤ b ⇒ b ≤ a ⇒ a = b ≡⟨ induction hypothesis `a ≤ b ⇒ b ≤ a ⇒ a = b` ⟩ true
Observe
- We performed a double induction since the definition of containment `≤' is defined inductively on both arguments.
- This is an involved proof and so we communicated our intentions to the system at each proof obligation by
indicating our proof goal in
`
back-ticks`
. - A double induction means that the key-phrase
induction hypothesis
is ambiguous; we communicate which one we want to utilise by enclosing the hypothesis in`
back-ticks.`
Similar to some programming languages, recall that the CalcCheck system is indentation and case sensitive.
Extending the left-column
Leibniz —substituting equals for equals—
can be formulated as the “Substitution”
principle:
\[ e = f ∧ E[z :\!= e] \quad≡\quad e = f ∧ E[z :\!= f] \]
This rule permits us, for any relation _∼_
, to take a proof of the shape
Theorem: a ∼ c Proof: a ∼ c ≡⟨ “Identity of ∧” and “Hint why a = b” ⟩ a = b ∧ a ∼ c ≡⟨ “Substiution” ⟩ a = b ∧ b ∼ c ≡⟨ “Hint why b ∼ c” and “Hint why a = b” and “Identity of ∧” ⟩ true
and render it more succinctly as
Theorem: a ∼ c Proof: a =⟨ “Hint why a = b” ⟩ b ∼⟨ “Hint why b ∼ c” ⟩ c
- This relaxed proof demonstrates
a = b ∧ b ∼ c
- By Leibniz, this yields
a = b ∧ a ∼ c
- Then by weakening, p ∧ q ⇒ q, this yields
a ∼ c
.
As it stands, we can have only one occurrence of the relation _∼_
in the left-column since
we are not ensured that multiple occurrences can be “glued” into a single one.
Hence, relations _∼_
proven to be transitive, x ∼ y ∧ y ∼ z ⇒ x ∼ z
, can appear multiple
times in the left-column of a calculation.
Declaration: X : Type Precedence 25 for: _~_ Declaration: _~_ : X → X → 𝔹 Axiom “Transitivity of ~”: (x ~ y) ∧ (y ~ z) ⇒ (x ~ z) Activate transitivity property “Transitivity of ~” Declaration: P, A, Q, B, R : X Axiom (0): P = A Axiom (1): A ~ B Axiom (2): B = Q Axiom (3): Q ~ R Theorem “T0”: P ~ R Proof: P =⟨ (0) ⟩ A ~⟨ (1) ⟩ B =⟨ (2) ⟩ Q ~⟨ (3) ⟩ R
Minimal working example for non-transitive relations:
Declaration: X : Type Precedence 25 for: _~_ Declaration: _~_ : X → X → 𝔹 Declaration: P, A, Q, B : X Axiom (0): P = A Axiom (1): A ~ B Axiom (2): B = Q Theorem “T1”: P ~ Q Proof: P =⟨ (0) ⟩ A ~⟨ (1) ⟩ B =⟨ (2) ⟩ Q
The calculational style is valid for any non-transitive relation as long as it occurs only once in the left-column.
- In-practice, the
Axiom
's seen here are actuallyTheorem
's. - Without the
Activate transitivity property “Transitivity of ~”
our proof for“T0”
will not go through: The calculation will have proven(P ~ B) ∧ (B ~ R)
and will not automatically rewrite this intoP ~ R
since the transitivity property has not been activated. Instead we obtain the red error message CalcCheck: Could not match calculation with stated goal. - If
~⟨ ? ⟩
occurs twice in a calculation for non-transitive~
—i.e., above in the right side— as in the proof of“T0”
, then the proof yields(P ~ B) ∧ (B ~ R)
which would implyP ~ R
if the relation~
were transitive. In such cases the system reports Could not match calculation with stated goal, which is justified since the former is a conjunction that could not be reduced to an expression involving only a single~
.
Discharging provisos with with
It is a common scenario that we can prove certain results provided some constraints are satisfied.
CalcCheck overloads the with
combinator to act as syntactic sugar for discharging the premises of
such theorems when one wishes to utilise their result within a calculation.
The most elementary application
For example, suppose that we have a function f
that when applied to any argument x
is the same as another
function g
applied to any argument y
provided x
and y
satisfy some given property P
.
Then, we can use this result in a calculation as follows:
Comparison
Declaration: P, Q : 𝔹 Axiom “F”: P ⇒ Q Axiom “X”: P Theorem: Q Proof: By “F” with “X”
Notice that the with
syntax acts like the function application operation:
If we construe P and Q as types then we have f : P → Q and x : P implies f x : Q,
just as “F” with “X”
is a proof of proposition Q
.
Without the syntactic sugar:
Theorem: Q Proof: Q ⇐⟨ “Consequence” and “Modus ponens” ⟩ P ∧ (P ⇒ Q) ≡⟨ “F”, “X”, and “Idempotency of ∧” ⟩ true
Simplifying laws to obtain particular instances with with
A tremendously powerful usage of the with
feature is to use one side of an equivalence in a calculation when the other side can be discharged. Needless to say, this is nothing more than syntactic sugar of modus ponens and weakening.
Here are the pieces required to ensure the neighbouring snippets to be minimal working examples.
In-practice the Axiom
's here are Theorem
's or Subproof
's.
Declaration: X : Type Precedence 45 for: _~_ Declaration: _~_ : X → X → 𝔹 Declaration: P : 𝔹 Declaration: r, s, t, u : X Axiom “Fact”: P ≡ (s ~ t) Axiom “Hint why P is true”: P ≡ true Axiom “Hint why t = u”: t = u Axiom “Hint why r = s”: r = s
Verbose Plain CalcCheck
Theorem: r ~ u Proof: r ~ u ⇐⟨ “Consequence” with “Weakening” ⟩ r = s ∧ t = u ∧ r ~ u ≡⟨ Substitution ⟩ r = s ∧ t = u ∧ (x ~ y)[x ≔ r][y ≔ u] ≡⟨ “Replacement” and Substitution ⟩ r = s ∧ t = u ∧ s ~ t ≡⟨ “Hint why r = s” and “Identity of ∧” ⟩ (s ~ t) ∧ t = u ≡⟨ “Hint why t = u” and “Identity of ∧” ⟩ s ~ t ≡⟨ “Fact” ⟩ P ≡⟨ “Hint why P is true” ⟩ true
Sweetened with sugar
Theorem: r ~ u Proof: r =⟨ “Hint why r = s” ⟩ s ~⟨ “Fact” with “Hint why P is true” ⟩ t =⟨ “Hint why t = u” ⟩ u
—Recall that relations can be used in the left-column.—
with
associates to the right
The keyword with
is right-associative:
That is, X with Y with Z
essentially parses as X with (Y with Z)
.
- This happens when we wish to use the result of
X
whose proviso is the consequent ofY
andY
itself has a proviso which must be discharged.
Declaration: T : Type Precedence 45 for: _~_ Declaration: _~_ : T → T → 𝔹 Declaration: pre, proviso, pre : 𝔹 Axiom “X”: pre ⇒ (lhs ~ rhs) Axiom “Y”: proviso ⇒ pre Axiom “Z”: proviso Calculation: lhs ~⟨ “X” with “Y” with “Z” ⟩ rhs This proves: Theorem “Neat”: lhs ~ rhs
Discharging Implication Provisos
Declaration: pre, proviso, pre, pos : 𝔹 Axiom “X”: pre ⇒ pos Axiom “Y”: proviso ⇒ pre Axiom “Z”: proviso Theorem: pos Proof: By “X” with “Y” with “Z”
Discharging equivalences
Declaration: pre, proviso, pre, pos : 𝔹 Axiom “X”: pre ≡ pos Axiom “Y”: proviso ≡ pre Axiom “Z”: proviso Theorem: pos Proof: By “X” with “Y” with “Z”
At times we do not wish to make an auxiliary lemma that may be trivial and only serve to discharge a proviso, in such cases we may provide the proof directly in the calculation.
- E.g., above we could have had
=⟨ “X” with “Y” with Subproof for `proviso`: <<proof here>> ⟩
. - The final section on
Subproof
's shows an example of this nature.
Discharging multiple obligations with with
Here we show an example of how multiple provisos can be discharged.
Recall that conjunction is order-preserving —a proof is shown in the Subproof
sections—
Theorem “Monotonicity of ∧”: (p ⇒ p') ⇒ (q ⇒ q') ⇒ ((p ∧ q) ⇒ (p' ∧ q'))
Let us apply such a monotonicity law:
Theorem (3.76e) “Weakening”: p ∧ q ⇒ (p ∨ r) ∧ q Proof: p ∧ q ⇒⟨ “Left-monotonicity of ∧” with (3.76a) and “Left-identity of ⇒” ⟩ (p ∨ r) ∧ q
What will be going on here behind the scenes is essentially the following:
Theorem (3.76e) “Weakening”: p ∧ q ⇒ (p ∨ r) ∧ q Proof: p ∧ q ⇒ (p ∨ r) ∧ q ≡⟨ “Left-identity of ⇒” ⟩ true ⇒ (p ∧ q ⇒ (p ∨ r) ∧ q) ≡⟨ (3.76a) ⟩ (p ⇒ p ∨ r) ⇒ (p ∧ q ⇒ (p ∨ r) ∧ q) — This is “Left-monotonicity of ∧”
Assuming
the Antecedent
A common practice in mathematics is to prove an implication P ⇒ Q
by assuming the “antecedent” P
and proving the “consequent” Q
. That is, we momentarily take P
to be a given truth, thereby equivalent to true
, and its variables as immutable (non-substitutable!) constants, then utilise this extra knowledge in the aim of proving the truth of Q
.
The Sugar
Leibniz, for the Booleans, along with the identity of equivalence gives us the following rule \[ p \qquad⇒\qquad E[z :\!= p] \;=\; E[z :\!= true] \]
This rule justifies the common practice in mathematics in which one proves an implication \(P ⇒ Q\) by momentarily thinking of \(P\) as equivalent to \(true\) and then attempting to prove \(Q\) with this added knowledge.
CalcCheck caters to this common scenario by allowing us to take proofs such as that on the left side and render them more clearly as that on the right:
Theorem: p ⇒ q ⇒ (p ≡ q) Proof: p ⇒ q ⇒ (p ≡ q) ≡⟨ Substitution ⟩ p ⇒ (q ⇒ (p ≡ q)[q := q])[p := p] ≡⟨ “Replace by `true`” — performed twice and Substitution ⟩ p ⇒ q ⇒ (true ≡ true) ≡⟨ “Reflexivity of ≡” and “Right-zero of ⇒” ⟩ true
Sweetened with Sugar
Theorem: p ⇒ q ⇒ (p ≡ q) Proof: Assuming `p`: Assuming `q`: p ≡⟨ Assumption `p` ⟩ true ≡⟨ Assumption `q` ⟩ q
More syntactic Sugar
Theorem: p ⇒ q ⇒ (p ≡ q) Proof: Assuming `p`, `q`: p ≡⟨ Assumption `p` ⟩ true ≡⟨ Assumption `q` ⟩ q
- Note that the keyword
Assumption
necessarily takes an argument enclosed in back-quotes!- Important There must be a space after each comma in an
Assuming
clause. - Otherwise a syntax error.
- Important There must be a space after each comma in an
- With the relaxed approach, we can be less verbose.
- Not only is this clearer to communicate, it also lessens the technical burden on the reader (and writer!).
- We may want to name assumptions if they are lengthy or would make the proof clearer.
- This can be performed by giving the
Assuming
keyword a name, enclosed in quotes, before the actual assumption; e.g.,Assuming “p is true” `p`:
. - Named assumptions can be invoked as usual or by using their name, e.g.,
Assumption “p is true”
.
- This can be performed by giving the
- Just as the “Proof” syntax is hierarchical, so is the “Assuming” syntax. For example, a proof of a nested implication
P ⇒ (Q ⇒ R)
can be presented using nested “Assuming” sub-proofs as in the middle snippet above. - To reduce nesting and indentation, consecutive unnamed suppositions can be placed in one level, as in the right-most snippet above.
Assuming Conjunctions
However, by “Shunting” (3.65), proving P ⇒ (Q ⇒ R)
is tantamount to proving P ∧ Q ⇒ R
, and so we might consider to use such proofs also for this kind of theorem. This is currently not directly supported, however the extensibility syntax Using
gives a work-around,
Theorem: p ∧ q ⇒ (p ≡ q) Proof: Using “Shunting”: Subproof for `p ⇒ q ⇒ (p ≡ q)`: Assuming `p`, `q`: p =⟨ Assumption `p` ⟩ true =⟨ Assumption `q` ⟩ q
( More on the Using
and Subproof
syntax later. )
Of course such a hierarchical approach has its limits and at times if there are many involved sub-proofs, then it may be prudent to make them first-class lemmas or theorems in their own right. Among other things, this will make it easier for the reader to follow the exposition.
Two worked-out examples
LADM shows examples where assumptions are used in a modified shape; one way to achieve this is by modification using “with” to rewrite the assumption using some other laws:
Axiom “Cancellation of ·”: c ≠ 0 ⇒ (c · a = c · b ≡ a = b) Theorem “Non-zero multiplication”: a ≠ 0 ⇒ b ≠ 0 ⇒ a · b ≠ 0 Proof: Assuming `a ≠ 0`, `b ≠ 0`: a · b ≠ 0 ≡⟨ “Definition of ≠” ⟩ ¬ (a · b = 0) ≡⟨ “Zero of ·” ⟩ ¬ (a · b = a · 0) ≡⟨ “Cancellation of ·” with assumption `a ≠ 0` ⟩ ¬ (b = 0) ≡⟨ “Definition of ≠”, Assumption `b ≠ 0` ⟩ true
For the right side,
- In the third step, the implicit renaming of the variables to fit the context
renders
Axiom “Cancellation of ·”
asa ≠ 0 ⇒ (a · 0 = a · b ≡ 0 = b)
. - Then the
with
discharges the proviso to give us the rulea · 0 = a · b ≡ 0 = b
, which is then used to rewrite the third expression into the fourth.
Subproof
When calculating it is common that we require an auxiliary result to progress or we
could prove such a result in-place while doing the necessary bookkeeping to carry
the context-along. The latter is clunky since it carries the context while only
a certain subexpression is being altered for some time. The former is not much better
since it requires the introduction of new Theorem
's whose purpose is limited.
An alternative is to prove a result or simplify an expression in-place.
Calculation: ⋮ E[z ≔ F] =⟨ Subproof for `F = G`: F =⟨ ? ⟩ G ⟩ E[z ≔ G] ⋮
Without Subproof
Theorem “Helper”: F = G Proof: ? Calculation: ⋮ E[z ≔ F] =⟨ “Helper” ⟩ E[z ≔ G] ⋮
- Delete the vdots, ⋮, to obtain minimal working examples.
- The sub-proof body currently still needs to start on a new line and indented inside the hint, and the hint end `⟩' must also be on a new line, indented not more than the start of the sub-proof body.
Example of Assuming
within a Subproof
Rather than do an Assuming
immediately —which would be more elegant and readable—, for the sake of example, we modify the antecedents before assuming them, which pushes the Assuming
structure into a sub-proof inside a calculation hint:
Theorem “Monotonicity of ∧”: (p ⇒ p') ⇒ (q ⇒ q') ⇒ ( (p ∧ q) ⇒ (p' ∧ q') ) Proof: (p ⇒ p') ⇒ (q ⇒ q') ⇒ ((p ∧ q) ⇒ (p' ∧ q')) ≡⟨ “Definition of ⇒” (3.60) ⟩ (p ∧ p' ≡ p) ⇒ (q ∧ q' ≡ q) ⇒ ((p ∧ q) ⇒ (p' ∧ q')) ≡⟨ Subproof: Assuming `p ∧ p' ≡ p`, `q ∧ q' ≡ q`: p ∧ q ≡⟨ Assumption `p ∧ p' ≡ p` ⟩ p ∧ p' ∧ q ≡⟨ Assumption `q ∧ q' ≡ q` ⟩ p ∧ p' ∧ q ∧ q' ⇒⟨ “Weakening” ⟩ p' ∧ q' ⟩ true
Where a Subproof
is the only item in a hint, the for
and the explicit sub-proof goal are not necessary. However, the sub-proof body currently still needs to start on a new line, and indented inside the hint, and the hint end ⟩
must also be on a new line, indented not more than the start of the sub-proof body.
Discharging a proof obligation in-place
The following silly calculation shows the various forms of proof presentation are still valid in a subproof setting. In-particular, we can satisfy an obligation in-place rather than as some previously proven result.
Theorem “Monotony of ·”: b ≤ c ⇒ a · b ≤ a · c Theorem “Antitony of -”: b ≤ c ⇒ a - c ≤ a - b Theorem “Silly”: 6 · (12 - S n) ≤ 7 · (12 - n) Proof: 6 · (12 - S n) =⟨ Evaluation ⟩ (10 - 4) · (12 - S n) ≤⟨ “Monotony of ·” with “Antitony of -” with subproof for `3 ≤ 4`: By Evaluation ⟩ (10 - 3) · (12 - S n) ≤⟨ “Monotony of ·” with “Antitony of -” with subproof for `n ≤ S n`: By induction on `n : ℕ`: Base case `0 ≤ S 0`: By “Zero is least element” Induction step `S n ≤ S (S n)`: S n ≤ S (S n) ≡⟨ “Isotony of successor” ⟩ n ≤ S n ≡⟨ induction hypothesis ⟩ true ⟩ (10 - 3) · (12 - n) =⟨ Evaluation ⟩ 7 · (12 - n)
Recall that the with
keyword associates to the right.
Proving universals using For any
It often happens that we need to prove statements of the form
(∀ x • P)
, ``Metatheorem (9.16)'' of LADM ensures that it suffices to prove
P
. We mark this transition between the logic and ambient language using the For any
syntax:
Theorem: ∀ x • P Proof: For any `x`: ?
General form
Theorem: ∀ x ❙ R • P Proof: For any `x` satisfying `R`: ?
- Where
?
is a proof forP
.
Extensiblity: Using
theorems as proof methods
Sometimes a concept is defined in such a way that it is difficult and awkward to prove properties about it and but there is some extensional view of the concept that admits formuale more amicable to calculation – c.f., indirect equality. Alternatively, there may not be an obvious way to prove a result but if we reshape it then we may end up with a proof-obligation whose form immediately suggests a proof approach – c.f., induction.
The Using
syntax allows us to move from a general shape to a the more specific or calculation-friendly shape and proof that in-order to prove our initial goal.
Indirect Equality
The usual minimum operation can be defined by conditional but that would result in case-analysis proofs and so an alternative is to define it by its relation to other numbers:
Declaration: _↓_ : ℤ → ℤ → ℤ Axiom “Definition of ↓”: z ≤ x ↓ y ≡ z ≤ x ∧ z ≤ y
Suppose we now wish to prove the minimum is a symmetric operation: x ↓ y = y ↓ x
.
The definition gives us no clear indication how to proceed, however in the presence of an
anti-symmetric order `≤' we can prove
Theorem (15.47) “Indirect Equality from below”: a = b ≡ (∀ z • z ≤ a ≡ z ≤ b)
( Proof shown in a following sub-section! )
Now we use this result as it gives us a more calculation-friendly formula to work with:
Theorem (15.54) “Symmetry of ↓”: x ↓ y = y ↓ x Proof: x ↓ y = y ↓ x ≡⟨ “Indirect Equality from below” ⟩ ∀ z • z ≤ x ↓ y ≡ z ≤ y ↓ x ≡⟨ Subproof for `∀ z • z ≤ x ↓ y ≡ z ≤ y ↓ x`: For any `z`: z ≤ x ↓ y ≡⟨ “Definition of ↓” ⟩ z ≤ x ∧ z ≤ y ≡⟨ “Symmetry of ∧” ⟩ z ≤ y ∧ z ≤ x ≡⟨ “Definition of ↓” ⟩ z ≤ y ↓ x ⟩ true
Slight Sweetener
Theorem (15.54) “Symmetry of ↓”: x ↓ y = y ↓ x Proof: Using “Indirect Equality from below”: Subproof for `∀ z • z ≤ x ↓ y ≡ z ≤ y ↓ x`: For any `z`: z ≤ x ↓ y ≡⟨ “Definition of ↓” ⟩ z ≤ x ∧ z ≤ y ≡⟨ “Symmetry of ∧” ⟩ z ≤ y ∧ z ≤ x ≡⟨ “Definition of ↓” ⟩ z ≤ y ↓ x
The syntactic sugar makes the proof easier to write and easier to read & understand.
Mutual Implication
Sometimes we have to prove p ≡ q
and the sides are sufficiently different that we are unable
to massage one of them so as to transform it to the other. In such situations, we appeal to
Theorem “Mutual implication”: p ≡ q ≡ (p ⇒ q) ∧ (q ⇒ p)
Two examples follow,
Theorem: a = b ≡ (∀ z • z ≤ a ≡ z ≤ b) Proof: Using “Mutual implication”: Subproof for `a = b ⇒ (∀ z • z ≤ a ≡ z ≤ b)`: Assuming `a = b`: For any `z`: By Assumption `a = b` Subproof for `(∀ z • z ≤ a ≡ z ≤ b) ⇒ a = b`: Assuming “A” `(∀ z • z ≤ a ≡ z ≤ b)`: a = b ≡⟨ “Antisymmetry of ≤” ⟩ a ≤ b ∧ b ≤ a ≡⟨ Assumption “A” ⟩ a ≤ a ∧ b ≤ b ≡⟨ “Reflexivity of ≤”, “Idempotency of ∧” ⟩ true
(15.44A) “Trichotomy — A”
Theorem: a < b ≡ a = b ≡ a > b Proof: Using “Mutual implication”: Subproof for `a = b ⇒ (a < b ≡ a > b)`: Assuming `a = b`: a < b ≡⟨ “Converse of <”, Assumption `a = b` ⟩ a > b Subproof for `(a < b ≡ a > b) ⇒ a = b`: a < b ≡ a > b ≡⟨ “Definition of <”, “Definition of >” ⟩ pos (b - a) ≡ pos (a - b) ≡⟨ (15.17), (15.19), “Subtraction” ⟩ pos (b - a) ≡ pos (- (b - a)) ⇒⟨ (15.33c) ⟩ b - a = 0 ≡⟨ “Cancellation of +” ⟩ b - a + a = 0 + a ≡⟨ “Identity of +”, “Subtraction”, “Unary minus” ⟩ a = b