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.
- checksums.yaml +7 -0
- data/Area Class Diagram.dia +0 -0
- data/Area Class Diagram.png +0 -0
- data/Class Diagram.dia +0 -0
- data/Class Diagram.png +0 -0
- data/Example-Catalonia.md +361 -0
- data/Example-Flanders.md +486 -0
- data/Example-Greece.md +25 -0
- data/Example-Oslo.md +678 -0
- data/Example-UnitedKingdom-Referendum.md +132 -0
- data/Examples.md +15 -0
- data/LICENSE +674 -0
- data/README.md +103 -0
- data/Rakefile +18 -0
- data/Technical Documentation.md +14 -0
- data/bin/create_installation_package.sh +49 -0
- data/bin/install.sh +45 -0
- data/bin/sapor.rb +24 -0
- data/bin/sapor.sh +106 -0
- data/data/hu/hungary-2014.txt +1680 -0
- data/data/hu/hungary_2014_screen_scraper.rb +48 -0
- data/data/hu/hungary_2014_to_psv.rb +80 -0
- data/data/hu/index-2014.txt +106 -0
- data/data/pl/2015-gl-lis-okr.csv +42 -0
- data/data/pl/poland_2015_to_psv.rb +79 -0
- data/data/pl/poland_2015_to_psv_with_ko_and_rsw.rb +94 -0
- data/data/pl/poland_2015_to_psv_with_ko_konf_kp_l_and_zp.rb +100 -0
- data/data/pl/poland_2015_to_psv_with_ko_sld_and_wi.rb +92 -0
- data/data/pl/poland_2015_to_psv_with_sld.rb +84 -0
- data/data/pl/poland_2015_to_psv_with_sld_and_wi.rb +85 -0
- data/data/uk/inject_ukip_2015_as_brexit_2019_in_2017.rb +54 -0
- data/data/uk/united_kingdom_2015.txt +651 -0
- data/data/uk/united_kingdom_2015_to_psv.rb +104 -0
- data/data/uk/united_kingdom_2017.txt +651 -0
- data/data/uk/united_kingdom_2017_to_psv.rb +104 -0
- data/data/uk/united_kingdom_2017_to_psv_with_brexit_and_chuk.rb +113 -0
- data/data/uk/united_kingdom_2017_to_psv_with_tig.rb +111 -0
- data/lib/sapor.rb +150 -0
- data/lib/sapor/binomials_cache.rb +45 -0
- data/lib/sapor/combinations_distribution.rb +222 -0
- data/lib/sapor/denominators.rb +67 -0
- data/lib/sapor/dichotomies.rb +138 -0
- data/lib/sapor/dichotomy.rb +164 -0
- data/lib/sapor/first_past_the_post.rb +82 -0
- data/lib/sapor/largest_remainder.rb +118 -0
- data/lib/sapor/log4r_logger.rb +49 -0
- data/lib/sapor/log_facade.rb +40 -0
- data/lib/sapor/multi_district_leveled_proportional.rb +64 -0
- data/lib/sapor/multi_district_proportional.rb +123 -0
- data/lib/sapor/multi_district_variable_threshold_proportional.rb +128 -0
- data/lib/sapor/number_formatter.rb +45 -0
- data/lib/sapor/options.rb +73 -0
- data/lib/sapor/poll.rb +286 -0
- data/lib/sapor/polychotomy.rb +200 -0
- data/lib/sapor/pseudorandom_multirange_enumerator.rb +87 -0
- data/lib/sapor/referendum_polychotomy.rb +165 -0
- data/lib/sapor/regional_data/area.rb +82 -0
- data/lib/sapor/regional_data/austria.rb +84 -0
- data/lib/sapor/regional_data/belgium-brussels-2014.psv +46 -0
- data/lib/sapor/regional_data/belgium-brussels-20190526.psv +33 -0
- data/lib/sapor/regional_data/belgium-flanders-2014.psv +80 -0
- data/lib/sapor/regional_data/belgium-flanders-20190526.psv +74 -0
- data/lib/sapor/regional_data/belgium-wallonia-2014.psv +114 -0
- data/lib/sapor/regional_data/belgium-wallonia-20190526.psv +93 -0
- data/lib/sapor/regional_data/belgium.rb +97 -0
- data/lib/sapor/regional_data/belgium_brussels.rb +62 -0
- data/lib/sapor/regional_data/belgium_flanders.rb +64 -0
- data/lib/sapor/regional_data/belgium_wallonia.rb +63 -0
- data/lib/sapor/regional_data/catalonia-2012-2015.psv +100 -0
- data/lib/sapor/regional_data/catalonia-2012.psv +87 -0
- data/lib/sapor/regional_data/catalonia-2015-jxcat.psv +68 -0
- data/lib/sapor/regional_data/catalonia-2015-no-jxsi.psv +68 -0
- data/lib/sapor/regional_data/catalonia-2015.psv +63 -0
- data/lib/sapor/regional_data/catalonia-jxcat.rb +109 -0
- data/lib/sapor/regional_data/catalonia-no-jxsi.rb +96 -0
- data/lib/sapor/regional_data/catalonia.rb +96 -0
- data/lib/sapor/regional_data/denmark-20150618-with-e-and-p.psv +164 -0
- data/lib/sapor/regional_data/denmark-20150618-with-e.psv +153 -0
- data/lib/sapor/regional_data/denmark-20150618-with-p.psv +153 -0
- data/lib/sapor/regional_data/denmark-20150618.psv +142 -0
- data/lib/sapor/regional_data/denmark.rb +128 -0
- data/lib/sapor/regional_data/denmark_with_e.rb +128 -0
- data/lib/sapor/regional_data/denmark_with_e_and_p.rb +128 -0
- data/lib/sapor/regional_data/denmark_with_p.rb +128 -0
- data/lib/sapor/regional_data/estonia.rb +88 -0
- data/lib/sapor/regional_data/european-union-great-britain-20140522-brexit-chuk.psv +172 -0
- data/lib/sapor/regional_data/european-union-great-britain-20140522.psv +146 -0
- data/lib/sapor/regional_data/european-union-great-britain-20190523.psv +141 -0
- data/lib/sapor/regional_data/european-union-ireland-2014-ia-ri-sd.psv +64 -0
- data/lib/sapor/regional_data/european-union-ireland-2014-ia-sd.psv +60 -0
- data/lib/sapor/regional_data/european-union-ireland-2014-ia.psv +56 -0
- data/lib/sapor/regional_data/european-union-ireland-2014-sd.psv +56 -0
- data/lib/sapor/regional_data/european-union-ireland-2014.psv +50 -0
- data/lib/sapor/regional_data/european-union-ireland-20190524-ia.psv +58 -0
- data/lib/sapor/regional_data/european-union-ireland-20190524.psv +52 -0
- data/lib/sapor/regional_data/european_union_27_austria.rb +76 -0
- data/lib/sapor/regional_data/european_union_27_croatia.rb +81 -0
- data/lib/sapor/regional_data/european_union_27_denmark.rb +77 -0
- data/lib/sapor/regional_data/european_union_27_estonia.rb +74 -0
- data/lib/sapor/regional_data/european_union_27_finland.rb +74 -0
- data/lib/sapor/regional_data/european_union_27_ireland.rb +96 -0
- data/lib/sapor/regional_data/european_union_27_ireland_with_ia.rb +97 -0
- data/lib/sapor/regional_data/european_union_27_italy.rb +84 -0
- data/lib/sapor/regional_data/european_union_27_netherlands.rb +81 -0
- data/lib/sapor/regional_data/european_union_27_poland.rb +84 -0
- data/lib/sapor/regional_data/european_union_27_romania.rb +78 -0
- data/lib/sapor/regional_data/european_union_27_slovakia.rb +80 -0
- data/lib/sapor/regional_data/european_union_27_spain.rb +82 -0
- data/lib/sapor/regional_data/european_union_27_sweden.rb +76 -0
- data/lib/sapor/regional_data/european_union_austria.rb +76 -0
- data/lib/sapor/regional_data/european_union_bulgaria.rb +82 -0
- data/lib/sapor/regional_data/european_union_croatia.rb +81 -0
- data/lib/sapor/regional_data/european_union_cyprus.rb +72 -0
- data/lib/sapor/regional_data/european_union_czech_republic.rb +82 -0
- data/lib/sapor/regional_data/european_union_denmark.rb +77 -0
- data/lib/sapor/regional_data/european_union_estonia.rb +74 -0
- data/lib/sapor/regional_data/european_union_finland.rb +74 -0
- data/lib/sapor/regional_data/european_union_flanders.rb +74 -0
- data/lib/sapor/regional_data/european_union_france.rb +84 -0
- data/lib/sapor/regional_data/european_union_france_2019.rb +84 -0
- data/lib/sapor/regional_data/european_union_french_community_of_belgium.rb +73 -0
- data/lib/sapor/regional_data/european_union_germany.rb +86 -0
- data/lib/sapor/regional_data/european_union_great_britain.rb +98 -0
- data/lib/sapor/regional_data/european_union_greece.rb +77 -0
- data/lib/sapor/regional_data/european_union_hungary.rb +76 -0
- data/lib/sapor/regional_data/european_union_ireland.rb +96 -0
- data/lib/sapor/regional_data/european_union_ireland_with_ia.rb +97 -0
- data/lib/sapor/regional_data/european_union_italy.rb +84 -0
- data/lib/sapor/regional_data/european_union_latvia.rb +81 -0
- data/lib/sapor/regional_data/european_union_lithuania.rb +80 -0
- data/lib/sapor/regional_data/european_union_luxembourg.rb +75 -0
- data/lib/sapor/regional_data/european_union_malta.rb +71 -0
- data/lib/sapor/regional_data/european_union_netherlands.rb +81 -0
- data/lib/sapor/regional_data/european_union_northern_ireland.rb +75 -0
- data/lib/sapor/regional_data/european_union_poland.rb +84 -0
- data/lib/sapor/regional_data/european_union_portugal.rb +75 -0
- data/lib/sapor/regional_data/european_union_romania.rb +78 -0
- data/lib/sapor/regional_data/european_union_slovakia.rb +81 -0
- data/lib/sapor/regional_data/european_union_slovenia.rb +85 -0
- data/lib/sapor/regional_data/european_union_spain.rb +82 -0
- data/lib/sapor/regional_data/european_union_sweden.rb +76 -0
- data/lib/sapor/regional_data/finland-20150419-with-sin.psv +224 -0
- data/lib/sapor/regional_data/finland-20150419.psv +212 -0
- data/lib/sapor/regional_data/finland.rb +107 -0
- data/lib/sapor/regional_data/finland_with_sin.rb +107 -0
- data/lib/sapor/regional_data/flanders-2014.psv +96 -0
- data/lib/sapor/regional_data/flanders-20190526.psv +87 -0
- data/lib/sapor/regional_data/flanders.rb +115 -0
- data/lib/sapor/regional_data/france.rb +38 -0
- data/lib/sapor/regional_data/greece.rb +92 -0
- data/lib/sapor/regional_data/hungary-2014.psv +2104 -0
- data/lib/sapor/regional_data/hungary.rb +116 -0
- data/lib/sapor/regional_data/iceland-20161029-midflokkurinn.psv +94 -0
- data/lib/sapor/regional_data/iceland-20161029.psv +88 -0
- data/lib/sapor/regional_data/iceland-20171028.psv +85 -0
- data/lib/sapor/regional_data/iceland.rb +133 -0
- data/lib/sapor/regional_data/latvia-20141004-kpv-p-par.psv +109 -0
- data/lib/sapor/regional_data/latvia-20141004-kpv-par.psv +103 -0
- data/lib/sapor/regional_data/latvia-20141004-kpv.psv +97 -0
- data/lib/sapor/regional_data/latvia-20141004.psv +89 -0
- data/lib/sapor/regional_data/latvia.rb +112 -0
- data/lib/sapor/regional_data/latvia_kpv.rb +112 -0
- data/lib/sapor/regional_data/latvia_kpv_p_par.rb +112 -0
- data/lib/sapor/regional_data/latvia_kpv_par.rb +112 -0
- data/lib/sapor/regional_data/luxembourg-20131020.psv +76 -0
- data/lib/sapor/regional_data/luxembourg.rb +82 -0
- data/lib/sapor/regional_data/netherlands.rb +108 -0
- data/lib/sapor/regional_data/norway.rb +425 -0
- data/lib/sapor/regional_data/norwegian_municipality.rb +68 -0
- data/lib/sapor/regional_data/poland-20151025-with-ko-and-l-without-n-po-r-and-zl.psv +321 -0
- 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
- data/lib/sapor/regional_data/poland-20151025-with-ko-sld-and-wi-without-n-po-and-zl.psv +403 -0
- data/lib/sapor/regional_data/poland-20151025-with-sld-and-wi-without-zl.psv +444 -0
- data/lib/sapor/regional_data/poland-20151025-with-sld-without-zl.psv +403 -0
- data/lib/sapor/regional_data/poland-20151025.psv +403 -0
- data/lib/sapor/regional_data/poland.rb +125 -0
- data/lib/sapor/regional_data/poland_with_ko_and_l_without_n_po_r_and_zl.rb +122 -0
- 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
- data/lib/sapor/regional_data/poland_with_ko_sld_and_wi_without_n_po_and_zl.rb +125 -0
- data/lib/sapor/regional_data/poland_with_sld_and_wi_without_zl.rb +126 -0
- data/lib/sapor/regional_data/poland_with_sld_without_zl.rb +126 -0
- data/lib/sapor/regional_data/portugal-20151004-with-a-and-ch-without-paf.psv +438 -0
- data/lib/sapor/regional_data/portugal-20151004-with-a-and-il-without-paf.psv +438 -0
- data/lib/sapor/regional_data/portugal-20151004-with-a-ch-and-il-without-paf.psv +461 -0
- data/lib/sapor/regional_data/portugal-20151004-with-a-without-paf.psv +415 -0
- data/lib/sapor/regional_data/portugal-20151004-with-ch-and-il-without-paf.psv +438 -0
- data/lib/sapor/regional_data/portugal-20151004-without-paf.psv +392 -0
- data/lib/sapor/regional_data/portugal-20151004.psv +370 -0
- data/lib/sapor/regional_data/portugal.rb +101 -0
- data/lib/sapor/regional_data/portugal_with_a_and_ch_without_paf.rb +92 -0
- data/lib/sapor/regional_data/portugal_with_a_and_il_without_paf.rb +92 -0
- data/lib/sapor/regional_data/portugal_with_a_ch_and_il_without_paf.rb +92 -0
- data/lib/sapor/regional_data/portugal_with_a_without_paf.rb +92 -0
- data/lib/sapor/regional_data/portugal_with_ch_and_il_without_paf.rb +92 -0
- data/lib/sapor/regional_data/portugal_without_paf.rb +92 -0
- data/lib/sapor/regional_data/slovakia.rb +81 -0
- data/lib/sapor/regional_data/slovenia.rb +114 -0
- data/lib/sapor/regional_data/spain-20160626.psv +619 -0
- data/lib/sapor/regional_data/spain.rb +136 -0
- data/lib/sapor/regional_data/sweden.rb +92 -0
- data/lib/sapor/regional_data/sweden_20140914.rb +89 -0
- data/lib/sapor/regional_data/united_kingdom-2015.psv +4358 -0
- data/lib/sapor/regional_data/united_kingdom-20170608-brexit-chuk.psv +5154 -0
- data/lib/sapor/regional_data/united_kingdom-20170608-brexit.psv +4521 -0
- data/lib/sapor/regional_data/united_kingdom-20170608-tig.psv +4529 -0
- data/lib/sapor/regional_data/united_kingdom-20170608.psv +3894 -0
- data/lib/sapor/regional_data/united_kingdom.rb +94 -0
- data/lib/sapor/regional_data/united_kingdom_with_brexit.rb +110 -0
- data/lib/sapor/regional_data/united_kingdom_with_brexit_and_chuk.rb +111 -0
- data/lib/sapor/regional_data/united_kingdom_with_tig.rb +111 -0
- data/lib/sapor/regional_data/utopia.rb +66 -0
- data/lib/sapor/regional_data/wallonia-2014.psv +101 -0
- data/lib/sapor/regional_data/wallonia-20190526.psv +88 -0
- data/lib/sapor/regional_data/wallonia.rb +112 -0
- data/lib/sapor/representatives_polychotomy.rb +338 -0
- data/lib/sapor/single_district_proportional.rb +75 -0
- data/sapor.gemspec +35 -0
- data/spec/integration/area_spec.rb +28 -0
- data/spec/integration/poll_spec.rb +112 -0
- data/spec/integration/sample.poll +8 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/unit/area_spec.rb +115 -0
- data/spec/unit/austria_spec.rb +76 -0
- data/spec/unit/belgium_brussels_spec.rb +58 -0
- data/spec/unit/belgium_flanders_spec.rb +62 -0
- data/spec/unit/belgium_spec.rb +26 -0
- data/spec/unit/belgium_wallonia_spec.rb +65 -0
- data/spec/unit/binomials_cache_spec.rb +34 -0
- data/spec/unit/catalonia_spec.rb +74 -0
- data/spec/unit/combinations_distribution_spec.rb +241 -0
- data/spec/unit/denmark_spec.rb +56 -0
- data/spec/unit/denmark_with_e_and_p_spec.rb +58 -0
- data/spec/unit/denmark_with_e_spec.rb +57 -0
- data/spec/unit/denmark_with_p_spec.rb +57 -0
- data/spec/unit/denominators_spec.rb +40 -0
- data/spec/unit/dichotomies_spec.rb +154 -0
- data/spec/unit/dichotomy_spec.rb +320 -0
- data/spec/unit/estonia_spec.rb +65 -0
- data/spec/unit/european_union_27_austria_spec.rb +61 -0
- data/spec/unit/european_union_27_croatia_spec.rb +60 -0
- data/spec/unit/european_union_27_denmark_spec.rb +62 -0
- data/spec/unit/european_union_27_estonia_spec.rb +94 -0
- data/spec/unit/european_union_27_finland_spec.rb +75 -0
- data/spec/unit/european_union_27_ireland_spec.rb +72 -0
- data/spec/unit/european_union_27_ireland_with_ia_spec.rb +74 -0
- data/spec/unit/european_union_27_italy_spec.rb +69 -0
- data/spec/unit/european_union_27_netherlands_spec.rb +81 -0
- data/spec/unit/european_union_27_poland_spec.rb +69 -0
- data/spec/unit/european_union_27_romania_spec.rb +67 -0
- data/spec/unit/european_union_27_slovakia_spec.rb +111 -0
- data/spec/unit/european_union_27_spain_spec.rb +130 -0
- data/spec/unit/european_union_27_sweden_spec.rb +89 -0
- data/spec/unit/european_union_austria_spec.rb +61 -0
- data/spec/unit/european_union_bulgaria_spec.rb +97 -0
- data/spec/unit/european_union_croatia_spec.rb +59 -0
- data/spec/unit/european_union_cyprus_spec.rb +65 -0
- data/spec/unit/european_union_czech_republic_spec.rb +125 -0
- data/spec/unit/european_union_denmark_spec.rb +61 -0
- data/spec/unit/european_union_estonia_spec.rb +93 -0
- data/spec/unit/european_union_finland_spec.rb +75 -0
- data/spec/unit/european_union_flanders_spec.rb +56 -0
- data/spec/unit/european_union_france_2019_spec.rb +73 -0
- data/spec/unit/european_union_france_spec.rb +73 -0
- data/spec/unit/european_union_french_community_of_belgium_spec.rb +61 -0
- data/spec/unit/european_union_germany_spec.rb +90 -0
- data/spec/unit/european_union_great_britain_spec.rb +87 -0
- data/spec/unit/european_union_greece_spec.rb +148 -0
- data/spec/unit/european_union_hungary_spec.rb +57 -0
- data/spec/unit/european_union_ireland_spec.rb +72 -0
- data/spec/unit/european_union_ireland_with_ia_spec.rb +74 -0
- data/spec/unit/european_union_italy_spec.rb +69 -0
- data/spec/unit/european_union_latvia_spec.rb +76 -0
- data/spec/unit/european_union_lithuania_spec.rb +68 -0
- data/spec/unit/european_union_luxembourg_spec.rb +63 -0
- data/spec/unit/european_union_malta_spec.rb +60 -0
- data/spec/unit/european_union_netherlands_spec.rb +81 -0
- data/spec/unit/european_union_northern_ireland_spec.rb +66 -0
- data/spec/unit/european_union_poland_spec.rb +69 -0
- data/spec/unit/european_union_portugal_spec.rb +77 -0
- data/spec/unit/european_union_romania_spec.rb +67 -0
- data/spec/unit/european_union_slovakia_spec.rb +111 -0
- data/spec/unit/european_union_slovenia_spec.rb +77 -0
- data/spec/unit/european_union_spain_spec.rb +129 -0
- data/spec/unit/european_union_sweden_spec.rb +89 -0
- data/spec/unit/finland_spec.rb +65 -0
- data/spec/unit/finland_with_sin_spec.rb +67 -0
- data/spec/unit/first_past_the_post_spec.rb +54 -0
- data/spec/unit/flanders_spec.rb +70 -0
- data/spec/unit/france_spec.rb +32 -0
- data/spec/unit/greece_spec.rb +118 -0
- data/spec/unit/hungary_spec.rb +132 -0
- data/spec/unit/iceland_spec.rb +57 -0
- data/spec/unit/largest_remainder_spec.rb +79 -0
- data/spec/unit/latvia_kpv_p_par_spec.rb +38 -0
- data/spec/unit/latvia_kpv_par_spec.rb +38 -0
- data/spec/unit/latvia_kpv_spec.rb +38 -0
- data/spec/unit/latvia_spec.rb +60 -0
- data/spec/unit/luxembourg_spec.rb +54 -0
- data/spec/unit/multi_district_leveled_proportional_spec.rb +49 -0
- data/spec/unit/multi_district_proportional_spec.rb +81 -0
- data/spec/unit/netherlands_spec.rb +107 -0
- data/spec/unit/norway_spec.rb +64 -0
- data/spec/unit/norwegian_municipality_spec.rb +89 -0
- data/spec/unit/number_formatter_spec.rb +173 -0
- data/spec/unit/poland_spec.rb +62 -0
- data/spec/unit/poland_with_ko_and_l_without_n_po_r_and_zl_spec.rb +60 -0
- 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
- data/spec/unit/poland_with_ko_sld_and_wi_without_n_po_and_zl_spec.rb +62 -0
- data/spec/unit/poland_with_sld_and_wi_without_zl_spec.rb +63 -0
- data/spec/unit/poland_with_sld_without_zl_spec.rb +62 -0
- data/spec/unit/poll_spec.rb +110 -0
- data/spec/unit/portugal_spec.rb +66 -0
- data/spec/unit/portugal_with_a_and_ch_without_paf_spec.rb +68 -0
- data/spec/unit/portugal_with_a_and_il_without_paf_spec.rb +68 -0
- data/spec/unit/portugal_with_a_ch_and_il_without_paf_spec.rb +69 -0
- data/spec/unit/portugal_with_a_without_paf_spec.rb +67 -0
- data/spec/unit/portugal_with_ch_and_il_without_paf_spec.rb +68 -0
- data/spec/unit/portugal_without_paf_spec.rb +66 -0
- data/spec/unit/pseudorandom_multirange_enumerator_spec.rb +82 -0
- data/spec/unit/referendum_polychotomy_spec.rb +289 -0
- data/spec/unit/representatives_polychotomy_spec.rb +332 -0
- data/spec/unit/slovakia_spec.rb +99 -0
- data/spec/unit/slovenia_spec.rb +80 -0
- data/spec/unit/spain_spec.rb +101 -0
- data/spec/unit/sweden_20140914_spec.rb +112 -0
- data/spec/unit/sweden_spec.rb +113 -0
- data/spec/unit/united_kingdom_spec.rb +65 -0
- data/spec/unit/united_kingdom_with_brexit_and_chuk_spec.rb +67 -0
- data/spec/unit/united_kingdom_with_brexit_spec.rb +66 -0
- data/spec/unit/united_kingdom_with_tig_spec.rb +66 -0
- data/spec/unit/wallonia_spec.rb +70 -0
- metadata +490 -0
|
@@ -0,0 +1,45 @@
|
|
|
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 'large_binomials'
|
|
21
|
+
|
|
22
|
+
module Sapor
|
|
23
|
+
#
|
|
24
|
+
# Caches binomials.
|
|
25
|
+
#
|
|
26
|
+
class BinomialsCache
|
|
27
|
+
include Singleton
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@cache = {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.binomial(k, n)
|
|
34
|
+
instance.get_binomial(k, n)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def get_binomial(k, n)
|
|
38
|
+
@cache[n] = {} unless @cache.key?(n)
|
|
39
|
+
unless @cache[n].key?(k)
|
|
40
|
+
@cache[n][k] = k.large_float_binomial_by_product_of_divisions(n)
|
|
41
|
+
end
|
|
42
|
+
@cache[n][k]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
module Sapor
|
|
21
|
+
#
|
|
22
|
+
# Represents the distribution of combinations over a set of values. This is
|
|
23
|
+
# basically a simple hash with some helper methods for the Sapor domain.
|
|
24
|
+
#
|
|
25
|
+
class CombinationsDistribution
|
|
26
|
+
def initialize
|
|
27
|
+
@distribution = {}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def []=(value, combinations)
|
|
31
|
+
@distribution[value] = combinations
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def [](value)
|
|
35
|
+
@distribution[value]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def +(other)
|
|
39
|
+
sum = CombinationsDistribution.new
|
|
40
|
+
@distribution.keys.each { |key| sum[key] = self[key] }
|
|
41
|
+
other.values.each do |key|
|
|
42
|
+
if self[key].nil?
|
|
43
|
+
sum[key] = other[key]
|
|
44
|
+
else
|
|
45
|
+
sum[key] += other[key]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
sum
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def empty?
|
|
52
|
+
@distribution.empty?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def interval_probabilities(intervals, population_size)
|
|
56
|
+
value_interval_probabilities(intervals.map {|interval| [interval.first * population_size, interval.last * population_size]})
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def value_interval_probabilities(value_intervals)
|
|
60
|
+
total = @distribution.values.inject(:+)
|
|
61
|
+
value_intervals.map do | value_interval |
|
|
62
|
+
distribution_in_interval = @distribution.select do |k, _|
|
|
63
|
+
k >= value_interval.first && k < value_interval.last
|
|
64
|
+
end
|
|
65
|
+
if distribution_in_interval.empty?
|
|
66
|
+
0
|
|
67
|
+
else
|
|
68
|
+
in_interval = distribution_in_interval.values.inject(:+)
|
|
69
|
+
probability = in_interval / total
|
|
70
|
+
probability.mantissa * (10**probability.exponent)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def value_threshold_probability(threshold_value)
|
|
76
|
+
total = @distribution.values.inject(:+)
|
|
77
|
+
distribution_over_threshold = @distribution.select do |k, _|
|
|
78
|
+
k >= threshold_value
|
|
79
|
+
end
|
|
80
|
+
if distribution_over_threshold.empty?
|
|
81
|
+
0
|
|
82
|
+
else
|
|
83
|
+
over_threshold = distribution_over_threshold.values.inject(:+)
|
|
84
|
+
probability = over_threshold / total
|
|
85
|
+
probability.mantissa * (10**probability.exponent)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def probabilities(values)
|
|
90
|
+
total = @distribution.values.inject(:+)
|
|
91
|
+
values.map do | value |
|
|
92
|
+
if @distribution.key?(value)
|
|
93
|
+
probability = @distribution[value] / total
|
|
94
|
+
probability.mantissa * (10**probability.exponent)
|
|
95
|
+
else
|
|
96
|
+
0
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def probability(value)
|
|
102
|
+
if @distribution.key?(value)
|
|
103
|
+
total = @distribution.values.inject(:+)
|
|
104
|
+
probability = @distribution[value] / total
|
|
105
|
+
probability.mantissa * (10**probability.exponent)
|
|
106
|
+
else
|
|
107
|
+
0
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def threshold_probability(threshold, population_size)
|
|
112
|
+
value_threshold_probability(population_size * threshold)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def size
|
|
116
|
+
@distribution.size
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def values
|
|
120
|
+
@distribution.keys
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def most_probable_value
|
|
124
|
+
@distribution.max { |a, b| a.last <=> b.last }[0]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Given all fractions rounded to one decimal, returns the one that has the
|
|
128
|
+
# highest probability.
|
|
129
|
+
def most_probable_rounded_fraction(population_size)
|
|
130
|
+
rf_combinations = \
|
|
131
|
+
calculate_rounded_fractions_combinations(population_size)
|
|
132
|
+
max_probability = rf_combinations.values.max
|
|
133
|
+
opt_rfs = rf_combinations.reject { |_, v| v < max_probability }.keys
|
|
134
|
+
opt_rfs.sort[opt_rfs.size / 2]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def confidence_interval(level, population_size = nil)
|
|
138
|
+
combinations_sum = @distribution.values.inject(:+)
|
|
139
|
+
one_side_level = (1 - level) / 2
|
|
140
|
+
one_side_threshold = combinations_sum * one_side_level
|
|
141
|
+
bottom = find_confidence_interval_bottom(one_side_threshold,
|
|
142
|
+
population_size)
|
|
143
|
+
top = find_confidence_interval_top(one_side_threshold, population_size)
|
|
144
|
+
[bottom, top]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def confidence_interval_values(level)
|
|
148
|
+
interval = confidence_interval(level)
|
|
149
|
+
@distribution.keys.reject do |value|
|
|
150
|
+
value < interval.first || value > interval.last
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
def confidence_interval_index(sorted_combinations, one_side_threshold)
|
|
157
|
+
i = 0
|
|
158
|
+
sum_to_i = sorted_combinations[i][1]
|
|
159
|
+
while sum_to_i < one_side_threshold
|
|
160
|
+
i += 1
|
|
161
|
+
sum_to_i += sorted_combinations[i][1]
|
|
162
|
+
end
|
|
163
|
+
i
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def find_confidence_interval_bottom(one_side_threshold, population_size)
|
|
167
|
+
sorted_combinations = @distribution.sort
|
|
168
|
+
i = confidence_interval_index(sorted_combinations, one_side_threshold)
|
|
169
|
+
if i == 0
|
|
170
|
+
population_size.nil? ? sorted_combinations[0][0] : 0
|
|
171
|
+
else
|
|
172
|
+
(sorted_combinations[i - 1][0] + sorted_combinations[i][0] + 1) / 2
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def find_confidence_interval_top(one_side_threshold, population_size)
|
|
177
|
+
sorted_combinations = @distribution.sort.reverse
|
|
178
|
+
i = confidence_interval_index(sorted_combinations, one_side_threshold)
|
|
179
|
+
if i == 0
|
|
180
|
+
population_size.nil? ? sorted_combinations[0][0] : population_size
|
|
181
|
+
else
|
|
182
|
+
(sorted_combinations[i - 1][0] + sorted_combinations[i][0]) / 2
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def calculate_rounded_fractions_combinations(population_size)
|
|
187
|
+
sorted_combinations = @distribution.sort
|
|
188
|
+
combinations_by_interval = []
|
|
189
|
+
sorted_combinations.each_with_index do |c, ix|
|
|
190
|
+
if ix == 0
|
|
191
|
+
bottom = 0
|
|
192
|
+
else
|
|
193
|
+
bottom = combinations_by_interval[ix - 1].first.last + 1
|
|
194
|
+
end
|
|
195
|
+
if ix == sorted_combinations.size - 1
|
|
196
|
+
top = population_size
|
|
197
|
+
else
|
|
198
|
+
top = (sorted_combinations[ix].first + sorted_combinations[ix + 1].first) / 2
|
|
199
|
+
end
|
|
200
|
+
combinations_by_interval << [[bottom, top], c.last]
|
|
201
|
+
end
|
|
202
|
+
result = Hash.new(0.to_lf)
|
|
203
|
+
combinations_by_interval.each do |i_c|
|
|
204
|
+
bottom = (i_c.first.first.to_f / population_size).round(3)
|
|
205
|
+
top = (i_c.first.last.to_f / population_size).round(3)
|
|
206
|
+
ix = bottom
|
|
207
|
+
loop do
|
|
208
|
+
interval_bottom = ((ix - 0.0005) * population_size).ceil
|
|
209
|
+
interval_top = ((ix + 0.0005) * population_size).ceil - 1
|
|
210
|
+
if (((interval_bottom + interval_top) / 2).to_f / population_size).round(3) == ix
|
|
211
|
+
low = [i_c.first.first, interval_bottom].max
|
|
212
|
+
high = [i_c.first.last, interval_top].min
|
|
213
|
+
result[ix] += i_c.last * (high + 1 - low)
|
|
214
|
+
end
|
|
215
|
+
break if ix == top
|
|
216
|
+
ix = (ix + 0.001).round(3)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
result
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
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
|
+
module Sapor
|
|
20
|
+
#
|
|
21
|
+
# Class building the denominators for D'Hondt.
|
|
22
|
+
#
|
|
23
|
+
class DhondtDenominators
|
|
24
|
+
def self.get(size)
|
|
25
|
+
Range.new(1, size)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Class building the denominators for modified D'Hondt raising the
|
|
31
|
+
# denominators to the power 0.9.
|
|
32
|
+
#
|
|
33
|
+
class Dhondt09Denominators
|
|
34
|
+
def self.get(size)
|
|
35
|
+
Range.new(1, size).map { |a| a**0.9 }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Class building the denominators for Sainte-Lague.
|
|
41
|
+
#
|
|
42
|
+
class SainteLagueDenominators
|
|
43
|
+
def self.get(size)
|
|
44
|
+
Range.new(1, size).map { |a| a * 2 - 1 }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#
|
|
49
|
+
# Class building the denominators for the modified Sainte-Lague starting with
|
|
50
|
+
# 1.2.
|
|
51
|
+
#
|
|
52
|
+
class SainteLague12Denominators
|
|
53
|
+
def self.get(size)
|
|
54
|
+
Range.new(1, size).map { |a| a.equal?(1) ? 1.2 : a * 2 - 1 }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Class building the denominators for the modified Sainte-Lague starting with
|
|
60
|
+
# 1.4.
|
|
61
|
+
#
|
|
62
|
+
class SainteLague14Denominators
|
|
63
|
+
def self.get(size)
|
|
64
|
+
Range.new(1, size).map { |a| a.equal?(1) ? 1.4 : a * 2 - 1 }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
module Sapor
|
|
21
|
+
#
|
|
22
|
+
# Represents a set of dichotomies.
|
|
23
|
+
#
|
|
24
|
+
class Dichotomies
|
|
25
|
+
include NumberFormatter
|
|
26
|
+
|
|
27
|
+
def initialize(results, population_size, threshold = nil)
|
|
28
|
+
sample_size = results.values.inject(:+)
|
|
29
|
+
@dichotomy_hash = {}
|
|
30
|
+
results.each_pair do |choice, number|
|
|
31
|
+
@dichotomy_hash[choice] = Dichotomy.new(number, sample_size,
|
|
32
|
+
population_size)
|
|
33
|
+
end
|
|
34
|
+
@threshold = threshold
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def refine
|
|
38
|
+
@dichotomy_hash.values.each(&:refine)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def error_estimate
|
|
42
|
+
@dichotomy_hash.values.map(&:error_estimate).max
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def confidence_interval_values(choice, level)
|
|
46
|
+
@dichotomy_hash[choice].confidence_interval_values(level)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def report
|
|
50
|
+
choice_lengths = @dichotomy_hash.keys.map(&:length)
|
|
51
|
+
choice_lengths << 6
|
|
52
|
+
max_choice_width = choice_lengths.max
|
|
53
|
+
sorted_choices = sort_choices_by_label_and_mpv
|
|
54
|
+
lines = sorted_choices.map do |choice|
|
|
55
|
+
create_report_line(choice, @dichotomy_hash[choice], max_choice_width)
|
|
56
|
+
end
|
|
57
|
+
"Most probable fractions and 95% confidence intervals:\n" +
|
|
58
|
+
'Choice'.ljust(max_choice_width) + ' MPF CI(95%)' +
|
|
59
|
+
(@threshold.nil? ? '' : ' P(≥' + (100 * @threshold).to_i.to_s +
|
|
60
|
+
'%)') +
|
|
61
|
+
"\n" + lines.join("\n")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def progress_report
|
|
65
|
+
size = @dichotomy_hash.values.first.values.size
|
|
66
|
+
"Number of data points: #{with_thousands_separator(size)}."
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def size
|
|
70
|
+
@dichotomy_hash.values.first.values.size
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def write_outputs(filename)
|
|
74
|
+
write_confidence_intervals(filename)
|
|
75
|
+
write_probabilities(filename)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def compare_choices_by_label_and_mpv(a, b)
|
|
81
|
+
if a == OTHER
|
|
82
|
+
1
|
|
83
|
+
elsif b == OTHER
|
|
84
|
+
-1
|
|
85
|
+
else
|
|
86
|
+
mpv_a = @dichotomy_hash[a].most_probable_value
|
|
87
|
+
mpv_b = @dichotomy_hash[b].most_probable_value
|
|
88
|
+
mpv_a == mpv_b ? a <=> b : mpv_b <=> mpv_a
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def sort_choices_by_label_and_mpv
|
|
93
|
+
@dichotomy_hash.keys.sort do |a, b|
|
|
94
|
+
compare_choices_by_label_and_mpv(a, b)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def create_report_line(choice, dichotomy, max_choice_width)
|
|
99
|
+
choice.ljust(max_choice_width) + ' ' + \
|
|
100
|
+
six_char_percentage(dichotomy.most_probable_fraction) + ' ' + \
|
|
101
|
+
six_char_percentage(dichotomy.confidence_interval.first) + '–' + \
|
|
102
|
+
six_char_percentage(dichotomy.confidence_interval.last) +
|
|
103
|
+
(@threshold.nil? ? '' : ' ' +
|
|
104
|
+
six_char_percentage(dichotomy.threshold_probability(@threshold)))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def write_confidence_intervals(filename)
|
|
108
|
+
ci_filename = filename.gsub('.poll', '-dichotomies-confidence-intervals.psv')
|
|
109
|
+
File.open(ci_filename, 'w') do |file|
|
|
110
|
+
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')
|
|
111
|
+
@dichotomy_hash.each_pair do | choice, dichotomy |
|
|
112
|
+
ci80 = dichotomy.confidence_interval(0.8)
|
|
113
|
+
ci90 = dichotomy.confidence_interval(0.9)
|
|
114
|
+
ci95 = dichotomy.confidence_interval(0.95)
|
|
115
|
+
ci99 = dichotomy.confidence_interval(0.99)
|
|
116
|
+
file.puts(choice + ' | ' + ci80.first.to_s + ' | ' + \
|
|
117
|
+
ci80.last.to_s + ' | ' + ci90.first.to_s + ' | ' + \
|
|
118
|
+
ci90.last.to_s + ' | ' + ci95.first.to_s + ' | ' + \
|
|
119
|
+
ci95.last.to_s + ' | ' + ci99.first.to_s + ' | ' + \
|
|
120
|
+
ci99.last.to_s)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def write_probabilities(filename)
|
|
126
|
+
ci_filename = filename.gsub('.poll', '-dichotomies-probabilities.psv')
|
|
127
|
+
File.open(ci_filename, 'w') do |file|
|
|
128
|
+
intervals = Range.new(0, 1999).map{ | i | [i.to_f / 2000, (i + 1).to_f / 2000]}
|
|
129
|
+
file.puts('Choice | ' + intervals.map{|a| "#{sprintf('%.4f', a.first)}–#{sprintf('%.4f', a.last)}"}.join(' | '))
|
|
130
|
+
@dichotomy_hash.each_pair do | choice, dichotomy |
|
|
131
|
+
unless choice == OTHER
|
|
132
|
+
file.puts(choice + ' | ' + dichotomy.interval_probabilities(intervals).join(' | '))
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|