Zulip Chat Archive

Stream: new members

Topic: Rewriting function definition


Aron Erben (May 24 2022 at 11:55):

Hello, I would like to rewrite a function definition with a specified target. Here is an MWE:

import data.matrix.basic
import data.real.basic
localized "infixl ` ⬝ `:75 := matrix.mul" in matrix

variables
  {n m : }
  {X : matrix (fin n) (fin m) }
  {Y : matrix (fin m) (fin n) }

lemma matrix_mul_mul : X  Y  X = X
:=
begin
  -- This should rewrite the first ⬝, not the second one!
  rw matrix.mul,
end

Currently, the rw matrix.mul rewrites Y ⬝ X, but I would like it to rewrite X ⬝ Y. I had the following two ideas, neither of which worked:

  1. Adding an argument to the rewrite to indicate what should be rewritten:
begin
  -- This should rewrite the first ⬝, not the second one!
  rw matrix.mul X _,
end

This, unsurprisingly, doesn't work, I assume because matrix.mul is a function definition and not a theorem/lemma. So it just takes the X as the first argument.

  1. Using nth_rewrite.
begin
  -- This should rewrite the first ⬝, not the second one!
  -- 1 should do the 2nd rewrite, as 0 does the 1st
  nth_rewrite 1 matrix.mul,
end

Which gives the following error:

31:3: failed: not enough rewrites found
state:
n m : ,
X : matrix (fin n) (fin m) ,
Y : matrix (fin m) (fin n) 
 X  Y  X = X

This also doesn't entirely make sense to me, as it should be able to do 2 rewrites.
Is there a way to do this?

Eric Rodriguez (May 24 2022 at 11:58):

Note that infixl is telling Lean that matrix.mul associates on the left. so the term is actually (X.mul Y).mul X, not X.mul (Y.mul X). you can see this with the option pp.notation (specifically the line set_option pp.notation false before the theorem statement, as a debugging option)

Eric Rodriguez (May 24 2022 at 11:59):

but for me, this does rewrite X * Y already, as you have Y * X terms left in the definition

Aron Erben (May 24 2022 at 12:01):

Eric Rodriguez said:

but for me, this does rewrite X * Y already, as you have Y * X terms left in the definition

My context after rw matrix.mul (without pp.notation turned off) is:

n m : ,
X : matrix (fin n) (fin m) ,
Y : matrix (fin m) (fin n) 
 (λ (i : fin n) (k : fin m), matrix.dot_product (λ (j : fin n), (X  Y) i j) (λ (j : fin n), X j k)) = X

So, for me, there is still (X ⬝ Y), is that not the case for you?

Eric Rodriguez (May 24 2022 at 12:02):

not at all:

n m : ,
X : matrix (fin n) (fin m) ,
Y : matrix (fin m) (fin n) 
 (λ (i : fin n) (k : fin m), matrix.dot_product (λ (j : fin m), X i j) (λ (j : fin m), (Y  X) j k)) = X

are you on the latest mathlib?

Aron Erben (May 24 2022 at 12:08):

Now I am on the newest version, but I'm still getting the same context as before...

Regardless, I would still like to be able to select which mul is being rewritten, so in your case I would like Y ⬝ X to be rewritten...

Eric Rodriguez (May 24 2022 at 12:09):

but note that Y * X doesn't exist! if the term is (X.mul Y).mul X, there is no Y.mul X in there. You first have to check that multiplication is associative, and then you can do that

Eric Rodriguez (May 24 2022 at 12:10):

(and of course it is, and the correct theorem is docs#matrix.mul_assoc)

Aron Erben (May 24 2022 at 12:12):

Eric Rodriguez said:

but note that Y * X doesn't exist! if the term is (X.mul Y).mul X, there is no Y.mul X in there. You first have to check that multiplication is associative, and then you can do that

Oh dangit, you're completely right... I've been doing this for all the other theorems, but completely missed it here (probably, as you pointed out, because of infixl). Thanks a lot!

Aron Erben (May 24 2022 at 12:27):

Ah, I've misunderstood my initial problem. It's not Y.mul X I would like to have rewritten but (X.mul Y).mul X (the outer mul). So I still have this problem in my non-MWE unfortunately... In general, I would just like to know how I can control which rewrite happens when I'm rewriting function definitions.

Eric Rodriguez (May 24 2022 at 12:35):

I'm personally a bit surprised that nth_rewrite doesn't work, and the docs#matrix.mul_apply methods have the arguments implicit, so you can't really do that either without a lot of _s

Eric Rodriguez (May 24 2022 at 12:36):

can you try rw [...] { occs := occurrences.pos [x] } and try messing with x and see if that works?

Eric Rodriguez (May 24 2022 at 12:36):

you can also try use conv to drill down to what you want


Last updated: Dec 20 2023 at 11:08 UTC