Related
Im very new to programming, I wrote a simple program for a school project and wanted to make the code "prettier" by not just having the program be one giant function but instead be made up of multiple smaller functions with a singe purpose. I seemed to have messed up royally since the program now runs 13 times slower. How should I structured the program to make it run faster and just in general make programs easier to write, read and edit?
Here are the two programs:
First program (for reference values runs in ≈0:20):
import numpy as np
import matplotlib.pyplot as plt
def graf(a,b,H,p):
GM = 39.5216489684
x_0 = a + np.sqrt(a**2 - b**2)
v_0 = np.sqrt(GM*(2/x_0 - 1/a))
konstant_period = np.sqrt(a**3)*H
h = 1/H
'''starting position given by an elliptic orbit '''
stor_x_lista = [x_0]
stor_y_lista = [0]
hastighet_x = [0]
hastighet_y = [v_0]
liten_x_lista = []
liten_y_lista = []
''' a loop that approximates the points of the orbit'''
t = 0
tid_lista = []
n = 0
while n < konstant_period:
hastighet_x.append(hastighet_x[n] - h*GM* stor_x_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_x_lista.append(stor_x_lista[n] + h*hastighet_x[n])
hastighet_y.append(hastighet_y[n] - h*GM*stor_y_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_y_lista.append(stor_y_lista[n] + h*hastighet_y[n])
'''smaller list of points to run faster'''
if n % p == 0:
liten_x_lista.append(stor_x_lista[n])
liten_y_lista.append(stor_y_lista[n])
tid_lista.append(t)
n += 1
t += h
''' function that finds the angle'''
vinkel = []
siffra = 0
while siffra < len(liten_x_lista):
if liten_y_lista[siffra ] >= 0:
vinkel.append( np.arccos( liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2)))
siffra += 1
elif liten_y_lista[siffra] < 0 :
vinkel.append( np.pi + np.arccos( -liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2) ))
siffra += 1
'''get rid of line to find periodic function'''
mod_lista = []
modn = 0
while modn < len(vinkel):
mod_lista.append(vinkel[modn] - (2*np.pi*tid_lista[modn])/np.sqrt(a**3))
modn += 1
'''make all inputs have period 1'''
squeeze_tid = []
squeezen = 0
while squeezen < len(tid_lista):
squeeze_tid.append(tid_lista[squeezen]/np.sqrt(a**3))
squeezen += 1
del mod_lista[-1:]
del tid_lista[-1:]
del squeeze_tid[-1:]
plt.plot(squeeze_tid,mod_lista)
plt.title('p(t) där a = ' + str(a) + ' och b = ' + str(b))
plt.show
Second more split up program (for reference values runs in ≈4:20):
import numpy as np
import matplotlib.pyplot as plt
'''function that generates the points of the orbit'''
def punkt(a,b,H,p):
GM = 39.5216489684
x_0 = a + np.sqrt(a**2 - b**2)
v_0 = np.sqrt(GM*(2/x_0 - 1/a))
konstant_period = np.sqrt(a**3)*H
h = 1/H
'''starting position given by an elliptic orbit '''
stor_x_lista = [x_0]
stor_y_lista = [0]
hastighet_x = [0]
hastighet_y = [v_0]
liten_x_lista = []
liten_y_lista = []
''' a loop that approximates the points of the orbit'''
t = 0
tid_lista = []
n = 0
while n < konstant_period:
hastighet_x.append(hastighet_x[n] - h*GM* stor_x_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_x_lista.append(stor_x_lista[n] + h*hastighet_x[n])
hastighet_y.append(hastighet_y[n] - h*GM*stor_y_lista[n]/(np.sqrt(stor_x_lista[n]**2 + stor_y_lista[n]**2))**3)
stor_y_lista.append(stor_y_lista[n] + h*hastighet_y[n])
'''smaller list of points to run faster'''
if n % p == 0:
liten_x_lista.append(stor_x_lista[n])
liten_y_lista.append(stor_y_lista[n])
tid_lista.append(t)
n += 1
t += h
return (liten_x_lista,liten_y_lista,tid_lista)
''' function that finds the angle'''
def vinkel(a,b,H,p):
'''import lists'''
liten_x_lista = punkt(a,b,H,p)[0]
liten_y_lista = punkt(a,b,H,p)[1]
tid_lista = punkt(a,b,H,p)[2]
'''find the angle'''
vinkel_lista = []
siffra = 0
while siffra < len(liten_x_lista):
if liten_y_lista[siffra ] >= 0:
vinkel_lista.append( np.arccos( liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2)))
siffra += 1
elif liten_y_lista[siffra] < 0 :
vinkel_lista.append( np.pi + np.arccos( -liten_x_lista[siffra]/np.sqrt( liten_x_lista[siffra]**2 + liten_y_lista[siffra]**2) ))
siffra += 1
return (vinkel_lista, tid_lista)
def periodisk(a,b,H,p):
'''import lists'''
tid_lista = vinkel(a,b,H,p)[1]
vinkel_lista = vinkel(a,b,H,p)[0]
'''get rid of linear line to find p(t)'''
mod_lista = []
modn = 0
while modn < len(vinkel_lista):
mod_lista.append((vinkel_lista[modn] - (2*np.pi*tid_lista[modn])/np.sqrt(a**3)))
modn += 1
'''make all inputs have period 1'''
squeeze_tid = []
squeezen = 0
while squeezen < len(tid_lista):
squeeze_tid.append(tid_lista[squeezen]/np.sqrt(a**3))
squeezen += 1
del mod_lista[-1:]
del tid_lista[-1:]
del squeeze_tid[-1:]
return (squeeze_tid,mod_lista)
'''fixa 3d-punkt av p(a,b) a är konstant b varierar??? '''
def hitta_amp(a):
x_b = []
y_b = []
n_b = 0.1
while n_b <= a:
x_b.append(n_b)
y_b.append(punkt(a,n_b,10**5,10**3))
return 0
def graf(a,b,H,p):
plt.plot(periodisk(a,b,H,p)[0],periodisk(a,b,H,p)[1])
plt.show
I would assume the thing that is going wrong is that the program is running the same, slow code multiple times instead of just running it once and then accessing the data. Is the problem that everything is done locally and nothing is stored globally or is it something else?
Just as a heads up, the only thing I know about programming is basic syntax, I have no clue how to actually write and run programs. I ran all the code in spyder if that affects anything.
plt.plot(periodisk(a,b,H,p)[0],periodisk(a,b,H,p)[1])
This code runs periodisk twice with the same arguments, thus at this point we know we run things at least 2 times slower.
You should do some_var = periodisk(a,b,H,p) and then some_var[0], some_var[1]. Or just use unpacking:
plt.plot(*periodisk(a,b,H,p))
tid_lista = vinkel(a,b,H,p)[1]
vinkel_lista = vinkel(a,b,H,p)[0]
Again doing the same thing twice (total: 4*time of (current) vinkel function). Again, smart assignment to fix this:
vinkel_lista, tid_lista = vinkel(a,b,H,p)
liten_x_lista = punkt(a,b,H,p)[0]
liten_y_lista = punkt(a,b,H,p)[1]
tid_lista = punkt(a,b,H,p)[2]
And now you repeat yourself thrice. (total: 12 * time of current punkt function)
liten_x_lista, liten_y_lista, tid_lista = punkt(a,b,H,p)
punkt function is like in original, so we arrived as total being 12 times slower - which quite matches your time estimations. :)
You are calling the functions once per returned list, you should only call them once.
When a method returns multiple variables, (e.g. punkt):
def punkt(a,b,H,p):
# Here is all your code
return (liten_x_lista,liten_y_lista,tid_lista)
You must be careful to only call the function once:
result = punkt(a,b,H,p)
liten_x_lista = result[0]
liten_y_lista = result[1]
tid_lista = result[2]
# As opposed to:
liten_x_lista = punkt(a,b,H,p)[0] # 1st call, ignoring results 2 and 3
liten_y_lista = punkt(a,b,H,p)[1] # 2nd call, ignoring results 1 and 3
tid_lista = punkt(a,b,H,p)[2] # 3rd call, ignoring results 1 and 2
Note: I would personally not return a list, but use python's unpacking:
def punkt(a,b,H,p):
# Here is all your code
return liten_x_lista, liten_y_lista, tid_lista
And you'd access it:
liten_x_lista, liten_y_lista, tid_lista = punkt(a,b,H,p)
I have four variables with in a defined function.
def xyz():
a_1 = self.bal.getcod1()
a_2 = self.bal.getcod2()
a_3 = self.bal.getcod3()
a_4 = self.bal.getcod4()
i = getx(a_1)
j = getx(a_2)
k = getx(a_3)
l = getx(a_4)
x = gety(a_1, i)
y = gety(a_2,j)
z = gety(a_3, k)
w = gety(a_4,l)
val = x*y*z*w
return val
For eg :
Based on the return value of getcod() i get 2,3,2,3 as a_1,a_2,a_3,a_4 respectively.
I dont want duplicates to pass into the four variables i,j,k,l
I want 2,3 to pass only once in two variables out of four variables and the rest should do nothing.
If i have all 4,4,4,4 then only one time i need to pass it to one variable out of four variables and the rest should do nothing.
If i have all 1,1,1,4 then i need 1,4 alone to pass it to two variables out of four variables and the rest should do nothing.
so that i can avoid to return duplicate multiplied data in 'Val' variable.
import numpy as np
If you want to keep the structure of your code, you could do:
def getx(var):
return var+10 #Example function
def gety(var1, var2):
return var1+var2 #Example function #2
def xyz():
a_1 = 2 #Replace with your function
a_2 = 3
a_3 = 2
a_4 = 3
i = getx(a_1)
j = getx(a_2)
k = getx(a_3)
l = getx(a_4)
w = gety(a_1, i)
x = gety(a_2, j)
y = gety(a_3, k)
z = gety(a_4, l)
val = np.prod(list({w,x,y,z}))
return val
Explanation:
w,x,y,z will be 14,16,14,16 respectively. You turn that into a set using {w,x,y,z}, so you get only one of each different element, getting 14,16. Then you turn that into a list, and then multiply each element of the list using np.prod().
Output:
224 # That is, 14*16.
based on the answer above, another method:
from functools import reduce
and then add this to your def xyz():
val = reduce((lambda x, y: x * y),list({w,x,y,z}))
The trick would be to use set to remove duplicates, but then you wouldn't know how many elements you got as the result, so use this to solve your problema:
result = reduce((lambda x, y: x * y), list(set([getx(a_1), getx(a_2), getx(a_3), getx(a_4)])))
Working sample:
from functools import reduce
def getx(x):
return x
def xyz():
a_1 = 2
a_2 = 3
a_3 = 2
a_4 = 3
return reduce((lambda x, y: x * y), list(set([getx(a_1), getx(a_2), getx(a_3), getx(a_4)])))
print(xyz())
returns: 6
I wrote a script whose aim is to find the parameters best fitting a function by trial and error (a Markov Chain Monte Carlo). The viability of the parameters is judged by a chi value -- the lower the chi, the better.
Below is a section of my code as currently written:
chi1 = fun_chi(B1,G1,C11,C21,C31,C41,C01)
BGCchilist = []
count = -1
for i in range(iteration_MCMC):
count = count + 1
print(count)
B2,G2,C12,C22,C32,C42,C02 = gen_param(B1,G1,C11,C21,C31,C41,C01)
chi2 = fun_chi(B2,G2,C12,C22,C32,C42,C02)
ratio = np.exp((-chi2 + chi1) / 2)
rand = np.random.uniform(0,1)
if rand < ratio:
B1 = B2
G1 = G2
C11 = C12
C21 = C22
C31 = C32
C41 = C42
C01 = C02
chi1 = chi2
##save the data
Bsave = B1
Gsave = G1
C1save = C11
C2save = C21
C3save = C31
C4save = C41
C0save = C01
chisave = chi1
BGCchilist.append((Bsave,Gsave,C1save,C2save,C3save,C4save,C0save,chisave))
Blist = [x[0] for x in BGCchilist]
Glist = [x[1] for x in BGCchilist]
C1list = [x[2] for x in BGCchilist]
C2list = [x[3] for x in BGCchilist]
C3list = [x[4] for x in BGCchilist]
C4list = [x[5] for x in BGCchilist]
C0list = [x[6] for x in BGCchilist]
chilist = [x[7] for x in BGCchilist]
minchi = min(x[7] for x in BGCchilist)
mintuple = [x for x in BGCchilist if x[7] == minchi]
I ultimately individually graph all of those lists versus iteration via Matplotlib and then save mintuple as a text file.
A colleague took a look at this and told me that perhaps I would be better served by using a dictionary, where for every iteration I do something like a_dictionary[chisave] = (B,G,...C0) and then find mintuple by looking for the minimum value in the dictionary. However, it seems like extracting lists from the value tuples in the dictionary for graphing would be more unwieldy and take more steps.
Would the dictionary approach allow for fewer steps, greater efficiency, or is this all lists approach okay as is?
Thank you for your help.
This is making an answer out of the comments. I thought that the question about the efficiency but after closer examination, it looks like it is about how to clean up the code. If that is the confer, then the following might be useful:
For the first part, we just keep everything as a tuple, and use inlace expansion like so ...
par1 = B1,G1,C11,C21,C31,C41,C01
chi1 = fun_chi(*par1)
BGCchilist = []
for i in range(iteration_MCMC):
print (i-1)
par2 = gen_param(*par1)
chi2 = fun_chi(*par2)
ratio = np.exp((-chi2 + chi1) / 2)
rand = np.random.uniform(0,1)
if rand < ratio: par1 = par2
BGCchilist.append(list(par1) + [chi1]) ##save the data
This is a verbatim logical copy. However, I don't see chi1 being updated within the for loop. I am guessing that you want that to happen as well? Like so:
par1 = B1,G1,C11,C21,C31,C41,C01
BGCchilist = []
for i in range(iteration_MCMC):
print (i-1)
chi1 = fun_chi(*par1) # This is the change
par2 = gen_param(*par1)
chi2 = fun_chi(*par2)
if np.random.uniform(0,1) < np.exp((-chi2 + chi1) / 2): par1 = par2
BGCchilist.append(list(par1) + [chi1]) ##save the data
I am not sure about the algorithm, so cannot definitively comment on that part.
The next part is more interesting.
Blist = [x[0] for x in BGCchilist]
Glist = [x[1] for x in BGCchilist]
C1list = [x[2] for x in BGCchilist]
C2list = [x[3] for x in BGCchilist]
C3list = [x[4] for x in BGCchilist]
C0list = [x[6] for x in BGCchilist]
C4list = [x[5] for x in BGCchilist]
chilist = [x[7] for x in BGCchilist]
can be simply replaced by:
BList, GList, \
C1List, C2List, C3List \
C0List, C4List, chilist = zip(*BGCchilist)
I think this is what it does. Please check this part separately.
Finally, do you really need all the lists? Or do you just need the chiList ?
The rest should be easy I think? What you have is pretty ok. Check the key parameter in the min function. So if you dont want all the lists for some reason, you can simply skip that part and find the minimum within the for loop, or you can just do:
minChi = min( zip(*BGCchilist)[-1] )
allMinChis = filter( lambda m: m[7] == minChi, BGCchilist)
Cheeers!
N.B. I havent tested the code so there might be errors. Please go through the code and make sure that that is what you want.
A dict will be fewer steps, and be easier to read as well. Using minchi as the key:
BGCchilist = {}
# in the loop
BGCchilist[chisave] = [Bsave, Gsave, C1save,C2save,C3save,C4save,C0save,chisave]
# out of the loop
minchi = min(BGCchilist.keys())
mintuple = BGCchilist[minchi]
If you need to save each combination of parameters that result in the same chi value, change the dict to hold a list of tuples per key, instead of just a list:
from collections import defaultdict
BGCchilist = defaultdict(list)
...
BGCchilist[chisave].append([...all the saves...])
...
minchi = min(BGCchilist.keys())
mintuples = BGCchilist[minchi]
# at this point mintuples has at least one tuple of params that got
# this chi score, maybe more
Update:
Okay, so here's my understanding of your requirements:
you need to save each combination of parameters and the resulting chi score
you need to get the lowest chi score when done
you need a list of each input parameter, and the chi scores, when done
I would use a simple class for this. It might not be fewer lines, but it will be much more readable:
# lightly tested
class BGCChiData(object): # (object) not needed in Python3
def __init__(self):
self.data = defaultdict(list)
def __getitem__(self, chi):
return self.data[chi]
def __setitem__(self, chi, params):
self.data[chi].append(params)
#property
def min_chi(self):
return min(self.data.keys())
#property
def B(self):
return [tup[0] for val in self.data.values() for tup in val]
#property
def G(self):
return [tup[1] for val in self.data.values() for tup in val]
#property
def C1(self):
return [tup[2] for val in self.data.values() for tup in val]
#property
def C2(self):
return [tup[3] for val in self.data.values() for tup in val]
#property
def C3(self):
return [tup[4] for val in self.data.values() for tup in val]
#property
def C4(self):
return [tup[5] for val in self.data.values() for tup in val]
#property
def C0(self):
return [tup[6] for val in self.data.values() for tup in val]
#property
def chi(self):
return [tup[7] for val in self.data.values() for tup in val]
chi1 = fun_chi(B1,G1,C11,C21,C31,C41,C01)
BGCchi = BGCChiData()
for count in range(iteration_MCMC):
print(count)
B2,G2,C12,C22,C32,C42,C02 = gen_param(B1,G1,C11,C21,C31,C41,C01)
chi2 = fun_chi(B2,G2,C12,C22,C32,C42,C02)
ratio = np.exp((-chi2 + chi1) / 2)
rand = np.random.uniform(0,1)
if rand < ratio:
B1 = B2
G1 = G2
C11 = C12
C21 = C22
C31 = C32
C41 = C42
C01 = C02
chi1 = chi2
##save the data
BGCchi[chi1].append(B1, G1, C11, C21, C31, C41, C01)
minchi = BGCchi.min_chi
mintuple = BGCchi[minchi]
B1list = BGCchi.B
# etc. etc.
I have a class that was taking in lists of 1's and 0's and performing GF(2) finite field arithmetic operations. It used to work until I tried to make it take the input in polynomial format. As for how the finite arithmetic will be done after fixing the regex issue, I was thinking about overloading the operators.
The actual code in parsePolyToListInput(input) works when outside the class. The problem seems to be in the regex, which errors that it will only take in a string (this makes sense), but does not seem to initialize with self.expr as a parameter (that's a problem). The #staticmethod just before the initialization was an attempt to salvage the unbound error as it the polynomial was passed in, but this is apparently completely wrong. Just to save you time if you decide to look at any of the arithmetic operations, modular inverse does not work (seems to be due to the formatting issue after every iteration of that while loop for division in the function and what the return type is):
import re
class gf2poly:
#binary arithemtic on polynomials
##staticmethod
def __init__(self,expr):
self.expr = expr
#self.expr = [int(i) for i in expr]
self.expr = gf2poly.parsePolyToListInput(self.expr)
def convert(self): #to clarify the input if necessary
convertToString = str(self.expr)
print "expression is %s"%(convertToString)
def id(self): #returns modulus 2 (1,0,0,1,1,....) for input lists
return [int(self.expr[i])%2 for i in range(len(self.expr))]
def listToInt(self): #converts list to integer for later use
result = gf2poly.id(self)
return int(''.join(map(str,result)))
def prepBinary(a,b): #converts to base 2 and orders min and max for use
a = gf2poly.listToInt(a); b = gf2poly.listToInt(b)
bina = int(str(a),2); binb = int(str(b),2)
a = min(bina,binb); b = max(bina,binb);
return a,b
#staticmethod
def outFormat(raw):
raw = str(raw[::-1]); g = [] #reverse binary string for enumeration
[g.append(i) for i,c in enumerate(raw) if c == '1']
processed = "x**"+' + x**'.join(map(str, g[::-1]))
if len(g) == 0: return 0 #return 0 if list empty
return processed #returns result in gf(2) polynomial form
def parsePolyToListInput(poly):
c = [int(i.group(0)) for i in re.finditer(r'\d+', poly)] #re.finditer returns an iterator
#m = max(c)
return [1 if x in c else 0 for x in xrange(max(c), -1, -1)]
#return d
def add(self,other): #accepts 2 lists as parameters
a = gf2poly.listToInt(self); b = gf2poly.listToInt(other)
bina = int(str(a),2); binb = int(str(b),2)
m = bina^binb; z = "{0:b}".format(m)
return z #returns binary string
def subtract(self,other): #basically same as add() but built differently
result = [self.expr[i] ^ other.expr[i] for i in range(len(max(self.expr,other.expr)))]
return int(''.join(map(str,result)))
def multiply(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
g = []; bitsa = "{0:b}".format(a)
[g.append((b<<i)*int(bit)) for i,bit in enumerate(bitsa)]
m = reduce(lambda x,y: x^y,g); z = "{0:b}".format(m)
return z #returns product of 2 polynomials in gf2
def divide(a,b): #a,b are lists like (1,0,1,0,0,1,....)
a,b = gf2poly.prepBinary(a,b)
bitsa = "{0:b}".format(a); bitsb = "{0:b}".format(b)
difflen = len(str(bitsb)) - len(str(bitsa))
c = a<<difflen; q=0
while difflen >= 0 and b != 0: #a is divisor, b is dividend, b/a
q+=1<<difflen; b = b^c # b/a because of sorting in prep
lendif = abs(len(str(bin(b))) - len(str(bin(c))))
c = c>>lendif; difflen -= lendif
r = "{0:b}".format(b); q = "{0:b}".format(q)
return r,q #returns r remainder and q quotient in gf2 division
def remainder(a,b): #separate function for clarity when calling
r = gf2poly.divide(a,b)[0]; r = int(str(r),2)
return "{0:b}".format(r)
def quotient(a,b): #separate function for clarity when calling
q = gf2poly.divide(a,b)[1]; q = int(str(q),2)
return "{0:b}".format(q)
def extendedEuclideanGF2(a,b): # extended euclidean. a,b are GF(2) polynomials in list form
inita,initb=a,b; x,prevx=0,1; y,prevy = 1,0
while sum(b) != 0:
q = gf2poly.quotient(a,b);
q = list(q); q = [int(x) for x in q]
#q = list(q);
#q = tuple([int(i) for i in q])
q = gf2poly(q)
a,b = b,gf2poly.remainder(a,b);
#a = map(list, a);
#b = [list(x) for x in a];
#a = [int(x) for x in a]; b = [int(x) for x in b];
b = list(b); b = [int(x) for x in b]
#b = list(b);
#b = tuple([int(i) for i in b])
b = gf2poly(b)
#x,prevx = (prevx-q*x, x);
#y,prevy=(prevy-q*y, y)
print "types ",type(q),type(a),type(b)
#q=a//b; a,b = b,a%b; x,prevx = (prevx-q*x, x); y,prevy=(prevy-q*y, y)
#print("%d * %d + %d * %d = %d" % (inita,prevx,initb,prevy,a))
return a,prevx,prevy # returns gcd of (a,b), and factors s and t
def modular_inverse(a,mod): # where a,mod are GF(2) polynomials in list form
gcd,s,t = gf2poly.extendedEuclideanGF2(a,mod); mi = gf2poly.remainder(s,mod)
#gcd,s,t = ext_euc_alg_i(a,mod); mi = s%mod
if gcd !=1: return False
#print ("%d * %d mod %d = 1"%(a,mi,mod))
return mi # returns modular inverse of a,mod
I usually test it with this input:
a = x**14 + x**1 + x**0
p1 = gf2poly(a)
b = x**6 + x**2 + x**1
p2 = gf2poly(b)
The first thing you might notice about my code is that it's not very good. There are 2 reasons for that:
1) I wrote it so that the 1st version could do work in the finite field GF(2), and output in polynomial format. Then the next versions were supposed to be able to take polynomial inputs, and also perform the crucial 'modular inverse' function which is not working as planned (this means it's actually not working at all).
2) I'm teaching myself Python (I'm actually teaching myself programming overall), so any constructive criticism from pro Python programmers is welcome as I'm trying to break myself of beginner habits as quickly as possible.
EDIT:
Maybe some more of the code I've been testing with will help clarify what works and what doesn't:
t1 = [1,1,1]; t2 = [1,0,1]; t3 = [1,1]; t4 = [1, 0, 1, 1, 1, 1, 1]
t5 = [1,1,1,1]; t6 = [1,1,0,1]; t7 = [1,0,1,1,0]
f1 = gf2poly(t1); f2 = gf2poly(t2); f3 = gf2poly(t3); f4 = gf2poly(t4)
f5 = gf2poly(t5);f6 = gf2poly(t6);f7 = gf2poly(t7)
##print "subtract: ",a.subtract(b)
##print "add: ",a.add(b)
##print "multiply: ",gf2poly.multiply(f1,f3)
##print "multiply: ",gf2poly.multiply(f1,f2)
##print "multiply: ",gf2poly.multiply(f3,f4)
##print "degree a: ",a.degree()
##print "degree c: ",c.degree()
##print "divide: ",gf2poly.divide(f1,b)
##print "divide: ",gf2poly.divide(f4,a)
##print "divide: ",gf2poly.divide(f4,f2)
##print "divide: ",gf2poly.divide(f2,a)
##print "***********************************"
##print "quotient: ",gf2poly.quotient(f2,f5)
##print "remainder: ",gf2poly.remainder(f2,f5)
##testq = gf2poly.quotient(f4,f2)
##testr = gf2poly.remainder(f4,f2)
##print "quotient: ",testq,type(testq)
##print "remainder: ",testr,type(testr)
##print "***********************************"
##print "outFormat testp: ",gf2poly.outFormat(testq)
##print "outFormat testr: ",gf2poly.outFormat(testr)
##print "***********************************"
#print "gf2poly.modular_inverse(): ",gf2poly.modular_inverse(f2,f3)
print "p1 ",p1 #,type(f2),type(f3)
#print "parsePolyToListInput ",gf2poly.parsePolyToListInput(a)
Part of your problem is that you haven't declared self as an argument for parsePolyToListInput. When you call a method, the instance you call it on is implicitly bound as the first argument. Naming the first argument self is a convention, not a strict requirement - the instance is being bound to poly, which you then try to run a regexp over.
It looks me like there's some confusion in your design here about what's behavior of individual instances of the class and what's class-level or module-level behavior. In Python, it's perfectly acceptable to leave something that doesn't take an instance of a class as a parameter defined as a module-level function rather than shoehorning it in awkwardly. parsePolyToListInput might be one such function.
Your add implementation, similarly, has a comment saying it "accepts 2 lists as parameters". In fact, it's going to get a gf2poly instance as its first argument - this is probably right if you're planning to do operator overloading, but it means the second argument should also be a gf2poly instance as well.
EDIT:
Yeah, your example code shows a breakdown between class behavior and instance behavior. Either your multiply call should look something like this:
print "multiply: ",f1.multiply(f3)
Or multiply shouldn't be a method at all:
gfpoly.py:
def multiply(f1, f2):
a,b = prepBinary(a,b)
g = []; bitsa = "{0:b}".format(a)
[g.append((b<<i)*int(bit)) for i,bit in enumerate(bitsa)]
m = reduce(lambda x,y: x^y,g); z = "{0:b}".format(m)
return z #returns product of 2 polynomials in gf2
That latter approach is, for instance, how the standard math library does things.
The advantage of defining a multiplication method is that you could name it appropriately (http://docs.python.org/2/reference/datamodel.html#special-method-names) and use it with the * operator:
print "multiply: ",f1 *f3
My code is working right except when i enter r1 into the function equation below
def u(Substrate):
return((u_max*ys[:,0])/(Ks+ys[:,0]))
biomass = ys[:,1]
u = u(ys[:,0])
def r1(u,biomass):
r1 = u*biomass*YieldCO2_1
return r1
r1 = r1(u,biomass)
def F(y,t):
Ptot = 710
Vgas = 2
D = 0.00826*(273.15+Temp)
Cstar_CO2 = KH_CO2 * y[2]
Cstar_CH4 = KH_CH4 * y[3]
TG_CO2 = KLa_CO2*(Cstar_CO2-y[0])
TG_CH4 = KLa_CH4*(Cstar_CH4-y[1])
Q_CO2 = -D*V*TG_CO2
Q_CH4 = -D*V*TG_CH4
Qgas = (Q_CO2+Q_CH4)+Q
F=np.zeros(4)
F[0] = Q/V * (CO2_To-y[0]) + TG_CO2 + r1
F[1] = Q/V * (CH4_Do-y[1]) + TG_CH4
F[2] = -Ptot*D*TG_CO2*(V/Vgas)-y[2]*(Qgas/Vgas)
F[3] = -Ptot*D*TG_CH4*(V/Vgas)-y[3]*(Qgas/Vgas)
return F
yinit = np.array([4,3,250,200])
ts = np.arange(0,4,0.4)
y = odeint(F,yinit,ts)
When r1 is seen in equation F[0] I get the following error:
F[0] = Q/V * (CO2_To-y[0]) + TG_CO2 + r1
ValueError: setting an array element with a sequence.
odepack.error: Error occurred while calling the Python function named F
However when I do the function without the r1 array, there is no error. so that is why i am assuming something is wrong with putting the r1 array into the function
If anyone could provide input to my problem i would
F[0] = expression expects expression to be a number here, not an array. However Q/V * (CO2_To-y[0]) + TG_CO2 + r1 is an array of r1 dimensions. To see this, try evaluating the following line:
>>> 1 + numpy.array([1,2])
array([2, 3])
To get rid of the exception you should covert this expression to a number somehow depending on what you are trying to achieve.