I am trying to create an Euclidean algorithm (to solve Bezout's Relation) for 2 polynomials in the GF(2^8).
I currently have this code for my different operations
class ReedSolomon:
gfSize = 256
genPoly = 285
log = [0]*gfSize
antilog = [0]*gfSize
def _genLogAntilogArrays(self):
self.antilog[0] = 1
self.log[0] = 0
self.antilog[255] = 1
for i in range(1,255):
self.antilog[i] = self.antilog[i-1] << 1
if self.antilog[i] >= self.gfSize:
self.antilog[i] = self.antilog[i] ^ self.genPoly
self.log[self.antilog[i]] = i
def __init__(self):
self._genLogAntilogArrays()
def _galPolynomialDivision(self,dividend, divisor):
result = dividend.copy()
for i in range(len(dividend) - (len(divisor)-1)):
coef = result[i]
if coef != 0:
for j in range(1, len(divisor)):
if divisor[j] != 0:
result[i + j] ^= self._galMult(divisor[j], coef) # équivalent result[i + j] += -divisor[j] * coef car dans un champ GF(2) addition <=> substraction <=> XOR
remainderIndex = -(len(divisor)-1)
return result[:remainderIndex], result[remainderIndex:]
def _galMultiplicationPolynomiale(self, x,y):
result = [0]*(len(x)+len(y)-1)
for i in range(len(x)):
for j in range(len(y)):
result[i+j] ^= self._galMult(x[i],y[j])
return result
def _galMult(self,x,y):
if ((x == 0) or (y == 0)):
val = 0
else:
val = self.antilog[(self.log[x] + self.log[y])%255]
return val
def _galPolynomialAddition(self, a, b):
polSum = [0] * max(len(a), len(b))
for index in range(0, len(a)):
polSum[index + len(polSum) - len(a)] = a[index]
for index in range(0, len(b)):
polSum[index + len(polSum) - len(b)] ^= b[index]
return (polSum)
And here is my euclidean algorithm :
def _galEuclideanAlgorithm(self,a,b):
r0 = a.copy()
r1 = b.copy()
u0 = [1]
u1 = [0]
v0 = [0]
v1 = [1]
while max(r1) != 0:
print(r1)
q,r = self._galPolynomialDivision(r0,r1)
r0 = self._galPolynomialAddition(self._galMultiplicationPolynomiale(q,r1),r)
r1,r0 = self._galPolynomialAddition(r0,self._galMultiplicationPolynomiale(q,r1)),r1.copy()
u1,u0 = self._galPolynomialAddition(u0,self._galMultiplicationPolynomiale(q,u1)),u1.copy()
v1,v0 = self._galPolynomialAddition(v0,self._galMultiplicationPolynomiale(q,v1)),v1.copy()
return r1,u1,v1
I don't understand my issue where my algorithm is looping, here is my remainder output with my tests:
rs = ReedSolomon()
a = [1,15,7,8,0,11]
b = [1,0,0,0,0,0,0]
print(rs._galEuclideanAlgorithm(b,a))
#Console output
'''
[1, 15, 7, 8, 0, 11]
[0, 0, 82, 37, 120, 11, 105]
[1, 15, 7, 8, 0, 11]
[0, 0, 82, 37, 120, 11, 105]
[1, 15, 7, 8, 0, 11]
[0, 0, 82, 37, 120, 11, 105]
[1, 15, 7, 8, 0, 11]
'''
I know it might seem like I'm throwing some code just expecting an answer, but I'm genuinely searching for the error.
Thanks in advance !
I created a Python package called galois that does this. galois extends NumPy arrays to operate over Galois fields. The code is written in Python but JIT compiled with Numba for speed. In addition to array arithmetic, it also supports polynomials over Galois fields. ...And Reed-Solomon codes are implemented too :)
The Extended Euclidean Algorithm to solve the Bezout identity for two polynomials in GF(2^8) would be solved this way. Below is an abbreviated chunk of source code. You can see my full source code here.
def poly_egcd(a, b):
field = a.field
zero = Poly.Zero(field)
one = Poly.One(field)
r2, r1 = a, b
s2, s1 = one, zero
t2, t1 = zero, one
while r1 != zero:
q = r2 / r1
r2, r1 = r1, r2 - q*r1
s2, s1 = s1, s2 - q*s1
t2, t1 = t1, t2 - q*t1
# Make the GCD polynomial monic
c = r2.coeffs[0] # The leading coefficient
if c > 1:
r2 /= c
s2 /= c
t2 /= c
return r2, s2, t2
And here is a complete example using the galois library and the polynomials from your example. (I'm assuming the highest-degree coefficient is first?)
In [1]: import galois
In [2]: GF = galois.GF(2**8)
In [3]: print(GF.properties)
GF(2^8):
characteristic: 2
degree: 8
order: 256
irreducible_poly: x^8 + x^4 + x^3 + x^2 + 1
is_primitive_poly: True
primitive_element: x
In [4]: a = galois.Poly([1,15,7,8,0,11], field=GF); a
Out[4]: Poly(x^5 + 15x^4 + 7x^3 + 8x^2 + 11, GF(2^8))
In [5]: b = galois.Poly([1,0,0,0,0,0,0], field=GF); b
Out[5]: Poly(x^6, GF(2^8))
In [6]: d, s, t = galois.poly_egcd(a, b); d, s, t
Out[6]:
(Poly(1, GF(2^8)),
Poly(78x^5 + 7x^4 + 247x^3 + 74x^2 + 152, GF(2^8)),
Poly(78x^4 + 186x^3 + 45x^2 + x + 70, GF(2^8)))
In [7]: a*s + b*t == d
Out[7]: True
I'm working with single variable polynomials with coefficients +1/-1 (and zero). These can be very long and the range of powers can be quite big. It would be convenient for me to view the powers as a vector - is there any way of doing this quickly? I had hoped there would be a command already in Pari to do this, but I can't seem to see one?
Just an example to confirm what I'm trying to do...
Input:x^10 - x^8 + x^5 - x^2 + x + 1
Desired output: [10, 8, 5, 2, 1, 0]
You can use Vecrev to get the polynomial coefficients. After that just enumerate them to select the zero-based positions of non-zeros. You want the following one-liner:
nonzeros(xs) = Vecrev([x[2]-1 | x <- select(x -> x[1] != 0, vector(#xs, i, [xs[i], i]))])
Now you can easily get the list of polynomial powers:
p = x^10 - x^8 + x^5 - x^2 + x + 1
nonzeros(Vecrev(p))
>> [10, 8, 5, 2, 1, 0]
I use parse_expr("-5 + 2*x + 3 - 7*x + 5 - 3*x", evaluate=False).
According to documentation for evaluate=False, I expected to keep the order of the expression:
"When False, the order of the arguments will remain as they were in the string ..."
But the result is sorted:
-7*x - 3*x + 2*x - 5 + 3 + 5
sympy=1.4
It is as advertised:
>>> u = parse_expr("-5 + 2*x + 3 - 7*x + 5 - 3*x", evaluate=False); u.args
(-5, 2*x, 3, -7*x, 5, -3*x)
The printer, however, prints them in sorted order. It seems like there should be an easier way to do the following, but it works:
>>> s=StrPrinter(dict(order='none'))
>>> s._print_Add(u)
-5 + 2*x + 3 - 7*x + 5 - 3*x
I have the following code to find the only integer in a list which appears only once while all other appear 3 times. The code works fine for positive integers, but have problem with negative integers.
Can anyone help me fix it? Thanks.
class Solution:
# #param A, a list of integer
# #return an integer
def singleNumber(self, A):
if(A==None):
return None
else:
s=[0]*32
ans=0
for i in range(len(s)):
for j in A[:]:
if (j>>i)&1:
s[i] +=1
s[i]=s[i]%3
ans |= (s[i]<<i)
return ans
collections.Counter is useful for this kind of thing and won't choke on negative numbers.
>>> import collections
>>> l = [1, 1, 1, 2, 3, 3, 3, 4, 4, 4]
>>> c = collections.Counter(l).items()
>>> [k for k, v in c if v == 1][0]
2
>>> l = [-i for i in l]
>>> c = collections.Counter(l).items()
>>> [k for k, v in c if v == 1][0]
-2
def getSingle( arr, n):
ones = 0
twos = 0
for i in range(0,n):
twos = twos | (ones & arr[i]);
ones = ones ^ arr[i];
common_bit_mask = ~(ones & twos);
ones = ones & common_bit_mask;
twos = twos & common_bit_mask;
return ones;
Works for negative numbers too.
https://ideone.com/365Iie
My understanding is that (one use of) numpy's vectorize allows me to send an array to a function that normally only takes scalars, instead of using the built in map function (in combination with a lambda function or the like). However, under the following scenario I am getting different results when I use map vs numpy.vectorize and I can't seem to figure out why.
import numpy as np
def basis2(dim, k, x):
y = np.array([-0.2, -0.13, -0.06, 0, 0.02, 0.06, 0.15, 0.3, 0.8,
1.6, 3.1, 6.1, 10.1, 15.1, 23.1, 30.1, 35.0, 40.0, 45.0, 50.0, 55.0])
if x < y[k] or x > y[k + dim + 1]:
return 0
elif dim != 0:
ret = ((x - y[k]) / (y[k + dim] - y[k])) * basis2(dim - 1, k, x) + (
(y[k + dim + 1] - x) / (y[k + dim + 1] - y[k + 1])) * basis2(dim - 1, k + 1, x)
return ret
else:
return 1.0
w = np.array([20.0, 23.1, 30.0])
func = lambda x: basis2(3, 14, x)
vec = map(func, w)
func2 = np.vectorize(basis2)
vec2 = func2(3, 14, w)
print vec # = [0, 0.0, 0.23335417007039491]
print vec2 # = [0 0 0]
As the docstring says:
The data type of the output of vectorized is determined by calling
the function with the first element of the input. This can be avoided
by specifying the otypes argument.
you need to add a otypes argument:
func2 = np.vectorize(basis2, otypes="d")
or change return 0 to return 0.0 in basis2().