Skip to content

Commit

Permalink
Add one(::MPolyQuo) and sort the code a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
thofma committed Jan 25, 2021
1 parent 0d9ab86 commit c0e7dcd
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 144 deletions.
1 change: 1 addition & 0 deletions src/Oscar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ include("Rings/integer.jl")
include("Rings/rational.jl")
include("Rings/Hecke.jl")
include("Rings/mpoly.jl")
include("Rings/MPolyQuo.jl")
include("Rings/mpoly-graded.jl")
include("Rings/mpoly-local.jl")
include("Rings/FinField.jl")
Expand Down
165 changes: 165 additions & 0 deletions src/Rings/MPolyQuo.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
##############################################################################
#
# quotient rings
#
##############################################################################

#TODO: add to singular_ring natively as this is potentially one
mutable struct MPolyQuo{S} <: AbstractAlgebra.Ring
R::MPolyRing
I::MPolyIdeal{S}
AbstractAlgebra.@declare_other

function MPolyQuo(R, I) where S
@assert base_ring(I) == R
r = new{elem_type(R)}()
r.R = R
r.I = I
return r
end
end

function show(io::IO, Q::MPolyQuo)
Hecke.@show_name(io, Q)
Hecke.@show_special(io, Q)
io = IOContext(io, :compact => true)
print(io, "Quotient of $(Q.R) by $(Q.I)")
end

gens(Q::MPolyQuo) = [Q(x) for x = gens(Q.R)]
ngens(Q::MPolyQuo) = ngens(Q.R)
gen(Q::MPolyQuo, i::Int) = Q(gen(Q.R, i))
Base.getindex(Q::MPolyQuo, i::Int) = Q(Q.R[i])

#TODO: think: do we want/ need to keep f on the Singular side to avoid conversions?
# or use Bill's divrem to speed things up?
mutable struct MPolyQuoElem{S} <: RingElem
f::S
P::MPolyQuo{S}
end

AbstractAlgebra.expressify(a::MPolyQuoElem; context = nothing) = expressify(a.f, context = context)

function show(io::IO, a::MPolyQuoElem)
print(io, AbstractAlgebra.obj_to_string(a, context = io))
end

function singular_ring(Rx::MPolyQuo; keep_ordering::Bool = true)
Sx = singular_ring(Rx.R, keep_ordering = keep_ordering)
groebner_assure(Rx.I)
Q = Sx(Singular.libSingular.rQuotientRing(Rx.I.gb.S.ptr, Sx.ptr))
return Q
end

parent_type(::MPolyQuoElem{S}) where S = MPolyQuo{S}
parent_type(::Type{MPolyQuoElem{S}}) where S = MPolyQuo{S}
elem_type(::MPolyQuo{S}) where S= MPolyQuoElem{S}
elem_type(::Type{MPolyQuo{S}}) where S= MPolyQuoElem{S}

canonical_unit(a::MPolyQuoElem) = one(parent(a))

parent(a::MPolyQuoElem) = a.P

+(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f+b.f, a.P)
-(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f-b.f, a.P)
-(a::MPolyQuoElem) = MPolyQuoElem(-a.f, a.P)
*(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f*b.f, a.P)
^(a::MPolyQuoElem, b::Integer) = MPolyQuoElem(Base.power_by_squaring(a.f, b), a.P)

function Oscar.mul!(a::MPolyQuoElem, b::MPolyQuoElem, c::MPolyQuoElem)
a.f = b.f*c.f
return a
end

function Oscar.addeq!(a::MPolyQuoElem, b::MPolyQuoElem)
a.f += b.f
return a
end

function simplify!(a::MPolyQuoElem)
R = parent(a)
I = R.I
groebner_assure(I)
singular_assure(I.gb)
Sx = base_ring(I.gb.S)
I.gb.S.isGB = true
f = a.f
a.f = convert(I.gens.Ox, reduce(convert(Sx, f), I.gb.S))
return a
end

function ==(a::MPolyQuoElem, b::MPolyQuoElem)
simplify!(a)
simplify!(b)
return a.f == b.f
end

function quo(R::MPolyRing, I::MPolyIdeal)
q = MPolyQuo(R, I)
function im(a::MPolyElem)
return MPolyQuoElem(a, q)
end
function pr(a::MPolyQuoElem)
return a.f
end
return q, MapFromFunc(im, pr, R, q)
end

lift(a::MPolyQuoElem) = a.f

(Q::MPolyQuo)() = MPolyQuoElem(Q.R(), Q)
(Q::MPolyQuo)(a::MPolyQuoElem) = a
(Q::MPolyQuo)(a) = MPolyQuoElem(Q.R(a), Q)

zero(Q::MPolyQuo) = Q(0)

one(Q::MPolyQuo) = Q(1)

#TODO: find a more descriptive, meaningful name
function _kbase(Q::MPolyQuo)
I = Q.I
groebner_assure(I)
s = Singular.kbase(I.gb.S)
if iszero(s)
error("ideal was no zero-dimensional")
end
return [convert(Q.R, x) for x = gens(s)]
end

#TODO: the reverse map...
# problem: the "canonical" reps are not the monomials.
function vector_space(K::AbstractAlgebra.Field, Q::MPolyQuo)
R = Q.R
@assert K == base_ring(R)
l = _kbase(Q)
V = free_module(K, length(l))
function im(a::Generic.FreeModuleElem)
@assert parent(a) == V
b = R(0)
for i=1:length(l)
c = a[i]
if !iszero(c)
b += c*l[i]
end
end
return Q(b)
end
return MapFromFunc(im, V, Q)
end

################################################################################
#
# To fix printing of fraction fields of MPolyQuo
#
################################################################################

function AbstractAlgebra.expressify(a::AbstractAlgebra.Generic.Frac{T};
context = nothing) where {T <: MPolyQuoElem}
n = numerator(a, false)
d = denominator(a, false)
if isone(d)
return expressify(n, context = context)
else
return Expr(:call, ://, expressify(n, context = context), expressify(d, context = context))
end
end
144 changes: 0 additions & 144 deletions src/Rings/mpoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1079,147 +1079,3 @@ function factor(f::MPolyElem)
return Nemo.Fac(convert(R, fS.unit), Dict(convert(R, k) =>v for (k,v) = fS.fac))
end
=#

##############################################################################
#
# quotient rings
#
##############################################################################
#TODO: add to singular_ring natively as this is potentially one
mutable struct MPolyQuo{S} <: AbstractAlgebra.Ring
R::MPolyRing
I::MPolyIdeal{S}
AbstractAlgebra.@declare_other

function MPolyQuo(R, I) where S
@assert base_ring(I) == R
r = new{elem_type(R)}()
r.R = R
r.I = I
return r
end
end

function show(io::IO, Q::MPolyQuo)
Hecke.@show_name(io, Q)
Hecke.@show_special(io, Q)
io = IOContext(io, :compact => true)
print(io, "Quotient of $(Q.R) by $(Q.I)")
end

gens(Q::MPolyQuo) = [Q(x) for x = gens(Q.R)]
ngens(Q::MPolyQuo) = ngens(Q.R)
gen(Q::MPolyQuo, i::Int) = Q(gen(Q.R, i))
Base.getindex(Q::MPolyQuo, i::Int) = Q(Q.R[i])

#TODO: think: do we want/ need to keep f on the Singular side to avoid conversions?
# or use Bill's divrem to speed things up?
mutable struct MPolyQuoElem{S} <: RingElem
f::S
P::MPolyQuo{S}
end

function show(io::IO, A::MPolyQuoElem)
print(io, A.f)
end

function singular_ring(Rx::MPolyQuo; keep_ordering::Bool = true)
Sx = singular_ring(Rx.R, keep_ordering = keep_ordering)
groebner_assure(Rx.I)
Q = Sx(Singular.libSingular.rQuotientRing(Rx.I.gb.S.ptr, Sx.ptr))
return Q
end

parent_type(::MPolyQuoElem{S}) where S = MPolyQuo{S}
parent_type(::Type{MPolyQuoElem{S}}) where S = MPolyQuo{S}
elem_type(::MPolyQuo{S}) where S= MPolyQuoElem{S}
elem_type(::Type{MPolyQuo{S}}) where S= MPolyQuoElem{S}

parent(a::MPolyQuoElem) = a.P

+(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f+b.f, a.P)
-(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f-b.f, a.P)
-(a::MPolyQuoElem) = MPolyQuoElem(-a.f, a.P)
*(a::MPolyQuoElem, b::MPolyQuoElem) = MPolyQuoElem(a.f*b.f, a.P)
^(a::MPolyQuoElem, b::Integer) = MPolyQuoElem(Base.power_by_squaring(a.f, b), a.P)

function Oscar.mul!(a::MPolyQuoElem, b::MPolyQuoElem, c::MPolyQuoElem)
a.f = b.f*c.f
return a
end

function Oscar.addeq!(a::MPolyQuoElem, b::MPolyQuoElem)
a.f += b.f
return a
end

function simplify!(a::MPolyQuoElem)
R = parent(a)
I = R.I
groebner_assure(I)
singular_assure(I.gb)
Sx = base_ring(I.gb.S)
I.gb.S.isGB = true
f = a.f
a.f = convert(I.gens.Ox, reduce(convert(Sx, f), I.gb.S))
return a
end

function ==(a::MPolyQuoElem, b::MPolyQuoElem)
simplify!(a)
simplify!(b)
return a.f == b.f
end

function quo(R::MPolyRing, I::MPolyIdeal)
q = MPolyQuo(R, I)
function im(a::MPolyElem)
return MPolyQuoElem(a, q)
end
function pr(a::MPolyQuoElem)
return a.f
end
return q, MapFromFunc(im, pr, R, q)
end

lift(a::MPolyQuoElem) = a.f

(Q::MPolyQuo)() = MPolyQuoElem(Q.R(), Q)
(Q::MPolyQuo)(a::MPolyQuoElem) = a
(Q::MPolyQuo)(a) = MPolyQuoElem(Q.R(a), Q)

zero(Q::MPolyQuo) = Q(0)

#TODO: find a more descriptive, meaningful name
function _kbase(Q::MPolyQuo)
I = Q.I
groebner_assure(I)
s = Singular.kbase(I.gb.S)
if iszero(s)
error("ideal was no zero-dimensional")
end
return [convert(Q.R, x) for x = gens(s)]
end

#TODO: the reverse map...
# problem: the "canonical" reps are not the monomials.
function vector_space(K::AbstractAlgebra.Field, Q::MPolyQuo)
R = Q.R
@assert K == base_ring(R)
l = _kbase(Q)
V = free_module(K, length(l))
function im(a::Generic.FreeModuleElem)
@assert parent(a) == V
b = R(0)
for i=1:length(l)
c = a[i]
if !iszero(c)
b += c*l[i]
end
end
return Q(b)
end
return MapFromFunc(im, V, Q)
end

#end #MPolyModule
10 changes: 10 additions & 0 deletions test/Rings/MPolyQuo.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@testset "MPolyQuo" begin
R, (x,y) = PolynomialRing(QQ, ["x", "y"])

f = y^2+y+x^2
C = ideal(R, [f])
Q, = quo(R, C)

@test one(Q) == 1
@test zero(Q) == 0
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ include("Rings/rational-test.jl")
include("Rings/mpoly-test.jl")
include("Rings/mpoly-graded-test.jl")
include("Rings/mpoly-local-test.jl")
include("Rings/MPolyQuo.jl")
include("Rings/slpolys-test.jl")
include("Polymake/nmbthy-test.jl")
include("Groups/runtests.jl")
Expand Down

0 comments on commit c0e7dcd

Please sign in to comment.