From 891f82e1484ccc2512850ca2773a8f9f97dead52 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sun, 3 Jan 2021 02:05:49 +1100 Subject: [PATCH] Fix bug in JS implementation of exclusive Gregory Remove dependency on Transcrypt's itertools.groupby as this does not appear to work --- pyRCV2/method/base_stv.py | 30 ++++++++++++++++++++++++++++-- pyRCV2/numbers/fixed_js.py | 2 ++ pyRCV2/numbers/fixed_py.py | 3 +++ pyRCV2/numbers/native_js.py | 2 ++ pyRCV2/numbers/native_py.py | 3 +++ pyRCV2/numbers/rational_js.py | 2 ++ pyRCV2/numbers/rational_py.py | 3 +++ 7 files changed, 43 insertions(+), 2 deletions(-) diff --git a/pyRCV2/method/base_stv.py b/pyRCV2/method/base_stv.py index 5c15cbe..f6751a2 100644 --- a/pyRCV2/method/base_stv.py +++ b/pyRCV2/method/base_stv.py @@ -15,12 +15,38 @@ # along with this program. If not, see . __pragma__ = lambda x: None +is_py = False +__pragma__('skip') +is_py = True +__pragma__('noskip') from pyRCV2.model import CandidateState, CountCard, CountCompleted, CountStepResult from pyRCV2.numbers import Num from pyRCV2.safedict import SafeDict -import itertools +# Stubs for JS +def groupby(iterable, keyfunc): + if is_py: + __pragma__('skip') + import itertools + return [list(g) for k, g in itertools.groupby(iterable, keyfunc)] + __pragma__('noskip') + else: + groups = [] + group = [] + last_result = None + for i in iterable: + this_result = keyfunc(i) + __pragma__('opov') + if last_result is not None and this_result != last_result: + __pragma__('noopov') + groups.append(group) + group = [] + last_result = this_result + group.append(i) + if group: + groups.append(group) + return groups class STVException(Exception): pass @@ -569,7 +595,7 @@ class WIGSTVCounter(BaseSTVCounter): ballots.sort(key=lambda x: x[1] / x[0].value, reverse=True) # Round to 8 decimal places to consider equality # FIXME: Work out a better way of doing this - count_card.parcels = [list(g) for k, g in itertools.groupby(ballots, lambda x: (x[1] / x[0].value).round(8, x[1].ROUND_DOWN))] + count_card.parcels = groupby(ballots, lambda x: (x[1] / x[0].value).round(8, x[1].ROUND_DOWN)) __pragma__('noopov') if len(count_card.parcels) > 0: diff --git a/pyRCV2/numbers/fixed_js.py b/pyRCV2/numbers/fixed_js.py index 7347bfb..4384af4 100644 --- a/pyRCV2/numbers/fixed_js.py +++ b/pyRCV2/numbers/fixed_js.py @@ -55,6 +55,8 @@ class Fixed: def __eq__(self, other): return self.impl.eq(other.impl) + def __ne__(self, other): + return not self.impl.eq(other.impl) def __gt__(self, other): return self.impl.gt(other.impl) def __ge__(self, other): diff --git a/pyRCV2/numbers/fixed_py.py b/pyRCV2/numbers/fixed_py.py index d455d8b..68fea8e 100644 --- a/pyRCV2/numbers/fixed_py.py +++ b/pyRCV2/numbers/fixed_py.py @@ -76,6 +76,9 @@ class Fixed: def __eq__(self, other): return self.impl == other.impl @compatible_types + def __ne__(self, other): + return self.impl != other.impl + @compatible_types def __gt__(self, other): return self.impl > other.impl @compatible_types diff --git a/pyRCV2/numbers/native_js.py b/pyRCV2/numbers/native_js.py index a36e9eb..341c7bd 100644 --- a/pyRCV2/numbers/native_js.py +++ b/pyRCV2/numbers/native_js.py @@ -50,6 +50,8 @@ class Native: def __eq__(self, other): return self.impl == other.impl + def __ne__(self, other): + return self.impl != other.impl def __gt__(self, other): return self.impl > other.impl def __ge__(self, other): diff --git a/pyRCV2/numbers/native_py.py b/pyRCV2/numbers/native_py.py index e2a1933..778e9d0 100644 --- a/pyRCV2/numbers/native_py.py +++ b/pyRCV2/numbers/native_py.py @@ -69,6 +69,9 @@ class Native: def __eq__(self, other): return self.impl == other.impl @compatible_types + def __ne__(self, other): + return self.impl != other.impl + @compatible_types def __gt__(self, other): return self.impl > other.impl @compatible_types diff --git a/pyRCV2/numbers/rational_js.py b/pyRCV2/numbers/rational_js.py index ef2e510..b935510 100644 --- a/pyRCV2/numbers/rational_js.py +++ b/pyRCV2/numbers/rational_js.py @@ -60,6 +60,8 @@ class Rational: def __eq__(self, other): return self.impl.equals(other.impl) + def __ne__(self, other): + return not self.impl.equals(other.impl) def __gt__(self, other): return self.impl.greater(other.impl) def __ge__(self, other): diff --git a/pyRCV2/numbers/rational_py.py b/pyRCV2/numbers/rational_py.py index d3c1d3b..2155250 100644 --- a/pyRCV2/numbers/rational_py.py +++ b/pyRCV2/numbers/rational_py.py @@ -78,6 +78,9 @@ class Rational: def __eq__(self, other): return self.impl == other.impl @compatible_types + def __ne__(self, other): + return self.impl != other.impl + @compatible_types def __gt__(self, other): return self.impl > other.impl @compatible_types