packages feed

varan-0.3: src/RandomSelect.hs

-- Calculates p-values using a permutation test (not currently used)

module RandomSelect where

import System.Random
import Control.Monad.State
import Variants
import AgrestiCoull (confidenceInterval)

pval_max_count :: Int
pval_max_count = 1000

pval_acc :: Double
pval_acc = 0.01

pval :: RandomGen g => g -> ([Counts] -> Double) -> [Counts] -> (Double,Double)
pval g f cs = let thresh = f cs
                  xs = take pval_max_count $ rselect g cs
                  go suc tot (y:ys) = let (a,b) = confidenceInterval 1.0 suc (tot-suc) 
                                      in if b-a <= pval_acc then fromIntegral suc/fromIntegral tot 
                                         else go (suc + if f y >= thresh then 1 else 0) (tot+1) ys
                  go suc tot [] = fromIntegral suc/fromIntegral tot
              in if thresh > 0 then (thresh, go 0 0 xs) else (0,1)

type AlleleSample = (Int,Int,Int,Int)

-- generate an infinite stream of sampled allele distributions
rselect :: RandomGen g => g -> [Counts] -> [[Counts]]
rselect g cs = map fromLists $ fst $ runState sel (g,sum_al,pool_sizes)
  where (_tot,sum_al,pool_sizes) = count cs
        
fromLists :: [AlleleSample] -> [Counts]
fromLists = map f
  where f (a,b,c,d) = C a b c d []
        
sel :: RandomGen g => State (g,AlleleSample,[Int]) [[AlleleSample]]
sel = do
  a <- select1
  as <- sel
  return (a:as)
        
select1 :: RandomGen g => State (g,AlleleSample,[Int]) [AlleleSample]
select1 = do
  -- select randomly for each p_sz
  (g,s_al,p_sz) <- get
  let (g',g'') = split g
  put (g'',s_al,p_sz) -- restore state
  return $ pickNs g' p_sz s_al

-- pick a random sampling of alleles given pool sizes
pickNs :: RandomGen g => g -> [Int] -> AlleleSample -> [AlleleSample]
pickNs _ [] _als = [] -- verify that als is empty
pickNs g (p:ps) als = let
  (g1,g2) = split g
  in pickN' g1 als p : pickNs g2 ps als

-- sample alleles given randomgen, count, and sum alleles (i.e. distribution)
pickN' :: RandomGen g => g -> AlleleSample -> Int -> AlleleSample
pickN' g als = go (0,0,0,0) g
  where
        go acc _ 0 = acc
        go acc g1 cnt = 
          let (i,g2) = randomR (1,sum' als) g1
          in go (add i als acc) g2 (cnt-1)
        sum' (a,b,c,d) = a+b+c+d
        
-- count total alleles, number of each variant, and number in each count
count :: [Counts] -> (Int,AlleleSample,[Int])
count cs = let xs = sumList . map toList $ cs
               ys = map (sum . toList) cs
               tuple [a,b,c,d] = (a,b,c,d)
           in (sum xs,tuple xs,ys)

add :: Int -> AlleleSample -> AlleleSample -> AlleleSample
add i (a,b,c,d) (x,y,z,w)
  | i <= a = (x+1,y,z,w)
  | i <= a+b = (x,y+1,z,w)
  | i <= a+b+c = (x,y,z+1,w)               
  | i <= a+b+c+d = (x,y,z,w+1)               
  | otherwise = error "too high i"

{-
-- remove allele number x from input
pick :: Int -> AlleleSample -> AlleleSample
pick x (a:as) | x <= a = 1 : map (const 0) as
              | otherwise = 0 : pick (x-a) as
pick _ [] = error "pick ran out of input, x too large"
-}