Zulip Chat Archive

Stream: Is there code for X?

Topic: multiplying a matrix and a vector in Euclidean space


David Renshaw (Jun 16 2025 at 14:15):

import Mathlib.Analysis.InnerProductSpace.PiL2

open scoped Matrix

def I : Matrix (Fin 3) (Fin 3)  := !![1,0,0; 0,1,0; 0,0,1]

def v : EuclideanSpace  (Fin 3) := ![3,4,5]
def w : EuclideanSpace  (Fin 3) := ![6,7,8]

-- To my surprise, I get a type error on the following:
#check w + I *ᵥ v
--failed to synthesize
--  HAdd (EuclideanSpace ℚ (Fin 3)) (Fin 3 → ℚ) ?m.1201

-- The problem seems to be that matrix multiplication puts us in `Fin 3 → ℚ`
-- rather than `EuclideanSpace ℚ (Fin 3)`:
#check I *ᵥ v
-- I *ᵥ v : Fin 3 → ℚ

-- Even casting back does not seem to help:
#check ((I *ᵥ v) : EuclideanSpace  (Fin 3))
-- I *ᵥ v : Fin 3 → ℚ

-- I can use `WithLp.equiv`, but that's ugly and noncomputable:
#check w + (WithLp.equiv _ _).symm (I *ᵥ v)
-- w + (WithLp.equiv 2 (Fin 3 → ℚ)).symm (I *ᵥ v) : EuclideanSpace ℚ (Fin 3)

David Renshaw (Jun 16 2025 at 14:15):

^ Is there a nice way to apply a matrix to a vector in Euclidean space and get back a vector in Euclidean space?

David Renshaw (Jun 16 2025 at 14:17):

(I'm aware that WithLp has known issues with defeq abuse that are being worked on: https://leanprover.zulipchat.com/#narrow/channel/345428-mathlib-reviewers/topic/.2324261.20WithLp.20refactoring/near/522889153 )

David Renshaw (Jun 16 2025 at 16:53):

It seems that I can use the id function to cast, but I can't use ( · : EuclideanSpace ℚ (Fin 3)):

import Mathlib.Analysis.InnerProductSpace.PiL2

open scoped Matrix

def I : Matrix (Fin 3) (Fin 3)  := !![1,0,0; 0,1,0; 0,0,1]

def v : EuclideanSpace  (Fin 3) := ![3,4,5]
def w : EuclideanSpace  (Fin 3) := ![6,7,8]

-- This works:
#check w + (id (α := EuclideanSpace  (Fin 3)) (I *ᵥ v))

-- This does not work:
#check w + ((I *ᵥ v) : EuclideanSpace  (Fin 3))
-- failed to synthesize
--  HAdd (EuclideanSpace ℚ (Fin 3)) (Fin 3 → ℚ) ?m.2359

David Renshaw (Jun 16 2025 at 16:58):

Ah, maybe I'm supposed to be using docs#Matrix.toEuclideanLin. But then I need to change my field to .

Eric Wieser (Jun 16 2025 at 21:05):

Either that or pull the vectors back into non euclidean space

David Renshaw (Jun 22 2025 at 18:11):

The RCLike / IsROrC assumption got dropped from EuclideanSpace in mathlib4#11428. I wonder if it should be correspondingly relaxed for Matrix.toEuclideanLin.

Eric Wieser (Jun 22 2025 at 18:29):

It definitely should

Eric Wieser (Jun 22 2025 at 18:30):

PR welcome!

Paul Lezeau (Nov 18 2025 at 14:24):

(resurrecting this old thread): @Eric Wieser do you think it would be reasonable to add a SMul instance for this?

Eric Wieser (Nov 18 2025 at 14:58):

With what type?

Paul Lezeau (Nov 18 2025 at 15:17):

Something along the lines of

import Mathlib

variable {n : Type*} [Fintype n] [DecidableEq n]

noncomputable instance : SMul (Matrix n n ) (EuclideanSpace  n) where
  smul A v := Matrix.toEuclideanLin A v

-- Looks a little nicer than `Matrix.toEuclideanLin !![1, 0; 0, 1] !₂[1, 0]`
example : !![1, 0; 0, 1]  !₂[1, 0] = !₂[1, 0] := by
  ext i
  fin_cases i <;> simp

Paul Lezeau (Nov 18 2025 at 15:18):

(replacing R\mathbb{R} by a general field of course)

Eric Wieser (Nov 18 2025 at 15:46):

I was going to make a counter-argument, but ran into a bug instead:

import Mathlib

variable {n : Type*} [Fintype n] [DecidableEq n]

#synth Module (EuclideanSpace  n →ₗ[] EuclideanSpace  n) (EuclideanSpace  n)  -- ok
#synth SMul (EuclideanSpace  n →ₗ[] EuclideanSpace  n) (EuclideanSpace  n)  -- times out

Eric Wieser (Nov 18 2025 at 16:02):

Paul Lezeau said:

(replacing R\mathbb{R} by a general field of course)

Note that your example doesn't work any more with this change, since Lean can't infer the ring

Paul Lezeau (Nov 18 2025 at 16:09):

Eric Wieser said:

Note that your example doesn't work any more with this change, since Lean can't infer the ring

By this change, do you mean replacing Matrix n n F by (EuclideanSpace F n →ₗ[F] EuclideanSpace F n) ?
This seems to work for me

import Mathlib

variable {R : Type*} [Field R] [RCLike R] {n : Type*} [Fintype n] [DecidableEq n]

noncomputable instance : SMul (Matrix n n R) (EuclideanSpace R n) where
  smul A v := Matrix.toEuclideanLin A v

-- Looks a little nicer than `Matrix.toEuclideanLin !![1, 0; 0, 1] !₂[1, 0]`
example : !![(1 : R), 0; 0, 1]  !₂[(1 : R), 0] = !₂[1, 0] := by
  sorry

Eric Wieser (Nov 18 2025 at 16:19):

In that case you can write !![(1 : R), 0; 0, 1].toEuclideanLin !₂[1, 0] as a middle ground

Eric Wieser (Nov 18 2025 at 16:19):

(my comment was how you couldn't avoid the : R, which in your previous example was needed to make dot notation work)

Paul Lezeau (Nov 18 2025 at 16:26):

Right! But I think this will often be fine in the case where one is working with variables of type R/over R anyway (e.g an abstract matrix A : Matrix n n R)


Last updated: Dec 20 2025 at 21:32 UTC