Zulip Chat Archive
Stream: general
Topic: Failure to identify two types
Heather Macbeth (Feb 08 2021 at 06:37):
I'm having a problem where Lean can figure out that an object is of type {A // A.det = 1}
, but not recognize it as an object of type special_linear_group
, even though that is precisely the definition (docs#special_linear_group).
Apologies for the long example. The problem seems to turn up only after I've defined a coercion
has_coe (special_linear_group n ℤ) (special_linear_group n R)
(you'll see that a similar example phrased without this coercion typechecks). So maybe this is a bad coercion (... ambiguity between this coercion and the subtype coercion?).
import linear_algebra.special_linear_group
import data.matrix.notation
open matrix
variables {n : Type*} [decidable_eq n] [fintype n]
variables {R : Type*} [comm_ring R] {S : Type*} [comm_ring S]
/-- A ring homomorphism from `S` to `R` induces a group homomorphism from
`special_linear_group n S` to `special_linear_group n R`. -/
def ring_hom.map_special_linear_group (f : S →+* R) :
(special_linear_group n S) →* (special_linear_group n R) :=
{ to_fun := λ g, ⟨f.map_matrix g, by rw ← matrix.ring_hom.map_det; simp [g.2]⟩,
map_one' := by simpa,
map_mul' := λ x y, by simpa }
variables {a : ℕ} (M : matrix (fin a) (fin a.succ) ℤ) (v : (fin a.succ) → ℤ)
(hM : det (vec_cons v M) = 1)
/- This typechecks! -/
example : (int.cast_ring_hom R).map_special_linear_group ⟨vec_cons v M, hM⟩ = 1 :=
sorry
/-- The coercion homomorphism from `ℤ` to `R` induces a group homomorphism from
`special_linear_group n ℤ` to `special_linear_group n R`. -/
instance : has_coe (special_linear_group n ℤ) (special_linear_group n R) :=
⟨(int.cast_ring_hom R).map_special_linear_group⟩
/- This doesn't typecheck!
invalid type ascription, term has type
{A // A.det = 1} : Type
but is expected to have type
special_linear_group (fin a.succ) R : Type u_2
-/
example :
((⟨vec_cons v M, hM⟩ : special_linear_group (fin a.succ) ℤ) : special_linear_group (fin a.succ) R)
= 1 :=
sorry
Anne Baanen (Feb 08 2021 at 09:50):
I think the : Type
versus : Type u_2
is causing the error. Let me see...
Anne Baanen (Feb 08 2021 at 09:51):
This works:
example :
@coe (special_linear_group (fin a.succ) ℤ) _ _ ⟨vec_cons v M, hM⟩ = (1 : special_linear_group (fin a.succ) R) :=
sorry
Anne Baanen (Feb 08 2021 at 09:56):
Another issue is the has_coe
, which should be has_coe_t
to avoid looping:
/-- The coercion homomorphism from `ℤ` to `R` induces a group homomorphism from
`special_linear_group n ℤ` to `special_linear_group n R`. -/
instance : has_coe_t (special_linear_group n ℤ) (special_linear_group n R) :=
⟨(int.cast_ring_hom R).map_special_linear_group⟩
Anne Baanen (Feb 08 2021 at 09:58):
Aha! Looks like special_linear_group _ ℤ
is unfolded before the coercion is inserted, and then the system can't find a coercion {A // A.det = (1 : ℤ)} → special_linear_group (fin a.succ) R
. If we use show
instead of type ascription, the type doesn't get unfolded and it works:
import linear_algebra.special_linear_group
import data.matrix.notation
open matrix
variables {n : Type*} [decidable_eq n] [fintype n]
variables {R : Type*} [comm_ring R] {S : Type*} [comm_ring S]
/-- A ring homomorphism from `S` to `R` induces a group homomorphism from
`special_linear_group n S` to `special_linear_group n R`. -/
def ring_hom.map_special_linear_group (f : S →+* R) :
(special_linear_group n S) →* (special_linear_group n R) :=
{ to_fun := λ g, ⟨f.map_matrix g, by rw ← matrix.ring_hom.map_det; simp [g.2]⟩,
map_one' := by simpa,
map_mul' := λ x y, by simpa }
variables {a : ℕ} (M : matrix (fin a) (fin a.succ) ℤ) (v : (fin a.succ) → ℤ)
(hM : det (vec_cons v M) = 1)
/- This typechecks! -/
example : (int.cast_ring_hom R).map_special_linear_group ⟨vec_cons v M, hM⟩ = 1 :=
sorry
/-- The coercion homomorphism from `ℤ` to `R` induces a group homomorphism from
`special_linear_group n ℤ` to `special_linear_group n R`. -/
instance : has_coe_t (special_linear_group n ℤ) (special_linear_group n R) :=
⟨(int.cast_ring_hom R).map_special_linear_group⟩
example :
((show special_linear_group (fin a.succ) ℤ, from ⟨vec_cons v M, hM⟩) : special_linear_group (fin a.succ) R)
= 1 :=
sorry
Kevin Buzzard (Feb 08 2021 at 10:23):
I used to think that if X : A
then (X : B)
meant "please coerce X to type B and then continue", but it actually means "oh, while we're here, please check that it makes sense to consider X as having type B". If A and B are not defeq but there's a coercion from A to B then this coercion will happen, but if A and B are defeq then my impression is that it could well happen that Lean just checks that (X : B)
makes sense but then keeps considering X
as having type A
.
Kevin Buzzard (Feb 08 2021 at 10:24):
def a : ℕ := 37
#check (a : ℤ) -- ↑a : ℤ
def newnat := ℕ
#check (a : newnat) -- a : ℕ
Kevin Buzzard (Feb 08 2021 at 10:25):
Thanks Heather and Anne! I had never understood why "sometimes (X : B) works and sometimes it doesn't" -- maybe the issue is simply whether there is a non-trivial coercion or whether it's a defeq thing. I had seen it failing in the past. To be quite frank I wish it always meant "OK now X has type B", I think this show B, from X
idiom is a workaround but it does look weird. Whyever would I want (X : B)
to mean anything other than "yes I mean X has type B"?
Kevin Buzzard (Feb 08 2021 at 10:28):
I've never understood has_coe_t
either, but that's another story :-)
Kevin Buzzard (Feb 08 2021 at 10:32):
#check (⟨vec_cons v M, hM⟩ : special_linear_group (fin a.succ) ℤ) -- ⟨vec_cons v M, hM⟩ : {A // A.det = 1}
Rob Lewis (Feb 08 2021 at 10:36):
(X : B)
is just a hint for the elaborator. The : B
doesn't show up in the resulting term at all. The type of this term will be whatever Lean infers as the type of the elaborated X
. On the other hand, the show ...
annotation does appear in the elaborated term.
Kevin Buzzard (Feb 08 2021 at 10:36):
def constructor_with_right_type (A : matrix n n R) (hA : A.det = 1) : special_linear_group n R :=
⟨A, hA⟩
#check constructor_with_right_type (vec_cons v M) hM -- special_linear_group (fin a.succ) ℤ
example :
((constructor_with_right_type (vec_cons v M) hM : special_linear_group (fin a.succ) ℤ) : special_linear_group (fin a.succ) R)
= 1 :=
sorry
Kevin Buzzard (Feb 08 2021 at 10:37):
But if B is not defeq to what the actual type of X is, then a coercion is inserted, so the notation really does change the term in that case.
Kevin Buzzard (Feb 08 2021 at 10:39):
All these little tricks which one picks up over the years -- and with Lean 4 some will be wrong, some will still work, and we'll need to pick up a bunch of new ones.
Kevin Buzzard (Feb 08 2021 at 10:40):
Presumably in Lean 4 I'll be able to write a macro to get (X : B) to mean (show B, from X), which is the thing which I think I've always wanted it to mean (and which Heather wanted it to mean above).
Sebastien Gouezel (Feb 08 2021 at 10:40):
Another trick that works is to insert an id
, as in:
example :
(((id ⟨vec_cons v M, hM⟩) : special_linear_group (fin a.succ) ℤ) : special_linear_group (fin a.succ) R)
= 1 :=
Kevin Buzzard (Feb 08 2021 at 10:40):
again looks ugly :-/
Kevin Buzzard (Feb 08 2021 at 10:40):
but also good to know!
Rob Lewis (Feb 08 2021 at 10:41):
Kevin Buzzard said:
But if B is not defeq to what the actual type of X is, then a coercion is inserted, so the notation really does change the term in that case.
Well, kind of. (X : B)
is a preterm (unelaborated term). Elaboration "changes" the preterm into a term, regardless of whether there's a coercion or not. Elaborated X
is never the same as unelaborated X
.
Sebastien Gouezel (Feb 08 2021 at 10:41):
Don't ask me why it works, by the way. You don't understand Lean3, you just get used to it :-)
Kevin Buzzard (Feb 08 2021 at 10:41):
I guess the id trick works because id is id {alpha} and the elaboration hint tells Lean what alpha to use.
Sebastien Gouezel (Feb 08 2021 at 10:42):
Yes, it builds stuff from the outside, so it chooses the type of id
before it chooses the type of ⟨vec_cons v M, hM⟩
.
Rob Lewis (Feb 08 2021 at 10:43):
I think the show B, from X
macro expands to something like @id B X
, right?
Kevin Buzzard (Feb 08 2021 at 10:43):
I love it when someone asks just the right question :-)
Heather Macbeth (Feb 08 2021 at 18:54):
Thank you very much, @Anne Baanen and all! You never understand something until it's bit you ... I'd seen people use these show ... from ...
and id ... : ...
idioms before but without quite internalizing the use case. The whole discussion was very instructive, for example this:
Kevin Buzzard said:
I used to think that if
X : A
then(X : B)
meant "please coerce X to type B and then continue", but it actually means "oh, while we're here, please check that it makes sense to consider X as having type B". If A and B are not defeq but there's a coercion from A to B then this coercion will happen, but if A and B are defeq then my impression is that it could well happen that Lean just checks that(X : B)
makes sense but then keeps consideringX
as having typeA
.
Last updated: Dec 20 2023 at 11:08 UTC