diff --git a/docs/src/Groups/matgroup.md b/docs/src/Groups/matgroup.md index 0c09ec130d6b..cbb9645e2c29 100644 --- a/docs/src/Groups/matgroup.md +++ b/docs/src/Groups/matgroup.md @@ -5,10 +5,92 @@ DocTestSetup = Oscar.doctestsetup() # Matrix groups +## Introduction + +A *matrix group* is a group that consists of invertible square matrices +over a common ring, the *base ring* of the group +(see [`base_ring(G::MatrixGroup{RE}) where RE <: RingElem`](@ref)). + +Matrix groups in Oscar have the type +[`MatrixGroup{RE<:RingElem, T<:MatElem{RE}}`](@ref), +their elements have the type +[`MatrixGroupElem{RE<:RingElem, T<:MatElem{RE}}`](@ref). + +## Basic Creation + +In order to *create* a matrix group, +one first creates matrices that generate the group, +and then calls `matrix_group` with these generators. + +```jldoctest matgroupxpl +julia> mats = [[0 -1; 1 -1], [0 1; 1 0]] +2-element Vector{Matrix{Int64}}: + [0 -1; 1 -1] + [0 1; 1 0] + +julia> matelms = map(m -> matrix(ZZ, m), mats) +2-element Vector{ZZMatrix}: + [0 -1; 1 -1] + [0 1; 1 0] + +julia> g = matrix_group(matelms) +Matrix group of degree 2 + over integer ring + +julia> describe(g) +"S3" + +julia> t = matrix_group(ZZ, 2, typeof(matelms[1])[]) +Matrix group of degree 2 + over integer ring + +julia> t == trivial_subgroup(g)[1] +true + +julia> F = GF(3); matelms = map(m -> matrix(F, m), mats) +2-element Vector{FqMatrix}: + [0 2; 1 2] + [0 1; 1 0] + +julia> g = matrix_group(matelms) +Matrix group of degree 2 + over prime field of characteristic 3 + +julia> describe(g) +"S3" +``` + +Alternatively, +one can start with [a classical matrix group](@ref "Classical groups"). + +```jldoctest matgroupxpl +julia> g = GL(3, GF(2)) +GL(3,2) + +julia> F = GF(4) +Finite field of degree 2 and characteristic 2 + +julia> G = GL(3, F) +GL(3,4) + +julia> is_subset(g, G) +false + +julia> h = change_base_ring(F, g) +Matrix group of degree 3 + over finite field of degree 2 and characteristic 2 + +julia> flag, mp = is_subgroup(h, G) +(true, Hom: h -> G) + +julia> mp(gen(h, 1)) in G +true +``` + +## Functions for matrix groups + ```@docs matrix_group(R::Ring, m::Int, V::AbstractVector{T}; check::Bool=true) where T<:Union{MatElem,MatrixGroupElem} -MatrixGroup{RE<:RingElem, T<:MatElem{RE}} -MatrixGroupElem{RE<:RingElem, T<:MatElem{RE}} base_ring(G::MatrixGroup{RE}) where RE <: RingElem degree(G::MatrixGroup) centralizer(G::MatrixGroup{T}, x::MatrixGroupElem{T}) where T <: FinFieldElem @@ -17,6 +99,9 @@ map_entries(f, G::MatrixGroup) ## Elements of matrix groups +The following functions delegate to the underlying matrix +of the given matrix group element. + ```@docs matrix(x::MatrixGroupElem) base_ring(x::MatrixGroupElem) @@ -30,17 +115,33 @@ is_unipotent(x::MatrixGroupElem{T}) where T <: FinFieldElem ## Sesquilinear forms +Sesquilinear forms are alternating and symmetric bilinear forms, +hermitian forms, and quadratic forms. + +Sesquilinear forms in Oscar have the type +[`SesquilinearForm{T<:RingElem}`](@ref). + +A sesquilinear form can be created +[from its Gram matrix](@ref "Create sesquilinear forms from Gram matrices") +or [as an invariant form of a matrix group](@ref "Invariant forms"). + +## Create sesquilinear forms from Gram matrices + ```@docs -SesquilinearForm{T<:RingElem} -is_alternating(f::SesquilinearForm) -is_hermitian(f::SesquilinearForm) -is_quadratic(f::SesquilinearForm) -is_symmetric(f::SesquilinearForm) alternating_form(B::MatElem{T}) where T <: FieldElem symmetric_form(B::MatElem{T}) where T <: FieldElem hermitian_form(B::MatElem{T}) where T <: FieldElem quadratic_form(B::MatElem{T}) where T <: FieldElem quadratic_form(f::MPolyRingElem{T}) where T <: FieldElem +``` + +## Functions for sesquilinear forms + +```@docs +is_alternating(f::SesquilinearForm) +is_hermitian(f::SesquilinearForm) +is_quadratic(f::SesquilinearForm) +is_symmetric(f::SesquilinearForm) corresponding_bilinear_form(B::SesquilinearForm) corresponding_quadratic_form(B::SesquilinearForm) gram_matrix(f::SesquilinearForm) @@ -50,10 +151,14 @@ witt_index(f::SesquilinearForm{T}) where T is_degenerate(f::SesquilinearForm{T}) where T is_singular(f::SesquilinearForm{T}) where T is_congruent(f::SesquilinearForm{T}, g::SesquilinearForm{T}) where T <: RingElem +isometry_group(f::SesquilinearForm{T}) where T ``` ## Invariant forms +The following functions compute (Gram matrices of) sesquilinear forms +that are invariant under the given matrix group. + ```@docs invariant_bilinear_forms(G::MatrixGroup{S,T}) where {S,T} invariant_sesquilinear_forms(G::MatrixGroup{S,T}) where {S,T} @@ -66,12 +171,14 @@ invariant_sesquilinear_form(G::MatrixGroup) invariant_quadratic_form(G::MatrixGroup) preserved_quadratic_forms(G::MatrixGroup{S,T}) where {S,T} preserved_sesquilinear_forms(G::MatrixGroup{S,T}) where {S,T} -isometry_group(f::SesquilinearForm{T}) where T orthogonal_sign(G::MatrixGroup) ``` ## Utilities for matrices +(The inputs/outputs of the functions described in this section +are matrices not matrix group elements.) + ```@docs pol_elementary_divisors(A::MatElem{T}) where T generalized_jordan_block(f::T, n::Int) where T<:PolyRingElem @@ -98,3 +205,13 @@ omega_group(e::Int, n::Int, F::Ring) unitary_group(n::Int, q::Int) special_unitary_group(n::Int, q::Int) ``` + +## Technicalities + +```@docs +MatrixGroup{RE<:RingElem, T<:MatElem{RE}} +MatrixGroupElem{RE<:RingElem, T<:MatElem{RE}} +ring_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} +mat_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} +SesquilinearForm{T<:RingElem} +``` diff --git a/src/Groups/matrices/MatGrp.jl b/src/Groups/matrices/MatGrp.jl index 58269dafa52c..563627618959 100644 --- a/src/Groups/matrices/MatGrp.jl +++ b/src/Groups/matrices/MatGrp.jl @@ -75,8 +75,42 @@ MatrixGroupElem(G::MatrixGroup{RE,T}, x::T, x_gap::GapObj) where {RE,T} = Matrix MatrixGroupElem(G::MatrixGroup{RE,T}, x::T) where {RE, T} = MatrixGroupElem{RE,T}(G,x) MatrixGroupElem(G::MatrixGroup{RE,T}, x_gap::GapObj) where {RE, T} = MatrixGroupElem{RE,T}(G,x_gap) +""" + ring_elem_type(G::MatrixGroup{S,T}) where {S,T} + ring_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} + +Return the type `S` of the entries of the elements of `G`. +One can enter the type of `G` instead of `G`. + +# Examples +```jldoctest +julia> g = GL(2, 3); + +julia> ring_elem_type(typeof(g)) == elem_type(typeof(base_ring(g))) +true +``` +""" ring_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} = S +ring_elem_type(::MatrixGroup{S,T}) where {S,T} = S + +""" + mat_elem_type(G::MatrixGroup{S,T}) where {S,T} + mat_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} + +Return the type `T` of `matrix(x)`, for elements `x` of `G`. +One can enter the type of `G` instead of `G`. + +# Examples +```jldoctest +julia> g = GL(2, 3); + +julia> mat_elem_type(typeof(g)) == typeof(matrix(one(g))) +true +``` +""" mat_elem_type(::Type{MatrixGroup{S,T}}) where {S,T} = T +mat_elem_type(::MatrixGroup{S,T}) where {S,T} = T + _gap_filter(::Type{<:MatrixGroup}) = GAP.Globals.IsMatrixGroup elem_type(::Type{MatrixGroup{S,T}}) where {S,T} = MatrixGroupElem{S,T} @@ -419,7 +453,23 @@ det(x::MatrixGroupElem) = det(matrix(x)) """ base_ring(x::MatrixGroupElem) -Return the base ring of the underlying matrix of `x`. +Return the base ring of the matrix group to which `x` belongs. +This is also the base ring of the underlying matrix of `x`. + +# Examples +```jldoctest +julia> F = GF(4); g = general_linear_group(2, F); + +julia> x = gen(g, 1) +[o 0] +[0 1] + +julia> base_ring(x) == F +true + +julia> base_ring(x) == base_ring(matrix(x)) +true +``` """ base_ring(x::MatrixGroupElem) = base_ring(parent(x)) @@ -431,6 +481,25 @@ parent(x::MatrixGroupElem) = x.parent matrix(x::MatrixGroupElem) Return the underlying matrix of `x`. + +# Examples +```jldoctest +julia> F = GF(4); g = general_linear_group(2, F); + +julia> x = gen(g, 1) +[o 0] +[0 1] + +julia> m = matrix(x) +[o 0] +[0 1] + +julia> x == m +false + +julia> x == g(m) +true +``` """ function matrix(x::MatrixGroupElem) if !isdefined(x, :elm) @@ -463,6 +532,21 @@ size(x::MatrixGroupElem) = size(matrix(x)) tr(x::MatrixGroupElem) Return the trace of the underlying matrix of `x`. + +# Examples +```jldoctest +julia> F = GF(4); g = general_linear_group(2, F); + +julia> x = gen(g, 1) +[o 0] +[0 1] + +julia> t = tr(x) +o + 1 + +julia> t in F +true +``` """ tr(x::MatrixGroupElem) = tr(matrix(x)) @@ -484,6 +568,14 @@ transpose(x::MatrixGroupElem) = MatrixGroupElem(parent(x), transpose(matrix(x))) base_ring(G::MatrixGroup) Return the base ring of the matrix group `G`. + +# Examples +```jldoctest +julia> F = GF(4); g = general_linear_group(2, F); + +julia> base_ring(g) == F +true +``` """ base_ring(G::MatrixGroup{RE}) where RE <: RingElem = G.ring::parent_type(RE) @@ -492,7 +584,13 @@ base_ring_type(::Type{<:MatrixGroup{RE}}) where {RE} = parent_type(RE) """ degree(G::MatrixGroup) -Return the degree of the matrix group `G`, i.e. the number of rows of its matrices. +Return the degree of `G`, i.e., the number of rows of its matrices. + +# Examples +```jldoctest +julia> degree(GL(4, 2)) +4 +``` """ degree(G::MatrixGroup) = G.deg @@ -543,7 +641,7 @@ function compute_order(G::MatrixGroup{T}) where {T <: Union{AbsSimpleNumFieldEle return ZZRingElem(GAPWrap.Size(GapObj(G))) else n = order(isomorphic_group_over_finite_field(G)[1]) - GAP.Globals.SetSize(GapObj(G), GAP.Obj(n)) + set_order(G, n) return n end end diff --git a/src/Groups/matrices/form_group.jl b/src/Groups/matrices/form_group.jl index 64351110ad06..ad07f4991b8c 100644 --- a/src/Groups/matrices/form_group.jl +++ b/src/Groups/matrices/form_group.jl @@ -408,12 +408,21 @@ end """ invariant_bilinear_form(G::MatrixGroup) -Return an invariant bilinear form for the group `G`. +Return the Gram matrix of an invariant bilinear form for `G`. An exception is thrown if the module induced by the action of `G` is not absolutely irreducible. !!! warning "Note:" At the moment, the output is returned of type `mat_elem_type(G)`. + +# Examples +```jldoctest +julia> invariant_bilinear_form(Sp(4, 2)) +[0 0 0 1] +[0 0 1 0] +[0 1 0 0] +[1 0 0 0] +``` """ function invariant_bilinear_form(G::MatrixGroup) V = GAP.Globals.GModuleByMats(GAPWrap.GeneratorsOfGroup(GapObj(G)), codomain(_ring_iso(G))) @@ -424,13 +433,23 @@ end """ invariant_sesquilinear_form(G::MatrixGroup) -Return an invariant sesquilinear (non bilinear) form for the group `G`. +Return the Gram matrix of an invariant sesquilinear (non bilinear) form for `G`. + An exception is thrown if the module induced by the action of `G` -is not absolutely irreducible or if the group is defined over a finite field +is not absolutely irreducible or if `G` is defined over a finite field of odd degree over the prime field. !!! warning "Note:" At the moment, the output is returned of type `mat_elem_type(G)`. + +# Examples +```jldoctest +julia> invariant_sesquilinear_form(GU(4, 2)) +[0 0 0 1] +[0 0 1 0] +[0 1 0 0] +[1 0 0 0] +``` """ function invariant_sesquilinear_form(G::MatrixGroup) @req iseven(degree(base_ring(G))) "group is defined over a field of odd degree" @@ -442,12 +461,21 @@ end """ invariant_quadratic_form(G::MatrixGroup) -Return an invariant quadratic form for the group `G`. +Return the Gram matrix of an invariant quadratic form for `G`. An exception is thrown if the module induced by the action of `G` is not absolutely irreducible. !!! warning "Note:" At the moment, the output is returned of type `mat_elem_type(G)`. + +# Examples +```jldoctest +julia> invariant_quadratic_form(GO(1, 4, 2)) +[0 1 0 0] +[0 0 0 0] +[0 0 0 1] +[0 0 0 0] +``` """ function invariant_quadratic_form(G::MatrixGroup) if iseven(characteristic(base_ring(G))) @@ -523,6 +551,15 @@ is a finite field, return - `0` if `n` is odd and `G` preserves a nonzero quadratic form, - `1` if `n` is even and `G` preserves a nonzero quadratic form of `+` type, - `-1` if `n` is even and `G` preserves a nonzero quadratic form of `-` type. + +# Examples +```jldoctest +julia> orthogonal_sign(GO(1, 4, 2)) +1 + +julia> orthogonal_sign(GO(-1, 4, 2)) +-1 +``` """ function orthogonal_sign(G::MatrixGroup) R = base_ring(G) diff --git a/src/Groups/matrices/forms.jl b/src/Groups/matrices/forms.jl index f5c9abe38a9a..5d45e81cd9fa 100644 --- a/src/Groups/matrices/forms.jl +++ b/src/Groups/matrices/forms.jl @@ -10,8 +10,9 @@ """ SesquilinearForm{T<:RingElem} -Type of groups `G` of `n x n` matrices over the ring `R`, where `n = degree(G)` and `R = base_ring(G)`. -At the moment, only rings of type `fqPolyRepField` are supported. +Type of alternating and symmetric bilinear forms, hermitian forms, +and quadratic forms, defined by a Gram matrix +(or, in the case of a quadratic form, alternatively by a polynomial). """ mutable struct SesquilinearForm{T<:RingElem} matrix::MatElem{T} @@ -63,14 +64,16 @@ SesquilinearForm(f::MPolyRingElem{T},sym) where T = SesquilinearForm{T}(f,sym) """ is_alternating(f::SesquilinearForm) -Return whether the form `f` is an alternating form. +Return whether the form `f` is an alternating form, +see [`is_alternating(B::MatElem)`](@ref). """ is_alternating(f::SesquilinearForm) = f.descr==:alternating """ is_hermitian(f::SesquilinearForm) -Return whether the form `f` is a hermitian form. +Return whether the form `f` is a hermitian form, +see [`is_hermitian(B::MatElem{T}) where T <: FinFieldElem`](@ref). """ is_hermitian(f::SesquilinearForm) = f.descr==:hermitian @@ -100,6 +103,19 @@ is_symmetric(f::SesquilinearForm) = f.descr==:symmetric alternating_form(B::MatElem{T}) Return the alternating form with Gram matrix `B`. +An exception is thrown if `B` is not square or does not have zeros on the +diagonal or does not satisfy `B = -transpose(B)`. + +# Examples +```jldoctest +julia> f = alternating_form(matrix(GF(3), 2, 2, [0, 1, -1, 0])) +alternating form with Gram matrix +[0 1] +[2 0] + +julia> describe(isometry_group(f)) +"SL(2,3)" +``` """ alternating_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :alternating) @@ -107,6 +123,18 @@ alternating_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :alte symmetric_form(B::MatElem{T}) Return the symmetric form with Gram matrix `B`. +An exception is thrown if `B` is not square or not symmetric. + +# Examples +```jldoctest +julia> f = symmetric_form(matrix(GF(3), 2, 2, [0, 1, 1, 0])) +symmetric form with Gram matrix +[0 1] +[1 0] + +julia> describe(isometry_group(f)) +"C2 x C2" +``` """ symmetric_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :symmetric) @@ -114,6 +142,21 @@ symmetric_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :symmet hermitian_form(B::MatElem{T}) Return the hermitian form with Gram matrix `B`. +An exception is thrown if `B` is not square or does not satisfy +`B = conjugate_transpose(B)`, see [`conjugate_transpose`](@ref). + +# Examples +```jldoctest +julia> F = GF(4); z = gen(F); + +julia> f = hermitian_form(matrix(F, 2, 2, [0, z, z^2, 0])) +hermitian form with Gram matrix +[ 0 o] +[o + 1 0] + +julia> describe(isometry_group(f)) +"C3 x S3" +``` """ hermitian_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :hermitian) @@ -132,6 +175,17 @@ end quadratic_form(B::MatElem{T}) Return the quadratic form with Gram matrix `B`. + +# Examples +```jldoctest +julia> f = quadratic_form(matrix(GF(3), 2, 2, [2, 2, 0, 1])) +quadratic form with Gram matrix +[2 2] +[0 1] + +julia> describe(isometry_group(f)) +"D8" +``` """ quadratic_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :quadratic) @@ -140,8 +194,21 @@ quadratic_form(B::MatElem{T}) where T <: FieldElem = SesquilinearForm(B, :quadra Return the quadratic form described by the polynomial `f`. Here, `f` must be a homogeneous polynomial of degree 2. -If `check` is set as `false`, it does not check whether the polynomial is homogeneous of degree 2. +If `check` is set to `false`, it is not checked whether `f` is homogeneous of degree 2. To define quadratic forms of dimension 1, `f` can also have type `PolyRingElem{T}`. + +# Examples +```jldoctest +julia> _, (x1, x2) = polynomial_ring(GF(3), [:x1, :x2]); + +julia> f = quadratic_form(2*x1^2 + 2*x1*x2 + x2^2) +quadratic form with Gram matrix +[2 2] +[0 1] + +julia> describe(isometry_group(f)) +"D8" +``` """ quadratic_form(f::MPolyRingElem{T}) where T <: FieldElem = SesquilinearForm(f, :quadratic) # TODO : neither is_homogeneous or is_homogeneous works for variables of type MPolyRingElem{T} @@ -162,7 +229,7 @@ end function Base.show(io::IO, f::SesquilinearForm) - println(io, "$(f.descr) form with Gram matrix ") + println(io, "$(f.descr) form with Gram matrix") show(io, "text/plain", gram_matrix(f)) end @@ -194,7 +261,14 @@ end """ corresponding_bilinear_form(Q::SesquilinearForm) -Given a quadratic form `Q`, return the bilinear form `B` defined by `B(u,v) = Q(u+v)-Q(u)-Q(v)`. +Given a quadratic form `Q`, return the symmetric form with Gram matrix `B` +defined by `B(u,v) = Q(u+v)-Q(u)-Q(v)`. + +# Examples +```@repl +Q = quadratic_form(invariant_quadratic_form(GO(3,3))) +corresponding_bilinear_form(Q) +``` """ function corresponding_bilinear_form(B::SesquilinearForm) @req B.descr==:quadratic "The form must be a quadratic form" @@ -205,10 +279,17 @@ function corresponding_bilinear_form(B::SesquilinearForm) end """ - corresponding_quadratic_form(Q::SesquilinearForm) + corresponding_quadratic_form(f::SesquilinearForm) -Given a symmetric form `f`, returns the quadratic form `Q` defined by `Q(v) = f(v,v)/2`. +Given a symmetric form `f`, return the quadratic form `Q` +defined by `Q(v) = f(v,v)/2`. It is defined only in odd characteristic. + +# Examples +```@repl +f = symmetric_form(invariant_bilinear_form(GO(3, 3))) +corresponding_quadratic_form(f) +``` """ function corresponding_quadratic_form(B::SesquilinearForm) @req B.descr==:symmetric "The form must be a symmetric form" @@ -233,9 +314,9 @@ end ######################################################################## """ - gram_matrix(B::SesquilinearForm) + gram_matrix(f::SesquilinearForm) -Return the Gram matrix of a sesquilinear or quadratic form `B`. +Return the Gram matrix that defines `f`. """ function gram_matrix(f::SesquilinearForm) isdefined(f,:matrix) && return f.matrix @@ -268,7 +349,7 @@ end """ defining_polynomial(f::SesquilinearForm) -Return the polynomial that defines the quadratic form `f`. +Return the polynomial that defines `f`. """ function defining_polynomial(f::SesquilinearForm) isdefined(f,:pol) && return f.pol @@ -374,10 +455,27 @@ end """ radical(f::SesquilinearForm{T}) -Return the radical of the sesquilinear form `f`, i.e. the subspace of all `v` -such that `f(u,v)=0` for all `u`. -The radical of a quadratic form `Q` is the set of vectors `v` such that `Q(v)=0` - and `v` lies in the radical of the corresponding bilinear form. +Return `(U, emb)` where `U` is the radical of `f` and `emb` is the +embedding of `U` into the full vector space on which `f` is defined. + +For a quadratic form `f`, the radical is defined as the set of vectors `v` +such that `f(v) = 0` and `v` lies in the radical of the corresponding +bilinear form. + +Otherwise the radical of `f` is defined as the subspace of all `v` +such that `f(u, v) = 0` for all `u`. + +# Examples +```jldoctest +julia> g = GO(7, 2); + +julia> f = symmetric_form(invariant_symmetric_forms(g)[1]); + +julia> U, emb = radical(f); + +julia> dim(U) +1 +``` """ function radical(f::SesquilinearForm{T}) where T V = vector_space(base_ring(f), nrows(gram_matrix(f)) ) @@ -395,7 +493,21 @@ end witt_index(f::SesquilinearForm{T}) Return the Witt index of the form induced by `f` on `V/Rad(f)`. -The Witt Index is the dimension of a maximal totally isotropic (singular for quadratic forms) subspace. +The Witt index is the dimension of a maximal totally isotropic +(singular for quadratic forms) subspace. + +# Examples +```jldoctest +julia> g = GO(1, 6, 2); + +julia> witt_index(quadratic_form(invariant_quadratic_forms(g)[1])) +3 + +julia> g = GO(-1, 6, 2); + +julia> witt_index(quadratic_form(invariant_quadratic_forms(g)[1])) +2 +``` """ witt_index(f::SesquilinearForm{T}) where T = GAP.Globals.WittIndex(GapObj(f)) diff --git a/src/Groups/matrices/linear_centralizer.jl b/src/Groups/matrices/linear_centralizer.jl index 6ceda1e693cf..60ab8ff35d27 100644 --- a/src/Groups/matrices/linear_centralizer.jl +++ b/src/Groups/matrices/linear_centralizer.jl @@ -442,8 +442,20 @@ end centralizer(G::MatrixGroup{T}, x::MatrixGroupElem{T}) Return (`C`,`f`), where `C` is the centralizer of `x` in `C` and `f` is the embedding of `C` into `G`. -If `G` = `GL(n,F)` or `SL(n,F)`, then `f` = `nothing`. In this case, to get the embedding homomorphism of `C` into `G`, use -> `is_subgroup(C, G)[2]` +If `G` = `GL(n,F)` or `SL(n,F)`, then `f` = `nothing`. +In this case, use `is_subgroup(C, G)[2]` to get the embedding homomorphism +of `C` into `G`. + +# Examples +```jldoctest +julia> g = Sp(4, 2); x = gen(g, 1); + +julia> C, emb = centralizer(g, x) +(Matrix group of degree 4 over GF(2), Hom: C -> g) + +julia> order(C) +8 +``` """ function centralizer(G::MatrixGroup{T}, x::MatrixGroupElem{T}) where T <: FinFieldElem if isdefined(G,:descr) && (G.descr==:GL || G.descr==:SL) diff --git a/src/Groups/matrices/linear_isconjugate.jl b/src/Groups/matrices/linear_isconjugate.jl index f6157fd61261..9f30db7e1968 100644 --- a/src/Groups/matrices/linear_isconjugate.jl +++ b/src/Groups/matrices/linear_isconjugate.jl @@ -19,7 +19,8 @@ Return `S` and `U` in the group `G = parent(M)` such that `S` is semisimple, `U` is unipotent and `M = SU = US`. !!! warning "WARNING:" - this is *NOT*, in general, the same output returned when `M` has type `MatElem`. + this is *NOT*, in general, equal to + `multiplicative_jordan_decomposition(matrix(M))`. """ function multiplicative_jordan_decomposition(x::MatrixGroupElem) a = order(x) diff --git a/src/Groups/matrices/matrix_manipulation.jl b/src/Groups/matrices/matrix_manipulation.jl index 5b62d9450631..a5184f501e21 100644 --- a/src/Groups/matrices/matrix_manipulation.jl +++ b/src/Groups/matrices/matrix_manipulation.jl @@ -56,11 +56,11 @@ function conjugate_transpose(x::MatElem{T}) where T <: FinFieldElem end -# computes a complement for W in V (i.e. a subspace U of V such that V is direct sum of U and W) """ complement(V::AbstractAlgebra.Generic.FreeModule{T}, W::AbstractAlgebra.Generic.Submodule{T}) where T <: FieldElem -Return a complement for `W` in `V`, i.e. a subspace `U` of `V` such that `V` is direct sum of `U` and `W`. +Return a complement for `W` in `V`, i.e. a subspace `U` of `V` such that `V` is +the direct sum of `U` and `W`. """ function complement(V::AbstractAlgebra.Generic.FreeModule{T}, W::AbstractAlgebra.Generic.Submodule{T}) where T <: FieldElem @assert is_submodule(V,W) "The second argument is not a subspace of the first one" diff --git a/src/Groups/matrices/transform_form.jl b/src/Groups/matrices/transform_form.jl index 3214cf07abea..463f681471e1 100644 --- a/src/Groups/matrices/transform_form.jl +++ b/src/Groups/matrices/transform_form.jl @@ -374,15 +374,15 @@ end """ is_congruent(f::SesquilinearForm{T}, g::SesquilinearForm{T}) where T <: RingElem -If `f` and `g` are sesquilinear forms, return (`true`, `C`) if there exists a +If `f` and `g` are quadratic forms, return (`true`, `C`) if there exists a +matrix `C` such that `f^C = ag` for some scalar `a`. If such `C` does not +exist, then return (`false`, `nothing`). + +Otherwise return (`true`, `C`) if there exists a matrix `C` such that `f^C = g`, or equivalently, `CBC* = A`, where `A` and `B` are the Gram matrices of `f` and `g` respectively, and `C*` is the transpose-conjugate matrix of `C`. If such `C` does not exist, then return (`false`, `nothing`). - -If `f` and `g` are quadratic forms, return (`true`, `C`) if there exists a -matrix `C` such that `f^A = ag` for some scalar `a`. If such `C` does not -exist, then return (`false`, `nothing`). """ function is_congruent(f::SesquilinearForm{T}, g::SesquilinearForm{T}) where T <: RingElem diff --git a/src/exports.jl b/src/exports.jl index 3caa57a941b0..56c7183815ae 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -783,10 +783,13 @@ export intersections export inv export inv! export invariant_alternating_forms +export invariant_bilinear_form export invariant_bilinear_forms export invariant_hermitian_forms +export invariant_quadratic_form export invariant_quadratic_forms export invariant_ring +export invariant_sesquilinear_form export invariant_sesquilinear_forms export invariant_symmetric_forms export inverse