Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

an algorithm for polynomial composition, an algorithm for FFT-based * #530

Merged
merged 1 commit into from
Aug 21, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/polynomials/standard-basis/standard-basis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,113 @@
x, y
end

#### --------------------------------------------------

## Issue 511 for alternatives to polynomial composition
# https://ens-lyon.hal.science/ensl-00546102/document
# should be faster, but not using O(nlog(n)) multiplication below.
function ranged_horner(f::StandardBasisPolynomial, g::StandardBasisPolynomial, i, l)
out = f[i+l-1] * one(g)
for j ∈ (l-2):-1:0
out = muladd(out, g, f[i+j])
end
out

Check warning on line 842 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L837-L842

Added lines #L837 - L842 were not covered by tests
end

# Compute `p(q)`. Seems more performant than
function practical_polynomial_composition(f::StandardBasisPolynomial, g::StandardBasisPolynomial)
l = 4
n = degree(f)

Check warning on line 848 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L846-L848

Added lines #L846 - L848 were not covered by tests

kᵢ = ceil(Int, (n + 1)/l)
isone(kᵢ) && return f(g)

Check warning on line 851 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L850-L851

Added lines #L850 - L851 were not covered by tests

hij = [ranged_horner(f, g, j*l, l) for j ∈ 0:(kᵢ-1)]

Check warning on line 853 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L853

Added line #L853 was not covered by tests

G = g^l
o = 1
while kᵢ > 1
kᵢ = ceil(Int, kᵢ/2)
isodd(length(hij)) && push!(hij, zero(f))
hij = [hij[2j+o] + hij[2j+1+o]*G for j ∈ 0:(kᵢ-1)]
kᵢ > 1 && (G = G^2)
end

Check warning on line 862 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L855-L862

Added lines #L855 - L862 were not covered by tests

return only(hij)

Check warning on line 864 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L864

Added line #L864 was not covered by tests
end

## issue #519 polynomial multiplication via FFT
## cf. http://www.cs.toronto.edu/~denisp/csc373/docs/tutorial3-adv-writeup.pdf
## Compute recursive_fft
## assumes length(as) = 2^k for some k
## ωₙ is exp(-2pi*im/n) or Cyclotomics.E(n), the latter slower but non-lossy
function recursive_fft(as, ωₙ = nothing)
n = length(as)
N = 2^ceil(Int, log2(n))
ω = something(ωₙ, exp(-2pi*im/N))
R = typeof(ω * first(as))
ys = Vector{R}(undef, N)
recursive_fft!(ys, as, ω)
ys

Check warning on line 879 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L872-L879

Added lines #L872 - L879 were not covered by tests
end

## pass in same ωₙ as recursive_fft
function inverse_fft(as, ωₙ=nothing)
n = length(as)
ω = something(ωₙ, exp(-2pi*im/n))
recursive_fft(as, conj(ω)) / n

Check warning on line 886 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L883-L886

Added lines #L883 - L886 were not covered by tests
end

# note: can write version for big coefficients, but still allocates a bit
function recursive_fft!(ys, as, ωₙ)

Check warning on line 890 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L890

Added line #L890 was not covered by tests

n = length(as)
@assert n == length(ys) == 2^(ceil(Int, log2(n)))

Check warning on line 893 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L892-L893

Added lines #L892 - L893 were not covered by tests

ω = one(ωₙ) * one(first(as))
isone(n) && (ys[1] = ω * as[1]; return ys)

Check warning on line 896 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L895-L896

Added lines #L895 - L896 were not covered by tests

o = 1
eidx = o .+ range(0, n-2, step=2)
oidx = o .+ range(1, n-1, step=2)

Check warning on line 900 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L898-L900

Added lines #L898 - L900 were not covered by tests

n2 = n ÷ 2

Check warning on line 902 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L902

Added line #L902 was not covered by tests

ye = recursive_fft!(view(ys, 1:n2), view(as, eidx), ωₙ^2)
yo = recursive_fft!(view(ys, (n2+1):n), view(as, oidx), ωₙ^2)

Check warning on line 905 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L904-L905

Added lines #L904 - L905 were not covered by tests

@inbounds for k ∈ o .+ range(0, n2 - 1)
yₑ, yₒ = ye[k], yo[k]
ys[k ] = muladd(ω, yₒ, yₑ)
ys[k + n2] = yₑ - ω*yₒ
ω *= ωₙ
end
return ys

Check warning on line 913 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L907-L913

Added lines #L907 - L913 were not covered by tests
end

# This *should* be faster -- (O(nlog(n)), but this version is definitely not so.
# when `ωₙ = Cyclotomics.E` and T,S are integer, this can be exact
function poly_multiplication_fft(p::P, q::Q, ωₙ=nothing) where {T,P<:StandardBasisPolynomial{T},

Check warning on line 918 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L918

Added line #L918 was not covered by tests
S,Q<:StandardBasisPolynomial{S}}
as, bs = coeffs0(p), coeffs0(q)
n = maximum(length, (as, bs))
N = 2^ceil(Int, log2(n))

Check warning on line 922 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L920-L922

Added lines #L920 - L922 were not covered by tests

as′ = zeros(promote_type(T,S), 2N)
copy!(view(as′, 1:length(as)), as)

Check warning on line 925 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L924-L925

Added lines #L924 - L925 were not covered by tests

ω = something(ωₙ, n -> exp(-2im*pi/n))(2N)
âs = recursive_fft(as′, ω)

Check warning on line 928 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L927-L928

Added lines #L927 - L928 were not covered by tests

as′ .= 0
copy!(view(as′, 1:length(bs)), bs)
b̂s = recursive_fft(as′, ω)

Check warning on line 932 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L930-L932

Added lines #L930 - L932 were not covered by tests

âb̂s = âs .* b̂s

Check warning on line 934 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L934

Added line #L934 was not covered by tests

PP = promote_type(P,Q)
⟒(PP)(inverse_fft(âb̂s, ω))

Check warning on line 937 in src/polynomials/standard-basis/standard-basis.jl

View check run for this annotation

Codecov / codecov/patch

src/polynomials/standard-basis/standard-basis.jl#L936-L937

Added lines #L936 - L937 were not covered by tests
end


## --------------------------------------------------
Expand Down
Loading