Многочлены Python в конечных полях. Почему в этом случае с super() работает только __add__()?

Я пытаюсь использовать __div__() родительского класса, чтобы поддерживать один и тот же тип, чтобы можно было вызывать сразу несколько операций, как в последнем примере mix1 = bf2/bf4*bf1%bf5 в main() ниже, где несколько арифметических операций связаны вместе. По какой-то причине я могу использовать super() в __add__(), но не в __div__(). Ошибка «IndexError: индекс списка вне диапазона», и я повторял это снова и снова без какого-либо прогресса. Обратите внимание, что все это связано с полиномиальной арифметикой в ​​пределах конечного поля.

Я включаю parsePolyVariable() и его иждивенцев (извините, если это выглядит так, как будто есть немного кода, но я уверяю вас, что все это по уважительной причине и создает характер), так как это то, откуда ошибка списка, но я могу' t для жизни мне понять, где все идет очень неправильно. Я сам учу Python, поэтому уверен, что есть и другие новички, которые увидят, где я упускаю очевидное.

Я просматривал их, но они, похоже, не связаны с этой ситуацией:

http://docs.python.org/2/library/functions.html#super

Python super(Class, self).method vs super( Родитель, я).метод

Как я могу использовать супер () для обновления родительского значения?

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

А вот и 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)

РЕДАКТИРОВАТЬ: полная трассировка --

Message File Name   Line    Position    
Traceback               
    <module>    C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py    233     
    __div__ C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py    197     
    __div__ C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py    100     
    __init__    C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py    20      
    parsePolyVariable   C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py    48      
IndexError: list index out of range             

Для ссылочной строки 48 используется degree = max(c); varmatch = True; key = letter[0]. Личные заметки и информация были удалены, скорректированы номера строк.


person stackuser    schedule 13.08.2013    source источник
comment
Какова полная трассировка исключения, которое вы получаете? Можете ли вы сократить код примера до просто кода, выдающего ошибку?   -  person Martijn Pieters    schedule 14.08.2013
comment
Ошибка связана не с super, а с внутренним состоянием ваших полиномов. Родительский метод (вероятно... без трассировки, я не могу точно сказать) вызывается правильно, но он не работает по какой-то другой причине. Вы должны дважды проверить правильность реализации __div__. (Примечания к стилю: я действительно не вижу ` == False. Simply use not self.polyVariableCheck(other)` и не могу понять, почему ваши __div__ методы возвращают строки ошибок, когда они терпят неудачу. Вместо этого вам, вероятно, следует вызвать исключение).   -  person Bakuriu    schedule 14.08.2013
comment
Полная трассировка опубликована. Код, размещенный выше, уже значительно сокращен до основных методов-виновников и их зависимостей. __mod__ необходим во время инициализации класса, а __mul__ (также может потребоваться исправление) предназначен для сравнения типа возвращаемого значения с другими специальными методами. Ценю любую помощь, которую вы можете предоставить, так как я отлаживал эту единственную проблему в течение очень долгого времени. Я не знаю, что еще проверить в __div__(), так как это, по сути, только само подразделение. Я хотел бы использовать __div__() из родителя вместо того, чтобы переписывать его, поэтому я пытаюсь использовать super().   -  person stackuser    schedule 14.08.2013
comment
Это не имеет ничего общего с super().   -  person Martijn Pieters    schedule 14.08.2013


Ответы (1)


Ваша строка return GF2Polynomial(self.outFormat(self.bin/other.bin)) приводит к строке 1, которая затем передается методу GF2Polynomial.parsePolyVariable().

В этом значении нет букв, поэтому строка:

letter = [str(m.group(0)) for m in re.finditer(r'[a-z]', poly)]

возвращает пустой список. Следующая строка:

degree = max(c); varmatch = True; key = letter[0]

затем терпит неудачу, потому что key = letter[0] дает исключение IndexError.

Ваш код трудно читать, потому что вы используете однобуквенные переменные и размещаете несколько операторов в одной строке, поэтому трудно понять, чего вы ожидаете от этой функции.

В противном случае исключение не имеет ничего общего с super(). Где-то в вашем собственном коде есть простая ошибка.

person Martijn Pieters    schedule 13.08.2013
comment
Спасибо! +1. Я добавил if letter == []: return "1",[1] в строку 48, и, казалось, все шло хорошо, пока я на самом деле не попробовал это с mix1 = bf5/bf2*bf1%bf5, и это привело к ошибке Message File Name Line Position Traceback <module> C:\Users\win7pro-vm\Desktop\crypto\GF2BinaryField.py 245 TypeError: can't multiply sequence by non-int of type 'BinaryField' , что является ошибкой, которую я получил и раньше, что не позволяет мне использовать несколько операций вместе, как я ищу сделать (согласно моему первоначальному вопросу). - person stackuser; 14.08.2013
comment
С исправлением я также вижу mix1 error: variables of x and x**5 + x**4 + x**2 + 1 do not match <type 'str'>. - person Martijn Pieters; 14.08.2013
comment
и заменив строку mix1 в конце, я вижу TypeError: not all arguments converted during string formatting для строки, которую вы дали. - person Martijn Pieters; 14.08.2013
comment
на что ты заменил mix1? все форматирование строк имеет правильное количество и тип заполнителей... но mix1 = bf2*bf1/bf5 работает, так что, по крайней мере, это прогресс. - person stackuser; 14.08.2013
comment
с mix1 = bf5/bf2*bf1%bf5. Выражение bf5/bf2*bf1 возвращает строку, поэтому % интерпретируется как интерполяция строки. - person Martijn Pieters; 14.08.2013
comment
Вы не должны не смешивать сообщения об ошибках с вашими методами. Вместо этого используйте исключения. - person Martijn Pieters; 14.08.2013
comment
Ооооооооооооооооооооооооооооооооооооооооо. Я вижу сейчас. он возвращает строки (по частям после каждой части выражения, а не только в конце), поэтому их нужно будет снова инициализировать в классе, иначе они просто останутся строками (а не полиномами). я думал, что они стали строкой после выполнения всего выражения. спасибо, что научил меня кое-чему сегодня. теперь это заставляет меня хотеть читать ваш блог. - person stackuser; 14.08.2013