A tactic for normalizing casts inside expressions #
This tactic normalizes casts inside expressions. It can be thought of as a call to the simplifier with a specific set of lemmas to move casts upwards in the expression. It has special handling of numerals and a simple heuristic to help moving casts "past" binary operators. Contrary to simp, it should be safe to use as a non-terminating tactic.
The algorithm implemented here is described in the paper https://lean-forward.github.io/norm_cast/norm_cast.pdf.
Important definitions #
- elim : norm_cast.label
- move : norm_cast.label
- squash : norm_cast.label
label
is a type used to classify norm_cast
lemmas.
- elim lemma: LHS has 0 head coes and ≥ 1 internal coe
- move lemma: LHS has 1 head coe and 0 internal coes, RHS has 0 head coes and ≥ 1 internal coes
- squash lemma: LHS has ≥ 1 head coes and 0 internal coes, RHS has fewer head coes
Instances for norm_cast.label
- norm_cast.label.has_sizeof_inst
- norm_cast.label.has_reflect
- norm_cast.label.inhabited
- norm_cast.label.has_to_string
- norm_cast.label.has_repr
- norm_cast.label.has_to_format
Convert label
into string
.
Equations
- norm_cast.label.squash.to_string = "squash"
- norm_cast.label.move.to_string = "move"
- norm_cast.label.elim.to_string = "elim"
Equations
Equations
Convert string
into label
.
The following auxiliary functions are used to handle numerals.
The norm_cast
family of tactics is used to normalize casts inside expressions.
It is basically a simp tactic with a specific set of lemmas to move casts
upwards in the expression.
Therefore it can be used more safely as a non-terminating tactic.
It also has special handling of numerals.
For instance, given an assumption
a b : ℤ
h : ↑a + ↑b < (10 : ℚ)
writing norm_cast at h
will turn h
into
h : a + b < 10
You can also use exact_mod_cast
, apply_mod_cast
, rw_mod_cast
or assumption_mod_cast
.
Writing exact_mod_cast h
and apply_mod_cast h
will normalize the goal and
h
before using exact h
or apply h
.
Writing assumption_mod_cast
will normalize the goal and for every
expression h
in the context it will try to normalize h
and use
exact h
.
rw_mod_cast
acts like the rw
tactic but it applies norm_cast
between steps.
push_cast
rewrites the expression to move casts toward the leaf nodes.
This uses norm_cast
lemmas in the forward direction.
For example, ↑(a + b)
will be written to ↑a + ↑b
.
It is equivalent to simp only with push_cast
.
It can also be used at hypotheses with push_cast at h
and with extra simp lemmas with push_cast [int.add_zero]
.
example (a b : ℕ) (h1 : ((a + b : ℕ) : ℤ) = 10) (h2 : ((a + b + 0 : ℕ) : ℤ) = 10) :
((a + b : ℕ) : ℤ) = 10 :=
begin
push_cast,
push_cast at h1,
push_cast [int.add_zero] at h2,
end
The implementation and behavior of the norm_cast
family is described in detail at
https://lean-forward.github.io/norm_cast/norm_cast.pdf.
The norm_cast
attribute should be given to lemmas that describe the
behaviour of a coercion in regard to an operator, a relation, or a particular
function.
It only concerns equality or iff lemmas involving ↑
, ⇑
and ↥
, describing the behavior of
the coercion functions.
It does not apply to the explicit functions that define the coercions.
Examples:
@[norm_cast] theorem coe_nat_inj' {m n : ℕ} : (↑m : ℤ) = ↑n ↔ m = n
@[norm_cast] theorem coe_int_denom (n : ℤ) : (n : ℚ).denom = 1
@[norm_cast] theorem cast_id : ∀ n : ℚ, ↑n = n
@[norm_cast] theorem coe_nat_add (m n : ℕ) : (↑(m + n) : ℤ) = ↑m + ↑n
@[norm_cast] theorem cast_sub [add_group α] [has_one α] {m n} (h : m ≤ n) :
((n - m : ℕ) : α) = n - m
@[norm_cast] theorem coe_nat_bit0 (n : ℕ) : (↑(bit0 n) : ℤ) = bit0 ↑n
@[norm_cast] theorem cast_coe_nat (n : ℕ) : ((n : ℤ) : α) = n
@[norm_cast] theorem cast_one : ((1 : ℚ) : α) = 1
Lemmas tagged with @[norm_cast]
are classified into three categories: move
, elim
, and
squash
. They are classified roughly as follows:
- elim lemma: LHS has 0 head coes and ≥ 1 internal coe
- move lemma: LHS has 1 head coe and 0 internal coes, RHS has 0 head coes and ≥ 1 internal coes
- squash lemma: LHS has ≥ 1 head coes and 0 internal coes, RHS has fewer head coes
norm_cast
uses move
and elim
lemmas to factor coercions toward the root of an expression
and to cancel them from both sides of an equation or relation. It uses squash
lemmas to clean
up the result.
Occasionally you may want to override the automatic classification.
You can do this by giving an optional elim
, move
, or squash
parameter to the attribute.
@[simp, norm_cast elim] lemma nat_cast_re (n : ℕ) : (n : ℂ).re = n :=
by rw [← of_real_nat_cast, of_real_re]
Don't do this unless you understand what you are doing.
A full description of the tactic, and the use of each lemma category, can be found at https://lean-forward.github.io/norm_cast/norm_cast.pdf.