NAME

Sidef::Types::Number::Polynomial - Polynomial type supporting symbolic manipulation and algebraic operations.

DESCRIPTION

This class implements univariate polynomials with arbitrary-precision coefficients. Polynomials are represented as mathematical expressions in a single variable (x), supporting arithmetic, evaluation, differentiation, root-finding, and algebraic manipulation.

Internally, polynomials are stored as a sparse hash mapping integer exponents to their coefficients (Sidef::Types::Number::Number objects). Terms with a zero coefficient are never stored, making the representation efficient for sparse polynomials with many zero terms.

SYNOPSIS

# Constructors
var a = Polynomial(5)                  # monomial x^5
var b = Polynomial([1, 2, 3, 4])       # x^3 + 2*x^2 + 3*x + 4
var c = Polynomial(5 => 3, 2 => 10)    # 3*x^5 + 10*x^2
var d = Polynomial("x^3 - 2*x + 1")    # parsed from string

# Arithmetic
var sum  = (b + c)                     # polynomial addition
var prod = (b * c)                     # polynomial multiplication
var quot = (b / c)                     # polynomial division

# Evaluation
say(b.eval(2))                         # evaluate at x=2: 26

# Algebraic operations
say(b.derivative)                      # 3*x^2 + 4*x + 3
say(b.roots)                           # numerical roots
say(b.gcd(c))                          # greatest common divisor

COEFFICIENT ORDER IN ARRAY CONSTRUCTORS

When building a polynomial from an array, coefficients are supplied in descending degree order (highest-degree first):

Polynomial([a_n, a_{n-1}, ..., a_1, a_0])
# represents: a_n*x^n + a_{n-1}*x^{n-1} + ... + a_1*x + a_0

Examples:

Polynomial([1, 2, 3])      # x^2 + 2*x + 3   (NOT 3*x^2 + 2*x + 1)
Polynomial([1, 0, -1])     # x^2 - 1
Polynomial([1, 0, 0, 1])   # x^3 + 1

Individual array elements may also be [exponent, coefficient] pairs to set a coefficient at an explicit degree:

Polynomial([[3, 2], [1, 5]])   # 2*x^3 + 5*x

INHERITS

Inherits methods from Sidef::Types::Number::Number.

CONSTRUCTION

new

Polynomial(n)
Polynomial([c_n, ..., c_1, c_0])
Polynomial("expression")
Polynomial(exp1 => coeff1, exp2 => coeff2, ...)
self.new(value)

Constructs a new Polynomial object. The following calling forms are supported:

Monomial — a single Number argument n: creates the monomial x^n.
Polynomial(5)    # x^5
Polynomial(0)    # x^0 = 1
Array — a single array-ref argument: coefficients in descending degree order.
Polynomial([1, 2, 3])    # x^2 + 2*x + 3

Array elements may themselves be [exponent, coeff] pairs for explicit placement:

Polynomial([[2, 1], [0, 3]])   # x^2 + 3
String — a single string argument: parses an algebraic expression. Supports terms of the form [±][coefficient[/denominator]*]x[^exponent], as well as fraction syntax (numerator)/(denominator).
Polynomial("3*x^2 + 2*x + 1")   # 3*x^2 + 2*x + 1
Polynomial("x^3 - 5")           # x^3 - 5
Polynomial("1/2*x^2 + 3/4")     # (1/2)*x^2 + 3/4

A string that can't be parsed in full returns the constant polynomial NaN, rather than raising an error.

Sparse key-value pairs — alternating exponent/coefficient arguments:
Polynomial(5 => 3, 2 => 10)   # 3*x^5 + 10*x^2
Polynomial(0 => 7)            # constant 7

Zero coefficients are silently dropped. If the same exponent is given more than once, only the last value for that exponent is kept.

Instance call with one argument — when called as a method on an existing polynomial, evaluates that polynomial at the given value (equivalent to "eval"):
var p = Polynomial([1, 0, -1])   # x^2 - 1
say(p.new(3))                    # 3^2 - 1 = 8

Aliases: call

with_value

self.with_value(value)

Creates a new constant polynomial holding just value (equivalent to Polynomial(0 = value)>), discarding the receiver's own terms entirely. Useful in generic code that has a Polynomial in hand and wants to build a plain scalar-valued polynomial of the same type.

var p = Polynomial([1, 2, 3])
say(p.with_value(7))    # 7

ARITHMETIC OPERATIONS

add

a + b

Returns the sum of a and b. When both arguments are polynomials, corresponding coefficients are added. When b is a scalar, it is added to the constant term (x^0 coefficient), inserting it if absent.

say(Polynomial([1, 2]) + Polynomial([3, 4]))   # 4*x + 6

Aliases: +

sub

a - b

Returns the difference a - b. When both arguments are polynomials, corresponding coefficients are subtracted. When b is a scalar, it is subtracted from the constant term, inserting a negated term if absent.

say(Polynomial([1, 2, 3]) - Polynomial([0, 1]))   # x^2 + x + 3

Aliases: -

mul

a * b

Returns the product of a and b. When both are polynomials, performs full polynomial multiplication (convolution of coefficients): the degree of the result equals deg(a) + deg(b). When b is a scalar, each coefficient is multiplied by b.

say(Polynomial([1, 2, 3]) * Polynomial([4, 5])) # (x^2 + 2*x + 3) * (4*x + 5) = 4*x^3 + 13*x^2 + 22*x + 15

Aliases: *

sqr

x.sqr

Returns the square of x. Equivalent to x * x.

say(Polynomial([1, 1]).sqr)   # (x+1)^2 = x^2 + 2*x + 1

pow

a ** n

Returns a raised to the power n using binary (square-and-multiply) exponentiation.

say(Polynomial([1, 1]) ** 3)    # (x+1)^3 = x^3 + 3*x^2 + 3*x + 1
  • If n is a non-negative integer, returns the polynomial product.

  • If n is a negative integer, returns the multiplicative inverse ("inv") of a raised to |n| — typically a rational function.

  • If n is not an integer, falls back to a.to_n.pow(n), converting the polynomial to a scalar first (only valid for constant polynomials).

Aliases: **

div

a / b

Divides a by b.

say(Polynomial([1, 0, -1]) / Polynomial([1, -1]))   #=> x + 1
  • If b is a polynomial and division is exact (zero remainder), returns the quotient polynomial.

  • If the division is inexact, returns a Sidef::Types::Number::Fraction representing the rational function (q*b + r) / b where q, r are the quotient and remainder.

  • If b is zero, returns a polynomial with an infinite coefficient.

  • If b is a scalar, divides each coefficient by b.

Aliases: ÷

idiv

a // b

Returns only the quotient polynomial from Euclidean division, discarding the remainder. Equivalent to the first element of "divmod".

Note: The rounding-mode variants (idiv_ceil, idiv_floor, idiv_round, idiv_trunc) are all currently aliased to the same behaviour as plain idiv.

Aliases: //, idiv_ceil, idiv_floor, idiv_round, idiv_trunc

divmod

x.divmod(y)

Performs Euclidean polynomial long division and returns a two-element list (quotient, remainder) satisfying:

x == (quotient * y) + remainder
deg(remainder) < deg(y)

Returns (NaN, zero) if the leading coefficient of y is zero or NaN.

var (q, r) = Polynomial([1, 0, 0]) .divmod( Polynomial([1, 1]) )    #=>  q = x-1,  r = 1

mod

a % b

Returns the remainder polynomial from Euclidean division of a by b, i.e. the polynomial r of degree less than deg(b) satisfying a = q*b + r. When b is a scalar, each coefficient is reduced modulo b by wrapping it in a Sidef::Types::Number::Mod object.

say(Polynomial([1, 0, 0, 0]) % Polynomial([1, 0, 1]))   # x^3 mod (x^2+1) = -x

Aliases: %

neg

x.neg

Returns the additive inverse of x: all coefficients are negated. Adding x and x.neg gives the zero polynomial.

say(Polynomial([1, 2, 3]).neg)   # -x^2 - 2*x - 3

abs

x.abs

Returns x * x.sgn, i.e. the polynomial multiplied by the sign of its leading coefficient. This ensures the leading coefficient is positive. For the zero polynomial, returns zero.

say(Polynomial([-1, 2, -3]).abs)    #=> x^2 - 2*x + 3

sgn

x.sgn

Returns the sign of the leading coefficient of x: -1, 0, or 1 as a Sidef::Types::Number::Number. Returns 0 for the zero polynomial.

inc

++a

Adds 1 to the constant term of a. Returns a new polynomial with the x^0 coefficient incremented by one.

var p = Polynomial([1, 2, 3])
say(++p)   # x^2 + 2*x + 4

Aliases: ++

dec

--a

Subtracts 1 from the constant term of a. Returns a new polynomial with the x^0 coefficient decremented by one.

var p = Polynomial([1, 2, 3])
say(--p)   # x^2 + 2*x + 2

Aliases: --

inv

x.inv

Returns a Sidef::Types::Number::Fraction representing 1/x. This creates the rational function 1 / x(t). Meaningful as an exact inverse only when x is a constant polynomial; for non-constant polynomials in a quotient ring, see Sidef::Types::Number::PolynomialMod.

invmod

x.invmod(m)

Computes x.mod(m).inv: reduces x modulo the polynomial m and then returns its multiplicative inverse. Equivalent to creating PolynomialMod(x, m).inv.

powmod

x.powmod(n, m)

Computes x^n mod m using binary (square-and-multiply) exponentiation, reducing modulo polynomial m after each multiplication step. More efficient than computing x**n and then taking % m separately for large n.

say(Polynomial([1, 1]).powmod(100, Polynomial([1, 0, 1])))
# (x+1)^100 mod (x^2+1)

GCD, LCM, AND FACTORIZATION

gcd

x.gcd(y)

Returns the greatest common divisor of polynomials x and y using the polynomial Euclidean algorithm. Handles zero polynomials explicitly: gcd(x, 0) = x and gcd(0, y) = y. The result is normalized to monic (leading coefficient equal to 1) before being returned.

var p = Polynomial([1, 0, -1])   # x^2 - 1
var q = Polynomial([1, -1])      # x - 1
say(p.gcd(q))                    # x - 1  (monic)

gcdext

x.gcdext(y)

Extended Euclidean algorithm for polynomials. Returns a list of five values:

(g, u, v, a1, b1)

where g = gcd(x, y) and u, v are Bézout coefficient polynomials satisfying:

(u * x) + (v * y) == g

The additional values a1 and b1 are the final-step remainder polynomials scaled by a sign factor (-1)^i; they are the cofactors of the last non-trivial step and satisfy x/g = ±a1, y/g = ±b1 in the monic-normalised sense.

Note: The return list has five elements. If you only need the GCD and Bézout pair, capture just the first three:

var (g, u, v) = x.gcdext(y)
say(((u * x) + (v * y)) == g)   # true

lcm

x.lcm(y)

Returns the least common multiple of polynomials x and y, computed as:

lcm(x, y) = abs(x * y) / gcd(x, y)

The abs ensures the leading coefficient of the result is positive.

normalize_to_monic

x.normalize_to_monic

Returns a monic version of x by dividing all coefficients by the leading coefficient. If the leading coefficient is already 1, returns x unchanged. If the leading coefficient is zero or the polynomial is empty, returns x unchanged.

say(Polynomial([3, 6, 9]).normalize_to_monic)   # x^2 + 2*x + 3

is_monic

x.is_monic

Returns true if the leading coefficient of x is 1. Complements "normalize_to_monic".

content

x.content

Returns the content of the polynomial: the GCD of all its coefficients. Useful for extracting the largest scalar factor.

say(Polynomial([6, 9, 12]).content)   # 3  (gcd(6,9,12))

Aliases: cont

primitive_part

x.primitive_part

Returns the primitive part of x: the polynomial divided by its content. The result has integer coefficients whose GCD is 1.

say(Polynomial([6, 9, 12]).primitive_part)
# (6*x^2 + 9*x + 12) / 3 = 2*x^2 + 3*x + 4

Aliases: prim_part, primpart

is_squarefree

x.is_squarefree

Returns true if x has no repeated irreducible factors, i.e. if gcd(x, x.derivative) equals 1 (the constant polynomial 1, monic of degree 0). Equivalently, x is square-free if and only if it shares no root with its own derivative.

say(Polynomial([1, 0, -1]).is_squarefree)    # true  (x^2-1 = (x-1)(x+1))
say(Polynomial([1, -2, 1]).is_squarefree)    # false (x^2-2x+1 = (x-1)^2)

squarefree_part

x.squarefree_part

Returns the square-free part of x: the result of dividing x by gcd(x, x.derivative). The square-free part has the same roots as x but each root occurs with multiplicity at most 1.

say(Polynomial([1, -2, 1]).squarefree_part)
# (x-1)^2 → squarefree part is (x-1)

say(Polynomial([1, 0, 0, 0]).squarefree_part)
# x^3 → squarefree part is x

CALCULUS

derivative

x.derivative

Returns the formal derivative of x using the power rule: each term c_k * x^k maps to k * c_k * x^{k-1}. The constant term (k=0) is dropped. Works with any coefficient type, including complex or rational coefficients.

var p = Polynomial([1, 0, -3, 2])   # x^3 - 3*x + 2
say(p.derivative)                   # 3*x^2 - 3

eval

x.eval(value)

Evaluates the polynomial at value by computing the sum:

sum of:  coeff_k * value^k  for each nonzero term k

Each coefficient is itself evaluated at value via its own .eval method, allowing polynomials with polynomial coefficients (multivariate use). Returns 0 for the zero polynomial. As a special case, evaluating at the monomial x itself (i.e. Polynomial(1 = 1)>) returns the polynomial unchanged.

var p = Polynomial([1, 2, 3])   # x^2 + 2*x + 3
say(p.eval(5))                  # 25 + 10 + 3 = 38

compose

p.compose(q)

Returns the polynomial p(q(x)) — substitutes the polynomial q for the variable in p, using polynomial arithmetic throughout (unlike "eval", which substitutes a scalar value).

var p = Polynomial([1, 0, 1])   # x^2 + 1
var q = Polynomial([1, 1])      # x + 1
say p.compose(q)                # (x+1)^2 + 1 = x^2 + 2x + 2

ROOT FINDING

newton_method

f.newton_method
f.newton_method(x0)
f.newton_method(x0, df)

Applies Newton's method to find a root of f, starting from initial guess x0. Both x0 and df (the derivative polynomial) are optional:

  • x0 defaults to Number::i (the complex unit i = sqrt(-1)).

  • df defaults to f.derivative.

The iteration x_{n+1} = x_n - f(x_n) / f'(x_n) runs for up to PREC steps (the current working precision). Returns the last refined approximation, which equals an actual root when convergence is detected (f(x) rounds to zero within precision).

var f  = Polynomial([1, 0, -2])   # x^2 - 2
var df = f.derivative
say(f.newton_method(1.5, df))     # ≈ 1.41421356...  (√2)

roots

f.roots

Attempts to find all roots of f numerically. Returns an Sidef::Types::Array::Array of root values (which may be complex numbers).

The algorithm:

1. Uses deg(f) evenly-spaced roots of unity (slightly perturbed) as initial guesses.
2. Refines all guesses simultaneously via the Aberth-Ehrlich method.
3. Polishes each candidate with Newton's method and deduplicates within working precision.
4. If fewer than deg(f) distinct roots were found, retries with a series of transformed starting points (e.g. multiplied by i, exp, etc.) as a fallback.

For a constant polynomial (degree 0), no roots exist by construction and an empty array is returned. For polynomials with repeated roots, some roots may be missed.

say(Polynomial([1, 0, -1]).roots)    # [-1, 1]  (roots of x^2 - 1)
say(Polynomial([1, 0, 0, -1]).roots) # roots of x^3 - 1

roots_mod

poly.roots_mod(m)

Returns all roots of the polynomial modulo m.

Given a polynomial f(x) and a positive modulus m, this method finds every residue class x satisfying:

f(x) ≡ 0 (mod m)

The result is returned as an array of distinct roots, sorted in ascending order. If the polynomial has no roots modulo m, an empty array is returned.

var p = Polynomial([1, 0, -1])      # x^2 - 1
say p.roots_mod(7)                  # [1, 6]

var q = Polynomial([1, 0, 0, -1])   # x^3 - 1
say q.roots_mod(13)                 # [1, 3, 9]

var r = Polynomial([1, 3, 4, 2, 0, 5])  # x^5 + 3*x^4 + 4*x^3 + 2*x^2 + 5
say r.roots_mod(17)                     # [11, 14]

COMBINATORICS

binomial

n.binomial(k)

Computes the generalised binomial coefficient C(n, k) where n is a Polynomial and k is a non-negative integer, using the falling-factorial definition:

C(n, k) = (n * (n-1) * (n-2) * ... * (n-k+1)) / k!

The numerator product is computed via binary splitting for efficiency. Returns the constant polynomial 1 when k = 0.

var x = Polynomial(1)             # x  (monomial x^1)
say(x.binomial(2))                # x*(x-1)/2

INSPECTION

degree

x.degree

Returns the degree of the polynomial: the highest exponent with a non-zero coefficient, as a Sidef::Types::Number::Number. Returns 0 for the zero polynomial (the empty polynomial has no keys, so the fallback value is 0).

say(Polynomial([1, 2, 3]).degree)   # 2
say(Polynomial([]).degree)          # 0  (zero polynomial)

Aliases: deg

coeff

x.coeff(k)

Returns the coefficient of the term with exponent k. Returns 0 if no such term exists.

var p = Polynomial([3, 2, 1])   # 3*x^2 + 2*x + 1
say(p.coeff(0))                 # 1  (constant term)
say(p.coeff(1))                 # 2  (coefficient of x)
say(p.coeff(2))                 # 3  (coefficient of x^2)
say(p.coeff(5))                 # 0  (absent term)

Aliases: coefficient

coeffs

x.coeffs

Returns an Array of [exponent, coefficient] pairs for all nonzero terms, sorted in ascending order by exponent (lowest degree first).

var p = Polynomial([1, 2, 3])   # x^2 + 2*x + 3
say(p.coeffs)
# [[0, 3], [1, 2], [2, 1]]
# (constant term first, highest-degree term last)

Aliases: coefficients

exponents

x.exponents

Returns an Array of all exponents that have nonzero coefficients, sorted in ascending order.

say(Polynomial(5 => 3, 2 => 1).exponents)   # [2, 5]

leading_coefficient

x.leading_coefficient

Returns the coefficient of the highest-degree term. Returns 0 for the zero polynomial.

say(Polynomial([3, 2, 1]).leading_coefficient)   # 3

Aliases: leading_coeff

leading_term

x.leading_term

Returns the leading term of x as a Polynomial consisting of only the highest-degree term (with its coefficient intact).

say(Polynomial([3, 2, 1]).leading_term)   # 3*x^2

leading_monomial

x.leading_monomial

Returns the leading monomial of x: the highest-degree term with its coefficient replaced by 1.

say(Polynomial([3, 2, 1]).leading_monomial)   # x^2

height

x.height

Returns the maximum absolute value among all coefficients of x. Also called the infinity norm or Chebyshev norm of the coefficient vector.

say(Polynomial([3, -5, 2]).height)   # 5

real

x.real

Returns the constant term (coefficient of x^0) of the polynomial, as a Sidef::Types::Number::Number. Returns 0 if no constant term is present. This reflects the embedding of scalars into the polynomial ring.

say(Polynomial([1, 2, 3]).real)   # 3  (a Number, not a Polynomial)

Aliases: re

ROUNDING AND CONVERSION

float

x.float

Returns a new Polynomial with each coefficient converted to a floating-point approximation.

rat

x.rat

Returns a new Polynomial with each coefficient converted to an exact rational number (Math::GMPq).

rat_approx

x.rat_approx

Returns a new Polynomial with each floating-point coefficient replaced by a nearby rational approximation.

floor

x.floor

Returns a new Polynomial with floor() applied to each coefficient, rounding each one down to the nearest integer.

say(Polynomial([1.8, 2.3]).floor)   # x + 2

ceil

x.ceil

Returns a new Polynomial with ceil() applied to each coefficient, rounding each one up to the nearest integer.

say(Polynomial([1.5, 2.3]).ceil)   # 2*x + 3

round

x.round(r)

Returns a new Polynomial with each coefficient rounded to r decimal places (or to the nearest integer when r is zero).

say(Polynomial([1.456, 2.789]).round(1))   # 1.5*x + 2.8

lift

x.lift

Returns a new Polynomial with each coefficient replaced by its .lift value. For plain Number coefficients this is a no-op (returns an equivalent copy). For polynomials with Mod-valued coefficients (e.g. after calling .mod(n) on a polynomial over a modular ring), lift unwraps each coefficient from its modular context.

to_n

x.to_n

Converts the polynomial to a scalar Sidef::Types::Number::Number:

  • Zero polynomial (no terms): returns 0.

  • Constant polynomial (only a x^0 term, all others zero or absent): returns the constant coefficient.

  • Non-constant polynomial: returns NaN.

to_poly

x.to_poly

Returns the polynomial itself. Provides a uniform interface for type conversion (e.g. PolynomialMod overrides this to return the underlying residue polynomial).

PREDICATES

is_real

x.is_real

Returns true if and only if x is effectively a real scalar constant: either the zero polynomial, or a polynomial with a single term at degree 0 whose coefficient satisfies .is_real. Returns false for any polynomial with a non-zero higher-degree term.

say(Polynomial([5]).is_real)     # true   (constant real)
say(Polynomial([1, 0]).is_real)  # false  (non-constant)

is_zero

x.is_zero

Returns true if x is the zero polynomial (no nonzero terms).

say(Polynomial([]).is_zero)      # true   (empty polynomial)
say(Polynomial([0, 1]).is_zero)  # false  (x is not zero)

is_one

x.is_one

Returns true if x equals the constant polynomial 1 (the multiplicative identity).

say(Polynomial([1]).is_one)    # true
say(Polynomial([1, 0]).is_one) # false  (this is x, not 1)

is_mone

x.is_mone

Returns true if x equals the constant polynomial -1.

is_nan

x.is_nan

Returns true if any coefficient of the polynomial is NaN. A NaN coefficient can appear as a result of invalid operations such as division by zero or failed modular inversion.

is_inf

x.is_inf

Returns true if any coefficient of the polynomial is positive infinity.

is_ninf

x.is_ninf

Returns true if any coefficient of the polynomial is negative infinity.

norm

x.norm

Returns the norm of the constant term: x.real.norm. This is the norm of the x^0 coefficient as a number, not the Euclidean norm of the coefficient vector.

COMPARISON

eq

a == b

Returns true if a equals b.

  • Polynomial vs Polynomial: true if every coefficient of a equals the corresponding coefficient of b (missing coefficients are treated as zero). Comparison is symmetric.

  • Polynomial vs scalar: true if a is a constant polynomial whose x^0 coefficient equals the scalar, and all other coefficients are zero.

Aliases: ==

ne

a != b

Returns true if a and b are not equal. Implemented as the logical negation of "eq".

Aliases: !=

cmp

a <=> b

Three-way comparison. Returns -1, 0, or 1.

  • Polynomial vs Polynomial:

    1. Polynomials with more nonzero terms are considered greater.
    2. Among polynomials with the same number of terms, comparison proceeds from the highest degree downward: compare exponents (higher exponent → greater), then compare coefficients at matching degrees.
  • Polynomial vs scalar: only defined for constant polynomials (all non-constant coefficients zero). Returns undef for non-constant polynomials when compared against a scalar.

Aliases: <=>

lt

a < b

Returns true if a is strictly less than b under the ordering defined by "cmp".

Aliases: <

gt

a > b

Returns true if a is strictly greater than b.

Aliases: >

le

a <= b

Returns true if a is less than or equal to b.

Aliases: <=, ≤

ge

a >= b

Returns true if a is greater than or equal to b.

Aliases: >=, ≥

STRING REPRESENTATION AND BOOLEAN CONTEXT

to_s

x.to_s

Returns a Sidef::Types::String::String representation of the polynomial in standard mathematical notation, with terms ordered from highest to lowest degree:

say(Polynomial([1, 2, 3]).to_s)   # "x^2 + 2*x + 3"
say(Polynomial([1, 0, -1]).to_s)  # "x^2 - 1"
say(Polynomial([]).to_s)          # "0"

Coefficient 1 is suppressed (x not 1*x); negative signs replace leading +. Parentheses are added around complex coefficients. This is also what a Polynomial produces when stringified implicitly (e.g. via interpolation).

Aliases: stringify

pretty

x.pretty

Like "to_s" but calls the .pretty method on each coefficient rather than .to_s. This may produce Unicode formatting (e.g. Unicode fractions or superscripts) depending on the coefficient type.

dump

x.dump

Returns a Sidef::Types::String::String showing the polynomial's internal sparse representation, suitable for debugging and round-tripping:

say(Polynomial([1, 2, 3]).dump)
# Polynomial(0 => 3, 1 => 2, 2 => 1)

Terms are listed in ascending exponent order with each coefficient shown via its own .dump.

__boolify__

self.__boolify__

Backs the polynomial's boolean-context overload (e.g. if polynomial_value). This checks only the constant term (the x^0 coefficient) — a polynomial with no constant term is falsy in a boolean context even if it has other nonzero terms, and one is not required to be the zero polynomial to be falsy this way.

if (Polynomial([1, 0])) { ... }   # falsy: no constant term
if (Polynomial([1, 3])) { ... }   # truthy: constant term is 3

EXAMPLES

Basic arithmetic

var p = Polynomial([1, -2, 1])   # x^2 - 2*x + 1  =  (x-1)^2
var q = Polynomial([1, -1])      # x - 1

var sum = (p + q)
say(sum)                         # x^2 - x

var prod = (p * q)
say(prod)                        # x^3 - 3*x^2 + 3*x - 1

var (quot, rem) = p.divmod(q)
say(quot)                        # x - 1
say(rem)                         # 0

say(p.eval(3))                   # 9 - 6 + 1 = 4
say(p.eval(1))                   # 0  (1 is a double root)

Differentiation

var p = Polynomial([1, 0, -3, 2])   # x^3 - 3*x + 2
var dp = p.derivative
say(dp)                             # 3*x^2 - 3
say(dp.derivative)                  # 6*x

Root finding

say(Polynomial([1, 0, -1]).roots)   # roots of x^2-1: [-1, 1]
say(Polynomial([1, 0, 1]).roots)    # roots of x^2+1: [-i, i]

GCD, extended GCD, and Bézout identity

var p = Polynomial([1, 0, -1])   # x^2 - 1
var q = Polynomial([1, -1])      # x - 1

say(p.gcd(q))    # x - 1

var (g, u, v) = p.gcdext(q)
say(g)           # x - 1
say(((u * p) + (v * q)) == g)   # true

Content and primitive part

var r = Polynomial([6, 9, 12])   # 6*x^2 + 9*x + 12
say(r.content)                   # 3
say(r.primitive_part)            # 2*x^2 + 3*x + 4

Square-free decomposition

var p = Polynomial([1, -2, 1])   # (x-1)^2
say(p.is_squarefree)             # false
say(p.squarefree_part)           # x - 1

Modular polynomial exponentiation

var base = Polynomial([1, 1])             # x + 1
var mod  = Polynomial([1, 0, 1])          # x^2 + 1
say(base.powmod(10, mod))
# (x+1)^10 mod (x^2+1)

Sparse construction and inspection

var p = Polynomial(7 => 1, 3 => 5, 0 => 2)   # x^7 + 5*x^3 + 2
say(p.degree)                                  # 7
say(p.exponents)                               # [0, 3, 7]
say(p.coeff(3))                                # 5
say(p.height)                                  # 5

String constructor

var p = Polynomial("3*x^2 - 2*x + 1")
say(p.eval(0))    # 1
say(p.eval(1))    # 2

Newton's method

var f  = Polynomial([1, 0, -2])   # x^2 - 2
var df = f.derivative             # 2*x
say(f.newton_method(1.5, df))     # ≈ 1.41421356...  (√2)

NOTES

  • Zero polynomial: The zero polynomial is represented as an empty hash (no keys). Its degree is 0, not -1 or -∞. Use .is_zero to test for it explicitly.

  • Coefficient ring: Coefficients are arbitrary Sidef::Types::Number::Number objects — integers, rationals, floats, or even complex numbers. There is no restriction to any particular coefficient ring.

  • Division: The / operator returns a Sidef::Types::Number::Fraction when division is inexact. Use // (idiv) to always get just the quotient polynomial, or divmod to get both quotient and remainder.

  • Comparison vs scalar: The <=> operator returns undef (not a defined value) when comparing a non-constant polynomial against a scalar. Guard with a defined-check when this is possible.

REFERENCES

SEE ALSO

Sidef::Types::Number::Number, Sidef::Types::Number::PolynomialMod, Sidef::Types::Number::Fraction, Sidef::Types::Number::Mod