annotate src/fftw-3.3.8/genfft/oracle.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 (*
Chris@82 23 * the oracle decrees whether the sign of an expression should
Chris@82 24 * be changed.
Chris@82 25 *
Chris@82 26 * Say the expression (A - B) appears somewhere. Elsewhere in the
Chris@82 27 * expression dag the expression (B - A) may appear.
Chris@82 28 * The oracle determines which of the two forms is canonical.
Chris@82 29 *
Chris@82 30 * Algorithm: evaluate the expression at a random input, and
Chris@82 31 * keep the expression with the positive sign.
Chris@82 32 *)
Chris@82 33
Chris@82 34 let make_memoizer hash equal =
Chris@82 35 let table = ref Assoctable.empty
Chris@82 36 in
Chris@82 37 (fun f k ->
Chris@82 38 match Assoctable.lookup hash equal k !table with
Chris@82 39 Some value -> value
Chris@82 40 | None ->
Chris@82 41 let value = f k in
Chris@82 42 begin
Chris@82 43 table := Assoctable.insert hash k value !table;
Chris@82 44 value
Chris@82 45 end)
Chris@82 46
Chris@82 47 let almost_equal x y =
Chris@82 48 let epsilon = 1.0E-8 in
Chris@82 49 (abs_float (x -. y) < epsilon) ||
Chris@82 50 (abs_float (x -. y) < epsilon *. (abs_float x +. abs_float y))
Chris@82 51
Chris@82 52 let absid = make_memoizer
Chris@82 53 (fun x -> Expr.hash_float (abs_float x))
Chris@82 54 (fun a b -> almost_equal a b || almost_equal (-. a) b)
Chris@82 55 (fun x -> x)
Chris@82 56
Chris@82 57 let make_random_oracle () = make_memoizer
Chris@82 58 Variable.hash
Chris@82 59 Variable.same
Chris@82 60 (fun _ -> (float (Random.bits())) /. 1073741824.0)
Chris@82 61
Chris@82 62 let the_random_oracle = make_random_oracle ()
Chris@82 63
Chris@82 64 let sum_list l = List.fold_right (+.) l 0.0
Chris@82 65
Chris@82 66 let eval_aux random_oracle =
Chris@82 67 let memoizing = make_memoizer Expr.hash (==) in
Chris@82 68 let rec eval x =
Chris@82 69 memoizing
Chris@82 70 (function
Chris@82 71 | Expr.Num x -> Number.to_float x
Chris@82 72 | Expr.NaN x -> Expr.transcendent_to_float x
Chris@82 73 | Expr.Load v -> random_oracle v
Chris@82 74 | Expr.Store (v, x) -> eval x
Chris@82 75 | Expr.Plus l -> sum_list (List.map eval l)
Chris@82 76 | Expr.Times (a, b) -> (eval a) *. (eval b)
Chris@82 77 | Expr.CTimes (a, b) ->
Chris@82 78 1.098612288668109691395245236 +.
Chris@82 79 1.609437912434100374600759333 *. (eval a) *. (eval b)
Chris@82 80 | Expr.CTimesJ (a, b) ->
Chris@82 81 0.9102392266268373936142401657 +.
Chris@82 82 0.6213349345596118107071993881 *. (eval a) *. (eval b)
Chris@82 83 | Expr.Uminus x -> -. (eval x))
Chris@82 84 x
Chris@82 85 in eval
Chris@82 86
Chris@82 87 let eval = eval_aux the_random_oracle
Chris@82 88
Chris@82 89 let should_flip_sign node =
Chris@82 90 let v = eval node in
Chris@82 91 let v' = absid v in
Chris@82 92 not (almost_equal v v')
Chris@82 93
Chris@82 94 (*
Chris@82 95 * determine with high probability if two expressions are equal.
Chris@82 96 *
Chris@82 97 * The test is randomized: if the two expressions have the
Chris@82 98 * same value for NTESTS random inputs, then they are proclaimed
Chris@82 99 * equal. (Note that two distinct linear functions L1(x0, x1, ..., xn)
Chris@82 100 * and L2(x0, x1, ..., xn) have the same value with probability
Chris@82 101 * 0 for random x's, and thus this test is way more paranoid than
Chris@82 102 * necessary.)
Chris@82 103 *)
Chris@82 104 let likely_equal a b =
Chris@82 105 let tolerance = 1.0e-8
Chris@82 106 and ntests = 20
Chris@82 107 in
Chris@82 108 let rec loop n =
Chris@82 109 if n = 0 then
Chris@82 110 true
Chris@82 111 else
Chris@82 112 let r = make_random_oracle () in
Chris@82 113 let va = eval_aux r a
Chris@82 114 and vb = eval_aux r b
Chris@82 115 in
Chris@82 116 if (abs_float (va -. vb)) >
Chris@82 117 tolerance *. (abs_float va +. abs_float vb +. 0.0001)
Chris@82 118 then
Chris@82 119 false
Chris@82 120 else
Chris@82 121 loop (n - 1)
Chris@82 122 in
Chris@82 123 match (a, b) with
Chris@82 124
Chris@82 125 (*
Chris@82 126 * Because of the way eval is constructed, we have
Chris@82 127 * eval (Store (v, x)) == eval x
Chris@82 128 * However, we never consider the two expressions equal
Chris@82 129 *)
Chris@82 130 | (Expr.Store _, _) -> false
Chris@82 131 | (_, Expr.Store _) -> false
Chris@82 132
Chris@82 133 (*
Chris@82 134 * Expressions of the form ``Uminus (Store _)''
Chris@82 135 * are artifacts of algsimp
Chris@82 136 *)
Chris@82 137 | ((Expr.Uminus (Expr.Store _)), _) -> false
Chris@82 138 | (_, Expr.Uminus (Expr.Store _)) -> false
Chris@82 139
Chris@82 140 | _ -> loop ntests
Chris@82 141
Chris@82 142 let hash x =
Chris@82 143 let f = eval x in
Chris@82 144 truncate (f *. 65536.0)