sapor 0.3.4

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 (332) 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/Example-Catalonia.md +361 -0
  7. data/Example-Flanders.md +486 -0
  8. data/Example-Greece.md +25 -0
  9. data/Example-Oslo.md +678 -0
  10. data/Example-UnitedKingdom-Referendum.md +132 -0
  11. data/Examples.md +15 -0
  12. data/LICENSE +674 -0
  13. data/README.md +103 -0
  14. data/Rakefile +18 -0
  15. data/Technical Documentation.md +14 -0
  16. data/bin/create_installation_package.sh +49 -0
  17. data/bin/install.sh +45 -0
  18. data/bin/sapor.rb +24 -0
  19. data/bin/sapor.sh +106 -0
  20. data/data/hu/hungary-2014.txt +1680 -0
  21. data/data/hu/hungary_2014_screen_scraper.rb +48 -0
  22. data/data/hu/hungary_2014_to_psv.rb +80 -0
  23. data/data/hu/index-2014.txt +106 -0
  24. data/data/pl/2015-gl-lis-okr.csv +42 -0
  25. data/data/pl/poland_2015_to_psv.rb +79 -0
  26. data/data/pl/poland_2015_to_psv_with_ko_and_rsw.rb +94 -0
  27. data/data/pl/poland_2015_to_psv_with_ko_konf_kp_l_and_zp.rb +100 -0
  28. data/data/pl/poland_2015_to_psv_with_ko_sld_and_wi.rb +92 -0
  29. data/data/pl/poland_2015_to_psv_with_sld.rb +84 -0
  30. data/data/pl/poland_2015_to_psv_with_sld_and_wi.rb +85 -0
  31. data/data/uk/inject_ukip_2015_as_brexit_2019_in_2017.rb +54 -0
  32. data/data/uk/united_kingdom_2015.txt +651 -0
  33. data/data/uk/united_kingdom_2015_to_psv.rb +104 -0
  34. data/data/uk/united_kingdom_2017.txt +651 -0
  35. data/data/uk/united_kingdom_2017_to_psv.rb +104 -0
  36. data/data/uk/united_kingdom_2017_to_psv_with_brexit_and_chuk.rb +113 -0
  37. data/data/uk/united_kingdom_2017_to_psv_with_tig.rb +111 -0
  38. data/lib/sapor.rb +150 -0
  39. data/lib/sapor/binomials_cache.rb +45 -0
  40. data/lib/sapor/combinations_distribution.rb +222 -0
  41. data/lib/sapor/denominators.rb +67 -0
  42. data/lib/sapor/dichotomies.rb +138 -0
  43. data/lib/sapor/dichotomy.rb +164 -0
  44. data/lib/sapor/first_past_the_post.rb +82 -0
  45. data/lib/sapor/largest_remainder.rb +118 -0
  46. data/lib/sapor/log4r_logger.rb +49 -0
  47. data/lib/sapor/log_facade.rb +40 -0
  48. data/lib/sapor/multi_district_leveled_proportional.rb +64 -0
  49. data/lib/sapor/multi_district_proportional.rb +123 -0
  50. data/lib/sapor/multi_district_variable_threshold_proportional.rb +128 -0
  51. data/lib/sapor/number_formatter.rb +45 -0
  52. data/lib/sapor/options.rb +73 -0
  53. data/lib/sapor/poll.rb +286 -0
  54. data/lib/sapor/polychotomy.rb +200 -0
  55. data/lib/sapor/pseudorandom_multirange_enumerator.rb +87 -0
  56. data/lib/sapor/referendum_polychotomy.rb +165 -0
  57. data/lib/sapor/regional_data/area.rb +82 -0
  58. data/lib/sapor/regional_data/austria.rb +84 -0
  59. data/lib/sapor/regional_data/belgium-brussels-2014.psv +46 -0
  60. data/lib/sapor/regional_data/belgium-brussels-20190526.psv +33 -0
  61. data/lib/sapor/regional_data/belgium-flanders-2014.psv +80 -0
  62. data/lib/sapor/regional_data/belgium-flanders-20190526.psv +74 -0
  63. data/lib/sapor/regional_data/belgium-wallonia-2014.psv +114 -0
  64. data/lib/sapor/regional_data/belgium-wallonia-20190526.psv +93 -0
  65. data/lib/sapor/regional_data/belgium.rb +97 -0
  66. data/lib/sapor/regional_data/belgium_brussels.rb +62 -0
  67. data/lib/sapor/regional_data/belgium_flanders.rb +64 -0
  68. data/lib/sapor/regional_data/belgium_wallonia.rb +63 -0
  69. data/lib/sapor/regional_data/catalonia-2012-2015.psv +100 -0
  70. data/lib/sapor/regional_data/catalonia-2012.psv +87 -0
  71. data/lib/sapor/regional_data/catalonia-2015-jxcat.psv +68 -0
  72. data/lib/sapor/regional_data/catalonia-2015-no-jxsi.psv +68 -0
  73. data/lib/sapor/regional_data/catalonia-2015.psv +63 -0
  74. data/lib/sapor/regional_data/catalonia-jxcat.rb +109 -0
  75. data/lib/sapor/regional_data/catalonia-no-jxsi.rb +96 -0
  76. data/lib/sapor/regional_data/catalonia.rb +96 -0
  77. data/lib/sapor/regional_data/denmark-20150618-with-e-and-p.psv +164 -0
  78. data/lib/sapor/regional_data/denmark-20150618-with-e.psv +153 -0
  79. data/lib/sapor/regional_data/denmark-20150618-with-p.psv +153 -0
  80. data/lib/sapor/regional_data/denmark-20150618.psv +142 -0
  81. data/lib/sapor/regional_data/denmark.rb +128 -0
  82. data/lib/sapor/regional_data/denmark_with_e.rb +128 -0
  83. data/lib/sapor/regional_data/denmark_with_e_and_p.rb +128 -0
  84. data/lib/sapor/regional_data/denmark_with_p.rb +128 -0
  85. data/lib/sapor/regional_data/estonia.rb +88 -0
  86. data/lib/sapor/regional_data/european-union-great-britain-20140522-brexit-chuk.psv +172 -0
  87. data/lib/sapor/regional_data/european-union-great-britain-20140522.psv +146 -0
  88. data/lib/sapor/regional_data/european-union-great-britain-20190523.psv +141 -0
  89. data/lib/sapor/regional_data/european-union-ireland-2014-ia-ri-sd.psv +64 -0
  90. data/lib/sapor/regional_data/european-union-ireland-2014-ia-sd.psv +60 -0
  91. data/lib/sapor/regional_data/european-union-ireland-2014-ia.psv +56 -0
  92. data/lib/sapor/regional_data/european-union-ireland-2014-sd.psv +56 -0
  93. data/lib/sapor/regional_data/european-union-ireland-2014.psv +50 -0
  94. data/lib/sapor/regional_data/european-union-ireland-20190524-ia.psv +58 -0
  95. data/lib/sapor/regional_data/european-union-ireland-20190524.psv +52 -0
  96. data/lib/sapor/regional_data/european_union_27_austria.rb +76 -0
  97. data/lib/sapor/regional_data/european_union_27_croatia.rb +81 -0
  98. data/lib/sapor/regional_data/european_union_27_denmark.rb +77 -0
  99. data/lib/sapor/regional_data/european_union_27_estonia.rb +74 -0
  100. data/lib/sapor/regional_data/european_union_27_finland.rb +74 -0
  101. data/lib/sapor/regional_data/european_union_27_ireland.rb +96 -0
  102. data/lib/sapor/regional_data/european_union_27_ireland_with_ia.rb +97 -0
  103. data/lib/sapor/regional_data/european_union_27_italy.rb +84 -0
  104. data/lib/sapor/regional_data/european_union_27_netherlands.rb +81 -0
  105. data/lib/sapor/regional_data/european_union_27_poland.rb +84 -0
  106. data/lib/sapor/regional_data/european_union_27_romania.rb +78 -0
  107. data/lib/sapor/regional_data/european_union_27_slovakia.rb +80 -0
  108. data/lib/sapor/regional_data/european_union_27_spain.rb +82 -0
  109. data/lib/sapor/regional_data/european_union_27_sweden.rb +76 -0
  110. data/lib/sapor/regional_data/european_union_austria.rb +76 -0
  111. data/lib/sapor/regional_data/european_union_bulgaria.rb +82 -0
  112. data/lib/sapor/regional_data/european_union_croatia.rb +81 -0
  113. data/lib/sapor/regional_data/european_union_cyprus.rb +72 -0
  114. data/lib/sapor/regional_data/european_union_czech_republic.rb +82 -0
  115. data/lib/sapor/regional_data/european_union_denmark.rb +77 -0
  116. data/lib/sapor/regional_data/european_union_estonia.rb +74 -0
  117. data/lib/sapor/regional_data/european_union_finland.rb +74 -0
  118. data/lib/sapor/regional_data/european_union_flanders.rb +74 -0
  119. data/lib/sapor/regional_data/european_union_france.rb +84 -0
  120. data/lib/sapor/regional_data/european_union_france_2019.rb +84 -0
  121. data/lib/sapor/regional_data/european_union_french_community_of_belgium.rb +73 -0
  122. data/lib/sapor/regional_data/european_union_germany.rb +86 -0
  123. data/lib/sapor/regional_data/european_union_great_britain.rb +98 -0
  124. data/lib/sapor/regional_data/european_union_greece.rb +77 -0
  125. data/lib/sapor/regional_data/european_union_hungary.rb +76 -0
  126. data/lib/sapor/regional_data/european_union_ireland.rb +96 -0
  127. data/lib/sapor/regional_data/european_union_ireland_with_ia.rb +97 -0
  128. data/lib/sapor/regional_data/european_union_italy.rb +84 -0
  129. data/lib/sapor/regional_data/european_union_latvia.rb +81 -0
  130. data/lib/sapor/regional_data/european_union_lithuania.rb +80 -0
  131. data/lib/sapor/regional_data/european_union_luxembourg.rb +75 -0
  132. data/lib/sapor/regional_data/european_union_malta.rb +71 -0
  133. data/lib/sapor/regional_data/european_union_netherlands.rb +81 -0
  134. data/lib/sapor/regional_data/european_union_northern_ireland.rb +75 -0
  135. data/lib/sapor/regional_data/european_union_poland.rb +84 -0
  136. data/lib/sapor/regional_data/european_union_portugal.rb +75 -0
  137. data/lib/sapor/regional_data/european_union_romania.rb +78 -0
  138. data/lib/sapor/regional_data/european_union_slovakia.rb +81 -0
  139. data/lib/sapor/regional_data/european_union_slovenia.rb +85 -0
  140. data/lib/sapor/regional_data/european_union_spain.rb +82 -0
  141. data/lib/sapor/regional_data/european_union_sweden.rb +76 -0
  142. data/lib/sapor/regional_data/finland-20150419-with-sin.psv +224 -0
  143. data/lib/sapor/regional_data/finland-20150419.psv +212 -0
  144. data/lib/sapor/regional_data/finland.rb +107 -0
  145. data/lib/sapor/regional_data/finland_with_sin.rb +107 -0
  146. data/lib/sapor/regional_data/flanders-2014.psv +96 -0
  147. data/lib/sapor/regional_data/flanders-20190526.psv +87 -0
  148. data/lib/sapor/regional_data/flanders.rb +115 -0
  149. data/lib/sapor/regional_data/france.rb +38 -0
  150. data/lib/sapor/regional_data/greece.rb +92 -0
  151. data/lib/sapor/regional_data/hungary-2014.psv +2104 -0
  152. data/lib/sapor/regional_data/hungary.rb +116 -0
  153. data/lib/sapor/regional_data/iceland-20161029-midflokkurinn.psv +94 -0
  154. data/lib/sapor/regional_data/iceland-20161029.psv +88 -0
  155. data/lib/sapor/regional_data/iceland-20171028.psv +85 -0
  156. data/lib/sapor/regional_data/iceland.rb +133 -0
  157. data/lib/sapor/regional_data/latvia-20141004-kpv-p-par.psv +109 -0
  158. data/lib/sapor/regional_data/latvia-20141004-kpv-par.psv +103 -0
  159. data/lib/sapor/regional_data/latvia-20141004-kpv.psv +97 -0
  160. data/lib/sapor/regional_data/latvia-20141004.psv +89 -0
  161. data/lib/sapor/regional_data/latvia.rb +112 -0
  162. data/lib/sapor/regional_data/latvia_kpv.rb +112 -0
  163. data/lib/sapor/regional_data/latvia_kpv_p_par.rb +112 -0
  164. data/lib/sapor/regional_data/latvia_kpv_par.rb +112 -0
  165. data/lib/sapor/regional_data/luxembourg-20131020.psv +76 -0
  166. data/lib/sapor/regional_data/luxembourg.rb +82 -0
  167. data/lib/sapor/regional_data/netherlands.rb +108 -0
  168. data/lib/sapor/regional_data/norway.rb +425 -0
  169. data/lib/sapor/regional_data/norwegian_municipality.rb +68 -0
  170. data/lib/sapor/regional_data/poland-20151025-with-ko-and-l-without-n-po-r-and-zl.psv +321 -0
  171. data/lib/sapor/regional_data/poland-20151025-with-ko-konf-kp-l-and-zp-without-k-k15-n-pis-po-psl-r-and-zl.psv +280 -0
  172. data/lib/sapor/regional_data/poland-20151025-with-ko-sld-and-wi-without-n-po-and-zl.psv +403 -0
  173. data/lib/sapor/regional_data/poland-20151025-with-sld-and-wi-without-zl.psv +444 -0
  174. data/lib/sapor/regional_data/poland-20151025-with-sld-without-zl.psv +403 -0
  175. data/lib/sapor/regional_data/poland-20151025.psv +403 -0
  176. data/lib/sapor/regional_data/poland.rb +125 -0
  177. data/lib/sapor/regional_data/poland_with_ko_and_l_without_n_po_r_and_zl.rb +122 -0
  178. data/lib/sapor/regional_data/poland_with_ko_konf_kp_l_and_zp_without_k_k15_n_pis_po_psl_r_and_zl.rb +123 -0
  179. data/lib/sapor/regional_data/poland_with_ko_sld_and_wi_without_n_po_and_zl.rb +125 -0
  180. data/lib/sapor/regional_data/poland_with_sld_and_wi_without_zl.rb +126 -0
  181. data/lib/sapor/regional_data/poland_with_sld_without_zl.rb +126 -0
  182. data/lib/sapor/regional_data/portugal-20151004-with-a-and-ch-without-paf.psv +438 -0
  183. data/lib/sapor/regional_data/portugal-20151004-with-a-and-il-without-paf.psv +438 -0
  184. data/lib/sapor/regional_data/portugal-20151004-with-a-ch-and-il-without-paf.psv +461 -0
  185. data/lib/sapor/regional_data/portugal-20151004-with-a-without-paf.psv +415 -0
  186. data/lib/sapor/regional_data/portugal-20151004-with-ch-and-il-without-paf.psv +438 -0
  187. data/lib/sapor/regional_data/portugal-20151004-without-paf.psv +392 -0
  188. data/lib/sapor/regional_data/portugal-20151004.psv +370 -0
  189. data/lib/sapor/regional_data/portugal.rb +101 -0
  190. data/lib/sapor/regional_data/portugal_with_a_and_ch_without_paf.rb +92 -0
  191. data/lib/sapor/regional_data/portugal_with_a_and_il_without_paf.rb +92 -0
  192. data/lib/sapor/regional_data/portugal_with_a_ch_and_il_without_paf.rb +92 -0
  193. data/lib/sapor/regional_data/portugal_with_a_without_paf.rb +92 -0
  194. data/lib/sapor/regional_data/portugal_with_ch_and_il_without_paf.rb +92 -0
  195. data/lib/sapor/regional_data/portugal_without_paf.rb +92 -0
  196. data/lib/sapor/regional_data/slovakia.rb +81 -0
  197. data/lib/sapor/regional_data/slovenia.rb +114 -0
  198. data/lib/sapor/regional_data/spain-20160626.psv +619 -0
  199. data/lib/sapor/regional_data/spain.rb +136 -0
  200. data/lib/sapor/regional_data/sweden.rb +92 -0
  201. data/lib/sapor/regional_data/sweden_20140914.rb +89 -0
  202. data/lib/sapor/regional_data/united_kingdom-2015.psv +4358 -0
  203. data/lib/sapor/regional_data/united_kingdom-20170608-brexit-chuk.psv +5154 -0
  204. data/lib/sapor/regional_data/united_kingdom-20170608-brexit.psv +4521 -0
  205. data/lib/sapor/regional_data/united_kingdom-20170608-tig.psv +4529 -0
  206. data/lib/sapor/regional_data/united_kingdom-20170608.psv +3894 -0
  207. data/lib/sapor/regional_data/united_kingdom.rb +94 -0
  208. data/lib/sapor/regional_data/united_kingdom_with_brexit.rb +110 -0
  209. data/lib/sapor/regional_data/united_kingdom_with_brexit_and_chuk.rb +111 -0
  210. data/lib/sapor/regional_data/united_kingdom_with_tig.rb +111 -0
  211. data/lib/sapor/regional_data/utopia.rb +66 -0
  212. data/lib/sapor/regional_data/wallonia-2014.psv +101 -0
  213. data/lib/sapor/regional_data/wallonia-20190526.psv +88 -0
  214. data/lib/sapor/regional_data/wallonia.rb +112 -0
  215. data/lib/sapor/representatives_polychotomy.rb +338 -0
  216. data/lib/sapor/single_district_proportional.rb +75 -0
  217. data/sapor.gemspec +35 -0
  218. data/spec/integration/area_spec.rb +28 -0
  219. data/spec/integration/poll_spec.rb +112 -0
  220. data/spec/integration/sample.poll +8 -0
  221. data/spec/spec_helper.rb +31 -0
  222. data/spec/unit/area_spec.rb +115 -0
  223. data/spec/unit/austria_spec.rb +76 -0
  224. data/spec/unit/belgium_brussels_spec.rb +58 -0
  225. data/spec/unit/belgium_flanders_spec.rb +62 -0
  226. data/spec/unit/belgium_spec.rb +26 -0
  227. data/spec/unit/belgium_wallonia_spec.rb +65 -0
  228. data/spec/unit/binomials_cache_spec.rb +34 -0
  229. data/spec/unit/catalonia_spec.rb +74 -0
  230. data/spec/unit/combinations_distribution_spec.rb +241 -0
  231. data/spec/unit/denmark_spec.rb +56 -0
  232. data/spec/unit/denmark_with_e_and_p_spec.rb +58 -0
  233. data/spec/unit/denmark_with_e_spec.rb +57 -0
  234. data/spec/unit/denmark_with_p_spec.rb +57 -0
  235. data/spec/unit/denominators_spec.rb +40 -0
  236. data/spec/unit/dichotomies_spec.rb +154 -0
  237. data/spec/unit/dichotomy_spec.rb +320 -0
  238. data/spec/unit/estonia_spec.rb +65 -0
  239. data/spec/unit/european_union_27_austria_spec.rb +61 -0
  240. data/spec/unit/european_union_27_croatia_spec.rb +60 -0
  241. data/spec/unit/european_union_27_denmark_spec.rb +62 -0
  242. data/spec/unit/european_union_27_estonia_spec.rb +94 -0
  243. data/spec/unit/european_union_27_finland_spec.rb +75 -0
  244. data/spec/unit/european_union_27_ireland_spec.rb +72 -0
  245. data/spec/unit/european_union_27_ireland_with_ia_spec.rb +74 -0
  246. data/spec/unit/european_union_27_italy_spec.rb +69 -0
  247. data/spec/unit/european_union_27_netherlands_spec.rb +81 -0
  248. data/spec/unit/european_union_27_poland_spec.rb +69 -0
  249. data/spec/unit/european_union_27_romania_spec.rb +67 -0
  250. data/spec/unit/european_union_27_slovakia_spec.rb +111 -0
  251. data/spec/unit/european_union_27_spain_spec.rb +130 -0
  252. data/spec/unit/european_union_27_sweden_spec.rb +89 -0
  253. data/spec/unit/european_union_austria_spec.rb +61 -0
  254. data/spec/unit/european_union_bulgaria_spec.rb +97 -0
  255. data/spec/unit/european_union_croatia_spec.rb +59 -0
  256. data/spec/unit/european_union_cyprus_spec.rb +65 -0
  257. data/spec/unit/european_union_czech_republic_spec.rb +125 -0
  258. data/spec/unit/european_union_denmark_spec.rb +61 -0
  259. data/spec/unit/european_union_estonia_spec.rb +93 -0
  260. data/spec/unit/european_union_finland_spec.rb +75 -0
  261. data/spec/unit/european_union_flanders_spec.rb +56 -0
  262. data/spec/unit/european_union_france_2019_spec.rb +73 -0
  263. data/spec/unit/european_union_france_spec.rb +73 -0
  264. data/spec/unit/european_union_french_community_of_belgium_spec.rb +61 -0
  265. data/spec/unit/european_union_germany_spec.rb +90 -0
  266. data/spec/unit/european_union_great_britain_spec.rb +87 -0
  267. data/spec/unit/european_union_greece_spec.rb +148 -0
  268. data/spec/unit/european_union_hungary_spec.rb +57 -0
  269. data/spec/unit/european_union_ireland_spec.rb +72 -0
  270. data/spec/unit/european_union_ireland_with_ia_spec.rb +74 -0
  271. data/spec/unit/european_union_italy_spec.rb +69 -0
  272. data/spec/unit/european_union_latvia_spec.rb +76 -0
  273. data/spec/unit/european_union_lithuania_spec.rb +68 -0
  274. data/spec/unit/european_union_luxembourg_spec.rb +63 -0
  275. data/spec/unit/european_union_malta_spec.rb +60 -0
  276. data/spec/unit/european_union_netherlands_spec.rb +81 -0
  277. data/spec/unit/european_union_northern_ireland_spec.rb +66 -0
  278. data/spec/unit/european_union_poland_spec.rb +69 -0
  279. data/spec/unit/european_union_portugal_spec.rb +77 -0
  280. data/spec/unit/european_union_romania_spec.rb +67 -0
  281. data/spec/unit/european_union_slovakia_spec.rb +111 -0
  282. data/spec/unit/european_union_slovenia_spec.rb +77 -0
  283. data/spec/unit/european_union_spain_spec.rb +129 -0
  284. data/spec/unit/european_union_sweden_spec.rb +89 -0
  285. data/spec/unit/finland_spec.rb +65 -0
  286. data/spec/unit/finland_with_sin_spec.rb +67 -0
  287. data/spec/unit/first_past_the_post_spec.rb +54 -0
  288. data/spec/unit/flanders_spec.rb +70 -0
  289. data/spec/unit/france_spec.rb +32 -0
  290. data/spec/unit/greece_spec.rb +118 -0
  291. data/spec/unit/hungary_spec.rb +132 -0
  292. data/spec/unit/iceland_spec.rb +57 -0
  293. data/spec/unit/largest_remainder_spec.rb +79 -0
  294. data/spec/unit/latvia_kpv_p_par_spec.rb +38 -0
  295. data/spec/unit/latvia_kpv_par_spec.rb +38 -0
  296. data/spec/unit/latvia_kpv_spec.rb +38 -0
  297. data/spec/unit/latvia_spec.rb +60 -0
  298. data/spec/unit/luxembourg_spec.rb +54 -0
  299. data/spec/unit/multi_district_leveled_proportional_spec.rb +49 -0
  300. data/spec/unit/multi_district_proportional_spec.rb +81 -0
  301. data/spec/unit/netherlands_spec.rb +107 -0
  302. data/spec/unit/norway_spec.rb +64 -0
  303. data/spec/unit/norwegian_municipality_spec.rb +89 -0
  304. data/spec/unit/number_formatter_spec.rb +173 -0
  305. data/spec/unit/poland_spec.rb +62 -0
  306. data/spec/unit/poland_with_ko_and_l_without_n_po_r_and_zl_spec.rb +60 -0
  307. data/spec/unit/poland_with_ko_konf_kp_l_and_zp_without_k_k15_n_pis_po_psl_r_and_zl_spec.rb +59 -0
  308. data/spec/unit/poland_with_ko_sld_and_wi_without_n_po_and_zl_spec.rb +62 -0
  309. data/spec/unit/poland_with_sld_and_wi_without_zl_spec.rb +63 -0
  310. data/spec/unit/poland_with_sld_without_zl_spec.rb +62 -0
  311. data/spec/unit/poll_spec.rb +110 -0
  312. data/spec/unit/portugal_spec.rb +66 -0
  313. data/spec/unit/portugal_with_a_and_ch_without_paf_spec.rb +68 -0
  314. data/spec/unit/portugal_with_a_and_il_without_paf_spec.rb +68 -0
  315. data/spec/unit/portugal_with_a_ch_and_il_without_paf_spec.rb +69 -0
  316. data/spec/unit/portugal_with_a_without_paf_spec.rb +67 -0
  317. data/spec/unit/portugal_with_ch_and_il_without_paf_spec.rb +68 -0
  318. data/spec/unit/portugal_without_paf_spec.rb +66 -0
  319. data/spec/unit/pseudorandom_multirange_enumerator_spec.rb +82 -0
  320. data/spec/unit/referendum_polychotomy_spec.rb +289 -0
  321. data/spec/unit/representatives_polychotomy_spec.rb +332 -0
  322. data/spec/unit/slovakia_spec.rb +99 -0
  323. data/spec/unit/slovenia_spec.rb +80 -0
  324. data/spec/unit/spain_spec.rb +101 -0
  325. data/spec/unit/sweden_20140914_spec.rb +112 -0
  326. data/spec/unit/sweden_spec.rb +113 -0
  327. data/spec/unit/united_kingdom_spec.rb +65 -0
  328. data/spec/unit/united_kingdom_with_brexit_and_chuk_spec.rb +67 -0
  329. data/spec/unit/united_kingdom_with_brexit_spec.rb +66 -0
  330. data/spec/unit/united_kingdom_with_tig_spec.rb +66 -0
  331. data/spec/unit/wallonia_spec.rb +70 -0
  332. metadata +490 -0
@@ -0,0 +1,56 @@
1
+ #
2
+ # Statistical Analysis of Polling Results (SAPoR)
3
+ # Copyright (C) 2016 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ #
5
+ # This file is part of SAPoR.
6
+ #
7
+ # SAPoR is free software: you can redistribute it and/or modify it under the
8
+ # terms of the GNU General Public License as published by the Free Software
9
+ # Foundation, either version 3 of the License, or (at your option) any later
10
+ # version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
13
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
+ # A PARTICULAR PURPOSE. See the GNU General 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
+ require 'spec_helper'
20
+
21
+ describe Sapor::Denmark, '#area_code' do
22
+ it 'returns DK as the area code' do
23
+ expect(Sapor::Denmark.instance.area_code).to eq('DK')
24
+ end
25
+ end
26
+
27
+ describe Sapor::Denmark, '#no_of_seats' do
28
+ it 'returns 179 as the number of seats' do
29
+ expect(Sapor::Denmark.instance.no_of_seats).to eq(175)
30
+ end
31
+ end
32
+
33
+ describe Sapor::Denmark, '#population_size' do
34
+ it 'returns a population size of 3,518,987' do
35
+ expect(Sapor::Denmark.instance.population_size).to eq(3_518_987)
36
+ end
37
+ end
38
+
39
+ describe Sapor::Denmark, '#seats' do
40
+ it 'calculates the number of seats for the election of 2015 correctly' do
41
+ Denmark = Sapor::Denmark.instance
42
+ results = Denmark.overall_election_results_of_2015
43
+ seats = Denmark.seats(results)
44
+ expect(seats['Socialdemokraterne']).to eq(47 - 2)
45
+ expect(seats['Dansk Folkeparti']).to eq(37 - 1)
46
+ expect(seats['Venstre']).to eq(34 - 1)
47
+ expect(seats['Enhedslisten–De Rød-Grønne']).to eq(14 - 1)
48
+ expect(seats['Liberal Alliance']).to eq(13)
49
+ expect(seats['Alternativet']).to eq(9 - 1)
50
+ expect(seats['Radikale Venstre']).to eq(8)
51
+ expect(seats['Socialistisk Folkeparti']).to eq(7)
52
+ expect(seats['Det Konservative Folkeparti']).to eq(6)
53
+ expect(seats['Nye Borgerlige']).to eq(6)
54
+ expect(seats['Kristendemokraterne']).to eq(0)
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ #
2
+ # Statistical Analysis of Polling Results (SAPoR)
3
+ # Copyright (C) 2016 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ #
5
+ # This file is part of SAPoR.
6
+ #
7
+ # SAPoR is free software: you can redistribute it and/or modify it under the
8
+ # terms of the GNU General Public License as published by the Free Software
9
+ # Foundation, either version 3 of the License, or (at your option) any later
10
+ # version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
13
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
+ # A PARTICULAR PURPOSE. See the GNU General 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
+ require 'spec_helper'
20
+
21
+ describe Sapor::DenmarkWithEAndP, '#area_code' do
22
+ it 'returns DK∪{E,P} as the area code' do
23
+ expect(Sapor::DenmarkWithEAndP.instance.area_code).to eq('DK∪{E,P}')
24
+ end
25
+ end
26
+
27
+ describe Sapor::DenmarkWithEAndP, '#no_of_seats' do
28
+ it 'returns 179 as the number of seats' do
29
+ expect(Sapor::DenmarkWithEAndP.instance.no_of_seats).to eq(175)
30
+ end
31
+ end
32
+
33
+ describe Sapor::DenmarkWithEAndP, '#population_size' do
34
+ it 'returns a population size of 3,518,987' do
35
+ expect(Sapor::DenmarkWithEAndP.instance.population_size).to eq(3_518_987)
36
+ end
37
+ end
38
+
39
+ describe Sapor::DenmarkWithEAndP, '#seats' do
40
+ it 'calculates the number of seats for the election of 2015 correctly' do
41
+ Denmark = Sapor::DenmarkWithEAndP.instance
42
+ results = Denmark.overall_election_results_of_2015
43
+ seats = Denmark.seats(results)
44
+ expect(seats['Socialdemokraterne']).to eq(37)
45
+ expect(seats['Dansk Folkeparti']).to eq(29)
46
+ expect(seats['Venstre']).to eq(27)
47
+ expect(seats['Klaus Riskær Pedersen']).to eq(27)
48
+ expect(seats['Enhedslisten–De Rød-Grønne']).to eq(11)
49
+ expect(seats['Liberal Alliance']).to eq(10)
50
+ expect(seats['Alternativet']).to eq(7)
51
+ expect(seats['Radikale Venstre']).to eq(6)
52
+ expect(seats['Socialistisk Folkeparti']).to eq(6)
53
+ expect(seats['Det Konservative Folkeparti']).to eq(5)
54
+ expect(seats['Nye Borgerlige']).to eq(5)
55
+ expect(seats['Stram Kurs']).to eq(5)
56
+ expect(seats['Kristendemokraterne']).to eq(0)
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Statistical Analysis of Polling Results (SAPoR)
3
+ # Copyright (C) 2016 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ #
5
+ # This file is part of SAPoR.
6
+ #
7
+ # SAPoR is free software: you can redistribute it and/or modify it under the
8
+ # terms of the GNU General Public License as published by the Free Software
9
+ # Foundation, either version 3 of the License, or (at your option) any later
10
+ # version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
13
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
+ # A PARTICULAR PURPOSE. See the GNU General 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
+ require 'spec_helper'
20
+
21
+ describe Sapor::DenmarkWithE, '#area_code' do
22
+ it 'returns DK∪{E} as the area code' do
23
+ expect(Sapor::DenmarkWithE.instance.area_code).to eq('DK∪{E}')
24
+ end
25
+ end
26
+
27
+ describe Sapor::DenmarkWithE, '#no_of_seats' do
28
+ it 'returns 179 as the number of seats' do
29
+ expect(Sapor::DenmarkWithE.instance.no_of_seats).to eq(175)
30
+ end
31
+ end
32
+
33
+ describe Sapor::DenmarkWithE, '#population_size' do
34
+ it 'returns a population size of 3,518,987' do
35
+ expect(Sapor::DenmarkWithE.instance.population_size).to eq(3_518_987)
36
+ end
37
+ end
38
+
39
+ describe Sapor::DenmarkWithE, '#seats' do
40
+ it 'calculates the number of seats for the election of 2015 correctly' do
41
+ Denmark = Sapor::DenmarkWithE.instance
42
+ results = Denmark.overall_election_results_of_2015
43
+ seats = Denmark.seats(results)
44
+ expect(seats['Socialdemokraterne']).to eq(38)
45
+ expect(seats['Dansk Folkeparti']).to eq(30)
46
+ expect(seats['Venstre']).to eq(28)
47
+ expect(seats['Klaus Riskær Pedersen']).to eq(28)
48
+ expect(seats['Enhedslisten–De Rød-Grønne']).to eq(11)
49
+ expect(seats['Liberal Alliance']).to eq(11)
50
+ expect(seats['Alternativet']).to eq(7)
51
+ expect(seats['Radikale Venstre']).to eq(6)
52
+ expect(seats['Socialistisk Folkeparti']).to eq(6)
53
+ expect(seats['Det Konservative Folkeparti']).to eq(5)
54
+ expect(seats['Nye Borgerlige']).to eq(5)
55
+ expect(seats['Kristendemokraterne']).to eq(0)
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Statistical Analysis of Polling Results (SAPoR)
3
+ # Copyright (C) 2016 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ #
5
+ # This file is part of SAPoR.
6
+ #
7
+ # SAPoR is free software: you can redistribute it and/or modify it under the
8
+ # terms of the GNU General Public License as published by the Free Software
9
+ # Foundation, either version 3 of the License, or (at your option) any later
10
+ # version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
13
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
+ # A PARTICULAR PURPOSE. See the GNU General 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
+ require 'spec_helper'
20
+
21
+ describe Sapor::DenmarkWithP, '#area_code' do
22
+ it 'returns DK∪{P} as the area code' do
23
+ expect(Sapor::DenmarkWithP.instance.area_code).to eq('DK∪{P}')
24
+ end
25
+ end
26
+
27
+ describe Sapor::DenmarkWithP, '#no_of_seats' do
28
+ it 'returns 179 as the number of seats' do
29
+ expect(Sapor::DenmarkWithP.instance.no_of_seats).to eq(175)
30
+ end
31
+ end
32
+
33
+ describe Sapor::DenmarkWithP, '#population_size' do
34
+ it 'returns a population size of 3,518,987' do
35
+ expect(Sapor::DenmarkWithP.instance.population_size).to eq(3_518_987)
36
+ end
37
+ end
38
+
39
+ describe Sapor::DenmarkWithP, '#seats' do
40
+ it 'calculates the number of seats for the election of 2015 correctly' do
41
+ Denmark = Sapor::DenmarkWithP.instance
42
+ results = Denmark.overall_election_results_of_2015
43
+ seats = Denmark.seats(results)
44
+ expect(seats['Socialdemokraterne']).to eq(43)
45
+ expect(seats['Dansk Folkeparti']).to eq(35)
46
+ expect(seats['Venstre']).to eq(32)
47
+ expect(seats['Enhedslisten–De Rød-Grønne']).to eq(13)
48
+ expect(seats['Liberal Alliance']).to eq(12)
49
+ expect(seats['Alternativet']).to eq(8)
50
+ expect(seats['Radikale Venstre']).to eq(8)
51
+ expect(seats['Socialistisk Folkeparti']).to eq(7)
52
+ expect(seats['Det Konservative Folkeparti']).to eq(6)
53
+ expect(seats['Nye Borgerlige']).to eq(6)
54
+ expect(seats['Stram Kurs']).to eq(5)
55
+ expect(seats['Kristendemokraterne']).to eq(0)
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # Statistical Analysis of Polling Results (SAPoR)
3
+ # Copyright (C) 2016 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ #
5
+ # This file is part of SAPoR.
6
+ #
7
+ # SAPoR is free software: you can redistribute it and/or modify it under the
8
+ # terms of the GNU General Public License as published by the Free Software
9
+ # Foundation, either version 3 of the License, or (at your option) any later
10
+ # version.
11
+ #
12
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
13
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
+ # A PARTICULAR PURPOSE. See the GNU General 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
+ require 'spec_helper'
20
+
21
+ describe Sapor::DhondtDenominators, '#get' do
22
+ it 'returns [1, 2, 3, 4, 5] as the five first elements' do
23
+ denominators = Sapor::DhondtDenominators.get(5).each.to_a
24
+ expect(denominators).to eq([1, 2, 3, 4, 5])
25
+ end
26
+ end
27
+
28
+ describe Sapor::SainteLague12Denominators, '#get' do
29
+ it 'returns [1.2, 3, 5, 7, 9] as the five first elements' do
30
+ denominators = Sapor::SainteLague12Denominators.get(5).each.to_a
31
+ expect(denominators).to eq([1.2, 3, 5, 7, 9])
32
+ end
33
+ end
34
+
35
+ describe Sapor::SainteLague14Denominators, '#get' do
36
+ it 'returns [1.4, 3, 5, 7, 9] as the five first elements' do
37
+ denominators = Sapor::SainteLague14Denominators.get(5).each.to_a
38
+ expect(denominators).to eq([1.4, 3, 5, 7, 9])
39
+ end
40
+ end
@@ -0,0 +1,154 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2016 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 'spec_helper'
21
+
22
+ SAMPLE_RESULTS = { 'Red' => 1, 'Green' => 2, 'Blue' => 3, 'Other' => 1 }
23
+ SAMPLE_POPULATION_SIZE = 1_000_000
24
+
25
+ describe Sapor::Dichotomies, '#confidence_interval_values' do
26
+ it 'returns the confidence interval values' do
27
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
28
+ SAMPLE_POPULATION_SIZE)
29
+ expect(dichotomies.confidence_interval_values('Red', 0.95)).to \
30
+ eq([500_000])
31
+ end
32
+
33
+ it 'returns the non-default confidence interval values' do
34
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
35
+ SAMPLE_POPULATION_SIZE)
36
+ dichotomies.refine
37
+ expect(dichotomies.confidence_interval_values('Red', 0.9999).sort).to \
38
+ eq([166_667, 500_000, 833_333])
39
+ end
40
+ end
41
+
42
+ describe Sapor::Dichotomies, '#error_estimate' do
43
+ it 'returns the largest error estimate of the underlying Dichotomy ' \
44
+ 'objects' do
45
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
46
+ SAMPLE_POPULATION_SIZE)
47
+ expect(dichotomies.error_estimate).to eq(1)
48
+ end
49
+ end
50
+
51
+ describe Sapor::Dichotomies, '#progress_report' do
52
+ it 'reports progress as 1 data point by default' do
53
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
54
+ SAMPLE_POPULATION_SIZE)
55
+ expect(dichotomies.progress_report).to eq('Number of data points: 1.')
56
+ end
57
+
58
+ it 'reports progress as 3 data points after the first refinement' do
59
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
60
+ SAMPLE_POPULATION_SIZE)
61
+ dichotomies.refine
62
+ expect(dichotomies.progress_report).to eq('Number of data points: 3.')
63
+ end
64
+ end
65
+
66
+ describe Sapor::Dichotomies, '#report' do
67
+ it 'produces a report by default for short choice labels' do
68
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
69
+ SAMPLE_POPULATION_SIZE)
70
+ expected_report = 'Most probable fractions and 95% confidence ' \
71
+ "intervals:\n" \
72
+ "Choice MPF CI(95%)\n" \
73
+ "Blue 50.0% 0.0%–100.0%\n" \
74
+ "Green 50.0% 0.0%–100.0%\n" \
75
+ "Red 50.0% 0.0%–100.0%\n" \
76
+ 'Other 50.0% 0.0%–100.0%'
77
+ expect(dichotomies.report).to eq(expected_report)
78
+ end
79
+
80
+ it 'produces a report by default for long choice labels' do
81
+ dichotomies = Sapor::Dichotomies.new({ 'Dark Red' => 1,
82
+ 'Light Green' => 2,
83
+ 'Medium Blue' => 3, 'Other' => 1 },
84
+ SAMPLE_POPULATION_SIZE)
85
+ expected_report = 'Most probable fractions and 95% confidence ' \
86
+ "intervals:\n" \
87
+ "Choice MPF CI(95%)\n" \
88
+ "Dark Red 50.0% 0.0%–100.0%\n" \
89
+ "Light Green 50.0% 0.0%–100.0%\n" \
90
+ "Medium Blue 50.0% 0.0%–100.0%\n" \
91
+ 'Other 50.0% 0.0%–100.0%'
92
+ expect(dichotomies.report).to eq(expected_report)
93
+ end
94
+
95
+ it 'produces a report after the first refinement' do
96
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
97
+ SAMPLE_POPULATION_SIZE)
98
+ dichotomies.refine
99
+ expected_report = 'Most probable fractions and 95% confidence ' \
100
+ "intervals:\n" \
101
+ "Choice MPF CI(95%)\n" \
102
+ "Blue 50.0% 0.0%–100.0%\n" \
103
+ "Green 16.7% 0.0%– 66.7%\n" \
104
+ "Red 16.7% 0.0%– 66.7%\n" \
105
+ 'Other 16.7% 0.0%– 66.7%'
106
+ expect(dichotomies.report).to eq(expected_report)
107
+ end
108
+
109
+ it 'sorts the choices according to MPV' do
110
+ dichotomies = Sapor::Dichotomies.new({ 'Red' => 3, 'Green' => 2,
111
+ 'Blue' => 1, 'Other' => 1 },
112
+ SAMPLE_POPULATION_SIZE)
113
+ dichotomies.refine
114
+ expected_report = 'Most probable fractions and 95% confidence ' \
115
+ "intervals:\n" \
116
+ "Choice MPF CI(95%)\n" \
117
+ "Red 50.0% 0.0%–100.0%\n" \
118
+ "Blue 16.7% 0.0%– 66.7%\n" \
119
+ "Green 16.7% 0.0%– 66.7%\n" \
120
+ 'Other 16.7% 0.0%– 66.7%'
121
+ expect(dichotomies.report).to eq(expected_report)
122
+ end
123
+
124
+ it "puts Other on the last line, even if it's listed first and largest" do
125
+ dichotomies = Sapor::Dichotomies.new({ 'Other' => 4, 'Red' => 1,
126
+ 'Green' => 2, 'Blue' => 3 },
127
+ SAMPLE_POPULATION_SIZE)
128
+ dichotomies.refine
129
+ expected_report = 'Most probable fractions and 95% confidence ' \
130
+ "intervals:\n" \
131
+ "Choice MPF CI(95%)\n" \
132
+ "Blue 16.7% 0.0%– 66.7%\n" \
133
+ "Green 16.7% 0.0%– 66.7%\n" \
134
+ "Red 16.7% 0.0%– 66.7%\n" \
135
+ 'Other 50.0% 0.0%– 66.7%'
136
+ expect(dichotomies.report).to eq(expected_report)
137
+ end
138
+
139
+ it 'includes threshold probabilities when a threshold provided' do
140
+ dichotomies = Sapor::Dichotomies.new(SAMPLE_RESULTS,
141
+ SAMPLE_POPULATION_SIZE,
142
+ 0.15)
143
+ dichotomies.refine
144
+ dichotomies.refine
145
+ expected_report = 'Most probable fractions and 95% confidence ' \
146
+ "intervals:\n" \
147
+ "Choice MPF CI(95%) P(≥15%)\n" \
148
+ "Blue 38.9% 11.1%– 77.8% 99.6%\n" \
149
+ "Green 27.8% 0.0%– 66.7% 95.7%\n" \
150
+ "Red 16.7% 0.0%– 55.6% 76.1%\n" \
151
+ 'Other 16.7% 0.0%– 55.6% 76.1%'
152
+ expect(dichotomies.report).to eq(expected_report)
153
+ end
154
+ end
@@ -0,0 +1,320 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2016 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 'spec_helper'
21
+
22
+ def dichotomy_of_eight
23
+ Sapor::Dichotomy.new(2, 5, 8)
24
+ end
25
+
26
+ def dichotomy_of_nine
27
+ Sapor::Dichotomy.new(2, 5, 9)
28
+ end
29
+
30
+ def dichotomy_of_thousand
31
+ Sapor::Dichotomy.new(2, 5, 1000)
32
+ end
33
+
34
+ def dichotomy_of_nine_hundred_ninety_nine
35
+ Sapor::Dichotomy.new(2, 5, 999)
36
+ end
37
+
38
+ describe Sapor::Dichotomy, '#new' do
39
+ it 'creates an array with a value at 50% of the population size' do
40
+ expect(dichotomy_of_eight.values).to eq([4])
41
+ end
42
+
43
+ it 'creates an array with a value at 50% of the population size' \
44
+ ' (rounding)' do
45
+ expect(dichotomy_of_nine.values).to eq([4])
46
+ end
47
+
48
+ it 'creates an array with a combination for 50% of the population size' do
49
+ expect(dichotomy_of_eight.combinations(4)).to eq(24.to_lf)
50
+ end
51
+ end
52
+
53
+ describe Sapor::Dichotomy, '#confidence_interval' do
54
+ it 'returns [0%, 100%] after new for default level 95%' do
55
+ expect(dichotomy_of_eight.confidence_interval).to eq([0.0, 1.0])
56
+ end
57
+
58
+ it 'returns the default 95% confidence interval after one refinement' do
59
+ dichotomy = Sapor::Dichotomy.new(20, 50, 80)
60
+ dichotomy.refine
61
+ expect(dichotomy.confidence_interval).to eq([0.3375, 0.6625])
62
+ end
63
+
64
+ it 'returns the default 95% confidence interval after three refinements' do
65
+ dichotomy = dichotomy_of_thousand
66
+ dichotomy.refine
67
+ dichotomy.refine
68
+ dichotomy.refine
69
+ expect(dichotomy.confidence_interval).to eq([0.112, 0.777])
70
+ end
71
+
72
+ it 'returns the 80% confidence interval after three refinements' do
73
+ dichotomy = dichotomy_of_thousand
74
+ dichotomy.refine
75
+ dichotomy.refine
76
+ dichotomy.refine
77
+ expect(dichotomy.confidence_interval(0.8)).to eq([0.186, 0.666])
78
+ end
79
+ end
80
+
81
+ describe Sapor::Dichotomy, '#error_estimate' do
82
+ it 'is 0 when population size is reached' do
83
+ dichotomy = dichotomy_of_eight
84
+ dichotomy.refine
85
+ dichotomy.refine
86
+ dichotomy.refine
87
+ expect(dichotomy.error_estimate).to eq(0)
88
+ end
89
+
90
+ it 'is at least the resolution (no refinement)' do
91
+ dichotomy = dichotomy_of_eight
92
+ expect(dichotomy.error_estimate).to eq(1.0)
93
+ end
94
+
95
+ it 'is at least the resolution (one refinement)' do
96
+ dichotomy = dichotomy_of_eight
97
+ dichotomy.refine
98
+ expect(dichotomy.error_estimate).to eq(1.to_f / 3)
99
+ end
100
+ end
101
+
102
+ describe Sapor::Dichotomy, '#most_probable_fraction' do
103
+ it 'returns the fraction of the single value after new' do
104
+ expect(dichotomy_of_eight.most_probable_fraction).to eq(0.5)
105
+ end
106
+
107
+ it 'returns the one probable value after one refinement' do
108
+ dichotomy = dichotomy_of_eight
109
+ dichotomy.refine
110
+ expect(dichotomy.most_probable_fraction).to eq(0.5)
111
+ end
112
+
113
+ it 'returns the new most probable value after two refinements' do
114
+ dichotomy = dichotomy_of_eight
115
+ dichotomy.refine
116
+ dichotomy.refine
117
+ expect(dichotomy.most_probable_fraction).to eq(0.375)
118
+ end
119
+ end
120
+
121
+ describe Sapor::Dichotomy, '#most_probable_value' do
122
+ it 'returns the single value after new' do
123
+ expect(dichotomy_of_eight.most_probable_value).to eq(4)
124
+ end
125
+
126
+ it 'returns the one probable value after one refinement' do
127
+ dichotomy = dichotomy_of_eight
128
+ dichotomy.refine
129
+ expect(dichotomy.most_probable_value).to eq(4)
130
+ end
131
+
132
+ it 'returns the new most probable value after two refinements' do
133
+ dichotomy = dichotomy_of_eight
134
+ dichotomy.refine
135
+ dichotomy.refine
136
+ expect(dichotomy.most_probable_value).to eq(3)
137
+ end
138
+ end
139
+
140
+ describe Sapor::Dichotomy, '#refine' do
141
+ it 'adds values after one refinement (power of three)' do
142
+ dichotomy = dichotomy_of_eight
143
+ dichotomy.refine
144
+ expect(dichotomy.values.sort).to eq([1, 4, 7])
145
+ end
146
+
147
+ it 'adds values after one refinement (small population)' do
148
+ dichotomy = dichotomy_of_nine
149
+ dichotomy.refine
150
+ expect(dichotomy.values.sort).to eq([1, 4, 7])
151
+ end
152
+
153
+ it 'adds values after one refinement (large population)' do
154
+ dichotomy = dichotomy_of_thousand
155
+ dichotomy.refine
156
+ expect(dichotomy.values.sort).to eq([167, 500, 833])
157
+ end
158
+
159
+ it 'adds values after two refinements (power of three)' do
160
+ dichotomy = dichotomy_of_eight
161
+ dichotomy.refine
162
+ dichotomy.refine
163
+ expect(dichotomy.values.sort).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8])
164
+ end
165
+
166
+ it 'adds values after two refinements (small population)' do
167
+ dichotomy = dichotomy_of_nine
168
+ dichotomy.refine
169
+ dichotomy.refine
170
+ expect(dichotomy.values.sort).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8])
171
+ end
172
+
173
+ it 'adds values after two refinements (small population)' do
174
+ dichotomy = Sapor::Dichotomy.new(2, 5, 60)
175
+ dichotomy.refine
176
+ dichotomy.refine
177
+ expect(dichotomy.values.sort).to eq([3, 10, 17, 23, 30, 37, 43, 50, 57])
178
+ end
179
+
180
+ it 'adds values after two refinements (large population)' do
181
+ dichotomy = dichotomy_of_thousand
182
+ dichotomy.refine
183
+ dichotomy.refine
184
+ expect(dichotomy.values.sort).to eq([56, 167, 278, 389, 500, 611, 722, 833,
185
+ 944])
186
+ end
187
+
188
+ it "doesn't add values when population size is reached" do
189
+ dichotomy = dichotomy_of_eight
190
+ dichotomy.refine
191
+ dichotomy.refine
192
+ dichotomy.refine
193
+ expect(dichotomy.values.sort).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8])
194
+ end
195
+
196
+ it 'fills up the values when population size is reached' do
197
+ dichotomy = dichotomy_of_nine
198
+ dichotomy.refine
199
+ dichotomy.refine
200
+ dichotomy.refine
201
+ expect(dichotomy.values.sort).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
202
+ end
203
+
204
+ it 'fills up the values when population size is reached' do
205
+ dichotomy = Sapor::Dichotomy.new(2, 5, 11)
206
+ dichotomy.refine
207
+ dichotomy.refine
208
+ dichotomy.refine
209
+ expect(dichotomy.values.sort).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
210
+ end
211
+
212
+ it 'adds combinations after a refinement' do
213
+ dichotomy = dichotomy_of_thousand
214
+ dichotomy.refine
215
+ expect(dichotomy.combinations(167)).to eq(1_330_493_216_416.to_lf)
216
+ expect(dichotomy.combinations(833)).to eq(264_177_353_440.to_lf)
217
+ end
218
+
219
+ it 'adds combinations of zero for impossible values' do
220
+ dichotomy = dichotomy_of_eight
221
+ dichotomy.refine
222
+ expect(dichotomy.combinations(1)).to eq(0.to_lf)
223
+ expect(dichotomy.combinations(7)).to eq(0.to_lf)
224
+ end
225
+ end
226
+
227
+ describe Sapor::Dichotomy, '#threshold_probability' do
228
+ it 'returns 100% after new for a 50% threshold' do
229
+ expect(dichotomy_of_thousand.threshold_probability(0.5)).to eq(1)
230
+ end
231
+
232
+ it 'returns 0% after new for a 51% threshold' do
233
+ expect(dichotomy_of_thousand.threshold_probability(0.51)).to eq(0)
234
+ end
235
+
236
+ it 'returns 100% for a 5% threshold after one refinement' do
237
+ dichotomy = dichotomy_of_thousand
238
+ dichotomy.refine
239
+ expect(dichotomy.threshold_probability(0.05)).to eq(1)
240
+ end
241
+
242
+ it 'returns 68% (after rounding) for a 50% threshold after one refinement' do
243
+ dichotomy = dichotomy_of_thousand
244
+ dichotomy.refine
245
+ expect(dichotomy.threshold_probability(0.5).round(2)).to eq(0.68)
246
+ end
247
+
248
+ it 'returns 0% for a 95% threshold after one refinement' do
249
+ dichotomy = dichotomy_of_thousand
250
+ dichotomy.refine
251
+ expect(dichotomy.threshold_probability(0.95)).to eq(0)
252
+ end
253
+ end
254
+
255
+ describe Sapor::Dichotomy, '#value_confidence_interval' do
256
+ it 'returns [0, population_size] values after new for default level 95%' do
257
+ expect(dichotomy_of_eight.value_confidence_interval).to eq([0, 8])
258
+ end
259
+
260
+ it 'returns [0, population_size] values after new for level 80%' do
261
+ expect(dichotomy_of_eight.value_confidence_interval(0.8)).to eq([0, 8])
262
+ end
263
+
264
+ it 'returns the value confidence interval after one refinement' do
265
+ dichotomy = Sapor::Dichotomy.new(20, 50, 80)
266
+ dichotomy.refine
267
+ expect(dichotomy.value_confidence_interval).to eq([27, 53])
268
+ end
269
+
270
+ it 'returns the value confidence interval after full refinement' do
271
+ dichotomy = dichotomy_of_eight
272
+ dichotomy.refine
273
+ dichotomy.refine
274
+ expect(dichotomy.value_confidence_interval).to eq([2, 5])
275
+ end
276
+
277
+ it 'returns the 80% value confidence interval after full refinement' do
278
+ dichotomy = dichotomy_of_eight
279
+ dichotomy.refine
280
+ dichotomy.refine
281
+ expect(dichotomy.value_confidence_interval(0.8)).to eq([2, 5])
282
+ end
283
+
284
+ it 'returns the value confidence interval after two refinements' do
285
+ dichotomy = dichotomy_of_thousand
286
+ dichotomy.refine
287
+ dichotomy.refine
288
+ expect(dichotomy.value_confidence_interval).to eq([112, 777])
289
+ end
290
+
291
+ it 'returns the 80% value confidence interval after two refinements' do
292
+ dichotomy = dichotomy_of_thousand
293
+ dichotomy.refine
294
+ dichotomy.refine
295
+ expect(dichotomy.value_confidence_interval(0.8)).to eq([112, 666])
296
+ end
297
+
298
+ it 'returns the value confidence interval after three refinements' do
299
+ dichotomy = dichotomy_of_thousand
300
+ dichotomy.refine
301
+ dichotomy.refine
302
+ dichotomy.refine
303
+ expect(dichotomy.value_confidence_interval).to eq([112, 777])
304
+ end
305
+
306
+ it 'can return a confidence interval starting at 0 after refinements' do
307
+ dichotomy = Sapor::Dichotomy.new(0, 5, 1000)
308
+ dichotomy.refine
309
+ dichotomy.refine
310
+ expect(dichotomy.value_confidence_interval).to eq([0, 555])
311
+ end
312
+
313
+ it 'can return a confidence interval ending at population size after ' \
314
+ 'refinements' do
315
+ dichotomy = Sapor::Dichotomy.new(5, 5, 1000)
316
+ dichotomy.refine
317
+ dichotomy.refine
318
+ expect(dichotomy.value_confidence_interval).to eq([445, 1000])
319
+ end
320
+ end