LAProof.C.cblas.scal_model: functional model of GSL's [cblas_dscal].
Corresponds to C program C/cblas/src/dscal.c (ported from GSL cblas).
for (i = 0; i < N; i++) { X[ix] *= alpha; ix += incX; }
i.e., X[ix] *= alpha is BMULT (X[ix]) alpha (element-first).
scal_model below captures the contiguous whole-list special case; the
later scal_strided definition captures the kernel for arbitrary positive
stride when the input array may contain unselected elements.
Require Import VST.floyd.proofauto.
From vcfloat Require Import FPStdCompCert FPStdLib.
From LAProof.C Require Import floatlib.
Definition scal_model (alpha: ftype Tdouble) (X: list (ftype Tdouble)) : list (ftype Tdouble) :=
map (fun x ⇒ BMULT x alpha) X.
Lemma Zlength_scal_model: ∀ alpha X,
Zlength (scal_model alpha X) = Zlength X.
Lemma Znth_scal_model: ∀ alpha X k,
0 ≤ k < Zlength X →
Znth k (scal_model alpha X) = BMULT (Znth k X) alpha.
Strided-access helper used by dscal and dasum.
Definition strided {A} `{Inhabitant A} (incX N : Z) (X : list A) : list A :=
map (fun i ⇒ Znth (i × incX) X) (upto (Z.to_nat N)).
Lemma Zlength_strided: ∀ {A} `{Inhabitant A} incX N (X: list A),
0 ≤ N → Zlength (strided incX N X) = N.
Lemma strided_snoc: ∀ {A} `{Inhabitant A} incX k (X: list A),
0 ≤ k → strided incX (k+1) X = strided incX k X ++ [Znth (k×incX) X].
map (fun i ⇒ Znth (i × incX) X) (upto (Z.to_nat N)).
Lemma Zlength_strided: ∀ {A} `{Inhabitant A} incX N (X: list A),
0 ≤ N → Zlength (strided incX N X) = N.
Lemma strided_snoc: ∀ {A} `{Inhabitant A} incX k (X: list A),
0 ≤ k → strided incX (k+1) X = strided incX k X ++ [Znth (k×incX) X].
Strided in-place scaling model (general positive stride incX > 0).
Definition scal_fold (incX: Z) (alpha: ftype Tdouble) (src: list (ftype Tdouble))
(l: list Z) (acc: list (ftype Tdouble)) : list (ftype Tdouble) :=
fold_left (fun a i ⇒ upd_Znth (i×incX) a (BMULT (Znth (i×incX) src) alpha)) l acc.
Definition scal_strided (incX N: Z) (alpha: ftype Tdouble) (X: list (ftype Tdouble))
: list (ftype Tdouble) :=
scal_fold incX alpha X (upto (Z.to_nat N)) X.
Lemma scal_strided_0: ∀ incX alpha X, scal_strided incX 0 alpha X = X.
Lemma Zlength_scal_fold: ∀ incX alpha src l acc,
(∀ i, In i l → 0 ≤ i×incX < Zlength acc) →
Zlength (scal_fold incX alpha src l acc) = Zlength acc.
Lemma Znth_scal_fold_notin: ∀ incX alpha src l acc p,
0 ≤ p < Zlength acc →
(∀ i, In i l → 0 ≤ i×incX < Zlength acc) →
¬ In p (map (fun i ⇒ i×incX) l) →
Znth p (scal_fold incX alpha src l acc) = Znth p acc.
Lemma scal_strided_snoc: ∀ incX k alpha X, 0 ≤ k →
scal_strided incX (k+1) alpha X
= upd_Znth (k×incX) (scal_strided incX k alpha X) (BMULT (Znth (k×incX) X) alpha).
Lemma Zlength_scal_strided: ∀ incX N alpha X,
0 ≤ N → 0 < incX → (N-1)*incX < Zlength X →
Zlength (scal_strided incX N alpha X) = Zlength X.
(l: list Z) (acc: list (ftype Tdouble)) : list (ftype Tdouble) :=
fold_left (fun a i ⇒ upd_Znth (i×incX) a (BMULT (Znth (i×incX) src) alpha)) l acc.
Definition scal_strided (incX N: Z) (alpha: ftype Tdouble) (X: list (ftype Tdouble))
: list (ftype Tdouble) :=
scal_fold incX alpha X (upto (Z.to_nat N)) X.
Lemma scal_strided_0: ∀ incX alpha X, scal_strided incX 0 alpha X = X.
Lemma Zlength_scal_fold: ∀ incX alpha src l acc,
(∀ i, In i l → 0 ≤ i×incX < Zlength acc) →
Zlength (scal_fold incX alpha src l acc) = Zlength acc.
Lemma Znth_scal_fold_notin: ∀ incX alpha src l acc p,
0 ≤ p < Zlength acc →
(∀ i, In i l → 0 ≤ i×incX < Zlength acc) →
¬ In p (map (fun i ⇒ i×incX) l) →
Znth p (scal_fold incX alpha src l acc) = Znth p acc.
Lemma scal_strided_snoc: ∀ incX k alpha X, 0 ≤ k →
scal_strided incX (k+1) alpha X
= upd_Znth (k×incX) (scal_strided incX k alpha X) (BMULT (Znth (k×incX) X) alpha).
Lemma Zlength_scal_strided: ∀ incX N alpha X,
0 ≤ N → 0 < incX → (N-1)*incX < Zlength X →
Zlength (scal_strided incX N alpha X) = Zlength X.
The C kernel X[ix] *= alpha is a read-modify-write -- X[ix] = X[ix] ×
alpha -- reading the current contents of X[ix] before storing back. At
step k the slot k×incX is still untouched: prior writes hit j×incX,
j < k, all below k×incX since incX > 0. So the value read equals the
original Znth (k×incX) X.