Copyright | Copyright 2024 Yoo Chung |
---|---|
License | Apache-2.0 |
Maintainer | dev@chungyc.org |
Safe Haskell | None |
Language | GHC2021 |
This modules defines a type class that concrete types representing polynomials should be an instance of. It includes important algorithms operating on polynomials. In particular, algorithms for polynomial division and the extended Euclidean algorithm are included.
Synopsis
- class (Integral e, Num c) => Polynomial (p :: Type -> Type -> Type) e c where
- degree :: p e c -> e
- coefficient :: p e c -> e -> c
- leadingCoefficient :: p e c -> c
- deleteLeadingTerm :: p e c -> p e c
- foldTerms :: Monoid m => (e -> c -> m) -> p e c -> m
- scale :: c -> p e c -> p e c
- power :: e -> p e c
- monic :: (Polynomial p e c, Eq c, Fractional c) => p e c -> p e c
- mapCoefficients :: (Polynomial p e c, Polynomial p e c', Num (p e c), Num (p e c')) => (c -> c') -> p e c -> p e c'
- divide :: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) => p e c -> p e c -> (p e c, p e c)
- pseudoDivide :: (Polynomial p e c, Eq (p e c), Num (p e c), Num c) => p e c -> p e c -> (p e c, p e c)
- extendedEuclidean :: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) => p e c -> p e c -> (p e c, p e c, p e c)
- diophantineEuclidean :: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) => p e c -> p e c -> p e c -> Maybe (p e c, p e c)
- greatestCommonDivisor :: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) => p e c -> p e c -> p e c
- subresultant :: (Polynomial p e c, Eq (p e c), Num (p e c), Num e, Fractional c) => p e c -> p e c -> (c, [p e c])
- differentiate :: (Polynomial p e c, Num (p e c), Num c) => p e c -> p e c
- integrate :: (Polynomial p e c, Num (p e c), Fractional c) => p e c -> p e c
- squarefree :: (Polynomial p e c, Eq (p e c), Num (p e c), Eq c, Fractional c) => p e c -> [p e c]
Polynomials
class (Integral e, Num c) => Polynomial (p :: Type -> Type -> Type) e c where Source #
Polynomials must support the operations specified in this type class. All powers must be non-negative.
Returns the degree of a given polynomial.
The following returns 9 for the highest term in \(3x^9 + 2x^4 + x\):
>>>
degree (3 * power 9 + 2 * power 4 + power 1 :: IndexedPolynomial)
9
coefficient :: p e c -> e -> c Source #
Returns the coefficient for the term with the given power.
The following returns 4 from the \(4x^3\) term in \(x^4 + 4x^3 + 3\):
>>>
coefficient (power 4 + 4 * power 3 + 3 :: IndexedPolynomial) 3
4 % 1
leadingCoefficient :: p e c -> c Source #
Returns the leading coefficient.
The following returns 6 from the \(6x^3\) term in \(6x^3 + 2x^2\):
>>>
leadingCoefficient (6 * power 3 + 2 * power 2 :: IndexedPolynomial)
6 % 1
The leading coefficient is never zero unless the polynomial itself is zero.
deleteLeadingTerm :: p e c -> p e c Source #
Returns the polynomial without the leading term.
>>>
deleteLeadingTerm (2 * power 3 + power 1 + 2 :: IndexedPolynomial)
x + 2
foldTerms :: Monoid m => (e -> c -> m) -> p e c -> m Source #
Fold the terms, i.e., the powers and coefficients, using the given monoid. Only terms with non-zero coefficients will be folded. Folding is ordered from lower to higher terms.
For example with \(3x^5 - 2x + 7\),
>>>
foldTerms (\e c -> show (e, c)) (3 * power 5 - 2 * power 1 + 7 :: IndexedPolynomial)
"(0,7 % 1)(1,(-2) % 1)(5,3 % 1)"
scale :: c -> p e c -> p e c Source #
Multiplies a polynomial by a scalar.
The following divides \(6x + 2\) by 2:
>>>
scale (1 % 2) (6 * power 1 + 2 :: IndexedPolynomial)
3x + 1
Returns a single term with the variable raised to the given power.
The following is equivalent to \(x^5\):
>>>
power 5 :: IndexedPolynomial
x^5
monic :: (Polynomial p e c, Eq c, Fractional c) => p e c -> p e c Source #
Scale the polynomial so that its leading coefficient is one.
>>>
monic $ 4 * power 2 + 4 * power 1 + 4 :: IndexedPolynomial
x^2 + x + 1
The exception is when the polynomial is zero.
>>>
monic 0 :: IndexedPolynomial
0
mapCoefficients :: (Polynomial p e c, Polynomial p e c', Num (p e c), Num (p e c')) => (c -> c') -> p e c -> p e c' Source #
Maps the coefficients in a polynomial to form another polynomial.
For example, it can be used to convert a polynomial with Rational
coefficients
into a polynomial with Expression
coefficients.
>>>
let p = 2 * power 1 + 1 :: IndexedPolynomial
>>>
let q = mapCoefficients fromRational p :: IndexedSymbolicPolynomial
>>>
simplify $ coefficient q 1
Number 2
Algorithms
:: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) | |
=> p e c | Dividend polynomial being divided. |
-> p e c | Divisor polynomial dividing the dividend. |
-> (p e c, p e c) | Quotient and remainder. |
Polynomial division. It returns the quotient polynomial and the remainder polynomial.
For example, dividing \(p = x^3-12x^2-42\) by \(q = x^2 - 2x + 1\) returns \(x-10\) as the quotient and \(-21x-32\) as the remainder, since \(p = (x-10)q -21x - 32\):
>>>
let p = power 3 - 12 * power 2 - 42 :: IndexedPolynomial
>>>
let q = power 2 - 2 * power 1 + 1 :: IndexedPolynomial
>>>
divide p q
(x + (-10),(-21)x + (-32))
:: (Polynomial p e c, Eq (p e c), Num (p e c), Num c) | |
=> p e c | Dividend polynomial being pseudo-divided. |
-> p e c | Divisor polynomial pseudo-dividing the dividend. |
-> (p e c, p e c) | Pseudo-quotient and pseudo-remainder. |
Polynomial pseudo-division. It returns the pseudo-quotient and pseudo-remainder polynomials.
Equivalent to \(b^{\delta+1} p\) divided by \(q\), where \(p\) and \(q\) are polynomials with integer coefficients, \(b\) is the leading coefficient of \(q\) and \(\delta=\max(-1, \deg(p) - \deg(q))\). This guarantees the pseudo-quotient and pseudo-remainder exist, even when the quotient and remainder do not when only integer coefficients are allowed.
For example, with \(p = 3x^3 + x^2 + x + 5\) and \(q = 5x^2 - 3x + 1\), it is the case that \(5^2p = (15x + 14)q + (52x + 111)\):
>>>
let p = 3 * power 3 + power 2 + power 1 + 5 :: IndexedPolynomial
>>>
let q = 5 * power 2 - 3 * power 1 + 1 :: IndexedPolynomial
>>>
pseudoDivide p q
(15x + 14,52x + 111)
:: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) | |
=> p e c | Polynomial \(p\). |
-> p e c | Polynomial \(q\). |
-> (p e c, p e c, p e c) | \(s\), \(t\), and \(\gcd(p,q)\). |
The extended Euclidean algorithm. For polynomials \(p\) and \(q\), it returns the greatest common divisor between \(p\) and \(q\). It also returns \(s\) and \(t\) such that \(sp+tq = \gcd(p,q)\).
For example, for \(p=2x^5-2x\) and \(q=x^4-2x^2+1\), it is the case that \(\gcd(p,q)=-x^2+1\) and \((-\frac{1}{4}x) p + (\frac{1}{2}x^2 + 1) q = -x^2+1\):
>>>
let p = 2 * power 5 - 2 * power 1 :: IndexedPolynomial
>>>
let q = power 4 - 2 * power 2 + 1 :: IndexedPolynomial
>>>
extendedEuclidean p q
(((-1) % 4)x,(1 % 2)x^2 + 1,(-1)x^2 + 1)
:: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) | |
=> p e c | Polynomial \(a\). |
-> p e c | Polynomial \(b\). |
-> p e c | Polynomial \(c\). |
-> Maybe (p e c, p e c) | \((s,t)\) such that \(sa + tb = c\). |
Solves \(sa + tb = c\) for given polynomials \(a\), \(b\), and \(c\). It will be the case that either \(s=0\) or the degree of \(s\) will be less than the degree of \(b\).
>>>
let a = power 4 - 2 * power 3 - 6 * power 2 + 12 * power 1 + 15 :: IndexedPolynomial
>>>
let b = power 3 + power 2 - 4 * power 1 - 4 :: IndexedPolynomial
>>>
let c = power 2 - 1 :: IndexedPolynomial
>>>
diophantineEuclidean a b c
Just (((-1) % 5)x^2 + (4 % 5)x + ((-3) % 5),(1 % 5)x^3 + ((-7) % 5)x^2 + (16 % 5)x + (-2))
If there is no such \((s,t)\), then Nothing
is returned.
greatestCommonDivisor Source #
:: (Polynomial p e c, Eq (p e c), Num (p e c), Fractional c) | |
=> p e c | Polynomial \(p\). |
-> p e c | Polynomial \(q\). |
-> p e c | \(\gcd(p,q)\). |
Returns the greatest common divisor btween two polynomials.
Convenient wrapper over extendedEuclidean
which only returns the greatest common divisor.
:: (Polynomial p e c, Eq (p e c), Num (p e c), Num e, Fractional c) | |
=> p e c | First element in the remainder sequence. |
-> p e c | Second element in the remainder sequence. |
-> (c, [p e c]) | The resultant and the subresultant polynomial remainder sequence. |
Returns the resultant and the subresultant polynomial remainder sequence for the given polynomials.
>>>
subresultant (power 2 + 1) (power 2 - 1 :: IndexedPolynomial)
(4 % 1,[x^2 + 1,x^2 + (-1),(-2),0])>>>
subresultant (2 * power 2 - 3 * power 1 + 1) (5 * power 2 + power 1 - 6 :: IndexedPolynomial)
(0 % 1,[2x^2 + (-3)x + 1,5x^2 + x + (-6),17x + (-17),0])>>>
subresultant (power 3 + 2 * power 2 + 3 * power 1 + 4) (5 * power 2 + 6 * power 1 + 7 :: IndexedPolynomial)
(832 % 1,[x^3 + 2x^2 + 3x + 4,5x^2 + 6x + 7,16x + 72,832,0])
Reference
See sections 1.4 and 1.5 in Symbolic Integration I: Transcendental Functions by Manuel Bronstein for the definition of resultants, subresultants, polynomial remainder sequences, and subresultant polynomial remainder sequences.
differentiate :: (Polynomial p e c, Num (p e c), Num c) => p e c -> p e c Source #
Returns the derivative of the given polynomial.
>>>
differentiate (power 2 + power 1 :: IndexedPolynomial)
2x + 1
integrate :: (Polynomial p e c, Num (p e c), Fractional c) => p e c -> p e c Source #
Returns the integral of the given polynomial.
>>>
integrate (power 2 + power 1 :: IndexedPolynomial)
(1 % 3)x^3 + (1 % 2)x^2
squarefree :: (Polynomial p e c, Eq (p e c), Num (p e c), Eq c, Fractional c) => p e c -> [p e c] Source #
Returns the squarefree factorization of the given polynomial.
Specifically, for a polynomial \(p\), find \([p_1, p_2, \ldots, p_n]\) such that
\[ p = \sum_{k=1}^n p_k^k \]
where all \(p_k\) are squarefree, i.e., there is no polynomial \(q\) such that \(q^2 = p_k\).
For example, the squarefree factorization of \(x^8 + 6x^6 + 12x^4 + 8x^2\) is \(x^2 (x^2 + 2)^3\):
>>>
squarefree (power 8 + 6 * power 6 + 12 * power 4 + 8 * power 2 :: IndexedPolynomial)
[1,x,x^2 + 2]