-1

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)])) 
Georgy
  • 12,464
  • 7
  • 65
  • 73
  • Why reinventing the wheel? NumPy has a Polynomial module: https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.polynomials.polynomial.html. Also, take a look at SymPy: https://docs.sympy.org/latest/modules/polys/reference.html – Georgy Sep 13 '18 at 09:55

4 Answers4

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
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
0

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.

Madhusudan chowdary
  • 543
  • 1
  • 12
  • 20
0

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
VanTan
  • 617
  • 4
  • 12
0

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)]
gboffi
  • 22,939
  • 8
  • 54
  • 85