Skip to content

Commit

Permalink
docs almost done
Browse files Browse the repository at this point in the history
  • Loading branch information
antonydellavecchia committed Oct 29, 2024
1 parent 901dc91 commit dbf2651
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 66 deletions.
11 changes: 11 additions & 0 deletions experimental/AlgebraicShifting/docs/src/exterior_shifting.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@ DocTestSetup = Oscar.doctestsetup()

# Exterior Shifting

## Uniform Hypergraphs
```@docs
uniform_hypergraph
```

## Helpful Matrix constructions

```@docs
generic_unipotent_matrix
rothe_matrix
compound_matrix
```

## Exterior (Partial) Shifting
```@docs
exterior_shift
```
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
```@meta
CurrentModule = Oscar
DocTestSetup = Oscar.doctestsetup()
```

# Partial Shift Graph

```@docs
partial_shift_graph_vertices
```
1 change: 1 addition & 0 deletions experimental/AlgebraicShifting/src/AlgebraicShifting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export UniformHypergraph

export compound_matrix
export exterior_shift
export face_size
export generic_unipotent_matrix
export partial_shift_graph_vertices
export partial_shift_graph
Expand Down
157 changes: 124 additions & 33 deletions experimental/AlgebraicShifting/src/PartialShift.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ function generic_unipotent_matrix(R::MPolyRing)
return u
end

function generic_unipotent_matrix(F::Field, n::Int)
Fx, x = polynomial_ring(F, :x => (1:n, 1:n))
return generic_unipotent_matrix(Fx)
end

@doc raw"""
generic_unipotent_matrix(R::MPolyRing)
generic_unipotent_matrix(F::Field, n::Int)
Expand All @@ -55,23 +50,45 @@ julia> generic_unipotent_matrix(GF(2), 2)
[0 1]
```
"""
function generic_unipotent_matrix(F::Field, n::Int)
Fx, x = polynomial_ring(F, :x => (1:n, 1:n))
return generic_unipotent_matrix(Fx)
end

@doc raw"""
rothe_matrix(F::Field, w::WeylGroupElem; K::Union{SimplicialComplex, Nothing} = nothing)
For a base field `F` and a weyl group element `w` return the matrix with entries in the
multivariate polynomial ring `R` with `n^2` many indeterminants where `n - 1` is the rank of the
root system of the weyl group.
We know that since `general_linear_group(n^2, R)` has a Bruhat decomposition, and element lies in some double coset $BwB$.
The \emph{Rothe matrix} is a normal form for a the matrix on the left of a representative for the double coset corresponding to `w`.
We use the name \emph{Rothe matrix} because of its resemblance with a \emph{Rothe diagram} (add ref?)
We know that since `general_linear_group(n^2, R)` has a Bruhat decomposition, any element lies in some double coset $BwB$.
The Rothe matrix is a normal form for the matrix on the left of a representative for the double coset corresponding to `w`.
(this might need to be explained further and reference the preprint)
We use the name Rothe matrix because of its resemblance with a Rothe diagram. (add ref?)
# Examples
```jldoctest
julia> W = weyl_group(:A, 4)
Weyl group for root system defined by Cartan matrix [2 -1 0 0; -1 2 -1 0; 0 -1 2 -1; 0 0 -1 2]
julia> s = gens(W)
4-element Vector{WeylGroupElem}:
s1
s2
s3
s4
julia> w = s[2] * s[3] * s[4]
s2 * s3 * s4
julia> rothe_matrix(GF(2), w)
[1 0 0 0 0]
[0 x[2, 3] x[2, 4] x[2, 5] 1]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
```
"""

function rothe_matrix(F::Field, w::WeylGroupElem)
n = rank(root_system(parent(w)))+1
Fx, x = polynomial_ring(F, :x => (1:n, 1:n))
Expand All @@ -82,22 +99,66 @@ function rothe_matrix(F::Field, w::WeylGroupElem)
return u * permutation_matrix(F, perm(w))
end

""" The `K`-indexed rows of the `k`th compound matrix of a square matrix `X`, where `K` is `k`-homogeneous. """
function compound_matrix(m::MatElem, K::Vector{Vector{Int}})
@doc raw"""
compound_matrix(m::MatElem, k::Int)
compound_matrix(p::PermGroupElem, k::Int)
compound_matrix(w::WeylGroupElem, k::Int)
compound_matrix(m::MatElem, K::Vector{Vector{Int}})
Given a matrix `m` return the matrix where each entry is a `k` minor of `m`.
The entries of the compound matrix are ordered with respect to the lexicographic order on sets.
When passed a `PermGroupElem` or `WeylGroupElem`, return the copound matrix for their
permutation matrix representation.
Alternatively, passing a `UniformHypergraph` `K` will return the compound matrix with entries the `face_size(K)` minors, and restrict the rows to the rows corresponding to `K`
# Examples
```jldoctest
julia> M = generic_unipotent_matrix(QQ, 3)
[1 x[1, 2] x[1, 3]]
[0 1 x[2, 3]]
[0 0 1]
julia> compound_matrix(M, 2)
[1 x[2, 3] x[1, 2]*x[2, 3] - x[1, 3]]
[0 1 x[1, 2]]
[0 0 1]
julia> compound_matrix(perm([1, 3, 2]), 2)
[0 1 0]
[1 0 0]
[0 0 -1]
julia> W = weyl_group(:A, 2)
Weyl group for root system defined by Cartan matrix [2 -1; -1 2]
julia> compound_matrix(longest_element(W), 2)
[ 0 0 -1]
[ 0 -1 0]
[-1 0 0]
julia> K = uniform_hypergraph([[1, 2], [2, 3]])
UniformHypergraph(3, 2, [[1, 2], [2, 3]])
julia> compound_matrix(M, K)
[1 x[2, 3] x[1, 2]*x[2, 3] - x[1, 3]]
[0 0 1]
```
"""
function compound_matrix(m::MatElem, K::UniformHypergraph)
@req size(m,1) == size(m,2) "Only valid for square matrices"
@req length(Set(map(length, K))) == 1 "All entries in K must have the same size."
n = size(m, 1)
k = collect(Set(map(length, K)))[1]
@req all(1 <= i <= n for s in K for i in s) "All entries in K must represent $k-element subsets of [n]."
k = face_size(K)
nCk = sort(subsets(n, k))
return matrix(base_ring(m), [det(m[row, col]) for row in K, col in nCk])
return matrix(base_ring(m), [det(m[row, col]) for row in faces(K), col in nCk])
end

compound_matrix(m::MatElem, k::Int) = compound_matrix(m, sort(subsets(size(m, 1), k)))
compound_matrix(m::MatElem, k::Int) = compound_matrix(m, uniform_hypergraph(sort(subsets(size(m, 1), k))))
compound_matrix(p::PermGroupElem, k::Int) = compound_matrix(permutation_matrix(ZZ, p), k)
compound_matrix(w::WeylGroupElem, k::Int) = compound_matrix(perm(w), k)

""" Given `K` checks if matrix entry can be set to zero zero """
# this might be removed (currently is not used)
function _set_to_zero(K::SimplicialComplex, indices::Tuple{Int, Int})
row, col = indices
row == col && return false
Expand Down Expand Up @@ -128,7 +189,7 @@ function exterior_shift(K::UniformHypergraph, g::MatElem)
@req size(g, 1) == n_vertices(K) "Matrix size does not match K."
matrix_base = base_ring(g)
nCk = sort!(subsets(n_vertices(K), face_size(K)))
c = compound_matrix(g, faces(K))
c = compound_matrix(g, K)
if matrix_base isa MPolyRing
Oscar.ModStdQt.ref_ff_rc!(c)
elseif matrix_base isa MPolyQuoRing
Expand All @@ -149,30 +210,60 @@ function exterior_shift(K::SimplicialComplex, g::MatElem)
end

@doc raw"""
exterior_shift(F::Field, K::ComplexOrHypergraph, w::WeylGroupElem)
exterior_shift(K::ComplexOrHypergraph, w::WeylGroupElem)
exterior_shift(K::ComplexOrHypergraph)
exterior_shift(F::Field, K::SimplicialComplex, w::WeylGroupElem)
exterior_shift(F::Field, K::UniformHypergraph, w::WeylGroupElem)
exterior_shift(K::SimplicialComplex, w::WeylGroupElem)
exterior_shift(K::UniformHypergraph, w::WeylGroupElem)
exterior_shift(K::SimplicialComplex)
exterior_shift(K::UniformHypergraph)
Computes the (partial) exterior shift of a simplical complex or uniform hypergraph `K` with respect to the Weyl group element `w` and the field `F`.
If the field is not given then `QQ` is used during the computation.
If `w` is not given then `longest_element(weyl_group(:A, n_vertices(K) - 1))` is used
# Example
Compute the exterior generic shift of the real projective plane:
```
julia> K = real_projective_plane()
# Examples
```jldoctest
julia> is_shifted(K)
false
julia> L = exterior_shift(K)
Abstract simplicial complex of dimension 2 on 6 vertices
julia> facets(L)
10-element Vector{Set{Int64}}:
Set([2, 3, 1])
Set([4, 2, 1])
Set([5, 2, 1])
Set([6, 2, 1])
Set([4, 3, 1])
Set([5, 3, 1])
Set([6, 3, 1])
Set([5, 4, 1])
Set([4, 6, 1])
Set([5, 6, 1])
julia> is_shifted(L)
julia> betti_numbers(K) == betti_numbers(L)
```
Apply the partial generic shift w.r.t. a permutation ``w``:
```
julia> W = weyl_group(:A, 5)
true
julia> betti_numbers(L) == betti_numbers(K)
true
julia> W = weyl_group(:A, n_vertices(K) - 1)
Weyl group for root system defined by Cartan matrix [2 -1 0 0 0; -1 2 -1 0 0; 0 -1 2 -1 0; 0 0 -1 2 -1; 0 0 0 -1 2]
julia> s = gens(W)
julia> w = s[1] * s[2] * s[1]
julia> L = exterior_shift(K, w)
5-element Vector{WeylGroupElem}:
s1
s2
s3
s4
s5
julia> w = s[2] * s[3] * s[4]
s2 * s3 * s4
julia> L = exterior_shift(GF(2), K, w)
Abstract simplicial complex of dimension 2 on 6 vertices
```
"""
function exterior_shift(F::Field, K::ComplexOrHypergraph, w::WeylGroupElem)
Expand Down
78 changes: 58 additions & 20 deletions experimental/AlgebraicShifting/src/PartialShiftGraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,44 @@ end
"""
isless_lex(K1::SimplicialComplex, K2::SimplicialComplex) = isless_lex(Set(facets(K1)), Set(facets(K2)))

"""
Discovers the nodes of partial shift graph starting from `K`.
@doc raw"""
partial_shift_graph_vertices(F::Field,::SimplicialComplex, W::Union{WeylGroup, Vector{WeylGroupElem}};)
Given a field `F` discover the vertices of the partial shift graph starting from `K`
using exterior partial shifts corresponding to elements in `W`.
Returns a `Vector{SimplicialCompplex}` ordered lexicographically.
#Example
```jldoctest
julia> K = simplicial_complex([[1, 2], [2, 3], [3, 4]])
Abstract simplicial complex of dimension 1 on 4 vertices
julia> shifts = partial_shift_graph_vertices(QQ, K, weyl_group(:A, 3))
6-element Vector{SimplicialComplex}:
Abstract simplicial complex of dimension 1 on 4 vertices
Abstract simplicial complex of dimension 1 on 4 vertices
Abstract simplicial complex of dimension 1 on 4 vertices
Abstract simplicial complex of dimension 1 on 4 vertices
Abstract simplicial complex of dimension 1 on 4 vertices
Abstract simplicial complex of dimension 1 on 4 vertices
julia> facets.(shifts)
6-element Vector{Vector{Set{Int64}}}:
[Set([3, 1]), Set([4, 1]), Set([2, 1])]
[Set([3, 1]), Set([2, 3]), Set([2, 1]), Set([4])]
[Set([3, 1]), Set([4, 2]), Set([2, 1])]
[Set([4, 3]), Set([3, 1]), Set([2, 1])]
[Set([2, 1]), Set([2, 3]), Set([4, 2])]
[Set([2, 1]), Set([2, 3]), Set([4, 3])]
```
"""
function partial_shift_graph_vertices(F::Field,
K::SimplicialComplex,
W::Union{WeylGroup, Vector{WeylGroupElem}};)
current = K
visited = [current]
# by properties of algebraic shifting
# we know that K we be the last in this list since it is sorted
# we know that K we be the last in this sorted list
unvisited = unique(
x -> Set(facets(x)),
sort([exterior_shift(F, K, w) for w in W]; lt=isless_lex))[1:end - 1]
Expand Down Expand Up @@ -66,31 +94,36 @@ function multi_edges(F::Field,
end

@doc raw"""
partial_shift_graph(complexes::Vector{Simplicialcomplex})
partial_shift_graph(complexes::Vector{Uniformhypergraph})
partial_shift_graph(F::Field, complexes::Vector{Simplicialcomplex}; parallel=false)
partial_shift_graph(F::Field, complexes::Vector{Uniformhypergraph}; parallel=false)
partial_shift_graph(F::Field, complexes::Vector{Simplicialcomplex}, W::Union{WeylGroup, Vector{WeylGroupElem}}; parallel=false)
partial_shift_graph(F::Field, complexes::Vector{Uniformhypergraph}, W::Union{WeylGroup, Vector{WeylGroupElem}}; parallel=false)
Constructs the partial shift graph on `complexes`.
Returns a tuple `(G, D)`, where `G` is a directed graph whose vertices correspond to the `complexes`,
such that there is an edge `K → L` if there exists a shift matrix `w` such that `L` is the partial generic shift of `K` by `w`.
If `K` and `K` are the `i`th and `j`th entry of `complexes`, resp.,
If `K` and `L` are the `i`th and `j`th entry of `complexes`, resp.,
`D[i,j]` contains all `w ∈ W` such that `L` is the partial generic shift of `K` by `w`.
# Arguments
- `complexes`: A vector of simplicial complexes of uniform hypergraphs (all belonging to the same ``Γ(n, k, l)``).
- `parallel :: Bool` (default: `false`) run the process in parrallel using the `Distributed` package; the setup is left to the user.
- `parallel :: Bool` (default: `false`) run the process in parrallel using the `Distributed` package; make sure to do `@everywhere using Oscar`.
- `W`: The user may provide a list `W` of Weyl group elements to be used to construct the shifts.
`W` must be a subset the (same instance of the) symmetric group of the same order as the complexes.
If `W` is not provided, the function will use the symmetric group of the same order as the complexes.
# Examples
```
julia> Γ(n,k,l) = uniform_hypergraph.(subsets(subsets(n, k), l), n)
julia> Ks = Γ(4,2,5)
julia> G, D = construct_full_graph(Ks)
julia> gamma(n,k,l) = uniform_hypergraph.(subsets(subsets(n, k), l), n)
julia> Ks = gamma(4,2,5)
julia> G, D = partial_shift_graph(QQ, Ks)
```
"""
function partial_shift_graph(F::Field, complexes::Vector{T}, W::Union{Nothing, WeylGroup, Vector{WeylGroupElem}} = nothing;
function partial_shift_graph(F::Field, complexes::Vector{T}, W::Union{WeylGroup, Vector{WeylGroupElem}};
parallel::Bool = false) :: Tuple{Graph{Directed}, EdgeLabels} where T <: ComplexOrHypergraph;
# Deal with trivial case
if length(complexes) <= 1
Expand All @@ -103,15 +136,10 @@ function partial_shift_graph(F::Field, complexes::Vector{T}, W::Union{Nothing, W

# inverse lookup K → index of K in complexes
complex_labels = Dict(Set(facets(K)) => index for (index, K) in enumerate(complexes))

# set the weyl group to be used to construct the shifts
if isnothing(W)
W = weyl_group(:A, n - 1);
else
W2 = only(unique(parent.(W)))
rs_type = root_system_type(root_system(W2))
@req rs_type[1][1] == :A && rs_type[1][2] == n - 1 "Only Weyl groups type A_$(n-1) are currently support and received type $(T[1])."
end

W2 = only(unique(parent.(W)))
rs_type = root_system_type(root_system(W2))
@req rs_type[1][1] == :A && rs_type[1][2] == n - 1 "Only Weyl groups type A_$(n-1) are currently support and received type $(T[1])."

task_size = 1
map_function = map
Expand Down Expand Up @@ -141,3 +169,13 @@ function partial_shift_graph(F::Field, complexes::Vector{T}, W::Union{Nothing, W
return (graph, edge_labels)
end

function partial_shift_graph(F::Field, complexes::Vector{T}; parallel=false) where T <: ComplexOrHypergraph
# Deal with trivial case
if length(complexes) <= 1
return (graph_from_adjacency_matrix(Directed, zeros(length(complexes),length(complexes))), EdgeLabels())
end

n = n_vertices(complexes[1])
W = weyl_group(:A, n - 1)
return partial_shift_graph(F, complexes, W;parallel=parallel)
end
Loading

0 comments on commit dbf2651

Please sign in to comment.