sapor 0.1b1

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.
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