Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Try doing some basic maths questions in the Lean Theorem Prover. Functions, real numbers, equivalence relations and groups. Click on README.md and then on "Open in CoCalc with one click".
License: APACHE
The equation compiler and using_well_founded
To define functions and proofs recursively you can use the equation compiler, if you have a well founded relation on that type
For example the definition of gcd on naturals uses well founded recursion
Because < is a well founded relation on naturals, and because y % succ x < succ x
this recursive function is well_founded.
Whenever you use the equation compiler there will be a default well founded relation on the type being recursed on and the equation compiler will automatically attempt to prove the function is well founded.
When the equation compiler fails, there are three main causes.
It has failed to prove the required inequality.
It is not using the correct well founded relation.
A bug in the default tactic. (Often indicated by the message
nested exception message: tactic failed, there are no goals to be solved
, and solved by appendingusing_well_founded wf_tacs
.)
Proving required inequality
If we modify the gcd example above, by removing the have
, we get an error.
The error message has given us a goal, y % succ x < succ x
. Including a proof of this goal as part of our definition using have
removes the error.
Note that the have
must not be in tactics mode, i.e. inside any begin
end
. If you are in tactics mode, there is the option of putting the have
statement inside the exact statement, as in the following example.
order of arguments
Sometimes the default relation the equation compiler uses is not the correct one. For example swapping the order of x and y in the above example causes a failure
Now the error message is asking us to prove succ x < y
. This is because by default the equation compiler tries to recurse on the first argument. More precisely, the relation that the equation compiler tries to use in this example is on the type of pairs of natural numbers Σ' (a : ℕ), ℕ
, and it uses a lexicographical relation where the pair ⟨a, b⟩ ≺ ⟨c, d⟩
iff a < c ∨ (a = c ∧ b < d)
This situation can be resolved, either by changing the order of the arguments or by specifying a rel_tac
as decribed later in this doc.
Sometimes moving an argument outside of the equation compiler, can help the equation compiler prove a recursion is well_founded. For example the following proof from data.nat.prime
fails.
But moving the h
into a lambda after the :=
makes it work
This is because for some reason, in the first example, the equation compiler tries to use the always false relation.
Conjecture : this is because the type of h
depends on n
and the equation compiler can only synthesize useful relations on non dependent products
using_well_founded rel_tac
Sometimes you need to change the well founded relation to prove that a recursion is well founded. To do this you need a has_well_founded
instance. This is a structure with two fields, a relation and a proof that this relation is well founded. The easiest way to define a well founded relation is using a function to the natural numbers. For example on multisets the relation λ s t, card s < card t
is a well founded relation.
The following proof in data.multiset
uses this relation.
The final line tells the equation compiler to use this relation. It is not necessary to fully understand the final line to be able to use well_founded tactics. The most important part is ⟨_, measure_wf card⟩
This is the well_founded instance. measure_wf
is a proof that any relation generated from a function to the natural numbers, i.e. for a function f : α → ℕ
, the relation λ x y, f x < f y
. The underscore is a placeholder for the relation, as it can be inferred from the type of the proof. Note that the well founded relation must be on a psigma
type corresponding to the product of the types of the arguments after the vertical bar, if there are multiple arguments after the vertical bar.
In the gcd example the psigma
type is Σ' (a : ℕ), ℕ
. In order to solve the problem in the example where the order of the arguments was flipped, you could define a well founded relation on Σ' (a : ℕ), ℕ
using the function psigma.snd
, the function giving the second element of the pair, and then the error disappears.