Zulip Chat Archive
Stream: general
Topic: Concerns about `invertible` class
Oliver Nash (Jun 20 2020 at 15:29):
I'm looking guidance on when it is a good idea to use the invertible
class. I am concerned that naive usage can set things up for the dreaded motive is not type correct
error.
Oliver Nash (Jun 20 2020 at 15:30):
Specifically the "function" defined by "a ↦ ⅟a" pulls data from a typeclass instance and so is not really a function. I encountered this a couple of hours ago when I was considering modifying matrix.nonsing_inv
to use invertible
so that it was not necessary for the base type to carry a has_inv
instance.
Oliver Nash (Jun 20 2020 at 15:31):
Here is the example:
import linear_algebra.nonsingular_inverse
import algebra.invertible
universes u v
namespace matrix
open_locale matrix
section bad_invertible
variables {n : Type u} [fintype n] [decidable_eq n]
variables {R : Type v} [comm_ring R]
variables (A : matrix n n R) [invertible A.det]
variables (B : matrix n n R) [invertible B.det]
/-- Bad definition: pulls data from a typeclass instance. -/
def nonsing_inv' : matrix n n R := ⅟(A.det) • adjugate A
lemma inverses_are_unique (h : A = B) :
A.nonsing_inv' = B.nonsing_inv' :=
begin
rw h, -- rewrite tactic failed, motive is not type correct
end
end bad_invertible
end matrix
Oliver Nash (Jun 20 2020 at 15:34):
Now the above is not a problem in the sense that inverses_are_unique
is provable by other means but it still seems like nonsing_inv'
would be a pretty horrible definition to make.
Oliver Nash (Jun 20 2020 at 15:35):
So I had a quick look for usage of invertible
and I see that equivariant_projection
in representation_theory.maschke
uses it and, I think, will one day trigger the motive is not type correct
error.
Oliver Nash (Jun 20 2020 at 15:37):
Am I missing the obvious and somehow this is all fine? Do others feel like invertible
should come with guidance to stop it being a footgun?
Jalex Stark (Jun 20 2020 at 15:38):
Oliver Nash said:
Specifically the "function" defined by "a ↦ ⅟a" pulls data from a typeclass instance and so is not really a function.
i'm confused. isn't *
a function which takes data from a typeclass, namely has_mul
? does your objection also apply to this?
Oliver Nash (Jun 20 2020 at 15:38):
That same thought is in the back of my mind. I haven't bottomed out on it yet.
Jalex Stark (Jun 20 2020 at 15:39):
what do you want to be able to do with invertible
that you can't "because it's not really a function"? (probably i will know the answer to this question after poking at your example for a few minutes)
Sebastien Gouezel (Jun 20 2020 at 15:39):
I don't think this is the indended use of the invertible
typeclass: it is only there to provide (once and for all) invertibility of a few fixed elements in a ring. If you want to discuss invertibility of variables or complicated objects, is_unit
should be used instead (if I understand correctly what the doc in invertible.lean
says).
Oliver Nash (Jun 20 2020 at 15:40):
Aha, so perhaps I should just be reading the docs!
Oliver Nash (Jun 20 2020 at 15:41):
OK I see that now. I still think the fact that it has crept into equivariant_projection
indicates there is potential for future problems.
Reid Barton (Jun 20 2020 at 15:41):
I think the main difference with has_mul
(and this also goes for other things like is_ring_hom
) is that invertible
has a parameter which is a value, for which you are likely to want to reason about its equality to other values, while has_mul
takes a type
Oliver Nash (Jun 20 2020 at 15:49):
Jalex Stark said:
what do you want to be able to do with
invertible
that you can't "because it's not really a function"? (probably i will know the answer to this question after poking at your example for a few minutes)
Sorry I missed this. The rw h
in my example is the best example I can give.
In any case, I'm happy to leave this now. I recognise that there is already documentation not to use invertible
in the way that I did in my example.
Yury G. Kudryashov (Jun 20 2020 at 16:50):
As far as I understand, non-typeclass version of ⅟(A.det)
is def nonsing_inv' (A : matrix n n R) {u : units R} (hu : (u : R) = A.det) := ((u⁻¹ : units R) : R) • adjugate A
Oliver Nash (Jun 20 2020 at 18:14):
Thanks @Yury G. Kudryashov I think that's exactly what Sebastian was hinting me toward.
Yury G. Kudryashov (Jun 20 2020 at 18:16):
The only difference between these two approaches is that u : units R
shows the problem explicitly. Note that while rw
doesn't work dsimp [nonsing_inv']; simp only [h]
should work.
Oliver Nash (Jun 20 2020 at 18:17):
Yes absolutely, I see that.
Oliver Nash (Jun 20 2020 at 18:18):
The fact that hu
appears an explicit argument makes it clear that there is additional data to handle.
Oliver Nash (Jun 20 2020 at 18:19):
I have a little time now so I might see if it looks like it is worth changing the definition of matrix.nonsing_inv
along these lines. It would suit something else I'd like to do.
Yury G. Kudryashov (Jun 20 2020 at 18:21):
What's wrong with invertible
definition + subsingleton
instance? AFAIR, this should be enough for simp
to be able to rewrite h : A = B
.
Oliver Nash (Jun 20 2020 at 18:22):
Perhaps nothing: I don't know anything about subsingleton
s!
Yury G. Kudryashov (Jun 20 2020 at 18:23):
[subsingleton α]
means that α
has at most one element.
Oliver Nash (Jun 20 2020 at 18:24):
I see, and from what you're saying simp
will be smart enough to make use of this. However would rw
still trigger the rewrite tactic failed, motive is not type correct
error?
Yury G. Kudryashov (Jun 20 2020 at 18:24):
AFAIR, simp
can unify two subsingleton
s automatically. If not, then @[congr] lemma nonsing_inv'_congr (h : A = B) : nonsing_inv' A = nonsing_inv' B
should help.
Yury G. Kudryashov (Jun 20 2020 at 18:25):
Yes, rw
won't work. For me the general rule is "if rw
or simp
doesn't work, try the other one".
Oliver Nash (Jun 20 2020 at 18:25):
Understood, this is really a great tutorial you are giving me. Thank you. I'm still reluctant to design something that will cause problems for rw
though. Do you think I'm being too conservative?
Oliver Nash (Jun 20 2020 at 18:27):
Admittedly I haven't tried it yet but the approach via unit
s seems more attractive.
Yury G. Kudryashov (Jun 20 2020 at 18:31):
How are you going to use this definition? If you want a user to explicitly prove that det A
is invertible, then (u : units R)
is a good approach. If you want Lean to automatically figure out that det A
is invertible, then inv_of
is better.
If you use (u : units R)
, then you'll need @[congr] lemma nonsing_inv'_congr {A B : matrix n n R} (h : A = B) {uA uB : units R} {hA : (uA : R) = det A} {hB : (uB : R) = det B} : nonsing_inv' A hA = nonsing_inv' B hB
.
Yury G. Kudryashov (Jun 20 2020 at 18:32):
This should help simp
go from nonsing_inv' A hA = nonsing_inv' B hB
to A = B
, not A = B
and uA = uB
.
Oliver Nash (Jun 20 2020 at 18:33):
I see, it's great to know that the congr
decorator can make Lean consume a proof that inverses are unique in this way.
Yury G. Kudryashov (Jun 20 2020 at 18:34):
Another question is whether you want it to be computable. If not, then you can use hA : is_unit (det A)
, and get u
from classical.choice
.
Oliver Nash (Jun 20 2020 at 18:34):
I don't care about computability.
Yury G. Kudryashov (Jun 20 2020 at 18:34):
Note that @[congr]
is used by simp
but not congr
and convert
.
Oliver Nash (Jun 20 2020 at 18:37):
I plan to have the user provide proof that A.det
is invertible so I guess I'll try the approach via unit
s. I guess the advantage of the approach via is_unit
over raw unit
is that the user need only provide a single argument?
Oliver Nash (Jun 20 2020 at 18:37):
Hmm, well I can imagine other differences.
Yury G. Kudryashov (Jun 20 2020 at 18:45):
The theory of units
has more simp
lemmas etc.
Oliver Nash (Jun 20 2020 at 18:46):
I did see that is_unit
is basically just a wrapper on top of it. I'm currently tinkering to see if I can get something sane with just unit
.
Yakov Pechersky (Jun 21 2020 at 04:28):
simp_rw will avoid the motive issue
Oliver Nash (Jun 22 2020 at 14:56):
I explored various approaches for nonsing_inv
and eventually settled on https://github.com/leanprover-community/mathlib/pull/3136
Last updated: Dec 20 2023 at 11:08 UTC