Zulip Chat Archive
Stream: general
Topic: Notation for mul_vec and vec_mul
Alexander Bentkamp (Jun 10 2022 at 07:44):
What do you all think about introducing infix notations for matrix.mul_vec
and matrix.vec_mul
?
I am currently working on this lemma:
lemma schur_complement_eq' {A : matrix n n R} (hA : A.is_symm) [invertible A] :
(vec_mul (sum.elim x y) (from_blocks A B Bᵀ D)) ⬝ᵥ (sum.elim x y) =
vec_mul (x + (mul_vec (A⁻¹ ⬝ B) y)) A ⬝ᵥ (x + mul_vec (A⁻¹ ⬝ B) y) + vec_mul y (D - Bᵀ ⬝ A⁻¹ ⬝ B) ⬝ᵥ y :=
It is really hard to read without infix notation. I would propose something like this:
localized "infix ` ⊕ᵥ `:65 := sum.elim" in matrix
localized "infix ` ᵛ⬝ `:73 := vec_mul" in matrix
localized "infix ` ⬝ᵛ `:74 := mul_vec" in matrix
lemma schur_complement_eq {A : matrix n n R} (hA : A.is_symm) [invertible A] :
(x ⊕ᵥ y) ᵛ⬝ from_blocks A B Bᵀ D ⬝ᵥ (x ⊕ᵥ y) =
(x + A⁻¹ ⬝ B ⬝ᵛ y) ᵛ⬝ A ⬝ᵥ (x + A⁻¹ ⬝ B ⬝ᵛ y) + y ᵛ⬝ (D - Bᵀ ⬝ A⁻¹ ⬝ B) ⬝ᵥ y :=
Eric Wieser (Jun 10 2022 at 07:57):
I feel like if we go down that route we should change dot_product u v
to u ᵛ⬝ᵛ v
Eric Wieser (Jun 10 2022 at 07:58):
The other option would be a has_mat_mul
class and use ⬝
for all four operations
Alexander Bentkamp (Jun 10 2022 at 08:19):
⬝
for all of them would be amazing. What would be the best way to approach such a big refactoring?
Eric Wieser (Jun 10 2022 at 08:33):
I don't think the refactor will be all that big, although a danger with this change is that ![![1,2],![3,4]] ⬝ ![![1,2],![3,4]] = ![10, 20]
Eric Wieser (Jun 10 2022 at 08:34):
(because ![![...]]
creates a vector of vectors not a matrix)
Anne Baanen (Jun 10 2022 at 08:37):
Eric Wieser said:
I don't think the refactor will be all that big, although a danger with this change is that
![![1,2],![3,4]] ⬝ ![![1,2],![3,4]] = ![10, 20]
I believe it would not be a problem since we can require that the entries of the vector are non_unital_non_assoc_semiring
, and now we're applying has_mat_mul
to the entries
Eric Wieser (Jun 10 2022 at 08:42):
I don't understand that suggestion. The problem is that
![![1,2],![3,4]] ⬝ ![![1,2],![3,4]]
= dot_product ![![1,2],![3,4]] ![![1,2],![3,4]]
= ![1,2] * ![1,2] + ![3,4] * ![3,4]
= ![1,4] + ![9,16]
= ![10, 20]
Eric Wieser (Jun 10 2022 at 08:42):
docs#pi.non_unital_non_assoc_semiring
Eric Wieser (Jun 10 2022 at 08:43):
Arguably the real problem here is that we don't have notation that actually produces a matrix
Eric Wieser (Jun 10 2022 at 08:43):
![![1,2],![3,4]] * ![![1,2],![3,4]]
already fails to perform matrix multiplication
Eric Wieser (Jun 10 2022 at 08:44):
This has come up before, but I think the lean3 notation
command isn't powerful enough to allow a special !![1, 2; 3, 4]
notation
Eric Wieser (Jun 10 2022 at 08:45):
We could use a user_notation
, but then it would print as something like to_matrix ![![1,2],![3,4]]
.
Eric Wieser (Jun 10 2022 at 08:45):
Maybe thats ok though
Anne Baanen (Jun 10 2022 at 08:50):
Indeed, we can't put the notation on matrix
currently, or the instance isn't picked up.
import data.matrix.notation
class has_mat_mul (α β : Type*) (γ : out_param Type*) :=
(mat_mul : α → β → γ)
#print notation
infix `⬝`:75 := has_mat_mul.mat_mul
variables {m n o : Type*} {α β γ : Type*}
/-
-- Notation not found
instance matrix.has_mat_mul [non_unital_non_assoc_semiring α] [fintype n] :
has_mat_mul (matrix m n α) (matrix n o α) (matrix m o α) :=
⟨matrix.mul⟩
-/
instance matrix.has_mat_mul [non_unital_non_assoc_semiring α] [fintype n] :
has_mat_mul (m → n → α) (n → o → α) (m → o → α) :=
⟨matrix.mul⟩
@[priority 100]
instance matrix.has_dot_product [non_unital_non_assoc_semiring α] [fintype n] :
has_mat_mul (n → α) (n → α) α :=
⟨matrix.dot_product⟩
instance matrix.has_mat_mul_right [non_unital_non_assoc_semiring α] [fintype n] :
has_mat_mul (matrix m n α) (n → α) (m → α) :=
⟨matrix.mul_vec⟩
instance matrix.has_mat_mul_left [non_unital_non_assoc_semiring α] [fintype m] :
has_mat_mul (m → α) (matrix m n α) (n → α) :=
⟨matrix.vec_mul⟩
#eval ((![![1,2],![3,4]]) ⬝ (![![1,2],![3,4]]))
#eval ((![![1,2],![3,4]] : matrix (fin 2) (fin 2) ℕ) ⬝ (![![1,2],![3,4]] : matrix (fin 2) (fin 2) ℕ))
Eric Wieser (Jun 10 2022 at 09:13):
(x : A) * (x : A)
where x : X
is not enough to tell lean to use the multiplication on A
Alexander Bentkamp (Jun 10 2022 at 09:14):
Ok, but what's the problem with the instance on m → n → α
as in Anne's code above?
Eric Wieser (Jun 10 2022 at 09:15):
I think it's a bad idea to ever spell matrix m n a
in that way
Eric Wieser (Jun 10 2022 at 09:15):
It feels as bad as spelling opposite a
as a
or multiplicative a
as a
Eric Wieser (Jun 10 2022 at 09:17):
This does the right thing:
#eval (show matrix (fin 2) (fin 2) ℕ, from ![![1,2],![3,4]])
⬝ (show matrix (fin 2) (fin 2) ℕ, from ![![1,2],![3,4]])
Eric Wieser (Jun 10 2022 at 09:18):
foo (x : A)
where x : X
and def A := X
means "parse x
as an A
, but then call foo
with x
as an X
"
Eric Wieser (Jun 10 2022 at 09:20):
Here's a nicer spelling:
def to_matrix : (m → n → α) ≃ matrix m n α := equiv.refl _
@[simp] lemma to_matrix_apply (f : m → n → α) (i j) : to_matrix f i j = f i j := rfl
@[simp] lemma to_matrix_symm_apply (f : matrix m n α) (i j) : to_matrix.symm f i j = f i j := rfl
notation `!ₘ[` l:(foldr `, ` (h t, matrix.vec_cons h t) matrix.vec_empty `]`) := to_matrix l
#eval !ₘ[![1,2],![3,4]] ⬝ !ₘ[![1,2],![3,4]] -- does the right thing
Eric Wieser (Jun 10 2022 at 09:51):
I implemented the user_notation
in #14665
Eric Wieser (Jul 13 2022 at 12:26):
Now that !![1, 2; 3, 4]
notation is merged, we could consider revisiting class has_mat_mul
Wrenna Robson (Jul 13 2022 at 15:37):
What are the operations it would apply to (and what is that symbol - is it different from the smul symbol?)
Alexander Bentkamp (Jul 14 2022 at 09:08):
The symbol is \cdot
. It's different from the smul symbol. The dot is a bit smaller.
Alexander Bentkamp (Jul 14 2022 at 09:08):
We could use it for matrix.mul
, where it is used already, for matrix.mul_vec
, matrix.vec_mul
, and matrix.dot_product
.
Wrenna Robson (Jul 15 2022 at 10:01):
And possibly matrix.vec_mul_vec
?
Wrenna Robson (Jul 15 2022 at 10:02):
Though that may not work with matrix.dot_product
.
Eric Wieser (Jul 15 2022 at 12:03):
We don't need notation for that, you can spell it col v ⬝ row w
Eric Wieser (Jul 15 2022 at 12:03):
You don't have that option for the others, because the result type ends up a matrix not a vector
Wrenna Robson (Jul 15 2022 at 13:08):
Ah, so you can.
Eric Wieser (Jul 21 2022 at 10:56):
I tried this in #15585, but it doesn't work as well as I'd hoped because lean's overloaded notations:
- Doesn't seem to work with
local
oropen_locale
- Unfolds type synonyms
Alexander Bentkamp (Jul 21 2022 at 12:35):
I thought you planned to create a type class has_mat_mul
. Why do you use overloaded notations now?
Eric Wieser (Jul 21 2022 at 12:44):
The typeclass had its own problems:
- The
out_param
stuff doesn't always help, you still can't write things likev ⬝ 0
- You now have to change everything to be stated about
has_mat_mul.mul
instead ofdot_product
etc. This is a lot more unwieldy if the notation is not enabled;
Alexander Bentkamp (Jul 21 2022 at 13:08):
I see. But I feel that the type class approach works quite well for +
, *
, •
, etc. The fact that we can't write v ⋅ 0
doesn't shock me. Somehow we need to tell Lean what 0
we mean. You probably can't write a • 0
either, right?
Eric Wieser (Jul 21 2022 at 13:25):
a • 0
isn't quite as bad because lean knows the result type is the same type as the 0
Alexander Bentkamp (Jul 21 2022 at 13:35):
Ah, ok, right. ⋅
would be extremely ambiguous about what comes in and what comes out...
Alexander Bentkamp (Jul 21 2022 at 13:49):
How about this: we add a typeclass has_mat_mul
using ⋅
and in addition localized notations ᵥ⋅ₘ
, ᵥ⋅ₘ
, ₘ⋅ₘ
, ᵥ⋅ᵥ
that abbreviate has_mat_mul
with the appropriate type class instance specified. So in most cases, you'll be able to use ⋅
. Whenever Lean doesn't understand what's going on because it's not clear what types the arguments have, you can use the more specific notation.
It would be nice if the output window would show ⋅
whenever possible, though.
Last updated: Dec 20 2023 at 11:08 UTC