Документация Engee

Справка по API

Для всех многочленов доступны перечисленные ниже возможности. В некоторых случаях прямой вызов функции невозможен, поэтому многочлен сначала нужно преобразовать в стандартный тип Polynomial.

Арифметические операции

Для всех многочленов AbstractPolynomials определены основные арифметические операции (+, -, *, /, ÷, %, ==).

julia> p = Polynomial([1, 2])
Polynomial(1 + 2*x)

julia> q = Polynomial([1, 0, -1])
Polynomial(1 - x^2)

julia> 2p
Polynomial(2 + 4*x)

julia> 2 + p
Polynomial(3 + 2*x)

julia> p - q
Polynomial(2*x + x^2)

julia> p * q
Polynomial(1 + 2*x - x^2 - 2*x^3)

julia> q / 2
Polynomial(0.5 - 0.5*x^2)

Проверка

# Polynomials.degreeFunction

degree(::AbstractPolynomial)

Возвращает степень многочлена, то есть наибольший показатель степени с ненулевым коэффициентом. Согласно определению степень нулевого многочлена равна --1. Метод по умолчанию предполагает, что базисный многочлен βₖ имеет степень k.

# Base.lengthFunction

length(::AbstractPolynomial)

The length of the polynomial.

# Base.sizeFunction

size(::AbstractPolynomial, [i])

Возвращает размер полиномиальных коэффициентов по оси i, если указано.

# Polynomials.domainFunction

Polynomials.domain(::Type{<:AbstractPolynomial})

Возвращает область определения многочлена.

# Polynomials.mapdomainFunction

mapdomain(::Type{<:AbstractPolynomial}, x::AbstractArray)
mapdomain(::AbstractPolynomial, x::AbstractArray)

Для данных значений x, которые предполагаются неограниченными (--∞, ∞), возвращает значения, приведенные к области определения данного многочлена.

Примеры

julia> using Polynomials

julia> x = -10:10
-10:10

julia> extrema(mapdomain(ChebyshevT, x))
(-1.0, 1.0)

# Base.chopFunction

chop(::AbstractPolynomial{T};
    rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0))

Удаляет все начальные коэффициенты, которые примерно равны 0 (с помощью rtol и atol с norm(p)). Возвращает многочлен, степень которого гарантированно равна степени данного многочлена или меньше ее.

# Polynomials.chop!Function

chop!(::AbstractPolynomial{T};
    rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0))

Версия chop, выполняемая на месте.

# Base.truncateFunction

truncate(::AbstractPolynomial{T};
    rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0)

Округляет близкие к нулю коэффициенты, определенные с помощью rtol и atol, а затем отсекает все начальные нули. Возвращает новый многочлен.

# Polynomials.truncate!Function

truncate!(::AbstractPolynomial{T};
    rtol::Real = Base.rtoldefault(real(T)), atol::Real = 0)

Версия truncate, выполняемая на месте.

# Polynomials.isconstantFunction

isconstant(::AbstractPolynomial)

Является ли многочлен p константой.

# Polynomials.constanttermFunction

constantterm(p::AbstractPolynomial)

Возвращает p(0), свободный член в стандартном базисе.

# Base.isrealFunction

isreal(p::AbstractPolynomial)

Определяет, является ли многочлен вещественным, то есть являются ли все его коэффициенты вещественными числами.

См. также описание real.

# Base.realFunction

real(p::AbstractPolynomial)

Создает вещественный многочлен на основе вещественных частей коэффициентов p.

См. также описание isreal.

Может привести к потере членов в p. Этот метод обычно вызывается для таких многочленов, как p = Polynomial([1, 2 + 0im, 3.0, 4.0 + 0.0im]), где нужно отсечь мнимые части коэффициентов p.

# Polynomials.isintegralFunction

isintegral(p::AbstractPolynomial)

Определяет, является ли многочлен целочисленным, то есть являются ли все его коэффициенты целыми числами.

# Polynomials.ismonicFunction

ismonic(p::AbstractPolynomial)

Определяет, является ли многочлен приведенным, то есть равен ли его первый коэффициент единице.

# Polynomials.hasnanFunction

hasnan(p::AbstractPolynomial) возвращает все коэффициенты, равные NaN.

Итерация

Для типа Polynomial естественное сопоставление многочлена с коэффициентами приводит к тому, что многочлен рассматривается как отсчитываемый от вектор. То же самое верно в случае, когда члены базиса не относятся к стандартному базису. Метод coeffs возвращает эти коэффициенты в итерируемом объекте (векторе или кортеже). Для многочленов Лорана возвращаются коэффициенты от firstindex(p) до lastindex(p).

Говоря шире, pairs(p) возвращает значения i => aᵢ для многочлена с членами в базисе . (Для разреженных многочленов эти значения могут следовать не по порядку и могут включать только члены, для которых .) Методы keys и values выполняют итерацию по i и aᵢ.

Метод firstindex обращается к наименьшему хранящемуся индексу базиса, который вследствие смещений необязательно должен быть равен 0. Он будет не меньше Polynomials.minimumexponent, то есть наименьшего допустимого индекса для данного типа многочлена. Метод lastindex обращается к последнему индексу базиса. Если тип допускает конечные нули (например, ImmutablePolynomial), результат будет отличаться от значения, возвращаемого методом degree.

Метод getindex(p,i) возвращает p_i либо ноль при выходе за допустимые границы (если для типа элементов многочлена определено zero(T)). Для изменяемых многочленов метод setindex!(p, val, i) задает p[i] равным val. Благодаря этому для некоторых типов многочленов может расширяться базовый контейнер для хранения данных. Для ImmutablePolynomial макрос @set! из Setfield может использоваться со стандартной нотацией setindex!.

Метод map(fn, p) сопоставляет fn с коэффициентами и возвращает многочлен того же типа, что и p.

# Polynomials.coeffsFunction

coeffs(::AbstractPolynomial)

Возвращает вектор коэффициентов. Для многочлена в стандартном базисе это [a_0, a_1, ..., a_n].

# Base.mapFunction

map(fn, p::AbstractPolynomial, args...)

Преобразует коэффициенты p, применяя функцию (или другие вызываемые объекты) fn к каждому из них.

Вы можете применить real и т. д. к Polynomial с помощью map.

Математические функции

# Base.zeroFunction

zero(::Type{<:AbstractPolynomial})
zero(::AbstractPolynomial)

Возвращает представление 0 в качестве заданного многочлена.

# Base.oneFunction

one(::Type{<:AbstractPolynomial})
one(::AbstractPolynomial)

Возвращает представление 1 в качестве заданного многочлена.

# Polynomials.variableFunction

variable(var=:x)
variable(::Type{<:AbstractPolynomial}, var=:x)
variable(p::AbstractPolynomial, var=indeterminate(p))

Возвращает одночлен x в указанном полиномиальном базисе. Если тип не указан, по умолчанию используется Polynomial. Эквивалентно P(var).

Примеры

julia> using Polynomials

julia> x = variable()
Polynomial(x)

julia> p = 100 + 24x - 3x^2
Polynomial(100 + 24*x - 3*x^2)

julia> roots((x - 3) * (x + 2))
2-element Vector{Float64}:
 -2.0
  3.0

# Polynomials.fromrootsFunction

fromroots(::AbstractVector{<:Number}; var=:x)
fromroots(::Type{<:AbstractPolynomial}, ::AbstractVector{<:Number}; var=:x)

Строит многочлен указанного типа на основе корней. Если тип не указан, по умолчанию используется Polynomial.

Примеры

julia> using Polynomials

julia> r = [3, 2]; # (x - 3)(x - 2)

julia> fromroots(r)
Polynomial(6 - 5*x + x^2)
fromroots(::AbstractMatrix{<:Number}; var=:x)
fromroots(::Type{<:AbstractPolynomial}, ::AbstractMatrix{<:Number}; var=:x)

Строит многочлен указанного типа на основе собственных значений заданной матрицы в качестве корней. Если тип не указан, по умолчанию используется Polynomial.

Примеры

julia> using Polynomials

julia> A = [1 2; 3 4]; # (x - 5.37228)(x + 0.37228)

julia> fromroots(A)
Polynomial(-1.9999999999999998 - 5.0*x + 1.0*x^2)

# Base.gcdFunction

gcd(a::AbstractPolynomial, b::AbstractPolynomial; atol::Real=0, rtol::Real=Base.rtoldefault)

Рекурсивно находит наибольший общий знаменатель двух многочленов с помощью алгоритма Евклида.

Примеры

julia> using Polynomials

julia> gcd(fromroots([1, 1, 2]), fromroots([1, 2, 3]))
Polynomial(4.0 - 6.0*x + 2.0*x^2)
gcd(p1::StandardBasisPolynomial, p2::StandardBasisPolynomial; method=:euclidean, kwargs...)

Находит наибольший общий делитель.

По умолчанию использует алгоритм деления Евклида (method=:euclidean), который подвержен проблемам с плавающей запятой.

Чтобы избежать некоторых из них, можно передать method=:noda_sasaki для масштабирования.

Если передать method=:numerical, будет вызван внутренний метод NGCD.ngcd для численного нахождения наибольшего общего делителя. Подробные сведения см. на странице справки по Polynomials.NGCD.ngcd(p,q).

# Polynomials.derivativeFunction

derivative(::AbstractPolynomial, order::Int = 1)

Возвращает многочлен, являющийся производной order-го порядка указанного многочлена. Значение order должно быть неотрицательным.

# Polynomials.integrateFunction

integrate(p::AbstractPolynomial)

Возвращает первообразную для p.

integrate(::AbstractPolynomial, C)

Возвращает неопределенный интеграл многочлена, выраженного в стандартном базисе, с константой C.

integrate(::AbstractPolynomial, a, b)

Вычисляет определенный интеграл указанного многочлена на интервале от a до b. Если значение a или b находится за пределами области определения многочлена, возникает ошибка.

# Polynomials.rootsFunction

roots(p)

Вычисляет корни многочлена Лорана p.

Корни функции (в данном случае многочлена Лорана) a(z) — это значения z, при которых функция обращается в нуль. Многочлен Лорана можно рассматривать как рациональную функцию с множественной сингулярностью (полюсом) в начальной точке. Его корнями являются корни многочлена-числителя. Например, можно записать как , и корнями a являются корни многочлена .

Пример

julia> using Polynomials;

julia> p = LaurentPolynomial([24,10,-15,0,1],-2,:z)
LaurentPolynomial(24*z⁻² + 10*z⁻¹ - 15 + z²)

julia> roots(p)
4-element Vector{Float64}:
 -3.999999999999999
 -0.9999999999999994
  1.9999999999999998
  2.9999999999999982
roots(p)

Compute the roots of the Laurent polynomial p.

The roots of a function (Laurent polynomial in this case) a(z) are the values of z for which the function vanishes. A Laurent polynomial can equivalently be viewed as a rational function with a multiple singularity (pole) at the origin. The roots are then the roots of the numerator polynomial. For example, can be written as and the roots of a are the roots of .

Example

julia> using Polynomials;

julia> p = LaurentPolynomial([24,10,-15,0,1],-2,:z)
LaurentPolynomial(24*z⁻² + 10*z⁻¹ - 15 + z²)

julia> roots(p)
4-element Vector{Float64}:
 -3.999999999999999
 -0.9999999999999994
  1.9999999999999998
  2.9999999999999982
roots(pq::AbstractRationalFunction; kwargs...)

Возвращает нули (zeros) рациональной функции (после сокращения общих множителей zeros — это корни числителя).

# Polynomials.companionFunction

companion(::AbstractPolynomial)

Возвращает сопровождающую матрицу для указанного многочлена.

Ссылки

# Polynomials.fitFunction

fit(x, y, deg=length(x) - 1; [weights], var=:x)
fit(::Type{<:AbstractPolynomial}, x, y, deg=length(x)-1; [weights], var=:x)

Аппроксимирует указанные данные типом многочлена заданной степени. Использует линейный метод наименьших квадратов для минимизации нормы ||y - V⋅β||^2, где V — это матрица Вандермонда, а β — коэффициенты подобранного многочлена.

Данные автоматически приводятся к области определения (domain) типа многочлена с помощью mapdomain. Тип многочлена по умолчанию — Polynomial.

Веса

Веса можно присвоить точкам путем указания вектора или матрицы весов.

При указании в виде вектора [w₁,…,wₙ] веса должны быть неотрицательными, так как задача минимизации имеет вид argmin_β Σᵢ wᵢ |yᵢ - Σⱼ Vᵢⱼ βⱼ|² = argmin_β || √(W)⋅(y - V(x)β)||², where, W, диагональная матрица, образованная из [w₁,…,wₙ], используется для решения, а V — это матрица Вандермонда для x, соответствующая указанной степени. Такая параметризация весов отличается от используемой в numpy.polyfit, где веса задаются в виде [ω₁,ω₂,…,ωₙ] = [√w₁, √w₂,…,√wₙ] и решение имеет вид argminᵦ | (ωᵢ⋅yᵢ- ΣⱼVᵢⱼ(ω⋅x) βⱼ) |^2.

При указании в виде матрицы W решение находится посредством нормальных уравнений (VᵀWV)β = (Vᵀy), где V — это опять-таки матрица Вандермонда для x, соответствующая указанной степени.

(В статистике вариант с вектором соответствует взвешенным наименьшим квадратам, для которых веса обычно задаются в виде wᵢ = 1/σᵢ², где σᵢ² — дисперсия измерения; форма матрицы соответствует обобщенной оценке по методу наименьших квадратов с W = Σ⁻¹ и является обращенной матрицей дисперсий и ковариаций.)

Высокая степень

С повышением степени при подборе обусловленность матрицы Вандермонда ухудшается экспоненциально. Тип ArnoldiFit вводит ортогонализацию Арнольди, которая решает эту проблему.

fit(::Type{RationalFunction}, xs::AbstractVector{S}, ys::AbstractVector{T}, m, n; var=:x)

Подбирает рациональную функцию вида pq = (a₀ + a₁x¹ + … + aₘxᵐ) / (1 + b₁x¹ + … + bₙxⁿ) к данным (x,y).

При этом используется простая реализация метода Гаусса-Ньютона для решения нелинейной задачи наименьших квадратов: minᵦ Σ(yᵢ - pq(xᵢ,β)², где β=(a₀,a₁,…,aₘ,b₁,…,bₙ).

Метод с более быстрой сходимостью применяется в пакете LsqFit.jl, поэтому если важна производительность, рекомендуется переформулировать задачу для использования с этим пакетом.

Кроме того, если требуется точная аппроксимация рациональной функции адаптивной степени, в пакете BaryRational.jl реализован алгоритм AAA («который обеспечивает скорость, гибкость и надежность, не наблюдавшиеся в других алгоритмах» Накацукаса (Nakatsukasa), Сет (Sète), Трефетен (Trefethen)) и алгоритм, использующий веса Флоутера-Хорманна Флоутер (Floater), Хорманн (Hormann) («не имеющие вещественных полюсов и произвольно высоких порядков аппроксимации на любом вещественном интервале независимо от распределения точек»).

В пакете RationalApproximations также есть реализация алгоритма AAA.

В библиотеке Python polyrat есть реализации других алгоритмов.

Пример

julia> x = variable(Polynomial{Float64})
Polynomial(1.0*x)

julia> pq = (1+x)//(1-x)
(1.0 + 1.0*x) // (1.0 - 1.0*x)

julia> xs = 2.0:.1:3;

julia> ys = pq.(xs);

julia> v = fit(RationalFunction, xs, ys, 2, 2)
(1.0 + 1.0*x - 6.82121e-13*x^2) // (1.0 - 1.0*x + 2.84217e-13*x^2)

julia> maximum(abs, v(x)-pq(x) for x ∈ 2.1:0.1:3.0)
1.06314956838105e-12

julia> using BaryRational

julia> u = aaa(xs,ys)
(::BaryRational.AAAapprox{Vector{Float64}}) (generic function with 1 method)

julia> maximum(abs, u(x)-pq(x) for x ∈ 2.1:0.1:3.0)
4.440892098500626e-16

julia> u(variable(pq)) # для вывода используемого многочлена
(2.68328 + 0.447214*x - 1.78885*x^2 + 0.447214*x^3) // (2.68328 - 4.91935*x + 2.68328*x^2 - 0.447214*x^3)
fit(::Type{RationalFunction}, r::Polynomial, m, n; var=:x)

Подбирает аппроксимант Паде (pade_fit) к r.

Примеры:

julia> using Polynomials, PolynomialRatios

julia> x = variable()
Polynomial(x)

julia> ex = 1 + x + x^2/2 + x^3/6 + x^4/24 + x^5/120 # Многочлен Тейлора для e^x
Polynomial(1.0 + 1.0*x + 0.5*x^2 + 0.16666666666666666*x^3 + 0.041666666666666664*x^4 + 0.008333333333333333*x^5)

julia> maximum(abs, exp(x) - fit(RationalFunction, ex, 1,1)(x) for x ∈ 0:.05:0.5)
0.017945395966538547

julia> maximum(abs, exp(x) - fit(RationalFunction, ex, 1,2)(x) for x ∈ 0:.05:0.5)
0.0016624471707165078

julia> maximum(abs, exp(x) - fit(RationalFunction, ex, 2,1)(x) for x ∈ 0:.05:0.5)
0.001278729299871717

julia> maximum(abs, exp(x) - fit(RationalFunction, ex, 2,2)(x) for x ∈ 0:.05:0.5)
7.262205147950951e-5

# Polynomials.vanderFunction

vander(::Type{AbstractPolynomial}, x::AbstractVector, deg::Integer)

Вычисляет псевдоматрицу Вандермонда для указанного типа многочлена заданной степени.

Ссылки

Построение графиков

Графики многочленов можно строить непосредственно с помощью Plots.jl или Makie.jl.

plot(::AbstractPolynomial; kwds...)

автоматически определяет диапазон на основе критических точек (корней, экстремумов и точек перегиба).

plot(::AbstractPolynomial, a, b; kwds...)

строит график многочлена в диапазоне [a, b].

Пример: Логотип пакета Polynomials.jl

using Plots, Polynomials
# T1, T2, T3 и T4:
chebs = [
  ChebyshevT([0, 1]),
  ChebyshevT([0, 0, 1]),
  ChebyshevT([0, 0, 0, 1]),
  ChebyshevT([0, 0, 0, 0, 1]),
]
colors = ["#4063D8", "#389826", "#CB3C33", "#9558B2"]

p = plot(legend=false, label="")
for (cheb, col) in zip(chebs, colors)
  plot!(cheb, c=col, lw=5)
end
chebs