Skip to content

Commit

Permalink
support immutable parents (#537)
Browse files Browse the repository at this point in the history
Co-authored-by: Tommy Hofmann <thofma@gmail.com>
Co-authored-by: Max Horn <max@quendi.de>
  • Loading branch information
3 people committed Jan 13, 2022
1 parent 5b4827a commit fc255ce
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 31 deletions.
92 changes: 67 additions & 25 deletions src/number/n_unknown.jl
Expand Up @@ -287,7 +287,10 @@ end
#
###############################################################################

# mutable
# Singular needs addresses for both elements and parents.
# Both of these wrappers are to provide singular with addresses for both
# element objects and parent objects in case that the julia object does not
# support pointer_from_objref.
mutable struct RingWrapper{S, T} <: Nemo.Ring
data::S
end
Expand All @@ -314,6 +317,20 @@ function promote_rule(::Type{n_FieldElem{FieldElemWrapper{S, T}}}, ::Type{T}) wh
return n_FieldElem{FieldElemWrapper{S, T}}
end

# julia says the above are ambiguous on these cases
function promote_rule(::Type{Singular.n_RingElem{Singular.RingElemWrapper{S, Nemo.fmpz}}}, ::Type{Nemo.fmpz}) where S
return Singular.n_RingElem{Singular.RingElemWrapper{S, Nemo.fmpz}}
end

function promote_rule(::Type{Singular.n_FieldElem{Singular.FieldElemWrapper{S, Nemo.fmpq}}}, ::Type{Nemo.fmpz}) where S
return Singular.n_FieldElem{Singular.FieldElemWrapper{S, Nemo.fmpq}}
end

function promote_rule(::Type{Singular.n_FieldElem{Singular.FieldElemWrapper{S, Nemo.fmpq}}}, ::Type{Nemo.fmpq}) where S
return Singular.n_FieldElem{Singular.FieldElemWrapper{S, Nemo.fmpq}}
end


function expressify(a::Union{RingWrapper, FieldWrapper}; context = nothing)
return expressify(a.data, context = context)
end
Expand All @@ -333,9 +350,13 @@ end
elem_type(::Type{RingWrapper{S, T}}) where {S, T} = RingElemWrapper{S, T}
elem_type(::Type{FieldWrapper{S, T}}) where {S, T} = FieldElemWrapper{S, T}

parent_type(a::Type{RingElemWrapper{S, T}}) where {S, T} = RingWrapper{S, T}
parent_type(a::Type{FieldElemWrapper{S, T}}) where {S, T} = FieldWrapper{S, T}

parent(a::RingElemWrapper{S, T}) where {S, T} = a.parent
parent(a::FieldElemWrapper{S, T}) where {S, T} = a.parent


function (R::RingWrapper{S, T})() where {S, T}
return RingElemWrapper{S, T}(R.data(), R)
end
Expand Down Expand Up @@ -416,7 +437,7 @@ for op in (:iszero, :isone)
end

# one input, one wrapped output
for op in (:-, :zero, :one, :inv)
for op in (:-, :zero, :one, :inv, :canonical_unit)
@eval begin
function ($op)(a::($rew){S, T}) where {S, T}
return ($rew){S, T}(($op)(a.data), a.parent)
Expand Down Expand Up @@ -486,29 +507,50 @@ end

end # for (rw, rew) in

################################################################################
#
# Coefficient ring wrapper
#
################################################################################

function CoefficientRing(R::Nemo.Ring)
T = elem_type(R)

if VERSION >= v"1.8"
ok = ismutabletype(T)
else
ok = ismutable(R())
end
CoefficientRingID = Dict{Nemo.Ring, Any}()

if R isa Nemo.Field
if ok
return N_Field{T}(R)
else
RR = FieldWrapper{typeof(R), elem_type(R)}(R)
return N_Field{elem_type(RR)}(RR)
end
else
if ok
return N_Ring{T}(R)
else
RR = RingWrapper{typeof(R), elem_type(R)}(R)
return N_Ring{elem_type(RR)}(RR)
end
end
# We wrap everything into an N_Field or N_Ring.
# But if the ring or the element type is mutable, we have to wrap them first
# into something mutable (RingWrapper and FieldWrapper)
#
# To keep it type stable, we use a @generated function to treat being mutable
# as a property available at compile time.

if VERSION < v"1.7"
# This function was added in >= 1.7
ismutabletype(::Type{T}) where {T} = T.mutable
end

@generated function mutable_field_or_ring_type_wrapper(::Type{T}, ::Type{U}) where {T <: Nemo.Ring, U}
if ismutabletype(T) && ismutabletype(U)
S = T
elseif T <: Nemo.Field
S = FieldWrapper{T, U}
else
S = RingWrapper{T, U}
end
return :($S)
end

function CoefficientRing(R::T, cached::Bool = true) where {T <: Nemo.Ring}
U = elem_type(T)
wrappertype = mutable_field_or_ring_type_wrapper(T, U)
wrapperelemtype = elem_type(wrappertype)
rettype = T <: Nemo.Field ? N_Field{wrapperelemtype} : N_Ring{wrapperelemtype}
return AbstractAlgebra.get_cached!(CoefficientRingID, R, cached) do
if ismutabletype(T) && ismutabletype(U)
newring = R
elseif T <: Nemo.Field
newring = FieldWrapper{T, U}(R)
else
newring = RingWrapper{T, U}(R)
end
return rettype(newring)
end::rettype
end
27 changes: 27 additions & 0 deletions src/poly/poly.jl
Expand Up @@ -1203,6 +1203,33 @@ function (R::AbstractAlgebra.Generic.MPolyRing{T})(p::Singular.spoly{Singular.n_
return finish(B)
end


function (R::AbstractAlgebra.Generic.MPolyRing{T})(
p::Singular.spoly{Singular.n_RingElem{Singular.RingElemWrapper{S, T}}}
) where {S, T <: Nemo.RingElem}

B = MPolyBuildCtx(R)
cvzip = zip(coefficients(p), exponent_vectors(p))
for (c, v) in cvzip
cc = GC.@preserve c libSingular.julia(libSingular.cast_number_to_void(c.ptr))
push_term!(B, cc.data, v)
end
return finish(B)
end

function (R::AbstractAlgebra.Generic.MPolyRing{T})(
p::Singular.spoly{Singular.n_FieldElem{Singular.FieldElemWrapper{S, T}}}
) where {S, T <: Nemo.FieldElem}

B = MPolyBuildCtx(R)
cvzip = zip(coefficients(p), exponent_vectors(p))
for (c, v) in cvzip
cc = GC.@preserve c libSingular.julia(libSingular.cast_number_to_void(c.ptr))
push_term!(B, cc.data, v)
end
return finish(B)
end

###############################################################################
#
# Differential functions
Expand Down
8 changes: 4 additions & 4 deletions src/poly/weyl.jl
Expand Up @@ -45,17 +45,17 @@ end
function WeylAlgebra(R::Nemo.Ring, s::Vector{String};
ordering = :degrevlex, ordering2::Symbol = :comp1min,
cached::Bool = true, degree_bound::Int = 0)
R = CoefficientRing(R)
RR = CoefficientRing(R)
s = vcat(s, ["d"*sym for sym in s])
return _WeylAlgebra(R, s, ordering, ordering2, cached, degree_bound)
return _WeylAlgebra(RR, s, ordering, ordering2, cached, degree_bound)
end

function WeylAlgebra(R::Nemo.Ring, s2::Matrix{String};
ordering = :degrevlex, ordering2::Symbol = :comp1min,
cached::Bool = true, degree_bound::Int = 0)
R = CoefficientRing(R)
RR = CoefficientRing(R)
s = vcat(view(s, 1, :), view(s, 2, :))
return _WeylAlgebra(R, s, ordering, ordering2, cached, degree_bound)
return _WeylAlgebra(RR, s, ordering, ordering2, cached, degree_bound)
end

macro WeylAlgebra(R, s, n, o)
Expand Down
7 changes: 5 additions & 2 deletions test/libsingular/nemo-test.jl
Expand Up @@ -6,7 +6,9 @@
f3 = x^2 + 2x + 1

f1c = [c for c in coefficients(f1)]
@test isa(f1c[1], Singular.n_FieldElem{Nemo.fmpq})

# disable this until we figure out if QQ is mutable or not
# @test isa(f1c[1], Singular.n_FieldElem{Singular.FieldElemWrapper{Nemo.FlintRationalField, Nemo.fmpq}})
@test isa(Nemo.QQ(f1c[1]), Nemo.fmpq)
@test !isempty(string(f1c[1]))
@test leading_coefficient(f1) == f1c[1]
Expand Down Expand Up @@ -58,7 +60,8 @@ end
f3 = x^2 + 2x + 1

f1c = [c for c in coefficients(f1)]
@test f1c[1] isa Singular.n_RingElem{Nemo.fmpz}
# disable this until we figure out if ZZ is mutable or not
# @test f1c[1] isa Singular.n_RingElem{Singular.RingElemWrapper{Nemo.FlintIntegerRing, Nemo.fmpz}}
@test Nemo.ZZ(f1c[1]) isa Nemo.fmpz
@test !isempty(string(f1c[1]))
@test leading_coefficient(f1) == f1c[1]
Expand Down

0 comments on commit fc255ce

Please sign in to comment.