annotate src/fftw-3.3.5/genfft/fft.ml @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 7867fa7e1b6b
children
rev   line source
cannam@127 1 (*
cannam@127 2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
cannam@127 3 * Copyright (c) 2003, 2007-14 Matteo Frigo
cannam@127 4 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
cannam@127 5 *
cannam@127 6 * This program is free software; you can redistribute it and/or modify
cannam@127 7 * it under the terms of the GNU General Public License as published by
cannam@127 8 * the Free Software Foundation; either version 2 of the License, or
cannam@127 9 * (at your option) any later version.
cannam@127 10 *
cannam@127 11 * This program is distributed in the hope that it will be useful,
cannam@127 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cannam@127 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cannam@127 14 * GNU General Public License for more details.
cannam@127 15 *
cannam@127 16 * You should have received a copy of the GNU General Public License
cannam@127 17 * along with this program; if not, write to the Free Software
cannam@127 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cannam@127 19 *
cannam@127 20 *)
cannam@127 21
cannam@127 22
cannam@127 23 (* This is the part of the generator that actually computes the FFT
cannam@127 24 in symbolic form *)
cannam@127 25
cannam@127 26 open Complex
cannam@127 27 open Util
cannam@127 28
cannam@127 29 (* choose a suitable factor of n *)
cannam@127 30 let choose_factor n =
cannam@127 31 (* first choice: i such that gcd(i, n / i) = 1, i as big as possible *)
cannam@127 32 let choose1 n =
cannam@127 33 let rec loop i f =
cannam@127 34 if (i * i > n) then f
cannam@127 35 else if ((n mod i) == 0 && gcd i (n / i) == 1) then loop (i + 1) i
cannam@127 36 else loop (i + 1) f
cannam@127 37 in loop 1 1
cannam@127 38
cannam@127 39 (* second choice: the biggest factor i of n, where i < sqrt(n), if any *)
cannam@127 40 and choose2 n =
cannam@127 41 let rec loop i f =
cannam@127 42 if (i * i > n) then f
cannam@127 43 else if ((n mod i) == 0) then loop (i + 1) i
cannam@127 44 else loop (i + 1) f
cannam@127 45 in loop 1 1
cannam@127 46
cannam@127 47 in let i = choose1 n in
cannam@127 48 if (i > 1) then i
cannam@127 49 else choose2 n
cannam@127 50
cannam@127 51 let is_power_of_two n = (n > 0) && ((n - 1) land n == 0)
cannam@127 52
cannam@127 53 let rec dft_prime sign n input =
cannam@127 54 let sum filter i =
cannam@127 55 sigma 0 n (fun j ->
cannam@127 56 let coeff = filter (exp n (sign * i * j))
cannam@127 57 in coeff @* (input j)) in
cannam@127 58 let computation_even = array n (sum identity)
cannam@127 59 and computation_odd =
cannam@127 60 let sumr = array n (sum real)
cannam@127 61 and sumi = array n (sum ((times Complex.i) @@ imag)) in
cannam@127 62 array n (fun i ->
cannam@127 63 if (i = 0) then
cannam@127 64 (* expose some common subexpressions *)
cannam@127 65 input 0 @+
cannam@127 66 sigma 1 ((n + 1) / 2) (fun j -> input j @+ input (n - j))
cannam@127 67 else
cannam@127 68 let i' = min i (n - i) in
cannam@127 69 if (i < n - i) then
cannam@127 70 sumr i' @+ sumi i'
cannam@127 71 else
cannam@127 72 sumr i' @- sumi i') in
cannam@127 73 if (n >= !Magic.rader_min) then
cannam@127 74 dft_rader sign n input
cannam@127 75 else if (n == 2) then
cannam@127 76 computation_even
cannam@127 77 else
cannam@127 78 computation_odd
cannam@127 79
cannam@127 80
cannam@127 81 and dft_rader sign p input =
cannam@127 82 let half =
cannam@127 83 let one_half = inverse_int 2 in
cannam@127 84 times one_half
cannam@127 85
cannam@127 86 and make_product n a b =
cannam@127 87 let scale_factor = inverse_int n in
cannam@127 88 array n (fun i -> a i @* (scale_factor @* b i)) in
cannam@127 89
cannam@127 90 (* generates a convolution using ffts. (all arguments are the
cannam@127 91 same as to gen_convolution, below) *)
cannam@127 92 let gen_convolution_by_fft n a b addtoall =
cannam@127 93 let fft_a = dft 1 n a
cannam@127 94 and fft_b = dft 1 n b in
cannam@127 95
cannam@127 96 let fft_ab = make_product n fft_a fft_b
cannam@127 97 and dc_term i = if (i == 0) then addtoall else zero in
cannam@127 98
cannam@127 99 let fft_ab1 = array n (fun i -> fft_ab i @+ dc_term i)
cannam@127 100 and sum = fft_a 0 in
cannam@127 101 let conv = dft (-1) n fft_ab1 in
cannam@127 102 (sum, conv)
cannam@127 103
cannam@127 104 (* alternate routine for convolution. Seems to work better for
cannam@127 105 small sizes. I have no idea why. *)
cannam@127 106 and gen_convolution_by_fft_alt n a b addtoall =
cannam@127 107 let ap = array n (fun i -> half (a i @+ a ((n - i) mod n)))
cannam@127 108 and am = array n (fun i -> half (a i @- a ((n - i) mod n)))
cannam@127 109 and bp = array n (fun i -> half (b i @+ b ((n - i) mod n)))
cannam@127 110 and bm = array n (fun i -> half (b i @- b ((n - i) mod n)))
cannam@127 111 in
cannam@127 112
cannam@127 113 let fft_ap = dft 1 n ap
cannam@127 114 and fft_am = dft 1 n am
cannam@127 115 and fft_bp = dft 1 n bp
cannam@127 116 and fft_bm = dft 1 n bm in
cannam@127 117
cannam@127 118 let fft_abpp = make_product n fft_ap fft_bp
cannam@127 119 and fft_abpm = make_product n fft_ap fft_bm
cannam@127 120 and fft_abmp = make_product n fft_am fft_bp
cannam@127 121 and fft_abmm = make_product n fft_am fft_bm
cannam@127 122 and sum = fft_ap 0 @+ fft_am 0
cannam@127 123 and dc_term i = if (i == 0) then addtoall else zero in
cannam@127 124
cannam@127 125 let fft_ab1 = array n (fun i -> (fft_abpp i @+ fft_abmm i) @+ dc_term i)
cannam@127 126 and fft_ab2 = array n (fun i -> fft_abpm i @+ fft_abmp i) in
cannam@127 127 let conv1 = dft (-1) n fft_ab1
cannam@127 128 and conv2 = dft (-1) n fft_ab2 in
cannam@127 129 let conv = array n (fun i ->
cannam@127 130 conv1 i @+ conv2 i) in
cannam@127 131 (sum, conv)
cannam@127 132
cannam@127 133 (* generator of assignment list assigning conv to the convolution of
cannam@127 134 a and b, all of which are of length n. addtoall is added to
cannam@127 135 all of the elements of the result. Returns (sum, convolution) pair
cannam@127 136 where sum is the sum of the elements of a. *)
cannam@127 137
cannam@127 138 in let gen_convolution =
cannam@127 139 if (p <= !Magic.alternate_convolution) then
cannam@127 140 gen_convolution_by_fft_alt
cannam@127 141 else
cannam@127 142 gen_convolution_by_fft
cannam@127 143
cannam@127 144 (* fft generator for prime n = p using Rader's algorithm for
cannam@127 145 turning the fft into a convolution, which then can be
cannam@127 146 performed in a variety of ways *)
cannam@127 147 in
cannam@127 148 let g = find_generator p in
cannam@127 149 let ginv = pow_mod g (p - 2) p in
cannam@127 150 let input_perm = array p (fun i -> input (pow_mod g i p))
cannam@127 151 and omega_perm = array p (fun i -> exp p (sign * (pow_mod ginv i p)))
cannam@127 152 and output_perm = array p (fun i -> pow_mod ginv i p)
cannam@127 153 in let (sum, conv) =
cannam@127 154 (gen_convolution (p - 1) input_perm omega_perm (input 0))
cannam@127 155 in array p (fun i ->
cannam@127 156 if (i = 0) then
cannam@127 157 input 0 @+ sum
cannam@127 158 else
cannam@127 159 let i' = suchthat 0 (fun i' -> i = output_perm i')
cannam@127 160 in conv i')
cannam@127 161
cannam@127 162 (* our modified version of the conjugate-pair split-radix algorithm,
cannam@127 163 which reduces the number of multiplications by rescaling the
cannam@127 164 sub-transforms (power-of-two n's only) *)
cannam@127 165 and newsplit sign n input =
cannam@127 166 let rec s n k = (* recursive scale factor *)
cannam@127 167 if n <= 4 then
cannam@127 168 one
cannam@127 169 else
cannam@127 170 let k4 = (abs k) mod (n / 4) in
cannam@127 171 let k4' = if k4 <= (n / 8) then k4 else (n/4 - k4) in
cannam@127 172 (s (n / 4) k4') @* (real (exp n k4'))
cannam@127 173
cannam@127 174 and sinv n k = (* 1 / s(n,k) *)
cannam@127 175 if n <= 4 then
cannam@127 176 one
cannam@127 177 else
cannam@127 178 let k4 = (abs k) mod (n / 4) in
cannam@127 179 let k4' = if k4 <= (n / 8) then k4 else (n/4 - k4) in
cannam@127 180 (sinv (n / 4) k4') @* (sec n k4')
cannam@127 181
cannam@127 182 in let sdiv2 n k = (s n k) @* (sinv (2*n) k) (* s(n,k) / s(2*n,k) *)
cannam@127 183 and sdiv4 n k = (* s(n,k) / s(4*n,k) *)
cannam@127 184 let k4 = (abs k) mod n in
cannam@127 185 sec (4*n) (if k4 <= (n / 2) then k4 else (n - k4))
cannam@127 186
cannam@127 187 in let t n k = (exp n k) @* (sdiv4 (n/4) k)
cannam@127 188
cannam@127 189 and dft1 input = input
cannam@127 190 and dft2 input = array 2 (fun k -> (input 0) @+ ((input 1) @* exp 2 k))
cannam@127 191
cannam@127 192 in let rec newsplit0 sign n input =
cannam@127 193 if (n == 1) then dft1 input
cannam@127 194 else if (n == 2) then dft2 input
cannam@127 195 else let u = newsplit0 sign (n / 2) (fun i -> input (i*2))
cannam@127 196 and z = newsplitS sign (n / 4) (fun i -> input (i*4 + 1))
cannam@127 197 and z' = newsplitS sign (n / 4) (fun i -> input ((n + i*4 - 1) mod n))
cannam@127 198 and twid = array n (fun k -> s (n/4) k @* exp n (sign * k)) in
cannam@127 199 let w = array n (fun k -> twid k @* z (k mod (n / 4)))
cannam@127 200 and w' = array n (fun k -> conj (twid k) @* z' (k mod (n / 4))) in
cannam@127 201 let ww = array n (fun k -> w k @+ w' k) in
cannam@127 202 array n (fun k -> u (k mod (n / 2)) @+ ww k)
cannam@127 203
cannam@127 204 and newsplitS sign n input =
cannam@127 205 if (n == 1) then dft1 input
cannam@127 206 else if (n == 2) then dft2 input
cannam@127 207 else let u = newsplitS2 sign (n / 2) (fun i -> input (i*2))
cannam@127 208 and z = newsplitS sign (n / 4) (fun i -> input (i*4 + 1))
cannam@127 209 and z' = newsplitS sign (n / 4) (fun i -> input ((n + i*4 - 1) mod n)) in
cannam@127 210 let w = array n (fun k -> t n (sign * k) @* z (k mod (n / 4)))
cannam@127 211 and w' = array n (fun k -> conj (t n (sign * k)) @* z' (k mod (n / 4))) in
cannam@127 212 let ww = array n (fun k -> w k @+ w' k) in
cannam@127 213 array n (fun k -> u (k mod (n / 2)) @+ ww k)
cannam@127 214
cannam@127 215 and newsplitS2 sign n input =
cannam@127 216 if (n == 1) then dft1 input
cannam@127 217 else if (n == 2) then dft2 input
cannam@127 218 else let u = newsplitS4 sign (n / 2) (fun i -> input (i*2))
cannam@127 219 and z = newsplitS sign (n / 4) (fun i -> input (i*4 + 1))
cannam@127 220 and z' = newsplitS sign (n / 4) (fun i -> input ((n + i*4 - 1) mod n)) in
cannam@127 221 let w = array n (fun k -> t n (sign * k) @* z (k mod (n / 4)))
cannam@127 222 and w' = array n (fun k -> conj (t n (sign * k)) @* z' (k mod (n / 4))) in
cannam@127 223 let ww = array n (fun k -> (w k @+ w' k) @* (sdiv2 n k)) in
cannam@127 224 array n (fun k -> u (k mod (n / 2)) @+ ww k)
cannam@127 225
cannam@127 226 and newsplitS4 sign n input =
cannam@127 227 if (n == 1) then dft1 input
cannam@127 228 else if (n == 2) then
cannam@127 229 let f = dft2 input
cannam@127 230 in array 2 (fun k -> (f k) @* (sinv 8 k))
cannam@127 231 else let u = newsplitS2 sign (n / 2) (fun i -> input (i*2))
cannam@127 232 and z = newsplitS sign (n / 4) (fun i -> input (i*4 + 1))
cannam@127 233 and z' = newsplitS sign (n / 4) (fun i -> input ((n + i*4 - 1) mod n)) in
cannam@127 234 let w = array n (fun k -> t n (sign * k) @* z (k mod (n / 4)))
cannam@127 235 and w' = array n (fun k -> conj (t n (sign * k)) @* z' (k mod (n / 4))) in
cannam@127 236 let ww = array n (fun k -> w k @+ w' k) in
cannam@127 237 array n (fun k -> (u (k mod (n / 2)) @+ ww k) @* (sdiv4 n k))
cannam@127 238
cannam@127 239 in newsplit0 sign n input
cannam@127 240
cannam@127 241 and dft sign n input =
cannam@127 242 let rec cooley_tukey sign n1 n2 input =
cannam@127 243 let tmp1 =
cannam@127 244 array n2 (fun i2 ->
cannam@127 245 dft sign n1 (fun i1 -> input (i1 * n2 + i2))) in
cannam@127 246 let tmp2 =
cannam@127 247 array n1 (fun i1 ->
cannam@127 248 array n2 (fun i2 ->
cannam@127 249 exp n (sign * i1 * i2) @* tmp1 i2 i1)) in
cannam@127 250 let tmp3 = array n1 (fun i1 -> dft sign n2 (tmp2 i1)) in
cannam@127 251 (fun i -> tmp3 (i mod n1) (i / n1))
cannam@127 252
cannam@127 253 (*
cannam@127 254 * This is "exponent -1" split-radix by Dan Bernstein.
cannam@127 255 *)
cannam@127 256 and split_radix_dit sign n input =
cannam@127 257 let f0 = dft sign (n / 2) (fun i -> input (i * 2))
cannam@127 258 and f10 = dft sign (n / 4) (fun i -> input (i * 4 + 1))
cannam@127 259 and f11 = dft sign (n / 4) (fun i -> input ((n + i * 4 - 1) mod n)) in
cannam@127 260 let g10 = array n (fun k ->
cannam@127 261 exp n (sign * k) @* f10 (k mod (n / 4)))
cannam@127 262 and g11 = array n (fun k ->
cannam@127 263 exp n (- sign * k) @* f11 (k mod (n / 4))) in
cannam@127 264 let g1 = array n (fun k -> g10 k @+ g11 k) in
cannam@127 265 array n (fun k -> f0 (k mod (n / 2)) @+ g1 k)
cannam@127 266
cannam@127 267 and split_radix_dif sign n input =
cannam@127 268 let n2 = n / 2 and n4 = n / 4 in
cannam@127 269 let x0 = array n2 (fun i -> input i @+ input (i + n2))
cannam@127 270 and x10 = array n4 (fun i -> input i @- input (i + n2))
cannam@127 271 and x11 = array n4 (fun i ->
cannam@127 272 input (i + n4) @- input (i + n2 + n4)) in
cannam@127 273 let x1 k i =
cannam@127 274 exp n (k * i * sign) @* (x10 i @+ exp 4 (k * sign) @* x11 i) in
cannam@127 275 let f0 = dft sign n2 x0
cannam@127 276 and f1 = array 4 (fun k -> dft sign n4 (x1 k)) in
cannam@127 277 array n (fun k ->
cannam@127 278 if k mod 2 = 0 then f0 (k / 2)
cannam@127 279 else let k' = k mod 4 in f1 k' ((k - k') / 4))
cannam@127 280
cannam@127 281 and prime_factor sign n1 n2 input =
cannam@127 282 let tmp1 = array n2 (fun i2 ->
cannam@127 283 dft sign n1 (fun i1 -> input ((i1 * n2 + i2 * n1) mod n)))
cannam@127 284 in let tmp2 = array n1 (fun i1 ->
cannam@127 285 dft sign n2 (fun k2 -> tmp1 k2 i1))
cannam@127 286 in fun i -> tmp2 (i mod n1) (i mod n2)
cannam@127 287
cannam@127 288 in let algorithm sign n =
cannam@127 289 let r = choose_factor n in
cannam@127 290 if List.mem n !Magic.rader_list then
cannam@127 291 (* special cases *)
cannam@127 292 dft_rader sign n
cannam@127 293 else if (r == 1) then (* n is prime *)
cannam@127 294 dft_prime sign n
cannam@127 295 else if (gcd r (n / r)) == 1 then
cannam@127 296 prime_factor sign r (n / r)
cannam@127 297 else if (n mod 4 = 0 && n > 4) then
cannam@127 298 if !Magic.newsplit && is_power_of_two n then
cannam@127 299 newsplit sign n
cannam@127 300 else if !Magic.dif_split_radix then
cannam@127 301 split_radix_dif sign n
cannam@127 302 else
cannam@127 303 split_radix_dit sign n
cannam@127 304 else
cannam@127 305 cooley_tukey sign r (n / r)
cannam@127 306 in
cannam@127 307 array n (algorithm sign n input)