diff --git a/src/Rings/mpolyquo-localizations.jl b/src/Rings/mpolyquo-localizations.jl index e0e3ecf557d3..173b6761cd4e 100644 --- a/src/Rings/mpolyquo-localizations.jl +++ b/src/Rings/mpolyquo-localizations.jl @@ -1850,6 +1850,83 @@ function vector_space_dimension(R::MPolyQuoLocRing{<:Field, <:Any,<:Any, <:Any, return vector_space_dimension(quo(base_ring(R),ideal(base_ring(R),gens(LI)))[1]) end +@doc raw""" + _monomial_basis(L::MPolyLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}, I::MPolyLocalizedIdeal) + +If, say, `A = L/I`, where `L` is a localization of multivariate polynomial ring over a field +`K` at a point `p`, and `I` is an ideal of `L`, return a vector of monomials of `L` +such that the residue classes of these monomials form a basis of `A` as a `K`-vector +space. +!!! note + This is an internal method for computing a monomial basis without creating the quotient. +""" +function _monomial_basis(L::MPolyLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}, I::MPolyLocalizedIdeal) + base_ring(I) == L || error("ideal does not belong to the correct ring") + G = numerator.(gens(I)) + shift,_ = base_ring_shifts(L) + G_0 = shift.(G) + R = base_ring(L) + LI = leading_ideal(ideal(R, G_0), ordering = negdeglex(R)) + return L.(monomial_basis(quo(R, LI)[1])) +end + +@doc raw""" + monomial_basis(A::MPolyQuoLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}) + +If, say, `A = L/I`, where `L` is a localization of multivariate polynomial ring over a field +`K` at a point `p`, and `I` is an ideal of `L`, return a vector of monomials of `L` +such that the residue classes of these monomials form a basis of `A` as a `K`-vector +space. +!!! note + The monomials are for readabilty in the varibles of the underlying polynomial ring of `L` and not in the variables of power series ring $K[[x_1-p_1,...,x_n-p_n]]$ in which `L` is embedded. +!!! note + If `A` is not finite-dimensional as a `K`-vector space, an error is thrown. +# Examples +```jldoctest +julia> R, (x,y) = QQ["x","y"]; + +julia> f = (x^2-y^3)*(y-1); # 3 singularities, a cusp singularity and two node singularities + +julia> A = tjurina_algebra(f) +Quotient + of multivariate polynomial ring in 2 variables x, y + over rational field + by ideal (x^2*y - x^2 - y^4 + y^3, 2*x*y - 2*x, x^2 - 4*y^3 + 3*y^2) + +julia> monomial_basis(A) +4-element Vector{QQMPolyRingElem}: + y^2 + y + x + 1 + +julia> Aloc0,_ = localization(A, complement_of_point_ideal(R, [0,0])); + +julia> monomial_basis(Aloc0) +2-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}: + y + 1 + +julia> Aloc1,_ = localization(A, complement_of_point_ideal(R, [1,1])); + +julia> monomial_basis(Aloc1) +1-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}: + 1 + +julia> Aloc2,_ = localization(A, complement_of_point_ideal(R, [-1,1])); + +julia> monomial_basis(Aloc2) +1-element Vector{Oscar.MPolyLocRingElem{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem, Oscar.MPolyComplementOfKPointIdeal{QQField, QQFieldElem, QQMPolyRing, QQMPolyRingElem}}}: + 1 + +julia> vector_space_dimension(A) == vector_space_dimension(Aloc0) + vector_space_dimension(Aloc1) + vector_space_dimension(Aloc2) +true +``` +""" +function monomial_basis(A::MPolyQuoLocRing{<:Field, <:Any, <:Any, <:Any, <:MPolyComplementOfKPointIdeal}) + return _monomial_basis(localized_ring(A), modulus(A)) +end + function is_finite_dimensional_vector_space(R::MPolyQuoLocRing) throw(NotImplementedError(:is_finite_dimensional_vector_space, R)) end diff --git a/test/Rings/mpolyquo-localizations.jl b/test/Rings/mpolyquo-localizations.jl index d3c910c10662..ce7a37d225de 100644 --- a/test/Rings/mpolyquo-localizations.jl +++ b/test/Rings/mpolyquo-localizations.jl @@ -510,3 +510,20 @@ end @test Oscar._get_generators_string_one_line(ideal(R, x)) == "with 100 generators" @test Oscar._get_generators_string_one_line(ideal(R, [sum(x)])) == "with 1 generator" end + +@testset "monomial_basis MPolyQuoLocRing" begin + R, (x,y) = QQ["x", "y"] + L, _ = localization(R, complement_of_point_ideal(R, [0,0])) + Q1, _ = quo(L, ideal(L, L(x+1))) + @test isempty(monomial_basis(Q1)) + Q2, _ = quo(L, ideal(L, L(x^2))) + @test_throws InfiniteDimensionError() monomial_basis(Q2) + Q3, _ = quo(L, ideal(L, L.([x^2, y^3]))) + @test monomial_basis(Q3) == L.([x*y^2, y^2, x*y, y, x, 1]) + Q4,_ = quo(L, ideal(L, [x^2-x, y^2-2*y])) + @test monomial_basis(Q4) == [L(1)] #test for difference in localized and non-localized case + @test Oscar._monomial_basis(L, ideal(L, [x^3*(x-1), y*(y-1)*(y-2)])) == L.([x^2, x, 1]) + L1, _ = localization(R, complement_of_point_ideal(R, [1,2])) + @test Oscar._monomial_basis(L1, ideal(L1, [(x-1)^2, (y-2)^2])) == L1.([x*y, y, x, 1]) + @test isempty(Oscar._monomial_basis(L1, ideal(L1, L1.([x, y])))) +end