5 , Monad(..), forM, replicateM, unless, when
7 , Either(..), either, isLeft, isRight
8 , ($), (.), id, const, flip
12 , Monoid(..), Semigroup(..)
17 , Num, Fractional(..), Integral(..), Integer, fromIntegral
31 import Control.Applicative (Applicative(..))
33 import Control.Monad.Trans.Class
34 import Control.Monad.Trans.Except
35 import Control.Monad.Trans.State.Strict
37 import Data.Either (Either(..), either, isLeft, isRight)
38 import Data.Eq (Eq(..))
40 import Data.Functor ((<$>))
42 import Data.Maybe (Maybe(..))
43 import Data.Monoid (Monoid(..))
44 import Data.Ord (Ord(..))
45 import Data.Semigroup (Semigroup(..))
46 import Data.String (String)
47 import Data.Text (Text)
48 import Data.Word (Word8)
50 import Prelude (Num(..), Fractional(..), Integral(..), Integer, undefined, fromIntegral)
51 import System.Random (mkStdGen)
53 import Text.Show (Show(..))
55 debug msg x = trace (msg<>": "<>show x) x
57 -- | @'nCk' n k@ returns the number of combinations
58 -- of size 'k' from a set of size 'n'.
60 -- Computed using the formula:
61 -- @'nCk' n (k+1) == 'nCk' n (k-1) * (n-k+1) / k@
62 nCk :: Integral i => i -> i -> i
63 n`nCk`k | n<0||k<0||n<k = undefined
66 go i acc = if k' < i then acc else go (i+1) (acc * (n-i+1) `div` i)
67 -- Use a symmetry to compute over smaller numbers,
68 -- which is more efficient and safer
69 k' = if n`div`2 < k then n-k else k
71 -- | @'combinOfRank' n k r@ returns the @r@-th combination
72 -- of @k@ elements from a set of @n@ elements.
73 -- DOC: <http://www.site.uottawa.ca/~lucia/courses/5165-09/GenCombObj.pdf>, p.26
74 combinOfRank :: Integral i => i -> i -> i -> [i]
75 combinOfRank n k rk | rk<0||n`nCk`k<rk = undefined
76 | otherwise = for1K 1 1 rk
78 for1K i j r | i < k = uptoRank i j r
79 | i == k = [j+r] -- because when i == k, nbCombs is always 1
81 uptoRank i j r | nbCombs <- (n-j)`nCk`(k-i)
82 , nbCombs <= r = uptoRank i (j+1) (r-nbCombs)
83 | otherwise = j : for1K (i+1) (j+1) r