rational_choice 2.0.0 → 2.0.1
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.
- checksums.yaml +5 -5
- data/.gitignore +50 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +1 -1
- data/Gemfile +2 -8
- data/Rakefile +8 -36
- data/lib/rational_choice.rb +17 -17
- data/rational_choice.gemspec +21 -60
- data/spec/rational_choice/dimension_spec.rb +34 -34
- data/spec/rational_choice/many_dimensions_spec.rb +12 -13
- data/spec/rational_choice_spec.rb +6 -5
- data/spec/spec_helper.rb +1 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c062495abe33854b1fdda0b37fe663d2f53f1036b2d79c6491577fe06b645b90
|
4
|
+
data.tar.gz: 5155200d59d02441f02c2500adab6676cfe45a294c1319adea2670eedf7cb8cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3de02bef19b681e9467383fd86e9653813201c4a0af91bc9f9efabb60b1c5fd4265ddc93d004aa9bf90cfe66fdae356a02481d084ce014182ce53e3baf2381ea
|
7
|
+
data.tar.gz: b76b864d7bda067426bcd555def66fecd57a5652dfd12426fb544e6d6ae955e24899def8cb74710e596797f0de25043eb56887336f19d44037f53e9b2053a3cf
|
data/.gitignore
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
coverage.data
|
4
|
+
|
5
|
+
# rdoc generated
|
6
|
+
rdoc
|
7
|
+
|
8
|
+
# yard generated
|
9
|
+
doc
|
10
|
+
.yardoc
|
11
|
+
|
12
|
+
# bundler
|
13
|
+
.bundle
|
14
|
+
Gemfile.lock
|
15
|
+
|
16
|
+
# jeweler generated
|
17
|
+
pkg
|
18
|
+
|
19
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
20
|
+
#
|
21
|
+
# * Create a file at ~/.gitignore
|
22
|
+
# * Include files you want ignored
|
23
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
24
|
+
#
|
25
|
+
# After doing this, these files will be ignored in all your git projects,
|
26
|
+
# saving you from having to 'pollute' every project you touch with them
|
27
|
+
#
|
28
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
29
|
+
#
|
30
|
+
# For MacOS:
|
31
|
+
#
|
32
|
+
#.DS_Store
|
33
|
+
|
34
|
+
# For TextMate
|
35
|
+
#*.tmproj
|
36
|
+
#tmtags
|
37
|
+
|
38
|
+
# For emacs:
|
39
|
+
#*~
|
40
|
+
#\#*
|
41
|
+
#.\#*
|
42
|
+
|
43
|
+
# For vim:
|
44
|
+
#*.swp
|
45
|
+
|
46
|
+
# For redcar:
|
47
|
+
#.redcar
|
48
|
+
|
49
|
+
# For rubinius:
|
50
|
+
#*.rbc
|
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,43 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
5
|
-
begin
|
6
|
-
Bundler.setup(:default, :development)
|
7
|
-
rescue Bundler::BundlerError => e
|
8
|
-
$stderr.puts e.message
|
9
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
-
exit e.status_code
|
11
|
-
end
|
12
|
-
require 'rake'
|
13
|
-
require_relative 'lib/rational_choice'
|
14
|
-
|
15
|
-
require 'jeweler'
|
16
|
-
Jeweler::Tasks.new do |gem|
|
17
|
-
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
18
|
-
gem.version = RationalChoice::VERSION
|
19
|
-
gem.name = "rational_choice"
|
20
|
-
gem.homepage = "https://github.com/wetransfer/rational_choice"
|
21
|
-
gem.license = "MIT"
|
22
|
-
gem.description = %Q{Fuzzy logic gate}
|
23
|
-
gem.summary = %Q{Makes life-concerning choices based on an informed coin toss}
|
24
|
-
gem.email = "me@julik.nl"
|
25
|
-
gem.authors = ["Julik Tarkhanov"]
|
26
|
-
# dependencies defined in Gemfile
|
27
|
-
end
|
28
|
-
Jeweler::RubygemsDotOrgTasks.new
|
29
|
-
|
30
|
-
require 'rspec/core'
|
1
|
+
require 'bundler/gem_tasks'
|
31
2
|
require 'rspec/core/rake_task'
|
32
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
33
|
-
spec.pattern = FileList['spec/**/*_spec.rb']
|
34
|
-
end
|
35
|
-
|
36
|
-
task :default => :spec
|
37
|
-
|
38
3
|
require 'yard'
|
4
|
+
require 'rubocop/rake_task'
|
5
|
+
|
39
6
|
YARD::Rake::YardocTask.new do |t|
|
40
7
|
t.files = ['lib/**/*.rb', 'README*'] # optional
|
41
8
|
t.options = ['--markup markdown'] # optional
|
42
9
|
t.stats_options = ['--list-undoc'] # optional
|
43
10
|
end
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
13
|
+
RuboCop::RakeTask.new
|
14
|
+
|
15
|
+
task default: [:spec, :rubocop]
|
data/lib/rational_choice.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# Tiny fuzzy-logic gate for making choices based on a continuum of permitted values
|
2
2
|
# as opposed to a hard condition.
|
3
3
|
module RationalChoice
|
4
|
-
VERSION = '2.0.
|
5
|
-
|
4
|
+
VERSION = '2.0.1'
|
5
|
+
|
6
6
|
# Gets raised when a multidimensional choice has to be made with a wrong number
|
7
7
|
# of values versus the number of dimensions
|
8
8
|
CardinalityError = Class.new(ArgumentError)
|
9
|
-
|
9
|
+
|
10
10
|
# Gets raised when a dimension has to be created with the same parameters
|
11
11
|
DomainError = Class.new(ArgumentError)
|
12
|
-
|
12
|
+
|
13
13
|
# Represents a fuzzy choice on a single dimension (one real number)
|
14
14
|
class Dimension
|
15
15
|
# Initializes a new Dimension to evaluate values
|
16
16
|
#
|
17
17
|
# @param false_at_or_below[#to_f, #<=>] the lower bound, at or below which the value will be considered false
|
18
18
|
# @param true_at_or_above[#to_f, #<=>] the upper bound, at or above which the value will be considered true
|
19
|
-
def initialize(false_at_or_below
|
19
|
+
def initialize(false_at_or_below:, true_at_or_above:)
|
20
20
|
raise DomainError, "Bounds were the same at #{false_at_or_below}" if false_at_or_below == true_at_or_above
|
21
|
-
|
21
|
+
|
22
22
|
@lower, @upper = [false_at_or_below, true_at_or_above].sort
|
23
23
|
@flip_sign = [@lower, @upper].sort != [false_at_or_below, true_at_or_above]
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Evaluate a value against the given false and true bound.
|
27
27
|
#
|
28
28
|
# If the value is less than or equal to the false bound, the method will return `false`.
|
@@ -55,7 +55,7 @@ module RationalChoice
|
|
55
55
|
delta = @upper.to_f - @lower.to_f
|
56
56
|
v = (value - @lower).to_f
|
57
57
|
t = (v / delta)
|
58
|
-
|
58
|
+
|
59
59
|
r = Random.new # To override in tests if needed
|
60
60
|
r.rand < t
|
61
61
|
else
|
@@ -64,7 +64,7 @@ module RationalChoice
|
|
64
64
|
end
|
65
65
|
choice ^ @flip_sign
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# Tells whether the evaluation will use the probabilities or not
|
69
69
|
# (whether the given value is within the range where probability evaluation will take place).
|
70
70
|
#
|
@@ -74,23 +74,23 @@ module RationalChoice
|
|
74
74
|
value > @lower && value < @upper
|
75
75
|
end
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# Performs an evaluation based on multiple dimensions. The dimensions
|
79
79
|
# will be first coerced into one (number of truthy evaluations vs. number of falsey evaluations)
|
80
80
|
# and then a true/false value will be deduced from that.
|
81
81
|
class ManyDimensions
|
82
82
|
def initialize(*dimensions)
|
83
83
|
@dimensions = dimensions
|
84
|
-
raise CardinalityError,
|
84
|
+
raise CardinalityError, '%s has no dimensions to evaluate' % inspect if @dimensions.empty?
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
# Performs a weighted choice, by first collecting choice results from all the dimensions,
|
88
88
|
# and then by interpolating those results by the ratio of truthy values vs falsey values.
|
89
89
|
#
|
90
90
|
# x = Dimension.new(0,1)
|
91
91
|
# y = Dimension.new(0,1)
|
92
92
|
# z = Dimension.new(0,1)
|
93
|
-
#
|
93
|
+
#
|
94
94
|
# within_positive_3d_space = ManyDimensions.new(x, y, z)
|
95
95
|
# within_positive_3d_space.choose(-1, -1, -0.5) #=> false
|
96
96
|
# within_positive_3d_space.choose(1.1, 123, 1) #=> true
|
@@ -100,12 +100,12 @@ module RationalChoice
|
|
100
100
|
# @return [Boolean] true or false
|
101
101
|
def choose(*values)
|
102
102
|
if @dimensions.length != values.length
|
103
|
-
raise CardinalityError,
|
103
|
+
raise CardinalityError, '%s has %d dimensions but %d values were given' % [inspect, @dimensions.length, values.length]
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
evaluations = values.zip(@dimensions).map { |(v, d)| d.choose(v) }
|
107
|
-
num_truthy_choices = evaluations.select{|e| e}.length
|
108
|
-
|
107
|
+
num_truthy_choices = evaluations.select { |e| e }.length
|
108
|
+
|
109
109
|
Dimension.new(false_at_or_below: 0, true_at_or_above: evaluations.length).choose(num_truthy_choices)
|
110
110
|
end
|
111
111
|
end
|
data/rational_choice.gemspec
CHANGED
@@ -1,65 +1,26 @@
|
|
1
|
-
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: rational_choice 2.0.0 ruby lib
|
1
|
+
require_relative 'lib/rational_choice'
|
6
2
|
|
7
3
|
Gem::Specification.new do |s|
|
8
|
-
s.name =
|
9
|
-
s.version =
|
4
|
+
s.name = 'rational_choice'
|
5
|
+
s.version = RationalChoice::VERSION
|
10
6
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
12
|
-
s.require_paths = [
|
13
|
-
s.authors = [
|
14
|
-
s.date =
|
15
|
-
s.description =
|
16
|
-
s.email =
|
17
|
-
s.extra_rdoc_files = [
|
18
|
-
|
19
|
-
|
20
|
-
]
|
21
|
-
s.
|
22
|
-
|
23
|
-
".rspec",
|
24
|
-
".travis.yml",
|
25
|
-
"Gemfile",
|
26
|
-
"LICENSE.txt",
|
27
|
-
"README.md",
|
28
|
-
"Rakefile",
|
29
|
-
"lib/rational_choice.rb",
|
30
|
-
"rational_choice.gemspec",
|
31
|
-
"spec/rational_choice/dimension_spec.rb",
|
32
|
-
"spec/rational_choice/many_dimensions_spec.rb",
|
33
|
-
"spec/rational_choice_spec.rb",
|
34
|
-
"spec/spec_helper.rb"
|
35
|
-
]
|
36
|
-
s.homepage = "https://github.com/wetransfer/rational_choice"
|
37
|
-
s.licenses = ["MIT"]
|
38
|
-
s.rubygems_version = "2.2.2"
|
39
|
-
s.summary = "Makes life-concerning choices based on an informed coin toss"
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
8
|
+
s.require_paths = ['lib']
|
9
|
+
s.authors = ['Julik Tarkhanov']
|
10
|
+
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
11
|
+
s.description = 'Fuzzy logic gate'
|
12
|
+
s.email = 'me@julik.nl'
|
13
|
+
s.extra_rdoc_files = ['LICENSE.txt', 'README.md']
|
14
|
+
s.files = `git ls-files -z`.split("\x0")
|
15
|
+
s.homepage = 'https://github.com/wetransfer/rational_choice'
|
16
|
+
s.licenses = ['MIT']
|
17
|
+
s.rubygems_version = '2.2.2'
|
18
|
+
s.summary = 'Makes life-concerning choices based on an informed coin toss'
|
40
19
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
48
|
-
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
49
|
-
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
50
|
-
else
|
51
|
-
s.add_dependency(%q<yard>, [">= 0"])
|
52
|
-
s.add_dependency(%q<rspec>, ["~> 3.4.0"])
|
53
|
-
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
54
|
-
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
55
|
-
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
56
|
-
end
|
57
|
-
else
|
58
|
-
s.add_dependency(%q<yard>, [">= 0"])
|
59
|
-
s.add_dependency(%q<rspec>, ["~> 3.4.0"])
|
60
|
-
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
61
|
-
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
62
|
-
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
63
|
-
end
|
20
|
+
s.specification_version = 4
|
21
|
+
s.add_development_dependency 'yard', '>= 0'
|
22
|
+
s.add_development_dependency 'rspec', '~> 3.4.0'
|
23
|
+
s.add_development_dependency 'rake', '~> 10'
|
24
|
+
s.add_development_dependency 'bundler', '~> 1.0'
|
25
|
+
s.add_development_dependency 'wetransfer_style', '0.5.0'
|
64
26
|
end
|
65
|
-
|
@@ -8,7 +8,7 @@ describe 'RationalChoice::Dimension' do
|
|
8
8
|
}.to raise_error(/Bounds were the same at 2/)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
describe 'with values at or beyound the thresholds' do
|
13
13
|
it 'always evaluates to true for values above upper threshold' do
|
14
14
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
@@ -16,21 +16,21 @@ describe 'RationalChoice::Dimension' do
|
|
16
16
|
expect(d.choose(1.1)).to eq(true)
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
it 'always evaluates to true for values at upper threshold' do
|
21
21
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
22
22
|
10_000.times do
|
23
23
|
expect(d.choose(1)).to eq(true)
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it 'always evaluates to false for values at lower threshold' do
|
28
28
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
29
29
|
10_000.times do
|
30
30
|
expect(d.choose(0)).to eq(false)
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it 'always evaluates to false for values below lower threshold' do
|
35
35
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
36
36
|
10_000.times do
|
@@ -38,98 +38,98 @@ describe 'RationalChoice::Dimension' do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
describe 'with values between thresholds creates a sensible choice distribution' do
|
43
43
|
it 'for 0.5 on a continuum from 0 to 1' do
|
44
44
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
45
45
|
expect(d).to be_fuzzy(0.5)
|
46
|
-
|
46
|
+
|
47
47
|
trues = 0
|
48
|
-
|
48
|
+
|
49
49
|
n_evaluations = 100_000
|
50
50
|
n_evaluations.times { trues += 1 if d.choose(0.5) }
|
51
|
-
|
51
|
+
|
52
52
|
expect(trues).to be_within(1000).of(n_evaluations / 2)
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
it 'for 0.1 on a continuum from 0 to 1' do
|
56
56
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
57
57
|
expect(d).to be_fuzzy(0.1)
|
58
|
-
|
58
|
+
|
59
59
|
trues = 0
|
60
|
-
|
60
|
+
|
61
61
|
n_evaluations = 100_000
|
62
62
|
n_evaluations.times { trues += 1 if d.choose(0.1) }
|
63
|
-
|
63
|
+
|
64
64
|
expect(trues).to be_within(1000).of(n_evaluations / 10)
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
it 'for 0.5 on a continuum from 1 to 0' do
|
68
68
|
d = RationalChoice::Dimension.new(false_at_or_below: 1, true_at_or_above: 0)
|
69
69
|
expect(d).to be_fuzzy(0.5)
|
70
|
-
|
70
|
+
|
71
71
|
falses = 0
|
72
72
|
n_evaluations = 100_000
|
73
|
-
n_evaluations.times { falses += 1
|
74
|
-
|
73
|
+
n_evaluations.times { falses += 1 unless d.choose(0.5) }
|
74
|
+
|
75
75
|
expect(falses).to be_within(1000).of(n_evaluations / 2)
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
it 'for 0.1 on a continuum from 1 to 0' do
|
79
79
|
d = RationalChoice::Dimension.new(false_at_or_below: 1, true_at_or_above: 0)
|
80
80
|
expect(d).to be_fuzzy(0.1)
|
81
|
-
|
81
|
+
|
82
82
|
trues = 0
|
83
|
-
|
83
|
+
|
84
84
|
n_evaluations = 100_000
|
85
85
|
n_evaluations.times { trues += 1 if d.choose(0.1) }
|
86
|
-
|
86
|
+
|
87
87
|
expect(trues).to be_within(1000).of(n_evaluations / 10 * 9) # Over 90% of the choices must be trues
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
it 'for -0.5 on a continuum from -1 to 0' do
|
91
91
|
d = RationalChoice::Dimension.new(false_at_or_below: -1, true_at_or_above: 0)
|
92
92
|
expect(d).to be_fuzzy(-0.5)
|
93
|
-
|
93
|
+
|
94
94
|
trues = 0
|
95
95
|
n_evaluations = 100_000
|
96
96
|
n_evaluations.times { trues += 1 if d.choose(-0.5) }
|
97
|
-
|
97
|
+
|
98
98
|
expect(trues).to be_within(1000).of(n_evaluations / 2)
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
it 'for -0.1 on a continuum from -1 to 0' do
|
102
102
|
d = RationalChoice::Dimension.new(false_at_or_below: -1, true_at_or_above: 0)
|
103
103
|
expect(d).to be_fuzzy(-0.1)
|
104
|
-
|
104
|
+
|
105
105
|
trues = 0
|
106
|
-
|
106
|
+
|
107
107
|
n_evaluations = 100_000
|
108
108
|
n_evaluations.times { trues += 1 if d.choose(-0.1) }
|
109
|
-
|
109
|
+
|
110
110
|
expect(trues).to be_within(1000).of(n_evaluations / 10 * 9) # Over 90% of the choices must be trues
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
it 'for -0.5 on a continuum from 0 to -1' do
|
114
114
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: -1)
|
115
115
|
expect(d).to be_fuzzy(-0.5)
|
116
|
-
|
116
|
+
|
117
117
|
trues = 0
|
118
118
|
n_evaluations = 100_000
|
119
119
|
n_evaluations.times { trues += 1 if d.choose(-0.5) }
|
120
|
-
|
120
|
+
|
121
121
|
expect(trues).to be_within(1000).of(n_evaluations / 2)
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
it 'for -0.1 on a continuum from 0 to -1' do
|
125
125
|
d = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: -1)
|
126
126
|
expect(d).to be_fuzzy(-0.1)
|
127
|
-
|
127
|
+
|
128
128
|
trues = 0
|
129
|
-
|
129
|
+
|
130
130
|
n_evaluations = 100_000
|
131
131
|
n_evaluations.times { trues += 1 if d.choose(-0.1) }
|
132
|
-
|
132
|
+
|
133
133
|
expect(trues).to be_within(1000).of(n_evaluations / 10) # Over 90% of the choices must be trues
|
134
134
|
end
|
135
135
|
end
|
@@ -8,7 +8,7 @@ describe 'RationalChoice::ManyDimensions' do
|
|
8
8
|
}.to raise_error(RationalChoice::CardinalityError)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
describe '.choose' do
|
13
13
|
it 'raises a CardinalityError if the number of values does not match the number of dimensions' do
|
14
14
|
md = RationalChoice::ManyDimensions.new(nil, nil, nil)
|
@@ -16,39 +16,38 @@ describe 'RationalChoice::ManyDimensions' do
|
|
16
16
|
md.choose(1, 2)
|
17
17
|
}.to raise_error(RationalChoice::CardinalityError)
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
let(:md) {
|
21
21
|
one_to_zero = RationalChoice::Dimension.new(false_at_or_below: 0, true_at_or_above: 1)
|
22
22
|
RationalChoice::ManyDimensions.new(one_to_zero, one_to_zero, one_to_zero)
|
23
23
|
}
|
24
|
-
|
24
|
+
|
25
25
|
it 'returns "true" when all dimensions are at or above upper bound' do
|
26
|
-
10_000.times { expect(md.choose(1,1,1)).to eq(true) }
|
27
|
-
10_000.times { expect(md.choose(2,2,2)).to eq(true) }
|
26
|
+
10_000.times { expect(md.choose(1, 1, 1)).to eq(true) }
|
27
|
+
10_000.times { expect(md.choose(2, 2, 2)).to eq(true) }
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it 'returns "false" when all dimensions are at or below lower bound' do
|
31
|
-
10_000.times { expect(md.choose(0,0,0)).to eq(false) }
|
32
|
-
10_000.times { expect(md.choose(-1
|
31
|
+
10_000.times { expect(md.choose(0, 0, 0)).to eq(false) }
|
32
|
+
10_000.times { expect(md.choose(-1, -1, -1)).to eq(false) }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
it 'returns "true" in approximately 50% of the cases when all the values are at 0.5' do
|
36
36
|
truthy = 0
|
37
37
|
10_000.times { truthy += 1 if md.choose(0.5, 0.5, 0.5) }
|
38
38
|
expect(truthy).to be_within(100).of(10_000 / 2)
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it 'returns "true" in approximately 10% of the cases when all the values are at 0.1' do
|
42
42
|
truthy = 0
|
43
43
|
10_000.times { truthy += 1 if md.choose(0.1, 0.1, 0.1) }
|
44
44
|
expect(truthy).to be_within(100).of(10_000 / 10)
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
it 'creates a very uniform distribution of values with random values across the board' do
|
48
48
|
truthy = 0
|
49
49
|
10_000.times { truthy += 1 if md.choose(rand, rand, rand) } # default rand() is 0..1
|
50
50
|
expect(truthy).to be_within(200).of(10_000 / 2)
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
54
|
-
end
|
53
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
describe
|
4
|
-
it
|
5
|
-
RationalChoice::
|
6
|
-
RationalChoice::
|
7
|
-
RationalChoice::
|
3
|
+
describe 'RationalChoice' do
|
4
|
+
it 'has the necessary constants' do
|
5
|
+
expect(RationalChoice::VERSION).to be_kind_of(String)
|
6
|
+
expect(RationalChoice::CardinalityError).to be_kind_of(Class)
|
7
|
+
expect(RationalChoice::Dimension).to be_kind_of(Class)
|
8
|
+
expect(RationalChoice::ManyDimensions).to be_kind_of(Class)
|
8
9
|
end
|
9
10
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rational_choice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -39,19 +39,19 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 3.4.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '10'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '10'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,19 +67,19 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: wetransfer_style
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 0.5.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 0.5.0
|
83
83
|
description: Fuzzy logic gate
|
84
84
|
email: me@julik.nl
|
85
85
|
executables: []
|
@@ -89,7 +89,9 @@ extra_rdoc_files:
|
|
89
89
|
- README.md
|
90
90
|
files:
|
91
91
|
- ".document"
|
92
|
+
- ".gitignore"
|
92
93
|
- ".rspec"
|
94
|
+
- ".rubocop.yml"
|
93
95
|
- ".travis.yml"
|
94
96
|
- Gemfile
|
95
97
|
- LICENSE.txt
|
@@ -121,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
123
|
version: '0'
|
122
124
|
requirements: []
|
123
125
|
rubyforge_project:
|
124
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.7.3
|
125
127
|
signing_key:
|
126
128
|
specification_version: 4
|
127
129
|
summary: Makes life-concerning choices based on an informed coin toss
|