Re: [Haskell-cafe] Bug with QuickCheck 1.1 and GHC 6.8.2

The bug is in the "variant" function in QuickCheck. I replaced variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! (v+1)) where rands r0 = r1 : rands r2 where (r1, r2) = split r0 with variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! v')) where v' = abs (v+1) `mod` 10000 rands r0 = r1 : rands r2 where (r1, r2) = split r0 and now everything works fine. "10000" seems like a reasonable value here, but one could hard-code a lower or higher value as well. Can someone make sure this gets fixed in the next version of QuickCheck? I'm not sure who the maintainer is. Patrick

On Thu, Aug 14, 2008 at 1:58 AM, Patrick Perry
variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! v')) where v' = abs (v+1) `mod` 10000 rands r0 = r1 : rands r2 where (r1, r2) = split r0
Note that if you have a uniformly distributed random value in [0, n) and take its value mod k you don't end up with another random uniformly distributed value unless n `mod` k == 0. Consider n = 3 and k = 2. What you can do is to throw away all random numbers larger than n - (n `mod` k) and just generate a new number. This will terminate with a high probability if n >> k. Cheers, Johan

Actually, a much better solution is: variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r v)) where rands r0 0 = r0 rands r0 n = let (r1,r2) = split r0 (n',s) = n `quotRem` 2 in case s of 0 -> rands r1 n' _ -> rands r2 n' Patrick On Aug 14, 2008, at 2:17 AM, Johan Tibell wrote:
On Thu, Aug 14, 2008 at 1:58 AM, Patrick Perry
wrote: variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! v')) where v' = abs (v+1) `mod` 10000 rands r0 = r1 : rands r2 where (r1, r2) = split r0
Note that if you have a uniformly distributed random value in [0, n) and take its value mod k you don't end up with another random uniformly distributed value unless n `mod` k == 0. Consider n = 3 and k = 2. What you can do is to throw away all random numbers larger than n - (n `mod` k) and just generate a new number. This will terminate with a high probability if n >> k.
Cheers,
Johan

On Thu, Aug 14, 2008 at 12:15 PM, Patrick Perry
Actually, a much better solution is:
variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r v)) where rands r0 0 = r0 rands r0 n = let (r1,r2) = split r0 (n',s) = n `quotRem` 2 in case s of 0 -> rands r1 n' _ -> rands r2 n'
It's not really clear to me how this works. Could you please explain? Cheers, Johan

'split' has type split :: StdGen -> (StdGen, StdGen) It takes a generator and produces two independent generators. The old version of variant calls 'split' n times to get a new generator, and it only calls "split" on the second result. The new version calls split (log n) times. It gets a unique generator for each value of n by using both results from split. For example, rands 2 r0 = let (r1, r2) = split r0 (r3, r4) = split r1 in r4 rands 3 r0 = let (r1,r2) = split r0 (r3',r4') = split r2 in r4' Patrick On Aug 14, 2008, at 4:57 AM, Johan Tibell wrote:
On Thu, Aug 14, 2008 at 12:15 PM, Patrick Perry
wrote: Actually, a much better solution is:
variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r v)) where rands r0 0 = r0 rands r0 n = let (r1,r2) = split r0 (n',s) = n `quotRem` 2 in case s of 0 -> rands r1 n' _ -> rands r2 n'
It's not really clear to me how this works. Could you please explain?
Cheers,
Johan

On Wed 2008-08-13 16:58, Patrick Perry wrote:
variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! v')) where v' = abs (v+1) `mod` 10000 rands r0 = r1 : rands r2 where (r1, r2) = split r0
This sort of defeats the purpose of variant since it is now a nearly random sampling in the predefined range. I filed a bug report (http://hackage.haskell.org/trac/ghc/ticket/2065) but it was closed since it works with QC-2. However, most people don't seem to use QC-2 so it still seems relevant to me. Jed
participants (3)
-
Jed Brown
-
Johan Tibell
-
Patrick Perry