efficiently construct a "switch" statement within a while loop - python

Here's a minimalistic view of my problem (removing all unnecessary details). Essentially, it is an "assembly code" executor:
while(self.pc < len(self.memory)):
instruction = [int(i) for i in str(self.memory[self.pc])]
#simulated "switch" statement.
def switch(Opcode):
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
def add():
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
self.clock += self.clockSpeed['add']
def subtract():
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
self.clock += self.clockSpeed['subtract']
def invalid():
raise ValueError('invalid Opcode in instruction: {}'.format(instruction)
return {
0: add,
1: subtract,
"invalid": invalid
}.get(Opcode, "invalid")()
switch(instruction[0])
self.pc += 1
when I run this program with a simple array of around 40 elements (slightly more complicated method, but not much more) using the timeit module, it does take quite some time:
print 'timing execution of execute: ', timeit.timeit('vm.CPUexecuteProgram()', setup="from __main__ import OS; vm=OS(); vm.AbsoluteLoader('../assembly_code/assemble_code.exe')")
timing execution of execute: 0.673621892929
I believe that the definition is "re-making" itself on every iteration. Would there be a more efficient way which would follow the same "pattern" shown here? I'd like to avoid using if/elif/else if possible, to make it more readable.

This:
if op1['mode'] = self.modes['gpr']:
Needs to be:
if op1['mode'] == self.modes['gpr']:
For all of your comparisons. The double-equal is "does left equal right?". The single equal is "assign right to left, then return right".

Yes, you code creates all the functions and the entire dictionary on every instruction. In your real code (assuming 40 distinct opcodes), this means at least 42 object instantiations (1 per opcode, switch, the dict) per instruction executed. You can simply pull the loop-invariant parts (creation of add, sub, ...; creation of the opcode->function dict) out of the loop, make op1 and op2 parameters, and reduce the loop to this:
while self.pc < len(self.memory):
instruction = ...
op1 = ...
op2 = ...
implementations[instruction](op1, op2)
self.pc += 1
That should shave off a considerable fraction of the time. There are probably other places where one can optimize a bit, but since that isn't your real code and it's quite sloppy (several syntax errors, some parts look wrong) I will refrain from guessing.

Rearrange it:
def add(op1, op2):
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
self.clock += self.clockSpeed['add']
def subtract(op1, op2):
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
self.clock += self.clockSpeed['subtract']
def invalid(op1, op2):
raise ValueError('invalid Opcode in instruction: {}'.format(instruction)
switch = {0: add, 1: subtract}
while (self.pc < len(self.memory)):
instruction = [int(i) for i in str(self.memory[self.pc])]
Opcode = instruction[0]
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
switch.get(Opcode, invalid)(op1, op2)
self.pc += 1
this way it won't redefine all the methods every time.

import operator
class Something(object):
_operations = {
0: lambda self, instruction: self._execute("add", instruction),
1: lambda self, instruction: self._execute("subtract", instruction),
"invalid": lambda self, instruction: self_invalid(instruction)
}
_operators = {
"add": operator.add,
"substract": operator.sub
}
def _execute(self, operation, instruction):
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
operator = self._operators[operation]
val = operator(op1, op2)
if op1['mode'] == self.modes['gpr']:
self.gpr[op1['gpr']] = val
else:
self.memory[op1['opAddress']] = val
self.clock += self.clockSpeed[operation]
def _invalid(self, instruction):
raise ValueError(
'invalid Opcode in instruction: {}'.format(instruction)
)
def _switch(self, instruction):
return self._operations.get(instruction[0], self._invalid)(self, instruction)
def whatever(self):
while self.pc < len(self.memory):
instruction = [int(i) for i in str(self.memory[self.pc])]
self._switch(instruction)
self.pc += 1

Related

Is there a way to simplify this if else block?

So I have this really long if else block and I was wondering if there is a way to simplify it?
def position(self, k):
if self.b == None:
self.b = k
if (self.b).location_of(k) == 0:
if self.aquire(0) == None:
self.put(0, ABK(k))
else:
self.aquire(0).insert(k)
elif (self.b).location_of(k) == 1:
if self.aquire(1) == None:
self.put(1, ABK(k))
else:
self.aquire(1).insert(k)
elif (self.b).location_of(k) == 2:
if self.aquire(2) == None:
self.put(2, ABK(k))
else:
self.aquire(2).insert(k)
You could store the value of self.b.location_of(k) on a variable and use it later to call your functions.
def position(self, k):
if self.b is None:
self.b = k
loc = self.b.location_of(k)
if loc < 0 or loc > 2:
return # Return in case the value is out of scope
if self.aquire(loc) is None:
self.put(loc, ABK(k))
else:
self.aquire(loc).insert(k)
Edit:
Olvin Roght pointed out that you can also save the result of the self.aquire(loc) call:
def position(self, k):
if self.b is None:
self.b = k
loc = self.b.location_of(k)
if loc < 0 or loc > 2:
return
aqu = self.aquire(loc)
if aqu is None:
self.put(loc, ABK(k))
else:
aqu.insert(k)
As of python 3.8, you can achieve a result similar to the other answers in a shorter manner using the walrus operator (:=), more formally known as the assignment expression operator. This sort of inline assignment is similar to the way assignment can sometimes be done in nested ifs in C:
def position(self, k):
if self.b is None:
self.b = k
if 0 <= (loc := self.b.location_of(k)) <= 2:
if (val := self.aquire(loc)) is None:
self.put(loc, ABK(k))
else:
val.insert(k)
In addition to the more obvious changes, I recommend using x is None rather than x == None, as it is the more idiomatic comparison.

Allocation dynamic truthtable values to a dictionary

NOTE: This post is heavy edited. I found a solution.
My question was, how I can apply all possible combinations of a truth table for an arbitary number of variables to a dictionary. E.g. for 3 vars I have a dictionary like 'lib = {"x":0, "y":0, "z":0}' I wanted to generate all 8 possible combinations.
I need the n-tuples in this format to evaluate a given expression.
Because some wanted to know why I needed it. I was working on an exercise where I created a class with subclasses to handle boolean expressions.
While brooding over the problem I looked over the previous chapters in the exercise book and realized, that I might solve it with recursion.
For those interested here is my implementation and with my solution:
# classes to handle boolean expressions
class ExprBoolean:
def __str__(self): # necessary for considering precedence: not > and > or > equal
return self.str_aux(0)
def init_Lib_Keys(self): # if not existent, generate class var: lib - dictionary with all
try: # vars, keys - list with all vars, tt - empty list for truth table
self.lib
except:
self.lib = self.getVar({})
self.keys = list(self.lib.keys())
self.tt = []
# ---- Solution I was looking for --------------------------------
def TruthTable(self,keys): # generates truth table considering all vars and entered expression
if keys == []: # condition to insert n-tupel as row in lib-string
dummy = []
for key in self.lib:
dummy += [self.lib[key]] + ["\t| "]
dummy += [self.eval(self.lib)] + ["\n"]
self.tt += [dummy]
return
for keyN in range(len(keys)):
for i in [True,False]:
self.lib[keys[keyN]] = i
self.TruthTable(keys[1:])
break
# ----------------------------------------------------------------
def make_tt(self): # prints a truth table
self.init_Lib_Keys()
for key in self.keys:
print("{}\t\t| ".format(key),end="") # header of table with
print(self) # expression in last column
if not self.tt:
self.TruthTable(self.keys) # generates truth table
for row in self.tt: # prints row after row
for col in row:
print(col,end="")
def isTauto(self): # checks if expression is tautology (always True)
self.init_Lib_Keys()
if not self.tt:
self.TruthTable(self.keys)
for row in self.tt:
if not row[-2]: # in row[-2] is evaluated expression
print(row[-2])
return
print(True)
class Not(ExprBoolean):
prec = 3 # precedence rank for brackets
def __init__(self,arg):
self.arg = arg
def str_aux(self,prec):
return "!" + self.arg.str_aux(self.prec)
def getVar(self,env):
return self.arg.getVar(env)
def eval(self,env):
return not self.arg.eval(env)
class BooOp(ExprBoolean):
def __init__(self,x,y):
self.x = x
self.y = y
def str_aux(self,prec):
s = self.x.str_aux(self.prec) + self.op + self.y.str_aux(self.prec)
if self.prec < prec:
return "(" + s + ")"
else:
return s
def getVar(self,env):
new_env = self.x.getVar(env)
new_env = self.y.getVar(new_env)
return new_env
def eval(self,env):
return self.fun(self.x.eval(env),self.y.eval(env))
class And(BooOp):
prec = 2
op = "&"
def fun(self,x,y):
return x & y
class Or(BooOp):
prec = 1
op = "|"
def fun(self,x,y):
return x | y
class Eq(BooOp):
prec = 0
op = "=="
def fun(self,x,y):
return x == y
class Var(ExprBoolean):
def __init__(self,name):
self.name = name
def str_aux(self,prec):
return self.name
def getVar(self,env):
env[self.name] = 0
return env
def eval(self,env):
return env[self.name]
# examples to test class
lib = {"x":True, "y":False, "z":True}
e1 = Or(Var("x"),Not(Var("x")))
e2 = Eq(Var("x"),Not(Not(Var("x"))))
e3 = Eq(Not(And(Var("x"),Var("y"))),Or(Not(Var("x")),Not(Var("y"))))
e4 = Eq(Not(And(Var("x"),Var("y"))),And(Not(Var("x")),Not(Var("y"))))
e5 = Eq(Eq(Eq(Var("p"),Var("q")),Var("r")),Eq(Var("p"),Eq(Var("q"),Var("r"))))
e6 = And(Or(Var("x"),Var("y")),Eq(Var("x"),Var("y")))
e4.make_tt()
e4.isTauto()
If I understand the problem, this is one way to help solve it without using eval() or having to parse the expression yourself. (You will have to implement the other Boolean functions yourself.)
def AND(a, b):
return a and b
def OR(a, b):
return a or b
def NOT(a):
return not a
x = True
y = False
z = True
print(AND(x, y))
# False
print(NOT(AND(x, y)))
# True
print(OR(x, y))
# True
print(AND(AND(x, z), NOT(y)))
# True
Even though python has classes, that doesn't mean you should treat every problem as an invitation to write a class hierarchy.
Evaluating expression is a verb, not a noun.
First off, you don't always have to write an expression evaluator. Python has eval and exec, and boolean and arithmetic expressions in Python are pretty much standard:
>>> eval("3+5")
8
>>> eval("x=3+5")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
x=3+5
^
SyntaxError: invalid syntax
>>> exec("x=3+5")
>>> x
8
If that is enough, look at the ast module in the standard library.
Even if you want to write it yourself, programming is often more about creating smart data that writing lots of code.
Below is a small implementation of a postfix expression parser (from one of my github repos).
import operator
import math
# Global constants {{{1
_add, _sub, _mul = operator.add, operator.sub, operator.mul
_truediv, _pow, _sqrt = operator.truediv, operator.pow, math.sqrt
_sin, _cos, _tan, _radians = math.sin, math.cos, math.tan, math.radians
_asin, _acos, _atan = math.asin, math.acos, math.atan
_degrees, _log, _log10 = math.degrees, math.log, math.log10
_e, _pi = math.e, math.pi
_ops = {
"+": (2, _add),
"-": (2, _sub),
"*": (2, _mul),
"/": (2, _truediv),
"**": (2, _pow),
"sin": (1, _sin),
"cos": (1, _cos),
"tan": (1, _tan),
"asin": (1, _asin),
"acos": (1, _acos),
"atan": (1, _atan),
"sqrt": (1, _sqrt),
"rad": (1, _radians),
"deg": (1, _degrees),
"ln": (1, _log),
"log": (1, _log10),
}
_okeys = tuple(_ops.keys())
_consts = {"e": _e, "pi": _pi}
_ckeys = tuple(_consts.keys())
def postfix(expression): # {{{1
"""
Evaluate a postfix expression.
Arguments:
expression: The expression to evaluate. Should be a string or a
sequence of strings. In a string numbers and operators
should be separated by whitespace
Returns:
The result of the expression.
"""
if isinstance(expression, str):
expression = expression.split()
stack = []
for val in expression:
if val in _okeys:
n, op = _ops[val]
if n > len(stack):
raise ValueError("not enough data on the stack")
args = stack[-n:]
stack[-n:] = [op(*args)]
elif val in _ckeys:
stack.append(_consts[val])
else:
stack.append(float(val))
return stack[-1]
The "intelligence" of this is in the _ops dictionary, which links an operator to a two-tuple of a number of arguments and an operator function.
Because of that, the evaluator itself is only 14 lines of code.

How to clean (reset) cache memory of my decorator?

I need to write decorator to remember function results for given parameters. I did it, but how to reset the memory? I tried to reset func.cache, but without correct result.
from random import random
def cached(func):
cache = func.cache = {}
func.call_num = 0
func.eval_num = 0
def memorised_func(*args, **kwargs):
key = str(args) + str(sorted(kwargs.items(), key=lambda kv: kv[1]))
#print(key)
if key not in cache:
cache[key] = func(*args, **kwargs)
func.eval_num += 1
func.call_num += 1
print(func.call_num, func.eval_num)
return cache[key]
memorised_func.cache_status = lambda: print(f"Function {func.__name__} called {func.call_num} times, evaluated {func.eval_num} times")
#memorised_func.cache_reset = lambda : func.cache #-TODO , help
return memorised_func
#cached
def foo(x, y=1, z=4):
return random()
#EXAMPLE THAT SHOULD WORK
print(foo(3) == foo(3))
print(foo(4) == foo(4))
print(foo(3, z=-1, y=3) == foo(3, y=3, z=-1))
print(foo(3) != foo(x=3))
a = foo(3)
foo.cache_reset() #HERE DOESN'T WORK - TODO
print(a != foo(3))
print(foo.cache_status() == 'Function foo called 10 times, evaluated 5 times')
the commented out section is simply:
memorised_func.cache_reset = lambda: func.cache.clear()
You have a strong crossover with memoize from the func library, consider looking in to that, too.

Why does passing a dictionary as a parameter take more time?

I tried to a leetcode problem. I find one of the following code throws a time limit exceeded error. I created the following testing code. I found the first one pass dictionary as a parameter takes more time the the other one. 0.94s vs 0.84s.
Can anyone explain this ?
class Solution(object):
def longestPalindromeSubseq(self, x):
"""
:type s: str
:rtype: int
"""
#dic = {}
def helper(s, dic):
if len(s) == 0:
return 0
if len(s) == 1:
return 1
if s in dic:
return dic[s]
if s[0] == s[-1]:
res = helper(s[1:-1], dic)+2
else:
l1 = helper(s[:-1], dic)
l2 = helper(s[1:], dic)
res = max(l1,l2)
dic[s] = res
#print (id(dic), dic)
return res
d = {}
ans = helper(x, d)
#print (id(d), d)
return ans
class Solution1(object):
def longestPalindromeSubseq(self, x):
"""
:type s: str
:rtype: int
"""
dic = {}
def helper(s):
if len(s) == 0:
return 0
if len(s) == 1:
return 1
if s in dic:
return dic[s]
if s[0] == s[-1]:
res = helper(s[1:-1])+2
else:
l1 = helper(s[:-1])
l2 = helper(s[1:])
res = max(l1,l2)
dic[s] = res
#print (id(dic), dic)
return res
ans = helper(x)
#print (id(dic), dic)
return ans
import time
if __name__ == "__main__":
x = "gphyvqruxjmwhonjjrgumxjhfyupajxbjgthzdvrdqmdouuukeaxhjumkmmhdglqrrohydrmbvtuwstgkobyzjjtdtjroqpyusfsbjlusekghtfbdctvgmqzeybnwzlhdnhwzptgkzmujfldoiejmvxnorvbiubfflygrkedyirienybosqzrkbpcfidvkkafftgzwrcitqizelhfsruwmtrgaocjcyxdkovtdennrkmxwpdsxpxuarhgusizmwakrmhdwcgvfljhzcskclgrvvbrkesojyhofwqiwhiupujmkcvlywjtmbncurxxmpdskupyvvweuhbsnanzfioirecfxvmgcpwrpmbhmkdtckhvbxnsbcifhqwjjczfokovpqyjmbywtpaqcfjowxnmtirdsfeujyogbzjnjcmqyzciwjqxxgrxblvqbutqittroqadqlsdzihngpfpjovbkpeveidjpfjktavvwurqrgqdomiibfgqxwybcyovysydxyyymmiuwovnevzsjisdwgkcbsookbarezbhnwyqthcvzyodbcwjptvigcphawzxouixhbpezzirbhvomqhxkfdbokblqmrhhioyqubpyqhjrnwhjxsrodtblqxkhezubprqftrqcyrzwywqrgockioqdmzuqjkpmsyohtlcnesbgzqhkalwixfcgyeqdzhnnlzawrdgskurcxfbekbspupbduxqxjeczpmdvssikbivjhinaopbabrmvscthvoqqbkgekcgyrelxkwoawpbrcbszelnxlyikbulgmlwyffurimlfxurjsbzgddxbgqpcdsuutfiivjbyqzhprdqhahpgenjkbiukurvdwapuewrbehczrtswubthodv"
print (x)
t0 = time.time()
sol = Solution()
print (sol.longestPalindromeSubseq(x))
t1 = time.time()
print(t1- t0)
sol1 = Solution1()
print (sol1.longestPalindromeSubseq(x))
t2 = time.time()
print(t2-t1)
Python uses something that is called call by sharing. The function gets only the alias on the parameter. With that in mind, it does't matter what you pass to the function.
But the script may take different time to execute. It is not constant. Using recursion makes it even harder to predict

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)
EDIT:
The full traceback --
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
For reference line 48 is degree = max(c); varmatch = True; key = letter[0].
Personal notes and information were removed, adjusting the line numbers.
Your return GF2Polynomial(self.outFormat(self.bin/other.bin)) line results in the string 1, which is then passed to the GF2Polynomial.parsePolyVariable() method.
This value has no letters, so the line:
letter = [str(m.group(0)) for m in re.finditer(r'[a-z]', poly)]
returns an empty list. The next line:
degree = max(c); varmatch = True; key = letter[0]
then fails because key = letter[0] gives a IndexError exception.
Your code is hard to read because you use one-letter variables and put multiple statements on one line, so it is hard to make out what your expectations are in that function.
The exception has otherwise nothing to do with super(). There is a simple bug in your own code somewhere.

Categories

Resources