# Polynomial

Polynomial types using the standard basis.

## Polynomial

`Polynomials.Polynomial`

— Type`Polynomial{T, X}(coeffs::AbstractVector{T}, [var = :x])`

Construct a polynomial from its coefficients `coeffs`

, lowest order first, optionally in terms of the given variable `var`

which may be a character, symbol, or a string.

If $p = a_n x^n + \ldots + a_2 x^2 + a_1 x + a_0$, we construct this through `Polynomial([a_0, a_1, ..., a_n])`

.

The usual arithmetic operators are overloaded to work with polynomials as well as with combinations of polynomials and scalars. However, operations involving two polynomials of different variables causes an error except those involving a constant polynomial.

`Polynomial`

is not axis-aware, and it treats `coeffs`

simply as a list of coefficients with the first index always corresponding to the constant term. In order to use the axis of `coeffs`

as exponents, consider using a `LaurentPolynomial`

or possibly a `SparsePolynomial`

.

**Examples**

```
julia> using Polynomials
julia> Polynomial([1, 0, 3, 4])
Polynomial(1 + 3*x^2 + 4*x^3)
julia> Polynomial([1, 2, 3], :s)
Polynomial(1 + 2*s + 3*s^2)
julia> one(Polynomial)
Polynomial(1.0)
```

## Immutable Polynomial

`Polynomials.ImmutablePolynomial`

— Type`ImmutablePolynomial{T, X, N}(coeffs::AbstractVector{T})`

Construct an immutable (static) polynomial from its coefficients `a₀, a₁, …, aₙ`

, lowest order first, optionally in terms of the given variable `x`

where `x`

can be a character, symbol, or string.

If $p = a_n x^n + \ldots + a_2 x^2 + a_1 x + a_0$, we construct this through `ImmutablePolynomial((a_0, a_1, ..., a_n))`

(assuming `a_n ≠ 0`

). As well, a vector or number can be used for construction.

The usual arithmetic operators are overloaded to work with polynomials as well as with combinations of polynomials and scalars. However, operations involving two non-constant polynomials of different variables causes an error. Unlike other polynomials, `setindex!`

is not defined for `ImmutablePolynomials`

.

As the degree of the polynomial (`+1`

) is a compile-time constant, several performance improvements are possible. For example, immutable polynomials can take advantage of faster polynomial evaluation provided by `evalpoly`

from Julia 1.4; similar methods are also used for addtion and multiplication.

However, as the degree is included in the type, promotion between immutable polynomials can not promote to a common type. As such, they are precluded from use in rational functions.

`ImmutablePolynomial`

is not axis-aware, and it treats `coeffs`

simply as a list of coefficients with the first index always corresponding to the constant term.

**Examples**

```
julia> using Polynomials
julia> ImmutablePolynomial((1, 0, 3, 4))
ImmutablePolynomial(1 + 3*x^2 + 4*x^3)
julia> ImmutablePolynomial((1, 2, 3), :s)
ImmutablePolynomial(1 + 2*s + 3*s^2)
julia> one(ImmutablePolynomial)
ImmutablePolynomial(1.0)
```

This was modeled after StaticUnivariatePolynomials by `@tkoolen`

.

## Sparse Polynomial

`Polynomials.SparsePolynomial`

— Type`SparsePolynomial{T, X}(coeffs::Dict, [var = :x])`

Polynomials in the standard basis backed by a dictionary holding the non-zero coefficients. For polynomials of high degree, this might be advantageous.

**Examples:**

```
julia> using Polynomials
julia> P = SparsePolynomial
SparsePolynomial
julia> p, q = P([1,2,3]), P([4,3,2,1])
(SparsePolynomial(1 + 2*x + 3*x^2), SparsePolynomial(4 + 3*x + 2*x^2 + x^3))
julia> p + q
SparsePolynomial(5 + 5*x + 5*x^2 + x^3)
julia> p * q
SparsePolynomial(4 + 11*x + 20*x^2 + 14*x^3 + 8*x^4 + 3*x^5)
julia> p + 1
SparsePolynomial(2 + 2*x + 3*x^2)
julia> q * 2
SparsePolynomial(8 + 6*x + 4*x^2 + 2*x^3)
julia> p = Polynomials.basis(P, 10^9) - Polynomials.basis(P,0) # also P(Dict(0=>-1, 10^9=>1))
SparsePolynomial(-1.0 + 1.0*x^1000000000)
julia> p(1)
0.0
```

## Laurent Polynomial

`Polynomials.LaurentPolynomial`

— Type`LaurentPolynomial{T,X}(coeffs::AbstractVector, [m::Integer = 0], [var = :x])`

A Laurent polynomial is of the form `a_{m}x^m + ... + a_{n}x^n`

where `m,n`

are integers (not necessarily positive) with `m <= n`

.

The `coeffs`

specify `a_{m}, a_{m-1}, ..., a_{n}`

. The argument `m`

represents the lowest exponent of the variable in the series, and is taken to be zero by default.

Laurent polynomials and standard basis polynomials promote to Laurent polynomials. Laurent polynomials may be converted to a standard basis polynomial when `m >= 0`

.

Integration will fail if there is a `x⁻¹`

term in the polynomial.

`LaurentPolynomial`

is axis-aware, unlike the other polynomial types in this package.

**Examples:**

```
julia> using Polynomials
julia> P = LaurentPolynomial
LaurentPolynomial
julia> p = P([1,1,1], -1)
LaurentPolynomial(x⁻¹ + 1 + x)
julia> q = P([1,1,1])
LaurentPolynomial(1 + x + x²)
julia> pp = Polynomial([1,1,1])
Polynomial(1 + x + x^2)
julia> p + q
LaurentPolynomial(x⁻¹ + 2 + 2*x + x²)
julia> p * q
LaurentPolynomial(x⁻¹ + 2 + 3*x + 2*x² + x³)
julia> p * pp
LaurentPolynomial(x⁻¹ + 2 + 3*x + 2*x² + x³)
julia> pp - q
LaurentPolynomial(0)
julia> derivative(p)
LaurentPolynomial(-x⁻² + 1)
julia> integrate(q)
LaurentPolynomial(1.0*x + 0.5*x² + 0.3333333333333333*x³)
julia> integrate(p) # x⁻¹ term is an issue
ERROR: ArgumentError: Can't integrate Laurent polynomial with `x⁻¹` term
julia> integrate(P([1,1,1], -5))
LaurentPolynomial(-0.25*x⁻⁴ - 0.3333333333333333*x⁻³ - 0.5*x⁻²)
julia> x⁻¹ = inv(variable(LaurentPolynomial)) # `inv` defined on monomials
LaurentPolynomial(1.0*x⁻¹)
julia> p = Polynomial([1,2,3])
Polynomial(1 + 2*x + 3*x^2)
julia> x = variable()
Polynomial(x)
julia> x^degree(p) * p(x⁻¹) # reverses coefficients
LaurentPolynomial(3.0 + 2.0*x + 1.0*x²)
```

## Factored Polynomial

`Polynomials.FactoredPolynomial`

— Type`FactoredPolynomial{T,X}`

A polynomial type that stores its data in a dictionary whose keys are the roots and whose values are the respective multiplicities along with a leading coefficient.

The structure is utilized for scalar multiplication, polynomial multiplication and powers, the finding of roots, and the identification of a greatest common divisor. For other operations, say addition, the operation is done after converting to the `Polynomial`

type then converting back. (This requires the identification of the roots, so is subject to numeric issues.)

**Examples**

```
julia> using Polynomials
julia> p = FactoredPolynomial(Dict([0=>1, 1=>2, 3=>4]))
FactoredPolynomial(x * (x - 3)⁴ * (x - 1)²)
julia> q = fromroots(FactoredPolynomial, [0,1,2,3])
FactoredPolynomial(x * (x - 2) * (x - 3) * (x - 1))
julia> p*q
FactoredPolynomial(x² * (x - 2) * (x - 3)⁵ * (x - 1)³)
julia> p^1000
FactoredPolynomial(x¹⁰⁰⁰ * (x - 3)⁴⁰⁰⁰ * (x - 1)²⁰⁰⁰)
julia> gcd(p,q)
FactoredPolynomial(x * (x - 3) * (x - 1))
julia> p = Polynomial([24, -50, 35, -10, 1])
Polynomial(24 - 50*x + 35*x^2 - 10*x^3 + x^4)
julia> q = convert(FactoredPolynomial, p) # noisy form of `factor`:
FactoredPolynomial((x - 4.0000000000000036) * (x - 2.9999999999999942) * (x - 1.0000000000000002) * (x - 2.0000000000000018))
julia> map(x->round(x, digits=12), q) # map works over factors and leading coefficient -- not coefficients in the standard basis
FactoredPolynomial((x - 4.0) * (x - 2.0) * (x - 3.0) * (x - 1.0))
```

## Rational Function

`Polynomials.RationalFunction`

— Type```
RationalFunction(p::AbstractPolynomial, q::AbstractPolynomial)
p // q
```

Create a rational expression (`p//q`

) from the two polynomials.

Common factors are not cancelled by the constructor, as they are for the base `Rational`

type. The `lowest_terms(pq)`

function attempts that operation.

For purposes of iteration, a rational function is treated like a two-element container.

**Examples**

```
julia> using Polynomials
julia> p,q = fromroots(Polynomial, [1,2,3]), fromroots(Polynomial, [2,3,4])
(Polynomial(-6 + 11*x - 6*x^2 + x^3), Polynomial(-24 + 26*x - 9*x^2 + x^3))
julia> pq = p // q
(-6 + 11*x - 6*x^2 + x^3) // (-24 + 26*x - 9*x^2 + x^3)
julia> lowest_terms(pq)
(-0.333333 + 0.333333*x) // (-1.33333 + 0.333333*x)
julia> pq(2.5)
-1.0
julia> pq(2) # uses first non-`0/0` ratio of `p⁽ᵏ⁾/q⁽ᵏ⁾`
-0.5
julia> pq^2
(36 - 132*x + 193*x^2 - 144*x^3 + 58*x^4 - 12*x^5 + x^6) // (576 - 1248*x + 1108*x^2 - 516*x^3 + 133*x^4 - 18*x^5 + x^6)
julia> derivative(pq)
(-108 + 180*x - 111*x^2 + 30*x^3 - 3*x^4) // (576 - 1248*x + 1108*x^2 - 516*x^3 + 133*x^4 - 18*x^5 + x^6)
```

The RationalFunctions.jl package was a helpful source of ideas.

The `ImmutablePolynomial`

type can not be used for rational functions, as the type requires the numerator and denominator to have the exact same type.