Skip to content

Commit

Permalink
Merge branch 'master' into lg/coxeter
Browse files Browse the repository at this point in the history
  • Loading branch information
lgoettgens committed Sep 9, 2024
2 parents cd9043c + f777526 commit 18f00d5
Show file tree
Hide file tree
Showing 16 changed files with 515 additions and 199 deletions.
1 change: 1 addition & 0 deletions docs/src/Groups/pcgroup.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ map_word(g::Union{PcGroupElem, SubPcGroupElem}, genimgs::Vector; genimgs_inv::Ve
Julia has the following functions that allow to generate polycyclic groups:
```@docs
abelian_group(::Type{T}, v::Vector{Int}) where T <: GAPGroup
elementary_abelian_group
cyclic_group
dihedral_group
quaternion_group
Expand Down
77 changes: 77 additions & 0 deletions docs/src/TropicalGeometry/hypersurface.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
```@meta
CurrentModule = Oscar
DocTestSetup = Oscar.doctestsetup()
```
# Tropical hypersurfaces

## Introduction
Expand Down Expand Up @@ -26,3 +30,76 @@ algebraic_polynomial(TropH::TropicalHypersurface)
tropical_polynomial(TropH::TropicalHypersurface)
dual_subdivision(TropH::TropicalHypersurface)
```

## Example
The following code sets up an example and prints the vertices and rays of the tropical hypersurface (in no particular order).
```jldoctest exampleHypersurface
julia> T = tropical_semiring();
julia> Tx,(x1,x2) = polynomial_ring(T, 2);
julia> g = 1 + 2*x1^2 + 2*x2^2 + 1*x1*x2;
julia> TropH = tropical_hypersurface(g);
julia> vertRays = vertices_and_rays(TropH)
5-element SubObjectIterator{Union{PointVector{QQFieldElem}, RayVector{QQFieldElem}}}:
[-1, -1]
[1, 0]
[0, 1]
[-1//2, 1//2]
[1//2, -1//2]
```
By broadcasting the `typeof()` command, we can see, which are vertices, and which are rays.
```jldoctest exampleHypersurface
julia> typeof.(vertRays)
5-element Vector{DataType}:
RayVector{QQFieldElem}
RayVector{QQFieldElem}
RayVector{QQFieldElem}
PointVector{QQFieldElem}
PointVector{QQFieldElem}
```
The maximal polyhedra of our tropical hypersurface is simply the edges (both bounded and unbounded). The command `maximal_polyhedra()` gives us a list of these edges (in no particular order).
```jldoctest exampleHypersurface
julia> maxPol = maximal_polyhedra(TropH)
5-element SubObjectIterator{Polyhedron{QQFieldElem}}:
Polyhedron in ambient dimension 2
Polyhedron in ambient dimension 2
Polyhedron in ambient dimension 2
Polytope in ambient dimension 2
Polyhedron in ambient dimension 2
```
The polyhedrons are the unbounded edges, and the polytopes are the bounded edges.

The incidence matrix of the maximal polyhedra is a list of the relations between the elements of `vertices_and_rays(TropH)`.
From these relations, we can draw the hypersurface. However, one should be careful, as there is no distinction between vertices and rays in the incidence matrix.
```jldoctest exampleHypersurface
julia> IncidenceMatrix(maxPol)
5×5 IncidenceMatrix
[1, 4]
[1, 5]
[3, 4]
[4, 5]
[2, 5]
```
This is made clearer if we ask for the vertices of each of the maximal polyhedra (the bounded edges have a vertex at each end, while the unbounded only have one vertex).
```jldoctest exampleHypersurface
julia> vertices.(maxPol)
5-element Vector{SubObjectIterator{PointVector{QQFieldElem}}}:
[[-1//2, 1//2]]
[[1//2, -1//2]]
[[-1//2, 1//2]]
[[-1//2, 1//2], [1//2, -1//2]]
[[1//2, -1//2]]
```
Instead of being between two vertices, the unbounded edges are defined by a vertex and a ray. These rays can be seen in the following way.
```jldoctest exampleHypersurface
julia> rays.(maxPol)
5-element Vector{SubObjectIterator{RayVector{QQFieldElem}}}:
[[-1, -1]]
[[-1, -1]]
[[0, 1]]
0-element SubObjectIterator{RayVector{QQFieldElem}}
[[1, 0]]
```
164 changes: 25 additions & 139 deletions experimental/GModule/src/Cohomology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,22 +184,9 @@ function inv_action(C::GModule)
end

function fp_group_with_isomorphism(C::GModule)
#TODO: better for PcGroup!!!
G = group(C)
if !isdefined(C, :F)
if (!isa(G, FPGroup)) && is_trivial(G)
C.F = free_group(0)
C.mF = hom(G, C.F, elem_type(G)[], elem_type(C.F)[])
elseif isa(group(C), PcGroup) && GAP.Globals.GeneratorsOfGroup(G.X) == GAP.Globals.Pcgs(G.X)
X = GAPWrap.IsomorphismFpGroupByPcgs(GAP.Globals.InducedPcgsWrtFamilyPcgs(G.X), GAP.julia_to_gap("a"))

C.F = FPGroup(GAPWrap.Range(X))
C.mF = GAPGroupHomomorphism(G, C.F, X)
return C.F, C.mF
else
C.F, C.mF = fp_group_with_isomorphism(gens(G))
# C.mF = GAPGroupHomomorphism(C.F, group(C), GAP.Globals.InverseGeneralMapping(C.mF.map))
end
iso = isomorphism(FPGroup, group(C), on_gens=true)
C.F, C.mF = codomain(iso), iso
end
return C.F, C.mF
end
Expand Down Expand Up @@ -550,17 +537,6 @@ Oscar.group(C::GModule) = C.G
# To be moved and revised eventually
###########################################################

"""
Compute an fp-presentation of the common parent 'G' of 'g'
and return both the group and the map from 'G' to the new group.
"""
function fp_group_with_isomorphism(g::Vector{<:Oscar.GAPGroupElem})
G = parent(g[1])
@assert all(x->parent(x) == G, g)
iso = isomorphism(FPGroup, G, on_gens=true)
return codomain(iso), iso
end

"""
For an element of an fp-group, return a corresponding word as a sequence
of integers. A positive integers indicates the corresponding generator,
Expand All @@ -572,39 +548,18 @@ function word(y::FPGroupElem)
end

"""
The relations defining 'F' as an array of pairs.
The relations defining 'G' as an array of pairs.
"""
function _relations_by_generators(G::Oscar.GAPGroup)
f = GAPWrap.IsomorphismFpGroupByGenerators(GapObj(G), GAPWrap.GeneratorsOfGroup(GapObj(G)))
@req f != GAP.Globals.fail "Could not convert group into a group of type FPGroup"
H = FPGroup(GAPWrap.Image(f))
return relations(H)
end

Oscar.relations(G::Oscar.GAPGroup) = _relations_by_generators(G)

function Oscar.relations(F::Union{FPGroup, SubFPGroup})
Oscar._is_full_fp_group(GapObj(F)) || return _relations_by_generators(F)
R = relators(F)
z = one(free_group(F))
return [(x, z) for x = R]
end

function Oscar.relators(F::PcGroup)
#TODO: do it properly!!!!
return [x[1] for x = relations(F)]
function Oscar.relations(G::Oscar.GAPGroup)
rels = relators(G)
if length(rels) == 0
T = eltype(rels)
return Tuple{T,T}[]
end
z = one(parent(rels[1]))
return [(x, z) for x in rels]
end

function Oscar.relations(G::PcGroup)
# Call `GAPWrap.IsomorphismFpGroupByPcgs` only if `gens(G)` is a pcgs.
Ggens = GAPWrap.GeneratorsOfGroup(GapObj(G))
Gpcgs = GAPWrap.Pcgs(GapObj(G))
Ggens == Gpcgs || return _relations_by_generators(G)
f = GAPWrap.IsomorphismFpGroupByPcgs(Gpcgs, GAP.Obj("g"))
@req f != GAP.Globals.fail "Could not convert group into a group of type FPGroup"
H = FPGroup(GAPWrap.Image(f))
return relations(H)
end

######################################################
#
Expand Down Expand Up @@ -759,14 +714,14 @@ end
Evaluate a 2-cochain, a 2-cochain is a map from pairs of group elements
into the module
"""
function (C::CoChain{2})(g::Oscar.BasicGAPGroupElem, h::Oscar.BasicGAPGroupElem)
function (C::CoChain{2})(g::Oscar.GAPGroupElem, h::Oscar.GAPGroupElem)
if haskey(C.d, (g,h))
return C.d[(g,h)]
end
@assert isdefined(C, :D)
return C.d[(g,h)] = C.D((g, h))
end
(C::CoChain{2})(g::NTuple{2, <:Oscar.BasicGAPGroupElem}) = C(g[1], g[2])
(C::CoChain{2})(g::NTuple{2, <:Oscar.GAPGroupElem}) = C(g[1], g[2])

#TODO: re-write to get the maps! To support Q/Z as well
"""
Expand Down Expand Up @@ -1705,10 +1660,10 @@ returns (I, q), (hom(Z[G], C), B)
function dimension_shift(C::GModule)
G = C.G
if isa(C.M, FinGenAbGroup)
zg, ac, em = Oscar.GModuleFromGap.natural_gmodule(FinGenAbGroup, G, ZZ)
zg, ac, em = regular_gmodule(FinGenAbGroup, G, ZZ)
Z = Hecke.zero_obj(zg.M)
elseif isa(C.M, AbstractAlgebra.FPModule{<:FieldElem})
zg, ac, em = Oscar.GModuleFromGap.natural_gmodule(G, base_ring(C))
zg, ac, em = regular_gmodule(G, base_ring(C))
Z = free_module(base_ring(C), 0)
else
error("unsupported module")
Expand Down Expand Up @@ -1751,10 +1706,10 @@ end
function dimension_shift_left(C::GModule)
G = C.G
if isa(C.M, FinGenAbGroup)
zg, ac, em = Oscar.GModuleFromGap.natural_gmodule(FinGenAbGroup, G, ZZ)
zg, ac, em = regular_gmodule(FinGenAbGroup, G, ZZ)
Z = Hecke.zero_obj(zg.M)
elseif isa(C.M, AbstractAlgebra.FPModule{<:FieldElem})
zg, ac, em = Oscar.GModuleFromGap.natural_gmodule(G, base_ring(C))
zg, ac, em = regular_gmodule(G, base_ring(C))
Z = free_module(base_ring(C), 0)
else
error("unsupported module")
Expand Down Expand Up @@ -1853,13 +1808,13 @@ function cohomology_group(C::GModule, i::Int; Tate::Bool = false)
error("only H^0, H^1 and H^2 are supported")
end

# return an f.p. group `F` and an isomorphism `M -> F`
# better use `isomorphism` directly
function fp_group_with_isomorphism(M::AbstractAlgebra.FPModule{<:FinFieldElem})
p, mp = pc_group_with_isomorphism(M, refine = false)
mf = isomorphism(FPGroup, p)
return codomain(mf), mf*mp
iso = isomorphism(FPGroup, M, on_gens=true)
return codomain(iso), iso
end


#########################################################
function Oscar.matrix(M::FreeModuleHom{FreeMod{QQAbFieldElem}, FreeMod{QQAbFieldElem}})
return M.matrix
Expand Down Expand Up @@ -1973,82 +1928,13 @@ function pc_group_with_isomorphism(M::FinGenAbGroup; refine::Bool = true)
x->image(mM, gap_to_julia(GapObj(x))))
end

# `refine` is irrelevant because `M` is elementary abelian.
function pc_group_with_isomorphism(M::AbstractAlgebra.FPModule{<:FinFieldElem}; refine::Bool = true)
k = base_ring(M)
p = characteristic(k)

G = free_group(degree(k)*dim(M))

C = GAP.Globals.CombinatorialCollector(GapObj(G),
GAP.Obj([p for i=1:ngens(G)]; recursive = true))
F = GAP.Globals.FamilyObj(GAP.Globals.Identity(GapObj(G)))

# Note that we have specified all relative orders as `p`.
# Missing commutator and power relators are interpreted as trivial,
# thus `C` describes an elementary abelian group.
B = PcGroup(GAP.Globals.GroupByRws(C))
@assert is_abelian(B)
@assert order(B) == order(M)

FB = GAP.Globals.FamilyObj(GAP.Globals.Identity(GapObj(B)))

function Julia_to_gap(a::AbstractAlgebra.FPModuleElem{<:Union{fpFieldElem, FpFieldElem, FqFieldElem}})
F = base_ring(parent(a))
@assert absolute_degree(F) == 1
r = ZZRingElem[]
for i=1:ngens(M)
if !iszero(a[i])
push!(r, i)
push!(r, lift(ZZ, a[i]))
end
end
g = GAP.Globals.ObjByExtRep(FB, GAP.Obj(r; recursive = true))
return g
end

function Julia_to_gap(a::AbstractAlgebra.FPModuleElem{<:Union{FqPolyRepFieldElem, fqPolyRepFieldElem}})
r = ZZRingElem[]
for i=1:ngens(M)
if !iszero(a[i])
for j=0:degree(k)-1
if !iszero(coeff(a[i], j))
push!(r, (i-1)*degree(k)+j+1)
push!(r, ZZ(coeff(a[i], j)))
end
end
end
end
g = GAP.Globals.ObjByExtRep(FB, GAP.Obj(r; recursive = true))
return g
end


gap_to_julia = function(a::GapObj)
e = GAPWrap.ExtRepOfObj(a)
z = zeros(ZZRingElem, ngens(M)*degree(k))
for i=1:2:length(e)
if !iszero(e[i+1])
z[e[i]] = e[i+1]
end
end
c = elem_type(k)[]
for i=1:dim(M)
push!(c, k(z[(i-1)*degree(k)+1:i*degree(k)]))
end
return M(c)
end

return B, MapFromFunc(
M, B,
y->PcGroupElem(B, Julia_to_gap(y)),
x->gap_to_julia(GapObj(x)))
iso = isomorphism(PcGroup, M, on_gens=true)
return codomain(iso), iso
end


function underlying_word(g::FPGroupElem)
return FPGroupElem(free_group(parent(g)), GAPWrap.UnderlyingElement(GapObj(g)))
end

"""
Given a 2-cocycle, return the corresponding group extension, ie. the large
group, the injection of the abelian group and the quotient as well as a map
Expand All @@ -2061,7 +1947,7 @@ If the gmodule is defined via a pc-group and the 1st argument is the
function extension(c::CoChain{2,<:Oscar.GAPGroupElem})
C = c.C
G = Group(C)
F, _ = fp_group_with_isomorphism(gens(G))
F = codomain(isomorphism(FPGroup, G, on_gens=true))
M = Module(C)
ac = action(C)
iac = inv_action(C)
Expand Down
Loading

0 comments on commit 18f00d5

Please sign in to comment.