From 7769ffa8553b4d65fcbc5e677a91c0f99e45abf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Wed, 9 Oct 2024 11:43:12 +0200 Subject: [PATCH] Update `exterior_algebra` (#4093) * `have_special_impl` -> `has_special_impl` * Update `exterior_algebra` - unify functions for coefficient field and ring (while still using singular in the former case) - use `@varnames_interface` - re-structure tests * format * fix doctest --- .../PBWAlgebras/quotients.md | 2 +- .../ExteriorAlgebra/src/ExteriorAlgebra.jl | 170 ++++------------ experimental/ExteriorAlgebra/test/runtests.jl | 183 ++++++------------ src/Rings/PBWAlgebraQuo.jl | 22 +-- 4 files changed, 111 insertions(+), 266 deletions(-) diff --git a/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md b/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md index 6625e08213c1..9d59afdcaafe 100644 --- a/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md +++ b/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md @@ -36,7 +36,7 @@ modulo the two-sided ideal $\langle e_1^2,\dots, e_n^2\rangle.$ ```@docs -exterior_algebra +exterior_algebra(::Ring, ::Vector{Symbol}) ``` ## Data Associated to Affine GR-Algebras diff --git a/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl b/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl index b259ba961f09..76b7dbd37dda 100644 --- a/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl +++ b/experimental/ExteriorAlgebra/src/ExteriorAlgebra.jl @@ -1,27 +1,11 @@ -export exterior_algebra # MAIN EXPORT! - -# Commented out old impl: exterior_algebra_PBWAlgQuo (allows coeffs in a non-field) - -#-------------------------------------------- -# Two implementations of exterior algebras: -# (1) delegating everything to Singular -- fast, coeff ring must be a field -# (2) as a quotient of PBW algebra -- slower, coeff ring must be commutative - -# ADVICE: avoid impl (2) which deliberately has an awkward name. +export exterior_algebra # See also: # * tests in Oscar.jl/test/Experimental/ExteriorAlgebra-test.jl # * doc tests in Oscar.jl/docs/src/NoncommutativeAlgebra/PBWAlgebras/quotients.md -# ------------------------------------------------------- -# Exterior algebra: delegating everything to Singular. - #---------------------- MAIN FUNCTION ---------------------- -# exterior_algebra constructor: args are -# - underlying coeff FIELD and -# - number of indets (or list of indet names) - # Returns 2 components: ExtAlg, list of the gens/variables # DEVELOPER DOC @@ -45,66 +29,41 @@ export exterior_algebra # MAIN EXPORT! # PBWAlgQuoElem did not need to change. Its "data" field just refers # to a PBWAlgElem (namely some representative of the class). -# Attach docstring to "abstract" function exterior_algebra, so that -# it is automatically "inherited" by the methods. - @doc raw""" - exterior_algebra(K::Field, numVars::Int) - exterior_algebra(K::Field, listOfVarNames::AbstractVector{<:VarName}) + exterior_algebra(K::Ring, nvars::Int) + exterior_algebra(K::Ring, varnames::AbstractVector{<:VarName}) -The *first form* returns an exterior algebra with coefficient field `K` and -`numVars` variables: `numVars` must be positive, and the variables are - called `e1, e2, ...`. +Given a coefficient ring `K` and variable names, say `varnames = [:x1, :x2, ...]`, +return a tuple `E, [x1, x2, ...] of the exterior algebra `E` over +the polynomial ring `R[x1, x2, \dots]``, and its generators `x1, x2, \dots`. -The *second form* returns an exterior algebra with coefficient field `K`, and -variables named as specified in `listOfVarNames` (which must be non-empty). - -NOTE: Creating an `exterior_algebra` with many variables will create an object -occupying a lot of memory (probably cubic in `numVars`). +If `K` is a field, this function will use a special implementation in Singular. +!!! note + Creating an `exterior_algebra` with many variables will create an object + occupying a lot of memory (probably cubic in `nvars`). # Examples ```jldoctest -julia> ExtAlg, (e1,e2) = exterior_algebra(QQ, 2); +julia> E, (x1,x2) = exterior_algebra(QQ, 2); -julia> e2*e1 --e1*e2 +julia> x2*x1 +-x1*x2 -julia> (e1+e2)^2 # result is automatically reduced! +julia> (x1+x2)^2 # over fields, result is automatically reduced! 0 -julia> ExtAlg, (x,y) = exterior_algebra(QQ, ["x","y"]); +julia> E, (x,y) = exterior_algebra(QQ, ["x","y"]); julia> y*x -x*y ``` """ -function exterior_algebra end - -# --------------------------------- -# -- Method where caller specifies just number of variables +function exterior_algebra(K::Ring, varnames::Vector{Symbol}) + @req !isempty(varnames) "no variables given" + numVars = length(varnames) -function exterior_algebra(K::Field, numVars::Int) - if numVars < 1 - throw(ArgumentError("numVars must be strictly positive, but numVars=$numVars")) - end - return exterior_algebra(K, (k -> "e$k").((1:numVars))) -end - -#--------------------------------- -# Method where caller specifies name of variables. - -function exterior_algebra(K::Field, listOfVarNames::AbstractVector{<:VarName}) - numVars = length(listOfVarNames) - if numVars == 0 - throw(ArgumentError("no variables/indeterminates given")) - end - # if (!allunique(VarNames)) - # throw(ArgumentError("variable names must be distinct")) - # end - - R, indets = polynomial_ring(K, listOfVarNames) - SameCoeffRing = singular_coeff_ring(coefficient_ring(R)) + R, indets = polynomial_ring(K, varnames; cached=false) M = zero_matrix(R, numVars, numVars) for i in 1:(numVars - 1) for j in (i + 1):numVars @@ -113,81 +72,26 @@ function exterior_algebra(K::Field, listOfVarNames::AbstractVector{<:VarName}) end PBW, PBW_indets = pbw_algebra(R, M, degrevlex(indets); check=false) # disable check since we know it is OK! I = two_sided_ideal(PBW, PBW_indets .^ 2) - # Now construct the fast exteriorAlgebra in Singular; - # get var names from PBW in case it had "mangled" them. - P, _ = Singular.polynomial_ring(SameCoeffRing, string.(symbols(PBW))) - SINGULAR_PTR = Singular.libSingular.exteriorAlgebra(Singular.libSingular.rCopy(P.ptr)) - ExtAlg_singular = Singular.create_ring_from_singular_ring(SINGULAR_PTR) - # Create Quotient ring with special implementation: - ExtAlg, _ = quo(PBW, I; SpecialImpl=ExtAlg_singular) # 2nd result is a QuoMap, apparently not needed - ###### set_attribute!(ExtAlg, :is_exterior_algebra, :true) ### DID NOT WORK (see PBWAlgebraQuo.jl) Anyway, the have_special_impl function suffices. - return ExtAlg, gens(ExtAlg) + + if K isa Field + # Now construct the fast exteriorAlgebra in Singular; + # get var names from PBW in case it had "mangled" them. + K_singular = singular_coeff_ring(coefficient_ring(R)) + R_singular, _ = Singular.polynomial_ring(K_singular, symbols(PBW)) + SINGULAR_PTR = Singular.libSingular.exteriorAlgebra( + Singular.libSingular.rCopy(R_singular.ptr) + ) + ExtAlg_singular = Singular.create_ring_from_singular_ring(SINGULAR_PTR) + # Create Quotient ring with special implementation: + ExtAlg, _ = quo(PBW, I; special_impl=ExtAlg_singular) # 2nd result is a QuoMap, apparently not needed + return ExtAlg, gens(ExtAlg) + else + ExtAlg, QuoMap = quo(PBW, I) + return ExtAlg, QuoMap.(PBW_indets) + end end -# COMMENTED OUT "OLD IMPLEMENTATION" (so as not to lose the code) - -# #-------------------------------------------- -# # Exterior algebra implementation as a quotient of a PBW algebra; -# # **PREFER** exterior_algebra over this SLOW implementation! - -# # Returns 2 components: ExtAlg, list of the gens/variables in order (e1,..,en) - -# @doc raw""" -# exterior_algebra_PBWAlgQuo(coeffRing::Ring, numVars::Int) -# exterior_algebra_PBWAlgQuo(coeffRing::Ring, listOfVarNames::Vector{String}) - -# Use `exterior_algebra` in preference to this function when `coeffRing` is a field. - -# The first form returns an exterior algebra with given `coeffRing` and `numVars` variables; -# the variables are called `e1, e2, ...`. The value `numVars` must be positive; be aware that -# large values will create an object occupying a lot of memory (probably cubic in `numVars`). - -# The second form returns an exterior algebra with given `coeffRing`, and variables named -# as specified in `listOfVarNames` (which must be non-empty). - -# # Examples -# ```jldoctest -# julia> ExtAlg, (e1,e2) = exterior_algebra_PBWAlgQuo(QQ, 2); - -# julia> e2*e1 -# -e1*e2 - -# julia> is_zero((e1+e2)^2) -# true - -# julia> ExtAlg, (x,y) = exterior_algebra_PBWAlgQuo(QQ, ["x","y"]); - -# julia> y*x -# -x*y -# ``` -# """ -# function exterior_algebra_PBWAlgQuo(K::Ring, numVars::Int) -# if (numVars < 1) -# throw(ArgumentError("numVars must be strictly positive: numVars=$numVars")) -# end -# return exterior_algebra_PBWAlgQuo(K, (1:numVars) .|> (k -> "e$k")) -# end - -# function exterior_algebra_PBWAlgQuo(K::Ring, listOfVarNames::AbstractVector{<:VarName}) -# numVars = length(listOfVarNames) -# if (numVars == 0) -# throw(ArgumentError("no variables/indeterminates given")) -# end -# # if (!allunique(listOfVarNames)) -# # throw(ArgumentError("variable names must be distinct")) -# # end -# R, indets = polynomial_ring(K, listOfVarNames) -# M = zero_matrix(R, numVars, numVars) -# for i in 1:numVars-1 -# for j in i+1:numVars -# M[i,j] = -indets[i]*indets[j] -# end -# end -# PBW, PBW_indets = pbw_algebra(R, M, degrevlex(indets); check = false) # disable check since we know it is OK! -# I = two_sided_ideal(PBW, PBW_indets.^2) -# ExtAlg,QuoMap = quo(PBW, I) -# return ExtAlg, QuoMap.(PBW_indets) -# end +AbstractAlgebra.@varnames_interface exterior_algebra(K::Ring, varnames) macros = :no # # BUGS/DEFICIENCIES (2023-02-13): # # (1) Computations with elements DO NOT AUTOMATICALLY REDUCE diff --git a/experimental/ExteriorAlgebra/test/runtests.jl b/experimental/ExteriorAlgebra/test/runtests.jl index 96d8b2e118ed..1db6ca9f9b02 100644 --- a/experimental/ExteriorAlgebra/test/runtests.jl +++ b/experimental/ExteriorAlgebra/test/runtests.jl @@ -1,10 +1,5 @@ @testset "ExteriorAlgebra" begin - - ### 2023-02-10 Tests for experimental/ExteriorAlgebra/ExteriorAlgebra.jl - - ######## CONSTRUCTOR TESTs - @test_throws ArgumentError exterior_algebra(QQ, 0) - @testset "exterior_algebra constructor" for (R, n) in [ + @testset "exterior_algebra constructor, R=$R, n=$n" for (R, n) in [ (QQ, 1) # --> special case (is commutative) (QQ, 2) # --> first general case (QQ, 99) # --> Also tried with 999 indets, but takes a long time [~19s] @@ -12,9 +7,10 @@ (GF(3), 4) (residue_field(ZZ, 2)[1], 2) (residue_field(ZZ, 3)[1], 4) - #(GF(1180591620717411303449), 2) - #(residue_field(ZZ, 1180591620717411303449)[1], 2) - ## (GF(2), 1500); ## limit 1500 on my 32Gbyte machine (!NB printing requires a lot of space!) + (GF(1180591620717411303449), 2) + (residue_field(ZZ, 1180591620717411303449)[1], 2) + (ZZ, 3) # coeffs not field + (residue_ring(ZZ, 4)[1], 3) # coeffs not field ] A, g = exterior_algebra(R, n) @test A isa PBWAlgQuo @@ -24,116 +20,63 @@ @test gens(A) == g end - # Duplicate names are allowed - exterior_algebra(QQ, ["x", "y", "x"]) - - @test_throws MethodError exterior_algebra(ZZ, 3) # Coeffs not field - @test_throws MethodError exterior_algebra(residue_ring(ZZ, 4)[1], 3) # Coeffs not field - - @test_throws ArgumentError exterior_algebra(QQ, String[]) # empty name list - - ## (reduced) COMPUTATIONAL SPEED TEST - - ExtAlg, (e1, e2, e3, e4, e5, e6) = exterior_algebra(QQ, 6) - fac1 = - e1 + - 2 * e1 * e2 + - 3 * e1 * e2 * e3 + - 4 * e1 * e2 * e3 * e4 + - 5 * e1 * e2 * e3 * e4 * e5 + - 6 * e1 * e2 * e3 * e4 * e5 * e6 - fac2 = - e6 + - 2 * e5 * e6 + - 3 * e4 * e5 * e6 + - 4 * e3 * e4 * e5 * e6 + - 5 * e2 * e3 * e4 * e5 * e6 + - 6 * e1 * e2 * e3 * e4 * e5 * e6 - prod12 = fac1 * fac2 - prod21 = fac2 * fac1 - expected12 = - 35 * e1 * e2 * e3 * e4 * e5 * e6 + - 4 * e1 * e2 * e3 * e4 * e6 + - 6 * e1 * e2 * e3 * e5 * e6 + - 6 * e1 * e2 * e4 * e5 * e6 + - 4 * e1 * e3 * e4 * e5 * e6 + - 3 * e1 * e2 * e3 * e6 + - 4 * e1 * e2 * e5 * e6 + - 3 * e1 * e4 * e5 * e6 + - 2 * e1 * e2 * e6 + - 2 * e1 * e5 * e6 + - e1 * e6 - expected21 = - -3 * e1 * e2 * e3 * e4 * e5 * e6 + - 4 * e1 * e2 * e3 * e4 * e6 + - 6 * e1 * e2 * e3 * e5 * e6 + - 6 * e1 * e2 * e4 * e5 * e6 + - 4 * e1 * e3 * e4 * e5 * e6 - 3 * e1 * e2 * e3 * e6 + 4 * e1 * e2 * e5 * e6 - - 3 * e1 * e4 * e5 * e6 + - 2 * e1 * e2 * e6 + - 2 * e1 * e5 * e6 - e1 * e6 - @test is_zero(prod12 - expected12) - @test is_zero(prod21 - expected21) - - @test is_zero(fac1 * prod12) - @test is_zero(prod12 * fac1) - @test is_zero(fac2 * prod12) - @test is_zero(prod12 * fac2) + @testset "constructor with no variables" begin + @test_throws ArgumentError exterior_algebra(QQ, 0) + @test_throws ArgumentError exterior_algebra(QQ, Symbol[]) + @test_throws ArgumentError exterior_algebra(ZZ, 0) + @test_throws ArgumentError exterior_algebra(ZZ, Symbol[]) + end - @test is_zero(fac1 * prod21) - @test is_zero(prod21 * fac1) - @test is_zero(fac2 * prod21) - @test is_zero(prod21 * fac2) + @testset "computational test, R=$R" for R in [QQ, ZZ] + E, (e1, e2, e3, e4, e5, e6) = exterior_algebra(R, 6) + fac1 = + e1 + + 2 * e1 * e2 + + 3 * e1 * e2 * e3 + + 4 * e1 * e2 * e3 * e4 + + 5 * e1 * e2 * e3 * e4 * e5 + + 6 * e1 * e2 * e3 * e4 * e5 * e6 + fac2 = + e6 + + 2 * e5 * e6 + + 3 * e4 * e5 * e6 + + 4 * e3 * e4 * e5 * e6 + + 5 * e2 * e3 * e4 * e5 * e6 + + 6 * e1 * e2 * e3 * e4 * e5 * e6 + prod12 = fac1 * fac2 + prod21 = fac2 * fac1 + expected12 = + 35 * e1 * e2 * e3 * e4 * e5 * e6 + + 4 * e1 * e2 * e3 * e4 * e6 + + 6 * e1 * e2 * e3 * e5 * e6 + + 6 * e1 * e2 * e4 * e5 * e6 + + 4 * e1 * e3 * e4 * e5 * e6 + + 3 * e1 * e2 * e3 * e6 + + 4 * e1 * e2 * e5 * e6 + + 3 * e1 * e4 * e5 * e6 + + 2 * e1 * e2 * e6 + + 2 * e1 * e5 * e6 + + e1 * e6 + expected21 = + -3 * e1 * e2 * e3 * e4 * e5 * e6 + + 4 * e1 * e2 * e3 * e4 * e6 + + 6 * e1 * e2 * e3 * e5 * e6 + + 6 * e1 * e2 * e4 * e5 * e6 + + 4 * e1 * e3 * e4 * e5 * e6 - 3 * e1 * e2 * e3 * e6 + 4 * e1 * e2 * e5 * e6 - + 3 * e1 * e4 * e5 * e6 + + 2 * e1 * e2 * e6 + + 2 * e1 * e5 * e6 - e1 * e6 + @test is_zero(prod12 - expected12) + @test is_zero(prod21 - expected21) + + @test is_zero(fac1 * prod12) + @test is_zero(prod12 * fac1) + @test is_zero(fac2 * prod12) + @test is_zero(prod12 * fac2) + + @test is_zero(fac1 * prod21) + @test is_zero(prod21 * fac1) + @test is_zero(fac2 * prod21) + @test is_zero(prod21 * fac2) + end end - -# # ------------------------------------------------------- -# # Duplicate of test above, but using the PBWAlgQuo implementation: - -# @testset "ExteriorAlgebra_PBWAlgQuo" begin - -# ### 2023-02-10 Tests for experimental/ExteriorAlgebra/ExteriorAlgebra_PBWAlgQuo.jl - -# ######## CONSTRUCTOR TESTs -# @test_throws ArgumentError exterior_algebra_PBWAlgQuo(QQ, 0); -# exterior_algebra_PBWAlgQuo(QQ, 1); # --> special case (is commutative) -# exterior_algebra_PBWAlgQuo(QQ, 2); # --> first general case -# exterior_algebra_PBWAlgQuo(QQ, 99); # --> with 999 indets takes a long time [~19s] - -# exterior_algebra_PBWAlgQuo(GF(2), 2); # BUG?? not recognized as commutative!! -# exterior_algebra_PBWAlgQuo(GF(3), 4); -# ## exterior_algebra_PBWAlgQuo(GF(2), 1500); ## limit 1500 on my 32Gbyte machine (!NB printing requires a lot of space!) - -# ### exterior_algebra_PBWAlgQuo(GF(1180591620717411303449), 2); # --> ERROR prime too big (for GF) - -# exterior_algebra_PBWAlgQuo(residue_field(ZZ, 2)[1], 2); -# exterior_algebra_PBWAlgQuo(residue_field(ZZ, 3)[1], 4); -# exterior_algebra_PBWAlgQuo(residue_field(ZZ, 1180591620717411303449)[1], 2); - -# exterior_algebra_PBWAlgQuo(residue_ring(ZZ,4)[1], 3) # Coeffs not integral domain - -# @test_throws ArgumentError exterior_algebra_PBWAlgQuo(QQ, String[]); # empty name list -# exterior_algebra_PBWAlgQuo(QQ, ["x", "y", "x"]); # !!duplicate names are allowed!! - -# ## (reduced) COMPUTATIONAL SPEED TEST - -# ExtAlg, (e1,e2,e3,e4,e5,e6) = exterior_algebra_PBWAlgQuo(QQ, 6); -# fac1 = e1 + 2*e1*e2 + 3*e1*e2*e3 + 4*e1*e2*e3*e4 + 5*e1*e2*e3*e4*e5 + 6*e1*e2*e3*e4*e5*e6; -# fac2 = e6 + 2*e5*e6 + 3*e4*e5*e6 + 4*e3*e4*e5*e6 + 5*e2*e3*e4*e5*e6 + 6*e1*e2*e3*e4*e5*e6; -# prod12 = fac1*fac2; -# prod21 = fac2*fac1; -# expected12 = 35*e1*e2*e3*e4*e5*e6 +4*e1*e2*e3*e4*e6 +6*e1*e2*e3*e5*e6 +6*e1*e2*e4*e5*e6 +4*e1*e3*e4*e5*e6 +3*e1*e2*e3*e6 +4*e1*e2*e5*e6 +3*e1*e4*e5*e6 +2*e1*e2*e6 +2*e1*e5*e6 +e1*e6; -# expected21 = - 3*e1*e2*e3*e4*e5*e6 + 4*e1*e2*e3*e4*e6 + 6*e1*e2*e3*e5*e6 + 6*e1*e2*e4*e5*e6 + 4*e1*e3*e4*e5*e6 - 3*e1*e2*e3*e6 + 4*e1*e2*e5*e6 - 3*e1*e4*e5*e6 + 2*e1*e2*e6 + 2*e1*e5*e6 - e1*e6; -# @test is_zero(prod12 - expected12); -# @test is_zero(prod21 - expected21); - -# @test is_zero(fac1*prod12); -# @test is_zero(prod12*fac1); -# @test is_zero(fac2*prod12); -# @test is_zero(prod12*fac2); - -# @test is_zero(fac1*prod21); -# @test is_zero(prod21*fac1); -# @test is_zero(fac2*prod21); -# @test is_zero(prod21*fac2); - -# end diff --git a/src/Rings/PBWAlgebraQuo.jl b/src/Rings/PBWAlgebraQuo.jl index 3462ecf45746..a717e729c19d 100644 --- a/src/Rings/PBWAlgebraQuo.jl +++ b/src/Rings/PBWAlgebraQuo.jl @@ -32,7 +32,7 @@ export PBWAlgQuo, PBWAlgQuoElem -###### @attributes ### DID NOT WORK -- alternative solution found (via have_special_impl, see ExteriorAlgebra.jl) +###### @attributes ### DID NOT WORK -- alternative solution found (via has_special_impl, see ExteriorAlgebra.jl) mutable struct PBWAlgQuo{T, S} <: NCRing I::PBWAlgIdeal{0, T, S} sring::Singular.PluralRing{S} # For ExtAlg this is the Singular impl; o/w same as I.basering.sring @@ -46,7 +46,7 @@ function PBWAlgQuo(I::PBWAlgIdeal{0, T, S}) where {T, S} end -function have_special_impl(Q::PBWAlgQuo) +function has_special_impl(Q::PBWAlgQuo) return (Q.sring != Q.I.basering.sring) end @@ -96,7 +96,7 @@ end function expressify(Q::PBWAlgQuo; context = nothing) # what about new sring data-field ??? ## special printing if Q is an exterior algebra ###### if get_attribute(Q, :is_exterior_algebra) === :true - if have_special_impl(Q) + if has_special_impl(Q) a = Q.I.basering x = symbols(a) n = length(x) @@ -137,7 +137,7 @@ function one(Q::PBWAlgQuo) end function simplify(a::PBWAlgQuoElem) - if have_special_impl(parent(a)) + if has_special_impl(parent(a)) return a # short-cut for impls with reducing arithmetic (e.g. exterior algebras) end I = parent(a).I @@ -152,7 +152,7 @@ function Base.hash(a::PBWAlgQuoElem, h::UInt) end function is_zero(a::PBWAlgQuoElem) - if !have_special_impl(parent(a)) # must reduce if not exterior algebras + if !has_special_impl(parent(a)) # must reduce if not exterior algebras simplify(a) # see GitHub discussion #2014 -- is_zero can modify repr of its arg! end return is_zero(a.data.sdata) # EQUIV is_zero(a.data) @@ -236,15 +236,13 @@ Map defined by a julia-function with inverse For reasons of efficiency, it is recommended to use the built-in constructor `exterior_algebra` when working with exterior algebras in OSCAR. """ -function quo(Q::PBWAlgRing, I::PBWAlgIdeal; SpecialImpl::Union{Nothing, Singular.PluralRing} = nothing) - @assert (Q == base_ring(I)); - ### No idea how to check whether SpecialImpl is sane! -#??? Check if I is ideal of squares of gens then produce ExtAlg??? -##??if isnothing(SpecialImpl) SpecialImpl = I.basering.sring; end; - if isnothing(SpecialImpl) +function quo(Q::PBWAlgRing, I::PBWAlgIdeal; special_impl::Union{Nothing, Singular.PluralRing} = nothing) + @assert Q == base_ring(I) + # we assume that special_impl is correct, if given + if isnothing(special_impl) q = PBWAlgQuo(I) else - q = PBWAlgQuo(I, SpecialImpl) + q = PBWAlgQuo(I, special_impl) end function im(a::PBWAlgElem) @assert parent(a) == Q