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

Unsafe funcs for FreeAssAlgebra, Poly, MPoly #1847

Merged
merged 6 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
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
142 changes: 141 additions & 1 deletion src/generic/FreeAssociativeAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
if length(a) < 1
return isone(zero(base_ring(a)))
else
return a.length == 1 && isone(a.coeffs[1]) && isempty(a.exps[1])
return length(a) == 1 && isone(a.coeffs[1]) && isempty(a.exps[1])
end
end

Expand Down Expand Up @@ -646,6 +646,146 @@
return combine_like_terms!(FreeAssociativeAlgebraElem{T}(R, zcoeffs, copy(a.exps), n))
end

###############################################################################
#
# Unsafe arithmetic functions
#
###############################################################################

function zero!(a::FreeAssociativeAlgebraElem{T}) where T <: RingElement
a.length = 0
return a
end

function one!(a::FreeAssociativeAlgebraElem{T}) where T <: RingElement
a.length = 1
fit!(a, 1)
a.coeffs[1] = one(base_ring(parent(a)))
a.exps[1] = Int[]
return a
end

function neg!(a::FreeAssociativeAlgebraElem{T}) where T <: RingElement
for i in 1:length(a)
a.coeffs[i] = neg!(a.coeffs[i])
end
return a
end

function neg!(z::FreeAssociativeAlgebraElem{T}, a::FreeAssociativeAlgebraElem{T}) where T <: RingElement
if z === a
return neg!(a)

Check warning on line 677 in src/generic/FreeAssociativeAlgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/generic/FreeAssociativeAlgebra.jl#L677

Added line #L677 was not covered by tests
end
z.length = length(a)
fit!(z, length(a))
for i in 1:length(a)
if isassigned(z.coeffs, i)
z.coeffs[i] = neg!(z.coeffs[i], a.coeffs[i])
else
z.coeffs[i] = -a.coeffs[i]
end
# mutating z.exps[i] is not allowed since it could be aliased
z.exps[i] = a.exps[i]
end
return z
end

function add!(a::FreeAssociativeAlgebraElem{T}, b::FreeAssociativeAlgebraElem{T}) where T <: RingElement
iszero(b) && return a
return add!(zero(a), a, b)
end

function add!(z::FreeAssociativeAlgebraElem{T}, a::FreeAssociativeAlgebraElem{T}, b::FreeAssociativeAlgebraElem{T}) where T <: RingElement
if z === a
return add!(z, b)
elseif z === b
return add!(z, a)
end
z.coeffs = empty!(z.coeffs)
z.exps = empty!(z.exps)
i = j = 1
while i <= a.length && j <= b.length
c = word_cmp(a.exps[i], b.exps[j])
if c < 0
push!(z.coeffs, b.coeffs[j])
push!(z.exps, b.exps[j])
j += 1
elseif c > 0
push!(z.coeffs, a.coeffs[i])
push!(z.exps, a.exps[i])
i += 1
else
s = a.coeffs[i] + b.coeffs[j]
if !iszero(s)
push!(z.coeffs, s)
push!(z.exps, a.exps[i])
end
i += 1
j += 1
end
end
while i <= a.length
push!(z.coeffs, a.coeffs[i])
push!(z.exps, a.exps[i])
i += 1
end
while j <= b.length
push!(z.coeffs, b.coeffs[j])
push!(z.exps, b.exps[j])
j += 1
end
z.length = length(z.coeffs)
return z
end

function sub!(a::FreeAssociativeAlgebraElem{T}, b::FreeAssociativeAlgebraElem{T}) where T <: RingElement
iszero(b) && return a
return sub!(zero(a), a, b)
end

function sub!(z::FreeAssociativeAlgebraElem{T}, a::FreeAssociativeAlgebraElem{T}, b::FreeAssociativeAlgebraElem{T}) where T <: RingElement
if z === a
return sub!(z, b)
elseif z === b
return sub!(zero(a), a, b)
end
z.coeffs = empty!(z.coeffs)
z.exps = empty!(z.exps)
i = j = 1
while i <= a.length && j <= b.length
c = word_cmp(a.exps[i], b.exps[j])
if c < 0
push!(z.coeffs, -b.coeffs[j])
push!(z.exps, b.exps[j])
j += 1
elseif c > 0
push!(z.coeffs, a.coeffs[i])
push!(z.exps, a.exps[i])
i += 1
else
s = a.coeffs[i] - b.coeffs[j]
if !iszero(s)
push!(z.coeffs, s)
push!(z.exps, a.exps[i])
end
i += 1
j += 1
end
end
while i <= a.length
push!(z.coeffs, a.coeffs[i])
push!(z.exps, a.exps[i])
i += 1
end
while j <= b.length
push!(z.coeffs, -b.coeffs[j])
push!(z.exps, b.exps[j])
j += 1
end
z.length = length(z.coeffs)
return z
end


################################################################################
#
Expand Down
42 changes: 37 additions & 5 deletions src/generic/MPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3886,6 +3886,43 @@ end
#
###############################################################################

function zero!(a::MPoly{T}) where {T <: RingElement}
a.length = 0
return a
end

function one!(a::MPoly{T}) where {T <: RingElement}
a.length = 1
fit!(a, 1)
a.coeffs[1] = one(base_ring(a))
a.exps = zero(a.exps)
return a
end

function neg!(a::MPoly{T}) where {T <: RingElement}
for i in 1:length(a)
a.coeffs[i] = neg!(a.coeffs[i])
end
return a
end

function neg!(z::MPoly{T}, a::MPoly{T}) where {T <: RingElement}
if z === a
return neg!(a)
end
z.length = length(a)
fit!(z, length(a))
for i in 1:length(a)
if isassigned(z.coeffs, i)
z.coeffs[i] = neg!(z.coeffs[i], a.coeffs[i])
else
z.coeffs[i] = -a.coeffs[i]
end
end
z.exps[:,1:length(a)] .= a.exps[:,1:length(a)]
return z
end

function add!(a::MPoly{T}, b::MPoly{T}, c::MPoly{T}) where {T <: RingElement}
t = b + c
a.coeffs = t.coeffs
Expand Down Expand Up @@ -3933,11 +3970,6 @@ function fit!(a::MPoly{T}, n::Int) where {T <: RingElement}
end
return nothing
end
#
function zero!(a::MPoly{T}) where {T <: RingElement}
a.length = 0
return a
end

@doc raw"""
setcoeff!(a::MPoly{T}, i::Int, c::T) where T <: RingElement
Expand Down
23 changes: 23 additions & 0 deletions src/generic/Poly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,29 @@ function zero!(c::Poly{T}) where T <: RingElement
return c
end

function one!(c::Poly{T}) where T <: RingElement
fit!(c, 1)
c = set_length!(c, 1)
c.coeffs[1] = one(base_ring(c))
return c
end

function neg!(a::Poly{T}) where T <: RingElement
for i in 1:length(a)
a.coeffs[i] = neg!(a.coeffs[i])
end
return a
end

function neg!(z::Poly{T}, a::Poly{T}) where T <: RingElement
fit!(z, length(a))
z = set_length!(z, length(a))
for i in 1:length(a)
z.coeffs[i] = neg!(z.coeffs[i], a.coeffs[i])
end
return z
end

function mul!(c::Poly{T}, a::Poly{T}, b::Poly{T}) where T <: RingElement
lena = length(a)
lenb = length(b)
Expand Down
2 changes: 1 addition & 1 deletion src/generic/UnivPoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ function one!(a::UnivPoly{T}) where {T <: RingElement}
end

function neg!(z::UnivPoly{T}, a::UnivPoly{T}) where {T <: RingElement}
z.p = neg!(a.p)
z.p = neg!(z.p, a.p)
return z
end

Expand Down
1 change: 1 addition & 0 deletions src/generic/imports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ import ..AbstractAlgebra: mul!
import ..AbstractAlgebra: mul_classical
import ..AbstractAlgebra: mul_karatsuba
import ..AbstractAlgebra: mullow
import ..AbstractAlgebra: neg!
import ..AbstractAlgebra: number_of_columns
import ..AbstractAlgebra: number_of_generators
import ..AbstractAlgebra: number_of_rows
Expand Down
25 changes: 25 additions & 0 deletions test/Rings-conformance-tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ function test_elem(Rx::AbstractAlgebra.PolyRing)
return Rx(elem_type(R)[test_elem(R) for i in 1:rand(0:6)])
end

function test_elem(Rx::AbstractAlgebra.MPolyRing)
R = base_ring(Rx)
num_gens = ngens(Rx)
iszero(num_gens) && return Rx(test_elem(R))
len_bound = 8
exp_bound = rand(1:5)
len = rand(0:len_bound)
coeffs = [test_elem(R) for _ in 1:len]
exps = [[rand(0:exp_bound) for _ in 1:num_gens] for _ in 1:len]
return Rx(coeffs, exps)
end

function test_elem(S::Union{AbstractAlgebra.MatSpace,
AbstractAlgebra.MatRing})
R = base_ring(S)
Expand Down Expand Up @@ -72,6 +84,19 @@ function test_elem(Rx::AbstractAlgebra.SeriesRing)
end
end

function test_elem(S::AbstractAlgebra.FreeAssociativeAlgebra)
f = S()
g = gens(S)
R = base_ring(S)
isempty(g) && return S(test_elem(R))
len_bound = 8
exp_bound = 6
for i in 1:rand(0:len_bound)
f += test_elem(R) * prod(rand(g) for _ in 1:rand(0:exp_bound); init = S(1))
end
return f
end


# helper
function equality(a::T, b::T) where T <: AbstractAlgebra.NCRingElement
Expand Down
11 changes: 6 additions & 5 deletions test/generic/FreeAssociativeAlgebra-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,6 @@ end
@test !occursin("\n", sprint(show, R))
end

function test_elem(R::Generic.FreeAssociativeAlgebra{elem_type(ZZ)})
return rand(R, 0:4, 0:5, -10:10)
end

@testset "Generic.FreeAssociativeAlgebra.change_base_ring" begin
F5, = residue_ring(ZZ, 5)
R, varsR = polynomial_ring(F5, ["x"])
Expand Down Expand Up @@ -221,6 +217,11 @@ end
end

@testset "Generic.FreeAssociativeAlgebra.NCRing_interface" begin
test_NCRing_interface(free_associative_algebra(ZZ, 3)[1])
S, = free_associative_algebra(ZZ, 3)
test_NCRing_interface(S)

R, = QQ[:x, :y]
S, = free_associative_algebra(R, :z => 1:3)
test_NCRing_interface(S)
end

15 changes: 15 additions & 0 deletions test/generic/MPoly-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1704,3 +1704,18 @@ end
@test leading_coefficient(f, 1) == coefficients(f, 1)[end]
@test content(f, 1) == y
end

@testset "Generic.MPoly.Ring_interface" begin
S, = polynomial_ring(QQ, 0)
test_Ring_interface_recursive(S)

S, = polynomial_ring(QQ, 1)
test_Ring_interface_recursive(S)

S, = polynomial_ring(ZZ, 2)
test_Ring_interface_recursive(S)

R, = QQ[:x]
S, = polynomial_ring(R, :z => 1:3)
test_Ring_interface(S) # _recursive needs too many ressources
end
Loading