annotate src/fftw-3.3.8/genfft/twiddle.ml @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents d0c2a83c1364
children
rev   line source
Chris@82 1 (*
Chris@82 2 * Copyright (c) 1997-1999 Massachusetts Institute of Technology
Chris@82 3 * Copyright (c) 2003, 2007-14 Matteo Frigo
Chris@82 4 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
Chris@82 5 *
Chris@82 6 * This program is free software; you can redistribute it and/or modify
Chris@82 7 * it under the terms of the GNU General Public License as published by
Chris@82 8 * the Free Software Foundation; either version 2 of the License, or
Chris@82 9 * (at your option) any later version.
Chris@82 10 *
Chris@82 11 * This program is distributed in the hope that it will be useful,
Chris@82 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@82 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@82 14 * GNU General Public License for more details.
Chris@82 15 *
Chris@82 16 * You should have received a copy of the GNU General Public License
Chris@82 17 * along with this program; if not, write to the Free Software
Chris@82 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Chris@82 19 *
Chris@82 20 *)
Chris@82 21
Chris@82 22 (* policies for loading/computing twiddle factors *)
Chris@82 23 open Complex
Chris@82 24 open Util
Chris@82 25
Chris@82 26 type twop = TW_FULL | TW_CEXP | TW_NEXT
Chris@82 27
Chris@82 28 let optostring = function
Chris@82 29 | TW_CEXP -> "TW_CEXP"
Chris@82 30 | TW_NEXT -> "TW_NEXT"
Chris@82 31 | TW_FULL -> "TW_FULL"
Chris@82 32
Chris@82 33 type twinstr = (twop * int * int)
Chris@82 34
Chris@82 35 let rec unroll_twfull l = match l with
Chris@82 36 | [] -> []
Chris@82 37 | (TW_FULL, v, n) :: b ->
Chris@82 38 (forall [] cons 1 n (fun i -> (TW_CEXP, v, i)))
Chris@82 39 @ unroll_twfull b
Chris@82 40 | a :: b -> a :: unroll_twfull b
Chris@82 41
Chris@82 42 let twinstr_to_c_string l =
Chris@82 43 let one (op, a, b) = Printf.sprintf "{ %s, %d, %d }" (optostring op) a b
Chris@82 44 in let rec loop first = function
Chris@82 45 | [] -> ""
Chris@82 46 | a :: b -> (if first then "\n" else ",\n") ^ (one a) ^ (loop false b)
Chris@82 47 in "{" ^ (loop true l) ^ "}"
Chris@82 48
Chris@82 49 let twinstr_to_simd_string vl l =
Chris@82 50 let one sep = function
Chris@82 51 | (TW_NEXT, 1, 0) -> sep ^ "{TW_NEXT, " ^ vl ^ ", 0}"
Chris@82 52 | (TW_NEXT, _, _) -> failwith "twinstr_to_simd_string"
Chris@82 53 | (TW_CEXP, v, b) -> sep ^ (Printf.sprintf "VTW(%d,%d)" v b)
Chris@82 54 | _ -> failwith "twinstr_to_simd_string"
Chris@82 55 in let rec loop first = function
Chris@82 56 | [] -> ""
Chris@82 57 | a :: b -> (one (if first then "\n" else ",\n") a) ^ (loop false b)
Chris@82 58 in "{" ^ (loop true (unroll_twfull l)) ^ "}"
Chris@82 59
Chris@82 60 let rec pow m n =
Chris@82 61 if (n = 0) then 1
Chris@82 62 else m * pow m (n - 1)
Chris@82 63
Chris@82 64 let rec is_pow m n =
Chris@82 65 n = 1 || ((n mod m) = 0 && is_pow m (n / m))
Chris@82 66
Chris@82 67 let rec log m n = if n = 1 then 0 else 1 + log m (n / m)
Chris@82 68
Chris@82 69 let rec largest_power_smaller_than m i =
Chris@82 70 if (is_pow m i) then i
Chris@82 71 else largest_power_smaller_than m (i - 1)
Chris@82 72
Chris@82 73 let rec smallest_power_larger_than m i =
Chris@82 74 if (is_pow m i) then i
Chris@82 75 else smallest_power_larger_than m (i + 1)
Chris@82 76
Chris@82 77 let rec_array n f =
Chris@82 78 let g = ref (fun i -> Complex.zero) in
Chris@82 79 let a = Array.init n (fun i -> lazy (!g i)) in
Chris@82 80 let h i = f (fun i -> Lazy.force a.(i)) i in
Chris@82 81 begin
Chris@82 82 g := h;
Chris@82 83 h
Chris@82 84 end
Chris@82 85
Chris@82 86
Chris@82 87 let ctimes use_complex_arith a b =
Chris@82 88 if use_complex_arith then
Chris@82 89 Complex.ctimes a b
Chris@82 90 else
Chris@82 91 Complex.times a b
Chris@82 92
Chris@82 93 let ctimesj use_complex_arith a b =
Chris@82 94 if use_complex_arith then
Chris@82 95 Complex.ctimesj a b
Chris@82 96 else
Chris@82 97 Complex.times (Complex.conj a) b
Chris@82 98
Chris@82 99 let make_bytwiddle sign use_complex_arith g f i =
Chris@82 100 if i = 0 then
Chris@82 101 f i
Chris@82 102 else if sign = 1 then
Chris@82 103 ctimes use_complex_arith (g i) (f i)
Chris@82 104 else
Chris@82 105 ctimesj use_complex_arith (g i) (f i)
Chris@82 106
Chris@82 107 (* various policies for computing/loading twiddle factors *)
Chris@82 108
Chris@82 109 let twiddle_policy_load_all v use_complex_arith =
Chris@82 110 let bytwiddle n sign w f =
Chris@82 111 make_bytwiddle sign use_complex_arith (fun i -> w (i - 1)) f
Chris@82 112 and twidlen n = 2 * (n - 1)
Chris@82 113 and twdesc r = [(TW_FULL, v, r);(TW_NEXT, 1, 0)]
Chris@82 114 in bytwiddle, twidlen, twdesc
Chris@82 115
Chris@82 116 (*
Chris@82 117 * if i is a power of two, then load w (log i)
Chris@82 118 * else let x = largest power of 2 less than i in
Chris@82 119 * let y = i - x in
Chris@82 120 * compute w^{x+y} = w^x * w^y
Chris@82 121 *)
Chris@82 122 let twiddle_policy_log2 v use_complex_arith =
Chris@82 123 let bytwiddle n sign w f =
Chris@82 124 let g = rec_array n (fun self i ->
Chris@82 125 if i = 0 then Complex.one
Chris@82 126 else if is_pow 2 i then w (log 2 i)
Chris@82 127 else let x = largest_power_smaller_than 2 i in
Chris@82 128 let y = i - x in
Chris@82 129 ctimes use_complex_arith (self x) (self y))
Chris@82 130 in make_bytwiddle sign use_complex_arith g f
Chris@82 131 and twidlen n = 2 * (log 2 (largest_power_smaller_than 2 (2 * n - 1)))
Chris@82 132 and twdesc n =
Chris@82 133 (List.flatten
Chris@82 134 (List.map
Chris@82 135 (fun i ->
Chris@82 136 if i > 0 && is_pow 2 i then
Chris@82 137 [TW_CEXP, v, i]
Chris@82 138 else
Chris@82 139 [])
Chris@82 140 (iota n)))
Chris@82 141 @ [(TW_NEXT, 1, 0)]
Chris@82 142 in bytwiddle, twidlen, twdesc
Chris@82 143
Chris@82 144 let twiddle_policy_log3 v use_complex_arith =
Chris@82 145 let rec terms_needed i pi s n =
Chris@82 146 if (s >= n - 1) then i
Chris@82 147 else terms_needed (i + 1) (3 * pi) (s + pi) n
Chris@82 148 in
Chris@82 149 let rec bytwiddle n sign w f =
Chris@82 150 let nterms = terms_needed 0 1 0 n in
Chris@82 151 let maxterm = pow 3 (nterms - 1) in
Chris@82 152 let g = rec_array (3 * n) (fun self i ->
Chris@82 153 if i = 0 then Complex.one
Chris@82 154 else if is_pow 3 i then w (log 3 i)
Chris@82 155 else if i = (n - 1) && maxterm >= n then
Chris@82 156 w (nterms - 1)
Chris@82 157 else let x = smallest_power_larger_than 3 i in
Chris@82 158 if (i + i >= x) then
Chris@82 159 let x = min x (n - 1) in
Chris@82 160 ctimesj use_complex_arith (self (x - i)) (self x)
Chris@82 161 else let x = largest_power_smaller_than 3 i in
Chris@82 162 ctimes use_complex_arith (self (i - x)) (self x))
Chris@82 163 in make_bytwiddle sign use_complex_arith g f
Chris@82 164 and twidlen n = 2 * (terms_needed 0 1 0 n)
Chris@82 165 and twdesc n =
Chris@82 166 (List.map
Chris@82 167 (fun i ->
Chris@82 168 let x = min (pow 3 i) (n - 1) in
Chris@82 169 TW_CEXP, v, x)
Chris@82 170 (iota ((twidlen n) / 2)))
Chris@82 171 @ [(TW_NEXT, 1, 0)]
Chris@82 172 in bytwiddle, twidlen, twdesc
Chris@82 173
Chris@82 174 let current_twiddle_policy = ref twiddle_policy_load_all
Chris@82 175
Chris@82 176 let twiddle_policy use_complex_arith =
Chris@82 177 !current_twiddle_policy use_complex_arith
Chris@82 178
Chris@82 179 let set_policy x = Arg.Unit (fun () -> current_twiddle_policy := x)
Chris@82 180 let set_policy_int x = Arg.Int (fun i -> current_twiddle_policy := x i)
Chris@82 181
Chris@82 182 let undocumented = " Undocumented twiddle policy"
Chris@82 183
Chris@82 184 let speclist = [
Chris@82 185 "-twiddle-load-all", set_policy twiddle_policy_load_all, undocumented;
Chris@82 186 "-twiddle-log2", set_policy twiddle_policy_log2, undocumented;
Chris@82 187 "-twiddle-log3", set_policy twiddle_policy_log3, undocumented;
Chris@82 188 ]