Updated for Python3
This commit is contained in:
parent
54cbe3c594
commit
0d92601702
70
galois.py
70
galois.py
@ -23,13 +23,19 @@ class GaloisNumber:
|
|||||||
The class supports "normal" syntax for the addition, subtraction, multiplication,
|
The class supports "normal" syntax for the addition, subtraction, multiplication,
|
||||||
division, additive inverse (-), and multiplicative inverse (~) operations.
|
division, additive inverse (-), and multiplicative inverse (~) operations.
|
||||||
'''
|
'''
|
||||||
def __init__ (self, x, value=0):
|
def __init__ (self, x, field=None):
|
||||||
if isinstance(x, GaloisNumber):
|
if isinstance(x, GaloisNumber):
|
||||||
self.field = x.field
|
self.field = x.field
|
||||||
self.value = x.value
|
self.value = x.value
|
||||||
|
elif type(field) not in (GaloisFieldLog, GaloisFieldDirect):
|
||||||
|
raise ValueError ("Must specify field")
|
||||||
else:
|
else:
|
||||||
self.field = x
|
self.field = field
|
||||||
self.assign (value)
|
if type(x) == bytes:
|
||||||
|
x = int.from_bytes (x, 'big')
|
||||||
|
elif type(x) != int:
|
||||||
|
raise ValueError ("Must be an integer or bytes")
|
||||||
|
self.assign (x)
|
||||||
|
|
||||||
def assign (self, v):
|
def assign (self, v):
|
||||||
'''
|
'''
|
||||||
@ -37,13 +43,13 @@ class GaloisNumber:
|
|||||||
the field with which the GaloisNumber instance was defined.
|
the field with which the GaloisNumber instance was defined.
|
||||||
'''
|
'''
|
||||||
if v > self.field.size:
|
if v > self.field.size:
|
||||||
raise GaloisException ("Value {0} is outside field".format (v))
|
raise ValueError ("Value {0} is outside field".format (v))
|
||||||
self.value = v
|
self.value = v
|
||||||
|
|
||||||
def __add__ (self, other):
|
def __add__ (self, other):
|
||||||
if self.field != other.field:
|
if self.field != other.field:
|
||||||
raise GaloisException ("Field elements from different fields")
|
raise GaloisException ("Field elements from different fields")
|
||||||
return GaloisNumber (self.field, self.value ^ other.value)
|
return GaloisNumber (self.value ^ other.value, self.field)
|
||||||
|
|
||||||
def __iadd__ (self, other):
|
def __iadd__ (self, other):
|
||||||
if self.field != other.field:
|
if self.field != other.field:
|
||||||
@ -72,11 +78,14 @@ class GaloisNumber:
|
|||||||
raise GaloisException ("Field elements from different fields")
|
raise GaloisException ("Field elements from different fields")
|
||||||
self.value = self.field.direct_multiply (self.value, other.value)
|
self.value = self.field.direct_multiply (self.value, other.value)
|
||||||
|
|
||||||
def __div__ (self, other):
|
def __floordiv__ (self, other):
|
||||||
if self.field != other.field:
|
if self.field != other.field:
|
||||||
raise GaloisException ("Field elements from different fields")
|
raise GaloisException ("Field elements from different fields")
|
||||||
return self.field.divide (self, other)
|
return self.field.divide (self, other)
|
||||||
|
|
||||||
|
def __truediv__ (self, other):
|
||||||
|
return self // other
|
||||||
|
|
||||||
def __eq__ (self, other):
|
def __eq__ (self, other):
|
||||||
if self.field != other.field:
|
if self.field != other.field:
|
||||||
raise GaloisException ("Field elements from different fields")
|
raise GaloisException ("Field elements from different fields")
|
||||||
@ -128,33 +137,32 @@ class GaloisFieldLog:
|
|||||||
a = v1.value
|
a = v1.value
|
||||||
b = v2.value
|
b = v2.value
|
||||||
if a == 0 or b == 0:
|
if a == 0 or b == 0:
|
||||||
return GaloisNumber (self, 0)
|
return GaloisNumber (0, self)
|
||||||
return GaloisNumber (self, self.antilog_tbl[(self.log_tbl[a] + self.log_tbl[b]) %
|
return GaloisNumber (self.antilog_tbl[(self.log_tbl[a] + self.log_tbl[b]) % (self.size - 1)], self)
|
||||||
(self.size - 1)])
|
|
||||||
|
|
||||||
def invert (self, v):
|
def invert (self, v):
|
||||||
if v.value == 0:
|
if v.value == 0:
|
||||||
return GaloisNumber(self, 0)
|
return GaloisNumber(0, self)
|
||||||
elif v.value == 1:
|
elif v.value == 1:
|
||||||
return GaloisNumber (self, 1)
|
return GaloisNumber (1, self)
|
||||||
else:
|
else:
|
||||||
return GaloisNumber (self, self.antilog_tbl[self.size - 1 - self.log_tbl[v.value]])
|
return GaloisNumber (self.antilog_tbl[self.size - 1 - self.log_tbl[v.value]], self)
|
||||||
|
|
||||||
def divide (self, v1, v2):
|
def divide (self, v1, v2):
|
||||||
return self.multiply (v1, self.invert(v2))
|
return self.multiply (v1, self.invert(v2))
|
||||||
|
|
||||||
def self_test (self):
|
def self_test (self):
|
||||||
mul_identity = GaloisNumber (self, 1)
|
mul_identity = GaloisNumber (1, self)
|
||||||
v = GaloisNumber (self)
|
v = GaloisNumber (0, self)
|
||||||
g_0 = GaloisNumber (self, 0)
|
g_0 = GaloisNumber (0, self)
|
||||||
g_1 = GaloisNumber (self, 1)
|
g_1 = GaloisNumber (1, self)
|
||||||
for i in range (self.size):
|
for i in range (self.size):
|
||||||
v.assign (i)
|
v.assign (i)
|
||||||
if i == 0: continue
|
if i == 0: continue
|
||||||
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
|
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
|
||||||
assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
|
assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
|
||||||
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
|
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
|
||||||
vb = GaloisNumber (self)
|
vb = GaloisNumber (0, self)
|
||||||
for a in range (1, self.multiply_test_size):
|
for a in range (1, self.multiply_test_size):
|
||||||
v.assign (random.randint (1, self.size - 1))
|
v.assign (random.randint (1, self.size - 1))
|
||||||
vb.assign (random.randint (1, self.size - 1))
|
vb.assign (random.randint (1, self.size - 1))
|
||||||
@ -184,7 +192,7 @@ class GaloisFieldDirect:
|
|||||||
self.bits = bits
|
self.bits = bits
|
||||||
self.size = (1 << bits)
|
self.size = (1 << bits)
|
||||||
self.prim = self.poly_defaults[bits] if not primitive_polynomial else primitive_polynomial
|
self.prim = self.poly_defaults[bits] if not primitive_polynomial else primitive_polynomial
|
||||||
self.value_format = repr_prefix + '{:0>' + str(bits / 4) + 'x}'
|
self.value_format = repr_prefix + '{:0>' + str(bits // 4) + 'x}'
|
||||||
self.alpha = alpha
|
self.alpha = alpha
|
||||||
|
|
||||||
def __eq__ (self, other):
|
def __eq__ (self, other):
|
||||||
@ -194,7 +202,7 @@ class GaloisFieldDirect:
|
|||||||
return self.value_format.format (v)
|
return self.value_format.format (v)
|
||||||
|
|
||||||
def multiply (self, v1, v2):
|
def multiply (self, v1, v2):
|
||||||
return GaloisNumber (self, self.direct_multiply (v1.value, v2.value))
|
return GaloisNumber (self.direct_multiply (v1.value, v2.value), self)
|
||||||
|
|
||||||
def direct_multiply (self, a, b):
|
def direct_multiply (self, a, b):
|
||||||
# Multiplication is commutative, and it's faster if we use the smaller value as the
|
# Multiplication is commutative, and it's faster if we use the smaller value as the
|
||||||
@ -223,24 +231,24 @@ class GaloisFieldDirect:
|
|||||||
to field width in bits.
|
to field width in bits.
|
||||||
'''
|
'''
|
||||||
if v.value == 0:
|
if v.value == 0:
|
||||||
return GaloisNumber(self, 0)
|
return GaloisNumber(0, self)
|
||||||
elif v.value == 1:
|
elif v.value == 1:
|
||||||
return GaloisNumber (self, 1)
|
return GaloisNumber (1, self)
|
||||||
inv = 1
|
inv = 1
|
||||||
sq = v.value
|
sq = v.value
|
||||||
for i in range (1, self.bits):
|
for i in range (1, self.bits):
|
||||||
sq = self.direct_multiply (sq, sq)
|
sq = self.direct_multiply (sq, sq)
|
||||||
inv = self.direct_multiply (inv, sq)
|
inv = self.direct_multiply (inv, sq)
|
||||||
return GaloisNumber (self, inv)
|
return GaloisNumber (inv, self)
|
||||||
|
|
||||||
def divide (self, v1, v2):
|
def divide (self, v1, v2):
|
||||||
return self.multiply (v1, self.invert(v2))
|
return self.multiply (v1, self.invert(v2))
|
||||||
|
|
||||||
def self_test (self):
|
def self_test (self):
|
||||||
mul_identity = GaloisNumber (self, 1)
|
mul_identity = GaloisNumber (1, self)
|
||||||
v = GaloisNumber (self)
|
v = GaloisNumber (0, self)
|
||||||
g_0 = GaloisNumber (self, 0)
|
g_0 = GaloisNumber (0, self)
|
||||||
g_1 = GaloisNumber (self, 1)
|
g_1 = GaloisNumber (1, self)
|
||||||
small_field = self.size < self.max_test_size
|
small_field = self.size < self.max_test_size
|
||||||
n_tests = (self.size - 1) if small_field else self.max_test_size
|
n_tests = (self.size - 1) if small_field else self.max_test_size
|
||||||
for i in range (0, n_tests):
|
for i in range (0, n_tests):
|
||||||
@ -248,7 +256,7 @@ class GaloisFieldDirect:
|
|||||||
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
|
assert v * ~v == mul_identity, "Multiplicative inverse failed at {}".format (i)
|
||||||
assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
|
assert g_0 - v == -v, "Additive inverse failed at {}".format (i)
|
||||||
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
|
assert v * g_1 == v, "Multiplicative identity failed at {}".format (i)
|
||||||
vb = GaloisNumber (self)
|
vb = GaloisNumber (0, self)
|
||||||
for a in range (1, self.max_test_size):
|
for a in range (1, self.max_test_size):
|
||||||
v.assign (random.randint (1, self.size - 1))
|
v.assign (random.randint (1, self.size - 1))
|
||||||
vb.assign (random.randint (1, self.size - 1))
|
vb.assign (random.randint (1, self.size - 1))
|
||||||
@ -261,16 +269,16 @@ if __name__ == '__main__':
|
|||||||
print ('\nTesting direct fields...........')
|
print ('\nTesting direct fields...........')
|
||||||
for width in GaloisFieldDirect.field_widths:
|
for width in GaloisFieldDirect.field_widths:
|
||||||
field = GaloisFieldDirect (width)
|
field = GaloisFieldDirect (width)
|
||||||
g0 = GaloisNumber (field, 2)
|
g0 = GaloisNumber (2, field)
|
||||||
g1 = GaloisNumber (field, 7)
|
g1 = GaloisNumber (7, field)
|
||||||
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
|
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
|
||||||
if field.self_test ():
|
if field.self_test ():
|
||||||
print ("{0} bit field (direct) passed!".format (width))
|
print ("{0} bit field (direct) passed!".format (width))
|
||||||
print ('\nTesting log fields...........')
|
print ('\nTesting log fields...........')
|
||||||
for width in GaloisFieldLog.field_widths:
|
for width in GaloisFieldLog.field_widths:
|
||||||
field = GaloisFieldLog (width)
|
field = GaloisFieldLog (width)
|
||||||
g0 = GaloisNumber (field, 2)
|
g0 = GaloisNumber (2, field)
|
||||||
g1 = GaloisNumber (field, 7)
|
g1 = GaloisNumber (7, field)
|
||||||
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
|
print ('{0} + {1} = {2}'.format (g0, g1, g0 + g1))
|
||||||
if field.self_test ():
|
if field.self_test ():
|
||||||
print ("{0} bit field (log) passed!".format (width))
|
print ("{0} bit field (log) passed!".format (width))
|
||||||
|
Loading…
Reference in New Issue
Block a user