http://qs1969.pair.com?node_id=482077


in reply to Re^6: Algorithm for cancelling common factors between two lists of multiplicands
in thread Algorithm for cancelling common factors between two lists of multiplicands

My Haskell implementation represents numbers as the ratio of products of ordered integer streams. For example, I represent 3!/(4*5) as (R numerator=[1,2,3] denominator=[4,5]). In this representation, multiplication becomes merging the numerator and denominator streams and then canceling the first stream by the second. In this way I can remove all cancelable original terms in the Pcutoff formula before finally multiplying the terms that remain.
*FishersExactTest> fac 6 R {numer = [2,3,4,5,6], denom = []} *FishersExactTest> fac 3 R {numer = [2,3], denom = []} *FishersExactTest> fac 6 `rdivide` fac 3 R {numer = [4,5,6], denom = []}
Here's the example from the MathWorld page:
*FishersExactTest> rpCutoff [ [5,0], [1,4] ] R {numer = [2,3,4,5], denom = [7,8,9,10]} *FishersExactTest> fromRational . toRatio $ it 2.3809523809523808e-2
The code:
module FishersExactTest (pCutoff) where import Data.Ratio import Data.List (transpose) pCutoff = toRatio . rpCutoff rpCutoff rows = facproduct (rs ++ cs) `rdivide` facproduct (n:xs) where rs = map sum rows cs = map sum (transpose rows) n = sum rs xs = concat rows -- cells facproduct = rproduct . map fac fac n | n < 2 = runit | otherwise = R [2..n] [] -- I represent numbers as ratios of products of integer streams -- R [1,2,3] [4,5] === (1 * 2 * 3) / (4 * 5) data Rops = R { numer :: [Int], denom :: [Int] } deriving Show runit = R [] [] -- the number 1 toRatio (R ns ds) = bigProduct ns % bigProduct ds bigProduct = product . map toInteger -- multiplication is merging numerator and denominator streams -- and then canceling the first by the second rtimes (R xns xds) (R yns yds) = uncurry R $ (merge xns yns) `cancel` (merge xds yds) rproduct = foldr rtimes runit -- division is multiplication by the inverse rdivide x (R yns yds) = rtimes x (R yds yns) -- helpers merge (x:xs) (y:ys) | x < y = x : merge xs (y:ys) | otherwise = y : merge (x:xs) ys merge [] ys = ys merge xs [] = xs cancel (x:xs) (y:ys) | x == y = cancel xs ys | x < y = let (xs', ys') = cancel xs (y:ys) in (x:xs', ys') | otherwise = let (xs', ys') = cancel (x:xs) ys in (xs', y:ys') cancel xs ys = (xs, ys)

Replies are listed 'Best First'.
Re^8: Algorithm for cancelling common factors between two lists of multiplicands
by BrowserUk (Patriarch) on Aug 09, 2005 at 01:18 UTC
      You didn't do anything wrong, but you did ask for the internal representation (via rpCutoff) instead of the final ratio (via pCutoff). The internal representation is likely to be insanly huge for large problems.

      Save the other code as FishersExactTest.hs and the following as Main.hs and then compile:
      ghc -O2 -o fet --make Main.hs
      to get a program fet that you can pipe a matrix into.

      module Main (main) where import FishersExactTest (pCutoff) main = interact $ show . pCutoff . map (map read . words) . lines
      See my earlier node (Re^5: Algorithm for cancelling common factors between two lists of multiplicands) for an example of usage.

        Hmm 1%1?

        C:\ghc\ghc-6.4\code>ghc --make FET.hs -o FET.exe Chasing modules from: FET.hs Compiling FishersExactTest ( ./FishersExactTest.hs, ./FishersExactTest +.o ) Compiling Main ( FET.hs, FET.o ) Linking ... C:\ghc\ghc-6.4\code>FET 989 9400 43400 2400 ^Z 1%1 C:\ghc\ghc-6.4\code>echo 989 9400 43400 2400 | FET 1%1

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.