Add and Multiplication of Polynomials in Python - python-3.x

I want to add and multiply two polynomials. A function takes two arguments like add([(4,3),(3,0)],[(-4,3),(2,1)]).So, the polynomial looks like
4x^3 + 3 and -4x^3 + 2x
I want to add and multiply both these two polynomials without using any library.

I have created a simplified version for both addition and multiplication by creating a blank list that can store the coefficients from constant terms to the co-eff of highest exponents. The logic is simply to update the coefficients and creating a list containing tuple pairs of the format (co-eff, exponent)
def add(p1,p2):
x = [0]*(max(p1[0][1],p2[0][1])+1)
for i in p1+p2:
x[i[1]]+=i[0]
res = [(x[i],i) for i in range(len(x)) if x[i]!=0]
res.sort(key = lambda r: r[1], reverse= True)
return res
def mul(p1,p2):
x = [0]*(p1[0][1]*p2[0][1]+1)
for i in p1:
for j in p2:
x[i[1]+j[1]]+=i[0]*j[0]
res = [(x[i],i) for i in range(len(x)) if x[i]!=0]
res.sort(key = lambda r: r[1], reverse= True)
return res
pls note that this code works only for non negative exponents
addition and multiplication of the polynomials you referred in the question yields the following results
add([(4,3),(3,0)],[(-4,3),(2,1)]) = [(2, 1), (3, 0)]
mul([(4,3),(3,0)],[(-4,3),(2,1)]) = [(-16, 6), (8, 4), (-12, 3), (6, 1)]

For addition I have written a method
def poly_add( x, y):
r = []
min_len = min( len(x), len(y))
for i in range(min_len):
if x[i][1] == y[i][1]:
m = x[i][0] + y[i][0]
if m != 0:
r.append((m, x[i][1]))
if x[i][1] != y[i][1]:
r.append((y[i]))
r.append((x[i]))
return r

Related

Numpy Vectorization for Nested 'for' loop

I was trying to write a program which plots level set for any given function.
rmin = -5.0
rmax = 5.0
c = 4.0
x = np.arange(rmin,rmax,0.1)
y = np.arange(rmin,rmax,0.1)
x,y = np.meshgrid(x,y)
f = lambda x,y: y**2.0 - 4*x
realplots = []
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if abs(f(x[i,j],y[i,j])-c)< 1e-4:
realplots.append([x[i,j],y[i,j]])`
But it being a nested for loop, is taking lot of time. Any help in vectorizing the above code/new method of plotting level set is highly appreciated.(Note: The function 'f' will be changed at the time of running.So, the vectorization must be done without considering the function's properties)
I tried vectorizing through
ans = np.where(abs(f(x,y)-c)<1e-4,np.array([x,y]),[0,0])
but it was giving me operands could not be broadcast together with shapes (100,100) (2,100,100) (2,)
I was adding [0,0] as an escape from else condition in np.where which is indeed wrong.
Since you get the values rather than the indexes, you don't really need np.where.
You can directly use the mask to index x and y, look at the "Boolean array indexing" section of the documentation.
It is straightforward:
def vectorized(x, y, c, f, threshold):
mask = np.abs(f(x, y) - c) < threshold
x, y = x[mask], y[mask]
return np.stack([x, y], axis=-1)
Your function for reference:
def op(x, y, c, f, threshold):
res = []
for i in range(x.shape[0]):
for j in range(x.shape[1]):
if abs(f(x[i, j], y[i, j]) - c) < threshold:
res.append([x[i, j], y[i, j]])
return res
Tests:
rmin, rmax = -5.0, +5.0
c = 4.0
threshold = 1e-4
x = np.arange(rmin, rmax, 0.1)
y = np.arange(rmin, rmax, 0.1)
x, y = np.meshgrid(x, y)
f = lambda x, y: y**2 - 4 * x
res_op = op(x, y, c, f, threshold)
res_vec = vectorized(x, y, c, f, threshold)
assert np.allclose(res_op, res_vec)

Comparing two methods to get the same array

np.random.seed(123456)
X = np.random.normal(0,1,1000)
Y = np.random.normal(0,1,1000)
Z = np.random.normal(0.5, 1.7,1000)
W = np.random.normal(0,1,1000)
stream_A = np.concatenate((X,Y,Z,W))
Then I am running the code below: Basically I need to create a iterator to feed one sample at a time to another function.
# 4 chunks of 1000 samples, so X,Y,W and Z arrays
n = 4
iter_array = iter(stream_A) # Size 4000
result = [[] for _ in range(n)]
for _ in itertools.repeat(None, 1000):
for i in range(n):
result[i].append(next(iter_array))
The problem is:
results[0] is a list with all elements of stream X defined above.
If a compare results[0] == X I get false
If I transform the list into np.array:
y=np.array([np.array(xi) for xi in result], dtype=object)
and then:
y[0] == X I also get false
Can someone help me why I am getting False?
And they are somehow not same because the results I am getting when I apply X to the function is not the same of them result when I apply y[0] to the same function.
Just stack them:
stream_A = np.stack((X,Y,Z,W))
stream_A.shape
# (4, 1000)
np.all(stream_A[0] == X)
# True

recursive function for compare two tuples and return one tuple with no repetitions

I've tried everything, but I can't make this function work at all. At least not the way I want.
def uniao(x, y):
a = list(x)
b = list(y)
i = len(a)-1
j = len(b)-1
if a == b:
return tuple(a) + tuple(b)
else:
if b[j] != a[i]:
a.append(b[j])
return uniao(a, b)
else:
return tuple(a)
print(uniao((1, 2, 3), (2, 4, 5)))
This is where I approached the result, but it should be '12345'.
Does this rewrite of your function do what you want:
def uniao(x, y):
if not y:
return x
head, *tail = y
if head not in x:
x += (head,)
return uniao(x, tail)
print(uniao((1, 2, 3), (2, 4, 5)))
Or are there more rules to this puzzle?

PyMC3 variable dependent on result of another

I am implementing a MCMC simulation for the first time and I have a variable that is defined based on the result of a previous variable. For instance if my bernoulli variable returns a 0, there will be a different value that gets fed into a deterministic variable than if it returns a 1.
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
if x == 1:
y = 1
elif x == 0:
y = 2
z = pm.Deterministic('z', y * 1000)
My issue is that neither of these if statements will get entered because x is not an integer, it is a distribution. Is there a way to get the sampled values of x? Or am I just thinking about this wrong?
You are right, you should use Theano's function switch
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
y = pm.math.switch(x, 1, 0)
z = pm.Deterministic('z', y * 1000)
or a little bit more verbose
with pm.Model() as model:
x = pm.Bernoulli('x', .5)
y = pm.math.switch(pm.math.eq(x, 1), 1, 0)
z = pm.Deterministic('z', y * 1000)
switch evaluates the first argument, if true returns the second argument, otherwise the third one.
You can also use more than one switch if you have more than two conditions.
with pm.Model() as model:
x = pm.DiscreteUniform('x', 0, 2)
y_ = pm.math.switch(pm.math.eq(x, 1), 1, 0)
y = pm.math.switch(pm.math.eq(x, 2), 2, y_)
z = pm.Deterministic('z', y * 1000)

Getting the wrong output (Ramanujan)

Essentially what I want the function to do is this:
Take an integer input and save it as n
Print a list of vectors with two entries (a,b), where
For example, when I input n = 443889, I should get an output of [(76,17),(38,73)], because the only two solutions to this problem are: , and
But with my code, when I give the input n=443889, I get the output [(76, 17), (75, 28), (74, 34), (73, 38), (72, 41)], even though some of these vectors doesn't give a solution to my equation.
def ramanujans(n):
lista = []
counter = 0
for a in range(1,n):
b = (n- (a**3))**(1/3)
result = a**3 + b**3
if isinstance(b,complex):
break
elif result == n:
b = int(round(b))
lista.insert(0,(a, b))
return (lista)
with a little different checking for complex results and a different check if result == n (integer comparison only) i seem to be getting the correct results:
def ramanujans(n):
res = []
for a in range(1, n):
s = n - a**3
if s < 0:
break
b = round(s**(1/3))
result = a**3 + b**3
if result == n:
res.append((a, b))
return res
with:
[(17, 76), (38, 73), (73, 38), (76, 17)]
as results for n=443889
you could stop the loop earlier; if a is around (n/2)**(1/3) you just get the results you already have with the a and b interchanged; this could then look like (did not carefully check the edge cases...):
from math import ceil
def ramanujans(n):
res = []
limit = ceil(((n/2)**(1/3)))
for a in range(1, limit+1):
s = n - a**3
b = round(s**(1/3))
result = a**3 + b**3
if result == n:
if a <= b: # this is to cover the edge cases...
res.append((a, b))
return res
print(ramanujans(n=443889)) # [(17, 76), (38, 73)]
print(ramanujans(n=2000)) # [(10, 10)]
print(ramanujans(n=1729)) # [(1, 12), (9, 10)]
and would only return 'half' the results.

Resources