croupier 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ })