diff --git a/docs/src/refs.bib b/docs/src/refs.bib index 0f1d5e40..67caf6b3 100644 --- a/docs/src/refs.bib +++ b/docs/src/refs.bib @@ -13,6 +13,19 @@ @Article{GHLMP96 doi = {10.1007/BF01190329} } +@Article{Kem21, + author = {Kempner, Aubrey J.}, + title = {Polynomials and their residue systems}, + mrnumber = {1501173}, + journal = {Trans. Amer. Math. Soc.}, + fjournal = {Transactions of the American Mathematical Society}, + volume = {22}, + number = {2}, + pages = {240--266}, + year = {1921}, + doi = {10.2307/1989020} +} + @Book{OSCAR, bibkey = {OSCAR}, title = {The Computer Algebra System OSCAR: Algorithms and Examples}, @@ -24,19 +37,3 @@ @Book{OSCAR month = {8}, url = {https://link.springer.com/book/9783031621260} } - -@Article{MR1501173, - author = {Kempner, Aubrey J.}, - title = {Polynomials and their residue systems}, - journal = {Trans. Amer. Math. Soc.}, - fjournal = {Transactions of the American Mathematical Society}, - volume = {22}, - year = {1921}, - number = {2}, - pages = {240--266}, - issn = {0002-9947,1088-6850}, - mrclass = {11C08 (13P99)}, - mrnumber = {1501173}, - doi = {10.2307/1989020}, - url = {https://doi.org/10.2307/1989020}, -} diff --git a/src/GenericCyclotomics.jl b/src/GenericCyclotomics.jl index 5fad9b4d..cc223405 100644 --- a/src/GenericCyclotomics.jl +++ b/src/GenericCyclotomics.jl @@ -61,7 +61,7 @@ end kempner(m::Int64) Return the minimal non-negative integer `k` such that `k!` is a multiple of `m`. This is called the `m`-th Kempner number. -Details about the Kempner numbers and how to compute them can be found in [MR1501173](@cite). +Details about the Kempner numbers and how to compute them can be found in [Kem21](@cite). # Examples ```jldoctest @@ -417,8 +417,13 @@ function (R::GenericCycloRing)(f::Dict{UPolyFrac, UPoly}; simplify::Bool=true) if !simplify return GenericCyclo(f, R) end + + if length(f) == 1 && is_one(numerator(first(first(f)))) + return GenericCyclo(f, R) + end # congruence preparation + # 68 allocations if R.congruence !== nothing q=gen(base_ring(R), 1) substitute=R.congruence[2]*q+R.congruence[1] @@ -426,17 +431,23 @@ function (R::GenericCycloRing)(f::Dict{UPolyFrac, UPoly}; simplify::Bool=true) end # reduce numerators modulo denominators + # 757 allocations -> 444 L=NTuple{4, UPoly}[] for (g,c) in f - if !iszero(c) - if R.congruence === nothing - gp=g - else - gp=evaluate(numerator(g), [1], [substitute])//evaluate(denominator(g), [1], [substitute]) - end - a,r=divrem(numerator(gp),denominator(gp)) - push!(L,(c,denominator(gp),r,a)) - end + iszero(c) && continue + + n = numerator(g, false) + d = denominator(g, false) + if R.congruence !== nothing + if !is_constant(n) n=evaluate(n, [1], [substitute]) end + if !is_constant(d) d=evaluate(d, [1], [substitute]) end + end + if is_one(n) + a,r=zero(n),n + else + a,r=divrem(n,d) + end + push!(L,(c,d,r,a)) end # return early if `L` is empty @@ -463,22 +474,22 @@ function (R::GenericCycloRing)(f::Dict{UPolyFrac, UPoly}; simplify::Bool=true) fp=Dict{UPolyFrac, UPoly}() for (c,g_2,r,a) in L # normalize the polynomial part of the exponent - ap=normal_form(change_base_ring(ZZ,d*a), d) + ap=normal_form(change_base_ring(ZZ,d*a), d) # 32 allocations # normalize the constant part t=constant_coefficient(ap) - app=change_base_ring(base_ring(base_ring(R)), ap-t, parent=base_ring(R)) - S,x=ZZ[:x] - p=mod(x^t,cyclotomic_polynomial(d,S)) + app=change_base_ring(base_ring(base_ring(R)), ap-t, parent=base_ring(R)) # 25 allocations + SSSS,x=ZZ[:x] + p=mod(x^t,cyclotomic_polynomial(d,SSSS)) # distribute the normalized constant part for (i,cp) in enumerate(coefficients(p)) tp=i-1 - g=1//d*app+r//g_2+tp//d + g=1//d*app+r//g_2+tp//d # 153 allocations if R.congruence === nothing gp=g else - gp=evaluate(numerator(g), [1], [substitute_inv])//evaluate(denominator(g), [1], [substitute_inv]) + gp=evaluate(numerator(g), [1], [substitute_inv])//evaluate(denominator(g), [1], [substitute_inv]) # 692 allocations end if haskey(fp,gp) fp[gp]+=cp*c