"""

Encapsulate Mono-Multinomial equations

"""

class Monomial:

def __init__(self, coefficient, exponentX, exponentY):

self.coeff = coefficient

self.expoX = exponentX

self.expoY = exponentY

def __repr__(self):

if abs(self.coeff) == 1:

coeffStr = ""

else:

coeffStr = '%s' % (abs(self.coeff))

if self.coeff < 0:

preStr = "-"

else:

preStr = "+"

if self.expoX == 0 and self.expoY == 0:

return '%s%s' % (preStr, coeffStr)

elif self.expoX == 0 and self.expoY != 1:

return '%s%s(y^%s)' % (preStr, coeffStr, self.expoY)

elif self.expoY == 0 and self.expoX != 1:

return '%s%s(x^%s)' % (preStr, coeffStr, self.expoX)

elif self.expoX == 1 and self.expoY == 1:

return '%s%s(x*y)' % (preStr, coeffStr)

elif self.expoX == 1 and self.expoY == 0:

return '%s%sx' % (preStr, coeffStr)

elif self.expoX == 0 and self.expoY == 1:

return '%s%sy' % (preStr, coeffStr)

elif self.expoX == 1:

return '%s%s(x*y^%s)' % (preStr, coeffStr, self.expoY)

elif self.expoY == 1:

return '%s%s(x^%s*y)' % (preStr, coeffStr, self.expoX)

return '%s%s(x^%s*y^%s)' % (preStr, coeffStr, self.expoX, self.expoY)

def __lt__(self, other):

return (self.expoX < other.expoX) or ((self.expoX == other.expoX) and (self.expoY < other.expoY))

def __gt__(self,other):

return (self.expoX > other.expoX) or ((self.expoX == other.expoX) and (self.expoY >other.expoY))

# addition method returns a Multinomial object

outMult = None

return simplifyMult(Multinomial(self, Multinomial(other, outMult)))

def __mul__(self, other):

return Monome(self.coeff * other.coeff, self.expoX + other.expoX, self.expoY + other.expoY)

class Multinomial:

def __init__(self,referenceMonomial,refnext):

self.refMon = referenceMonomial

self.next = refnext

sortMult(self)

def __repr__(self):

res = str(self.refMon)

a = self.next

while a:

res += str(a.refMon)

a = a.next

if res[0] == '+':

return res[1:]

return res

def __iter__(self):

m = self

while m:

yield m.refMon

m = m.next

# methods to add and subtract a Monomial and a Multinomial or add two Multinomials

# if adding or subtracting a Monomial, the Multinomial object must appear first in the expression

# format: Multinomial_object + Monomial_object or Multinomial_object + Multinomial_object

if isinstance(other, Monomial):

# if 'Monomial' in str(other.__class__):

outMult = None

for m in iterMult(self):

outMult = Multinomial(m, outMult)

return simplifyMult(Multinomial(other, outMult))

else:

outMult = None

for m in self:

outMult = Multinomial(m, outMult)

for m in other:

outMult = Multinomial(m, outMult)

outMult = simplifyMult(outMult)

if outMult:

return outMult

else:

return 0

def __sub__(self, other):

if isinstance(other, Monomial):

# if 'Monomial' in str(other.__class__):

outMult = None

for m in iterMult(self):

outMult = Multinomial(m, outMult)

return simplifyMult(Multinomial(Monomial(-other.coeff, other.expoX, other.expoY), outMult))

else:

outMult = None

for m in self:

outMult = Multinomial(m, outMult)

for m in other:

outMult = Multinomial(Monomial(-m.coeff, m.expoX, m.expoY), outMult)

outMult = simplifyMult(outMult)

if outMult:

return outMult

else:

return 0

def __mul__(self, other):

outMult = None

for d1 in self:

for d2 in other:

outMult = Multinomial(Monomial(d1.coeff * d2.coeff, d1.expoX + d2.expoX, d1.expoY + d2.expoY), outMult)

return simplifyMult(outMult)

# in-place sort function on Multinomial object in descending order of degree

def sortMult(d):

while d:

if d.next:

d2 = d.next

while d2:

if degre(d2.refMon) > degre(d.refMon):

d.refMon, d2.refMon = d2.refMon, d.refMon

elif degre(d2.refMon) == degre(d.refMon) and d2.refMon.expoX > d.refMon.expoX:

d.refMon, d2.refMon = d2.refMon, d.refMon

elif degre(d2.refMon) == degre(d.refMon) and d2.refMon.expoX == d.refMon.expoX and d2.refMon.coeff > d.refMon.coeff:

d.refMon, d2.refMon = d2.refMon, d.refMon

d2 = d2.next

d = d.next

# return a sorted Multinomial object in descending order of degree

def cmpMult(d):

mList = []

for m in iterMult(d):

mList.append((m.expoX+m.expoY, m.expoX, m.expoY, m.coeff, m))

mList.sort()

outMult = None

for item in mList:

outMult = Multinomial(Monomial(item[3], item[1], item[2]), outMult)

return outMult

# Add new Monomial object to existing Multinomial object and sort in descending order of degree

def insertMonomial(coefficient, exponentX, exponentY, d=None):

return cmpMult(Multinomial(Monomial(coefficient, exponentX, exponentY), d))

# Multinomial iterator

def iterMult(d):

while d:

yield d.refMon

d = d.next

# Simplify a Multinomial object, combine like terms, skip terms with a coefficient of 0

def simplifyMult(d):

dMult = {}

for m in iterMult(d):

if (m.expoX, m.expoY) not in dMult.keys():

dMult[(m.expoX, m.expoY)] = m.coeff

else:

dMult[(m.expoX, m.expoY)] = dMult[(m.expoX, m.expoY)] + m.coeff

outMult = None

for key in dMult.keys():

if abs(dMult[key]) > 0:

outMult = Multinomial(Monomial(dMult[key], key[0], key[1]), outMult)

return cmpMult(outMult)

# Combine 2 Multinomial objects, simplifying Monomials

# Return sorted Multinomial in descending order of degree

def joinMultinomials(d1, d2):

outMult = d1

for m in iterMult(d2):

outMult = Multinomial(m, outMult)

return simplifyMult(outMult)

m1 = Monomial(1,3,7)

m2 = Monomial(-2,4,9)

print 'm1 = %s' % m1

print 'm2 = %s' % m2

print 'm1*m2 = %s' % repr(m1*m2)

d1 = Multinomial(Monomial(5,1,0),Multinomial(Monomial(-8,6,3),Multinomial(Monomial(1,3,7),Multinomial(Monomial(-2,4,9), None))))

d2 = Multinomial(Monomial(5,6,3),Multinomial(Monomial(-8,3,7),Multinomial(Monomial(1,9,5),Multinomial(Monomial(-2,1,0), None))))

d3 = joinMultinomials(d1, d2)

print 'd1 = %s' % d1

print 'd2 = %s' % d2

print 'd3 = %s' % d3

print 'd1+d2 = %s' % repr(d1+d2)

print 'd1-d2 = %s' % repr(d1-d2)

print 'd1-d2 = %s' % repr(d1-d2)

print 'd1*d3 = %s' % repr(d2*d3)

print 'd1-Monomial(7,6,3) = %s' % repr(d1-Monomial(7,6,3))

print 'Monomial(-8,6,3)+Monomial(1,9,5) = %s' % repr(Monomial(-8,6,3)+Monomial(1,9,5))

print

print "Iteration on Monomial object d3 using built-in iteration method (__iter__):"

for m in d3:

print m

print

# 5x^3-3x^2+x-2

d = Multinomial(Monomial(5,3,0),Multinomial(Monomial(-3,2,0),Multinomial(Monomial(1,1,0),Multinomial(Monomial(-2,0,0), None))))

print 'Polynomial to solve using bisection method: %s' % d

def solve(d, vx, vy=1.0):

r = 0.0

for m in iterMult(d):

r += m.coeff*float(vx)**m.expoX*float(vy)**m.expoY

return r

def bisection(d, U, L, e):

if solve(d, U) > 0 and solve(d, L) < 0:

while abs(U - L) > e:

M = (U+L)/2

if solve(d, M)*solve(d,U) > 0:

U = M

else:

L = M

print U, L

return U,L

else:

return "Invalid arguments. f(U) must be > 0 and f(L) must be < 0."

print bisection(d, 1.0, -1.0, 0.00001)

def solve2(s, x, y=1.0):

return eval(s)

s = '5*(x**3)-3*(x**2)+x-2'

print solve2(s, 4.0)

# Output:

"""

>>> m1 = +(x^3*y^7)

m2 = -2(x^4*y^9)

m1*m2 = -2(x^7*y^16)

d1 = 5(x^6*y^3)-8(x^6*y^3)+5x-2x

d2 = (x^9*y^5)-8(x^3*y^7)+5(x^6*y^3)-2x

d3 = (x^9*y^5)-2(x^4*y^9)-7(x^3*y^7)-3(x^6*y^3)+3x

d1+d2 = (x^9*y^5)-8(x^3*y^7)+2(x^6*y^3)+x

d1-d2 = -(x^9*y^5)+8(x^3*y^7)-8(x^6*y^3)+5x

d1-d2 = -(x^9*y^5)+8(x^3*y^7)-8(x^6*y^3)+5x

d1*d3 = (x^18*y^10)-2(x^13*y^14)-15(x^12*y^12)+2(x^15*y^8)+16(x^7*y^16)-10(x^10*y^12)+56(x^6*y^14)\

-11(x^9*y^10)-15(x^12*y^6)+(x^10*y^5)+4(x^5*y^9)-10(x^4*y^7)+21(x^7*y^3)-6(x^2)

d1-Monomial(7,6,3) = -10(x^6*y^3)+3x

Monomial(-8,6,3)+Monomial(1,9,5) = (x^9*y^5)-8(x^6*y^3)

Iteration on Monomial object d3 using built-in iteration method (__iter__):

+(x^9*y^5)

-2(x^4*y^9)

-7(x^3*y^7)

-3(x^6*y^3)

+3x

Polynomial to solve using bisection method: 5(x^3)-3(x^2)+x-2

1.0 0.0

1.0 0.5

1.0 0.75

1.0 0.875

0.9375 0.875

0.90625 0.875

0.890625 0.875

0.890625 0.8828125

0.88671875 0.8828125

0.88671875 0.884765625

0.8857421875 0.884765625

0.88525390625 0.884765625

0.885009765625 0.884765625

0.884887695313 0.884765625

0.884887695313 0.884826660156

0.884857177734 0.884826660156

0.884857177734 0.884841918945

0.884857177734 0.88484954834

(0.884857177734375, 0.88484954833984375)

274.0

>>>

"""