GAP Integration
This section explains how Oscar interacts with GAP.
The Julia package GAP.jl
This package provides a bidirectional interface between GAP and Julia. Its documentation describes how to call GAP functions in Julia code and vice versa, and how low level Julia objects can be converted to GAP objects and vice versa.
When one works interactively in an Oscar session, calling GAP.prompt()
opens a GAP session which has access to the variables in the Julia session, in particular to all Oscar functions and objects; one can return to the Julia prompt by entering quit;
in the GAP session.
Interface functionalities beyond GAP.jl
For code involving Julia types that are defined in Oscar, GAP.jl cannot provide utility functions such as conversions to and from GAP.
The GAP package OscarInterface (at
gap/OscarInterface
) is intended to contain the GAP code in question, for example the declarations of new filters and the installation of new methods.Note that such code must be loaded at runtime into the GAP session that is started by Julia, and the OscarInterface package gets loaded in Oscar's
__init__
function.The files in the directory
src/GAP
are intended to contain the Julia code in question, for example conversions from GAP toZZRingElem
,QQFieldElem
,FinFieldElem
, etc., and the construction of isomorphisms between algebraic structures such as rings and fields in GAP and Oscar, viaOscar.iso_oscar_gap
andOscar.iso_gap_oscar
.In Oscar code, global GAP variables can be accessed as members of
GAP.Globals
, but for the case of GAP functions, it is more efficient to useOscar.GAPWrap
instead.For example, if one wants to call GAP's
IsFinite
then it is recommended to replace the callGAP.Globals.IsFinite(x)::Bool
, for some GAP objectx
(a group or a ring or a list, etc.), byOscar.GAPWrap.IsFinite(x)
. This works only if the method in question gets defined insrc/GAP/wrappers.jl
, thus methods with the required signatures should be added to this file when they turn out to be needed.(The reason why we collect the
GAP.@wrap
lines in an Oscar file and not inside GAP.jl is that we can extend the list without waiting for releases of GAP.jl.)In GAP code, global Julia variables can be accessed as members of
Julia
, relative to itsMain
module. For example, one can callJulia.sqrt
andJulia.typeof
(orJulia.Base.sqrt
andJulia.Core.typeof
) in GAP code.In order to access variables from the
Oscar
module, it is not safe to useJulia.Oscar
because the moduleOscar
is not always defined inMain
. Instead, there is the global GAP variableOscar
.
iso_oscar_gap
— FunctionOscar.iso_oscar_gap(R::T) -> Map{T, GapObj}
Return an isomorphism f
with domain R
and codomain
a GAP object S
.
Elements x
of R
are mapped to S
via f(x)
, and elements y
of S
are mapped to R
via preimage(f, y)
.
Matrices m
over R
are mapped to matrices over S
via map_entries(f, m)
, and matrices n
over S
are mapped to matrices over R
via Oscar.preimage_matrix(f, n)
.
Admissible values of R
and the corresponding S
are currently as follows.
R | S (in GAP.Globals ) |
---|---|
ZZ | Integers |
QQ | Rationals |
residue_ring(ZZ, n)[1] | mod(Integers, n) |
finite_field(p, d)[1] | GF(p, d) |
cyclotomic_field(n)[1] | CF(n) |
number_field(f::QQPolyRingElem)[1] | AlgebraicExtension(Rationals, g) |
abelian_closure(QQ)[1] | Cyclotomics |
polynomial_ring(F)[1] | PolynomialRing(G) |
polynomial_ring(F, n)[1] | PolynomialRing(G, n) |
(Here g
is the polynomial over GAP.Globals.Rationals
that corresponds to f
, and G
is equal to Oscar.iso_oscar_gap(F)
.)
Examples
julia> f = Oscar.iso_oscar_gap(ZZ);
julia> x = ZZ(2)^100; y = f(x)
GAP: 1267650600228229401496703205376
julia> preimage(f, y) == x
true
julia> m = matrix(ZZ, 2, 3, [1, 2, 3, 4, 5, 6]);
julia> n = map_entries(f, m)
GAP: [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
julia> Oscar.preimage_matrix(f, n) == m
true
julia> R, x = polynomial_ring(QQ);
julia> f = Oscar.iso_oscar_gap(R);
julia> pol = x^2 + x - 1;
julia> y = f(pol)
GAP: x_1^2+x_1-1
julia> preimage(f, y) == pol
true
The functions Oscar.iso_oscar_gap
and Oscar.iso_gap_oscar
are not injective. Due to caching, it may happen that S
stores an attribute value of Oscar.iso_gap_oscar(S)
, but that the codomain of this map is not identical with or even not equal to the given R
.
Note also that R
and S
may differ w.r.t. some structural properties because GAP does not support all kinds of constructions that are possible in Oscar. For example, if R
is a non-simple number field then S
will be a simple extension because GAP knows only simple field extensions. Thus using Oscar.iso_oscar_gap(R)
for objects R
whose recursive structure is not fully supported in GAP will likely cause overhead at runtime.
iso_gap_oscar
— FunctionOscar.iso_gap_oscar(R) -> Map{GapObj, T}
Return an isomorphism f
with domain
the GAP object R
and codomain
an Oscar object S
.
Elements x
of R
are mapped to S
via f(x)
, and elements y
of S
are mapped to R
via preimage(f, y)
.
Matrices m
over R
are mapped to matrices over S
via map_entries(f, m)
, and matrices n
over S
are mapped to matrices over R
via Oscar.preimage_matrix(f, n)
.
Admissible values of R
and the corresponding S
are currently as follows.
S (in GAP.Globals ) | R |
---|---|
Integers | ZZ |
Rationals | QQ |
mod(Integers, n) | residue_ring(ZZ, n)[1] |
GF(p, d) | finite_field(p, d)[1] |
CF(n) | cyclotomic_field(n)[1] |
AlgebraicExtension(Rationals, f) | number_field(g)[1] |
Cyclotomics | abelian_closure(QQ)[1] |
PolynomialRing(F) | polynomial_ring(G)[1] |
PolynomialRing(F, n) | polynomial_ring(G, n)[1] |
(Here g
is the polynomial over QQ
that corresponds to the polynomial f
, and G
is equal to Oscar.iso_gap_oscar(F)
.)
Examples
julia> f = Oscar.iso_gap_oscar(GAP.Globals.Integers);
julia> x = ZZ(2)^100; y = preimage(f, x)
GAP: 1267650600228229401496703205376
julia> f(y) == x
true
julia> m = matrix(ZZ, 2, 3, [1, 2, 3, 4, 5, 6]);
julia> n = Oscar.preimage_matrix(f, m)
GAP: [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
julia> map_entries(f, n) == m
true
julia> R = GAP.Globals.PolynomialRing(GAP.Globals.Rationals);
julia> f = Oscar.iso_gap_oscar(R);
julia> x = gen(codomain(f));
julia> pol = x^2 + x + 1;
julia> y = preimage(f, pol)
GAP: x_1^2+x_1+1
julia> f(y) == pol
true
The functions Oscar.iso_gap_oscar
and Oscar.iso_oscar_gap
are not injective. Due to caching, it may happen that S
stores an attribute value of Oscar.iso_oscar_gap(S)
, but that the codomain of this map is not identical with or even not equal to the given R
.