sapor 0.3.6

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 (343) 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/ie/2016-04-28_general-election-2016-candidate-details-csv_en.csv +552 -0
  25. data/data/ie/ireland_2016_to_psv.rb +138 -0
  26. data/data/no/2020-01-01_partifordeling_1_st_2017.csv +335 -0
  27. data/data/no/norway_2017_to_psv.rb +61 -0
  28. data/data/pl/2015-gl-lis-okr.csv +42 -0
  29. data/data/pl/poland_2015_to_psv.rb +79 -0
  30. data/data/pl/poland_2015_to_psv_with_ko_and_rsw.rb +94 -0
  31. data/data/pl/poland_2015_to_psv_with_ko_konf_kp_l_and_zp.rb +100 -0
  32. data/data/pl/poland_2015_to_psv_with_ko_sld_and_wi.rb +92 -0
  33. data/data/pl/poland_2015_to_psv_with_sld.rb +84 -0
  34. data/data/pl/poland_2015_to_psv_with_sld_and_wi.rb +85 -0
  35. data/data/uk/inject_ukip_2015_as_brexit_2019_in_2017.rb +54 -0
  36. data/data/uk/united_kingdom_2015.txt +651 -0
  37. data/data/uk/united_kingdom_2015_to_psv.rb +104 -0
  38. data/data/uk/united_kingdom_2017.txt +651 -0
  39. data/data/uk/united_kingdom_2017_to_psv.rb +104 -0
  40. data/data/uk/united_kingdom_2017_to_psv_with_brexit_and_chuk.rb +113 -0
  41. data/data/uk/united_kingdom_2017_to_psv_with_tig.rb +111 -0
  42. data/lib/sapor.rb +147 -0
  43. data/lib/sapor/binomials_cache.rb +45 -0
  44. data/lib/sapor/combinations_distribution.rb +222 -0
  45. data/lib/sapor/denominators.rb +67 -0
  46. data/lib/sapor/dichotomies.rb +138 -0
  47. data/lib/sapor/dichotomy.rb +164 -0
  48. data/lib/sapor/first_past_the_post.rb +82 -0
  49. data/lib/sapor/largest_remainder.rb +118 -0
  50. data/lib/sapor/log4r_logger.rb +49 -0
  51. data/lib/sapor/log_facade.rb +40 -0
  52. data/lib/sapor/many_past_the_post.rb +113 -0
  53. data/lib/sapor/multi_district_leveled_proportional.rb +64 -0
  54. data/lib/sapor/multi_district_proportional.rb +123 -0
  55. data/lib/sapor/multi_district_variable_threshold_proportional.rb +128 -0
  56. data/lib/sapor/number_formatter.rb +45 -0
  57. data/lib/sapor/options.rb +73 -0
  58. data/lib/sapor/poll.rb +282 -0
  59. data/lib/sapor/polychotomy.rb +200 -0
  60. data/lib/sapor/pseudorandom_multirange_enumerator.rb +87 -0
  61. data/lib/sapor/referendum_polychotomy.rb +165 -0
  62. data/lib/sapor/regional_data/area.rb +100 -0
  63. data/lib/sapor/regional_data/austria.rb +84 -0
  64. data/lib/sapor/regional_data/belgium-brussels-2014.psv +46 -0
  65. data/lib/sapor/regional_data/belgium-brussels-20190526.psv +33 -0
  66. data/lib/sapor/regional_data/belgium-flanders-2014.psv +80 -0
  67. data/lib/sapor/regional_data/belgium-flanders-20190526.psv +74 -0
  68. data/lib/sapor/regional_data/belgium-wallonia-2014.psv +114 -0
  69. data/lib/sapor/regional_data/belgium-wallonia-20190526.psv +93 -0
  70. data/lib/sapor/regional_data/belgium.rb +97 -0
  71. data/lib/sapor/regional_data/belgium_brussels.rb +62 -0
  72. data/lib/sapor/regional_data/belgium_flanders.rb +64 -0
  73. data/lib/sapor/regional_data/belgium_wallonia.rb +63 -0
  74. data/lib/sapor/regional_data/catalonia-2012-2015.psv +100 -0
  75. data/lib/sapor/regional_data/catalonia-2012.psv +87 -0
  76. data/lib/sapor/regional_data/catalonia-2015-jxcat.psv +68 -0
  77. data/lib/sapor/regional_data/catalonia-2015-no-jxsi.psv +68 -0
  78. data/lib/sapor/regional_data/catalonia-2015.psv +63 -0
  79. data/lib/sapor/regional_data/catalonia-20171221-with-vox.psv +67 -0
  80. data/lib/sapor/regional_data/catalonia-20171221.psv +61 -0
  81. data/lib/sapor/regional_data/catalonia.rb +124 -0
  82. data/lib/sapor/regional_data/denmark-20150618-with-e-and-p.psv +164 -0
  83. data/lib/sapor/regional_data/denmark-20150618-with-e.psv +153 -0
  84. data/lib/sapor/regional_data/denmark-20150618-with-p.psv +153 -0
  85. data/lib/sapor/regional_data/denmark-20150618.psv +142 -0
  86. data/lib/sapor/regional_data/denmark.rb +128 -0
  87. data/lib/sapor/regional_data/denmark_with_e.rb +128 -0
  88. data/lib/sapor/regional_data/denmark_with_e_and_p.rb +128 -0
  89. data/lib/sapor/regional_data/denmark_with_p.rb +128 -0
  90. data/lib/sapor/regional_data/estonia.rb +88 -0
  91. data/lib/sapor/regional_data/european-union-great-britain-20140522-brexit-chuk.psv +172 -0
  92. data/lib/sapor/regional_data/european-union-great-britain-20140522.psv +146 -0
  93. data/lib/sapor/regional_data/european-union-great-britain-20190523.psv +141 -0
  94. data/lib/sapor/regional_data/european-union-ireland-2014-ia-ri-sd.psv +64 -0
  95. data/lib/sapor/regional_data/european-union-ireland-2014-ia-sd.psv +60 -0
  96. data/lib/sapor/regional_data/european-union-ireland-2014-ia.psv +56 -0
  97. data/lib/sapor/regional_data/european-union-ireland-2014-sd.psv +56 -0
  98. data/lib/sapor/regional_data/european-union-ireland-2014.psv +50 -0
  99. data/lib/sapor/regional_data/european-union-ireland-20190524-ia.psv +58 -0
  100. data/lib/sapor/regional_data/european-union-ireland-20190524.psv +52 -0
  101. data/lib/sapor/regional_data/european_union_27_austria.rb +76 -0
  102. data/lib/sapor/regional_data/european_union_27_croatia.rb +83 -0
  103. data/lib/sapor/regional_data/european_union_27_denmark.rb +77 -0
  104. data/lib/sapor/regional_data/european_union_27_estonia.rb +74 -0
  105. data/lib/sapor/regional_data/european_union_27_finland.rb +74 -0
  106. data/lib/sapor/regional_data/european_union_27_france.rb +84 -0
  107. data/lib/sapor/regional_data/european_union_27_ireland.rb +96 -0
  108. data/lib/sapor/regional_data/european_union_27_ireland_with_ia.rb +97 -0
  109. data/lib/sapor/regional_data/european_union_27_italy.rb +84 -0
  110. data/lib/sapor/regional_data/european_union_27_netherlands.rb +81 -0
  111. data/lib/sapor/regional_data/european_union_27_poland.rb +84 -0
  112. data/lib/sapor/regional_data/european_union_27_romania.rb +78 -0
  113. data/lib/sapor/regional_data/european_union_27_slovakia.rb +80 -0
  114. data/lib/sapor/regional_data/european_union_27_spain.rb +82 -0
  115. data/lib/sapor/regional_data/european_union_27_sweden.rb +76 -0
  116. data/lib/sapor/regional_data/european_union_austria.rb +76 -0
  117. data/lib/sapor/regional_data/european_union_bulgaria.rb +82 -0
  118. data/lib/sapor/regional_data/european_union_croatia.rb +83 -0
  119. data/lib/sapor/regional_data/european_union_cyprus.rb +72 -0
  120. data/lib/sapor/regional_data/european_union_czech_republic.rb +82 -0
  121. data/lib/sapor/regional_data/european_union_denmark.rb +77 -0
  122. data/lib/sapor/regional_data/european_union_estonia.rb +74 -0
  123. data/lib/sapor/regional_data/european_union_finland.rb +74 -0
  124. data/lib/sapor/regional_data/european_union_flanders.rb +74 -0
  125. data/lib/sapor/regional_data/european_union_france.rb +84 -0
  126. data/lib/sapor/regional_data/european_union_french_community_of_belgium.rb +73 -0
  127. data/lib/sapor/regional_data/european_union_germany.rb +86 -0
  128. data/lib/sapor/regional_data/european_union_great_britain.rb +98 -0
  129. data/lib/sapor/regional_data/european_union_greece.rb +77 -0
  130. data/lib/sapor/regional_data/european_union_hungary.rb +76 -0
  131. data/lib/sapor/regional_data/european_union_ireland.rb +96 -0
  132. data/lib/sapor/regional_data/european_union_ireland_with_ia.rb +97 -0
  133. data/lib/sapor/regional_data/european_union_italy.rb +84 -0
  134. data/lib/sapor/regional_data/european_union_latvia.rb +81 -0
  135. data/lib/sapor/regional_data/european_union_lithuania.rb +80 -0
  136. data/lib/sapor/regional_data/european_union_luxembourg.rb +75 -0
  137. data/lib/sapor/regional_data/european_union_malta.rb +71 -0
  138. data/lib/sapor/regional_data/european_union_netherlands.rb +81 -0
  139. data/lib/sapor/regional_data/european_union_northern_ireland.rb +75 -0
  140. data/lib/sapor/regional_data/european_union_poland.rb +84 -0
  141. data/lib/sapor/regional_data/european_union_portugal.rb +75 -0
  142. data/lib/sapor/regional_data/european_union_romania.rb +78 -0
  143. data/lib/sapor/regional_data/european_union_slovakia.rb +81 -0
  144. data/lib/sapor/regional_data/european_union_slovenia.rb +85 -0
  145. data/lib/sapor/regional_data/european_union_spain.rb +82 -0
  146. data/lib/sapor/regional_data/european_union_sweden.rb +76 -0
  147. data/lib/sapor/regional_data/finland-20150419-with-sin.psv +224 -0
  148. data/lib/sapor/regional_data/finland-20150419.psv +212 -0
  149. data/lib/sapor/regional_data/finland.rb +107 -0
  150. data/lib/sapor/regional_data/finland_with_sin.rb +107 -0
  151. data/lib/sapor/regional_data/flanders-2014.psv +96 -0
  152. data/lib/sapor/regional_data/flanders-20190526.psv +87 -0
  153. data/lib/sapor/regional_data/flanders.rb +115 -0
  154. data/lib/sapor/regional_data/france.rb +38 -0
  155. data/lib/sapor/regional_data/greece.rb +92 -0
  156. data/lib/sapor/regional_data/hungary-2014.psv +2104 -0
  157. data/lib/sapor/regional_data/hungary.rb +116 -0
  158. data/lib/sapor/regional_data/iceland-20161029-midflokkurinn.psv +94 -0
  159. data/lib/sapor/regional_data/iceland-20161029.psv +88 -0
  160. data/lib/sapor/regional_data/iceland-20171028-with-j.psv +94 -0
  161. data/lib/sapor/regional_data/iceland-20171028.psv +85 -0
  162. data/lib/sapor/regional_data/iceland.rb +149 -0
  163. data/lib/sapor/regional_data/ireland-20160226-2020-candidates.psv +322 -0
  164. data/lib/sapor/regional_data/ireland-20160226-2020.psv +344 -0
  165. data/lib/sapor/regional_data/ireland-20160226.psv +348 -0
  166. data/lib/sapor/regional_data/ireland.rb +165 -0
  167. data/lib/sapor/regional_data/latvia-20141004-kpv-p-par.psv +109 -0
  168. data/lib/sapor/regional_data/latvia-20141004-kpv-par.psv +103 -0
  169. data/lib/sapor/regional_data/latvia-20141004-kpv.psv +97 -0
  170. data/lib/sapor/regional_data/latvia-20141004.psv +89 -0
  171. data/lib/sapor/regional_data/latvia-20181006.psv +104 -0
  172. data/lib/sapor/regional_data/latvia.rb +111 -0
  173. data/lib/sapor/regional_data/luxembourg-20131020.psv +60 -0
  174. data/lib/sapor/regional_data/luxembourg-20181014.psv +59 -0
  175. data/lib/sapor/regional_data/luxembourg.rb +88 -0
  176. data/lib/sapor/regional_data/netherlands.rb +108 -0
  177. data/lib/sapor/regional_data/norway-20170911.psv +331 -0
  178. data/lib/sapor/regional_data/norway.rb +130 -0
  179. data/lib/sapor/regional_data/norwegian_municipality.rb +68 -0
  180. data/lib/sapor/regional_data/poland-20151025-with-ko-and-l-without-n-po-r-and-zl.psv +321 -0
  181. 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
  182. data/lib/sapor/regional_data/poland-20151025-with-ko-sld-and-wi-without-n-po-and-zl.psv +403 -0
  183. data/lib/sapor/regional_data/poland-20151025-with-sld-and-wi-without-zl.psv +444 -0
  184. data/lib/sapor/regional_data/poland-20151025-with-sld-without-zl.psv +403 -0
  185. data/lib/sapor/regional_data/poland-20151025.psv +403 -0
  186. data/lib/sapor/regional_data/poland.rb +125 -0
  187. data/lib/sapor/regional_data/poland_with_ko_and_l_without_n_po_r_and_zl.rb +122 -0
  188. 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
  189. data/lib/sapor/regional_data/poland_with_ko_sld_and_wi_without_n_po_and_zl.rb +125 -0
  190. data/lib/sapor/regional_data/poland_with_sld_and_wi_without_zl.rb +126 -0
  191. data/lib/sapor/regional_data/poland_with_sld_without_zl.rb +126 -0
  192. data/lib/sapor/regional_data/portugal-20151004-with-a-and-ch-without-paf.psv +438 -0
  193. data/lib/sapor/regional_data/portugal-20151004-with-a-and-il-without-paf.psv +438 -0
  194. data/lib/sapor/regional_data/portugal-20151004-with-a-ch-and-il-without-paf.psv +461 -0
  195. data/lib/sapor/regional_data/portugal-20151004-with-a-without-paf.psv +415 -0
  196. data/lib/sapor/regional_data/portugal-20151004-with-ch-and-il-without-paf.psv +438 -0
  197. data/lib/sapor/regional_data/portugal-20151004-without-paf.psv +392 -0
  198. data/lib/sapor/regional_data/portugal-20151004.psv +370 -0
  199. data/lib/sapor/regional_data/portugal.rb +101 -0
  200. data/lib/sapor/regional_data/portugal_with_a_and_ch_without_paf.rb +92 -0
  201. data/lib/sapor/regional_data/portugal_with_a_and_il_without_paf.rb +92 -0
  202. data/lib/sapor/regional_data/portugal_with_a_ch_and_il_without_paf.rb +92 -0
  203. data/lib/sapor/regional_data/portugal_with_a_without_paf.rb +92 -0
  204. data/lib/sapor/regional_data/portugal_with_ch_and_il_without_paf.rb +92 -0
  205. data/lib/sapor/regional_data/portugal_without_paf.rb +92 -0
  206. data/lib/sapor/regional_data/slovakia.rb +81 -0
  207. data/lib/sapor/regional_data/slovenia.rb +114 -0
  208. data/lib/sapor/regional_data/spain-20160626.psv +619 -0
  209. data/lib/sapor/regional_data/spain.rb +136 -0
  210. data/lib/sapor/regional_data/sweden.rb +92 -0
  211. data/lib/sapor/regional_data/sweden_20140914.rb +89 -0
  212. data/lib/sapor/regional_data/united_kingdom-2015.psv +4358 -0
  213. data/lib/sapor/regional_data/united_kingdom-20170608-brexit-chuk.psv +5154 -0
  214. data/lib/sapor/regional_data/united_kingdom-20170608-brexit.psv +4521 -0
  215. data/lib/sapor/regional_data/united_kingdom-20170608-tig.psv +4529 -0
  216. data/lib/sapor/regional_data/united_kingdom-20170608.psv +3894 -0
  217. data/lib/sapor/regional_data/united_kingdom.rb +94 -0
  218. data/lib/sapor/regional_data/united_kingdom_with_brexit.rb +110 -0
  219. data/lib/sapor/regional_data/united_kingdom_with_brexit_and_chuk.rb +111 -0
  220. data/lib/sapor/regional_data/united_kingdom_with_tig.rb +111 -0
  221. data/lib/sapor/regional_data/utopia.rb +66 -0
  222. data/lib/sapor/regional_data/wallonia-2014.psv +101 -0
  223. data/lib/sapor/regional_data/wallonia-20190526.psv +88 -0
  224. data/lib/sapor/regional_data/wallonia.rb +112 -0
  225. data/lib/sapor/representatives_polychotomy.rb +338 -0
  226. data/lib/sapor/single_district_proportional.rb +75 -0
  227. data/sapor.gemspec +35 -0
  228. data/spec/integration/area_spec.rb +28 -0
  229. data/spec/integration/poll_spec.rb +112 -0
  230. data/spec/integration/sample.poll +8 -0
  231. data/spec/spec_helper.rb +31 -0
  232. data/spec/unit/area_spec.rb +115 -0
  233. data/spec/unit/austria_spec.rb +76 -0
  234. data/spec/unit/belgium_brussels_spec.rb +58 -0
  235. data/spec/unit/belgium_flanders_spec.rb +62 -0
  236. data/spec/unit/belgium_spec.rb +26 -0
  237. data/spec/unit/belgium_wallonia_spec.rb +65 -0
  238. data/spec/unit/binomials_cache_spec.rb +34 -0
  239. data/spec/unit/catalonia_spec.rb +61 -0
  240. data/spec/unit/catalonia_with_vox_spec.rb +62 -0
  241. data/spec/unit/combinations_distribution_spec.rb +241 -0
  242. data/spec/unit/denmark_spec.rb +56 -0
  243. data/spec/unit/denmark_with_e_and_p_spec.rb +58 -0
  244. data/spec/unit/denmark_with_e_spec.rb +57 -0
  245. data/spec/unit/denmark_with_p_spec.rb +57 -0
  246. data/spec/unit/denominators_spec.rb +40 -0
  247. data/spec/unit/dichotomies_spec.rb +154 -0
  248. data/spec/unit/dichotomy_spec.rb +320 -0
  249. data/spec/unit/estonia_spec.rb +65 -0
  250. data/spec/unit/european_union_27_austria_spec.rb +61 -0
  251. data/spec/unit/european_union_27_croatia_spec.rb +60 -0
  252. data/spec/unit/european_union_27_denmark_spec.rb +62 -0
  253. data/spec/unit/european_union_27_estonia_spec.rb +94 -0
  254. data/spec/unit/european_union_27_finland_spec.rb +75 -0
  255. data/spec/unit/european_union_27_france_spec.rb +73 -0
  256. data/spec/unit/european_union_27_ireland_spec.rb +72 -0
  257. data/spec/unit/european_union_27_ireland_with_ia_spec.rb +74 -0
  258. data/spec/unit/european_union_27_italy_spec.rb +69 -0
  259. data/spec/unit/european_union_27_netherlands_spec.rb +81 -0
  260. data/spec/unit/european_union_27_poland_spec.rb +69 -0
  261. data/spec/unit/european_union_27_romania_spec.rb +67 -0
  262. data/spec/unit/european_union_27_slovakia_spec.rb +111 -0
  263. data/spec/unit/european_union_27_spain_spec.rb +130 -0
  264. data/spec/unit/european_union_27_sweden_spec.rb +89 -0
  265. data/spec/unit/european_union_austria_spec.rb +61 -0
  266. data/spec/unit/european_union_bulgaria_spec.rb +97 -0
  267. data/spec/unit/european_union_croatia_spec.rb +59 -0
  268. data/spec/unit/european_union_cyprus_spec.rb +65 -0
  269. data/spec/unit/european_union_czech_republic_spec.rb +125 -0
  270. data/spec/unit/european_union_denmark_spec.rb +61 -0
  271. data/spec/unit/european_union_estonia_spec.rb +93 -0
  272. data/spec/unit/european_union_finland_spec.rb +75 -0
  273. data/spec/unit/european_union_flanders_spec.rb +56 -0
  274. data/spec/unit/european_union_france_spec.rb +73 -0
  275. data/spec/unit/european_union_french_community_of_belgium_spec.rb +61 -0
  276. data/spec/unit/european_union_germany_spec.rb +90 -0
  277. data/spec/unit/european_union_great_britain_spec.rb +87 -0
  278. data/spec/unit/european_union_greece_spec.rb +148 -0
  279. data/spec/unit/european_union_hungary_spec.rb +57 -0
  280. data/spec/unit/european_union_ireland_spec.rb +72 -0
  281. data/spec/unit/european_union_ireland_with_ia_spec.rb +74 -0
  282. data/spec/unit/european_union_italy_spec.rb +69 -0
  283. data/spec/unit/european_union_latvia_spec.rb +76 -0
  284. data/spec/unit/european_union_lithuania_spec.rb +68 -0
  285. data/spec/unit/european_union_luxembourg_spec.rb +63 -0
  286. data/spec/unit/european_union_malta_spec.rb +60 -0
  287. data/spec/unit/european_union_netherlands_spec.rb +81 -0
  288. data/spec/unit/european_union_northern_ireland_spec.rb +66 -0
  289. data/spec/unit/european_union_poland_spec.rb +69 -0
  290. data/spec/unit/european_union_portugal_spec.rb +77 -0
  291. data/spec/unit/european_union_romania_spec.rb +67 -0
  292. data/spec/unit/european_union_slovakia_spec.rb +111 -0
  293. data/spec/unit/european_union_slovenia_spec.rb +77 -0
  294. data/spec/unit/european_union_spain_spec.rb +129 -0
  295. data/spec/unit/european_union_sweden_spec.rb +89 -0
  296. data/spec/unit/finland_spec.rb +65 -0
  297. data/spec/unit/finland_with_sin_spec.rb +67 -0
  298. data/spec/unit/first_past_the_post_spec.rb +54 -0
  299. data/spec/unit/flanders_spec.rb +70 -0
  300. data/spec/unit/france_spec.rb +32 -0
  301. data/spec/unit/greece_spec.rb +118 -0
  302. data/spec/unit/hungary_spec.rb +132 -0
  303. data/spec/unit/iceland_spec.rb +57 -0
  304. data/spec/unit/iceland_with_j_spec.rb +58 -0
  305. data/spec/unit/ireland_2016_spec.rb +62 -0
  306. data/spec/unit/ireland_spec.rb +62 -0
  307. data/spec/unit/largest_remainder_spec.rb +79 -0
  308. data/spec/unit/latvia_spec.rb +62 -0
  309. data/spec/unit/luxembourg_spec.rb +55 -0
  310. data/spec/unit/multi_district_leveled_proportional_spec.rb +49 -0
  311. data/spec/unit/multi_district_proportional_spec.rb +81 -0
  312. data/spec/unit/netherlands_spec.rb +107 -0
  313. data/spec/unit/norway_spec.rb +69 -0
  314. data/spec/unit/norwegian_municipality_spec.rb +89 -0
  315. data/spec/unit/number_formatter_spec.rb +173 -0
  316. data/spec/unit/poland_spec.rb +62 -0
  317. data/spec/unit/poland_with_ko_and_l_without_n_po_r_and_zl_spec.rb +60 -0
  318. 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
  319. data/spec/unit/poland_with_ko_sld_and_wi_without_n_po_and_zl_spec.rb +62 -0
  320. data/spec/unit/poland_with_sld_and_wi_without_zl_spec.rb +63 -0
  321. data/spec/unit/poland_with_sld_without_zl_spec.rb +62 -0
  322. data/spec/unit/poll_spec.rb +110 -0
  323. data/spec/unit/portugal_spec.rb +66 -0
  324. data/spec/unit/portugal_with_a_and_ch_without_paf_spec.rb +68 -0
  325. data/spec/unit/portugal_with_a_and_il_without_paf_spec.rb +68 -0
  326. data/spec/unit/portugal_with_a_ch_and_il_without_paf_spec.rb +69 -0
  327. data/spec/unit/portugal_with_a_without_paf_spec.rb +67 -0
  328. data/spec/unit/portugal_with_ch_and_il_without_paf_spec.rb +68 -0
  329. data/spec/unit/portugal_without_paf_spec.rb +66 -0
  330. data/spec/unit/pseudorandom_multirange_enumerator_spec.rb +82 -0
  331. data/spec/unit/referendum_polychotomy_spec.rb +289 -0
  332. data/spec/unit/representatives_polychotomy_spec.rb +332 -0
  333. data/spec/unit/slovakia_spec.rb +99 -0
  334. data/spec/unit/slovenia_spec.rb +80 -0
  335. data/spec/unit/spain_spec.rb +101 -0
  336. data/spec/unit/sweden_20140914_spec.rb +112 -0
  337. data/spec/unit/sweden_spec.rb +113 -0
  338. data/spec/unit/united_kingdom_spec.rb +65 -0
  339. data/spec/unit/united_kingdom_with_brexit_and_chuk_spec.rb +67 -0
  340. data/spec/unit/united_kingdom_with_brexit_spec.rb +66 -0
  341. data/spec/unit/united_kingdom_with_tig_spec.rb +66 -0
  342. data/spec/unit/wallonia_spec.rb +70 -0
  343. metadata +502 -0
@@ -0,0 +1,101 @@
1
+ # Statistical Analysis of Polling Results (SAPoR)
2
+ # Copyright (C) 2020 Filip van Laenen <f.a.vanlaenen@ieee.org>
3
+ #
4
+ # This file is part of SAPoR.
5
+ #
6
+ # SAPoR is free software: you can redistribute it and/or modify it under the
7
+ # terms of the GNU General Public License as published by the Free Software
8
+ # Foundation, either version 3 of the License, or (at your option) any later
9
+ # version.
10
+ #
11
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
12
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
+ #
15
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
16
+ #
17
+
18
+ # Source: Official results by IBZ,
19
+ # downloaded on 21 July 2017,
20
+ # URL: http://elections2014.belgium.be/fr/wal/results/results_start.html
21
+
22
+ Brabant Wallon | MR | 97,349
23
+ Brabant Wallon | PS | 45,723
24
+ Brabant Wallon | cdH | 28,314
25
+ Brabant Wallon | Ecolo | 27,555
26
+ Brabant Wallon | DéFI | 10,945
27
+ Brabant Wallon | Parti Populaire | 9,563
28
+ Brabant Wallon | PTB | 6,592
29
+ Brabant Wallon | La Droite | 2,539
30
+ Brabant Wallon | PIRATE | 3,612
31
+ Brabant Wallon | R.W.F. | 1,277
32
+ Brabant Wallon | NATION | 867
33
+ Brabant Wallon | NWA | 453
34
+
35
+ Hainaut | MR | 162,607
36
+ Hainaut | DéFI | 16,843
37
+ Hainaut | Ecolo | 48,789
38
+ Hainaut | PS | 279,646
39
+ Hainaut | cdH | 93,321
40
+ Hainaut | Parti Populaire | 35,228
41
+ Hainaut | PTB | 42,629
42
+ Hainaut | MG | 2,419
43
+ Hainaut | La Droite | 11,076
44
+ Hainaut | Debout les Belges | 16,618
45
+ Hainaut | R.W.F. | 2,759
46
+ Hainaut | R | 789
47
+ Hainaut | Rassemblement Wallon | 3,298
48
+ Hainaut | P+ | 2,280
49
+ Hainaut | NATION | 6,923
50
+ Hainaut | NWA | 1,804
51
+ Hainaut | FW | 1,466
52
+ Hainaut | Wallonie d’Abord | 2,789
53
+ Hainaut | Atomique | 892
54
+
55
+ Liège | PS | 185,907
56
+ Liège | MR | 158,527
57
+ Liège | cdH | 81,364
58
+ Liège | Ecolo | 57,654
59
+ Liège | PTB | 51,064
60
+ Liège | Parti Populaire | 33,993
61
+ Liège | DéFI | 13,383
62
+ Liège | La Droite | 9,764
63
+ Liège | Wallonie d’Abord | 6,293
64
+ Liège | PP PARTIPENSIONNES | 4,811
65
+ Liège | VEGA | 3,501
66
+ Liège | ISLAM | 3,169
67
+ Liège | R.W.F. | 2,426
68
+ Liège | VLC | 1,927
69
+ Liège | NATION | 1,234
70
+ Liège | MG | 1,050
71
+ Liège | FW | 596
72
+ Liège | NWA | 420
73
+ Liège | R | 390
74
+
75
+ Luxembourg | cdH | 49,460
76
+ Luxembourg | MR | 46,546
77
+ Luxembourg | PS | 38,295
78
+ Luxembourg | Ecolo | 14,034
79
+ Luxembourg | Parti Populaire | 7,771
80
+ Luxembourg | DéFI | 3,270
81
+ Luxembourg | PTB | 2,848
82
+ Luxembourg | MG | 960
83
+ Luxembourg | R.W.F. | 721
84
+ Luxembourg | Rassemblement R | 487
85
+ Luxembourg | Union des Liberaux | 483
86
+
87
+ Namur | PS | 83,082
88
+ Namur | MR | 81,334
89
+ Namur | cdH | 58,036
90
+ Namur | Ecolo | 28,454
91
+ Namur | PTB | 14,749
92
+ Namur | Parti Populaire | 13,025
93
+ Namur | DéFI | 7,389
94
+ Namur | La Droite | 5,059
95
+ Namur | R.W.F. | 2,548
96
+ Namur | NATION | 1,815
97
+ Namur | R | 710
98
+ Namur | Rassemblement R | 595
99
+ Namur | FW | 557
100
+ Namur | MG | 529
101
+ Namur | UdL | 192
@@ -0,0 +1,88 @@
1
+ # Statistical Analysis of Polling Results (SAPoR)
2
+ # Copyright (C) 2020 Filip van Laenen <f.a.vanlaenen@ieee.org>
3
+ #
4
+ # This file is part of SAPoR.
5
+ #
6
+ # SAPoR is free software: you can redistribute it and/or modify it under the
7
+ # terms of the GNU General Public License as published by the Free Software
8
+ # Foundation, either version 3 of the License, or (at your option) any later
9
+ # version.
10
+ #
11
+ # SAPoR is distributed in the hope that it will be useful, but WITHOUT ANY
12
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
+ #
15
+ # You can find a copy of the GNU General Public License in /doc/gpl.txt
16
+ #
17
+
18
+ # Source: Web page with the official results of the elections of 26 May 2019,
19
+ # downloaded on 23 November 2019,
20
+ # URL: https://verkiezingen2019.belgium.be/nl/verkiezingen?el=WL
21
+
22
+ Brabant wallon | Mouvement Réformateur | 81,684
23
+ Brabant wallon | Ecolo | 47,410
24
+ Brabant wallon | Parti Socialiste | 35,803
25
+ Brabant wallon | Centre démocrate humaniste | 20,216
26
+ Brabant wallon | Parti du Travail de Belgique | 18,074
27
+ Brabant wallon | DéFI | 15,196
28
+ Brabant wallon | Parti Populaire | 6,547
29
+ Brabant wallon | Listes Destexhe | 6,031
30
+ Brabant wallon | DierAnimal | 3,675
31
+ Brabant wallon | Collectif Citoyen | 2,818
32
+ Brabant wallon | Wallonie Insoumise | 1,892
33
+ Brabant wallon | Turquoise | 590
34
+
35
+ Hainaut | Parti Socialiste | 239,616
36
+ Hainaut | Mouvement Réformateur | 122,336
37
+ Hainaut | Parti du Travail de Belgique | 115,073
38
+ Hainaut | Ecolo | 83,938
39
+ Hainaut | Centre démocrate humaniste | 63,296
40
+ Hainaut | DéFI | 26,907
41
+ Hainaut | Parti Populaire | 27,361
42
+ Hainaut | Collectif Citoyen | 10,545
43
+ Hainaut | Listes Destexhe | 8,900
44
+ Hainaut | DierAnimal | 6,347
45
+ Hainaut | AGIR | 5,967
46
+ Hainaut | NATION | 4,759
47
+ Hainaut | La Droite | 3,407
48
+ Hainaut | Demain | 1,659
49
+ Hainaut | Parti Communiste de Belgique | 944
50
+
51
+ Liège | Parti Socialiste | 154,893
52
+ Liège | Mouvement Réformateur | 124,103
53
+ Liège | Ecolo | 93,921
54
+ Liège | Parti du Travail de Belgique | 93,293
55
+ Liège | Centre démocrate humaniste | 56,816
56
+ Liège | Parti Populaire | 26,047
57
+ Liège | DéFI | 23,144
58
+ Liège | Listes Destexhe | 9,955
59
+ Liège | Collectif Citoyen | 8,786
60
+ Liège | Wallonie Insoumise | 6,263
61
+ Liège | DierAnimal | 5,393
62
+ Liège | Demain | 2,784
63
+ Liège | NATION | 2,070
64
+ Liège | REFERENDUM | 621
65
+
66
+ Luxembourg | Mouvement Réformateur | 41,705
67
+ Luxembourg | Centre démocrate humaniste | 37,151
68
+ Luxembourg | Parti Socialiste | 32,317
69
+ Luxembourg | Ecolo | 24,323
70
+ Luxembourg | Parti du Travail de Belgique | 14,933
71
+ Luxembourg | Parti Populaire | 5,044
72
+ Luxembourg | DéFI | 4,786
73
+ Luxembourg | Collectif Citoyen | 2,070
74
+ Luxembourg | Listes Destexhe | 1,549
75
+ Luxembourg | NATION | 1,170
76
+
77
+ Namur | Parti Socialiste | 69,793
78
+ Namur | Mouvement Réformateur | 66,050
79
+ Namur | Centre démocrate humaniste | 46,296
80
+ Namur | Ecolo | 45,039
81
+ Namur | Parti du Travail de Belgique | 36,970
82
+ Namur | DéFI | 14,186
83
+ Namur | Parti Populaire | 9,623
84
+ Namur | Listes Destexhe | 4,443
85
+ Namur | DierAnimal | 3,002
86
+ Namur | Collectif Citoyen | 2,454
87
+ Namur | NATION | 1,650
88
+ Namur | AGIR | 1,179
@@ -0,0 +1,112 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2020 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
+ # The regional data for Wallonia.
23
+ #
24
+ class Wallonia < Area
25
+ include Singleton
26
+ def area_code
27
+ 'BE-WAL'
28
+ end
29
+
30
+ CDH_PARTY = 'Centre démocrate humaniste'.freeze
31
+ ECOLO_PARTY = 'Ecolo'.freeze
32
+ MR_PARTY = 'Mouvement Réformateur'.freeze
33
+ PS_PARTY = 'Parti Socialiste'.freeze
34
+ PTB_PARTY = 'Parti du Travail de Belgique'.freeze
35
+
36
+ def coalitions
37
+ [[CDH_PARTY, ECOLO_PARTY, MR_PARTY],
38
+ [CDH_PARTY, ECOLO_PARTY, PS_PARTY],
39
+ [CDH_PARTY, MR_PARTY],
40
+ [CDH_PARTY, PS_PARTY],
41
+ [CDH_PARTY, PS_PARTY, PTB_PARTY],
42
+ [ECOLO_PARTY, MR_PARTY],
43
+ [ECOLO_PARTY, MR_PARTY, PS_PARTY],
44
+ [ECOLO_PARTY, PS_PARTY],
45
+ [ECOLO_PARTY, PS_PARTY, PTB_PARTY],
46
+ [ECOLO_PARTY, PTB_PARTY],
47
+ [MR_PARTY, PS_PARTY],
48
+ [PS_PARTY, PTB_PARTY]]
49
+ end
50
+
51
+ def no_of_seats
52
+ SEAT_DISTRIBUTION.values.inject(:+)
53
+ end
54
+
55
+ def overall_election_results_of_2019
56
+ if @overall_election_results_of_2019.nil?
57
+ @overall_election_results_of_2019 = \
58
+ summarize_election_results(election_results_of_2019)
59
+ end
60
+ @overall_election_results_of_2019
61
+ end
62
+
63
+ def population_size
64
+ # Voter turnout on 26 May 2019
65
+ # Source: https://verkiezingen2019.belgium.be/nl/verkiezingen?el=WL
66
+ # Retrieved on 7 December 2019
67
+ 2_034_813
68
+ end
69
+
70
+ def seats(simulation)
71
+ electoral_system.project(simulation)
72
+ end
73
+
74
+ def threshold
75
+ THRESHOLD
76
+ end
77
+
78
+ private
79
+
80
+ # Source: https://nl.wikipedia.org/wiki/Waals_Parlement
81
+ # Retrieved on 21 July 2017
82
+ SEAT_DISTRIBUTION = { 'Brabant wallon' => 8,
83
+ 'Hainaut' => 27,
84
+ 'Liège' => 23,
85
+ 'Luxembourg' => 6,
86
+ 'Namur' => 11 }.freeze
87
+
88
+ THRESHOLD = 0.05
89
+
90
+ def election_results_of_2019
91
+ if @election_results_of_2019.nil?
92
+ @election_results_of_2019 = load_election_results( \
93
+ 'wallonia-20190526.psv'
94
+ )
95
+ end
96
+ @election_results_of_2019
97
+ end
98
+
99
+ def electoral_system
100
+ if @electoral_system.nil?
101
+ @electoral_system = MultiDistrictProportional.new( \
102
+ overall_election_results_of_2019,
103
+ election_results_of_2019,
104
+ SEAT_DISTRIBUTION,
105
+ DhondtDenominators,
106
+ THRESHOLD
107
+ )
108
+ end
109
+ @electoral_system
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,338 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Statistical Analysis of Polling Results (SAPoR)
4
+ # Copyright (C) 2020 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 a polychotomy for the election of representatives.
23
+ #
24
+ class RepresentativesPolychotomy < Polychotomy
25
+ include NumberFormatter
26
+
27
+ def initialize(results, area, dichotomies, max_error, logger = nil)
28
+ @logger = logger
29
+ @coalitions = area.coalitions
30
+ super(results, area, dichotomies, max_error)
31
+ @seats = create_new_seats_distributions
32
+ end
33
+
34
+ def refine
35
+ no_of_new_simulations = 0
36
+ new_votes = create_new_votes_distributions
37
+ new_seats = create_new_seats_distributions
38
+ last_logger_info = 0
39
+ while @no_of_data_points == 0 || no_of_new_simulations == 0 ||
40
+ no_of_new_simulations < @no_of_simulations
41
+ no_of_new_simulations += try_next_data_point(new_votes, new_seats)
42
+ if @logger != nil && no_of_new_simulations > 0 && no_of_new_simulations % 131_072 == 0 && last_logger_info < no_of_new_simulations
43
+ @logger.info("#{with_thousands_separator(@no_of_simulations + no_of_new_simulations)} simulations done so far.")
44
+ last_logger_info = no_of_new_simulations
45
+ end
46
+ end
47
+ unless @no_of_simulations == 0
48
+ @error_estimate = calculate_error_estimate(new_votes)
49
+ end
50
+ @votes = merge_distributions(@votes, new_votes)
51
+ @seats = merge_distributions(@seats, new_seats)
52
+ @no_of_simulations += no_of_new_simulations
53
+ end
54
+
55
+ def try_next_data_point(new_votes, new_seats)
56
+ data_point = next_data_point
57
+ if data_point[OTHER] >= 0
58
+ simulate(new_votes, new_seats, data_point)
59
+ new_simulation = 1
60
+ else
61
+ new_simulation = 0
62
+ end
63
+ @no_of_data_points += 1
64
+ new_simulation
65
+ end
66
+
67
+ def report
68
+ choice_lengths = @choices.map(&:length)
69
+ choice_lengths << 6
70
+ max_choice_width = choice_lengths.max
71
+ max_seats_width = @area.no_of_seats.to_s.size
72
+ sorted_choices = sort_choices_by_result
73
+ choice_lines = sorted_choices.map.with_index do |choice, i|
74
+ next_choice = sorted_choices[i + 1]
75
+ create_choice_report_line(choice, next_choice, max_choice_width, max_seats_width)
76
+ end
77
+ coalition_lengths = @coalitions.map { |coalition| coalition_label(coalition).length }
78
+ coalition_lengths << 6
79
+ max_coalition_width = coalition_lengths.max
80
+ sorted_coalitions = sort_coalitions_by_result
81
+ coalition_lines = sorted_coalitions.map do |coalition|
82
+ create_coalition_report_line(coalition, max_coalition_width, max_seats_width)
83
+ end
84
+ 'Most probable rounded fractions, fractions and 95% confidence' \
85
+ " intervals:\n" + 'Choice'.ljust(max_choice_width) +
86
+ " Result MPRF MPF CI(95%) P(>↓) Seats\n" +
87
+ choice_lines.join("\n") + "\n" +
88
+ 'Coalition'.ljust(max_coalition_width) + ' Result MPRF MPF' \
89
+ " CI(95%) P(>50%) Seats P(>50%)\n" +
90
+ coalition_lines.join("\n")
91
+ end
92
+
93
+ def progress_report
94
+ space_size_ratio = space_size.to_f / @no_of_data_points
95
+ if space_size_ratio > 10
96
+ space_size_ratio = with_thousands_separator(space_size_ratio.round)
97
+ else
98
+ space_size_ratio = space_size_ratio.round(1)
99
+ end
100
+ "#{with_thousands_separator(@no_of_simulations)} simulations out of " \
101
+ "#{with_thousands_separator(@no_of_data_points)} data" \
102
+ " points, 1 / #{space_size_ratio} of search space size" \
103
+ " (#{with_thousands_separator(space_size)})."
104
+ end
105
+
106
+ def write_outputs(filename)
107
+ write_rankings(filename)
108
+ write_seats_confidence_intervals(filename)
109
+ write_seats_probabilities(filename)
110
+ write_coalitions_seats_confidence_intervals(filename)
111
+ write_coalitions_seats_probabilities(filename)
112
+ write_state_summary(filename)
113
+ end
114
+
115
+ private
116
+
117
+ def create_new_seats_distributions
118
+ seats = {}
119
+ @choices.each do |choice|
120
+ seats[choice] = CombinationsDistribution.new
121
+ Range.new(0, @area.no_of_seats).each do |value|
122
+ seats[choice][value] = 0.to_lf
123
+ end
124
+ end
125
+ @coalitions.each do |coalition|
126
+ seats[coalition] = CombinationsDistribution.new
127
+ Range.new(0, @area.no_of_seats).each do |value|
128
+ seats[coalition][value] = 0.to_lf
129
+ end
130
+ end
131
+ seats
132
+ end
133
+
134
+ def create_new_votes_distributions
135
+ votes = {}
136
+ @choices.each do |choice|
137
+ unless choice == OTHER
138
+ votes[choice] = CombinationsDistribution.new
139
+ @ranges[choice].each do |value|
140
+ votes[choice][value] = 0.to_lf
141
+ end
142
+ end
143
+ end
144
+ @coalitions.each do |coalition|
145
+ votes[coalition] = CombinationsDistribution.new
146
+ end
147
+ votes
148
+ end
149
+
150
+ def simulate(votes, seats, data_point)
151
+ combinations = 1.to_lf
152
+ data_point.each do |choice, value|
153
+ combinations *= BinomialsCache.binomial(value, @results[choice])
154
+ end
155
+ @combinations_sum += combinations
156
+ data_point.each do |choice, value|
157
+ votes[choice][value] += combinations unless choice == OTHER
158
+ end
159
+ @choices.each do |a|
160
+ @choices.each do |b|
161
+ if data_point[a] > data_point[b]
162
+ @comparisons[a + '>' + b] += combinations
163
+ end
164
+ end
165
+ end
166
+ @choices.sort { |a, b| data_point[b] <=> data_point[a] }.each_with_index do |choice, i|
167
+ @rankings[choice + '@' + i.to_s] += combinations
168
+ end
169
+ @coalitions.each do |coalition|
170
+ coalition_value = coalition.map { |choice| data_point.key?(choice) ? data_point[choice] : 0 }.inject(:+)
171
+ if votes[coalition][coalition_value].nil?
172
+ votes[coalition][coalition_value] = combinations
173
+ else
174
+ votes[coalition][coalition_value] += combinations
175
+ end
176
+ end
177
+ projection = @area.seats(data_point)
178
+ @choices.each do |choice|
179
+ if projection.key?(choice)
180
+ seats[choice][projection[choice]] += combinations
181
+ else
182
+ seats[choice][0] += combinations
183
+ end
184
+ end
185
+ @coalitions.each do |coalition|
186
+ coalition_value = coalition.map { |choice| projection.key?(choice) ? projection[choice] : 0 }.inject(:+)
187
+ if seats[coalition][coalition_value].nil?
188
+ seats[coalition][coalition_value] = combinations
189
+ else
190
+ seats[coalition][coalition_value] += combinations
191
+ end
192
+ end
193
+ end
194
+
195
+ def calculate_error_estimate(new_simulations)
196
+ error_estimate = 0
197
+ @choices.each do |choice|
198
+ unless choice == OTHER
199
+ mpv_new = calculate_most_probable_fraction(choice, new_simulations)
200
+ mpv_old = calculate_most_probable_fraction(choice, @votes)
201
+ delta = (mpv_new - mpv_old).abs
202
+ error_estimate = [error_estimate, delta].max
203
+ end
204
+ end
205
+ error_estimate
206
+ end
207
+
208
+ def merge_distributions(distributions1, distributions2)
209
+ merged_distributions = {}
210
+ @choices.each do |choice|
211
+ unless choice == OTHER
212
+ merged_distributions[choice] = distributions1[choice] + \
213
+ distributions2[choice]
214
+ end
215
+ end
216
+ @coalitions.each do |coalition|
217
+ merged_distributions[coalition] = distributions1[coalition] + \
218
+ distributions2[coalition]
219
+ end
220
+ merged_distributions
221
+ end
222
+
223
+ def coalition_label(coalition)
224
+ coalition.sort.join(' + ')
225
+ end
226
+
227
+ def sort_coalitions_by_result
228
+ @coalitions.sort do |a, b|
229
+ comparison = result(b) <=> result(a)
230
+ if comparison == 0
231
+ coalition_label(a) <=> coalition_label(b)
232
+ else
233
+ comparison
234
+ end
235
+ end
236
+ end
237
+
238
+ def coalition_result(coalition)
239
+ coalition.map { |choice| @results[choice].to_f }.inject(:+) / @results.values.inject(:+)
240
+ end
241
+
242
+ def create_choice_report_line(choice, next_choice, max_choice_width, max_seats_width)
243
+ ci_values = @votes[choice].confidence_interval(0.95)
244
+ confidence_interval = ci_values.map { |x| x.to_f / @area.population_size }
245
+ ci_seats = @seats[choice].confidence_interval(0.95)
246
+ choice.ljust(max_choice_width) + ' ' + \
247
+ six_char_percentage(result(choice)) + ' ' + \
248
+ six_char_percentage(most_probable_rounded_fraction(choice)) + ' ' + \
249
+ six_char_percentage(most_probable_fraction(choice)) + ' ' + \
250
+ six_char_percentage(confidence_interval.first) + '–' + \
251
+ six_char_percentage(confidence_interval.last) + ' ' + \
252
+ (next_choice.nil? ? ' ' : six_char_percentage(larger_than(choice, next_choice))) + ' ' + \
253
+ (max_seats_width == 1 ? ' ' : '') + \
254
+ ci_seats.first.to_s.rjust(max_seats_width) + '–' + \
255
+ ci_seats.last.to_s.rjust(max_seats_width)
256
+ end
257
+
258
+ def create_coalition_report_line(coalition, max_coalition_width, max_seats_width)
259
+ ci_values = @votes[coalition].confidence_interval(0.95)
260
+ majority_votes_probability = @votes[coalition].threshold_probability(0.5, @area.population_size)
261
+ confidence_interval = ci_values.map { |x| x.to_f / @area.population_size }
262
+ ci_seats = @seats[coalition].confidence_interval(0.95)
263
+ seats_majority = 1 + @area.no_of_seats / 2
264
+ majority_seats_probability = @seats[coalition].value_threshold_probability(seats_majority)
265
+ coalition_label(coalition).ljust(max_coalition_width) + ' ' + \
266
+ six_char_percentage(coalition_result(coalition)) + ' ' + \
267
+ six_char_percentage(most_probable_rounded_fraction(coalition)) + ' ' + \
268
+ six_char_percentage(most_probable_fraction(coalition)) + ' ' + \
269
+ six_char_percentage(confidence_interval.first) + '–' + \
270
+ six_char_percentage(confidence_interval.last) + ' ' + \
271
+ six_char_percentage(majority_votes_probability) + ' ' + \
272
+ (max_seats_width == 1 ? ' ' : '') + \
273
+ ci_seats.first.to_s.rjust(max_seats_width) + '–' + \
274
+ ci_seats.last.to_s.rjust(max_seats_width) + ' ' + \
275
+ six_char_percentage(majority_seats_probability)
276
+ end
277
+
278
+ def write_seats_confidence_intervals(filename)
279
+ ci_filename = filename.gsub('.poll', '-polychotomy-seats-confidence-intervals.psv')
280
+ File.open(ci_filename, 'w') do |file|
281
+ file.puts('Choice | CI(80%) Bottom | CI(80%) Top | CI(90%) Bottom | CI(90%) Top | CI(95%) Bottom | CI(95%) Top | CI(99%) Bottom | CI(99%) Top')
282
+ @choices.each do | choice |
283
+ unless choice == OTHER
284
+ ci80 = @seats[choice].confidence_interval(0.8)
285
+ ci90 = @seats[choice].confidence_interval(0.9)
286
+ ci95 = @seats[choice].confidence_interval(0.95)
287
+ ci99 = @seats[choice].confidence_interval(0.99)
288
+ file.puts(choice + ' | ' + ci80.first.to_s + ' | ' + \
289
+ ci80.last.to_s + ' | ' + ci90.first.to_s + ' | ' + \
290
+ ci90.last.to_s + ' | ' + ci95.first.to_s + ' | ' + \
291
+ ci95.last.to_s + ' | ' + ci99.first.to_s + ' | ' + \
292
+ ci99.last.to_s)
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ def write_seats_probabilities(filename)
299
+ ci_filename = filename.gsub('.poll', '-polychotomy-seats-probabilities.psv')
300
+ File.open(ci_filename, 'w') do |file|
301
+ file.puts('Choice | ' + Range.new(0, @area.no_of_seats).to_a.join(' | '))
302
+ @choices.each do | choice |
303
+ unless choice == OTHER
304
+ file.puts(choice + ' | ' + @seats[choice].probabilities(Range.new(0, @area.no_of_seats).to_a).join(' | '))
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ def write_coalitions_seats_confidence_intervals(filename)
311
+ ci_filename = filename.gsub('.poll', '-polychotomy-coalitions-seats-confidence-intervals.psv')
312
+ File.open(ci_filename, 'w') do |file|
313
+ file.puts('Coalition | CI(80%) Bottom | CI(80%) Top | CI(90%) Bottom | CI(90%) Top | CI(95%) Bottom | CI(95%) Top | CI(99%) Bottom | CI(99%) Top')
314
+ @coalitions.each do | coalition |
315
+ ci80 = @seats[coalition].confidence_interval(0.8)
316
+ ci90 = @seats[coalition].confidence_interval(0.9)
317
+ ci95 = @seats[coalition].confidence_interval(0.95)
318
+ ci99 = @seats[coalition].confidence_interval(0.99)
319
+ file.puts(coalition_label(coalition) + ' | ' + ci80.first.to_s + ' | ' + \
320
+ ci80.last.to_s + ' | ' + ci90.first.to_s + ' | ' + \
321
+ ci90.last.to_s + ' | ' + ci95.first.to_s + ' | ' + \
322
+ ci95.last.to_s + ' | ' + ci99.first.to_s + ' | ' + \
323
+ ci99.last.to_s)
324
+ end
325
+ end
326
+ end
327
+
328
+ def write_coalitions_seats_probabilities(filename)
329
+ ci_filename = filename.gsub('.poll', '-polychotomy-coalitions-seats-probabilities.psv')
330
+ File.open(ci_filename, 'w') do |file|
331
+ file.puts('Coalition | ' + Range.new(0, @area.no_of_seats).to_a.join(' | '))
332
+ @coalitions.each do | coalition |
333
+ file.puts(coalition_label(coalition) + ' | ' + @seats[coalition].probabilities(Range.new(0, @area.no_of_seats).to_a).join(' | '))
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end