diff --git a/apportionment/methods.py b/apportionment/methods.py index 9035680..c9ebaed 100644 --- a/apportionment/methods.py +++ b/apportionment/methods.py @@ -4,8 +4,8 @@ import math from fractions import Fraction -def method(method, votes, seats, parties=string.ascii_letters, - threshold=None, verbose=True): +def compute(method, votes, seats, parties=string.ascii_letters, + threshold=None, verbose=True): filtered_votes = apply_threshold(votes, threshold) if method == "quota": return quota(filtered_votes, seats, parties, verbose) diff --git a/apportionment/unittests.py b/apportionment/unittests.py index ba5452e..4784320 100644 --- a/apportionment/unittests.py +++ b/apportionment/unittests.py @@ -4,7 +4,7 @@ import unittest -import apportionment +import apportionment.methods as app METHODS = ["quota", "largest_remainder", "dhondt", "saintelague", @@ -24,8 +24,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [1] seats = 1 for method in ALLMETHODSSTRINGS: - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, [1], msg=method + " does not exist") @@ -35,8 +35,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [14, 28, 7, 35] seats = 12 for method in METHODS: - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, [2, 4, 1, 5], msg=method + " failed") @@ -46,8 +46,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [0, 14, 28, 0, 0] seats = 6 for method in METHODS: - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, [0, 2, 4, 0, 0], msg=method + " failed") @@ -57,8 +57,8 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [10, 9, 8, 8, 11, 12] seats = 3 for method in METHODS: - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, [1, 0, 0, 0, 1, 1], msg=method + " failed") @@ -66,14 +66,14 @@ class TestApprovalMultiwinner(unittest.TestCase): # Balinski, M. L., & Young, H. P. (1975). # The quota method of apportionment. # The American Mathematical Monthly, 82(7), 701-730. - def test_balinski_young_example(self): + def test_balinski_young_example1(self): self.longMessage = True RESULTS = {"quota": [52, 44, 2, 1, 1], "largest_remainder": [51, 44, 2, 2, 1], "dhondt": [52, 45, 1, 1, 1], "saintelague": [51, 43, 2, 2, 2], - "modified_saintelague": [51, 43, 2, 2, 2], + "modified_saintelague": [51, 43, 2, 2, 2], "huntington": [51, 43, 2, 2, 2], "adams": [51, 43, 2, 2, 2], "dean": [51, 43, 2, 2, 2] @@ -82,8 +82,29 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [5117, 4400, 162, 161, 160] seats = 100 for method in RESULTS.keys(): - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) + self.assertEqual(result, RESULTS[method], + msg=method + " failed") + + def test_balinski_young_example2(self): + self.longMessage = True + + RESULTS = {"quota": [10, 7, 5, 3, 1], + "largest_remainder": [9, 7, 5, 4, 1], + "dhondt": [10, 7, 5, 3, 1], + "saintelague": [9, 8, 5, 3, 1], + "modified_saintelague": [9, 8, 5, 3, 1], + "huntington": [9, 7, 6, 3, 1], + "adams": [9, 7, 5, 3, 2], + "dean": [9, 7, 5, 4, 1] + } + + votes = [9061, 7179, 5259, 3319, 1182] + seats = 26 + for method in RESULTS.keys(): + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, RESULTS[method], msg=method + " failed") @@ -93,54 +114,54 @@ class TestApprovalMultiwinner(unittest.TestCase): votes = [2, 1, 1, 2, 2] seats = 2 for method in METHODS: - result = apportionment.method(method, votes, - seats, verbose=False) + result = app.compute(method, votes, + seats, verbose=False) self.assertEqual(result, [1, 0, 0, 1, 0], msg=method + " failed") def test_within_quota(self): votes = [5117, 4400, 162, 161, 160] representatives = [51, 44, 2, 2, 1] - self.assertTrue(apportionment.within_quota(votes, representatives, - verbose=False)) + self.assertTrue(app.within_quota(votes, representatives, + verbose=False)) representatives = [52, 45, 1, 1, 1] - self.assertFalse(apportionment.within_quota(votes, representatives, - verbose=False)) + self.assertFalse(app.within_quota(votes, representatives, + verbose=False)) representatives = [52, 43, 2, 1, 2] - self.assertFalse(apportionment.within_quota(votes, representatives, - verbose=False)) + self.assertFalse(app.within_quota(votes, representatives, + verbose=False)) def test_threshold(self): votes = [41, 56, 3] seats = 60 threshold = 0.03 - filtered_votes = apportionment.apply_threshold(votes, threshold) + filtered_votes = app.apply_threshold(votes, threshold) self.assertEqual(filtered_votes, [41, 56, 3], "Threshold cut too much.") threshold = 0.031 - filtered_votes = apportionment.apply_threshold(votes, threshold) + filtered_votes = app.apply_threshold(votes, threshold) self.assertEqual(filtered_votes, [41, 56, 0], "Threshold was not applied correctly.") method = "dhondt" threshold = 0 - unfiltered_result = apportionment.method(method, votes, seats, - threshold=threshold, - verbose=False) + unfiltered_result = app.compute(method, votes, seats, + threshold=threshold, + verbose=False) threshold = 0.04 - filtered_result = apportionment.method(method, votes, seats, - threshold=threshold, - verbose=False) + filtered_result = app.compute(method, votes, seats, + threshold=threshold, + verbose=False) self.assertNotEqual(unfiltered_result, filtered_result, "Result did not change despite threshold") def test_saintelague_difference(self): votes = [6, 1] seats = 4 - r1 = apportionment.method("saintelague", votes, - seats, verbose=False) # [3, 1] - r2 = apportionment.method("modified_saintelague", votes, - seats, verbose=False) # [4, 0] + r1 = app.compute("saintelague", votes, + seats, verbose=False) # [3, 1] + r2 = app.compute("modified_saintelague", votes, + seats, verbose=False) # [4, 0] self.assertNotEqual(r1, r2, "Saintelague and its modified variant" + "should produce differents results.")