(* Title: Fast Fourier Transform Author:ClemensBallarin<ballarinatin.tum.de>,started12April2005 Maintainer:ClemensBallarin<ballarinatin.tum.de>
*)
theory FFT imports Complex_Main begin
text‹We formalise a functional implementation of the FFT algorithm
over the complex numbers, and its inverse. Both are shown
equivalent to the usual definitions
of these operations through Vandermonde matrices. They are also
shown to be inverse to each other, more precisely, that composition
of the inverse and the transformation yield the identity up to a
scalar.
The presentation closely follows Section 30.2 of Cormen \textit{et
al.}, \emph{Introduction to Algorithms}, 2nd edition, MIT Press,
2003.›
section‹Preliminaries›
text‹The following two lemmas are useful for experimenting with the
transformations, at a vector length of four.›
lemma Sum4: "(∑i=0..<4::nat. x i) = x 0 + x 1 + x 2 + x 3" by (simp add: Ivl4 eval_nat_numeral)
text‹A number of specialised lemmas for the summation operator,
where the index set is the natural numbers›
lemma sum_add_nat_ivl_singleton: assumes less: "m < (n::nat)" shows"f m + sum f {m<..<n} = sum f {m..<n}" proof - have"f m + sum f {m<..<n} = sum f ({m} ∪ {m<..<n})" by (simp add: sum.union_disjoint ivl_disj_int) alsofrom less have"... = sum f {m..<n}" by (simp only: ivl_disj_un) finallyshow ?thesis . qed
lemma sum_add_split_nat_ivl_singleton: assumes less: "m < (n::nat)" and g: "!!i. [| m < i; i < n |] ==> g i = f i" shows"f m + sum g {m<..<n} = sum f {m..<n}" using less g by(simp add: sum_add_nat_ivl_singleton cong: sum.cong_simp)
lemma sum_add_split_nat_ivl: assumes le: "m <= (k::nat)""k <= n" and g: "!!i. [| m <= i; i < k |] ==> g i = f i" and h: "!!i. [| k <= i; i < n |] ==> h i = f i" shows"sum g {m..<k} + sum h {k..<n} = sum f {m..<n}" using le g h by (simp add: sum.atLeastLessThan_concat cong: sum.cong_simp)
lemma sum_splice: "(∑i::nat = 0..<2*n. f i) = (∑i = 0..<n. f (2*i)) + (∑i = 0..<n. f (2*i+1))" proof - have"(∑i::nat = 0..<2*n. f i) = sum f ((*) 2 ` {0..<n}) + sum f ((%i. 2*i+1) ` {0..<n})" by (simp add: ivl_splice_Un ivl_splice_Int sum.union_disjoint) alsohave"... = (∑i = 0..<n. f (2*i)) + (∑i = 0..<n. f (2*i+1))" by (simp add: sum.reindex [OF double_inj_on]
sum.reindex [OF Suc_double_inj_on]) finallyshow ?thesis . qed
section‹Complex Roots of Unity›
text‹The function @{term cis} from the complex library returns the
point on the unity circle corresponding to the argument angle. It
is the base for our definition of ‹root›. The main property,
De Moirve's formula is already there in the library.›
lemma root_summation: assumes k: "0 < k""k < n" shows"(∑i=0..<n. (root n ^ k) ^ i) = 0" proof - from k have real0: "0 < real k * (2 * pi) / real n" by (simp add: zero_less_divide_iff
mult_strict_right_mono [where a = 0, simplified]) from k mult_strict_right_mono [where a = "real k"and
b = "real n"and c = "2 * pi / real n", simplified] have realk: "real k * (2 * pi) / real n < 2 * pi" by (simp add: zero_less_divide_iff) txt‹Main part of the proof› have"(∑i=0..<n. (root n ^ k) ^ i) = ((root n ^ k) ^ n - 1) / (root n ^ k - 1)" unfolding atLeast0LessThan apply (rule geometric_sum) apply (unfold root_def) apply (simp add: DeMoivre) using real0 realk sin_cos_between_zero_two_pi apply (auto simp add: complex_eq_iff) done alsohave"... = ((root n ^ n) ^ k - 1) / (root n ^ k - 1)" by (simp add: power_mult [THEN sym] ac_simps) alsohave"... = 0" by (simp add: root_unity) finallyshow ?thesis . qed
lemma root_summation_inv: assumes k: "0 < k""k < n" shows"(∑i=0..<n. ((1 / root n) ^ k) ^ i) = 0" proof - from k have real0: "0 < real k * (2 * pi) / real n" by (simp add: zero_less_divide_iff
mult_strict_right_mono [where a = 0, simplified]) from k mult_strict_right_mono [where a = "real k"and
b = "real n"and c = "2 * pi / real n", simplified] have realk: "real k * (2 * pi) / real n < 2 * pi" by (simp add: zero_less_divide_iff) txt‹Main part of the proof› have"(∑i=0..<n. ((1 / root n) ^ k) ^ i) = (((1 / root n) ^ k) ^ n - 1) / ((1 / root n) ^ k - 1)" unfolding atLeast0LessThan apply (rule geometric_sum) apply (simp add: nonzero_inverse_eq_divide [THEN sym] root_nonzero) apply (unfold root_def) apply (simp add: DeMoivre) using real0 realk sin_cos_between_zero_two_pi apply (auto simp add: complex_eq_iff) done alsohave"... = (((1 / root n) ^ n) ^ k - 1) / ((1 / root n) ^ k - 1)" by (simp add: power_mult [THEN sym] ac_simps) alsohave"... = 0" by (simp add: power_divide root_unity) finallyshow ?thesis . qed
lemma root_cancel1: "root (2 * m) ^ (i * (2 * j)) = root m ^ (i * j)" proof - have"root (2 * m) ^ (i * (2 * j)) = root (2 * m) ^ (2 * (i * j))" by (simp add: ac_simps) alsohave"... = root m ^ (i * j)" by (simp add: root_cancel) finallyshow ?thesis . qed
lemma root_cancel2: "0 < n ==> root (2 * n) ^ n = - 1" txt‹Note the space between ‹-› and ‹1›.› using root_cancel [where n = 2and k = 1] by (simp add: complex_eq_iff ac_simps)
section‹Discrete Fourier Transformation›
text‹
We define operations ‹DFT› and ‹IDFT› for the discrete
Fourier Transform and its inverse. Vectors are simply functions of
type ‹nat => complex›.›
text‹ ‹DFT n a› is the transform of vector ‹a›
of length ‹n›, ‹IDFT› its inverse.›
definition DFT :: "nat => (nat => complex) => (nat => complex)"where "DFT n a == (%i. ∑j=0..<n. (root n) ^ (i * j) * (a j))"
definition IDFT :: "nat => (nat => complex) => (nat => complex)"where "IDFT n a == (%i. (∑k=0..<n. (a k) / (root n) ^ (i * k)))"
lemma power_diff_inverse: assumes nz: "(a::'a::field) ~= 0" shows"m <= n ==> (inverse a) ^ (n-m) = (a^m) / (a^n)" apply (induct n m rule: diff_induct) apply (simp add: power_inverse
nonzero_inverse_eq_divide [THEN sym] nz) apply simp apply (simp add: nz) done
lemma power_diff_rev_if: assumes nz: "(a::'a::field) ~= 0" shows"(a^m) / (a^n) = (if n <= m then a ^ (m-n) else (1/a) ^ (n-m))" proof (cases "n <= m") case True with nz show ?thesis by (simp add: power_diff) next case False with nz show ?thesis by (simp add: power_diff_inverse nonzero_inverse_eq_divide [THEN sym]) qed
lemma power_divides_special: "(a::'a::field) ~= 0 ==> a ^ (i * j) / a ^ (k * i) = (a ^ j / a ^ k) ^ i" by (simp add: power_divide power_mult [THEN sym] ac_simps)
theorem DFT_inverse: assumes i_less: "i < n" shows"IDFT n (DFT n a) i = of_nat n * a i" using [[linarith_split_limit = 0]] apply (unfold DFT_def IDFT_def) apply (simp add: sum_divide_distrib) apply (subst sum.swap) apply (simp only: times_divide_eq_left [THEN sym]) apply (simp only: power_divides_special [OF root_nonzero]) apply (simp add: power_diff_rev_if root_nonzero) apply (simp add: sum_divide_distrib [THEN sym]
sum_distrib_right [THEN sym]) proof - from i_less have i_diff: "!!k. i - k < n"by arith have diff_i: "!!k. k < n ==> k - i < n"by arith
let ?sum = "%i j n. sum ((^) (if i <= j then root n ^ (j - i) else (1 / root n) ^ (i - j))) {0..<n} * a j" let ?sum1 = "%i j n. sum ((^) (root n ^ (j - i))) {0..<n} * a j" let ?sum2 = "%i j n. sum ((^) ((1 / root n) ^ (i - j))) {0..<n} * a j"
from i_less have"(∑j = 0..<n. ?sum i j n) = (∑j = 0..<i. ?sum2 i j n) + (∑j = i..<n. ?sum1 i j n)"
(is"?s = _") by (simp add: root_summation_inv nat_dvd_not_less
sum_add_split_nat_ivl [where f = "%j. ?sum i j n"]) alsofrom i_less i_diff have"... = (∑j = i..<n. ?sum1 i j n)" by (simp add: root_summation_inv nat_dvd_not_less) alsofrom i_less have"... = (∑j∈{i} ∪ {i<..<n}. ?sum1 i j n)" by (simp only: ivl_disj_un) alsohave"... = (?sum1 i i n + (∑j∈{i<..<n}. ?sum1 i j n))" by (simp add: sum.union_disjoint ivl_disj_int) alsofrom i_less diff_i have"... = ?sum1 i i n" by (simp add: root_summation nat_dvd_not_less) alsofrom i_less have"... = of_nat n * a i" (is"_ = ?t") by simp finallyshow"?s = ?t" . qed
section‹Discrete, Fast Fourier Transformation›
text‹‹FFT k a› is the transform of vector ‹a›
of length ‹2 ^ k›, ‹IFFT› its inverse.›
primrec FFT :: "nat => (nat => complex) => (nat => complex)"where "FFT 0 a = a"
| "FFT (Suc k) a = (let (x, y) = (FFT k (%i. a (2*i)), FFT k (%i. a (2*i+1))) in (%i. if i < 2^k then x i + (root (2 ^ (Suc k))) ^ i * y i else x (i- 2^k) - (root (2 ^ (Suc k))) ^ (i- 2^k) * y (i- 2^k)))"
primrec IFFT :: "nat => (nat => complex) => (nat => complex)"where "IFFT 0 a = a"
| "IFFT (Suc k) a = (let (x, y) = (IFFT k (%i. a (2*i)), IFFT k (%i. a (2*i+1))) in (%i. if i < 2^k then x i + (1 / root (2 ^ (Suc k))) ^ i * y i else x (i - 2^k) - (1 / root (2 ^ (Suc k))) ^ (i - 2^k) * y (i - 2^k)))"
text‹Finally, for vectors of length ‹2 ^ k›, ‹DFT› and ‹FFT›, and ‹IDFT› and ‹IFFT› are equivalent.›
theorem DFT_FFT: "!!a i. i < 2 ^ k ==> DFT (2 ^ k) a i = FFT k a i" proof (induct k) case0 thenshow ?caseby (simp add: DFT_def) next case (Suc k) assume i: "i < 2 ^ Suc k" show ?caseproof (cases "i < 2 ^ k") case True thenshow ?thesis apply simp apply (simp add: DFT_lower) apply (simp add: Suc) done next case False from i have"i - 2 ^ k < 2 ^ k"by simp with False i show ?thesis apply simp apply (simp add: DFT_upper) apply (simp add: Suc) done qed qed
theorem IDFT_IFFT: "!!a i. i < 2 ^ k ==> IDFT (2 ^ k) a i = IFFT k a i" proof (induct k) case0 thenshow ?caseby (simp add: IDFT_def) next case (Suc k) assume i: "i < 2 ^ Suc k" show ?caseproof (cases "i < 2 ^ k") case True thenshow ?thesis apply simp apply (simp add: IDFT_lower) apply (simp add: Suc) done next case False from i have"i - 2 ^ k < 2 ^ k"by simp with False i show ?thesis apply simp apply (simp add: IDFT_upper) apply (simp add: Suc) done qed qed
schematic_goal "map (FFT (Suc (Suc 0)) a) [0, 1, 2, 3] = ?x" by simp
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.