Remove native integers mode in preparation for more advanced rounding options

This commit is contained in:
RunasSudo 2021-01-03 00:28:35 +11:00
parent 1b74e41695
commit 7b52f8f06d
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
7 changed files with 5 additions and 150 deletions

View File

@ -47,10 +47,7 @@ This dropdown allows you to select how numbers (vote totals, etc.) are represent
* Fixed: Numbers are represented as fixed-precision decimals, up to a certain number of decimal places (default: 5). * Fixed: Numbers are represented as fixed-precision decimals, up to a certain number of decimal places (default: 5).
* Rational: Numbers are represented exactly as fractions, resulting in the elimination of rounding error, but increasing computational complexity when the number of surplus transfers is very large. * Rational: Numbers are represented exactly as fractions, resulting in the elimination of rounding error, but increasing computational complexity when the number of surplus transfers is very large.
* Native float: Numbers are represented as floating-point numbers. This is fast, but not recommended as unexpectedly large rounding errors may be introduced in some circumstances. * Native: Numbers are represented as native integers or floating-point numbers. This is fast, but not recommended as unexpectedly large rounding errors may be introduced in some circumstances.
* Native int: Numbers are represented as integers. Fractions are discarded.
Note that, during some calculations, in order to reduce rounding errors, ballot weights and intermediate may be represented internally as fractions irrespective of this option.
## Surplus order (-s/--surplus-order) ## Surplus order (-s/--surplus-order)

View File

@ -82,8 +82,7 @@
<label> <label>
Numbers: Numbers:
<select id="selNumbers"> <select id="selNumbers">
<option value="native">Native float</option> <option value="native">Native</option>
<option value="int">Native integer</option>
<option value="rational">Rational</option> <option value="rational">Rational</option>
<option value="fixed" selected>Fixed</option> <option value="fixed" selected>Fixed</option>
</select> </select>

View File

@ -26,9 +26,6 @@ onmessage = function(evt) {
if (evt.data.data.numbers === 'native') { if (evt.data.data.numbers === 'native') {
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Native); py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Native);
} }
if (evt.data.data.numbers === 'int') {
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.NativeInt);
}
if (evt.data.data.numbers === 'rational') { if (evt.data.data.numbers === 'rational') {
py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Rational); py.pyRCV2.numbers.set_numclass(py.pyRCV2.numbers.Rational);
} }

View File

@ -32,8 +32,10 @@ def add_parser(subparsers):
parser.add_argument('--quota-criterion', '-c', choices=['geq', 'gt'], default='geq', help='quota criterion (default: geq)') parser.add_argument('--quota-criterion', '-c', choices=['geq', 'gt'], default='geq', help='quota criterion (default: geq)')
parser.add_argument('--prog-quota', action='store_true', help='progressively reducing quota') parser.add_argument('--prog-quota', action='store_true', help='progressively reducing quota')
parser.add_argument('--no-bulk-election', action='store_true', help='disable bulk election unless absolutely required') parser.add_argument('--no-bulk-election', action='store_true', help='disable bulk election unless absolutely required')
parser.add_argument('--numbers', '-n', choices=['fixed', 'rational', 'int', 'native'], default='fixed', help='numbers mode (default: fixed)') parser.add_argument('--numbers', '-n', choices=['fixed', 'rational', 'native'], default='fixed', help='numbers mode (default: fixed)')
parser.add_argument('--decimals', type=int, default=5, help='decimal places if --numbers fixed (default: 5)') parser.add_argument('--decimals', type=int, default=5, help='decimal places if --numbers fixed (default: 5)')
parser.add_argument('--round-votes', type=int, help='round votes to specified decimal places')
parser.add_argument('--round-weights', type=int, help='round ballot weights to specified decimal places')
parser.add_argument('--surplus-order', '-s', choices=['size', 'order'], default='size', help='whether to distribute surpluses by size or by order of election (default: size)') parser.add_argument('--surplus-order', '-s', choices=['size', 'order'], default='size', help='whether to distribute surpluses by size or by order of election (default: size)')
parser.add_argument('--method', '-m', choices=['wig', 'uig', 'eg', 'wright'], default='wig', help='method of surpluses and exclusions (default: wig - weighted inclusive Gregory)') parser.add_argument('--method', '-m', choices=['wig', 'uig', 'eg', 'wright'], default='wig', help='method of surpluses and exclusions (default: wig - weighted inclusive Gregory)')
parser.add_argument('--transferable-only', action='store_true', help='examine only transferable papers during surplus distributions') parser.add_argument('--transferable-only', action='store_true', help='examine only transferable papers during surplus distributions')
@ -69,8 +71,6 @@ def main(args):
# Set settings # Set settings
if args.numbers == 'native': if args.numbers == 'native':
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Native) pyRCV2.numbers.set_numclass(pyRCV2.numbers.Native)
elif args.numbers == 'int':
pyRCV2.numbers.set_numclass(pyRCV2.numbers.NativeInt)
elif args.numbers == 'rational': elif args.numbers == 'rational':
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Rational) pyRCV2.numbers.set_numclass(pyRCV2.numbers.Rational)
elif args.numbers == 'fixed': elif args.numbers == 'fixed':

View File

@ -23,13 +23,11 @@ __pragma__('noskip')
if is_py: if is_py:
__pragma__('skip') __pragma__('skip')
from pyRCV2.numbers.fixed_py import Fixed, set_dps from pyRCV2.numbers.fixed_py import Fixed, set_dps
from pyRCV2.numbers.int_py import NativeInt
from pyRCV2.numbers.native_py import Native from pyRCV2.numbers.native_py import Native
from pyRCV2.numbers.rational_py import Rational from pyRCV2.numbers.rational_py import Rational
__pragma__('noskip') __pragma__('noskip')
else: else:
from pyRCV2.numbers.fixed_js import Fixed, set_dps from pyRCV2.numbers.fixed_js import Fixed, set_dps
from pyRCV2.numbers.int_js import NativeInt
from pyRCV2.numbers.native_js import Native from pyRCV2.numbers.native_js import Native
from pyRCV2.numbers.rational_js import Rational from pyRCV2.numbers.rational_js import Rational

View File

@ -1,58 +0,0 @@
# pyRCV2: Preferential vote counting
# Copyright © 2020 Lee Yingtong Li (RunasSudo)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
class NativeInt:
"""
Wrapper for JS integers
"""
def __init__(self, val):
if isinstance(val, NativeInt):
self.impl = val.impl
else:
self.impl = Math.floor(parseFloat(val))
def pp(self, dp):
"""Pretty print to specified number of decimal places"""
return self.impl.toFixed(0)
def to_rational(self):
"""Convert to an instance of Rational"""
from pyRCV2.numbers import Rational
return Rational(self.impl)
def __add__(self, other):
return NativeInt(self.impl + other.impl)
def __sub__(self, other):
return NativeInt(self.impl - other.impl)
def __mul__(self, other):
return NativeInt(self.impl * other.impl)
def __div__(self, other):
return NativeInt(self.impl / other.impl)
def __eq__(self, other):
return self.impl == other.impl
def __gt__(self, other):
return self.impl > other.impl
def __ge__(self, other):
return self.impl >= other.impl
def __lt__(self, other):
return self.impl < other.impl
def __le__(self, other):
return self.impl <= other.impl
def __floor__(self):
return NativeInt(Math.floor(self.impl))

View File

@ -1,78 +0,0 @@
# pyRCV2: Preferential vote counting
# Copyright © 2020 Lee Yingtong Li (RunasSudo)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import math
class NativeInt:
"""
Wrapper for Python int
"""
def __init__(self, val):
if isinstance(val, NativeInt):
self.impl = val.impl
else:
self.impl = int(val)
def pp(self, dp):
"""Pretty print to specified number of decimal places"""
return str(self.impl)
def to_rational(self):
"""Convert to an instance of Rational"""
from pyRCV2.numbers import Rational
return Rational(self.impl)
def __add__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return NativeInt(self.impl + other.impl)
def __sub__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return NativeInt(self.impl - other.impl)
def __mul__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return NativeInt(self.impl * other.impl)
def __truediv__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return NativeInt(self.impl / other.impl)
def __eq__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return self.impl == other.impl
def __gt__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return self.impl > other.impl
def __ge__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return self.impl >= other.impl
def __lt__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return self.impl < other.impl
def __le__(self, other):
if not isinstance(other, NativeInt):
raise ValueError('Attempt to operate on incompatible types')
return self.impl <= other.impl
def __floor__(self):
return NativeInt(math.floor(self.impl))