Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScalaCheck: choose an integer with custom probability distribution

I want to create a generator in ScalaCheck that generates numbers between say 1 and 100, but with a bell-like bias towards numbers closer to 1.

Gen.choose() distributes numbers randomly between the min and max value:

scala> (1 to 10).flatMap(_ => Gen.choose(1,100).sample).toList.sorted
res14: List[Int] = List(7, 21, 30, 46, 52, 64, 66, 68, 86, 86)

And Gen.chooseNum() has an added bias for the upper and lower bounds:

scala> (1 to 10).flatMap(_ => Gen.chooseNum(1,100).sample).toList.sorted
res15: List[Int] = List(1, 1, 1, 61, 85, 86, 91, 92, 100, 100)

I'd like a choose() function that would give me a result that looks something like this:

scala> (1 to 10).flatMap(_ => choose(1,100).sample).toList.sorted
res15: List[Int] = List(1, 1, 1, 2, 5, 11, 18, 35, 49, 100)

I see that choose() and chooseNum() take an implicit Choose trait as an argument. Should I use that?

like image 980
jjst Avatar asked Feb 15 '16 22:02

jjst


1 Answers

You could use Gen.frequency() (1):

 val frequencies = List(
   (50000, Gen.choose(0, 9)),
   (38209, Gen.choose(10, 19)),
   (27425, Gen.choose(20, 29)),
   (18406, Gen.choose(30, 39)),
   (11507, Gen.choose(40, 49)),
   ( 6681, Gen.choose(50, 59)),
   ( 3593, Gen.choose(60, 69)),
   ( 1786, Gen.choose(70, 79)),
   (  820, Gen.choose(80, 89)),
   (  347, Gen.choose(90, 100))
 )

 (1 to 10).flatMap(_ => Gen.frequency(frequencies:_*).sample).toList
 res209: List[Int] = List(27, 21, 31, 1, 21, 18, 9, 29, 69, 29)

I got the frequencies from https://en.wikipedia.org/wiki/Standard_normal_table#Complementary_cumulative. The code is just a sample of the table (% 3 or mod 3), but I think you can get the idea.

like image 81
Onilton Maciel Avatar answered Sep 28 '22 07:09

Onilton Maciel