How to calculate sum of two polynomials? - python

For instance 3x^4 - 17x^2 - 3x + 5. Each term of the polynomial can be represented as a pair of integers (coefficient,exponent). The polynomial itself is then a list of such pairs like
[(3,4), (-17,2), (-3,1), (5,0)] for the polynomial as shown.
Zero polynomial, 0, is represented as the empty list [], since it has no terms with nonzero coefficients.
I want to write two functions to add and multiply two input polynomials with the same representation of tuple (coefficient, exponent):
addpoly(p1, p2)
multpoly(p1, p2)
Test Cases:
addpoly([(4,3),(3,0)], [(-4,3),(2,1)])
should give [(2, 1),(3, 0)]
addpoly([(2,1)],[(-2,1)])
should give []
multpoly([(1,1),(-1,0)], [(1,2),(1,1),(1,0)])
should give [(1, 3),(-1, 0)]
Here is something that I started with but got completely struck!
def addpoly(p1, p2):
(coeff1, exp1) = p1
(coeff2, exp2) = p2
if exp1 == exp2:
coeff3 = coeff1 + coeff2

As suggested in the comments, it is much simpler to represent polynomials as multisets of exponents.
In Python, the closest thing to a multiset is the Counter data structure. Using a Counter (or even just a plain dictionary) that maps exponents to coefficients will automatically coalesce entries with the same exponent, just as you'd expect when writing a simplified polynomial.
You can perform operations using a Counter, and then convert back to your list of pairs representation when finished using a function like this:
def counter_to_poly(c):
p = [(coeff, exp) for exp, coeff in c.items() if coeff != 0]
# sort by exponents in descending order
p.sort(key = lambda pair: pair[1], reverse = True)
return p
To add polynomials, you group together like-exponents and sum their coefficients.
def addpoly(p, q):
r = collections.Counter()
for coeff, exp in (p + q):
r[exp] += coeff
return counter_to_poly(r)
(In fact, if you were to stick with the Counter representation throughout, you could just return p + q).
To multiply polynomials, you multiply each term from one polynomial pairwise with every term from the other. And furthermore, to multiply terms, you add exponents and multiply coefficients.
def mulpoly(p, q):
r = collections.Counter()
for (c1, e1), (c2, e2) in itertools.product(p, q):
r[e1 + e2] += c1 * c2
return counter_to_poly(r)

This python code worked for me,hope this works for u too...
Addition func
def addpoly(p1,p2):
i=0
su=0
j=0
c=[]
if len(p1)==0:
#if p1 empty
return p2
if len(p2)==0:
#if p2 is empty
return p1
while i<len(p1) and j<len(p2):
if int(p1[i][1])==int(p2[j][1]):
su=p1[i][0]+p2[j][0]
if su !=0:
c.append((su,p1[i][1]))
i=i+1
j=j+1
elif p1[i][1]>p2[j][1]:
c.append((p1[i]))
i=i+1
elif p1[i][1]<p2[j][1]:
c.append((p2[j]))
j=j+1
if p1[i:]!=[]:
for k in p1[i:]:
c.append(k)
if p2[j:]!=[]:
for k in p2[j:]:
c.append(k)
return c
Multiply func
def multipoly(p1,p2):
p=[]
s=0
for i in p1:
c=[]
for j in p2:
s=i[0]*j[0]
e=i[1]+j[1]
c.append((s,e))
p=addpoly(c,p)
return p

I have come up with a solution but I'm unsure that it's optimized!
def addpoly(p1,p2):
for i in range(len(p1)):
for item in p2:
if p1[i][1] == item[1]:
p1[i] = ((p1[i][0] + item[0]),p1[i][1])
p2.remove(item)
p3 = p1 + p2
for item in (p3):
if item[0] == 0:
p3.remove(item)
return sorted(p3)
and the second one:-
def multpoly(p1,p2):
for i in range(len(p1)):
for item in p2:
p1[i] = ((p1[i][0] * item[0]), (p1[i][1] + item[1]))
p2.remove(item)
return p1

Related

Find the possible states to make the result of the Bitwise OR answer

For example if you have a1 | a2 = 0011 so the possible states for a1 and a2 are => result = [ (0000,0011) , (0001,0010) , (0001,0011) ]
and a1 < a2.
Our numbers are not necessarily 4-bit, they can be more.
I mean, you have the answer of Bitwise OR and you are looking for all possible states for a2, a1 (in binary).
Could you help me how to find all possible states in python? Thank you.
If I understand you right, the following itertools-based solution should work:
from itertools import product
def or_factors(bits):
bit_pairs = [[('0','0')] if i == '0' else [('0','1'),('1','0'),('1','1')] for i in bits]
num_pairs = product(*bit_pairs)
factors = []
for pair in num_pairs:
a = ''
b = ''
for s,t in pair:
a += s
b += t
if a < b: factors.append((a,b))
return factors
print(or_factors('0011'))
#[('0000', '0011'), ('0001', '0010'), ('0001', '0011'), ('0010', '0011')]
The program is independent from the amount of bits of the matching result. A decimal to binary approach.
from itertools import combinations
def int2bin_str(n, N=4):
return f"{int(bin(n), 2):0{N}b}"
def int2bin_str_OR(n1, n2, N=4):
return f"{int(bin(n1), 2) | int(bin(n2), 2):0{N}b}"
res = "0011"
combs = []
N = len(res)
max_b = 2**N - 1 # maximal binary out of N-bits
for n1, n2 in combinations(range(max_b+1), r=2):
if int2bin_str_OR(n1, n2, N=N) == res:
combs.append((int2bin_str(n1, N=N), int2bin_str(n2, N=N)))
print(combs)
Notice that combinations returns already ordered tuples.
A bit computational expensive but versatile: to get the "inputs" of another bitwise operation just add a new function like this
def int2bin_str_AND(n1, n2, N=4):
return f"{int(bin(n1), 2) & int(bin(n2), 2):0{N}b}"

Determining if there exists numbers n1, n2 in a, b and n3 in c such that n1 + n2 = n3 [ftt, polynomial multiplication]

Hello I am working on a problem that seems to be out of my league so any tips, pointers to reading materials etc. are really appreciated. That being said here is the problem:
given 3 subsets of numbers a, b, c ⊆ {0, ..., n}. In nlog(n) check if there exists numbers n1, n2 in a, b and n3 in c where n1 + n2 = n3.
I am given the hint to convert a and b to polynomial coefficients and to use polynomial multiplication using ftt to multiply the coefficients of a and b.
Now where I am stuck is after getting the result of the polynomial multiplication, what do I do next?
Thank you in advanced.
from numpy.fft import fft, ifft
from numpy import real, imag
def polynomial_multiply(a_coeff_list, b_coeff_list):
# Return the coefficient list of the multiplication
# of the two polynomials
# Returned list must be a list of floating point numbers.
# list from complex to reals by using the
# real function in numpy
len_a = len(a_coeff_list)
len_b = len(b_coeff_list)
for i in range(len_a-1):
b_coeff_list.append(0)
for i in range(len_b-1):
a_coeff_list.append(0)
a_fft = fft(a_coeff_list)
b_fft = fft(b_coeff_list)
c = []
for i in range(len(a_fft)):
c.append(a_fft[i] * b_fft[i])
inverse_c = ifft(c)
return real(inverse_c)
# inputs sets a, b, c
# return True if there exist n1 in a, n2 in B such that n1+n2 in C
# return False otherwise
# number n which signifies the maximum number in a, b, c
def check_sum_exists(a, b, c, n):
a_coeffs = [0]*n
b_coeffs = [0]*n
# convert sets a, b into polynomials as provided in the hint
# a_coeffs and b_coeffs should contain the result
i = 0
for item in a:
a_coeffs[i] = item
i += 1
i = 0
for item in b:
b_coeffs[i] = item
i += 1
# multiply them together
c_coeffs = polynomial_multiply(a_coeffs, b_coeffs)
# now this is where i am lost
# how to determine with c_coeffs?
return False
# return True/False
Thanks to all who helped. I figured it out and hopefully this can help anyone who runs into a similar problem. The issue I had was I incorrectly assigned the coefficients for a_coeffs and b_coeffs.
Here is the solution which passed the tests for those interested.
from numpy.fft import fft, ifft
from numpy import real, imag
def check_sum_exists(a, b, c, n):
a_coeffs = [0] * n
b_coeffs = [0] * n
# convert sets a, b into polynomials as provided in the hint
# a_coeffs and b_coeffs should contain the result
for coeff in a:
a_coeffs[coeff] = 1
for coeff in b:
b_coeffs[coeff] = 1
# multiply them together
c_coeffs = polynomial_multiply(a_coeffs, b_coeffs)
# use the result to solve the problem at hand
for coeff in c:
if c_coeffs[coeff] >= .5:
return True
return False
# return True/False
def polynomial_multiply(a_coeff_list, b_coeff_list):
# Return the coefficient list of the multiplication
# of the two polynomials
# Returned list must be a list of floating point numbers.
# Please convert list from complex to reals by using the
# real function in numpy.
for i in range(len(a_coeff_list) - 1):
b_coeff_list.append(0)
for i in range(len(b_coeff_list) - 1):
a_coeff_list.append(0)
a_fft = fft(a_coeff_list)
b_fft = fft(b_coeff_list)
c = []
for i in range(len(a_fft)):
c.append(a_fft[i] * b_fft[i])
return real(ifft(c))

Recurrent sequence task

Given the sequence f0, f1, f2, ... given by the recurrence relations f0 = 0, f1 = 1, f2 = 2 and fk = f (k-1) + f (k-3)
Write a program that calculates the n elements of this sequence with the numbers k1, k2, ..., kn.
Input format
The first line of the input contains an integer n (1 <= n <= 1000)
The second line contains n non-negative integers ki (0 <= ki <= 16000), separated by spaces.
Output format
Output space-separated values ​​for fk1, fk2, ... fkn.
Memory Limit: 10MB
Time limit: 1 second
The problem is that the recursive function at large values ​​goes beyond the limit.
def f (a):
    if a <= 2:
        return a
    return f (a - 1) + f (a - 3)
n = int (input ())
nums = list (map (int, input (). split ()))
for i in range (len (nums)):
    if i <len (nums) - 1:
        print (f (nums [i]), end = '')
    else:
        print (f (nums [i]))
I also tried to solve through a cycle, but the task does not go through time (1 second):
fk1 = 0
fk2 = 0
fk3 = 0
n = int (input ())
nums = list (map (int, input (). split ()))
a = []
for i in range (len (nums)):
    itog = 0
    for j in range (1, nums [i] + 1):
        if j <= 2:
            itog = j
        else:
            if j == 3:
                itog = 0 + 2
                fk1 = itog
                fk2 = 2
                fk3 = 1
            else:
                itog = fk1 + fk3
                fk1, fk2, fk3 = itog, fk1, fk2
    if i <len (nums) - 1:
        print (itog, end = '')
    else:
        print (itog)
How else can you solve this problem so that it is optimal in time and memory?
Concerning the memory, the best solution probably is the iterative one. I think you are not far from the answer. The idea would be to first check for the simple cases f(k) = k (ie, k <= 2), for all other cases k > 2 you can simply compute fi using (fi-3, fi-2, fi-1) until i = k. What you need to do during this process is indeed to keep track of the last three values (similar to what you did in the line fk1, fk2, fk3 = itog, fk1, fk2).
On the other hand, there is one thing that you need to do here. If you just perform computations of fk1, fk2, ... fkn independently, then you are screwed (unless you use a super fast machine or a Cython implementation). On the other hand, there is no reason to perform n independent computations, you can just compute fx for x = max(k1, k2, ..., kn) and on the way you'll store every answer for fk1, fk2, ..., fkn (this will slow down the computation of fx by a little bit, but instead of doing this n times you'll do it only once). This way it can be solved under 1s even for n = 1000.
On my machine, independent calculations for f15000, f15001, ..., f16000 takes roughly 30s, the "all at once" solution takes roughly 0.035s.
Honestly, that's not such an easy exercise, it would be interesting to show your solution on a site like code review to get some feedback on your solution once you found one :).
First, you have to sort the numbers. Then calculate values of the sequence one by one:
while True:
a3 = a2 + a0
a0 = a3 + a1
a1 = a0 + a2
a2 = a1 + a3
Lastly, return values in beginning order. To do that you have to remember position of every number. From [45, 22, 14, 33] make [[45,0], [22,1], [14,2], [33,3]] and then sort, calculate values and change them with argument [[f45,0], [f22,1], [f14,2], [f33,3]], then sort by second value.

compare 2 strings for common substring

i wish to find longest common substring of 2 given strings recursively .i have written this code but it is too inefficient .is there a way i can do it in O(m*n) here m an n are respective lengths of string.here's my code:
def lcs(x,y):
if len(x)==0 or len(y)==0:
return " "
if x[0]==y[0]:
return x[0] + lcs(x[1:],y[1:])
t1 = lcs(x[1:],y)
t2 = lcs(x,y[1:])
if len(t1)>len(t2):
return t1
else:
return t2
x = str(input('enter string1:'))
y = str(input('enter string2:'))
print(lcs(x,y))
You need to memoize your recursion. Without that, you will end up with an exponential number of calls since you will be repeatedly solving the same problem over and over again. To make the memoized lookups more efficient, you can define your recursion in terms of the suffix lengths, instead of the actual suffixes.
You can also find the pseudocode for the DP on Wikipedia.
Here is a naive non-recursive solution which uses the powerset() recipe from itertools:
from itertools import chain, combinations, product
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
def naive_lcs(a, b):
return ''.join(max(set(powerset(a)) & set(powerset(b)), key=len))
It has problems:
>>> naive_lcs('ab', 'ba')
'b'
>>> naive_lcs('ba', 'ab')
'b'
There can be more than one solution for some pairs of strings, but my program picks one arbitrarily.
Also, since any of the combinations can be the longest common one, and since calculating these combinations takes O(2 ^ n) time, this solution doesn't compute in O(n * m) time. With Dynamic Programming and memoizing OTOH we can find a solution that, in theory, should perform better:
from functools import lru_cache
#lru_cache()
def _dynamic_lcs(xs, ys):
if not (xs and ys):
return set(['']), 0
elif xs[-1] == ys[-1]:
result, rlen = _dynamic_lcs(xs[:-1], ys[:-1])
return set(each + xs[-1] for each in result), rlen + 1
else:
xlcs, xlen = _dynamic_lcs(xs, ys[:-1])
ylcs, ylen = _dynamic_lcs(xs[:-1], ys)
if xlen > ylen:
return xlcs, xlen
elif xlen < ylen:
return ylcs, ylen
else:
return xlcs | ylcs, xlen
def dynamic_lcs(xs, ys):
result, _ = _dynamic_lcs(xs, ys)
return result
if __name__ == '__main__':
seqs = list(powerset('abcde'))
for a, b in product(seqs, repeat=2):
assert naive_lcs(a, b) in dynamic_lcs(a, b)
dynamic_lcs() also solves the problem that some pairs strings can have multiple common longest sub-sequences. The result is the set of these, instead of one string. Finding the set of all common sub-sequences though is still of exponential complexity.
Thanks to Pradhan for reminding me of Dynamic Programming and memoization.

Evaluating Polynomial coefficients

I'm trying to write a function that takes as input a list of coefficients (a0, a1, a2, a3.....a n) of a polynomial p(x) and the value x. The function will return p(x), which is the value of the polynomial when evaluated at x.
A polynomial of degree n with coefficient a0, a1, a2, a3........an is the function
p(x)= a0+a1*x+a2*x^2+a3*x^3+.....+an*x^n
So I'm not sure how to attack the problem. I'm thinking that I will need a range but how can I make it so that it can handle any numerical input for x? I'm not expecting you guys to give the answer, I'm just in need of a little kick start. Do I need a for loop, while loop or could recursive be an option here?
def poly(lst, x)
I need to iterate over the items in the list, do I use the indices for that, but how can I make it iterate over an unknown number of items?
I'm thinking I can use recursion here:
def poly(lst, x):
n = len(lst)
If n==4:
return lst[o]+lst[1]*x+lst[2]*x**2+lst[3]*x**3
elif n==3:
return lst[o]+lst[1]*x+lst[2]*x**2
elif n==2:
return lst[o]+lst[1]*x
elif n==1:
return lst[o]
else:
return lst[o]+lst[1]*x+lst[2]*x**2+lst[3]*x**3+lst[n]*x**n
This works for n<=4 but I get a index error: list index out of range for n>4, can't see why though.
The most efficient way is to evaluate the polynomial backwards using Horner's Rule. Very easy to do in Python:
# Evaluate a polynomial in reverse order using Horner's Rule,
# for example: a3*x^3+a2*x^2+a1*x+a0 = ((a3*x+a2)x+a1)x+a0
def poly(lst, x):
total = 0
for a in reversed(lst):
total = total*x+a
return total
simple:
def poly(lst, x):
n, tmp = 0, 0
for a in lst:
tmp = tmp + (a * (x**n))
n += 1
return tmp
print poly([1,2,3], 2)
simple recursion:
def poly(lst, x, i = 0):
try:
tmp = lst.pop(0)
except IndexError:
return 0
return tmp * (x ** (i)) + poly(lst, x, i+1)
print poly([1,2,3], 2)
def evalPoly(lst, x):
total = 0
for power, coeff in enumerate(lst): # starts at 0 by default
total += (x**power) * coeff
return total
Alternatively, you can use a list and then use sum:
def evalPoly(lst, x):
total = []
for power, coeff in enumerate(lst):
total.append((x**power) * coeff)
return sum(total)
Without enumerate:
def evalPoly(lst, x):
total, power = 0, 0
for coeff in lst:
total += (x**power) * coeff
power += 1
return total
Alternative to non-enumerate method:
def evalPoly(lst, x):
total = 0
for power in range(len(lst)):
total += (x**power) * lst[power] # lst[power] is the coefficient
return total
Also #DSM stated, you can put this together in a single line:
def evalPoly(lst, x):
return sum((x**power) * coeff for power, coeff in enumerate(lst))
Or, using lambda:
evalPoly = lambda lst, x: sum((x**power) * coeff for power, coeff in enumerate(lst))
Recursive solution:
def evalPoly(lst, x, power = 0):
if power == len(lst): return (x**power) * lst[power]
return ((x**power) * lst[power]) + evalPoly(lst, x, power + 1)
enumerate(iterable, start) is a generator expression (so it uses yield instead of return that yields a number and then an element of the iterable. The number is equivalent to the index of the element + start.
From the Python docs, it is also the same as:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1
Either with recursion, or without, the essence of the solution is to create a loop on "n", because the polynomial starts at x^0 and goes up to a_n.x^n and that's the variable you should also consider as an input. Besides that, use a trick called multiply and accumulate to be able to calculate partial results on each loop iteration.
def evalPoly(lst, x, power):
if power == 0:
return lst[power]
return ((x**power) * lst[power]) + evalPoly(lst, x, power - 1)
lst = [7, 1, 2, 3]
x = 5
print(evalPoly(lst, x, 3))
Equation to evaluate is - 3x^3 + 2x^2 + x + 7
when x = 5, result is - 437

Categories

Resources