Reversed Polynomials
Hello! I'd like to propose to add a **reverse: boolean = False** argument to the polynomial functions _polynomial_eval_, _polynomial_from_roots_ and _polynomial_derivative_, so they can also handle polynomials with coefficients ordered from lowest to highest degree (Little-endian notation) when such argument is set to True. Defaulting it to False would ensure backwards compatibility.
The current implementation of polynomials follows the Big-endian notation where the coefficient of highest degree comes first. For some cases, the reverse order could make some calculations easier as there would be a direct correspondence between the iterable index and the power of x, that is, instead of representing the polynomial:
x³ ‐ 4 x² ‐ 17 x + 60 as [1, -4, -17, 60], it could be reordered (60 - 17 x - 4 x² + x³) as [60, -17, -4, 1].
Code implementation
I have succesfully tested the code with minimal modifications:
def polynomial_from_roots(roots, reverse=False):
"""Compute a polynomial's coefficients from its roots.
>>> roots = [5, -4, 3] # (x - 5) * (x + 4) * (x - 3)
>>> polynomial_from_roots(roots) # x³ - 4 x² - 17 x + 60
[1, -4, -17, 60]
>>> roots = [5, -4, 3] # (x - 5) * (x + 4) * (x - 3)
>>> polynomial_from_roots(roots, reverse=True) # + 60 - 17 x - 4 x² + x³
[60, -17, -4, 1]
Supports all numeric types: int, float, complex, Decimal, Fraction.
"""
# This recipe differs from the one in itertools docs in that it
# applies list() after each call to convolve(). This avoids
# hitting stack limits with nested generators.
poly = [1]
if reverse:
for root in roots:
poly = list(convolve(poly, (-root, 1)))
return poly
for root in roots:
poly = list(convolve(poly, (1, -root)))
return poly
def polynomial_eval(coefficients, x, reverse=False):
"""Evaluate a polynomial at a specific value.
Computes with better numeric stability than Horner's method.
Evaluate ``x³ - 4 x² - 17 x + 60`` at ``x = 2.5``:
>>> coefficients = [1, -4, -17, 60]
>>> polynomial_eval(coefficients, x=2.5)
8.125
>>> coefficients = [60, -17, -4, 1]
>>> polynomial_eval(coefficients, x=2.5, reverse=True)
8.125
Supports all numeric types: int, float, complex, Decimal, Fraction.
"""
n = len(coefficients)
if n == 0:
return type(x)(0)
powers = map(pow, repeat(x), range(n) if reverse else reversed(range(n)))
return _sumprod(coefficients, powers)
def polynomial_derivative(coefficients, reverse=False):
"""Compute the first derivative of a polynomial.
Evaluate the derivative of ``x³ - 4 x² - 17 x + 60``:
>>> coefficients = [1, -4, -17, 60]
>>> polynomial_derivative(coefficients)
[3, -8, -17]
>>> coefficients = [60, -17, -4, 1]
>>> polynomial_derivative(coefficients, reverse=True)
[-17, -8, 3]
Supports all numeric types: int, float, complex, Decimal, Fraction.
"""
n = len(coefficients)
if reverse:
powers = range(n)
return list(map(mul, coefficients, powers))[1:]
powers = reversed(range(1, n))
return list(map(mul, coefficients, powers))
Practical example
- One example leveraging this rearrangement could be this alternative way to calculate a polynomial derivative:
d( 60 - 17 x - 4 x² + x³ )/dx = - 17 - 8 x + 3x²
print(list(reversed(more_itertools.polynomial_derivative(
list(reversed([60, -17, -4, 1]))
)))) # [-17, -8, 3]
index = itertools.count(1)
print(list(more_itertools.difference(
[60, -17, -4, 1],
func=lambda x, _: x*next(index),
initial=0
))) # [-17, -8, 3]
Thank you
Thank you very much for considering this idea. If I can help in any way to clarify it any further, just let me know.
Best Regards.
Reversed Polynomials
Hello! I'd like to propose to add a
**reverse: boolean = False**argument to the polynomial functions_polynomial_eval_,_polynomial_from_roots_and_polynomial_derivative_, so they can also handle polynomials with coefficients ordered from lowest to highest degree (Little-endian notation) when such argument is set to True. Defaulting it to False would ensure backwards compatibility.The current implementation of polynomials follows the Big-endian notation where the coefficient of highest degree comes first. For some cases, the reverse order could make some calculations easier as there would be a direct correspondence between the iterable index and the power of x, that is, instead of representing the polynomial:
x³ ‐ 4 x² ‐ 17 x + 60 as
[1, -4, -17, 60], it could be reordered (60 - 17 x - 4 x² + x³) as[60, -17, -4, 1].Code implementation
I have succesfully tested the code with minimal modifications:
Practical example
d( 60 - 17 x - 4 x² + x³ )/dx = - 17 - 8 x + 3x²
Thank you
Thank you very much for considering this idea. If I can help in any way to clarify it any further, just let me know.
Best Regards.