Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quantum_autmorphism_groups of matroid #3950

Merged
merged 26 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cc775e8
started adding the functions
Sequenzer Jul 17, 2024
7c9577f
Merge branch 'oscar-system:master' into feature/qAutMatroid
Sequenzer Jul 17, 2024
fa7a851
deleted empty lines
Sequenzer Jul 17, 2024
5eb2ec0
moved all functions to their own file, added tests
Sequenzer Jul 19, 2024
0ff08e8
deleted code duplicates
Sequenzer Jul 19, 2024
bd786d5
fixed test
Sequenzer Jul 19, 2024
f7ed65a
Apply suggestions from code review
Sequenzer Jul 19, 2024
696aed2
followed a bunch of maxs suggestions
Sequenzer Jul 19, 2024
a75d6b8
more suggestions
Sequenzer Jul 19, 2024
11eec61
followed a lot of suggestions
Sequenzer Jul 19, 2024
588f546
Apply suggestions from code review
Sequenzer Jul 19, 2024
555d68c
Update src/Combinatorics/Matroids/quantum_automorphism_groups.jl
Sequenzer Jul 19, 2024
03aecd9
hope to fix the doctests
Sequenzer Jul 19, 2024
fc763db
removed the experimental dependency
Sequenzer Jul 22, 2024
9ac2869
adresses some of dans changes
Sequenzer Jul 29, 2024
e176a17
deleted comment
Sequenzer Jul 29, 2024
455dbb0
changes to doctest
Sequenzer Jul 29, 2024
94c5d51
fixed doctest
Sequenzer Jul 29, 2024
0d3f710
tried making this faster but I believe I'm making it worse
Sequenzer Jul 30, 2024
7e1c4e5
Final changes
Sequenzer Jul 31, 2024
d021f41
Update src/Combinatorics/Matroids/quantum_automorphism_groups.jl
dcorey2814 Aug 1, 2024
574ec37
Update src/Combinatorics/Matroids/quantum_automorphism_groups.jl
Sequenzer Aug 1, 2024
094b97f
removed the assertion
Sequenzer Aug 1, 2024
711cc83
more suggestions by max
Sequenzer Aug 5, 2024
307bd84
added the functions to the documentation
Sequenzer Aug 14, 2024
53742db
Update docs/src/Combinatorics/matroids.md
benlorenz Aug 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/src/Combinatorics/graphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ Objects of type `Graph` can be saved to a file and loaded with the methods
polymake object. In particular, this file can now be read by both polymake and
OSCAR.

## Quantum Automorphisms
```@docs
quantum_automorphism_group(G::Graph{Undirected})
```
6 changes: 5 additions & 1 deletion docs/src/Combinatorics/matroids.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,8 @@ chow_ring(M::Matroid; ring::Union{MPolyRing,Nothing}=nothing, extended::Bool=fal
augmented_chow_ring(M::Matroid)
```


### Quantum Automorphisms
```@docs
quantum_symmetric_group(n::Int)
function quantum_automorphism_group(M::Matroid, structure::Symbol)
benlorenz marked this conversation as resolved.
Show resolved Hide resolved
```
1 change: 1 addition & 0 deletions src/Combinatorics/Matroids/JMatroids.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include("matroids.jl")
include("properties.jl")
include("ChowRings.jl")
include("quantum_automorphism_groups.jl")
228 changes: 228 additions & 0 deletions src/Combinatorics/Matroids/quantum_automorphism_groups.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
@doc raw"""
quantum_symmetric_group(n::Int)

Return the ideal that defines the quantum symmetric group on `n` elements.
It is comprised of `2*n + n^2 + 2*n*n*(n-1)` many generators.

The relations are:

- row and column sum relations: `2*n` relations
- idempotent relations: `n^2` relations
- relations of type `u[i,j]*u[i,k]` and `u[j,i]*u[k,i]` for `k != j`: `2*n*n*(n-1)` relations

# Example

```jldoctest
julia> S4 = quantum_symmetric_group(4);

julia> length(gens(S4))
120
```
"""
function quantum_symmetric_group(n::Int)
A, u = free_associative_algebra(QQ, :u => (1:n, 1:n))

relations = elem_type(A)[]

#Idempotent relations
for i in 1:n, j in 1:n
new_relation = u[i,j] * u[i,j] - u[i,j]
push!(relations, new_relation)
for k in 1:n
if k != j
new_relation = u[i,j] * u[i,k]
push!(relations, new_relation)
new_relation = u[j,i] * u[k,i]
push!(relations, new_relation)
end
end
end

#row and column sum relations
for i in 1:n
push!(relations, sum(u[i,:]) - 1)
push!(relations, sum(u[:,i]) - 1)

end
return ideal(relations)
end

@doc raw"""
_quantum_automorphism_group_indices(M::Matroid, structure::Symbol=:bases)

Return the indices of the relations that define the quantum automorphism group of a matroid for a given structure.

# Examples

```jldoctest
julia> M = uniform_matroid(3,4);

julia> idx = Oscar._quantum_automorphism_group_indices(M,:bases);

julia> length(idx)
1920
```
"""
function _quantum_automorphism_group_indices(M::Matroid, structure::Symbol=:bases)
Sequenzer marked this conversation as resolved.
Show resolved Hide resolved
@req structure in [:bases, :circuits, :flats] "structure must be one of :bases, :circuits, :flats"

matroid_groundset(M) isa Vector{Int} ? nothing : M=Matroid(Oscar.pm_object(M))

n = length(M)
grdSet = matroid_groundset(M)
Sequenzer marked this conversation as resolved.
Show resolved Hide resolved

rels = Vector{Tuple{Int,Int}}[]

sets = getproperty(Oscar, structure)(M)
sizes = unique!(map(length, sets))


#Computing the sizehint for the relations
setSizes = map(length, sets)

sets_count = [0 for _ in 1:maximum(setSizes)]
foreach(size->sets_count[size] += 1, setSizes)
for i in 1:length(sets_count)
if sets_count[i] == 0 || sets_count[i] == n^i
sets_count[i] = 0
continue
end
nonsets_count = n^i - (sets_count[i] * factorial(i))
sets_count[i] = sets_count[i] * factorial(i) * nonsets_count * 2
end

vector_size = sum(sets_count)
sizehint!(rels, vector_size)

for size in sizes
size == 0 && continue

S = symmetric_group(size)
permutedSets = [[set[g(i)] for i in 1:size] for g in S for set in sets if length(set) == size]

nonSets = MultiPartitionIterator{Int}(grdSet, size; toskip=permutedSets)

for nonset in nonSets
for set in permutedSets
push!(rels, [(set[i],nonset[i]) for i in 1:size])
push!(rels, [(nonset[i],set[i]) for i in 1:size])
end
end
end
@assert length(rels) == vector_size "The number of relations is not correct $(length(rels)) != $(vector_size)"

return Vector{Vector{Tuple{Int,Int}}}(rels)
end

@doc raw"""
quantum_automorphism_group(M::Matroid, structure::Symbol=:bases)

Return the ideal that defines the quantum automorphism group of a matroid for a given structure.

# Examples

```jldoctest
julia> G = complete_graph(4)
Undirected graph with 4 nodes and the following edges:
(2, 1)(3, 1)(3, 2)(4, 1)(4, 2)(4, 3)

julia> M = cycle_matroid(G);

julia> qAut = quantum_automorphism_group(M,:bases);

julia> length(gens(qAut))
23448
```
"""
function quantum_automorphism_group(
M::Matroid,
structure::Symbol=:bases)

relation_indices = _quantum_automorphism_group_indices(M, structure)
n = length(M)

SN = quantum_symmetric_group(n)
A = base_ring(SN)
u = permutedims(reshape(gens(A),(n, n)),[2, 1])

new_relations = elem_type(A)[prod(gen -> u[gen[1], gen[2]], relation; init=one(A)) for relation in relation_indices]
return ideal(vcat(gens(SN), new_relations))

end

@doc raw"""
quantum_automorphism_group(G::Graph{Undirected})

Return the ideal that defines the quantum automorphism group of the undirected graph `G`.

# Examples
```jldoctest
julia> G = graph_from_edges([[1, 2], [2, 4]]);

julia> qAut = quantum_automorphism_group(G);

julia> length(gens(qAut))
184
```
"""
function quantum_automorphism_group(G::Graph{Undirected})
n = nv(G)

SN = quantum_symmetric_group(n)
A = base_ring(SN)
u = permutedims(reshape(gens(A),(n, n)),[2, 1])

nonedges = Tuple{Int,Int}[(i, j) for i in 1:n for j in i:n if !has_edge(G,i,j)]

edgs = map(edg -> (src(edg), dst(edg)), edges(G)) # This should be |E| many edges

new_relations = copy(gens(SN))
sizehint!(new_relations, ngens(SN) + length(edgs) * length(nonedges)*8)

function _addrelations(edge,nonedg)
r1 = u[edge[1], nonedg[1]] * u[edge[2], nonedg[2]]
r2 = u[edge[2], nonedg[1]] * u[edge[1], nonedg[2]]
r3 = u[edge[1], nonedg[2]] * u[edge[2], nonedg[1]]
r4 = u[edge[2], nonedg[2]] * u[edge[1], nonedg[1]]
push!(new_relations, r1, r2, r3, r4)
end
for edge in edgs, nonedg in nonedges
_addrelations(edge,nonedg)
_addrelations(nonedg,edge)
end
unique!(new_relations)
return ideal(new_relations)
end

struct MultiPartitionIterator{T}
Sequenzer marked this conversation as resolved.
Show resolved Hide resolved
elements::Vector{T}
size::Int
toskip::Vector{Vector{T}}
function MultiPartitionIterator{T}(elements::Vector{T}, size::Int; toskip::Vector{Vector{T}}=Vector{Vector{T}}()) where T
@req map(length, toskip) == fill(size, length(toskip)) "The size of the subsets to skip must be the same as the size of the subsets"
@req all(x->x in elements, reduce(vcat, toskip)) "The elements to skip must be in the elements"
new(elements, size, toskip)
end
end

function Base.iterate(S::MultiPartitionIterator{T}, state=0) where T
n = length(S.elements)
while true
if state > n^S.size-1
return nothing
else
subset = [S.elements[div(state, n^(i-1)) % n + 1] for i in 1:S.size]
if subset in S.toskip
state += 1
continue
else
return (subset, state + 1)
end
end
end
end

Base.length(S::MultiPartitionIterator{T}) where T = length(S.elements)^S.size - length(S.toskip)
Base.IteratorSize(::Type{MultiPartitionIterator{T}}) where T = Base.HasLength()
Base.IteratorEltype(::Type{MultiPartitionIterator{T}}) where T = Base.HasEltype()
Base.eltype(::Type{MultiPartitionIterator{T}}) where T = Vector{T}
6 changes: 5 additions & 1 deletion src/Rings/FreeAssAlgIdeal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ _to_lpring(a::FreeAssAlgebra, deg_bound::Int) = Singular.FreeAlgebra(base_ring(a
@doc raw"""
groebner_basis(I::FreeAssAlgIdeal, deg_bound::Int=-1; protocol::Bool=false)

Return the Groebner basis of `I` with respect to the degree bound `deg_bound`. If `protocol` is `true`, the protocol of the computation is also returned. The default value of `deg_bound` is `-1`, which means that no degree bound is imposed, which leads to a computation that uses a much slower algorithm, that may not terminate, but returns a full groebner basis if it does.
Return the Groebner basis of `I` with respect to the degree bound `deg_bound`.
If `protocol` is `true`, the protocol of the computation is also returned.
The default value of `deg_bound` is `-1`, which means that no degree bound is
imposed, resulting in a computation that is usually slower, but will return a
full Groebner basis if there exists a finite one.
```jldoctest
julia> free, (x,y,z) = free_associative_algebra(QQ, ["x", "y", "z"]);

Expand Down
2 changes: 2 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,8 @@ export pseudo_del_pezzo_polytope
export pullback
export pyramid
export quadratic_form
export quantum_automorphism_group
export quantum_symmetric_group
export quaternion_group
export quo
export quo_object
Expand Down
50 changes: 50 additions & 0 deletions test/Combinatorics/Matroids/Matroids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,57 @@
M = cycle_matroid(g)
@test degree(automorphism_group(M)) == 5
end
@testset "quantum_automorphism_group" begin
Sequenzer marked this conversation as resolved.
Show resolved Hide resolved
# _cnt is the number of elements the quantum permutation group should have
_cnt(n::Int) = 2*n + n^2 + 2*n*n*(n-1)
function _cnt(M::Matroid, structure::Symbol=:bases)
k = rank(M)
b = length(eval(structure)(M))
n = length(M)
return 2 * factorial(k) * b * (n^k - b* factorial(k))
end
n = 4
# Test of quantum_symmetric_group
S4 = quantum_symmetric_group(n)
@test length(gens(S4)) == _cnt(n)
A = base_ring(S4)
u = permutedims(reshape(gens(A),(n,n)),[2,1])
@test u[2,3]*u[2,2] in gens(S4)
@test u[1,1]*u[1,1] - u[1,1] in gens(S4)
@test sum(u[2,n] for n in 1:4)-1 in gens(S4)

#Test of quantum_automorphism_group for bases of uniform_matroid
M = uniform_matroid(3,4)
qAut = quantum_automorphism_group(M,:bases)
n = length(uniform_matroid(3,4))
@test length(gens(qAut)) == _cnt(M) + _cnt(n)

A = base_ring(qAut)
u = permutedims(reshape(gens(A),(n,n)),[2,1])

@test u[2,3]*u[2,2] in gens(S4)
@test u[2,2]*u[2,2] - u[2,2] in gens(S4)
@test sum(u[2,n] for n in 1:4)-1 in gens(S4)

@test u[2,4]*u[2,3]*u[1,2] in gens(qAut)

#Test of quantum_automorphism_group for circuits of uniform_matroid
qAut1 = quantum_automorphism_group(M,:circuits)
A = base_ring(qAut1)
u = permutedims(reshape(gens(A),(n,n)),[2,1])

@test length(gens(qAut1)) == 11256
@test u[2,3]*u[2,2] in gens(qAut1)

#Test of quantum_automorphism_group for Graphs
G = complete_graph(5)
E = length(edges(G))
n = nv(G)
qAut2 = quantum_automorphism_group(G)
@test length(gens(qAut2)) == 235


end
@testset "matroid quotient" begin
Q1 = uniform_matroid(1, 3)
Q2 = uniform_matroid(2, 3)
Expand Down
Loading