Back to SDS/2 Parametric Scripts

"""

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

    def __add__(self, other):

        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

    def __add__(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(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

>>>

"""