Function multiplying two polynomials gives wrong result - python

I want to create a function called multipoly(x,y) which takes two lists as input, multiplies the lists and returns the answers.
Polynomial is represented as follows: for instance x^4+2X^3 is represented as [(1,4),(2,3)].
Here is something I get but it returns wrong answer for some test cases:
def multipoly(p1,p2):
x=max(p1,p2)
y=min(p1,p2)
p1=x
p2=y
for i in range(len(x)):
for item in p2:
p1[i] = ((p1[i][0] * item[0]), (p1[i][1] + item[1]))
p2.remove(item)
return p1
print(multipoly([(1,1),(-1,0)],[(1,2),(1,1),(1,0)]))

You are probably better off to implement this as a class to encapsulate all the operations on a polynomial:
maybe something like this as a basis to start?
Here, I chose to represent the polynomial via a sequence of coefficients where the indices are the corresponding exponents of x
Caveat, the results look okay, but I did not write tests, so it may be brittle on some corner cases.
class Polynomial:
def __init__(self, coefficients:list):
"""represents polynomials as a list of parameters where
the indices are the exponents"""
self.coefficients = coefficients
def __len__(self):
return len(self.coefficients)
def __getitem__(self, idx):
return self.coefficients[idx]
def __iter__(self):
for coeff in self.coefficients:
yield coeff
def __str__(self):
res = [str(self.coefficients[0]) + ' + '] if self.coefficients[0] != 0 else []
for exponent, coeff in enumerate(self.coefficients[1:]):
e = exponent + 1
if coeff != 0:
if e == 1:
if coeff == 1:
res.append('x + ')
else:
res.append(f'({coeff})*x + ')
elif coeff == 1:
res.append(f'x**{e} + ')
else:
res.append(f'({coeff})*x**{e} + ')
return ''.join(res)[:-3]
def __add__(self, other):
result = [0] * max(len(self), len(other))
for idx in range(len(result)):
try:
a = self[idx]
except IndexError:
a = 0
try:
b = other[idx]
except IndexError:
b = 0
result[idx] = a + b
return Polynomial(result)
def __mul__(self, other):
result = [0] * (len(self) + len(other))
for exponent_a, coeff_a in enumerate(self):
for exponent_b, coeff_b in enumerate(other):
result[exponent_a + exponent_b] += coeff_a * coeff_b
return Polynomial(result)
def d_dx(self):
return Polynomial([expo * coeff for expo, coeff in enumerate(self)][1:])
a = Polynomial([1, 2, 3, 0, 0, 6])
b = Polynomial([1, 2, 3, 1, 1, 0])
print(a, '\n', b, '\n', a + b, '\n', a * b, '\n', a.d_dx(), '\n', b.d_dx(), '\n', (a*b).d_dx())
print()
c = Polynomial([1, 1])
d = Polynomial([1, -1])
print(c, '\n', d, '\n', c + d, '\n', c * d)
output:
1 + (2)*x + (3)*x**2 + (6)*x**5
1 + (2)*x + (3)*x**2 + x**3 + x**4
2 + (4)*x + (6)*x**2 + x**3 + x**4 + (6)*x**5
1 + (4)*x + (10)*x**2 + (13)*x**3 + (12)*x**4 + (11)*x**5 + (15)*x**6 + (18)*x**7 + (6)*x**8 + (6)*x**9
2 + (6)*x + (30)*x**4
2 + (6)*x + (3)*x**2 + (4)*x**3
4 + (20)*x + (39)*x**2 + (48)*x**3 + (55)*x**4 + (90)*x**5 + (126)*x**6 + (48)*x**7 + (54)*x**8
1 + x
1 + (-1)*x
2
1 + (-1)*x**2

You can use a dictionary to store the result of the multiplication ,So that the exponents which are already calculated can directly be added to the previous calculated value
The following code works
def multipoly(p1,p2):
mul = dict()
for m in p1:
for n in p2:
if m[1] + n[1] in mul:
mul[m[1] + n[1]] += m[0] * n[0]
else:
mul[m[1] + n[1]] = m[0] * n[0]
m_res = []
for p, q in mul.items():
m_res.append((q, p))
return m_res
print(multipoly([(1,1),(-1,0)],[(1,2),(1,1),(1,0)]))
It takes less than your solution. Because in your solution you are removing an element in p2 which takes O(sizeof(p2)) time.

Yet another way. Using itertools groupby to combine similar terms:
from itertools import groupby
def multipoly(poly1,poly2):
#multiply two polynolials
temp = [(p1[0]*p2[0], p1[1]+p2[1]) for p1 in poly1 for p2 in poly2]
#sort to use for groupby
temp = sorted(temp, key= lambda x: x[1])
#groupby second term
g = groupby(temp, lambda x: x[1])
#combine terms
result = []
for k,v in g:
result.append((sum([i[0] for i in v]), k))
result.sort(key=lambda x: -x[1])
return result

If you simply want a function to multiply two polynomials, represented as a list of tuples [(coef, expn) ...] you can start by multiplying term by term the two polynomials p1, p2 like this
p3 = [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]
but you have a problem because, in general, you will have more than one term with the same exponent, to normalize the result in p3 we can use a dictionary
d = {}
for c, e in p3:
d[e] = d.get(e, 0) + c
note that d.get(e, 0) returns d[e] if the exponent is already present in d or returns 0.
Finally, you want back your results as a list of tuples
p3 = [(c, e) for e, c in d.items()]
but this list is not guaranteed to be sorted in order of decreasing exponent
p3 = sorted(p3, key=lambda t: -t[1])
It is possible to put all this in a single callable
def pmult(p1, p2):
d = {}
for coef, expn in [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]:
d[expn] = d.get(expn,0)+coef
return sorted([(c, e) for e, c in d.items()], key=lambda t: -t[1])
A test:
In [25]: a = [(1,2),(3,0)]
In [26]: b = [(1,4),(2,3),(3,2),(4,1),(5,0)]
In [27]: def pmult(p1, p2):
...: d = {}
...: for coef, expn in [(c1*c2, e1+e2) for c1, e1 in p1 for c2, e2 in p2]:
...: d[expn] = d.get(expn,0)+coef
...: return sorted([(c, e) for e, c in d.items()], key=lambda t: -t[1])
In [28]: pmult(a, b)
Out[28]: [(1, 6), (2, 5), (6, 4), (10, 3), (14, 2), (12, 1), (15, 0)]

Related

Expanding expression trees in sympy, keeping certain binomials together

I am manipulating multivariate polynomials in sympy that are all expressed as sums of products of terms of the form (x_i + y_j), where the i and j are indices, and I want to keep it that way, i.e. express everything in terms of sums of one x symbol and one y symbol.
For example, I want
(y_{1} + z_{2})*((0 + 1)*(y_{3} + z_{2}) + y_{1} + z_{1} + 0 + 0)
to become
(y_{1} + z_{2})*(y_{3} + z_{2}) + (y_{1} + z_{2})*(y_{1} + z_{1})
The first thing you can do is replace binomials that fit the pattern with dummy and expand. The problem is that you will have some dangling terms to group together. If you always have two, then it's easy. If you have more it will require more work and a good definition of which subindexed x should go with which y (or whatever letters you want paired up).
So let's start with your unevaluated expression which we will call u
Get the free symbols (assuming there are only x and y of interest):
>>> free = u.free_symbols
Replace existing binomials with a unique dummy variable
>>> reps = {}
>>> u.replace(lambda x:x.is_Add and len(x.args) == 2 and all(
... i in free for i in x.args),
... lambda x: reps.setdefault(x, Dummy()))
_Dummy_45*(_Dummy_47*(0 + 1) + y1 + z1)
Now expand
>>> expand(_)
_Dummy_45*_Dummy_47 + _Dummy_45*y1 + _Dummy_45*z1
and collect products of dummy symbols together
>>> _.replace(lambda x:x.is_Mul and len(x.args) == 2 and all(
... i in reps.values() for i in x.args),
... lambda x: reps.setdefault(x, Dummy())))
_Dummy_45*y1 + _Dummy_45*z1 + _Dummy_51
Collect on dummy symbols to get binomials to appear that were previously dangling
>>> collect(_, reps.values())
_Dummy_45*(y1 + z1) + _Dummy_51
Now replace Dummy symbols with their values (which are the keys in reps so we have to invert that dictionary):
>>> _.xreplace({v:k for k,v in reps.items()})
_Dummy_45*_Dummy_47 + (y1 + z1)*(y1 + z2)
Do it again
>>> _.xreplace({v:k for k,v in reps.items()})
(y1 + z1)*(y1 + z2) + (y1 + z2)*(y3 + z2)
Posting specific expressions that you would like to see re-arranged in some way would help to focus a more robust solution, but these techniques can get you started. Here, too, is a function that pairs up free symbols in an Add and replaces them with Dummy symbols.
def collect_pairs(e, X, Y):
free = e.free_symbols
xvars, yvars = [[i for i in free if i.name.startswith(j)] for j in (X, Y)]
reps = {}
def do(e):
if not e.is_Add: return e
x, cy = sift(e.args, lambda x: x in xvars, binary=True)
y, c = sift(cy, lambda x: x in yvars, binary=True)
if x and len(x) != len(y): return e
args = []
for i,j in zip(ordered(x), ordered(y)):
args.append(reps.setdefault(i+j, Dummy()))
return Add(*(c + args))
# hmmm...this destroys the reps and returns {}
#return {v:k for k,v in reps.items()}, bottom_up(e, do)
return reps, bottom_up(e, do)
>>> e1
(y1 + z2)*(y1 + y3 + z1 + z2)
>>> r, e = collect_pairs(e1,'y','z')
>>> expand(e).xreplace({v:k for k,v in r.items()})
(y1 + z1)*(y1 + z2) + (y1 + z2)*(y3 + z2)
This works with the fully expanded e1 if you factor it first:
>>> e2 = factor(expand(e1)); e2
(y1 + z2)*(y1 + y3 + z1 + z2)
>>> r, e = collect_pairs(e2, 'y', 'z')
>>> expand(e).xreplace({v:k for k,v in r.items()})
(y1 + z1)*(y1 + z2) + (y1 + z2)*(y3 + z2)
Looking at the code you originally posted, I would suggest keeping the binomials together and only replace them at the end, like this:
...
def single_variable_diff(perm_dict,k,m):
ret_dict = {}
for perm,val in perm_dict.items():
if len(perm)<k:
ret_dict[perm] = Add(ret_dict.get(perm,0), reps.setdefault(U(var2[k],var3[m]), Dummy())*val,evaluate=False)
else:
ret_dict[perm] = Add(ret_dict.get(perm,0), reps.setdefault(U(var2[perm[k-1]],var3[m]), Dummy())*val,evaluate=False)
...
reps = {}
U = lambda x,y: UnevaluatedExpr(Add(*ordered((x,y))))
ireps = lambda: {v:k for k,v in reps.items()}
perms=[]
curperm = []
...
coeff_perms.sort(key=lambda x: (inv(x),*x))
def touch(e):
from sympy.core.traversal import bottom_up
def do(e):
return e if not e.args else e.func(*e.args)
return bottom_up(e, do)
undo = ireps()
for perm in coeff_perms:
val = touch(coeff_dict[perm]).expand().xreplace(undo))
print(f"{str(perm):>{width}} {str(val)}")
(3, 4, 1, 2) will be given in terms of binomial products, but some elements will not -- they are just sums of binomials. In ordered to keep them together, you can create them as UnevaluatedExpr, e.g. the U lambda that is defined. I am guessing you don't have to use evaluated=False and will, then, not need the touch function.

Creating a general function

I have a function defintion -
Now I have to create a function like this-
The problem is that since there are 4 combinations of (t,c)(where t is the feature and c is the class) which can occur that is (t,c) , (t',c) , (t,c') , (t', c'). So according to the values of t,c the function defintion will also change.
Is there any method apart from calculating a , b ,c ,d 4 times and then summing the function values?
The dataset looks like this-
feature file_frequency_M file_frequency_B
abc 2 5
my attempt-
dataset = pd.read_csv('.csv')
score = []
###list =[(t,c) ,(t,c0),(t0,c),(t0,c0)] ##representation of the combination of (t,c)
l=152+1394
for index, row in dataset.iterrows():
a = row['file_frequency_M']
b = row['file_frequency_B']
c = 152 - a
d = 1394 - b
temp_score = 0
tmp1 = 0
tmp2 = 0
tmp3 = 0
tmp4 = 0
for i in range(4):
if i == 0:
if a == 0:
tmp1 = 0
else:
tmp1 = log10(((a * l) / (a + c) * (a + b)))
temp_score += tmp1
if i == 1:
if b == 0:
tmp2 = 0
else:
tmp2 = log10(((b * l) / (b + d) * (b + a)))
temp_score += tmp2
if i == 2:
if c == 0:
tmp3 = 0
else:
tmp3 = log10(((c * l) / (c + a) * (c + d)))
temp_score += tmp3
if i == 3:
if d == 0:
tmp4 = 0
else:
tmp4 = log10(((d * l) / (d + b) * (d + c)))
temp_score += tmp4
score.append(temp_score)
np.savetxt("m.csv", score, delimiter=",")
You can save a lot of code repetition by creating a function representation of I(t,c):
import numpy as np
import pandas as pd
from math import log10
dataset = pd.read_csv('.csv')
score = []
###list =[(t,c) ,(t,c0),(t0,c),(t0,c0)] ##representation of the combination of (t,c)
l=152+1394
def I(a,b,c,n):
"""Returns I(t,c) = A*N/((A+C)*(A+B))"""
if a == 0:
return 0
return log10((a * n) / ((a + c) * (a + b)))
for index, row in dataset.iterrows():
a = row['file_frequency_M']
b = row['file_frequency_B']
c = 152 - a
d = 1394 - b
tmp1 = I(a,b,c,l)
tmp2 = I(b,a,d,l)
tmp3 = I(c,d,a,l)
tmp4 = I(d,c,b,l)
temp_score = sum(tmp1,tmp2,tmp3,tmp4)
score.append(temp_score)
np.savetxt("m.csv", score, delimiter=",")
Note: you appear to have an error in your code, according to the image of your function definition, it should be:
log10((a * n) / ((a + c) * (a + b)))
not
log10(((a * l) / (a + c) * (a + b)))
(note the parentheses placement).

Remove mixed-variable terms in SymPy series expansion

Consider two functions of SymPy symbols e and i:
from sympy import Symbol, expand, Order
i = Symbol('i')
e = Symbol('e')
f = (i**3 + i**2 + i + 1)
g = (e**3 + e**2 + e + 1)
z = expand(f*g)
This will produce
z = e**3*i**3 + e**3*i**2 + e**3*i + e**3 + e**2*i**3 + e**2*i**2 + e**2*i + e**2 + e*i**3 + e*i**2 + e*i + e + i**3 + i**2 + i + 1
However, assume that e and i are both small and we can neglect both terms that are order three or higher. Using Sympy’s series tool or simply adding an O-notation Order class can handle this:
In : z = expand(f*g + Order(i**3) + Order(e**3))
Out: 1 + i + i**2 + e + e*i + e*i**2 + e**2 + e**2*i + e**2*i**2 + O(i**3) + O(e**3)
Looks great. However, I am still left with mixed terms e**2 * i**2. Individual variables in these terms are less than the desired cut-off so SymPy keeps them. However, mathematically small²·small² = small⁴. Likewise, e·i² = small·small² = small³.
At least for my purposes, I want these mixed terms dropped. Adding a mixed Order does not produce the desired result (it seems to ignore the first two orders).
In : expand(f*g + Order(i**3) + Order(e**3) + Order((i**2)*(e**2)))
Out: 1 + i + i**2 + i**3 + e + e*i + e*i**2 + e*i**3 + e**2 + e**2*i + e**3 + e**3*i + O(e**2*i**2, e, i)
Question: Does SymPy have an easy system to quickly remove the n-th order terms, as well as terms that are (e^a)·(i^b) where a+b > n?
Messy Solution: I have found a way to solve this, but it is messy and potentially not general.
z = expand(f*g + Order((e**2)*i) + Order(e*(i**2)))
zz = expand(z.removeO() + Order(e**3) + Order(i**3))
produces
zz = 1 + i + i**2 + e + e*i + e**2 + O(i**3) + O(e**3)
which is exactly what I want. So to specify my question: Is there a way to do this in one step that can be generalized to any n? Also, my solution loses the big-O notation that indicates mixed-terms were lost. This is not needed but would be nice.
As you have a dual limit, you must specify both infinitesimal variables (e and i) in all Order objects, even if they don’t appear in the first argument.
The reason for this is that Order(expr) only automatically chooses those symbols as infinitesimal that actually appear in the expr and thus, e.g., O(e) is only for the limit e→0.
Now, Order objects with different limits don’t mix well, e.g.:
O(e*i)+O(e) == O(e*i) != O(e)+O(e*i) == O(e) # True
This leads to a mess where results depend on the order of addition, which is a good indicator that this is something to avoid.
This can be avoided by explicitly specifying the infinitesimal symbols (as addition arguments of Order), e.g.:
O(e*i)+O(e,e,i) == O(e,e,i)+O(e*i) == O(e,e,i) # True
I haven’t found a way to avoid going through all combinations of e and i manually, but this can be done by a simple iteration:
orders = sum( Order(e**a*i**(n-a),e,i) for a in range(n+1) )
expand(f*g+orders)
# 1 + i + i**2 + e + e*i + e**2 + O(e**2*i, e, i) + O(e*i**2, e, i) + O(i**3, e, i) + O(e**3, e, i)
Without using Order you might try something simple like this:
>>> eq = expand(f*g) # as you defined
>>> def total_degree(e):
... x = Dummy()
... free = e.free_symbols
... if not free: return S.Zero
... for f in free:
... e = e.subs(f, x)
... return degree(e)
>>> eq.replace(lambda x: total_degree(x) > 2, lambda x: S.Zero)
e**2 + e*i + e + i**2 + i + 1
There is a way about it using Poly. I have made a function that keeps the O(...) term and another that does not (faster).
from sympy import Symbol, expand, Order, Poly
i = Symbol('i')
e = Symbol('e')
f = (i**3 + i**2 + i + 1)
g = (e**3 + e**2 + e + 1)
z = expand(f*g)
def neglect(expr, order=3):
z = Poly(expr)
# extract all terms and keep the lower order ones
d = z.as_dict()
d = {t: c for t,c in d.items() if sum(t) < order}
# Build resulting polynomial
return Poly(d, z.gens).as_expr()
def neglectO(expr, order=3):
# This one keeps O terms
z = Poly(expr)
# extract terms of higher "order"
d = z.as_dict()
large = {t: c for t,c in d.items() if sum(t) >= order}
for t in large: # Add each O(large monomial) to the expression
expr += Order(Poly({t:1},z.gens).as_expr(), *z.gens)
return expr
print(neglect(z))
print(neglectO(z))
This code prints the following:
e**2 + e*i + e + i**2 + i + 1
1 + i + i**2 + e + e*i + e**2 + O(e**2*i, e, i) + O(e*i**2, e, i) + O(i**3, e, i) + O(e**3, e, i)

More pythonic/elegant way to do this Python string slicing?

So I have a function that takes two string inputs - it slices them so that if of even length, the length of the front segment is the same as that of the back, and if of odd length, the middle character goes to the front segment (i.e. hello -> hel , lo). And then you mix and match the resulting front and back segments of the two string to produce the final output.
I want to be able to do this all under one function and what I came up with is ugly as all heck:
def front_back(a, b):
if len(a) % 2 == 0:
front_a = a[:len(a)/2]
back_a = a[len(a)/2:]
elif len(a) % 2 != 0:
front_a = a[:(len(a)/2)+1]
back_a = a[(len(a)/2)+1:]
if len(b) % 2 == 0:
front_b = b[:len(b)/2]
back_b = b[len(b)/2:]
elif len(b) % 2 != 0:
front_b = b[:(len(b)/2)+1]
back_b = b[(len(b)/2)+1:]
print front_a + front_b + back_a + back_b
front_back('Kitten', 'Donut') ---> KitDontenut
Is there a more pythonic/elegant way?
I couldn't figure out how to use lambdas (they can't process the if statement necessary to deal with even and odd length cases... i think?) if that's the way to go...
UPDATE:
thanks for the great suggestions everyone. just one more question:
when i try a version with lamdbas, based off a suggestion (for practice), I get a NameError that global name 's' isn't defined. What's wrong with how I wrote the lambda?
def front_back(a, b):
divideString = lambda s: s[:((1+len(s))//2)], s[((1+len(s))//2):]
a1, a2 = divideString(a)
b1, b2 = divideString(b)
print a1 + b1 + a2 + b2
front_back("hello","cookies")
You are making it more complicated than it needs to be:
def front_back(a, b):
mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
front_a, back_a = a[:mid_a], a[mid_a:]
front_b, back_b = b[:mid_b], b[mid_b:]
print front_a + front_b + back_a + back_b
By adding 1 before dividing by 2 (floor division), you round up.
Demo:
>>> def front_back(a, b):
... mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
... front_a, back_a = a[:mid_a], a[mid_a:]
... front_b, back_b = b[:mid_b], b[mid_b:]
... print front_a + front_b + back_a + back_b
...
>>> front_back('Kitten', 'Donut')
KitDontenut
You could inline the slicing even:
def front_back(a, b):
mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
print a[:mid_a] + b[:mid_b] + a[mid_a:] + b[mid_b:]
def divideString(myString):
sliceHere = ( (1 + len(myString)) // 2)
return myString[:sliceHere], myString[sliceHere:]
def front_back(a, b):
a1, a2 = divideString(a)
b1, b2 = divideString(b)
return a1 + b1 + a2 + b2
def front_back(a, b):
return "".join([a[:(len(a)+1)/2]], b[:(len(b)+1)/2], \
a[(len(a)+1)/2]:], b[:(len(b)+1)/2]])
You could also add the result of length % 2 to the fronts:
def front_back(a, b):
ln_a, ln_b = len(a), len(b)
a1 = a2 = ln_a // 2
b1 = b2 = ln_b // 2
a1 += ln_a % 2
b1 += ln_b % 2
return a[:a1] + b[:b1] + a[-a2:] + b[-b2:]
print(front_back('Kitten', 'Donut'))
There are a some good answers here already, but for the sake of diversity, since you seem to be interested in multiple possibilities, here's a different way of looking at it:
import itertools
def front_back(a,b):
words = [a,b]
output = [[],[]]
for word in words:
if len(word) % 2 == 0:
output[0].append(word[:len(word)//2])
output[1].append(word[len(word)//2:])
else:
output[0].append(word[:len(word)//2+1])
output[1].append(word[(len(word)//2)+1:])
return "".join(output[0]) + "".join(output[1])
print(front_back('Kitten', 'Donut'))
Interpret with Python 3.

Decomposition function

I've been puzzling over how to get a certain function working in Python. The function itself is like this:
(Phi_m)x((n2)) = (Phi_m)(x(m*n + r)) = m*x[n1] + r*(x([n1] + 1) - x[n1])
Note: n here is just to specify some multiple. It is not a list element, but it becomes a list element when x is applied. In the below example For example, we might have that n is larger than any element on the list. E.g. a list has 9 elements, the largest is 3, and m=1 - here n=9 =/= element of the list.
where n2 and n1 are two different values of an input string, and where n1 is derived by 'decomposing' n2. We consider x[0] = 0, r is always at zero or positive and less than m, and all values of n (either of them) are positive integers. In general functional takes in a string of numbers and outputs another string. What normally happens is we fix an m, say m = 2. Now we decompose n2. Say n2 = 5. Then F(x(5)) = F(x(2*2+1)) 2x[2] + 1(x[3] - x[2]). So if our full input sequence was 0, 1, 1, 2, 3, 3 we'd have 2*1+0=2. So our fifth output term is 2.
I initially thought to do something like:
x = [0,1,1,2,3,3,3,3]
def F(n,j,r,x):
return j * x[n] + r(x[n + 1] - x[n])
for n in range(len(x) - 1):
print n
but this clearly fails for my purposes.
The thing is, for Python to do this it has to know how to decompose each number. So it knows 2 is fixed, and knows 2*3 is too much and so chooses 2*2. Then it has to know this is too little and add remainder 1. Only once it's done this can it actually grab n = 5. That is, it can run the function. It seems clear that once it knows how to do this it can just run through every n in our range, but I'm really not sure how to program the meat of this function.
here is how I would decompose a number in the form of n2 = m * n1 + r:
>>> def decompose(number):
... # returns a generator of tuples (m, n1, r)
... for m in range(1, number+1):
... yield m, number // m, number % m
...
>>> for m, n1, r in decompose(5):
... print "5 = %s * %s + %s" % (m, n1, r)
...
5 = 1 * 5 + 0
5 = 2 * 2 + 1
5 = 3 * 1 + 2
5 = 4 * 1 + 1
5 = 5 * 1 + 0
or with a fixed m, this is the same as a regular divmod:
>>> def decompose(number):
... return number // m, number % m
...
>>> m = 2
>>> n1, r = decompose(5)
>>> print "5 = %s * %s + %s" % (m, n1, r)
5 = 2 * 2 + 1
>>> m = 4
>>> n1, r = decompose(5)
>>> print "5 = %s * %s + %s" % (m, n1, r)
5 = 4 * 1 + 1
or more simply using lambda:
>>> decompose = lambda number: divmod(number, m)
>>>
>>> m = 2
>>> decompose(5)
(2, 1)
>>> m = 4
>>> decompose(5)
(1, 1)
and now, for a full exanple:
>>> decompose = lambda number: divmod(number, m)
>>>
>>> class Phi_m(list):
... def __init__(self, items):
... list.__init__(self)
... # you need to know at least m numbers.
... assert len(items) >= m, 'Not enough data'
... list.extend(self, items)
... # this is a sparse list
... # http://stackoverflow.com/questions/1857780/sparse-assignment-list-in-python
... def __setitem__(self, index, value):
... missing = index - len(self) + 1
... if missing > 0:
... self.extend([None] * missing)
... list.__setitem__(self, index, value)
... def __getitem__(self, index):
... try:
... value = list.__getitem__(self, index)
... if value is not None:
... # the item is in the list, yeah!
... return value
... # the item is in the list because it was resized
... # but it is None, so go on and calculate it.
... except IndexError:
... # the item is not in the list, calculate it.
... pass
... print 'calculating Fm[%s]' % index
... A, B = decompose(index)
... value1 = self.__getitem__(A)
... value2 = self.__getitem__(A + 1)
... print 'Fm[A=%s] = %s, Fm[A+1=%s] = %s' % (A, value1, A+1, value2)
... print 'back to calculating Fm[%s]' % index
... # m * x[n1] + r * (x[n1 + 1] - x[n1]) = (m - r) * x[n1] + r * x[n1 + 1]
... # A = n1 ; B = r ; value1 = x[n1] ; value2 = x[n+1]
... value = (m - B) * value1 + B * value2
... self.__setitem__(index, value)
... return value
...
>>> x = Phi_m([0, 1, 1])
>>>
>>> x[5]
calculating Fm[5]
calculating Fm[3]
Fm[A=1] = 1, Fm[A+1=2] = 1
back to calculating Fm[3]
Fm[A=2] = 1, Fm[A+1=3] = 2
back to calculating Fm[5]
3
>>>
>>>

Categories