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