Tuesday, 13 August 2013

Python -- polynomials in finite fields. Why does only __add__() work with super() in this case?

Python -- polynomials in finite fields. Why does only __add__() work with
super() in this case?

I'm trying to use the parent class's __div__() in order to maintain the
same type so that many operations can be called at once as in the last
example mix1 = bf2/bf4*bf1%bf5 in main() below where multiple arithmetic
operations are strung together. For some reason, I can use super() in
__add__() but not in __div__(). The error is "IndexError: list index out
of range" and I've been going over and over this without any progress.
Note that this is all related to polynomial arithmetic within a finite
field.
I'm including the parsePolyVariable() and it's dependents (sorry if it
looks like there's a bit of code but I assure you it's all for a good
cause and builds character), since that's where the list error seems to be
stemming from but I can't for the life of me figure out where everything
is going very wrong. I'm teaching myself Python, so I'm sure there are
some other beginners out there who will see where I'm missing the obvious.
I've been looking over these but they don't seem to be related to this
situation:
http://docs.python.org/2/library/functions.html#super
Python super(Class, self).method vs super(Parent, self).method
How can I use Python's super() to update a parent value?
import re
class GF2Polynomial(object): #classes should generally inherit from object
def __init__(self, string):
'''__init__ is a standard special method used to initialize objects.
Here __init__ will initialize a gf2infix object based on a string.'''
self.string = string #basically the initial string (polynomial)
#if self.parsePolyVariable(string) == "0": self.key,self.lst =
"0",[0]
#else:
self.key,self.lst = self.parsePolyVariable(string) # key
determines polynomial compatibility
self.bin = self.prepBinary(string) #main value used in operations
def id(self,lst):
"""returns modulus 2 (1,0,0,1,1,....) for input lists"""
return [int(lst[i])%2 for i in range(len(lst))]
def listToInt(self,lst):
"""converts list to integer for later use"""
result = self.id(lst)
return int(''.join(map(str,result)))
def parsePolyToListInput(self,poly):
"""
replaced by parsePolyVariable. still functional but not needed.
performs regex on raw string and converts to list
"""
c = [int(i.group(0)) for i in re.finditer(r'\d+', poly)]
return [1 if x in c else 0 for x in xrange(max(c), -1, -1)]
def parsePolyVariable(self,poly):
"""
performs regex on raw string, converts to list.
also determines key (main variable used) in each polynomial on intake
"""
c = [int(m.group(0)) for m in re.finditer(r'\d+', poly)]
#re.finditer returns an iterator
if sum(c) == 0: return "0",[0]
letter = [str(m.group(0)) for m in re.finditer(r'[a-z]', poly)]
degree = max(c); varmatch = True; key = letter[0]
for i in range(len(letter)):
if letter[i] != key: varmatch = False
else: varmatch = True
if varmatch == False: return "error: not all variables in %s are
the same"%a
lst = [1 if x in c else (1 if x==0 else (1 if x=='x' else 0)) for
x in xrange(degree, -1, -1)]
return key,lst
def polyVariableCheck(self,other):
return self.key == other.key
def prepBinary(self,poly):
"""converts to base 2; bina,binb are binary values like
110100101100....."""
x = self.lst; a = self.listToInt(x)
return int(str(a),2)
def __add__(self,other):
"""
__add__ is another special method, and is used to override the +
operator. This will only
work for instances of gf2pim and its subclasses.
self,other are gf2infix instances; returns GF(2) polynomial in
string format
"""
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
return GF2Polynomial(self.outFormat(self.bin^other.bin))
def __sub__(self,other):
"""
__sub__ is the special method for overriding the - operator
same as addition in GF(2)
"""
return self.__add__(other)
def __mul__(self,other):
"""
__mul__ is the special method for overriding the * operator
returns product of 2 polynomials in gf2; self,other are values
10110011...
"""
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
bitsa = reversed("{0:b}".format(self.bin))
g = [(other.bin<<i)*int(bit) for i,bit in enumerate(bitsa)]
return GF2Polynomial(self.outFormat(reduce(lambda x,y: x^y,g)))
def __div__(self,other):
"""
__div__ is the special method for overriding the / operator
returns quotient formatted as polynomial
"""
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
if self.bin == other.bin: return 1
return GF2Polynomial(self.outFormat(self.bin/other.bin))
def __mod__(self,other):
"""
__mod__ is the special method for overriding the % operator
returns remainder formatted as polynomial
"""
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
if self.bin == other.bin: return 0
return GF2Polynomial(self.outFormat(self.bin%other.bin))
def __str__(self):
return self.string
def outFormat(self,raw):
"""process resulting values into polynomial format"""
raw = "{0:b}".format(raw); raw = str(raw[::-1]); g = [] #reverse
binary string for enumeration
g = [i for i,c in enumerate(raw) if c == '1']
processed = "x**"+" + x**".join(map(str, g[::-1]))
proc1 = processed.replace("x**1","x"); proc2 =
proc1.replace("x**0","1")
if len(g) == 0: return 0 #return 0 if list empty
return proc2 #returns result in gf(2) polynomial form
class BinaryField(GF2Polynomial):
def __init__(self, poly, mod):
if mod == "0": self.string = "Error: modulus division by 0"
elif mod == "0": self.string = "%s is 0 so resulting mod is 0"%(poly)
fieldPoly = GF2Polynomial(poly) % mod
if fieldPoly == 0: self.string = "%s and %s are the same so
resulting mod is 0"%(poly,mod)
else: super(BinaryField, self).__init__(fieldPoly.string)
#self.degree = len(str(fieldPoly))
def polyFieldCheck(self,other):
return self.degree() == other.degree()
def __add__(self, other):
"""
inherited from GF2Polynomial
"""
return super(BinaryField, self).__add__(other) % min(other,self)
def __sub__(self,other):
"""
inherited from GF2Polynomial
"""
return self.__add__(other)
def __mul__(self, other):
"""
special method of BinaryField, needed for format adjustments
between classes
"""
#print "self = %s,%s other = %s,%s
"%(self.degree(),type(self.degree()),other.degree(),type(other.degree()))
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
if self.polyFieldCheck(other) == False:
return "error: fields of %s and %s do not
match"%(self.string,other.string)
else: print "Operation will proceed: fields of %s and %s
match"%(self.string,other.string)
bitsa = reversed("{0:b}".format(self.bin))
g = [(other.bin<<i)*int(bit) for i,bit in enumerate(bitsa)]
result = reduce(lambda x,y: x^y,g)%min(self.bin,other.bin)
return GF2Polynomial(self.outFormat(result))
def __div__(self, other):
"""
special method of BinaryField, needed for format adjustments
between classes
"""
if self.polyVariableCheck(other) == False:
return "error: variables of %s and %s do not
match"%(self.string,other.string)
if self.polyFieldCheck(other) == False:
return "error: fields of %s and %s do not
match"%(self.string,other.string)
else: print "Operation will proceed: fields of %s and %s
match"%(self.string,other.string)
if self.bin == other.bin: return 1
result = self.bin/other.bin
#return self.outFormat(result)
return super(BinaryField, self).__div__(other) #% min(other,self)
def degree(self):
return len(self.lst)-1
And here's the main():
if __name__ == '__main__':
## "x**1 + x**0" polynomial string style input
poly1 = "x**14 + x**1 + x**0"; poly2 = "x**6 + x**2 + x**1"; poly3 =
"y**6 + y**2 + y**1"
a = GF2Polynomial(poly1); b = GF2Polynomial(poly2); c =
GF2Polynomial(poly3)
## "x+1" polynomial string style input
poly4 = "x**14 + x + 1"; poly5 = "x**6 + x**2 + x"; poly6 = "x**8 +
x**3 + 1"
d = GF2Polynomial(poly4); e = GF2Polynomial(poly5); f =
GF2Polynomial(poly6)
poly7 = "x**9 + x**5 + 1"; poly8 = "x**11 + x**7 + x**4 + 1"; poly9 =
"x**5 + x**4 + x**2 + x"
g = GF2Polynomial(poly7); h = GF2Polynomial(poly8); i =
GF2Polynomial(poly9)
## g = GF2Polynomial("x**5 + x**4 + x**3 + 1"); h = GF2Polynomial("x**5
+ x"); print "(g*h)%b = ",(g*h)%b
## dd = GF2Polynomial("x**0"); print "dd -- ",dd
## ee = GF2Polynomial("0"); print "ee -- ",ee
bf1 = BinaryField(poly1,b); print bf1; print "degree bf1 = ",bf1.degree()
bf2 = BinaryField(poly4,e); print "bf2 ",bf2; bf3 =
BinaryField(poly4,d); print "bf3 ",bf3,type(bf3)
bf4 = BinaryField(poly4,h); bf5 = BinaryField(poly9,e); bf6 =
BinaryField(poly8,i)
add1 = bf1+bf2
print "add1 ",add1
div1 = bf1/bf2
print "div1 ",div1,type(div1)
mix1 = bf2*bf1%bf5
print "mix1 ",mix1,type(mix1)

No comments:

Post a Comment