croupier 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Juanjo Bazán
1
+ Copyright (c) 2012 Juanjo Bazán
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -7,14 +7,14 @@ Croupier generates random samples of numbers with specific probability distribut
7
7
  You need to have Ruby and Rubygems installed in your system. Then install croupier with:
8
8
 
9
9
  $ gem install croupier
10
-
10
+
11
11
  ## Getting Started
12
12
 
13
13
  Once you have croupier installed in your machine, you can run the gem using the `croupier` executable:
14
14
 
15
15
  $ croupier
16
16
 
17
- The common case for invoking Cruopier is:
17
+ The common case for invoking Croupier is:
18
18
 
19
19
  $ croupier <distribution> <sample_size> [<options>]
20
20
 
@@ -33,7 +33,7 @@ where:
33
33
  ### Available distributions and options
34
34
 
35
35
  To get a list of all the available distributions use the ```--help``` (or ```-h```) option with croupier:
36
-
36
+
37
37
  $ croupier --help
38
38
 
39
39
  To get a list of all the available options for a given distribution use ```--help``` (or ```-h```) option with any available distribution:
@@ -48,11 +48,11 @@ First of all require the croupier library:
48
48
 
49
49
  require 'croupier'
50
50
 
51
- And then use the the distribution you want to generate the sample. You can get just one number (using ```.generate_single_number```) or an array of any given size (using ```.generate_numbers(N)```)
51
+ And then use the the distribution you want to generate the sample. You can get just one number (using ```.generate_number```) or an array of any given size (using ```.generate_sample(N)```)
52
52
 
53
- dist = ::Croupier::Distributions::Exponential.new(:lambda => 1.7)
54
- dist.generate_numbers(100) #=> returns an array of 100 random numbers following an exponential with rate 1.7
55
- dist.generate_single_number #=> returns one random number following an exponential with rate 1.7
53
+ dist = Croupier::Distributions::Exponential.new(:lambda => 1.7)
54
+ dist.generate_sample(100) #=> returns an array of 100 random numbers following an exponential with rate 1.7
55
+ dist.generate_number #=> returns one random number following an exponential with rate 1.7
56
56
 
57
57
  ## License
58
58
 
@@ -60,4 +60,4 @@ Croupier is released under the MIT license.
60
60
 
61
61
  ## Credits
62
62
 
63
- Developed by Juanjo Bazán [`@xuanxu`](http://twitter.com/xuanxu) & Sergio Arbeo [`@serabe`](http://twitter.com/serabe)
63
+ Developed by Juanjo Bazán [`@xuanxu`](http://twitter.com/xuanxu) & Sergio Arbeo [`@serabe`](http://twitter.com/serabe)
data/RUNNING_TESTS.md CHANGED
@@ -3,11 +3,11 @@
3
3
  The tests suite of the gem is located in the /test folder, and it's divided in two sets that run separately:
4
4
 
5
5
  * Ruby Tests
6
- * R tests
6
+ * R tests
7
7
 
8
8
  ### Ruby Tests
9
9
 
10
- The ruby set of tests are meant to test the general behaviour of the library.
10
+ The ruby set of tests are meant to test the general behaviour of the library.
11
11
  You can run these tests using the default Rake task:
12
12
 
13
13
  $ rake
@@ -15,12 +15,12 @@ You can run these tests using the default Rake task:
15
15
  ### R tests
16
16
 
17
17
  There's a group of tests validating the probability distribution of several samples of numbers generated with Croupier.
18
- These tests are statistical tests included in R scripts.
18
+ These tests are statistical tests included in R scripts.
19
19
  To run them you need to have R installed in your system. You can get the R software from ```http://www.r-project.org/```
20
20
  The testsuite uses the 'testthat' package. You can install it from the R console with the folowing command:
21
21
 
22
22
  install.packages("testthat", repos = "http://cran.r-project.org/", type="source")
23
-
23
+
24
24
  Once you have R and all the dependencies installed in your system, you can run the test/testsuite.R file:
25
25
 
26
26
  Using Rscript:
data/bin/croupier CHANGED
@@ -23,4 +23,4 @@
23
23
  #++
24
24
 
25
25
  require 'croupier'
26
- Croupier.application.run
26
+ Croupier.application.run
@@ -1,9 +1,9 @@
1
1
  module Croupier
2
2
  module CLI
3
3
  #####################################################################
4
- # Croupier main command line interface application object.
5
- #
6
- # When invoking +croupier+ from the command line,
4
+ # Croupier main command line interface application object.
5
+ #
6
+ # When invoking +croupier+ from the command line,
7
7
  # a Croupier::CLI::Application object is created and run.
8
8
  #
9
9
  class Application
@@ -30,11 +30,11 @@ module Croupier
30
30
  def run
31
31
  Croupier.trap_interrupt
32
32
  distribution, sample_size, params = parse_distribution_options
33
- distribution.new(params).generate_numbers(sample_size).each{|n| Croupier.message n}
33
+ distribution.new(params).generate_sample(sample_size).each{|n| Croupier.message n}
34
34
  end
35
35
 
36
36
  private
37
-
37
+
38
38
  def parse_distribution_options
39
39
  #Trollop needs this vars locally
40
40
  available_distribution_list = @distribution_list.keys
@@ -48,11 +48,11 @@ Currently you can use this distributions:
48
48
  [#{available_distribution_list.join(', ')}]
49
49
 
50
50
  Usage:
51
- croupier <distribution> <n> [options]
51
+ croupier <distribution> <n> [options]
52
52
  where <n> is the quantity of numbers Croupier will generate.
53
53
 
54
54
  Get options list for any distribution with: croupier <distrib> --help
55
-
55
+
56
56
  EOS
57
57
  stop_on available_distribution_list
58
58
  end
@@ -69,12 +69,12 @@ Get options list for any distribution with: croupier <distrib> --help
69
69
  else
70
70
  Trollop::die "unknown distribution #{dist.inspect}"
71
71
  end
72
-
72
+
73
73
  sample_size = ARGV.shift.to_i # get the sample size
74
74
  Trollop::die "Sample size must be a positive integer" if sample_size.nil? || sample_size < 1
75
-
75
+
76
76
  return [@distribution_list[dist], sample_size, dist_opts]
77
77
  end
78
78
  end
79
79
  end
80
- end
80
+ end
@@ -12,7 +12,7 @@ VERSION = "1.16.2"
12
12
  ## Thrown by Parser in the event of a commandline error. Not needed if
13
13
  ## you're using the Trollop::options entry.
14
14
  class CommandlineError < StandardError; end
15
-
15
+
16
16
  ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
17
17
  ## automatically by Trollop#options.
18
18
  class HelpNeeded < StandardError; end
@@ -250,7 +250,7 @@ class Parser
250
250
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
251
251
  @constraints << [:depends, syms]
252
252
  end
253
-
253
+
254
254
  ## Marks two (or more!) options as conflicting.
255
255
  def conflicts *syms
256
256
  syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
@@ -427,7 +427,7 @@ class Parser
427
427
  # call this unless the cursor's at the beginning of a line.
428
428
 
429
429
  left = {}
430
- @specs.each do |name, spec|
430
+ @specs.each do |name, spec|
431
431
  left[name] = "--#{spec[:long]}" +
432
432
  (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") +
433
433
  case spec[:type]
@@ -656,7 +656,7 @@ private
656
656
  start = 0
657
657
  ret = []
658
658
  until start > str.length
659
- nextt =
659
+ nextt =
660
660
  if start + width >= str.length
661
661
  str.length
662
662
  else
@@ -1,5 +1,5 @@
1
1
  module Croupier
2
-
2
+
3
3
  #####################################################################
4
4
  # Distribution represents the probability distribution used to
5
5
  # generate the sample of random numbers.
@@ -26,14 +26,15 @@ module Croupier
26
26
  end
27
27
 
28
28
  # Main method to generate n random numbers using the current probability distribution
29
- def generate_numbers(n=1)
30
- (1..n).map { generate_single_number }
29
+ def generate_sample(n=1)
30
+ (1..n).map { generate_number }
31
31
  end
32
32
 
33
33
  # Generates one random number using the current probability distribution
34
- def generate_single_number
34
+ def generate_number
35
+ generate_sample 1
35
36
  end
36
-
37
+
37
38
  # Defines a hash with banner and all available CLI options.
38
39
  # It is a hash with two keys:
39
40
  # :banner => A string used as banner in the command line help
@@ -45,7 +46,7 @@ module Croupier
45
46
  # [:mean, 'The mean of the distribution', {:default => 33}],
46
47
  # [:median, 'Median of the distribution',{:default => 33.0, :type => :float}]
47
48
  # ]
48
- # }
49
+ # }
49
50
  def self.cli_options
50
51
  {:banner => nil, :options=>[]}
51
52
  end
@@ -58,4 +59,4 @@ module Croupier
58
59
 
59
60
  module Distributions
60
61
  end
61
- end
62
+ end
@@ -1,20 +1,20 @@
1
1
  module Croupier
2
2
  module Distributions
3
-
3
+
4
4
  #####################################################################
5
- # Uniform Distribution
6
- # Continous distribution where all points in an interval have
7
- # the same probability.
5
+ # Exponential Distribution
6
+ # Continuous probability distribution with a lambda param rate
7
+ # describing the time between events in a Poisson process
8
8
  #
9
9
  class Exponential < ::Croupier::Distribution
10
-
10
+
11
11
  def initialize(options={})
12
12
  @name = "Exponential distribution"
13
13
  @description = "Continuous probability distribution with a lambda param rate describing the time between events in a Poisson process"
14
14
  configure(options)
15
15
  end
16
16
 
17
- def generate_single_number
17
+ def generate_number
18
18
  raise Croupier::InputParamsError, "Invalid interval values" if @parameters[:lambda] <= 0
19
19
  (-1/@parameters[:lambda]) * Math.log(rand)
20
20
  end
@@ -36,4 +36,4 @@ module Croupier
36
36
  end
37
37
  end
38
38
  end
39
- end
39
+ end
@@ -0,0 +1,56 @@
1
+ module Croupier
2
+ module Distributions
3
+
4
+ #####################################################################
5
+ # Normal Distribution
6
+ # Continuous distribution (mu,sigma) (defaults to (0,1) ) where
7
+ # mu is the mean and sigma the standard deviation.
8
+ #
9
+ class Normal < ::Croupier::Distribution
10
+
11
+ def initialize(options={})
12
+ @name = "Uniform distribution"
13
+ @description = "Continuous distribution (mu,sigma) (defaults to (0,1) ) where mu is the mean and sigma the standard deviation."
14
+ configure(options)
15
+ end
16
+
17
+ def generate_sample(n=1)
18
+ sample = n.odd? ? n+1 : n
19
+
20
+ # Generate
21
+ gen = (1..sample).map do |x|
22
+ 1 - rand # because uniform need to be in (0,1]
23
+ end.each_slice(2).flat_map do |x, y|
24
+ [
25
+ Math.sqrt(-2*Math.log(x)) * Math.cos(2*Math::PI*y),
26
+ Math.sqrt(-2*Math.log(x)) * Math.sin(2*Math::PI*y)
27
+ ]
28
+ end
29
+
30
+ # Adjust parameters.
31
+ gen.map!{ |x| x * @parameters[:std] } if @parameters[:std] != 1
32
+ gen.map!{ |x| x + @parameters[:mean] } if @parameters[:mean] != 0
33
+
34
+ # Adjust length
35
+ n.odd? ? gen[0..-2] : gen
36
+ end
37
+
38
+ def default_parameters
39
+ {:mean => 0, :std => 1}
40
+ end
41
+
42
+ def self.cli_name
43
+ "normal"
44
+ end
45
+
46
+ def self.cli_options
47
+ {:options => [
48
+ [:mean, 'mean of the distribution', {:type=>:float, :default => 0.0}],
49
+ [:std, 'standard deviation of the distribution', {:type=>:float, :default => 1.0}]
50
+ ],
51
+ :banner => "Normal distribution. Generate numbers following a continuous distribution the real line with mean :mean and standard deviation :std."
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,20 +1,20 @@
1
1
  module Croupier
2
2
  module Distributions
3
-
3
+
4
4
  #####################################################################
5
- # Uniform Distribution
6
- # Continous distribution where all points in an interval have
5
+ # Uniform Distribution
6
+ # Continous distribution where all points in an interval have
7
7
  # the same probability.
8
8
  #
9
9
  class Uniform < ::Croupier::Distribution
10
-
10
+
11
11
  def initialize(options={})
12
12
  @name = "Uniform distribution"
13
13
  @description = "Continuous distribution on [a,b] (defaults to [0,1]) where all points in the interval are equally likely"
14
14
  configure(options)
15
15
  end
16
16
 
17
- def generate_single_number
17
+ def generate_number
18
18
  raise Croupier::InputParamsError, "Invalid interval values" if @parameters[:b] < @parameters[:a]
19
19
  rand Range.new(@parameters[:a], @parameters[:b])
20
20
  end
@@ -37,4 +37,4 @@ module Croupier
37
37
  end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -5,4 +5,4 @@ module Croupier
5
5
  class InvalidOptionError < Error; end
6
6
  # Error in some of the input params.
7
7
  class InputParamsError < Error; end
8
- end
8
+ end
@@ -0,0 +1,52 @@
1
+ context('** Normal Distribution **')
2
+ # Run a K-S test on the Croupier sample against a exponential R-generated sample
3
+ # Accept Croupier's sample as normal if p-value > 0.05
4
+ # Also check for a statistic near 0
5
+
6
+ context('Kolmogorov-Smirnov test for default mean = 0 and std = 1')
7
+ croupier_normal <- read.table("../generated_samples/normal_0_1.data")
8
+ ks_result<-ks.test(croupier_normal$V1, "pnorm")
9
+
10
+ test_that("p-value > 0.05", {
11
+ expect_true(ks_result$p.value > 0.05)
12
+ })
13
+
14
+ test_that("statistic converging to 0", {
15
+ expect_true(as.numeric(ks_result$statistic) < 0.05)
16
+ })
17
+
18
+ context('Shapiro test for default mean = 0 and std = 1')
19
+ croupier_normal <- read.table("../generated_samples/normal_0_1.data")
20
+ s_result<-shapiro.test(croupier_normal$V1[1:5000])
21
+
22
+ test_that("p-value > 0.05", {
23
+ expect_true(s_result$p.value > 0.05)
24
+ })
25
+
26
+ test_that("statistic converging to 0", {
27
+ expect_true(as.numeric(ks_result$statistic) < 0.05)
28
+ })
29
+
30
+ context('Kolmogorov-Smirnov test for given mean = 5 and std = 6')
31
+ croupier_normal <- read.table("../generated_samples/normal_5_6.data")
32
+ ks_result<-ks.test((croupier_normal$V1 - 5)/6, "pnorm")
33
+
34
+ test_that("p-value > 0.05", {
35
+ expect_true(ks_result$p.value > 0.05)
36
+ })
37
+
38
+ test_that("statistic converging to 0", {
39
+ expect_true(as.numeric(ks_result$statistic) < 0.05)
40
+ })
41
+
42
+ context('Shapiro test for default mean = 5 and std = 1')
43
+ croupier_normal <- read.table("../generated_samples/normal_0_1.data")
44
+ s_result<-shapiro.test((croupier_normal$V1[1:5000] - 5 ) / 6)
45
+
46
+ test_that("p-value > 0.05", {
47
+ expect_true(s_result$p.value > 0.05)
48
+ })
49
+
50
+ test_that("statistic converging to 0", {
51
+ expect_true(as.numeric(ks_result$statistic) < 0.05)
52
+ })