Skip to content

Commit 5decab9

Browse files
committed
feat(LinearAlgebra/Matrix): num and denom of a rational matrix (#24951)
Write a rational matrix as an integer matrix `Matrix.num` divided by a nonzero natural `Matrix.den`.
1 parent 830a10e commit 5decab9

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,6 +3970,7 @@ import Mathlib.LinearAlgebra.Matrix.Gershgorin
39703970
import Mathlib.LinearAlgebra.Matrix.Hermitian
39713971
import Mathlib.LinearAlgebra.Matrix.HermitianFunctionalCalculus
39723972
import Mathlib.LinearAlgebra.Matrix.Ideal
3973+
import Mathlib.LinearAlgebra.Matrix.Integer
39733974
import Mathlib.LinearAlgebra.Matrix.InvariantBasisNumber
39743975
import Mathlib.LinearAlgebra.Matrix.IsDiag
39753976
import Mathlib.LinearAlgebra.Matrix.LDL
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/-
2+
Copyright (c) 2025 David Loeffler. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: David Loeffler
5+
-/
6+
import Mathlib.Algebra.Algebra.Defs
7+
import Mathlib.Algebra.GCDMonoid.Finset
8+
import Mathlib.Algebra.GCDMonoid.Nat
9+
import Mathlib.Data.Matrix.Mul
10+
import Mathlib.Data.Rat.Cast.CharZero
11+
12+
/-!
13+
# Lemmas on integer matrices
14+
15+
Here we collect some results about matrices over `ℚ` and `ℤ`.
16+
17+
## Main definitions and results
18+
19+
* `Matrix.num`, `Matrix.den`: express a rational matrix `A` as the quotient of an integer matrix
20+
by a (non-zero) natural.
21+
22+
## TODO
23+
24+
Consider generalizing these constructions to matrices over localizations of rings (or semirings).
25+
-/
26+
27+
namespace Matrix
28+
29+
variable {m n : Type*} [Fintype m] [Fintype n]
30+
31+
/-!
32+
## Casts
33+
34+
These results are useful shortcuts because the canonical casting maps out of `ℕ`, `ℤ`, and `ℚ` to
35+
suitable types are bare functions, not ring homs, so we cannot apply `Matrix.map_mul` directly to
36+
them.
37+
-/
38+
39+
lemma map_mul_natCast {α : Type*} [NonAssocSemiring α] (A B : Matrix n n ℕ) :
40+
map (A * B) ((↑) : ℕ → α) = map A (↑) * map B (↑) :=
41+
Matrix.map_mul (f := Nat.castRingHom α)
42+
43+
lemma map_mul_intCast {α : Type*} [NonAssocRing α] (A B : Matrix n n ℤ) :
44+
map (A * B) ((↑) : ℤ → α) = map A (↑) * map B (↑) :=
45+
Matrix.map_mul (f := Int.castRingHom α)
46+
47+
lemma map_mul_ratCast {α : Type*} [DivisionRing α] [CharZero α] (A B : Matrix n n ℚ) :
48+
map (A * B) ((↑) : ℚ → α) = map A (↑) * map B (↑) :=
49+
Matrix.map_mul (f := Rat.castHom α)
50+
51+
/-!
52+
## Denominator of a rational matrix
53+
-/
54+
55+
/-- The denominator of a matrix of rationals (as a `Nat`, defined as the LCM of the denominators of
56+
the entries). -/
57+
protected def den (A : Matrix m n ℚ) : ℕ := Finset.univ.lcm (fun P : m × n ↦ (A P.1 P.2).den)
58+
59+
/-- The numerator of a matrix of rationals (a matrix of integers, defined so that
60+
`A.num / A.den = A`). -/
61+
protected def num (A : Matrix m n ℚ) : Matrix m n ℤ := ((A.den : ℚ) • A).map Rat.num
62+
63+
lemma den_ne_zero (A : Matrix m n ℚ) : A.den ≠ 0 := by
64+
simp [Matrix.den, Finset.lcm_eq_zero_iff]
65+
66+
lemma num_eq_zero_iff (A : Matrix m n ℚ) : A.num = 0 ↔ A = 0 := by
67+
simp [Matrix.num, ← ext_iff, A.den_ne_zero]
68+
69+
lemma den_dvd_iff {A : Matrix m n ℚ} {r : ℕ} :
70+
A.den ∣ r ↔ ∀ i j, (A i j).den ∣ r := by
71+
simp [Matrix.den]
72+
73+
lemma num_div_den (A : Matrix m n ℚ) (i : m) (j : n) :
74+
A.num i j / A.den = A i j := by
75+
obtain ⟨k, hk⟩ := den_dvd_iff.mp (dvd_refl A.den) i j
76+
rw [Matrix.num, map_apply, smul_apply, smul_eq_mul, mul_comm,
77+
div_eq_iff <| Nat.cast_ne_zero.mpr A.den_ne_zero, hk, Nat.cast_mul, ← mul_assoc,
78+
Rat.mul_den_eq_num, ← Int.cast_natCast k, ← Int.cast_mul, Rat.num_intCast]
79+
80+
lemma inv_denom_smul_num (A : Matrix m n ℚ) :
81+
(A.den⁻¹ : ℚ) • A.num.map (↑) = A := by
82+
ext
83+
simp [← Matrix.num_div_den A, div_eq_inv_mul]
84+
85+
@[simp]
86+
lemma den_neg (A : Matrix m n ℚ) : (-A).den = A.den :=
87+
eq_of_forall_dvd <| by simp [den_dvd_iff]
88+
89+
@[simp]
90+
lemma num_neg (A : Matrix m n ℚ) : (-A).num = -A.num := by
91+
ext
92+
simp [Matrix.num, map_neg]
93+
94+
@[simp] lemma den_transpose (A : Matrix m n ℚ) : (Aᵀ).den = A.den :=
95+
eq_of_forall_dvd fun _ ↦ by simpa [den_dvd_iff] using forall_comm
96+
97+
@[simp] lemma num_transpose (A : Matrix m n ℚ) : (Aᵀ).num = (A.num)ᵀ := by
98+
ext; simp [Matrix.num]
99+
100+
/-!
101+
### Compatibility with `map`
102+
-/
103+
104+
@[simp]
105+
lemma den_map_intCast (A : Matrix m n ℤ) : (A.map (↑)).den = 1 := by
106+
simp [← Nat.dvd_one, Matrix.den_dvd_iff]
107+
108+
@[simp]
109+
lemma num_map_intCast (A : Matrix m n ℤ) : (A.map (↑)).num = A := by
110+
simp [Matrix.num, Function.comp_def]
111+
112+
@[simp]
113+
lemma den_map_natCast (A : Matrix m n ℕ) : (A.map (↑)).den = 1 := by
114+
simp [← Nat.dvd_one, Matrix.den_dvd_iff]
115+
116+
@[simp]
117+
lemma num_map_natCast (A : Matrix m n ℕ) : (A.map (↑)).num = A.map (↑) := by
118+
simp [Matrix.num, Function.comp_def]
119+
120+
/-!
121+
### Casts from scalar types
122+
-/
123+
124+
@[simp]
125+
lemma den_natCast [DecidableEq m] (a : ℕ) : (a : Matrix m m ℚ).den = 1 := by
126+
simpa [← diagonal_natCast] using den_map_natCast (a : Matrix m m ℕ)
127+
128+
@[simp]
129+
lemma num_natCast [DecidableEq m] (a : ℕ) : (a : Matrix m m ℚ).num = a := by
130+
simpa [← diagonal_natCast] using num_map_natCast (a : Matrix m m ℕ)
131+
132+
@[simp]
133+
lemma den_ofNat [DecidableEq m] (a : ℕ) [a.AtLeastTwo] :
134+
(ofNat(a) : Matrix m m ℚ).den = 1 :=
135+
den_natCast a
136+
137+
@[simp]
138+
lemma num_ofNat [DecidableEq m] (a : ℕ) [a.AtLeastTwo] :
139+
(ofNat(a) : Matrix m m ℚ).num = a :=
140+
num_natCast a
141+
142+
@[simp]
143+
lemma den_intCast [DecidableEq m] (a : ℤ) : (a : Matrix m m ℚ).den = 1 := by
144+
simpa [← diagonal_intCast] using den_map_intCast (a : Matrix m m ℤ)
145+
146+
@[simp]
147+
lemma num_intCast [DecidableEq m] (a : ℤ) : (a : Matrix m m ℚ).num = a := by
148+
simpa [← diagonal_intCast] using num_map_intCast (a : Matrix m m ℤ)
149+
150+
@[simp]
151+
lemma den_zero : (0 : Matrix m n ℚ).den = 1 :=
152+
den_map_natCast 0
153+
154+
@[simp]
155+
lemma num_zero : (0 : Matrix m n ℚ).num = 0 :=
156+
num_map_natCast 0
157+
158+
@[simp]
159+
lemma den_one [DecidableEq m] : (1 : Matrix m m ℚ).den = 1 :=
160+
den_natCast 1
161+
162+
@[simp]
163+
lemma num_one [DecidableEq m] : (1 : Matrix m m ℚ).num = 1 :=
164+
num_natCast 1
165+
166+
end Matrix

0 commit comments

Comments
 (0)