    -- |
    -- Module    : Statistics.Test.MannWhitneyU
    -- Copyright : (c) 2010 Neil Brown
    -- License   : BSD3
    --
    -- Maintainer  : bos@serpentine.com
    -- Stability   : experimental
    -- Portability : portable
    --
    -- Mann-Whitney U test (also know as Mann-Whitney-Wilcoxon and
    -- Wilcoxon rank sum test) is a non-parametric test for assessing
    -- whether two samples of independent observations have different
    -- mean.
    module Statistics.Test.MannWhitneyU (
        -- * Mann-Whitney U test
        mannWhitneyUtest
      , mannWhitneyU
      , mannWhitneyUCriticalValue
      , mannWhitneyUSignificant
        -- ** Wilcoxon rank sum test
      , wilcoxonRankSums
      , module Statistics.Test.Types
        -- * References
        -- $references
      ) where

    import Data.List (findIndex)
    import Data.Ord (comparing)
    import Numeric.SpecFunctions (choose)
    import Prelude hiding (sum)
    import Statistics.Distribution (quantile)
    import Statistics.Distribution.Normal (standard)
    import Statistics.Function (sortBy)
    import Statistics.Sample.Internal (sum)
    import Statistics.Test.Internal (rank, splitByTags)
    import Statistics.Test.Types (TestResult(..), PositionTest(..), significant)
    import Statistics.Types (PValue,pValue)
    import qualified Data.Vector.Unboxed as U

    -- | The Wilcoxon Rank Sums Test.
    --
    -- This test calculates the sum of ranks for the given two samples.
    -- The samples are ordered, and assigned ranks (ties are given their
    -- average rank), then these ranks are summed for each sample.
    --
    -- The return value is (W₁, W₂) where W₁ is the sum of ranks of the first sample
    -- and W₂ is the sum of ranks of the second sample.  This test is trivially transformed
    -- into the Mann-Whitney U test.  You will probably want to use 'mannWhitneyU'
    -- and the related functions for testing significance, but this function is exposed
    -- for completeness.
    wilcoxonRankSums :: (Ord a, U.Unbox a) => U.Vector a -> U.Vector a -> (Double, Double)
    wilcoxonRankSums :: forall a.
    (Ord a, Unbox a) =>
    Vector a -> Vector a -> (Double, Double)
    wilcoxonRankSums Vector a
    xs1 Vector a
    xs2 = (Vector Double -> Double
    forall (v :: * -> *). Vector v Double => v Double -> Double
    sum Vector Double
    ranks1, Vector Double -> Double
    forall (v :: * -> *). Vector v Double => v Double -> Double
    sum Vector Double
    ranks2)
      where
        -- Ranks for each sample
        (Vector Double
    ranks1,Vector Double
    ranks2) = Vector (Bool, Double) -> (Vector Double, Vector Double)
    forall (v :: * -> *) a.
    (Vector v a, Vector v (Bool, a)) =>
    v (Bool, a) -> (v a, v a)
    splitByTags (Vector (Bool, Double) -> (Vector Double, Vector Double))
    -> Vector (Bool, Double) -> (Vector Double, Vector Double)
    forall a b. (a -> b) -> a -> b
    $ Vector Bool -> Vector Double -> Vector (Bool, Double)
    forall a b.
    (Unbox a, Unbox b) =>
    Vector a -> Vector b -> Vector (a, b)
    U.zip Vector Bool
    tags ((a -> a -> Bool) -> Vector a -> Vector Double
    forall (v :: * -> *) a.
    (Vector v a, Vector v Double) =>
    (a -> a -> Bool) -> v a -> v Double
    rank a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) Vector a
    joinSample)
        -- Sorted and tagged sample
        (Vector Bool
    tags,Vector a
    joinSample) = Vector (Bool, a) -> (Vector Bool, Vector a)
    forall a b.
    (Unbox a, Unbox b) =>
    Vector (a, b) -> (Vector a, Vector b)
    U.unzip
                          (Vector (Bool, a) -> (Vector Bool, Vector a))
    -> Vector (Bool, a) -> (Vector Bool, Vector a)
    forall a b. (a -> b) -> a -> b
    $ Comparison (Bool, a) -> Vector (Bool, a) -> Vector (Bool, a)
    forall (v :: * -> *) e. Vector v e => Comparison e -> v e -> v e
    sortBy (((Bool, a) -> a) -> Comparison (Bool, a)
    forall a b. Ord a => (b -> a) -> b -> b -> Ordering
    comparing (Bool, a) -> a
    forall a b. (a, b) -> b
    snd)
                          (Vector (Bool, a) -> Vector (Bool, a))
    -> Vector (Bool, a) -> Vector (Bool, a)
    forall a b. (a -> b) -> a -> b
    $ Bool -> Vector a -> Vector (Bool, a)
    forall {b} {a}.
    (Unbox b, Unbox a) =>
    a -> Vector b -> Vector (a, b)
    tagSample Bool
    True Vector a
    xs1 Vector (Bool, a) -> Vector (Bool, a) -> Vector (Bool, a)
    forall a. Unbox a => Vector a -> Vector a -> Vector a
    U.++ Bool -> Vector a -> Vector (Bool, a)
    forall {b} {a}.
    (Unbox b, Unbox a) =>
    a -> Vector b -> Vector (a, b)
    tagSample Bool
    False Vector a
    xs2
        -- Add tag to a sample
        tagSample :: a -> Vector b -> Vector (a, b)
    tagSample a
    t = (b -> (a, b)) -> Vector b -> Vector (a, b)
    forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
    U.map (\b
    x -> (a
    t,b
    x))

    -- | The Mann-Whitney U Test.
    --
    -- This is sometimes known as the Mann-Whitney-Wilcoxon U test, and
    -- confusingly many sources state that the Mann-Whitney U test is the same as
    -- the Wilcoxon's rank sum test (which is provided as 'wilcoxonRankSums').
    -- The Mann-Whitney U is a simple transform of Wilcoxon's rank sum test.
    --
    -- Again confusingly, different sources state reversed definitions for U₁
    -- and U₂, so it is worth being explicit about what this function returns.
    -- Given two samples, the first, xs₁, of size n₁ and the second, xs₂,
    -- of size n₂, this function returns (U₁, U₂)
    -- where U₁ = W₁ - (n₁(n₁+1))\/2
    -- and U₂ = W₂ - (n₂(n₂+1))\/2,
    -- where (W₁, W₂) is the return value of @wilcoxonRankSums xs1 xs2@.
    --
    -- Some sources instead state that U₁ and U₂ should be the other way round, often
    -- expressing this using U₁' = n₁n₂ - U₁ (since U₁ + U₂ = n₁n₂).
    --
    -- All of which you probably don't care about if you just feed this into 'mannWhitneyUSignificant'.
    mannWhitneyU :: (Ord a, U.Unbox a) => U.Vector a -> U.Vector a -> (Double, Double)
    mannWhitneyU :: forall a.
    (Ord a, Unbox a) =>
    Vector a -> Vector a -> (Double, Double)
    mannWhitneyU Vector a
    xs1 Vector a
    xs2
      = ((Double, Double) -> Double
    forall a b. (a, b) -> a
    fst (Double, Double)
    summedRanks Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - (Double
    n1Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *(Double
    n1 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + Double
    1))Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    /Double
    2
        ,(Double, Double) -> Double
    forall a b. (a, b) -> b
    snd (Double, Double)
    summedRanks Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - (Double
    n2Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *(Double
    n2 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + Double
    1))Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    /Double
    2)
      where
        n1 :: Double
    n1 = Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> Double) -> Int -> Double
    forall a b. (a -> b) -> a -> b
    $ Vector a -> Int
    forall a. Unbox a => Vector a -> Int
    U.length Vector a
    xs1
        n2 :: Double
    n2 = Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> Double) -> Int -> Double
    forall a b. (a -> b) -> a -> b
    $ Vector a -> Int
    forall a. Unbox a => Vector a -> Int
    U.length Vector a
    xs2

        summedRanks :: (Double, Double)
    summedRanks = Vector a -> Vector a -> (Double, Double)
    forall a.
    (Ord a, Unbox a) =>
    Vector a -> Vector a -> (Double, Double)
    wilcoxonRankSums Vector a
    xs1 Vector a
    xs2

    -- | Calculates the critical value of Mann-Whitney U for the given sample
    -- sizes and significance level.
    --
    -- This function returns the exact calculated value of U for all sample sizes;
    -- it does not use the normal approximation at all.  Above sample size 20 it is
    -- generally recommended to use the normal approximation instead, but this function
    -- will calculate the higher critical values if you need them.
    --
    -- The algorithm to generate these values is a faster, memoised version of the
    -- simple unoptimised generating function given in section 2 of \"The Mann Whitney
    -- Wilcoxon Distribution Using Linked Lists\"
    mannWhitneyUCriticalValue
      :: (Int, Int)     -- ^ The sample size
      -> PValue Double  -- ^ The p-value (e.g. 0.05) for which you want the critical value.
      -> Maybe Int      -- ^ The critical value (of U).
    mannWhitneyUCriticalValue :: (Int, Int) -> PValue Double -> Maybe Int
    mannWhitneyUCriticalValue (Int
    m, Int
    n) PValue Double
    p
      | Int
    m Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    1 Bool -> Bool -> Bool
    || Int
    n Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    1 = Maybe Int
    forall a. Maybe a
    Nothing    -- Sample must be nonempty
      | Double
    p' Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Double
    1        = Maybe Int
    forall a. Maybe a
    Nothing    -- p-value is too small. Null hypothesis couldn't be disproved
      | Bool
    otherwise      = (Double -> Bool) -> [Double] -> Maybe Int
    forall a. (a -> Bool) -> [a] -> Maybe Int
    findIndex (Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Double
    p')
                       ([Double] -> Maybe Int) -> [Double] -> Maybe Int
    forall a b. (a -> b) -> a -> b
    $ Int -> [Double] -> [Double]
    forall a. Int -> [a] -> [a]
    take (Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    *Int
    n)
                       ([Double] -> [Double]) -> [Double] -> [Double]
    forall a b. (a -> b) -> a -> b
    $ [Double] -> [Double]
    forall a. HasCallStack => [a] -> [a]
    tail
                       ([Double] -> [Double]) -> [Double] -> [Double]
    forall a b. (a -> b) -> a -> b
    $ [[[Double]]]
    alookup [[[Double]]] -> Int -> [[Double]]
    forall a. HasCallStack => [a] -> Int -> a
    !! (Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    nInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    2) [[Double]] -> Int -> [Double]
    forall a. HasCallStack => [a] -> Int -> a
    !! (Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    min Int
    m Int
    n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1)
      where
        mnCn :: Double
    mnCn = (Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    n) Int -> Int -> Double
    `choose` Int
    n
        p' :: Double
    p'   = Double
    mnCn Double -> Double -> Double
    forall a. Num a => a -> a -> a
    * PValue Double -> Double
    forall a. PValue a -> a
    pValue PValue Double
    p

    {-
    -- Original function, without memoisation, from Cheung and Klotz:
    -- Double is needed to avoid integer overflows.
    a :: Int -> Int -> Int -> Double
    a u bigN m
      | u < 0            = 0
      | u >= m * n       = bigN `choose` m
      | m == 1 || n == 1 = fromIntegral (u + 1)
      | otherwise        = a  u      (bigN - 1)  m
                         + a (u - n) (bigN - 1) (m-1)
      where
        n = bigN - m
    -}

    -- Memoised version of the original a function, above.
    --
    -- Doubles are stored to avoid integer overflow. 32-bit Ints begin to
    -- overflow for bigN as small as 33 (64-bit one at 66) while Double to
    -- go to infinity till bigN=1029
    --
    --
    -- outer list is indexed by big N - 2
    -- inner list by (m-1) (we know m < bigN)
    -- innermost list by u
    --
    -- So: (alookup !! (bigN - 2) !! (m - 1) ! u) == a u bigN m
    alookup :: [[[Double]]]
    alookup :: [[[Double]]]
    alookup = Int -> [[Double]] -> [[[Double]]]
    gen Int
    2 [Double
    1 Double -> [Double] -> [Double]
    forall a. a -> [a] -> [a]
    : Double -> [Double]
    forall a. a -> [a]
    repeat Double
    2]
      where
        gen :: Int -> [[Double]] -> [[[Double]]]
    gen Int
    bigN [[Double]]
    predBigNList
           = let bigNlist :: [[Double]]
    bigNlist = [ [ Int -> Int -> Double
    amemoed Int
    u Int
    m
                              | Int
    u <- [Int
    0 .. Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    *(Int
    bigNInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    m)]
                              ] [Double] -> [Double] -> [Double]
    forall a. [a] -> [a] -> [a]
    ++ Double -> [Double]
    forall a. a -> [a]
    repeat (Int
    bigN Int -> Int -> Double
    `choose` Int
    m)
                            | Int
    m <- [Int
    1 .. (Int
    bigNInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    1)]] -- has bigN-1 elements
             in [[Double]]
    bigNlist [[Double]] -> [[[Double]]] -> [[[Double]]]
    forall a. a -> [a] -> [a]
    : Int -> [[Double]] -> [[[Double]]]
    gen (Int
    bigNInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +Int
    1) [[Double]]
    bigNlist
          where
            amemoed :: Int -> Int -> Double
            amemoed :: Int -> Int -> Double
    amemoed Int
    u Int
    m
              | Int
    m Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    1 Bool -> Bool -> Bool
    || Int
    n Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    1 = Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int
    u Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1)
              | Bool
    otherwise        = [Double]
    mList [Double] -> Int -> Double
    forall a. HasCallStack => [a] -> Int -> a
    !! Int
    u
                                 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + if Int
    u Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    n then Double
    0 else [Double]
    predmList [Double] -> Int -> Double
    forall a. HasCallStack => [a] -> Int -> a
    !! (Int
    uInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    n)
              where
                n :: Int
    n = Int
    bigN Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    m
                ([Double]
    predmList : [Double]
    mList : [[Double]]
    _) = Int -> [[Double]] -> [[Double]]
    forall a. Int -> [a] -> [a]
    drop (Int
    mInt -> Int -> Int
    forall a. Num a => a -> a -> a
    -Int
    2) [[Double]]
    predBigNList
                -- Lists for m-1 and m respectively. i-th list correspond to m=i+1
                --
                -- We know that predBigNList has bigN - 2 elements
                -- (and we know that n > 1 therefore bigN > m + 1)
                -- So bigN - 2 >= m, i.e. predBigNList must have at least m elements
                -- elements, so dropping (m-2) must leave at least 2

    -- | Calculates whether the Mann Whitney U test is significant.
    --
    -- If both sample sizes are less than or equal to 20, the exact U critical value
    -- (as calculated by 'mannWhitneyUCriticalValue') is used.  If either sample is
    -- larger than 20, the normal approximation is used instead.
    --
    -- If you use a one-tailed test, the test indicates whether the first sample is
    -- significantly larger than the second.  If you want the opposite, simply reverse
    -- the order in both the sample size and the (U₁, U₂) pairs.
    mannWhitneyUSignificant
      :: PositionTest     -- ^ Perform one-tailed test (see description above).
      -> (Int, Int)       -- ^ The samples' size from which the (U₁,U₂) values were derived.
      -> PValue Double    -- ^ The p-value at which to test (e.g. 0.05)
      -> (Double, Double) -- ^ The (U₁, U₂) values from 'mannWhitneyU'.
      -> Maybe TestResult -- ^ Return 'Nothing' if the sample was too
                          --   small to make a decision.
    mannWhitneyUSignificant :: PositionTest
    -> (Int, Int)
    -> PValue Double
    -> (Double, Double)
    -> Maybe TestResult
    mannWhitneyUSignificant PositionTest
    test (Int
    in1, Int
    in2) PValue Double
    pVal (Double
    u1, Double
    u2)
      -- Use normal approximation
      | Int
    in1 Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    20 Bool -> Bool -> Bool
    || Int
    in2 Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    20 =
        let mean :: Double
    mean  = Double
    n1 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    * Double
    n2 Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    / Double
    2     -- (u1+u2) / 2
            sigma :: Double
    sigma = Double -> Double
    forall a. Floating a => a -> a
    sqrt (Double -> Double) -> Double -> Double
    forall a b. (a -> b) -> a -> b
    $ Double
    n1Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *Double
    n2Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *(Double
    n1 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + Double
    n2 Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + Double
    1) Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    / Double
    12
            z :: Double
    z     = (Double
    mean Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    u1) Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    / Double
    sigma
        in TestResult -> Maybe TestResult
    forall a. a -> Maybe a
    Just (TestResult -> Maybe TestResult) -> TestResult -> Maybe TestResult
    forall a b. (a -> b) -> a -> b
    $ case PositionTest
    test of
                    PositionTest
    AGreater      -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ Double
    z     Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    < NormalDistribution -> Double -> Double
    forall d. ContDistr d => d -> Double -> Double
    quantile NormalDistribution
    standard Double
    p
                    PositionTest
    BGreater      -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ (-Double
    z)  Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    < NormalDistribution -> Double -> Double
    forall d. ContDistr d => d -> Double -> Double
    quantile NormalDistribution
    standard Double
    p
                    PositionTest
    SamplesDiffer -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ Double -> Double
    forall a. Num a => a -> a
    abs Double
    z Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    > Double -> Double
    forall a. Num a => a -> a
    abs (NormalDistribution -> Double -> Double
    forall d. ContDistr d => d -> Double -> Double
    quantile NormalDistribution
    standard (Double
    pDouble -> Double -> Double
    forall a. Fractional a => a -> a -> a
    /Double
    2))
      -- Use exact critical value
      | Bool
    otherwise = do Double
    crit <- Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Int -> Double) -> Maybe Int -> Maybe Double
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Int, Int) -> PValue Double -> Maybe Int
    mannWhitneyUCriticalValue (Int
    in1, Int
    in2) PValue Double
    pVal
                       TestResult -> Maybe TestResult
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (TestResult -> Maybe TestResult) -> TestResult -> Maybe TestResult
    forall a b. (a -> b) -> a -> b
    $ case PositionTest
    test of
                                  PositionTest
    AGreater      -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ Double
    u2        Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Double
    crit
                                  PositionTest
    BGreater      -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ Double
    u1        Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Double
    crit
                                  PositionTest
    SamplesDiffer -> Bool -> TestResult
    significant (Bool -> TestResult) -> Bool -> TestResult
    forall a b. (a -> b) -> a -> b
    $ Double -> Double -> Double
    forall a. Ord a => a -> a -> a
    min Double
    u1 Double
    u2 Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Double
    crit
      where
        n1 :: Double
    n1 = Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    in1
        n2 :: Double
    n2 = Int -> Double
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    in2
        p :: Double
    p  = PValue Double -> Double
    forall a. PValue a -> a
    pValue PValue Double
    pVal

    -- | Perform Mann-Whitney U Test for two samples and required
    -- significance. For additional information check documentation of
    -- 'mannWhitneyU' and 'mannWhitneyUSignificant'. This is just a helper
    -- function.
    --
    -- One-tailed test checks whether first sample is significantly larger
    -- than second. Two-tailed whether they are significantly different.
    mannWhitneyUtest
      :: (Ord a, U.Unbox a)
      => PositionTest     -- ^ Perform one-tailed test (see description above).
      -> PValue Double    -- ^ The p-value at which to test (e.g. 0.05)
      -> U.Vector a       -- ^ First sample
      -> U.Vector a       -- ^ Second sample
      -> Maybe TestResult -- ^ Return 'Nothing' if the sample was too small to
                          --   make a decision.
    mannWhitneyUtest :: forall a.
    (Ord a, Unbox a) =>
    PositionTest
    -> PValue Double -> Vector a -> Vector a -> Maybe TestResult
    mannWhitneyUtest PositionTest
    ontTail PValue Double
    p Vector a
    smp1 Vector a
    smp2 =
      PositionTest
    -> (Int, Int)
    -> PValue Double
    -> (Double, Double)
    -> Maybe TestResult
    mannWhitneyUSignificant PositionTest
    ontTail (Int
    n1,Int
    n2) PValue Double
    p ((Double, Double) -> Maybe TestResult)
    -> (Double, Double) -> Maybe TestResult
    forall a b. (a -> b) -> a -> b
    $ Vector a -> Vector a -> (Double, Double)
    forall a.
    (Ord a, Unbox a) =>
    Vector a -> Vector a -> (Double, Double)
    mannWhitneyU Vector a
    smp1 Vector a
    smp2
        where
          n1 :: Int
    n1 = Vector a -> Int
    forall a. Unbox a => Vector a -> Int
    U.length Vector a
    smp1
          n2 :: Int
    n2 = Vector a -> Int
    forall a. Unbox a => Vector a -> Int
    U.length Vector a
    smp2

    -- $references
    --
    -- * Cheung, Y.K.; Klotz, J.H. (1997) The Mann Whitney Wilcoxon
    --   distribution using linked lists. /Statistica Sinica/
    --   7:805&#8211;813.
    -- <http://www3.stat.sinica.edu.tw/statistica/oldpdf/A7n316.pdf>.