LAProof.accuracy_proofs.mv_mathcomp
Matrix and Vector Operations: MathComp–List Correspondence
Main Results
- Fmulmx_matrix_vector_mult: the floating-point matrix–vector product computed via F.FMA_mulmx on MathComp matrices equals the list-based matrix_vector_mult, bridging the MathComp and list-based worlds.
Structure
- Utility definitions for norms (normv, normM, sum_abs) and sequence extraction (seq_of_rV).
- Tactics ordify and case_splitP for working with ordinal indices and block-structured matrices.
- Enumeration lemmas connecting ord_enum, index_enum, and list operations (nth_ord_enum', nth_index_enum, index_ord_enum, etc.).
- Norm lemmas including positivity (normv_pos, normM_pos), the submultiplicative inequality (subMultNorm), and the triangle inequality (normv_triang).
- Module F defining floating-point matrix/vector operations (F.dotprod, F.mulmx, F.FMA_mulmx, etc.) and proving structural lemmas such as row/column block decompositions.
- Conversion lemmas between MathComp matrices and list-of-lists representations (listlist_of_mx, mx_of_listlist, list_of_cV, cV_of_list), including roundtrip identities and size invariants.
Dependencies
- preamble, common: basic setup and shared definitions
- dotprod_model, sum_model: relational models of dot product and summation
- dot_acc: dot product accuracy lemmas
- float_acc_lems: elementary floating-point accuracy lemmas
From LAProof.accuracy_proofs Require Import preamble common
dotprod_model sum_model dot_acc float_acc_lems.
From mathcomp.algebra_tactics Require Import ring.
Open Scope ring_scope.
Open Scope order_scope.
normv v is the infinity norm of a column vector
v , i.e.,
the maximum of the absolute values of its entries.
Tactics
i of type Z or nat with a
corresponding ordinal i : 'I_n , introducing the coercion hypothesis
Hi : i = nat_of_ord i (or its Z analogue).
Ltac ordify n i :=
let Hi := fresh "H" i in
let Hj := fresh "H" i in
let j := fresh "i" in
match type of i with ?t ⇒
let t' := eval hnf in t in
match t' with
| Z ⇒
assert (Hi : Datatypes.is_true (ssrnat.leq (S (Z.to_nat i)) n)) by lia;
set (j := @Ordinal n (Z.to_nat i) Hi);
assert (Hj : i = Z.of_nat (nat_of_ord j)) by (simpl; lia)
| nat ⇒
assert (Hi : Datatypes.is_true (ssrnat.leq (S i) n)) by lia;
set (j := @Ordinal n i Hi);
assert (Hj : i = nat_of_ord j) by (simpl; lia)
end
end;
clearbody j; clear Hi;
subst i;
rename j into i.
case_splitP j destructs an ordinal
j : 'I_(a + b) into its left
(lshift]) and right (rshift) components, rewriting j in the goal
accordingly.
Ltac case_splitP j :=
tryif clearbody j then
fail "case_splitP requires a variable, but got a local definition" j
else
tryif is_var j then idtac
else fail "case_splitP requires a variable, but got" j;
match type of j with 'I_(addn ?a ?b) ⇒
let i := fresh "j" in
let H := fresh in
destruct (splitP j) as [i H | i H];
[ replace j with (@lshift a b i);
[ | apply ord_inj; simpl; lia ]
| replace j with (@rshift a b i);
[ | apply ord_inj; simpl; lia ] ];
clear j H; rename i into j
end.
Example uses of case_splitP
A *m row_mx Bl Br = row_mx (A *m Bl) (A *m Br)
using case_splitP.
Local Remark mul_mx_row' [R : pzSemiRingType] m n p1 p2
(A : 'M[R]_(m,n))
(Bl : 'M[R]_(n,p1))
(Br : 'M[R]_(n,p2)) :
A ×m row_mx Bl Br = row_mx (A ×m Bl) (A ×m Br).
Alternative proof of mul_mx_row' following the MathComp style
from mathcomp.algebra.matrix.
Local Remark mul_mx_row'' [R : pzSemiRingType] m n p1 p2
(A : 'M[R]_(m, n))
(Bl : 'M_(n, p1))
(Br : 'M_(n, p2)) :
A ×m row_mx Bl Br = row_mx (A ×m Bl) (A ×m Br).
Lemma nth_List_nth : ∀ {A : Type} (d : A) (l : seq.seq A) (n : nat),
seq.nth d l n = List.nth n l d.
The predecessor of a positive natural number is strictly smaller.
The ordinal
n-1 : 'I_n for a positive n .
The finite enumeration of 'I_n has size
n .
Lemma nth_seq_of_rV : ∀ {T} [n] (d : T) (x : 'rV[T]_n) (i : 'I_n),
nth d (seq_of_rV x) i = x ord0 i.
maxr is associative.
Scalar multiplication distributes over a big
op -fold when op
is "linear" in the sense expressed by the hypothesis Hc .
Lemma big_mul {n : nat} (F : ordinal n → R) op a
(Hc: ∀ i b, op (F i) b × a = op (F i × a) (b × a)):
R0 ≤ a →
\big[op/0]_(i0 < n) (F i0) × a = \big[op/0]_(i0 < n) (F i0 × a).
Scalar multiplication distributes over a big maxr-fold for
nonnegative scalars.
Lemma big_max_mul {n : nat} (F : ordinal n → R) a :
R0 ≤ a →
\big[maxr/0]_(i0 < n) (F i0) × a = \big[maxr/0]_(i0 < n) (F i0 × a).
Triangle inequality for absolute values under a finite sum.
If witnesses exist for every entry, then a matrix with those entries exists.
Lemma exists_mx : ∀ {T} [m n] (F : 'I_m → 'I_n → T → Prop),
(∀ i j, ∃ x, F i j x) →
∃ A : 'M[T]_(m,n), ∀ i j, F i j (A i j).
Any list u is the image of nth d u composed with the ordinal
enumeration of size u.
Lemma nth_ord_enum_lemma : ∀ [T] (d : T) (u : seq T),
u = map (nth d u \o @nat_of_ord (size u)) (ord_enum (size u)).
u = map (nth d u \o @nat_of_ord (size u)) (ord_enum (size u)).
This module defines floating-point analogues of the standard matrix
and vector operations using MathComp's matrix type. The operations
are parameterized over a floating-point type
t and a NaN payload
NAN.
sum x computes the floating-point sum of the values of x over
all ordinal indices, accumulating in reverse order.
dotprod x y computes the floating-point dot product of row vector
x and column vector y using pairwise BMULT and BPLUS.
Definition dotprod [n : nat] (x : 'rV[ftype t]_n) (y : 'cV[ftype t]_n)
: ftype t :=
\big[BPLUS / pos_zero]_i (BMULT (x ord0 (rev_ord i)) (y (rev_ord i) ord0)).
: ftype t :=
\big[BPLUS / pos_zero]_i (BMULT (x ord0 (rev_ord i)) (y (rev_ord i) ord0)).
FMA_dotprod x y computes the dot product of x and y using
fused multiply-add (fma_dotprod) on their list representations.
Definition FMA_dotprod [n : nat] (x : 'rV[ftype t]_n) (y : 'cV[ftype t]_n)
: ftype t :=
fma_dotprod (seq_of_rV x) (seq_of_rV y^T).
: ftype t :=
fma_dotprod (seq_of_rV x) (seq_of_rV y^T).
Definition mulmx [m n p] (A : 'M[ftype t]_(m,n)) (B : 'M[ftype t]_(n,p)) :=
\matrix_(i,k) dotprod (row i A) (col k B).
\matrix_(i,k) dotprod (row i A) (col k B).
Definition FMA_mulmx [m n p] (A : 'M[ftype t]_(m,n)) (B : 'M[ftype t]_(n,p)) :=
\matrix_(i,k) FMA_dotprod (row i A) (col k B).
\matrix_(i,k) FMA_dotprod (row i A) (col k B).
Definition addmx [m n] (A B : 'M[ftype t]_(m,n)) : 'M[ftype t]_(m,n) :=
\matrix_(i,j) BPLUS (A i j) (B i j).
mulmx distributes over right block-row matrices.
Lemma mulmx_row :
∀ m n p1 p2
(A : 'M[ftype t]_(m,n))
(Bl : 'M_(n,p1))
(Br : 'M_(n,p2)),
mulmx A (row_mx Bl Br) = row_mx (mulmx A Bl) (mulmx A Br).
FMA_mulmx distributes over right block-row matrices.
Lemma FMA_mulmx_row :
∀ m n p1 p2
(A : 'M[ftype t]_(m,n))
(Bl : 'M_(n,p1))
(Br : 'M_(n,p2)),
FMA_mulmx A (row_mx Bl Br) = row_mx (FMA_mulmx A Bl) (FMA_mulmx A Br).
mulmx distributes over left block-column matrices.
Lemma mulmx_col :
∀ m1 m2 n p
(Au : 'M[ftype t]_(m1,n))
(Ad : 'M[ftype t]_(m2,n))
(B : 'M_(n,p)),
mulmx (col_mx Au Ad) B = col_mx (mulmx Au B) (mulmx Ad B).
FMA_mulmx distributes over left block-column matrices.
Lemma FMA_mulmx_col :
∀ m1 m2 n p
(Au : 'M[ftype t]_(m1,n))
(Ad : 'M[ftype t]_(m2,n))
(B : 'M_(n,p)),
FMA_mulmx (col_mx Au Ad) B = col_mx (FMA_mulmx Au B) (FMA_mulmx Ad B).
Lemma dotprod_dotprodF :
∀ [n] (x : 'rV[ftype t]_n) (y : 'cV[ftype t]_n),
dotprod x y = dotprodF (seq_of_rV x) (seq_of_rV (trmx y)).
∀ [n] (x : 'rV[ftype t]_n) (y : 'cV[ftype t]_n),
dotprod x y = dotprodF (seq_of_rV x) (seq_of_rV (trmx y)).
For 1 × n and n × 1 matrices, mulmx A B equals the constant
matrix whose sole entry is dotprodF (seq_of_rV A) (seq_of_rV B^T).
Lemma mulmx_dotprodF :
∀ [n] (A : 'M[ftype t]_(1,n)) (B : 'M[ftype t]_(n,1)),
mulmx A B = const_mx (dotprodF (seq_of_rV A) (seq_of_rV (trmx B))).
∀ [n] (A : 'M[ftype t]_(1,n)) (B : 'M[ftype t]_(n,1)),
mulmx A B = const_mx (dotprodF (seq_of_rV A) (seq_of_rV (trmx B))).
For 1 × n and n × 1 matrices, FMA_mulmx A B equals the
constant matrix whose sole entry is
fma_dotprod (seq_of_rV A) (seq_of_rV B^T).
Lemma FMA_mulmx_fma_dotprod :
∀ [n] (A : 'M[ftype t]_(1,n)) (B : 'M[ftype t]_(n,1)),
FMA_mulmx A B = const_mx (fma_dotprod (seq_of_rV A) (seq_of_rV (trmx B))).
∀ [n] (A : 'M[ftype t]_(1,n)) (B : 'M[ftype t]_(n,1)),
FMA_mulmx A B = const_mx (fma_dotprod (seq_of_rV A) (seq_of_rV (trmx B))).
Lemma finitemx_addmx_e : ∀ [m n] (A B : 'M[ftype t]_(m,n)),
finitemx (addmx A B) → finitemx A ∧ finitemx B.
Lemma finitemx_scalemx_e : ∀ [m n] (c : ftype t) (A : 'M[ftype t]_(m,n)),
finitemx (scalemx c A) → finitemx A.
End WithNAN.
End F.
Conversions between MathComp matrices and list-of-lists
Definition listlist_of_mx {T} [m n : nat] (A : 'M[T]_(m,n)) : list (list T) :=
map (fun i : 'I_m ⇒ map (A i) (ord_enum n)) (ord_enum m).
map (fun i : 'I_m ⇒ map (A i) (ord_enum n)) (ord_enum m).
list_of_cV V converts a MathComp column vector to a plain list.
mx_of_listlist rows cols mval builds a MathComp matrix from a
list-of-lists mval, using d as the default element for out-of-bounds
accesses.
Definition mx_of_listlist {T} {d : T} (rows cols : nat) (mval : list (list T))
: 'M[T]_(rows, cols) :=
\matrix_(i,j) seq.nth (d : T) (seq.nth nil mval i) j.
: 'M[T]_(rows, cols) :=
\matrix_(i,j) seq.nth (d : T) (seq.nth nil mval i) j.
cV_of_list n vval builds a MathComp column vector from a list vval,
using d as the default element for out-of-bounds accesses.
Definition cV_of_list {T} {d : T} (n : nat) (vval : list T) : 'cV[T]_n :=
\matrix_(i,j) seq.nth (d : T) vval i.
\matrix_(i,j) seq.nth (d : T) vval i.
Definition matrix_cols_nat {T} (m : list (list T)) (cols : nat) :=
Forall (fun r ⇒ size r = cols) m.
Round-trip: converting a list-of-lists to a MathComp matrix and back
recovers the original list-of-lists, provided the dimensions match.
Lemma listlist_of_mx_of_listlist :
∀ {t} {d} rows cols (mval : list (list (ftype t))),
rows = Datatypes.length mval →
matrix_cols_nat mval cols →
listlist_of_mx (@mx_of_listlist _ d rows cols mval) = mval.
∀ {t} {d} rows cols (mval : list (list (ftype t))),
rows = Datatypes.length mval →
matrix_cols_nat mval cols →
listlist_of_mx (@mx_of_listlist _ d rows cols mval) = mval.
Round-trip: converting a MathComp matrix to a list-of-lists and back
recovers the original matrix.
Lemma mx_of_listlist_of_mx :
∀ {T} {d : T} rows cols (A : 'M[T]_(rows,cols)),
@mx_of_listlist _ d rows cols (listlist_of_mx A) = A.
∀ {T} {d : T} rows cols (A : 'M[T]_(rows,cols)),
@mx_of_listlist _ d rows cols (listlist_of_mx A) = A.
Round-trip: converting a list to a column vector and back recovers
the original list, provided the sizes match.
Lemma list_of_cV_of_list :
∀ {T} {d : T} n (vval : list T),
size vval = n →
list_of_cV (@cV_of_list _ d n vval) = vval.
∀ {T} {d : T} n (vval : list T),
size vval = n →
list_of_cV (@cV_of_list _ d n vval) = vval.
Round-trip: converting a column vector to a list and back recovers
the original vector.
Lemma matrix_rows_listlist_of_mx : ∀ {T} [rows cols] (A : 'M[T]_(rows,cols)),
size (listlist_of_mx A) = rows.
Lemma matrix_cols_listlist_of_mx : ∀ {T} [rows cols] (A : 'M[T]_(rows,cols)),
matrix_cols_nat (listlist_of_mx A) cols.
Lemma nth_list_of_cV :
∀ {T} {d : T} [n] (vval : 'cV[T]_n) (i : 'I_n),
nth d (list_of_cV vval) (nat_of_ord i) = vval i ord0.
List-based floating-point operations
Definition list_dotprod {NAN : FPCore.Nans} {t : type}
(v1 v2 : list (ftype t)) : ftype t :=
foldl (fun s x12 ⇒ BFMA (fst x12) (snd x12) s) (Zconst t 0) (zip v1 v2).
(v1 v2 : list (ftype t)) : ftype t :=
foldl (fun s x12 ⇒ BFMA (fst x12) (snd x12) s) (Zconst t 0) (zip v1 v2).
matrix_vector_mult m v applies the matrix m (given as a list of rows)
to the vector v (a list), computing each entry via list_dotprod.
Definition matrix_vector_mult {NAN : FPCore.Nans} {t : type}
(m : list (list (ftype t))) (v : list (ftype t)) : list (ftype t) :=
map (fun row ⇒ list_dotprod row v) m.
(m : list (list (ftype t))) (v : list (ftype t)) : list (ftype t) :=
map (fun row ⇒ list_dotprod row v) m.
list_of_cV commutes with col_mx: stacking two column vectors and
converting to a list is the same as concatenating their list
representations.
Lemma list_of_cV_col_mx : ∀ {T} n1 n2 (x : 'cV[T]_n1) (y : 'cV[T]_n2),
list_of_cV (col_mx x y) = list_of_cV x ++ list_of_cV y.
list_of_cV (col_mx x y) = list_of_cV x ++ list_of_cV y.
Mapping a constant function yields a repeat.
listlist_of_mx commutes with col_mx: stacking two matrices and
converting to a list-of-lists is the same as appending their
list-of-lists representations.
Lemma listlist_of_mx_col_mx :
∀ {T} n1 n2 m (A : 'M[T]_(n1,m)) (B : 'M[T]_(n2,m)),
listlist_of_mx (col_mx A B) = listlist_of_mx A ++ listlist_of_mx B.
∀ {T} n1 n2 m (A : 'M[T]_(n1,m)) (B : 'M[T]_(n2,m)),
listlist_of_mx (col_mx A B) = listlist_of_mx A ++ listlist_of_mx B.
listlist_of_mx is injective.
Lemma listlist_of_mx_inj : ∀ {T} [m n] (A B : 'M[T]_(m,n)),
listlist_of_mx A = listlist_of_mx B → A = B.
Main theorem: floating-point matrix–vector multiplication
- mval: a list-of-lists of floating-point values with rows rows and cols columns,
- vval: a list of cols floating-point values,
Lemma Fmulmx_matrix_vector_mult :
∀ {NAN : FPCore.Nans} {t} rows cols
(mval : list (list (ftype t)))
(vval : list (ftype t)),
rows = size mval →
cols = size vval →
matrix_cols_nat mval cols →
matrix_vector_mult mval vval =
list_of_cV (F.FMA_mulmx
(@mx_of_listlist _ (Zconst t 0) rows cols mval)
(@cV_of_list _ (Zconst t 0) cols vval)).
∀ {NAN : FPCore.Nans} {t} rows cols
(mval : list (list (ftype t)))
(vval : list (ftype t)),
rows = size mval →
cols = size vval →
matrix_cols_nat mval cols →
matrix_vector_mult mval vval =
list_of_cV (F.FMA_mulmx
(@mx_of_listlist _ (Zconst t 0) rows cols mval)
(@cV_of_list _ (Zconst t 0) cols vval)).