Skip to content

Commit dd57fe6

Browse files
AbstractAlgebra.Generic.groebner_basis(::Vector{FreeAssAlgebraElem}): Support for precomputed groebner basis added. (#2076)
Co-authored-by: Lars Göttgens <lars.goettgens@gmail.com>
1 parent 01c211c commit dd57fe6

File tree

2 files changed

+64
-7
lines changed

2 files changed

+64
-7
lines changed

src/generic/FreeAssociativeAlgebraGroebner.jl

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -584,16 +584,32 @@ end
584584
function groebner_basis_buchberger(
585585
g::Vector{FreeAssociativeAlgebraElem{T}},
586586
reduction_bound::Int = typemax(Int),
587-
remove_redundancies::Bool = false
587+
remove_redundancies::Bool = false;
588+
obstruction_free_set::Vector{FreeAssociativeAlgebraElem{T}}=FreeAssociativeAlgebraElem{T}[]
588589
) where T<:FieldElement
589-
g = copy(g)
590+
591+
if isempty(obstruction_free_set)
592+
g = copy(g)
593+
obstruction_queue = get_obstructions(g)
594+
else
595+
temp_g = copy(obstruction_free_set)
596+
obstruction_queue = PriorityQueue{Obstruction{T},FreeAssociativeAlgebraElem{T}}()
597+
sizehint!(temp_g, length(g)+length(obstruction_free_set))
598+
599+
for p in g
600+
push!(temp_g,p)
601+
add_obstructions!(obstruction_queue,temp_g)
602+
end
603+
g = temp_g
604+
end
605+
590606
# interreduce!(g) # on some small examples, this increases running time, so it might not be optimal to use this here
591607
nonzero_reductions = 0
592608
# compute the aho corasick automaton
593609
# to make normal form computation more efficient
594610
aut = AhoCorasickAutomaton([g_i.exps[1] for g_i in g])
595611
# step 1 from Thm. 5.2.12 Noncommutative Groebner Bases and Applications, Xingqiang Xiu
596-
obstruction_queue = get_obstructions(g)
612+
597613
while !isempty(obstruction_queue) # step 2
598614
obstruction = popfirst!(obstruction_queue)[1]
599615
# step3
@@ -607,6 +623,7 @@ function groebner_basis_buchberger(
607623
push!(g, Sp)
608624
insert_keyword!(aut, Sp.exps[1], length(g))
609625
if nonzero_reductions >= reduction_bound
626+
@warn "The computation terminated because it exceeded the limit of $reduction_bound reduction steps."
610627
return g
611628
end
612629
add_obstructions!(obstruction_queue, g)
@@ -618,7 +635,7 @@ function groebner_basis_buchberger(
618635
end
619636

620637
@doc """
621-
groebner_basis(g::Vector{FreeAssociativeAlgebraElem{T}}, reduction_bound::Int = typemax(Int), remove_redundancies::Bool = false)
638+
groebner_basis(g::Vector{FreeAssociativeAlgebraElem{T}}, reduction_bound::Int = typemax(Int), remove_redundancies::Bool = false; obstruction_free_set::Vector{FreeAssociativeAlgebraElem{T}})
622639
623640
Compute a Groebner basis for the ideal generated by `g`. Stop when `reduction_bound` many
624641
non-zero entries have been added to the Groebner basis. If the computation stops due to the bound being exceeded,
@@ -627,11 +644,42 @@ respect to this incomplete Groebner basis is `0`, it will also be `0` with respe
627644
628645
If `remove_redundancies` is set to true, some redundant obstructions will be removed during the computation, which might save
629646
time, however in practice it seems to inflate the running time regularly.
647+
648+
One can provide the keyword argument `obstruction_free_set` with a precomputed partial Groebner basis.
649+
It is assumed (but not checked) that all entries of `obstruction_free_set` are indeed contained in the ideal generated by `g`.
650+
651+
# Example
652+
653+
```jldoctest
654+
julia> R, (a, b) = free_associative_algebra(QQ, ["a", "b"]);
655+
656+
julia> f1 = a^2 -1;
657+
658+
julia> f2 = b^3 -1;
659+
660+
julia> f3 = a*b*a*b^2*a*b*a - b;
661+
662+
julia> g = AbstractAlgebra.groebner_basis([(a*b*a*b^2)^2 - 1]; obstruction_free_set = [f1,f2,f3])
663+
12-element Vector{AbstractAlgebra.Generic.FreeAssociativeAlgebraElem{Rational{BigInt}}}:
664+
a^2 - 1
665+
b^3 - 1
666+
a*b*a*b^2*a*b*a - b
667+
a*b*a*b^2*a*b*a*b^2 - 1
668+
-b*a*b^2*a*b*a*b^2 + a
669+
-b*a*b^2*a*b*a + a*b
670+
-b*a*b^2*a*b + a*b*a
671+
-a*b^2*a*b + b^2*a*b*a
672+
b^2*a*b*a*b^2 - a*b^2*a
673+
-a*b*a*b^2 + b*a*b^2*a
674+
b^2*a*b*a*b*a*b - a*b*a*b*a
675+
-a*b*a*b*a*b + b*a*b*a*b*a
676+
```
630677
"""
631678
function groebner_basis(
632679
g::Vector{FreeAssociativeAlgebraElem{T}},
633680
reduction_bound::Int = typemax(Int),
634-
remove_redundancies::Bool = false
681+
remove_redundancies::Bool = false;
682+
obstruction_free_set::Vector{FreeAssociativeAlgebraElem{T}}=FreeAssociativeAlgebraElem{T}[]
635683
) where T<:FieldElement
636-
return groebner_basis_buchberger(g, reduction_bound, remove_redundancies)
684+
return groebner_basis_buchberger(g, reduction_bound, remove_redundancies; obstruction_free_set=obstruction_free_set)
637685
end

test/generic/FreeAssociativeAlgebraGroebner-test.jl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ include("AhoCorasick-test.jl")
99

1010
# Example 6.1 Kreuzer & Xiu
1111
R, (a, b) = free_associative_algebra(QQ, ["a", "b"])
12-
12+
1313
g = AbstractAlgebra.groebner_basis([a^2 - 1, b^3 - 1, (a*b*a*b^2)^2 - 1])
1414
AbstractAlgebra.interreduce!(g)
1515
@test length(g) == 5
@@ -22,6 +22,15 @@ include("AhoCorasick-test.jl")
2222
@test all(u ->iszero(normal_form(u, g2)), g) # make sure removing redundant obstructions in the computation does not change the groebner basis
2323
@test all(u ->iszero(normal_form(u, g)), g2)
2424

25+
f1 = a^2 -1;
26+
f2 = b^3 -1;
27+
f3 = a*b*a*b^2*a*b*a - b;
28+
g = AbstractAlgebra.groebner_basis([(a*b*a*b^2)^2 - 1]; obstruction_free_set = [f1,f2,f3])
29+
@test length(g) >= 5
30+
AbstractAlgebra.interreduce!(g)
31+
@test length(g) == 5
32+
33+
2534
end
2635

2736
@testset "Generic.free_associative_algebra.groebner.normal_form" begin

0 commit comments

Comments
 (0)