sapor 0.1b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/Area Class Diagram.dia +0 -0
  3. data/Area Class Diagram.png +0 -0
  4. data/Class Diagram.dia +0 -0
  5. data/Class Diagram.png +0 -0
  6. data/Examples.md +361 -0
  7. data/LICENSE +674 -0
  8. data/README.md +70 -0
  9. data/Rakefile +18 -0
  10. data/Technical Documentation.md +14 -0
  11. data/bin/create_installation_package.sh +49 -0
  12. data/bin/install.sh +45 -0
  13. data/bin/sapor.rb +22 -0
  14. data/bin/sapor.sh +105 -0
  15. data/lib/sapor.rb +44 -0
  16. data/lib/sapor/binomials_cache.rb +45 -0
  17. data/lib/sapor/combinations_distribution.rb +180 -0
  18. data/lib/sapor/dichotomies.rb +98 -0
  19. data/lib/sapor/dichotomy.rb +138 -0
  20. data/lib/sapor/first_past_the_post.rb +78 -0
  21. data/lib/sapor/leveled_proportional.rb +64 -0
  22. data/lib/sapor/log4r_logger.rb +49 -0
  23. data/lib/sapor/log_facade.rb +40 -0
  24. data/lib/sapor/number_formatter.rb +45 -0
  25. data/lib/sapor/poll.rb +137 -0
  26. data/lib/sapor/polychotomy.rb +359 -0
  27. data/lib/sapor/proportional.rb +128 -0
  28. data/lib/sapor/pseudorandom_multirange_enumerator.rb +87 -0
  29. data/lib/sapor/regional_data/area.rb +80 -0
  30. data/lib/sapor/regional_data/catalonia-2012-2015.psv +100 -0
  31. data/lib/sapor/regional_data/catalonia-2012.psv +87 -0
  32. data/lib/sapor/regional_data/catalonia.rb +90 -0
  33. data/lib/sapor/regional_data/norway.rb +408 -0
  34. data/lib/sapor/regional_data/united_kingdom.rb +1075 -0
  35. data/lib/sapor/regional_data/utopia.rb +66 -0
  36. data/sapor.gemspec +35 -0
  37. data/spec/integration/area_spec.rb +28 -0
  38. data/spec/integration/poll_spec.rb +107 -0
  39. data/spec/integration/sample.poll +7 -0
  40. data/spec/spec_helper.rb +31 -0
  41. data/spec/unit/area_spec.rb +115 -0
  42. data/spec/unit/binomials_cache_spec.rb +34 -0
  43. data/spec/unit/catalonia_spec.rb +82 -0
  44. data/spec/unit/combinations_distribution_spec.rb +241 -0
  45. data/spec/unit/denominators_spec.rb +34 -0
  46. data/spec/unit/dichotomies_spec.rb +154 -0
  47. data/spec/unit/dichotomy_spec.rb +320 -0
  48. data/spec/unit/first_past_the_post_spec.rb +53 -0
  49. data/spec/unit/leveled_proportional_spec.rb +51 -0
  50. data/spec/unit/norway_spec.rb +47 -0
  51. data/spec/unit/number_formatter_spec.rb +173 -0
  52. data/spec/unit/poll_spec.rb +105 -0
  53. data/spec/unit/polychotomy_spec.rb +332 -0
  54. data/spec/unit/proportional_spec.rb +86 -0
  55. data/spec/unit/pseudorandom_multirange_enumerator_spec.rb +82 -0
  56. metadata +119 -0
@@ -0,0 +1,70 @@
1
+ Statistical Analysis of Polling Results (SAPoR)
2
+ ===============================================
3
+
4
+ Installation
5
+ ------------
6
+
7
+ You can install this program by cloning this repository, and then executing the
8
+ following commands in the directory where it got cloned:
9
+
10
+ sudo gem build sapor.gemspec
11
+ sudo gem install sapor-0.1b1.gem
12
+
13
+ bin/create_installation_package.sh
14
+ tar -xzf sapor-0.1b1.tar.gz
15
+ cd sapor-0.1b1/
16
+ sudo ./install.sh
17
+
18
+ Usage
19
+ -----
20
+
21
+ Simply call `sapor` or `sapor help` to get instructions on how to use the
22
+ program.
23
+
24
+ Examples
25
+ --------
26
+
27
+ See [this](Examples.md) page.
28
+
29
+ Technical Documentation
30
+ -----------------------
31
+
32
+ See [this](Technical%20Documentation.md) page.
33
+
34
+ Changelog
35
+ ---------
36
+
37
+ **Version 0.1**
38
+
39
+ * First round analysis of poll results as a set of dichotomies, reporting on the
40
+ most probable fraction, the 95% confidence interval for the vote share, and
41
+ probability to reach a threshold
42
+ * Second round analysis of poll results as a polychotomy, reporting on the most
43
+ probable fraction, the most probable rounded fraction, the 95% confidence
44
+ interval for the vote share, the probability to be larger than the next party,
45
+ the 95% confidence interval for the number of seats in parliament, and for
46
+ coalitions the most probable fraction, the most probable rounded fraction, the
47
+ 95% confidence interval for the vote share, the probability to have a majority
48
+ of the popular vote (vote share larger than 50%), the 95% confidence interval
49
+ for the number of seats and the probability to have a majority in parliament.
50
+ * Areas: Catalan parliamentary election, 2015
51
+
52
+ License
53
+ -------
54
+
55
+ Statistical Analysis of Polling Results (SAPoR)
56
+ Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
57
+
58
+ This program is free software; you can redistribute it and/or modify
59
+ it under the terms of the GNU General Public License as published by
60
+ the Free Software Foundation; either version 2 of the License, or
61
+ (at your option) any later version.
62
+
63
+ This program is distributed in the hope that it will be useful,
64
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
65
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66
+ GNU General Public License for more details.
67
+
68
+ You should have received a copy of the GNU General Public License along
69
+ with this program; if not, write to the Free Software Foundation, Inc.,
70
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Default: run specs.'
6
+ task default: :spec
7
+
8
+ desc 'Run specs'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = './spec/**/*_spec.rb'
11
+ end
12
+
13
+ desc 'Run Mutant'
14
+ task :mutant do
15
+ require 'mutant'
16
+ status = Mutant::CLI.run(['-I', 'lib', '-r', 'sapor', '--use', 'rspec', 'Sapor*'])
17
+ abort 'Mutant task is not successful' if status.nonzero?
18
+ end
@@ -0,0 +1,14 @@
1
+ Technical Documentation
2
+ =======================
3
+
4
+ Class Diagram
5
+ -------------
6
+
7
+ ![Class diagram](Class%20Diagram.png "Class diagram")
8
+
9
+ Areas
10
+ -----
11
+
12
+ The following diagram shows the hierarchy of all areas.
13
+
14
+ ![Area Class diagram](Area%20Class%20Diagram.png "Area Class diagram")
@@ -0,0 +1,49 @@
1
+ #!/bin/sh
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright © 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the terms of the GNU General
9
+ # Public License as published by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
13
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14
+ # Public License for more details.
15
+ #
16
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
17
+ #
18
+
19
+ #
20
+ # Creates an installation package.
21
+ #
22
+
23
+ # Create an empty temporary directory
24
+
25
+ SCRIPTDIR="$( cd "$( dirname "$0" )" && pwd )"
26
+ VERSION="0.1b1"
27
+ TEMPDIR="sapor-${VERSION}"
28
+
29
+ if [ -d "$TEMPDIR" ]; then
30
+ rm -R "$TEMPDIR"
31
+ fi
32
+
33
+ mkdir "$TEMPDIR"
34
+
35
+ # Copy all resources to the temporary directory
36
+
37
+ BINDIR=${SCRIPTDIR}/../bin
38
+ cp ${BINDIR}/install.sh "$TEMPDIR"
39
+ cp ${BINDIR}/sapor.sh "$TEMPDIR"
40
+ cp ${BINDIR}/sapor.rb "$TEMPDIR"
41
+
42
+ # Creates the archive file
43
+
44
+ TARFILE="sapor-${VERSION}.tar.gz"
45
+ tar -pczf $TARFILE "$TEMPDIR"
46
+
47
+ # Remove the temporary directory
48
+
49
+ rm -R $TEMPDIR
@@ -0,0 +1,45 @@
1
+ #!/bin/sh
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright © 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the terms of the GNU General
9
+ # Public License as published by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
13
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14
+ # Public License for more details.
15
+ #
16
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
17
+ #
18
+
19
+ #
20
+ # Installs SAPoR into /opt, and creates a link from /usr/bin to the sapor script.
21
+ #
22
+ # Note: Requires root permissions to create the directory. Use sudo to execute this script.
23
+ #
24
+
25
+ SAPORDIR="/opt/sapor"
26
+
27
+ if [ -d "$SAPORDIR" ]; then
28
+ rm -R "$SAPORDIR"
29
+ fi
30
+
31
+ mkdir "$SAPORDIR"
32
+
33
+ cp sapor* "$SAPORDIR"
34
+ chmod a+x "$SAPORDIR/sapor.sh"
35
+ ln -f "$SAPORDIR/sapor.sh" /usr/bin/sapor
36
+
37
+ LOG4R=$(gem list log4r | awk '/log4r/ {print $1}')
38
+ if [ ${#LOG4R[@]} -eq "0" ]; then
39
+ gem install -r log4r
40
+ fi
41
+
42
+ SAPORGEM=$(gem list sapor | awk '/sapor/ {print $1}')
43
+ if [ ${#SAPORGEM[@]} -eq "0" ]; then
44
+ gem install -r sapor
45
+ fi
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'sapor'
21
+
22
+ Sapor.analyze(ARGV[1])
@@ -0,0 +1,105 @@
1
+ #!/bin/sh
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright © 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the terms of the GNU General
9
+ # Public License as published by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
13
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14
+ # Public License for more details.
15
+ #
16
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
17
+ #
18
+
19
+ #
20
+ # Central point to run SAPoR. The script accepts the following arguments:
21
+ # - help: To display the help information.
22
+ # - version: To display the version information.
23
+ # - copyright: To display the copyright information.
24
+ # - warranty: To display the warranty information.
25
+ #
26
+
27
+ ACTION="$1"
28
+
29
+ export SAPORDIR="/opt/sapor"
30
+ export LOCALSAPORDIR="${HOME}/.sapor"
31
+ export RUBY="ruby"
32
+
33
+ VERSION="0.1b1"
34
+ COPYRIGHTYEAR="2014"
35
+
36
+ case "$ACTION" in
37
+ analyze)
38
+ if [ ! -d "$LOCALSAPORDIR" ]; then
39
+ mkdir "$LOCALSAPORDIR"
40
+ fi
41
+ if [ ! -d "${LOCALSAPORDIR}/cache" ]; then
42
+ mkdir "${LOCALSAPORDIR}/cache"
43
+ fi
44
+ $RUBY -I "${SAPORDIR}/lib" "${SAPORDIR}/sapor.rb" "${LOCALSAPORDIR}" $2
45
+ ;;
46
+ help)
47
+ echo "Statistical Analysis of Polling Results (SAPoR) v${VERSION}"
48
+ echo "Copyright © ${COPYRIGHTYEAR} Filip van Laenen <f.a.vanlaenen@ieee.org>"
49
+ echo
50
+ echo "Usage:"
51
+ echo " sapor action [parameters]"
52
+ echo
53
+ echo "where actions and parameters include:"
54
+ echo " analyze <poll-file> run an analysis on the poll file"
55
+ echo " help show this message"
56
+ echo " version show the version information"
57
+ echo " copyright show the copyright information"
58
+ echo " warranty show the warranty information"
59
+ ;;
60
+ version)
61
+ echo "Statistical Analysis of Polling Results (SAPoR) v${VERSION}"
62
+ echo "Copyright © ${COPYRIGHTYEAR} Filip van Laenen <f.a.vanlaenen@ieee.org>"
63
+ echo "This program comes with ABSOLUTELY NO WARRANTY; for details run 'wruf warranty'."
64
+ echo "This is free software, and you are welcome to redistribute it"
65
+ echo "under certain conditions; run 'wruf copyright' for details."
66
+ ;;
67
+ copyright)
68
+ echo "Statistical Analysis of Polling Results (SAPoR) v${VERSION}"
69
+ echo "Copyright © ${COPYRIGHTYEAR} Filip van Laenen <f.a.vanlaenen@ieee.org>"
70
+ echo
71
+ echo "This program is free software: you can redistribute it and/or modify"
72
+ echo "it under the terms of the GNU General Public License as published by"
73
+ echo "the Free Software Foundation, either version 3 of the License, or"
74
+ echo "(at your option) any later version."
75
+ echo
76
+ echo "This program is distributed in the hope that it will be useful,"
77
+ echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
78
+ echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
79
+ echo "GNU General Public License for more details."
80
+ echo
81
+ echo "You should have received a copy of the GNU General Public License"
82
+ echo "along with this program. If not, see <http://www.gnu.org/licenses/>."
83
+ ;;
84
+ warranty)
85
+ echo "Statistical Analysis of Polling Results (SAPoR) v${VERSION}"
86
+ echo "Copyright © ${COPYRIGHTYEAR} Filip van Laenen <f.a.vanlaenen@ieee.org>"
87
+ echo
88
+ echo "There is no warranty for the program, to the extent permitted by applicable law."
89
+ echo "Except when otherwise stated in writing the copyright holders and/or other"
90
+ echo "parties provide the program “as is” without warranty of any kind, either"
91
+ echo "expressed or implied, including, but not limited to, the implied warranties of"
92
+ echo "merchantability and fitness for a particular purpose. The entire risk as to the"
93
+ echo "quality and performance of the program is with you. Should the program prove"
94
+ echo "defective, you assume the cost of all necessary servicing, repair or correction."
95
+ ;;
96
+ *)
97
+ echo "Statistical Analysis of Polling Results (SAPoR) v${VERSION}"
98
+ echo "Copyright © ${COPYRIGHTYEAR} Filip van Laenen <f.a.vanlaenen@ieee.org>"
99
+ echo
100
+ echo "Usage: sapor {analyze|help|version|warranty|copyright}" >&2
101
+ echo "Type 'sapor help' to get more information."
102
+ exit 1
103
+ ;;
104
+ esac
105
+
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ # Library namespace
21
+ module Sapor
22
+ def self.analyze(filename)
23
+ Poll.from_file(filename).analyze
24
+ end
25
+ end
26
+
27
+ require 'sapor/number_formatter'
28
+ require 'sapor/dichotomies'
29
+ require 'sapor/combinations_distribution'
30
+ require 'sapor/dichotomy'
31
+ require 'sapor/log4r_logger'
32
+ require 'sapor/log_facade'
33
+ require 'sapor/pseudorandom_multirange_enumerator'
34
+ require 'sapor/binomials_cache'
35
+ require 'sapor/polychotomy'
36
+ require 'sapor/first_past_the_post'
37
+ require 'sapor/proportional'
38
+ require 'sapor/leveled_proportional'
39
+ require 'sapor/regional_data/area'
40
+ require 'sapor/regional_data/catalonia'
41
+ require 'sapor/regional_data/norway'
42
+ require 'sapor/regional_data/united_kingdom'
43
+ require 'sapor/regional_data/utopia'
44
+ require 'sapor/poll'
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ require 'large_binomials'
21
+
22
+ module Sapor
23
+ #
24
+ # Caches binomials.
25
+ #
26
+ class BinomialsCache
27
+ include Singleton
28
+
29
+ def initialize
30
+ @cache = {}
31
+ end
32
+
33
+ def self.binomial(k, n)
34
+ instance.get_binomial(k, n)
35
+ end
36
+
37
+ def get_binomial(k, n)
38
+ @cache[n] = {} unless @cache.key?(n)
39
+ unless @cache[n].key?(k)
40
+ @cache[n][k] = k.large_float_binomial_by_product_of_divisions(n)
41
+ end
42
+ @cache[n][k]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,180 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2014 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
+ #
6
+ # This file is part of SAPoR.
7
+ #
8
+ # SAPoR is free software: you can redistribute it and/or modify it under the
9
+ # terms of the GNU General Public License as published by the Free Software
10
+ # Foundation, either version 3 of the License, or (at your option) any later
11
+ # version.
12
+ #
13
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
14
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16
+ #
17
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
18
+ #
19
+
20
+ module Sapor
21
+ #
22
+ # Represents the distribution of combinations over a set of values. This is
23
+ # basically a simple hash with some helper methods for the Sapor domain.
24
+ #
25
+ class CombinationsDistribution
26
+ def initialize
27
+ @distribution = {}
28
+ end
29
+
30
+ def []=(value, combinations)
31
+ @distribution[value] = combinations
32
+ end
33
+
34
+ def [](value)
35
+ @distribution[value]
36
+ end
37
+
38
+ def +(other)
39
+ sum = CombinationsDistribution.new
40
+ @distribution.keys.each { |key| sum[key] = self[key] }
41
+ other.values.each do |key|
42
+ if self[key].nil?
43
+ sum[key] = other[key]
44
+ else
45
+ sum[key] += other[key]
46
+ end
47
+ end
48
+ sum
49
+ end
50
+
51
+ def empty?
52
+ @distribution.empty?
53
+ end
54
+
55
+ def value_threshold_probability(threshold_value)
56
+ total = @distribution.values.inject(:+)
57
+ distribution_over_threshold = @distribution.select do |k, _|
58
+ k >= threshold_value
59
+ end
60
+ if distribution_over_threshold.empty?
61
+ 0
62
+ else
63
+ over_threshold = distribution_over_threshold.values.inject(:+)
64
+ probability = over_threshold / total
65
+ probability.mantissa * (10**probability.exponent)
66
+ end
67
+ end
68
+
69
+ def threshold_probability(threshold, population_size)
70
+ value_threshold_probability(population_size * threshold)
71
+ end
72
+
73
+ def size
74
+ @distribution.size
75
+ end
76
+
77
+ def values
78
+ @distribution.keys
79
+ end
80
+
81
+ def most_probable_value
82
+ @distribution.max { |a, b| a.last <=> b.last }[0]
83
+ end
84
+
85
+ # Given all fractions rounded to one decimal, returns the one that has the
86
+ # highest probability.
87
+ def most_probable_rounded_fraction(population_size)
88
+ rf_combinations = \
89
+ calculate_rounded_fractions_combinations(population_size)
90
+ max_probability = rf_combinations.values.max
91
+ opt_rfs = rf_combinations.reject { |_, v| v < max_probability }.keys
92
+ opt_rfs.sort[opt_rfs.size / 2]
93
+ end
94
+
95
+ def confidence_interval(level, population_size = nil)
96
+ combinations_sum = @distribution.values.inject(:+)
97
+ one_side_level = (1 - level) / 2
98
+ one_side_threshold = combinations_sum * one_side_level
99
+ bottom = find_confidence_interval_bottom(one_side_threshold,
100
+ population_size)
101
+ top = find_confidence_interval_top(one_side_threshold, population_size)
102
+ [bottom, top]
103
+ end
104
+
105
+ def confidence_interval_values(level)
106
+ interval = confidence_interval(level)
107
+ @distribution.keys.reject do |value|
108
+ value < interval.first || value > interval.last
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def confidence_interval_index(sorted_combinations, one_side_threshold)
115
+ i = 0
116
+ sum_to_i = sorted_combinations[i][1]
117
+ while sum_to_i < one_side_threshold
118
+ i += 1
119
+ sum_to_i += sorted_combinations[i][1]
120
+ end
121
+ i
122
+ end
123
+
124
+ def find_confidence_interval_bottom(one_side_threshold, population_size)
125
+ sorted_combinations = @distribution.sort
126
+ i = confidence_interval_index(sorted_combinations, one_side_threshold)
127
+ if i == 0
128
+ population_size.nil? ? sorted_combinations[0][0] : 0
129
+ else
130
+ (sorted_combinations[i - 1][0] + sorted_combinations[i][0] + 1) / 2
131
+ end
132
+ end
133
+
134
+ def find_confidence_interval_top(one_side_threshold, population_size)
135
+ sorted_combinations = @distribution.sort.reverse
136
+ i = confidence_interval_index(sorted_combinations, one_side_threshold)
137
+ if i == 0
138
+ population_size.nil? ? sorted_combinations[0][0] : population_size
139
+ else
140
+ (sorted_combinations[i - 1][0] + sorted_combinations[i][0]) / 2
141
+ end
142
+ end
143
+
144
+ def calculate_rounded_fractions_combinations(population_size)
145
+ sorted_combinations = @distribution.sort
146
+ combinations_by_interval = []
147
+ sorted_combinations.each_with_index do |c, ix|
148
+ if ix == 0
149
+ bottom = 0
150
+ else
151
+ bottom = combinations_by_interval[ix - 1].first.last + 1
152
+ end
153
+ if ix == sorted_combinations.size - 1
154
+ top = population_size
155
+ else
156
+ top = (sorted_combinations[ix].first + sorted_combinations[ix + 1].first) / 2
157
+ end
158
+ combinations_by_interval << [[bottom, top], c.last]
159
+ end
160
+ result = Hash.new(0.to_lf)
161
+ combinations_by_interval.each do |i_c|
162
+ bottom = (i_c.first.first.to_f / population_size).round(3)
163
+ top = (i_c.first.last.to_f / population_size).round(3)
164
+ ix = bottom
165
+ loop do
166
+ interval_bottom = ((ix - 0.0005) * population_size).ceil
167
+ interval_top = ((ix + 0.0005) * population_size).ceil - 1
168
+ if (((interval_bottom + interval_top) / 2).to_f / population_size).round(3) == ix
169
+ low = [i_c.first.first, interval_bottom].max
170
+ high = [i_c.first.last, interval_top].min
171
+ result[ix] += i_c.last * (high + 1 - low)
172
+ end
173
+ break if ix == top
174
+ ix = (ix + 0.001).round(3)
175
+ end
176
+ end
177
+ result
178
+ end
179
+ end
180
+ end