def testPolyint(self): p = pypol.poly1d([4, -3, 4, 1]) py.test.raises(ValueError, lambda: funcs.polyint(ONE, -1)) assert funcs.polyint(ONE) == x assert funcs.polyint(TWO) == 2*x assert funcs.polyint(p) == pypol.poly1d([1, -1, 2, 1, 0]) assert funcs.polyint(p, 2) == funcs.polyint(funcs.polyint(p)) \ == pypol.polynomial('+ 1/5x^5 - 1/4x^4 + 2/3x^3 + 1/2x^2')
def abel(n, variable='a'): ''' Returns the *n-th* Abel polynomial in ``x`` and *variable*. :raises: :exc:`ValueError` if *n* is negative :rtype: :class:`pypol.Polynomial` **Examples** :: >>> abel(0) + 1 >>> abel(1) + x >>> abel(2) + x^2 - 2ax >>> abel(5) + x^5 - 20ax^4 + 150a^2x^3 - 500a^3x^2 + 625a^4x >>> abel(9) + x^9 - 72ax^8 + 2268a^2x^7 - 40824a^3x^6 + 459270a^4x^5 - 3306744a^5x^4 + 14880348a^6x^3 - 38263752a^7x^2 + 43046721a^8x .. versionadded:: 0.3 ''' if n < 0: raise ValueError('Abel polynomials only defined for n >= 0') if n == 0: return ONE if n == 1: return x p = poly1d([n]) return x * (x - p*variable) ** (n - 1)
def quartic(poly): ''' Finds all four roots of a fourth-degree polynomial *poly*:: :raises: :exc:`AssertionError` if the polynomial's degree is not 4 :rtype: 4 numbers (integer, float or complex) in a tuple **Examples** When all the roots are real:: >>> from pypol.roots import * >>> from pypol.funcs import from_roots >>> p = from_roots([1, -4, 2, 3]) >>> p + x^4 - 2x^3 - 13x^2 + 38x - 24 >>> quartic(p) [1, 3.0, -4.0, 2.0] >>> map(p, quartic(p)) [0, 0.0, 0.0, 0.0] >>> p = from_roots([-1, 42, 2, -19239]) >>> p + x^4 + 19196x^3 - 827237x^2 + 769644x + 1616076 >>> quartic(p) [-1, 42.0, -19239.0, 2.0] >>> map(p, quartic(p)) [0, 0.0, 3.0, 0.0] Otherwise, if there are complex roots it loses precision and this is due to floating point numbers:: >>> from pypol import * >>> from pypol.roots import * >>> >>> p = poly1d([1, -3, 4, 2, 1]) >>> p + x^4 - 3x^3 + 4x^2 + 2x + 1 >>> quartic(p) ((1.7399843312651568+1.5686034407060976j), (1.7399843312651568-1.5686034407060976j), (-0.23998433126515695+0.35301727734776445j), (-0.23998433126515695-0.35301727734776445j)) >>> map(p, quartic(p)) [(8.8817841970012523e-16+8.4376949871511897e-15j), (8.8817841970012523e-16-8.4376949871511897e-15j), (8.3266726846886741e-15-2.7755575615628914e-15j), (8.3266726846886741e-15+2.7755575615628914e-15j)] >>> p = poly1d([4, -3, 4, 2, 1]) >>> p + 4x^4 - 3x^3 + 4x^2 + 2x + 1 >>> quartic(p) ((0.62277368382725595+1.0277469284099872j), (0.62277368382725595-1.0277469284099872j), (-0.24777368382725601+0.33425306402324328j), (-0.24777368382725601-0.33425306402324328j)) >>> map(p, quartic(p)) [(-2.5313084961453569e-14+3.730349362740526e-14j), (-2.5313084961453569e-14-3.730349362740526e-14j), (1.354472090042691e-14-1.2101430968414206e-14j), (1.354472090042691e-14+1.2101430968414206e-14j)] **References** `MathWorld <http://mathworld.wolfram.com/QuarticEquation.html>`_ ''' assert poly.degree == 4, 'The polynomial\'s degree must be 4' if len(poly.coefficients) == 5: a, b, c, d, e = poly.coefficients else: a, b, c, d, e = map(getattr(poly, 'get'), [4, 3, 2, 1, 0]) poly = poly1d([a, b, c, d, e]) if not poly(1): roots = [1] roots.extend(cubic(poly / 'x - 1')) return roots if not poly(-1): roots = [-1] roots.extend(cubic(poly / 'x + 1')) return roots #if b == d == 0: # biquadratic ## DECOMMENT THIS? # l = poly.letters[0] # for m in poly.monomials: # m[1][l] = m[1][l] / 2 # print poly # poly_ = poly(x=monomial(z=1)) # return quadratic(poly_) if (a, b) == (0, 0): return quadratic(Polynomial(poly[2:])) if a == 0: return cubic(Polynomial(poly[1:])) poly = poly.div_all(a, int=True) if len(poly.coefficients) == 5: a, b, c, d, e = map(float, poly.coefficients) else: a, b, c, d, e = map(float, map(getattr(poly, 'get'), [4, 3, 2, 1, 0])) f = c - 3*b**2 / 8 g = d + b**3 / 8 - b*c / 2 h = e - 3*b**4 / 256 + b**2 * c / 16 - b*d / 4 y = monomial(y=1) eq = y**3 + (f / 2) * y**2 + ((f**2 - 4*h)/16)*y - g**2 / 64 y1, y2, y3 = cubic(eq) roots = [cmath.sqrt(r) for r in (y1, y2, y3) if isinstance(r, complex)] if len(roots) >= 2: p, q = roots[:2] else: try: p, q = map(math.sqrt, [r for r in (y1, y2, y3) if r][:2]) except ValueError: p, q = map(cmath.sqrt, [r for r in (y1, y2, y3) if r][:2]) r = -g / (8*p*q) s = b / (4*a) x1 = p + q + r - s x2 = p - q - r - s x3 = - p + q - r - s x4 = - p - q + r - s return x1, x2, x3, x4
def cubic(poly): ''' Finds the three roots of the polynomial *poly* solving the equation: :math:`ax^3 + bx^2 + cx + d = 0`. :raises: :exc:`AssertionError` if the polynomial's degree is not 3. :rtype: 3 numbers (integer, float or complex) in a tuple **Examples** :: >>> k = poly1d([3, -2, 45, -1]) >>> k + 3x^3 - 2x^2 + 45x - 1 >>> cubic(k) (0.022243478406449024, (0.3222115941301088+3.8576995055778323j), (0.3222115941301088-3.8576995055778323j)) >>> k = poly1d([-9, 12, -2, -34]) >>> k - 9x^3 + 12x^2 - 2x - 34 >>> cubic(k) (-1.182116114781928, (1.2577247240576306+1.2703952413531459j), (1.2577247240576306-1.2703952413531459j)) >>> k = poly1d([1, 1, 1, 1]) >>> cubic(k) (-1.0, (5.551115123125783e-17+0.9999999999999999j), (5.551115123125783e-17-0.9999999999999999j)) >>> k(-1.) 0.0 >>> k = poly1d([-1, 1, 0, 1]) >>> cubic(k) (1.4655712318767669, (-0.23278561593838348+0.7925519925154489j), (-0.23278561593838348-0.7925519925154489j)) >>> k(cubic(k)[0]) 3.9968028886505635e-15 **References** `Wikipedia <http://en.wikipedia.org/wiki/Cubic_function>`_ | `MathWorld <http://mathworld.wolfram.com/CubicFormula.html>`_ | `1728 <http://www.1728.com/cubic.htm>`_ ''' poly = poly.filter() assert poly.degree == 3, 'The polynomial\'s degree must be 3' if len(poly.coefficients) == 4: a, b, c, d = poly.coefficients else: a, b, c, d = map(getattr(poly, 'get'), [3, 2, 1, 0]) if a == 0: poly = poly1d([a, b, c, d]) return quadratic(poly) f = ((3*c / a) - (b**2 / a**2)) / 3 g = ((2*b**3 / a**3) - (9*b*c / a**2) + (27*d / a)) / 27 h = (g**2 / 4) + (f**3 / 27) if h > 0: # only 1 root is real b_3a = - (b / (3*a)) r = -(g / 2) + math.sqrt(h) if r < 0: s = -((-r) ** (1/3)) else: s = r ** (1/3) t = -(g / 2) - math.sqrt(h) if t < 0: u = - ((-t) ** (1/3)) else: u = t ** (1/3) x1 = (s + u) + b_3a x2 = complex(-(s + u) / 2 + b_3a, (s - u) * math.sqrt(3) / 2) x3 = complex(-(s + u) / 2 + b_3a, -(s - u) * math.sqrt(3) / 2) if poly(x1) and not poly(round(x1)): x1 = round(x1) return x1, x2, x3 if f == g == h == 0: # all 3 roots are real and equal d_a = d / a if d_a < 0: x1 = x2 = x3 = (-d_a) ** (1/3) else: x1 = x2 = x3 = -((d / a) ** (1/3)) x1 = x1*1e14; x1 = round(x1); x1 = (x1/1e14) x2 = x2*1e14; x2 = round(x2); x2 = (x2/1e14) x3 = x3*1e14; x3 = round(x3); x3 = (x3/1e14) return x1, x2, x3 if h <= 0: # all 3 roots are real i = math.sqrt((g**2 / 4) - h) j_ = i ** (1 / 3) k = math.acos(-(g / (2*i))) l = -j_ m = math.cos(k / 3) n = math.sqrt(3) * math.sin(k / 3) p = -(b / (3*a)) x1 = 2*j_ * math.cos(k / 3) + p x2 = l * (m + n) + p x3 = l * (m - n) + p x1 = x1*1e14; x1 = round(x1); x1 = (x1/1e14) x2 = x2*1e14; x2 = round(x2); x2 = (x2/1e14) x3 = x3*1e14; x3 = round(x3); x3 = (x3/1e14) if poly(x1) and not poly(round(x1)): x1 = round(x1) if poly(x2) and not poly(round(x2)): x2 = round(x2) if poly(x3) and not poly(round(x3)): x3 = round(x3) return x1, x2, x3
def testPolyder(self): p = pypol.poly1d([1]*4) assert pypol.poly1d([3, 2, 1]) == funcs.polyder(p) assert pypol.poly1d([6, 2]) == funcs.polyder(p, 2) assert pypol.poly1d([6]) == funcs.polyder(p, 3)
def testDivisible(self): p = pypol.poly1d([2, 6, -4, 8]) * x assert funcs.divisible(p, p.gcd())