Python -- using __init__ with an inherited method for polynomials class

731 views Asked by At

This is a class which will take in as input and then output a polynomial in string form (both ways same format). Some arithmetic is performed in the various methods. I've been trying to inherit this class into another class that will then use the __mod__() special method of the first class (or make it's own special method if necessary but I don't see how you can't just use the original method) to perform the mod on intake. Seems like this goes into __init__() but I've tried 5 different versions of this, even going so far as to change the parent class, and I'm getting nowhere. I'm teaching myself Python so I'm sure that even a junior Python dev can see where I'm going totally wrong.

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)
        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
        letter = [str(m.group(0)) for m in re.finditer(r'[a-z]', poly)]
        m = 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
        d = [1 if x in c else (1 if x==0 else (1 if x=='x' else 0))  for x in xrange(m, -1, -1)]
        return key,d

    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 __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

The desired result is to be able to call it on a new (child) class with the parent type and while changing the parent class as little as possible (if even at all). Note that class "BinaryField" is the intended child class:

p=GF2Polynomial("x**2+x**1+x**0")
a=BinaryField("x**1+x**0", p)
b=BinaryField("x**1", p)

On intake, the given polynomial should be modulus divided by the 2nd element (here it's 'p'). This is necessary for finite field math.

EDIT: when running it with --

## "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 = "y**6 + y**2 + 1"
d = GF2Polynomial(poly4); e = GF2Polynomial(poly5); f = GF2Polynomial(poly6)
bf1 = BinaryField(poly1,b); print bf1
bf2 = BinaryField(poly4,e); print bf2

Both of these styles are possible because of the way I coded it, but they should both return the same answer. However the result on that code is:

>>> 
x**5 + x**4 + x**3 + 1
x**5 + x

Also, when using BinaryField(poly4,d), which is just the same string with it's GF2Polynomial() initialization, this errors as: AttributeError: 'int' object has no attribute 'string'

1

There are 1 answers

5
Viktor Kerkez On BEST ANSWER

Does this solves your problem?

class BinaryField(GF2Polynomial):
    def __init__(self, string, mod):
        modded = GF2Polynomial(string) % mod
        super(BinaryField, self).__init__(modded.string)


>>> p = GF2Polynomial("x**2+x**1+x**0")
>>> a = BinaryField("x**1+x**0", p)
>>> print a
x + 1

You can also make the BinaryField class to be just a factory method:

def BinaryField(string, mod):
    return GF2Polynomial(string) % mod